Add request-scoped context for session.getUser()
Use AsyncLocalStorage to provide request context so services can access the current user without needing Call passed through every function. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -6,6 +6,7 @@ import { match } from "path-to-regexp";
|
||||
import { Session } from "./auth";
|
||||
import { cli } from "./cli";
|
||||
import { contentTypes } from "./content-types";
|
||||
import { runWithContext } from "./context";
|
||||
import { httpCodes } from "./http-codes";
|
||||
import { routes } from "./routes";
|
||||
import { services } from "./services";
|
||||
@@ -75,7 +76,10 @@ routes.forEach((route: Route, _idx: number, _allRoutes: Route[]) => {
|
||||
};
|
||||
|
||||
try {
|
||||
const retval = await route.handler(req);
|
||||
const retval = await runWithContext(
|
||||
{ user: auth.user },
|
||||
() => route.handler(req),
|
||||
);
|
||||
return retval;
|
||||
} catch (error) {
|
||||
// Handle authentication errors
|
||||
|
||||
27
express/context.ts
Normal file
27
express/context.ts
Normal file
@@ -0,0 +1,27 @@
|
||||
// context.ts
|
||||
//
|
||||
// Request-scoped context using AsyncLocalStorage.
|
||||
// Allows services to access request data (like the current user) without
|
||||
// needing to pass Call through every function.
|
||||
|
||||
import { AsyncLocalStorage } from "node:async_hooks";
|
||||
import { AnonymousUser, type MaybeUser } from "./user";
|
||||
|
||||
type RequestContext = {
|
||||
user: MaybeUser;
|
||||
};
|
||||
|
||||
const asyncLocalStorage = new AsyncLocalStorage<RequestContext>();
|
||||
|
||||
// Run a function within a request context
|
||||
function runWithContext<T>(context: RequestContext, fn: () => T): T {
|
||||
return asyncLocalStorage.run(context, fn);
|
||||
}
|
||||
|
||||
// Get the current user from context, or AnonymousUser if not in a request
|
||||
function getCurrentUser(): MaybeUser {
|
||||
const context = asyncLocalStorage.getStore();
|
||||
return context?.user ?? AnonymousUser;
|
||||
}
|
||||
|
||||
export { getCurrentUser, runWithContext, type RequestContext };
|
||||
@@ -1,9 +1,10 @@
|
||||
// services.ts
|
||||
|
||||
import { AuthService } from "../auth";
|
||||
import { getCurrentUser } from "../context";
|
||||
import { db, migrate, migrationStatus, PostgresAuthStore } from "../database";
|
||||
import { getLogs, log } from "../logging";
|
||||
import { anonymousUser, type User } from "../user";
|
||||
import type { MaybeUser } from "../user";
|
||||
|
||||
const database = {
|
||||
db,
|
||||
@@ -29,8 +30,8 @@ const misc = {
|
||||
};
|
||||
|
||||
const session = {
|
||||
getUser: (): User => {
|
||||
return anonymousUser;
|
||||
getUser: (): MaybeUser => {
|
||||
return getCurrentUser();
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user