electron-incremental-update 0.1.0 → 0.1.2

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
@@ -47,7 +47,7 @@ const SIGNATURE_PUB = '' // auto generate RSA public key when start app
47
47
 
48
48
  const updater = createUpdater({
49
49
  SIGNATURE_PUB,
50
- githubRepository: repository,
50
+ repository,
51
51
  productName: name,
52
52
  })
53
53
  initApp(name, updater)
package/dist/index.cjs CHANGED
@@ -91,13 +91,20 @@ var import_node_https = __toESM(require("https"), 1);
91
91
  var import_electron2 = require("electron");
92
92
  function createUpdater({
93
93
  SIGNATURE_PUB,
94
- githubRepository: repository,
94
+ repository,
95
95
  productName,
96
- releaseCdnPrefix
96
+ releaseAsarURL: _release,
97
+ updateJsonURL: _update,
98
+ userAgent,
99
+ extraHeader
97
100
  }) {
98
101
  const updater = new import_node_events.EventEmitter();
99
102
  async function download(url, format) {
100
- 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";
103
+ 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";
104
+ const commonHeader = {
105
+ UserAgent: ua,
106
+ ...extraHeader
107
+ };
101
108
  return await new Promise((resolve2, reject) => {
102
109
  import_node_https.default.get(url, (res) => {
103
110
  if (format === "json") {
@@ -105,7 +112,7 @@ function createUpdater({
105
112
  res.setEncoding("utf8");
106
113
  res.headers = {
107
114
  Accept: "application/json",
108
- UserAgent: ua
115
+ ...commonHeader
109
116
  };
110
117
  res.on("data", (chunk) => data += chunk);
111
118
  res.on("end", () => {
@@ -115,7 +122,7 @@ function createUpdater({
115
122
  let data = [];
116
123
  res.headers = {
117
124
  Accept: "application/octet-stream",
118
- UserAgent: ua
125
+ ...commonHeader
119
126
  };
120
127
  res.on("data", (chunk) => {
121
128
  updater.emit("downloading", chunk.length);
@@ -162,16 +169,22 @@ function createUpdater({
162
169
  };
163
170
  return import_electron2.app.isPackaged && parseVersion(import_electron2.app.getVersion()) < parseVersion(version);
164
171
  }
165
- async function checkUpdate(releaseCdnPrefix2) {
172
+ async function checkUpdate(option) {
173
+ let {
174
+ updateJsonURL = _update,
175
+ releaseAsarURL = _release
176
+ } = option || {};
177
+ if ((!updateJsonURL || !releaseAsarURL) && !repository) {
178
+ throw new Error("updateJsonURL or releaseAsarURL are not set");
179
+ }
180
+ updateJsonURL ??= `${repository}/version.json`;
181
+ releaseAsarURL ??= `${repository}/releases/download/latest/${productName}.asar.gz`;
166
182
  const gzipPath = `../${productName}.asar.gz`;
167
183
  const tmpFile = gzipPath.replace(".asar.gz", ".tmp.gz");
168
- const base = repository.replace("https://github.com", "");
169
- const updateJSONUrl = `https://cdn.jsdelivr.net/gh/${base}/version.json`;
170
- const downloadUrl = `${releaseCdnPrefix2 ? `${releaseCdnPrefix2}/${base}` : repository}/releases/download/latest/${productName}.asar.gz`;
171
184
  if ((0, import_node_fs2.existsSync)(tmpFile)) {
172
185
  await (0, import_promises.rm)(tmpFile);
173
186
  }
174
- const json = await download(updateJSONUrl, "json");
187
+ const json = await download(updateJsonURL, "json");
175
188
  if (!json) {
176
189
  throw new Error("fetch update json failed");
177
190
  }
@@ -180,12 +193,11 @@ function createUpdater({
180
193
  version,
181
194
  size
182
195
  } = json;
183
- console.log(version, size, signature);
184
196
  if (!needUpdate(version)) {
185
197
  return "unavailable";
186
198
  }
187
199
  updater.emit("downloadStart", size);
188
- const buffer = await download(downloadUrl, "buffer");
200
+ const buffer = await download(releaseAsarURL, "buffer");
189
201
  if (!verify(buffer, signature)) {
190
202
  throw new Error("file broken, invalid signature!");
191
203
  }
@@ -193,9 +205,9 @@ function createUpdater({
193
205
  await extractFile(gzipPath);
194
206
  return "success";
195
207
  }
196
- const onCheck = async () => {
208
+ const onCheck = async (option) => {
197
209
  try {
198
- const result = await checkUpdate(releaseCdnPrefix);
210
+ const result = await checkUpdate(option);
199
211
  updater.emit("checkResult", result);
200
212
  } catch (error) {
201
213
  updater.emit("checkResult", "fail", error);
package/dist/index.d.ts CHANGED
@@ -8,6 +8,20 @@ type UpdateEvents = {
8
8
  donwnloadError: [error: unknown];
9
9
  };
10
10
  type MaybeArray<T> = T extends undefined | null | never ? [] : T extends any[] ? T['length'] extends 1 ? [data: T[0]] : T : [data: T];
11
+ interface UpdateOption {
12
+ /**
13
+ * URL of version info json
14
+ * @default `${repository}/version.json`
15
+ * @throws if `updateJsonURL` and `repository` are all not set
16
+ */
17
+ updateJsonURL?: string;
18
+ /**
19
+ * URL of release asar.gz
20
+ * @default `${repository}/releases/download/latest/${productName}.asar.gz`
21
+ * @throws if `releaseAsarURL` and `repository` are all not set
22
+ */
23
+ releaseAsarURL?: string;
24
+ }
11
25
  interface TypedUpdater<T extends Record<string | symbol, MaybeArray<any>>, Event extends Exclude<keyof T, number> = Exclude<keyof T, number>> {
12
26
  removeAllListeners<E extends Event>(event?: E): this;
13
27
  listeners<E extends Event>(eventName: E): Function[];
@@ -16,16 +30,52 @@ interface TypedUpdater<T extends Record<string | symbol, MaybeArray<any>>, Event
16
30
  once<E extends Event>(eventName: E, listener: (...args: MaybeArray<T[E]>) => void): this;
17
31
  emit<E extends Event>(eventName: E, ...args: MaybeArray<T[E]>): boolean;
18
32
  off<E extends Event>(eventName: E, listener: (...args: MaybeArray<T[E]>) => void): this;
19
- checkUpdate(releaseCdnPrefix?: string): Promise<void>;
33
+ checkUpdate(options?: UpdateOption): Promise<void>;
20
34
  }
21
35
  type Updater = TypedUpdater<UpdateEvents>;
22
- interface Options {
36
+ interface Options extends UpdateOption {
37
+ /**
38
+ * public key of signature
39
+ *
40
+ * it will be auto generated by plugin
41
+ * @example
42
+ * ```ts
43
+ * // auto filled by plugin
44
+ * const SIGNATURE_PUB = ''
45
+ *
46
+ * const updater = createUpdater({
47
+ * SIGNATURE_PUB,
48
+ * ...
49
+ * })
50
+ * ```
51
+ */
23
52
  SIGNATURE_PUB: string;
53
+ /**
54
+ * product name
55
+ *
56
+ * you can use the `name` in package.json
57
+ */
24
58
  productName: string;
25
- githubRepository: string;
26
- releaseCdnPrefix?: string;
59
+ /**
60
+ * repository url, e.g. `https://github.com/electron/electron`
61
+ *
62
+ * you can use the `repository` in package.json
63
+ *
64
+ * if `updateJsonURL` or `releaseAsarURL` are absent,
65
+ * `repository` will be used to determine the url
66
+ */
67
+ repository?: string;
68
+ /**
69
+ * download user agent
70
+ * @default 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.183 Safari/537.36'
71
+ */
72
+ userAgent?: string;
73
+ /**
74
+ * extra download header, `accept` and `user-agent` is set by default
75
+ */
76
+ extraHeader?: Record<string, string>;
27
77
  }
28
- declare function createUpdater({ SIGNATURE_PUB, githubRepository: repository, productName, releaseCdnPrefix, }: Options): Updater;
78
+ declare function createUpdater({ SIGNATURE_PUB, repository, productName, releaseAsarURL: _release, updateJsonURL: _update, userAgent, extraHeader, }: Options): Updater;
29
79
 
30
80
  declare function getAppAsarPath(name: string): string;
31
81
  declare function getElectronVersion(): string;
package/dist/index.mjs CHANGED
@@ -55,13 +55,20 @@ import https from "node:https";
55
55
  import { app as app2 } from "electron";
56
56
  function createUpdater({
57
57
  SIGNATURE_PUB,
58
- githubRepository: repository,
58
+ repository,
59
59
  productName,
60
- releaseCdnPrefix
60
+ releaseAsarURL: _release,
61
+ updateJsonURL: _update,
62
+ userAgent,
63
+ extraHeader
61
64
  }) {
62
65
  const updater = new EventEmitter();
63
66
  async function download(url, format) {
64
- 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";
67
+ 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";
68
+ const commonHeader = {
69
+ UserAgent: ua,
70
+ ...extraHeader
71
+ };
65
72
  return await new Promise((resolve2, reject) => {
66
73
  https.get(url, (res) => {
67
74
  if (format === "json") {
@@ -69,7 +76,7 @@ function createUpdater({
69
76
  res.setEncoding("utf8");
70
77
  res.headers = {
71
78
  Accept: "application/json",
72
- UserAgent: ua
79
+ ...commonHeader
73
80
  };
74
81
  res.on("data", (chunk) => data += chunk);
75
82
  res.on("end", () => {
@@ -79,7 +86,7 @@ function createUpdater({
79
86
  let data = [];
80
87
  res.headers = {
81
88
  Accept: "application/octet-stream",
82
- UserAgent: ua
89
+ ...commonHeader
83
90
  };
84
91
  res.on("data", (chunk) => {
85
92
  updater.emit("downloading", chunk.length);
@@ -126,16 +133,22 @@ function createUpdater({
126
133
  };
127
134
  return app2.isPackaged && parseVersion(app2.getVersion()) < parseVersion(version);
128
135
  }
129
- async function checkUpdate(releaseCdnPrefix2) {
136
+ async function checkUpdate(option) {
137
+ let {
138
+ updateJsonURL = _update,
139
+ releaseAsarURL = _release
140
+ } = option || {};
141
+ if ((!updateJsonURL || !releaseAsarURL) && !repository) {
142
+ throw new Error("updateJsonURL or releaseAsarURL are not set");
143
+ }
144
+ updateJsonURL ??= `${repository}/version.json`;
145
+ releaseAsarURL ??= `${repository}/releases/download/latest/${productName}.asar.gz`;
130
146
  const gzipPath = `../${productName}.asar.gz`;
131
147
  const tmpFile = gzipPath.replace(".asar.gz", ".tmp.gz");
132
- const base = repository.replace("https://github.com", "");
133
- const updateJSONUrl = `https://cdn.jsdelivr.net/gh/${base}/version.json`;
134
- const downloadUrl = `${releaseCdnPrefix2 ? `${releaseCdnPrefix2}/${base}` : repository}/releases/download/latest/${productName}.asar.gz`;
135
148
  if (existsSync(tmpFile)) {
136
149
  await rm(tmpFile);
137
150
  }
138
- const json = await download(updateJSONUrl, "json");
151
+ const json = await download(updateJsonURL, "json");
139
152
  if (!json) {
140
153
  throw new Error("fetch update json failed");
141
154
  }
@@ -144,12 +157,11 @@ function createUpdater({
144
157
  version,
145
158
  size
146
159
  } = json;
147
- console.log(version, size, signature);
148
160
  if (!needUpdate(version)) {
149
161
  return "unavailable";
150
162
  }
151
163
  updater.emit("downloadStart", size);
152
- const buffer = await download(downloadUrl, "buffer");
164
+ const buffer = await download(releaseAsarURL, "buffer");
153
165
  if (!verify(buffer, signature)) {
154
166
  throw new Error("file broken, invalid signature!");
155
167
  }
@@ -157,9 +169,9 @@ function createUpdater({
157
169
  await extractFile(gzipPath);
158
170
  return "success";
159
171
  }
160
- const onCheck = async () => {
172
+ const onCheck = async (option) => {
161
173
  try {
162
- const result = await checkUpdate(releaseCdnPrefix);
174
+ const result = await checkUpdate(option);
163
175
  updater.emit("checkResult", result);
164
176
  } catch (error) {
165
177
  updater.emit("checkResult", "fail", error);
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)("version.json", JSON.stringify({
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
@@ -47,6 +47,11 @@ type Options = {
47
47
  * @default `dist`
48
48
  */
49
49
  rendererDistPath?: string;
50
+ /**
51
+ * Path to version info output
52
+ * @default `version.json`
53
+ */
54
+ versionPath?: string;
50
55
  };
51
56
  keys?: {
52
57
  /**
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("version.json", JSON.stringify({
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,
package/package.json CHANGED
@@ -1,11 +1,12 @@
1
1
  {
2
2
  "name": "electron-incremental-update",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "electron incremental update tools, powered by vite",
5
5
  "scripts": {
6
6
  "build": "tsup",
7
- "release": "bumpp"
7
+ "release": "tsup && bumpp"
8
8
  },
9
+ "repository": "https://github.com/subframe7536/electron-incremental-update",
9
10
  "type": "module",
10
11
  "license": "MIT",
11
12
  "files": [