electron-incremental-update 0.5.1 → 0.6.0

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 CHANGED
@@ -58,15 +58,15 @@ src
58
58
  import { createUpdater, getGithubReleaseCdnGroup, initApp, parseGithubCdnURL } from 'electron-incremental-update'
59
59
  import { name, repository } from '../package.json'
60
60
 
61
- const SIGNATURE_PUB = '' // auto generate RSA public key when start app
61
+ const SIGNATURE_CERT = '' // auto generate certificate when start app
62
62
 
63
63
  // create updater when init, no need to set productName
64
- initApp({ name }, { SIGNATURE_PUB, repository })
64
+ initApp({ name }, { SIGNATURE_CERT, repository })
65
65
 
66
66
  // or create updater manually
67
67
  const { cdnPrefix } = getGithubReleaseCdnGroup()[0]
68
68
  const updater = createUpdater({
69
- SIGNATURE_PUB,
69
+ SIGNATURE_CERT,
70
70
  productName: name,
71
71
  repository,
72
72
  updateJsonURL: parseGithubCdnURL(repository, 'fastly.jsdelivr.net/gh', 'version.json'),
@@ -81,15 +81,15 @@ initApp({ name }).setUpdater(updater)
81
81
  ```ts
82
82
  // electron/main/index.ts
83
83
  import type { Updater } from 'electron-incremental-update'
84
- import { getAppAsarPath, getAppVersion, getEntryVersion } from 'electron-incremental-update'
84
+ import { getEntryVersion, getProductAsarPath, getProductVersion } from 'electron-incremental-update'
85
85
  import { app } from 'electron'
86
86
  import { name } from '../../package.json'
87
87
 
88
88
  export default function (updater: Updater) {
89
89
  console.log('\ncurrent:')
90
- console.log(`\tasar path: ${getAppAsarPath(name)}`)
90
+ console.log(`\tasar path: ${getProductAsarPath(name)}`)
91
91
  console.log(`\tentry: ${getEntryVersion()}`)
92
- console.log(`\tapp: ${getAppVersion(name)}`)
92
+ console.log(`\tapp: ${getProductVersion(name)}`)
93
93
  let size = 0
94
94
  updater.on('downloading', (progress) => {
95
95
  console.log(`${(progress / size).toFixed(2)}%`)
@@ -108,7 +108,7 @@ export default function (updater: Updater) {
108
108
  buttons: ['Download', 'Later'],
109
109
  message: 'Application update available!',
110
110
  })
111
- response === 0 && console.log(await updater.downloadUpdate())
111
+ response === 0 && console.log(await updater.downloadAndInstall())
112
112
  }
113
113
  })
114
114
  // app logics
@@ -7,46 +7,38 @@ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require
7
7
  });
8
8
 
9
9
  // src/crypto.ts
10
- import { constants, createCipheriv, createDecipheriv, createHash, createSign, createVerify, generateKeyPairSync } from "node:crypto";
10
+ import { constants, createCipheriv, createDecipheriv, createHash, createSign, createVerify } from "node:crypto";
11
11
  import { Buffer as Buffer2 } from "node:buffer";
12
12
  var aesEncode = "base64url";
13
- function generateRSA(length = 2048) {
14
- const pair = generateKeyPairSync("rsa", { modulusLength: length });
15
- const privateKey = pair.privateKey.export({ type: "pkcs1", format: "pem" });
16
- const publicKey = pair.publicKey.export({ type: "pkcs1", format: "pem" });
17
- return {
18
- privateKey,
19
- publicKey
20
- };
21
- }
22
- function encrypt(plainText, key, iv) {
23
- const cipher = createCipheriv("aes-256-cbc", key, iv);
13
+ function encrypt(plainText, key2, iv) {
14
+ const cipher = createCipheriv("aes-256-cbc", key2, iv);
24
15
  let encrypted = cipher.update(plainText, "utf8", aesEncode);
25
16
  encrypted += cipher.final(aesEncode);
26
17
  return encrypted;
27
18
  }
28
- function decrypt(encryptedText, key, iv) {
29
- const decipher = createDecipheriv("aes-256-cbc", key, iv);
19
+ function decrypt(encryptedText, key2, iv) {
20
+ const decipher = createDecipheriv("aes-256-cbc", key2, iv);
30
21
  let decrypted = decipher.update(encryptedText, aesEncode, "utf8");
31
22
  decrypted += decipher.final("utf8");
32
23
  return decrypted;
33
24
  }
34
- function generateKey(data, length) {
25
+ function key(data, length) {
35
26
  const hash = createHash("SHA256").update(data).digest("binary");
36
27
  return Buffer2.from(hash).subarray(0, length);
37
28
  }
38
- function signature(buffer, privateKey, publicKey) {
29
+ function signature(buffer, privateKey, cert, version) {
39
30
  const sig = createSign("RSA-SHA256").update(buffer).sign({
40
31
  key: privateKey,
41
32
  padding: constants.RSA_PKCS1_PADDING,
42
33
  saltLength: constants.RSA_PSS_SALTLEN_DIGEST
43
34
  }, "base64");
44
- return encrypt(sig, generateKey(publicKey, 32), generateKey(buffer, 16));
35
+ return encrypt(`${sig}%${version}`, key(cert, 32), key(buffer, 16));
45
36
  }
46
- function verify(buffer, signature2, publicKey) {
37
+ function verify(buffer, signature2, cert) {
47
38
  try {
48
- const sig = decrypt(signature2, generateKey(publicKey, 32), generateKey(buffer, 16));
49
- return createVerify("RSA-SHA256").update(buffer).verify(publicKey, sig, "base64");
39
+ const [sig, version] = decrypt(signature2, key(cert, 32), key(buffer, 16)).split("%");
40
+ const result = createVerify("RSA-SHA256").update(buffer).verify(cert, sig, "base64");
41
+ return result ? version : false;
50
42
  } catch (error) {
51
43
  return false;
52
44
  }
@@ -54,7 +46,6 @@ function verify(buffer, signature2, publicKey) {
54
46
 
55
47
  export {
56
48
  __require,
57
- generateRSA,
58
49
  signature,
59
50
  verify
60
51
  };
package/dist/index.cjs CHANGED
@@ -11,9 +11,9 @@ var __export = (target, all) => {
11
11
  };
12
12
  var __copyProps = (to, from, except, desc) => {
13
13
  if (from && typeof from === "object" || typeof from === "function") {
14
- for (let key of __getOwnPropNames(from))
15
- if (!__hasOwnProp.call(to, key) && key !== except)
16
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
14
+ for (let key2 of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key2) && key2 !== except)
16
+ __defProp(to, key2, { get: () => from[key2], enumerable: !(desc = __getOwnPropDesc(from, key2)) || desc.enumerable });
17
17
  }
18
18
  return to;
19
19
  };
@@ -31,44 +31,48 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
31
31
  var src_exports = {};
32
32
  __export(src_exports, {
33
33
  createUpdater: () => createUpdater,
34
- getAppAsarPath: () => getAppAsarPath,
35
- getAppVersion: () => getAppVersion,
36
34
  getEntryVersion: () => getEntryVersion,
37
35
  getGithubReleaseCdnGroup: () => getGithubReleaseCdnGroup,
36
+ getProductAsarPath: () => getProductAsarPath,
37
+ getProductVersion: () => getProductVersion,
38
38
  initApp: () => initApp,
39
+ isUpdateJSON: () => isUpdateJSON,
39
40
  parseGithubCdnURL: () => parseGithubCdnURL,
40
41
  requireNative: () => requireNative,
41
42
  restartApp: () => restartApp
42
43
  });
43
44
  module.exports = __toCommonJS(src_exports);
44
- var import_node_path2 = require("path");
45
+ var import_node_path3 = require("path");
45
46
  var import_electron3 = require("electron");
46
47
 
47
48
  // src/updater/index.ts
48
49
  var import_node_events = require("events");
50
+ var import_node_buffer3 = require("buffer");
49
51
  var import_node_zlib = require("zlib");
50
52
  var import_node_fs2 = require("fs");
51
53
  var import_promises = require("fs/promises");
54
+ var import_node_path2 = require("path");
52
55
  var import_electron2 = require("electron");
53
56
 
54
57
  // src/crypto.ts
55
58
  var import_node_crypto = require("crypto");
56
59
  var import_node_buffer = require("buffer");
57
60
  var aesEncode = "base64url";
58
- function decrypt(encryptedText, key, iv) {
59
- const decipher = (0, import_node_crypto.createDecipheriv)("aes-256-cbc", key, iv);
61
+ function decrypt(encryptedText, key2, iv) {
62
+ const decipher = (0, import_node_crypto.createDecipheriv)("aes-256-cbc", key2, iv);
60
63
  let decrypted = decipher.update(encryptedText, aesEncode, "utf8");
61
64
  decrypted += decipher.final("utf8");
62
65
  return decrypted;
63
66
  }
64
- function generateKey(data, length) {
67
+ function key(data, length) {
65
68
  const hash = (0, import_node_crypto.createHash)("SHA256").update(data).digest("binary");
66
69
  return import_node_buffer.Buffer.from(hash).subarray(0, length);
67
70
  }
68
- function verify(buffer, signature, publicKey) {
71
+ function verify(buffer, signature, cert) {
69
72
  try {
70
- const sig = decrypt(signature, generateKey(publicKey, 32), generateKey(buffer, 16));
71
- return (0, import_node_crypto.createVerify)("RSA-SHA256").update(buffer).verify(publicKey, sig, "base64");
73
+ const [sig, version] = decrypt(signature, key(cert, 32), key(buffer, 16)).split("%");
74
+ const result = (0, import_node_crypto.createVerify)("RSA-SHA256").update(buffer).verify(cert, sig, "base64");
75
+ return result ? version : false;
72
76
  } catch (error) {
73
77
  return false;
74
78
  }
@@ -77,8 +81,15 @@ function verify(buffer, signature, publicKey) {
77
81
  // src/updater/defaultFunctions.ts
78
82
  var import_node_buffer2 = require("buffer");
79
83
  var import_node_https = __toESM(require("https"), 1);
84
+
85
+ // src/updater/types.ts
86
+ function isUpdateJSON(json) {
87
+ return "signature" in json && "version" in json && "size" in json;
88
+ }
89
+
90
+ // src/updater/defaultFunctions.ts
80
91
  function downloadJSONDefault(url, updater, headers) {
81
- return new Promise((resolve2, reject) => {
92
+ return new Promise((resolve3, reject) => {
82
93
  import_node_https.default.get(url, (res) => {
83
94
  let data = "";
84
95
  res.setEncoding("utf8");
@@ -87,8 +98,8 @@ function downloadJSONDefault(url, updater, headers) {
87
98
  res.on("end", () => {
88
99
  try {
89
100
  const json = JSON.parse(data);
90
- if ("signature" in json && "version" in json && "size" in json) {
91
- resolve2(json);
101
+ if (isUpdateJSON(json)) {
102
+ resolve3(json);
92
103
  } else {
93
104
  throw Error;
94
105
  }
@@ -103,7 +114,7 @@ function downloadJSONDefault(url, updater, headers) {
103
114
  }
104
115
  function downloadBufferDefault(url, updater, headers) {
105
116
  let progress = 0;
106
- return new Promise((resolve2, reject) => {
117
+ return new Promise((resolve3, reject) => {
107
118
  import_node_https.default.get(url, (res) => {
108
119
  let data = [];
109
120
  res.headers = headers;
@@ -113,7 +124,7 @@ function downloadBufferDefault(url, updater, headers) {
113
124
  data.push(chunk);
114
125
  });
115
126
  res.on("end", () => {
116
- resolve2(import_node_buffer2.Buffer.concat(data));
127
+ resolve3(import_node_buffer2.Buffer.concat(data));
117
128
  });
118
129
  }).on("error", (e) => {
119
130
  reject(e);
@@ -147,14 +158,14 @@ function compareVersionDefault(oldVersion, newVersion) {
147
158
  var import_node_fs = require("fs");
148
159
  var import_node_path = require("path");
149
160
  var import_electron = require("electron");
150
- function getAppAsarPath(name) {
161
+ function getProductAsarPath(name) {
151
162
  return import_electron.app.isPackaged ? (0, import_node_path.join)((0, import_node_path.dirname)(import_electron.app.getAppPath()), `${name}.asar`) : "dev";
152
163
  }
153
164
  function getEntryVersion() {
154
165
  return import_electron.app.getVersion();
155
166
  }
156
- function getAppVersion(name) {
157
- return import_electron.app.isPackaged ? (0, import_node_fs.readFileSync)((0, import_node_path.join)(getAppAsarPath(name), "version"), "utf-8") : getEntryVersion();
167
+ function getProductVersion(name) {
168
+ return import_electron.app.isPackaged ? (0, import_node_fs.readFileSync)((0, import_node_path.join)(getProductAsarPath(name), "version"), "utf-8") : getEntryVersion();
158
169
  }
159
170
  function requireNative(packageName) {
160
171
  const path = import_electron.app.isPackaged ? (0, import_node_path.join)(import_electron.app.getAppPath(), "node_modules", packageName) : packageName;
@@ -194,7 +205,7 @@ function restartApp() {
194
205
 
195
206
  // src/updater/index.ts
196
207
  function createUpdater({
197
- SIGNATURE_PUB,
208
+ SIGNATURE_CERT,
198
209
  repository,
199
210
  productName,
200
211
  releaseAsarURL: _release,
@@ -205,94 +216,103 @@ function createUpdater({
205
216
  }) {
206
217
  const updater = new import_node_events.EventEmitter();
207
218
  let signature = "";
208
- let version = "";
209
- const gzipPath = `../${productName}.asar.gz`;
210
- const tmpFile = gzipPath.replace(".asar.gz", ".tmp.gz");
219
+ const asarPath = getProductAsarPath(productName);
220
+ const gzipPath = `${asarPath}.gz`;
221
+ const tmpFilePath = gzipPath.replace(".asar.gz", ".tmp.asar");
211
222
  const { downloadBuffer, downloadJSON, extraHeader, userAgent } = downloadConfig || {};
212
223
  function log(msg) {
213
224
  debug && updater.emit("debug", msg);
214
225
  }
215
- async function download(url, format) {
216
- 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";
217
- const headers = {
218
- Accept: `application/${format === "json" ? "json" : "octet-stream"}`,
219
- UserAgent: ua,
220
- ...extraHeader
221
- };
222
- log(`download headers: ${JSON.stringify(headers, null, 2)}`);
223
- const downloadFn = format === "json" ? downloadJSON ?? downloadJSONDefault : downloadBuffer ?? downloadBufferDefault;
224
- log(`download ${format} from ${url}`);
225
- const ret = await downloadFn(url, updater, headers);
226
- log(`download ${format} success`);
227
- return ret;
228
- }
229
- async function extractFile(gzipFilePath) {
230
- if (!gzipFilePath.endsWith(".asar.gz") || !(0, import_node_fs2.existsSync)(gzipFilePath)) {
231
- log("update .asar.gz file not exist");
232
- return;
226
+ async function extractFile() {
227
+ if (!gzipPath.endsWith(".asar.gz") || !(0, import_node_fs2.existsSync)(gzipPath)) {
228
+ throw new Error(".asar.gz file not exist");
233
229
  }
234
- gzipFilePath = gzipFilePath.replace(".asar.gz", ".tmp.gz");
235
- return new Promise((resolve2, reject) => {
230
+ return new Promise((resolve3, reject) => {
236
231
  const gunzip = (0, import_node_zlib.createGunzip)();
237
- const input = (0, import_node_fs2.createReadStream)(gzipFilePath);
238
- const outputFilePath = gzipFilePath.replace(".tmp.gz", ".asar");
239
- const output = (0, import_node_fs2.createWriteStream)(outputFilePath);
240
- log(`outputFilePath: ${outputFilePath}`);
232
+ const input = (0, import_node_fs2.createReadStream)(gzipPath);
233
+ const output = (0, import_node_fs2.createWriteStream)(tmpFilePath);
234
+ log(`outputFilePath: ${tmpFilePath}`);
241
235
  input.pipe(gunzip).pipe(output).on("finish", async () => {
242
- await (0, import_promises.rm)(gzipFilePath);
243
- log(`${gzipFilePath} unzipped`);
244
- resolve2(outputFilePath);
236
+ await (0, import_promises.rm)(gzipPath);
237
+ log(`${gzipPath} unzipped`);
238
+ resolve3(null);
245
239
  }).on("error", async (err) => {
246
- await (0, import_promises.rm)(gzipFilePath);
240
+ await (0, import_promises.rm)(gzipPath);
247
241
  output.destroy(err);
248
242
  reject(err);
249
243
  });
250
244
  });
251
245
  }
252
- function needUpdate(version2) {
246
+ function needUpdate(version) {
253
247
  if (!import_electron2.app.isPackaged) {
254
248
  log("in dev mode, no need to update");
255
249
  return false;
256
250
  }
257
251
  const currentVersion = getEntryVersion();
258
- log(`check update:
259
- current version is ${currentVersion},
260
- new version is ${version2}`);
252
+ log(`check update: current version is ${currentVersion}, new version is ${version}`);
261
253
  const _compare = compareVersion ?? compareVersionDefault;
262
- return _compare(currentVersion, version2);
254
+ return _compare(currentVersion, version);
263
255
  }
264
- updater.checkUpdate = async (url) => {
265
- try {
266
- url ??= _update;
267
- if (!url) {
268
- log("no updateJsonURL, fallback to use repository");
256
+ async function parseData(format, data) {
257
+ if ((0, import_node_fs2.existsSync)(tmpFilePath)) {
258
+ log(`remove tmp file: ${tmpFilePath}`);
259
+ await (0, import_promises.rm)(tmpFilePath);
260
+ }
261
+ if ((0, import_node_fs2.existsSync)(gzipPath)) {
262
+ log(`remove .gz file: ${gzipPath}`);
263
+ await (0, import_promises.rm)(gzipPath);
264
+ }
265
+ if (typeof data === "object") {
266
+ if (format === "json" && isUpdateJSON(data) || format === "buffer" && import_node_buffer3.Buffer.isBuffer(data)) {
267
+ return data;
268
+ } else {
269
+ throw new Error(`invalid type at format '${format}': ${data}`);
270
+ }
271
+ } else if (["string", "undefined"].includes(typeof data)) {
272
+ 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";
273
+ const headers = {
274
+ Accept: `application/${format === "json" ? "json" : "octet-stream"}`,
275
+ UserAgent: ua,
276
+ ...extraHeader
277
+ };
278
+ log(`download headers: ${JSON.stringify(headers, null, 2)}`);
279
+ const info = format === "json" ? {
280
+ name: "updateJsonURL",
281
+ url: _update,
282
+ repoFallback: `${repository.replace("github.com", "raw.githubusercontent.com")}/master/version.json`,
283
+ fn: downloadJSON ?? downloadJSONDefault
284
+ } : {
285
+ name: "releaseAsarURL",
286
+ url: _release,
287
+ repoFallback: `${repository}/releases/download/latest/${productName}.asar.gz`,
288
+ fn: downloadBuffer ?? downloadBufferDefault
289
+ };
290
+ data ??= info.url;
291
+ if (!data) {
292
+ log(`no ${info.name}, fallback to use repository`);
269
293
  if (!repository) {
270
- throw new Error("updateJsonURL or repository are not set");
294
+ throw new Error(`${info.name} or repository are not set`);
271
295
  }
272
- url = `${repository.replace("github.com", "raw.githubusercontent.com")}/master/version.json`;
296
+ data = info.repoFallback;
273
297
  }
274
- if ((0, import_node_fs2.existsSync)(tmpFile)) {
275
- log(`remove tmp file: ${tmpFile}`);
276
- await (0, import_promises.rm)(tmpFile);
277
- }
278
- if ((0, import_node_fs2.existsSync)(gzipPath)) {
279
- log(`remove .gz file: ${gzipPath}`);
280
- await (0, import_promises.rm)(gzipPath);
281
- }
282
- const json = await download(url, "json");
283
- const {
284
- signature: _sig,
285
- version: _v,
286
- size
287
- } = json;
288
- log(`update info: ${JSON.stringify(json, null, 2)}`);
289
- if (!await needUpdate(_v)) {
290
- log(`update unavailable: ${_v}`);
298
+ log(`download ${format} from ${data}`);
299
+ const ret = await info.fn(data, updater, headers);
300
+ log(`download ${format} success`);
301
+ return ret;
302
+ } else {
303
+ throw new Error(`invalid type at format '${format}': ${data}`);
304
+ }
305
+ }
306
+ updater.checkUpdate = async (data) => {
307
+ try {
308
+ const { signature: _sig, size, version } = await parseData("json", data);
309
+ log(`checked version: ${version}, size: ${size}`);
310
+ if (!await needUpdate(version)) {
311
+ log(`update unavailable: ${version}`);
291
312
  return void 0;
292
313
  } else {
293
- log(`update available: ${_v}`);
314
+ log(`update available: ${version}`);
294
315
  signature = _sig;
295
- version = _v;
296
316
  return { size, version };
297
317
  }
298
318
  } catch (error) {
@@ -300,30 +320,35 @@ function createUpdater({
300
320
  return error;
301
321
  }
302
322
  };
303
- updater.downloadUpdate = async (src) => {
323
+ updater.downloadAndInstall = async (data, sig) => {
304
324
  try {
305
- if (typeof src !== "object") {
306
- let _url = src ?? _release;
307
- if (!_url) {
308
- log("no releaseAsarURL, fallback to use repository");
309
- if (!repository) {
310
- throw new Error("releaseAsarURL or repository are not set");
311
- }
312
- _url = `${repository}/releases/download/latest/${productName}.asar.gz`;
313
- }
314
- src = await download(_url, "buffer");
325
+ const _sig = sig ?? signature;
326
+ if (!_sig) {
327
+ throw new Error("signature are not set, please checkUpdate first or set the second parameter");
315
328
  }
329
+ const buffer = await parseData("buffer", data);
316
330
  log("verify start");
317
- if (!verify(src, signature, SIGNATURE_PUB)) {
318
- log("verify failed");
319
- throw new Error("invalid signature");
331
+ const version = verify(buffer, _sig, SIGNATURE_CERT);
332
+ if (!version) {
333
+ throw new Error("verify failed, invalid signature");
320
334
  }
321
335
  log("verify success");
336
+ if (!await needUpdate(version)) {
337
+ throw new Error(`update unavailable: ${version}`);
338
+ }
322
339
  log(`write file: ${gzipPath}`);
323
- await (0, import_promises.writeFile)(gzipPath, src);
340
+ await (0, import_promises.writeFile)(gzipPath, buffer);
324
341
  log(`extract file: ${gzipPath}`);
325
- await extractFile(gzipPath);
342
+ await extractFile();
343
+ const asarVersion = await (0, import_promises.readFile)((0, import_node_path2.resolve)(tmpFilePath, "version"), "utf8");
344
+ if (asarVersion !== version) {
345
+ (0, import_node_fs2.rmSync)(tmpFilePath);
346
+ throw new Error(`update failed: asar version is ${asarVersion}, but it should be ${version}`);
347
+ } else {
348
+ await (0, import_promises.rename)(tmpFilePath, asarPath);
349
+ }
326
350
  log(`update success, version: ${version}`);
351
+ signature = "";
327
352
  return true;
328
353
  } catch (error) {
329
354
  log(error);
@@ -341,7 +366,7 @@ function initApp(appOptions, updaterOptions) {
341
366
  mainPath = "main/index.js"
342
367
  } = appOptions ?? {};
343
368
  const mainDir = import_electron3.app.isPackaged ? `../${productName}.asar` : electronDistPath;
344
- const entry = (0, import_node_path2.resolve)(__dirname, mainDir, mainPath);
369
+ const entry = (0, import_node_path3.resolve)(__dirname, mainDir, mainPath);
345
370
  if (updaterOptions) {
346
371
  require(entry)(
347
372
  createUpdater({ ...updaterOptions, productName })
@@ -357,11 +382,12 @@ function initApp(appOptions, updaterOptions) {
357
382
  // Annotate the CommonJS export names for ESM import in node:
358
383
  0 && (module.exports = {
359
384
  createUpdater,
360
- getAppAsarPath,
361
- getAppVersion,
362
385
  getEntryVersion,
363
386
  getGithubReleaseCdnGroup,
387
+ getProductAsarPath,
388
+ getProductVersion,
364
389
  initApp,
390
+ isUpdateJSON,
365
391
  parseGithubCdnURL,
366
392
  requireNative,
367
393
  restartApp
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
@@ -148,7 +159,7 @@ declare function getGithubReleaseCdnGroup(): {
148
159
  }[];
149
160
  declare function restartApp(): void;
150
161
 
151
- declare function createUpdater({ SIGNATURE_PUB, repository, productName, releaseAsarURL: _release, updateJsonURL: _update, debug, downloadConfig, compareVersion, }: UpdaterOption): Updater;
162
+ declare function createUpdater({ SIGNATURE_CERT, repository, productName, releaseAsarURL: _release, updateJsonURL: _update, debug, downloadConfig, compareVersion, }: UpdaterOption): Updater;
152
163
 
153
164
  type AppOption = {
154
165
  /**
@@ -177,11 +188,11 @@ type InitUpdaterOptions = OptionalProperty<UpdaterOption, 'productName'>;
177
188
  * import { createUpdater, getGithubReleaseCdnGroup, initApp, parseGithubCdnURL } from 'electron-incremental-update'
178
189
  * import { name, repository } from '../package.json'
179
190
  *
180
- * const SIGNATURE_PUB = '' // auto generate
191
+ * const SIGNATURE_CERT = '' // auto generate
181
192
  *
182
193
  * const { cdnPrefix } = getGithubReleaseCdnGroup()[0]
183
194
  * const updater = createUpdater({
184
- * SIGNATURE_PUB,
195
+ * SIGNATURE_CERT,
185
196
  * productName: name,
186
197
  * repository,
187
198
  * updateJsonURL: parseGithubCdnURL(repository, 'fastly.jsdelivr.net/gh', 'version.json'),
@@ -202,11 +213,11 @@ declare function initApp(appOptions: AppOption): {
202
213
  * import { initApp } from 'electron-incremental-update'
203
214
  * import { name, repository } from '../package.json'
204
215
  *
205
- * const SIGNATURE_PUB = '' // auto generate
216
+ * const SIGNATURE_CERT = '' // auto generate
206
217
  *
207
- * initApp({ name }, { SIGNATURE_PUB, repository })
218
+ * initApp({ name }, { SIGNATURE_CERT, repository })
208
219
  * ```
209
220
  */
210
221
  declare function initApp(appOptions: AppOption, updaterOptions: InitUpdaterOptions): undefined;
211
222
 
212
- export { AppOption, CheckResultType, DownloadResult, InitUpdaterOptions, UpdateJSON, Updater, UpdaterOption, createUpdater, getAppAsarPath, getAppVersion, getEntryVersion, getGithubReleaseCdnGroup, initApp, parseGithubCdnURL, requireNative, restartApp };
223
+ export { AppOption, CheckResultType, InitUpdaterOptions, InstallResult, UpdateJSON, Updater, UpdaterOption, createUpdater, getEntryVersion, getGithubReleaseCdnGroup, getProductAsarPath, getProductVersion, initApp, isUpdateJSON, parseGithubCdnURL, requireNative, restartApp };