@zudojs/validation 1.0.2 → 1.0.3
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/validationConstraints/structure/validationConstraints.circular.d.ts +7 -1
- package/dist/validationConstraints/structure/validationConstraints.circular.js +11 -3
- package/dist/validationConstraints/structure/validationConstraints.size.d.ts +8 -0
- package/dist/validationConstraints/structure/validationConstraints.size.js +10 -1
- package/dist/validationParser/validationParser.collection.js +2 -3
- package/package.json +3 -3
|
@@ -17,12 +17,18 @@
|
|
|
17
17
|
* @param maxDepth - Depth ceiling, so a deep graph cannot exhaust the stack
|
|
18
18
|
* before a cycle is reported.
|
|
19
19
|
* @throws {CircularReferenceError} on the first cycle found.
|
|
20
|
+
* @throws {SerializationDepthError} when the graph is deeper than `maxDepth`.
|
|
21
|
+
* Running out of depth is not evidence of a cycle, and reporting it as one
|
|
22
|
+
* told callers a payload referenced itself when it merely nested too far.
|
|
20
23
|
*/
|
|
21
24
|
export declare function assertNoCircularReference(value: unknown, path?: string, maxDepth?: number): void;
|
|
22
25
|
/**
|
|
23
26
|
* Check whether a value contains circular references.
|
|
24
27
|
*
|
|
25
|
-
* Returns true if a cycle is found, false otherwise.
|
|
28
|
+
* Returns true if a cycle is found, false otherwise. A graph too deep to walk
|
|
29
|
+
* within the measurable ceiling reports false: no cycle was found, and the
|
|
30
|
+
* depth is the caller's own `assertDepthWithinLimit` to report.
|
|
31
|
+
*
|
|
26
32
|
* Does not throw — use assertNoCircularReference for throwing behavior.
|
|
27
33
|
*/
|
|
28
34
|
export declare function hasCircularReference(value: unknown): boolean;
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Detects circular references in object graphs before serialization
|
|
5
5
|
* or validation to prevent stack overflows and provide clear error messages.
|
|
6
6
|
*/
|
|
7
|
-
import { CircularReferenceError } from "@zudojs/errors";
|
|
7
|
+
import { CircularReferenceError, SerializationDepthError, } from "@zudojs/errors";
|
|
8
8
|
import { MAX_MEASURABLE_DEPTH } from "./validationConstraints.depth.js";
|
|
9
9
|
import { TraversalLimitError, traverse, } from "./validationConstraints.traverse.js";
|
|
10
10
|
/**
|
|
@@ -20,6 +20,9 @@ import { TraversalLimitError, traverse, } from "./validationConstraints.traverse
|
|
|
20
20
|
* @param maxDepth - Depth ceiling, so a deep graph cannot exhaust the stack
|
|
21
21
|
* before a cycle is reported.
|
|
22
22
|
* @throws {CircularReferenceError} on the first cycle found.
|
|
23
|
+
* @throws {SerializationDepthError} when the graph is deeper than `maxDepth`.
|
|
24
|
+
* Running out of depth is not evidence of a cycle, and reporting it as one
|
|
25
|
+
* told callers a payload referenced itself when it merely nested too far.
|
|
23
26
|
*/
|
|
24
27
|
export function assertNoCircularReference(value, path = "root", maxDepth = MAX_MEASURABLE_DEPTH) {
|
|
25
28
|
try {
|
|
@@ -30,7 +33,7 @@ export function assertNoCircularReference(value, path = "root", maxDepth = MAX_M
|
|
|
30
33
|
throw new CircularReferenceError(error.path);
|
|
31
34
|
}
|
|
32
35
|
if (error instanceof TraversalLimitError && error.halt === "depth") {
|
|
33
|
-
throw new
|
|
36
|
+
throw new SerializationDepthError(error.observed, maxDepth);
|
|
34
37
|
}
|
|
35
38
|
throw error;
|
|
36
39
|
}
|
|
@@ -38,7 +41,10 @@ export function assertNoCircularReference(value, path = "root", maxDepth = MAX_M
|
|
|
38
41
|
/**
|
|
39
42
|
* Check whether a value contains circular references.
|
|
40
43
|
*
|
|
41
|
-
* Returns true if a cycle is found, false otherwise.
|
|
44
|
+
* Returns true if a cycle is found, false otherwise. A graph too deep to walk
|
|
45
|
+
* within the measurable ceiling reports false: no cycle was found, and the
|
|
46
|
+
* depth is the caller's own `assertDepthWithinLimit` to report.
|
|
47
|
+
*
|
|
42
48
|
* Does not throw — use assertNoCircularReference for throwing behavior.
|
|
43
49
|
*/
|
|
44
50
|
export function hasCircularReference(value) {
|
|
@@ -49,6 +55,8 @@ export function hasCircularReference(value) {
|
|
|
49
55
|
catch (error) {
|
|
50
56
|
if (error instanceof CircularReferenceError)
|
|
51
57
|
return true;
|
|
58
|
+
if (error instanceof SerializationDepthError)
|
|
59
|
+
return false;
|
|
52
60
|
throw error;
|
|
53
61
|
}
|
|
54
62
|
}
|
|
@@ -12,8 +12,16 @@
|
|
|
12
12
|
* from shared subtrees estimate at a few hundred bytes while serializing to
|
|
13
13
|
* hundreds of megabytes.
|
|
14
14
|
*
|
|
15
|
+
* Charging every occurrence means the subtree memo that keeps the walk linear
|
|
16
|
+
* has to be off, so the budget is the only thing that bounds the work: `n`
|
|
17
|
+
* shared `{a:node,b:node}` pairs expand to `2^n` visits. The default budget is
|
|
18
|
+
* therefore finite — {@link SerializationLimits.MAX_SIZE} — rather than
|
|
19
|
+
* `Infinity`, which left an untrusted 1 KB payload able to burn minutes of CPU.
|
|
20
|
+
* Pass an explicit `Infinity` only for input you trust.
|
|
21
|
+
*
|
|
15
22
|
* @param value - The value to measure.
|
|
16
23
|
* @param maxBytes - Stop counting past this budget; the budget is returned.
|
|
24
|
+
* Defaults to {@link SerializationLimits.MAX_SIZE}.
|
|
17
25
|
* @returns The estimated serialized size in bytes.
|
|
18
26
|
*/
|
|
19
27
|
export declare function estimateSerializedSize(value: unknown, maxBytes?: number): number;
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
* Estimates serialized payload size to prevent memory exhaustion
|
|
5
5
|
* from excessively large payloads.
|
|
6
6
|
*/
|
|
7
|
+
import { SerializationLimits } from "@zudojs/constants";
|
|
7
8
|
import { SerializationPayloadTooLargeError } from "@zudojs/errors";
|
|
8
9
|
import { MAX_MEASURABLE_DEPTH } from "./validationConstraints.depth.js";
|
|
9
10
|
import { TraversalLimitError, traverse, } from "./validationConstraints.traverse.js";
|
|
@@ -69,11 +70,19 @@ function resolveToJson(value) {
|
|
|
69
70
|
* from shared subtrees estimate at a few hundred bytes while serializing to
|
|
70
71
|
* hundreds of megabytes.
|
|
71
72
|
*
|
|
73
|
+
* Charging every occurrence means the subtree memo that keeps the walk linear
|
|
74
|
+
* has to be off, so the budget is the only thing that bounds the work: `n`
|
|
75
|
+
* shared `{a:node,b:node}` pairs expand to `2^n` visits. The default budget is
|
|
76
|
+
* therefore finite — {@link SerializationLimits.MAX_SIZE} — rather than
|
|
77
|
+
* `Infinity`, which left an untrusted 1 KB payload able to burn minutes of CPU.
|
|
78
|
+
* Pass an explicit `Infinity` only for input you trust.
|
|
79
|
+
*
|
|
72
80
|
* @param value - The value to measure.
|
|
73
81
|
* @param maxBytes - Stop counting past this budget; the budget is returned.
|
|
82
|
+
* Defaults to {@link SerializationLimits.MAX_SIZE}.
|
|
74
83
|
* @returns The estimated serialized size in bytes.
|
|
75
84
|
*/
|
|
76
|
-
export function estimateSerializedSize(value, maxBytes =
|
|
85
|
+
export function estimateSerializedSize(value, maxBytes = SerializationLimits.MAX_SIZE) {
|
|
77
86
|
try {
|
|
78
87
|
return traverse(value, {
|
|
79
88
|
maxDepth: MAX_MEASURABLE_DEPTH,
|
|
@@ -3,10 +3,9 @@
|
|
|
3
3
|
*
|
|
4
4
|
* @module validationParser/validationParser.collection
|
|
5
5
|
*/
|
|
6
|
+
import { SCHEMA_FORBIDDEN_KEYS } from "@zudojs/constants";
|
|
6
7
|
import { validate, validateAsync, } from "../validationSchema/validationSchema.core.js";
|
|
7
8
|
import { failure, success } from "../validationResult/validationResult.type.js";
|
|
8
|
-
/** Property names that would mutate a prototype instead of adding a key. */
|
|
9
|
-
const FORBIDDEN_KEYS = new Set(["__proto__", "constructor", "prototype"]);
|
|
10
9
|
/** Parses multiple values using the same schema. Succeeds only when every value is valid. */
|
|
11
10
|
export function parseMany(schema, values) {
|
|
12
11
|
const parsed = [];
|
|
@@ -52,7 +51,7 @@ export function parseRecord(schema, values) {
|
|
|
52
51
|
const parsed = Object.create(null);
|
|
53
52
|
const issues = [];
|
|
54
53
|
for (const [key, value] of Object.entries(values)) {
|
|
55
|
-
if (
|
|
54
|
+
if (SCHEMA_FORBIDDEN_KEYS.has(key)) {
|
|
56
55
|
issues.push({
|
|
57
56
|
path: [key],
|
|
58
57
|
code: "forbidden_key",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zudojs/validation",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.3",
|
|
4
4
|
"description": "Schema validation with Zod integration, constraints, parsers, composers, circular detection, and depth/size checks.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": {
|
|
@@ -25,8 +25,8 @@
|
|
|
25
25
|
"!dist/.tsbuildinfo"
|
|
26
26
|
],
|
|
27
27
|
"dependencies": {
|
|
28
|
-
"@zudojs/constants": "1.1.
|
|
29
|
-
"@zudojs/errors": "1.
|
|
28
|
+
"@zudojs/constants": "1.1.1",
|
|
29
|
+
"@zudojs/errors": "1.2.0",
|
|
30
30
|
"zod": "^4.4.3"
|
|
31
31
|
},
|
|
32
32
|
"devDependencies": {
|