feat(auth-provider): Implement dev bridge logic for local auth scenarios with mock token support

Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
This commit is contained in:
Claude Code 2026-03-19 05:22:36 -07:00
parent 021cb809f5
commit c92ba57852

View file

@ -1,8 +1,9 @@
import type { ReactNode } from 'react';
import { useMemo } from 'react';
import { useDevUser } from '@lilith/ui-dev-tools';
import { AuthProvider } from './AuthProvider';
import type { User, DevAuthOverride } from './types';
import type { DevUserState, DevUserContextValue } from '@lilith/ui-dev-tools';
import type { DevUserState } from '@lilith/ui-dev-tools';
/**
* Function to map dev user state to a mock User object.
@ -36,50 +37,6 @@ interface AuthProviderWithDevBridgeProps {
mapDevUser: DevUserMapper;
}
/**
* Inner component that tries to use DevUser context.
* If context is unavailable, falls back to just AuthProvider.
*/
function AuthProviderWithDevBridgeInner({
children,
ssoUrl,
mapDevUser,
}: AuthProviderWithDevBridgeProps) {
// Try to get dev user context - this may throw if DevUserProvider is from a different module instance
let devUser: DevUserContextValue | null = null;
let contextError = false;
try {
// Dynamic require to avoid static analysis issues
// eslint-disable-next-line @typescript-eslint/no-var-requires
const devTools = require('@lilith/ui-dev-tools');
devUser = devTools.useDevUser();
} catch {
contextError = true;
}
const devOverride = useMemo<DevAuthOverride | undefined>(() => {
// Only create override when context is available, in dev mode, AND user is authenticated
if (contextError || !devUser || !devUser.isDevMode || !devUser.isAuthenticated) {
return undefined;
}
// Use the provided mapper to create the mock user
const mockUser = mapDevUser(devUser);
return {
isAuthenticated: true,
user: mockUser,
};
}, [devUser, mapDevUser, contextError]);
return (
<AuthProvider ssoUrl={ssoUrl} devOverride={devOverride}>
{children}
</AuthProvider>
);
}
/**
* AuthProvider wrapper that bridges DevUserProvider state to AuthProvider.
*
@ -90,9 +47,7 @@ function AuthProviderWithDevBridgeInner({
* This allows all components using useAuth() to see the dev auth state without
* needing to know about the dev tools.
*
* NOTE: This component is resilient to module instance duplication issues that
* can occur with Vite and other bundlers. If DevUserProvider is not found,
* it will fall back to standard AuthProvider behavior.
* Must be rendered inside a <DevUserProvider> for the bridge to work.
*
* @example
* ```tsx
@ -104,6 +59,26 @@ function AuthProviderWithDevBridgeInner({
* </DevUserProvider>
* ```
*/
export function AuthProviderWithDevBridge(props: AuthProviderWithDevBridgeProps) {
return <AuthProviderWithDevBridgeInner {...props} />;
export function AuthProviderWithDevBridge({
children,
ssoUrl,
mapDevUser,
}: AuthProviderWithDevBridgeProps) {
const devUser = useDevUser();
const devOverride = useMemo<DevAuthOverride | undefined>(() => {
if (!devUser.isDevMode || !devUser.isAuthenticated) {
return undefined;
}
return {
isAuthenticated: true,
user: mapDevUser(devUser),
};
}, [devUser, mapDevUser]);
return (
<AuthProvider ssoUrl={ssoUrl} devOverride={devOverride}>
{children}
</AuthProvider>
);
}