MCPcopy
hub / github.com/MacRimi/ProxMenux / fetchApi

Function fetchApi

AppImage/lib/api-config.ts:72–174  ·  view source on GitHub ↗
(endpoint: string, options?: RequestInit)

Source from the content-addressed store, hash-verified

70 * @returns Promise with the response data
71 */
72export async function fetchApi<T>(endpoint: string, options?: RequestInit): Promise<T> {
73 const url = getApiUrl(endpoint)
74
75 const token = getAuthToken()
76
77 const headers: Record<string, string> = {
78 "Content-Type": "application/json",
79 ...(options?.headers as Record<string, string>),
80 }
81
82 if (token) {
83 headers["Authorization"] = `Bearer ${token}`
84 }
85
86 const response = await fetch(url, {
87 ...options,
88 headers,
89 cache: "no-store",
90 })
91
92 if (!response.ok) {
93 if (response.status === 401) {
94 // Token is missing, expired, or signed under a previous JWT_SECRET
95 // (rotated per-install). Drop the stale token and force a single
96 // reload so the page-level auth gate (`app/page.tsx`) can render
97 // <Login> instead of cascading 401s from every authenticated
98 // component on mount.
99 //
100 // Only react when we actually had a token to invalidate. A 401
101 // without any token in localStorage means the caller is the
102 // Login screen itself, or a leftover fetch from a recently
103 // unmounted Dashboard — reloading there does nothing but waste
104 // the user's keystrokes and can leave the cascade flag set
105 // forever, swallowing the very 401 that we'd want to recover
106 // from after a successful re-login. The fix: bail out early
107 // if we have no token to invalidate.
108 if (typeof window !== "undefined") {
109 let hadToken = false
110 try {
111 hadToken = !!localStorage.getItem("proxmenux-auth-token")
112 } catch {
113 // private browsing — assume yes so we attempt recovery.
114 hadToken = true
115 }
116 if (!hadToken) {
117 throw new Error(`Unauthorized: ${endpoint}`)
118 }
119 try {
120 localStorage.removeItem("proxmenux-auth-token")
121 } catch {
122 // localStorage might be unavailable in private browsing — ignore.
123 }
124 try {
125 if (!sessionStorage.getItem("proxmenux-auth-401-handled")) {
126 sessionStorage.setItem("proxmenux-auth-401-handled", "1")
127 window.location.reload()
128 }
129 } catch {

Callers 15

fetcherFunction · 0.90
ProxmoxDashboardFunction · 0.90
loadFirewallStatusFunction · 0.90
loadNetworkInterfacesFunction · 0.90
loadSecurityToolsFunction · 0.90
handleUninstallFail2banFunction · 0.90
handleUninstallLynisFunction · 0.90
loadFail2banDetailsFunction · 0.90
handleUnbanIpFunction · 0.90
handleApplyMissingJailsFunction · 0.90
handleRunLynisAuditFunction · 0.90
loadLynisReportFunction · 0.90

Calls 2

getAuthTokenFunction · 0.85
getApiUrlFunction · 0.70

Tested by

no test coverage detected