Files
OmniRoute/tests/unit/multipart-body-arraybuffer-backing.test.ts
backryun 2a8b8bcf13 refactor(sse): declare the multipart/gRPC frame bodies as ArrayBuffer-backed
Seven TS2769 across three files, one root cause: a bare `Uint8Array` widens to
`Uint8Array<ArrayBufferLike>`, which admits `SharedArrayBuffer` and so is not
assignable to `BodyInit`. Every one of the seven is a `fetch({ body })` call
rejecting an otherwise-valid payload.

They flow from exactly two producers:

  buildMultipartBody()  audioTranscription.ts  -> 5 sites here + 1 in audioTranslation.ts
  grpcWebFrame()        windsurf.ts            -> 1 site

Both allocate with `new Uint8Array(length)`, which is always ArrayBuffer-backed,
so declaring `Uint8Array<ArrayBuffer>` states what the code already guarantees.
This is a narrowing of the declaration to match reality, not a cast at the call
sites — no `as BodyInit` anywhere, and the seven call sites are untouched.

280 -> 273, zero new, on a line-number-agnostic diff of the full tsc error set.
The runtime diff is two return-type annotations; nothing executable changed.

Tests: buildMultipartBody already has four direct tests, but they assert the
payload's *contents* (boundary, filename sanitization, MIME fallback) — none
assert the backing, which is precisely what the new type guarantees and what a
plausible switch to a pooled `Buffer.concat` would break. Added
multipart-body-arraybuffer-backing.test.ts (3 tests): the buffer is a plain
ArrayBuffer, the view spans it entirely at offset 0 (no pool remainder), and
both hold for a 64 KiB payload past Node's Buffer-pool threshold. 258/258 across
the 17 affected audio/windsurf suites.

Not included: the 3 remaining TS2339 in audioTranscription.ts (`data?.data?.…`
on an untyped poll result). Different root cause — grouped by kind, not by file,
per #8484.
2026-07-25 17:24:12 +09:00

63 lines
2.8 KiB
TypeScript

import test from "node:test";
import assert from "node:assert/strict";
const { buildMultipartBody } = await import("../../open-sse/handlers/audioTranscription.ts");
/**
* `buildMultipartBody` is handed straight to `fetch` as the request body by six
* call sites across `audioTranscription.ts` and `audioTranslation.ts`, so its
* result must satisfy `BodyInit` — which requires an `ArrayBuffer`-backed view,
* not merely "some Uint8Array". A `SharedArrayBuffer`-backed view, or a slice
* into a shared pool, is not a valid request body.
*
* The four existing `buildMultipartBody` tests in
* `audio-transcription-handler.test.ts` decode the payload and assert its
* *contents* (boundary, filename sanitization, MIME fallback). None of them
* assert the backing, which is the property the declared
* `Uint8Array<ArrayBuffer>` return type exists to guarantee — and the one a
* plausible "optimization" to a pooled `Buffer.concat` would break.
*/
function audioFile(name = "clip.wav", type = "audio/wav") {
return Object.assign(new Blob([new Uint8Array([1, 2, 3, 4])], { type }), { name });
}
test("the assembled body is backed by a plain ArrayBuffer, never a shared one", async () => {
const { body } = await buildMultipartBody(audioFile(), { model: "whisper-1" });
assert.ok(body instanceof Uint8Array);
assert.ok(
body.buffer instanceof ArrayBuffer,
"a SharedArrayBuffer-backed view is not accepted as a fetch BodyInit"
);
});
test("the assembled body owns its whole buffer — not a view into a shared pool", async () => {
const { body } = await buildMultipartBody(audioFile(), { model: "whisper-1" });
// `new Uint8Array(totalLength)` allocates exclusively. A pooled allocation
// (e.g. switching to Buffer.concat) would leave a non-zero byteOffset and a
// buffer larger than the payload, so the bytes handed to fetch would no
// longer be the whole buffer.
assert.equal(body.byteOffset, 0, "body must start at offset 0 of its own buffer");
assert.equal(
body.byteLength,
body.buffer.byteLength,
"body must span its entire buffer, with no pooled remainder"
);
});
test("the backing holds for a larger payload than a single pool slab", async () => {
// 64 KiB — comfortably past Node's 8 KiB Buffer pool threshold, so a pooled
// implementation would behave differently here than for the small case above.
const big = Object.assign(new Blob([new Uint8Array(64 * 1024)], { type: "audio/wav" }), {
name: "big.wav",
});
const { body } = await buildMultipartBody(big, { model: "whisper-1" });
assert.ok(body.buffer instanceof ArrayBuffer);
assert.equal(body.byteOffset, 0);
assert.equal(body.byteLength, body.buffer.byteLength);
assert.ok(body.byteLength > 64 * 1024, "payload carries the file plus the multipart envelope");
});