@rocketnew/llm-sdk
Version:
Universal LLM SDK for JavaScript/TypeScript - OpenAI, Anthropic, Gemini, Perplexity and more
188 lines (184 loc) • 6.02 kB
JavaScript
import {
__esm,
__privateAdd,
__privateGet,
__privateSet
} from "./chunk-DDRQKMV4.mjs";
// src/types/responses/binary.ts
var _cached, BinaryResponseContent;
var init_binary = __esm({
"src/types/responses/binary.ts"() {
"use strict";
BinaryResponseContent = class {
constructor(response) {
/**
* Free-form metadata bag used to attach attribution fields (model,
* custom_llm_provider, etc.) that downstream tooling may read. Mutable
* by design — callers are expected to append to it.
*/
this.hiddenParams = {};
/**
* Cached body. Populated on first `content()` call so multiple call
* sites can consume `content()` / `text()` / `json()` after streaming
* has already started.
*/
__privateAdd(this, _cached, null);
this.response = response;
}
get status() {
return this.response.status;
}
get headers() {
return this.response.headers;
}
/**
* Charset parsed from the `content-type` header (e.g. `utf-8` for
* `text/plain; charset=utf-8`). Null if no charset is present.
*/
get encoding() {
const ct = this.response.headers.get("content-type") ?? "";
const match = /charset=([^;]+)/i.exec(ct);
return match ? match[1].trim() : null;
}
get charsetEncoding() {
return this.encoding;
}
/**
* Read the full body as a `Uint8Array`. Caches the result so repeat
* calls do not attempt to drain an already-consumed body stream.
*/
async content() {
if (__privateGet(this, _cached)) return __privateGet(this, _cached);
const buf = new Uint8Array(await this.response.arrayBuffer());
__privateSet(this, _cached, buf);
return buf;
}
/**
* Alias of `content()` for API symmetry with common binary-response
* wrappers in other HTTP clients.
*/
read() {
return this.content();
}
/**
* Decode the full body using the response's charset (defaults to
* `utf-8`).
*/
async text() {
const bytes = await this.content();
return new TextDecoder(this.encoding ?? "utf-8").decode(bytes);
}
async json() {
return JSON.parse(await this.text());
}
/**
* Async byte iterator. If `content()` has already been called, yields
* slices of the cached buffer sized by `chunkSize`. Otherwise streams
* directly from the live response body — which is drained as a side
* effect, so subsequent `content()` calls on the same instance will
* return an empty cache.
*/
async *iterBytes(chunkSize) {
if (__privateGet(this, _cached)) {
const size = __privateGet(this, _cached).length;
const step = chunkSize && chunkSize > 0 ? chunkSize : size;
for (let i = 0; i < size; i += step) {
yield __privateGet(this, _cached).subarray(i, Math.min(i + step, size));
}
return;
}
const body = this.response.body;
if (!body) return;
const reader = body.getReader();
try {
for (; ; ) {
const { value, done } = await reader.read();
if (done) break;
if (value) yield value;
}
} finally {
reader.releaseLock();
}
}
/**
* Iterate decoded text chunks. Uses a streaming TextDecoder so
* multi-byte sequences that straddle chunk boundaries are handled
* correctly.
*/
async *iterText(chunkSize) {
const decoder = new TextDecoder(this.encoding ?? "utf-8", { fatal: false });
for await (const chunk of this.iterBytes(chunkSize)) {
yield decoder.decode(chunk, { stream: true });
}
const final = decoder.decode();
if (final) yield final;
}
/**
* Iterate decoded lines. Splits on `\n` and strips trailing `\r` for
* CR-LF inputs. The last partial line (no trailing newline) is yielded
* on stream end.
*/
async *iterLines() {
let buffer = "";
for await (const chunk of this.iterText()) {
buffer += chunk;
let idx;
while ((idx = buffer.indexOf("\n")) !== -1) {
let line = buffer.slice(0, idx);
if (line.endsWith("\r")) line = line.slice(0, -1);
yield line;
buffer = buffer.slice(idx + 1);
}
}
if (buffer.length > 0) {
if (buffer.endsWith("\r")) buffer = buffer.slice(0, -1);
yield buffer;
}
}
/**
* Buffer the entire body and write it to disk in one shot.
*/
async writeToFile(path) {
const { writeFile } = await import("fs/promises");
await writeFile(path, await this.content());
}
/**
* Stream body chunks to disk. Preferred over `writeToFile()` for large
* outputs where materializing the full buffer in memory is undesirable.
*/
async streamToFile(path, opts) {
const { open } = await import("fs/promises");
const handle = await open(path, "w");
try {
for await (const chunk of this.iterBytes(opts?.chunkSize)) {
await handle.write(chunk);
}
} finally {
await handle.close();
}
}
/**
* Cancel the underlying stream. Safe to call multiple times; swallows
* any error thrown by the already-consumed or already-aborted stream.
*/
async close() {
try {
await this.response.body?.cancel();
} catch {
}
}
};
_cached = new WeakMap();
}
});
// src/types/responses/index.ts
var init_responses = __esm({
"src/types/responses/index.ts"() {
"use strict";
init_binary();
}
});
export {
BinaryResponseContent,
init_responses
};