mirror of
https://github.com/ZHANGTIANYAO1/teamspeak-music-bot.git
synced 2026-10-02 04:52:50 +08:00
fix(web): break infinite recursion in apiFetch by capturing nativeFetch
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>
This commit is contained in:
1 parent
a8b056d2aa
commit
f46b37192f
1 file changed
+5
-4
+5
-4
@@ -2,11 +2,14 @@ import router from '../router/index.js';
|
|||||||
import { useSession } from '../composables/useSession.js';
|
import { useSession } from '../composables/useSession.js';
|
||||||
|
|
||||||
let installed = false;
|
let installed = false;
|
||||||
|
const nativeFetch: typeof window.fetch = window.fetch.bind(window);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Wraps fetch so every call:
|
* Wraps fetch so every call:
|
||||||
* - sends cookies (`credentials: 'same-origin'`)
|
* - sends cookies (`credentials: 'same-origin'`)
|
||||||
* - on 401 from /api/*: clear local session, redirect to /login
|
* - 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> {
|
export function apiFetch(input: RequestInfo | URL, init: RequestInit = {}): Promise<Response> {
|
||||||
const merged: RequestInit = {
|
const merged: RequestInit = {
|
||||||
@@ -14,7 +17,7 @@ export function apiFetch(input: RequestInfo | URL, init: RequestInit = {}): Prom
|
|||||||
...init,
|
...init,
|
||||||
headers: { ...(init.headers ?? {}) },
|
headers: { ...(init.headers ?? {}) },
|
||||||
};
|
};
|
||||||
return fetch(input, merged).then(async (res) => {
|
return nativeFetch(input, merged).then(async (res) => {
|
||||||
if (res.status === 401 && shouldTriggerRefresh(input)) {
|
if (res.status === 401 && shouldTriggerRefresh(input)) {
|
||||||
const session = useSession();
|
const session = useSession();
|
||||||
await session.refresh();
|
await session.refresh();
|
||||||
@@ -39,10 +42,8 @@ function shouldTriggerRefresh(input: RequestInfo | URL): boolean {
|
|||||||
export function installApiClient(): void {
|
export function installApiClient(): void {
|
||||||
if (installed) return;
|
if (installed) return;
|
||||||
installed = true;
|
installed = true;
|
||||||
const original = window.fetch.bind(window);
|
|
||||||
window.fetch = ((input: RequestInfo | URL, init?: RequestInit) => {
|
window.fetch = ((input: RequestInfo | URL, init?: RequestInit) => {
|
||||||
return apiFetch(input, init ?? {});
|
return apiFetch(input, init ?? {});
|
||||||
}) as typeof window.fetch;
|
}) as typeof window.fetch;
|
||||||
// Keep original accessible if anything needs to bypass
|
(window as unknown as { __originalFetch?: typeof fetch }).__originalFetch = nativeFetch;
|
||||||
(window as unknown as { __originalFetch?: typeof fetch }).__originalFetch = original;
|
|
||||||
}
|
}
|
||||||
Reference in new issue
Block a user