@naturalcycles/js-lib 14.135.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 (42) hide show
  1. package/dist/decorators/logMethod.decorator.js +2 -2
  2. package/dist/error/error.util.d.ts +1 -1
  3. package/dist/error/error.util.js +2 -0
  4. package/dist/error/tryCatch.js +1 -3
  5. package/dist/index.d.ts +1 -0
  6. package/dist/index.js +1 -0
  7. package/dist/promise/abortable.d.ts +20 -0
  8. package/dist/promise/abortable.js +36 -0
  9. package/dist/promise/pDefer.d.ts +14 -1
  10. package/dist/promise/pDefer.js +2 -0
  11. package/dist/promise/pDelay.d.ts +18 -0
  12. package/dist/promise/pDelay.js +37 -2
  13. package/dist/promise/pRetry.d.ts +0 -8
  14. package/dist/promise/pRetry.js +37 -63
  15. package/dist/promise/pTimeout.d.ts +4 -6
  16. package/dist/promise/pTimeout.js +8 -10
  17. package/dist/string/stringifyAny.d.ts +0 -6
  18. package/dist/string/stringifyAny.js +0 -5
  19. package/dist/types.d.ts +3 -0
  20. package/dist-esm/decorators/logMethod.decorator.js +2 -2
  21. package/dist-esm/error/error.util.js +2 -0
  22. package/dist-esm/error/tryCatch.js +2 -4
  23. package/dist-esm/index.js +1 -0
  24. package/dist-esm/promise/abortable.js +32 -0
  25. package/dist-esm/promise/pDefer.js +2 -0
  26. package/dist-esm/promise/pDelay.js +35 -1
  27. package/dist-esm/promise/pRetry.js +38 -61
  28. package/dist-esm/promise/pTimeout.js +8 -7
  29. package/dist-esm/string/stringifyAny.js +0 -5
  30. package/package.json +1 -1
  31. package/src/decorators/logMethod.decorator.ts +2 -2
  32. package/src/error/error.util.ts +3 -1
  33. package/src/error/tryCatch.ts +2 -6
  34. package/src/index.ts +1 -0
  35. package/src/promise/abortable.ts +34 -0
  36. package/src/promise/pDefer.ts +19 -1
  37. package/src/promise/pDelay.ts +44 -2
  38. package/src/promise/pRetry.ts +41 -89
  39. package/src/promise/pState.ts +1 -1
  40. package/src/promise/pTimeout.ts +12 -14
  41. package/src/string/stringifyAny.ts +0 -13
  42. package/src/types.ts +3 -0
@@ -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
  }
@@ -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 {
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';
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);
@@ -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
  */
@@ -2,7 +2,6 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.pRetry = exports.pRetryFn = void 0;
4
4
  const __1 = require("..");
5
- const pTimeout_1 = require("./pTimeout");
6
5
  /**
7
6
  * Returns a Function (!), enhanced with retry capabilities.
8
7
  * Implements "Exponential back-off strategy" by multiplying the delay by `delayMultiplier` with each try.
@@ -14,8 +13,8 @@ function pRetryFn(fn, opt = {}) {
14
13
  }
15
14
  exports.pRetryFn = pRetryFn;
16
15
  async function pRetry(fn, opt = {}) {
17
- const { maxAttempts = 4, delay: initialDelay = 1000, delayMultiplier = 2, predicate, logger = console, name, keepStackTrace = true, timeout, } = opt;
18
- const fakeError = keepStackTrace ? new Error('RetryError') : undefined;
16
+ const { maxAttempts = 4, delay: initialDelay = 1000, delayMultiplier = 2, predicate, logger = console, name, timeout, } = opt;
17
+ const fakeError = timeout ? new Error('TimeoutError') : undefined;
19
18
  let { logFirstAttempt = false, logRetries = true, logFailures = false, logSuccess = false } = opt;
20
19
  if (opt.logAll) {
21
20
  logSuccess = logFirstAttempt = logRetries = logFailures = true;
@@ -26,70 +25,45 @@ async function pRetry(fn, opt = {}) {
26
25
  const fname = name || fn.name || 'pRetry function';
27
26
  let delay = initialDelay;
28
27
  let attempt = 0;
29
- let timer;
30
- let timedOut = false;
31
- return await new Promise((resolve, reject) => {
32
- const rejectWithTimeout = () => {
33
- timedOut = true; // to prevent more tries
34
- const err = new pTimeout_1.TimeoutError(`"${fname}" timed out after ${timeout} ms`, opt.errorData);
35
- if (fakeError) {
36
- // keep original stack
37
- err.stack = fakeError.stack.replace('Error: RetryError', 'TimeoutError');
28
+ /* eslint-disable no-await-in-loop, no-constant-condition */
29
+ while (true) {
30
+ const started = Date.now();
31
+ try {
32
+ attempt++;
33
+ if ((attempt === 1 && logFirstAttempt) || (attempt > 1 && logRetries)) {
34
+ logger.log(`${fname} attempt #${attempt}...`);
38
35
  }
39
- reject(err);
40
- };
41
- const next = async () => {
42
- if (timedOut)
43
- return;
36
+ let result;
44
37
  if (timeout) {
45
- timer = setTimeout(rejectWithTimeout, timeout);
38
+ await (0, __1.pTimeout)(async () => await fn(attempt), {
39
+ timeout,
40
+ name: fname,
41
+ errorData: opt.errorData,
42
+ fakeError,
43
+ });
46
44
  }
47
- const started = Date.now();
48
- try {
49
- attempt++;
50
- if ((attempt === 1 && logFirstAttempt) || (attempt > 1 && logRetries)) {
51
- logger.log(`${fname} attempt #${attempt}...`);
52
- }
53
- const r = await fn(attempt);
54
- clearTimeout(timer);
55
- if (logSuccess) {
56
- logger.log(`${fname} attempt #${attempt} succeeded in ${(0, __1._since)(started)}`);
57
- }
58
- resolve(r);
45
+ else {
46
+ result = await fn(attempt);
59
47
  }
60
- catch (err) {
61
- clearTimeout(timer);
62
- if (logFailures) {
63
- logger.warn(`${fname} attempt #${attempt} error in ${(0, __1._since)(started)}:`, (0, __1._stringifyAny)(err, {
64
- includeErrorData: true,
65
- }));
66
- }
67
- if (attempt >= maxAttempts ||
68
- (predicate && !predicate(err, attempt, maxAttempts))) {
69
- // Give up
70
- if (fakeError) {
71
- // Preserve the original call stack
72
- Object.defineProperty(err, 'stack', {
73
- value: err.stack +
74
- '\n --' +
75
- fakeError.stack.replace('Error: RetryError', ''),
76
- });
77
- }
78
- ;
79
- err.data = {
80
- ...err.data,
81
- ...opt.errorData,
82
- };
83
- reject(err);
84
- }
85
- else {
86
- // Retry after delay
87
- delay *= delayMultiplier;
88
- setTimeout(next, delay);
89
- }
48
+ if (logSuccess) {
49
+ logger.log(`${fname} attempt #${attempt} succeeded in ${(0, __1._since)(started)}`);
90
50
  }
91
- };
92
- void next();
93
- });
51
+ return result;
52
+ }
53
+ catch (err) {
54
+ if (logFailures) {
55
+ logger.warn(`${fname} attempt #${attempt} error in ${(0, __1._since)(started)}:`, err);
56
+ }
57
+ if (attempt >= maxAttempts || (predicate && !predicate(err, attempt, maxAttempts))) {
58
+ // Give up
59
+ (0, __1._errorDataAppend)(err, opt.errorData);
60
+ throw err;
61
+ }
62
+ // Retry after delay
63
+ delay *= delayMultiplier;
64
+ await (0, __1.pDelay)(delay);
65
+ // back to while(true) loop
66
+ }
67
+ }
94
68
  }
95
69
  exports.pRetry = pRetry;
@@ -23,13 +23,11 @@ export interface PTimeoutOptions {
23
23
  */
24
24
  onTimeout?: (err: TimeoutError) => any;
25
25
  /**
26
- * Defaults to true.
27
- * If true - preserves the stack trace in case of a Timeout (usually - very useful!).
28
- * It has a certain perf cost.
29
- *
30
- * @experimental
26
+ * If passed - fakeError.stack will be used as a stacktrace.
27
+ * This is to "keep stacktrace" when pTimeout is called from another
28
+ * function (like pRetry).
31
29
  */
32
- keepStackTrace?: boolean;
30
+ fakeError?: Error;
33
31
  /**
34
32
  * Will be merged with `err.data` object.
35
33
  */
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.pTimeout = exports.pTimeoutFn = exports.TimeoutError = void 0;
4
4
  const app_error_1 = require("../error/app.error");
5
+ const error_util_1 = require("../error/error.util");
5
6
  class TimeoutError extends app_error_1.AppError {
6
7
  constructor(message, data = {}, opt) {
7
8
  super(message, data, opt, 'TimeoutError');
@@ -29,26 +30,23 @@ exports.pTimeoutFn = pTimeoutFn;
29
30
  * If the Function rejects - passes this rejection further.
30
31
  */
31
32
  async function pTimeout(fn, opt) {
32
- const { timeout, name = fn.name || 'pTimeout function', onTimeout, keepStackTrace = true } = opt;
33
- const fakeError = keepStackTrace ? new Error('TimeoutError') : undefined;
33
+ const { timeout, name = fn.name || 'pTimeout function', onTimeout } = opt;
34
+ const fakeError = opt.fakeError || new Error('TimeoutError');
34
35
  // eslint-disable-next-line no-async-promise-executor
35
36
  return await new Promise(async (resolve, reject) => {
36
37
  // Prepare the timeout timer
37
38
  const timer = setTimeout(() => {
38
39
  const err = new TimeoutError(`"${name}" timed out after ${timeout} ms`, opt.errorData);
39
- if (fakeError)
40
- err.stack = fakeError.stack; // keep original stack
40
+ // keep original stack
41
+ err.stack = fakeError.stack.replace('Error: TimeoutError', 'TimeoutError: ' + err.message);
41
42
  if (onTimeout) {
42
43
  try {
43
44
  resolve(onTimeout(err));
44
45
  }
45
46
  catch (err) {
46
- if (fakeError)
47
- err.stack = fakeError.stack; // keep original stack
48
- err.data = {
49
- ...err.data,
50
- ...opt.errorData,
51
- };
47
+ // keep original stack
48
+ err.stack = fakeError.stack.replace('Error: TimeoutError', err.name + ': ' + err.message);
49
+ (0, error_util_1._errorDataAppend)(err, opt.errorData);
52
50
  reject(err);
53
51
  }
54
52
  return;
@@ -20,12 +20,6 @@ export interface StringifyAnyOptions {
20
20
  * Default limit is less than in Node, cause it's likely to be used e.g in Browser alert()
21
21
  */
22
22
  maxLen?: number;
23
- /**
24
- * Pass true to include "stringified" `error.data` in the output.
25
- *
26
- * @default false
27
- */
28
- includeErrorData?: boolean;
29
23
  /**
30
24
  * Set to true to print Error.stack instead of just Error.message.
31
25
  *
@@ -86,11 +86,6 @@ function _stringifyAny(obj, opt = {}) {
86
86
  // `replace` here works ONCE, exactly as we need it
87
87
  s = s.replace('HttpError', `HttpError(${obj.data.httpStatusCode})`);
88
88
  }
89
- // Here we ensure it has `data`
90
- const { data } = obj;
91
- if (opt.includeErrorData && Object.keys(data).length > 0) {
92
- s = [s, _stringifyAny(data, opt)].join('\n');
93
- }
94
89
  }
95
90
  else if (typeof obj.code === 'string') {
96
91
  // Error that has no `data`, but has `code` property
package/dist/types.d.ts CHANGED
@@ -59,6 +59,9 @@ export type UnsavedId<T extends Partial<ObjectWithId>> = Omit<T, 'id'> & {
59
59
  */
60
60
  export type AnyFunction<T = any> = (...args: any[]) => T;
61
61
  export type AnyAsyncFunction<T = any> = (...args: any[]) => Promise<T>;
62
+ export type AsyncFunction<T = any> = () => Promise<T>;
63
+ export type AnyPromisableFunction<T = any> = (...args: any[]) => Promisable<T>;
64
+ export type PromisableFunction<T = any> = () => Promisable<T>;
62
65
  /**
63
66
  * Symbol to indicate END of Sequence.
64
67
  */
@@ -76,10 +76,10 @@ function logFinished(logger, callSignature, started, sma, logResultFn, res, err)
76
76
  t.push(`(avg ${_ms(sma.push(millis))})`);
77
77
  }
78
78
  if (err !== undefined) {
79
- t.push('ERROR:', _stringifyAny(err, { includeErrorData: true }));
79
+ t.push('ERROR:', err);
80
80
  }
81
81
  else if (logResultFn) {
82
82
  t.push(...logResultFn(res));
83
83
  }
84
- logger.log(t.filter(Boolean).join(' '));
84
+ logger.log(...t.filter(Boolean));
85
85
  }
@@ -143,5 +143,7 @@ export function _isErrorObject(o) {
143
143
  * }
144
144
  */
145
145
  export function _errorDataAppend(err, data) {
146
+ if (!data)
147
+ return;
146
148
  err.data = Object.assign(Object.assign({}, err.data), data);
147
149
  }
@@ -1,4 +1,4 @@
1
- import { _anyToError, _since, _stringifyAny } from '../index';
1
+ import { _anyToError, _since } from '../index';
2
2
  /**
3
3
  * Decorates a function with "try/catch", so it'll never reject/throw.
4
4
  * Only applies to async functions (or, turns sync function into async).
@@ -21,9 +21,7 @@ export function _tryCatch(fn, opt = {}) {
21
21
  }
22
22
  catch (err) {
23
23
  if (logError) {
24
- logger.warn(`tryCatch.${fname} error in ${_since(started)}:\n${_stringifyAny(err, {
25
- includeErrorData: true,
26
- })}`);
24
+ logger.warn(`tryCatch.${fname} error in ${_since(started)}:`, err);
27
25
  }
28
26
  if (onError) {
29
27
  try {
package/dist-esm/index.js 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';
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Similar to AbortController and AbortSignal.
3
+ * Similar to pDefer and Promise.
4
+ * Similar to Subject and Observable.
5
+ *
6
+ * Minimal interface for something that can be aborted in the future,
7
+ * but not necessary.
8
+ * Allows to listen to `onAbort` event.
9
+ *
10
+ * @experimental
11
+ */
12
+ export class Abortable {
13
+ constructor(onAbort) {
14
+ this.onAbort = onAbort;
15
+ this.aborted = false;
16
+ }
17
+ abort() {
18
+ var _a;
19
+ if (this.aborted)
20
+ return;
21
+ this.aborted = true;
22
+ (_a = this.onAbort) === null || _a === void 0 ? void 0 : _a.call(this);
23
+ this.onAbort = undefined; // cleanup listener
24
+ }
25
+ clear() {
26
+ this.onAbort = undefined;
27
+ }
28
+ }
29
+ // convenience function
30
+ export function abortable(onAbort) {
31
+ return new Abortable(onAbort);
32
+ }
@@ -11,5 +11,7 @@ export function pDefer() {
11
11
  });
12
12
  promise.resolve = resolve;
13
13
  promise.reject = reject;
14
+ promise.rejectAborted = reason => reject(new Error(['Aborted', reason].filter(Boolean).join(': ')));
15
+ promise.abort = reason => promise.rejectAborted(reason);
14
16
  return promise;
15
17
  }
@@ -1,3 +1,37 @@
1
+ import { pDefer } from './pDefer';
2
+ /**
3
+ * Promisified version of setTimeout.
4
+ *
5
+ * Can return a value.
6
+ * If value is instanceof Error - rejects the Promise instead of resolving.
7
+ */
1
8
  export async function pDelay(ms = 0, value) {
2
- return await new Promise(resolve => setTimeout(() => resolve(value), ms));
9
+ return await new Promise((resolve, reject) => setTimeout(value instanceof Error ? reject : resolve, ms, value));
10
+ }
11
+ /* eslint-disable @typescript-eslint/promise-function-async */
12
+ /**
13
+ * Promisified version of setTimeout.
14
+ *
15
+ * Wraps the passed function with try/catch,
16
+ * catch will propagate to pDelayFn rejection,
17
+ * otherwise pDelayFn will resolve with returned value.
18
+ *
19
+ * On abort() - clears the Timeout and immediately resolves the Promise with void.
20
+ */
21
+ export function pDelayFn(ms = 0, fn) {
22
+ const p = pDefer();
23
+ const timer = setTimeout(async () => {
24
+ try {
25
+ p.resolve(await fn());
26
+ }
27
+ catch (err) {
28
+ p.reject(err);
29
+ }
30
+ }, ms);
31
+ p.abort = () => {
32
+ clearTimeout(timer);
33
+ // p.rejectAborted(reason) // nope
34
+ p.resolve();
35
+ };
36
+ return p;
3
37
  }
@@ -1,5 +1,4 @@
1
- import { _since, _stringifyAny } from '..';
2
- import { TimeoutError } from './pTimeout';
1
+ import { _errorDataAppend, _since, pDelay, pTimeout } from '..';
3
2
  /**
4
3
  * Returns a Function (!), enhanced with retry capabilities.
5
4
  * Implements "Exponential back-off strategy" by multiplying the delay by `delayMultiplier` with each try.
@@ -10,8 +9,8 @@ export function pRetryFn(fn, opt = {}) {
10
9
  };
11
10
  }
12
11
  export async function pRetry(fn, opt = {}) {
13
- const { maxAttempts = 4, delay: initialDelay = 1000, delayMultiplier = 2, predicate, logger = console, name, keepStackTrace = true, timeout, } = opt;
14
- const fakeError = keepStackTrace ? new Error('RetryError') : undefined;
12
+ const { maxAttempts = 4, delay: initialDelay = 1000, delayMultiplier = 2, predicate, logger = console, name, timeout, } = opt;
13
+ const fakeError = timeout ? new Error('TimeoutError') : undefined;
15
14
  let { logFirstAttempt = false, logRetries = true, logFailures = false, logSuccess = false } = opt;
16
15
  if (opt.logAll) {
17
16
  logSuccess = logFirstAttempt = logRetries = logFailures = true;
@@ -22,66 +21,44 @@ export async function pRetry(fn, opt = {}) {
22
21
  const fname = name || fn.name || 'pRetry function';
23
22
  let delay = initialDelay;
24
23
  let attempt = 0;
25
- let timer;
26
- let timedOut = false;
27
- return await new Promise((resolve, reject) => {
28
- const rejectWithTimeout = () => {
29
- timedOut = true; // to prevent more tries
30
- const err = new TimeoutError(`"${fname}" timed out after ${timeout} ms`, opt.errorData);
31
- if (fakeError) {
32
- // keep original stack
33
- err.stack = fakeError.stack.replace('Error: RetryError', 'TimeoutError');
24
+ /* eslint-disable no-await-in-loop, no-constant-condition */
25
+ while (true) {
26
+ const started = Date.now();
27
+ try {
28
+ attempt++;
29
+ if ((attempt === 1 && logFirstAttempt) || (attempt > 1 && logRetries)) {
30
+ logger.log(`${fname} attempt #${attempt}...`);
34
31
  }
35
- reject(err);
36
- };
37
- const next = async () => {
38
- if (timedOut)
39
- return;
32
+ let result;
40
33
  if (timeout) {
41
- timer = setTimeout(rejectWithTimeout, timeout);
34
+ await pTimeout(async () => await fn(attempt), {
35
+ timeout,
36
+ name: fname,
37
+ errorData: opt.errorData,
38
+ fakeError,
39
+ });
42
40
  }
43
- const started = Date.now();
44
- try {
45
- attempt++;
46
- if ((attempt === 1 && logFirstAttempt) || (attempt > 1 && logRetries)) {
47
- logger.log(`${fname} attempt #${attempt}...`);
48
- }
49
- const r = await fn(attempt);
50
- clearTimeout(timer);
51
- if (logSuccess) {
52
- logger.log(`${fname} attempt #${attempt} succeeded in ${_since(started)}`);
53
- }
54
- resolve(r);
41
+ else {
42
+ result = await fn(attempt);
55
43
  }
56
- catch (err) {
57
- clearTimeout(timer);
58
- if (logFailures) {
59
- logger.warn(`${fname} attempt #${attempt} error in ${_since(started)}:`, _stringifyAny(err, {
60
- includeErrorData: true,
61
- }));
62
- }
63
- if (attempt >= maxAttempts ||
64
- (predicate && !predicate(err, attempt, maxAttempts))) {
65
- // Give up
66
- if (fakeError) {
67
- // Preserve the original call stack
68
- Object.defineProperty(err, 'stack', {
69
- value: err.stack +
70
- '\n --' +
71
- fakeError.stack.replace('Error: RetryError', ''),
72
- });
73
- }
74
- ;
75
- err.data = Object.assign(Object.assign({}, err.data), opt.errorData);
76
- reject(err);
77
- }
78
- else {
79
- // Retry after delay
80
- delay *= delayMultiplier;
81
- setTimeout(next, delay);
82
- }
44
+ if (logSuccess) {
45
+ logger.log(`${fname} attempt #${attempt} succeeded in ${_since(started)}`);
83
46
  }
84
- };
85
- void next();
86
- });
47
+ return result;
48
+ }
49
+ catch (err) {
50
+ if (logFailures) {
51
+ logger.warn(`${fname} attempt #${attempt} error in ${_since(started)}:`, err);
52
+ }
53
+ if (attempt >= maxAttempts || (predicate && !predicate(err, attempt, maxAttempts))) {
54
+ // Give up
55
+ _errorDataAppend(err, opt.errorData);
56
+ throw err;
57
+ }
58
+ // Retry after delay
59
+ delay *= delayMultiplier;
60
+ await pDelay(delay);
61
+ // back to while(true) loop
62
+ }
63
+ }
87
64
  }
@@ -1,4 +1,5 @@
1
1
  import { AppError } from '../error/app.error';
2
+ import { _errorDataAppend } from '../error/error.util';
2
3
  export class TimeoutError extends AppError {
3
4
  constructor(message, data = {}, opt) {
4
5
  super(message, data, opt, 'TimeoutError');
@@ -24,23 +25,23 @@ export function pTimeoutFn(fn, opt) {
24
25
  * If the Function rejects - passes this rejection further.
25
26
  */
26
27
  export async function pTimeout(fn, opt) {
27
- const { timeout, name = fn.name || 'pTimeout function', onTimeout, keepStackTrace = true } = opt;
28
- const fakeError = keepStackTrace ? new Error('TimeoutError') : undefined;
28
+ const { timeout, name = fn.name || 'pTimeout function', onTimeout } = opt;
29
+ const fakeError = opt.fakeError || new Error('TimeoutError');
29
30
  // eslint-disable-next-line no-async-promise-executor
30
31
  return await new Promise(async (resolve, reject) => {
31
32
  // Prepare the timeout timer
32
33
  const timer = setTimeout(() => {
33
34
  const err = new TimeoutError(`"${name}" timed out after ${timeout} ms`, opt.errorData);
34
- if (fakeError)
35
- err.stack = fakeError.stack; // keep original stack
35
+ // keep original stack
36
+ err.stack = fakeError.stack.replace('Error: TimeoutError', 'TimeoutError: ' + err.message);
36
37
  if (onTimeout) {
37
38
  try {
38
39
  resolve(onTimeout(err));
39
40
  }
40
41
  catch (err) {
41
- if (fakeError)
42
- err.stack = fakeError.stack; // keep original stack
43
- err.data = Object.assign(Object.assign({}, err.data), opt.errorData);
42
+ // keep original stack
43
+ err.stack = fakeError.stack.replace('Error: TimeoutError', err.name + ': ' + err.message);
44
+ _errorDataAppend(err, opt.errorData);
44
45
  reject(err);
45
46
  }
46
47
  return;
@@ -82,11 +82,6 @@ export function _stringifyAny(obj, opt = {}) {
82
82
  // `replace` here works ONCE, exactly as we need it
83
83
  s = s.replace('HttpError', `HttpError(${obj.data.httpStatusCode})`);
84
84
  }
85
- // Here we ensure it has `data`
86
- const { data } = obj;
87
- if (opt.includeErrorData && Object.keys(data).length > 0) {
88
- s = [s, _stringifyAny(data, opt)].join('\n');
89
- }
90
85
  }
91
86
  else if (typeof obj.code === 'string') {
92
87
  // Error that has no `data`, but has `code` property
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@naturalcycles/js-lib",
3
- "version": "14.135.0",
3
+ "version": "14.136.0",
4
4
  "scripts": {
5
5
  "prepare": "husky install",
6
6
  "build-prod": "build-prod-esm-cjs",
@@ -155,10 +155,10 @@ function logFinished(
155
155
  }
156
156
 
157
157
  if (err !== undefined) {
158
- t.push('ERROR:', _stringifyAny(err, { includeErrorData: true }))
158
+ t.push('ERROR:', err)
159
159
  } else if (logResultFn) {
160
160
  t.push(...logResultFn(res))
161
161
  }
162
162
 
163
- logger.log(t.filter(Boolean).join(' '))
163
+ logger.log(...t.filter(Boolean))
164
164
  }
@@ -181,7 +181,9 @@ export function _isErrorObject(o: any): o is ErrorObject {
181
181
  * })
182
182
  * }
183
183
  */
184
- export function _errorDataAppend(err: any, data: ErrorData): void {
184
+ export function _errorDataAppend(err: any, data?: ErrorData): void {
185
+ if (!data) return
186
+
185
187
  err.data = {
186
188
  ...err.data,
187
189
  ...data,
@@ -1,5 +1,5 @@
1
1
  import type { CommonLogger } from '../index'
2
- import { _anyToError, _since, _stringifyAny } from '../index'
2
+ import { _anyToError, _since } from '../index'
3
3
  import type { AnyFunction } from '../types'
4
4
 
5
5
  export interface TryCatchOptions {
@@ -51,11 +51,7 @@ export function _tryCatch<T extends AnyFunction>(fn: T, opt: TryCatchOptions = {
51
51
  return r
52
52
  } catch (err) {
53
53
  if (logError) {
54
- logger.warn(
55
- `tryCatch.${fname} error in ${_since(started)}:\n${_stringifyAny(err, {
56
- includeErrorData: true,
57
- })}`,
58
- )
54
+ logger.warn(`tryCatch.${fname} error in ${_since(started)}:`, err)
59
55
  }
60
56
 
61
57
  if (onError) {
package/src/index.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'
@@ -0,0 +1,34 @@
1
+ import { AnyFunction } from '../types'
2
+
3
+ /**
4
+ * Similar to AbortController and AbortSignal.
5
+ * Similar to pDefer and Promise.
6
+ * Similar to Subject and Observable.
7
+ *
8
+ * Minimal interface for something that can be aborted in the future,
9
+ * but not necessary.
10
+ * Allows to listen to `onAbort` event.
11
+ *
12
+ * @experimental
13
+ */
14
+ export class Abortable {
15
+ constructor(public onAbort?: AnyFunction) {}
16
+
17
+ aborted = false
18
+
19
+ abort(): void {
20
+ if (this.aborted) return
21
+ this.aborted = true
22
+ this.onAbort?.()
23
+ this.onAbort = undefined // cleanup listener
24
+ }
25
+
26
+ clear(): void {
27
+ this.onAbort = undefined
28
+ }
29
+ }
30
+
31
+ // convenience function
32
+ export function abortable(onAbort?: AnyFunction): Abortable {
33
+ return new Abortable(onAbort)
34
+ }
@@ -3,7 +3,22 @@
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
+ /**
9
+ * Can be overridden.
10
+ * Otherwise will reject with "Aborted" or "Aborted: $reason" on abort().
11
+ *
12
+ * @experimental
13
+ */
14
+ abort: (reason?: string) => void
15
+
16
+ /**
17
+ * Rejects the promise with `new Error('Aborted: $reason')`.
18
+ *
19
+ * @experimental
20
+ */
21
+ rejectAborted: (reason?: string) => void
7
22
  }
8
23
 
9
24
  /* eslint-disable @typescript-eslint/promise-function-async */
@@ -22,6 +37,9 @@ export function pDefer<T = void>(): DeferredPromise<T> {
22
37
 
23
38
  promise.resolve = resolve
24
39
  promise.reject = reject
40
+ promise.rejectAborted = reason =>
41
+ reject(new Error(['Aborted', reason].filter(Boolean).join(': ')))
42
+ promise.abort = reason => promise.rejectAborted(reason)
25
43
 
26
44
  return promise
27
45
  }
@@ -1,3 +1,45 @@
1
- export async function pDelay<T>(ms: number = 0, value?: T): Promise<T> {
2
- return await new Promise<T>(resolve => setTimeout(() => resolve(value as T), ms))
1
+ import type { PromisableFunction } from '../types'
2
+ import { DeferredPromise, pDefer } from './pDefer'
3
+
4
+ /**
5
+ * Promisified version of setTimeout.
6
+ *
7
+ * Can return a value.
8
+ * If value is instanceof Error - rejects the Promise instead of resolving.
9
+ */
10
+ export async function pDelay<T>(ms = 0, value?: T): Promise<T> {
11
+ return await new Promise<T>((resolve, reject) =>
12
+ setTimeout(value instanceof Error ? reject : resolve, ms, value),
13
+ )
14
+ }
15
+
16
+ /* eslint-disable @typescript-eslint/promise-function-async */
17
+
18
+ /**
19
+ * Promisified version of setTimeout.
20
+ *
21
+ * Wraps the passed function with try/catch,
22
+ * catch will propagate to pDelayFn rejection,
23
+ * otherwise pDelayFn will resolve with returned value.
24
+ *
25
+ * On abort() - clears the Timeout and immediately resolves the Promise with void.
26
+ */
27
+ export function pDelayFn<T>(ms = 0, fn: PromisableFunction<T>): DeferredPromise<T> {
28
+ const p = pDefer<T>()
29
+
30
+ const timer = setTimeout(async () => {
31
+ try {
32
+ p.resolve(await fn())
33
+ } catch (err) {
34
+ p.reject(err as Error)
35
+ }
36
+ }, ms)
37
+
38
+ p.abort = () => {
39
+ clearTimeout(timer)
40
+ // p.rejectAborted(reason) // nope
41
+ p.resolve()
42
+ }
43
+
44
+ return p
3
45
  }
@@ -1,6 +1,5 @@
1
- import type { AnyFunction, AppError, CommonLogger, ErrorData } from '..'
2
- import { _since, _stringifyAny } from '..'
3
- import { TimeoutError } from './pTimeout'
1
+ import type { AnyFunction, CommonLogger, ErrorData } from '..'
2
+ import { _errorDataAppend, _since, pDelay, pTimeout } from '..'
4
3
 
5
4
  export interface PRetryOptions {
6
5
  /**
@@ -84,15 +83,6 @@ export interface PRetryOptions {
84
83
  */
85
84
  logger?: CommonLogger
86
85
 
87
- /**
88
- * Defaults to true.
89
- * If true - preserves the stack trace in case of a Timeout (usually - very useful!).
90
- * It has a certain perf cost.
91
- *
92
- * @experimental
93
- */
94
- keepStackTrace?: boolean
95
-
96
86
  /**
97
87
  * Will be merged with `err.data` object.
98
88
  */
@@ -120,12 +110,10 @@ export async function pRetry<T>(
120
110
  predicate,
121
111
  logger = console,
122
112
  name,
123
- keepStackTrace = true,
124
113
  timeout,
125
114
  } = opt
126
115
 
127
- const fakeError = keepStackTrace ? new Error('RetryError') : undefined
128
-
116
+ const fakeError = timeout ? new Error('TimeoutError') : undefined
129
117
  let { logFirstAttempt = false, logRetries = true, logFailures = false, logSuccess = false } = opt
130
118
 
131
119
  if (opt.logAll) {
@@ -139,86 +127,50 @@ export async function pRetry<T>(
139
127
 
140
128
  let delay = initialDelay
141
129
  let attempt = 0
142
- let timer: NodeJS.Timeout | undefined
143
- let timedOut = false
144
-
145
- return await new Promise((resolve, reject) => {
146
- const rejectWithTimeout = () => {
147
- timedOut = true // to prevent more tries
148
- const err = new TimeoutError(`"${fname}" timed out after ${timeout} ms`, opt.errorData)
149
- if (fakeError) {
150
- // keep original stack
151
- err.stack = fakeError.stack!.replace('Error: RetryError', 'TimeoutError')
130
+
131
+ /* eslint-disable no-await-in-loop, no-constant-condition */
132
+ while (true) {
133
+ const started = Date.now()
134
+
135
+ try {
136
+ attempt++
137
+ if ((attempt === 1 && logFirstAttempt) || (attempt > 1 && logRetries)) {
138
+ logger.log(`${fname} attempt #${attempt}...`)
152
139
  }
153
- reject(err)
154
- }
155
140
 
156
- const next = async () => {
157
- if (timedOut) return
141
+ let result: any
158
142
 
159
143
  if (timeout) {
160
- timer = setTimeout(rejectWithTimeout, timeout)
144
+ await pTimeout(async () => await fn(attempt), {
145
+ timeout,
146
+ name: fname,
147
+ errorData: opt.errorData,
148
+ fakeError,
149
+ })
150
+ } else {
151
+ result = await fn(attempt)
161
152
  }
162
153
 
163
- const started = Date.now()
164
-
165
- try {
166
- attempt++
167
- if ((attempt === 1 && logFirstAttempt) || (attempt > 1 && logRetries)) {
168
- logger.log(`${fname} attempt #${attempt}...`)
169
- }
170
-
171
- const r = await fn(attempt)
172
-
173
- clearTimeout(timer)
174
-
175
- if (logSuccess) {
176
- logger.log(`${fname} attempt #${attempt} succeeded in ${_since(started)}`)
177
- }
178
-
179
- resolve(r)
180
- } catch (err) {
181
- clearTimeout(timer)
182
-
183
- if (logFailures) {
184
- logger.warn(
185
- `${fname} attempt #${attempt} error in ${_since(started)}:`,
186
- _stringifyAny(err, {
187
- includeErrorData: true,
188
- }),
189
- )
190
- }
191
-
192
- if (
193
- attempt >= maxAttempts ||
194
- (predicate && !predicate(err as Error, attempt, maxAttempts))
195
- ) {
196
- // Give up
197
-
198
- if (fakeError) {
199
- // Preserve the original call stack
200
- Object.defineProperty(err, 'stack', {
201
- value:
202
- (err as Error).stack +
203
- '\n --' +
204
- fakeError.stack!.replace('Error: RetryError', ''),
205
- })
206
- }
207
-
208
- ;(err as AppError).data = {
209
- ...(err as AppError).data,
210
- ...opt.errorData,
211
- }
212
-
213
- reject(err)
214
- } else {
215
- // Retry after delay
216
- delay *= delayMultiplier
217
- setTimeout(next, delay)
218
- }
154
+ if (logSuccess) {
155
+ logger.log(`${fname} attempt #${attempt} succeeded in ${_since(started)}`)
156
+ }
157
+
158
+ return result
159
+ } catch (err) {
160
+ if (logFailures) {
161
+ logger.warn(`${fname} attempt #${attempt} error in ${_since(started)}:`, err)
219
162
  }
220
- }
221
163
 
222
- void next()
223
- })
164
+ if (attempt >= maxAttempts || (predicate && !predicate(err as Error, attempt, maxAttempts))) {
165
+ // Give up
166
+ _errorDataAppend(err, opt.errorData)
167
+ throw err
168
+ }
169
+
170
+ // Retry after delay
171
+ delay *= delayMultiplier
172
+ await pDelay(delay)
173
+ // back to while(true) loop
174
+ }
175
+ }
224
176
  }
@@ -13,6 +13,6 @@ export async function pState(p: Promise<any>): Promise<'resolved' | 'rejected' |
13
13
  v => {
14
14
  return v === UNIQUE_VALUE ? 'pending' : 'resolved'
15
15
  },
16
- () => 'rejected' as const,
16
+ () => 'rejected',
17
17
  )
18
18
  }
@@ -1,5 +1,6 @@
1
1
  import { AppError } from '../error/app.error'
2
2
  import type { ErrorData } from '../error/error.model'
3
+ import { _errorDataAppend } from '../error/error.util'
3
4
  import type { AnyAsyncFunction } from '../types'
4
5
 
5
6
  export class TimeoutError extends AppError {
@@ -30,13 +31,11 @@ export interface PTimeoutOptions {
30
31
  onTimeout?: (err: TimeoutError) => any
31
32
 
32
33
  /**
33
- * Defaults to true.
34
- * If true - preserves the stack trace in case of a Timeout (usually - very useful!).
35
- * It has a certain perf cost.
36
- *
37
- * @experimental
34
+ * If passed - fakeError.stack will be used as a stacktrace.
35
+ * This is to "keep stacktrace" when pTimeout is called from another
36
+ * function (like pRetry).
38
37
  */
39
- keepStackTrace?: boolean
38
+ fakeError?: Error
40
39
 
41
40
  /**
42
41
  * Will be merged with `err.data` object.
@@ -66,25 +65,24 @@ export function pTimeoutFn<T extends AnyAsyncFunction>(fn: T, opt: PTimeoutOptio
66
65
  * If the Function rejects - passes this rejection further.
67
66
  */
68
67
  export async function pTimeout<T>(fn: AnyAsyncFunction<T>, opt: PTimeoutOptions): Promise<T> {
69
- const { timeout, name = fn.name || 'pTimeout function', onTimeout, keepStackTrace = true } = opt
70
- const fakeError = keepStackTrace ? new Error('TimeoutError') : undefined
68
+ const { timeout, name = fn.name || 'pTimeout function', onTimeout } = opt
69
+ const fakeError = opt.fakeError || new Error('TimeoutError')
71
70
 
72
71
  // eslint-disable-next-line no-async-promise-executor
73
72
  return await new Promise(async (resolve, reject) => {
74
73
  // Prepare the timeout timer
75
74
  const timer = setTimeout(() => {
76
75
  const err = new TimeoutError(`"${name}" timed out after ${timeout} ms`, opt.errorData)
77
- if (fakeError) err.stack = fakeError.stack // keep original stack
76
+ // keep original stack
77
+ err.stack = fakeError.stack!.replace('Error: TimeoutError', 'TimeoutError: ' + err.message)
78
78
 
79
79
  if (onTimeout) {
80
80
  try {
81
81
  resolve(onTimeout(err))
82
82
  } catch (err: any) {
83
- if (fakeError) err.stack = fakeError.stack // keep original stack
84
- err.data = {
85
- ...err.data,
86
- ...opt.errorData,
87
- }
83
+ // keep original stack
84
+ err.stack = fakeError.stack!.replace('Error: TimeoutError', err.name + ': ' + err.message)
85
+ _errorDataAppend(err, opt.errorData)
88
86
  reject(err)
89
87
  }
90
88
  return
@@ -33,13 +33,6 @@ export interface StringifyAnyOptions {
33
33
  */
34
34
  maxLen?: number
35
35
 
36
- /**
37
- * Pass true to include "stringified" `error.data` in the output.
38
- *
39
- * @default false
40
- */
41
- includeErrorData?: boolean
42
-
43
36
  /**
44
37
  * Set to true to print Error.stack instead of just Error.message.
45
38
  *
@@ -130,12 +123,6 @@ export function _stringifyAny(obj: any, opt: StringifyAnyOptions = {}): string {
130
123
  // `replace` here works ONCE, exactly as we need it
131
124
  s = s.replace('HttpError', `HttpError(${obj.data.httpStatusCode})`)
132
125
  }
133
-
134
- // Here we ensure it has `data`
135
- const { data } = obj
136
- if (opt.includeErrorData && Object.keys(data).length > 0) {
137
- s = [s, _stringifyAny(data, opt)].join('\n')
138
- }
139
126
  } else if (typeof (obj as any).code === 'string') {
140
127
  // Error that has no `data`, but has `code` property
141
128
  s = [s, `code: ${(obj as any).code}`].join('\n')
package/src/types.ts CHANGED
@@ -80,6 +80,9 @@ export type UnsavedId<T extends Partial<ObjectWithId>> = Omit<T, 'id'> & {
80
80
  */
81
81
  export type AnyFunction<T = any> = (...args: any[]) => T
82
82
  export type AnyAsyncFunction<T = any> = (...args: any[]) => Promise<T>
83
+ export type AsyncFunction<T = any> = () => Promise<T>
84
+ export type AnyPromisableFunction<T = any> = (...args: any[]) => Promisable<T>
85
+ export type PromisableFunction<T = any> = () => Promisable<T>
83
86
 
84
87
  /**
85
88
  * Symbol to indicate END of Sequence.