From 1aa8865641309c3eaaf494628d07bcad89001595 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Tue, 19 Aug 2025 13:17:35 -0400 Subject: [PATCH 1/3] failing test --- .../test/apps/basics/src/routes/load/serialization/+page.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/kit/test/apps/basics/src/routes/load/serialization/+page.js b/packages/kit/test/apps/basics/src/routes/load/serialization/+page.js index 72f7c4d96c37..ba92f18d1f94 100644 --- a/packages/kit/test/apps/basics/src/routes/load/serialization/+page.js +++ b/packages/kit/test/apps/basics/src/routes/load/serialization/+page.js @@ -5,5 +5,9 @@ export async function load({ fetch, data, url }) { const res = await fetch(new URL('/load/serialization/fetched-from-shared.json', url.origin)); const { b } = await res.json(); - return { a, b, c: a + b }; + // check that this doesn't mutate the original object + // and make the server data unserializable + data.sum = () => a + b; + + return { a, b, c: data.sum() }; } From b5664c51800722d710b1ee25148cb21710831333 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Tue, 19 Aug 2025 13:34:39 -0400 Subject: [PATCH 2/3] fix: serialize server `load` data before passing to universal `load`, to handle mutations --- .changeset/clever-boxes-feel.md | 5 +++ .../kit/src/runtime/server/page/load_data.js | 40 ++++++++++++++++--- 2 files changed, 39 insertions(+), 6 deletions(-) create mode 100644 .changeset/clever-boxes-feel.md diff --git a/.changeset/clever-boxes-feel.md b/.changeset/clever-boxes-feel.md new file mode 100644 index 000000000000..c33ab43d5931 --- /dev/null +++ b/.changeset/clever-boxes-feel.md @@ -0,0 +1,5 @@ +--- +'@sveltejs/kit': patch +--- + +fix: serialize server `load` data before passing to universal `load`, to handle mutations diff --git a/packages/kit/src/runtime/server/page/load_data.js b/packages/kit/src/runtime/server/page/load_data.js index d70276550469..dbe4e7c2ef17 100644 --- a/packages/kit/src/runtime/server/page/load_data.js +++ b/packages/kit/src/runtime/server/page/load_data.js @@ -1,9 +1,10 @@ import { DEV } from 'esm-env'; +import * as devalue from 'devalue'; import { disable_search, make_trackable } from '../../../utils/url.js'; import { validate_depends, validate_load_response } from '../../shared.js'; import { with_request_store, merge_tracing } from '@sveltejs/kit/internal/server'; import { record_span } from '../../telemetry/record_span.js'; -import { get_node_type } from '../utils.js'; +import { clarify_devalue_error, get_node_type } from '../utils.js'; import { base64_encode, text_decoder } from '../../utils.js'; /** @@ -232,11 +233,38 @@ export async function load_data({ }, fn: async (current) => { const traced_event = merge_tracing(event, current); - return await with_request_store({ event: traced_event, state: event_state }, () => - load.call(null, { + return await with_request_store({ event: traced_event, state: event_state }, () => { + /** @type {Record | null} */ + let data = null; + + return load.call(null, { url: event.url, params: event.params, - data: server_data_node?.data ?? null, + get data() { + if (data === null && server_data_node?.data != null) { + /** @type {Record any>} */ + const reducers = {}; + + /** @type {Record any>} */ + const revivers = {}; + + for (const key in event_state.transport) { + reducers[key] = event_state.transport[key].encode; + revivers[key] = event_state.transport[key].decode; + } + + // run it through devalue so that the developer can't accidentally mutate it + try { + data = devalue.parse(devalue.stringify(server_data_node.data, reducers), revivers); + } catch (e) { + // @ts-expect-error + e.path = e.path.slice(1); + throw new Error(clarify_devalue_error(event, /** @type {any} */ (e))); + } + } + + return data; + }, route: event.route, fetch: create_universal_fetch(event, state, fetched, csr, resolve_opts), setHeaders: event.setHeaders, @@ -244,8 +272,8 @@ export async function load_data({ parent, untrack: (fn) => fn(), tracing: traced_event.tracing - }) - ); + }); + }); } }); From 5aab6bf434ff08ee57c86aa3f80cee3d455c21df Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Tue, 19 Aug 2025 13:52:40 -0400 Subject: [PATCH 3/3] ugh --- .../kit/test/apps/basics/src/routes/load/serialization/+page.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/kit/test/apps/basics/src/routes/load/serialization/+page.js b/packages/kit/test/apps/basics/src/routes/load/serialization/+page.js index ba92f18d1f94..0cf6e8feaa3d 100644 --- a/packages/kit/test/apps/basics/src/routes/load/serialization/+page.js +++ b/packages/kit/test/apps/basics/src/routes/load/serialization/+page.js @@ -7,7 +7,9 @@ export async function load({ fetch, data, url }) { // check that this doesn't mutate the original object // and make the server data unserializable + // @ts-expect-error data.sum = () => a + b; + // @ts-expect-error return { a, b, c: data.sum() }; }