@naturalcycles/js-lib 14.134.0 → 14.136.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 (54) hide show
  1. package/dist/decorators/logMethod.decorator.js +2 -2
  2. package/dist/env.d.ts +14 -0
  3. package/dist/env.js +23 -0
  4. package/dist/error/error.util.d.ts +1 -1
  5. package/dist/error/error.util.js +2 -0
  6. package/dist/error/tryCatch.js +1 -3
  7. package/dist/http/fetcher.d.ts +2 -0
  8. package/dist/http/fetcher.js +104 -92
  9. package/dist/http/fetcher.model.d.ts +14 -3
  10. package/dist/index.d.ts +2 -0
  11. package/dist/index.js +2 -0
  12. package/dist/promise/abortable.d.ts +20 -0
  13. package/dist/promise/abortable.js +36 -0
  14. package/dist/promise/pDefer.d.ts +14 -1
  15. package/dist/promise/pDefer.js +2 -0
  16. package/dist/promise/pDelay.d.ts +18 -0
  17. package/dist/promise/pDelay.js +37 -2
  18. package/dist/promise/pRetry.d.ts +0 -8
  19. package/dist/promise/pRetry.js +37 -63
  20. package/dist/promise/pTimeout.d.ts +4 -6
  21. package/dist/promise/pTimeout.js +8 -10
  22. package/dist/string/stringifyAny.d.ts +0 -6
  23. package/dist/string/stringifyAny.js +0 -5
  24. package/dist/types.d.ts +3 -0
  25. package/dist/vendor/is.d.ts +2 -2
  26. package/dist-esm/decorators/logMethod.decorator.js +2 -2
  27. package/dist-esm/env.js +18 -0
  28. package/dist-esm/error/error.util.js +2 -0
  29. package/dist-esm/error/tryCatch.js +2 -4
  30. package/dist-esm/http/fetcher.js +111 -98
  31. package/dist-esm/index.js +2 -0
  32. package/dist-esm/promise/abortable.js +32 -0
  33. package/dist-esm/promise/pDefer.js +2 -0
  34. package/dist-esm/promise/pDelay.js +35 -1
  35. package/dist-esm/promise/pRetry.js +38 -61
  36. package/dist-esm/promise/pTimeout.js +8 -7
  37. package/dist-esm/string/stringifyAny.js +0 -5
  38. package/package.json +1 -1
  39. package/src/decorators/logMethod.decorator.ts +2 -2
  40. package/src/env.ts +19 -0
  41. package/src/error/error.util.ts +3 -1
  42. package/src/error/tryCatch.ts +2 -6
  43. package/src/http/fetcher.model.ts +14 -3
  44. package/src/http/fetcher.ts +117 -95
  45. package/src/index.ts +2 -0
  46. package/src/promise/abortable.ts +34 -0
  47. package/src/promise/pDefer.ts +19 -1
  48. package/src/promise/pDelay.ts +44 -2
  49. package/src/promise/pRetry.ts +41 -89
  50. package/src/promise/pState.ts +1 -1
  51. package/src/promise/pTimeout.ts +12 -14
  52. package/src/string/stringifyAny.ts +0 -13
  53. package/src/types.ts +3 -0
  54. package/src/vendor/is.ts +3 -3
@@ -80,10 +80,10 @@ function logFinished(logger, callSignature, started, sma, logResultFn, res, err)
80
80
  t.push(`(avg ${(0, time_util_1._ms)(sma.push(millis))})`);
81
81
  }
82
82
  if (err !== undefined) {
83
- t.push('ERROR:', (0, __1._stringifyAny)(err, { includeErrorData: true }));
83
+ t.push('ERROR:', err);
84
84
  }
85
85
  else if (logResultFn) {
86
86
  t.push(...logResultFn(res));
87
87
  }
88
- logger.log(t.filter(Boolean).join(' '));
88
+ logger.log(...t.filter(Boolean));
89
89
  }
package/dist/env.d.ts ADDED
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Use it to detect SSR/Node.js environment.
3
+ *
4
+ * Will return `true` in Node.js.
5
+ * Will return `false` in the Browser.
6
+ */
7
+ export declare function isServerSide(): boolean;
8
+ /**
9
+ * Use it to detect Browser (not SSR/Node) environment.
10
+ *
11
+ * Will return `true` in the Browser.
12
+ * Will return `false` in Node.js.
13
+ */
14
+ export declare function isClientSide(): boolean;
package/dist/env.js ADDED
@@ -0,0 +1,23 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.isClientSide = exports.isServerSide = void 0;
4
+ /**
5
+ * Use it to detect SSR/Node.js environment.
6
+ *
7
+ * Will return `true` in Node.js.
8
+ * Will return `false` in the Browser.
9
+ */
10
+ function isServerSide() {
11
+ return typeof window === 'undefined';
12
+ }
13
+ exports.isServerSide = isServerSide;
14
+ /**
15
+ * Use it to detect Browser (not SSR/Node) environment.
16
+ *
17
+ * Will return `true` in the Browser.
18
+ * Will return `false` in Node.js.
19
+ */
20
+ function isClientSide() {
21
+ return typeof window !== 'undefined';
22
+ }
23
+ exports.isClientSide = isClientSide;
@@ -36,4 +36,4 @@ export declare function _isErrorObject(o: any): o is ErrorObject;
36
36
  * })
37
37
  * }
38
38
  */
39
- export declare function _errorDataAppend(err: any, data: ErrorData): void;
39
+ export declare function _errorDataAppend(err: any, data?: ErrorData): void;
@@ -155,6 +155,8 @@ exports._isErrorObject = _isErrorObject;
155
155
  * }
156
156
  */
157
157
  function _errorDataAppend(err, data) {
158
+ if (!data)
159
+ return;
158
160
  err.data = {
159
161
  ...err.data,
160
162
  ...data,
@@ -24,9 +24,7 @@ function _tryCatch(fn, opt = {}) {
24
24
  }
25
25
  catch (err) {
26
26
  if (logError) {
27
- logger.warn(`tryCatch.${fname} error in ${(0, index_1._since)(started)}:\n${(0, index_1._stringifyAny)(err, {
28
- includeErrorData: true,
29
- })}`);
27
+ logger.warn(`tryCatch.${fname} error in ${(0, index_1._since)(started)}:`, err);
30
28
  }
31
29
  if (onError) {
32
30
  try {
@@ -38,6 +38,8 @@ export declare class Fetcher {
38
38
  * Never throws, returns `err` property in the response instead.
39
39
  */
40
40
  rawFetch<T = unknown>(url: string, rawOpt?: FetcherOptions): Promise<FetcherResponse<T>>;
41
+ private onOkResponse;
42
+ private onNotOkResponse;
41
43
  private processRetry;
42
44
  /**
43
45
  * Default is yes,
@@ -2,6 +2,7 @@
2
2
  /// <reference lib="dom"/>
3
3
  Object.defineProperty(exports, "__esModule", { value: true });
4
4
  exports.getFetcher = exports.Fetcher = void 0;
5
+ const env_1 = require("../env");
5
6
  const error_util_1 = require("../error/error.util");
6
7
  const http_error_1 = require("../error/http.error");
7
8
  const number_util_1 = require("../number/number.util");
@@ -94,7 +95,7 @@ class Fetcher {
94
95
  async rawFetch(url, rawOpt = {}) {
95
96
  const { logger } = this.cfg;
96
97
  const req = this.normalizeOptions(url, rawOpt);
97
- const { timeoutSeconds, mode, init: { method }, } = req;
98
+ const { timeoutSeconds, init: { method }, } = req;
98
99
  // setup timeout
99
100
  let timeout;
100
101
  if (timeoutSeconds) {
@@ -107,6 +108,10 @@ class Fetcher {
107
108
  for await (const hook of this.cfg.hooks.beforeRequest || []) {
108
109
  await hook(req);
109
110
  }
111
+ const isFullUrl = req.url.includes('://');
112
+ const fullUrl = isFullUrl ? new URL(req.url) : undefined;
113
+ const shortUrl = fullUrl ? this.getShortUrl(fullUrl) : req.url;
114
+ const signature = [method, shortUrl].join(' ');
110
115
  const res = {
111
116
  req,
112
117
  retryStatus: {
@@ -114,10 +119,8 @@ class Fetcher {
114
119
  retryStopped: false,
115
120
  retryTimeout: req.retry.timeout,
116
121
  },
122
+ signature,
117
123
  };
118
- const fullUrl = new URL(req.url);
119
- const shortUrl = this.getShortUrl(fullUrl);
120
- const signature = [method, shortUrl].join(' ');
121
124
  /* eslint-disable no-await-in-loop */
122
125
  while (!res.retryStatus.retryStopped) {
123
126
  const started = Date.now();
@@ -141,95 +144,11 @@ class Fetcher {
141
144
  }
142
145
  res.statusFamily = this.getStatusFamily(res);
143
146
  if (res.fetchResponse?.ok) {
144
- if (mode === 'json') {
145
- if (res.fetchResponse.body) {
146
- const text = await res.fetchResponse.text();
147
- if (text) {
148
- try {
149
- res.body = text;
150
- res.body = JSON.parse(text, req.jsonReviver);
151
- }
152
- catch (err) {
153
- const { message } = (0, error_util_1._anyToError)(err);
154
- res.err = new http_error_1.HttpError([signature, message].join('\n'), {
155
- httpStatusCode: 0,
156
- url: req.url,
157
- });
158
- res.ok = false;
159
- }
160
- }
161
- else {
162
- // Body had a '' (empty string)
163
- res.body = {};
164
- }
165
- }
166
- else {
167
- // if no body: set responseBody as {}
168
- // do not throw a "cannot parse null as Json" error
169
- res.body = {};
170
- }
171
- }
172
- else if (mode === 'text') {
173
- res.body = res.fetchResponse.body ? await res.fetchResponse.text() : '';
174
- }
175
- else if (mode === 'arrayBuffer') {
176
- res.body = res.fetchResponse.body ? await res.fetchResponse.arrayBuffer() : {};
177
- }
178
- else if (mode === 'blob') {
179
- res.body = res.fetchResponse.body ? await res.fetchResponse.blob() : {};
180
- }
181
- clearTimeout(timeout);
182
- res.retryStatus.retryStopped = true;
183
- // res.err can happen on JSON.parse error
184
- if (!res.err && this.cfg.logResponse) {
185
- const { retryAttempt } = res.retryStatus;
186
- logger.log([
187
- ' <<',
188
- res.fetchResponse.status,
189
- signature,
190
- retryAttempt && `try#${retryAttempt + 1}/${req.retry.count + 1}`,
191
- (0, time_util_1._since)(started),
192
- ]
193
- .filter(Boolean)
194
- .join(' '));
195
- if (this.cfg.logResponseBody) {
196
- logger.log(res.body);
197
- }
198
- }
147
+ await this.onOkResponse(res, started, timeout);
199
148
  }
200
149
  else {
201
150
  // !res.ok
202
- clearTimeout(timeout);
203
- let errObj;
204
- if (res.fetchResponse) {
205
- const body = (0, json_util_1._jsonParseIfPossible)(await res.fetchResponse.text());
206
- errObj = (0, error_util_1._anyToErrorObject)(body);
207
- }
208
- else if (res.err) {
209
- errObj = (0, error_util_1._errorToErrorObject)(res.err);
210
- }
211
- else {
212
- errObj = {};
213
- }
214
- const originalMessage = errObj.message;
215
- errObj.message = [
216
- [res.fetchResponse?.status, signature].filter(Boolean).join(' '),
217
- originalMessage,
218
- ]
219
- .filter(Boolean)
220
- .join('\n');
221
- res.err = new http_error_1.HttpError(errObj.message, (0, object_util_1._filterNullishValues)({
222
- ...errObj.data,
223
- originalMessage,
224
- httpStatusCode: res.fetchResponse?.status || 0,
225
- // These properties are provided to be used in e.g custom Sentry error grouping
226
- // Actually, disabled now, to avoid unnecessary error printing when both msg and data are printed
227
- // Enabled, cause `data` is not printed by default when error is HttpError
228
- // method: req.method,
229
- url: req.url,
230
- // tryCount: req.tryCount,
231
- }));
232
- await this.processRetry(res);
151
+ await this.onNotOkResponse(res, timeout);
233
152
  }
234
153
  }
235
154
  for await (const hook of this.cfg.hooks.afterResponse || []) {
@@ -237,6 +156,99 @@ class Fetcher {
237
156
  }
238
157
  return res;
239
158
  }
159
+ async onOkResponse(res, started, timeout) {
160
+ const { req } = res;
161
+ const { mode } = res.req;
162
+ if (mode === 'json') {
163
+ if (res.fetchResponse.body) {
164
+ const text = await res.fetchResponse.text();
165
+ if (text) {
166
+ try {
167
+ res.body = text;
168
+ res.body = JSON.parse(text, req.jsonReviver);
169
+ }
170
+ catch (err) {
171
+ const { message } = (0, error_util_1._anyToError)(err);
172
+ res.err = new http_error_1.HttpError([res.signature, message].join('\n'), {
173
+ httpStatusCode: 0,
174
+ url: req.url,
175
+ });
176
+ res.ok = false;
177
+ }
178
+ }
179
+ else {
180
+ // Body had a '' (empty string)
181
+ res.body = {};
182
+ }
183
+ }
184
+ else {
185
+ // if no body: set responseBody as {}
186
+ // do not throw a "cannot parse null as Json" error
187
+ res.body = {};
188
+ }
189
+ }
190
+ else if (mode === 'text') {
191
+ res.body = res.fetchResponse.body ? await res.fetchResponse.text() : '';
192
+ }
193
+ else if (mode === 'arrayBuffer') {
194
+ res.body = res.fetchResponse.body ? await res.fetchResponse.arrayBuffer() : {};
195
+ }
196
+ else if (mode === 'blob') {
197
+ res.body = res.fetchResponse.body ? await res.fetchResponse.blob() : {};
198
+ }
199
+ clearTimeout(timeout);
200
+ res.retryStatus.retryStopped = true;
201
+ // res.err can happen on JSON.parse error
202
+ if (!res.err && this.cfg.logResponse) {
203
+ const { retryAttempt } = res.retryStatus;
204
+ const { logger } = this.cfg;
205
+ logger.log([
206
+ ' <<',
207
+ res.fetchResponse.status,
208
+ res.signature,
209
+ retryAttempt && `try#${retryAttempt + 1}/${req.retry.count + 1}`,
210
+ (0, time_util_1._since)(started),
211
+ ]
212
+ .filter(Boolean)
213
+ .join(' '));
214
+ if (this.cfg.logResponseBody) {
215
+ logger.log(res.body);
216
+ }
217
+ }
218
+ }
219
+ async onNotOkResponse(res, timeout) {
220
+ clearTimeout(timeout);
221
+ let errObj;
222
+ if (res.fetchResponse) {
223
+ const body = (0, json_util_1._jsonParseIfPossible)(await res.fetchResponse.text());
224
+ errObj = (0, error_util_1._anyToErrorObject)(body);
225
+ }
226
+ else if (res.err) {
227
+ errObj = (0, error_util_1._errorToErrorObject)(res.err);
228
+ }
229
+ else {
230
+ errObj = {};
231
+ }
232
+ const originalMessage = errObj.message;
233
+ errObj.message = [
234
+ [res.fetchResponse?.status, res.signature].filter(Boolean).join(' '),
235
+ originalMessage,
236
+ ]
237
+ .filter(Boolean)
238
+ .join('\n');
239
+ res.err = new http_error_1.HttpError(errObj.message, (0, object_util_1._filterNullishValues)({
240
+ ...errObj.data,
241
+ originalMessage,
242
+ httpStatusCode: res.fetchResponse?.status || 0,
243
+ // These properties are provided to be used in e.g custom Sentry error grouping
244
+ // Actually, disabled now, to avoid unnecessary error printing when both msg and data are printed
245
+ // Enabled, cause `data` is not printed by default when error is HttpError
246
+ // method: req.method,
247
+ url: res.req.url,
248
+ // tryCount: req.tryCount,
249
+ }));
250
+ await this.processRetry(res);
251
+ }
240
252
  async processRetry(res) {
241
253
  const { retryStatus } = res;
242
254
  if (!this.shouldRetry(res)) {
@@ -307,7 +319,7 @@ class Fetcher {
307
319
  if (!this.cfg.logWithSearchParams) {
308
320
  shortUrl = shortUrl.split('?')[0];
309
321
  }
310
- if (!this.cfg.logWithPrefixUrl && baseUrl && shortUrl.startsWith(baseUrl)) {
322
+ if (!this.cfg.logWithBaseUrl && baseUrl && shortUrl.startsWith(baseUrl)) {
311
323
  shortUrl = shortUrl.slice(baseUrl.length);
312
324
  }
313
325
  return shortUrl;
@@ -334,7 +346,7 @@ class Fetcher {
334
346
  logRequestBody: debug,
335
347
  logResponse: debug,
336
348
  logResponseBody: debug,
337
- logWithPrefixUrl: true,
349
+ logWithBaseUrl: (0, env_1.isServerSide)(),
338
350
  logWithSearchParams: true,
339
351
  retry: { ...defRetryOptions },
340
352
  init: {
@@ -43,10 +43,19 @@ export interface FetcherCfg {
43
43
  logResponse?: boolean;
44
44
  logResponseBody?: boolean;
45
45
  /**
46
- * Default to true.
47
- * Set to false to exclude `prefixUrl` from logs (both success and error)
46
+ * Controls if `baseUrl` should be included in logs (both success and error).
47
+ *
48
+ * Defaults to `true` on ServerSide and `false` on ClientSide.
49
+ *
50
+ * Reasoning.
51
+ *
52
+ * ClientSide often uses one main "backend host".
53
+ * Not including baseUrl improves Sentry error grouping.
54
+ *
55
+ * ServerSide often uses one Fetcher instance per 3rd-party API.
56
+ * Not including baseUrl can introduce confusion of "which API is it?".
48
57
  */
49
- logWithPrefixUrl?: boolean;
58
+ logWithBaseUrl?: boolean;
50
59
  /**
51
60
  * Default to true.
52
61
  * Set to false to strip searchParams from url when logging (both success and error)
@@ -138,6 +147,7 @@ export interface FetcherSuccessResponse<BODY = unknown> {
138
147
  req: FetcherRequest;
139
148
  statusFamily?: HttpStatusFamily;
140
149
  retryStatus: FetcherRetryStatus;
150
+ signature: string;
141
151
  }
142
152
  export interface FetcherErrorResponse<BODY = unknown> {
143
153
  ok: false;
@@ -147,6 +157,7 @@ export interface FetcherErrorResponse<BODY = unknown> {
147
157
  req: FetcherRequest;
148
158
  statusFamily?: HttpStatusFamily;
149
159
  retryStatus: FetcherRetryStatus;
160
+ signature: string;
150
161
  }
151
162
  export type FetcherResponse<BODY = unknown> = FetcherSuccessResponse<BODY> | FetcherErrorResponse<BODY>;
152
163
  export type FetcherMode = 'json' | 'text' | 'void' | 'arrayBuffer' | 'blob';
package/dist/index.d.ts CHANGED
@@ -61,6 +61,7 @@ export * from './unit/size.util';
61
61
  export * from './log/commonLogger';
62
62
  export * from './string/safeJsonStringify';
63
63
  export * from './promise/pQueue';
64
+ export * from './promise/abortable';
64
65
  export * from './seq/seq';
65
66
  export * from './math/stack.util';
66
67
  export * from './string/leven';
@@ -72,6 +73,7 @@ export * from './datetime/localDate';
72
73
  export * from './datetime/localTime';
73
74
  export * from './datetime/dateInterval';
74
75
  export * from './datetime/timeInterval';
76
+ export * from './env';
75
77
  export * from './http/http.model';
76
78
  export * from './http/fetcher';
77
79
  export * from './http/fetcher.model';
package/dist/index.js CHANGED
@@ -65,6 +65,7 @@ tslib_1.__exportStar(require("./unit/size.util"), exports);
65
65
  tslib_1.__exportStar(require("./log/commonLogger"), exports);
66
66
  tslib_1.__exportStar(require("./string/safeJsonStringify"), exports);
67
67
  tslib_1.__exportStar(require("./promise/pQueue"), exports);
68
+ tslib_1.__exportStar(require("./promise/abortable"), exports);
68
69
  tslib_1.__exportStar(require("./seq/seq"), exports);
69
70
  tslib_1.__exportStar(require("./math/stack.util"), exports);
70
71
  tslib_1.__exportStar(require("./string/leven"), exports);
@@ -76,6 +77,7 @@ tslib_1.__exportStar(require("./datetime/localDate"), exports);
76
77
  tslib_1.__exportStar(require("./datetime/localTime"), exports);
77
78
  tslib_1.__exportStar(require("./datetime/dateInterval"), exports);
78
79
  tslib_1.__exportStar(require("./datetime/timeInterval"), exports);
80
+ tslib_1.__exportStar(require("./env"), exports);
79
81
  tslib_1.__exportStar(require("./http/http.model"), exports);
80
82
  tslib_1.__exportStar(require("./http/fetcher"), exports);
81
83
  tslib_1.__exportStar(require("./http/fetcher.model"), exports);
@@ -0,0 +1,20 @@
1
+ import { AnyFunction } from '../types';
2
+ /**
3
+ * Similar to AbortController and AbortSignal.
4
+ * Similar to pDefer and Promise.
5
+ * Similar to Subject and Observable.
6
+ *
7
+ * Minimal interface for something that can be aborted in the future,
8
+ * but not necessary.
9
+ * Allows to listen to `onAbort` event.
10
+ *
11
+ * @experimental
12
+ */
13
+ export declare class Abortable {
14
+ onAbort?: AnyFunction<any> | undefined;
15
+ constructor(onAbort?: AnyFunction<any> | undefined);
16
+ aborted: boolean;
17
+ abort(): void;
18
+ clear(): void;
19
+ }
20
+ export declare function abortable(onAbort?: AnyFunction): Abortable;
@@ -0,0 +1,36 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.abortable = exports.Abortable = void 0;
4
+ /**
5
+ * Similar to AbortController and AbortSignal.
6
+ * Similar to pDefer and Promise.
7
+ * Similar to Subject and Observable.
8
+ *
9
+ * Minimal interface for something that can be aborted in the future,
10
+ * but not necessary.
11
+ * Allows to listen to `onAbort` event.
12
+ *
13
+ * @experimental
14
+ */
15
+ class Abortable {
16
+ constructor(onAbort) {
17
+ this.onAbort = onAbort;
18
+ this.aborted = false;
19
+ }
20
+ abort() {
21
+ if (this.aborted)
22
+ return;
23
+ this.aborted = true;
24
+ this.onAbort?.();
25
+ this.onAbort = undefined; // cleanup listener
26
+ }
27
+ clear() {
28
+ this.onAbort = undefined;
29
+ }
30
+ }
31
+ exports.Abortable = Abortable;
32
+ // convenience function
33
+ function abortable(onAbort) {
34
+ return new Abortable(onAbort);
35
+ }
36
+ exports.abortable = abortable;
@@ -3,7 +3,20 @@
3
3
  */
4
4
  export interface DeferredPromise<T = void> extends Promise<T> {
5
5
  resolve: (a?: T) => void;
6
- reject: (e?: Error) => void;
6
+ reject: (err?: Error) => void;
7
+ /**
8
+ * Can be overridden.
9
+ * Otherwise will reject with "Aborted" or "Aborted: $reason" on abort().
10
+ *
11
+ * @experimental
12
+ */
13
+ abort: (reason?: string) => void;
14
+ /**
15
+ * Rejects the promise with `new Error('Aborted: $reason')`.
16
+ *
17
+ * @experimental
18
+ */
19
+ rejectAborted: (reason?: string) => void;
7
20
  }
8
21
  /**
9
22
  * Returns DeferredPromise - a Promise that has .resolve() and .reject() methods.
@@ -14,6 +14,8 @@ function pDefer() {
14
14
  });
15
15
  promise.resolve = resolve;
16
16
  promise.reject = reject;
17
+ promise.rejectAborted = reason => reject(new Error(['Aborted', reason].filter(Boolean).join(': ')));
18
+ promise.abort = reason => promise.rejectAborted(reason);
17
19
  return promise;
18
20
  }
19
21
  exports.pDefer = pDefer;
@@ -1 +1,19 @@
1
+ import type { PromisableFunction } from '../types';
2
+ import { DeferredPromise } from './pDefer';
3
+ /**
4
+ * Promisified version of setTimeout.
5
+ *
6
+ * Can return a value.
7
+ * If value is instanceof Error - rejects the Promise instead of resolving.
8
+ */
1
9
  export declare function pDelay<T>(ms?: number, value?: T): Promise<T>;
10
+ /**
11
+ * Promisified version of setTimeout.
12
+ *
13
+ * Wraps the passed function with try/catch,
14
+ * catch will propagate to pDelayFn rejection,
15
+ * otherwise pDelayFn will resolve with returned value.
16
+ *
17
+ * On abort() - clears the Timeout and immediately resolves the Promise with void.
18
+ */
19
+ export declare function pDelayFn<T>(ms: number | undefined, fn: PromisableFunction<T>): DeferredPromise<T>;
@@ -1,7 +1,42 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.pDelay = void 0;
3
+ exports.pDelayFn = exports.pDelay = void 0;
4
+ const pDefer_1 = require("./pDefer");
5
+ /**
6
+ * Promisified version of setTimeout.
7
+ *
8
+ * Can return a value.
9
+ * If value is instanceof Error - rejects the Promise instead of resolving.
10
+ */
4
11
  async function pDelay(ms = 0, value) {
5
- return await new Promise(resolve => setTimeout(() => resolve(value), ms));
12
+ return await new Promise((resolve, reject) => setTimeout(value instanceof Error ? reject : resolve, ms, value));
6
13
  }
7
14
  exports.pDelay = pDelay;
15
+ /* eslint-disable @typescript-eslint/promise-function-async */
16
+ /**
17
+ * Promisified version of setTimeout.
18
+ *
19
+ * Wraps the passed function with try/catch,
20
+ * catch will propagate to pDelayFn rejection,
21
+ * otherwise pDelayFn will resolve with returned value.
22
+ *
23
+ * On abort() - clears the Timeout and immediately resolves the Promise with void.
24
+ */
25
+ function pDelayFn(ms = 0, fn) {
26
+ const p = (0, pDefer_1.pDefer)();
27
+ const timer = setTimeout(async () => {
28
+ try {
29
+ p.resolve(await fn());
30
+ }
31
+ catch (err) {
32
+ p.reject(err);
33
+ }
34
+ }, ms);
35
+ p.abort = () => {
36
+ clearTimeout(timer);
37
+ // p.rejectAborted(reason) // nope
38
+ p.resolve();
39
+ };
40
+ return p;
41
+ }
42
+ exports.pDelayFn = pDelayFn;
@@ -68,14 +68,6 @@ export interface PRetryOptions {
68
68
  * Default to `console`
69
69
  */
70
70
  logger?: CommonLogger;
71
- /**
72
- * Defaults to true.
73
- * If true - preserves the stack trace in case of a Timeout (usually - very useful!).
74
- * It has a certain perf cost.
75
- *
76
- * @experimental
77
- */
78
- keepStackTrace?: boolean;
79
71
  /**
80
72
  * Will be merged with `err.data` object.
81
73
  */