@naturalcycles/js-lib 14.159.0 → 14.161.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.
- package/dist/{lazy.d.ts → define.d.ts} +26 -0
- package/dist/define.js +118 -0
- package/dist/error/app.error.d.ts +16 -3
- package/dist/error/app.error.js +22 -19
- package/dist/error/assert.d.ts +1 -1
- package/dist/error/assert.js +2 -2
- package/dist/error/error.model.d.ts +7 -0
- package/dist/error/error.util.js +29 -22
- package/dist/error/httpRequestError.d.ts +2 -2
- package/dist/error/httpRequestError.js +7 -2
- package/dist/error/jsonParseError.d.ts +2 -2
- package/dist/error/jsonParseError.js +5 -2
- package/dist/error/try.js +3 -1
- package/dist/http/fetcher.js +6 -3
- package/dist/http/fetcher.model.d.ts +1 -0
- package/dist/http/fetcher.model.js +1 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/object/object.util.d.ts +16 -11
- package/dist/object/object.util.js +29 -12
- package/dist/promise/pTimeout.d.ts +3 -3
- package/dist/promise/pTimeout.js +2 -2
- package/dist/types.d.ts +9 -2
- package/dist/types.js +9 -2
- package/dist-esm/{lazy.js → define.js} +38 -0
- package/dist-esm/error/app.error.js +22 -19
- package/dist-esm/error/assert.js +2 -2
- package/dist-esm/error/error.util.js +30 -23
- package/dist-esm/error/httpRequestError.js +7 -2
- package/dist-esm/error/jsonParseError.js +5 -2
- package/dist-esm/error/try.js +3 -1
- package/dist-esm/http/fetcher.js +6 -3
- package/dist-esm/http/fetcher.model.js +1 -0
- package/dist-esm/index.js +1 -1
- package/dist-esm/object/object.util.js +27 -11
- package/dist-esm/promise/pTimeout.js +2 -2
- package/dist-esm/types.js +8 -1
- package/package.json +1 -1
- package/src/{lazy.ts → define.ts} +68 -0
- package/src/error/app.error.ts +39 -22
- package/src/error/assert.ts +2 -2
- package/src/error/error.model.ts +8 -0
- package/src/error/error.util.ts +31 -25
- package/src/error/httpRequestError.ts +9 -3
- package/src/error/jsonParseError.ts +7 -8
- package/src/error/try.ts +7 -1
- package/src/http/fetcher.model.ts +2 -0
- package/src/http/fetcher.ts +6 -3
- package/src/index.ts +1 -1
- package/src/object/object.util.ts +51 -30
- package/src/promise/pTimeout.ts +4 -4
- package/src/types.ts +12 -2
- package/dist/lazy.js +0 -65
package/dist/types.d.ts
CHANGED
|
@@ -120,7 +120,7 @@ export type ValuesOf<T extends readonly any[]> = T[number];
|
|
|
120
120
|
*/
|
|
121
121
|
export type ValueOf<T> = T[keyof T];
|
|
122
122
|
export type KeyValueTuple<K, V> = [key: K, value: V];
|
|
123
|
-
export type ObjectMapper<OBJ, OUT> = (key:
|
|
123
|
+
export type ObjectMapper<OBJ, OUT> = (key: keyof OBJ, value: Exclude<OBJ[keyof OBJ], undefined>, obj: OBJ) => OUT;
|
|
124
124
|
export type ObjectPredicate<OBJ> = (key: keyof OBJ, value: Exclude<OBJ[keyof OBJ], undefined>, obj: OBJ) => boolean;
|
|
125
125
|
/**
|
|
126
126
|
* Allows to identify instance of Class by `instanceId`.
|
|
@@ -185,10 +185,17 @@ export declare const _stringMapValues: <T>(m: StringMap<T>) => T[];
|
|
|
185
185
|
*/
|
|
186
186
|
export declare const _stringMapEntries: <T>(m: StringMap<T>) => [k: string, v: T][];
|
|
187
187
|
/**
|
|
188
|
-
*
|
|
188
|
+
* Alias of `Object.keys`, but returns keys typed as `keyof T`, not as just `string`.
|
|
189
189
|
* This is how TypeScript should work, actually.
|
|
190
190
|
*/
|
|
191
191
|
export declare const _objectKeys: <T extends AnyObject>(obj: T) => (keyof T)[];
|
|
192
|
+
/**
|
|
193
|
+
* Alias of `Object.entries`, but returns better-typed output.
|
|
194
|
+
*
|
|
195
|
+
* So e.g you can use _objectEntries(obj).map([k, v] => {})
|
|
196
|
+
* and `k` will be `keyof obj` instead of generic `string`.
|
|
197
|
+
*/
|
|
198
|
+
export declare const _objectEntries: <T extends AnyObject>(obj: T) => [k: keyof T, v: T[keyof T]][];
|
|
192
199
|
export type NullishValue = null | undefined;
|
|
193
200
|
export type FalsyValue = false | '' | 0 | null | undefined;
|
|
194
201
|
/**
|
package/dist/types.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports._objectAssign = exports._typeCast = exports._objectKeys = exports._stringMapEntries = exports._stringMapValues = exports._passNothingPredicate = exports._passthroughPredicate = exports._noop = exports._passUndefinedMapper = exports._passthroughMapper = exports.SKIP = exports.END = void 0;
|
|
3
|
+
exports._objectAssign = exports._typeCast = exports._objectEntries = exports._objectKeys = exports._stringMapEntries = exports._stringMapValues = exports._passNothingPredicate = exports._passthroughPredicate = exports._noop = exports._passUndefinedMapper = exports._passthroughMapper = exports.SKIP = exports.END = void 0;
|
|
4
4
|
/**
|
|
5
5
|
* Symbol to indicate END of Sequence.
|
|
6
6
|
*/
|
|
@@ -33,10 +33,17 @@ exports._stringMapValues = Object.values;
|
|
|
33
33
|
*/
|
|
34
34
|
exports._stringMapEntries = Object.entries;
|
|
35
35
|
/**
|
|
36
|
-
*
|
|
36
|
+
* Alias of `Object.keys`, but returns keys typed as `keyof T`, not as just `string`.
|
|
37
37
|
* This is how TypeScript should work, actually.
|
|
38
38
|
*/
|
|
39
39
|
exports._objectKeys = Object.keys;
|
|
40
|
+
/**
|
|
41
|
+
* Alias of `Object.entries`, but returns better-typed output.
|
|
42
|
+
*
|
|
43
|
+
* So e.g you can use _objectEntries(obj).map([k, v] => {})
|
|
44
|
+
* and `k` will be `keyof obj` instead of generic `string`.
|
|
45
|
+
*/
|
|
46
|
+
exports._objectEntries = Object.entries;
|
|
40
47
|
/**
|
|
41
48
|
* Utility function that helps to cast *existing variable* to needed type T.
|
|
42
49
|
*
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { _mapObject, _mapValues } from './object/object.util';
|
|
2
|
+
import { SKIP } from './types';
|
|
1
3
|
/**
|
|
2
4
|
* const value = lazyValue(() => expensiveComputation())
|
|
3
5
|
*
|
|
@@ -57,3 +59,39 @@ export function _defineLazyProps(obj, props) {
|
|
|
57
59
|
Object.entries(props).forEach(([k, fn]) => _defineLazyProperty(obj, k, fn));
|
|
58
60
|
return obj;
|
|
59
61
|
}
|
|
62
|
+
/**
|
|
63
|
+
* Same as Object.defineProperty, but with better (least restricting) defaults.
|
|
64
|
+
*
|
|
65
|
+
* Defaults are:
|
|
66
|
+
* writable: true
|
|
67
|
+
* configurable: true
|
|
68
|
+
* enumerable: true
|
|
69
|
+
* value: existing obj[prop] value
|
|
70
|
+
*
|
|
71
|
+
* Original defaults:
|
|
72
|
+
* writable: false
|
|
73
|
+
* configurable: false
|
|
74
|
+
* enumerable: false
|
|
75
|
+
* value: existing obj[prop] value
|
|
76
|
+
*
|
|
77
|
+
*/
|
|
78
|
+
export function _defineProperty(obj, prop, pd) {
|
|
79
|
+
return Object.defineProperty(obj, prop, Object.assign({ writable: true, configurable: true, enumerable: true }, pd));
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Object.defineProperties with better defaults.
|
|
83
|
+
* See _defineProperty for exact defaults definition.
|
|
84
|
+
*/
|
|
85
|
+
export function _defineProps(obj, props) {
|
|
86
|
+
return Object.defineProperties(obj, _mapValues(props, (k, pd) => (Object.assign({ writable: true, configurable: true, enumerable: true }, pd))));
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Like _defineProps, but skips props with nullish values.
|
|
90
|
+
*/
|
|
91
|
+
export function _defineNonNullishProps(obj, props) {
|
|
92
|
+
return _defineProps(obj, _mapObject(props, (k, pd) => {
|
|
93
|
+
if (pd.value === null || pd.value === undefined)
|
|
94
|
+
return SKIP;
|
|
95
|
+
return [k, pd];
|
|
96
|
+
}));
|
|
97
|
+
}
|
|
@@ -3,29 +3,26 @@
|
|
|
3
3
|
*
|
|
4
4
|
* message - "technical" message. Frontend decides to show it or not.
|
|
5
5
|
* data - optional "any" payload.
|
|
6
|
-
* data.
|
|
6
|
+
* data.userFriendly - if present, will be displayed to the User as is.
|
|
7
7
|
*
|
|
8
8
|
* Based on: https://medium.com/@xpl/javascript-deriving-from-error-properly-8d2f8f315801
|
|
9
9
|
*/
|
|
10
10
|
export class AppError extends Error {
|
|
11
|
-
constructor(message, data = {},
|
|
11
|
+
constructor(message, data = {}, opt = {}) {
|
|
12
12
|
super(message);
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
writable: true,
|
|
27
|
-
configurable: true,
|
|
28
|
-
enumerable: false,
|
|
13
|
+
const { name = this.constructor.name, cause } = opt;
|
|
14
|
+
Object.defineProperties(this, {
|
|
15
|
+
name: {
|
|
16
|
+
value: name,
|
|
17
|
+
configurable: true,
|
|
18
|
+
writable: true,
|
|
19
|
+
},
|
|
20
|
+
data: {
|
|
21
|
+
value: data,
|
|
22
|
+
writable: true,
|
|
23
|
+
configurable: true,
|
|
24
|
+
enumerable: false,
|
|
25
|
+
},
|
|
29
26
|
});
|
|
30
27
|
if (cause) {
|
|
31
28
|
Object.defineProperty(this, 'cause', {
|
|
@@ -33,9 +30,15 @@ export class AppError extends Error {
|
|
|
33
30
|
value: cause,
|
|
34
31
|
writable: true,
|
|
35
32
|
configurable: true,
|
|
36
|
-
enumerable:
|
|
33
|
+
enumerable: true, // unlike standard - setting it to true for "visibility"
|
|
37
34
|
});
|
|
38
35
|
}
|
|
36
|
+
// this is to allow changing this.constuctor.name to a non-minified version
|
|
37
|
+
Object.defineProperty(this.constructor, 'name', {
|
|
38
|
+
value: name,
|
|
39
|
+
configurable: true,
|
|
40
|
+
writable: true,
|
|
41
|
+
});
|
|
39
42
|
// todo: check if it's needed at all!
|
|
40
43
|
// if (Error.captureStackTrace) {
|
|
41
44
|
// Error.captureStackTrace(this, this.constructor)
|
package/dist-esm/error/assert.js
CHANGED
|
@@ -106,7 +106,7 @@ export function _assertTypeOf(v, expectedType, message) {
|
|
|
106
106
|
}
|
|
107
107
|
}
|
|
108
108
|
export class AssertionError extends AppError {
|
|
109
|
-
constructor(message, data
|
|
110
|
-
super(message, data,
|
|
109
|
+
constructor(message, data) {
|
|
110
|
+
super(message, data, { name: 'AssertionError' });
|
|
111
111
|
}
|
|
112
112
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { _jsonParseIfPossible, _stringifyAny } from '..';
|
|
1
|
+
import { AppError, _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`).
|
|
@@ -78,36 +78,43 @@ export function _errorLikeToErrorObject(e) {
|
|
|
78
78
|
export function _errorObjectToError(o, errorClass = Error) {
|
|
79
79
|
if (o instanceof errorClass)
|
|
80
80
|
return o;
|
|
81
|
-
|
|
81
|
+
// Here we pass constructor values assuming it's AppError or sub-class of it
|
|
82
|
+
// If not - will be checked at the next step
|
|
83
|
+
// We cannot check `if (errorClass instanceof AppError)`, only `err instanceof AppError`
|
|
84
|
+
const { name, cause } = o;
|
|
85
|
+
const err = new errorClass(o.message, o.data, { name, cause });
|
|
82
86
|
// name: err.name, // cannot be assigned to a readonly property like this
|
|
83
87
|
// stack: o.stack, // also readonly e.g in Firefox
|
|
84
|
-
Object.defineProperty(err, 'name', {
|
|
85
|
-
value: o.name,
|
|
86
|
-
configurable: true,
|
|
87
|
-
writable: true,
|
|
88
|
-
});
|
|
89
|
-
Object.defineProperty(err.constructor, 'name', {
|
|
90
|
-
value: o.name,
|
|
91
|
-
configurable: true,
|
|
92
|
-
writable: true,
|
|
93
|
-
});
|
|
94
|
-
Object.defineProperty(err, 'data', {
|
|
95
|
-
value: o.data,
|
|
96
|
-
writable: true,
|
|
97
|
-
configurable: true,
|
|
98
|
-
enumerable: false,
|
|
99
|
-
});
|
|
100
88
|
if (o.stack) {
|
|
101
89
|
Object.defineProperty(err, 'stack', {
|
|
102
90
|
value: o.stack,
|
|
103
91
|
});
|
|
104
92
|
}
|
|
105
|
-
if (
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
93
|
+
if (!(err instanceof AppError)) {
|
|
94
|
+
// Following actions are only needed for non-AppError-like errors
|
|
95
|
+
Object.defineProperties(err, {
|
|
96
|
+
name: {
|
|
97
|
+
value: name,
|
|
98
|
+
configurable: true,
|
|
99
|
+
writable: true,
|
|
100
|
+
},
|
|
101
|
+
data: {
|
|
102
|
+
value: o.data,
|
|
103
|
+
writable: true,
|
|
104
|
+
configurable: true,
|
|
105
|
+
enumerable: false,
|
|
106
|
+
},
|
|
107
|
+
cause: {
|
|
108
|
+
value: cause,
|
|
109
|
+
writable: true,
|
|
110
|
+
configurable: true,
|
|
111
|
+
enumerable: true,
|
|
112
|
+
},
|
|
113
|
+
});
|
|
114
|
+
Object.defineProperty(err.constructor, 'name', {
|
|
115
|
+
value: name,
|
|
109
116
|
configurable: true,
|
|
110
|
-
|
|
117
|
+
writable: true,
|
|
111
118
|
});
|
|
112
119
|
}
|
|
113
120
|
return err;
|
|
@@ -17,7 +17,12 @@ import { AppError } from './app.error';
|
|
|
17
17
|
* (by default).
|
|
18
18
|
*/
|
|
19
19
|
export class HttpRequestError extends AppError {
|
|
20
|
-
constructor(message, data,
|
|
21
|
-
|
|
20
|
+
constructor(message, data, opt) {
|
|
21
|
+
if (data.response) {
|
|
22
|
+
Object.defineProperty(data, 'response', {
|
|
23
|
+
enumerable: false,
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
super(message, data, Object.assign(Object.assign({}, opt), { name: 'HttpRequestError' }));
|
|
22
27
|
}
|
|
23
28
|
}
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import { _truncateMiddle } from '../string/string.util';
|
|
2
2
|
import { AppError } from './app.error';
|
|
3
3
|
export class JsonParseError extends AppError {
|
|
4
|
-
constructor(data
|
|
5
|
-
|
|
4
|
+
constructor(data) {
|
|
5
|
+
const message = ['Failed to parse', data.text && _truncateMiddle(data.text, 200)]
|
|
6
|
+
.filter(Boolean)
|
|
7
|
+
.join(': ');
|
|
8
|
+
super(message, data, { name: 'JsonParseError' });
|
|
6
9
|
}
|
|
7
10
|
}
|
package/dist-esm/error/try.js
CHANGED
|
@@ -52,7 +52,9 @@ export async function pTry(promise, errorClass) {
|
|
|
52
52
|
*/
|
|
53
53
|
export class UnexpectedPassError extends AppError {
|
|
54
54
|
constructor() {
|
|
55
|
-
super('expected error was not thrown', {},
|
|
55
|
+
super('expected error was not thrown', {}, {
|
|
56
|
+
name: 'UnexpectedPassError',
|
|
57
|
+
});
|
|
56
58
|
}
|
|
57
59
|
}
|
|
58
60
|
/**
|
package/dist-esm/http/fetcher.js
CHANGED
|
@@ -295,6 +295,7 @@ export class Fetcher {
|
|
|
295
295
|
});
|
|
296
296
|
const message = [(_a = res.fetchResponse) === null || _a === void 0 ? void 0 : _a.status, res.signature].filter(Boolean).join(' ');
|
|
297
297
|
res.err = new HttpRequestError(message, _filterNullishValues({
|
|
298
|
+
response: res.fetchResponse,
|
|
298
299
|
responseStatusCode: ((_b = res.fetchResponse) === null || _b === void 0 ? void 0 : _b.status) || 0,
|
|
299
300
|
// These properties are provided to be used in e.g custom Sentry error grouping
|
|
300
301
|
// Actually, disabled now, to avoid unnecessary error printing when both msg and data are printed
|
|
@@ -302,11 +303,13 @@ export class Fetcher {
|
|
|
302
303
|
// method: req.method,
|
|
303
304
|
// tryCount: req.tryCount,
|
|
304
305
|
requestUrl: res.req.fullUrl,
|
|
305
|
-
requestBaseUrl: this.cfg.baseUrl ||
|
|
306
|
+
requestBaseUrl: this.cfg.baseUrl || undefined,
|
|
306
307
|
requestMethod: res.req.init.method,
|
|
307
308
|
requestSignature: res.signature,
|
|
308
309
|
requestDuration: Date.now() - res.req.started,
|
|
309
|
-
}),
|
|
310
|
+
}), {
|
|
311
|
+
cause,
|
|
312
|
+
});
|
|
310
313
|
await this.processRetry(res);
|
|
311
314
|
}
|
|
312
315
|
async processRetry(res) {
|
|
@@ -512,7 +515,7 @@ export class Fetcher {
|
|
|
512
515
|
const searchParams = _filterUndefinedValues(Object.assign(Object.assign({}, this.cfg.searchParams), opt.searchParams));
|
|
513
516
|
if (Object.keys(searchParams).length) {
|
|
514
517
|
const qs = new URLSearchParams(searchParams).toString();
|
|
515
|
-
req.fullUrl += req.fullUrl.includes('?') ? '&' : '?' + qs;
|
|
518
|
+
req.fullUrl += (req.fullUrl.includes('?') ? '&' : '?') + qs;
|
|
516
519
|
}
|
|
517
520
|
// setup request body
|
|
518
521
|
if (opt.json !== undefined) {
|
package/dist-esm/index.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { _isEmpty, _isObject } from '../is.util';
|
|
2
|
+
import { _objectEntries, SKIP } from '../types';
|
|
2
3
|
/**
|
|
3
4
|
* Returns clone of `obj` with only `props` preserved.
|
|
4
5
|
* Opposite of Omit.
|
|
@@ -82,27 +83,27 @@ export function _filterObject(obj, predicate, mutate = false) {
|
|
|
82
83
|
* 'pebbles': { 'user': 'pebbles', 'age': 1 }
|
|
83
84
|
* }
|
|
84
85
|
*
|
|
85
|
-
*
|
|
86
|
+
* _mapValues(users, (_key, value) => value.age)
|
|
86
87
|
* // => { 'fred': 40, 'pebbles': 1 } (iteration order is not guaranteed)
|
|
87
88
|
*
|
|
88
|
-
*
|
|
89
|
-
* _.mapValues(users, 'age')
|
|
90
|
-
* // => { 'fred': 40, 'pebbles': 1 } (iteration order is not guaranteed)
|
|
89
|
+
* To skip some key-value pairs - use _mapObject instead.
|
|
91
90
|
*/
|
|
92
91
|
export function _mapValues(obj, mapper, mutate = false) {
|
|
93
|
-
return
|
|
92
|
+
return _objectEntries(obj).reduce((map, [k, v]) => {
|
|
94
93
|
map[k] = mapper(k, v, obj);
|
|
95
94
|
return map;
|
|
96
|
-
},
|
|
95
|
+
}, mutate ? obj : {});
|
|
97
96
|
}
|
|
98
97
|
/**
|
|
99
98
|
* _.mapKeys({ 'a': 1, 'b': 2 }, (key, value) => key + value)
|
|
100
99
|
* // => { 'a1': 1, 'b2': 2 }
|
|
101
100
|
*
|
|
102
101
|
* Does not support `mutate` flag.
|
|
102
|
+
*
|
|
103
|
+
* To skip some key-value pairs - use _mapObject instead.
|
|
103
104
|
*/
|
|
104
105
|
export function _mapKeys(obj, mapper) {
|
|
105
|
-
return
|
|
106
|
+
return _objectEntries(obj).reduce((map, [k, v]) => {
|
|
106
107
|
map[mapper(k, v, obj)] = v;
|
|
107
108
|
return map;
|
|
108
109
|
}, {});
|
|
@@ -119,15 +120,14 @@ export function _mapKeys(obj, mapper) {
|
|
|
119
120
|
* 0 - key of returned object (string)
|
|
120
121
|
* 1 - value of returned object (any)
|
|
121
122
|
*
|
|
122
|
-
* If predicate returns
|
|
123
|
+
* If predicate returns SKIP symbol - such key/value pair is ignored (filtered out).
|
|
123
124
|
*
|
|
124
125
|
* Non-string keys are passed via String(...)
|
|
125
126
|
*/
|
|
126
127
|
export function _mapObject(obj, mapper) {
|
|
127
128
|
return Object.entries(obj).reduce((map, [k, v]) => {
|
|
128
|
-
const r = mapper(k, v, obj)
|
|
129
|
-
if (r
|
|
130
|
-
;
|
|
129
|
+
const r = mapper(k, v, obj);
|
|
130
|
+
if (r !== SKIP) {
|
|
131
131
|
map[r[0]] = r[1];
|
|
132
132
|
}
|
|
133
133
|
return map;
|
|
@@ -342,3 +342,19 @@ export function _has(obj, path) {
|
|
|
342
342
|
const v = _get(obj, path);
|
|
343
343
|
return v !== undefined && v !== null;
|
|
344
344
|
}
|
|
345
|
+
/**
|
|
346
|
+
* Does Object.freeze recursively for given object.
|
|
347
|
+
*
|
|
348
|
+
* Based on: https://github.com/substack/deep-freeze/blob/master/index.js
|
|
349
|
+
*/
|
|
350
|
+
export function _deepFreeze(o) {
|
|
351
|
+
Object.freeze(o);
|
|
352
|
+
Object.getOwnPropertyNames(o).forEach(prop => {
|
|
353
|
+
if (o.hasOwnProperty(prop) && // eslint-disable-line no-prototype-builtins
|
|
354
|
+
o[prop] !== null &&
|
|
355
|
+
(typeof o[prop] === 'object' || typeof o[prop] === 'function') &&
|
|
356
|
+
!Object.isFrozen(o[prop])) {
|
|
357
|
+
_deepFreeze(o[prop]);
|
|
358
|
+
}
|
|
359
|
+
});
|
|
360
|
+
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { AppError } from '../error/app.error';
|
|
2
2
|
import { _errorDataAppend } from '../error/error.util';
|
|
3
3
|
export class TimeoutError extends AppError {
|
|
4
|
-
constructor(message, data
|
|
5
|
-
super(message, data,
|
|
4
|
+
constructor(message, data, opt) {
|
|
5
|
+
super(message, data, Object.assign(Object.assign({}, opt), { name: 'TimeoutError' }));
|
|
6
6
|
}
|
|
7
7
|
}
|
|
8
8
|
/**
|
package/dist-esm/types.js
CHANGED
|
@@ -25,10 +25,17 @@ export const _stringMapValues = Object.values;
|
|
|
25
25
|
*/
|
|
26
26
|
export const _stringMapEntries = Object.entries;
|
|
27
27
|
/**
|
|
28
|
-
*
|
|
28
|
+
* Alias of `Object.keys`, but returns keys typed as `keyof T`, not as just `string`.
|
|
29
29
|
* This is how TypeScript should work, actually.
|
|
30
30
|
*/
|
|
31
31
|
export const _objectKeys = Object.keys;
|
|
32
|
+
/**
|
|
33
|
+
* Alias of `Object.entries`, but returns better-typed output.
|
|
34
|
+
*
|
|
35
|
+
* So e.g you can use _objectEntries(obj).map([k, v] => {})
|
|
36
|
+
* and `k` will be `keyof obj` instead of generic `string`.
|
|
37
|
+
*/
|
|
38
|
+
export const _objectEntries = Object.entries;
|
|
32
39
|
/**
|
|
33
40
|
* Utility function that helps to cast *existing variable* to needed type T.
|
|
34
41
|
*
|
package/package.json
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { _mapObject, _mapValues } from './object/object.util'
|
|
2
|
+
import { SKIP } from './types'
|
|
1
3
|
import type { AnyFunction, AnyObject } from './types'
|
|
2
4
|
|
|
3
5
|
/**
|
|
@@ -72,3 +74,69 @@ export function _defineLazyProps<OBJ extends AnyObject>(
|
|
|
72
74
|
Object.entries(props).forEach(([k, fn]) => _defineLazyProperty(obj, k, fn!))
|
|
73
75
|
return obj
|
|
74
76
|
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Same as Object.defineProperty, but with better (least restricting) defaults.
|
|
80
|
+
*
|
|
81
|
+
* Defaults are:
|
|
82
|
+
* writable: true
|
|
83
|
+
* configurable: true
|
|
84
|
+
* enumerable: true
|
|
85
|
+
* value: existing obj[prop] value
|
|
86
|
+
*
|
|
87
|
+
* Original defaults:
|
|
88
|
+
* writable: false
|
|
89
|
+
* configurable: false
|
|
90
|
+
* enumerable: false
|
|
91
|
+
* value: existing obj[prop] value
|
|
92
|
+
*
|
|
93
|
+
*/
|
|
94
|
+
export function _defineProperty<T extends AnyObject>(
|
|
95
|
+
obj: T,
|
|
96
|
+
prop: keyof T,
|
|
97
|
+
pd: PropertyDescriptor,
|
|
98
|
+
): T {
|
|
99
|
+
return Object.defineProperty(obj, prop, {
|
|
100
|
+
writable: true,
|
|
101
|
+
configurable: true,
|
|
102
|
+
enumerable: true,
|
|
103
|
+
// value: obj[prop], // existing value is already kept by default
|
|
104
|
+
...pd,
|
|
105
|
+
})
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Object.defineProperties with better defaults.
|
|
110
|
+
* See _defineProperty for exact defaults definition.
|
|
111
|
+
*/
|
|
112
|
+
export function _defineProps<T extends AnyObject>(
|
|
113
|
+
obj: T,
|
|
114
|
+
props: Partial<Record<keyof T, PropertyDescriptor>>,
|
|
115
|
+
): T {
|
|
116
|
+
return Object.defineProperties(
|
|
117
|
+
obj,
|
|
118
|
+
_mapValues(props, (k, pd) => ({
|
|
119
|
+
writable: true,
|
|
120
|
+
configurable: true,
|
|
121
|
+
enumerable: true,
|
|
122
|
+
// value: obj[k], // existing value is already kept by default
|
|
123
|
+
...pd,
|
|
124
|
+
})) as PropertyDescriptorMap,
|
|
125
|
+
)
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Like _defineProps, but skips props with nullish values.
|
|
130
|
+
*/
|
|
131
|
+
export function _defineNonNullishProps<T extends AnyObject>(
|
|
132
|
+
obj: T,
|
|
133
|
+
props: Partial<Record<keyof T, PropertyDescriptor>>,
|
|
134
|
+
): T {
|
|
135
|
+
return _defineProps(
|
|
136
|
+
obj,
|
|
137
|
+
_mapObject(props, (k, pd) => {
|
|
138
|
+
if (pd.value === null || pd.value === undefined) return SKIP
|
|
139
|
+
return [k as string, pd]
|
|
140
|
+
}),
|
|
141
|
+
)
|
|
142
|
+
}
|
package/src/error/app.error.ts
CHANGED
|
@@ -5,7 +5,7 @@ import type { ErrorData, ErrorObject } from './error.model'
|
|
|
5
5
|
*
|
|
6
6
|
* message - "technical" message. Frontend decides to show it or not.
|
|
7
7
|
* data - optional "any" payload.
|
|
8
|
-
* data.
|
|
8
|
+
* data.userFriendly - if present, will be displayed to the User as is.
|
|
9
9
|
*
|
|
10
10
|
* Based on: https://medium.com/@xpl/javascript-deriving-from-error-properly-8d2f8f315801
|
|
11
11
|
*/
|
|
@@ -13,31 +13,26 @@ 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 an ErrorObject
|
|
16
|
+
* `cause` here is normalized to be an ErrorObject
|
|
17
17
|
*/
|
|
18
18
|
override cause?: ErrorObject
|
|
19
19
|
|
|
20
|
-
constructor(message: string, data = {} as DATA_TYPE,
|
|
20
|
+
constructor(message: string, data = {} as DATA_TYPE, opt: AppErrorOptions = {}) {
|
|
21
21
|
super(message)
|
|
22
|
+
const { name = this.constructor.name, cause } = opt
|
|
22
23
|
|
|
23
|
-
Object.
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
Object.defineProperty(this, 'data', {
|
|
37
|
-
value: data,
|
|
38
|
-
writable: true,
|
|
39
|
-
configurable: true,
|
|
40
|
-
enumerable: false,
|
|
24
|
+
Object.defineProperties(this, {
|
|
25
|
+
name: {
|
|
26
|
+
value: name,
|
|
27
|
+
configurable: true,
|
|
28
|
+
writable: true,
|
|
29
|
+
},
|
|
30
|
+
data: {
|
|
31
|
+
value: data,
|
|
32
|
+
writable: true,
|
|
33
|
+
configurable: true,
|
|
34
|
+
enumerable: false,
|
|
35
|
+
},
|
|
41
36
|
})
|
|
42
37
|
|
|
43
38
|
if (cause) {
|
|
@@ -46,10 +41,17 @@ export class AppError<DATA_TYPE extends ErrorData = ErrorData> extends Error {
|
|
|
46
41
|
value: cause,
|
|
47
42
|
writable: true,
|
|
48
43
|
configurable: true,
|
|
49
|
-
enumerable:
|
|
44
|
+
enumerable: true, // unlike standard - setting it to true for "visibility"
|
|
50
45
|
})
|
|
51
46
|
}
|
|
52
47
|
|
|
48
|
+
// this is to allow changing this.constuctor.name to a non-minified version
|
|
49
|
+
Object.defineProperty(this.constructor, 'name', {
|
|
50
|
+
value: name,
|
|
51
|
+
configurable: true,
|
|
52
|
+
writable: true,
|
|
53
|
+
})
|
|
54
|
+
|
|
53
55
|
// todo: check if it's needed at all!
|
|
54
56
|
// if (Error.captureStackTrace) {
|
|
55
57
|
// Error.captureStackTrace(this, this.constructor)
|
|
@@ -62,3 +64,18 @@ export class AppError<DATA_TYPE extends ErrorData = ErrorData> extends Error {
|
|
|
62
64
|
// }
|
|
63
65
|
}
|
|
64
66
|
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Extra options for AppError constructor.
|
|
70
|
+
*/
|
|
71
|
+
export interface AppErrorOptions {
|
|
72
|
+
/**
|
|
73
|
+
* Overrides Error.name and Error.constructor.name
|
|
74
|
+
*/
|
|
75
|
+
name?: string
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Sets Error.cause
|
|
79
|
+
*/
|
|
80
|
+
cause?: ErrorObject
|
|
81
|
+
}
|
package/src/error/assert.ts
CHANGED
|
@@ -152,7 +152,7 @@ export function _assertTypeOf<T>(v: any, expectedType: string, message?: string)
|
|
|
152
152
|
}
|
|
153
153
|
|
|
154
154
|
export class AssertionError extends AppError {
|
|
155
|
-
constructor(message: string, data
|
|
156
|
-
super(message, data,
|
|
155
|
+
constructor(message: string, data?: ErrorData) {
|
|
156
|
+
super(message, data, { name: 'AssertionError' })
|
|
157
157
|
}
|
|
158
158
|
}
|
package/src/error/error.model.ts
CHANGED
|
@@ -85,6 +85,14 @@ export interface ErrorData {
|
|
|
85
85
|
}
|
|
86
86
|
|
|
87
87
|
export interface HttpRequestErrorData extends ErrorData {
|
|
88
|
+
/**
|
|
89
|
+
* Actual `fetch` Response as it was returned.
|
|
90
|
+
* Note that not every Request has a Response, hence it's optional.
|
|
91
|
+
*
|
|
92
|
+
* Non-enumerable.
|
|
93
|
+
*/
|
|
94
|
+
response?: Response
|
|
95
|
+
|
|
88
96
|
requestUrl: string
|
|
89
97
|
requestBaseUrl?: string
|
|
90
98
|
requestMethod: HttpMethod
|