@naturalcycles/js-lib 15.68.0 → 15.70.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/promise/pProps.js +0 -2
- package/dist/string/regex.js +1 -1
- package/dist/types.d.ts +8 -0
- package/package.json +3 -8
- package/src/promise/pProps.ts +1 -5
- package/src/string/regex.ts +1 -1
- package/src/types.ts +10 -0
- package/dist/zod/customZod.d.ts +0 -6
- package/dist/zod/customZod.js +0 -4
- package/dist/zod/index.d.ts +0 -3
- package/dist/zod/index.js +0 -3
- package/dist/zod/zod.shared.schemas.d.ts +0 -46
- package/dist/zod/zod.shared.schemas.js +0 -101
- package/dist/zod/zod.util.d.ts +0 -13
- package/dist/zod/zod.util.js +0 -54
- package/src/zod/customZod.ts +0 -11
- package/src/zod/index.ts +0 -3
- package/src/zod/zod.shared.schemas.ts +0 -139
- package/src/zod/zod.util.ts +0 -72
package/dist/promise/pProps.js
CHANGED
|
@@ -14,7 +14,5 @@
|
|
|
14
14
|
*/
|
|
15
15
|
export async function pProps(input) {
|
|
16
16
|
const keys = Object.keys(input);
|
|
17
|
-
// `as any` here is added to make it compile when `noUncheckedIndexedAccess` is false
|
|
18
|
-
// oxlint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
|
|
19
17
|
return Object.fromEntries((await Promise.all(Object.values(input))).map((v, i) => [keys[i], v]));
|
|
20
18
|
}
|
package/dist/string/regex.js
CHANGED
package/dist/types.d.ts
CHANGED
|
@@ -84,6 +84,14 @@ export type AnyAsyncFunction<T = any> = (...args: any[]) => Promise<T>;
|
|
|
84
84
|
export type AsyncFunction<T = any> = () => Promise<T>;
|
|
85
85
|
export type AnyPromisableFunction<T = any> = (...args: any[]) => Promisable<T>;
|
|
86
86
|
export type PromisableFunction<T = any> = () => Promisable<T>;
|
|
87
|
+
export type AnySyncFunction<T = any> = (...args: any[]) => NotPromise<T>;
|
|
88
|
+
export type SyncFunction<T = any> = () => NotPromise<T>;
|
|
89
|
+
/**
|
|
90
|
+
* Compile-time guard against accidentally returning a Promise from a sync context.
|
|
91
|
+
* Example usage: `fn: () => NotPromise<T>`
|
|
92
|
+
* This would fail if fn returns a Promise (e.g an async function).
|
|
93
|
+
*/
|
|
94
|
+
export type NotPromise<T> = [T] extends [PromiseLike<any>] ? never : T;
|
|
87
95
|
/**
|
|
88
96
|
* A function that lazily calculates something.
|
|
89
97
|
*/
|
package/package.json
CHANGED
|
@@ -1,20 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@naturalcycles/js-lib",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "15.
|
|
4
|
+
"version": "15.70.0",
|
|
5
5
|
"dependencies": {
|
|
6
6
|
"tslib": "^2"
|
|
7
7
|
},
|
|
8
8
|
"peerDependencies": {
|
|
9
|
-
"undici": "^7"
|
|
10
|
-
"zod": "^4"
|
|
9
|
+
"undici": "^7"
|
|
11
10
|
},
|
|
12
11
|
"peerDependenciesMeta": {
|
|
13
12
|
"undici": {
|
|
14
13
|
"optional": true
|
|
15
|
-
},
|
|
16
|
-
"zod": {
|
|
17
|
-
"optional": true
|
|
18
14
|
}
|
|
19
15
|
},
|
|
20
16
|
"devDependencies": {
|
|
@@ -52,8 +48,7 @@
|
|
|
52
48
|
"./semver": "./dist/semver.js",
|
|
53
49
|
"./string": "./dist/string/index.js",
|
|
54
50
|
"./string/*.js": "./dist/string/*.js",
|
|
55
|
-
"./types": "./dist/types.js"
|
|
56
|
-
"./zod": "./dist/zod/index.js"
|
|
51
|
+
"./types": "./dist/types.js"
|
|
57
52
|
},
|
|
58
53
|
"files": [
|
|
59
54
|
"dist",
|
package/src/promise/pProps.ts
CHANGED
|
@@ -16,9 +16,5 @@ export async function pProps<T>(input: { [K in keyof T]: T[K] | Promise<T[K]> })
|
|
|
16
16
|
[K in keyof T]: Awaited<T[K]>
|
|
17
17
|
}> {
|
|
18
18
|
const keys = Object.keys(input)
|
|
19
|
-
|
|
20
|
-
// oxlint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
|
|
21
|
-
return Object.fromEntries(
|
|
22
|
-
(await Promise.all(Object.values(input))).map((v, i) => [keys[i], v]),
|
|
23
|
-
) as any
|
|
19
|
+
return Object.fromEntries((await Promise.all(Object.values(input))).map((v, i) => [keys[i], v]))
|
|
24
20
|
}
|
package/src/string/regex.ts
CHANGED
package/src/types.ts
CHANGED
|
@@ -105,6 +105,16 @@ export type AnyAsyncFunction<T = any> = (...args: any[]) => Promise<T>
|
|
|
105
105
|
export type AsyncFunction<T = any> = () => Promise<T>
|
|
106
106
|
export type AnyPromisableFunction<T = any> = (...args: any[]) => Promisable<T>
|
|
107
107
|
export type PromisableFunction<T = any> = () => Promisable<T>
|
|
108
|
+
export type AnySyncFunction<T = any> = (...args: any[]) => NotPromise<T>
|
|
109
|
+
export type SyncFunction<T = any> = () => NotPromise<T>
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Compile-time guard against accidentally returning a Promise from a sync context.
|
|
113
|
+
* Example usage: `fn: () => NotPromise<T>`
|
|
114
|
+
* This would fail if fn returns a Promise (e.g an async function).
|
|
115
|
+
*/
|
|
116
|
+
export type NotPromise<T> = [T] extends [PromiseLike<any>] ? never : T
|
|
117
|
+
|
|
108
118
|
/**
|
|
109
119
|
* A function that lazily calculates something.
|
|
110
120
|
*/
|
package/dist/zod/customZod.d.ts
DELETED
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
import { z as z4, ZodType } from 'zod';
|
|
2
|
-
import { customZodSchemas } from './zod.shared.schemas.js';
|
|
3
|
-
type ExtendedZod = Omit<typeof z4, keyof typeof customZodSchemas | 'iso'> & typeof customZodSchemas;
|
|
4
|
-
declare const z: ExtendedZod;
|
|
5
|
-
type zInfer<T> = z4.infer<T>;
|
|
6
|
-
export { z, type zInfer, ZodType };
|
package/dist/zod/customZod.js
DELETED
package/dist/zod/index.d.ts
DELETED
package/dist/zod/index.js
DELETED
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
import type { ZodString } from 'zod';
|
|
2
|
-
import { z } from 'zod';
|
|
3
|
-
import type { IANATimezone, IsoDate, UnixTimestamp, UnixTimestampMillis } from '../types.js';
|
|
4
|
-
type ZodBranded<T, B> = T & Record<'_zod', Record<'output', B>>;
|
|
5
|
-
export type ZodBrandedString<B> = ZodBranded<z.ZodString, B>;
|
|
6
|
-
export type ZodBrandedInt<B> = ZodBranded<z.ZodInt, B>;
|
|
7
|
-
export type ZodBrandedNumber<B> = ZodBranded<z.ZodNumber, B>;
|
|
8
|
-
export type ZodBrandedIsoDate = ZodBranded<z.ZodISODate, IsoDate>;
|
|
9
|
-
declare function unixTimestamp(): ZodBrandedInt<UnixTimestamp>;
|
|
10
|
-
declare function unixTimestamp2000(): ZodBrandedInt<UnixTimestamp>;
|
|
11
|
-
declare function unixTimestampMillis(): ZodBranded<z.ZodNumber, UnixTimestampMillis>;
|
|
12
|
-
declare function unixTimestampMillis2000(): ZodBrandedInt<UnixTimestampMillis>;
|
|
13
|
-
declare function semVer(): z.ZodString;
|
|
14
|
-
declare function isoDate(): ZodBrandedString<IsoDate>;
|
|
15
|
-
declare function base62(): z.ZodString;
|
|
16
|
-
declare function base64(): z.ZodString;
|
|
17
|
-
declare function base64Url(): z.ZodString;
|
|
18
|
-
declare function jwt(): z.ZodString;
|
|
19
|
-
/**
|
|
20
|
-
* "Slug" - a valid URL, filename, etc.
|
|
21
|
-
*/
|
|
22
|
-
declare function slug(): z.ZodString;
|
|
23
|
-
declare function ianaTimezone(): ZodBrandedString<IANATimezone>;
|
|
24
|
-
type BaseDBEntityZodShape = {
|
|
25
|
-
id: ZodString;
|
|
26
|
-
created: ZodBrandedInt<UnixTimestamp>;
|
|
27
|
-
updated: ZodBrandedInt<UnixTimestamp>;
|
|
28
|
-
};
|
|
29
|
-
declare function dbEntity(): z.ZodObject<BaseDBEntityZodShape>;
|
|
30
|
-
declare function dbEntity<T extends z.ZodRawShape>(shape: T): z.ZodObject<BaseDBEntityZodShape & T>;
|
|
31
|
-
export declare const customZodSchemas: {
|
|
32
|
-
base62: typeof base62;
|
|
33
|
-
base64: typeof base64;
|
|
34
|
-
base64Url: typeof base64Url;
|
|
35
|
-
dbEntity: typeof dbEntity;
|
|
36
|
-
ianaTimezone: typeof ianaTimezone;
|
|
37
|
-
isoDate: typeof isoDate;
|
|
38
|
-
jwt: typeof jwt;
|
|
39
|
-
slug: typeof slug;
|
|
40
|
-
semver: typeof semVer;
|
|
41
|
-
unixTimestamp: typeof unixTimestamp;
|
|
42
|
-
unixTimestamp2000: typeof unixTimestamp2000;
|
|
43
|
-
unixTimestampMillis: typeof unixTimestampMillis;
|
|
44
|
-
unixTimestampMillis2000: typeof unixTimestampMillis2000;
|
|
45
|
-
};
|
|
46
|
-
export {};
|
|
@@ -1,101 +0,0 @@
|
|
|
1
|
-
import { z } from 'zod';
|
|
2
|
-
const TS_2500 = 16725225600; // 2500-01-01
|
|
3
|
-
const TS_2000 = 946684800; // 2000-01-01
|
|
4
|
-
function unixTimestamp() {
|
|
5
|
-
return z
|
|
6
|
-
.number()
|
|
7
|
-
.int()
|
|
8
|
-
.min(0)
|
|
9
|
-
.max(TS_2500, 'Must be a UnixTimestamp number')
|
|
10
|
-
.describe('UnixTimestamp');
|
|
11
|
-
}
|
|
12
|
-
function unixTimestamp2000() {
|
|
13
|
-
return z
|
|
14
|
-
.number()
|
|
15
|
-
.int()
|
|
16
|
-
.min(TS_2000)
|
|
17
|
-
.max(TS_2500, 'Must be a UnixTimestamp number after 2000-01-01')
|
|
18
|
-
.describe('UnixTimestamp2000');
|
|
19
|
-
}
|
|
20
|
-
function unixTimestampMillis() {
|
|
21
|
-
return z
|
|
22
|
-
.number()
|
|
23
|
-
.int()
|
|
24
|
-
.min(0)
|
|
25
|
-
.max(TS_2500 * 1000, 'Must be a UnixTimestampMillis number')
|
|
26
|
-
.describe('UnixTimestampMillis');
|
|
27
|
-
}
|
|
28
|
-
function unixTimestampMillis2000() {
|
|
29
|
-
return z
|
|
30
|
-
.number()
|
|
31
|
-
.int()
|
|
32
|
-
.min(TS_2000 * 1000)
|
|
33
|
-
.max(TS_2500 * 1000, 'Must be a UnixTimestampMillis number after 2000-01-01')
|
|
34
|
-
.describe('UnixTimestampMillis2000');
|
|
35
|
-
}
|
|
36
|
-
function semVer() {
|
|
37
|
-
return z
|
|
38
|
-
.string()
|
|
39
|
-
.regex(/^[0-9]+\.[0-9]+\.[0-9]+$/, 'Must be a SemVer string')
|
|
40
|
-
.describe('SemVer');
|
|
41
|
-
}
|
|
42
|
-
function isoDate() {
|
|
43
|
-
return z
|
|
44
|
-
.string()
|
|
45
|
-
.regex(/^\d{4}-\d{2}-\d{2}$/, { error: 'Must be a YYYY-MM-DD string' })
|
|
46
|
-
.describe('IsoDate');
|
|
47
|
-
}
|
|
48
|
-
const BASE62_REGEX = /^[a-zA-Z0-9]+$/;
|
|
49
|
-
const BASE64_REGEX = /^[A-Za-z0-9+/]+={0,2}$/;
|
|
50
|
-
const BASE64URL_REGEX = /^[\w\-/]+$/;
|
|
51
|
-
function base62() {
|
|
52
|
-
return z.string().regex(BASE62_REGEX, 'Must be a base62 string').describe('Base62String');
|
|
53
|
-
}
|
|
54
|
-
function base64() {
|
|
55
|
-
return z.string().regex(BASE64_REGEX, 'Must be a base64 string').describe('Base64String');
|
|
56
|
-
}
|
|
57
|
-
function base64Url() {
|
|
58
|
-
return z.string().regex(BASE64URL_REGEX, 'Must be a base64url string').describe('Base64UrlString');
|
|
59
|
-
}
|
|
60
|
-
const JWT_REGEX = /^[\w-]+\.[\w-]+\.[\w-]+$/;
|
|
61
|
-
function jwt() {
|
|
62
|
-
return z.string().regex(JWT_REGEX, 'Must be a JWT string').describe('JWTString');
|
|
63
|
-
}
|
|
64
|
-
/**
|
|
65
|
-
* "Slug" - a valid URL, filename, etc.
|
|
66
|
-
*/
|
|
67
|
-
function slug() {
|
|
68
|
-
return z
|
|
69
|
-
.string()
|
|
70
|
-
.regex(/^[a-z0-9-]{1,255}$/, 'Must be a slug string')
|
|
71
|
-
.describe('Slug');
|
|
72
|
-
}
|
|
73
|
-
function ianaTimezone() {
|
|
74
|
-
return z
|
|
75
|
-
// UTC is added to assist unit-testing, which uses UTC by default (not technically a valid Iana timezone identifier)
|
|
76
|
-
.enum([...Intl.supportedValuesOf('timeZone'), 'UTC'])
|
|
77
|
-
.describe('IANATimezone');
|
|
78
|
-
}
|
|
79
|
-
const baseDBEntitySchema = z.object({
|
|
80
|
-
id: z.string(),
|
|
81
|
-
created: unixTimestamp2000(),
|
|
82
|
-
updated: unixTimestamp2000(),
|
|
83
|
-
});
|
|
84
|
-
function dbEntity(shape) {
|
|
85
|
-
return baseDBEntitySchema.extend(shape ?? {});
|
|
86
|
-
}
|
|
87
|
-
export const customZodSchemas = {
|
|
88
|
-
base62,
|
|
89
|
-
base64,
|
|
90
|
-
base64Url,
|
|
91
|
-
dbEntity,
|
|
92
|
-
ianaTimezone,
|
|
93
|
-
isoDate,
|
|
94
|
-
jwt,
|
|
95
|
-
slug,
|
|
96
|
-
semver: semVer,
|
|
97
|
-
unixTimestamp,
|
|
98
|
-
unixTimestamp2000,
|
|
99
|
-
unixTimestampMillis,
|
|
100
|
-
unixTimestampMillis2000,
|
|
101
|
-
};
|
package/dist/zod/zod.util.d.ts
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import type { ZodError, ZodType } from 'zod';
|
|
2
|
-
import type { ErrorData } from '../error/error.model.js';
|
|
3
|
-
import { AppError } from '../error/error.util.js';
|
|
4
|
-
import type { ValidationFunction, ValidationFunctionResult } from '../validation/validation.js';
|
|
5
|
-
export declare function getZodValidationFunction<T>(schema: ZodType<T>): ValidationFunction<T, ZodValidationError>;
|
|
6
|
-
export declare function zIsValid<T>(value: unknown, schema: ZodType<T>): boolean;
|
|
7
|
-
export declare function zValidate<T>(value: unknown, schema: ZodType<T>): T;
|
|
8
|
-
export declare function zSafeValidate<T>(input: unknown, schema: ZodType<T>): ValidationFunctionResult<T, ZodValidationError>;
|
|
9
|
-
export interface ZodValidationErrorData extends ErrorData {
|
|
10
|
-
}
|
|
11
|
-
export declare class ZodValidationError extends AppError<ZodValidationErrorData> {
|
|
12
|
-
constructor(zodError: ZodError, value: any, schema: ZodType);
|
|
13
|
-
}
|
package/dist/zod/zod.util.js
DELETED
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
import { _assert } from '../error/assert.js';
|
|
2
|
-
import { AppError } from '../error/error.util.js';
|
|
3
|
-
import { _stringify } from '../string/stringify.js';
|
|
4
|
-
export function getZodValidationFunction(schema) {
|
|
5
|
-
return (input, opt) => {
|
|
6
|
-
_assert(!opt?.mutateInput, 'mutateInput=true is not yet supported with Zod');
|
|
7
|
-
return zSafeValidate(input, schema);
|
|
8
|
-
};
|
|
9
|
-
}
|
|
10
|
-
export function zIsValid(value, schema) {
|
|
11
|
-
const { success } = schema.safeParse(value);
|
|
12
|
-
return success;
|
|
13
|
-
}
|
|
14
|
-
export function zValidate(value, schema) {
|
|
15
|
-
const [err, data] = zSafeValidate(value, schema);
|
|
16
|
-
if (err)
|
|
17
|
-
throw err;
|
|
18
|
-
return data;
|
|
19
|
-
}
|
|
20
|
-
export function zSafeValidate(input, schema
|
|
21
|
-
// inputName?: string,
|
|
22
|
-
) {
|
|
23
|
-
const r = schema.safeParse(input);
|
|
24
|
-
if (r.success) {
|
|
25
|
-
return [null, r.data];
|
|
26
|
-
}
|
|
27
|
-
return [new ZodValidationError(r.error, input, schema), r.data ?? input];
|
|
28
|
-
}
|
|
29
|
-
export class ZodValidationError extends AppError {
|
|
30
|
-
constructor(zodError, value, schema) {
|
|
31
|
-
const message = createZodErrorMessage(zodError, schema, value);
|
|
32
|
-
// const message = z.prettifyError(zodError) // todo: consider adopting it instead
|
|
33
|
-
super(message, {}, { name: 'ZodValidationError' });
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
function createZodErrorMessage(err, schema, value) {
|
|
37
|
-
let objectTitle = schema.description;
|
|
38
|
-
if (typeof value === 'object' && value) {
|
|
39
|
-
const inputName = schema.description || value.constructor?.name;
|
|
40
|
-
const inputId = value['id'];
|
|
41
|
-
objectTitle = [inputName, inputId].filter(Boolean).join('.');
|
|
42
|
-
}
|
|
43
|
-
objectTitle ||= 'data';
|
|
44
|
-
return [
|
|
45
|
-
`Invalid ${objectTitle}`,
|
|
46
|
-
'',
|
|
47
|
-
'Input:',
|
|
48
|
-
_stringify(value),
|
|
49
|
-
err.issues.length > 1 ? `\n${err.issues.length} issues:` : '',
|
|
50
|
-
...err.issues.slice(0, 100).map(i => {
|
|
51
|
-
return [i.path.join('.'), i.message].filter(Boolean).join(': ');
|
|
52
|
-
}),
|
|
53
|
-
].join('\n');
|
|
54
|
-
}
|
package/src/zod/customZod.ts
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import { z as z4, ZodType } from 'zod'
|
|
2
|
-
import { customZodSchemas } from './zod.shared.schemas.js'
|
|
3
|
-
|
|
4
|
-
type ExtendedZod = Omit<typeof z4, keyof typeof customZodSchemas | 'iso'> & typeof customZodSchemas
|
|
5
|
-
|
|
6
|
-
const z: ExtendedZod = { ...z4, ...customZodSchemas }
|
|
7
|
-
|
|
8
|
-
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
9
|
-
type zInfer<T> = z4.infer<T>
|
|
10
|
-
|
|
11
|
-
export { z, type zInfer, ZodType }
|
package/src/zod/index.ts
DELETED
|
@@ -1,139 +0,0 @@
|
|
|
1
|
-
import type { ZodString } from 'zod'
|
|
2
|
-
import { z } from 'zod'
|
|
3
|
-
import type { IANATimezone, IsoDate, UnixTimestamp, UnixTimestampMillis } from '../types.js'
|
|
4
|
-
|
|
5
|
-
type ZodBranded<T, B> = T & Record<'_zod', Record<'output', B>>
|
|
6
|
-
export type ZodBrandedString<B> = ZodBranded<z.ZodString, B>
|
|
7
|
-
export type ZodBrandedInt<B> = ZodBranded<z.ZodInt, B>
|
|
8
|
-
export type ZodBrandedNumber<B> = ZodBranded<z.ZodNumber, B>
|
|
9
|
-
export type ZodBrandedIsoDate = ZodBranded<z.ZodISODate, IsoDate>
|
|
10
|
-
|
|
11
|
-
const TS_2500 = 16725225600 // 2500-01-01
|
|
12
|
-
const TS_2000 = 946684800 // 2000-01-01
|
|
13
|
-
|
|
14
|
-
function unixTimestamp(): ZodBrandedInt<UnixTimestamp> {
|
|
15
|
-
return z
|
|
16
|
-
.number()
|
|
17
|
-
.int()
|
|
18
|
-
.min(0)
|
|
19
|
-
.max(TS_2500, 'Must be a UnixTimestamp number')
|
|
20
|
-
.describe('UnixTimestamp') as ZodBrandedInt<UnixTimestamp>
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
function unixTimestamp2000(): ZodBrandedInt<UnixTimestamp> {
|
|
24
|
-
return z
|
|
25
|
-
.number()
|
|
26
|
-
.int()
|
|
27
|
-
.min(TS_2000)
|
|
28
|
-
.max(TS_2500, 'Must be a UnixTimestamp number after 2000-01-01')
|
|
29
|
-
.describe('UnixTimestamp2000') as ZodBrandedInt<UnixTimestamp>
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
function unixTimestampMillis(): ZodBranded<z.ZodNumber, UnixTimestampMillis> {
|
|
33
|
-
return z
|
|
34
|
-
.number()
|
|
35
|
-
.int()
|
|
36
|
-
.min(0)
|
|
37
|
-
.max(TS_2500 * 1000, 'Must be a UnixTimestampMillis number')
|
|
38
|
-
.describe('UnixTimestampMillis') as ZodBrandedInt<UnixTimestampMillis>
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
function unixTimestampMillis2000(): ZodBrandedInt<UnixTimestampMillis> {
|
|
42
|
-
return z
|
|
43
|
-
.number()
|
|
44
|
-
.int()
|
|
45
|
-
.min(TS_2000 * 1000)
|
|
46
|
-
.max(TS_2500 * 1000, 'Must be a UnixTimestampMillis number after 2000-01-01')
|
|
47
|
-
.describe('UnixTimestampMillis2000') as ZodBrandedInt<UnixTimestampMillis>
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
function semVer(): z.ZodString {
|
|
51
|
-
return z
|
|
52
|
-
.string()
|
|
53
|
-
.regex(/^[0-9]+\.[0-9]+\.[0-9]+$/, 'Must be a SemVer string')
|
|
54
|
-
.describe('SemVer')
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
function isoDate(): ZodBrandedString<IsoDate> {
|
|
58
|
-
return z
|
|
59
|
-
.string()
|
|
60
|
-
.regex(/^\d{4}-\d{2}-\d{2}$/, { error: 'Must be a YYYY-MM-DD string' })
|
|
61
|
-
.describe('IsoDate') as ZodBrandedString<IsoDate>
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
const BASE62_REGEX = /^[a-zA-Z0-9]+$/
|
|
65
|
-
const BASE64_REGEX = /^[A-Za-z0-9+/]+={0,2}$/
|
|
66
|
-
const BASE64URL_REGEX = /^[\w\-/]+$/
|
|
67
|
-
|
|
68
|
-
function base62(): z.ZodString {
|
|
69
|
-
return z.string().regex(BASE62_REGEX, 'Must be a base62 string').describe('Base62String')
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
function base64(): z.ZodString {
|
|
73
|
-
return z.string().regex(BASE64_REGEX, 'Must be a base64 string').describe('Base64String')
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
function base64Url(): z.ZodString {
|
|
77
|
-
return z.string().regex(BASE64URL_REGEX, 'Must be a base64url string').describe('Base64UrlString')
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
const JWT_REGEX = /^[\w-]+\.[\w-]+\.[\w-]+$/
|
|
81
|
-
|
|
82
|
-
function jwt(): z.ZodString {
|
|
83
|
-
return z.string().regex(JWT_REGEX, 'Must be a JWT string').describe('JWTString')
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
/**
|
|
87
|
-
* "Slug" - a valid URL, filename, etc.
|
|
88
|
-
*/
|
|
89
|
-
function slug(): z.ZodString {
|
|
90
|
-
return z
|
|
91
|
-
.string()
|
|
92
|
-
.regex(/^[a-z0-9-]{1,255}$/, 'Must be a slug string')
|
|
93
|
-
.describe('Slug')
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
function ianaTimezone(): ZodBrandedString<IANATimezone> {
|
|
97
|
-
return (
|
|
98
|
-
z
|
|
99
|
-
// UTC is added to assist unit-testing, which uses UTC by default (not technically a valid Iana timezone identifier)
|
|
100
|
-
.enum([...Intl.supportedValuesOf('timeZone'), 'UTC'])
|
|
101
|
-
.describe('IANATimezone') as unknown as ZodBrandedString<IANATimezone>
|
|
102
|
-
)
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
const baseDBEntitySchema = z.object({
|
|
106
|
-
id: z.string(),
|
|
107
|
-
created: unixTimestamp2000(),
|
|
108
|
-
updated: unixTimestamp2000(),
|
|
109
|
-
})
|
|
110
|
-
|
|
111
|
-
// oxlint-disable-next-line @typescript-eslint/consistent-type-definitions
|
|
112
|
-
type BaseDBEntityZodShape = {
|
|
113
|
-
id: ZodString
|
|
114
|
-
created: ZodBrandedInt<UnixTimestamp>
|
|
115
|
-
updated: ZodBrandedInt<UnixTimestamp>
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
function dbEntity(): z.ZodObject<BaseDBEntityZodShape>
|
|
119
|
-
function dbEntity<T extends z.ZodRawShape>(shape: T): z.ZodObject<BaseDBEntityZodShape & T>
|
|
120
|
-
|
|
121
|
-
function dbEntity<T extends z.ZodRawShape>(shape?: T): z.ZodObject<BaseDBEntityZodShape & T> {
|
|
122
|
-
return baseDBEntitySchema.extend(shape ?? {}) as z.ZodObject<BaseDBEntityZodShape & T>
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
export const customZodSchemas = {
|
|
126
|
-
base62,
|
|
127
|
-
base64,
|
|
128
|
-
base64Url,
|
|
129
|
-
dbEntity,
|
|
130
|
-
ianaTimezone,
|
|
131
|
-
isoDate,
|
|
132
|
-
jwt,
|
|
133
|
-
slug,
|
|
134
|
-
semver: semVer,
|
|
135
|
-
unixTimestamp,
|
|
136
|
-
unixTimestamp2000,
|
|
137
|
-
unixTimestampMillis,
|
|
138
|
-
unixTimestampMillis2000,
|
|
139
|
-
}
|
package/src/zod/zod.util.ts
DELETED
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
import type { ZodError, ZodType } from 'zod'
|
|
2
|
-
import { _assert } from '../error/assert.js'
|
|
3
|
-
import type { ErrorData } from '../error/error.model.js'
|
|
4
|
-
import { AppError } from '../error/error.util.js'
|
|
5
|
-
import { _stringify } from '../string/stringify.js'
|
|
6
|
-
import type { ValidationFunction, ValidationFunctionResult } from '../validation/validation.js'
|
|
7
|
-
|
|
8
|
-
export function getZodValidationFunction<T>(
|
|
9
|
-
schema: ZodType<T>,
|
|
10
|
-
): ValidationFunction<T, ZodValidationError> {
|
|
11
|
-
return (input, opt) => {
|
|
12
|
-
_assert(!opt?.mutateInput, 'mutateInput=true is not yet supported with Zod')
|
|
13
|
-
return zSafeValidate(input, schema)
|
|
14
|
-
}
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export function zIsValid<T>(value: unknown, schema: ZodType<T>): boolean {
|
|
18
|
-
const { success } = schema.safeParse(value)
|
|
19
|
-
return success
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
export function zValidate<T>(value: unknown, schema: ZodType<T>): T {
|
|
23
|
-
const [err, data] = zSafeValidate(value, schema)
|
|
24
|
-
if (err) throw err
|
|
25
|
-
return data
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
export function zSafeValidate<T>(
|
|
29
|
-
input: unknown,
|
|
30
|
-
schema: ZodType<T>,
|
|
31
|
-
// inputName?: string,
|
|
32
|
-
): ValidationFunctionResult<T, ZodValidationError> {
|
|
33
|
-
const r = schema.safeParse(input)
|
|
34
|
-
if (r.success) {
|
|
35
|
-
return [null, r.data]
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
return [new ZodValidationError(r.error, input, schema), r.data ?? (input as T)]
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
export interface ZodValidationErrorData extends ErrorData {}
|
|
42
|
-
|
|
43
|
-
export class ZodValidationError extends AppError<ZodValidationErrorData> {
|
|
44
|
-
constructor(zodError: ZodError, value: any, schema: ZodType) {
|
|
45
|
-
const message = createZodErrorMessage(zodError, schema, value)
|
|
46
|
-
// const message = z.prettifyError(zodError) // todo: consider adopting it instead
|
|
47
|
-
super(message, {}, { name: 'ZodValidationError' })
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
function createZodErrorMessage<T>(err: ZodError<T>, schema: ZodType<T>, value: T): string {
|
|
52
|
-
let objectTitle = schema.description
|
|
53
|
-
|
|
54
|
-
if (typeof value === 'object' && value) {
|
|
55
|
-
const inputName = schema.description || value.constructor?.name
|
|
56
|
-
const inputId = (value as any)['id'] as string
|
|
57
|
-
objectTitle = [inputName, inputId].filter(Boolean).join('.')
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
objectTitle ||= 'data'
|
|
61
|
-
|
|
62
|
-
return [
|
|
63
|
-
`Invalid ${objectTitle}`,
|
|
64
|
-
'',
|
|
65
|
-
'Input:',
|
|
66
|
-
_stringify(value),
|
|
67
|
-
err.issues.length > 1 ? `\n${err.issues.length} issues:` : '',
|
|
68
|
-
...err.issues.slice(0, 100).map(i => {
|
|
69
|
-
return [i.path.join('.'), i.message].filter(Boolean).join(': ')
|
|
70
|
-
}),
|
|
71
|
-
].join('\n')
|
|
72
|
-
}
|