diff --git a/.changeset/weak-rings-open.md b/.changeset/weak-rings-open.md new file mode 100644 index 000000000000..ea0c75871037 --- /dev/null +++ b/.changeset/weak-rings-open.md @@ -0,0 +1,5 @@ +--- +'@sveltejs/kit': patch +--- + +fix: allow `fetch` in remote function without emitting a warning diff --git a/packages/kit/src/runtime/app/server/remote/shared.js b/packages/kit/src/runtime/app/server/remote/shared.js index eb32437bbf52..c078d290db6f 100644 --- a/packages/kit/src/runtime/app/server/remote/shared.js +++ b/packages/kit/src/runtime/app/server/remote/shared.js @@ -1,5 +1,5 @@ /** @import { RequestEvent } from '@sveltejs/kit' */ -/** @import { ServerHooks, MaybePromise, RequestState, RemoteInfo } from 'types' */ +/** @import { ServerHooks, MaybePromise, RequestState, RemoteInfo, RequestStore } from 'types' */ import { parse } from 'devalue'; import { error } from '@sveltejs/kit'; import { with_request_store, get_request_store } from '@sveltejs/kit/internal/server'; @@ -103,42 +103,48 @@ export function parse_remote_response(data, transport) { * @param {(arg?: any) => T} fn */ export async function run_remote_function(event, state, allow_cookies, arg, validate, fn) { - /** @type {RequestEvent} */ - const cleansed = { - ...event, - setHeaders: () => { - throw new Error('setHeaders is not allowed in remote functions'); - }, - cookies: { - ...event.cookies, - set: (name, value, opts) => { - if (!allow_cookies) { - throw new Error('Cannot set cookies in `query` or `prerender` functions'); - } - - if (opts.path && !opts.path.startsWith('/')) { - throw new Error('Cookies set in remote functions must have an absolute path'); - } - - return event.cookies.set(name, value, opts); + /** @type {RequestStore} */ + const store = { + event: { + ...event, + setHeaders: () => { + throw new Error('setHeaders is not allowed in remote functions'); }, - delete: (name, opts) => { - if (!allow_cookies) { - throw new Error('Cannot delete cookies in `query` or `prerender` functions'); + cookies: { + ...event.cookies, + set: (name, value, opts) => { + if (!allow_cookies) { + throw new Error('Cannot set cookies in `query` or `prerender` functions'); + } + + if (opts.path && !opts.path.startsWith('/')) { + throw new Error('Cookies set in remote functions must have an absolute path'); + } + + return event.cookies.set(name, value, opts); + }, + delete: (name, opts) => { + if (!allow_cookies) { + throw new Error('Cannot delete cookies in `query` or `prerender` functions'); + } + + if (opts.path && !opts.path.startsWith('/')) { + throw new Error('Cookies deleted in remote functions must have an absolute path'); + } + + return event.cookies.delete(name, opts); } - - if (opts.path && !opts.path.startsWith('/')) { - throw new Error('Cookies deleted in remote functions must have an absolute path'); - } - - return event.cookies.delete(name, opts); } + }, + state: { + ...state, + is_in_remote_function: true } }; // In two parts, each with_event, so that runtimes without async local storage can still get the event at the start of the function - const validated = await with_request_store({ event: cleansed, state }, () => validate(arg)); - return with_request_store({ event: cleansed, state }, () => fn(validated)); + const validated = await with_request_store(store, () => validate(arg)); + return with_request_store(store, () => fn(validated)); } /** diff --git a/packages/kit/src/runtime/server/page/render.js b/packages/kit/src/runtime/server/page/render.js index ff3ce32d5d4d..3793fbae39a5 100644 --- a/packages/kit/src/runtime/server/page/render.js +++ b/packages/kit/src/runtime/server/page/render.js @@ -13,7 +13,7 @@ import { SVELTE_KIT_ASSETS } from '../../../constants.js'; import { SCHEME } from '../../../utils/url.js'; import { create_server_routing_response, generate_route_object } from './server_routing.js'; import { add_resolution_suffix } from '../../pathname.js'; -import { with_request_store } from '@sveltejs/kit/internal/server'; +import { try_get_request_store, with_request_store } from '@sveltejs/kit/internal/server'; import { text_encoder } from '../../utils.js'; import { get_global_name } from '../utils.js'; import { create_remote_cache_key } from '../../shared.js'; @@ -190,7 +190,7 @@ export async function render_response({ throw new Error( `Cannot call \`fetch\` eagerly during server-side rendering with relative URL (${info}) — put your \`fetch\` calls inside \`onMount\` or a \`load\` function instead` ); - } else if (!warned) { + } else if (!warned && !try_get_request_store()?.state.is_in_remote_function) { console.warn( 'Avoid calling `fetch` eagerly during server-side rendering — put your `fetch` calls inside `onMount` or a `load` function instead' ); diff --git a/packages/kit/src/runtime/server/respond.js b/packages/kit/src/runtime/server/respond.js index 3edc91734380..9067418bc450 100644 --- a/packages/kit/src/runtime/server/respond.js +++ b/packages/kit/src/runtime/server/respond.js @@ -148,7 +148,8 @@ export async function internal_respond(request, options, manifest, state) { handleValidationError: options.hooks.handleValidationError, tracing: { record_span - } + }, + is_in_remote_function: false }; /** @type {import('@sveltejs/kit').RequestEvent} */ diff --git a/packages/kit/src/types/internal.d.ts b/packages/kit/src/types/internal.d.ts index 367d9ceda6ff..a043b0ceaa05 100644 --- a/packages/kit/src/types/internal.d.ts +++ b/packages/kit/src/types/internal.d.ts @@ -604,6 +604,7 @@ export interface RequestState { tracing: { record_span: RecordSpan; }; + is_in_remote_function: boolean; form_instances?: Map; remote_data?: Map>>; refreshes?: Record>;