html-snapshots 5.7.2 → 5.9.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/lib/common/index.js +43 -9
- package/lib/common/sitemap/sitemap.js +13 -13
- package/lib/input-generators/robots.js +9 -11
- package/package.json +4 -5
package/lib/common/index.js
CHANGED
|
@@ -17,10 +17,8 @@
|
|
|
17
17
|
*/
|
|
18
18
|
function ensure (options, must) {
|
|
19
19
|
if (must) {
|
|
20
|
-
for (
|
|
21
|
-
|
|
22
|
-
options[prop] = must[prop];
|
|
23
|
-
}
|
|
20
|
+
for (const prop in must) {
|
|
21
|
+
options[prop] ??= must[prop];
|
|
24
22
|
}
|
|
25
23
|
}
|
|
26
24
|
return options;
|
|
@@ -126,23 +124,25 @@ function prependMsgToErr (error, message, quoteInput) {
|
|
|
126
124
|
* Simple response checker for remote files.
|
|
127
125
|
* Expected use in robots.txt or sitemap.xml only.
|
|
128
126
|
*
|
|
129
|
-
* @param {
|
|
127
|
+
* @param {Response} res - The IncomingMessage response to check.
|
|
130
128
|
* @param {Array} mediaTypes - array of acceptable content-type media type strings.
|
|
131
129
|
* @returns {String} Error message, empty string (falsy) if OK.
|
|
132
130
|
*/
|
|
133
131
|
function checkResponse (res, mediaTypes) {
|
|
134
|
-
let result = `status: '${res.
|
|
132
|
+
let result = `status: '${res.status}', GET failed.`;
|
|
135
133
|
|
|
136
134
|
mediaTypes = !Array.isArray(mediaTypes) ? [mediaTypes] : mediaTypes;
|
|
137
135
|
|
|
138
|
-
if (res.
|
|
136
|
+
if (res.status === 200) {
|
|
137
|
+
const contentType = res.headers.get("Content-Type");
|
|
138
|
+
|
|
139
139
|
// if content-type exists, and media type found then contentTypeOk
|
|
140
140
|
const contentTypeOk =
|
|
141
|
-
|
|
141
|
+
contentType &&
|
|
142
142
|
// empty array and none found return true
|
|
143
143
|
!mediaTypes.every(mediaType => {
|
|
144
144
|
// flip -1 to 0 and NOT, so that true == NOT found, found stops loop w/false
|
|
145
|
-
return !~
|
|
145
|
+
return !~contentType.indexOf(mediaType);
|
|
146
146
|
});
|
|
147
147
|
|
|
148
148
|
result = contentTypeOk ? "" :
|
|
@@ -152,9 +152,43 @@ function checkResponse (res, mediaTypes) {
|
|
|
152
152
|
return result;
|
|
153
153
|
}
|
|
154
154
|
|
|
155
|
+
/**
|
|
156
|
+
* Simple fetch with timeout and retries.
|
|
157
|
+
* Retries on throw (timeout) or 500+ response with backoff delay.
|
|
158
|
+
*
|
|
159
|
+
* @param {String|Request} url - The fetch resource
|
|
160
|
+
* @param {Object} options - The fetch RequestInit object
|
|
161
|
+
* @param {Number} timeout - The request timeout in milliseconds
|
|
162
|
+
* @param {Number} retries - The retries on timeout or 500+ responses
|
|
163
|
+
* @param {Number} backoff - The initial backoff to wait between retries, backoff * 2 each iter
|
|
164
|
+
*/
|
|
165
|
+
async function simpleFetch (url, options = {}, timeout = 3000, retries = 3, backoff = 1000) {
|
|
166
|
+
try {
|
|
167
|
+
const response = await fetch(url, {
|
|
168
|
+
signal: AbortSignal.timeout(timeout),
|
|
169
|
+
...options
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
if (!response.ok && response.status >= 500 && retries > 0) {
|
|
173
|
+
throw new Error(`Server error: ${response.status}`);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
return response;
|
|
177
|
+
} catch (error) {
|
|
178
|
+
if (retries <= 0) throw error;
|
|
179
|
+
|
|
180
|
+
console.warn(`Retrying... (${retries} attempts left)`);
|
|
181
|
+
|
|
182
|
+
await new Promise(resolve => setTimeout(resolve, backoff));
|
|
183
|
+
|
|
184
|
+
return simpleFetch(url, options, timeout, retries - 1, backoff * 2);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
155
188
|
module.exports = {
|
|
156
189
|
checkResponse,
|
|
157
190
|
ensure,
|
|
191
|
+
get: (url, timeout) => simpleFetch(url, {}, timeout),
|
|
158
192
|
head,
|
|
159
193
|
isUrl,
|
|
160
194
|
isFunction,
|
|
@@ -178,23 +178,23 @@ function convert (options, buffer, next, callback) {
|
|
|
178
178
|
* @return {Promise} resolves to data on completion.
|
|
179
179
|
*/
|
|
180
180
|
async function getUrl (options, parseFn) {
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
responseType: "buffer",
|
|
185
|
-
timeout: {
|
|
186
|
-
request: options.timeout() // get the default timeout
|
|
187
|
-
}
|
|
188
|
-
}).then(res => {
|
|
189
|
-
let error = common.checkResponse(res, ["text/xml", "application/xml"]);
|
|
181
|
+
try {
|
|
182
|
+
const res = await common.get(options.source, options.timeout());
|
|
183
|
+
const error = common.checkResponse(res, ["text/xml", "application/xml"]);
|
|
190
184
|
if (error) {
|
|
191
185
|
throw new Error(error);
|
|
192
186
|
}
|
|
187
|
+
|
|
188
|
+
const arrayBuffer = await res.arrayBuffer();
|
|
189
|
+
|
|
193
190
|
const conv = util.promisify(convert);
|
|
194
|
-
return conv(options,
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
|
|
191
|
+
return conv(options, Buffer.from(arrayBuffer), parseFn);
|
|
192
|
+
}
|
|
193
|
+
catch (err) {
|
|
194
|
+
throw new Error(common.prependMsgToErr(err, options.source, true), {
|
|
195
|
+
cause: err
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
198
|
}
|
|
199
199
|
|
|
200
200
|
/**
|
|
@@ -122,21 +122,19 @@ function processRobotsTxt (options, body) {
|
|
|
122
122
|
* @returns {Promise} resolves to undefined.
|
|
123
123
|
*/
|
|
124
124
|
async function getRobotsUrl (options) {
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
url: options.source,
|
|
128
|
-
timeout: {
|
|
129
|
-
request: options.timeout()
|
|
130
|
-
}
|
|
131
|
-
}).then(res => {
|
|
125
|
+
try {
|
|
126
|
+
const res = await common.get(options.source, options.timeout());
|
|
132
127
|
const error = common.checkResponse(res, "text/plain");
|
|
133
128
|
if (error) {
|
|
134
129
|
throw new Error(error);
|
|
135
130
|
}
|
|
136
|
-
return processRobotsTxt(options, res.
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
|
|
131
|
+
return processRobotsTxt(options, await res.text());
|
|
132
|
+
}
|
|
133
|
+
catch (err) {
|
|
134
|
+
throw new Error(common.prependMsgToErr(err, options.source, true), {
|
|
135
|
+
cause: err
|
|
136
|
+
});
|
|
137
|
+
}
|
|
140
138
|
}
|
|
141
139
|
|
|
142
140
|
/**
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "html-snapshots",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.9.0",
|
|
4
4
|
"author": {
|
|
5
5
|
"name": "Alex Grant",
|
|
6
6
|
"email": "alex@localnerve.com",
|
|
@@ -53,15 +53,14 @@
|
|
|
53
53
|
"async": "3.2.6",
|
|
54
54
|
"async-lock": "1.4.1",
|
|
55
55
|
"combine-errors": "3.0.3",
|
|
56
|
-
"got": "^14.6.6",
|
|
57
56
|
"phantomjs-prebuilt": "2.1.16",
|
|
58
|
-
"puppeteer": "^24.
|
|
57
|
+
"puppeteer": "^24.41.0",
|
|
59
58
|
"xml2js": "0.6.2"
|
|
60
59
|
},
|
|
61
60
|
"devDependencies": {
|
|
62
61
|
"eslint": "^10.2.0",
|
|
63
62
|
"@eslint/js": "^10.0.1",
|
|
64
|
-
"globals": "^17.
|
|
63
|
+
"globals": "^17.5.0",
|
|
65
64
|
"express": "^5.2.1",
|
|
66
65
|
"mocha": "^11.7.5",
|
|
67
66
|
"c8": "^11.0.0",
|
|
@@ -70,7 +69,7 @@
|
|
|
70
69
|
},
|
|
71
70
|
"overrides": {
|
|
72
71
|
"request": "npm:@cypress/request@3.0.10",
|
|
73
|
-
"diff": "^
|
|
72
|
+
"diff": "^9.0.0",
|
|
74
73
|
"glob": "^13.0.6",
|
|
75
74
|
"serialize-javascript": "^7.0.5",
|
|
76
75
|
"brace-expansion": "^5.0.5"
|