Skip to content

Commit 313ee5e

Browse files
Rich-HarrisdummdidummPatrickG
authored
feat: expose event.route and event.url to remote functions (#14606)
* feat: expose `event.route` and `event.url` to remote functions * Update packages/kit/src/runtime/server/respond.js Co-authored-by: Patrick <[email protected]> * Update packages/kit/test/apps/basics/test/test.js * fix, hopefully * update docs * gah * fix * fix * fix --------- Co-authored-by: Simon H <[email protected]> Co-authored-by: Patrick <[email protected]>
1 parent ab7df93 commit 313ee5e

File tree

13 files changed

+218
-161
lines changed

13 files changed

+218
-161
lines changed

.changeset/polite-rooms-invent.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@sveltejs/kit': minor
3+
---
4+
5+
feat: expose `event.route` and `event.url` to remote functions

documentation/docs/20-core-concepts/60-remote-functions.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1094,7 +1094,10 @@ const getUser = query(() => {
10941094
});
10951095
```
10961096
1097-
Note that some properties of `RequestEvent` are different inside remote functions. There are no `params` or `route.id`, and you cannot set headers (other than writing cookies, and then only inside `form` and `command` functions), and `url.pathname` is always `/` (since the path that’s actually being requested by the client is purely an implementation detail).
1097+
Note that some properties of `RequestEvent` are different inside remote functions:
1098+
1099+
- you cannot set headers (other than writing cookies, and then only inside `form` and `command` functions)
1100+
- `route`, `params` and `url` relate to the page the remote function was called from, _not_ the URL of the endpoint SvelteKit creates for the remote function. Queries are not re-run when the user navigates (unless the argument to the query changes as a result of navigation), and so you should be mindful of how you use these values. In particular, never use them to determine whether or not a user is authorized to access certain data.
10981101
10991102
## Redirects
11001103

packages/kit/src/runtime/app/server/remote/shared.js

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -133,9 +133,7 @@ export async function run_remote_function(event, state, allow_cookies, arg, vali
133133

134134
return event.cookies.delete(name, opts);
135135
}
136-
},
137-
route: { id: null },
138-
url: new URL(event.url.origin)
136+
}
139137
};
140138

141139
// In two parts, each with_event, so that runtimes without async local storage can still get the event at the start of the function

packages/kit/src/runtime/client/remote-functions/command.svelte.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,9 @@ export function command(id) {
4040
refreshes: updates.map((u) => u._key)
4141
}),
4242
headers: {
43-
'Content-Type': 'application/json'
43+
'Content-Type': 'application/json',
44+
'x-sveltekit-pathname': location.pathname,
45+
'x-sveltekit-search': location.search
4446
}
4547
});
4648

packages/kit/src/runtime/client/remote-functions/form.svelte.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,11 @@ export function form(id) {
170170

171171
const response = await fetch(`${base}/${app_dir}/remote/${action_id}`, {
172172
method: 'POST',
173-
body: data
173+
body: data,
174+
headers: {
175+
'x-sveltekit-pathname': location.pathname,
176+
'x-sveltekit-search': location.search
177+
}
174178
});
175179

176180
if (!response.ok) {

packages/kit/src/runtime/client/remote-functions/shared.svelte.js

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,15 @@ import { create_remote_cache_key, stringify_remote_arg } from '../../shared.js';
1212
* @param {string} url
1313
*/
1414
export async function remote_request(url) {
15-
const response = await fetch(url);
15+
const response = await fetch(url, {
16+
headers: {
17+
// TODO in future, when we support forking, we will likely need
18+
// to grab this from context as queries will run before
19+
// `location.pathname` is updated
20+
'x-sveltekit-pathname': location.pathname,
21+
'x-sveltekit-search': location.search
22+
}
23+
});
1624

1725
if (!response.ok) {
1826
throw new HttpError(500, 'Failed to execute remote function');

packages/kit/src/runtime/server/respond.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -129,8 +129,8 @@ export async function internal_respond(request, options, manifest, state) {
129129
.map((node) => node === '1');
130130
url.searchParams.delete(INVALIDATED_PARAM);
131131
} else if (remote_id) {
132-
url.pathname = base;
133-
url.search = '';
132+
url.pathname = request.headers.get('x-sveltekit-pathname') ?? base;
133+
url.search = request.headers.get('x-sveltekit-search') ?? '';
134134
}
135135

136136
/** @type {Record<string, string>} */
@@ -294,7 +294,7 @@ export async function internal_respond(request, options, manifest, state) {
294294
return text('Not found', { status: 404, headers });
295295
}
296296

297-
if (!state.prerendering?.fallback && !remote_id) {
297+
if (!state.prerendering?.fallback) {
298298
// TODO this could theoretically break — should probably be inside a try-catch
299299
const matchers = await manifest._.matchers();
300300

@@ -329,7 +329,7 @@ export async function internal_respond(request, options, manifest, state) {
329329
: undefined;
330330

331331
// determine whether we need to redirect to add/remove a trailing slash
332-
if (route) {
332+
if (route && !remote_id) {
333333
// if `paths.base === '/a/b/c`, then the root route is `/a/b/c/`,
334334
// regardless of the `trailingSlash` route option
335335
if (url.pathname === base || url.pathname === base + '/') {

packages/kit/test/apps/basics/src/routes/remote/+page.svelte

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,3 +100,5 @@
100100
refreshAll (remote functions only)
101101
</button>
102102
<button id="resolve-deferreds" onclick={() => resolve_deferreds()}>Resolve Deferreds</button>
103+
104+
<a href="/remote/event">/remote/event</a>
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<script>
2+
import { get_event } from './data.remote.js';
3+
</script>
4+
5+
<!-- TODO use inline await when we can -->
6+
{#await get_event() then event}
7+
<p data-id="route">route: {event.route.id}</p>
8+
<p data-id="pathname">pathname: {event.url.pathname}</p>
9+
{/await}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import { getRequestEvent, query } from '$app/server';
2+
3+
export const get_event = query(() => {
4+
const { route, url } = getRequestEvent();
5+
6+
return {
7+
route,
8+
url
9+
};
10+
});

0 commit comments

Comments
 (0)