@naturalcycles/js-lib 14.129.0 → 14.130.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 +2 -2
- package/dist/decorators/createPromiseDecorator.d.ts +6 -6
- package/dist/decorators/debounce.d.ts +2 -2
- package/dist/decorators/memo.decorator.d.ts +2 -2
- package/dist/decorators/memo.util.d.ts +7 -7
- package/dist/error/app.error.d.ts +5 -1
- package/dist/error/app.error.js +10 -1
- package/dist/error/assert.d.ts +0 -1
- package/dist/error/assert.js +0 -3
- package/dist/error/error.model.d.ts +1 -0
- package/dist/error/error.util.d.ts +4 -5
- package/dist/error/error.util.js +27 -18
- package/dist/error/errorMode.d.ts +1 -1
- package/dist/error/errorMode.js +1 -1
- package/dist/error/http.error.d.ts +1 -1
- package/dist/error/http.error.js +2 -2
- package/dist/error/tryCatch.d.ts +1 -1
- package/dist/http/fetcher.js +4 -3
- package/dist/index.d.ts +0 -1
- package/dist/index.js +0 -1
- package/dist/json-schema/jsonSchemaBuilder.d.ts +1 -1
- package/dist/promise/pDefer.d.ts +2 -2
- package/dist/promise/pMap.js +3 -4
- package/dist/promise/pRetry.d.ts +1 -1
- package/dist/promise/pTimeout.d.ts +1 -1
- package/dist/string/pupa.d.ts +2 -2
- package/dist/string/readingTime.d.ts +1 -1
- package/dist/string/stringifyAny.d.ts +6 -0
- package/dist/string/stringifyAny.js +13 -1
- package/dist-esm/error/app.error.js +10 -1
- package/dist-esm/error/assert.js +0 -3
- package/dist-esm/error/error.util.js +27 -15
- package/dist-esm/error/errorMode.js +1 -1
- package/dist-esm/error/http.error.js +2 -2
- package/dist-esm/http/fetcher.js +4 -3
- package/dist-esm/index.js +0 -1
- package/dist-esm/promise/pMap.js +3 -4
- package/dist-esm/string/stringifyAny.js +13 -1
- package/package.json +1 -1
- package/src/decorators/asyncMemo.decorator.ts +2 -2
- package/src/decorators/createPromiseDecorator.ts +4 -4
- package/src/decorators/debounce.ts +2 -2
- package/src/decorators/memo.decorator.ts +2 -2
- package/src/decorators/memo.util.ts +7 -7
- package/src/error/app.error.ts +16 -1
- package/src/error/assert.ts +1 -5
- package/src/error/error.model.ts +10 -0
- package/src/error/error.util.ts +27 -28
- package/src/error/errorMode.ts +1 -1
- package/src/error/http.error.ts +2 -2
- package/src/error/tryCatch.ts +1 -1
- package/src/http/fetcher.ts +5 -8
- package/src/index.ts +0 -1
- package/src/json-schema/jsonSchemaBuilder.ts +1 -1
- package/src/promise/pDefer.ts +2 -2
- package/src/promise/pMap.ts +3 -4
- package/src/promise/pRetry.ts +1 -1
- package/src/promise/pTimeout.ts +1 -1
- package/src/string/pupa.ts +1 -1
- package/src/string/readingTime.ts +1 -1
- package/src/string/stringifyAny.ts +23 -1
- package/dist/promise/AggregatedError.d.ts +0 -10
- package/dist/promise/AggregatedError.js +0 -34
- package/dist-esm/promise/AggregatedError.js +0 -30
- package/src/promise/AggregatedError.ts +0 -36
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { _jsonParseIfPossible, _stringifyAny } from '..';
|
|
2
2
|
/**
|
|
3
3
|
* Useful to ensure that error in `catch (err) { ... }`
|
|
4
4
|
* is indeed an Error (and not e.g `string` or `undefined`).
|
|
@@ -7,14 +7,14 @@ import { AppError, _jsonParseIfPossible, _stringifyAny } from '..';
|
|
|
7
7
|
*
|
|
8
8
|
* Alternatively, if you're sure it's Error - you can use `_assertIsError(err)`.
|
|
9
9
|
*/
|
|
10
|
-
export function _anyToError(o, errorClass = Error, errorData
|
|
10
|
+
export function _anyToError(o, errorClass = Error, errorData) {
|
|
11
11
|
let e;
|
|
12
12
|
if (o instanceof errorClass) {
|
|
13
13
|
e = o;
|
|
14
14
|
}
|
|
15
15
|
else {
|
|
16
16
|
// If it's an instance of Error, but ErrorClass is something else (e.g AppError) - it'll be "repacked" into AppError
|
|
17
|
-
const errorObject =
|
|
17
|
+
const errorObject = _anyToErrorObject(o);
|
|
18
18
|
e = _errorObjectToError(errorObject, errorClass);
|
|
19
19
|
}
|
|
20
20
|
if (errorData) {
|
|
@@ -29,11 +29,10 @@ export function _anyToError(o, errorClass = Error, errorData, opt) {
|
|
|
29
29
|
* If object is Error - Error.message will be used.
|
|
30
30
|
* Objects (not Errors) get converted to prettified JSON string (via `_stringifyAny`).
|
|
31
31
|
*/
|
|
32
|
-
export function _anyToErrorObject(o, errorData
|
|
33
|
-
var _a;
|
|
32
|
+
export function _anyToErrorObject(o, errorData) {
|
|
34
33
|
let eo;
|
|
35
34
|
if (o instanceof Error) {
|
|
36
|
-
eo = _errorToErrorObject(o
|
|
35
|
+
eo = _errorToErrorObject(o);
|
|
37
36
|
}
|
|
38
37
|
else {
|
|
39
38
|
o = _jsonParseIfPossible(o);
|
|
@@ -48,7 +47,7 @@ export function _anyToErrorObject(o, errorData, opt) {
|
|
|
48
47
|
// so, fair to return `data: {}` in the end
|
|
49
48
|
// Also we're sure it includes no "error name", e.g no `Error: ...`,
|
|
50
49
|
// so, fair to include `name: 'Error'`
|
|
51
|
-
const message = _stringifyAny(o
|
|
50
|
+
const message = _stringifyAny(o);
|
|
52
51
|
eo = {
|
|
53
52
|
name: 'Error',
|
|
54
53
|
message,
|
|
@@ -59,20 +58,18 @@ export function _anyToErrorObject(o, errorData, opt) {
|
|
|
59
58
|
Object.assign(eo.data, errorData);
|
|
60
59
|
return eo;
|
|
61
60
|
}
|
|
62
|
-
export function _errorToErrorObject(e
|
|
61
|
+
export function _errorToErrorObject(e) {
|
|
63
62
|
const obj = {
|
|
64
63
|
name: e.name,
|
|
65
64
|
message: e.message,
|
|
66
|
-
data: Object.assign({}, e.data),
|
|
65
|
+
data: Object.assign({}, e.data),
|
|
66
|
+
stack: e.stack,
|
|
67
67
|
};
|
|
68
|
-
if (
|
|
69
|
-
obj.
|
|
68
|
+
if (e.cause) {
|
|
69
|
+
obj.cause = _anyToErrorObject(e.cause);
|
|
70
70
|
}
|
|
71
71
|
return obj;
|
|
72
72
|
}
|
|
73
|
-
export function _errorObjectToAppError(o) {
|
|
74
|
-
return _errorObjectToError(o, AppError);
|
|
75
|
-
}
|
|
76
73
|
export function _errorObjectToError(o, errorClass = Error) {
|
|
77
74
|
if (o instanceof errorClass)
|
|
78
75
|
return o;
|
|
@@ -94,6 +91,14 @@ export function _errorObjectToError(o, errorClass = Error) {
|
|
|
94
91
|
value: o.stack,
|
|
95
92
|
});
|
|
96
93
|
}
|
|
94
|
+
if (o.cause) {
|
|
95
|
+
Object.defineProperty(err, 'cause', {
|
|
96
|
+
value: o.cause,
|
|
97
|
+
writable: true,
|
|
98
|
+
configurable: true,
|
|
99
|
+
enumerable: false,
|
|
100
|
+
});
|
|
101
|
+
}
|
|
97
102
|
return err;
|
|
98
103
|
}
|
|
99
104
|
export function _isHttpErrorResponse(o) {
|
|
@@ -110,8 +115,15 @@ export function _isHttpErrorObject(o) {
|
|
|
110
115
|
* Note: any instance of AppError is also automatically an ErrorObject
|
|
111
116
|
*/
|
|
112
117
|
export function _isErrorObject(o) {
|
|
113
|
-
return (!!o &&
|
|
118
|
+
return (!!o &&
|
|
119
|
+
typeof o === 'object' &&
|
|
120
|
+
typeof o.name === 'string' &&
|
|
121
|
+
typeof o.message === 'string' &&
|
|
122
|
+
typeof o.data === 'object');
|
|
114
123
|
}
|
|
124
|
+
// export function _isErrorLike(o: any): o is ErrorLike {
|
|
125
|
+
// return !!o && typeof o === 'object' && typeof o.name === 'string' && typeof o.message === 'string'
|
|
126
|
+
// }
|
|
115
127
|
/**
|
|
116
128
|
* Convenience function to safely add properties to Error's `data` object
|
|
117
129
|
* (even if it wasn't previously existing)
|
|
@@ -10,7 +10,7 @@ export var ErrorMode;
|
|
|
10
10
|
*/
|
|
11
11
|
ErrorMode["THROW_IMMEDIATELY"] = "THROW_IMMEDIATELY";
|
|
12
12
|
/**
|
|
13
|
-
* Don't throw on errors, but collect them and throw as
|
|
13
|
+
* Don't throw on errors, but collect them and throw as AggregateError in the end.
|
|
14
14
|
*/
|
|
15
15
|
ErrorMode["THROW_AGGREGATED"] = "THROW_AGGREGATED";
|
|
16
16
|
/**
|
|
@@ -3,7 +3,7 @@ import { AppError } from './app.error';
|
|
|
3
3
|
* Base class for HTTP errors - errors that define HTTP error code.
|
|
4
4
|
*/
|
|
5
5
|
export class HttpError extends AppError {
|
|
6
|
-
constructor(message, data) {
|
|
7
|
-
super(message, data);
|
|
6
|
+
constructor(message, data, opt) {
|
|
7
|
+
super(message, data, opt);
|
|
8
8
|
}
|
|
9
9
|
}
|
package/dist-esm/http/fetcher.js
CHANGED
|
@@ -159,11 +159,12 @@ export class Fetcher {
|
|
|
159
159
|
res.body = JSON.parse(text, req.jsonReviver);
|
|
160
160
|
}
|
|
161
161
|
catch (err) {
|
|
162
|
-
|
|
163
|
-
res.err =
|
|
162
|
+
const { message } = _anyToError(err);
|
|
163
|
+
res.err = new HttpError([signature, message].join('\n'), {
|
|
164
164
|
httpStatusCode: 0,
|
|
165
165
|
url: req.url,
|
|
166
|
-
})
|
|
166
|
+
});
|
|
167
|
+
res.ok = false;
|
|
167
168
|
}
|
|
168
169
|
}
|
|
169
170
|
else {
|
package/dist-esm/index.js
CHANGED
|
@@ -37,7 +37,6 @@ export * from './object/deepEquals';
|
|
|
37
37
|
export * from './object/object.util';
|
|
38
38
|
export * from './object/sortObject';
|
|
39
39
|
export * from './object/sortObjectDeep';
|
|
40
|
-
export * from './promise/AggregatedError';
|
|
41
40
|
export * from './promise/pDefer';
|
|
42
41
|
export * from './promise/pDelay';
|
|
43
42
|
export * from './promise/pFilter';
|
package/dist-esm/promise/pMap.js
CHANGED
|
@@ -8,7 +8,6 @@ Improvements:
|
|
|
8
8
|
*/
|
|
9
9
|
import { __asyncValues } from "tslib";
|
|
10
10
|
import { END, ErrorMode, SKIP } from '..';
|
|
11
|
-
import { AggregatedError } from './AggregatedError';
|
|
12
11
|
/**
|
|
13
12
|
* Returns a `Promise` that is fulfilled when all promises in `input` and ones returned from `mapper` are fulfilled,
|
|
14
13
|
* or rejects if any of the promises reject. The fulfilled value is an `Array` of the fulfilled values returned
|
|
@@ -86,7 +85,7 @@ export async function pMap(iterable, mapper, opt = {}) {
|
|
|
86
85
|
finally { if (e_1) throw e_1.error; }
|
|
87
86
|
}
|
|
88
87
|
if (errors.length) {
|
|
89
|
-
throw new
|
|
88
|
+
throw new AggregateError(errors, `pMap resulted in ${errors.length} error(s)`);
|
|
90
89
|
}
|
|
91
90
|
return ret;
|
|
92
91
|
}
|
|
@@ -106,7 +105,7 @@ export async function pMap(iterable, mapper, opt = {}) {
|
|
|
106
105
|
}
|
|
107
106
|
});
|
|
108
107
|
if (errors.length) {
|
|
109
|
-
throw new
|
|
108
|
+
throw new AggregateError(errors, `pMap resulted in ${errors.length} error(s)`);
|
|
110
109
|
}
|
|
111
110
|
return ret;
|
|
112
111
|
}
|
|
@@ -122,7 +121,7 @@ export async function pMap(iterable, mapper, opt = {}) {
|
|
|
122
121
|
isSettled = true;
|
|
123
122
|
const r = ret.filter(r => r !== SKIP);
|
|
124
123
|
if (errors.length) {
|
|
125
|
-
reject(new
|
|
124
|
+
reject(new AggregateError(errors, `pMap resulted in ${errors.length} error(s)`));
|
|
126
125
|
}
|
|
127
126
|
else {
|
|
128
127
|
resolve(r);
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { _isErrorObject, _isHttpErrorObject, _isHttpErrorResponse } from '../error/error.util';
|
|
2
2
|
import { _jsonParseIfPossible } from './json.util';
|
|
3
3
|
import { _safeJsonStringify } from './safeJsonStringify';
|
|
4
|
+
const supportsAggregateError = typeof globalThis.AggregateError === 'function';
|
|
4
5
|
let globalStringifyFunction = _safeJsonStringify;
|
|
5
6
|
/**
|
|
6
7
|
* Allows to set Global "stringifyFunction" that will be used to "pretty-print" objects
|
|
@@ -55,6 +56,7 @@ export function _stringifyAny(obj, opt = {}) {
|
|
|
55
56
|
return _stringifyAny(obj.error, opt);
|
|
56
57
|
}
|
|
57
58
|
if (obj instanceof Error || _isErrorObject(obj)) {
|
|
59
|
+
const { includeErrorCause = true } = opt;
|
|
58
60
|
//
|
|
59
61
|
// Error or ErrorObject
|
|
60
62
|
//
|
|
@@ -63,7 +65,7 @@ export function _stringifyAny(obj, opt = {}) {
|
|
|
63
65
|
// if (obj?.name === 'Error') {
|
|
64
66
|
// s = obj.message
|
|
65
67
|
// }
|
|
66
|
-
s = [obj.name, obj.message].join(': ');
|
|
68
|
+
s = [obj.name, obj.message].filter(Boolean).join(': ');
|
|
67
69
|
if (opt.includeErrorStack && obj.stack) {
|
|
68
70
|
// Here we're using the previously-generated "title line" (e.g "Error: some_message"),
|
|
69
71
|
// concatenating it with the Stack (but without the title line of the Stack)
|
|
@@ -88,6 +90,16 @@ export function _stringifyAny(obj, opt = {}) {
|
|
|
88
90
|
// Error that has no `data`, but has `code` property
|
|
89
91
|
s = [s, `code: ${obj.code}`].join('\n');
|
|
90
92
|
}
|
|
93
|
+
if (supportsAggregateError && obj instanceof AggregateError && obj.errors.length) {
|
|
94
|
+
s = [
|
|
95
|
+
s,
|
|
96
|
+
`${obj.errors.length} error(s):`,
|
|
97
|
+
...obj.errors.map((err, i) => `${i + 1}. ${_stringifyAny(err, opt)}`),
|
|
98
|
+
].join('\n');
|
|
99
|
+
}
|
|
100
|
+
if (obj.cause && includeErrorCause) {
|
|
101
|
+
s = s + '\ncaused by: ' + _stringifyAny(obj.cause, opt);
|
|
102
|
+
}
|
|
91
103
|
}
|
|
92
104
|
else if (typeof obj === 'string') {
|
|
93
105
|
//
|
package/package.json
CHANGED
|
@@ -11,12 +11,12 @@ export interface AsyncMemoOptions {
|
|
|
11
11
|
* Function that creates an instance of `MemoCache`.
|
|
12
12
|
* e.g LRUMemoCache from `@naturalcycles/nodejs-lib`.
|
|
13
13
|
*/
|
|
14
|
-
cacheFactory
|
|
14
|
+
cacheFactory?: () => AsyncMemoCache
|
|
15
15
|
|
|
16
16
|
/**
|
|
17
17
|
* Provide a custom implementation of CacheKey function.
|
|
18
18
|
*/
|
|
19
|
-
cacheKeyFn
|
|
19
|
+
cacheKeyFn?: (args: any[]) => any
|
|
20
20
|
|
|
21
21
|
/**
|
|
22
22
|
* Default true.
|
|
@@ -7,14 +7,14 @@ export interface PromiseDecoratorCfg<RES = any, PARAMS = any> {
|
|
|
7
7
|
* Called BEFORE the original function.
|
|
8
8
|
* If Promise is returned - it will be awaited.
|
|
9
9
|
*/
|
|
10
|
-
beforeFn
|
|
10
|
+
beforeFn?: (r: PromiseDecoratorResp<PARAMS>) => void | Promise<void>
|
|
11
11
|
|
|
12
12
|
/**
|
|
13
13
|
* Called just AFTER the original function.
|
|
14
14
|
* The output of this hook will be passed further,
|
|
15
15
|
* so, pay attention to pass through (or modify) the result.
|
|
16
16
|
*/
|
|
17
|
-
thenFn
|
|
17
|
+
thenFn?: (r: PromiseDecoratorResp<PARAMS> & { res: RES }) => RES
|
|
18
18
|
|
|
19
19
|
/**
|
|
20
20
|
* Called on Promise.reject.
|
|
@@ -23,13 +23,13 @@ export interface PromiseDecoratorCfg<RES = any, PARAMS = any> {
|
|
|
23
23
|
* If `catchFn` is present - it's responsible for handling or re-throwing the error.
|
|
24
24
|
* Whatever `catchFn` returns - passed to the original output.
|
|
25
25
|
*/
|
|
26
|
-
catchFn
|
|
26
|
+
catchFn?: (r: PromiseDecoratorResp<PARAMS> & { err: any }) => RES
|
|
27
27
|
|
|
28
28
|
/**
|
|
29
29
|
* Fires AFTER thenFn / catchFn, like a usual Promise.finally().
|
|
30
30
|
* Doesn't have access to neither res nor err (same as Promise.finally).
|
|
31
31
|
*/
|
|
32
|
-
finallyFn
|
|
32
|
+
finallyFn?: (r: PromiseDecoratorResp<PARAMS>) => any
|
|
33
33
|
}
|
|
34
34
|
|
|
35
35
|
export interface PromiseDecoratorResp<PARAMS> {
|
|
@@ -11,12 +11,12 @@ export interface MemoOptions {
|
|
|
11
11
|
* Function that creates an instance of `MemoCache`.
|
|
12
12
|
* e.g LRUMemoCache from `@naturalcycles/nodejs-lib`
|
|
13
13
|
*/
|
|
14
|
-
cacheFactory
|
|
14
|
+
cacheFactory?: () => MemoCache
|
|
15
15
|
|
|
16
16
|
/**
|
|
17
17
|
* Provide a custom implementation of CacheKey function.
|
|
18
18
|
*/
|
|
19
|
-
cacheKeyFn
|
|
19
|
+
cacheKeyFn?: (args: any[]) => any
|
|
20
20
|
|
|
21
21
|
/**
|
|
22
22
|
* Defaults to true.
|
|
@@ -10,15 +10,15 @@ export const jsonMemoSerializer: MemoSerializer = args => {
|
|
|
10
10
|
}
|
|
11
11
|
|
|
12
12
|
export interface MemoCache<KEY = any, VALUE = any> {
|
|
13
|
-
has(k: KEY)
|
|
14
|
-
get(k: KEY)
|
|
15
|
-
set(k: KEY, v: VALUE | Error)
|
|
13
|
+
has: (k: KEY) => boolean
|
|
14
|
+
get: (k: KEY) => VALUE | Error | undefined
|
|
15
|
+
set: (k: KEY, v: VALUE | Error) => void
|
|
16
16
|
|
|
17
17
|
/**
|
|
18
18
|
* Clear is only called when `.dropCache()` is called.
|
|
19
19
|
* Otherwise the Cache is "persistent" (never cleared).
|
|
20
20
|
*/
|
|
21
|
-
clear()
|
|
21
|
+
clear: () => void
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
export interface AsyncMemoCache<KEY = any, VALUE = any> {
|
|
@@ -29,14 +29,14 @@ export interface AsyncMemoCache<KEY = any, VALUE = any> {
|
|
|
29
29
|
* This also means that you CANNOT store `undefined` value in the Cache, as it'll be treated as a MISS.
|
|
30
30
|
* You CAN store `null` value instead, it will be treated as a HIT.
|
|
31
31
|
*/
|
|
32
|
-
get(k: KEY)
|
|
33
|
-
set(k: KEY, v: VALUE | Error)
|
|
32
|
+
get: (k: KEY) => Promisable<VALUE | Error | undefined>
|
|
33
|
+
set: (k: KEY, v: VALUE | Error) => Promisable<void>
|
|
34
34
|
|
|
35
35
|
/**
|
|
36
36
|
* Clear is only called when `.dropCache()` is called.
|
|
37
37
|
* Otherwise the Cache is "persistent" (never cleared).
|
|
38
38
|
*/
|
|
39
|
-
clear()
|
|
39
|
+
clear: () => Promisable<void>
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
// SingleValueMemoCache and ObjectMemoCache are example-only, not used in production code
|
package/src/error/app.error.ts
CHANGED
|
@@ -12,7 +12,12 @@ import type { ErrorData } from './error.model'
|
|
|
12
12
|
export class AppError<DATA_TYPE extends ErrorData = ErrorData> extends Error {
|
|
13
13
|
data!: DATA_TYPE
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
/**
|
|
16
|
+
* cause here is normalized to be instance of Error
|
|
17
|
+
*/
|
|
18
|
+
override cause?: Error
|
|
19
|
+
|
|
20
|
+
constructor(message: string, data = {} as DATA_TYPE, opt?: ErrorOptions) {
|
|
16
21
|
super(message)
|
|
17
22
|
|
|
18
23
|
Object.defineProperty(this, 'name', {
|
|
@@ -27,6 +32,16 @@ export class AppError<DATA_TYPE extends ErrorData = ErrorData> extends Error {
|
|
|
27
32
|
enumerable: false,
|
|
28
33
|
})
|
|
29
34
|
|
|
35
|
+
if (opt?.cause) {
|
|
36
|
+
Object.defineProperty(this, 'cause', {
|
|
37
|
+
// I'd love to do _anyToError(opt.cause) here, but it causes circular dep ;(
|
|
38
|
+
value: opt.cause,
|
|
39
|
+
writable: true,
|
|
40
|
+
configurable: true,
|
|
41
|
+
enumerable: false,
|
|
42
|
+
})
|
|
43
|
+
}
|
|
44
|
+
|
|
30
45
|
// todo: check if it's needed at all!
|
|
31
46
|
// if (Error.captureStackTrace) {
|
|
32
47
|
// Error.captureStackTrace(this, this.constructor)
|
package/src/error/assert.ts
CHANGED
|
@@ -123,8 +123,4 @@ export function _assertTypeOf<T>(v: any, expectedType: string, message?: string)
|
|
|
123
123
|
}
|
|
124
124
|
}
|
|
125
125
|
|
|
126
|
-
export class AssertionError extends AppError {
|
|
127
|
-
constructor(message: string, data = {} as ErrorData) {
|
|
128
|
-
super(message, data)
|
|
129
|
-
}
|
|
130
|
-
}
|
|
126
|
+
export class AssertionError extends AppError {}
|
package/src/error/error.model.ts
CHANGED
|
@@ -76,6 +76,14 @@ export interface Admin403ErrorData extends HttpErrorData {
|
|
|
76
76
|
adminPermissionsRequired: string[]
|
|
77
77
|
}
|
|
78
78
|
|
|
79
|
+
// export interface ErrorLike {
|
|
80
|
+
// name: string
|
|
81
|
+
// message: string
|
|
82
|
+
// stack?: string
|
|
83
|
+
// data?: any
|
|
84
|
+
// cause?: any
|
|
85
|
+
// }
|
|
86
|
+
|
|
79
87
|
/**
|
|
80
88
|
* Portable object that represents Error.
|
|
81
89
|
* Has extendable generic `data` property.
|
|
@@ -114,6 +122,8 @@ export interface ErrorObject<DATA_TYPE extends ErrorData = ErrorData> {
|
|
|
114
122
|
* It's non-optional, to save some null-checks.
|
|
115
123
|
*/
|
|
116
124
|
data: DATA_TYPE
|
|
125
|
+
|
|
126
|
+
cause?: ErrorObject
|
|
117
127
|
}
|
|
118
128
|
|
|
119
129
|
/**
|
package/src/error/error.util.ts
CHANGED
|
@@ -1,11 +1,4 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
ErrorData,
|
|
3
|
-
ErrorObject,
|
|
4
|
-
HttpErrorData,
|
|
5
|
-
HttpErrorResponse,
|
|
6
|
-
StringifyAnyOptions,
|
|
7
|
-
Class,
|
|
8
|
-
} from '..'
|
|
1
|
+
import type { ErrorData, ErrorObject, HttpErrorData, HttpErrorResponse, Class } from '..'
|
|
9
2
|
import { AppError, _jsonParseIfPossible, _stringifyAny } from '..'
|
|
10
3
|
|
|
11
4
|
/**
|
|
@@ -20,7 +13,6 @@ export function _anyToError<ERROR_TYPE extends Error = Error>(
|
|
|
20
13
|
o: any,
|
|
21
14
|
errorClass: Class<ERROR_TYPE> = Error as any,
|
|
22
15
|
errorData?: ErrorData,
|
|
23
|
-
opt?: StringifyAnyOptions,
|
|
24
16
|
): ERROR_TYPE {
|
|
25
17
|
let e: ERROR_TYPE
|
|
26
18
|
|
|
@@ -29,8 +21,8 @@ export function _anyToError<ERROR_TYPE extends Error = Error>(
|
|
|
29
21
|
} else {
|
|
30
22
|
// If it's an instance of Error, but ErrorClass is something else (e.g AppError) - it'll be "repacked" into AppError
|
|
31
23
|
|
|
32
|
-
const errorObject =
|
|
33
|
-
e = _errorObjectToError(errorObject, errorClass)
|
|
24
|
+
const errorObject = _anyToErrorObject(o)
|
|
25
|
+
e = _errorObjectToError(errorObject, errorClass)
|
|
34
26
|
}
|
|
35
27
|
|
|
36
28
|
if (errorData) {
|
|
@@ -52,17 +44,16 @@ export function _anyToError<ERROR_TYPE extends Error = Error>(
|
|
|
52
44
|
export function _anyToErrorObject<DATA_TYPE extends ErrorData = ErrorData>(
|
|
53
45
|
o: any,
|
|
54
46
|
errorData?: Partial<DATA_TYPE>,
|
|
55
|
-
opt?: StringifyAnyOptions,
|
|
56
47
|
): ErrorObject<DATA_TYPE> {
|
|
57
48
|
let eo: ErrorObject<DATA_TYPE>
|
|
58
49
|
|
|
59
50
|
if (o instanceof Error) {
|
|
60
|
-
eo = _errorToErrorObject<DATA_TYPE>(o
|
|
51
|
+
eo = _errorToErrorObject<DATA_TYPE>(o)
|
|
61
52
|
} else {
|
|
62
53
|
o = _jsonParseIfPossible(o)
|
|
63
54
|
|
|
64
55
|
if (_isHttpErrorResponse(o)) {
|
|
65
|
-
eo = o.error as
|
|
56
|
+
eo = o.error as ErrorObject<DATA_TYPE>
|
|
66
57
|
} else if (_isErrorObject(o)) {
|
|
67
58
|
eo = o as ErrorObject<DATA_TYPE>
|
|
68
59
|
} else {
|
|
@@ -70,10 +61,7 @@ export function _anyToErrorObject<DATA_TYPE extends ErrorData = ErrorData>(
|
|
|
70
61
|
// so, fair to return `data: {}` in the end
|
|
71
62
|
// Also we're sure it includes no "error name", e.g no `Error: ...`,
|
|
72
63
|
// so, fair to include `name: 'Error'`
|
|
73
|
-
const message = _stringifyAny(o
|
|
74
|
-
includeErrorData: true, // cause we're returning an ErrorObject, not a stringified error (yet)
|
|
75
|
-
...opt,
|
|
76
|
-
})
|
|
64
|
+
const message = _stringifyAny(o)
|
|
77
65
|
|
|
78
66
|
eo = {
|
|
79
67
|
name: 'Error',
|
|
@@ -89,27 +77,21 @@ export function _anyToErrorObject<DATA_TYPE extends ErrorData = ErrorData>(
|
|
|
89
77
|
|
|
90
78
|
export function _errorToErrorObject<DATA_TYPE extends ErrorData = ErrorData>(
|
|
91
79
|
e: AppError<DATA_TYPE> | Error,
|
|
92
|
-
includeErrorStack = true,
|
|
93
80
|
): ErrorObject<DATA_TYPE> {
|
|
94
81
|
const obj: ErrorObject<DATA_TYPE> = {
|
|
95
82
|
name: e.name,
|
|
96
83
|
message: e.message,
|
|
97
84
|
data: { ...(e as any).data }, // empty by default
|
|
85
|
+
stack: e.stack,
|
|
98
86
|
}
|
|
99
87
|
|
|
100
|
-
if (
|
|
101
|
-
obj.
|
|
88
|
+
if (e.cause) {
|
|
89
|
+
obj.cause = _anyToErrorObject(e.cause)
|
|
102
90
|
}
|
|
103
91
|
|
|
104
92
|
return obj
|
|
105
93
|
}
|
|
106
94
|
|
|
107
|
-
export function _errorObjectToAppError<DATA_TYPE extends ErrorData>(
|
|
108
|
-
o: ErrorObject<DATA_TYPE>,
|
|
109
|
-
): AppError<DATA_TYPE> {
|
|
110
|
-
return _errorObjectToError(o, AppError)
|
|
111
|
-
}
|
|
112
|
-
|
|
113
95
|
export function _errorObjectToError<DATA_TYPE extends ErrorData, ERROR_TYPE extends Error>(
|
|
114
96
|
o: ErrorObject<DATA_TYPE>,
|
|
115
97
|
errorClass: Class<ERROR_TYPE> = Error as any,
|
|
@@ -138,6 +120,15 @@ export function _errorObjectToError<DATA_TYPE extends ErrorData, ERROR_TYPE exte
|
|
|
138
120
|
})
|
|
139
121
|
}
|
|
140
122
|
|
|
123
|
+
if (o.cause) {
|
|
124
|
+
Object.defineProperty(err, 'cause', {
|
|
125
|
+
value: o.cause,
|
|
126
|
+
writable: true,
|
|
127
|
+
configurable: true,
|
|
128
|
+
enumerable: false,
|
|
129
|
+
})
|
|
130
|
+
}
|
|
131
|
+
|
|
141
132
|
return err
|
|
142
133
|
}
|
|
143
134
|
|
|
@@ -159,10 +150,18 @@ export function _isHttpErrorObject(o: any): o is ErrorObject<HttpErrorData> {
|
|
|
159
150
|
*/
|
|
160
151
|
export function _isErrorObject(o: any): o is ErrorObject {
|
|
161
152
|
return (
|
|
162
|
-
!!o &&
|
|
153
|
+
!!o &&
|
|
154
|
+
typeof o === 'object' &&
|
|
155
|
+
typeof o.name === 'string' &&
|
|
156
|
+
typeof o.message === 'string' &&
|
|
157
|
+
typeof o.data === 'object'
|
|
163
158
|
)
|
|
164
159
|
}
|
|
165
160
|
|
|
161
|
+
// export function _isErrorLike(o: any): o is ErrorLike {
|
|
162
|
+
// return !!o && typeof o === 'object' && typeof o.name === 'string' && typeof o.message === 'string'
|
|
163
|
+
// }
|
|
164
|
+
|
|
166
165
|
/**
|
|
167
166
|
* Convenience function to safely add properties to Error's `data` object
|
|
168
167
|
* (even if it wasn't previously existing)
|
package/src/error/errorMode.ts
CHANGED
|
@@ -10,7 +10,7 @@ export enum ErrorMode {
|
|
|
10
10
|
THROW_IMMEDIATELY = 'THROW_IMMEDIATELY',
|
|
11
11
|
|
|
12
12
|
/**
|
|
13
|
-
* Don't throw on errors, but collect them and throw as
|
|
13
|
+
* Don't throw on errors, but collect them and throw as AggregateError in the end.
|
|
14
14
|
*/
|
|
15
15
|
THROW_AGGREGATED = 'THROW_AGGREGATED',
|
|
16
16
|
|
package/src/error/http.error.ts
CHANGED
|
@@ -7,7 +7,7 @@ import type { HttpErrorData } from './error.model'
|
|
|
7
7
|
export class HttpError<
|
|
8
8
|
DATA_TYPE extends HttpErrorData = HttpErrorData,
|
|
9
9
|
> extends AppError<DATA_TYPE> {
|
|
10
|
-
constructor(message: string, data: DATA_TYPE) {
|
|
11
|
-
super(message, data)
|
|
10
|
+
constructor(message: string, data: DATA_TYPE, opt?: ErrorOptions) {
|
|
11
|
+
super(message, data, opt)
|
|
12
12
|
}
|
|
13
13
|
}
|
package/src/error/tryCatch.ts
CHANGED
package/src/http/fetcher.ts
CHANGED
|
@@ -219,15 +219,12 @@ export class Fetcher {
|
|
|
219
219
|
res.body = text
|
|
220
220
|
res.body = JSON.parse(text, req.jsonReviver)
|
|
221
221
|
} catch (err) {
|
|
222
|
+
const { message } = _anyToError(err)
|
|
223
|
+
res.err = new HttpError([signature, message].join('\n'), {
|
|
224
|
+
httpStatusCode: 0,
|
|
225
|
+
url: req.url,
|
|
226
|
+
})
|
|
222
227
|
res.ok = false
|
|
223
|
-
res.err = _anyToError(
|
|
224
|
-
err,
|
|
225
|
-
HttpError,
|
|
226
|
-
_filterNullishValues({
|
|
227
|
-
httpStatusCode: 0,
|
|
228
|
-
url: req.url,
|
|
229
|
-
}),
|
|
230
|
-
)
|
|
231
228
|
}
|
|
232
229
|
} else {
|
|
233
230
|
// Body had a '' (empty string)
|
package/src/index.ts
CHANGED
|
@@ -37,7 +37,6 @@ export * from './object/deepEquals'
|
|
|
37
37
|
export * from './object/object.util'
|
|
38
38
|
export * from './object/sortObject'
|
|
39
39
|
export * from './object/sortObjectDeep'
|
|
40
|
-
export * from './promise/AggregatedError'
|
|
41
40
|
export * from './promise/pDefer'
|
|
42
41
|
export * from './promise/pDelay'
|
|
43
42
|
export * from './promise/pFilter'
|
package/src/promise/pDefer.ts
CHANGED
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
* Similar to Deferred object, which is also a promise itself (instead of deferred.promise).
|
|
3
3
|
*/
|
|
4
4
|
export interface DeferredPromise<T = void> extends Promise<T> {
|
|
5
|
-
resolve(a?: T)
|
|
6
|
-
reject(e?: Error)
|
|
5
|
+
resolve: (a?: T) => void
|
|
6
|
+
reject: (e?: Error) => void
|
|
7
7
|
}
|
|
8
8
|
|
|
9
9
|
/* eslint-disable @typescript-eslint/promise-function-async */
|
package/src/promise/pMap.ts
CHANGED
|
@@ -9,7 +9,6 @@ Improvements:
|
|
|
9
9
|
|
|
10
10
|
import type { AbortableAsyncMapper } from '..'
|
|
11
11
|
import { END, ErrorMode, SKIP } from '..'
|
|
12
|
-
import { AggregatedError } from './AggregatedError'
|
|
13
12
|
|
|
14
13
|
export interface PMapOptions {
|
|
15
14
|
/**
|
|
@@ -93,7 +92,7 @@ export async function pMap<IN, OUT>(
|
|
|
93
92
|
}
|
|
94
93
|
|
|
95
94
|
if (errors.length) {
|
|
96
|
-
throw new
|
|
95
|
+
throw new AggregateError(errors, `pMap resulted in ${errors.length} error(s)`)
|
|
97
96
|
}
|
|
98
97
|
|
|
99
98
|
return ret as OUT[]
|
|
@@ -115,7 +114,7 @@ export async function pMap<IN, OUT>(
|
|
|
115
114
|
})
|
|
116
115
|
|
|
117
116
|
if (errors.length) {
|
|
118
|
-
throw new
|
|
117
|
+
throw new AggregateError(errors, `pMap resulted in ${errors.length} error(s)`)
|
|
119
118
|
}
|
|
120
119
|
|
|
121
120
|
return ret as OUT[]
|
|
@@ -135,7 +134,7 @@ export async function pMap<IN, OUT>(
|
|
|
135
134
|
isSettled = true
|
|
136
135
|
const r = ret.filter(r => r !== SKIP) as OUT[]
|
|
137
136
|
if (errors.length) {
|
|
138
|
-
reject(new
|
|
137
|
+
reject(new AggregateError(errors, `pMap resulted in ${errors.length} error(s)`))
|
|
139
138
|
} else {
|
|
140
139
|
resolve(r)
|
|
141
140
|
}
|