update prettier
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
2026-02-23 14:23:46 +01:00
parent 33d1425fbb
commit cbabf43584
25 changed files with 1373 additions and 1363 deletions

View File

@@ -6,91 +6,91 @@ const DEFAULT_REFRESH_TOKEN_KEY = 'refreshToken';
const DEFAULT_LEGACY_KEYS = ['auth_token', 'auth_user', 'token'];
export type AuthState<TUser> = {
authToken: string | null;
refreshToken: string | null;
currentUser: TUser | null;
authToken: string | null;
refreshToken: string | null;
currentUser: TUser | null;
};
export type AuthContextValue<TUser> = AuthState<TUser> & {
setSession: (authToken: string, refreshToken: string, currentUser: TUser) => void;
setCurrentUser: (currentUser: TUser | null) => void;
clearSession: () => void;
setSession: (authToken: string, refreshToken: string, currentUser: TUser) => void;
setCurrentUser: (currentUser: TUser | null) => void;
clearSession: () => void;
};
export type CreateAuthContextOptions = {
authTokenKey?: string;
refreshTokenKey?: string;
legacyKeys?: string[];
authTokenKey?: string;
refreshTokenKey?: string;
legacyKeys?: string[];
};
export function createAuthContext<TUser>(options: CreateAuthContextOptions = {}) {
const authTokenKey = options.authTokenKey ?? DEFAULT_AUTH_TOKEN_KEY;
const refreshTokenKey = options.refreshTokenKey ?? DEFAULT_REFRESH_TOKEN_KEY;
const legacyKeys = options.legacyKeys ?? DEFAULT_LEGACY_KEYS;
const authTokenKey = options.authTokenKey ?? DEFAULT_AUTH_TOKEN_KEY;
const refreshTokenKey = options.refreshTokenKey ?? DEFAULT_REFRESH_TOKEN_KEY;
const legacyKeys = options.legacyKeys ?? DEFAULT_LEGACY_KEYS;
const AuthContext = createContext<AuthContextValue<TUser> | undefined>(undefined);
const AuthContext = createContext<AuthContextValue<TUser> | undefined>(undefined);
function readStoredSession(): AuthState<TUser> {
for (const key of legacyKeys) {
localStorage.removeItem(key);
function readStoredSession(): AuthState<TUser> {
for (const key of legacyKeys) {
localStorage.removeItem(key);
}
const authToken = localStorage.getItem(authTokenKey);
const refreshToken = localStorage.getItem(refreshTokenKey);
return {
authToken,
refreshToken,
currentUser: null,
};
}
const authToken = localStorage.getItem(authTokenKey);
const refreshToken = localStorage.getItem(refreshTokenKey);
function AuthProvider({ children }: Readonly<{ children: ReactNode }>) {
const [state, setState] = useState<AuthState<TUser>>(readStoredSession);
const setSession = useCallback(
(authToken: string, refreshToken: string, currentUser: TUser) => {
localStorage.setItem(authTokenKey, authToken);
localStorage.setItem(refreshTokenKey, refreshToken);
setState({ authToken, refreshToken, currentUser });
},
[],
);
const clearSession = useCallback(() => {
localStorage.removeItem(authTokenKey);
localStorage.removeItem(refreshTokenKey);
setState({ authToken: null, refreshToken: null, currentUser: null });
}, []);
const setCurrentUser = useCallback((currentUser: TUser | null) => {
setState((prev) => ({ ...prev, currentUser }));
}, []);
const value = useMemo<AuthContextValue<TUser>>(
() => ({
...state,
setSession,
setCurrentUser,
clearSession,
}),
[state, setSession, setCurrentUser, clearSession],
);
return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>;
}
function useAuth() {
const ctx = useContext(AuthContext);
if (!ctx) {
throw new Error('useAuth must be used within AuthProvider');
}
return ctx;
}
return {
authToken,
refreshToken,
currentUser: null,
AuthProvider,
useAuth,
AuthContext,
};
}
function AuthProvider({ children }: Readonly<{ children: ReactNode }>) {
const [state, setState] = useState<AuthState<TUser>>(readStoredSession);
const setSession = useCallback(
(authToken: string, refreshToken: string, currentUser: TUser) => {
localStorage.setItem(authTokenKey, authToken);
localStorage.setItem(refreshTokenKey, refreshToken);
setState({ authToken, refreshToken, currentUser });
},
[],
);
const clearSession = useCallback(() => {
localStorage.removeItem(authTokenKey);
localStorage.removeItem(refreshTokenKey);
setState({ authToken: null, refreshToken: null, currentUser: null });
}, []);
const setCurrentUser = useCallback((currentUser: TUser | null) => {
setState((prev) => ({ ...prev, currentUser }));
}, []);
const value = useMemo<AuthContextValue<TUser>>(
() => ({
...state,
setSession,
setCurrentUser,
clearSession,
}),
[state, setSession, setCurrentUser, clearSession],
);
return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>;
}
function useAuth() {
const ctx = useContext(AuthContext);
if (!ctx) {
throw new Error('useAuth must be used within AuthProvider');
}
return ctx;
}
return {
AuthProvider,
useAuth,
AuthContext,
};
}

View File

@@ -1,35 +1,35 @@
const MILLISECONDS_PER_SECOND = 1000;
export function decodeJwtPayload(token: string): Record<string, unknown> | null {
const parts = token.split('.');
if (parts.length !== 3) {
return null;
}
const base64Url = parts[1];
const base64 = base64Url.replaceAll('-', '+').replaceAll('_', '/');
const padded = base64.padEnd(base64.length + ((4 - (base64.length % 4)) % 4), '=');
try {
const payload = JSON.parse(atob(padded));
if (payload && typeof payload === 'object') {
return payload as Record<string, unknown>;
const parts = token.split('.');
if (parts.length !== 3) {
return null;
}
} catch {
return null;
}
return null;
const base64Url = parts[1];
const base64 = base64Url.replaceAll('-', '+').replaceAll('_', '/');
const padded = base64.padEnd(base64.length + ((4 - (base64.length % 4)) % 4), '=');
try {
const payload = JSON.parse(atob(padded));
if (payload && typeof payload === 'object') {
return payload as Record<string, unknown>;
}
} catch {
return null;
}
return null;
}
export function isJwtExpired(token: string, skewSeconds = 0) {
const payload = decodeJwtPayload(token);
const exp = payload?.exp;
if (typeof exp !== 'number' || !Number.isFinite(exp)) {
return false;
}
const payload = decodeJwtPayload(token);
const exp = payload?.exp;
if (typeof exp !== 'number' || !Number.isFinite(exp)) {
return false;
}
const expiresAt = exp * MILLISECONDS_PER_SECOND;
const now = Date.now();
return expiresAt <= now + skewSeconds * MILLISECONDS_PER_SECOND;
const expiresAt = exp * MILLISECONDS_PER_SECOND;
const now = Date.now();
return expiresAt <= now + skewSeconds * MILLISECONDS_PER_SECOND;
}