blade
Version:
React at the edge.
162 lines (158 loc) • 4.62 kB
JavaScript
import { n as resolveCallback, t as HtmlEscapedCallbackPhase } from "./html-BHm7adlz.js";
//#region ../../node_modules/hono/dist/utils/stream.js
var StreamingApi = class {
writer;
encoder;
writable;
abortSubscribers = [];
responseReadable;
aborted = false;
closed = false;
constructor(writable, _readable) {
this.writable = writable;
this.writer = writable.getWriter();
this.encoder = new TextEncoder();
const reader = _readable.getReader();
this.abortSubscribers.push(async () => {
await reader.cancel();
});
this.responseReadable = new ReadableStream({
async pull(controller) {
const { done, value } = await reader.read();
done ? controller.close() : controller.enqueue(value);
},
cancel: () => {
this.abort();
}
});
}
async write(input) {
try {
if (typeof input === "string") input = this.encoder.encode(input);
await this.writer.write(input);
} catch {}
return this;
}
async writeln(input) {
await this.write(input + "\n");
return this;
}
sleep(ms) {
return new Promise((res) => setTimeout(res, ms));
}
async close() {
try {
await this.writer.close();
} catch {}
this.closed = true;
}
async pipe(body) {
this.writer.releaseLock();
await body.pipeTo(this.writable, { preventClose: true });
this.writer = this.writable.getWriter();
}
onAbort(listener) {
this.abortSubscribers.push(listener);
}
abort() {
if (!this.aborted) {
this.aborted = true;
this.abortSubscribers.forEach((subscriber) => subscriber());
}
}
};
//#endregion
//#region ../../node_modules/hono/dist/helper/streaming/sse.js
var SSEStreamingApi = class extends StreamingApi {
constructor(writable, readable) {
super(writable, readable);
}
async writeSSE(message) {
const dataLines = (await resolveCallback(message.data, HtmlEscapedCallbackPhase.Stringify, false, {})).split("\n").map((line) => {
return `data: ${line}`;
}).join("\n");
const sseData = [
message.event && `event: ${message.event}`,
dataLines,
message.id && `id: ${message.id}`,
message.retry && `retry: ${message.retry}`
].filter(Boolean).join("\n") + "\n\n";
await this.write(sseData);
}
};
//#endregion
//#region private/server/utils/index.ts
/**
* Generates a short numeric hash from a string input.
*
* @param input - The input to use for generating the hash.
*
* @returns A numeric hash.
*/
const generateHashSync = (input) => {
let hash = 0;
for (let i = 0; i < input.length; i++) hash = Math.imul(31, hash) + input.charCodeAt(i) | 0;
return hash >>> 0;
};
var ResponseStream = class extends SSEStreamingApi {
/** The first request object provided by the client. */
request;
/** The first response object returned to the client. */
response;
/**
* The time at which the last update started processing. If the value is `null`, no
* update started processing yet.
*/
lastUpdate = null;
/**
* The results of the read queries that were executed last. Allows for caching read
* query results between flushes, to not run all read queries every time.
*/
lastResults = [];
/** Allows for tracking whether the response is ready to be returned. */
headersReady;
setHeadersReady;
headersMarkedReady = false;
constructor(request) {
const { readable, writable } = new TransformStream();
super(writable, readable);
this.request = request;
this.response = new Response(this.responseReadable, { headers: {
"Transfer-Encoding": "chunked",
"Content-Type": "text/plain",
"Cache-Control": "no-cache, no-transform",
"X-Accel-Buffering": "no"
} });
this.headersReady = new Promise((resolve) => {
this.setHeadersReady = () => {
if (this.headersMarkedReady) return;
this.headersMarkedReady = true;
resolve();
};
});
}
/**
* Consumes a `Response`, which is converted into a chunk on the current stream.
*
* @param type - The type of chunk that should be sent.
* @param response - The response that should be consumed.
*
* @returns A `Promise` that will resolve once the chunk has been flushed.
*/
writeChunk(type, response) {
response.headers.forEach((value, key) => {
if (key === "set-cookie") this.response.headers.append(key, value);
else this.response.headers.set(key, value);
});
this.setHeadersReady();
const newURL = response.headers.get("Content-Location");
if (newURL) this.request = new Request(new URL(newURL, this.request.url), this.request);
return this.writeSSE({
id: `${crypto.randomUUID()}-${import.meta.env.__BLADE_BUNDLE_ID}`,
event: type,
data: response.text()
});
}
};
//#endregion
export { generateHashSync as n, ResponseStream as t };