Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/weak-rings-open.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@sveltejs/kit': patch
---

fix: allow `fetch` in remote function without emitting a warning
66 changes: 36 additions & 30 deletions packages/kit/src/runtime/app/server/remote/shared.js
Original file line number Diff line number Diff line change
@@ -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';
Expand Down Expand Up @@ -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));
}

/**
Expand Down
4 changes: 2 additions & 2 deletions packages/kit/src/runtime/server/page/render.js
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -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'
);
Expand Down
3 changes: 2 additions & 1 deletion packages/kit/src/runtime/server/respond.js
Original file line number Diff line number Diff line change
Expand Up @@ -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} */
Expand Down
1 change: 1 addition & 0 deletions packages/kit/src/types/internal.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -604,6 +604,7 @@ export interface RequestState {
tracing: {
record_span: RecordSpan;
};
is_in_remote_function: boolean;
form_instances?: Map<any, any>;
remote_data?: Map<RemoteInfo, Record<string, MaybePromise<any>>>;
refreshes?: Record<string, Promise<any>>;
Expand Down
Loading