electron-incremental-update 2.0.0-beta.1 → 2.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.
package/dist/index.js CHANGED
@@ -1,43 +1,30 @@
1
- import {
2
- __require,
3
- getAppVersion,
4
- getEntryVersion,
5
- getPathFromAppNameAsar,
6
- isDev,
7
- isUpdateJSON,
8
- restartApp,
9
- unzipFile
10
- } from "./chunk-RSLOPAIZ.js";
11
-
12
- // src/entry.ts
13
- import { join } from "node:path";
14
- import { existsSync as existsSync2, renameSync } from "node:fs";
15
- import { app as app2 } from "electron";
16
-
17
- // src/updater/core.ts
18
- import { existsSync, rmSync, writeFileSync } from "node:fs";
19
- import { app } from "electron";
1
+ import { isDev, getPathFromAppNameAsar, getEntryVersion, getAppVersion, restartApp } from './chunk-PNYRQYFC.js';
2
+ import { isUpdateJSON, __require } from './chunk-BVFQWBLK.js';
3
+ import { join } from 'node:path';
4
+ import { existsSync, rmSync, renameSync } from 'node:fs';
5
+ import { app } from 'electron';
6
+ import { EventEmitter } from 'node:events';
20
7
 
21
8
  // src/updater/types.ts
22
9
  var ErrorInfo = {
23
10
  download: "Download failed",
24
11
  validate: "Validate failed",
25
12
  param: "Missing params",
26
- version: "Unsatisfied version"
13
+ network: "Network error"
27
14
  };
28
15
  var UpdaterError = class extends Error {
16
+ code;
29
17
  constructor(msg, info) {
30
- super(msg + ": " + info);
18
+ super(ErrorInfo[msg] + ": " + info);
19
+ this.code = msg;
31
20
  }
32
21
  };
33
22
 
34
23
  // src/updater/core.ts
35
- var Updater = class {
24
+ var Updater = class extends EventEmitter {
36
25
  CERT = __EIU_SIGNATURE_CERT__;
37
26
  info;
38
- options;
39
27
  asarPath;
40
- gzipPath;
41
28
  tmpFilePath;
42
29
  provider;
43
30
  /**
@@ -45,141 +32,134 @@ var Updater = class {
45
32
  */
46
33
  logger;
47
34
  /**
48
- * downloading progress hook
49
- * @param progress download progress
50
- * @example
51
- * updater.onDownloading = ({ percent, total, current }) => {
52
- * console.log(`download progress: ${percent}, total: ${total}, current: ${current}`)
53
- * }
35
+ * whether to receive beta update
54
36
  */
55
- onDownloading;
37
+ receiveBeta;
56
38
  /**
57
- * URL handler hook
58
- *
59
- * for Github, there are some {@link https://github.com/XIU2/UserScript/blob/master/GithubEnhanced-High-Speed-Download.user.js#L34 public CDN links}
60
- * @param url source url
61
- * @param isDownloadAsar whether is download asar
39
+ * whether force update in DEV
62
40
  */
63
- handleURL;
64
- /**
65
- * whether receive beta version
66
- */
67
- get receiveBeta() {
68
- return !!this.options.receiveBeta;
69
- }
70
- set receiveBeta(receiveBeta) {
71
- this.options.receiveBeta = receiveBeta;
72
- }
41
+ forceUpdate;
73
42
  /**
74
43
  * initialize incremental updater
75
44
  * @param provider update provider
76
45
  * @param option UpdaterOption
77
46
  */
78
47
  constructor(provider, option = {}) {
48
+ super();
79
49
  this.provider = provider;
80
- this.options = option;
50
+ this.receiveBeta = option.receiveBeta;
81
51
  if (option.SIGNATURE_CERT) {
82
52
  this.CERT = option.SIGNATURE_CERT;
83
53
  }
84
54
  if (option.logger) {
85
55
  this.logger = option.logger;
86
56
  }
57
+ if (isDev && !this.logger) {
58
+ this.logger = {
59
+ info: (...args) => console.log("[EIU-INFO ]", ...args),
60
+ debug: (...args) => console.log("[EIU-DEBUG]", ...args),
61
+ warn: (...args) => console.log("[EIU-WARN ]", ...args),
62
+ error: (...args) => console.error("[EIU-ERROR]", ...args)
63
+ };
64
+ this.logger.info("no logger set, enable dev-only logger");
65
+ }
87
66
  this.asarPath = getPathFromAppNameAsar();
88
- this.gzipPath = `${this.asarPath}.gz`;
89
67
  this.tmpFilePath = `${this.asarPath}.tmp`;
90
68
  }
91
- async needUpdate(version, minVersion) {
92
- if (isDev) {
93
- this.logger?.warn(`in dev mode, skip check update`);
94
- return false;
95
- }
96
- const isLowerVersion = this.provider.isLowerVersion;
97
- const entryVersion = getEntryVersion();
98
- const appVersion = getAppVersion();
99
- if (await isLowerVersion(entryVersion, minVersion)) {
100
- throw new UpdaterError(ErrorInfo.version, `entry version (${entryVersion}) < minimumVersion (${minVersion})`);
101
- }
102
- this.logger?.info(`check update: current version is ${appVersion}, new version is ${version}`);
103
- return await isLowerVersion(appVersion, version);
104
- }
105
- async parseData(format, data) {
69
+ async fetch(format, data) {
106
70
  if (existsSync(this.tmpFilePath)) {
107
71
  this.logger?.warn(`remove tmp file: ${this.tmpFilePath}`);
108
72
  rmSync(this.tmpFilePath);
109
73
  }
110
- if (existsSync(this.gzipPath)) {
111
- this.logger?.warn(`remove .gz file: ${this.gzipPath}`);
112
- rmSync(this.gzipPath);
113
- }
114
74
  if (typeof data === "object") {
115
75
  if (format === "json" && isUpdateJSON(data) || format === "buffer" && Buffer.isBuffer(data)) {
116
76
  return data;
117
77
  } else {
118
- throw new UpdaterError(ErrorInfo.param, `invalid type at format '${format}': ${JSON.stringify(data)}`);
78
+ this.err("invalid type", "param", `invalid type at format '${format}': ${JSON.stringify(data)}`);
79
+ return;
119
80
  }
120
81
  }
121
82
  this.logger?.debug(`download from ${this.provider.name}`);
122
83
  try {
123
- const result = format === "json" ? await this.provider.downloadJSON(data ?? __EIU_VERSION_PATH__) : await this.provider.downloadBuffer(app.name, this.info, this.onDownloading);
84
+ const result = format === "json" ? await this.provider.downloadJSON(data ?? __EIU_VERSION_PATH__) : await this.provider.downloadAsar(app.name, this.info, (data2) => this.emit("download-progress", data2));
124
85
  this.logger?.debug(`download ${format} success${format === "buffer" ? `, file size: ${result.length}` : ""}`);
125
86
  return result;
126
87
  } catch (e) {
127
- this.logger?.warn(`download ${format} failed: ${e}`);
128
- throw new UpdaterError(ErrorInfo.download, `download ${format} failed: ${e}`);
88
+ this.err(`fetch ${format} failed`, "network", `download ${format} failed: ${e}`);
129
89
  }
130
90
  }
91
+ /**
92
+ * handle error message and emit error event
93
+ */
94
+ err(msg, code, errorInfo) {
95
+ const err = new UpdaterError(code, errorInfo);
96
+ this.logger?.error(msg, err);
97
+ this.emit("error", err);
98
+ }
131
99
  async checkUpdate(data) {
132
- try {
133
- let { signature, size, version, minimumVersion, beta } = await this.parseData("json", data);
134
- if (this.receiveBeta) {
135
- version = beta.version;
136
- signature = beta.signature;
137
- minimumVersion = beta.minimumVersion;
138
- size = beta.size;
139
- }
140
- this.logger?.debug(`checked update, version: ${version}, size: ${size}, signature: ${signature}`);
141
- if (!await this.needUpdate(version, minimumVersion)) {
142
- this.logger?.info(`update unavailable: ${version} is the latest version`);
143
- return { success: false, data: version };
144
- } else {
145
- this.logger?.info(`update available: ${version}`);
146
- this.info = { signature, minimumVersion, version, size };
147
- return { success: true, data: this.info };
148
- }
149
- } catch (error) {
150
- this.logger?.error("check update failed", error);
151
- return {
152
- success: false,
153
- data: error instanceof UpdaterError ? error : new UpdaterError(ErrorInfo.download, error.toString())
154
- };
100
+ const emitUnavailable = (msg) => {
101
+ this.logger?.info(msg);
102
+ this.emit("update-unavailable", msg);
103
+ return false;
104
+ };
105
+ const _data = await this.fetch("json", data);
106
+ if (!_data) {
107
+ return emitUnavailable("failed to get update info");
108
+ }
109
+ let { signature, size, version, minimumVersion, beta } = _data;
110
+ if (this.receiveBeta) {
111
+ version = beta.version;
112
+ signature = beta.signature;
113
+ minimumVersion = beta.minimumVersion;
114
+ size = beta.size;
115
+ }
116
+ this.logger?.debug(`checked update, version: ${version}, size: ${size}, signature: ${signature}`);
117
+ if (isDev && !this.forceUpdate && !data) {
118
+ return emitUnavailable("skip check update in dev mode, to force update, set `updater.forceUpdate` to true or call checkUpdate with UpdateJSON");
119
+ }
120
+ const isLowerVersion = this.provider.isLowerVersion;
121
+ const entryVersion = getEntryVersion();
122
+ const appVersion = getAppVersion();
123
+ if (isLowerVersion(entryVersion, minimumVersion)) {
124
+ return emitUnavailable(`entry version (${entryVersion}) < minimumVersion (${minimumVersion})`);
125
+ }
126
+ this.logger?.info(`check update: current version is ${appVersion}, new version is ${version}`);
127
+ if (!isLowerVersion(appVersion, version)) {
128
+ return emitUnavailable(`current version (${appVersion}) < new version (${version})`);
155
129
  }
130
+ this.logger?.info(`update available: ${version}`);
131
+ this.info = { signature, minimumVersion, version, size };
132
+ this.emit("update-available", this.info);
133
+ return true;
156
134
  }
157
135
  async download(data, sig) {
136
+ const _sig = sig ?? this.info?.signature;
137
+ if (!_sig) {
138
+ this.err("download failed", "param", "no update signature, please call `checkUpdate` first");
139
+ return false;
140
+ }
141
+ const buffer = await this.fetch("buffer", data ? Buffer.from(data) : void 0);
142
+ if (!buffer) {
143
+ this.err("download failed", "param", "no update asar file buffer");
144
+ return false;
145
+ }
146
+ this.logger?.debug("verify start");
147
+ const _ver = await this.provider.verifySignaure(buffer, _sig, this.CERT);
148
+ if (!_ver) {
149
+ this.err("download failed", "validate", "invalid signature / certificate pair");
150
+ return false;
151
+ }
152
+ this.logger?.debug("verify success");
158
153
  try {
159
- if (!this.info) {
160
- throw new UpdaterError(ErrorInfo.param, "no update info");
161
- }
162
- const _sig = sig ?? this.info.signature;
163
- const buffer = await this.parseData("buffer", data);
164
- this.logger?.debug("verify start");
165
- const _ver = await this.provider.verifySignaure(buffer, _sig, this.CERT);
166
- if (!_ver) {
167
- throw new UpdaterError(ErrorInfo.validate, "invalid signature or certificate");
168
- }
169
- this.logger?.debug("verify success");
170
- this.logger?.debug(`write to ${this.gzipPath}`);
171
- writeFileSync(this.gzipPath, buffer);
172
154
  this.logger?.debug(`extract to ${this.tmpFilePath}`);
173
- await unzipFile(this.gzipPath, this.tmpFilePath);
155
+ await this.provider.unzipFile(buffer, this.tmpFilePath);
174
156
  this.logger?.info(`download success, version: ${_ver}`);
175
157
  this.info = void 0;
176
- return { success: true };
158
+ this.emit("update-downloaded");
159
+ return true;
177
160
  } catch (error) {
178
- this.logger?.error("download asar failed", error);
179
- return {
180
- success: false,
181
- data: error instanceof UpdaterError ? error : new UpdaterError(ErrorInfo.download, error.toString())
182
- };
161
+ this.err("download failed", "download", `fail to unwrap asar file, ${error}`);
162
+ return false;
183
163
  }
184
164
  }
185
165
  /**
@@ -189,6 +169,19 @@ var Updater = class {
189
169
  this.logger?.info("quit and install");
190
170
  restartApp();
191
171
  }
172
+ /**
173
+ * setup provider URL handler
174
+ *
175
+ * @example
176
+ * updater.setURLHandler((url, isDownloadingAsar) => {
177
+ * if (isDownloadingAsar) {
178
+ * return url.replace('https://raw.githubusercontent.com', 'https://cdn.jsdelivr.net/gh')
179
+ * }
180
+ * })
181
+ */
182
+ setURLHandler(handler) {
183
+ this.provider.urlHandler = handler;
184
+ }
192
185
  };
193
186
 
194
187
  // src/entry.ts
@@ -197,7 +190,7 @@ function startupWithUpdater(fn) {
197
190
  }
198
191
  var defaultOnInstall = (install, _, __, logger) => {
199
192
  install();
200
- logger.info(`update success!`);
193
+ logger?.info(`update success!`);
201
194
  };
202
195
  async function initApp(appOptions) {
203
196
  const {
@@ -213,31 +206,34 @@ async function initApp(appOptions) {
213
206
  } else {
214
207
  updaterInstance = await updater();
215
208
  }
216
- const logger = updaterInstance.logger || console;
209
+ let logger = updaterInstance.logger;
210
+ if (isDev && !logger) {
211
+ logger = {
212
+ info: (...args) => console.log("[EIU-INFO ]", ...args),
213
+ debug: (...args) => console.log("[EIU-DEBUG]", ...args),
214
+ warn: (...args) => console.log("[EIU-WARN ]", ...args),
215
+ error: (...args) => console.error("[EIU-ERROR]", ...args)
216
+ };
217
+ }
217
218
  try {
218
219
  const appNameAsarPath = getPathFromAppNameAsar();
219
220
  const tempAsarPath = `${appNameAsarPath}.tmp`;
220
- if (existsSync2(tempAsarPath)) {
221
- logger.info(`installing new asar: ${tempAsarPath}`);
221
+ if (existsSync(tempAsarPath)) {
222
+ logger?.info(`installing new asar: ${tempAsarPath}`);
222
223
  await onInstall(() => renameSync(tempAsarPath, appNameAsarPath), tempAsarPath, appNameAsarPath, logger);
223
224
  }
224
225
  const mainFilePath = join(
225
- isDev ? join(app2.getAppPath(), __EIU_MAIN_DEV_DIR__) : appNameAsarPath,
226
+ isDev ? join(app.getAppPath(), __EIU_MAIN_DEV_DIR__) : appNameAsarPath,
226
227
  "main",
227
228
  __EIU_MAIN_FILE__
228
229
  );
229
230
  await beforeStart?.(mainFilePath, logger);
230
231
  __require(mainFilePath)(updaterInstance);
231
232
  } catch (error) {
232
- logger.error("startup error", error);
233
+ logger?.error("startup error", error);
233
234
  onStartError?.(error, logger);
234
- app2.quit();
235
+ app.quit();
235
236
  }
236
237
  }
237
- export {
238
- ErrorInfo,
239
- Updater,
240
- UpdaterError,
241
- initApp,
242
- startupWithUpdater
243
- };
238
+
239
+ export { ErrorInfo, Updater, UpdaterError, initApp, startupWithUpdater };
package/dist/provider.cjs CHANGED
@@ -1,58 +1,11 @@
1
- "use strict";
2
- var __defProp = Object.defineProperty;
3
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
- var __getOwnPropNames = Object.getOwnPropertyNames;
5
- var __hasOwnProp = Object.prototype.hasOwnProperty;
6
- var __export = (target, all) => {
7
- for (var name in all)
8
- __defProp(target, name, { get: all[name], enumerable: true });
9
- };
10
- var __copyProps = (to, from, except, desc) => {
11
- if (from && typeof from === "object" || typeof from === "function") {
12
- for (let key of __getOwnPropNames(from))
13
- if (!__hasOwnProp.call(to, key) && key !== except)
14
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
- }
16
- return to;
17
- };
18
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
-
20
- // src/provider/index.ts
21
- var provider_exports = {};
22
- __export(provider_exports, {
23
- GitHubProvider: () => GitHubProvider,
24
- downloadAsarBufferDefault: () => downloadAsarBufferDefault,
25
- downloadUpdateJSONDefault: () => downloadUpdateJSONDefault
26
- });
27
- module.exports = __toCommonJS(provider_exports);
28
-
29
- // src/utils/electron.ts
30
- var import_node_fs = require("fs");
31
- var import_node_path = require("path");
32
- var import_electron = require("electron");
33
- var isDev = __EIU_IS_DEV__;
34
- var isWin = process.platform === "win32";
35
- var isMac = process.platform === "darwin";
36
- var isLinux = process.platform === "linux";
37
- function waitAppReady(timeout = 1e3) {
38
- return import_electron.app.isReady() ? Promise.resolve() : new Promise((resolve, reject) => {
39
- const _ = setTimeout(() => {
40
- reject(new Error("app is not ready"));
41
- }, timeout);
42
- import_electron.app.whenReady().then(() => {
43
- clearTimeout(_);
44
- resolve();
45
- });
46
- });
47
- }
1
+ 'use strict';
48
2
 
49
- // src/utils/zip.ts
50
- var import_node_fs2 = require("fs");
51
- var import_node_zlib = require("zlib");
3
+ var electron = require('electron');
4
+ var crypto = require('crypto');
5
+ var fs = require('fs');
6
+ var zlib = require('zlib');
52
7
 
53
- // src/utils/unzip.ts
54
- var import_node_fs3 = require("fs");
55
- var import_node_zlib2 = require("zlib");
8
+ // src/provider/download.ts
56
9
 
57
10
  // src/utils/version.ts
58
11
  function parseVersion(version) {
@@ -78,7 +31,7 @@ function parseVersion(version) {
78
31
  }
79
32
  return ret;
80
33
  }
81
- function isLowerVersionDefault(oldVer, newVer) {
34
+ function defaultIsLowerVersion(oldVer, newVer) {
82
35
  const oldV = parseVersion(oldVer);
83
36
  const newV = parseVersion(newVer);
84
37
  function compareStrings(str1, str2) {
@@ -103,42 +56,11 @@ function isUpdateJSON(json) {
103
56
  return is(json) && is(json?.beta);
104
57
  }
105
58
 
106
- // src/utils/crypto/decrypt.ts
107
- var import_node_crypto2 = require("crypto");
108
-
109
- // src/utils/crypto/utils.ts
110
- var import_node_crypto = require("crypto");
111
- function hashString(data, length) {
112
- const hash = (0, import_node_crypto.createHash)("SHA256").update(data).digest("binary");
113
- return Buffer.from(hash).subarray(0, length);
114
- }
115
-
116
- // src/utils/crypto/decrypt.ts
117
- function decrypt(encryptedText, key, iv) {
118
- const decipher = (0, import_node_crypto2.createDecipheriv)("aes-256-cbc", key, iv);
119
- let decrypted = decipher.update(encryptedText, "base64url", "utf8");
120
- decrypted += decipher.final("utf8");
121
- return decrypted;
122
- }
123
- function verifySignatureDefault(buffer, signature, cert) {
124
- try {
125
- const [sig, version] = decrypt(signature, hashString(cert, 32), hashString(buffer, 16)).split("%");
126
- const result = (0, import_node_crypto2.createVerify)("RSA-SHA256").update(buffer).verify(cert, sig, "base64");
127
- return result ? version : void 0;
128
- } catch (error) {
129
- return void 0;
130
- }
131
- }
132
-
133
- // src/utils/crypto/encrypt.ts
134
- var import_node_crypto3 = require("crypto");
135
-
136
59
  // src/provider/download.ts
137
- var import_electron2 = require("electron");
138
- async function downlaodFn(url, headers, onResponse) {
139
- await waitAppReady();
60
+ async function downloadFn(url, headers, onResponse) {
61
+ await electron.app.whenReady();
140
62
  return new Promise((resolve, reject) => {
141
- const request = import_electron2.net.request({ url, method: "GET", redirect: "follow" });
63
+ const request = electron.net.request({ url, method: "GET", redirect: "follow" });
142
64
  Object.keys(headers).forEach((key) => request.setHeader(key, headers[key]));
143
65
  request.on("response", (resp) => {
144
66
  resp.on("aborted", () => reject(new Error("aborted")));
@@ -149,8 +71,8 @@ async function downlaodFn(url, headers, onResponse) {
149
71
  request.end();
150
72
  });
151
73
  }
152
- async function downloadUpdateJSONDefault(url, headers) {
153
- return await downlaodFn(url, headers, (resp, resolve, reject) => {
74
+ async function defaultDownloadUpdateJSON(url, headers) {
75
+ return await downloadFn(url, headers, (resp, resolve, reject) => {
154
76
  let data = "";
155
77
  resp.on("data", (chunk) => data += chunk);
156
78
  resp.on("end", () => {
@@ -161,67 +83,120 @@ async function downloadUpdateJSONDefault(url, headers) {
161
83
  } else {
162
84
  throw Error;
163
85
  }
164
- } catch (ignore) {
86
+ } catch {
165
87
  reject(new Error("invalid update json"));
166
88
  }
167
89
  });
168
90
  });
169
91
  }
170
- async function downloadAsarBufferDefault(url, headers, total, onDownloading) {
171
- let current = 0;
172
- return await downlaodFn(url, headers, (resp, resolve) => {
92
+ async function defaultDownloadAsar(url, headers, total, onDownloading) {
93
+ let transferred = 0;
94
+ let time = Date.now();
95
+ return await downloadFn(url, headers, (resp, resolve) => {
173
96
  let data = [];
174
97
  resp.on("data", (chunk) => {
175
- current += chunk.length;
176
- onDownloading?.({ percent: `${+(current / total).toFixed(2) * 100}%`, total, current });
98
+ transferred += chunk.length;
99
+ const current = Date.now();
100
+ onDownloading?.({
101
+ percent: +(transferred / total).toFixed(2) * 100,
102
+ total,
103
+ transferred,
104
+ delta: chunk.length,
105
+ bps: chunk.length / ((current - time) * 1e3)
106
+ });
107
+ time = current;
177
108
  data.push(chunk);
178
109
  });
179
110
  resp.on("end", () => resolve(Buffer.concat(data)));
180
111
  });
181
112
  }
113
+ function hashBuffer(data, length) {
114
+ const hash = crypto.createHash("SHA256").update(data).digest("binary");
115
+ return Buffer.from(hash).subarray(0, length);
116
+ }
117
+ function aesDecrypt(encryptedText, key, iv) {
118
+ const decipher = crypto.createDecipheriv("aes-256-cbc", key, iv);
119
+ return decipher.update(encryptedText, "base64url", "utf8") + decipher.final("utf8");
120
+ }
121
+ function defaultVerify(buffer, signature, cert) {
122
+ try {
123
+ const [sig, version] = aesDecrypt(signature, hashBuffer(cert, 32), hashBuffer(buffer, 16)).split("%");
124
+ const result = crypto.createVerify("RSA-SHA256").update(buffer).verify(cert, sig, "base64");
125
+ return result ? version : void 0;
126
+ } catch {
127
+ return void 0;
128
+ }
129
+ }
130
+ async function defaultUnzipFile(buffer, targetFilePath) {
131
+ return new Promise((resolve, reject) => {
132
+ zlib.brotliDecompress(buffer, (err, buffer2) => {
133
+ if (err) {
134
+ reject(err);
135
+ }
136
+ fs.writeFileSync(targetFilePath, buffer2);
137
+ resolve();
138
+ });
139
+ });
140
+ }
141
+
142
+ // src/provider/base.ts
143
+ var BaseProvider = class {
144
+ name = "BaseProvider";
145
+ isLowerVersion = defaultIsLowerVersion;
146
+ verifySignaure = defaultVerify;
147
+ unzipFile = defaultUnzipFile;
148
+ };
182
149
 
183
150
  // src/provider/github.ts
184
- var GitHubProvider = class {
151
+ var GitHubProvider = class extends BaseProvider {
185
152
  ua = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.183 Safari/537.36";
186
153
  name = "GithubProvider";
187
154
  urlHandler;
188
155
  url;
189
156
  extraHeaders;
157
+ /**
158
+ * Update Provider for Github repo
159
+ * - download update json from `https://raw.githubusercontent.com/{user}/{repo}/HEAD/{versionPath}`
160
+ * - download update asar from `https://github.com/{user}/{repo}/releases/download/v{version}/{name}-{version}.asar.gz`
161
+ *
162
+ * you can setup `urlHandler` in {@link GitHubProviderOptions} or `Updater` to modify url before request
163
+ * @param options provider options
164
+ */
190
165
  constructor(options) {
191
- this.url = new URL(options.url);
166
+ super();
192
167
  this.extraHeaders = options.extraHeaders;
193
168
  this.urlHandler = options.urlHandler;
194
- if (this.url.host !== "github.com") {
169
+ if (!options.url.startsWith("https://github.com")) {
195
170
  throw new Error(`${this.name}: invalid github url: ${options.url}`);
196
171
  }
197
- if (!this.url.pathname.endsWith("/")) {
198
- this.url.pathname += "/";
172
+ this.url = options.url;
173
+ if (!this.url.endsWith("/")) {
174
+ this.url += "/";
199
175
  }
200
176
  }
201
- parseURL(isDownloadAsar, path) {
202
- const url = this.url.href + path;
203
- return this.urlHandler ? this.urlHandler(url, isDownloadAsar) : url;
177
+ async parseURL(isDownloadAsar, extraPath) {
178
+ const _url = new URL(this.url);
179
+ _url.hostname = isDownloadAsar ? "github.com" : "raw.githubusercontent.com";
180
+ _url.pathname += extraPath;
181
+ return (await this.urlHandler?.(_url, isDownloadAsar) || _url).toString();
204
182
  }
205
- isLowerVersion = isLowerVersionDefault;
206
- verifySignaure = verifySignatureDefault;
207
183
  async downloadJSON(versionPath) {
208
- return await downloadUpdateJSONDefault(
209
- this.parseURL(false, `HEAD/${versionPath}`),
184
+ return await defaultDownloadUpdateJSON(
185
+ await this.parseURL(false, `HEAD/${versionPath}`),
210
186
  { userAgent: this.ua, accept: "application/json", ...this.extraHeaders }
211
187
  );
212
188
  }
213
- async downloadBuffer(name, { version, size }, onDownloading) {
214
- return await downloadAsarBufferDefault(
215
- this.parseURL(true, `releases/download/v${version}/${name}-${version}.asar.gz`),
189
+ async downloadAsar(name, { version, size }, onDownloading) {
190
+ return await defaultDownloadAsar(
191
+ await this.parseURL(true, `releases/download/v${version}/${name}-${version}.asar.gz`),
216
192
  { userAgent: this.ua, accept: "application/octet-stream", ...this.extraHeaders },
217
193
  size,
218
194
  onDownloading
219
195
  );
220
196
  }
221
197
  };
222
- // Annotate the CommonJS export names for ESM import in node:
223
- 0 && (module.exports = {
224
- GitHubProvider,
225
- downloadAsarBufferDefault,
226
- downloadUpdateJSONDefault
227
- });
198
+
199
+ exports.BaseProvider = BaseProvider;
200
+ exports.GitHubProvider = GitHubProvider;
201
+ exports.defaultDownloadAsar = defaultDownloadAsar;
202
+ exports.defaultDownloadUpdateJSON = defaultDownloadUpdateJSON;