@microlink/mql 0.10.32 → 0.10.34
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/LICENSE.md +0 -0
- package/README.md +2 -1
- package/dist/mql.js +219 -114
- package/dist/mql.js.map +1 -1
- package/dist/mql.min.js +2 -2
- package/dist/mql.min.js.map +1 -1
- package/dist/mql.min.mjs +2 -2
- package/dist/mql.min.mjs.map +1 -1
- package/dist/mql.mjs +219 -114
- package/dist/mql.mjs.map +1 -1
- package/index.d.ts +100 -225
- package/package.json +31 -25
- package/src/browser.js +1 -0
- package/src/factory.js +2 -13
- package/src/ky.js +203 -92
- package/src/node.js +1 -1
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@microlink/mql",
|
|
3
3
|
"description": "Microlink Query Language. The official HTTP client to interact with Microlink API for Node.js, browsers & Deno.",
|
|
4
4
|
"homepage": "https://nicedoc.io/microlinkhq/mql",
|
|
5
|
-
"version": "0.10.
|
|
5
|
+
"version": "0.10.34",
|
|
6
6
|
"browser": "src/browser.js",
|
|
7
7
|
"main": "src/node.js",
|
|
8
8
|
"author": {
|
|
@@ -44,18 +44,20 @@
|
|
|
44
44
|
],
|
|
45
45
|
"dependencies": {
|
|
46
46
|
"flattie": "~1.1.0",
|
|
47
|
-
"got": "~11.8.
|
|
47
|
+
"got": "~11.8.6",
|
|
48
48
|
"url-http": "~1.0.7",
|
|
49
49
|
"whoops": "~4.1.1"
|
|
50
50
|
},
|
|
51
51
|
"devDependencies": {
|
|
52
52
|
"@commitlint/cli": "latest",
|
|
53
53
|
"@commitlint/config-conventional": "latest",
|
|
54
|
+
"@ksmithut/prettier-standard": "latest",
|
|
54
55
|
"@rollup/plugin-commonjs": "latest",
|
|
55
56
|
"@rollup/plugin-node-resolve": "latest",
|
|
56
57
|
"@rollup/plugin-replace": "latest",
|
|
57
58
|
"@rollup/plugin-terser": "latest",
|
|
58
59
|
"abort-controller": "latest",
|
|
60
|
+
"async-listen": "latest",
|
|
59
61
|
"ava": "3",
|
|
60
62
|
"beauty-error": "latest",
|
|
61
63
|
"c8": "latest",
|
|
@@ -80,7 +82,7 @@
|
|
|
80
82
|
"standard-markdown": "latest",
|
|
81
83
|
"standard-version": "latest",
|
|
82
84
|
"stream-to-promise": "latest",
|
|
83
|
-
"
|
|
85
|
+
"tsd": "latest",
|
|
84
86
|
"web-streams-polyfill": "latest"
|
|
85
87
|
},
|
|
86
88
|
"engines": {
|
|
@@ -92,6 +94,25 @@
|
|
|
92
94
|
"lightweight",
|
|
93
95
|
"src"
|
|
94
96
|
],
|
|
97
|
+
"scripts": {
|
|
98
|
+
"build": "rollup -c rollup.config.js --bundleConfigAsCjs",
|
|
99
|
+
"build:kys": "[ -f src/ky.js ] || rollup node_modules/ky/distribution/index.js --format=umd --name=ky --exports=named --file=src/ky.js",
|
|
100
|
+
"clean": "rm -rf node_modules",
|
|
101
|
+
"clean:build": "rm -rf dist",
|
|
102
|
+
"contributors": "(npx git-authors-cli && npx finepack --sort-ignore-object-at ava && git add package.json && git commit -m 'build: contributors' --no-verify) || true",
|
|
103
|
+
"dev": "npm run build -- -w",
|
|
104
|
+
"lint": "standard && tsd",
|
|
105
|
+
"postrelease": "npm run release:tags && npm run release:github && (ci-publish || npm publish --access=public)",
|
|
106
|
+
"prebuild": "npm run clean:build && npm run build:kys",
|
|
107
|
+
"prerelease": "npm run update:check",
|
|
108
|
+
"pretest": "npm run lint && npm run build",
|
|
109
|
+
"release": "standard-version -a",
|
|
110
|
+
"release:github": "conventional-github-releaser -p angular",
|
|
111
|
+
"release:tags": "git push --follow-tags origin HEAD:master",
|
|
112
|
+
"test": "c8 ava --verbose",
|
|
113
|
+
"update": "ncu -u",
|
|
114
|
+
"update:check": "ncu -- --error-level 2"
|
|
115
|
+
},
|
|
95
116
|
"license": "MIT",
|
|
96
117
|
"ava": {
|
|
97
118
|
"files": [
|
|
@@ -111,7 +132,8 @@
|
|
|
111
132
|
},
|
|
112
133
|
"nano-staged": {
|
|
113
134
|
"*.js,!*.min.js,": [
|
|
114
|
-
"prettier-standard"
|
|
135
|
+
"prettier-standard",
|
|
136
|
+
"standard --fix"
|
|
115
137
|
],
|
|
116
138
|
"*.md": [
|
|
117
139
|
"standard-markdown"
|
|
@@ -135,26 +157,10 @@
|
|
|
135
157
|
"postbump": "npm run build"
|
|
136
158
|
}
|
|
137
159
|
},
|
|
160
|
+
"tsd": {
|
|
161
|
+
"directory": "test"
|
|
162
|
+
},
|
|
138
163
|
"types": "index.d.ts",
|
|
139
164
|
"umd:main": "dist/mql.js",
|
|
140
|
-
"unpkg": "dist/mql.js"
|
|
141
|
-
|
|
142
|
-
"build": "rollup -c rollup.config.js --bundleConfigAsCjs",
|
|
143
|
-
"build:kys": "[ -f src/ky.js ] || rollup node_modules/ky/distribution/index.js --format=umd --name=ky --exports=named --file=src/ky.js",
|
|
144
|
-
"clean": "rm -rf node_modules",
|
|
145
|
-
"clean:build": "rm -rf dist",
|
|
146
|
-
"contributors": "(npx git-authors-cli && npx finepack --sort-ignore-object-at ava && git add package.json && git commit -m 'build: contributors' --no-verify) || true",
|
|
147
|
-
"dev": "npm run build -- -w",
|
|
148
|
-
"lint": "standard",
|
|
149
|
-
"postrelease": "npm run release:tags && npm run release:github && (ci-publish || npm publish --access=public)",
|
|
150
|
-
"prebuild": "npm run clean:build && npm run build:kys",
|
|
151
|
-
"prerelease": "npm run update:check",
|
|
152
|
-
"pretest": "npm run lint && npm run build",
|
|
153
|
-
"release": "standard-version -a",
|
|
154
|
-
"release:github": "conventional-github-releaser -p angular",
|
|
155
|
-
"release:tags": "git push --follow-tags origin HEAD:master",
|
|
156
|
-
"test": "c8 ava --verbose",
|
|
157
|
-
"update": "ncu -u",
|
|
158
|
-
"update:check": "ncu -- --error-level 2"
|
|
159
|
-
}
|
|
160
|
-
}
|
|
165
|
+
"unpkg": "dist/mql.js"
|
|
166
|
+
}
|
package/src/browser.js
CHANGED
|
@@ -20,6 +20,7 @@ class MicrolinkError extends Error {
|
|
|
20
20
|
|
|
21
21
|
const got = async (url, opts) => {
|
|
22
22
|
try {
|
|
23
|
+
if (opts.retry > 0) opts.retry = opts.retry + 1
|
|
23
24
|
if (opts.timeout === undefined) opts.timeout = false
|
|
24
25
|
const response = await ky(url, opts)
|
|
25
26
|
const body = await response.json()
|
package/src/factory.js
CHANGED
|
@@ -28,14 +28,7 @@ const parseBody = (input, error, url) => {
|
|
|
28
28
|
}
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
-
const factory = ({
|
|
32
|
-
VERSION,
|
|
33
|
-
MicrolinkError,
|
|
34
|
-
urlHttp,
|
|
35
|
-
stringify,
|
|
36
|
-
got,
|
|
37
|
-
flatten
|
|
38
|
-
}) => {
|
|
31
|
+
const factory = ({ VERSION, MicrolinkError, urlHttp, got, flatten }) => {
|
|
39
32
|
const assertUrl = (url = '') => {
|
|
40
33
|
if (!urlHttp(url)) {
|
|
41
34
|
const message = `The \`url\` as \`${url}\` is not valid. Ensure it has protocol (http or https) and hostname.`
|
|
@@ -59,7 +52,7 @@ const factory = ({
|
|
|
59
52
|
}, {})
|
|
60
53
|
}
|
|
61
54
|
|
|
62
|
-
const fetchFromApi = async (apiUrl, opts = {}
|
|
55
|
+
const fetchFromApi = async (apiUrl, opts = {}) => {
|
|
63
56
|
try {
|
|
64
57
|
const response = await got(apiUrl, opts)
|
|
65
58
|
return opts.responseType === 'buffer'
|
|
@@ -80,10 +73,6 @@ const factory = ({
|
|
|
80
73
|
? rawBody
|
|
81
74
|
: parseBody(isBodyBuffer ? rawBody.toString() : rawBody, err, uri)
|
|
82
75
|
|
|
83
|
-
if (body.code === 'EFATALCLIENT' && retryCount++ < 2) {
|
|
84
|
-
return fetchFromApi(apiUrl, opts, retryCount)
|
|
85
|
-
}
|
|
86
|
-
|
|
87
76
|
throw new MicrolinkError({
|
|
88
77
|
...body,
|
|
89
78
|
message: body.message,
|
package/src/ky.js
CHANGED
|
@@ -12,6 +12,24 @@
|
|
|
12
12
|
const status = `${code} ${title}`.trim();
|
|
13
13
|
const reason = status ? `status code ${status}` : 'an unknown error';
|
|
14
14
|
super(`Request failed with ${reason}`);
|
|
15
|
+
Object.defineProperty(this, "response", {
|
|
16
|
+
enumerable: true,
|
|
17
|
+
configurable: true,
|
|
18
|
+
writable: true,
|
|
19
|
+
value: void 0
|
|
20
|
+
});
|
|
21
|
+
Object.defineProperty(this, "request", {
|
|
22
|
+
enumerable: true,
|
|
23
|
+
configurable: true,
|
|
24
|
+
writable: true,
|
|
25
|
+
value: void 0
|
|
26
|
+
});
|
|
27
|
+
Object.defineProperty(this, "options", {
|
|
28
|
+
enumerable: true,
|
|
29
|
+
configurable: true,
|
|
30
|
+
writable: true,
|
|
31
|
+
value: void 0
|
|
32
|
+
});
|
|
15
33
|
this.name = 'HTTPError';
|
|
16
34
|
this.response = response;
|
|
17
35
|
this.request = request;
|
|
@@ -22,6 +40,12 @@
|
|
|
22
40
|
class TimeoutError extends Error {
|
|
23
41
|
constructor(request) {
|
|
24
42
|
super('Request timed out');
|
|
43
|
+
Object.defineProperty(this, "request", {
|
|
44
|
+
enumerable: true,
|
|
45
|
+
configurable: true,
|
|
46
|
+
writable: true,
|
|
47
|
+
value: void 0
|
|
48
|
+
});
|
|
25
49
|
this.name = 'TimeoutError';
|
|
26
50
|
this.request = request;
|
|
27
51
|
}
|
|
@@ -32,7 +56,7 @@
|
|
|
32
56
|
|
|
33
57
|
const validateAndMerge = (...sources) => {
|
|
34
58
|
for (const source of sources) {
|
|
35
|
-
if ((!isObject(source) || Array.isArray(source)) &&
|
|
59
|
+
if ((!isObject(source) || Array.isArray(source)) && source !== undefined) {
|
|
36
60
|
throw new TypeError('The `options` argument must be an object');
|
|
37
61
|
}
|
|
38
62
|
}
|
|
@@ -79,8 +103,26 @@
|
|
|
79
103
|
return returnValue;
|
|
80
104
|
};
|
|
81
105
|
|
|
106
|
+
const supportsRequestStreams = (() => {
|
|
107
|
+
let duplexAccessed = false;
|
|
108
|
+
let hasContentType = false;
|
|
109
|
+
const supportsReadableStream = typeof globalThis.ReadableStream === 'function';
|
|
110
|
+
const supportsRequest = typeof globalThis.Request === 'function';
|
|
111
|
+
if (supportsReadableStream && supportsRequest) {
|
|
112
|
+
hasContentType = new globalThis.Request('https://empty.invalid', {
|
|
113
|
+
body: new globalThis.ReadableStream(),
|
|
114
|
+
method: 'POST',
|
|
115
|
+
// @ts-expect-error - Types are outdated.
|
|
116
|
+
get duplex() {
|
|
117
|
+
duplexAccessed = true;
|
|
118
|
+
return 'half';
|
|
119
|
+
},
|
|
120
|
+
}).headers.has('Content-Type');
|
|
121
|
+
}
|
|
122
|
+
return duplexAccessed && !hasContentType;
|
|
123
|
+
})();
|
|
82
124
|
const supportsAbortController = typeof globalThis.AbortController === 'function';
|
|
83
|
-
const
|
|
125
|
+
const supportsResponseStreams = typeof globalThis.ReadableStream === 'function';
|
|
84
126
|
const supportsFormData = typeof globalThis.FormData === 'function';
|
|
85
127
|
const requestMethods = ['get', 'post', 'put', 'patch', 'head', 'delete'];
|
|
86
128
|
const responseTypes = {
|
|
@@ -104,6 +146,7 @@
|
|
|
104
146
|
statusCodes: retryStatusCodes,
|
|
105
147
|
afterStatusCodes: retryAfterStatusCodes,
|
|
106
148
|
maxRetryAfter: Number.POSITIVE_INFINITY,
|
|
149
|
+
backoffLimit: Number.POSITIVE_INFINITY,
|
|
107
150
|
};
|
|
108
151
|
const normalizeRetryOptions = (retry = {}) => {
|
|
109
152
|
if (typeof retry === 'number') {
|
|
@@ -126,30 +169,139 @@
|
|
|
126
169
|
};
|
|
127
170
|
|
|
128
171
|
// `Promise.race()` workaround (#91)
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
abortController
|
|
172
|
+
async function timeout(request, abortController, options) {
|
|
173
|
+
return new Promise((resolve, reject) => {
|
|
174
|
+
const timeoutId = setTimeout(() => {
|
|
175
|
+
if (abortController) {
|
|
176
|
+
abortController.abort();
|
|
177
|
+
}
|
|
178
|
+
reject(new TimeoutError(request));
|
|
179
|
+
}, options.timeout);
|
|
180
|
+
void options
|
|
181
|
+
.fetch(request)
|
|
182
|
+
.then(resolve)
|
|
183
|
+
.catch(reject)
|
|
184
|
+
.then(() => {
|
|
185
|
+
clearTimeout(timeoutId);
|
|
186
|
+
});
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// https://github.com/sindresorhus/delay/tree/ab98ae8dfcb38e1593286c94d934e70d14a4e111
|
|
191
|
+
async function delay(ms, { signal }) {
|
|
192
|
+
return new Promise((resolve, reject) => {
|
|
193
|
+
if (signal) {
|
|
194
|
+
signal.throwIfAborted();
|
|
195
|
+
signal.addEventListener('abort', abortHandler, { once: true });
|
|
133
196
|
}
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
197
|
+
function abortHandler() {
|
|
198
|
+
clearTimeout(timeoutId);
|
|
199
|
+
reject(signal.reason);
|
|
200
|
+
}
|
|
201
|
+
const timeoutId = setTimeout(() => {
|
|
202
|
+
signal?.removeEventListener('abort', abortHandler);
|
|
203
|
+
resolve();
|
|
204
|
+
}, ms);
|
|
142
205
|
});
|
|
143
|
-
}
|
|
144
|
-
const delay = async (ms) => new Promise(resolve => {
|
|
145
|
-
setTimeout(resolve, ms);
|
|
146
|
-
});
|
|
206
|
+
}
|
|
147
207
|
|
|
148
208
|
class Ky {
|
|
209
|
+
static create(input, options) {
|
|
210
|
+
const ky = new Ky(input, options);
|
|
211
|
+
const fn = async () => {
|
|
212
|
+
if (typeof ky._options.timeout === 'number' && ky._options.timeout > maxSafeTimeout) {
|
|
213
|
+
throw new RangeError(`The \`timeout\` option cannot be greater than ${maxSafeTimeout}`);
|
|
214
|
+
}
|
|
215
|
+
// Delay the fetch so that body method shortcuts can set the Accept header
|
|
216
|
+
await Promise.resolve();
|
|
217
|
+
let response = await ky._fetch();
|
|
218
|
+
for (const hook of ky._options.hooks.afterResponse) {
|
|
219
|
+
// eslint-disable-next-line no-await-in-loop
|
|
220
|
+
const modifiedResponse = await hook(ky.request, ky._options, ky._decorateResponse(response.clone()));
|
|
221
|
+
if (modifiedResponse instanceof globalThis.Response) {
|
|
222
|
+
response = modifiedResponse;
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
ky._decorateResponse(response);
|
|
226
|
+
if (!response.ok && ky._options.throwHttpErrors) {
|
|
227
|
+
let error = new HTTPError(response, ky.request, ky._options);
|
|
228
|
+
for (const hook of ky._options.hooks.beforeError) {
|
|
229
|
+
// eslint-disable-next-line no-await-in-loop
|
|
230
|
+
error = await hook(error);
|
|
231
|
+
}
|
|
232
|
+
throw error;
|
|
233
|
+
}
|
|
234
|
+
// If `onDownloadProgress` is passed, it uses the stream API internally
|
|
235
|
+
/* istanbul ignore next */
|
|
236
|
+
if (ky._options.onDownloadProgress) {
|
|
237
|
+
if (typeof ky._options.onDownloadProgress !== 'function') {
|
|
238
|
+
throw new TypeError('The `onDownloadProgress` option must be a function');
|
|
239
|
+
}
|
|
240
|
+
if (!supportsResponseStreams) {
|
|
241
|
+
throw new Error('Streams are not supported in your environment. `ReadableStream` is missing.');
|
|
242
|
+
}
|
|
243
|
+
return ky._stream(response.clone(), ky._options.onDownloadProgress);
|
|
244
|
+
}
|
|
245
|
+
return response;
|
|
246
|
+
};
|
|
247
|
+
const isRetriableMethod = ky._options.retry.methods.includes(ky.request.method.toLowerCase());
|
|
248
|
+
const result = (isRetriableMethod ? ky._retry(fn) : fn());
|
|
249
|
+
for (const [type, mimeType] of Object.entries(responseTypes)) {
|
|
250
|
+
result[type] = async () => {
|
|
251
|
+
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
|
|
252
|
+
ky.request.headers.set('accept', ky.request.headers.get('accept') || mimeType);
|
|
253
|
+
const awaitedResult = await result;
|
|
254
|
+
const response = awaitedResult.clone();
|
|
255
|
+
if (type === 'json') {
|
|
256
|
+
if (response.status === 204) {
|
|
257
|
+
return '';
|
|
258
|
+
}
|
|
259
|
+
const arrayBuffer = await response.clone().arrayBuffer();
|
|
260
|
+
const responseSize = arrayBuffer.byteLength;
|
|
261
|
+
if (responseSize === 0) {
|
|
262
|
+
return '';
|
|
263
|
+
}
|
|
264
|
+
if (options.parseJson) {
|
|
265
|
+
return options.parseJson(await response.text());
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
return response[type]();
|
|
269
|
+
};
|
|
270
|
+
}
|
|
271
|
+
return result;
|
|
272
|
+
}
|
|
149
273
|
// eslint-disable-next-line complexity
|
|
150
274
|
constructor(input, options = {}) {
|
|
151
|
-
|
|
152
|
-
|
|
275
|
+
Object.defineProperty(this, "request", {
|
|
276
|
+
enumerable: true,
|
|
277
|
+
configurable: true,
|
|
278
|
+
writable: true,
|
|
279
|
+
value: void 0
|
|
280
|
+
});
|
|
281
|
+
Object.defineProperty(this, "abortController", {
|
|
282
|
+
enumerable: true,
|
|
283
|
+
configurable: true,
|
|
284
|
+
writable: true,
|
|
285
|
+
value: void 0
|
|
286
|
+
});
|
|
287
|
+
Object.defineProperty(this, "_retryCount", {
|
|
288
|
+
enumerable: true,
|
|
289
|
+
configurable: true,
|
|
290
|
+
writable: true,
|
|
291
|
+
value: 0
|
|
292
|
+
});
|
|
293
|
+
Object.defineProperty(this, "_input", {
|
|
294
|
+
enumerable: true,
|
|
295
|
+
configurable: true,
|
|
296
|
+
writable: true,
|
|
297
|
+
value: void 0
|
|
298
|
+
});
|
|
299
|
+
Object.defineProperty(this, "_options", {
|
|
300
|
+
enumerable: true,
|
|
301
|
+
configurable: true,
|
|
302
|
+
writable: true,
|
|
303
|
+
value: void 0
|
|
304
|
+
});
|
|
153
305
|
this._input = input;
|
|
154
306
|
this._options = {
|
|
155
307
|
// TODO: credentials can be removed when the spec change is implemented in all browsers. Context: https://www.chromestatus.com/feature/4539473312350208
|
|
@@ -162,13 +314,13 @@
|
|
|
162
314
|
beforeError: [],
|
|
163
315
|
afterResponse: [],
|
|
164
316
|
}, options.hooks),
|
|
165
|
-
method: normalizeRequestMethod(
|
|
317
|
+
method: normalizeRequestMethod(options.method ?? this._input.method),
|
|
166
318
|
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
|
|
167
319
|
prefixUrl: String(options.prefixUrl || ''),
|
|
168
320
|
retry: normalizeRetryOptions(options.retry),
|
|
169
321
|
throwHttpErrors: options.throwHttpErrors !== false,
|
|
170
|
-
timeout:
|
|
171
|
-
fetch:
|
|
322
|
+
timeout: options.timeout ?? 10000,
|
|
323
|
+
fetch: options.fetch ?? globalThis.fetch.bind(globalThis),
|
|
172
324
|
};
|
|
173
325
|
if (typeof this._input !== 'string' && !(this._input instanceof URL || this._input instanceof globalThis.Request)) {
|
|
174
326
|
throw new TypeError('`input` must be a string, URL, or Request');
|
|
@@ -185,12 +337,17 @@
|
|
|
185
337
|
if (supportsAbortController) {
|
|
186
338
|
this.abortController = new globalThis.AbortController();
|
|
187
339
|
if (this._options.signal) {
|
|
340
|
+
const originalSignal = this._options.signal;
|
|
188
341
|
this._options.signal.addEventListener('abort', () => {
|
|
189
|
-
this.abortController.abort();
|
|
342
|
+
this.abortController.abort(originalSignal.reason);
|
|
190
343
|
});
|
|
191
344
|
}
|
|
192
345
|
this._options.signal = this.abortController.signal;
|
|
193
346
|
}
|
|
347
|
+
if (supportsRequestStreams) {
|
|
348
|
+
// @ts-expect-error - Types are outdated.
|
|
349
|
+
this._options.duplex = 'half';
|
|
350
|
+
}
|
|
194
351
|
this.request = new globalThis.Request(this._input, this._options);
|
|
195
352
|
if (this._options.searchParams) {
|
|
196
353
|
// eslint-disable-next-line unicorn/prevent-abbreviations
|
|
@@ -205,74 +362,15 @@
|
|
|
205
362
|
|| this._options.body instanceof URLSearchParams) && !(this._options.headers && this._options.headers['content-type'])) {
|
|
206
363
|
this.request.headers.delete('content-type');
|
|
207
364
|
}
|
|
208
|
-
this.request
|
|
365
|
+
// The spread of `this.request` is required as otherwise it misses the `duplex` option for some reason and throws.
|
|
366
|
+
this.request = new globalThis.Request(new globalThis.Request(url, { ...this.request }), this._options);
|
|
209
367
|
}
|
|
210
368
|
if (this._options.json !== undefined) {
|
|
211
369
|
this._options.body = JSON.stringify(this._options.json);
|
|
212
|
-
this.request.headers.set('content-type',
|
|
370
|
+
this.request.headers.set('content-type', this._options.headers.get('content-type') ?? 'application/json');
|
|
213
371
|
this.request = new globalThis.Request(this.request, { body: this._options.body });
|
|
214
372
|
}
|
|
215
373
|
}
|
|
216
|
-
// eslint-disable-next-line @typescript-eslint/promise-function-async
|
|
217
|
-
static create(input, options) {
|
|
218
|
-
const ky = new Ky(input, options);
|
|
219
|
-
const fn = async () => {
|
|
220
|
-
if (ky._options.timeout > maxSafeTimeout) {
|
|
221
|
-
throw new RangeError(`The \`timeout\` option cannot be greater than ${maxSafeTimeout}`);
|
|
222
|
-
}
|
|
223
|
-
// Delay the fetch so that body method shortcuts can set the Accept header
|
|
224
|
-
await Promise.resolve();
|
|
225
|
-
let response = await ky._fetch();
|
|
226
|
-
for (const hook of ky._options.hooks.afterResponse) {
|
|
227
|
-
// eslint-disable-next-line no-await-in-loop
|
|
228
|
-
const modifiedResponse = await hook(ky.request, ky._options, ky._decorateResponse(response.clone()));
|
|
229
|
-
if (modifiedResponse instanceof globalThis.Response) {
|
|
230
|
-
response = modifiedResponse;
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
|
-
ky._decorateResponse(response);
|
|
234
|
-
if (!response.ok && ky._options.throwHttpErrors) {
|
|
235
|
-
let error = new HTTPError(response, ky.request, ky._options);
|
|
236
|
-
for (const hook of ky._options.hooks.beforeError) {
|
|
237
|
-
// eslint-disable-next-line no-await-in-loop
|
|
238
|
-
error = await hook(error);
|
|
239
|
-
}
|
|
240
|
-
throw error;
|
|
241
|
-
}
|
|
242
|
-
// If `onDownloadProgress` is passed, it uses the stream API internally
|
|
243
|
-
/* istanbul ignore next */
|
|
244
|
-
if (ky._options.onDownloadProgress) {
|
|
245
|
-
if (typeof ky._options.onDownloadProgress !== 'function') {
|
|
246
|
-
throw new TypeError('The `onDownloadProgress` option must be a function');
|
|
247
|
-
}
|
|
248
|
-
if (!supportsStreams) {
|
|
249
|
-
throw new Error('Streams are not supported in your environment. `ReadableStream` is missing.');
|
|
250
|
-
}
|
|
251
|
-
return ky._stream(response.clone(), ky._options.onDownloadProgress);
|
|
252
|
-
}
|
|
253
|
-
return response;
|
|
254
|
-
};
|
|
255
|
-
const isRetriableMethod = ky._options.retry.methods.includes(ky.request.method.toLowerCase());
|
|
256
|
-
const result = (isRetriableMethod ? ky._retry(fn) : fn());
|
|
257
|
-
for (const [type, mimeType] of Object.entries(responseTypes)) {
|
|
258
|
-
result[type] = async () => {
|
|
259
|
-
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
|
|
260
|
-
ky.request.headers.set('accept', ky.request.headers.get('accept') || mimeType);
|
|
261
|
-
const awaitedResult = await result;
|
|
262
|
-
const response = awaitedResult.clone();
|
|
263
|
-
if (type === 'json') {
|
|
264
|
-
if (response.status === 204) {
|
|
265
|
-
return '';
|
|
266
|
-
}
|
|
267
|
-
if (options.parseJson) {
|
|
268
|
-
return options.parseJson(await response.text());
|
|
269
|
-
}
|
|
270
|
-
}
|
|
271
|
-
return response[type]();
|
|
272
|
-
};
|
|
273
|
-
}
|
|
274
|
-
return result;
|
|
275
|
-
}
|
|
276
374
|
_calculateRetryDelay(error) {
|
|
277
375
|
this._retryCount++;
|
|
278
376
|
if (this._retryCount < this._options.retry.limit && !(error instanceof TimeoutError)) {
|
|
@@ -289,7 +387,7 @@
|
|
|
289
387
|
else {
|
|
290
388
|
after *= 1000;
|
|
291
389
|
}
|
|
292
|
-
if (
|
|
390
|
+
if (this._options.retry.maxRetryAfter !== undefined && after > this._options.retry.maxRetryAfter) {
|
|
293
391
|
return 0;
|
|
294
392
|
}
|
|
295
393
|
return after;
|
|
@@ -299,7 +397,7 @@
|
|
|
299
397
|
}
|
|
300
398
|
}
|
|
301
399
|
const BACKOFF_FACTOR = 0.3;
|
|
302
|
-
return BACKOFF_FACTOR * (2 ** (this._retryCount - 1)) * 1000;
|
|
400
|
+
return Math.min(this._options.retry.backoffLimit, BACKOFF_FACTOR * (2 ** (this._retryCount - 1)) * 1000);
|
|
303
401
|
}
|
|
304
402
|
return 0;
|
|
305
403
|
}
|
|
@@ -312,12 +410,11 @@
|
|
|
312
410
|
async _retry(fn) {
|
|
313
411
|
try {
|
|
314
412
|
return await fn();
|
|
315
|
-
// eslint-disable-next-line @typescript-eslint/no-implicit-any-catch
|
|
316
413
|
}
|
|
317
414
|
catch (error) {
|
|
318
415
|
const ms = Math.min(this._calculateRetryDelay(error), maxSafeTimeout);
|
|
319
416
|
if (ms !== 0 && this._retryCount > 0) {
|
|
320
|
-
await delay(ms);
|
|
417
|
+
await delay(ms, { signal: this._options.signal });
|
|
321
418
|
for (const hook of this._options.hooks.beforeRetry) {
|
|
322
419
|
// eslint-disable-next-line no-await-in-loop
|
|
323
420
|
const hookResult = await hook({
|
|
@@ -357,6 +454,16 @@
|
|
|
357
454
|
_stream(response, onDownloadProgress) {
|
|
358
455
|
const totalBytes = Number(response.headers.get('content-length')) || 0;
|
|
359
456
|
let transferredBytes = 0;
|
|
457
|
+
if (response.status === 204) {
|
|
458
|
+
if (onDownloadProgress) {
|
|
459
|
+
onDownloadProgress({ percent: 1, totalBytes, transferredBytes }, new Uint8Array());
|
|
460
|
+
}
|
|
461
|
+
return new globalThis.Response(null, {
|
|
462
|
+
status: response.status,
|
|
463
|
+
statusText: response.statusText,
|
|
464
|
+
headers: response.headers,
|
|
465
|
+
});
|
|
466
|
+
}
|
|
360
467
|
return new globalThis.Response(new globalThis.ReadableStream({
|
|
361
468
|
async start(controller) {
|
|
362
469
|
const reader = response.body.getReader();
|
|
@@ -379,7 +486,11 @@
|
|
|
379
486
|
}
|
|
380
487
|
await read();
|
|
381
488
|
},
|
|
382
|
-
})
|
|
489
|
+
}), {
|
|
490
|
+
status: response.status,
|
|
491
|
+
statusText: response.statusText,
|
|
492
|
+
headers: response.headers,
|
|
493
|
+
});
|
|
383
494
|
}
|
|
384
495
|
}
|
|
385
496
|
|
|
@@ -400,7 +511,7 @@
|
|
|
400
511
|
|
|
401
512
|
exports.HTTPError = HTTPError;
|
|
402
513
|
exports.TimeoutError = TimeoutError;
|
|
403
|
-
exports
|
|
514
|
+
exports.default = ky;
|
|
404
515
|
|
|
405
516
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
406
517
|
|
package/src/node.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
module.exports = require('./factory')({
|
|
2
2
|
MicrolinkError: require('whoops')('MicrolinkError'),
|
|
3
3
|
urlHttp: require('url-http/lightweight'),
|
|
4
|
-
got: require('got'),
|
|
4
|
+
got: require('got').extend({ headers: { 'user-agent': undefined } }),
|
|
5
5
|
flatten: require('flattie').flattie,
|
|
6
6
|
VERSION: require('../package.json').version
|
|
7
7
|
})
|