@naturalcycles/js-lib 14.156.0 → 14.157.1
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/dist/form.util.d.ts +9 -0
- package/dist/form.util.js +19 -0
- package/dist/http/fetcher.d.ts +1 -0
- package/dist/http/fetcher.js +85 -58
- package/dist/http/fetcher.model.d.ts +29 -10
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/promise/pTimeout.d.ts +2 -2
- package/dist-esm/form.util.js +14 -0
- package/dist-esm/http/fetcher.js +85 -60
- package/dist-esm/index.js +1 -0
- package/package.json +1 -2
- package/src/form.util.ts +17 -0
- package/src/http/fetcher.model.ts +38 -9
- package/src/http/fetcher.ts +96 -67
- package/src/index.ts +1 -0
- package/src/promise/pTimeout.ts +2 -2
package/dist-esm/http/fetcher.js
CHANGED
|
@@ -1,15 +1,24 @@
|
|
|
1
1
|
/// <reference lib="dom"/>
|
|
2
|
+
/// <reference lib="dom.iterable"/>
|
|
2
3
|
import { isServerSide } from '../env';
|
|
3
4
|
import { _anyToError, _anyToErrorObject, _errorLikeToErrorObject } from '../error/error.util';
|
|
4
5
|
import { HttpRequestError } from '../error/httpRequestError';
|
|
5
6
|
import { _clamp } from '../number/number.util';
|
|
6
7
|
import { _filterNullishValues, _filterUndefinedValues, _mapKeys, _merge, _omit, _pick, } from '../object/object.util';
|
|
7
8
|
import { pDelay } from '../promise/pDelay';
|
|
8
|
-
import { TimeoutError } from '../promise/pTimeout';
|
|
9
|
+
import { pTimeout, TimeoutError } from '../promise/pTimeout';
|
|
9
10
|
import { _jsonParse, _jsonParseIfPossible } from '../string/json.util';
|
|
10
11
|
import { _stringifyAny } from '../string/stringifyAny';
|
|
11
|
-
import { _since } from '../time/time.util';
|
|
12
|
+
import { _ms, _since } from '../time/time.util';
|
|
12
13
|
import { HTTP_METHODS } from './http.model';
|
|
14
|
+
const acceptByResponseType = {
|
|
15
|
+
text: 'text/plain',
|
|
16
|
+
json: 'application/json',
|
|
17
|
+
void: '*/*',
|
|
18
|
+
readableStream: 'application/octet-stream',
|
|
19
|
+
arrayBuffer: 'application/octet-stream',
|
|
20
|
+
blob: 'application/octet-stream',
|
|
21
|
+
};
|
|
13
22
|
const defRetryOptions = {
|
|
14
23
|
count: 2,
|
|
15
24
|
timeout: 1000,
|
|
@@ -31,18 +40,18 @@ export class Fetcher {
|
|
|
31
40
|
const m = method.toLowerCase();
|
|
32
41
|
this[`${m}Void`] = async (url, opt) => {
|
|
33
42
|
return await this.fetch(Object.assign({ url,
|
|
34
|
-
method,
|
|
43
|
+
method, responseType: 'void' }, opt));
|
|
35
44
|
};
|
|
36
45
|
if (method === 'HEAD')
|
|
37
|
-
return //
|
|
46
|
+
return // responseType=text
|
|
38
47
|
;
|
|
39
48
|
this[`${m}Text`] = async (url, opt) => {
|
|
40
49
|
return await this.fetch(Object.assign({ url,
|
|
41
|
-
method,
|
|
50
|
+
method, responseType: 'text' }, opt));
|
|
42
51
|
};
|
|
43
52
|
this[m] = async (url, opt) => {
|
|
44
53
|
return await this.fetch(Object.assign({ url,
|
|
45
|
-
method,
|
|
54
|
+
method, responseType: 'json' }, opt));
|
|
46
55
|
};
|
|
47
56
|
});
|
|
48
57
|
}
|
|
@@ -70,7 +79,7 @@ export class Fetcher {
|
|
|
70
79
|
static create(cfg = {}) {
|
|
71
80
|
return new Fetcher(cfg);
|
|
72
81
|
}
|
|
73
|
-
//
|
|
82
|
+
// responseType=readableStream
|
|
74
83
|
/**
|
|
75
84
|
* Returns raw fetchResponse.body, which is a ReadableStream<Uint8Array>
|
|
76
85
|
*
|
|
@@ -78,7 +87,7 @@ export class Fetcher {
|
|
|
78
87
|
* https://css-tricks.com/web-streams-everywhere-and-fetch-for-node-js/
|
|
79
88
|
*/
|
|
80
89
|
async getReadableStream(url, opt) {
|
|
81
|
-
return await this.fetch(Object.assign({ url,
|
|
90
|
+
return await this.fetch(Object.assign({ url, responseType: 'readableStream' }, opt));
|
|
82
91
|
}
|
|
83
92
|
async fetch(opt) {
|
|
84
93
|
const res = await this.doFetch(opt);
|
|
@@ -97,19 +106,6 @@ export class Fetcher {
|
|
|
97
106
|
const req = this.normalizeOptions(opt);
|
|
98
107
|
const { logger } = this.cfg;
|
|
99
108
|
const { timeoutSeconds, init: { method }, } = req;
|
|
100
|
-
// setup timeout
|
|
101
|
-
let timeout;
|
|
102
|
-
if (timeoutSeconds) {
|
|
103
|
-
const abortController = new AbortController();
|
|
104
|
-
req.init.signal = abortController.signal;
|
|
105
|
-
timeout = setTimeout(() => {
|
|
106
|
-
// Apparently, providing a `string` reason to abort() causes Undici to throw `invalid_argument` error,
|
|
107
|
-
// so, we're wrapping it in a TimeoutError instance
|
|
108
|
-
abortController.abort(new TimeoutError(`request timed out after ${timeoutSeconds} sec`));
|
|
109
|
-
// abortController.abort(`timeout of ${timeoutSeconds} sec`)
|
|
110
|
-
// abortController.abort()
|
|
111
|
-
}, timeoutSeconds * 1000);
|
|
112
|
-
}
|
|
113
109
|
for (const hook of this.cfg.hooks.beforeRequest || []) {
|
|
114
110
|
await hook(req);
|
|
115
111
|
}
|
|
@@ -128,6 +124,18 @@ export class Fetcher {
|
|
|
128
124
|
};
|
|
129
125
|
while (!res.retryStatus.retryStopped) {
|
|
130
126
|
req.started = Date.now();
|
|
127
|
+
// setup timeout
|
|
128
|
+
let timeoutId;
|
|
129
|
+
if (timeoutSeconds) {
|
|
130
|
+
const abortController = new AbortController();
|
|
131
|
+
req.init.signal = abortController.signal;
|
|
132
|
+
timeoutId = setTimeout(() => {
|
|
133
|
+
// console.log(`actual request timed out in ${_since(req.started)}`)
|
|
134
|
+
// Apparently, providing a `string` reason to abort() causes Undici to throw `invalid_argument` error,
|
|
135
|
+
// so, we're wrapping it in a TimeoutError instance
|
|
136
|
+
abortController.abort(new TimeoutError(`request timed out after ${timeoutSeconds} sec`));
|
|
137
|
+
}, timeoutSeconds * 1000);
|
|
138
|
+
}
|
|
131
139
|
if (this.cfg.logRequest) {
|
|
132
140
|
const { retryAttempt } = res.retryStatus;
|
|
133
141
|
logger.log([' >>', signature, retryAttempt && `try#${retryAttempt + 1}/${req.retry.count + 1}`]
|
|
@@ -151,14 +159,30 @@ export class Fetcher {
|
|
|
151
159
|
// important to set it to undefined, otherwise it can keep the previous value (from previous try)
|
|
152
160
|
res.fetchResponse = undefined;
|
|
153
161
|
}
|
|
162
|
+
finally {
|
|
163
|
+
clearTimeout(timeoutId);
|
|
164
|
+
// Separate Timeout will be introduced to "download and parse the body"
|
|
165
|
+
}
|
|
154
166
|
res.statusFamily = this.getStatusFamily(res);
|
|
155
167
|
res.statusCode = (_a = res.fetchResponse) === null || _a === void 0 ? void 0 : _a.status;
|
|
156
168
|
if ((_b = res.fetchResponse) === null || _b === void 0 ? void 0 : _b.ok) {
|
|
157
|
-
|
|
169
|
+
try {
|
|
170
|
+
// We are applying a separate Timeout (as long as original Timeout for now) to "download and parse the body"
|
|
171
|
+
await pTimeout(async () => await this.onOkResponse(res), {
|
|
172
|
+
timeout: timeoutSeconds * 1000 || Number.POSITIVE_INFINITY,
|
|
173
|
+
name: 'Fetcher.onOkResponse',
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
catch (err) {
|
|
177
|
+
// onOkResponse can still fail, e.g when loading/parsing json, text or doing other response manipulation
|
|
178
|
+
res.err = _anyToError(err);
|
|
179
|
+
res.ok = false;
|
|
180
|
+
await this.onNotOkResponse(res);
|
|
181
|
+
}
|
|
158
182
|
}
|
|
159
183
|
else {
|
|
160
184
|
// !res.ok
|
|
161
|
-
await this.onNotOkResponse(res
|
|
185
|
+
await this.onNotOkResponse(res);
|
|
162
186
|
}
|
|
163
187
|
}
|
|
164
188
|
for (const hook of this.cfg.hooks.afterResponse || []) {
|
|
@@ -166,31 +190,17 @@ export class Fetcher {
|
|
|
166
190
|
}
|
|
167
191
|
return res;
|
|
168
192
|
}
|
|
169
|
-
async onOkResponse(res
|
|
193
|
+
async onOkResponse(res) {
|
|
170
194
|
const { req } = res;
|
|
171
|
-
const {
|
|
172
|
-
|
|
195
|
+
const { responseType } = res.req;
|
|
196
|
+
// This function is subject to a separate timeout to "download and parse the data"
|
|
197
|
+
if (responseType === 'json') {
|
|
173
198
|
if (res.fetchResponse.body) {
|
|
174
199
|
const text = await res.fetchResponse.text();
|
|
175
200
|
if (text) {
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
}
|
|
180
|
-
catch (err) {
|
|
181
|
-
// Error while parsing json
|
|
182
|
-
// res.err = _anyToError(err, HttpRequestError, {
|
|
183
|
-
// requestUrl: res.req.url,
|
|
184
|
-
// requestBaseUrl: this.cfg.baseUrl,
|
|
185
|
-
// requestMethod: res.req.init.method,
|
|
186
|
-
// requestSignature: res.signature,
|
|
187
|
-
// requestDuration: Date.now() - started,
|
|
188
|
-
// responseStatusCode: res.fetchResponse.status,
|
|
189
|
-
// } satisfies HttpRequestErrorData)
|
|
190
|
-
res.err = _anyToError(err);
|
|
191
|
-
res.ok = false;
|
|
192
|
-
return await this.onNotOkResponse(res, timeout);
|
|
193
|
-
}
|
|
201
|
+
res.body = text;
|
|
202
|
+
res.body = _jsonParse(text, req.jsonReviver);
|
|
203
|
+
// Error while parsing json can happen - it'll be handled upstream
|
|
194
204
|
}
|
|
195
205
|
else {
|
|
196
206
|
// Body had a '' (empty string)
|
|
@@ -203,24 +213,22 @@ export class Fetcher {
|
|
|
203
213
|
res.body = {};
|
|
204
214
|
}
|
|
205
215
|
}
|
|
206
|
-
else if (
|
|
216
|
+
else if (responseType === 'text') {
|
|
207
217
|
res.body = res.fetchResponse.body ? await res.fetchResponse.text() : '';
|
|
208
218
|
}
|
|
209
|
-
else if (
|
|
219
|
+
else if (responseType === 'arrayBuffer') {
|
|
210
220
|
res.body = res.fetchResponse.body ? await res.fetchResponse.arrayBuffer() : {};
|
|
211
221
|
}
|
|
212
|
-
else if (
|
|
222
|
+
else if (responseType === 'blob') {
|
|
213
223
|
res.body = res.fetchResponse.body ? await res.fetchResponse.blob() : {};
|
|
214
224
|
}
|
|
215
|
-
else if (
|
|
225
|
+
else if (responseType === 'readableStream') {
|
|
216
226
|
res.body = res.fetchResponse.body;
|
|
217
227
|
if (res.body === null) {
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
return await this.onNotOkResponse(res, timeout);
|
|
228
|
+
// Error is to be handled upstream
|
|
229
|
+
throw new Error(`fetchResponse.body is null`);
|
|
221
230
|
}
|
|
222
231
|
}
|
|
223
|
-
clearTimeout(timeout);
|
|
224
232
|
res.retryStatus.retryStopped = true;
|
|
225
233
|
// res.err can happen on `failed to fetch` type of error, e.g JSON.parse, CORS, unexpected redirect
|
|
226
234
|
if (!res.err && this.cfg.logResponse) {
|
|
@@ -246,9 +254,8 @@ export class Fetcher {
|
|
|
246
254
|
async callNativeFetch(url, init) {
|
|
247
255
|
return await globalThis.fetch(url, init);
|
|
248
256
|
}
|
|
249
|
-
async onNotOkResponse(res
|
|
257
|
+
async onNotOkResponse(res) {
|
|
250
258
|
var _a, _b;
|
|
251
|
-
clearTimeout(timeout);
|
|
252
259
|
let cause;
|
|
253
260
|
if (res.err) {
|
|
254
261
|
// This is only possible on JSON.parse error, or CORS error,
|
|
@@ -315,7 +322,11 @@ export class Fetcher {
|
|
|
315
322
|
return;
|
|
316
323
|
retryStatus.retryAttempt++;
|
|
317
324
|
retryStatus.retryTimeout = _clamp(retryStatus.retryTimeout * timeoutMultiplier, 0, timeoutMax);
|
|
318
|
-
|
|
325
|
+
const timeout = this.getRetryTimeout(res);
|
|
326
|
+
if (res.req.debug) {
|
|
327
|
+
this.cfg.logger.log(` .. ${res.signature} waiting ${_ms(timeout)}`);
|
|
328
|
+
}
|
|
329
|
+
await pDelay(timeout);
|
|
319
330
|
}
|
|
320
331
|
getRetryTimeout(res) {
|
|
321
332
|
var _a;
|
|
@@ -371,8 +382,9 @@ export class Fetcher {
|
|
|
371
382
|
if (statusFamily === 3 && !retry3xx)
|
|
372
383
|
return false;
|
|
373
384
|
// should not retry on `unexpected redirect` in error.cause.cause
|
|
374
|
-
if ((_e = (_d = (_c = (_b = res.err) === null || _b === void 0 ? void 0 : _b.cause) === null || _c === void 0 ? void 0 : _c.cause) === null || _d === void 0 ? void 0 : _d.message) === null || _e === void 0 ? void 0 : _e.includes('unexpected redirect'))
|
|
385
|
+
if ((_e = (_d = (_c = (_b = res.err) === null || _b === void 0 ? void 0 : _b.cause) === null || _c === void 0 ? void 0 : _c.cause) === null || _d === void 0 ? void 0 : _d.message) === null || _e === void 0 ? void 0 : _e.includes('unexpected redirect')) {
|
|
375
386
|
return false;
|
|
387
|
+
}
|
|
376
388
|
return true; // default is true
|
|
377
389
|
}
|
|
378
390
|
getStatusFamily(res) {
|
|
@@ -412,14 +424,14 @@ export class Fetcher {
|
|
|
412
424
|
normalizeCfg(cfg) {
|
|
413
425
|
var _a;
|
|
414
426
|
if ((_a = cfg.baseUrl) === null || _a === void 0 ? void 0 : _a.endsWith('/')) {
|
|
415
|
-
console.warn(`Fetcher: baseUrl should not end with
|
|
427
|
+
console.warn(`Fetcher: baseUrl should not end with slash: ${cfg.baseUrl}`);
|
|
416
428
|
cfg.baseUrl = cfg.baseUrl.slice(0, cfg.baseUrl.length - 1);
|
|
417
429
|
}
|
|
418
430
|
const { debug = false } = cfg;
|
|
419
431
|
const norm = _merge({
|
|
420
432
|
baseUrl: '',
|
|
421
433
|
inputUrl: '',
|
|
422
|
-
|
|
434
|
+
responseType: 'void',
|
|
423
435
|
searchParams: {},
|
|
424
436
|
timeoutSeconds: 30,
|
|
425
437
|
retryPost: false,
|
|
@@ -438,7 +450,7 @@ export class Fetcher {
|
|
|
438
450
|
retry: Object.assign({}, defRetryOptions),
|
|
439
451
|
init: {
|
|
440
452
|
method: cfg.method || 'GET',
|
|
441
|
-
headers:
|
|
453
|
+
headers: Object.assign({ 'user-agent': 'fetcher' }, cfg.headers),
|
|
442
454
|
credentials: cfg.credentials,
|
|
443
455
|
redirect: cfg.redirect,
|
|
444
456
|
},
|
|
@@ -448,17 +460,19 @@ export class Fetcher {
|
|
|
448
460
|
return norm;
|
|
449
461
|
}
|
|
450
462
|
normalizeOptions(opt) {
|
|
463
|
+
var _a;
|
|
451
464
|
const req = Object.assign(Object.assign(Object.assign(Object.assign({}, _pick(this.cfg, [
|
|
452
465
|
'timeoutSeconds',
|
|
453
466
|
'retryPost',
|
|
454
467
|
'retry4xx',
|
|
455
468
|
'retry5xx',
|
|
456
|
-
'
|
|
469
|
+
'responseType',
|
|
457
470
|
'jsonReviver',
|
|
458
471
|
'logRequest',
|
|
459
472
|
'logRequestBody',
|
|
460
473
|
'logResponse',
|
|
461
474
|
'logResponseBody',
|
|
475
|
+
'debug',
|
|
462
476
|
])), { started: Date.now() }), _omit(opt, ['method', 'headers', 'credentials'])), { inputUrl: opt.url || '', fullUrl: opt.url || '', retry: Object.assign(Object.assign({}, this.cfg.retry), _filterUndefinedValues(opt.retry || {})), init: _merge(Object.assign(Object.assign({}, this.cfg.init), { method: opt.method || this.cfg.init.method, credentials: opt.credentials || this.cfg.init.credentials, redirect: opt.redirect || this.cfg.init.redirect || 'follow' }), {
|
|
463
477
|
headers: _mapKeys(opt.headers || {}, k => k.toLowerCase()),
|
|
464
478
|
}) });
|
|
@@ -485,9 +499,20 @@ export class Fetcher {
|
|
|
485
499
|
req.init.body = opt.text;
|
|
486
500
|
req.init.headers['content-type'] = 'text/plain';
|
|
487
501
|
}
|
|
502
|
+
else if (opt.form) {
|
|
503
|
+
if (opt.form instanceof URLSearchParams || opt.form instanceof FormData) {
|
|
504
|
+
req.init.body = opt.form;
|
|
505
|
+
}
|
|
506
|
+
else {
|
|
507
|
+
req.init.body = new URLSearchParams(opt.form);
|
|
508
|
+
}
|
|
509
|
+
req.init.headers['content-type'] = 'application/x-www-form-urlencoded';
|
|
510
|
+
}
|
|
488
511
|
else if (opt.body !== undefined) {
|
|
489
512
|
req.init.body = opt.body;
|
|
490
513
|
}
|
|
514
|
+
// Unless `accept` header was already set - set it based on responseType
|
|
515
|
+
(_a = req.init.headers)['accept'] || (_a['accept'] = acceptByResponseType[req.responseType]);
|
|
491
516
|
return req;
|
|
492
517
|
}
|
|
493
518
|
}
|
package/dist-esm/index.js
CHANGED
|
@@ -80,6 +80,7 @@ export * from './http/fetcher';
|
|
|
80
80
|
export * from './http/fetcher.model';
|
|
81
81
|
export * from './string/hash.util';
|
|
82
82
|
export * from './env/buildInfo';
|
|
83
|
+
export * from './form.util';
|
|
83
84
|
export * from './zod/zod.util';
|
|
84
85
|
export * from './zod/zod.shared.schemas';
|
|
85
86
|
import { z, ZodSchema, ZodError } from 'zod';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@naturalcycles/js-lib",
|
|
3
|
-
"version": "14.
|
|
3
|
+
"version": "14.157.1",
|
|
4
4
|
"scripts": {
|
|
5
5
|
"prepare": "husky install",
|
|
6
6
|
"build-prod": "build-prod-esm-cjs",
|
|
@@ -21,7 +21,6 @@
|
|
|
21
21
|
"crypto-js": "^4.1.1",
|
|
22
22
|
"jest": "^29.0.0",
|
|
23
23
|
"prettier": "^3.0.0",
|
|
24
|
-
"rxjs": "^7.0.1",
|
|
25
24
|
"vuepress": "^1.7.1",
|
|
26
25
|
"vuepress-plugin-typescript": "^0.3.1"
|
|
27
26
|
},
|
package/src/form.util.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { AnyObject } from './types'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Convert any object to FormData.
|
|
5
|
+
* Please note that every key and value of FormData is `string`.
|
|
6
|
+
* Even if you pass a number - it'll be converted to string.
|
|
7
|
+
* Think URLSearchParams.
|
|
8
|
+
*/
|
|
9
|
+
export function objectToFormData(obj: AnyObject = {}): FormData {
|
|
10
|
+
const fd = new FormData()
|
|
11
|
+
Object.entries(obj).forEach(([k, v]) => fd.append(k, v))
|
|
12
|
+
return fd
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function formDataToObject<T extends AnyObject>(formData: FormData): T {
|
|
16
|
+
return Object.fromEntries(formData) as T
|
|
17
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { CommonLogger } from '../log/commonLogger'
|
|
2
2
|
import type { Promisable } from '../typeFest'
|
|
3
|
-
import type { Reviver, UnixTimestampMillisNumber } from '../types'
|
|
3
|
+
import type { AnyObject, NumberOfMilliseconds, Reviver, UnixTimestampMillisNumber } from '../types'
|
|
4
4
|
import type { HttpMethod, HttpStatusFamily } from './http.model'
|
|
5
5
|
|
|
6
6
|
export interface FetcherNormalizedCfg
|
|
@@ -13,6 +13,7 @@ export interface FetcherNormalizedCfg
|
|
|
13
13
|
| 'logRequestBody'
|
|
14
14
|
| 'logResponse'
|
|
15
15
|
| 'logResponseBody'
|
|
16
|
+
| 'debug'
|
|
16
17
|
| 'redirect'
|
|
17
18
|
| 'credentials'
|
|
18
19
|
> {
|
|
@@ -93,14 +94,14 @@ export interface FetcherCfg {
|
|
|
93
94
|
|
|
94
95
|
export interface FetcherRetryStatus {
|
|
95
96
|
retryAttempt: number
|
|
96
|
-
retryTimeout:
|
|
97
|
+
retryTimeout: NumberOfMilliseconds
|
|
97
98
|
retryStopped: boolean
|
|
98
99
|
}
|
|
99
100
|
|
|
100
101
|
export interface FetcherRetryOptions {
|
|
101
102
|
count: number
|
|
102
|
-
timeout:
|
|
103
|
-
timeoutMax:
|
|
103
|
+
timeout: NumberOfMilliseconds
|
|
104
|
+
timeoutMax: NumberOfMilliseconds
|
|
104
105
|
timeoutMultiplier: number
|
|
105
106
|
}
|
|
106
107
|
|
|
@@ -116,7 +117,7 @@ export interface FetcherRequest
|
|
|
116
117
|
*/
|
|
117
118
|
fullUrl: string
|
|
118
119
|
init: RequestInitNormalized
|
|
119
|
-
|
|
120
|
+
responseType: FetcherResponseType
|
|
120
121
|
timeoutSeconds: number
|
|
121
122
|
retry: FetcherRetryOptions
|
|
122
123
|
retryPost: boolean
|
|
@@ -145,8 +146,6 @@ export interface FetcherOptions {
|
|
|
145
146
|
*/
|
|
146
147
|
timeoutSeconds?: number
|
|
147
148
|
|
|
148
|
-
json?: any
|
|
149
|
-
text?: string
|
|
150
149
|
/**
|
|
151
150
|
* Supports all the types that RequestInit.body supports.
|
|
152
151
|
*
|
|
@@ -154,6 +153,26 @@ export interface FetcherOptions {
|
|
|
154
153
|
*/
|
|
155
154
|
body?: Blob | BufferSource | FormData | URLSearchParams | string
|
|
156
155
|
|
|
156
|
+
/**
|
|
157
|
+
* Same as `body`, but also conveniently sets the
|
|
158
|
+
* Content-Type header to `text/plain`
|
|
159
|
+
*/
|
|
160
|
+
text?: string
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Same as `body`, but:
|
|
164
|
+
* 1. JSON.stringifies the passed variable
|
|
165
|
+
* 2. Conveniently sets the Content-Type header to `application/json`
|
|
166
|
+
*/
|
|
167
|
+
json?: any
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Same as `body`, but:
|
|
171
|
+
* 1. Transforms the passed plain js object into URLSearchParams and passes it to `body`
|
|
172
|
+
* 2. Conveniently sets the Content-Type header to `application/x-www-form-urlencoded`
|
|
173
|
+
*/
|
|
174
|
+
form?: FormData | URLSearchParams | AnyObject
|
|
175
|
+
|
|
157
176
|
credentials?: RequestCredentials
|
|
158
177
|
/**
|
|
159
178
|
* Default to 'follow'.
|
|
@@ -167,7 +186,7 @@ export interface FetcherOptions {
|
|
|
167
186
|
// init?: Partial<RequestInitNormalized>
|
|
168
187
|
|
|
169
188
|
headers?: Record<string, any>
|
|
170
|
-
|
|
189
|
+
responseType?: FetcherResponseType // default to 'void'
|
|
171
190
|
|
|
172
191
|
searchParams?: Record<string, any>
|
|
173
192
|
|
|
@@ -201,6 +220,10 @@ export interface FetcherOptions {
|
|
|
201
220
|
logRequestBody?: boolean
|
|
202
221
|
logResponse?: boolean
|
|
203
222
|
logResponseBody?: boolean
|
|
223
|
+
/**
|
|
224
|
+
* If true - enables all possible logging.
|
|
225
|
+
*/
|
|
226
|
+
debug?: boolean
|
|
204
227
|
}
|
|
205
228
|
|
|
206
229
|
export type RequestInitNormalized = Omit<RequestInit, 'method' | 'headers'> & {
|
|
@@ -236,4 +259,10 @@ export type FetcherResponse<BODY = unknown> =
|
|
|
236
259
|
| FetcherSuccessResponse<BODY>
|
|
237
260
|
| FetcherErrorResponse<BODY>
|
|
238
261
|
|
|
239
|
-
export type
|
|
262
|
+
export type FetcherResponseType =
|
|
263
|
+
| 'json'
|
|
264
|
+
| 'text'
|
|
265
|
+
| 'void'
|
|
266
|
+
| 'arrayBuffer'
|
|
267
|
+
| 'blob'
|
|
268
|
+
| 'readableStream'
|