@naturalcycles/js-lib 14.80.1 → 14.83.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/decorators/asyncMemo.decorator.d.ts +22 -0
- package/dist/decorators/asyncMemo.decorator.js +96 -0
- package/dist/decorators/memo.decorator.d.ts +8 -0
- package/dist/decorators/memo.decorator.js +11 -6
- package/dist/decorators/memo.util.d.ts +27 -8
- package/dist/decorators/memo.util.js +1 -1
- package/dist/decorators/retry.decorator.js +1 -1
- package/dist/error/error.model.d.ts +6 -0
- package/dist/index.d.ts +5 -5
- package/dist/index.js +3 -2
- package/dist/promise/AggregatedError.d.ts +1 -1
- package/dist/promise/AggregatedError.js +2 -7
- package/dist/promise/pFilter.d.ts +2 -3
- package/dist/promise/pFilter.js +4 -4
- package/dist/promise/pMap.d.ts +1 -1
- package/dist/promise/pMap.js +67 -19
- package/dist/promise/pRetry.d.ts +17 -2
- package/dist/promise/pRetry.js +72 -40
- package/dist-esm/decorators/asyncMemo.decorator.js +104 -0
- package/dist-esm/decorators/memo.decorator.js +11 -5
- package/dist-esm/decorators/memo.util.js +1 -1
- package/dist-esm/decorators/retry.decorator.js +2 -2
- package/dist-esm/index.js +3 -3
- package/dist-esm/promise/AggregatedError.js +2 -7
- package/dist-esm/promise/pFilter.js +4 -4
- package/dist-esm/promise/pMap.js +79 -19
- package/dist-esm/promise/pRetry.js +70 -39
- package/package.json +1 -1
- package/src/decorators/asyncMemo.decorator.ts +151 -0
- package/src/decorators/memo.decorator.ts +16 -5
- package/src/decorators/memo.util.ts +36 -10
- package/src/decorators/retry.decorator.ts +2 -2
- package/src/error/error.model.ts +7 -0
- package/src/index.ts +5 -3
- package/src/promise/AggregatedError.ts +3 -8
- package/src/promise/pFilter.ts +5 -14
- package/src/promise/pMap.ts +72 -21
- package/src/promise/pRetry.ts +105 -41
- package/dist/promise/pBatch.d.ts +0 -7
- package/dist/promise/pBatch.js +0 -30
- package/dist-esm/promise/pBatch.js +0 -23
- package/src/promise/pBatch.ts +0 -31
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { Merge } from '../typeFest';
|
|
2
|
+
import { MemoOptions } from './memo.decorator';
|
|
3
|
+
import { AsyncMemoCache } from './memo.util';
|
|
4
|
+
export declare type AsyncMemoOptions = Merge<MemoOptions, {
|
|
5
|
+
/**
|
|
6
|
+
* Provide a custom implementation of MemoCache.
|
|
7
|
+
* Function that creates an instance of `MemoCache`.
|
|
8
|
+
* e.g LRUMemoCache from `@naturalcycles/nodejs-lib`.
|
|
9
|
+
*
|
|
10
|
+
* It's an ARRAY of Caches, to allow multiple layers of Cache.
|
|
11
|
+
* It will check it one by one, starting from the first.
|
|
12
|
+
* HIT will be returned immediately, MISS will go one level deeper, or returned (if the end of the Cache stack is reached).
|
|
13
|
+
*/
|
|
14
|
+
cacheFactory: () => AsyncMemoCache[];
|
|
15
|
+
}>;
|
|
16
|
+
/**
|
|
17
|
+
* Like @_Memo, but allowing async MemoCache implementation.
|
|
18
|
+
*
|
|
19
|
+
* Method CANNOT return `undefined`, as undefined will always be treated as cache MISS and retried.
|
|
20
|
+
* Return `null` instead (it'll be cached).
|
|
21
|
+
*/
|
|
22
|
+
export declare const _AsyncMemo: (opt: AsyncMemoOptions) => MethodDecorator;
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports._AsyncMemo = void 0;
|
|
4
|
+
const time_util_1 = require("../time/time.util");
|
|
5
|
+
const decorator_util_1 = require("./decorator.util");
|
|
6
|
+
const memo_decorator_1 = require("./memo.decorator");
|
|
7
|
+
const memo_util_1 = require("./memo.util");
|
|
8
|
+
/**
|
|
9
|
+
* Like @_Memo, but allowing async MemoCache implementation.
|
|
10
|
+
*
|
|
11
|
+
* Method CANNOT return `undefined`, as undefined will always be treated as cache MISS and retried.
|
|
12
|
+
* Return `null` instead (it'll be cached).
|
|
13
|
+
*/
|
|
14
|
+
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
15
|
+
const _AsyncMemo = (opt) => (target, key, descriptor) => {
|
|
16
|
+
if (typeof descriptor.value !== 'function') {
|
|
17
|
+
throw new TypeError('Memoization can be applied only to methods');
|
|
18
|
+
}
|
|
19
|
+
const originalFn = descriptor.value;
|
|
20
|
+
// Map from "instance" of the Class where @_AsyncMemo is applied to AsyncMemoCache instance.
|
|
21
|
+
const cache = new Map();
|
|
22
|
+
const { logHit = false, logMiss = false, noLogArgs = false, logger = console, cacheFactory, cacheKeyFn = memo_util_1.jsonMemoSerializer, noCacheRejected = false, noCacheResolved = false, } = opt;
|
|
23
|
+
const keyStr = String(key);
|
|
24
|
+
const methodSignature = (0, decorator_util_1._getTargetMethodSignature)(target, keyStr);
|
|
25
|
+
descriptor.value = async function (...args) {
|
|
26
|
+
const ctx = this;
|
|
27
|
+
const cacheKey = cacheKeyFn(args);
|
|
28
|
+
if (!cache.has(ctx)) {
|
|
29
|
+
cache.set(ctx, cacheFactory());
|
|
30
|
+
// here, no need to check the cache. It's definitely a miss, because the cacheLayers is just created
|
|
31
|
+
// UPD: no! AsyncMemo supports "persistent caches" (e.g Database-backed cache)
|
|
32
|
+
}
|
|
33
|
+
if (args.length === 1 && args[0] === memo_decorator_1.CACHE_DROP) {
|
|
34
|
+
// Special event - CACHE_DROP
|
|
35
|
+
// Function will return undefined
|
|
36
|
+
logger.log(`${methodSignature} @_AsyncMemo.dropCache()`);
|
|
37
|
+
try {
|
|
38
|
+
await Promise.all(cache.get(ctx).map(c => c.clear()));
|
|
39
|
+
}
|
|
40
|
+
catch (err) {
|
|
41
|
+
logger.error(err);
|
|
42
|
+
}
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
let value;
|
|
46
|
+
try {
|
|
47
|
+
for await (const cacheLayer of cache.get(ctx)) {
|
|
48
|
+
value = await cacheLayer.get(cacheKey);
|
|
49
|
+
if (value !== undefined) {
|
|
50
|
+
// it's a hit!
|
|
51
|
+
break;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
catch (err) {
|
|
56
|
+
// log error, but don't throw, treat it as a "miss"
|
|
57
|
+
logger.error(err);
|
|
58
|
+
}
|
|
59
|
+
if (value !== undefined) {
|
|
60
|
+
// hit!
|
|
61
|
+
if (logHit) {
|
|
62
|
+
logger.log(`${(0, decorator_util_1._getMethodSignature)(ctx, keyStr)}(${(0, decorator_util_1._getArgsSignature)(args, noLogArgs)}) @_AsyncMemo hit`);
|
|
63
|
+
}
|
|
64
|
+
return value instanceof Error ? Promise.reject(value) : Promise.resolve(value);
|
|
65
|
+
}
|
|
66
|
+
// Here we know it's a MISS, let's execute the real method
|
|
67
|
+
const started = Date.now();
|
|
68
|
+
try {
|
|
69
|
+
value = await originalFn.apply(ctx, args);
|
|
70
|
+
if (!noCacheResolved) {
|
|
71
|
+
Promise.all(cache.get(ctx).map(cacheLayer => cacheLayer.set(cacheKey, value))).catch(err => {
|
|
72
|
+
// log and ignore the error
|
|
73
|
+
logger.error(err);
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
return value;
|
|
77
|
+
}
|
|
78
|
+
catch (err) {
|
|
79
|
+
if (!noCacheRejected) {
|
|
80
|
+
// We put it to cache as raw Error, not Promise.reject(err)
|
|
81
|
+
Promise.all(cache.get(ctx).map(cacheLayer => cacheLayer.set(cacheKey, err))).catch(err => {
|
|
82
|
+
// log and ignore the error
|
|
83
|
+
logger.error(err);
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
throw err;
|
|
87
|
+
}
|
|
88
|
+
finally {
|
|
89
|
+
if (logMiss) {
|
|
90
|
+
logger.log(`${(0, decorator_util_1._getMethodSignature)(ctx, keyStr)}(${(0, decorator_util_1._getArgsSignature)(args, noLogArgs)}) @_AsyncMemo miss (${(0, time_util_1._since)(started)})`);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
};
|
|
94
|
+
return descriptor;
|
|
95
|
+
};
|
|
96
|
+
exports._AsyncMemo = _AsyncMemo;
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import { CommonLogger } from '../log/commonLogger';
|
|
2
2
|
import { MemoCache } from './memo.util';
|
|
3
|
+
/**
|
|
4
|
+
* Symbol to indicate that the Cache should be dropped.
|
|
5
|
+
*/
|
|
6
|
+
export declare const CACHE_DROP: unique symbol;
|
|
3
7
|
export interface MemoOptions {
|
|
4
8
|
/**
|
|
5
9
|
* Default to false
|
|
@@ -30,11 +34,15 @@ export interface MemoOptions {
|
|
|
30
34
|
/**
|
|
31
35
|
* Don't cache resolved promises.
|
|
32
36
|
* Setting this to `true` will make the decorator to await the result.
|
|
37
|
+
*
|
|
38
|
+
* Default false.
|
|
33
39
|
*/
|
|
34
40
|
noCacheResolved?: boolean;
|
|
35
41
|
/**
|
|
36
42
|
* Don't cache rejected promises.
|
|
37
43
|
* Setting this to `true` will make the decorator to await the result.
|
|
44
|
+
*
|
|
45
|
+
* Default false.
|
|
38
46
|
*/
|
|
39
47
|
noCacheRejected?: boolean;
|
|
40
48
|
}
|
|
@@ -5,10 +5,14 @@
|
|
|
5
5
|
// http://inlehmansterms.net/2015/03/01/javascript-memoization/
|
|
6
6
|
// https://community.risingstack.com/the-worlds-fastest-javascript-memoization-library/
|
|
7
7
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
-
exports._Memo = void 0;
|
|
8
|
+
exports._Memo = exports.CACHE_DROP = void 0;
|
|
9
9
|
const time_util_1 = require("../time/time.util");
|
|
10
10
|
const decorator_util_1 = require("./decorator.util");
|
|
11
11
|
const memo_util_1 = require("./memo.util");
|
|
12
|
+
/**
|
|
13
|
+
* Symbol to indicate that the Cache should be dropped.
|
|
14
|
+
*/
|
|
15
|
+
exports.CACHE_DROP = Symbol('CACHE_DROP');
|
|
12
16
|
/**
|
|
13
17
|
* Memoizes the method of the class, so it caches the output and returns the cached version if the "key"
|
|
14
18
|
* of the cache is the same. Key, by defaul, is calculated as `JSON.stringify(...args)`.
|
|
@@ -39,6 +43,12 @@ const _Memo = (opt = {}) => (target, key, descriptor) => {
|
|
|
39
43
|
const methodSignature = (0, decorator_util_1._getTargetMethodSignature)(target, keyStr);
|
|
40
44
|
descriptor.value = function (...args) {
|
|
41
45
|
const ctx = this;
|
|
46
|
+
if (args.length === 1 && args[0] === exports.CACHE_DROP) {
|
|
47
|
+
// Special event - CACHE_DROP
|
|
48
|
+
// Function will return undefined
|
|
49
|
+
logger.log(`${methodSignature} @_Memo.CACHE_DROP`);
|
|
50
|
+
return cache.get(ctx)?.clear();
|
|
51
|
+
}
|
|
42
52
|
const cacheKey = cacheKeyFn(args);
|
|
43
53
|
if (!cache.has(ctx)) {
|
|
44
54
|
cache.set(ctx, cacheFactory());
|
|
@@ -91,11 +101,6 @@ const _Memo = (opt = {}) => (target, key, descriptor) => {
|
|
|
91
101
|
return res;
|
|
92
102
|
}
|
|
93
103
|
};
|
|
94
|
-
descriptor.value.dropCache = () => {
|
|
95
|
-
logger.log(`${methodSignature} @_Memo.dropCache()`);
|
|
96
|
-
cache.forEach(memoCache => memoCache.clear());
|
|
97
|
-
cache.clear();
|
|
98
|
-
};
|
|
99
104
|
return descriptor;
|
|
100
105
|
};
|
|
101
106
|
exports._Memo = _Memo;
|
|
@@ -1,15 +1,34 @@
|
|
|
1
|
+
import { Promisable } from '../typeFest';
|
|
1
2
|
export declare type MemoSerializer = (args: any[]) => any;
|
|
2
3
|
export declare const jsonMemoSerializer: MemoSerializer;
|
|
3
|
-
export interface MemoCache {
|
|
4
|
-
has(k:
|
|
5
|
-
get(k:
|
|
6
|
-
set(k:
|
|
4
|
+
export interface MemoCache<KEY = any, VALUE = any> {
|
|
5
|
+
has(k: KEY): boolean;
|
|
6
|
+
get(k: KEY): VALUE | undefined;
|
|
7
|
+
set(k: KEY, v: VALUE): void;
|
|
8
|
+
/**
|
|
9
|
+
* Clear is only called when `.dropCache()` is called.
|
|
10
|
+
* Otherwise the Cache is "persistent" (never cleared).
|
|
11
|
+
*/
|
|
7
12
|
clear(): void;
|
|
8
13
|
}
|
|
9
|
-
export
|
|
14
|
+
export interface AsyncMemoCache<KEY = any, VALUE = any> {
|
|
15
|
+
/**
|
|
16
|
+
* `undefined` value returned indicates the ABSENCE of value in the Cache.
|
|
17
|
+
* This also means that you CANNOT store `undefined` value in the Cache, as it'll be treated as a MISS.
|
|
18
|
+
* You CAN store `null` value instead, it will be treated as a HIT.
|
|
19
|
+
*/
|
|
20
|
+
get(k: KEY): Promisable<VALUE | undefined>;
|
|
21
|
+
set(k: KEY, v: VALUE): Promisable<void>;
|
|
22
|
+
/**
|
|
23
|
+
* Clear is only called when `.dropCache()` is called.
|
|
24
|
+
* Otherwise the Cache is "persistent" (never cleared).
|
|
25
|
+
*/
|
|
26
|
+
clear(): Promisable<void>;
|
|
27
|
+
}
|
|
28
|
+
export declare class MapMemoCache<KEY = any, VALUE = any> implements MemoCache<KEY, VALUE>, AsyncMemoCache<KEY, VALUE> {
|
|
10
29
|
private m;
|
|
11
|
-
has(k:
|
|
12
|
-
get(k:
|
|
13
|
-
set(k:
|
|
30
|
+
has(k: KEY): boolean;
|
|
31
|
+
get(k: KEY): VALUE | undefined;
|
|
32
|
+
set(k: KEY, v: VALUE): void;
|
|
14
33
|
clear(): void;
|
|
15
34
|
}
|
|
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.MapMemoCache = exports.jsonMemoSerializer = void 0;
|
|
4
4
|
const object_util_1 = require("../object/object.util");
|
|
5
5
|
const jsonMemoSerializer = args => {
|
|
6
|
-
if (
|
|
6
|
+
if (args.length === 0)
|
|
7
7
|
return undefined;
|
|
8
8
|
if (args.length === 1 && (0, object_util_1._isPrimitive)(args[0]))
|
|
9
9
|
return args[0];
|
|
@@ -6,7 +6,7 @@ const __1 = require("..");
|
|
|
6
6
|
function _Retry(opt = {}) {
|
|
7
7
|
return (target, key, descriptor) => {
|
|
8
8
|
const originalFn = descriptor.value;
|
|
9
|
-
descriptor.value = (0, __1.
|
|
9
|
+
descriptor.value = (0, __1.pRetryFn)(originalFn, opt);
|
|
10
10
|
return descriptor;
|
|
11
11
|
};
|
|
12
12
|
}
|
|
@@ -26,6 +26,12 @@ export interface ErrorData {
|
|
|
26
26
|
* `originalMessage` is used to preserve the original `error.message` as it came from the backend.
|
|
27
27
|
*/
|
|
28
28
|
originalMessage?: string;
|
|
29
|
+
/**
|
|
30
|
+
* Can be used by error-reporting tools (e.g Sentry).
|
|
31
|
+
* If fingerprint is defined - it'll be used INSTEAD of default fingerprint of a tool.
|
|
32
|
+
* Can be used to force-group errors that are NOT needed to be split by endpoint or calling function.
|
|
33
|
+
*/
|
|
34
|
+
fingerprint?: string[];
|
|
29
35
|
/**
|
|
30
36
|
* Open-ended.
|
|
31
37
|
*/
|
package/dist/index.d.ts
CHANGED
|
@@ -8,7 +8,8 @@ export * from './decorators/debounce.decorator';
|
|
|
8
8
|
export * from './decorators/decorator.util';
|
|
9
9
|
export * from './decorators/logMethod.decorator';
|
|
10
10
|
export * from './decorators/memo.decorator';
|
|
11
|
-
|
|
11
|
+
export * from './decorators/asyncMemo.decorator';
|
|
12
|
+
import { MemoCache, AsyncMemoCache } from './decorators/memo.util';
|
|
12
13
|
export * from './decorators/memoFn';
|
|
13
14
|
export * from './decorators/retry.decorator';
|
|
14
15
|
export * from './decorators/timeout.decorator';
|
|
@@ -34,14 +35,13 @@ export * from './object/object.util';
|
|
|
34
35
|
export * from './object/sortObject';
|
|
35
36
|
export * from './object/sortObjectDeep';
|
|
36
37
|
import { AggregatedError } from './promise/AggregatedError';
|
|
37
|
-
export * from './promise/pBatch';
|
|
38
38
|
import { DeferredPromise, pDefer } from './promise/pDefer';
|
|
39
39
|
export * from './promise/pDelay';
|
|
40
40
|
export * from './promise/pFilter';
|
|
41
41
|
export * from './promise/pHang';
|
|
42
42
|
import { pMap, PMapOptions } from './promise/pMap';
|
|
43
43
|
export * from './promise/pProps';
|
|
44
|
-
import { pRetry, PRetryOptions } from './promise/pRetry';
|
|
44
|
+
import { pRetry, pRetryFn, PRetryOptions } from './promise/pRetry';
|
|
45
45
|
export * from './promise/pState';
|
|
46
46
|
import { pTimeout, pTimeoutFn, PTimeoutOptions } from './promise/pTimeout';
|
|
47
47
|
export * from './promise/pTuple';
|
|
@@ -59,5 +59,5 @@ export * from './string/safeJsonStringify';
|
|
|
59
59
|
import { PQueue, PQueueCfg } from './promise/pQueue';
|
|
60
60
|
export * from './seq/seq';
|
|
61
61
|
export * from './math/stack.util';
|
|
62
|
-
export type { AbortableMapper, AbortablePredicate, AbortableAsyncPredicate, AbortableAsyncMapper, PQueueCfg, MemoCache, PromiseDecoratorCfg, PromiseDecoratorResp, ErrorData, ErrorObject, HttpErrorData, HttpErrorResponse, Admin401ErrorData, Admin403ErrorData, StringMap, PromiseMap, AnyObject, AnyFunction, ValuesOf, ValueOf, KeyValueTuple, ObjectMapper, ObjectPredicate, InstanceId, IsoDate, IsoDateTime, Reviver, PMapOptions, Mapper, AsyncMapper, Predicate, AsyncPredicate, BatchResult, DeferredPromise, PRetryOptions, PTimeoutOptions, TryCatchOptions, StringifyAnyOptions, JsonStringifyFunction, Merge, ReadonlyDeep, Promisable, Simplify, ConditionalPick, ConditionalExcept, Class, UnixTimestamp, BaseDBEntity, SavedDBEntity, Saved, Unsaved, CreatedUpdated, CreatedUpdatedId, ObjectWithId, AnyObjectWithId, JsonSchema, JsonSchemaAny, JsonSchemaOneOf, JsonSchemaAllOf, JsonSchemaAnyOf, JsonSchemaNot, JsonSchemaRef, JsonSchemaConst, JsonSchemaEnum, JsonSchemaString, JsonSchemaNumber, JsonSchemaBoolean, JsonSchemaNull, JsonSchemaRootObject, JsonSchemaObject, JsonSchemaArray, JsonSchemaTuple, JsonSchemaBuilder, CommonLogLevel, CommonLogWithLevelFunction, CommonLogFunction, CommonLogger, };
|
|
63
|
-
export { is, _createPromiseDecorator, _stringMapValues, _stringMapEntries, _objectKeys, pMap, _passthroughMapper, _passUndefinedMapper, _passthroughPredicate, _passNothingPredicate, _noop, ErrorMode, pDefer, AggregatedError, pRetry, pTimeout, pTimeoutFn, _tryCatch, _TryCatch, _stringifyAny, jsonSchema, JsonSchemaAnyBuilder, commonLoggerMinLevel, commonLoggerNoop, commonLogLevelNumber, commonLoggerPipe, commonLoggerPrefix, commonLoggerCreate, PQueue, END, SKIP, };
|
|
62
|
+
export type { AbortableMapper, AbortablePredicate, AbortableAsyncPredicate, AbortableAsyncMapper, PQueueCfg, MemoCache, AsyncMemoCache, PromiseDecoratorCfg, PromiseDecoratorResp, ErrorData, ErrorObject, HttpErrorData, HttpErrorResponse, Admin401ErrorData, Admin403ErrorData, StringMap, PromiseMap, AnyObject, AnyFunction, ValuesOf, ValueOf, KeyValueTuple, ObjectMapper, ObjectPredicate, InstanceId, IsoDate, IsoDateTime, Reviver, PMapOptions, Mapper, AsyncMapper, Predicate, AsyncPredicate, BatchResult, DeferredPromise, PRetryOptions, PTimeoutOptions, TryCatchOptions, StringifyAnyOptions, JsonStringifyFunction, Merge, ReadonlyDeep, Promisable, Simplify, ConditionalPick, ConditionalExcept, Class, UnixTimestamp, BaseDBEntity, SavedDBEntity, Saved, Unsaved, CreatedUpdated, CreatedUpdatedId, ObjectWithId, AnyObjectWithId, JsonSchema, JsonSchemaAny, JsonSchemaOneOf, JsonSchemaAllOf, JsonSchemaAnyOf, JsonSchemaNot, JsonSchemaRef, JsonSchemaConst, JsonSchemaEnum, JsonSchemaString, JsonSchemaNumber, JsonSchemaBoolean, JsonSchemaNull, JsonSchemaRootObject, JsonSchemaObject, JsonSchemaArray, JsonSchemaTuple, JsonSchemaBuilder, CommonLogLevel, CommonLogWithLevelFunction, CommonLogFunction, CommonLogger, };
|
|
63
|
+
export { is, _createPromiseDecorator, _stringMapValues, _stringMapEntries, _objectKeys, pMap, _passthroughMapper, _passUndefinedMapper, _passthroughPredicate, _passNothingPredicate, _noop, ErrorMode, pDefer, AggregatedError, pRetry, pRetryFn, pTimeout, pTimeoutFn, _tryCatch, _TryCatch, _stringifyAny, jsonSchema, JsonSchemaAnyBuilder, commonLoggerMinLevel, commonLoggerNoop, commonLogLevelNumber, commonLoggerPipe, commonLoggerPrefix, commonLoggerCreate, PQueue, END, SKIP, };
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.SKIP = exports.END = exports.PQueue = exports.commonLoggerCreate = exports.commonLoggerPrefix = exports.commonLoggerPipe = exports.commonLogLevelNumber = exports.commonLoggerNoop = exports.commonLoggerMinLevel = exports.JsonSchemaAnyBuilder = exports.jsonSchema = exports._stringifyAny = exports._TryCatch = exports._tryCatch = exports.pTimeoutFn = exports.pTimeout = exports.pRetry = exports.AggregatedError = exports.pDefer = exports.ErrorMode = exports._noop = exports._passNothingPredicate = exports._passthroughPredicate = exports._passUndefinedMapper = exports._passthroughMapper = exports.pMap = exports._objectKeys = exports._stringMapEntries = exports._stringMapValues = exports._createPromiseDecorator = exports.is = void 0;
|
|
3
|
+
exports.SKIP = exports.END = exports.PQueue = exports.commonLoggerCreate = exports.commonLoggerPrefix = exports.commonLoggerPipe = exports.commonLogLevelNumber = exports.commonLoggerNoop = exports.commonLoggerMinLevel = exports.JsonSchemaAnyBuilder = exports.jsonSchema = exports._stringifyAny = exports._TryCatch = exports._tryCatch = exports.pTimeoutFn = exports.pTimeout = exports.pRetryFn = exports.pRetry = exports.AggregatedError = exports.pDefer = exports.ErrorMode = exports._noop = exports._passNothingPredicate = exports._passthroughPredicate = exports._passUndefinedMapper = exports._passthroughMapper = exports.pMap = exports._objectKeys = exports._stringMapEntries = exports._stringMapValues = exports._createPromiseDecorator = exports.is = void 0;
|
|
4
4
|
const tslib_1 = require("tslib");
|
|
5
5
|
(0, tslib_1.__exportStar)(require("./array/array.util"), exports);
|
|
6
6
|
(0, tslib_1.__exportStar)(require("./lazy"), exports);
|
|
@@ -13,6 +13,7 @@ Object.defineProperty(exports, "_createPromiseDecorator", { enumerable: true, ge
|
|
|
13
13
|
(0, tslib_1.__exportStar)(require("./decorators/decorator.util"), exports);
|
|
14
14
|
(0, tslib_1.__exportStar)(require("./decorators/logMethod.decorator"), exports);
|
|
15
15
|
(0, tslib_1.__exportStar)(require("./decorators/memo.decorator"), exports);
|
|
16
|
+
(0, tslib_1.__exportStar)(require("./decorators/asyncMemo.decorator"), exports);
|
|
16
17
|
(0, tslib_1.__exportStar)(require("./decorators/memoFn"), exports);
|
|
17
18
|
(0, tslib_1.__exportStar)(require("./decorators/retry.decorator"), exports);
|
|
18
19
|
(0, tslib_1.__exportStar)(require("./decorators/timeout.decorator"), exports);
|
|
@@ -42,7 +43,6 @@ Object.defineProperty(exports, "JsonSchemaAnyBuilder", { enumerable: true, get:
|
|
|
42
43
|
(0, tslib_1.__exportStar)(require("./object/sortObjectDeep"), exports);
|
|
43
44
|
const AggregatedError_1 = require("./promise/AggregatedError");
|
|
44
45
|
Object.defineProperty(exports, "AggregatedError", { enumerable: true, get: function () { return AggregatedError_1.AggregatedError; } });
|
|
45
|
-
(0, tslib_1.__exportStar)(require("./promise/pBatch"), exports);
|
|
46
46
|
const pDefer_1 = require("./promise/pDefer");
|
|
47
47
|
Object.defineProperty(exports, "pDefer", { enumerable: true, get: function () { return pDefer_1.pDefer; } });
|
|
48
48
|
(0, tslib_1.__exportStar)(require("./promise/pDelay"), exports);
|
|
@@ -53,6 +53,7 @@ Object.defineProperty(exports, "pMap", { enumerable: true, get: function () { re
|
|
|
53
53
|
(0, tslib_1.__exportStar)(require("./promise/pProps"), exports);
|
|
54
54
|
const pRetry_1 = require("./promise/pRetry");
|
|
55
55
|
Object.defineProperty(exports, "pRetry", { enumerable: true, get: function () { return pRetry_1.pRetry; } });
|
|
56
|
+
Object.defineProperty(exports, "pRetryFn", { enumerable: true, get: function () { return pRetry_1.pRetryFn; } });
|
|
56
57
|
(0, tslib_1.__exportStar)(require("./promise/pState"), exports);
|
|
57
58
|
const pTimeout_1 = require("./promise/pTimeout");
|
|
58
59
|
Object.defineProperty(exports, "pTimeout", { enumerable: true, get: function () { return pTimeout_1.pTimeout; } });
|
|
@@ -8,17 +8,12 @@ exports.AggregatedError = void 0;
|
|
|
8
8
|
*/
|
|
9
9
|
class AggregatedError extends Error {
|
|
10
10
|
constructor(errors, results = []) {
|
|
11
|
-
const mappedErrors = errors.map(e => {
|
|
12
|
-
if (typeof e === 'string')
|
|
13
|
-
return new Error(e);
|
|
14
|
-
return e;
|
|
15
|
-
});
|
|
16
11
|
const message = [
|
|
17
12
|
`${errors.length} errors:`,
|
|
18
|
-
...
|
|
13
|
+
...errors.map((e, i) => `${i + 1}. ${e.message}`),
|
|
19
14
|
].join('\n');
|
|
20
15
|
super(message);
|
|
21
|
-
this.errors =
|
|
16
|
+
this.errors = errors;
|
|
22
17
|
this.results = results;
|
|
23
18
|
Object.defineProperty(this, 'name', {
|
|
24
19
|
value: this.constructor.name,
|
|
@@ -1,3 +1,2 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
export declare function pFilter<T>(iterable: Iterable<T | PromiseLike<T>>, filterFn: AbortableAsyncPredicate<T>, opt?: PMapOptions): Promise<T[]>;
|
|
1
|
+
import { AsyncPredicate } from '../types';
|
|
2
|
+
export declare function pFilter<T>(iterable: Iterable<T>, filterFn: AsyncPredicate<T>): Promise<T[]>;
|
package/dist/promise/pFilter.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.pFilter = void 0;
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
const
|
|
7
|
-
return
|
|
4
|
+
async function pFilter(iterable, filterFn) {
|
|
5
|
+
const items = [...iterable];
|
|
6
|
+
const predicates = await Promise.all(items.map((item, i) => filterFn(item, i)));
|
|
7
|
+
return items.filter((item, i) => predicates[i]);
|
|
8
8
|
}
|
|
9
9
|
exports.pFilter = pFilter;
|
package/dist/promise/pMap.d.ts
CHANGED
|
@@ -41,4 +41,4 @@ export interface PMapOptions {
|
|
|
41
41
|
* //=> ['http://ava.li/', 'http://todomvc.com/']
|
|
42
42
|
* })();
|
|
43
43
|
*/
|
|
44
|
-
export declare function pMap<IN, OUT>(iterable: Iterable<IN
|
|
44
|
+
export declare function pMap<IN, OUT>(iterable: Iterable<IN>, mapper: AbortableAsyncMapper<IN, OUT>, opt?: PMapOptions): Promise<OUT[]>;
|
package/dist/promise/pMap.js
CHANGED
|
@@ -38,28 +38,74 @@ const AggregatedError_1 = require("./AggregatedError");
|
|
|
38
38
|
* })();
|
|
39
39
|
*/
|
|
40
40
|
async function pMap(iterable, mapper, opt = {}) {
|
|
41
|
+
const ret = [];
|
|
42
|
+
// const iterator = iterable[Symbol.iterator]()
|
|
43
|
+
const items = [...iterable];
|
|
44
|
+
const itemsLength = items.length;
|
|
45
|
+
if (itemsLength === 0)
|
|
46
|
+
return []; // short circuit
|
|
47
|
+
const { concurrency = itemsLength, errorMode = __1.ErrorMode.THROW_IMMEDIATELY } = opt;
|
|
48
|
+
const errors = [];
|
|
49
|
+
let isSettled = false;
|
|
50
|
+
let resolvingCount = 0;
|
|
51
|
+
let currentIndex = 0;
|
|
52
|
+
// Special cases that are able to preserve async stack traces
|
|
53
|
+
if (concurrency === 1) {
|
|
54
|
+
// Special case for concurrency == 1
|
|
55
|
+
for await (const item of items) {
|
|
56
|
+
try {
|
|
57
|
+
const r = await mapper(item, currentIndex++);
|
|
58
|
+
if (r === __1.END)
|
|
59
|
+
break;
|
|
60
|
+
if (r !== __1.SKIP)
|
|
61
|
+
ret.push(r);
|
|
62
|
+
}
|
|
63
|
+
catch (err) {
|
|
64
|
+
if (errorMode === __1.ErrorMode.THROW_IMMEDIATELY)
|
|
65
|
+
throw err;
|
|
66
|
+
if (errorMode === __1.ErrorMode.THROW_AGGREGATED) {
|
|
67
|
+
errors.push(err);
|
|
68
|
+
}
|
|
69
|
+
// otherwise, suppress completely
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
if (errors.length) {
|
|
73
|
+
throw new AggregatedError_1.AggregatedError(errors, ret);
|
|
74
|
+
}
|
|
75
|
+
return ret;
|
|
76
|
+
}
|
|
77
|
+
else if (!opt.concurrency || items.length <= opt.concurrency) {
|
|
78
|
+
// Special case for concurrency == infinity or iterable.length < concurrency
|
|
79
|
+
if (errorMode === __1.ErrorMode.THROW_IMMEDIATELY) {
|
|
80
|
+
return (await Promise.all(items.map((item, i) => mapper(item, i)))).filter(r => r !== __1.SKIP && r !== __1.END);
|
|
81
|
+
}
|
|
82
|
+
;
|
|
83
|
+
(await Promise.allSettled(items.map((item, i) => mapper(item, i)))).forEach(r => {
|
|
84
|
+
if (r.status === 'fulfilled') {
|
|
85
|
+
if (r.value !== __1.SKIP && r.value !== __1.END)
|
|
86
|
+
ret.push(r.value);
|
|
87
|
+
}
|
|
88
|
+
else if (errorMode === __1.ErrorMode.THROW_AGGREGATED) {
|
|
89
|
+
errors.push(r.reason);
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
if (errors.length) {
|
|
93
|
+
throw new AggregatedError_1.AggregatedError(errors, ret);
|
|
94
|
+
}
|
|
95
|
+
return ret;
|
|
96
|
+
}
|
|
41
97
|
return new Promise((resolve, reject) => {
|
|
42
|
-
const
|
|
43
|
-
const ret = [];
|
|
44
|
-
const iterator = iterable[Symbol.iterator]();
|
|
45
|
-
const errors = [];
|
|
46
|
-
let isSettled = false;
|
|
47
|
-
let isIterableDone = false;
|
|
48
|
-
let resolvingCount = 0;
|
|
49
|
-
let currentIndex = 0;
|
|
50
|
-
const next = (skipped = false) => {
|
|
98
|
+
const next = () => {
|
|
51
99
|
if (isSettled) {
|
|
52
100
|
return;
|
|
53
101
|
}
|
|
54
|
-
const nextItem =
|
|
55
|
-
const i = currentIndex
|
|
56
|
-
if (
|
|
57
|
-
currentIndex++;
|
|
58
|
-
if (nextItem.done) {
|
|
59
|
-
isIterableDone = true;
|
|
102
|
+
const nextItem = items[currentIndex];
|
|
103
|
+
const i = currentIndex++;
|
|
104
|
+
if (currentIndex > itemsLength) {
|
|
60
105
|
if (resolvingCount === 0) {
|
|
106
|
+
isSettled = true;
|
|
61
107
|
const r = ret.filter(r => r !== __1.SKIP);
|
|
62
|
-
if (errors.length
|
|
108
|
+
if (errors.length) {
|
|
63
109
|
reject(new AggregatedError_1.AggregatedError(errors, r));
|
|
64
110
|
}
|
|
65
111
|
else {
|
|
@@ -69,7 +115,7 @@ async function pMap(iterable, mapper, opt = {}) {
|
|
|
69
115
|
return;
|
|
70
116
|
}
|
|
71
117
|
resolvingCount++;
|
|
72
|
-
Promise.resolve(nextItem
|
|
118
|
+
Promise.resolve(nextItem)
|
|
73
119
|
.then(async (element) => await mapper(element, i))
|
|
74
120
|
.then(value => {
|
|
75
121
|
if (value === __1.END) {
|
|
@@ -85,7 +131,9 @@ async function pMap(iterable, mapper, opt = {}) {
|
|
|
85
131
|
reject(err);
|
|
86
132
|
}
|
|
87
133
|
else {
|
|
88
|
-
|
|
134
|
+
if (errorMode === __1.ErrorMode.THROW_AGGREGATED) {
|
|
135
|
+
errors.push(err);
|
|
136
|
+
}
|
|
89
137
|
resolvingCount--;
|
|
90
138
|
next();
|
|
91
139
|
}
|
|
@@ -93,7 +141,7 @@ async function pMap(iterable, mapper, opt = {}) {
|
|
|
93
141
|
};
|
|
94
142
|
for (let i = 0; i < concurrency; i++) {
|
|
95
143
|
next();
|
|
96
|
-
if (
|
|
144
|
+
if (isSettled) {
|
|
97
145
|
break;
|
|
98
146
|
}
|
|
99
147
|
}
|
package/dist/promise/pRetry.d.ts
CHANGED
|
@@ -5,6 +5,12 @@ export interface PRetryOptions {
|
|
|
5
5
|
* Can be used to identify the place in the code that failed.
|
|
6
6
|
*/
|
|
7
7
|
name?: string;
|
|
8
|
+
/**
|
|
9
|
+
* Timeout for each Try, in milliseconds.
|
|
10
|
+
*
|
|
11
|
+
* Defaults to no timeout.
|
|
12
|
+
*/
|
|
13
|
+
timeout?: number;
|
|
8
14
|
/**
|
|
9
15
|
* How many attempts to try.
|
|
10
16
|
* First attempt is not a retry, but "initial try". It still counts.
|
|
@@ -29,7 +35,7 @@ export interface PRetryOptions {
|
|
|
29
35
|
*
|
|
30
36
|
* @default () => true
|
|
31
37
|
*/
|
|
32
|
-
predicate?: (err:
|
|
38
|
+
predicate?: (err: Error, attempt: number, maxAttempts: number) => boolean;
|
|
33
39
|
/**
|
|
34
40
|
* Log the first attempt (which is not a "retry" yet).
|
|
35
41
|
*
|
|
@@ -62,9 +68,18 @@ export interface PRetryOptions {
|
|
|
62
68
|
* Default to `console`
|
|
63
69
|
*/
|
|
64
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;
|
|
65
79
|
}
|
|
66
80
|
/**
|
|
67
81
|
* Returns a Function (!), enhanced with retry capabilities.
|
|
68
82
|
* Implements "Exponential back-off strategy" by multiplying the delay by `delayMultiplier` with each try.
|
|
69
83
|
*/
|
|
70
|
-
export declare function
|
|
84
|
+
export declare function pRetryFn<T extends AnyFunction>(fn: T, opt?: PRetryOptions): T;
|
|
85
|
+
export declare function pRetry<T>(fn: (attempt: number) => Promise<T>, opt?: PRetryOptions): Promise<T>;
|