@naturalcycles/js-lib 14.117.0 → 14.118.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.
Files changed (62) hide show
  1. package/dist/array/array.util.js +4 -4
  2. package/dist/datetime/dateInterval.js +1 -0
  3. package/dist/datetime/localDate.js +2 -0
  4. package/dist/datetime/localTime.js +2 -3
  5. package/dist/datetime/timeInterval.js +1 -0
  6. package/dist/decorators/asyncMemo.decorator.d.ts +2 -2
  7. package/dist/decorators/createPromiseDecorator.d.ts +6 -6
  8. package/dist/decorators/logMethod.decorator.js +4 -5
  9. package/dist/decorators/memo.decorator.d.ts +2 -2
  10. package/dist/error/tryCatch.d.ts +1 -1
  11. package/dist/http/fetcher.d.ts +146 -0
  12. package/dist/http/fetcher.js +298 -0
  13. package/dist/http/http.model.d.ts +2 -0
  14. package/dist/http/http.model.js +2 -0
  15. package/dist/index.d.ts +2 -0
  16. package/dist/index.js +2 -0
  17. package/dist/object/deepEquals.js +1 -0
  18. package/dist/object/object.util.js +8 -10
  19. package/dist/promise/pRetry.d.ts +1 -1
  20. package/dist/promise/pTimeout.d.ts +1 -1
  21. package/dist/string/pupa.d.ts +2 -2
  22. package/dist/string/readingTime.d.ts +1 -1
  23. package/dist/string/safeJsonStringify.js +5 -7
  24. package/dist/string/stringifyAny.js +2 -1
  25. package/dist/string/url.util.js +1 -1
  26. package/dist-esm/array/array.util.js +4 -4
  27. package/dist-esm/datetime/dateInterval.js +1 -0
  28. package/dist-esm/datetime/localDate.js +2 -0
  29. package/dist-esm/datetime/localTime.js +2 -3
  30. package/dist-esm/datetime/timeInterval.js +1 -0
  31. package/dist-esm/decorators/logMethod.decorator.js +4 -5
  32. package/dist-esm/http/fetcher.js +251 -0
  33. package/dist-esm/http/http.model.js +1 -0
  34. package/dist-esm/index.js +2 -0
  35. package/dist-esm/object/deepEquals.js +1 -0
  36. package/dist-esm/object/object.util.js +8 -10
  37. package/dist-esm/string/safeJsonStringify.js +5 -7
  38. package/dist-esm/string/stringifyAny.js +2 -1
  39. package/dist-esm/string/url.util.js +1 -1
  40. package/package.json +1 -1
  41. package/src/array/array.util.ts +4 -4
  42. package/src/datetime/dateInterval.ts +1 -0
  43. package/src/datetime/localDate.ts +2 -0
  44. package/src/datetime/localTime.ts +2 -2
  45. package/src/datetime/timeInterval.ts +1 -0
  46. package/src/decorators/asyncMemo.decorator.ts +2 -2
  47. package/src/decorators/createPromiseDecorator.ts +4 -4
  48. package/src/decorators/logMethod.decorator.ts +4 -4
  49. package/src/decorators/memo.decorator.ts +2 -2
  50. package/src/error/tryCatch.ts +1 -1
  51. package/src/http/fetcher.ts +469 -0
  52. package/src/http/http.model.ts +3 -0
  53. package/src/index.ts +2 -0
  54. package/src/object/deepEquals.ts +1 -0
  55. package/src/object/object.util.ts +7 -8
  56. package/src/promise/pRetry.ts +1 -1
  57. package/src/promise/pTimeout.ts +1 -1
  58. package/src/string/pupa.ts +1 -1
  59. package/src/string/readingTime.ts +1 -1
  60. package/src/string/safeJsonStringify.ts +3 -5
  61. package/src/string/stringifyAny.ts +3 -1
  62. package/src/string/url.util.ts +1 -1
@@ -15,14 +15,12 @@ function _pick(obj, props, mutate = false) {
15
15
  return r;
16
16
  }, obj);
17
17
  }
18
- else {
19
- // Start as empty object, pick/add needed properties
20
- return props.reduce((r, prop) => {
21
- if (prop in obj)
22
- r[prop] = obj[prop];
23
- return r;
24
- }, {});
25
- }
18
+ // Start as empty object, pick/add needed properties
19
+ return props.reduce((r, prop) => {
20
+ if (prop in obj)
21
+ r[prop] = obj[prop];
22
+ return r;
23
+ }, {});
26
24
  }
27
25
  exports._pick = _pick;
28
26
  /**
@@ -259,7 +257,7 @@ function _unset(obj, prop) {
259
257
  }
260
258
  const segs = prop.split('.');
261
259
  let last = segs.pop();
262
- while (segs.length && segs[segs.length - 1].slice(-1) === '\\') {
260
+ while (segs.length && segs[segs.length - 1].endsWith('\\')) {
263
261
  last = segs.pop().slice(0, -1) + '.' + last;
264
262
  }
265
263
  while (segs.length && (0, is_util_1._isObject)(obj)) {
@@ -329,7 +327,7 @@ function _set(obj, path, value) {
329
327
  a[c]
330
328
  : // No: create the key. Is the next key a potential array-index?
331
329
  (a[c] =
332
- // @ts-ignore
330
+ // @ts-expect-error
333
331
  // eslint-disable-next-line
334
332
  Math.abs(path[i + 1]) >> 0 === +path[i + 1]
335
333
  ? [] // Yes: assign a new array object
@@ -35,7 +35,7 @@ export interface PRetryOptions {
35
35
  *
36
36
  * @default () => true
37
37
  */
38
- predicate?: (err: Error, attempt: number, maxAttempts: number) => boolean;
38
+ predicate?(err: Error, attempt: number, maxAttempts: number): boolean;
39
39
  /**
40
40
  * Log the first attempt (which is not a "retry" yet).
41
41
  *
@@ -20,7 +20,7 @@ export interface PTimeoutOptions {
20
20
  * err (which is TimeoutError) is passed as an argument for convenience, so it can
21
21
  * be logged or such. You don't have to consume it in any way though.
22
22
  */
23
- onTimeout?: (err: TimeoutError) => any;
23
+ onTimeout?(err: TimeoutError): any;
24
24
  /**
25
25
  * Defaults to true.
26
26
  * If true - preserves the stack trace in case of a Timeout (usually - very useful!).
@@ -11,10 +11,10 @@ export interface PupaOptions {
11
11
  /**
12
12
  * Performs arbitrary operation for each interpolation. If the returned value was `undefined`, it behaves differently depending on the `ignoreMissing` option. Otherwise, the returned value will be interpolated into a string (and escaped when double-braced) and embedded into the template.
13
13
  */
14
- transform?: (data: {
14
+ transform?(data: {
15
15
  value: any;
16
16
  key: string;
17
- }) => unknown;
17
+ }): unknown;
18
18
  }
19
19
  /**
20
20
  * API: https://github.com/sindresorhus/pupa
@@ -4,7 +4,7 @@ export interface ReadingTimeOptions {
4
4
  * A function that returns a boolean value depending on if a character is considered as a word bound.
5
5
  * Default: spaces, new lines and tabs
6
6
  */
7
- wordBound?: (char: string) => boolean;
7
+ wordBound?(char: string): boolean;
8
8
  /**
9
9
  * Default 200
10
10
  */
@@ -21,13 +21,11 @@ exports._safeJsonStringify = _safeJsonStringify;
21
21
  function serializer(replacer, cycleReplacer) {
22
22
  const stack = [];
23
23
  const keys = [];
24
- if (cycleReplacer == null) {
25
- cycleReplacer = function (key, value) {
26
- if (stack[0] === value)
27
- return '[Circular ~]';
28
- return '[Circular ~.' + keys.slice(0, stack.indexOf(value)).join('.') + ']';
29
- };
30
- }
24
+ cycleReplacer ??= function (key, value) {
25
+ if (stack[0] === value)
26
+ return '[Circular ~]';
27
+ return '[Circular ~.' + keys.slice(0, stack.indexOf(value)).join('.') + ']';
28
+ };
31
29
  return function (key, value) {
32
30
  if (stack.length > 0) {
33
31
  const thisPos = stack.indexOf(this);
@@ -56,7 +56,8 @@ function _stringifyAny(obj, opt = {}) {
56
56
  // This is to fix the rare error (happened with Got) where `err.message` was changed,
57
57
  // but err.stack had "old" err.message
58
58
  // This should "fix" that
59
- s = [s, ...obj.stack.split('\n').slice(1)].join('\n');
59
+ const sLines = s.split('\n').length;
60
+ s = [s, ...obj.stack.split('\n').slice(sLines)].join('\n');
60
61
  }
61
62
  if ((0, error_util_1._isErrorObject)(obj)) {
62
63
  if ((0, error_util_1._isHttpErrorObject)(obj)) {
@@ -17,7 +17,7 @@ exports._parseQueryString = void 0;
17
17
  function _parseQueryString(search) {
18
18
  const qs = {};
19
19
  search
20
- .slice(search[0] === '?' ? 1 : 0)
20
+ .slice(search.startsWith('?') ? 1 : 0)
21
21
  .split('&')
22
22
  .forEach(p => {
23
23
  const [k, v] = p.split('=');
@@ -148,21 +148,21 @@ export function _findLast(items, predicate) {
148
148
  }
149
149
  export function _takeWhile(items, predicate) {
150
150
  let proceed = true;
151
- return items.filter((v, index) => (proceed = proceed && predicate(v, index)));
151
+ return items.filter((v, index) => (proceed && (proceed = predicate(v, index))));
152
152
  }
153
153
  export function _takeRightWhile(items, predicate) {
154
154
  let proceed = true;
155
- return [...items].reverse().filter((v, index) => (proceed = proceed && predicate(v, index)));
155
+ return [...items].reverse().filter((v, index) => (proceed && (proceed = predicate(v, index))));
156
156
  }
157
157
  export function _dropWhile(items, predicate) {
158
158
  let proceed = false;
159
- return items.filter((v, index) => (proceed = proceed || !predicate(v, index)));
159
+ return items.filter((v, index) => (proceed || (proceed = !predicate(v, index))));
160
160
  }
161
161
  export function _dropRightWhile(items, predicate) {
162
162
  let proceed = false;
163
163
  return [...items]
164
164
  .reverse()
165
- .filter((v, index) => (proceed = proceed || !predicate(v, index)))
165
+ .filter((v, index) => (proceed || (proceed = !predicate(v, index))))
166
166
  .reverse();
167
167
  }
168
168
  export function _countBy(items, mapper) {
@@ -46,6 +46,7 @@ export class DateInterval {
46
46
  */
47
47
  includes(d, incl = '[]') {
48
48
  d = LocalDate.of(d);
49
+ // eslint-disable-next-line @typescript-eslint/prefer-string-starts-ends-with
49
50
  return d.isAfter(this.start, incl[0] === '[') && d.isBefore(this.end, incl[1] === ']');
50
51
  }
51
52
  intersects(int, inclusive = true) {
@@ -109,6 +109,7 @@ export class LocalDate {
109
109
  const $min = LocalDate.of(min);
110
110
  const $max = LocalDate.of(max).startOf(stepUnit);
111
111
  let current = $min.startOf(stepUnit);
112
+ // eslint-disable-next-line @typescript-eslint/prefer-string-starts-ends-with
112
113
  if (current.isAfter($min, incl[0] === '[')) {
113
114
  // ok
114
115
  }
@@ -167,6 +168,7 @@ export class LocalDate {
167
168
  }
168
169
  isBetween(min, max, incl = '[)') {
169
170
  let r = this.cmp(min);
171
+ // eslint-disable-next-line @typescript-eslint/prefer-string-starts-ends-with
170
172
  if (r < 0 || (r === 0 && incl[0] === '('))
171
173
  return false;
172
174
  r = this.cmp(max);
@@ -345,6 +345,7 @@ export class LocalTime {
345
345
  }
346
346
  isBetween(min, max, incl = '[)') {
347
347
  let r = this.cmp(min);
348
+ // eslint-disable-next-line @typescript-eslint/prefer-string-starts-ends-with
348
349
  if (r < 0 || (r === 0 && incl[0] === '('))
349
350
  return false;
350
351
  r = this.cmp(max);
@@ -521,9 +522,7 @@ function getWeekYear(date) {
521
522
  else if (date.getTime() >= startOfThisYear.getTime()) {
522
523
  return year;
523
524
  }
524
- else {
525
- return year - 1;
526
- }
525
+ return year - 1;
527
526
  }
528
527
  // based on: https://github.com/date-fns/date-fns/blob/fd6bb1a0bab143f2da068c05a9c562b9bee1357d/src/startOfWeek/index.ts
529
528
  function startOfWeek(date, mutate = false) {
@@ -56,6 +56,7 @@ export class TimeInterval {
56
56
  }
57
57
  includes(d, incl = '[)') {
58
58
  d = LocalTime.parseToUnixTimestamp(d);
59
+ // eslint-disable-next-line @typescript-eslint/prefer-string-starts-ends-with
59
60
  if (d < this.$start || (d === this.$start && incl[0] === '('))
60
61
  return false;
61
62
  if (d > this.$end || (d === this.$end && incl[1] === ')'))
@@ -56,11 +56,9 @@ export function _LogMethod(opt = {}) {
56
56
  throw err;
57
57
  });
58
58
  }
59
- else {
60
- // not a Promise
61
- logFinished(logger, callSignature, started, sma, logResultFn, res);
62
- return res;
63
- }
59
+ // not a Promise
60
+ logFinished(logger, callSignature, started, sma, logResultFn, res);
61
+ return res;
64
62
  }
65
63
  catch (err) {
66
64
  logFinished(logger, callSignature, started, sma, logResultFn, undefined, err);
@@ -70,6 +68,7 @@ export function _LogMethod(opt = {}) {
70
68
  return descriptor;
71
69
  };
72
70
  }
71
+ // eslint-disable-next-line max-params
73
72
  function logFinished(logger, callSignature, started, sma, logResultFn, res, err) {
74
73
  const millis = Date.now() - started;
75
74
  const t = ['<<', callSignature, 'took', _ms(millis)];
@@ -0,0 +1,251 @@
1
+ /// <reference lib="dom"/>
2
+ import { _anyToErrorObject } from '../error/error.util';
3
+ import { HttpError } from '../error/http.error';
4
+ import { _clamp } from '../number/number.util';
5
+ import { _filterNullishValues, _filterUndefinedValues } from '../object/object.util';
6
+ import { pDelay } from '../promise/pDelay';
7
+ import { _jsonParseIfPossible } from '../string/json.util';
8
+ import { _stringifyAny } from '../string/stringifyAny';
9
+ import { _since } from '../time/time.util';
10
+ import { _objectAssign } from '../types';
11
+ const defRetryOptions = {
12
+ count: 2,
13
+ timeout: 500,
14
+ timeoutMax: 30000,
15
+ timeoutMultiplier: 2,
16
+ };
17
+ /**
18
+ * Experimental wrapper around Fetch.
19
+ * Works in both Browser and Node, using `globalThis.fetch`.
20
+ *
21
+ * @experimental
22
+ */
23
+ export class Fetcher {
24
+ constructor(cfg = {}) {
25
+ this.cfg = this.normalizeCfg(cfg);
26
+ }
27
+ static create(cfg = {}) {
28
+ return new Fetcher(cfg);
29
+ }
30
+ async getJson(url, opt = {}) {
31
+ return await this.fetch(url, Object.assign(Object.assign({}, opt), { mode: 'json' }));
32
+ }
33
+ async postJson(url, opt = {}) {
34
+ return await this.fetch(url, Object.assign(Object.assign({}, opt), { method: 'post', mode: 'json' }));
35
+ }
36
+ async getText(url, opt = {}) {
37
+ return await this.fetch(url, Object.assign(Object.assign({}, opt), { mode: 'text' }));
38
+ }
39
+ async postText(url, opt = {}) {
40
+ return await this.fetch(url, Object.assign(Object.assign({}, opt), { method: 'post', mode: 'text' }));
41
+ }
42
+ async fetch(url, opt = {}) {
43
+ const res = await this.rawFetch(url, opt);
44
+ if (res.err) {
45
+ if (res.req.opt.throwHttpErrors)
46
+ throw res.err;
47
+ return res;
48
+ }
49
+ return res.body;
50
+ }
51
+ async rawFetch(url, rawOpt = {}) {
52
+ var _a, _b, _c, _d;
53
+ const { baseUrl, logger } = this.cfg;
54
+ const opt = this.normalizeOptions(rawOpt);
55
+ const { method, timeoutSeconds, mode } = opt;
56
+ const req = {
57
+ url,
58
+ init: Object.assign(Object.assign({}, this.cfg.requestInit), { method }),
59
+ opt,
60
+ };
61
+ // setup url
62
+ if (baseUrl) {
63
+ if (url.startsWith('/')) {
64
+ console.warn(`Fetcher: url should not start with / when baseUrl is specified`);
65
+ url = url.slice(1);
66
+ }
67
+ req.url = `${baseUrl}/${url}`;
68
+ }
69
+ // setup request body
70
+ if (opt.json !== undefined) {
71
+ req.init.body = JSON.stringify(opt.json);
72
+ }
73
+ else if (opt.text !== undefined) {
74
+ req.init.body = opt.text;
75
+ }
76
+ // setup timeout
77
+ let timeout;
78
+ if (timeoutSeconds) {
79
+ const abortController = new AbortController();
80
+ req.init.signal = abortController.signal;
81
+ timeout = setTimeout(() => {
82
+ abortController.abort(`timeout of ${timeoutSeconds} sec`);
83
+ }, timeoutSeconds * 1000);
84
+ }
85
+ if (opt.requestInit) {
86
+ _objectAssign(req.init, opt.requestInit);
87
+ }
88
+ await ((_b = (_a = this.cfg.hooks) === null || _a === void 0 ? void 0 : _a.beforeRequest) === null || _b === void 0 ? void 0 : _b.call(_a, req));
89
+ const res = {
90
+ req,
91
+ retryStatus: {
92
+ retryAttempt: 0,
93
+ retryStopped: false,
94
+ retryTimeout: opt.retry.timeout,
95
+ },
96
+ };
97
+ const shortUrl = this.getShortUrl(req.url);
98
+ const signature = [method.toUpperCase(), shortUrl].join(' ');
99
+ /* eslint-disable no-await-in-loop */
100
+ while (!res.retryStatus.retryStopped) {
101
+ const started = Date.now();
102
+ if (this.cfg.logRequest) {
103
+ const { retryAttempt } = res.retryStatus;
104
+ logger.log([' >>', signature, retryAttempt && `try#${retryAttempt + 1}/${opt.retry.count}`]
105
+ .filter(Boolean)
106
+ .join(' '));
107
+ if (this.cfg.logRequestBody && req.init.body) {
108
+ logger.log(req.init.body); // todo: check if we can _inspect it
109
+ }
110
+ }
111
+ res.fetchResponse = await globalThis.fetch(req.url, req.init);
112
+ res.statusFamily = this.getStatusFamily(res);
113
+ if (res.fetchResponse.ok) {
114
+ if (mode === 'json') {
115
+ // if no body: set responseBody as {}
116
+ // do not throw a "cannot parse null as Json" error
117
+ res.body = res.fetchResponse.body ? await res.fetchResponse.json() : {};
118
+ }
119
+ else if (mode === 'text') {
120
+ res.body = res.fetchResponse.body ? await res.fetchResponse.text() : '';
121
+ }
122
+ clearTimeout(timeout);
123
+ res.retryStatus.retryStopped = true;
124
+ if (this.cfg.logResponse) {
125
+ const { retryAttempt } = res.retryStatus;
126
+ logger.log([
127
+ ' <<',
128
+ res.fetchResponse.status,
129
+ signature,
130
+ retryAttempt && `try#${retryAttempt + 1}/${opt.retry.count}`,
131
+ _since(started),
132
+ ]
133
+ .filter(Boolean)
134
+ .join(' '));
135
+ if (this.cfg.logResponseBody) {
136
+ logger.log(res.body);
137
+ }
138
+ }
139
+ }
140
+ else {
141
+ clearTimeout(timeout);
142
+ const body = _jsonParseIfPossible(await res.fetchResponse.text());
143
+ const errObj = _anyToErrorObject(body);
144
+ const originalMessage = errObj.message;
145
+ errObj.message = [[res.fetchResponse.status, signature].join(' '), originalMessage].join('\n');
146
+ res.err = new HttpError(errObj.message, _filterNullishValues(Object.assign(Object.assign({}, errObj.data), { originalMessage, httpStatusCode: res.fetchResponse.status,
147
+ // These properties are provided to be used in e.g custom Sentry error grouping
148
+ // Actually, disabled now, to avoid unnecessary error printing when both msg and data are printed
149
+ // Enabled, cause `data` is not printed by default when error is HttpError
150
+ // method: req.method,
151
+ url: req.url })));
152
+ if (this.cfg.logResponse) {
153
+ const { retryAttempt } = res.retryStatus;
154
+ logger.error([
155
+ [
156
+ ' <<',
157
+ res.fetchResponse.status,
158
+ signature,
159
+ retryAttempt && `try#${retryAttempt + 1}/${opt.retry.count}`,
160
+ _since(started),
161
+ ]
162
+ .filter(Boolean)
163
+ .join(' '),
164
+ _stringifyAny(body),
165
+ ].join('\n'));
166
+ }
167
+ await this.processRetry(res);
168
+ }
169
+ }
170
+ await ((_d = (_c = this.cfg.hooks) === null || _c === void 0 ? void 0 : _c.beforeResponse) === null || _d === void 0 ? void 0 : _d.call(_c, res));
171
+ return res;
172
+ }
173
+ async processRetry(res) {
174
+ var _a, _b;
175
+ const { retryStatus } = res;
176
+ if (!this.shouldRetry(res)) {
177
+ retryStatus.retryStopped = true;
178
+ }
179
+ await ((_b = (_a = this.cfg.hooks) === null || _a === void 0 ? void 0 : _a.beforeRetry) === null || _b === void 0 ? void 0 : _b.call(_a, res));
180
+ const { count, timeoutMultiplier, timeoutMax } = res.req.opt.retry;
181
+ if (retryStatus.retryAttempt >= count) {
182
+ retryStatus.retryStopped = true;
183
+ }
184
+ if (retryStatus.retryStopped)
185
+ return;
186
+ retryStatus.retryTimeout = _clamp(retryStatus.retryTimeout * timeoutMultiplier, 0, timeoutMax);
187
+ await pDelay(retryStatus.retryTimeout);
188
+ }
189
+ /**
190
+ * Default is yes,
191
+ * unless there's reason not to (e.g method is POST).
192
+ */
193
+ shouldRetry(res) {
194
+ const { retryPost, retry4xx, retry5xx } = res.req.opt;
195
+ const { method } = res.req.init;
196
+ if (method === 'post' && !retryPost)
197
+ return false;
198
+ const { statusFamily } = res;
199
+ if (statusFamily === '5xx' && !retry5xx)
200
+ return false;
201
+ if (statusFamily === '4xx' && !retry4xx)
202
+ return false;
203
+ return true; // default is true
204
+ }
205
+ getStatusFamily(res) {
206
+ var _a;
207
+ const status = (_a = res.fetchResponse) === null || _a === void 0 ? void 0 : _a.status;
208
+ if (!status)
209
+ return;
210
+ if (status >= 500)
211
+ return '5xx';
212
+ if (status >= 400)
213
+ return '4xx';
214
+ if (status >= 300)
215
+ return '3xx';
216
+ if (status >= 200)
217
+ return '2xx';
218
+ if (status >= 100)
219
+ return '1xx';
220
+ }
221
+ /**
222
+ * Returns url without baseUrl and before ?queryString
223
+ */
224
+ getShortUrl(url) {
225
+ const { baseUrl } = this.cfg;
226
+ if (!baseUrl)
227
+ return url;
228
+ return url.split('?')[0].slice(baseUrl.length);
229
+ }
230
+ normalizeCfg(cfg) {
231
+ var _a;
232
+ if ((_a = cfg.baseUrl) === null || _a === void 0 ? void 0 : _a.endsWith('/')) {
233
+ console.warn(`Fetcher: baseUrl should not end with /`);
234
+ cfg.baseUrl = cfg.baseUrl.slice(0, cfg.baseUrl.length - 1);
235
+ }
236
+ const { debug } = cfg;
237
+ return Object.assign(Object.assign({ timeoutSeconds: 30, method: 'get', throwHttpErrors: true, retryPost: false, retry4xx: false, retry5xx: true, logger: console, logRequest: debug, logRequestBody: debug, logResponse: debug, logResponseBody: debug }, cfg), { retry: Object.assign(Object.assign({}, defRetryOptions), cfg.retry) });
238
+ }
239
+ normalizeOptions(opt) {
240
+ const { timeoutSeconds, throwHttpErrors, method, retryPost, retry4xx, retry5xx, retry } = this.cfg;
241
+ return Object.assign(Object.assign({ timeoutSeconds,
242
+ throwHttpErrors,
243
+ method,
244
+ retryPost,
245
+ retry4xx,
246
+ retry5xx }, opt), { retry: Object.assign(Object.assign({}, retry), _filterUndefinedValues(opt.retry || {})) });
247
+ }
248
+ }
249
+ export function getFetcher(cfg = {}) {
250
+ return Fetcher.create(cfg);
251
+ }
@@ -0,0 +1 @@
1
+ export {};
package/dist-esm/index.js CHANGED
@@ -74,4 +74,6 @@ export * from './datetime/localDate';
74
74
  export * from './datetime/localTime';
75
75
  export * from './datetime/dateInterval';
76
76
  export * from './datetime/timeInterval';
77
+ export * from './http/http.model';
78
+ export * from './http/fetcher';
77
79
  export { is };
@@ -51,5 +51,6 @@ export function _deepEquals(a, b) {
51
51
  }
52
52
  return true;
53
53
  }
54
+ // eslint-disable-next-line no-self-compare
54
55
  return a !== a && b !== b;
55
56
  }
@@ -12,14 +12,12 @@ export function _pick(obj, props, mutate = false) {
12
12
  return r;
13
13
  }, obj);
14
14
  }
15
- else {
16
- // Start as empty object, pick/add needed properties
17
- return props.reduce((r, prop) => {
18
- if (prop in obj)
19
- r[prop] = obj[prop];
20
- return r;
21
- }, {});
22
- }
15
+ // Start as empty object, pick/add needed properties
16
+ return props.reduce((r, prop) => {
17
+ if (prop in obj)
18
+ r[prop] = obj[prop];
19
+ return r;
20
+ }, {});
23
21
  }
24
22
  /**
25
23
  * Returns clone of `obj` with `props` omitted.
@@ -239,7 +237,7 @@ export function _unset(obj, prop) {
239
237
  }
240
238
  const segs = prop.split('.');
241
239
  let last = segs.pop();
242
- while (segs.length && segs[segs.length - 1].slice(-1) === '\\') {
240
+ while (segs.length && segs[segs.length - 1].endsWith('\\')) {
243
241
  last = segs.pop().slice(0, -1) + '.' + last;
244
242
  }
245
243
  while (segs.length && _isObject(obj)) {
@@ -305,7 +303,7 @@ export function _set(obj, path, value) {
305
303
  a[c]
306
304
  : // No: create the key. Is the next key a potential array-index?
307
305
  (a[c] =
308
- // @ts-ignore
306
+ // @ts-expect-error
309
307
  // eslint-disable-next-line
310
308
  Math.abs(path[i + 1]) >> 0 === +path[i + 1]
311
309
  ? [] // Yes: assign a new array object
@@ -17,13 +17,11 @@ export function _safeJsonStringify(obj, replacer, spaces, cycleReplacer) {
17
17
  function serializer(replacer, cycleReplacer) {
18
18
  const stack = [];
19
19
  const keys = [];
20
- if (cycleReplacer == null) {
21
- cycleReplacer = function (key, value) {
22
- if (stack[0] === value)
23
- return '[Circular ~]';
24
- return '[Circular ~.' + keys.slice(0, stack.indexOf(value)).join('.') + ']';
25
- };
26
- }
20
+ cycleReplacer !== null && cycleReplacer !== void 0 ? cycleReplacer : (cycleReplacer = function (key, value) {
21
+ if (stack[0] === value)
22
+ return '[Circular ~]';
23
+ return '[Circular ~.' + keys.slice(0, stack.indexOf(value)).join('.') + ']';
24
+ });
27
25
  return function (key, value) {
28
26
  if (stack.length > 0) {
29
27
  const thisPos = stack.indexOf(this);
@@ -53,7 +53,8 @@ export function _stringifyAny(obj, opt = {}) {
53
53
  // This is to fix the rare error (happened with Got) where `err.message` was changed,
54
54
  // but err.stack had "old" err.message
55
55
  // This should "fix" that
56
- s = [s, ...obj.stack.split('\n').slice(1)].join('\n');
56
+ const sLines = s.split('\n').length;
57
+ s = [s, ...obj.stack.split('\n').slice(sLines)].join('\n');
57
58
  }
58
59
  if (_isErrorObject(obj)) {
59
60
  if (_isHttpErrorObject(obj)) {
@@ -14,7 +14,7 @@
14
14
  export function _parseQueryString(search) {
15
15
  const qs = {};
16
16
  search
17
- .slice(search[0] === '?' ? 1 : 0)
17
+ .slice(search.startsWith('?') ? 1 : 0)
18
18
  .split('&')
19
19
  .forEach(p => {
20
20
  const [k, v] = p.split('=');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@naturalcycles/js-lib",
3
- "version": "14.117.0",
3
+ "version": "14.118.0",
4
4
  "scripts": {
5
5
  "prepare": "husky install",
6
6
  "build-prod": "build-prod-esm-cjs",
@@ -164,24 +164,24 @@ export function _findLast<T>(items: T[], predicate: Predicate<T>): T | undefined
164
164
 
165
165
  export function _takeWhile<T>(items: T[], predicate: Predicate<T>): T[] {
166
166
  let proceed = true
167
- return items.filter((v, index) => (proceed = proceed && predicate(v, index)))
167
+ return items.filter((v, index) => (proceed &&= predicate(v, index)))
168
168
  }
169
169
 
170
170
  export function _takeRightWhile<T>(items: T[], predicate: Predicate<T>): T[] {
171
171
  let proceed = true
172
- return [...items].reverse().filter((v, index) => (proceed = proceed && predicate(v, index)))
172
+ return [...items].reverse().filter((v, index) => (proceed &&= predicate(v, index)))
173
173
  }
174
174
 
175
175
  export function _dropWhile<T>(items: T[], predicate: Predicate<T>): T[] {
176
176
  let proceed = false
177
- return items.filter((v, index) => (proceed = proceed || !predicate(v, index)))
177
+ return items.filter((v, index) => (proceed ||= !predicate(v, index)))
178
178
  }
179
179
 
180
180
  export function _dropRightWhile<T>(items: T[], predicate: Predicate<T>): T[] {
181
181
  let proceed = false
182
182
  return [...items]
183
183
  .reverse()
184
- .filter((v, index) => (proceed = proceed || !predicate(v, index)))
184
+ .filter((v, index) => (proceed ||= !predicate(v, index)))
185
185
  .reverse()
186
186
  }
187
187
 
@@ -58,6 +58,7 @@ export class DateInterval {
58
58
  */
59
59
  includes(d: LocalDateConfig, incl: Inclusiveness = '[]'): boolean {
60
60
  d = LocalDate.of(d)
61
+ // eslint-disable-next-line @typescript-eslint/prefer-string-starts-ends-with
61
62
  return d.isAfter(this.start, incl[0] === '[') && d.isBefore(this.end, incl[1] === ']')
62
63
  }
63
64
 
@@ -154,6 +154,7 @@ export class LocalDate {
154
154
  const $max = LocalDate.of(max).startOf(stepUnit)
155
155
 
156
156
  let current = $min.startOf(stepUnit)
157
+ // eslint-disable-next-line @typescript-eslint/prefer-string-starts-ends-with
157
158
  if (current.isAfter($min, incl[0] === '[')) {
158
159
  // ok
159
160
  } else {
@@ -228,6 +229,7 @@ export class LocalDate {
228
229
 
229
230
  isBetween(min: LocalDateConfig, max: LocalDateConfig, incl: Inclusiveness = '[)'): boolean {
230
231
  let r = this.cmp(min)
232
+ // eslint-disable-next-line @typescript-eslint/prefer-string-starts-ends-with
231
233
  if (r < 0 || (r === 0 && incl[0] === '(')) return false
232
234
  r = this.cmp(max)
233
235
  if (r > 0 || (r === 0 && incl[1] === ')')) return false