* feat(phase-4): persistent architectural and network test harness * docs(audit): add phase 4 post-implementation audit
49 lines
1.3 KiB
TypeScript
49 lines
1.3 KiB
TypeScript
import type { Context } from "jsr:@hono/hono@4";
|
|
import { streamSSE } from "jsr:@hono/hono@4/streaming";
|
|
|
|
export interface DatastarSSEEvent {
|
|
event?: string; // usually 'datastar-fragment', 'datastar-signal', etc
|
|
data: string; // The HTML fragment or JSON payload
|
|
id?: string;
|
|
retry?: number;
|
|
}
|
|
|
|
export function streamDatastar(
|
|
c: Context,
|
|
callback: (stream: {
|
|
write: (event: DatastarSSEEvent) => Promise<void>;
|
|
close: () => Promise<void>;
|
|
sleep: (ms: number) => Promise<void>;
|
|
aborted: boolean;
|
|
}) => Promise<void>,
|
|
) {
|
|
// Set anti-buffering headers for Nginx / Traefik reverse proxies
|
|
c.header("X-Accel-Buffering", "no");
|
|
c.header("Cache-Control", "no-cache, no-transform");
|
|
|
|
return streamSSE(c, async (stream) => {
|
|
// Add custom datastar helper methods
|
|
const adapter = {
|
|
write: async (event: DatastarSSEEvent) => {
|
|
await stream.writeSSE({
|
|
data: event.data,
|
|
event: event.event || "datastar-fragment",
|
|
id: event.id,
|
|
retry: event.retry,
|
|
});
|
|
},
|
|
close: async () => {
|
|
await stream.close();
|
|
},
|
|
sleep: async (ms: number) => {
|
|
await stream.sleep(ms);
|
|
},
|
|
get aborted() {
|
|
return stream.aborted;
|
|
},
|
|
};
|
|
|
|
await callback(adapter);
|
|
});
|
|
}
|