@@ -43,19 +43,23 @@ export type AuthorizationOption =
4343 resource : RbacResource | RbacResource [ ] ;
4444 } ;
4545
46- export type DashboardLoaderOptions < TParams , TSearchParams > = {
46+ // Plugin-side scope: whatever the route's `context` returns must include
47+ // these (or just be `{}` when the route doesn't scope by org/project).
48+ // rbac.authenticateSession reads them off the value to filter UserRole.
49+ type AuthScope = { organizationId ?: string ; projectId ?: string } ;
50+
51+ export type DashboardLoaderOptions < TParams , TSearchParams , TContext extends AuthScope > = {
4752 params ?: TParams ;
4853 searchParams ?: TSearchParams ;
49- // Optional: provides organizationId / projectId to rbac.authenticateSession
50- // when the route's ability check needs it. The default fallback
51- // ignores context; an installed plugin may use it to scope the
52- // returned ability.
54+ // Resolves any per-request data the handler + auth check both need
55+ // (typically org/project lookups from URL params). The returned object
56+ // is fed to `rbac.authenticateSession` as the auth scope AND passed
57+ // through to the handler in `args.context`, so the route does each
58+ // lookup once.
5359 context ?: (
5460 params : InferZod < TParams > ,
5561 request : Request
56- ) =>
57- | { organizationId ?: string ; projectId ?: string }
58- | Promise < { organizationId ?: string ; projectId ?: string } > ;
62+ ) => TContext | Promise < TContext > ;
5963 authorization ?: AuthorizationOption ;
6064 // Where to send unauthenticated requests. Defaults to /login with a
6165 // redirectTo back to the original path.
@@ -65,21 +69,25 @@ export type DashboardLoaderOptions<TParams, TSearchParams> = {
6569 unauthorizedRedirect ?: string ;
6670} ;
6771
68- export type DashboardLoaderHandlerArgs < TParams , TSearchParams > = {
72+ export type DashboardLoaderHandlerArgs < TParams , TSearchParams , TContext > = {
6973 params : InferZod < TParams > ;
7074 searchParams : InferZod < TSearchParams > ;
7175 user : SessionUser ;
7276 ability : RbacAbility ;
77+ context : TContext ;
7378 request : Request ;
7479} ;
7580
7681export function dashboardLoader <
7782 TParams extends AnyZodSchema | undefined = undefined ,
7883 TSearchParams extends AnyZodSchema | undefined = undefined ,
84+ TContext extends AuthScope = AuthScope ,
7985 TReturn extends Response = Response
8086> (
81- options : DashboardLoaderOptions < TParams , TSearchParams > ,
82- handler : ( args : DashboardLoaderHandlerArgs < TParams , TSearchParams > ) => Promise < TReturn >
87+ options : DashboardLoaderOptions < TParams , TSearchParams , TContext > ,
88+ handler : (
89+ args : DashboardLoaderHandlerArgs < TParams , TSearchParams , TContext >
90+ ) => Promise < TReturn >
8391) {
8492 return async function loader ( { request, params } : LoaderFunctionArgs ) : Promise < TReturn > {
8593 // Server-only — see comment at top. Node caches the module after the
@@ -93,30 +101,28 @@ export function dashboardLoader<
93101 searchParams : result . searchParams as InferZod < TSearchParams > ,
94102 user : result . user ,
95103 ability : result . ability ,
104+ context : result . context as TContext ,
96105 request,
97106 } ) ;
98107 } ;
99108}
100109
101- export type DashboardActionOptions < TParams , TSearchParams > = DashboardLoaderOptions <
102- TParams ,
103- TSearchParams
104- > ;
110+ export type DashboardActionOptions < TParams , TSearchParams , TContext extends AuthScope > =
111+ DashboardLoaderOptions < TParams , TSearchParams , TContext > ;
105112
106- export type DashboardActionHandlerArgs < TParams , TSearchParams > = DashboardLoaderHandlerArgs <
107- TParams ,
108- TSearchParams
109- > & {
110- request : Request ;
111- } ;
113+ export type DashboardActionHandlerArgs < TParams , TSearchParams , TContext > =
114+ DashboardLoaderHandlerArgs < TParams , TSearchParams , TContext > ;
112115
113116export function dashboardAction <
114117 TParams extends AnyZodSchema | undefined = undefined ,
115118 TSearchParams extends AnyZodSchema | undefined = undefined ,
119+ TContext extends AuthScope = AuthScope ,
116120 TReturn extends Response = Response
117121> (
118- options : DashboardActionOptions < TParams , TSearchParams > ,
119- handler : ( args : DashboardActionHandlerArgs < TParams , TSearchParams > ) => Promise < TReturn >
122+ options : DashboardActionOptions < TParams , TSearchParams , TContext > ,
123+ handler : (
124+ args : DashboardActionHandlerArgs < TParams , TSearchParams , TContext >
125+ ) => Promise < TReturn >
120126) {
121127 return async function action ( { request, params } : ActionFunctionArgs ) : Promise < TReturn > {
122128 const { authenticateAndAuthorize } = await import ( "./dashboardBuilder.server" ) ;
@@ -128,6 +134,7 @@ export function dashboardAction<
128134 searchParams : result . searchParams as InferZod < TSearchParams > ,
129135 user : result . user ,
130136 ability : result . ability ,
137+ context : result . context as TContext ,
131138 request,
132139 } ) ;
133140 } ;
0 commit comments