openclaw
Version:
Multi-channel AI gateway with extensible messaging integrations
47 lines (46 loc) • 1.72 kB
JavaScript
//#region packages/media-core/src/read-byte-stream-with-limit.ts
function normalizeByteChunk(chunk) {
if (Buffer.isBuffer(chunk)) return chunk;
if (typeof chunk === "string") return Buffer.from(chunk);
if (chunk instanceof ArrayBuffer) return Buffer.from(chunk);
if (ArrayBuffer.isView(chunk)) return Buffer.from(chunk.buffer, chunk.byteOffset, chunk.byteLength);
throw new TypeError(`Unsupported byte stream chunk: ${typeof chunk}`);
}
function destroyReadableOnOverflow(stream, err) {
const readable = stream;
if (typeof readable.destroy === "function") {
try {
readable.destroy();
} catch {}
return;
}
if (typeof readable.cancel === "function") try {
Promise.resolve(readable.cancel(err)).catch(() => void 0);
} catch {}
}
/** Reads and concatenates an async byte stream, throwing once the byte cap is exceeded. */
async function readByteStreamWithLimit(stream, opts) {
const { maxBytes } = opts;
if (!Number.isFinite(maxBytes) || maxBytes < 0) throw new RangeError(`maxBytes must be a non-negative finite number: ${maxBytes}`);
const onOverflow = opts.onOverflow ?? ((params) => /* @__PURE__ */ new Error(`Content too large: ${params.size} bytes (limit: ${params.maxBytes} bytes)`));
const chunks = [];
let total = 0;
for await (const chunk of stream) {
const buffer = normalizeByteChunk(chunk);
if (buffer.byteLength === 0) continue;
const nextTotal = total + buffer.byteLength;
if (nextTotal > maxBytes) {
const err = onOverflow({
size: nextTotal,
maxBytes
});
destroyReadableOnOverflow(stream, err);
throw err;
}
chunks.push(buffer);
total = nextTotal;
}
return Buffer.concat(chunks, total);
}
//#endregion
export { readByteStreamWithLimit as t };