Skip to content

Commit 977b8bd

Browse files
Bugfix: Fix #15004 by applying MDN recommended fix when proxying Response in page_load (#15005)
* Apply MDN recommended fix when proxying Response to avoid TypeError. On Node v24+, the undici library used for HTTP has a Response class with a private element. Proxying the response therefore fails when calling clone() as the method returned by the proxy cannot access the private state element. * Use more comprehensive Response proxy fix that makes linter happy. By using Object.defineProperty(), we make the function identical to introspection. Also, the linter didn't like the `...args`. * Add page to test undici Response TypeError. * Add generated changeset file. * Apply suggestion from @elliott-with-the-longest-name-on-github --------- Co-authored-by: Elliott Johnson <hello@ell.iott.dev>
1 parent 9fda2fc commit 977b8bd

File tree

4 files changed

+47
-2
lines changed

4 files changed

+47
-2
lines changed

.changeset/tangy-donkeys-knock.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@sveltejs/kit': patch
3+
---
4+
5+
fix: TypeError when doing response.clone() in page load

packages/kit/src/runtime/server/page/load_data.js

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -316,7 +316,7 @@ export function create_universal_fetch(event, state, fetched, csr, resolve_opts)
316316
let teed_body;
317317

318318
const proxy = new Proxy(response, {
319-
get(response, key, _receiver) {
319+
get(response, key, receiver) {
320320
/**
321321
* @param {string | undefined} body
322322
* @param {boolean} is_b64
@@ -427,7 +427,28 @@ export function create_universal_fetch(event, state, fetched, csr, resolve_opts)
427427
};
428428
}
429429

430-
return Reflect.get(response, key, response);
430+
const value = Reflect.get(response, key, response);
431+
432+
if (value instanceof Function) {
433+
// On Node v24+, the Response object has a private element #state – we
434+
// need to bind this function to the response in order to allow it to
435+
// access this private element. Defining the name and length ensure it
436+
// is identical to the original function when introspected.
437+
return Object.defineProperties(
438+
/**
439+
* @this {any}
440+
*/
441+
function () {
442+
return Reflect.apply(value, this === receiver ? response : this, arguments);
443+
},
444+
{
445+
name: { value: value.name },
446+
length: { value: value.length }
447+
}
448+
);
449+
}
450+
451+
return value;
431452
}
432453
});
433454

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
/** @type {import('@sveltejs/kit').Load} */
2+
export async function load({ url, fetch }) {
3+
const href = new URL(url);
4+
href.pathname = '';
5+
6+
const res = await fetch(href);
7+
const clonedRes = res.clone();
8+
return { text: await clonedRes.text() };
9+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<script>
2+
/** @type {import('./$types').PageData} */
3+
export let data;
4+
</script>
5+
6+
<h1>the text is:</h1>
7+
8+
<p>
9+
{data.text}
10+
</p>

0 commit comments

Comments
 (0)