import { Logger } from "./logger.js"; import { ChatCompletionRequest, Fixture, RecordConfig, RecordProviderKey } from "./types.js"; import * as http$1 from "node:http"; //#region src/recorder.d.ts /** * Captured upstream response, exposed to the `beforeWriteResponse` hook so * callers can decide whether to relay it or mutate it (e.g. chaos injection). */ interface ProxyCapturedResponse { status: number; contentType: string; body: Buffer; } interface ProxyOptions { /** * Called after the upstream response has been captured and recorded, but * before the relay to the client. Contract when the hook returns `true`: * 1. It wrote its own response body on `res`. * 2. It journaled the outcome (proxyAndRecord will NOT journal it). * 3. proxyAndRecord skips its default relay and returns `"handled_by_hook"`. * * Returning `false` (or omitting the hook) lets proxyAndRecord relay the * upstream response normally and leaves journaling to the caller via the * `"relayed"` outcome. Rejected promises propagate and leave the response * unwritten. * * NOT invoked when the upstream response was streamed progressively to the * client (SSE, NDJSON, or binary event streams) — the bytes are already on * the wire and can't be mutated. * Callers that need to observe the bypass should pass `onHookBypassed`. */ beforeWriteResponse?: (response: ProxyCapturedResponse) => boolean | Promise; /** * Called when `beforeWriteResponse` was provided but could not be invoked * because the upstream response was streamed to the client progressively. * The hook was rolled + wired but the bytes left before it could fire. * Intended for observability (log/metric/journal annotation) — proxyAndRecord * still returns `"relayed"`. */ onHookBypassed?: (reason: "sse_streamed" | "ndjson_streamed" | "binary_streamed") => void; } /** * Outcome of a proxyAndRecord call, returned so the caller can decide whether * to journal, fall through, or stop — without sharing a mutable flag with the * `beforeWriteResponse` hook. * * - `"not_configured"` — no upstream URL for this provider; caller should fall * through to its next branch (typically strict/404). * - `"relayed"` — the default code path wrote a response (upstream success or * synthesized 502 error). Caller should journal the outcome. * - `"handled_by_hook"` — the hook wrote + journaled its own response. Caller * should not double-journal. */ type ProxyOutcome = "not_configured" | "relayed" | "handled_by_hook"; /** * Result of `persistFixture`: * - `"skipped"` — proxy-only mode; the caller has nothing else to do. * - `"written"` — fixture saved to `filepath` and (unless the match was empty) * registered into the in-memory cache so the next identical request matches. * - `"failed"` — filesystem write failed. Caller decides how to surface it * (e.g. setting `X-AIMock-Record-Error` on a relay response). */ /** * Proxy an unmatched request to the real upstream provider, record the * response as a fixture on disk and in memory, then relay the response * back to the original client. */ declare function proxyAndRecord(req: http$1.IncomingMessage, res: http$1.ServerResponse, request: ChatCompletionRequest, providerKey: RecordProviderKey, pathname: string, fixtures: Fixture[], defaults: { record?: RecordConfig; logger: Logger; requestTransform?: (req: ChatCompletionRequest) => ChatCompletionRequest; }, rawBody?: string, options?: ProxyOptions): Promise; /** * Decodes a sequence of byte chunks to UTF-8 text for SSE/NDJSON frame * splitting on the streamed-capture path. Wraps Node's StringDecoder so a * multibyte UTF-8 character (CJK, emoji, ...) whose bytes are split across a * TCP chunk boundary buffers across chunks instead of decoding to U+FFFD * replacement characters — decoding each chunk independently with * Buffer#toString() would corrupt the recorded frame text. */ //#endregion export { proxyAndRecord }; //# sourceMappingURL=recorder.d.ts.map