From 16b03d18bfac995c2a4bcdc9aad94e4da5725ac5 Mon Sep 17 00:00:00 2001 From: wuyangfan Date: Mon, 25 May 2026 17:09:56 +0800 Subject: [PATCH 1/2] fix: check FormData before buffer in isJSONSerializable Closes #580 --- src/utils.ts | 6 +++--- test/index.test.ts | 18 ++++++++++++++++++ 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/src/utils.ts b/src/utils.ts index a773431b..f8d3afdf 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -28,14 +28,14 @@ export function isJSONSerializable(value: any): boolean { if (Array.isArray(value)) { return true; } - if (value.buffer) { - return false; - } // `FormData` and `URLSearchParams` should't have a `toJSON` method, // but Bun adds it, which is non-standard. if (value instanceof FormData || value instanceof URLSearchParams) { return false; } + if (value.buffer) { + return false; + } return ( (value.constructor && value.constructor.name === "Object") || typeof value.toJSON === "function" diff --git a/test/index.test.ts b/test/index.test.ts index 5ac20b07..3b2eb1a6 100644 --- a/test/index.test.ts +++ b/test/index.test.ts @@ -525,3 +525,21 @@ describe("ofetch", () => { }); }); }); + +describe("isJSONSerializable", () => { + let isJSONSerializable: (value: unknown) => boolean; + + beforeAll(async () => { + const utils = await import("../src/utils.ts"); + isJSONSerializable = utils.isJSONSerializable; + }); + + it("returns false for FormData and URLSearchParams before buffer checks", () => { + expect(isJSONSerializable(new FormData())).toBe(false); + expect(isJSONSerializable(new URLSearchParams())).toBe(false); + + const data = new FormData(); + data.append("foo", "bar"); + expect(isJSONSerializable(data)).toBe(false); + }); +}); From 9c657a9afca222abcfcbe35ef48a335504397533 Mon Sep 17 00:00:00 2001 From: wuyangfan Date: Tue, 26 May 2026 09:40:20 +0800 Subject: [PATCH 2/2] fix: handle null in isJSONSerializable and check FormData first Treat null as JSON-serializable via explicit check (typeof null is "object") and probe FormData/URLSearchParams before value.buffer. Fixes #571 Fixes #580 --- src/utils.ts | 5 ++++- test/index.test.ts | 4 ++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/utils.ts b/src/utils.ts index f8d3afdf..ff7871a0 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -18,8 +18,11 @@ export function isJSONSerializable(value: any): boolean { if (value === undefined) { return false; } + if (value === null) { + return true; + } const t = typeof value; - if (t === "string" || t === "number" || t === "boolean" || t === null) { + if (t === "string" || t === "number" || t === "boolean") { return true; } if (t !== "object") { diff --git a/test/index.test.ts b/test/index.test.ts index 3b2eb1a6..c3f7a848 100644 --- a/test/index.test.ts +++ b/test/index.test.ts @@ -542,4 +542,8 @@ describe("isJSONSerializable", () => { data.append("foo", "bar"); expect(isJSONSerializable(data)).toBe(false); }); + + it("returns true for null without throwing", () => { + expect(isJSONSerializable(null)).toBe(true); // eslint-disable-line unicorn/no-null + }); });