@kawaiininja/fetch 1.0.59 → 1.0.60
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/hooks/useCsrf.d.ts +7 -3
- package/dist/hooks/useCsrf.js +74 -54
- package/dist/hooks/useFetch.js +1 -1
- package/package.json +1 -1
package/dist/hooks/useCsrf.d.ts
CHANGED
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
export
|
|
2
|
-
|
|
1
|
+
export interface CsrfOptions {
|
|
2
|
+
force?: boolean;
|
|
3
|
+
}
|
|
4
|
+
export interface CsrfResult {
|
|
5
|
+
fetchCSRF: (options?: CsrfOptions) => Promise<string>;
|
|
3
6
|
clearCsrf: () => Promise<void>;
|
|
4
|
-
}
|
|
7
|
+
}
|
|
8
|
+
export declare function useCsrf(): CsrfResult;
|
package/dist/hooks/useCsrf.js
CHANGED
|
@@ -2,80 +2,100 @@ import { useCallback, useRef } from "react";
|
|
|
2
2
|
import { INTERNAL_HEADER } from "../context/ApiContext";
|
|
3
3
|
import { isNative } from "./platform";
|
|
4
4
|
import { useApiConfig } from "./useApiConfig";
|
|
5
|
+
// --- Helpers ---
|
|
6
|
+
const getFromStorage = (debug) => {
|
|
7
|
+
if (typeof window === "undefined")
|
|
8
|
+
return null;
|
|
9
|
+
const stored = localStorage.getItem("csrf_token");
|
|
10
|
+
if (stored && debug)
|
|
11
|
+
console.log("[useCsrf] Retrieved from localStorage.");
|
|
12
|
+
return stored || null;
|
|
13
|
+
};
|
|
14
|
+
const saveToStorage = (token) => {
|
|
15
|
+
if (typeof window !== "undefined") {
|
|
16
|
+
localStorage.setItem("csrf_token", token);
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
const fetchFromNetwork = async (apiUrl, debug) => {
|
|
20
|
+
if (debug)
|
|
21
|
+
console.log("[useCsrf] Fetching new CSRF token from server...");
|
|
22
|
+
const csrfUrl = apiUrl("auth/csrf-token");
|
|
23
|
+
const controller = new AbortController();
|
|
24
|
+
const timeoutId = setTimeout(() => controller.abort(), 15000);
|
|
25
|
+
try {
|
|
26
|
+
const res = await fetch(csrfUrl, {
|
|
27
|
+
method: "GET",
|
|
28
|
+
headers: INTERNAL_HEADER,
|
|
29
|
+
credentials: "include",
|
|
30
|
+
signal: controller.signal,
|
|
31
|
+
});
|
|
32
|
+
if (!res.ok)
|
|
33
|
+
throw new Error(`CSRF HTTP Error: ${res.status}`);
|
|
34
|
+
const json = await res.json();
|
|
35
|
+
const token = json?.csrfToken;
|
|
36
|
+
if (!token)
|
|
37
|
+
throw new Error("Missing CSRF token in response");
|
|
38
|
+
return token;
|
|
39
|
+
}
|
|
40
|
+
catch (error) {
|
|
41
|
+
if (debug)
|
|
42
|
+
console.error("[useCsrf] Network Error:", error);
|
|
43
|
+
throw error;
|
|
44
|
+
}
|
|
45
|
+
finally {
|
|
46
|
+
clearTimeout(timeoutId);
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
// --- Hook ---
|
|
5
50
|
export function useCsrf() {
|
|
6
51
|
const { apiUrl, debug, disableCsrf } = useApiConfig();
|
|
7
52
|
const csrfRef = useRef(null);
|
|
53
|
+
const csrfPromiseRef = useRef(null);
|
|
8
54
|
const clearCsrf = useCallback(async () => {
|
|
9
55
|
if (isNative() || disableCsrf)
|
|
10
56
|
return;
|
|
11
57
|
if (debug)
|
|
12
58
|
console.log("[useCsrf] Clearing CSRF token...");
|
|
13
59
|
csrfRef.current = null;
|
|
14
|
-
if (typeof window !== "undefined")
|
|
60
|
+
if (typeof window !== "undefined")
|
|
15
61
|
localStorage.removeItem("csrf_token");
|
|
16
|
-
}
|
|
17
62
|
}, [debug, disableCsrf]);
|
|
18
|
-
const
|
|
19
|
-
|
|
20
|
-
console.log(`[useCsrf] fetchCSRF invoked. disableCsrf: ${disableCsrf}`);
|
|
63
|
+
const fetchCSRF = useCallback(async (options) => {
|
|
64
|
+
const { force = false } = options || {};
|
|
21
65
|
if (isNative() || disableCsrf) {
|
|
22
|
-
|
|
66
|
+
if (debug)
|
|
67
|
+
console.log(`[useCsrf] Skipped (Platform/Config)`);
|
|
23
68
|
return "";
|
|
24
69
|
}
|
|
25
|
-
|
|
70
|
+
// 1. Memory Cache
|
|
71
|
+
if (!force && csrfRef.current)
|
|
26
72
|
return csrfRef.current;
|
|
27
|
-
if (csrfPromiseRef.current)
|
|
73
|
+
if (!force && csrfPromiseRef.current)
|
|
28
74
|
return csrfPromiseRef.current;
|
|
29
|
-
|
|
30
|
-
//
|
|
31
|
-
if (
|
|
32
|
-
const
|
|
33
|
-
if (
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
csrfRef.current = storedCsrf;
|
|
37
|
-
return storedCsrf;
|
|
75
|
+
const task = async () => {
|
|
76
|
+
// 2. Storage Cache
|
|
77
|
+
if (!force) {
|
|
78
|
+
const stored = getFromStorage(debug);
|
|
79
|
+
if (stored) {
|
|
80
|
+
csrfRef.current = stored;
|
|
81
|
+
return stored;
|
|
38
82
|
}
|
|
39
83
|
}
|
|
40
|
-
//
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
headers: INTERNAL_HEADER,
|
|
51
|
-
credentials: "include",
|
|
52
|
-
signal: controller.signal,
|
|
53
|
-
});
|
|
54
|
-
clearTimeout(timeoutId);
|
|
55
|
-
if (!res.ok) {
|
|
56
|
-
throw new Error(`CSRF Fetch failed with status: ${res.status}`);
|
|
57
|
-
}
|
|
58
|
-
const json = await res.json();
|
|
59
|
-
const token = json?.csrfToken;
|
|
60
|
-
if (!token)
|
|
61
|
-
throw new Error("Missing CSRF token in response");
|
|
62
|
-
csrfRef.current = token;
|
|
63
|
-
// Store in storage
|
|
64
|
-
if (typeof window !== "undefined") {
|
|
65
|
-
localStorage.setItem("csrf_token", token);
|
|
66
|
-
}
|
|
67
|
-
return token;
|
|
68
|
-
}
|
|
69
|
-
catch (error) {
|
|
70
|
-
clearTimeout(timeoutId);
|
|
71
|
-
console.error("[useCsrf] CSRF Fetch Failed/Timed-out:", error);
|
|
72
|
-
throw error;
|
|
73
|
-
}
|
|
74
|
-
finally {
|
|
84
|
+
// 3. Network Fetch
|
|
85
|
+
const newToken = await fetchFromNetwork(apiUrl, debug);
|
|
86
|
+
csrfRef.current = newToken;
|
|
87
|
+
saveToStorage(newToken);
|
|
88
|
+
return newToken;
|
|
89
|
+
};
|
|
90
|
+
const promise = task();
|
|
91
|
+
// Cleanup ref on completion
|
|
92
|
+
const chained = promise.finally(() => {
|
|
93
|
+
if (csrfPromiseRef.current === chained) {
|
|
75
94
|
csrfPromiseRef.current = null;
|
|
76
95
|
}
|
|
77
|
-
})
|
|
78
|
-
|
|
96
|
+
});
|
|
97
|
+
csrfPromiseRef.current = chained;
|
|
98
|
+
return chained;
|
|
79
99
|
}, [apiUrl, debug, disableCsrf]);
|
|
80
100
|
return { fetchCSRF, clearCsrf };
|
|
81
101
|
}
|
package/dist/hooks/useFetch.js
CHANGED
|
@@ -70,7 +70,7 @@ export const useFetch = (endpoint, baseOptions = {}) => {
|
|
|
70
70
|
if (debug)
|
|
71
71
|
console.log(`[useFetch] 🔄 CSRF Error on ${reqId}. Retrying with fresh token...`);
|
|
72
72
|
await clearCsrf();
|
|
73
|
-
token = await fetchCSRF();
|
|
73
|
+
token = await fetchCSRF({ force: true });
|
|
74
74
|
res = await performFetch(finalUrl, params.method || "GET", token, params.body, params.headers, { ...stableOptions, ...params }, debug, abortRef.current.signal, apiUrl);
|
|
75
75
|
parsed = await parseResponse(res, params.parseAs || "auto");
|
|
76
76
|
}
|