Skip to content

Commit e1eff94

Browse files
[miniflare] Fix Buffer type not accepted for D1 blob bindings (#12514)
Co-authored-by: devin-ai-integration[bot] <158243242+devin-ai-integration[bot]@users.noreply.github.com>
1 parent 31b14ac commit e1eff94

3 files changed

Lines changed: 47 additions & 6 deletions

File tree

.changeset/fix-buffer-devalue.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
---
2+
"miniflare": patch
3+
---
4+
5+
fix: normalise typed array subclasses in devalue serialization
6+
7+
Node.js `Buffer` extends `Uint8Array` but isn't available in all runtimes. When
8+
a `Buffer` was passed through the proxy serialization bridge (e.g. as a D1 bind
9+
parameter via `getPlatformProxy()`), the reviver would fail because `"Buffer"`
10+
isn't in the allowed constructor list and may not exist on `globalThis` in workerd.
11+
12+
The reducer now normalises subclass constructor names to the nearest standard
13+
typed array parent before serialization, matching structured clone behaviour.

packages/miniflare/src/workers/core/devalue.ts

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -52,12 +52,26 @@ export const structuredSerializableReducers: ReducersRevivers = {
5252
},
5353
ArrayBufferView(value) {
5454
if (ArrayBuffer.isView(value)) {
55-
return [
56-
value.constructor.name,
57-
value.buffer,
58-
value.byteOffset,
59-
value.byteLength,
60-
];
55+
let name = value.constructor.name;
56+
// Subclasses like Node.js `Buffer` extend standard typed arrays but
57+
// aren't available in all runtimes. Normalise to the parent constructor.
58+
if (
59+
!ALLOWED_ARRAY_BUFFER_VIEW_CONSTRUCTORS.some((c) => c.name === name)
60+
) {
61+
for (const ctor of ALLOWED_ARRAY_BUFFER_VIEW_CONSTRUCTORS) {
62+
if (value instanceof ctor) {
63+
name = ctor.name;
64+
break;
65+
}
66+
}
67+
}
68+
let buf = value.buffer;
69+
let off = value.byteOffset;
70+
if (off !== 0 || buf.byteLength !== value.byteLength) {
71+
buf = buf.slice(off, off + value.byteLength);
72+
off = 0;
73+
}
74+
return [name, buf, off, value.byteLength];
6175
}
6276
},
6377
RegExp(value) {

packages/miniflare/test/workers/core/serialize.spec.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { Buffer } from "node:buffer";
12
import { parse, stringify } from "devalue";
23
import {
34
createHTTPReducers,
@@ -8,6 +9,19 @@ import {
89
import { test } from "vitest";
910
import { NODE_PLATFORM_IMPL } from "../../../src/plugins/core/proxy/types";
1011

12+
test("serialize Buffer as Uint8Array", ({ expect }) => {
13+
const input = Buffer.from([99, 88, 77]);
14+
15+
const serialized = stringify(input, structuredSerializableReducers);
16+
const deserialized = parse(serialized, structuredSerializableRevivers);
17+
18+
// Buffer should round-trip as Uint8Array since Buffer isn't available in all runtimes
19+
expect(deserialized).toBeInstanceOf(Uint8Array);
20+
expect(new Uint8Array(deserialized as ArrayBuffer)).toEqual(
21+
new Uint8Array([99, 88, 77])
22+
);
23+
});
24+
1125
test("serialize RegExp object consisting of only ascii chars", ({ expect }) => {
1226
const input = new RegExp(/HelloWorld/);
1327

0 commit comments

Comments
 (0)