@naturalcycles/js-lib 14.144.1 → 14.146.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/dist/array/array.util.js +2 -2
- package/dist/datetime/localDate.js +0 -1
- package/dist/datetime/localTime.js +0 -1
- package/dist/decorators/createPromiseDecorator.js +0 -1
- package/dist/http/fetcher.d.ts +27 -19
- package/dist/http/fetcher.js +60 -13
- package/dist/http/fetcher.model.d.ts +21 -8
- package/dist/object/object.util.js +0 -1
- package/dist/object/sortObjectDeep.js +0 -1
- package/dist/promise/abortable.d.ts +2 -2
- package/dist/promise/pMap.js +1 -1
- package/dist/string/leven.js +0 -1
- package/dist/string/string.util.js +0 -1
- package/dist/vendor/is.d.ts +1 -1
- package/dist/vendor/is.js +1 -7
- package/dist-esm/array/array.util.js +2 -2
- package/dist-esm/datetime/localDate.js +0 -1
- package/dist-esm/datetime/localTime.js +0 -1
- package/dist-esm/decorators/createPromiseDecorator.js +0 -1
- package/dist-esm/http/fetcher.js +61 -71
- package/dist-esm/object/object.util.js +0 -1
- package/dist-esm/object/sortObjectDeep.js +0 -1
- package/dist-esm/promise/pMap.js +15 -34
- package/dist-esm/string/leven.js +0 -1
- package/dist-esm/string/string.util.js +0 -1
- package/dist-esm/vendor/is.js +1 -7
- package/package.json +1 -1
- package/src/array/array.util.ts +2 -2
- package/src/datetime/localDate.ts +0 -2
- package/src/datetime/localTime.ts +0 -2
- package/src/decorators/createPromiseDecorator.ts +1 -1
- package/src/http/fetcher.model.ts +31 -8
- package/src/http/fetcher.ts +98 -46
- package/src/json-schema/jsonSchema.model.ts +0 -1
- package/src/object/object.util.ts +0 -1
- package/src/object/sortObjectDeep.ts +0 -1
- package/src/promise/pMap.ts +1 -1
- package/src/string/leven.ts +1 -1
- package/src/string/string.util.ts +0 -2
- package/src/vendor/is.ts +7 -10
package/dist-esm/http/fetcher.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
/// <reference lib="dom"/>
|
|
2
|
-
import { __asyncValues } from "tslib";
|
|
3
2
|
import { isServerSide } from '../env';
|
|
4
3
|
import { _anyToError, _anyToErrorObject, _errorToErrorObject } from '../error/error.util';
|
|
5
4
|
import { HttpRequestError } from '../error/httpRequestError';
|
|
@@ -66,6 +65,16 @@ export class Fetcher {
|
|
|
66
65
|
static create(cfg = {}) {
|
|
67
66
|
return new Fetcher(cfg);
|
|
68
67
|
}
|
|
68
|
+
// mode=readableStream
|
|
69
|
+
/**
|
|
70
|
+
* Returns raw fetchResponse.body, which is a ReadableStream<Uint8Array>
|
|
71
|
+
*
|
|
72
|
+
* More on streams and Node interop:
|
|
73
|
+
* https://css-tricks.com/web-streams-everywhere-and-fetch-for-node-js/
|
|
74
|
+
*/
|
|
75
|
+
async getReadableStream(url, opt) {
|
|
76
|
+
return await this.fetch(url, Object.assign({ mode: 'readableStream' }, opt));
|
|
77
|
+
}
|
|
69
78
|
async fetch(url, opt) {
|
|
70
79
|
const res = await this.doFetch(url, opt);
|
|
71
80
|
if (res.err) {
|
|
@@ -80,11 +89,13 @@ export class Fetcher {
|
|
|
80
89
|
* Never throws, returns `err` property in the response instead.
|
|
81
90
|
* Use this method instead of `throwHttpErrors: false` or try-catching.
|
|
82
91
|
*/
|
|
83
|
-
async doFetch(url,
|
|
84
|
-
|
|
85
|
-
|
|
92
|
+
async doFetch(url, opt = {}) {
|
|
93
|
+
const req = this.normalizeOptions(url, opt);
|
|
94
|
+
return await this.doFetchRequest(req);
|
|
95
|
+
}
|
|
96
|
+
async doFetchRequest(req) {
|
|
97
|
+
var _a;
|
|
86
98
|
const { logger } = this.cfg;
|
|
87
|
-
const req = this.normalizeOptions(url, rawOpt);
|
|
88
99
|
const { timeoutSeconds, init: { method }, } = req;
|
|
89
100
|
// setup timeout
|
|
90
101
|
let timeout;
|
|
@@ -95,25 +106,8 @@ export class Fetcher {
|
|
|
95
106
|
abortController.abort(`timeout of ${timeoutSeconds} sec`);
|
|
96
107
|
}, timeoutSeconds * 1000);
|
|
97
108
|
}
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
_c = _k.value;
|
|
101
|
-
_h = false;
|
|
102
|
-
try {
|
|
103
|
-
const hook = _c;
|
|
104
|
-
await hook(req);
|
|
105
|
-
}
|
|
106
|
-
finally {
|
|
107
|
-
_h = true;
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
catch (e_1_1) { e_1 = { error: e_1_1 }; }
|
|
112
|
-
finally {
|
|
113
|
-
try {
|
|
114
|
-
if (!_h && !_a && (_b = _j.return)) await _b.call(_j);
|
|
115
|
-
}
|
|
116
|
-
finally { if (e_1) throw e_1.error; }
|
|
109
|
+
for (const hook of this.cfg.hooks.beforeRequest || []) {
|
|
110
|
+
await hook(req);
|
|
117
111
|
}
|
|
118
112
|
const isFullUrl = req.url.includes('://');
|
|
119
113
|
const fullUrl = isFullUrl ? new URL(req.url) : undefined;
|
|
@@ -129,7 +123,7 @@ export class Fetcher {
|
|
|
129
123
|
signature,
|
|
130
124
|
};
|
|
131
125
|
while (!res.retryStatus.retryStopped) {
|
|
132
|
-
|
|
126
|
+
req.started = Date.now();
|
|
133
127
|
if (this.cfg.logRequest) {
|
|
134
128
|
const { retryAttempt } = res.retryStatus;
|
|
135
129
|
logger.log([' >>', signature, retryAttempt && `try#${retryAttempt + 1}/${req.retry.count + 1}`]
|
|
@@ -151,37 +145,26 @@ export class Fetcher {
|
|
|
151
145
|
res.fetchResponse = undefined;
|
|
152
146
|
}
|
|
153
147
|
res.statusFamily = this.getStatusFamily(res);
|
|
154
|
-
if ((
|
|
155
|
-
await this.onOkResponse(res,
|
|
148
|
+
if ((_a = res.fetchResponse) === null || _a === void 0 ? void 0 : _a.ok) {
|
|
149
|
+
await this.onOkResponse(res, timeout);
|
|
156
150
|
}
|
|
157
151
|
else {
|
|
158
152
|
// !res.ok
|
|
159
|
-
await this.onNotOkResponse(res,
|
|
153
|
+
await this.onNotOkResponse(res, timeout);
|
|
160
154
|
}
|
|
161
155
|
}
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
_f = _o.value;
|
|
165
|
-
_l = false;
|
|
166
|
-
try {
|
|
167
|
-
const hook = _f;
|
|
168
|
-
await hook(res);
|
|
169
|
-
}
|
|
170
|
-
finally {
|
|
171
|
-
_l = true;
|
|
172
|
-
}
|
|
173
|
-
}
|
|
156
|
+
for (const hook of this.cfg.hooks.afterResponse || []) {
|
|
157
|
+
await hook(res);
|
|
174
158
|
}
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
159
|
+
if (req.paginate && res.ok) {
|
|
160
|
+
const proceed = await req.paginate(req, res);
|
|
161
|
+
if (proceed) {
|
|
162
|
+
return await this.doFetchRequest(req);
|
|
179
163
|
}
|
|
180
|
-
finally { if (e_2) throw e_2.error; }
|
|
181
164
|
}
|
|
182
165
|
return res;
|
|
183
166
|
}
|
|
184
|
-
async onOkResponse(res,
|
|
167
|
+
async onOkResponse(res, timeout) {
|
|
185
168
|
const { req } = res;
|
|
186
169
|
const { mode } = res.req;
|
|
187
170
|
if (mode === 'json') {
|
|
@@ -204,7 +187,7 @@ export class Fetcher {
|
|
|
204
187
|
// } satisfies HttpRequestErrorData)
|
|
205
188
|
res.err = _anyToError(err);
|
|
206
189
|
res.ok = false;
|
|
207
|
-
return await this.onNotOkResponse(res,
|
|
190
|
+
return await this.onNotOkResponse(res, timeout);
|
|
208
191
|
}
|
|
209
192
|
}
|
|
210
193
|
else {
|
|
@@ -227,6 +210,14 @@ export class Fetcher {
|
|
|
227
210
|
else if (mode === 'blob') {
|
|
228
211
|
res.body = res.fetchResponse.body ? await res.fetchResponse.blob() : {};
|
|
229
212
|
}
|
|
213
|
+
else if (mode === 'readableStream') {
|
|
214
|
+
res.body = res.fetchResponse.body;
|
|
215
|
+
if (res.body === null) {
|
|
216
|
+
res.err = new Error(`fetchResponse.body is null`);
|
|
217
|
+
res.ok = false;
|
|
218
|
+
return await this.onNotOkResponse(res, timeout);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
230
221
|
clearTimeout(timeout);
|
|
231
222
|
res.retryStatus.retryStopped = true;
|
|
232
223
|
// res.err can happen on JSON.parse error
|
|
@@ -238,7 +229,7 @@ export class Fetcher {
|
|
|
238
229
|
res.fetchResponse.status,
|
|
239
230
|
res.signature,
|
|
240
231
|
retryAttempt && `try#${retryAttempt + 1}/${req.retry.count + 1}`,
|
|
241
|
-
_since(started),
|
|
232
|
+
_since(res.req.started),
|
|
242
233
|
]
|
|
243
234
|
.filter(Boolean)
|
|
244
235
|
.join(' '));
|
|
@@ -253,7 +244,7 @@ export class Fetcher {
|
|
|
253
244
|
async callNativeFetch(url, init) {
|
|
254
245
|
return await globalThis.fetch(url, init);
|
|
255
246
|
}
|
|
256
|
-
async onNotOkResponse(res,
|
|
247
|
+
async onNotOkResponse(res, timeout) {
|
|
257
248
|
var _a, _b;
|
|
258
249
|
clearTimeout(timeout);
|
|
259
250
|
let cause;
|
|
@@ -280,35 +271,18 @@ export class Fetcher {
|
|
|
280
271
|
requestBaseUrl: this.cfg.baseUrl || null,
|
|
281
272
|
requestMethod: res.req.init.method,
|
|
282
273
|
requestSignature: res.signature,
|
|
283
|
-
requestDuration: Date.now() - started,
|
|
274
|
+
requestDuration: Date.now() - res.req.started,
|
|
284
275
|
}), cause);
|
|
285
276
|
await this.processRetry(res);
|
|
286
277
|
}
|
|
287
278
|
async processRetry(res) {
|
|
288
|
-
var _a
|
|
279
|
+
var _a;
|
|
289
280
|
const { retryStatus } = res;
|
|
290
281
|
if (!this.shouldRetry(res)) {
|
|
291
282
|
retryStatus.retryStopped = true;
|
|
292
283
|
}
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
_c = _f.value;
|
|
296
|
-
_d = false;
|
|
297
|
-
try {
|
|
298
|
-
const hook = _c;
|
|
299
|
-
await hook(res);
|
|
300
|
-
}
|
|
301
|
-
finally {
|
|
302
|
-
_d = true;
|
|
303
|
-
}
|
|
304
|
-
}
|
|
305
|
-
}
|
|
306
|
-
catch (e_3_1) { e_3 = { error: e_3_1 }; }
|
|
307
|
-
finally {
|
|
308
|
-
try {
|
|
309
|
-
if (!_d && !_a && (_b = _e.return)) await _b.call(_e);
|
|
310
|
-
}
|
|
311
|
-
finally { if (e_3) throw e_3.error; }
|
|
284
|
+
for (const hook of this.cfg.hooks.beforeRetry || []) {
|
|
285
|
+
await hook(res);
|
|
312
286
|
}
|
|
313
287
|
const { count, timeoutMultiplier, timeoutMax } = res.req.retry;
|
|
314
288
|
if (retryStatus.retryAttempt >= count) {
|
|
@@ -316,6 +290,22 @@ export class Fetcher {
|
|
|
316
290
|
}
|
|
317
291
|
if (retryStatus.retryStopped)
|
|
318
292
|
return;
|
|
293
|
+
// Here we know that more retries will be attempted
|
|
294
|
+
// We don't log "last error", because it will be thrown and logged by consumer,
|
|
295
|
+
// but we should log all previous errors, otherwise they are lost.
|
|
296
|
+
// Here is the right place where we know it's not the "last error"
|
|
297
|
+
if (res.err) {
|
|
298
|
+
const { retryAttempt } = retryStatus;
|
|
299
|
+
this.cfg.logger.error([
|
|
300
|
+
' <<',
|
|
301
|
+
((_a = res.fetchResponse) === null || _a === void 0 ? void 0 : _a.status) || 0,
|
|
302
|
+
res.signature,
|
|
303
|
+
`try#${retryAttempt + 1}/${count + 1}`,
|
|
304
|
+
_since(res.req.started),
|
|
305
|
+
]
|
|
306
|
+
.filter(Boolean)
|
|
307
|
+
.join(' '), res.err.cause || res.err);
|
|
308
|
+
}
|
|
319
309
|
retryStatus.retryAttempt++;
|
|
320
310
|
retryStatus.retryTimeout = _clamp(retryStatus.retryTimeout * timeoutMultiplier, 0, timeoutMax);
|
|
321
311
|
const noise = Math.random() * 500;
|
|
@@ -419,7 +409,7 @@ export class Fetcher {
|
|
|
419
409
|
normalizeOptions(url, opt) {
|
|
420
410
|
var _a, _b;
|
|
421
411
|
const { timeoutSeconds, throwHttpErrors, retryPost, retry4xx, retry5xx, retry, mode, jsonReviver, } = this.cfg;
|
|
422
|
-
const req = Object.assign(Object.assign({ mode,
|
|
412
|
+
const req = Object.assign(Object.assign({ started: Date.now(), mode,
|
|
423
413
|
url,
|
|
424
414
|
timeoutSeconds,
|
|
425
415
|
throwHttpErrors,
|
|
@@ -102,7 +102,6 @@ export function _mapValues(obj, mapper, mutate = false) {
|
|
|
102
102
|
* Does not support `mutate` flag.
|
|
103
103
|
*/
|
|
104
104
|
export function _mapKeys(obj, mapper) {
|
|
105
|
-
// eslint-disable-next-line unicorn/prefer-object-from-entries
|
|
106
105
|
return Object.entries(obj).reduce((map, [k, v]) => {
|
|
107
106
|
map[mapper(k, v, obj)] = v;
|
|
108
107
|
return map;
|
package/dist-esm/promise/pMap.js
CHANGED
|
@@ -6,7 +6,6 @@ Improvements:
|
|
|
6
6
|
- Included Typescript typings (no need for @types/p-map)
|
|
7
7
|
- Compatible with pProps (that had typings issues)
|
|
8
8
|
*/
|
|
9
|
-
import { __asyncValues } from "tslib";
|
|
10
9
|
import { END, ErrorMode, SKIP } from '..';
|
|
11
10
|
/**
|
|
12
11
|
* Returns a `Promise` that is fulfilled when all promises in `input` and ones returned from `mapper` are fulfilled,
|
|
@@ -35,7 +34,6 @@ import { END, ErrorMode, SKIP } from '..';
|
|
|
35
34
|
* })();
|
|
36
35
|
*/
|
|
37
36
|
export async function pMap(iterable, mapper, opt = {}) {
|
|
38
|
-
var _a, e_1, _b, _c;
|
|
39
37
|
const ret = [];
|
|
40
38
|
// const iterator = iterable[Symbol.iterator]()
|
|
41
39
|
const items = [...iterable];
|
|
@@ -49,40 +47,23 @@ export async function pMap(iterable, mapper, opt = {}) {
|
|
|
49
47
|
let currentIndex = 0;
|
|
50
48
|
// Special cases that are able to preserve async stack traces
|
|
51
49
|
if (concurrency === 1) {
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
for (var _d = true, items_1 = __asyncValues(items), items_1_1; items_1_1 = await items_1.next(), _a = items_1_1.done, !_a;) {
|
|
55
|
-
_c = items_1_1.value;
|
|
56
|
-
_d = false;
|
|
57
|
-
try {
|
|
58
|
-
const item = _c;
|
|
59
|
-
try {
|
|
60
|
-
const r = await mapper(item, currentIndex++);
|
|
61
|
-
if (r === END)
|
|
62
|
-
break;
|
|
63
|
-
if (r !== SKIP)
|
|
64
|
-
ret.push(r);
|
|
65
|
-
}
|
|
66
|
-
catch (err) {
|
|
67
|
-
if (errorMode === ErrorMode.THROW_IMMEDIATELY)
|
|
68
|
-
throw err;
|
|
69
|
-
if (errorMode === ErrorMode.THROW_AGGREGATED) {
|
|
70
|
-
errors.push(err);
|
|
71
|
-
}
|
|
72
|
-
// otherwise, suppress completely
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
finally {
|
|
76
|
-
_d = true;
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
catch (e_1_1) { e_1 = { error: e_1_1 }; }
|
|
81
|
-
finally {
|
|
50
|
+
// Special case for concurrency == 1
|
|
51
|
+
for (const item of items) {
|
|
82
52
|
try {
|
|
83
|
-
|
|
53
|
+
const r = await mapper(item, currentIndex++);
|
|
54
|
+
if (r === END)
|
|
55
|
+
break;
|
|
56
|
+
if (r !== SKIP)
|
|
57
|
+
ret.push(r);
|
|
58
|
+
}
|
|
59
|
+
catch (err) {
|
|
60
|
+
if (errorMode === ErrorMode.THROW_IMMEDIATELY)
|
|
61
|
+
throw err;
|
|
62
|
+
if (errorMode === ErrorMode.THROW_AGGREGATED) {
|
|
63
|
+
errors.push(err);
|
|
64
|
+
}
|
|
65
|
+
// otherwise, suppress completely
|
|
84
66
|
}
|
|
85
|
-
finally { if (e_1) throw e_1.error; }
|
|
86
67
|
}
|
|
87
68
|
if (errors.length) {
|
|
88
69
|
throw new AggregateError(errors, `pMap resulted in ${errors.length} error(s)`);
|
package/dist-esm/string/leven.js
CHANGED
|
@@ -56,7 +56,6 @@ export function _leven(first, second) {
|
|
|
56
56
|
for (index = 0; index < firstLength; index++) {
|
|
57
57
|
temporary2 = bCharacterCode === characterCodeCache[index] ? temporary : temporary + 1;
|
|
58
58
|
temporary = array[index];
|
|
59
|
-
// eslint-disable-next-line no-multi-assign
|
|
60
59
|
result = array[index] =
|
|
61
60
|
temporary > result
|
|
62
61
|
? temporary2 > result
|
package/dist-esm/vendor/is.js
CHANGED
|
@@ -60,7 +60,6 @@ const primitiveTypeNames = [
|
|
|
60
60
|
function isPrimitiveTypeName(name) {
|
|
61
61
|
return primitiveTypeNames.includes(name);
|
|
62
62
|
}
|
|
63
|
-
// eslint-disable-next-line @typescript-eslint/ban-types
|
|
64
63
|
function isOfType(type) {
|
|
65
64
|
return (value) => typeof value === type;
|
|
66
65
|
}
|
|
@@ -122,7 +121,6 @@ is.string = isOfType('string');
|
|
|
122
121
|
const isNumberType = isOfType('number');
|
|
123
122
|
is.number = (value) => isNumberType(value) && !is.nan(value);
|
|
124
123
|
is.bigint = isOfType('bigint');
|
|
125
|
-
// eslint-disable-next-line @typescript-eslint/ban-types
|
|
126
124
|
is.function_ = isOfType('function');
|
|
127
125
|
is.null_ = (value) => value === null;
|
|
128
126
|
is.class_ = (value) => is.function_(value) && value.toString().startsWith('class ');
|
|
@@ -151,7 +149,6 @@ is.promise = (value) => is.nativePromise(value) || hasPromiseAPI(value);
|
|
|
151
149
|
is.generatorFunction = isObjectOfType('GeneratorFunction');
|
|
152
150
|
is.asyncGeneratorFunction = (value) => getObjectType(value) === 'AsyncGeneratorFunction';
|
|
153
151
|
is.asyncFunction = (value) => getObjectType(value) === 'AsyncFunction';
|
|
154
|
-
// eslint-disable-next-line no-prototype-builtins, @typescript-eslint/ban-types
|
|
155
152
|
is.boundFunction = (value) => is.function_(value) && !value.hasOwnProperty('prototype');
|
|
156
153
|
is.regExp = isObjectOfType('RegExp');
|
|
157
154
|
is.date = isObjectOfType('Date');
|
|
@@ -181,7 +178,7 @@ is.urlString = (value) => {
|
|
|
181
178
|
return false;
|
|
182
179
|
}
|
|
183
180
|
try {
|
|
184
|
-
new URL(value);
|
|
181
|
+
new URL(value);
|
|
185
182
|
return true;
|
|
186
183
|
}
|
|
187
184
|
catch (_a) {
|
|
@@ -341,7 +338,6 @@ export const assert = {
|
|
|
341
338
|
string: (value) => assertType(is.string(value), 'string', value),
|
|
342
339
|
number: (value) => assertType(is.number(value), 'number', value),
|
|
343
340
|
bigint: (value) => assertType(is.bigint(value), 'bigint', value),
|
|
344
|
-
// eslint-disable-next-line @typescript-eslint/ban-types
|
|
345
341
|
function_: (value) => assertType(is.function_(value), 'Function', value),
|
|
346
342
|
null_: (value) => assertType(is.null_(value), 'null', value),
|
|
347
343
|
class_: (value) => assertType(is.class_(value), AssertionTypeDescription.class_, value),
|
|
@@ -366,9 +362,7 @@ export const assert = {
|
|
|
366
362
|
promise: (value) => assertType(is.promise(value), 'Promise', value),
|
|
367
363
|
generatorFunction: (value) => assertType(is.generatorFunction(value), 'GeneratorFunction', value),
|
|
368
364
|
asyncGeneratorFunction: (value) => assertType(is.asyncGeneratorFunction(value), 'AsyncGeneratorFunction', value),
|
|
369
|
-
// eslint-disable-next-line @typescript-eslint/ban-types
|
|
370
365
|
asyncFunction: (value) => assertType(is.asyncFunction(value), 'AsyncFunction', value),
|
|
371
|
-
// eslint-disable-next-line @typescript-eslint/ban-types
|
|
372
366
|
boundFunction: (value) => assertType(is.boundFunction(value), 'Function', value),
|
|
373
367
|
regExp: (value) => assertType(is.regExp(value), 'RegExp', value),
|
|
374
368
|
date: (value) => assertType(is.date(value), 'Date', value),
|
package/package.json
CHANGED
package/src/array/array.util.ts
CHANGED
|
@@ -149,7 +149,7 @@ export function _sortBy<T>(
|
|
|
149
149
|
): T[] {
|
|
150
150
|
const mod = descending ? -1 : 1
|
|
151
151
|
return (mutate ? items : [...items]).sort((_a, _b) => {
|
|
152
|
-
const [a, b] = [_a, _b].map(mapper)
|
|
152
|
+
const [a, b] = [_a, _b].map(mapper)
|
|
153
153
|
if (typeof a === 'number' && typeof b === 'number') return (a - b) * mod
|
|
154
154
|
return String(a).localeCompare(String(b)) * mod
|
|
155
155
|
})
|
|
@@ -159,7 +159,7 @@ export function _sortBy<T>(
|
|
|
159
159
|
* Like items.find(), but it tries to find from the END of the array.
|
|
160
160
|
*/
|
|
161
161
|
export function _findLast<T>(items: T[], predicate: Predicate<T>): T | undefined {
|
|
162
|
-
return [...items].reverse().find(predicate)
|
|
162
|
+
return [...items].reverse().find(predicate)
|
|
163
163
|
}
|
|
164
164
|
|
|
165
165
|
export function _takeWhile<T>(items: T[], predicate: Predicate<T>): T[] {
|
|
@@ -52,7 +52,7 @@ export interface PromiseDecoratorResp<PARAMS> {
|
|
|
52
52
|
*
|
|
53
53
|
* @experimental
|
|
54
54
|
*/
|
|
55
|
-
|
|
55
|
+
|
|
56
56
|
export function _createPromiseDecorator<RES = any, PARAMS = any>(
|
|
57
57
|
cfg: PromiseDecoratorCfg<RES, PARAMS>,
|
|
58
58
|
decoratorParams: PARAMS = {} as any,
|
|
@@ -1,16 +1,24 @@
|
|
|
1
1
|
import type { CommonLogger } from '../log/commonLogger'
|
|
2
2
|
import type { Promisable } from '../typeFest'
|
|
3
|
-
import type { Reviver } from '../types'
|
|
3
|
+
import type { Reviver, UnixTimestampMillisNumber } from '../types'
|
|
4
4
|
import type { HttpMethod, HttpStatusFamily } from './http.model'
|
|
5
5
|
|
|
6
|
-
export interface FetcherNormalizedCfg
|
|
6
|
+
export interface FetcherNormalizedCfg
|
|
7
|
+
extends Required<FetcherCfg>,
|
|
8
|
+
Omit<FetcherRequest, 'started'> {
|
|
7
9
|
logger: CommonLogger
|
|
8
10
|
searchParams: Record<string, any>
|
|
9
11
|
}
|
|
10
12
|
|
|
11
|
-
export type FetcherBeforeRequestHook =
|
|
12
|
-
|
|
13
|
-
|
|
13
|
+
export type FetcherBeforeRequestHook = <BODY = unknown>(
|
|
14
|
+
req: FetcherRequest<BODY>,
|
|
15
|
+
) => Promisable<void>
|
|
16
|
+
export type FetcherAfterResponseHook = <BODY = unknown>(
|
|
17
|
+
res: FetcherResponse<BODY>,
|
|
18
|
+
) => Promisable<void>
|
|
19
|
+
export type FetcherBeforeRetryHook = <BODY = unknown>(
|
|
20
|
+
res: FetcherResponse<BODY>,
|
|
21
|
+
) => Promisable<void>
|
|
14
22
|
|
|
15
23
|
export interface FetcherCfg {
|
|
16
24
|
/**
|
|
@@ -88,7 +96,8 @@ export interface FetcherRetryOptions {
|
|
|
88
96
|
timeoutMultiplier: number
|
|
89
97
|
}
|
|
90
98
|
|
|
91
|
-
export interface FetcherRequest
|
|
99
|
+
export interface FetcherRequest<BODY = unknown>
|
|
100
|
+
extends Omit<FetcherOptions<BODY>, 'method' | 'headers' | 'baseUrl'> {
|
|
92
101
|
url: string
|
|
93
102
|
init: RequestInitNormalized
|
|
94
103
|
mode: FetcherMode
|
|
@@ -98,9 +107,10 @@ export interface FetcherRequest extends Omit<FetcherOptions, 'method' | 'headers
|
|
|
98
107
|
retryPost: boolean
|
|
99
108
|
retry4xx: boolean
|
|
100
109
|
retry5xx: boolean
|
|
110
|
+
started: UnixTimestampMillisNumber
|
|
101
111
|
}
|
|
102
112
|
|
|
103
|
-
export interface FetcherOptions {
|
|
113
|
+
export interface FetcherOptions<BODY = unknown> {
|
|
104
114
|
method?: HttpMethod
|
|
105
115
|
|
|
106
116
|
baseUrl?: string
|
|
@@ -159,6 +169,19 @@ export interface FetcherOptions {
|
|
|
159
169
|
retry5xx?: boolean
|
|
160
170
|
|
|
161
171
|
jsonReviver?: Reviver
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* Allows to walk over multiple pages of results.
|
|
175
|
+
* Paginate take a function.
|
|
176
|
+
* Function has access to FetcherRequest and FetcherResponse
|
|
177
|
+
* and has to make a decision to continue pagination or not.
|
|
178
|
+
* Return true to continue, false otherwise.
|
|
179
|
+
* If continue - it is expected to modify/mutate the FetcherRequest, as it will be used
|
|
180
|
+
* to request the next page.
|
|
181
|
+
*
|
|
182
|
+
* @experimental
|
|
183
|
+
*/
|
|
184
|
+
paginate?: (req: FetcherRequest<BODY>, res: FetcherSuccessResponse<BODY>) => Promisable<boolean>
|
|
162
185
|
}
|
|
163
186
|
|
|
164
187
|
export type RequestInitNormalized = Omit<RequestInit, 'method' | 'headers'> & {
|
|
@@ -192,4 +215,4 @@ export type FetcherResponse<BODY = unknown> =
|
|
|
192
215
|
| FetcherSuccessResponse<BODY>
|
|
193
216
|
| FetcherErrorResponse<BODY>
|
|
194
217
|
|
|
195
|
-
export type FetcherMode = 'json' | 'text' | 'void' | 'arrayBuffer' | 'blob'
|
|
218
|
+
export type FetcherMode = 'json' | 'text' | 'void' | 'arrayBuffer' | 'blob' | 'readableStream'
|