Initial values and ending a stream
What a stream holds before any text, what to do when Solid cannot work that out, and how to tell a reply that stopped early from a whole one.
pnpm add @niscorp/solid zodThe shape
The schema is the shape you asked the model for. Solid needs it before any text arrives.
import { z } from 'zod';
import { createStream } from '@niscorp/solid';
const Suggestion = z.object({
show: z.string(),
seats: z.array(z.string()),
price_cents: z.number(),
why: z.string(),
});Where it starts
With no initial, Solid builds the first object from the schema: a default where there is one, an empty string, 0, an empty list, and for an enum its first value.
console.log(JSON.stringify(createStream({ schema: Suggestion }).current()));A schema it cannot start from
The first object has to pass the schema. Where an empty value would not, createStream throws and says so, and you give it an initial that does.
const Seats = z.object({ count: z.number().min(1) });
try {
createStream({ schema: Seats });
} catch (error) {
console.log(error instanceof Error ? error.message.split('. ')[0] : error);
}
console.log(JSON.stringify(createStream({ schema: Seats, initial: { count: 1 } }).current()));A reply that stops early
A model can stop in the middle. Solid does not know that it has: final() waits for the closing brace.
close() says no more is coming, and final() resolves with what there is, defaults and half values included. That object can pass your schema. So note whether onFinal was called before you closed: if it was not, the reply was not whole.
const stream = createStream({ schema: Suggestion });
let whole = false;
stream.onFinal(() => (whole = true));
stream.write('{"show":"The Tempest","seats":["C4"');
console.log('whole:', whole);
stream.close();
console.log(JSON.stringify(await stream.final()));A stream you no longer want
destroy() drops every listener and rejects a final() somebody is waiting on. It is what to call when the reader has moved on.
const dropped = createStream({ schema: Suggestion });
const waiting = dropped.final().catch((error: Error) => error.message);
dropped.destroy();
console.log(await waiting);Run it.
The first object, the reason a schema could not be started from and the object it was given, whole: false with what the stream held when it was closed, and what destroy() rejects with.
npx tsx ends.mts{"show":"","seats":[],"price_cents":0,"why":""}
[solid] cannot derive valid base from schema defaults
{"count":1}
whole: false
{"show":"The Tempest","seats":["C4"],"price_cents":0,"why":""}
[solid] stream destroyed