@copilotkit/aimock 1.34.0 → 1.35.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/CHANGELOG.md +22 -0
- package/README.md +2 -1
- package/dist/agui-types.d.cts.map +1 -1
- package/dist/bedrock-converse.cjs +110 -8
- package/dist/bedrock-converse.cjs.map +1 -1
- package/dist/bedrock-converse.d.cts.map +1 -1
- package/dist/bedrock-converse.d.ts.map +1 -1
- package/dist/bedrock-converse.js +111 -9
- package/dist/bedrock-converse.js.map +1 -1
- package/dist/bedrock.cjs +141 -4
- package/dist/bedrock.cjs.map +1 -1
- package/dist/bedrock.d.cts.map +1 -1
- package/dist/bedrock.d.ts.map +1 -1
- package/dist/bedrock.js +142 -5
- package/dist/bedrock.js.map +1 -1
- package/dist/cohere.cjs +89 -7
- package/dist/cohere.cjs.map +1 -1
- package/dist/cohere.d.cts.map +1 -1
- package/dist/cohere.d.ts.map +1 -1
- package/dist/cohere.js +90 -8
- package/dist/cohere.js.map +1 -1
- package/dist/config-loader.d.cts.map +1 -1
- package/dist/fixture-loader.cjs +121 -20
- package/dist/fixture-loader.cjs.map +1 -1
- package/dist/fixture-loader.d.cts.map +1 -1
- package/dist/fixture-loader.d.ts.map +1 -1
- package/dist/fixture-loader.js +121 -20
- package/dist/fixture-loader.js.map +1 -1
- package/dist/gemini-interactions.cjs +97 -60
- package/dist/gemini-interactions.cjs.map +1 -1
- package/dist/gemini-interactions.d.cts.map +1 -1
- package/dist/gemini-interactions.d.ts.map +1 -1
- package/dist/gemini-interactions.js +98 -61
- package/dist/gemini-interactions.js.map +1 -1
- package/dist/gemini.cjs +71 -6
- package/dist/gemini.cjs.map +1 -1
- package/dist/gemini.d.cts.map +1 -1
- package/dist/gemini.d.ts.map +1 -1
- package/dist/gemini.js +72 -7
- package/dist/gemini.js.map +1 -1
- package/dist/grok-video.cjs +834 -0
- package/dist/grok-video.cjs.map +1 -0
- package/dist/grok-video.d.cts +74 -0
- package/dist/grok-video.d.cts.map +1 -0
- package/dist/grok-video.d.ts +74 -0
- package/dist/grok-video.d.ts.map +1 -0
- package/dist/grok-video.js +829 -0
- package/dist/grok-video.js.map +1 -0
- package/dist/helpers.cjs +181 -2
- package/dist/helpers.cjs.map +1 -1
- package/dist/helpers.d.cts +33 -3
- package/dist/helpers.d.cts.map +1 -1
- package/dist/helpers.d.ts +33 -3
- package/dist/helpers.d.ts.map +1 -1
- package/dist/helpers.js +181 -3
- package/dist/helpers.js.map +1 -1
- package/dist/index.cjs +11 -0
- package/dist/index.d.cts +5 -3
- package/dist/index.d.ts +5 -3
- package/dist/index.js +4 -2
- package/dist/messages.cjs +99 -10
- package/dist/messages.cjs.map +1 -1
- package/dist/messages.d.cts.map +1 -1
- package/dist/messages.d.ts.map +1 -1
- package/dist/messages.js +100 -11
- package/dist/messages.js.map +1 -1
- package/dist/metrics.cjs +11 -1
- package/dist/metrics.cjs.map +1 -1
- package/dist/metrics.d.cts.map +1 -1
- package/dist/metrics.d.ts.map +1 -1
- package/dist/metrics.js +8 -1
- package/dist/metrics.js.map +1 -1
- package/dist/ollama.cjs +74 -4
- package/dist/ollama.cjs.map +1 -1
- package/dist/ollama.d.cts.map +1 -1
- package/dist/ollama.d.ts.map +1 -1
- package/dist/ollama.js +75 -5
- package/dist/ollama.js.map +1 -1
- package/dist/openrouter-video.cjs +19 -138
- package/dist/openrouter-video.cjs.map +1 -1
- package/dist/openrouter-video.d.cts.map +1 -1
- package/dist/openrouter-video.d.ts.map +1 -1
- package/dist/openrouter-video.js +1 -120
- package/dist/openrouter-video.js.map +1 -1
- package/dist/recorder.cjs +36 -20
- package/dist/recorder.cjs.map +1 -1
- package/dist/recorder.js +36 -20
- package/dist/recorder.js.map +1 -1
- package/dist/responses.cjs +136 -58
- package/dist/responses.cjs.map +1 -1
- package/dist/responses.d.cts +2 -2
- package/dist/responses.d.cts.map +1 -1
- package/dist/responses.d.ts +2 -2
- package/dist/responses.d.ts.map +1 -1
- package/dist/responses.js +137 -59
- package/dist/responses.js.map +1 -1
- package/dist/server.cjs +162 -20
- package/dist/server.cjs.map +1 -1
- package/dist/server.d.cts +4 -0
- package/dist/server.d.cts.map +1 -1
- package/dist/server.d.ts +4 -0
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +164 -22
- package/dist/server.js.map +1 -1
- package/dist/stream-collapse.cjs +300 -74
- package/dist/stream-collapse.cjs.map +1 -1
- package/dist/stream-collapse.d.cts +17 -1
- package/dist/stream-collapse.d.cts.map +1 -1
- package/dist/stream-collapse.d.ts +17 -1
- package/dist/stream-collapse.d.ts.map +1 -1
- package/dist/stream-collapse.js +300 -74
- package/dist/stream-collapse.js.map +1 -1
- package/dist/types.d.cts +104 -7
- package/dist/types.d.cts.map +1 -1
- package/dist/types.d.ts +104 -7
- package/dist/types.d.ts.map +1 -1
- package/dist/vector-types.d.cts.map +1 -1
- package/dist/vector-types.d.ts.map +1 -1
- package/dist/veo-video.cjs +794 -0
- package/dist/veo-video.cjs.map +1 -0
- package/dist/veo-video.d.cts +50 -0
- package/dist/veo-video.d.cts.map +1 -0
- package/dist/veo-video.d.ts +50 -0
- package/dist/veo-video.d.ts.map +1 -0
- package/dist/veo-video.js +789 -0
- package/dist/veo-video.js.map +1 -0
- package/dist/video-proxy-shared.cjs +145 -0
- package/dist/video-proxy-shared.cjs.map +1 -0
- package/dist/video-proxy-shared.js +140 -0
- package/dist/video-proxy-shared.js.map +1 -0
- package/dist/ws-gemini-live.cjs +96 -3
- package/dist/ws-gemini-live.cjs.map +1 -1
- package/dist/ws-gemini-live.d.cts.map +1 -1
- package/dist/ws-gemini-live.d.ts.map +1 -1
- package/dist/ws-gemini-live.js +97 -4
- package/dist/ws-gemini-live.js.map +1 -1
- package/dist/ws-realtime.cjs +281 -4
- package/dist/ws-realtime.cjs.map +1 -1
- package/dist/ws-realtime.d.cts.map +1 -1
- package/dist/ws-realtime.d.ts.map +1 -1
- package/dist/ws-realtime.js +282 -5
- package/dist/ws-realtime.js.map +1 -1
- package/dist/ws-responses.cjs +1 -1
- package/dist/ws-responses.cjs.map +1 -1
- package/dist/ws-responses.js +1 -1
- package/dist/ws-responses.js.map +1 -1
- package/fixtures/examples/llm/blocks-tool-first.json +13 -0
- package/package.json +1 -1
- package/skills/write-fixtures/SKILL.md +19 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"openrouter-video.d.cts","names":[],"sources":["../src/openrouter-video.ts"],"sourcesContent":[],"mappings":";;;;;
|
|
1
|
+
{"version":3,"file":"openrouter-video.d.cts","names":[],"sources":["../src/openrouter-video.ts"],"sourcesContent":[],"mappings":";;;;;cAkEa,4BAAA;KAGR,qBAAA;AAHL,UAKU,wBAAA,CAL+B;EAGpC,IAAA,EAAA,QAAA;EAEK,KAAA,EAAA,MAAA;EAAwB,MAAA,EAGxB,qBAHwB;;WAWzB,EAAA,MAAA;EAAa;EAyBZ,qBAAA,EAAA,MAAwB;EAAA;sBAYxB,EAAA,MAAA;;EAWM,KAAA,EAhDP,aAgDO,CAAA,OAAA,CAAA;EAwBJ;;;;EAAwE,gBAAA,CAAA,EAAA,OAAA;EAoBvE;;;;;AAqNb;EAAiD,mBAAA,CAAA,EAAA,OAAA;;;;;;;;;;AAiKjD;;UAzbU,wBAAA,CA0bE;MACL,EAAA,QAAK;;OAGA,EAAA,MAAA;;;;;AAsmBZ;;;;QAGY,EA3hCF,qBA2hCE;;eAEA,EAAA,MAAA;;oBAET,EAAA,MAAA;EAAO;AAmIV;;;;;OAKW,EA5pCF,OA4pCE,CAAA,OAAA,CAAA;;;;;;AA+lBX;;;;;;;;;;;;;;;;;KAnuDY,kBAAA,GAAqB,2BAA2B;;;;;;;;;;;;;;cAoB/C,qBAAA;;;;;;;;;;;;oBAgBO;wBAUI;;;;;iBA2LF,2BAAA,MACf,MAAA,CAAK,sBACL,MAAA,CAAK,yCAEA,oBACD,mBACC,uCACY,MAAA,CAAK,+BACrB,wBACL;iBAwJmB,4BAAA,MACf,MAAA,CAAK,sBACL,MAAA,CAAK,wCAED,mBACC,uCACY,MAAA,CAAK,+BACrB,wBACL;;;;;;;;;;;;;;;iBAmmBmB,2BAAA,MACf,MAAA,CAAK,sBACL,MAAA,CAAK,0BACA,oBACD,mBACC,uCACY,MAAA,CAAK,0BAC1B;iBAmImB,2BAAA,MACf,MAAA,CAAK,sBACL,MAAA,CAAK,uCAEA,oBACD,mBACC,uCACY,MAAA,CAAK,+BACrB,wBACL;;;;;;;;;;;;;cA2lBU"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"openrouter-video.d.ts","names":[],"sources":["../src/openrouter-video.ts"],"sourcesContent":[],"mappings":";;;;;
|
|
1
|
+
{"version":3,"file":"openrouter-video.d.ts","names":[],"sources":["../src/openrouter-video.ts"],"sourcesContent":[],"mappings":";;;;;cAkEa,4BAAA;KAGR,qBAAA;AAHL,UAKU,wBAAA,CAL+B;EAGpC,IAAA,EAAA,QAAA;EAEK,KAAA,EAAA,MAAA;EAAwB,MAAA,EAGxB,qBAHwB;;WAWzB,EAAA,MAAA;EAAa;EAyBZ,qBAAA,EAAA,MAAwB;EAAA;sBAYxB,EAAA,MAAA;;EAWM,KAAA,EAhDP,aAgDO,CAAA,OAAA,CAAA;EAwBJ;;;;EAAwE,gBAAA,CAAA,EAAA,OAAA;EAoBvE;;;;;AAqNb;EAAiD,mBAAA,CAAA,EAAA,OAAA;;;;;;;;;;AAiKjD;;UAzbU,wBAAA,CA0bE;MACL,EAAA,QAAK;;OAGA,EAAA,MAAA;;;;;AAsmBZ;;;;QAGY,EA3hCF,qBA2hCE;;eAEA,EAAA,MAAA;;oBAET,EAAA,MAAA;EAAO;AAmIV;;;;;OAKW,EA5pCF,OA4pCE,CAAA,OAAA,CAAA;;;;;;AA+lBX;;;;;;;;;;;;;;;;;KAnuDY,kBAAA,GAAqB,2BAA2B;;;;;;;;;;;;;;cAoB/C,qBAAA;;;;;;;;;;;;oBAgBO;wBAUI;;;;;iBA2LF,2BAAA,MACf,MAAA,CAAK,sBACL,MAAA,CAAK,yCAEA,oBACD,mBACC,uCACY,MAAA,CAAK,+BACrB,wBACL;iBAwJmB,4BAAA,MACf,MAAA,CAAK,sBACL,MAAA,CAAK,wCAED,mBACC,uCACY,MAAA,CAAK,+BACrB,wBACL;;;;;;;;;;;;;;;iBAmmBmB,2BAAA,MACf,MAAA,CAAK,sBACL,MAAA,CAAK,0BACA,oBACD,mBACC,uCACY,MAAA,CAAK,0BAC1B;iBAmImB,2BAAA,MACf,MAAA,CAAK,sBACL,MAAA,CAAK,uCAEA,oBACD,mBACC,uCACY,MAAA,CAAK,+BACrB,wBACL;;;;;;;;;;;;;cA2lBU"}
|
package/dist/openrouter-video.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { DEFAULT_TEST_ID } from "./constants.js";
|
|
2
1
|
import { flattenHeaders, getContext, getTestId, isErrorResponse, isVideoResponse, resolveResponse, resolveStrictMode, serializeErrorResponse, strictNoMatchLogLine, strictNoMatchMessage, strictOverrideField } from "./helpers.js";
|
|
3
2
|
import { matchFixtureDiagnostic } from "./router.js";
|
|
4
3
|
import { writeErrorResponse } from "./sse-writer.js";
|
|
@@ -6,6 +5,7 @@ import { applyChaos } from "./chaos.js";
|
|
|
6
5
|
import { resolveUpstreamUrl } from "./url.js";
|
|
7
6
|
import { buildFixtureMatch, buildForwardHeaders, clampTimeout, persistFixture, sanitizeHeaderValue } from "./recorder.js";
|
|
8
7
|
import { resolveProgression } from "./fal.js";
|
|
8
|
+
import { DEFAULT_UPSTREAM_TIMEOUT_MS, readBodyIdle, readEnvelopeText, requestBase, testIdSuffix, upstreamTimeoutSignal } from "./video-proxy-shared.js";
|
|
9
9
|
import crypto from "node:crypto";
|
|
10
10
|
|
|
11
11
|
//#region src/openrouter-video.ts
|
|
@@ -98,61 +98,6 @@ function advanceJob(job) {
|
|
|
98
98
|
else if (job.pollCount >= job.pollsBeforeCompleted) job.status = terminalStatus(job);
|
|
99
99
|
}
|
|
100
100
|
/**
|
|
101
|
-
* First non-empty value of a possibly array-typed, possibly comma-joined
|
|
102
|
-
* header. An empty header value or a leading-comma list (", host") would
|
|
103
|
-
* otherwise yield "" — triggering a spurious rejection warn and discarding
|
|
104
|
-
* valid later entries — so empty segments are skipped.
|
|
105
|
-
*/
|
|
106
|
-
function firstForwardedValue(header) {
|
|
107
|
-
const raw = Array.isArray(header) ? header.join(",") : header;
|
|
108
|
-
if (raw === void 0) return void 0;
|
|
109
|
-
for (const segment of raw.split(",")) {
|
|
110
|
-
const trimmed = segment.trim();
|
|
111
|
-
if (trimmed) return trimmed;
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
const FORWARDED_HOST_RE = /^[a-zA-Z0-9._-]+(:\d+)?$/;
|
|
115
|
-
const FORWARDED_HOST_IPV6_RE = /^\[[0-9a-fA-F:.]+\](:\d+)?$/;
|
|
116
|
-
function requestBase(req, logger) {
|
|
117
|
-
const candidate = firstForwardedValue(req.headers["x-forwarded-proto"])?.toLowerCase();
|
|
118
|
-
const proto = candidate === "http" || candidate === "https" ? candidate : "http";
|
|
119
|
-
const fwdHost = firstForwardedValue(req.headers["x-forwarded-host"]);
|
|
120
|
-
const rawHost = req.headers.host;
|
|
121
|
-
let host = rawHost !== void 0 && (FORWARDED_HOST_RE.test(rawHost) || FORWARDED_HOST_IPV6_RE.test(rawHost)) ? rawHost : "localhost";
|
|
122
|
-
if (fwdHost !== void 0) if (FORWARDED_HOST_RE.test(fwdHost) || FORWARDED_HOST_IPV6_RE.test(fwdHost)) host = fwdHost;
|
|
123
|
-
else logger.warn(`x-forwarded-host value rejected, falling back to Host header: ${JSON.stringify(fwdHost.slice(0, 100))}`);
|
|
124
|
-
return `${proto}://${host}`;
|
|
125
|
-
}
|
|
126
|
-
/**
|
|
127
|
-
* Query-string suffix embedding the request's testId into generated URLs
|
|
128
|
-
* (polling_url, unsigned_urls). The @openrouter/sdk fetches these URLs with
|
|
129
|
-
* standard Authorization but no aimock-specific headers (no x-test-id) — so
|
|
130
|
-
* the testId must travel in the URL for getTestId's `?testId=` fallback to
|
|
131
|
-
* resolve the right job scope. The default testId is omitted to keep
|
|
132
|
-
* single-tenant URLs clean.
|
|
133
|
-
*/
|
|
134
|
-
function testIdSuffix(testId, sep) {
|
|
135
|
-
return testId === DEFAULT_TEST_ID ? "" : `${sep}testId=${encodeURIComponent(testId)}`;
|
|
136
|
-
}
|
|
137
|
-
/** Default upstream timeout for the live lifecycle proxy (matches recorder.ts). */
|
|
138
|
-
const DEFAULT_UPSTREAM_TIMEOUT_MS = 3e4;
|
|
139
|
-
/**
|
|
140
|
-
* Abort signal for the SMALL-JSON upstream fetches on this surface (submit,
|
|
141
|
-
* status poll, models listing), honoring `record.upstreamTimeoutMs` with the
|
|
142
|
-
* same clamp conventions as recorder.ts (non-finite / non-positive values
|
|
143
|
-
* fall back to the 30s default). Note the nuance (documented on
|
|
144
|
-
* RecordConfig.upstreamTimeoutMs): these envelope-sized fetches use the value
|
|
145
|
-
* as a TOTAL deadline via AbortSignal.timeout — indistinguishable from a
|
|
146
|
-
* socket-idle timeout for small bodies. The byte-bearing content fetches use
|
|
147
|
-
* `fetchHeadersWithTimeout` + `readBodyIdle` instead, which implement true
|
|
148
|
-
* idle semantics. An abort rejects the fetch and surfaces through the
|
|
149
|
-
* caller's existing failure path (502 proxy_error on submit/poll, models
|
|
150
|
-
* synthesis fallback).
|
|
151
|
-
*/
|
|
152
|
-
function upstreamTimeoutSignal(record) {
|
|
153
|
-
return AbortSignal.timeout(clampTimeout(record?.upstreamTimeoutMs, DEFAULT_UPSTREAM_TIMEOUT_MS));
|
|
154
|
-
}
|
|
155
|
-
/**
|
|
156
101
|
* Fetch a byte-bearing upstream URL with `record.upstreamTimeoutMs` gating
|
|
157
102
|
* only the HEADERS: the abort timer is cleared the moment the response head
|
|
158
103
|
* arrives, so a long — but steadily progressing — body download is never
|
|
@@ -173,50 +118,6 @@ async function fetchHeadersWithTimeout(url, headers, record) {
|
|
|
173
118
|
}
|
|
174
119
|
}
|
|
175
120
|
/**
|
|
176
|
-
* Buffer a fetch Response body with IDLE-based timeout semantics: a timer
|
|
177
|
-
* clamped from `record.bodyTimeoutMs` (30s default — same clamp as
|
|
178
|
-
* recorder.ts) is re-armed for every chunk, so a steadily-dripping body of
|
|
179
|
-
* any total duration completes and only a silent mid-body stall rejects.
|
|
180
|
-
* When `cap` > 0 the byte count is enforced DURING the read: on exceed the
|
|
181
|
-
* stream is cancelled and `{ overCap: true }` is returned with NOTHING
|
|
182
|
-
* oversized retained in memory — the cap is a memory guard as much as a
|
|
183
|
-
* disk guard.
|
|
184
|
-
*/
|
|
185
|
-
async function readBodyIdle(res, record, cap = 0) {
|
|
186
|
-
const body = res.body;
|
|
187
|
-
if (!body) return {
|
|
188
|
-
overCap: false,
|
|
189
|
-
buf: Buffer.alloc(0)
|
|
190
|
-
};
|
|
191
|
-
const idleMs = clampTimeout(record?.bodyTimeoutMs, DEFAULT_UPSTREAM_TIMEOUT_MS);
|
|
192
|
-
const reader = body.getReader();
|
|
193
|
-
const chunks = [];
|
|
194
|
-
let total = 0;
|
|
195
|
-
try {
|
|
196
|
-
for (;;) {
|
|
197
|
-
let idleTimer;
|
|
198
|
-
const readPromise = reader.read();
|
|
199
|
-
readPromise.catch(() => {});
|
|
200
|
-
const result = await Promise.race([readPromise, new Promise((_, reject) => {
|
|
201
|
-
idleTimer = setTimeout(() => reject(/* @__PURE__ */ new Error(`Upstream response body idle for ${idleMs}ms`)), idleMs);
|
|
202
|
-
})]).finally(() => clearTimeout(idleTimer));
|
|
203
|
-
if (result.done) break;
|
|
204
|
-
total += result.value.byteLength;
|
|
205
|
-
if (cap > 0 && total > cap) return {
|
|
206
|
-
overCap: true,
|
|
207
|
-
bytesRead: total
|
|
208
|
-
};
|
|
209
|
-
chunks.push(Buffer.from(result.value));
|
|
210
|
-
}
|
|
211
|
-
} finally {
|
|
212
|
-
reader.cancel().catch(() => {});
|
|
213
|
-
}
|
|
214
|
-
return {
|
|
215
|
-
overCap: false,
|
|
216
|
-
buf: Buffer.concat(chunks)
|
|
217
|
-
};
|
|
218
|
-
}
|
|
219
|
-
/**
|
|
220
121
|
* Cap on an upstream ERROR body (401/403 relays) buffered by the content
|
|
221
122
|
* proxy. Error bodies are envelope-sized JSON in practice — 64 KB is generous
|
|
222
123
|
* — and unlike the video bytes they are buffered in full before the relay, so
|
|
@@ -224,26 +125,6 @@ async function readBodyIdle(res, record, cap = 0) {
|
|
|
224
125
|
*/
|
|
225
126
|
const OPENROUTER_VIDEO_ERROR_BODY_CAP = 64 * 1024;
|
|
226
127
|
/**
|
|
227
|
-
* Cap on the small-JSON upstream envelope bodies (submit, status poll, models
|
|
228
|
-
* listing) buffered before parse/relay. Envelopes are KB-scale in practice —
|
|
229
|
-
* 1 MB is generous headroom even for a large models listing — and, like the
|
|
230
|
-
* error-body cap above, they are buffered in full, so an unbounded `text()`
|
|
231
|
-
* would be a memory hole on a hostile upstream.
|
|
232
|
-
*/
|
|
233
|
-
const OPENROUTER_VIDEO_ENVELOPE_BODY_CAP = 1024 * 1024;
|
|
234
|
-
/**
|
|
235
|
-
* Bounded read of a small-JSON upstream envelope body (submit, status poll,
|
|
236
|
-
* models listing): readBodyIdle's idle semantics plus the envelope cap. An
|
|
237
|
-
* over-cap body is a hard failure — the throw surfaces through each caller's
|
|
238
|
-
* existing failure path (502 proxy_error on submit/poll, models synthesis
|
|
239
|
-
* fallback) without retaining anything oversized in memory.
|
|
240
|
-
*/
|
|
241
|
-
async function readEnvelopeText(res, record) {
|
|
242
|
-
const read = await readBodyIdle(res, record, OPENROUTER_VIDEO_ENVELOPE_BODY_CAP);
|
|
243
|
-
if (read.overCap) throw new Error(`Upstream envelope body exceeded ${OPENROUTER_VIDEO_ENVELOPE_BODY_CAP} bytes (read aborted at ${read.bytesRead})`);
|
|
244
|
-
return read.buf.toString("utf8");
|
|
245
|
-
}
|
|
246
|
-
/**
|
|
247
128
|
* Rewrite an upstream poll body for relay to the client. Every field is
|
|
248
129
|
* relayed verbatim EXCEPT the ones that would let the client escape the mock
|
|
249
130
|
* or learn upstream identifiers:
|