chore: finish frontend ESLint migration #18
Frontend security / security (push) Successful in 9s
Frontend verify / verify (push) Failing after 37m50s
Frontend security / security (pull_request) Successful in 9s
Frontend verify / verify (pull_request) Failing after 42m10s
Conventional commits / commits (pull_request) Successful in 29s

Enable every plugin recommended preset and replace Biome with ESLint formatting.

Preserve API contracts and JSX whitespace; verify source, tests, builds and tooling.
This commit is contained in:
2026-09-28 07:31:28 +03:00
parent 851457e03c
commit 3eafad2657
253 changed files with 10059 additions and 8864 deletions
+58 -59
View File
@@ -2,65 +2,44 @@ import createClient from "openapi-fetch";
import createQueryClient from "openapi-react-query";
import type { paths } from "./generated/schema";
import { apiErrorCode } from "./problem-details";
const HTTP_UNAUTHORIZED = 401;
const configuredBaseUrl: unknown = import.meta.env.VITE_API_BASE_URL;
const apiBaseUrl =
typeof configuredBaseUrl === "string"
const apiBaseUrl
= typeof configuredBaseUrl === "string"
? configuredBaseUrl
: "http://localhost:3000";
type AuthHandlers = {
generation?: () => number;
accessToken: () => string | null;
refresh: () => Promise<boolean>;
accessToken: () => null | string | undefined;
clear: () => void;
generation?: () => number;
refresh: () => Promise<boolean>;
};
const inFlight = new Set<{ pathname: string; invalidated: boolean }>();
const latestReads = new Map<string, { sequence: number; pending: number }>();
function invalidateApiRequests(matches: (pathname: string) => boolean) {
const inFlight = new Set<{ invalidated: boolean; pathname: string }>();
const latestReads = new Map<string, { pending: number; sequence: number }>();
function invalidateApiRequests(isMatches: (pathname: string) => boolean) {
for (const request of inFlight)
if (matches(request.pathname)) request.invalidated = true;
if (isMatches(request.pathname)) request.invalidated = true;
}
let auth: AuthHandlers | null = null;
let hasAuthenticatedSession = false;
const sessionState: { handlers?: AuthHandlers; hasSession: boolean } = { hasSession: false };
const authSessionListeners = new Set<() => void>();
function setAuthenticatedSession(next: boolean) {
if (next === hasAuthenticatedSession) return;
hasAuthenticatedSession = next;
for (const listener of authSessionListeners) listener();
}
function configureAuthClient(handlers: AuthHandlers | null) {
if (!handlers) invalidateApiRequests(() => true);
auth = handlers;
setAuthenticatedSession(Boolean(auth?.accessToken()));
}
function getAuthenticatedSessionSnapshot() {
return hasAuthenticatedSession;
}
function subscribeAuthenticatedSession(listener: () => void) {
authSessionListeners.add(listener);
return () => authSessionListeners.delete(listener);
}
async function authenticatedFetch(request: Request): Promise<Response> {
const url = new URL(request.url);
url.searchParams.delete("sync");
url.searchParams.sort();
const key = `${request.method} ${url}`;
const ticket = { pathname: url.pathname, invalidated: false };
const read =
request.method === "GET"
? (latestReads.get(key) ?? { sequence: 0, pending: 0 })
: null;
const ticket = { invalidated: false, pathname: url.pathname };
const read
= request.method === "GET"
? (latestReads.get(key) ?? { pending: 0, sequence: 0 })
: undefined;
if (read) {
read.sequence += 1;
read.pending += 1;
@@ -73,12 +52,19 @@ async function authenticatedFetch(request: Request): Promise<Response> {
request,
() => !ticket.invalidated && (!read || sequence === read.sequence),
);
} finally {
}
finally {
inFlight.delete(ticket);
if (read && --read.pending === 0) latestReads.delete(key);
}
}
function configureAuthClient(handlers?: AuthHandlers) {
if (!handlers) invalidateApiRequests(() => true);
sessionState.handlers = handlers;
setAuthenticatedSession(Boolean(sessionState.handlers?.accessToken()));
}
async function fetchCurrent(
request: Request,
isLatest: () => boolean,
@@ -86,45 +72,43 @@ async function fetchCurrent(
const isAuthRequest = new URL(request.url).pathname.startsWith(
"/api/v1/auth/",
);
const session = auth;
const session = sessionState.handlers;
const generation = session?.generation?.();
const isCurrent = () =>
(session?.generation
? generation === session.generation() &&
generation === auth?.generation?.()
: session === auth) && isLatest();
? generation === session.generation()
&& generation === sessionState.handlers?.generation?.()
: session === sessionState.handlers) && isLatest();
const token = session?.accessToken();
const withToken = (source: Request, value: string) => {
const headers = new Headers(source.headers);
headers.set("Authorization", `Bearer ${value}`);
return new Request(source, { headers });
};
const authorized =
token && !isAuthRequest ? withToken(request, token) : request;
const authorized
= token && !isAuthRequest ? withToken(request, token) : request;
const retryRequest = authorized.clone();
const response = await fetch(authorized);
await response.clone().arrayBuffer();
if (!isAuthRequest && !isCurrent())
throw new DOMException("Session changed", "AbortError");
if (
response.status !== HTTP_UNAUTHORIZED ||
isAuthRequest ||
!auth ||
apiErrorCode(
await response
.clone()
.json()
.catch(() => null),
) !== "UNAUTHORIZED"
)
if (isAuthRequest || !sessionState.handlers || response.status !== HTTP_UNAUTHORIZED)
return response;
let problem: unknown;
try {
problem = await response.clone().json();
}
catch {
return response;
}
if (apiErrorCode(problem) !== "UNAUTHORIZED") return response;
if (!isCurrent()) throw new DOMException("Session changed", "AbortError");
if (!(await auth.refresh())) {
if (isCurrent()) auth.clear();
if (!(await sessionState.handlers.refresh())) {
if (isCurrent()) sessionState.handlers.clear();
return response;
}
if (!isCurrent()) throw new DOMException("Session changed", "AbortError");
const refreshedToken = auth.accessToken();
const refreshedToken = sessionState.handlers.accessToken();
if (!refreshedToken) return response;
const retried = await fetch(withToken(retryRequest, refreshedToken));
await retried.clone().arrayBuffer();
@@ -132,6 +116,21 @@ async function fetchCurrent(
return retried;
}
function hasAuthenticatedSession() {
return sessionState.hasSession;
}
function setAuthenticatedSession(hasSession: boolean) {
if (hasSession === sessionState.hasSession) return;
sessionState.hasSession = hasSession;
for (const listener of authSessionListeners) listener();
}
function subscribeAuthenticatedSession(listener: () => void) {
authSessionListeners.add(listener);
return () => authSessionListeners.delete(listener);
}
const apiClient = createClient<paths>({
baseUrl: apiBaseUrl,
credentials: "include",
@@ -144,7 +143,7 @@ export {
apiClient,
apiQueryClient,
configureAuthClient,
getAuthenticatedSessionSnapshot,
hasAuthenticatedSession as getAuthenticatedSessionSnapshot,
invalidateApiRequests,
subscribeAuthenticatedSession,
};