Skip to content
Source
Sign inSign up

electron-updater@6.8.9.patch

135 lines6.6 KB

1diff --git a/out/electronHttpExecutor.js b/out/electronHttpExecutor.js
2index 0ae9e1126e1dc136977914ef1bfd46709fc9db1b..c298ffe7808c421c29e16f1e2ba8510f0cd31142 100644
3--- a/out/electronHttpExecutor.js
4+++ b/out/electronHttpExecutor.js
5@@ -61,6 +61,35 @@ class ElectronHttpExecutor extends builder_util_runtime_1.HttpExecutor {
6 }
7 return request;
8 }
9+ // Electron's net.ClientRequest never emits "socket", so the inherited socket idle timeout never
10+ // arms and a stalled request stays pending forever. Reset an idle timer on every chunk instead.
11+ addTimeOutHandler(request, callback, timeout) {
12+ let timer = null;
13+ const clear = () => {
14+ if (timer != null) {
15+ clearTimeout(timer);
16+ timer = null;
17+ }
18+ };
19+ const arm = () => {
20+ clear();
21+ timer = setTimeout(() => {
22+ timer = null;
23+ request.abort();
24+ callback(new Error("Request timed out"));
25+ }, timeout);
26+ };
27+ request.on("response", (response) => {
28+ arm();
29+ response.on("data", arm);
30+ response.on("end", clear);
31+ response.on("aborted", clear);
32+ response.on("error", clear);
33+ });
34+ request.on("abort", clear);
35+ request.on("error", clear);
36+ arm();
37+ }
38 addRedirectHandlers(request, options, reject, redirectCount, handler) {
39 request.on("redirect", (statusCode, method, redirectUrl) => {
40 // no way to modify request options, abort old and make a new one
41diff --git a/out/providers/GitHubProvider.js b/out/providers/GitHubProvider.js
42index e768d24e7a957caf32a4b8ca6c68cb50eb5865ee..708a1fa7d740192944f04259cde6d6bf79d58c53 100644
43--- a/out/providers/GitHubProvider.js
44+++ b/out/providers/GitHubProvider.js
45@@ -107,6 +107,32 @@ class GitHubProvider extends BaseGitHubProvider {
46 catch (e) {
47 throw (0, builder_util_runtime_1.newError)(`Cannot parse releases feed: ${e.stack || e.message},\nXML:\n${feedXml}`, "ERR_UPDATER_INVALID_RELEASE_FEED");
48 }
49+ // The atom feed lists only the 10 newest git tags of any kind, in an order GitHub picks, so
50+ // the release workflow also records a prerelease channel's newest release at one fixed URL.
51+ // The newer of the two answers wins; the API scan is the last resort.
52+ let apiRelease = null;
53+ if (this.updater.allowPrerelease && this.updater.channel) {
54+ const feedTag = tag;
55+ const pointer = await this.getChannelPointerRelease(this.updater.channel, cancellationToken);
56+ if (pointer !== null && (tag == null || semver.gt(pointer.tag_name, tag))) {
57+ apiRelease = pointer;
58+ tag = pointer.tag_name;
59+ }
60+ // With no nightly in the feed, a pointer that offers nothing new may be stale, so the API
61+ // scan still runs. Its failure is fatal only when nothing else answered.
62+ if (feedTag == null && (tag == null || !semver.gt(tag, this.updater.currentVersion))) {
63+ const listed = await this.getLatestChannelRelease(this.updater.channel, cancellationToken).catch(e => {
64+ if (tag == null) {
65+ throw e;
66+ }
67+ return null;
68+ });
69+ if (listed !== null && (tag == null || semver.gt(listed.tag_name, tag))) {
70+ apiRelease = listed;
71+ tag = listed.tag_name;
72+ }
73+ }
74+ }
75 if (tag == null) {
76 throw (0, builder_util_runtime_1.newError)(`No published versions on GitHub`, "ERR_UPDATER_NO_PUBLISHED_VERSIONS");
77 }
78@@ -144,6 +170,14 @@ class GitHubProvider extends BaseGitHubProvider {
79 }
80 }
81 const result = (0, Provider_1.parseUpdateInfo)(rawData, channelFile, channelFileUrl);
82+ if (apiRelease !== null) {
83+ if (result.releaseName == null) {
84+ result.releaseName = apiRelease.name || apiRelease.tag_name;
85+ }
86+ if (result.releaseNotes == null) {
87+ result.releaseNotes = apiRelease.body || "";
88+ }
89+ }
90 if (result.releaseName == null) {
91 result.releaseName = latestRelease.elementValueOrEmpty("title");
92 }
93@@ -155,6 +189,42 @@ class GitHubProvider extends BaseGitHubProvider {
94 ...result,
95 };
96 }
97+ async getChannelPointerRelease(channel, cancellationToken) {
98+ try {
99+ const url = (0, util_1.newUrlFromBase)(this.getBaseDownloadPath("update-feed", `${channel}.json`), this.baseUrl);
100+ const rawData = await this.httpRequest(url, { accept: "application/json, */*" }, cancellationToken);
101+ const release = rawData == null ? null : JSON.parse(rawData);
102+ const releaseChannel = release == null || typeof release.tag_name !== "string" ? null : semver.prerelease(release.tag_name);
103+ return releaseChannel !== null && releaseChannel[0] === channel ? release : null;
104+ }
105+ catch (e) {
106+ // A fork, or a moment between two uploads, has no pointer. The feed still answers.
107+ return null;
108+ }
109+ }
110+ async getLatestChannelRelease(channel, cancellationToken) {
111+ for (let page = 1; page <= 5; page++) {
112+ const url = new url_1.URL(`${this.computeGithubBasePath(`/repos/${this.options.owner}/${this.options.repo}/releases`)}?per_page=100&page=${page}`, this.baseApiUrl);
113+ const rawData = await this.httpRequest(url, { Accept: "application/vnd.github+json" }, cancellationToken);
114+ const releases = rawData == null ? [] : JSON.parse(rawData);
115+ if (!Array.isArray(releases)) {
116+ return null;
117+ }
118+ for (const release of releases) {
119+ if (release == null || release.draft || typeof release.tag_name !== "string" || !semver.valid(release.tag_name)) {
120+ continue;
121+ }
122+ const releaseChannel = semver.prerelease(release.tag_name);
123+ if (releaseChannel !== null && releaseChannel[0] === channel) {
124+ return release;
125+ }
126+ }
127+ if (releases.length < 100) {
128+ return null;
129+ }
130+ }
131+ return null;
132+ }
133 async getLatestTagName(cancellationToken) {
134 const options = this.options;
135 // do not use API for GitHub to avoid limit, only for custom host or GitHub Enterprise