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/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 DownloadResult = true | Error;
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(url?: string): Promise<CheckResultType>;
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
- downloadUpdate(url?: string | Buffer): Promise<DownloadResult>;
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 SIGNATURE_PUB = ''
54
+ * const SIGNATURE_CERT = ''
44
55
  *
45
56
  * const updater = createUpdater({
46
- * SIGNATURE_PUB,
57
+ * SIGNATURE_CERT,
47
58
  * ...
48
59
  * })
49
60
  * ```
50
61
  */
51
- SIGNATURE_PUB: string;
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 | Promise<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 getAppAsarPath(name: string): string;
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 getAppVersion(name: string): string;
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({ SIGNATURE_PUB, repository, productName, releaseAsarURL: _release, updateJsonURL: _update, debug, downloadConfig, compareVersion, }: UpdaterOption): Updater;
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 SIGNATURE_PUB = '' // auto generate
192
+ * const SIGNATURE_CERT = '' // auto generate
181
193
  *
182
194
  * const { cdnPrefix } = getGithubReleaseCdnGroup()[0]
183
195
  * const updater = createUpdater({
184
- * SIGNATURE_PUB,
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 SIGNATURE_PUB = '' // auto generate
217
+ * const SIGNATURE_CERT = '' // auto generate
206
218
  *
207
- * initApp({ name }, { SIGNATURE_PUB, repository })
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, DownloadResult, InitUpdaterOptions, UpdateJSON, Updater, UpdaterOption, createUpdater, getAppAsarPath, getAppVersion, getEntryVersion, getGithubReleaseCdnGroup, initApp, parseGithubCdnURL, requireNative, restartApp };
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-OBERMV66.mjs";
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 https from "node:https";
20
- function downloadJSONDefault(url, updater, headers) {
21
- return new Promise((resolve2, reject) => {
22
- https.get(url, (res) => {
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 ("signature" in json && "version" in json && "size" in json) {
31
- resolve2(json);
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
- }).on("error", (e) => {
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((resolve2, reject) => {
47
- https.get(url, (res) => {
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
- resolve2(Buffer.concat(data));
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
- SIGNATURE_PUB,
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
- let version = "";
149
- const gzipPath = `../${productName}.asar.gz`;
150
- const tmpFile = gzipPath.replace(".asar.gz", ".tmp.gz");
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 download(url, format) {
156
- 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";
157
- const headers = {
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
- gzipFilePath = gzipFilePath.replace(".asar.gz", ".tmp.gz");
175
- return new Promise((resolve2, reject) => {
197
+ return new Promise((resolve3, reject) => {
176
198
  const gunzip = createGunzip();
177
- const input = createReadStream(gzipFilePath);
178
- const outputFilePath = gzipFilePath.replace(".tmp.gz", ".asar");
179
- const output = createWriteStream(outputFilePath);
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(gzipFilePath);
183
- log(`${gzipFilePath} unzipped`);
184
- resolve2(outputFilePath);
203
+ await rm(gzipPath);
204
+ log(`${gzipPath} unzipped`);
205
+ resolve3(null);
185
206
  }).on("error", async (err) => {
186
- await rm(gzipFilePath);
207
+ await rm(gzipPath);
187
208
  output.destroy(err);
188
209
  reject(err);
189
210
  });
190
211
  });
191
212
  }
192
- function needUpdate(version2) {
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, version2);
221
+ return _compare(currentVersion, version);
203
222
  }
204
- updater.checkUpdate = async (url) => {
205
- try {
206
- url ??= _update;
207
- if (!url) {
208
- log("no updateJsonURL, fallback to use repository");
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("updateJsonURL or repository are not set");
261
+ throw new Error(`${info.name} or repository are not set`);
211
262
  }
212
- url = `${repository.replace("github.com", "raw.githubusercontent.com")}/master/version.json`;
263
+ data = info.repoFallback;
213
264
  }
214
- if (existsSync(tmpFile)) {
215
- log(`remove tmp file: ${tmpFile}`);
216
- await rm(tmpFile);
217
- }
218
- if (existsSync(gzipPath)) {
219
- log(`remove .gz file: ${gzipPath}`);
220
- await rm(gzipPath);
221
- }
222
- const json = await download(url, "json");
223
- const {
224
- signature: _sig,
225
- version: _v,
226
- size
227
- } = json;
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: ${_v}`);
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.downloadUpdate = async (src) => {
290
+ updater.downloadAndInstall = async (data, sig) => {
244
291
  try {
245
- if (typeof src !== "object") {
246
- let _url = src ?? _release;
247
- if (!_url) {
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
- if (!verify(src, signature, SIGNATURE_PUB)) {
258
- log("verify failed");
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, src);
307
+ await writeFile(gzipPath, buffer);
264
308
  log(`extract file: ${gzipPath}`);
265
- await extractFile(gzipPath);
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 = resolve(__dirname, mainDir, mainPath);
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
  };