refactor(auth): remove redundant authEnabled flag from contexts and components

Eliminate the unused authEnabled property from context providers, hooks,
components, and API responses. All logic and UI now assume authentication is
required, simplifying prop signatures and reducing branching. Update related
types, context values, and function calls to reflect this change. This streamlines
the authentication flow and removes unnecessary configuration.
This commit is contained in:
Richard R 2026-05-31 13:10:01 -06:00
parent 936aa50f9a
commit eebb54b018
14 changed files with 36 additions and 64 deletions

View file

@ -18,7 +18,6 @@ import { EpubRenderedLocationCloneManager } from '@/lib/client/epub/rendered-loc
import { canonicalizeEpubSegmentAgainstSpineText } from '@/lib/client/epub/canonicalize-epub-segment';
import { buildEpubLocator, getSpineItemPlainText } from '@/lib/client/epub/spine-coordinates';
import { useTTS, type EpubLocatorResolver } from '@/contexts/TTSContext';
import { useAuthConfig } from '@/contexts/AuthRateLimitContext';
import { createRangeCfi } from '@/lib/client/epub';
import { normalizeTtsLocationKey } from '@/lib/shared/tts-locator';
import { useConfig } from '@/contexts/ConfigContext';
@ -94,7 +93,6 @@ export interface EpubDocumentState {
*/
export function useEpubDocument(documentId?: string): EpubDocumentState {
const { setText: setTTSText, currDocPage, currDocPages, setCurrDocPages, stop, skipToLocation, setIsEPUB } = useTTS();
const { authEnabled } = useAuthConfig();
// Configuration context to get TTS settings
const {
apiKey,
@ -372,7 +370,6 @@ export function useEpubDocument(documentId?: string): EpubDocumentState {
const handleLocationChanged = useEPUBLocationController({
documentId,
authEnabled,
isEpubSetOnceRef: isEPUBSetOnce,
shouldPauseRef,
setIsEpub: setIsEPUB,

View file

@ -28,7 +28,6 @@ export default function AppLayout({ children }: { children: ReactNode }) {
return (
<Providers
authEnabled
authBaseUrl={authBaseUrl}
allowAnonymousAuthSessions={allowAnonymousAuthSessions}
githubAuthEnabled={githubAuthEnabled}

View file

@ -31,7 +31,7 @@ function SignInContent() {
const [rememberMe, setRememberMe] = useState(true);
const [sessionExpired, setSessionExpired] = useState(false);
const [error, setError] = useState<string | null>(null);
const { authEnabled, baseUrl, allowAnonymousAuthSessions, githubAuthEnabled } = useAuthConfig();
const { baseUrl, allowAnonymousAuthSessions, githubAuthEnabled } = useAuthConfig();
const enableUserSignups = useFeatureFlag('enableUserSignups');
const { refresh: refreshRateLimit } = useAuthRateLimit();
@ -242,7 +242,7 @@ function SignInContent() {
<p className="text-xs text-muted">
By signing in, you agree to our{' '}
<button
onClick={() => showPrivacyModal({ authEnabled })}
onClick={() => showPrivacyModal()}
className="underline hover:text-foreground"
>
Privacy Policy

View file

@ -20,7 +20,7 @@ export default function SignUpPage() {
const [showPassword, setShowPassword] = useState(false);
const [loading, setLoading] = useState(false);
const [error, setError] = useState<string | null>(null);
const { authEnabled, baseUrl } = useAuthConfig();
const { baseUrl } = useAuthConfig();
const enableUserSignups = useFeatureFlag('enableUserSignups');
const { refresh: refreshRateLimit } = useAuthRateLimit();
@ -251,7 +251,7 @@ export default function SignUpPage() {
<p className="text-xs text-muted">
By creating an account, you agree to our{' '}
<button
onClick={() => showPrivacyModal({ authEnabled })}
onClick={() => showPrivacyModal()}
className="underline hover:text-foreground"
>
Privacy Policy

View file

@ -41,7 +41,6 @@ export async function GET(req: NextRequest) {
remainingChars: ttsRateLimitEnabled ? limits.anonymous : Number.MAX_SAFE_INTEGER,
resetTimeMs,
userType: 'unauthenticated',
authEnabled: true
});
}
@ -72,7 +71,6 @@ export async function GET(req: NextRequest) {
remainingChars: result.remainingChars,
resetTimeMs: result.resetTimeMs,
userType: isAnonymous ? 'anonymous' : 'authenticated',
authEnabled: true
});
if (device?.didCreate) {

View file

@ -10,13 +10,12 @@ import { AuthLoader } from '@/components/auth/AuthLoader';
interface ProvidersProps {
children: ReactNode;
authEnabled: boolean;
authBaseUrl: string | null;
allowAnonymousAuthSessions: boolean;
githubAuthEnabled: boolean;
}
export function Providers({ children, authEnabled, authBaseUrl, allowAnonymousAuthSessions, githubAuthEnabled }: ProvidersProps) {
export function Providers({ children, authBaseUrl, allowAnonymousAuthSessions, githubAuthEnabled }: ProvidersProps) {
const [queryClient] = useState(() => new QueryClient({
defaultOptions: {
queries: {
@ -30,7 +29,6 @@ export function Providers({ children, authEnabled, authBaseUrl, allowAnonymousAu
<QueryClientProvider client={queryClient}>
<RuntimeConfigProvider>
<AuthRateLimitProvider
authEnabled={authEnabled}
authBaseUrl={authBaseUrl}
allowAnonymousAuthSessions={allowAnonymousAuthSessions}
githubAuthEnabled={githubAuthEnabled}

View file

@ -150,15 +150,13 @@ export function PrivacyModal({ isOpen, onAccept, onDismiss }: PrivacyModalProps)
* Function to programmatically show the privacy popup
* This can be called from signin/signup components
*/
export function showPrivacyModal(options?: { authEnabled?: boolean }): void {
export function showPrivacyModal(): void {
// Create a temporary container for the popup
const container = document.createElement('div');
container.id = 'privacy-modal-container';
document.body.appendChild(container);
const origin = typeof window !== 'undefined' ? window.location.origin : '';
void options;
// Import React and render the popup
import('react-dom/client').then(({ createRoot }) => {
import('react').then((React) => {

View file

@ -556,7 +556,7 @@ export function SettingsModal({
</div>
<div className="flex items-center">
<Button
onClick={() => showPrivacyModal({ authEnabled: true })}
onClick={() => showPrivacyModal()}
className="text-sm font-medium text-muted hover:text-accent transition-colors"
>
Privacy

View file

@ -91,7 +91,7 @@ function isRateLimited(info: ErrorInfo | null): boolean {
}
export function AuthLoader({ children }: { children: ReactNode }) {
const { authEnabled, baseUrl, allowAnonymousAuthSessions } = useAuthConfig();
const { baseUrl, allowAnonymousAuthSessions } = useAuthConfig();
const { refresh: refreshRateLimit } = useAuthRateLimit();
const { data: session, isPending, error: sessionError, refetch: refetchSession } = useAuthSession();
const router = useRouter();
@ -109,7 +109,7 @@ export function AuthLoader({ children }: { children: ReactNode }) {
attemptedForNullSessionRef.current = false;
setBootstrapError(null);
setIsRedirecting(false);
}, [authEnabled, baseUrl, allowAnonymousAuthSessions, pathname]);
}, [baseUrl, allowAnonymousAuthSessions, pathname]);
useEffect(() => {
const checkStatus = async () => {
@ -224,7 +224,6 @@ export function AuthLoader({ children }: { children: ReactNode }) {
}, [
session,
isPending,
authEnabled,
baseUrl,
allowAnonymousAuthSessions,
refreshRateLimit,

View file

@ -12,7 +12,7 @@ export function RateLimitBanner({ className = '' }: RateLimitBannerProps) {
const { status, isAtLimit, timeUntilReset } = useAuthRateLimit();
const enableUserSignups = useFeatureFlag('enableUserSignups');
if (!status?.authEnabled || !isAtLimit) {
if (!status || !isAtLimit) {
return null;
}
@ -52,7 +52,7 @@ export function RateLimitBanner({ className = '' }: RateLimitBannerProps) {
export function RateLimitIndicator({ className = '' }: RateLimitBannerProps) {
const { status, isAtLimit } = useAuthRateLimit();
if (!status?.authEnabled) {
if (!status) {
return null;
}

View file

@ -11,12 +11,10 @@ export interface RateLimitStatus {
remainingChars: number;
resetTimeMs: number;
userType: 'anonymous' | 'authenticated' | 'unauthenticated';
authEnabled: boolean;
}
interface AuthRateLimitContextType {
// Auth Config
authEnabled: boolean;
authBaseUrl: string | null;
allowAnonymousAuthSessions: boolean;
githubAuthEnabled: boolean;
@ -45,8 +43,8 @@ export function useAuthRateLimit(): AuthRateLimitContextType {
}
export function useAuthConfig() {
const { authEnabled, authBaseUrl, allowAnonymousAuthSessions, githubAuthEnabled } = useAuthRateLimit();
return { authEnabled, baseUrl: authBaseUrl, allowAnonymousAuthSessions, githubAuthEnabled };
const { authBaseUrl, allowAnonymousAuthSessions, githubAuthEnabled } = useAuthRateLimit();
return { baseUrl: authBaseUrl, allowAnonymousAuthSessions, githubAuthEnabled };
}
export function useRateLimit() {
@ -87,7 +85,6 @@ function parseRateLimitStatus(raw: unknown): RateLimitStatus | null {
remainingChars: Number(data.remainingChars ?? 0),
resetTimeMs: coerceTimestampMs(data.resetTimeMs ?? data.resetTime, nextUtcMidnightTimestampMs()),
userType,
authEnabled: Boolean(data.authEnabled),
};
}
@ -105,7 +102,6 @@ export function formatCharCount(count: number): string {
interface AuthRateLimitProviderProps {
children: ReactNode;
authEnabled: boolean;
authBaseUrl: string | null;
allowAnonymousAuthSessions: boolean;
githubAuthEnabled: boolean;
@ -115,7 +111,6 @@ const RATE_LIMIT_QUERY_KEY = ['rate-limit-status'] as const;
export function AuthRateLimitProvider({
children,
authEnabled,
authBaseUrl,
allowAnonymousAuthSessions,
githubAuthEnabled,
@ -210,7 +205,6 @@ export function AuthRateLimitProvider({
}, []);
const contextValue: AuthRateLimitContextType = {
authEnabled,
authBaseUrl,
allowAnonymousAuthSessions,
githubAuthEnabled,

View file

@ -406,7 +406,6 @@ export function TTSProvider({ children }: { children: ReactNode }): ReactElement
configTTSModel,
);
const {
authEnabled,
onTTSStart,
onTTSComplete,
refresh: refreshRateLimit,
@ -3229,19 +3228,17 @@ export function TTSProvider({ children }: { children: ReactNode }): ReactElement
};
const load = async () => {
if (authEnabled) {
try {
const remote = await getDocumentProgress(docId);
if (!cancelled && remote?.location) {
await setLastDocumentLocation(docId, remote.location).catch((error) => {
console.warn('Error caching remote location locally:', error);
});
applyLocation(remote.location);
return;
}
} catch (error) {
console.warn('Error loading remote progress:', error);
try {
const remote = await getDocumentProgress(docId);
if (!cancelled && remote?.location) {
await setLastDocumentLocation(docId, remote.location).catch((error) => {
console.warn('Error caching remote location locally:', error);
});
applyLocation(remote.location);
return;
}
} catch (error) {
console.warn('Error loading remote progress:', error);
}
try {
@ -3259,7 +3256,7 @@ export function TTSProvider({ children }: { children: ReactNode }): ReactElement
return () => {
cancelled = true;
};
}, [id, isEPUB, currentReaderType, authEnabled]);
}, [id, isEPUB, currentReaderType]);
// Save current position periodically for non-EPUB readers.
useEffect(() => {
@ -3271,18 +3268,16 @@ export function TTSProvider({ children }: { children: ReactNode }): ReactElement
setLastDocumentLocation(id as string, location).catch(error => {
console.warn('Error saving non-EPUB location:', error);
});
if (authEnabled) {
scheduleDocumentProgressSync({
documentId: id as string,
readerType: currentReaderType,
location,
});
}
scheduleDocumentProgressSync({
documentId: id as string,
readerType: currentReaderType,
location,
});
}, 1000); // Debounce saves by 1 second
return () => clearTimeout(timeoutId);
}
}, [id, isEPUB, currDocPage, currDocPageNumber, currentIndex, sentences.length, currentReaderType, authEnabled]);
}, [id, isEPUB, currDocPage, currDocPageNumber, currentIndex, sentences.length, currentReaderType]);
/**
* Renders the TTS context provider with its children

View file

@ -33,7 +33,6 @@ export function shouldPersistEpubLocation(
type UseEpubLocationControllerParams = {
documentId?: string;
authEnabled: boolean;
isEpubSetOnceRef: MutableRefObject<boolean>;
shouldPauseRef: MutableRefObject<boolean>;
setIsEpub: (isEpub: boolean) => void;
@ -46,7 +45,6 @@ type UseEpubLocationControllerParams = {
export function useEPUBLocationController({
documentId,
authEnabled,
isEpubSetOnceRef,
shouldPauseRef,
setIsEpub,
@ -138,13 +136,11 @@ export function useEPUBLocationController({
// Save the location to IndexedDB if not initial
if (shouldPersistEpubLocation(documentId, locationRef.current)) {
setLastDocumentLocation(documentId, location.toString());
if (authEnabled) {
scheduleDocumentProgressSync({
documentId,
readerType: 'epub',
location: location.toString(),
});
}
scheduleDocumentProgressSync({
documentId,
readerType: 'epub',
location: location.toString(),
});
}
skipToLocation(location);
@ -155,7 +151,6 @@ export function useEPUBLocationController({
shouldPauseRef.current = true;
}
}, [
authEnabled,
bookRef,
documentId,
extractPageText,

View file

@ -320,7 +320,6 @@ export type User = AuthSessionUser & {
};
export type AuthContext = {
authEnabled: true;
session: Session | null;
user: User | null;
userId: string | null;
@ -342,7 +341,7 @@ export async function getAuthContext(request: Pick<NextRequest, 'headers'>): Pro
}
}
return { authEnabled: true, session, user, userId };
return { session, user, userId };
}
export async function requireAuthContext(