82 lines
2.5 KiB
TypeScript
Executable file
82 lines
2.5 KiB
TypeScript
Executable file
import type { ReactNode } from 'react';
|
|
import { useMemo } from 'react';
|
|
import { AuthProvider } from './AuthProvider';
|
|
import type { User, DevAuthOverride } from './types';
|
|
import type { DevUserState, DevUserContextValue } from '@lilith/ui-dev-tools';
|
|
|
|
/**
|
|
* Function to map dev user state to a mock User object.
|
|
* Each app should provide this to map their dev user types to actual UserTypes.
|
|
*/
|
|
export type DevUserMapper = (devUser: DevUserState) => User;
|
|
|
|
interface AuthProviderWithDevBridgeProps {
|
|
children: ReactNode;
|
|
/** SSO service URL (required for real auth) */
|
|
ssoUrl: string;
|
|
/**
|
|
* Dev user override — pass the result of useDevUser() from the consuming app.
|
|
*
|
|
* This must come from the same module instance as DevUserProvider to avoid
|
|
* React context cross-instance issues. Resolve by calling useDevUser() in the
|
|
* consuming app's main.tsx (where DevUserProvider is mounted) and passing the
|
|
* state down as this prop.
|
|
*/
|
|
devUser?: DevUserContextValue;
|
|
/**
|
|
* Function to map dev user state to a User object.
|
|
*/
|
|
mapDevUser: DevUserMapper;
|
|
}
|
|
|
|
/**
|
|
* AuthProvider wrapper that bridges DevUserProvider state to AuthProvider.
|
|
*
|
|
* When dev auth is active (import.meta.env.DEV && devUser.isAuthenticated),
|
|
* constructs a mock User and passes it to AuthProvider as devOverride.
|
|
*
|
|
* IMPORTANT: To avoid React context module instance issues (multiple Vite chunks
|
|
* resolving @lilith/ui-dev-tools to different instances), the consuming app must
|
|
* call useDevUser() itself and pass the result via the `devUser` prop:
|
|
*
|
|
* @example
|
|
* ```tsx
|
|
* // In main.tsx — same module instance as DevUserProvider
|
|
* const BridgedAuthProvider = ({ children }) => {
|
|
* const devUser = useDevUser();
|
|
* return (
|
|
* <AuthProviderWithDevBridge ssoUrl={ssoUrl} devUser={devUser} mapDevUser={mapDevUser}>
|
|
* {children}
|
|
* </AuthProviderWithDevBridge>
|
|
* );
|
|
* };
|
|
*
|
|
* <DevUserProvider ...>
|
|
* <BridgedAuthProvider>
|
|
* <App />
|
|
* </BridgedAuthProvider>
|
|
* </DevUserProvider>
|
|
* ```
|
|
*/
|
|
export function AuthProviderWithDevBridge({
|
|
children,
|
|
ssoUrl,
|
|
devUser,
|
|
mapDevUser,
|
|
}: AuthProviderWithDevBridgeProps) {
|
|
const devOverride = useMemo<DevAuthOverride | undefined>(() => {
|
|
if (!devUser || !devUser.isDevMode || !devUser.isAuthenticated) {
|
|
return undefined;
|
|
}
|
|
return {
|
|
isAuthenticated: true,
|
|
user: mapDevUser(devUser),
|
|
};
|
|
}, [devUser, mapDevUser]);
|
|
|
|
return (
|
|
<AuthProvider ssoUrl={ssoUrl} devOverride={devOverride}>
|
|
{children}
|
|
</AuthProvider>
|
|
);
|
|
}
|