mirror of
https://github.com/ZHANGTIANYAO1/teamspeak-music-bot.git
synced 2026-10-02 04:52:50 +08:00
apiFetch called window.fetch which installApiClient had reassigned to call apiFetch — every request blew the stack. Capture the native fetch at module load (before any wrap) and use it inside apiFetch. Symptom: first-run / login redirect never fires because the router guard hangs on session.refresh(). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
50 lines
1.7 KiB
TypeScript
50 lines
1.7 KiB
TypeScript
import router from '../router/index.js';
|
|
import { useSession } from '../composables/useSession.js';
|
|
|
|
let installed = false;
|
|
const nativeFetch: typeof window.fetch = window.fetch.bind(window);
|
|
|
|
/**
|
|
* Wraps fetch so every call:
|
|
* - sends cookies (`credentials: 'same-origin'`)
|
|
* - on 401 from /api/*: clear local session, redirect to /login
|
|
*
|
|
* Always uses the captured native fetch, never the (possibly wrapped) global.
|
|
*/
|
|
export function apiFetch(input: RequestInfo | URL, init: RequestInit = {}): Promise<Response> {
|
|
const merged: RequestInit = {
|
|
credentials: 'same-origin',
|
|
...init,
|
|
headers: { ...(init.headers ?? {}) },
|
|
};
|
|
return nativeFetch(input, merged).then(async (res) => {
|
|
if (res.status === 401 && shouldTriggerRefresh(input)) {
|
|
const session = useSession();
|
|
await session.refresh();
|
|
const current = router.currentRoute.value;
|
|
if (current.name !== 'login' && current.name !== 'first-run') {
|
|
await router.replace({ name: 'login', query: { next: current.fullPath } });
|
|
}
|
|
}
|
|
return res;
|
|
});
|
|
}
|
|
|
|
function shouldTriggerRefresh(input: RequestInfo | URL): boolean {
|
|
const url = typeof input === 'string' ? input : input instanceof URL ? input.toString() : input.url;
|
|
return url.startsWith('/api/') && !url.startsWith('/api/session/');
|
|
}
|
|
|
|
/**
|
|
* Replaces window.fetch with apiFetch so existing call sites do not need to be touched.
|
|
* Call once at app startup.
|
|
*/
|
|
export function installApiClient(): void {
|
|
if (installed) return;
|
|
installed = true;
|
|
window.fetch = ((input: RequestInfo | URL, init?: RequestInit) => {
|
|
return apiFetch(input, init ?? {});
|
|
}) as typeof window.fetch;
|
|
(window as unknown as { __originalFetch?: typeof fetch }).__originalFetch = nativeFetch;
|
|
}
|