electron-incremental-update 0.5.1 → 0.6.1
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 +13 -12
- package/dist/{chunk-OBERMV66.mjs → chunk-VADH6AZA.mjs} +12 -21
- package/dist/index.cjs +220 -173
- package/dist/index.d.ts +27 -15
- package/dist/index.mjs +204 -150
- package/dist/vite.cjs +72 -49
- package/dist/vite.d.ts +25 -3
- package/dist/vite.mjs +64 -33
- package/package.json +2 -1
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Buffer } from 'node:buffer';
|
|
2
2
|
|
|
3
3
|
type CheckResultType = Omit<UpdateJSON, 'signature'> | undefined | Error;
|
|
4
|
-
type
|
|
4
|
+
type InstallResult = true | Error;
|
|
5
5
|
type UpdateEvents = {
|
|
6
6
|
downloading: [progress: number];
|
|
7
7
|
debug: [msg: string | Error];
|
|
@@ -11,25 +11,36 @@ type UpdateJSON = {
|
|
|
11
11
|
version: string;
|
|
12
12
|
size: number;
|
|
13
13
|
};
|
|
14
|
+
declare function isUpdateJSON(json: any): json is UpdateJSON;
|
|
14
15
|
type MaybeArray<T> = T extends undefined | null | never ? [] : T extends any[] ? T['length'] extends 1 ? [data: T[0]] : T : [data: T];
|
|
15
16
|
interface TypedUpdater<T extends Record<string | symbol, MaybeArray<any>>, Event extends Exclude<keyof T, number> = Exclude<keyof T, number>> {
|
|
16
17
|
removeAllListeners<E extends Event>(event?: E): this;
|
|
17
18
|
listeners<E extends Event>(eventName: E): Function[];
|
|
18
19
|
eventNames(): (Event)[];
|
|
19
20
|
on<E extends Event>(eventName: E, listener: (...data: MaybeArray<T[E]>) => void): this;
|
|
21
|
+
once<E extends Event>(eventName: E, listener: (...data: MaybeArray<T[E]>) => void): this;
|
|
20
22
|
emit<E extends Event>(eventName: E, ...args: MaybeArray<T[E]>): boolean;
|
|
21
23
|
off<E extends Event>(eventName: E, listener: (...args: MaybeArray<T[E]>) => void): this;
|
|
22
24
|
/**
|
|
25
|
+
* check update info
|
|
26
|
+
* @param data update json url
|
|
27
|
+
* @returns
|
|
23
28
|
* - `{size: number, version: string}`: available
|
|
24
29
|
* - `false`: unavailable
|
|
25
30
|
* - `Error`: fail
|
|
26
31
|
*/
|
|
27
|
-
checkUpdate(
|
|
32
|
+
checkUpdate(data?: string | UpdateJSON): Promise<CheckResultType>;
|
|
28
33
|
/**
|
|
34
|
+
* download update and install
|
|
35
|
+
*
|
|
36
|
+
* if you want to update **offline**, you can set both `src` and `sig` to verify and install
|
|
37
|
+
* @param data asar download url or buffer
|
|
38
|
+
* @param sig signature
|
|
39
|
+
* @returns
|
|
29
40
|
* - `true`: success
|
|
30
41
|
* - `Error`: fail
|
|
31
42
|
*/
|
|
32
|
-
|
|
43
|
+
downloadAndInstall(data?: string | Buffer, sig?: string): Promise<InstallResult>;
|
|
33
44
|
}
|
|
34
45
|
type Updater = TypedUpdater<UpdateEvents>;
|
|
35
46
|
interface UpdaterOption {
|
|
@@ -40,15 +51,15 @@ interface UpdaterOption {
|
|
|
40
51
|
* @example
|
|
41
52
|
* ```ts
|
|
42
53
|
* // auto filled by plugin
|
|
43
|
-
* const
|
|
54
|
+
* const SIGNATURE_CERT = ''
|
|
44
55
|
*
|
|
45
56
|
* const updater = createUpdater({
|
|
46
|
-
*
|
|
57
|
+
* SIGNATURE_CERT,
|
|
47
58
|
* ...
|
|
48
59
|
* })
|
|
49
60
|
* ```
|
|
50
61
|
*/
|
|
51
|
-
|
|
62
|
+
SIGNATURE_CERT: string;
|
|
52
63
|
/**
|
|
53
64
|
* name of your application
|
|
54
65
|
*
|
|
@@ -86,7 +97,7 @@ interface UpdaterOption {
|
|
|
86
97
|
* @param newVersion new version string
|
|
87
98
|
* @returns whether to update
|
|
88
99
|
*/
|
|
89
|
-
compareVersion?: (oldVersion: string, newVersion: string) => boolean
|
|
100
|
+
compareVersion?: (oldVersion: string, newVersion: string) => boolean;
|
|
90
101
|
downloadConfig?: {
|
|
91
102
|
/**
|
|
92
103
|
* download user agent
|
|
@@ -120,7 +131,7 @@ interface UpdaterOption {
|
|
|
120
131
|
* get the application asar absolute path
|
|
121
132
|
* @param name The name of the application
|
|
122
133
|
*/
|
|
123
|
-
declare function
|
|
134
|
+
declare function getProductAsarPath(name: string): string;
|
|
124
135
|
/**
|
|
125
136
|
* get the version of entry (app.asar)
|
|
126
137
|
*/
|
|
@@ -129,7 +140,7 @@ declare function getEntryVersion(): string;
|
|
|
129
140
|
* get the version of application (name.asar)
|
|
130
141
|
* @param name - The name of the application
|
|
131
142
|
*/
|
|
132
|
-
declare function
|
|
143
|
+
declare function getProductVersion(name: string): string;
|
|
133
144
|
/**
|
|
134
145
|
* require native package from app.asar
|
|
135
146
|
* @param packageName native package name
|
|
@@ -147,8 +158,9 @@ declare function getGithubReleaseCdnGroup(): {
|
|
|
147
158
|
maintainer: string;
|
|
148
159
|
}[];
|
|
149
160
|
declare function restartApp(): void;
|
|
161
|
+
declare function waitAppReady(duration?: number): Promise<unknown>;
|
|
150
162
|
|
|
151
|
-
declare function createUpdater({
|
|
163
|
+
declare function createUpdater({ SIGNATURE_CERT, repository, productName, releaseAsarURL: _release, updateJsonURL: _update, debug, downloadConfig, compareVersion, }: UpdaterOption): Updater;
|
|
152
164
|
|
|
153
165
|
type AppOption = {
|
|
154
166
|
/**
|
|
@@ -177,11 +189,11 @@ type InitUpdaterOptions = OptionalProperty<UpdaterOption, 'productName'>;
|
|
|
177
189
|
* import { createUpdater, getGithubReleaseCdnGroup, initApp, parseGithubCdnURL } from 'electron-incremental-update'
|
|
178
190
|
* import { name, repository } from '../package.json'
|
|
179
191
|
*
|
|
180
|
-
* const
|
|
192
|
+
* const SIGNATURE_CERT = '' // auto generate
|
|
181
193
|
*
|
|
182
194
|
* const { cdnPrefix } = getGithubReleaseCdnGroup()[0]
|
|
183
195
|
* const updater = createUpdater({
|
|
184
|
-
*
|
|
196
|
+
* SIGNATURE_CERT,
|
|
185
197
|
* productName: name,
|
|
186
198
|
* repository,
|
|
187
199
|
* updateJsonURL: parseGithubCdnURL(repository, 'fastly.jsdelivr.net/gh', 'version.json'),
|
|
@@ -202,11 +214,11 @@ declare function initApp(appOptions: AppOption): {
|
|
|
202
214
|
* import { initApp } from 'electron-incremental-update'
|
|
203
215
|
* import { name, repository } from '../package.json'
|
|
204
216
|
*
|
|
205
|
-
* const
|
|
217
|
+
* const SIGNATURE_CERT = '' // auto generate
|
|
206
218
|
*
|
|
207
|
-
* initApp({ name }, {
|
|
219
|
+
* initApp({ name }, { SIGNATURE_CERT, repository })
|
|
208
220
|
* ```
|
|
209
221
|
*/
|
|
210
222
|
declare function initApp(appOptions: AppOption, updaterOptions: InitUpdaterOptions): undefined;
|
|
211
223
|
|
|
212
|
-
export { AppOption, CheckResultType,
|
|
224
|
+
export { AppOption, CheckResultType, InitUpdaterOptions, InstallResult, UpdateJSON, Updater, UpdaterOption, createUpdater, getEntryVersion, getGithubReleaseCdnGroup, getProductAsarPath, getProductVersion, initApp, isUpdateJSON, parseGithubCdnURL, requireNative, restartApp, waitAppReady };
|
package/dist/index.mjs
CHANGED
|
@@ -1,34 +1,110 @@
|
|
|
1
1
|
import {
|
|
2
2
|
__require,
|
|
3
3
|
verify
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-VADH6AZA.mjs";
|
|
5
5
|
|
|
6
6
|
// src/index.ts
|
|
7
|
-
import { resolve } from "node:path";
|
|
7
|
+
import { resolve as resolve2 } from "node:path";
|
|
8
8
|
import { app as app3 } from "electron";
|
|
9
9
|
|
|
10
10
|
// src/updater/index.ts
|
|
11
11
|
import { EventEmitter } from "node:events";
|
|
12
|
+
import { Buffer as Buffer2 } from "node:buffer";
|
|
12
13
|
import { createGunzip } from "node:zlib";
|
|
13
|
-
import { createReadStream, createWriteStream, existsSync } from "node:fs";
|
|
14
|
-
import { rm, writeFile } from "node:fs/promises";
|
|
14
|
+
import { createReadStream, createWriteStream, existsSync, rmSync } from "node:fs";
|
|
15
|
+
import { readFile, rename, rm, writeFile } from "node:fs/promises";
|
|
16
|
+
import { resolve } from "node:path";
|
|
15
17
|
import { app as app2 } from "electron";
|
|
16
18
|
|
|
17
19
|
// src/updater/defaultFunctions.ts
|
|
18
20
|
import { Buffer } from "node:buffer";
|
|
19
|
-
import
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
21
|
+
import { net } from "electron";
|
|
22
|
+
|
|
23
|
+
// src/updater/types.ts
|
|
24
|
+
function isUpdateJSON(json) {
|
|
25
|
+
return "signature" in json && "version" in json && "size" in json;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// src/updater/utils.ts
|
|
29
|
+
import { readFileSync } from "node:fs";
|
|
30
|
+
import { dirname, join } from "node:path";
|
|
31
|
+
import { app } from "electron";
|
|
32
|
+
function getProductAsarPath(name) {
|
|
33
|
+
return app.isPackaged ? join(dirname(app.getAppPath()), `${name}.asar`) : "dev";
|
|
34
|
+
}
|
|
35
|
+
function getEntryVersion() {
|
|
36
|
+
return app.getVersion();
|
|
37
|
+
}
|
|
38
|
+
function getProductVersion(name) {
|
|
39
|
+
return app.isPackaged ? readFileSync(join(getProductAsarPath(name), "version"), "utf-8") : getEntryVersion();
|
|
40
|
+
}
|
|
41
|
+
function requireNative(packageName) {
|
|
42
|
+
const path = app.isPackaged ? join(app.getAppPath(), "node_modules", packageName) : packageName;
|
|
43
|
+
return __require(path);
|
|
44
|
+
}
|
|
45
|
+
function parseGithubCdnURL(repository, cdnPrefix, relativeFilePath) {
|
|
46
|
+
if (!repository.startsWith("https://github.com/")) {
|
|
47
|
+
throw new Error("url must start with https://github.com/");
|
|
48
|
+
}
|
|
49
|
+
repository = repository.trim().replace(/\/?$/, "/").trim();
|
|
50
|
+
relativeFilePath = relativeFilePath.trim().replace(/^\/|\/?$/g, "").trim();
|
|
51
|
+
cdnPrefix = cdnPrefix.trim().replace(/^\/?|\/?$/g, "").trim();
|
|
52
|
+
return repository.replace("github.com", cdnPrefix) + relativeFilePath;
|
|
53
|
+
}
|
|
54
|
+
function getGithubReleaseCdnGroup() {
|
|
55
|
+
return [
|
|
56
|
+
{ cdnPrefix: "gh.gh2233.ml", maintainer: "@X.I.U/XIU2" },
|
|
57
|
+
{ cdnPrefix: "ghproxy.com", maintainer: "gh-proxy" },
|
|
58
|
+
{ cdnPrefix: "gh.ddlc.top", maintainer: "@mtr-static-official" },
|
|
59
|
+
{ cdnPrefix: "ghdl.feizhuqwq.cf", maintainer: "feizhuqwq.com" },
|
|
60
|
+
{ cdnPrefix: "slink.ltd", maintainer: "\u77E5\u4E86\u5C0F\u7AD9" },
|
|
61
|
+
{ cdnPrefix: "git.xfj0.cn", maintainer: "anonymous1" },
|
|
62
|
+
{ cdnPrefix: "gh.con.sh", maintainer: "anonymous2" },
|
|
63
|
+
{ cdnPrefix: "ghps.cc", maintainer: "anonymous3" },
|
|
64
|
+
{ cdnPrefix: "cors.isteed.cc/github.com", maintainer: "Lufs's" },
|
|
65
|
+
{ cdnPrefix: "hub.gitmirror.com", maintainer: "GitMirror" },
|
|
66
|
+
{ cdnPrefix: "js.xxooo.ml", maintainer: "\u996D\u592A\u786C" },
|
|
67
|
+
{ cdnPrefix: "download.njuu.cf", maintainer: "LibraryCloud-njuu" },
|
|
68
|
+
{ cdnPrefix: "download.yzuu.cf", maintainer: "LibraryCloud-yzuu" },
|
|
69
|
+
{ cdnPrefix: "download.nuaa.cf", maintainer: "LibraryCloud-nuaa" }
|
|
70
|
+
];
|
|
71
|
+
}
|
|
72
|
+
function restartApp() {
|
|
73
|
+
app.relaunch();
|
|
74
|
+
app.quit();
|
|
75
|
+
}
|
|
76
|
+
function waitAppReady(duration = 1e3) {
|
|
77
|
+
return new Promise((resolve3, reject) => {
|
|
78
|
+
const timeout = setTimeout(() => {
|
|
79
|
+
reject(new Error("app is not ready"));
|
|
80
|
+
}, duration);
|
|
81
|
+
app.whenReady().then(() => {
|
|
82
|
+
clearTimeout(timeout);
|
|
83
|
+
resolve3(null);
|
|
84
|
+
});
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// src/updater/defaultFunctions.ts
|
|
89
|
+
async function downloadJSONDefault(url, updater, headers) {
|
|
90
|
+
await waitAppReady();
|
|
91
|
+
return new Promise((resolve3, reject) => {
|
|
92
|
+
const request = net.request({
|
|
93
|
+
url,
|
|
94
|
+
method: "GET",
|
|
95
|
+
redirect: "follow"
|
|
96
|
+
});
|
|
97
|
+
Object.keys(headers).forEach((key) => {
|
|
98
|
+
request.setHeader(key, headers[key]);
|
|
99
|
+
});
|
|
100
|
+
request.on("response", (res) => {
|
|
23
101
|
let data = "";
|
|
24
|
-
res.setEncoding("utf8");
|
|
25
|
-
res.headers = headers;
|
|
26
102
|
res.on("data", (chunk) => data += chunk);
|
|
27
103
|
res.on("end", () => {
|
|
28
104
|
try {
|
|
29
105
|
const json = JSON.parse(data);
|
|
30
|
-
if (
|
|
31
|
-
|
|
106
|
+
if (isUpdateJSON(json)) {
|
|
107
|
+
resolve3(json);
|
|
32
108
|
} else {
|
|
33
109
|
throw Error;
|
|
34
110
|
}
|
|
@@ -36,28 +112,39 @@ function downloadJSONDefault(url, updater, headers) {
|
|
|
36
112
|
reject(new Error("invalid json"));
|
|
37
113
|
}
|
|
38
114
|
});
|
|
39
|
-
})
|
|
115
|
+
});
|
|
116
|
+
request.on("error", (e) => {
|
|
40
117
|
reject(e);
|
|
41
118
|
});
|
|
119
|
+
request.end();
|
|
42
120
|
});
|
|
43
121
|
}
|
|
44
|
-
function downloadBufferDefault(url, updater, headers) {
|
|
122
|
+
async function downloadBufferDefault(url, updater, headers) {
|
|
123
|
+
await waitAppReady();
|
|
45
124
|
let progress = 0;
|
|
46
|
-
return new Promise((
|
|
47
|
-
|
|
125
|
+
return new Promise((resolve3, reject) => {
|
|
126
|
+
const request = net.request({
|
|
127
|
+
url,
|
|
128
|
+
method: "GET",
|
|
129
|
+
redirect: "follow"
|
|
130
|
+
});
|
|
131
|
+
Object.keys(headers).forEach((key) => {
|
|
132
|
+
request.setHeader(key, headers[key]);
|
|
133
|
+
});
|
|
134
|
+
request.on("response", (res) => {
|
|
48
135
|
let data = [];
|
|
49
|
-
res.headers = headers;
|
|
50
136
|
res.on("data", (chunk) => {
|
|
51
137
|
progress += chunk.length;
|
|
52
138
|
updater.emit("downloading", progress);
|
|
53
139
|
data.push(chunk);
|
|
54
140
|
});
|
|
55
141
|
res.on("end", () => {
|
|
56
|
-
|
|
142
|
+
resolve3(Buffer.concat(data));
|
|
57
143
|
});
|
|
58
144
|
}).on("error", (e) => {
|
|
59
145
|
reject(e);
|
|
60
146
|
});
|
|
147
|
+
request.end();
|
|
61
148
|
});
|
|
62
149
|
}
|
|
63
150
|
function compareVersionDefault(oldVersion, newVersion) {
|
|
@@ -83,58 +170,9 @@ function compareVersionDefault(oldVersion, newVersion) {
|
|
|
83
170
|
return false;
|
|
84
171
|
}
|
|
85
172
|
|
|
86
|
-
// src/updater/utils.ts
|
|
87
|
-
import { readFileSync } from "node:fs";
|
|
88
|
-
import { dirname, join } from "node:path";
|
|
89
|
-
import { app } from "electron";
|
|
90
|
-
function getAppAsarPath(name) {
|
|
91
|
-
return app.isPackaged ? join(dirname(app.getAppPath()), `${name}.asar`) : "dev";
|
|
92
|
-
}
|
|
93
|
-
function getEntryVersion() {
|
|
94
|
-
return app.getVersion();
|
|
95
|
-
}
|
|
96
|
-
function getAppVersion(name) {
|
|
97
|
-
return app.isPackaged ? readFileSync(join(getAppAsarPath(name), "version"), "utf-8") : getEntryVersion();
|
|
98
|
-
}
|
|
99
|
-
function requireNative(packageName) {
|
|
100
|
-
const path = app.isPackaged ? join(app.getAppPath(), "node_modules", packageName) : packageName;
|
|
101
|
-
return __require(path);
|
|
102
|
-
}
|
|
103
|
-
function parseGithubCdnURL(repository, cdnPrefix, relativeFilePath) {
|
|
104
|
-
if (!repository.startsWith("https://github.com/")) {
|
|
105
|
-
throw new Error("url must start with https://github.com/");
|
|
106
|
-
}
|
|
107
|
-
repository = repository.trim().replace(/\/?$/, "/").trim();
|
|
108
|
-
relativeFilePath = relativeFilePath.trim().replace(/^\/|\/?$/g, "").trim();
|
|
109
|
-
cdnPrefix = cdnPrefix.trim().replace(/^\/?|\/?$/g, "").trim();
|
|
110
|
-
return repository.replace("github.com", cdnPrefix) + relativeFilePath;
|
|
111
|
-
}
|
|
112
|
-
function getGithubReleaseCdnGroup() {
|
|
113
|
-
return [
|
|
114
|
-
{ cdnPrefix: "gh.gh2233.ml", maintainer: "@X.I.U/XIU2" },
|
|
115
|
-
{ cdnPrefix: "ghproxy.com", maintainer: "gh-proxy" },
|
|
116
|
-
{ cdnPrefix: "gh.ddlc.top", maintainer: "@mtr-static-official" },
|
|
117
|
-
{ cdnPrefix: "ghdl.feizhuqwq.cf", maintainer: "feizhuqwq.com" },
|
|
118
|
-
{ cdnPrefix: "slink.ltd", maintainer: "\u77E5\u4E86\u5C0F\u7AD9" },
|
|
119
|
-
{ cdnPrefix: "git.xfj0.cn", maintainer: "anonymous1" },
|
|
120
|
-
{ cdnPrefix: "gh.con.sh", maintainer: "anonymous2" },
|
|
121
|
-
{ cdnPrefix: "ghps.cc", maintainer: "anonymous3" },
|
|
122
|
-
{ cdnPrefix: "cors.isteed.cc/github.com", maintainer: "Lufs's" },
|
|
123
|
-
{ cdnPrefix: "hub.gitmirror.com", maintainer: "GitMirror" },
|
|
124
|
-
{ cdnPrefix: "js.xxooo.ml", maintainer: "\u996D\u592A\u786C" },
|
|
125
|
-
{ cdnPrefix: "download.njuu.cf", maintainer: "LibraryCloud-njuu" },
|
|
126
|
-
{ cdnPrefix: "download.yzuu.cf", maintainer: "LibraryCloud-yzuu" },
|
|
127
|
-
{ cdnPrefix: "download.nuaa.cf", maintainer: "LibraryCloud-nuaa" }
|
|
128
|
-
];
|
|
129
|
-
}
|
|
130
|
-
function restartApp() {
|
|
131
|
-
app.relaunch();
|
|
132
|
-
app.quit();
|
|
133
|
-
}
|
|
134
|
-
|
|
135
173
|
// src/updater/index.ts
|
|
136
174
|
function createUpdater({
|
|
137
|
-
|
|
175
|
+
SIGNATURE_CERT,
|
|
138
176
|
repository,
|
|
139
177
|
productName,
|
|
140
178
|
releaseAsarURL: _release,
|
|
@@ -145,94 +183,103 @@ function createUpdater({
|
|
|
145
183
|
}) {
|
|
146
184
|
const updater = new EventEmitter();
|
|
147
185
|
let signature = "";
|
|
148
|
-
|
|
149
|
-
const gzipPath =
|
|
150
|
-
const
|
|
186
|
+
const asarPath = getProductAsarPath(productName);
|
|
187
|
+
const gzipPath = `${asarPath}.gz`;
|
|
188
|
+
const tmpFilePath = gzipPath.replace(".asar.gz", ".tmp.asar");
|
|
151
189
|
const { downloadBuffer, downloadJSON, extraHeader, userAgent } = downloadConfig || {};
|
|
152
190
|
function log(msg) {
|
|
153
191
|
debug && updater.emit("debug", msg);
|
|
154
192
|
}
|
|
155
|
-
async function
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
Accept: `application/${format === "json" ? "json" : "octet-stream"}`,
|
|
159
|
-
UserAgent: ua,
|
|
160
|
-
...extraHeader
|
|
161
|
-
};
|
|
162
|
-
log(`download headers: ${JSON.stringify(headers, null, 2)}`);
|
|
163
|
-
const downloadFn = format === "json" ? downloadJSON ?? downloadJSONDefault : downloadBuffer ?? downloadBufferDefault;
|
|
164
|
-
log(`download ${format} from ${url}`);
|
|
165
|
-
const ret = await downloadFn(url, updater, headers);
|
|
166
|
-
log(`download ${format} success`);
|
|
167
|
-
return ret;
|
|
168
|
-
}
|
|
169
|
-
async function extractFile(gzipFilePath) {
|
|
170
|
-
if (!gzipFilePath.endsWith(".asar.gz") || !existsSync(gzipFilePath)) {
|
|
171
|
-
log("update .asar.gz file not exist");
|
|
172
|
-
return;
|
|
193
|
+
async function extractFile() {
|
|
194
|
+
if (!gzipPath.endsWith(".asar.gz") || !existsSync(gzipPath)) {
|
|
195
|
+
throw new Error(".asar.gz file not exist");
|
|
173
196
|
}
|
|
174
|
-
|
|
175
|
-
return new Promise((resolve2, reject) => {
|
|
197
|
+
return new Promise((resolve3, reject) => {
|
|
176
198
|
const gunzip = createGunzip();
|
|
177
|
-
const input = createReadStream(
|
|
178
|
-
const
|
|
179
|
-
|
|
180
|
-
log(`outputFilePath: ${outputFilePath}`);
|
|
199
|
+
const input = createReadStream(gzipPath);
|
|
200
|
+
const output = createWriteStream(tmpFilePath);
|
|
201
|
+
log(`outputFilePath: ${tmpFilePath}`);
|
|
181
202
|
input.pipe(gunzip).pipe(output).on("finish", async () => {
|
|
182
|
-
await rm(
|
|
183
|
-
log(`${
|
|
184
|
-
|
|
203
|
+
await rm(gzipPath);
|
|
204
|
+
log(`${gzipPath} unzipped`);
|
|
205
|
+
resolve3(null);
|
|
185
206
|
}).on("error", async (err) => {
|
|
186
|
-
await rm(
|
|
207
|
+
await rm(gzipPath);
|
|
187
208
|
output.destroy(err);
|
|
188
209
|
reject(err);
|
|
189
210
|
});
|
|
190
211
|
});
|
|
191
212
|
}
|
|
192
|
-
function needUpdate(
|
|
213
|
+
function needUpdate(version) {
|
|
193
214
|
if (!app2.isPackaged) {
|
|
194
215
|
log("in dev mode, no need to update");
|
|
195
216
|
return false;
|
|
196
217
|
}
|
|
197
218
|
const currentVersion = getEntryVersion();
|
|
198
|
-
log(`check update:
|
|
199
|
-
current version is ${currentVersion},
|
|
200
|
-
new version is ${version2}`);
|
|
219
|
+
log(`check update: current version is ${currentVersion}, new version is ${version}`);
|
|
201
220
|
const _compare = compareVersion ?? compareVersionDefault;
|
|
202
|
-
return _compare(currentVersion,
|
|
221
|
+
return _compare(currentVersion, version);
|
|
203
222
|
}
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
223
|
+
async function parseData(format, data) {
|
|
224
|
+
if (existsSync(tmpFilePath)) {
|
|
225
|
+
log(`remove tmp file: ${tmpFilePath}`);
|
|
226
|
+
await rm(tmpFilePath);
|
|
227
|
+
}
|
|
228
|
+
if (existsSync(gzipPath)) {
|
|
229
|
+
log(`remove .gz file: ${gzipPath}`);
|
|
230
|
+
await rm(gzipPath);
|
|
231
|
+
}
|
|
232
|
+
if (typeof data === "object") {
|
|
233
|
+
if (format === "json" && isUpdateJSON(data) || format === "buffer" && Buffer2.isBuffer(data)) {
|
|
234
|
+
return data;
|
|
235
|
+
} else {
|
|
236
|
+
throw new Error(`invalid type at format '${format}': ${data}`);
|
|
237
|
+
}
|
|
238
|
+
} else if (["string", "undefined"].includes(typeof data)) {
|
|
239
|
+
const ua = userAgent || "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.183 Safari/537.36";
|
|
240
|
+
const headers = {
|
|
241
|
+
Accept: `application/${format === "json" ? "json" : "octet-stream"}`,
|
|
242
|
+
UserAgent: ua,
|
|
243
|
+
...extraHeader
|
|
244
|
+
};
|
|
245
|
+
log(`download headers: ${JSON.stringify(headers, null, 2)}`);
|
|
246
|
+
const info = format === "json" ? {
|
|
247
|
+
name: "updateJsonURL",
|
|
248
|
+
url: _update,
|
|
249
|
+
repoFallback: `${repository.replace("github.com", "raw.githubusercontent.com")}/master/version.json`,
|
|
250
|
+
fn: downloadJSON ?? downloadJSONDefault
|
|
251
|
+
} : {
|
|
252
|
+
name: "releaseAsarURL",
|
|
253
|
+
url: _release,
|
|
254
|
+
repoFallback: `${repository}/releases/download/latest/${productName}.asar.gz`,
|
|
255
|
+
fn: downloadBuffer ?? downloadBufferDefault
|
|
256
|
+
};
|
|
257
|
+
data ??= info.url;
|
|
258
|
+
if (!data) {
|
|
259
|
+
log(`no ${info.name}, fallback to use repository`);
|
|
209
260
|
if (!repository) {
|
|
210
|
-
throw new Error(
|
|
261
|
+
throw new Error(`${info.name} or repository are not set`);
|
|
211
262
|
}
|
|
212
|
-
|
|
263
|
+
data = info.repoFallback;
|
|
213
264
|
}
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
log(`update info: ${JSON.stringify(json, null, 2)}`);
|
|
229
|
-
if (!await needUpdate(_v)) {
|
|
230
|
-
log(`update unavailable: ${_v}`);
|
|
265
|
+
log(`download ${format} from ${data}`);
|
|
266
|
+
const ret = await info.fn(data, updater, headers);
|
|
267
|
+
log(`download ${format} success`);
|
|
268
|
+
return ret;
|
|
269
|
+
} else {
|
|
270
|
+
throw new Error(`invalid type at format '${format}': ${data}`);
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
updater.checkUpdate = async (data) => {
|
|
274
|
+
try {
|
|
275
|
+
const { signature: _sig, size, version } = await parseData("json", data);
|
|
276
|
+
log(`checked version: ${version}, size: ${size}, signature: ${_sig}`);
|
|
277
|
+
if (!needUpdate(version)) {
|
|
278
|
+
log(`update unavailable: ${version}`);
|
|
231
279
|
return void 0;
|
|
232
280
|
} else {
|
|
233
|
-
log(`update available: ${
|
|
281
|
+
log(`update available: ${version}`);
|
|
234
282
|
signature = _sig;
|
|
235
|
-
version = _v;
|
|
236
283
|
return { size, version };
|
|
237
284
|
}
|
|
238
285
|
} catch (error) {
|
|
@@ -240,30 +287,35 @@ function createUpdater({
|
|
|
240
287
|
return error;
|
|
241
288
|
}
|
|
242
289
|
};
|
|
243
|
-
updater.
|
|
290
|
+
updater.downloadAndInstall = async (data, sig) => {
|
|
244
291
|
try {
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
log("no releaseAsarURL, fallback to use repository");
|
|
249
|
-
if (!repository) {
|
|
250
|
-
throw new Error("releaseAsarURL or repository are not set");
|
|
251
|
-
}
|
|
252
|
-
_url = `${repository}/releases/download/latest/${productName}.asar.gz`;
|
|
253
|
-
}
|
|
254
|
-
src = await download(_url, "buffer");
|
|
292
|
+
const _sig = sig ?? signature;
|
|
293
|
+
if (!_sig) {
|
|
294
|
+
throw new Error("signature are not set, please checkUpdate first or set the second parameter");
|
|
255
295
|
}
|
|
296
|
+
const buffer = await parseData("buffer", data);
|
|
256
297
|
log("verify start");
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
throw new Error("invalid signature");
|
|
298
|
+
const version = verify(buffer, _sig, SIGNATURE_CERT);
|
|
299
|
+
if (!version) {
|
|
300
|
+
throw new Error("verify failed, invalid signature");
|
|
260
301
|
}
|
|
261
302
|
log("verify success");
|
|
303
|
+
if (!needUpdate(version)) {
|
|
304
|
+
throw new Error(`update unavailable: ${version}`);
|
|
305
|
+
}
|
|
262
306
|
log(`write file: ${gzipPath}`);
|
|
263
|
-
await writeFile(gzipPath,
|
|
307
|
+
await writeFile(gzipPath, buffer);
|
|
264
308
|
log(`extract file: ${gzipPath}`);
|
|
265
|
-
await extractFile(
|
|
309
|
+
await extractFile();
|
|
310
|
+
const asarVersion = await readFile(resolve(tmpFilePath, "version"), "utf8");
|
|
311
|
+
if (asarVersion !== version) {
|
|
312
|
+
rmSync(tmpFilePath);
|
|
313
|
+
throw new Error(`update failed: asar version is ${asarVersion}, but it should be ${version}`);
|
|
314
|
+
} else {
|
|
315
|
+
await rename(tmpFilePath, asarPath);
|
|
316
|
+
}
|
|
266
317
|
log(`update success, version: ${version}`);
|
|
318
|
+
signature = "";
|
|
267
319
|
return true;
|
|
268
320
|
} catch (error) {
|
|
269
321
|
log(error);
|
|
@@ -281,7 +333,7 @@ function initApp(appOptions, updaterOptions) {
|
|
|
281
333
|
mainPath = "main/index.js"
|
|
282
334
|
} = appOptions ?? {};
|
|
283
335
|
const mainDir = app3.isPackaged ? `../${productName}.asar` : electronDistPath;
|
|
284
|
-
const entry =
|
|
336
|
+
const entry = resolve2(__dirname, mainDir, mainPath);
|
|
285
337
|
if (updaterOptions) {
|
|
286
338
|
__require(entry)(
|
|
287
339
|
createUpdater({ ...updaterOptions, productName })
|
|
@@ -296,12 +348,14 @@ function initApp(appOptions, updaterOptions) {
|
|
|
296
348
|
}
|
|
297
349
|
export {
|
|
298
350
|
createUpdater,
|
|
299
|
-
getAppAsarPath,
|
|
300
|
-
getAppVersion,
|
|
301
351
|
getEntryVersion,
|
|
302
352
|
getGithubReleaseCdnGroup,
|
|
353
|
+
getProductAsarPath,
|
|
354
|
+
getProductVersion,
|
|
303
355
|
initApp,
|
|
356
|
+
isUpdateJSON,
|
|
304
357
|
parseGithubCdnURL,
|
|
305
358
|
requireNative,
|
|
306
|
-
restartApp
|
|
359
|
+
restartApp,
|
|
360
|
+
waitAppReady
|
|
307
361
|
};
|