@naturalcycles/js-lib 14.128.1 → 14.130.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/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 +1 -1
- package/dist/error/app.error.js +2 -2
- 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 -4
- package/dist/error/error.util.js +26 -13
- 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 +6 -3
- package/dist/index.js +9 -4
- 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/zod/zod.shared.schemas.d.ts +52 -0
- package/dist/zod/zod.shared.schemas.js +94 -0
- package/dist/zod/zod.util.d.ts +21 -0
- package/dist/zod/zod.util.js +59 -0
- package/dist-esm/error/app.error.js +2 -2
- package/dist-esm/error/assert.js +0 -3
- package/dist-esm/error/error.util.js +26 -11
- 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 +5 -3
- package/dist-esm/promise/pMap.js +3 -4
- package/dist-esm/string/stringifyAny.js +13 -1
- package/dist-esm/zod/zod.shared.schemas.js +91 -0
- package/dist-esm/zod/zod.util.js +53 -0
- package/package.json +3 -2
- 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 +2 -2
- package/src/error/assert.ts +1 -5
- package/src/error/error.model.ts +10 -0
- package/src/error/error.util.ts +26 -21
- 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 +6 -3
- 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/src/zod/zod.shared.schemas.ts +102 -0
- package/src/zod/zod.util.ts +77 -0
- 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
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.zSavedDBEntity = exports.zBaseDBEntity = exports.zSlug = exports.zIdBase64Url = exports.zIdBase64 = exports.zIdBase62 = exports.zId = exports.zJwt = exports.JWT_REGEX = exports.zBase64Url = exports.zBase64 = exports.zBase62 = exports.BASE64URL_REGEX = exports.BASE64_REGEX = exports.BASE62_REGEX = exports.zEmail = exports.zIsoDateString = exports.zSemVer = exports.zUnixTimestampMillis2000 = exports.zUnixTimestampMillis = exports.zUnixTimestamp2000 = exports.zUnixTimestamp = exports.TS_2000 = exports.TS_2500 = void 0;
|
|
4
|
+
const zod_1 = require("zod");
|
|
5
|
+
exports.TS_2500 = 16725225600; // 2500-01-01
|
|
6
|
+
exports.TS_2000 = 946684800; // 2000-01-01
|
|
7
|
+
exports.zUnixTimestamp = zod_1.z
|
|
8
|
+
.number()
|
|
9
|
+
.int()
|
|
10
|
+
.min(0)
|
|
11
|
+
.max(exports.TS_2500, 'Must be a UnixTimestamp number')
|
|
12
|
+
.describe('UnixTimestamp');
|
|
13
|
+
exports.zUnixTimestamp2000 = zod_1.z
|
|
14
|
+
.number()
|
|
15
|
+
.int()
|
|
16
|
+
.min(exports.TS_2000)
|
|
17
|
+
.max(exports.TS_2500, 'Must be a UnixTimestamp number after 2000-01-01')
|
|
18
|
+
.describe('UnixTimestamp2000');
|
|
19
|
+
exports.zUnixTimestampMillis = zod_1.z
|
|
20
|
+
.number()
|
|
21
|
+
.int()
|
|
22
|
+
.min(0)
|
|
23
|
+
.max(exports.TS_2500 * 1000, 'Must be a UnixTimestampMillis number')
|
|
24
|
+
.describe('UnixTimestampMillis');
|
|
25
|
+
exports.zUnixTimestampMillis2000 = zod_1.z
|
|
26
|
+
.number()
|
|
27
|
+
.int()
|
|
28
|
+
.min(exports.TS_2000 * 1000)
|
|
29
|
+
.max(exports.TS_2500 * 1000, 'Must be a UnixTimestampMillis number after 2000-01-01')
|
|
30
|
+
.describe('UnixTimestampMillis2000');
|
|
31
|
+
exports.zSemVer = zod_1.z
|
|
32
|
+
.string()
|
|
33
|
+
.regex(/^[0-9]+\.[0-9]+\.[0-9]+$/, 'Must be a SemVer string')
|
|
34
|
+
.describe('SemVer');
|
|
35
|
+
exports.zIsoDateString = zod_1.z
|
|
36
|
+
.string()
|
|
37
|
+
.refine(v => {
|
|
38
|
+
return /^\d{4}-\d{2}-\d{2}$/.test(v);
|
|
39
|
+
}, 'Must be an IsoDateString')
|
|
40
|
+
.describe('IsoDateString');
|
|
41
|
+
exports.zEmail = zod_1.z
|
|
42
|
+
.string()
|
|
43
|
+
.trim()
|
|
44
|
+
.email()
|
|
45
|
+
.transform(s => s.toLowerCase())
|
|
46
|
+
.describe('Email');
|
|
47
|
+
exports.BASE62_REGEX = /^[a-zA-Z0-9]+$/;
|
|
48
|
+
exports.BASE64_REGEX = /^[A-Za-z0-9+/]+={0,2}$/;
|
|
49
|
+
exports.BASE64URL_REGEX = /^[\w-/]+$/;
|
|
50
|
+
exports.zBase62 = zod_1.z
|
|
51
|
+
.string()
|
|
52
|
+
.regex(exports.BASE62_REGEX, 'Must be a base62 string')
|
|
53
|
+
.describe('Base62String');
|
|
54
|
+
exports.zBase64 = zod_1.z
|
|
55
|
+
.string()
|
|
56
|
+
.regex(exports.BASE64_REGEX, 'Must be a base64 string')
|
|
57
|
+
.describe('Base64String');
|
|
58
|
+
exports.zBase64Url = zod_1.z
|
|
59
|
+
.string()
|
|
60
|
+
.regex(exports.BASE64URL_REGEX, 'Must be a base64url string')
|
|
61
|
+
.describe('Base64UrlString');
|
|
62
|
+
exports.JWT_REGEX = /^[\w-]+\.[\w-]+\.[\w-]+$/;
|
|
63
|
+
exports.zJwt = zod_1.z.string().regex(exports.JWT_REGEX, 'Must be a JWT string').describe('JWTString');
|
|
64
|
+
exports.zId = zod_1.z
|
|
65
|
+
.string()
|
|
66
|
+
.regex(/^[a-zA-Z0-9_]{6,64}$/, 'Must be an id string')
|
|
67
|
+
.describe('IdString');
|
|
68
|
+
exports.zIdBase62 = zod_1.z
|
|
69
|
+
.string()
|
|
70
|
+
.regex(/^[a-zA-Z0-9]{8,64}$/, 'Must be a base62 id string')
|
|
71
|
+
.describe('Base62Id');
|
|
72
|
+
exports.zIdBase64 = zod_1.z
|
|
73
|
+
.string()
|
|
74
|
+
.regex(/^[A-Za-z0-9+/]{6,62}={0,2}$/, 'Must be a base64 id string')
|
|
75
|
+
.describe('Base64Id');
|
|
76
|
+
exports.zIdBase64Url = zod_1.z
|
|
77
|
+
.string()
|
|
78
|
+
.regex(/^[\w-/]{8,64}$/, 'Must be a base64url id string')
|
|
79
|
+
.describe('Base64UrlId');
|
|
80
|
+
/**
|
|
81
|
+
* "Slug" - a valid URL, filename, etc.
|
|
82
|
+
*/
|
|
83
|
+
exports.zSlug = zod_1.z
|
|
84
|
+
.string()
|
|
85
|
+
.regex(/^[a-z0-9-]{1,255}$/, 'Must be a slug string')
|
|
86
|
+
.describe('Slug');
|
|
87
|
+
exports.zBaseDBEntity = zod_1.z
|
|
88
|
+
.object({
|
|
89
|
+
id: zod_1.z.string().optional(),
|
|
90
|
+
created: exports.zUnixTimestamp2000.optional(),
|
|
91
|
+
updated: exports.zUnixTimestamp2000.optional(),
|
|
92
|
+
})
|
|
93
|
+
.describe('BaseDBEntity');
|
|
94
|
+
exports.zSavedDBEntity = exports.zBaseDBEntity.required().describe('SavedDBEntity');
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { ZodError, ZodSchema, ZodIssue } from 'zod';
|
|
2
|
+
export interface ZodErrorResult<T> {
|
|
3
|
+
success: false;
|
|
4
|
+
data?: T;
|
|
5
|
+
error: ZodValidationError<T>;
|
|
6
|
+
}
|
|
7
|
+
export interface ZodSuccessResult<T> {
|
|
8
|
+
success: true;
|
|
9
|
+
data: T;
|
|
10
|
+
error?: ZodValidationError<T>;
|
|
11
|
+
}
|
|
12
|
+
export declare function zIsValid<T>(value: T, schema: ZodSchema<T>): boolean;
|
|
13
|
+
export declare function zValidate<T>(value: T, schema: ZodSchema<T>): T;
|
|
14
|
+
export declare function zSafeValidate<T>(value: T, schema: ZodSchema<T>): ZodSuccessResult<T> | ZodErrorResult<T>;
|
|
15
|
+
export declare class ZodValidationError<T> extends ZodError<T> {
|
|
16
|
+
value: T;
|
|
17
|
+
schema: ZodSchema<T>;
|
|
18
|
+
constructor(issues: ZodIssue[], value: T, schema: ZodSchema<T>);
|
|
19
|
+
get message(): string;
|
|
20
|
+
annotate(): string;
|
|
21
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ZodValidationError = exports.zSafeValidate = exports.zValidate = exports.zIsValid = void 0;
|
|
4
|
+
const zod_1 = require("zod");
|
|
5
|
+
const stringifyAny_1 = require("../string/stringifyAny");
|
|
6
|
+
function zIsValid(value, schema) {
|
|
7
|
+
const { success } = schema.safeParse(value);
|
|
8
|
+
return success;
|
|
9
|
+
}
|
|
10
|
+
exports.zIsValid = zIsValid;
|
|
11
|
+
function zValidate(value, schema) {
|
|
12
|
+
const r = zSafeValidate(value, schema);
|
|
13
|
+
if (r.success) {
|
|
14
|
+
return r.data;
|
|
15
|
+
}
|
|
16
|
+
throw r.error;
|
|
17
|
+
}
|
|
18
|
+
exports.zValidate = zValidate;
|
|
19
|
+
function zSafeValidate(value, schema) {
|
|
20
|
+
const r = schema.safeParse(value);
|
|
21
|
+
if (r.success) {
|
|
22
|
+
return r;
|
|
23
|
+
}
|
|
24
|
+
return {
|
|
25
|
+
success: false,
|
|
26
|
+
error: new ZodValidationError(r.error.issues, value, schema),
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
exports.zSafeValidate = zSafeValidate;
|
|
30
|
+
class ZodValidationError extends zod_1.ZodError {
|
|
31
|
+
constructor(issues, value, schema) {
|
|
32
|
+
super(issues);
|
|
33
|
+
this.value = value;
|
|
34
|
+
this.schema = schema;
|
|
35
|
+
}
|
|
36
|
+
get message() {
|
|
37
|
+
return this.annotate();
|
|
38
|
+
}
|
|
39
|
+
annotate() {
|
|
40
|
+
let objectTitle = this.schema.description;
|
|
41
|
+
if (typeof this.value === 'object' && this.value) {
|
|
42
|
+
const objectName = this.schema.description || this.value.constructor?.name;
|
|
43
|
+
const objectId = this.value['id'];
|
|
44
|
+
objectTitle = [objectName, objectId].filter(Boolean).join('.');
|
|
45
|
+
}
|
|
46
|
+
objectTitle ||= 'data';
|
|
47
|
+
return [
|
|
48
|
+
`Invalid ${objectTitle}`,
|
|
49
|
+
'',
|
|
50
|
+
'Input:',
|
|
51
|
+
(0, stringifyAny_1._stringifyAny)(this.value),
|
|
52
|
+
this.issues.length > 1 ? `\n${this.issues.length} issues:` : '',
|
|
53
|
+
...this.issues.slice(0, 100).map(i => {
|
|
54
|
+
return [i.path.join('.'), i.message].filter(Boolean).join(': ');
|
|
55
|
+
}),
|
|
56
|
+
].join('\n');
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
exports.ZodValidationError = ZodValidationError;
|
|
@@ -8,8 +8,8 @@
|
|
|
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 = {}) {
|
|
12
|
-
super(message);
|
|
11
|
+
constructor(message, data = {}, opt) {
|
|
12
|
+
super(message, opt);
|
|
13
13
|
Object.defineProperty(this, 'name', {
|
|
14
14
|
value: this.constructor.name,
|
|
15
15
|
configurable: true,
|
package/dist-esm/error/assert.js
CHANGED
|
@@ -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,14 +58,15 @@ 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
|
}
|
|
@@ -94,6 +94,14 @@ export function _errorObjectToError(o, errorClass = Error) {
|
|
|
94
94
|
value: o.stack,
|
|
95
95
|
});
|
|
96
96
|
}
|
|
97
|
+
if (o.cause) {
|
|
98
|
+
Object.defineProperty(err, 'cause', {
|
|
99
|
+
value: o.cause,
|
|
100
|
+
writable: true,
|
|
101
|
+
configurable: true,
|
|
102
|
+
enumerable: false,
|
|
103
|
+
});
|
|
104
|
+
}
|
|
97
105
|
return err;
|
|
98
106
|
}
|
|
99
107
|
export function _isHttpErrorResponse(o) {
|
|
@@ -110,8 +118,15 @@ export function _isHttpErrorObject(o) {
|
|
|
110
118
|
* Note: any instance of AppError is also automatically an ErrorObject
|
|
111
119
|
*/
|
|
112
120
|
export function _isErrorObject(o) {
|
|
113
|
-
return (!!o &&
|
|
121
|
+
return (!!o &&
|
|
122
|
+
typeof o === 'object' &&
|
|
123
|
+
typeof o.name === 'string' &&
|
|
124
|
+
typeof o.message === 'string' &&
|
|
125
|
+
typeof o.data === 'object');
|
|
114
126
|
}
|
|
127
|
+
// export function _isErrorLike(o: any): o is ErrorLike {
|
|
128
|
+
// return !!o && typeof o === 'object' && typeof o.name === 'string' && typeof o.message === 'string'
|
|
129
|
+
// }
|
|
115
130
|
/**
|
|
116
131
|
* Convenience function to safely add properties to Error's `data` object
|
|
117
132
|
* (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';
|
|
@@ -59,7 +58,6 @@ export * from './is.util';
|
|
|
59
58
|
export * from './typeFest';
|
|
60
59
|
export * from './types';
|
|
61
60
|
export * from './unit/size.util';
|
|
62
|
-
import { is } from './vendor/is';
|
|
63
61
|
export * from './log/commonLogger';
|
|
64
62
|
export * from './string/safeJsonStringify';
|
|
65
63
|
export * from './promise/pQueue';
|
|
@@ -77,4 +75,8 @@ export * from './datetime/timeInterval';
|
|
|
77
75
|
export * from './http/http.model';
|
|
78
76
|
export * from './http/fetcher';
|
|
79
77
|
export * from './http/fetcher.model';
|
|
80
|
-
export
|
|
78
|
+
export * from './zod/zod.util';
|
|
79
|
+
export * from './zod/zod.shared.schemas';
|
|
80
|
+
import { z, ZodSchema, ZodError } from 'zod';
|
|
81
|
+
import { is } from './vendor/is';
|
|
82
|
+
export { is, z, ZodSchema, ZodError };
|
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
|
//
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export const TS_2500 = 16725225600; // 2500-01-01
|
|
3
|
+
export const TS_2000 = 946684800; // 2000-01-01
|
|
4
|
+
export const zUnixTimestamp = z
|
|
5
|
+
.number()
|
|
6
|
+
.int()
|
|
7
|
+
.min(0)
|
|
8
|
+
.max(TS_2500, 'Must be a UnixTimestamp number')
|
|
9
|
+
.describe('UnixTimestamp');
|
|
10
|
+
export const zUnixTimestamp2000 = z
|
|
11
|
+
.number()
|
|
12
|
+
.int()
|
|
13
|
+
.min(TS_2000)
|
|
14
|
+
.max(TS_2500, 'Must be a UnixTimestamp number after 2000-01-01')
|
|
15
|
+
.describe('UnixTimestamp2000');
|
|
16
|
+
export const zUnixTimestampMillis = z
|
|
17
|
+
.number()
|
|
18
|
+
.int()
|
|
19
|
+
.min(0)
|
|
20
|
+
.max(TS_2500 * 1000, 'Must be a UnixTimestampMillis number')
|
|
21
|
+
.describe('UnixTimestampMillis');
|
|
22
|
+
export const zUnixTimestampMillis2000 = z
|
|
23
|
+
.number()
|
|
24
|
+
.int()
|
|
25
|
+
.min(TS_2000 * 1000)
|
|
26
|
+
.max(TS_2500 * 1000, 'Must be a UnixTimestampMillis number after 2000-01-01')
|
|
27
|
+
.describe('UnixTimestampMillis2000');
|
|
28
|
+
export const zSemVer = z
|
|
29
|
+
.string()
|
|
30
|
+
.regex(/^[0-9]+\.[0-9]+\.[0-9]+$/, 'Must be a SemVer string')
|
|
31
|
+
.describe('SemVer');
|
|
32
|
+
export const zIsoDateString = z
|
|
33
|
+
.string()
|
|
34
|
+
.refine(v => {
|
|
35
|
+
return /^\d{4}-\d{2}-\d{2}$/.test(v);
|
|
36
|
+
}, 'Must be an IsoDateString')
|
|
37
|
+
.describe('IsoDateString');
|
|
38
|
+
export const zEmail = z
|
|
39
|
+
.string()
|
|
40
|
+
.trim()
|
|
41
|
+
.email()
|
|
42
|
+
.transform(s => s.toLowerCase())
|
|
43
|
+
.describe('Email');
|
|
44
|
+
export const BASE62_REGEX = /^[a-zA-Z0-9]+$/;
|
|
45
|
+
export const BASE64_REGEX = /^[A-Za-z0-9+/]+={0,2}$/;
|
|
46
|
+
export const BASE64URL_REGEX = /^[\w-/]+$/;
|
|
47
|
+
export const zBase62 = z
|
|
48
|
+
.string()
|
|
49
|
+
.regex(BASE62_REGEX, 'Must be a base62 string')
|
|
50
|
+
.describe('Base62String');
|
|
51
|
+
export const zBase64 = z
|
|
52
|
+
.string()
|
|
53
|
+
.regex(BASE64_REGEX, 'Must be a base64 string')
|
|
54
|
+
.describe('Base64String');
|
|
55
|
+
export const zBase64Url = z
|
|
56
|
+
.string()
|
|
57
|
+
.regex(BASE64URL_REGEX, 'Must be a base64url string')
|
|
58
|
+
.describe('Base64UrlString');
|
|
59
|
+
export const JWT_REGEX = /^[\w-]+\.[\w-]+\.[\w-]+$/;
|
|
60
|
+
export const zJwt = z.string().regex(JWT_REGEX, 'Must be a JWT string').describe('JWTString');
|
|
61
|
+
export const zId = z
|
|
62
|
+
.string()
|
|
63
|
+
.regex(/^[a-zA-Z0-9_]{6,64}$/, 'Must be an id string')
|
|
64
|
+
.describe('IdString');
|
|
65
|
+
export const zIdBase62 = z
|
|
66
|
+
.string()
|
|
67
|
+
.regex(/^[a-zA-Z0-9]{8,64}$/, 'Must be a base62 id string')
|
|
68
|
+
.describe('Base62Id');
|
|
69
|
+
export const zIdBase64 = z
|
|
70
|
+
.string()
|
|
71
|
+
.regex(/^[A-Za-z0-9+/]{6,62}={0,2}$/, 'Must be a base64 id string')
|
|
72
|
+
.describe('Base64Id');
|
|
73
|
+
export const zIdBase64Url = z
|
|
74
|
+
.string()
|
|
75
|
+
.regex(/^[\w-/]{8,64}$/, 'Must be a base64url id string')
|
|
76
|
+
.describe('Base64UrlId');
|
|
77
|
+
/**
|
|
78
|
+
* "Slug" - a valid URL, filename, etc.
|
|
79
|
+
*/
|
|
80
|
+
export const zSlug = z
|
|
81
|
+
.string()
|
|
82
|
+
.regex(/^[a-z0-9-]{1,255}$/, 'Must be a slug string')
|
|
83
|
+
.describe('Slug');
|
|
84
|
+
export const zBaseDBEntity = z
|
|
85
|
+
.object({
|
|
86
|
+
id: z.string().optional(),
|
|
87
|
+
created: zUnixTimestamp2000.optional(),
|
|
88
|
+
updated: zUnixTimestamp2000.optional(),
|
|
89
|
+
})
|
|
90
|
+
.describe('BaseDBEntity');
|
|
91
|
+
export const zSavedDBEntity = zBaseDBEntity.required().describe('SavedDBEntity');
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { ZodError } from 'zod';
|
|
2
|
+
import { _stringifyAny } from '../string/stringifyAny';
|
|
3
|
+
export function zIsValid(value, schema) {
|
|
4
|
+
const { success } = schema.safeParse(value);
|
|
5
|
+
return success;
|
|
6
|
+
}
|
|
7
|
+
export function zValidate(value, schema) {
|
|
8
|
+
const r = zSafeValidate(value, schema);
|
|
9
|
+
if (r.success) {
|
|
10
|
+
return r.data;
|
|
11
|
+
}
|
|
12
|
+
throw r.error;
|
|
13
|
+
}
|
|
14
|
+
export function zSafeValidate(value, schema) {
|
|
15
|
+
const r = schema.safeParse(value);
|
|
16
|
+
if (r.success) {
|
|
17
|
+
return r;
|
|
18
|
+
}
|
|
19
|
+
return {
|
|
20
|
+
success: false,
|
|
21
|
+
error: new ZodValidationError(r.error.issues, value, schema),
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
export class ZodValidationError extends ZodError {
|
|
25
|
+
constructor(issues, value, schema) {
|
|
26
|
+
super(issues);
|
|
27
|
+
this.value = value;
|
|
28
|
+
this.schema = schema;
|
|
29
|
+
}
|
|
30
|
+
get message() {
|
|
31
|
+
return this.annotate();
|
|
32
|
+
}
|
|
33
|
+
annotate() {
|
|
34
|
+
var _a;
|
|
35
|
+
let objectTitle = this.schema.description;
|
|
36
|
+
if (typeof this.value === 'object' && this.value) {
|
|
37
|
+
const objectName = this.schema.description || ((_a = this.value.constructor) === null || _a === void 0 ? void 0 : _a.name);
|
|
38
|
+
const objectId = this.value['id'];
|
|
39
|
+
objectTitle = [objectName, objectId].filter(Boolean).join('.');
|
|
40
|
+
}
|
|
41
|
+
objectTitle || (objectTitle = 'data');
|
|
42
|
+
return [
|
|
43
|
+
`Invalid ${objectTitle}`,
|
|
44
|
+
'',
|
|
45
|
+
'Input:',
|
|
46
|
+
_stringifyAny(this.value),
|
|
47
|
+
this.issues.length > 1 ? `\n${this.issues.length} issues:` : '',
|
|
48
|
+
...this.issues.slice(0, 100).map(i => {
|
|
49
|
+
return [i.path.join('.'), i.message].filter(Boolean).join(': ');
|
|
50
|
+
}),
|
|
51
|
+
].join('\n');
|
|
52
|
+
}
|
|
53
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@naturalcycles/js-lib",
|
|
3
|
-
"version": "14.
|
|
3
|
+
"version": "14.130.0",
|
|
4
4
|
"scripts": {
|
|
5
5
|
"prepare": "husky install",
|
|
6
6
|
"build-prod": "build-prod-esm-cjs",
|
|
@@ -8,7 +8,8 @@
|
|
|
8
8
|
"docs-build": "NODE_OPTIONS=--openssl-legacy-provider vuepress build docs"
|
|
9
9
|
},
|
|
10
10
|
"dependencies": {
|
|
11
|
-
"tslib": "^2.0.0"
|
|
11
|
+
"tslib": "^2.0.0",
|
|
12
|
+
"zod": "^3.20.2"
|
|
12
13
|
},
|
|
13
14
|
"devDependencies": {
|
|
14
15
|
"@naturalcycles/bench-lib": "^1.5.0",
|
|
@@ -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.
|