electron-incremental-update 0.1.1 → 0.1.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.
- package/README.md +37 -14
- package/dist/index.cjs +67 -45
- package/dist/index.d.ts +78 -6
- package/dist/index.mjs +67 -45
- package/dist/vite.cjs +7 -5
- package/dist/vite.d.ts +15 -4
- package/dist/vite.mjs +7 -5
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,25 +1,37 @@
|
|
|
1
1
|
## electron incremental updater
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
provider a vite plugin and useful functions to generate updater and split entry file and real app
|
|
4
|
+
|
|
5
|
+
### principle
|
|
6
|
+
|
|
7
|
+
using two asar, `app.asar` and `main.asar` (if "main" is your app's name)
|
|
8
|
+
|
|
9
|
+
the `app.asar` is used to load `main.asar` and initialize the updater
|
|
10
|
+
|
|
11
|
+
using RSA + Signature to sign the new `main.asar` downloaded from remote and replace the old one when verified
|
|
12
|
+
|
|
13
|
+
- inspired by Obsidian's update strategy
|
|
14
|
+
|
|
15
|
+
### notice
|
|
4
16
|
|
|
5
17
|
develop with [vite-plugin-electron](https://github.com/electron-vite/vite-plugin-electron), and may be effect in other electron vite frameworks
|
|
6
18
|
|
|
7
|
-
|
|
19
|
+
## install
|
|
8
20
|
|
|
9
|
-
|
|
21
|
+
### npm
|
|
10
22
|
```bash
|
|
11
23
|
npm install electron-incremental-update
|
|
12
24
|
```
|
|
13
|
-
|
|
25
|
+
### yarn
|
|
14
26
|
```bash
|
|
15
27
|
yarn add electron-incremental-update
|
|
16
28
|
```
|
|
17
|
-
|
|
29
|
+
### pnpm
|
|
18
30
|
```bash
|
|
19
31
|
pnpm add electron-incremental-update
|
|
20
32
|
```
|
|
21
33
|
|
|
22
|
-
|
|
34
|
+
## usage
|
|
23
35
|
|
|
24
36
|
base on [electron-vite-vue](https://github.com/electron-vite/electron-vite-vue)
|
|
25
37
|
|
|
@@ -36,7 +48,7 @@ src
|
|
|
36
48
|
└── ...
|
|
37
49
|
```
|
|
38
50
|
|
|
39
|
-
|
|
51
|
+
### setup app
|
|
40
52
|
|
|
41
53
|
```ts
|
|
42
54
|
// electron/app.ts
|
|
@@ -47,13 +59,13 @@ const SIGNATURE_PUB = '' // auto generate RSA public key when start app
|
|
|
47
59
|
|
|
48
60
|
const updater = createUpdater({
|
|
49
61
|
SIGNATURE_PUB,
|
|
50
|
-
|
|
62
|
+
repository,
|
|
51
63
|
productName: name,
|
|
52
64
|
})
|
|
53
65
|
initApp(name, updater)
|
|
54
66
|
```
|
|
55
67
|
|
|
56
|
-
|
|
68
|
+
### setup main
|
|
57
69
|
|
|
58
70
|
```ts
|
|
59
71
|
// electron/main/index.ts
|
|
@@ -103,7 +115,7 @@ export default function (updater: Updater) {
|
|
|
103
115
|
}
|
|
104
116
|
```
|
|
105
117
|
|
|
106
|
-
|
|
118
|
+
### use native modules
|
|
107
119
|
|
|
108
120
|
```ts
|
|
109
121
|
// db.ts
|
|
@@ -128,7 +140,7 @@ console.log(r)
|
|
|
128
140
|
db.close()
|
|
129
141
|
```
|
|
130
142
|
|
|
131
|
-
|
|
143
|
+
### setup vite.config.ts
|
|
132
144
|
|
|
133
145
|
```ts
|
|
134
146
|
import { rmSync } from 'node:fs'
|
|
@@ -189,7 +201,7 @@ export default defineConfig(({ command }) => {
|
|
|
189
201
|
})
|
|
190
202
|
```
|
|
191
203
|
|
|
192
|
-
|
|
204
|
+
#### option
|
|
193
205
|
|
|
194
206
|
```ts
|
|
195
207
|
type Options = {
|
|
@@ -213,6 +225,9 @@ type Options = {
|
|
|
213
225
|
* Whether to minify
|
|
214
226
|
*/
|
|
215
227
|
minify?: boolean
|
|
228
|
+
/**
|
|
229
|
+
* path config
|
|
230
|
+
*/
|
|
216
231
|
paths?: {
|
|
217
232
|
/**
|
|
218
233
|
* Path to app entry file
|
|
@@ -225,7 +240,7 @@ type Options = {
|
|
|
225
240
|
*/
|
|
226
241
|
entryOutputPath?: string
|
|
227
242
|
/**
|
|
228
|
-
* Path to
|
|
243
|
+
* Path to asar file
|
|
229
244
|
* @default `release/${ProductName}.asar`
|
|
230
245
|
*/
|
|
231
246
|
asarOutputPath?: string
|
|
@@ -239,7 +254,15 @@ type Options = {
|
|
|
239
254
|
* @default `dist`
|
|
240
255
|
*/
|
|
241
256
|
rendererDistPath?: string
|
|
257
|
+
/**
|
|
258
|
+
* Path to version info output
|
|
259
|
+
* @default `version.json`
|
|
260
|
+
*/
|
|
261
|
+
versionPath?: string
|
|
242
262
|
}
|
|
263
|
+
/**
|
|
264
|
+
* signature config
|
|
265
|
+
*/
|
|
243
266
|
keys?: {
|
|
244
267
|
/**
|
|
245
268
|
* Path to the pem file that contains private key
|
|
@@ -262,7 +285,7 @@ type Options = {
|
|
|
262
285
|
}
|
|
263
286
|
```
|
|
264
287
|
|
|
265
|
-
|
|
288
|
+
### electron-builder config
|
|
266
289
|
|
|
267
290
|
```js
|
|
268
291
|
const { name } = require('./package.json')
|
package/dist/index.cjs
CHANGED
|
@@ -89,49 +89,68 @@ var import_node_fs2 = require("fs");
|
|
|
89
89
|
var import_promises = require("fs/promises");
|
|
90
90
|
var import_node_https = __toESM(require("https"), 1);
|
|
91
91
|
var import_electron2 = require("electron");
|
|
92
|
+
function downloadJSONDefault(url, updater, headers) {
|
|
93
|
+
return new Promise((resolve2, reject) => {
|
|
94
|
+
import_node_https.default.get(url, (res) => {
|
|
95
|
+
let data = "";
|
|
96
|
+
res.setEncoding("utf8");
|
|
97
|
+
res.headers = headers;
|
|
98
|
+
res.on("data", (chunk) => data += chunk);
|
|
99
|
+
res.on("end", () => {
|
|
100
|
+
updater.emit("downloadEnd", true);
|
|
101
|
+
const json = JSON.parse(data);
|
|
102
|
+
if ("signature" in json && "version" in json && "size" in json) {
|
|
103
|
+
resolve2(json);
|
|
104
|
+
} else {
|
|
105
|
+
throw new Error("invalid update json");
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
}).on("error", (e) => {
|
|
109
|
+
e && updater.emit("donwnloadError", e);
|
|
110
|
+
updater.emit("downloadEnd", false);
|
|
111
|
+
reject(e);
|
|
112
|
+
});
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
function downloadBufferDefault(url, updater, headers) {
|
|
116
|
+
return new Promise((resolve2, reject) => {
|
|
117
|
+
import_node_https.default.get(url, (res) => {
|
|
118
|
+
let data = [];
|
|
119
|
+
res.headers = headers;
|
|
120
|
+
res.on("data", (chunk) => {
|
|
121
|
+
updater.emit("downloading", chunk.length);
|
|
122
|
+
data.push(chunk);
|
|
123
|
+
});
|
|
124
|
+
res.on("end", () => {
|
|
125
|
+
updater.emit("downloadEnd", true);
|
|
126
|
+
resolve2(import_node_buffer.Buffer.concat(data));
|
|
127
|
+
});
|
|
128
|
+
}).on("error", (e) => {
|
|
129
|
+
e && updater.emit("donwnloadError", e);
|
|
130
|
+
updater.emit("downloadEnd", false);
|
|
131
|
+
reject(e);
|
|
132
|
+
});
|
|
133
|
+
});
|
|
134
|
+
}
|
|
92
135
|
function createUpdater({
|
|
93
136
|
SIGNATURE_PUB,
|
|
94
|
-
|
|
137
|
+
repository,
|
|
95
138
|
productName,
|
|
96
|
-
|
|
97
|
-
updateJsonURL: _update
|
|
139
|
+
releaseAsarURL: _release,
|
|
140
|
+
updateJsonURL: _update,
|
|
141
|
+
downloadConfig
|
|
98
142
|
}) {
|
|
99
143
|
const updater = new import_node_events.EventEmitter();
|
|
144
|
+
const { downloadBuffer, downloadJSON, extraHeader, userAgent } = downloadConfig || {};
|
|
100
145
|
async function download(url, format) {
|
|
101
|
-
const ua = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.183 Safari/537.36";
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
UserAgent: ua
|
|
110
|
-
};
|
|
111
|
-
res.on("data", (chunk) => data += chunk);
|
|
112
|
-
res.on("end", () => {
|
|
113
|
-
resolve2(JSON.parse(data));
|
|
114
|
-
});
|
|
115
|
-
} else if (format === "buffer") {
|
|
116
|
-
let data = [];
|
|
117
|
-
res.headers = {
|
|
118
|
-
Accept: "application/octet-stream",
|
|
119
|
-
UserAgent: ua
|
|
120
|
-
};
|
|
121
|
-
res.on("data", (chunk) => {
|
|
122
|
-
updater.emit("downloading", chunk.length);
|
|
123
|
-
data.push(chunk);
|
|
124
|
-
});
|
|
125
|
-
res.on("end", () => {
|
|
126
|
-
updater.emit("downloadEnd", true);
|
|
127
|
-
resolve2(import_node_buffer.Buffer.concat(data));
|
|
128
|
-
});
|
|
129
|
-
}
|
|
130
|
-
}).on("error", (e) => {
|
|
131
|
-
e && updater.emit("donwnloadError", e);
|
|
132
|
-
reject(e);
|
|
133
|
-
});
|
|
134
|
-
});
|
|
146
|
+
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";
|
|
147
|
+
const headers = {
|
|
148
|
+
Accept: `application/${format === "json" ? "json" : "octet-stream"}`,
|
|
149
|
+
UserAgent: ua,
|
|
150
|
+
...extraHeader
|
|
151
|
+
};
|
|
152
|
+
const downloadFn = format === "json" ? downloadJSON ?? downloadJSONDefault : downloadBuffer ?? downloadBufferDefault;
|
|
153
|
+
return await downloadFn(url, updater, headers);
|
|
135
154
|
}
|
|
136
155
|
async function extractFile(gzipFilePath) {
|
|
137
156
|
if (!gzipFilePath.endsWith(".asar.gz") || !(0, import_node_fs2.existsSync)(gzipFilePath)) {
|
|
@@ -164,17 +183,21 @@ function createUpdater({
|
|
|
164
183
|
return import_electron2.app.isPackaged && parseVersion(import_electron2.app.getVersion()) < parseVersion(version);
|
|
165
184
|
}
|
|
166
185
|
async function checkUpdate(option) {
|
|
167
|
-
|
|
186
|
+
let {
|
|
187
|
+
updateJsonURL = _update,
|
|
188
|
+
releaseAsarURL = _release
|
|
189
|
+
} = option || {};
|
|
190
|
+
if ((!updateJsonURL || !releaseAsarURL) && !repository) {
|
|
191
|
+
throw new Error("updateJsonURL or releaseAsarURL are not set");
|
|
192
|
+
}
|
|
193
|
+
updateJsonURL ??= `${repository}/version.json`;
|
|
194
|
+
releaseAsarURL ??= `${repository}/releases/download/latest/${productName}.asar.gz`;
|
|
168
195
|
const gzipPath = `../${productName}.asar.gz`;
|
|
169
196
|
const tmpFile = gzipPath.replace(".asar.gz", ".tmp.gz");
|
|
170
|
-
const base = githubRepository.replace("https://github.com", "");
|
|
171
|
-
const updateJSONUrl = updateJsonURL ?? _update ?? `https://cdn.jsdelivr.net/gh/${base}/version.json`;
|
|
172
|
-
const prefix = releaseCdnPrefix ?? _release;
|
|
173
|
-
const downloadUrl = `${prefix ? `${prefix}/${base}` : githubRepository}/releases/download/latest/${productName}.asar.gz`;
|
|
174
197
|
if ((0, import_node_fs2.existsSync)(tmpFile)) {
|
|
175
198
|
await (0, import_promises.rm)(tmpFile);
|
|
176
199
|
}
|
|
177
|
-
const json = await download(
|
|
200
|
+
const json = await download(updateJsonURL, "json");
|
|
178
201
|
if (!json) {
|
|
179
202
|
throw new Error("fetch update json failed");
|
|
180
203
|
}
|
|
@@ -183,12 +206,11 @@ function createUpdater({
|
|
|
183
206
|
version,
|
|
184
207
|
size
|
|
185
208
|
} = json;
|
|
186
|
-
console.log(version, size, signature);
|
|
187
209
|
if (!needUpdate(version)) {
|
|
188
210
|
return "unavailable";
|
|
189
211
|
}
|
|
190
212
|
updater.emit("downloadStart", size);
|
|
191
|
-
const buffer = await download(
|
|
213
|
+
const buffer = await download(releaseAsarURL, "buffer");
|
|
192
214
|
if (!verify(buffer, signature)) {
|
|
193
215
|
throw new Error("file broken, invalid signature!");
|
|
194
216
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { Buffer } from 'node:buffer';
|
|
2
|
+
|
|
1
3
|
type CheckResultType = 'success' | 'fail' | 'unavailable';
|
|
2
4
|
type UpdateEvents = {
|
|
3
5
|
check: null;
|
|
@@ -7,10 +9,25 @@ type UpdateEvents = {
|
|
|
7
9
|
downloadEnd: [success: boolean];
|
|
8
10
|
donwnloadError: [error: unknown];
|
|
9
11
|
};
|
|
12
|
+
type UpdateJSON = {
|
|
13
|
+
signature: string;
|
|
14
|
+
version: string;
|
|
15
|
+
size: number;
|
|
16
|
+
};
|
|
10
17
|
type MaybeArray<T> = T extends undefined | null | never ? [] : T extends any[] ? T['length'] extends 1 ? [data: T[0]] : T : [data: T];
|
|
11
|
-
interface
|
|
18
|
+
interface UpdateOption {
|
|
19
|
+
/**
|
|
20
|
+
* URL of version info json
|
|
21
|
+
* @default `${repository}/version.json`
|
|
22
|
+
* @throws if `updateJsonURL` and `repository` are all not set
|
|
23
|
+
*/
|
|
12
24
|
updateJsonURL?: string;
|
|
13
|
-
|
|
25
|
+
/**
|
|
26
|
+
* URL of release asar.gz
|
|
27
|
+
* @default `${repository}/releases/download/latest/${productName}.asar.gz`
|
|
28
|
+
* @throws if `releaseAsarURL` and `repository` are all not set
|
|
29
|
+
*/
|
|
30
|
+
releaseAsarURL?: string;
|
|
14
31
|
}
|
|
15
32
|
interface TypedUpdater<T extends Record<string | symbol, MaybeArray<any>>, Event extends Exclude<keyof T, number> = Exclude<keyof T, number>> {
|
|
16
33
|
removeAllListeners<E extends Event>(event?: E): this;
|
|
@@ -20,15 +37,70 @@ interface TypedUpdater<T extends Record<string | symbol, MaybeArray<any>>, Event
|
|
|
20
37
|
once<E extends Event>(eventName: E, listener: (...args: MaybeArray<T[E]>) => void): this;
|
|
21
38
|
emit<E extends Event>(eventName: E, ...args: MaybeArray<T[E]>): boolean;
|
|
22
39
|
off<E extends Event>(eventName: E, listener: (...args: MaybeArray<T[E]>) => void): this;
|
|
23
|
-
checkUpdate(options?:
|
|
40
|
+
checkUpdate(options?: UpdateOption): Promise<void>;
|
|
24
41
|
}
|
|
25
42
|
type Updater = TypedUpdater<UpdateEvents>;
|
|
26
|
-
interface Options extends
|
|
43
|
+
interface Options extends UpdateOption {
|
|
44
|
+
/**
|
|
45
|
+
* public key of signature
|
|
46
|
+
*
|
|
47
|
+
* it will be auto generated by plugin
|
|
48
|
+
* @example
|
|
49
|
+
* ```ts
|
|
50
|
+
* // auto filled by plugin
|
|
51
|
+
* const SIGNATURE_PUB = ''
|
|
52
|
+
*
|
|
53
|
+
* const updater = createUpdater({
|
|
54
|
+
* SIGNATURE_PUB,
|
|
55
|
+
* ...
|
|
56
|
+
* })
|
|
57
|
+
* ```
|
|
58
|
+
*/
|
|
27
59
|
SIGNATURE_PUB: string;
|
|
60
|
+
/**
|
|
61
|
+
* product name
|
|
62
|
+
*
|
|
63
|
+
* you can use the `name` in `package.json`
|
|
64
|
+
*/
|
|
28
65
|
productName: string;
|
|
29
|
-
|
|
66
|
+
/**
|
|
67
|
+
* repository url, e.g. `https://github.com/electron/electron`
|
|
68
|
+
*
|
|
69
|
+
* you can use the `repository` in `package.json`
|
|
70
|
+
*
|
|
71
|
+
* if `updateJsonURL` or `releaseAsarURL` are absent,
|
|
72
|
+
* `repository` will be used to determine the url
|
|
73
|
+
*/
|
|
74
|
+
repository?: string;
|
|
75
|
+
downloadConfig?: {
|
|
76
|
+
/**
|
|
77
|
+
* download user agent
|
|
78
|
+
* @default 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.183 Safari/537.36'
|
|
79
|
+
*/
|
|
80
|
+
userAgent?: string;
|
|
81
|
+
/**
|
|
82
|
+
* extra download header, `accept` and `user-agent` is set by default
|
|
83
|
+
*/
|
|
84
|
+
extraHeader?: Record<string, string>;
|
|
85
|
+
/**
|
|
86
|
+
* download JSON function
|
|
87
|
+
* @param url download url
|
|
88
|
+
* @param updater updater, emit events
|
|
89
|
+
* @param header download header
|
|
90
|
+
* @returns `UpdateJSON`
|
|
91
|
+
*/
|
|
92
|
+
downloadJSON?: (url: string, updater: Updater, headers: Record<string, any>) => Promise<UpdateJSON>;
|
|
93
|
+
/**
|
|
94
|
+
* download buffer function
|
|
95
|
+
* @param url download url
|
|
96
|
+
* @param updater updater, emit events
|
|
97
|
+
* @param header download header
|
|
98
|
+
* @returns `Buffer`
|
|
99
|
+
*/
|
|
100
|
+
downloadBuffer?: (url: string, updater: Updater, headers: Record<string, any>) => Promise<Buffer>;
|
|
101
|
+
};
|
|
30
102
|
}
|
|
31
|
-
declare function createUpdater({ SIGNATURE_PUB,
|
|
103
|
+
declare function createUpdater({ SIGNATURE_PUB, repository, productName, releaseAsarURL: _release, updateJsonURL: _update, downloadConfig, }: Options): Updater;
|
|
32
104
|
|
|
33
105
|
declare function getAppAsarPath(name: string): string;
|
|
34
106
|
declare function getElectronVersion(): string;
|
package/dist/index.mjs
CHANGED
|
@@ -53,49 +53,68 @@ import { createReadStream, createWriteStream, existsSync } from "node:fs";
|
|
|
53
53
|
import { rm, writeFile } from "node:fs/promises";
|
|
54
54
|
import https from "node:https";
|
|
55
55
|
import { app as app2 } from "electron";
|
|
56
|
+
function downloadJSONDefault(url, updater, headers) {
|
|
57
|
+
return new Promise((resolve2, reject) => {
|
|
58
|
+
https.get(url, (res) => {
|
|
59
|
+
let data = "";
|
|
60
|
+
res.setEncoding("utf8");
|
|
61
|
+
res.headers = headers;
|
|
62
|
+
res.on("data", (chunk) => data += chunk);
|
|
63
|
+
res.on("end", () => {
|
|
64
|
+
updater.emit("downloadEnd", true);
|
|
65
|
+
const json = JSON.parse(data);
|
|
66
|
+
if ("signature" in json && "version" in json && "size" in json) {
|
|
67
|
+
resolve2(json);
|
|
68
|
+
} else {
|
|
69
|
+
throw new Error("invalid update json");
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
}).on("error", (e) => {
|
|
73
|
+
e && updater.emit("donwnloadError", e);
|
|
74
|
+
updater.emit("downloadEnd", false);
|
|
75
|
+
reject(e);
|
|
76
|
+
});
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
function downloadBufferDefault(url, updater, headers) {
|
|
80
|
+
return new Promise((resolve2, reject) => {
|
|
81
|
+
https.get(url, (res) => {
|
|
82
|
+
let data = [];
|
|
83
|
+
res.headers = headers;
|
|
84
|
+
res.on("data", (chunk) => {
|
|
85
|
+
updater.emit("downloading", chunk.length);
|
|
86
|
+
data.push(chunk);
|
|
87
|
+
});
|
|
88
|
+
res.on("end", () => {
|
|
89
|
+
updater.emit("downloadEnd", true);
|
|
90
|
+
resolve2(Buffer.concat(data));
|
|
91
|
+
});
|
|
92
|
+
}).on("error", (e) => {
|
|
93
|
+
e && updater.emit("donwnloadError", e);
|
|
94
|
+
updater.emit("downloadEnd", false);
|
|
95
|
+
reject(e);
|
|
96
|
+
});
|
|
97
|
+
});
|
|
98
|
+
}
|
|
56
99
|
function createUpdater({
|
|
57
100
|
SIGNATURE_PUB,
|
|
58
|
-
|
|
101
|
+
repository,
|
|
59
102
|
productName,
|
|
60
|
-
|
|
61
|
-
updateJsonURL: _update
|
|
103
|
+
releaseAsarURL: _release,
|
|
104
|
+
updateJsonURL: _update,
|
|
105
|
+
downloadConfig
|
|
62
106
|
}) {
|
|
63
107
|
const updater = new EventEmitter();
|
|
108
|
+
const { downloadBuffer, downloadJSON, extraHeader, userAgent } = downloadConfig || {};
|
|
64
109
|
async function download(url, format) {
|
|
65
|
-
const ua = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.183 Safari/537.36";
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
UserAgent: ua
|
|
74
|
-
};
|
|
75
|
-
res.on("data", (chunk) => data += chunk);
|
|
76
|
-
res.on("end", () => {
|
|
77
|
-
resolve2(JSON.parse(data));
|
|
78
|
-
});
|
|
79
|
-
} else if (format === "buffer") {
|
|
80
|
-
let data = [];
|
|
81
|
-
res.headers = {
|
|
82
|
-
Accept: "application/octet-stream",
|
|
83
|
-
UserAgent: ua
|
|
84
|
-
};
|
|
85
|
-
res.on("data", (chunk) => {
|
|
86
|
-
updater.emit("downloading", chunk.length);
|
|
87
|
-
data.push(chunk);
|
|
88
|
-
});
|
|
89
|
-
res.on("end", () => {
|
|
90
|
-
updater.emit("downloadEnd", true);
|
|
91
|
-
resolve2(Buffer.concat(data));
|
|
92
|
-
});
|
|
93
|
-
}
|
|
94
|
-
}).on("error", (e) => {
|
|
95
|
-
e && updater.emit("donwnloadError", e);
|
|
96
|
-
reject(e);
|
|
97
|
-
});
|
|
98
|
-
});
|
|
110
|
+
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";
|
|
111
|
+
const headers = {
|
|
112
|
+
Accept: `application/${format === "json" ? "json" : "octet-stream"}`,
|
|
113
|
+
UserAgent: ua,
|
|
114
|
+
...extraHeader
|
|
115
|
+
};
|
|
116
|
+
const downloadFn = format === "json" ? downloadJSON ?? downloadJSONDefault : downloadBuffer ?? downloadBufferDefault;
|
|
117
|
+
return await downloadFn(url, updater, headers);
|
|
99
118
|
}
|
|
100
119
|
async function extractFile(gzipFilePath) {
|
|
101
120
|
if (!gzipFilePath.endsWith(".asar.gz") || !existsSync(gzipFilePath)) {
|
|
@@ -128,17 +147,21 @@ function createUpdater({
|
|
|
128
147
|
return app2.isPackaged && parseVersion(app2.getVersion()) < parseVersion(version);
|
|
129
148
|
}
|
|
130
149
|
async function checkUpdate(option) {
|
|
131
|
-
|
|
150
|
+
let {
|
|
151
|
+
updateJsonURL = _update,
|
|
152
|
+
releaseAsarURL = _release
|
|
153
|
+
} = option || {};
|
|
154
|
+
if ((!updateJsonURL || !releaseAsarURL) && !repository) {
|
|
155
|
+
throw new Error("updateJsonURL or releaseAsarURL are not set");
|
|
156
|
+
}
|
|
157
|
+
updateJsonURL ??= `${repository}/version.json`;
|
|
158
|
+
releaseAsarURL ??= `${repository}/releases/download/latest/${productName}.asar.gz`;
|
|
132
159
|
const gzipPath = `../${productName}.asar.gz`;
|
|
133
160
|
const tmpFile = gzipPath.replace(".asar.gz", ".tmp.gz");
|
|
134
|
-
const base = githubRepository.replace("https://github.com", "");
|
|
135
|
-
const updateJSONUrl = updateJsonURL ?? _update ?? `https://cdn.jsdelivr.net/gh/${base}/version.json`;
|
|
136
|
-
const prefix = releaseCdnPrefix ?? _release;
|
|
137
|
-
const downloadUrl = `${prefix ? `${prefix}/${base}` : githubRepository}/releases/download/latest/${productName}.asar.gz`;
|
|
138
161
|
if (existsSync(tmpFile)) {
|
|
139
162
|
await rm(tmpFile);
|
|
140
163
|
}
|
|
141
|
-
const json = await download(
|
|
164
|
+
const json = await download(updateJsonURL, "json");
|
|
142
165
|
if (!json) {
|
|
143
166
|
throw new Error("fetch update json failed");
|
|
144
167
|
}
|
|
@@ -147,12 +170,11 @@ function createUpdater({
|
|
|
147
170
|
version,
|
|
148
171
|
size
|
|
149
172
|
} = json;
|
|
150
|
-
console.log(version, size, signature);
|
|
151
173
|
if (!needUpdate(version)) {
|
|
152
174
|
return "unavailable";
|
|
153
175
|
}
|
|
154
176
|
updater.emit("downloadStart", size);
|
|
155
|
-
const buffer = await download(
|
|
177
|
+
const buffer = await download(releaseAsarURL, "buffer");
|
|
156
178
|
if (!verify(buffer, signature)) {
|
|
157
179
|
throw new Error("file broken, invalid signature!");
|
|
158
180
|
}
|
package/dist/vite.cjs
CHANGED
|
@@ -140,7 +140,8 @@ async function buildAsar({
|
|
|
140
140
|
asarOutputPath,
|
|
141
141
|
privateKeyPath,
|
|
142
142
|
electronDistPath,
|
|
143
|
-
rendererDistPath
|
|
143
|
+
rendererDistPath,
|
|
144
|
+
versionPath
|
|
144
145
|
}) {
|
|
145
146
|
await (0, import_promises2.rename)(rendererDistPath, `${electronDistPath}/renderer`);
|
|
146
147
|
await (0, import_promises2.writeFile)(`${electronDistPath}/version`, version);
|
|
@@ -151,7 +152,7 @@ async function buildAsar({
|
|
|
151
152
|
await gzipFile(asarOutputPath);
|
|
152
153
|
const buffer = await (0, import_promises2.readFile)(`${asarOutputPath}.gz`);
|
|
153
154
|
const signature = generateSignature(buffer, await (0, import_promises2.readFile)(privateKeyPath, "utf-8"));
|
|
154
|
-
await (0, import_promises2.writeFile)(
|
|
155
|
+
await (0, import_promises2.writeFile)(versionPath, JSON.stringify({
|
|
155
156
|
signature,
|
|
156
157
|
version,
|
|
157
158
|
size: buffer.length
|
|
@@ -166,7 +167,8 @@ function parseOptions(options) {
|
|
|
166
167
|
entryOutputPath = "app.js",
|
|
167
168
|
asarOutputPath = `release/${productName}.asar`,
|
|
168
169
|
electronDistPath = "dist-electron",
|
|
169
|
-
rendererDistPath = "dist"
|
|
170
|
+
rendererDistPath = "dist",
|
|
171
|
+
versionPath = "version.json"
|
|
170
172
|
} = paths;
|
|
171
173
|
const {
|
|
172
174
|
privateKeyPath = "public/private.pem",
|
|
@@ -175,11 +177,11 @@ function parseOptions(options) {
|
|
|
175
177
|
} = keys;
|
|
176
178
|
const buildAsarOption = {
|
|
177
179
|
version,
|
|
178
|
-
productName,
|
|
179
180
|
asarOutputPath,
|
|
180
181
|
privateKeyPath,
|
|
181
182
|
electronDistPath,
|
|
182
|
-
rendererDistPath
|
|
183
|
+
rendererDistPath,
|
|
184
|
+
versionPath
|
|
183
185
|
};
|
|
184
186
|
const buildEntryOption = {
|
|
185
187
|
privateKeyPath,
|
package/dist/vite.d.ts
CHANGED
|
@@ -8,19 +8,22 @@ type Options = {
|
|
|
8
8
|
/**
|
|
9
9
|
* the name of you application
|
|
10
10
|
*
|
|
11
|
-
* you can set as 'name' in package.json
|
|
11
|
+
* you can set as 'name' in `package.json`
|
|
12
12
|
*/
|
|
13
13
|
productName: string;
|
|
14
14
|
/**
|
|
15
15
|
* the version of you application
|
|
16
16
|
*
|
|
17
|
-
* you can set as 'version' in package.json
|
|
17
|
+
* you can set as 'version' in `package.json`
|
|
18
18
|
*/
|
|
19
19
|
version: string;
|
|
20
20
|
/**
|
|
21
|
-
* Whether to minify
|
|
21
|
+
* Whether to minify entry file
|
|
22
22
|
*/
|
|
23
23
|
minify?: boolean;
|
|
24
|
+
/**
|
|
25
|
+
* paths config
|
|
26
|
+
*/
|
|
24
27
|
paths?: {
|
|
25
28
|
/**
|
|
26
29
|
* Path to app entry file
|
|
@@ -33,7 +36,7 @@ type Options = {
|
|
|
33
36
|
*/
|
|
34
37
|
entryOutputPath?: string;
|
|
35
38
|
/**
|
|
36
|
-
* Path to
|
|
39
|
+
* Path to asar file
|
|
37
40
|
* @default `release/${ProductName}.asar`
|
|
38
41
|
*/
|
|
39
42
|
asarOutputPath?: string;
|
|
@@ -47,7 +50,15 @@ type Options = {
|
|
|
47
50
|
* @default `dist`
|
|
48
51
|
*/
|
|
49
52
|
rendererDistPath?: string;
|
|
53
|
+
/**
|
|
54
|
+
* Path to version info output
|
|
55
|
+
* @default `version.json`
|
|
56
|
+
*/
|
|
57
|
+
versionPath?: string;
|
|
50
58
|
};
|
|
59
|
+
/**
|
|
60
|
+
* signature config
|
|
61
|
+
*/
|
|
51
62
|
keys?: {
|
|
52
63
|
/**
|
|
53
64
|
* Path to the pem file that contains private key
|
package/dist/vite.mjs
CHANGED
|
@@ -108,7 +108,8 @@ async function buildAsar({
|
|
|
108
108
|
asarOutputPath,
|
|
109
109
|
privateKeyPath,
|
|
110
110
|
electronDistPath,
|
|
111
|
-
rendererDistPath
|
|
111
|
+
rendererDistPath,
|
|
112
|
+
versionPath
|
|
112
113
|
}) {
|
|
113
114
|
await rename(rendererDistPath, `${electronDistPath}/renderer`);
|
|
114
115
|
await writeFile2(`${electronDistPath}/version`, version);
|
|
@@ -119,7 +120,7 @@ async function buildAsar({
|
|
|
119
120
|
await gzipFile(asarOutputPath);
|
|
120
121
|
const buffer = await readFile2(`${asarOutputPath}.gz`);
|
|
121
122
|
const signature = generateSignature(buffer, await readFile2(privateKeyPath, "utf-8"));
|
|
122
|
-
await writeFile2(
|
|
123
|
+
await writeFile2(versionPath, JSON.stringify({
|
|
123
124
|
signature,
|
|
124
125
|
version,
|
|
125
126
|
size: buffer.length
|
|
@@ -134,7 +135,8 @@ function parseOptions(options) {
|
|
|
134
135
|
entryOutputPath = "app.js",
|
|
135
136
|
asarOutputPath = `release/${productName}.asar`,
|
|
136
137
|
electronDistPath = "dist-electron",
|
|
137
|
-
rendererDistPath = "dist"
|
|
138
|
+
rendererDistPath = "dist",
|
|
139
|
+
versionPath = "version.json"
|
|
138
140
|
} = paths;
|
|
139
141
|
const {
|
|
140
142
|
privateKeyPath = "public/private.pem",
|
|
@@ -143,11 +145,11 @@ function parseOptions(options) {
|
|
|
143
145
|
} = keys;
|
|
144
146
|
const buildAsarOption = {
|
|
145
147
|
version,
|
|
146
|
-
productName,
|
|
147
148
|
asarOutputPath,
|
|
148
149
|
privateKeyPath,
|
|
149
150
|
electronDistPath,
|
|
150
|
-
rendererDistPath
|
|
151
|
+
rendererDistPath,
|
|
152
|
+
versionPath
|
|
151
153
|
};
|
|
152
154
|
const buildEntryOption = {
|
|
153
155
|
privateKeyPath,
|