release: WRNexusJS 0.3.0

This commit is contained in:
2026-07-22 17:29:08 +05:30
parent 13dfa31d19
commit 07d8fb59d6
145 changed files with 9664 additions and 3881 deletions
+59
View File
@@ -177,3 +177,62 @@ function resolveSeoUrl(
return value;
}
}
export interface StreamRenderOptions extends Omit<RenderOptions, "body"> {
body: string | Promise<string> | AsyncIterable<string>;
}
function isAsyncIterable(value: unknown): value is AsyncIterable<string> {
return (
typeof value === "object" &&
value !== null &&
Symbol.asyncIterator in value &&
typeof (value as AsyncIterable<string>)[Symbol.asyncIterator] === "function"
);
}
async function* bodyChunks(body: StreamRenderOptions["body"]): AsyncIterable<string> {
if (typeof body === "string") {
yield body;
return;
}
if (isAsyncIterable(body)) {
yield* body;
return;
}
yield await body;
}
/**
* Stream a complete document while preserving the exact head/body contract of
* `renderDocument`. Async iterables can flush a shell, primary content, and
* slower fragments without buffering the entire route.
*/
export function renderDocumentStream(opts: StreamRenderOptions): ReadableStream<Uint8Array> {
const marker = "<!--__WRNEXUS_STREAM_BODY__-->";
const document = renderDocument({ ...opts, body: marker });
const [prefix, suffix] = document.split(marker);
const encoder = new TextEncoder();
return new ReadableStream<Uint8Array>({
async start(controller) {
try {
controller.enqueue(encoder.encode(prefix ?? ""));
for await (const chunk of bodyChunks(opts.body)) controller.enqueue(encoder.encode(chunk));
controller.enqueue(encoder.encode(suffix ?? ""));
controller.close();
} catch (error) {
controller.error(error);
}
},
});
}
export function streamDocumentResponse(
opts: StreamRenderOptions,
init: ResponseInit = {},
): Response {
const headers = new Headers(init.headers);
if (!headers.has("content-type")) headers.set("content-type", "text/html; charset=utf-8");
return new Response(renderDocumentStream(opts), { ...init, headers });
}