feat(auth): add remembered local login to the frontend
This commit is contained in:
@@ -0,0 +1,71 @@
|
||||
import { useSyncExternalStore } from "react";
|
||||
import type { AuthenticatedUser } from "../api/types";
|
||||
import { queryClient } from "../app/queryClient";
|
||||
import { useSessionStore } from "../store/sessionStore";
|
||||
|
||||
let current: AuthenticatedUser | null = null;
|
||||
let generation = 0;
|
||||
const listeners = new Set<() => void>();
|
||||
|
||||
function notify() {
|
||||
for (const listener of listeners) listener();
|
||||
}
|
||||
|
||||
function scrubUserBoundState(): void {
|
||||
queryClient.clear();
|
||||
useSessionStore.getState().resetSession();
|
||||
}
|
||||
|
||||
/** Authentication is intentionally process-local; no browser storage is involved. */
|
||||
export function getAuthState(): AuthenticatedUser | null {
|
||||
return current;
|
||||
}
|
||||
|
||||
export function setAuthState(user: AuthenticatedUser): void {
|
||||
scrubUserBoundState();
|
||||
current = user;
|
||||
generation += 1;
|
||||
notify();
|
||||
}
|
||||
|
||||
export function clearAuthState(): void {
|
||||
scrubUserBoundState();
|
||||
current = null;
|
||||
generation += 1;
|
||||
notify();
|
||||
}
|
||||
|
||||
export function isAuthGenerationCurrent(expectedGeneration: number): boolean {
|
||||
return generation === expectedGeneration;
|
||||
}
|
||||
|
||||
export function clearAuthStateIfCurrent(expectedGeneration: number): boolean {
|
||||
if (!isAuthGenerationCurrent(expectedGeneration)) return false;
|
||||
clearAuthState();
|
||||
return true;
|
||||
}
|
||||
|
||||
export function getAuthGeneration(): number {
|
||||
return generation;
|
||||
}
|
||||
|
||||
export function subscribeAuthState(listener: () => void): () => void {
|
||||
listeners.add(listener);
|
||||
return () => listeners.delete(listener);
|
||||
}
|
||||
|
||||
export function useAuthState(): AuthenticatedUser | null {
|
||||
return useSyncExternalStore(subscribeAuthState, getAuthState, getAuthState);
|
||||
}
|
||||
|
||||
export function useAuthUser(): AuthenticatedUser | null {
|
||||
return useAuthState();
|
||||
}
|
||||
|
||||
export function useAuthGeneration(): number {
|
||||
return useSyncExternalStore(subscribeAuthState, getAuthGeneration, getAuthGeneration);
|
||||
}
|
||||
|
||||
export function hasPermission(user: Pick<AuthenticatedUser, "permissions"> | null | undefined, permission: string): boolean {
|
||||
return user?.permissions.includes(permission) ?? false;
|
||||
}
|
||||
Reference in New Issue
Block a user