MCPcopy Create free account
hub / github.com/CopilotKit/aimock / onUpstreamData

Function onUpstreamData

src/recorder.ts:1162–1288  ·  view source on GitHub ↗
(chunk: Buffer)

Source from the content-addressed store, hash-verified

1160 );
1161 };
1162 const onUpstreamData = (chunk: Buffer) => {
1163 totalBytes += chunk.length;
1164 // Trip truncation on EITHER bytes OR frame count. The byte cap alone
1165 // never bounds `frameTimestamps` (count-indexed, not byte-sized) nor a
1166 // never-completing parse buffer, so a long-lived / never-ending stream
1167 // would otherwise grow per-frame state forever. `frameTimestamps.length`
1168 // is the running complete-frame count. `>=` (not `>`) so we never
1169 // retain MORE than `maxBufferFrames` frames — see the "maximum N
1170 // frames retained" contract on DEFAULT_MAX_PROXY_BUFFER_FRAMES.
1171 if (!bufferTruncated && bufferedBytes + chunk.length > maxBufferBytes) {
1172 tripTruncation("byte");
1173 } else if (!bufferTruncated && frameTimestamps.length >= maxBufferFrames) {
1174 tripTruncation("frame");
1175 }
1176 // Buffer the raw bytes. Under cap: always. Over cap on a progressive
1177 // stream: never (bytes are already teed live; chunks was freed). Over
1178 // cap on a NON-progressive response: keep buffering for the relay —
1179 // it has no live tee, so `chunks` is the only copy the client can get
1180 // — but hard-cap it at HARD_CEILING (well under V8's max string
1181 // length) so the eventual rawBuffer.toString() relay can never throw
1182 // RangeError: Invalid string length.
1183 if (!bufferTruncated) {
1184 chunks.push(chunk);
1185 bufferedBytes += chunk.length;
1186 } else if (!isProgressiveStream) {
1187 if (bufferedBytes + chunk.length <= hardCeiling) {
1188 chunks.push(chunk);
1189 bufferedBytes += chunk.length;
1190 } else {
1191 // The non-progressive relay copy would exceed the hard ceiling.
1192 // We CANNOT relay the full body (it can't be buffered safely) and
1193 // MUST NOT relay the partial buffer as a success — flag it so the
1194 // caller fails loud (502) instead of presenting a truncated 2xx.
1195 hardCeilingExceeded = true;
1196 }
1197 }
1198
1199 // Capture per-frame timestamps for SSE/NDJSON streams. Gated on
1200 // !bufferTruncated so per-frame parse/timing state stops growing once
1201 // the cap trips (the byte/frame guard above already freed it).
1202 // TCP data events don't align with SSE frames — buffer and
1203 // split on the protocol delimiter to timestamp each complete frame.
1204 if (!bufferTruncated && (isSSE || isNDJSON)) {
1205 frameBuffer += frameDecoder.write(chunk);
1206 // Split on the protocol delimiter, tolerating CRLF line endings.
1207 // The SSE spec permits CRLF, and some upstreams/proxies emit
1208 // \r\n\r\n (SSE) or \r\n (NDJSON) frame boundaries. An LF-only
1209 // split would see the whole CRLF stream as a single frame and
1210 // lose per-frame timing. The last split element (a partial frame
1211 // tail) stays buffered, exactly as with a string delimiter.
1212 const delimiter = isNDJSON ? /\r?\n/ : /\r?\n\r?\n/;
1213 const parts = frameBuffer.split(delimiter);
1214 // All complete frames (everything except the last part which
1215 // may be incomplete). Enforce the frame cap PER-FRAME: a single
1216 // coalesced chunk can carry many complete frames, so checking only
1217 // at the top of the callback would let one event push them all and
1218 // overshoot the cap unbounded. Trip + bail mid-loop instead.
1219 for (let fi = 0; fi < parts.length - 1; fi++) {

Callers

nothing calls this directly

Calls 3

tripTruncationFunction · 0.85
writeMethod · 0.80
debugMethod · 0.80

Tested by

no test coverage detected

Used in the wild real call sites across dependent graphs

searching dependent graphs…