stream-validate 0.1.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/README.md +145 -0
- package/dist/__tests__/parser.test.d.ts +2 -0
- package/dist/__tests__/parser.test.d.ts.map +1 -0
- package/dist/__tests__/parser.test.js +77 -0
- package/dist/__tests__/parser.test.js.map +1 -0
- package/dist/__tests__/stream-validate.test.d.ts +2 -0
- package/dist/__tests__/stream-validate.test.d.ts.map +1 -0
- package/dist/__tests__/stream-validate.test.js +203 -0
- package/dist/__tests__/stream-validate.test.js.map +1 -0
- package/dist/events.d.ts +9 -0
- package/dist/events.d.ts.map +1 -0
- package/dist/events.js +30 -0
- package/dist/events.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +9 -0
- package/dist/index.js.map +1 -0
- package/dist/parser.d.ts +40 -0
- package/dist/parser.d.ts.map +1 -0
- package/dist/parser.js +257 -0
- package/dist/parser.js.map +1 -0
- package/dist/stream-validate.d.ts +9 -0
- package/dist/stream-validate.d.ts.map +1 -0
- package/dist/stream-validate.js +44 -0
- package/dist/stream-validate.js.map +1 -0
- package/dist/stream-validator.d.ts +4 -0
- package/dist/stream-validator.d.ts.map +1 -0
- package/dist/stream-validator.js +162 -0
- package/dist/stream-validator.js.map +1 -0
- package/dist/types.d.ts +54 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +3 -0
- package/dist/types.js.map +1 -0
- package/dist/validator.d.ts +23 -0
- package/dist/validator.d.ts.map +1 -0
- package/dist/validator.js +146 -0
- package/dist/validator.js.map +1 -0
- package/package.json +36 -0
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ProgressiveValidator = void 0;
|
|
4
|
+
const zod_1 = require("zod");
|
|
5
|
+
/**
|
|
6
|
+
* Navigate a Zod schema to a sub-schema by dot/bracket path.
|
|
7
|
+
* e.g. path "address.city" on z.object({address: z.object({city: z.string()})})
|
|
8
|
+
* returns the z.string() schema.
|
|
9
|
+
* Returns null if the path can't be resolved.
|
|
10
|
+
*/
|
|
11
|
+
function getSubSchema(schema, path) {
|
|
12
|
+
if (!path)
|
|
13
|
+
return schema;
|
|
14
|
+
// Unwrap optional/nullable/default wrappers
|
|
15
|
+
let s = schema;
|
|
16
|
+
while (s instanceof zod_1.z.ZodOptional ||
|
|
17
|
+
s instanceof zod_1.z.ZodNullable ||
|
|
18
|
+
s instanceof zod_1.z.ZodDefault) {
|
|
19
|
+
s = s._def.innerType;
|
|
20
|
+
}
|
|
21
|
+
const parts = path.replace(/\[(\d+)\]/g, '.$1').split('.');
|
|
22
|
+
const [head, ...rest] = parts;
|
|
23
|
+
const restPath = rest.join('.');
|
|
24
|
+
if (s instanceof zod_1.z.ZodObject) {
|
|
25
|
+
const shape = s.shape;
|
|
26
|
+
if (!(head in shape))
|
|
27
|
+
return null;
|
|
28
|
+
return getSubSchema(shape[head], restPath);
|
|
29
|
+
}
|
|
30
|
+
if (s instanceof zod_1.z.ZodArray) {
|
|
31
|
+
// head is an array index — recurse into element type
|
|
32
|
+
return getSubSchema(s._def.type, restPath);
|
|
33
|
+
}
|
|
34
|
+
return null;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Set a value at a dot/bracket path in a nested object (mutates).
|
|
38
|
+
*/
|
|
39
|
+
function setAtPath(obj, path, value) {
|
|
40
|
+
const parts = path.replace(/\[(\d+)\]/g, '.$1').split('.');
|
|
41
|
+
let cur = obj;
|
|
42
|
+
for (let i = 0; i < parts.length - 1; i++) {
|
|
43
|
+
const k = parts[i];
|
|
44
|
+
if (cur[k] === undefined || cur[k] === null || typeof cur[k] !== 'object') {
|
|
45
|
+
cur[k] = {};
|
|
46
|
+
}
|
|
47
|
+
cur = cur[k];
|
|
48
|
+
}
|
|
49
|
+
cur[parts[parts.length - 1]] = value;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Collect all required field paths from a Zod schema.
|
|
53
|
+
*/
|
|
54
|
+
function collectRequiredPaths(schema, prefix = '') {
|
|
55
|
+
let s = schema;
|
|
56
|
+
const isOptional = s instanceof zod_1.z.ZodOptional;
|
|
57
|
+
while (s instanceof zod_1.z.ZodOptional ||
|
|
58
|
+
s instanceof zod_1.z.ZodNullable ||
|
|
59
|
+
s instanceof zod_1.z.ZodDefault) {
|
|
60
|
+
s = s._def.innerType;
|
|
61
|
+
}
|
|
62
|
+
if (s instanceof zod_1.z.ZodObject) {
|
|
63
|
+
const paths = [];
|
|
64
|
+
const shape = s.shape;
|
|
65
|
+
for (const [k, v] of Object.entries(shape)) {
|
|
66
|
+
const childPaths = collectRequiredPaths(v, prefix ? `${prefix}.${k}` : k);
|
|
67
|
+
paths.push(...childPaths);
|
|
68
|
+
}
|
|
69
|
+
return paths;
|
|
70
|
+
}
|
|
71
|
+
// Leaf node
|
|
72
|
+
if (isOptional)
|
|
73
|
+
return [];
|
|
74
|
+
return prefix ? [prefix] : [];
|
|
75
|
+
}
|
|
76
|
+
class ProgressiveValidator {
|
|
77
|
+
schema;
|
|
78
|
+
data = {};
|
|
79
|
+
meta = {};
|
|
80
|
+
seq = 0;
|
|
81
|
+
startTime = Date.now();
|
|
82
|
+
requiredPaths;
|
|
83
|
+
failedPaths = [];
|
|
84
|
+
constructor(schema) {
|
|
85
|
+
this.schema = schema;
|
|
86
|
+
this.requiredPaths = collectRequiredPaths(schema);
|
|
87
|
+
}
|
|
88
|
+
applyField(path, value, options) {
|
|
89
|
+
const strategy = options?.strategy ?? 'skip';
|
|
90
|
+
const subSchema = getSubSchema(this.schema, path);
|
|
91
|
+
let status = 'complete';
|
|
92
|
+
let validationError;
|
|
93
|
+
if (subSchema) {
|
|
94
|
+
const result = subSchema.safeParse(value);
|
|
95
|
+
if (!result.success) {
|
|
96
|
+
const message = result.error.errors.map(e => e.message).join('; ');
|
|
97
|
+
validationError = {
|
|
98
|
+
path,
|
|
99
|
+
value,
|
|
100
|
+
message,
|
|
101
|
+
elapsedMs: Date.now() - this.startTime,
|
|
102
|
+
};
|
|
103
|
+
status = 'error';
|
|
104
|
+
this.failedPaths.push(path);
|
|
105
|
+
if (strategy === 'skip') {
|
|
106
|
+
// Don't set the value, mark as error and return
|
|
107
|
+
this.meta[path] = 'error';
|
|
108
|
+
return { partial: this.buildPartial(), error: validationError };
|
|
109
|
+
}
|
|
110
|
+
else if (strategy === 'error') {
|
|
111
|
+
this.meta[path] = 'error';
|
|
112
|
+
return { partial: this.buildPartial(), error: validationError };
|
|
113
|
+
}
|
|
114
|
+
// include-invalid: fall through and set value anyway
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
setAtPath(this.data, path, value);
|
|
118
|
+
this.meta[path] = status;
|
|
119
|
+
this.seq++;
|
|
120
|
+
return { partial: this.buildPartial(), error: validationError };
|
|
121
|
+
}
|
|
122
|
+
isComplete() {
|
|
123
|
+
if (this.requiredPaths.length === 0) {
|
|
124
|
+
// No required paths detected — check if we have any data
|
|
125
|
+
return Object.keys(this.meta).length > 0;
|
|
126
|
+
}
|
|
127
|
+
return this.requiredPaths.every(p => this.meta[p] === 'complete');
|
|
128
|
+
}
|
|
129
|
+
getFailedPaths() {
|
|
130
|
+
return this.failedPaths.slice();
|
|
131
|
+
}
|
|
132
|
+
getRequiredPaths() {
|
|
133
|
+
return this.requiredPaths.slice();
|
|
134
|
+
}
|
|
135
|
+
buildPartial() {
|
|
136
|
+
return {
|
|
137
|
+
data: this.data,
|
|
138
|
+
meta: { ...this.meta },
|
|
139
|
+
isComplete: this.isComplete(),
|
|
140
|
+
seq: this.seq,
|
|
141
|
+
elapsedMs: Date.now() - this.startTime,
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
exports.ProgressiveValidator = ProgressiveValidator;
|
|
146
|
+
//# sourceMappingURL=validator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validator.js","sourceRoot":"","sources":["../src/validator.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "stream-validate",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Progressive Zod validation for streaming LLM responses",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"files": [
|
|
8
|
+
"dist"
|
|
9
|
+
],
|
|
10
|
+
"scripts": {
|
|
11
|
+
"build": "tsc",
|
|
12
|
+
"test": "vitest run",
|
|
13
|
+
"lint": "eslint src/",
|
|
14
|
+
"prepublishOnly": "npm run build"
|
|
15
|
+
},
|
|
16
|
+
"keywords": [],
|
|
17
|
+
"author": "",
|
|
18
|
+
"license": "MIT",
|
|
19
|
+
"engines": {
|
|
20
|
+
"node": ">=18"
|
|
21
|
+
},
|
|
22
|
+
"publishConfig": {
|
|
23
|
+
"access": "public"
|
|
24
|
+
},
|
|
25
|
+
"dependencies": {
|
|
26
|
+
"zod": "^3.23.8"
|
|
27
|
+
},
|
|
28
|
+
"devDependencies": {
|
|
29
|
+
"@types/node": "^25.5.0",
|
|
30
|
+
"@typescript-eslint/eslint-plugin": "^8.57.1",
|
|
31
|
+
"@typescript-eslint/parser": "^8.57.1",
|
|
32
|
+
"eslint": "^10.1.0",
|
|
33
|
+
"typescript": "^5.9.3",
|
|
34
|
+
"vitest": "^4.1.0"
|
|
35
|
+
}
|
|
36
|
+
}
|