@@ -7,14 +7,15 @@ import type {
77 DataWithResponseInit ,
88 Session ,
99 UnauthorizedData ,
10+ UnwrapData ,
1011} from './interfaces.js' ;
1112import { getWorkOS } from './workos.js' ;
1213
1314import { sealData , unsealData } from 'iron-session' ;
1415import { createRemoteJWKSet , decodeJwt , jwtVerify } from 'jose' ;
1516import { getConfig } from './config.js' ;
1617import { configureSessionStorage , getSessionStorage } from './sessionStorage.js' ;
17- import { isJsonResponse , isRedirect , isResponse } from './utils.js' ;
18+ import { isDataWithResponseInit , isJsonResponse , isRedirect , isResponse } from './utils.js' ;
1819
1920// must be a type since this is a subtype of response
2021// interfaces must conform to the types they extend
@@ -168,11 +169,17 @@ type LoaderValue<Data> = Response | TypedResponse<Data> | NonNullable<Data> | nu
168169type LoaderReturnValue < Data > = Promise < LoaderValue < Data > > | LoaderValue < Data > ;
169170
170171type AuthLoader < Data > = (
171- args : LoaderFunctionArgs & { auth : AuthorizedData | UnauthorizedData ; getAccessToken : ( ) => string | null } ,
172+ args : LoaderFunctionArgs & {
173+ auth : AuthorizedData | UnauthorizedData ;
174+ getAccessToken : ( ) => string | null ;
175+ } ,
172176) => LoaderReturnValue < Data > ;
173177
174178type AuthorizedAuthLoader < Data > = (
175- args : LoaderFunctionArgs & { auth : AuthorizedData ; getAccessToken : ( ) => string } ,
179+ args : LoaderFunctionArgs & {
180+ auth : AuthorizedData ;
181+ getAccessToken : ( ) => string ;
182+ } ,
176183) => LoaderReturnValue < Data > ;
177184
178185/**
@@ -181,9 +188,6 @@ type AuthorizedAuthLoader<Data> = (
181188 *
182189 * Creates an authentication-aware loader function for React Router.
183190 *
184- * This loader handles authentication state, session management, and access token refreshing
185- * automatically, making it easier to build authenticated routes.
186- *
187191 * @overload
188192 * Basic usage with enforced authentication that redirects unauthenticated users to sign in.
189193 *
@@ -252,7 +256,7 @@ export async function authkitLoader<Data = unknown>(
252256 loaderArgs : LoaderFunctionArgs ,
253257 loader : AuthorizedAuthLoader < Data > ,
254258 options : AuthKitLoaderOptions & { ensureSignedIn : true } ,
255- ) : Promise < DataWithResponseInit < Data & AuthorizedData > > ;
259+ ) : Promise < DataWithResponseInit < UnwrapData < Data > & AuthorizedData > > ;
256260
257261/**
258262 * This loader handles authentication state, session management, and access token refreshing
@@ -287,7 +291,7 @@ export async function authkitLoader<Data = unknown>(
287291 loaderArgs : LoaderFunctionArgs ,
288292 loader : AuthLoader < Data > ,
289293 options ?: AuthKitLoaderOptions ,
290- ) : Promise < DataWithResponseInit < Data & ( AuthorizedData | UnauthorizedData ) > > ;
294+ ) : Promise < DataWithResponseInit < UnwrapData < Data > & ( AuthorizedData | UnauthorizedData ) > > ;
291295
292296export async function authkitLoader < Data = unknown > (
293297 loaderArgs : LoaderFunctionArgs ,
@@ -305,7 +309,10 @@ export async function authkitLoader<Data = unknown>(
305309 } = typeof loaderOrOptions === 'object' ? loaderOrOptions : options ;
306310
307311 const cookieName = cookie ?. name ?? getConfig ( 'cookieName' ) ;
308- const { getSession, destroySession } = await configureSessionStorage ( { storage, cookieName } ) ;
312+ const { getSession, destroySession } = await configureSessionStorage ( {
313+ storage,
314+ cookieName,
315+ } ) ;
309316
310317 const { request } = loaderArgs ;
311318
@@ -443,7 +450,11 @@ async function handleAuthLoader(
443450 } else {
444451 // Unauthorized case
445452 const getAccessToken = ( ) => null ;
446- loaderResult = await ( loader as AuthLoader < unknown > ) ( { ...args , auth, getAccessToken } ) ;
453+ loaderResult = await ( loader as AuthLoader < unknown > ) ( {
454+ ...args ,
455+ auth,
456+ getAccessToken,
457+ } ) ;
447458 }
448459
449460 if ( isResponse ( loaderResult ) ) {
@@ -467,9 +478,20 @@ async function handleAuthLoader(
467478 return data ( { ...responseData , ...auth } , newResponse ) ;
468479 }
469480
470- // If the loader returns a non-Response, assume it's a data object
471- // istanbul ignore next
472- return data ( { ...loaderResult , ...auth } , session ? { headers : { ...session . headers } } : undefined ) ;
481+ const actualData = isDataWithResponseInit ( loaderResult ) ? loaderResult . data : loaderResult ;
482+
483+ const mergedHeaders = isDataWithResponseInit ( loaderResult ) ? new Headers ( loaderResult . init ?. headers ) : new Headers ( ) ;
484+
485+ if ( session ?. headers ) {
486+ Object . entries ( session . headers ) . forEach ( ( [ key , value ] ) => {
487+ mergedHeaders . set ( key , value ) ;
488+ } ) ;
489+ }
490+
491+ const mergedData = actualData && typeof actualData === 'object' ? { ...actualData , ...auth } : { ...auth } ;
492+
493+ // Always pass headers (empty headers object is valid)
494+ return data ( mergedData , { headers : mergedHeaders } ) ;
473495}
474496
475497export async function terminateSession ( request : Request , { returnTo } : { returnTo ?: string } = { } ) {
0 commit comments