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
package/README.md
ADDED
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
# stream-validate
|
|
2
|
+
|
|
3
|
+
Progressive Zod validation for streaming LLM responses. Parse and validate JSON incrementally as it arrives chunk-by-chunk, emitting typed partial results as each field completes.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install stream-validate zod
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Quick Start — `streamValidate` async generator
|
|
12
|
+
|
|
13
|
+
```typescript
|
|
14
|
+
import { z } from 'zod'
|
|
15
|
+
import { streamValidate } from 'stream-validate'
|
|
16
|
+
|
|
17
|
+
const schema = z.object({
|
|
18
|
+
name: z.string(),
|
|
19
|
+
age: z.number(),
|
|
20
|
+
address: z.object({ city: z.string() }),
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
// Any AsyncIterable<string> — e.g. an LLM streaming response
|
|
24
|
+
async function* llmStream(): AsyncIterable<string> {
|
|
25
|
+
yield '{"name":"Al'
|
|
26
|
+
yield 'ice","age":30,"address":{"city":"NYC"}}'
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
for await (const partial of streamValidate(llmStream(), schema)) {
|
|
30
|
+
console.log(partial.data) // DeepPartial<T> — fields filled in as they arrive
|
|
31
|
+
console.log(partial.meta) // { "name": "complete", "age": "pending", ... }
|
|
32
|
+
console.log(partial.isComplete) // true when all required fields are validated
|
|
33
|
+
console.log(partial.seq) // monotonically increasing sequence number
|
|
34
|
+
console.log(partial.elapsedMs) // ms since validation started
|
|
35
|
+
}
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Push-based API — `createStreamValidator`
|
|
39
|
+
|
|
40
|
+
```typescript
|
|
41
|
+
import { z } from 'zod'
|
|
42
|
+
import { createStreamValidator } from 'stream-validate'
|
|
43
|
+
|
|
44
|
+
const schema = z.object({ name: z.string(), score: z.number() })
|
|
45
|
+
|
|
46
|
+
const validator = createStreamValidator(schema, {
|
|
47
|
+
validationErrorStrategy: 'skip', // 'skip' | 'include-invalid' | 'error'
|
|
48
|
+
timeoutMs: 5000,
|
|
49
|
+
onValidationError: (err) => console.error('Invalid field', err.path, err.message),
|
|
50
|
+
onParseError: (err) => console.error('Parse error', err.message),
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
// Subscribe to events
|
|
54
|
+
const unsub = validator.on('partial', (partial) => {
|
|
55
|
+
console.log('Got partial:', partial.data)
|
|
56
|
+
})
|
|
57
|
+
|
|
58
|
+
validator.on('complete', (event) => {
|
|
59
|
+
console.log('Done:', event.isComplete, event.truncated, event.totalMs + 'ms')
|
|
60
|
+
console.log('Failed paths:', event.failedPaths)
|
|
61
|
+
})
|
|
62
|
+
|
|
63
|
+
// Push chunks as they arrive
|
|
64
|
+
validator.write('{"name":"Bob"')
|
|
65
|
+
validator.write(',"score":95}')
|
|
66
|
+
validator.end() // flush and emit final complete event
|
|
67
|
+
|
|
68
|
+
// Inspect current state at any time
|
|
69
|
+
console.log(validator.current?.data)
|
|
70
|
+
|
|
71
|
+
// Unsubscribe
|
|
72
|
+
unsub()
|
|
73
|
+
|
|
74
|
+
// Abort mid-stream (emits complete with truncated=true)
|
|
75
|
+
validator.abort()
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### Async iterator on validator
|
|
79
|
+
|
|
80
|
+
```typescript
|
|
81
|
+
const validator = createStreamValidator(schema)
|
|
82
|
+
|
|
83
|
+
;(async () => {
|
|
84
|
+
for await (const partial of validator) {
|
|
85
|
+
console.log(partial.data)
|
|
86
|
+
}
|
|
87
|
+
})()
|
|
88
|
+
|
|
89
|
+
validator.write('{"name":"Charlie","score":88}')
|
|
90
|
+
validator.end()
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
## API
|
|
94
|
+
|
|
95
|
+
### `streamValidate<T>(stream, schema, options?)`
|
|
96
|
+
|
|
97
|
+
| Parameter | Type | Description |
|
|
98
|
+
|---|---|---|
|
|
99
|
+
| `stream` | `AsyncIterable<string>` | Source of JSON chunks |
|
|
100
|
+
| `schema` | `z.ZodSchema<T>` | Zod schema to validate against |
|
|
101
|
+
| `options` | `StreamValidatorOptions` | Optional configuration |
|
|
102
|
+
|
|
103
|
+
Returns `AsyncIterable<ValidatedPartial<T>>`.
|
|
104
|
+
|
|
105
|
+
### `createStreamValidator<T>(schema, options?)`
|
|
106
|
+
|
|
107
|
+
Returns a `StreamValidator<T>` with:
|
|
108
|
+
|
|
109
|
+
- `write(chunk: string)` — push a new chunk
|
|
110
|
+
- `end()` — signal end of stream
|
|
111
|
+
- `abort(error?)` — cancel with truncated=true
|
|
112
|
+
- `on('partial', fn)` — subscribe to partial updates; returns unsubscribe function
|
|
113
|
+
- `on('complete', fn)` — subscribe to final completion event
|
|
114
|
+
- `on('parse-error', fn)` — subscribe to JSON parse errors
|
|
115
|
+
- `on('validation-error', fn)` — subscribe to Zod validation errors
|
|
116
|
+
- `current` — getter for the latest `ValidatedPartial<T>` or `null`
|
|
117
|
+
- `[Symbol.asyncIterator]()` — async iterate over partials
|
|
118
|
+
|
|
119
|
+
### `StreamValidatorOptions`
|
|
120
|
+
|
|
121
|
+
```typescript
|
|
122
|
+
interface StreamValidatorOptions {
|
|
123
|
+
onParseError?: (err: StreamParseError) => void
|
|
124
|
+
onValidationError?: (err: StreamValidationError) => void
|
|
125
|
+
validationErrorStrategy?: 'skip' | 'include-invalid' | 'error'
|
|
126
|
+
timeoutMs?: number
|
|
127
|
+
signal?: AbortSignal
|
|
128
|
+
}
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
### `ValidatedPartial<T>`
|
|
132
|
+
|
|
133
|
+
```typescript
|
|
134
|
+
interface ValidatedPartial<T> {
|
|
135
|
+
data: DeepPartial<T> // partial object filled in so far
|
|
136
|
+
meta: FieldMeta // per-field status: 'complete' | 'active' | 'pending' | 'error'
|
|
137
|
+
isComplete: boolean // true when all required fields validated
|
|
138
|
+
seq: number // monotonically increasing
|
|
139
|
+
elapsedMs: number // ms since validator created
|
|
140
|
+
}
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
## License
|
|
144
|
+
|
|
145
|
+
MIT
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parser.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/parser.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const vitest_1 = require("vitest");
|
|
4
|
+
const parser_1 = require("../parser");
|
|
5
|
+
(0, vitest_1.describe)('IncrementalJsonParser', () => {
|
|
6
|
+
(0, vitest_1.it)('parses a simple object fed in 3 chunks', () => {
|
|
7
|
+
const parser = new parser_1.IncrementalJsonParser();
|
|
8
|
+
const fields = [
|
|
9
|
+
...parser.feed('{"na'),
|
|
10
|
+
...parser.feed('me":"Al'),
|
|
11
|
+
...parser.feed('ice"}'),
|
|
12
|
+
];
|
|
13
|
+
const nameField = fields.find(f => f.path === 'name');
|
|
14
|
+
(0, vitest_1.expect)(nameField).toBeDefined();
|
|
15
|
+
(0, vitest_1.expect)(nameField?.value).toBe('Alice');
|
|
16
|
+
});
|
|
17
|
+
(0, vitest_1.it)('parses two top-level fields from a single feed', () => {
|
|
18
|
+
const parser = new parser_1.IncrementalJsonParser();
|
|
19
|
+
const fields = parser.feed('{"a":1,"b":2}');
|
|
20
|
+
(0, vitest_1.expect)(fields.find(f => f.path === 'a')?.value).toBe(1);
|
|
21
|
+
(0, vitest_1.expect)(fields.find(f => f.path === 'b')?.value).toBe(2);
|
|
22
|
+
});
|
|
23
|
+
(0, vitest_1.it)('parses nested object and emits path for leaf field', () => {
|
|
24
|
+
const parser = new parser_1.IncrementalJsonParser();
|
|
25
|
+
const fields = parser.feed('{"addr":{"city":"NYC"}}');
|
|
26
|
+
(0, vitest_1.expect)(fields.find(f => f.path === 'addr.city')?.value).toBe('NYC');
|
|
27
|
+
});
|
|
28
|
+
(0, vitest_1.it)('parses boolean and null values', () => {
|
|
29
|
+
const parser = new parser_1.IncrementalJsonParser();
|
|
30
|
+
const fields = parser.feed('{"flag":true,"empty":null}');
|
|
31
|
+
(0, vitest_1.expect)(fields.find(f => f.path === 'flag')?.value).toBe(true);
|
|
32
|
+
(0, vitest_1.expect)(fields.find(f => f.path === 'empty')?.value).toBeNull();
|
|
33
|
+
});
|
|
34
|
+
(0, vitest_1.it)('parses numeric values', () => {
|
|
35
|
+
const parser = new parser_1.IncrementalJsonParser();
|
|
36
|
+
const fields = parser.feed('{"count":42,"ratio":3.14}');
|
|
37
|
+
(0, vitest_1.expect)(fields.find(f => f.path === 'count')?.value).toBe(42);
|
|
38
|
+
(0, vitest_1.expect)(fields.find(f => f.path === 'ratio')?.value).toBeCloseTo(3.14);
|
|
39
|
+
});
|
|
40
|
+
(0, vitest_1.it)('handles chunk boundary mid-key', () => {
|
|
41
|
+
const parser = new parser_1.IncrementalJsonParser();
|
|
42
|
+
const f1 = parser.feed('{"foo');
|
|
43
|
+
(0, vitest_1.expect)(f1).toHaveLength(0); // key incomplete
|
|
44
|
+
const f2 = parser.feed('":"bar"}');
|
|
45
|
+
const field = f2.find(f => f.path === 'foo');
|
|
46
|
+
(0, vitest_1.expect)(field?.value).toBe('bar');
|
|
47
|
+
});
|
|
48
|
+
(0, vitest_1.it)('handles chunk boundary mid-value', () => {
|
|
49
|
+
const parser = new parser_1.IncrementalJsonParser();
|
|
50
|
+
const f1 = parser.feed('{"x":"hel');
|
|
51
|
+
(0, vitest_1.expect)(f1).toHaveLength(0);
|
|
52
|
+
const f2 = parser.feed('lo"}');
|
|
53
|
+
(0, vitest_1.expect)(f2.find(f => f.path === 'x')?.value).toBe('hello');
|
|
54
|
+
});
|
|
55
|
+
(0, vitest_1.it)('end() flushes remaining content', () => {
|
|
56
|
+
const parser = new parser_1.IncrementalJsonParser();
|
|
57
|
+
parser.feed('{"z":99');
|
|
58
|
+
const fields = parser.end();
|
|
59
|
+
// After end with a complete-enough buffer
|
|
60
|
+
// The end() may or may not extract depending on completeness
|
|
61
|
+
// At minimum it should not throw
|
|
62
|
+
(0, vitest_1.expect)(Array.isArray(fields)).toBe(true);
|
|
63
|
+
});
|
|
64
|
+
(0, vitest_1.it)('emits position > 0 for fields', () => {
|
|
65
|
+
const parser = new parser_1.IncrementalJsonParser();
|
|
66
|
+
const fields = parser.feed('{"name":"Bob"}');
|
|
67
|
+
const field = fields.find(f => f.path === 'name');
|
|
68
|
+
(0, vitest_1.expect)(field).toBeDefined();
|
|
69
|
+
(0, vitest_1.expect)(field.position).toBeGreaterThan(0);
|
|
70
|
+
});
|
|
71
|
+
(0, vitest_1.it)('parses string with escaped quotes', () => {
|
|
72
|
+
const parser = new parser_1.IncrementalJsonParser();
|
|
73
|
+
const fields = parser.feed('{"msg":"say \\"hi\\""}');
|
|
74
|
+
(0, vitest_1.expect)(fields.find(f => f.path === 'msg')?.value).toBe('say "hi"');
|
|
75
|
+
});
|
|
76
|
+
});
|
|
77
|
+
//# sourceMappingURL=parser.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parser.test.js","sourceRoot":"","sources":["../../src/__tests__/parser.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stream-validate.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/stream-validate.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const vitest_1 = require("vitest");
|
|
4
|
+
const zod_1 = require("zod");
|
|
5
|
+
const stream_validator_1 = require("../stream-validator");
|
|
6
|
+
const stream_validate_1 = require("../stream-validate");
|
|
7
|
+
// Helper: split string into individual characters as async iterable
|
|
8
|
+
async function* charStream(s) {
|
|
9
|
+
for (const ch of s) {
|
|
10
|
+
yield ch;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
// Helper: split string into chunks of given size
|
|
14
|
+
async function* chunkStream(s, size) {
|
|
15
|
+
for (let i = 0; i < s.length; i += size) {
|
|
16
|
+
yield s.slice(i, i + size);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
(0, vitest_1.describe)('createStreamValidator', () => {
|
|
20
|
+
(0, vitest_1.it)('emits partial events as fields complete', () => {
|
|
21
|
+
const schema = zod_1.z.object({ name: zod_1.z.string() });
|
|
22
|
+
const validator = (0, stream_validator_1.createStreamValidator)(schema);
|
|
23
|
+
const partials = [];
|
|
24
|
+
validator.on('partial', p => partials.push(p));
|
|
25
|
+
validator.write('{"name":"Alice"}');
|
|
26
|
+
validator.end();
|
|
27
|
+
const namePartial = partials.find(p => p?.data && p.data.name === 'Alice');
|
|
28
|
+
(0, vitest_1.expect)(namePartial).toBeDefined();
|
|
29
|
+
});
|
|
30
|
+
(0, vitest_1.it)('emits complete event after end()', () => {
|
|
31
|
+
const schema = zod_1.z.object({ x: zod_1.z.number() });
|
|
32
|
+
const validator = (0, stream_validator_1.createStreamValidator)(schema);
|
|
33
|
+
const completeEvents = [];
|
|
34
|
+
validator.on('complete', e => completeEvents.push(e));
|
|
35
|
+
validator.write('{"x":42}');
|
|
36
|
+
validator.end();
|
|
37
|
+
(0, vitest_1.expect)(completeEvents).toHaveLength(1);
|
|
38
|
+
const evt = completeEvents[0];
|
|
39
|
+
(0, vitest_1.expect)(evt.truncated).toBe(false);
|
|
40
|
+
});
|
|
41
|
+
(0, vitest_1.it)('reports isComplete=true after all required fields are received', () => {
|
|
42
|
+
const schema = zod_1.z.object({ name: zod_1.z.string(), age: zod_1.z.number() });
|
|
43
|
+
const validator = (0, stream_validator_1.createStreamValidator)(schema);
|
|
44
|
+
const partials = [];
|
|
45
|
+
validator.on('partial', p => partials.push(p));
|
|
46
|
+
validator.write('{"name":"Bob","age":30}');
|
|
47
|
+
validator.end();
|
|
48
|
+
const last = partials[partials.length - 1];
|
|
49
|
+
(0, vitest_1.expect)(last?.isComplete).toBe(true);
|
|
50
|
+
});
|
|
51
|
+
(0, vitest_1.it)('current getter returns latest partial', () => {
|
|
52
|
+
const schema = zod_1.z.object({ val: zod_1.z.string() });
|
|
53
|
+
const validator = (0, stream_validator_1.createStreamValidator)(schema);
|
|
54
|
+
(0, vitest_1.expect)(validator.current).toBeNull();
|
|
55
|
+
validator.write('{"val":"test"}');
|
|
56
|
+
(0, vitest_1.expect)(validator.current).not.toBeNull();
|
|
57
|
+
(0, vitest_1.expect)(validator.current.data.val).toBe('test');
|
|
58
|
+
});
|
|
59
|
+
(0, vitest_1.it)('abort() emits complete with truncated=true', () => {
|
|
60
|
+
const schema = zod_1.z.object({ name: zod_1.z.string() });
|
|
61
|
+
const validator = (0, stream_validator_1.createStreamValidator)(schema);
|
|
62
|
+
const completeEvents = [];
|
|
63
|
+
validator.on('complete', e => completeEvents.push(e));
|
|
64
|
+
validator.write('{"na');
|
|
65
|
+
validator.abort();
|
|
66
|
+
(0, vitest_1.expect)(completeEvents[0]?.truncated).toBe(true);
|
|
67
|
+
});
|
|
68
|
+
(0, vitest_1.it)('emits validation-error for wrong type with include-invalid strategy', () => {
|
|
69
|
+
const schema = zod_1.z.object({ count: zod_1.z.number() });
|
|
70
|
+
const validationErrors = [];
|
|
71
|
+
const validator = (0, stream_validator_1.createStreamValidator)(schema, {
|
|
72
|
+
validationErrorStrategy: 'include-invalid',
|
|
73
|
+
onValidationError: e => validationErrors.push(e),
|
|
74
|
+
});
|
|
75
|
+
validator.write('{"count":"not-a-number"}');
|
|
76
|
+
validator.end();
|
|
77
|
+
(0, vitest_1.expect)(validationErrors.length).toBeGreaterThan(0);
|
|
78
|
+
});
|
|
79
|
+
(0, vitest_1.it)('invokes onParseError callback for malformed JSON context', () => {
|
|
80
|
+
// The parser is resilient but we can test the callback is wired
|
|
81
|
+
const schema = zod_1.z.object({ x: zod_1.z.number() });
|
|
82
|
+
const onParseError = vitest_1.vi.fn();
|
|
83
|
+
const validator = (0, stream_validator_1.createStreamValidator)(schema, { onParseError });
|
|
84
|
+
// Feed valid JSON — no parse error
|
|
85
|
+
validator.write('{"x":1}');
|
|
86
|
+
validator.end();
|
|
87
|
+
(0, vitest_1.expect)(onParseError).not.toHaveBeenCalled();
|
|
88
|
+
});
|
|
89
|
+
(0, vitest_1.it)('async iterator yields partials', async () => {
|
|
90
|
+
const schema = zod_1.z.object({ a: zod_1.z.string(), b: zod_1.z.number() });
|
|
91
|
+
const validator = (0, stream_validator_1.createStreamValidator)(schema);
|
|
92
|
+
const results = [];
|
|
93
|
+
const iterPromise = (async () => {
|
|
94
|
+
for await (const partial of validator) {
|
|
95
|
+
results.push(partial);
|
|
96
|
+
}
|
|
97
|
+
})();
|
|
98
|
+
validator.write('{"a":"hello","b":99}');
|
|
99
|
+
validator.end();
|
|
100
|
+
await iterPromise;
|
|
101
|
+
(0, vitest_1.expect)(results.length).toBeGreaterThan(0);
|
|
102
|
+
});
|
|
103
|
+
(0, vitest_1.it)('on() returns unsubscribe function', () => {
|
|
104
|
+
const schema = zod_1.z.object({ x: zod_1.z.string() });
|
|
105
|
+
const validator = (0, stream_validator_1.createStreamValidator)(schema);
|
|
106
|
+
const calls = [];
|
|
107
|
+
const unsub = validator.on('partial', p => calls.push(p));
|
|
108
|
+
validator.write('{"x":');
|
|
109
|
+
unsub();
|
|
110
|
+
validator.write('"hello"}');
|
|
111
|
+
validator.end();
|
|
112
|
+
// After unsub, no more events
|
|
113
|
+
(0, vitest_1.expect)(calls).toHaveLength(0);
|
|
114
|
+
});
|
|
115
|
+
(0, vitest_1.it)('timeoutMs causes truncated complete event', async () => {
|
|
116
|
+
const schema = zod_1.z.object({ slow: zod_1.z.string() });
|
|
117
|
+
const completeEvents = [];
|
|
118
|
+
const validator = (0, stream_validator_1.createStreamValidator)(schema, { timeoutMs: 10 });
|
|
119
|
+
validator.on('complete', e => completeEvents.push(e));
|
|
120
|
+
// Don't write anything — let timeout fire
|
|
121
|
+
await new Promise(r => setTimeout(r, 50));
|
|
122
|
+
(0, vitest_1.expect)(completeEvents[0]?.truncated).toBe(true);
|
|
123
|
+
});
|
|
124
|
+
});
|
|
125
|
+
(0, vitest_1.describe)('streamValidate', () => {
|
|
126
|
+
(0, vitest_1.it)('yields partials for single-field schema char by char', async () => {
|
|
127
|
+
const schema = zod_1.z.object({ name: zod_1.z.string() });
|
|
128
|
+
const input = '{"name":"Alice"}';
|
|
129
|
+
const results = [];
|
|
130
|
+
for await (const partial of (0, stream_validate_1.streamValidate)(charStream(input), schema)) {
|
|
131
|
+
results.push(partial);
|
|
132
|
+
}
|
|
133
|
+
const withName = results.find(r => r.data.name === 'Alice');
|
|
134
|
+
(0, vitest_1.expect)(withName).toBeDefined();
|
|
135
|
+
});
|
|
136
|
+
(0, vitest_1.it)('handles multi-field schema with chunked input', async () => {
|
|
137
|
+
const schema = zod_1.z.object({ first: zod_1.z.string(), last: zod_1.z.string() });
|
|
138
|
+
const input = '{"first":"John","last":"Doe"}';
|
|
139
|
+
const results = [];
|
|
140
|
+
for await (const partial of (0, stream_validate_1.streamValidate)(chunkStream(input, 5), schema)) {
|
|
141
|
+
results.push(partial);
|
|
142
|
+
}
|
|
143
|
+
const complete = results.find(r => r.isComplete);
|
|
144
|
+
(0, vitest_1.expect)(complete).toBeDefined();
|
|
145
|
+
});
|
|
146
|
+
(0, vitest_1.it)('yields seq numbers that increment', async () => {
|
|
147
|
+
const schema = zod_1.z.object({ a: zod_1.z.string(), b: zod_1.z.string() });
|
|
148
|
+
const input = '{"a":"x","b":"y"}';
|
|
149
|
+
const seqs = [];
|
|
150
|
+
for await (const partial of (0, stream_validate_1.streamValidate)(charStream(input), schema)) {
|
|
151
|
+
seqs.push(partial.seq);
|
|
152
|
+
}
|
|
153
|
+
// seqs should be non-empty and monotonically increasing
|
|
154
|
+
(0, vitest_1.expect)(seqs.length).toBeGreaterThan(0);
|
|
155
|
+
for (let i = 1; i < seqs.length; i++) {
|
|
156
|
+
(0, vitest_1.expect)(seqs[i]).toBeGreaterThanOrEqual(seqs[i - 1]);
|
|
157
|
+
}
|
|
158
|
+
});
|
|
159
|
+
(0, vitest_1.it)('elapsedMs is a non-negative number', async () => {
|
|
160
|
+
const schema = zod_1.z.object({ v: zod_1.z.number() });
|
|
161
|
+
const input = '{"v":7}';
|
|
162
|
+
for await (const partial of (0, stream_validate_1.streamValidate)(charStream(input), schema)) {
|
|
163
|
+
(0, vitest_1.expect)(partial.elapsedMs).toBeGreaterThanOrEqual(0);
|
|
164
|
+
}
|
|
165
|
+
});
|
|
166
|
+
(0, vitest_1.it)('meta marks received fields as complete', async () => {
|
|
167
|
+
const schema = zod_1.z.object({ city: zod_1.z.string() });
|
|
168
|
+
const input = '{"city":"Paris"}';
|
|
169
|
+
let lastPartial = null;
|
|
170
|
+
for await (const partial of (0, stream_validate_1.streamValidate)(charStream(input), schema)) {
|
|
171
|
+
lastPartial = partial;
|
|
172
|
+
}
|
|
173
|
+
(0, vitest_1.expect)(lastPartial?.meta?.city).toBe('complete');
|
|
174
|
+
});
|
|
175
|
+
(0, vitest_1.it)('works with nested schema', async () => {
|
|
176
|
+
const schema = zod_1.z.object({
|
|
177
|
+
user: zod_1.z.object({
|
|
178
|
+
name: zod_1.z.string(),
|
|
179
|
+
age: zod_1.z.number(),
|
|
180
|
+
}),
|
|
181
|
+
});
|
|
182
|
+
const input = '{"user":{"name":"Eve","age":25}}';
|
|
183
|
+
const results = [];
|
|
184
|
+
for await (const partial of (0, stream_validate_1.streamValidate)(chunkStream(input, 4), schema)) {
|
|
185
|
+
results.push(partial);
|
|
186
|
+
}
|
|
187
|
+
const withUser = results.find(r => r.data.user?.name === 'Eve');
|
|
188
|
+
(0, vitest_1.expect)(withUser).toBeDefined();
|
|
189
|
+
});
|
|
190
|
+
(0, vitest_1.it)('passes options through to validator', async () => {
|
|
191
|
+
const schema = zod_1.z.object({ n: zod_1.z.number() });
|
|
192
|
+
const validationErrors = [];
|
|
193
|
+
const input = '{"n":"not-a-number"}';
|
|
194
|
+
for await (const _partial of (0, stream_validate_1.streamValidate)(charStream(input), schema, {
|
|
195
|
+
validationErrorStrategy: 'include-invalid',
|
|
196
|
+
onValidationError: e => validationErrors.push(e),
|
|
197
|
+
})) {
|
|
198
|
+
// consume
|
|
199
|
+
}
|
|
200
|
+
(0, vitest_1.expect)(validationErrors.length).toBeGreaterThan(0);
|
|
201
|
+
});
|
|
202
|
+
});
|
|
203
|
+
//# sourceMappingURL=stream-validate.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stream-validate.test.js","sourceRoot":"","sources":["../../src/__tests__/stream-validate.test.ts"],"names":[],"mappings":"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"}
|
package/dist/events.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
type Listener<T> = (payload: T) => void;
|
|
2
|
+
export declare class TypedEmitter<Events extends Record<string, unknown>> {
|
|
3
|
+
private listeners;
|
|
4
|
+
on<K extends keyof Events & string>(event: K, fn: Listener<Events[K]>): () => void;
|
|
5
|
+
off<K extends keyof Events & string>(event: K, fn: Listener<Events[K]>): void;
|
|
6
|
+
emit<K extends keyof Events & string>(event: K, payload: Events[K]): void;
|
|
7
|
+
}
|
|
8
|
+
export {};
|
|
9
|
+
//# sourceMappingURL=events.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"events.d.ts","sourceRoot":"","sources":["../src/events.ts"],"names":[],"mappings":"AAAA,KAAK,QAAQ,CAAC,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,KAAK,IAAI,CAAA;AAEvC,qBAAa,YAAY,CAAC,MAAM,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAC9D,OAAO,CAAC,SAAS,CAAwD;IAEzE,EAAE,CAAC,CAAC,SAAS,MAAM,MAAM,GAAG,MAAM,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,GAAG,MAAM,IAAI;IAMlF,GAAG,CAAC,CAAC,SAAS,MAAM,MAAM,GAAG,MAAM,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI;IAO7E,IAAI,CAAC,CAAC,SAAS,MAAM,MAAM,GAAG,MAAM,EAAE,KAAK,EAAE,CAAC,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC,GAAG,IAAI;CAO1E"}
|
package/dist/events.js
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.TypedEmitter = void 0;
|
|
4
|
+
class TypedEmitter {
|
|
5
|
+
listeners = {};
|
|
6
|
+
on(event, fn) {
|
|
7
|
+
if (!this.listeners[event])
|
|
8
|
+
this.listeners[event] = [];
|
|
9
|
+
this.listeners[event].push(fn);
|
|
10
|
+
return () => this.off(event, fn);
|
|
11
|
+
}
|
|
12
|
+
off(event, fn) {
|
|
13
|
+
const arr = this.listeners[event];
|
|
14
|
+
if (!arr)
|
|
15
|
+
return;
|
|
16
|
+
const idx = arr.indexOf(fn);
|
|
17
|
+
if (idx !== -1)
|
|
18
|
+
arr.splice(idx, 1);
|
|
19
|
+
}
|
|
20
|
+
emit(event, payload) {
|
|
21
|
+
const arr = this.listeners[event];
|
|
22
|
+
if (!arr)
|
|
23
|
+
return;
|
|
24
|
+
for (const fn of arr.slice()) {
|
|
25
|
+
fn(payload);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
exports.TypedEmitter = TypedEmitter;
|
|
30
|
+
//# sourceMappingURL=events.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"events.js","sourceRoot":"","sources":["../src/events.ts"],"names":[],"mappings":";;;AAEA,MAAa,YAAY;IACf,SAAS,GAAsD,EAAE,CAAA;IAEzE,EAAE,CAAkC,KAAQ,EAAE,EAAuB;QACnE,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC;YAAE,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,GAAG,EAAE,CAAA;QACtD,IAAI,CAAC,SAAS,CAAC,KAAK,CAAE,CAAC,IAAI,CAAC,EAAuB,CAAC,CAAA;QACpD,OAAO,GAAG,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,EAAE,CAAC,CAAA;IAClC,CAAC;IAED,GAAG,CAAkC,KAAQ,EAAE,EAAuB;QACpE,MAAM,GAAG,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAA;QACjC,IAAI,CAAC,GAAG;YAAE,OAAM;QAChB,MAAM,GAAG,GAAG,GAAG,CAAC,OAAO,CAAC,EAAuB,CAAC,CAAA;QAChD,IAAI,GAAG,KAAK,CAAC,CAAC;YAAE,GAAG,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC,CAAC,CAAA;IACpC,CAAC;IAED,IAAI,CAAkC,KAAQ,EAAE,OAAkB;QAChE,MAAM,GAAG,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAA;QACjC,IAAI,CAAC,GAAG;YAAE,OAAM;QAChB,KAAK,MAAM,EAAE,IAAI,GAAG,CAAC,KAAK,EAAE,EAAE,CAAC;YAC7B,EAAE,CAAC,OAAO,CAAC,CAAA;QACb,CAAC;IACH,CAAC;CACF;AAvBD,oCAuBC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { createStreamValidator } from './stream-validator';
|
|
2
|
+
export { streamValidate } from './stream-validate';
|
|
3
|
+
export type { DeepPartial, FieldStatus, FieldMeta, ValidatedPartial, StreamCompletionEvent, StreamValidationError, StreamParseError, StreamValidatorOptions, StreamValidator, } from './types';
|
|
4
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAA;AAC1D,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAA;AAClD,YAAY,EACV,WAAW,EACX,WAAW,EACX,SAAS,EACT,gBAAgB,EAChB,qBAAqB,EACrB,qBAAqB,EACrB,gBAAgB,EAChB,sBAAsB,EACtB,eAAe,GAChB,MAAM,SAAS,CAAA"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.streamValidate = exports.createStreamValidator = void 0;
|
|
4
|
+
// stream-validate - Progressive Zod validation for streaming LLM responses
|
|
5
|
+
var stream_validator_1 = require("./stream-validator");
|
|
6
|
+
Object.defineProperty(exports, "createStreamValidator", { enumerable: true, get: function () { return stream_validator_1.createStreamValidator; } });
|
|
7
|
+
var stream_validate_1 = require("./stream-validate");
|
|
8
|
+
Object.defineProperty(exports, "streamValidate", { enumerable: true, get: function () { return stream_validate_1.streamValidate; } });
|
|
9
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA,2EAA2E;AAC3E,uDAA0D;AAAjD,yHAAA,qBAAqB,OAAA;AAC9B,qDAAkD;AAAzC,iHAAA,cAAc,OAAA"}
|
package/dist/parser.d.ts
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
export interface ParsedField {
|
|
2
|
+
path: string;
|
|
3
|
+
value: unknown;
|
|
4
|
+
position: number;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Incremental JSON parser that emits ParsedField events as object fields complete.
|
|
8
|
+
* Uses a buffering + scanning approach: buffer incoming chunks, scan for complete
|
|
9
|
+
* JSON values using balanced delimiter counting.
|
|
10
|
+
*/
|
|
11
|
+
export declare class IncrementalJsonParser {
|
|
12
|
+
private buf;
|
|
13
|
+
private streamPos;
|
|
14
|
+
private scanPos;
|
|
15
|
+
feed(chunk: string): ParsedField[];
|
|
16
|
+
end(): ParsedField[];
|
|
17
|
+
private insideObject;
|
|
18
|
+
private scan;
|
|
19
|
+
private skipWhitespace;
|
|
20
|
+
/**
|
|
21
|
+
* Parse a JSON string starting at pos (which must be `"`).
|
|
22
|
+
* Returns { value, endPos } where endPos is one past the closing `"`, or null if incomplete.
|
|
23
|
+
*/
|
|
24
|
+
private parseString;
|
|
25
|
+
/**
|
|
26
|
+
* Parse any JSON value starting at pos.
|
|
27
|
+
* Returns { value, endPos } or null if incomplete.
|
|
28
|
+
*/
|
|
29
|
+
private parseValue;
|
|
30
|
+
/**
|
|
31
|
+
* Parse a balanced `{...}` or `[...]` block.
|
|
32
|
+
*/
|
|
33
|
+
private parseBalanced;
|
|
34
|
+
/**
|
|
35
|
+
* Recursively extract leaf fields from a (possibly nested) object/value,
|
|
36
|
+
* emitting one ParsedField per leaf.
|
|
37
|
+
*/
|
|
38
|
+
private extractFields;
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=parser.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parser.d.ts","sourceRoot":"","sources":["../src/parser.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,EAAE,OAAO,CAAA;IACd,QAAQ,EAAE,MAAM,CAAA;CACjB;AAED;;;;GAIG;AACH,qBAAa,qBAAqB;IAChC,OAAO,CAAC,GAAG,CAAK;IAChB,OAAO,CAAC,SAAS,CAAI;IACrB,OAAO,CAAC,OAAO,CAAI;IAEnB,IAAI,CAAC,KAAK,EAAE,MAAM,GAAG,WAAW,EAAE;IAMlC,GAAG,IAAI,WAAW,EAAE;IAepB,OAAO,CAAC,YAAY,CAAQ;IAE5B,OAAO,CAAC,IAAI;IA4EZ,OAAO,CAAC,cAAc;IAKtB;;;OAGG;IACH,OAAO,CAAC,WAAW;IAqBnB;;;OAGG;IACH,OAAO,CAAC,UAAU;IA+ClB;;OAEG;IACH,OAAO,CAAC,aAAa;IAgCrB;;;OAGG;IACH,OAAO,CAAC,aAAa;CAkCtB"}
|