You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
* feat: add `getRequestEvent` to `$app/server`
* reduce indentation
* innocuous change to try and trigger a docs preview
* regenerate
* more detailed error message
* tighten up
* innocuous change to try and trigger a docs preview
* innocuous change to try and trigger a docs preview
* innocuous change to try and trigger a docs preview
* Update packages/kit/test/apps/basics/src/routes/get-request-event/endpoint/+server.js
Co-authored-by: Simon H <[email protected]>
* add since tag
* add some docs
---------
Co-authored-by: Simon H <[email protected]>
Copy file name to clipboardExpand all lines: documentation/docs/20-core-concepts/20-load.md
+68Lines changed: 68 additions & 0 deletions
Original file line number
Diff line number
Diff line change
@@ -713,6 +713,74 @@ To prevent data waterfalls and preserve layout `load` caches:
713
713
714
714
Putting an auth guard in `+layout.server.js` requires all child pages to call `await parent()` before protected code. Unless every child page depends on returned data from `await parent()`, the other options will be more performant.
715
715
716
+
## Using `getRequestEvent`
717
+
718
+
When running server `load` functions, the `event` object passed to the function as an argument can also be retrieved with [`getRequestEvent`]($app-server#getRequestEvent). This allows shared logic (such as authentication guards) to access information about the current request without it needing to be passed around.
719
+
720
+
For example, you might have a function that requires users to be logged in, and redirects them to `/login` if not:
721
+
722
+
```js
723
+
/// file: src/lib/server/auth.js
724
+
// @filename: ambient.d.ts
725
+
interface User {
726
+
name: string;
727
+
}
728
+
729
+
declare namespace App {
730
+
interface Locals {
731
+
user?: User;
732
+
}
733
+
}
734
+
735
+
// @filename: index.ts
736
+
// ---cut---
737
+
import { redirect } from'@sveltejs/kit';
738
+
import { getRequestEvent } from'$app/server';
739
+
740
+
exportfunctionrequireLogin() {
741
+
const { locals, url } =getRequestEvent();
742
+
743
+
// assume `locals.user` is populated in `handle`
744
+
if (!locals.user) {
745
+
constredirectTo=url.pathname+url.search;
746
+
constparams=newURLSearchParams({ redirectTo });
747
+
748
+
redirect(307, `/login?${params}`);
749
+
}
750
+
751
+
returnlocals.user;
752
+
}
753
+
```
754
+
755
+
Now, you can call `requireLogin` in any `load` function (or [form action](form-actions), for example) to guarantee that the user is logged in:
756
+
757
+
```js
758
+
/// file: +page.server.js
759
+
// @filename: ambient.d.ts
760
+
761
+
declare module'$lib/server/auth' {
762
+
interface User {
763
+
name: string;
764
+
}
765
+
766
+
exportfunctionrequireLogin(): User;
767
+
}
768
+
769
+
// @filename: index.ts
770
+
// ---cut---
771
+
import { requireLogin } from'$lib/server/auth';
772
+
773
+
exportfunctionload() {
774
+
constuser=requireLogin();
775
+
776
+
// `user` is guaranteed to be a user object here, because otherwise
777
+
// `requireLogin` would throw a redirect and we wouldn't get here
// can't use AsyncLocalStorage, but can still call getRequestEvent synchronously.
14
+
// this isn't behind `supports` because it's basically just StackBlitz (i.e.
15
+
// in-browser usage) that doesn't support it AFAICT
16
+
}
17
+
18
+
/**
19
+
* Returns the current `RequestEvent`. Can be used inside `handle`, `load` and actions (and functions called by them).
20
+
*
21
+
* In environments without [`AsyncLocalStorage`](https://nodejs.org/api/async_context.html#class-asynclocalstorage), this must be called synchronously (i.e. not after an `await`).
22
+
* @since 2.20.0
23
+
*/
24
+
exportfunctiongetRequestEvent(){
25
+
constevent=request_event??als?.getStore();
26
+
27
+
if(!event){
28
+
letmessage=
29
+
'Can only read the current request event inside functions invoked during `handle`, such as server `load` functions, actions, and server endpoints.';
30
+
31
+
if(!als){
32
+
message+=
33
+
' In environments without `AsyncLocalStorage`, the event must be read synchronously, not after an `await`.';
`${node.server_id}: Calling \`event.fetch(...)\` in a promise handler after \`load(...)\` has returned will not cause the function to re-run when the dependency is invalidated`
// Note: server fetches are not added to uses.depends due to security concerns
73
-
returnevent.fetch(info,init);
74
-
},
75
-
/** @param {string[]} deps */
76
-
depends: (...deps)=>{
77
-
for(constdepofdeps){
78
-
const{ href }=newURL(dep,event.url);
76
+
if(DEV&&done&&!uses.dependencies.has(url.href)){
77
+
console.warn(
78
+
`${node.server_id}: Calling \`event.fetch(...)\` in a promise handler after \`load(...)\` has returned will not cause the function to re-run when the dependency is invalidated`
`${node.server_id}: Calling \`depends(...)\` in a promise handler after \`load(...)\` has returned will not cause the function to re-run when the dependency is invalidated`
`${node.server_id}: Calling \`depends(...)\` in a promise handler after \`load(...)\` has returned will not cause the function to re-run when the dependency is invalidated`
107
+
`${node.server_id}: Accessing \`params.${String(
108
+
key
109
+
)}\` in a promise handler after \`load(...)\` has returned will not cause the function to re-run when the param changes`
)}\` in a promise handler after \`load(...)\` has returned will not cause the function to re-run when the param changes`
122
+
`${node.server_id}: Calling \`parent(...)\` in a promise handler after \`load(...)\` has returned will not cause the function to re-run when parent data changes`
100
123
);
101
124
}
102
125
103
126
if(is_tracking){
104
-
uses.params.add(key);
127
+
uses.parent=true;
105
128
}
106
-
returntarget[/** @type {string} */(key)];
107
-
}
108
-
}),
109
-
parent: async()=>{
110
-
if(DEV&&done&&!uses.parent){
111
-
console.warn(
112
-
`${node.server_id}: Calling \`parent(...)\` in a promise handler after \`load(...)\` has returned will not cause the function to re-run when parent data changes`
113
-
);
114
-
}
129
+
returnparent();
130
+
},
131
+
route: newProxy(event.route,{
132
+
get: (target,key)=>{
133
+
if(DEV&&done&&typeofkey==='string'&&!uses.route){
134
+
console.warn(
135
+
`${node.server_id}: Accessing \`route.${String(
136
+
key
137
+
)}\` in a promise handler after \`load(...)\` has returned will not cause the function to re-run when the route changes`
138
+
);
139
+
}
115
140
116
-
if(is_tracking){
117
-
uses.parent=true;
118
-
}
119
-
returnparent();
120
-
},
121
-
route: newProxy(event.route,{
122
-
get: (target,key)=>{
123
-
if(DEV&&done&&typeofkey==='string'&&!uses.route){
124
-
console.warn(
125
-
`${node.server_id}: Accessing \`route.${String(
126
-
key
127
-
)}\` in a promise handler after \`load(...)\` has returned will not cause the function to re-run when the route changes`
0 commit comments