fix(api): attach Bearer token to services/widgets/backups requests
Under AUTH_ENABLED=true, api/services.ts, api/widgets.ts, and api/backups.ts called fetch() directly without attaching the OIDC access token, so every services/widgets/backups request 401'd while api/client.ts requests succeeded. The token was only attached in client.ts. Extract the auth-attaching fetch helpers (buildUrl/buildHeaders/ readErrorDetail + get/post/put/del/postForm) into a new api/shared.ts that consults getAccessToken(), rewrite services.ts/widgets.ts/ backups.ts to use them, and consolidate client.ts to import from shared.ts (removing its duplicated copies). Now every backend request goes through one auth-attaching path. As a side benefit, error messages surface the HTTP status + backend detail instead of a generic "Failed to ..." string. Bug masked in dev because dev runs AUTH_ENABLED=false. npm run build clean; 0 lint errors; 72 frontend tests pass.
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
import { del, get, post, put } from "./shared";
|
||||
import type {
|
||||
BuiltinWidgetKindInfo,
|
||||
WidgetDataResponse,
|
||||
@@ -5,61 +6,37 @@ import type {
|
||||
WidgetInstanceInput,
|
||||
} from "../types";
|
||||
|
||||
const API_BASE = "/api";
|
||||
|
||||
export async function fetchBuiltinWidgetKinds(): Promise<
|
||||
BuiltinWidgetKindInfo[]
|
||||
> {
|
||||
const res = await fetch(`${API_BASE}/widgets/builtin`);
|
||||
if (!res.ok) throw new Error("Failed to fetch built-in widget kinds");
|
||||
return res.json();
|
||||
return get<BuiltinWidgetKindInfo[]>("/api/widgets/builtin");
|
||||
}
|
||||
|
||||
export async function fetchWidgetInstances(): Promise<WidgetInstance[]> {
|
||||
const res = await fetch(`${API_BASE}/widgets/instances`);
|
||||
if (!res.ok) throw new Error("Failed to fetch widget instances");
|
||||
return res.json();
|
||||
return get<WidgetInstance[]>("/api/widgets/instances");
|
||||
}
|
||||
|
||||
export async function createWidgetInstance(
|
||||
input: WidgetInstanceInput,
|
||||
): Promise<WidgetInstance> {
|
||||
const res = await fetch(`${API_BASE}/widgets/instances`, {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify(input),
|
||||
});
|
||||
if (!res.ok) throw new Error("Failed to create widget instance");
|
||||
return res.json();
|
||||
return post<WidgetInstance>("/api/widgets/instances", input);
|
||||
}
|
||||
|
||||
export async function updateWidgetInstance(
|
||||
input: WidgetInstanceInput,
|
||||
): Promise<WidgetInstance> {
|
||||
if (!input.id) throw new Error("Widget ID is required for update");
|
||||
const res = await fetch(`${API_BASE}/widgets/instances/${input.id}`, {
|
||||
method: "PUT",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify(input),
|
||||
});
|
||||
if (!res.ok) throw new Error("Failed to update widget instance");
|
||||
return res.json();
|
||||
return put<WidgetInstance>(`/api/widgets/instances/${input.id}`, input);
|
||||
}
|
||||
|
||||
export async function deleteWidgetInstance(
|
||||
widgetId: string,
|
||||
): Promise<{ status: string }> {
|
||||
const res = await fetch(`${API_BASE}/widgets/instances/${widgetId}`, {
|
||||
method: "DELETE",
|
||||
});
|
||||
if (!res.ok) throw new Error("Failed to delete widget instance");
|
||||
return res.json();
|
||||
return del<{ status: string }>(`/api/widgets/instances/${widgetId}`);
|
||||
}
|
||||
|
||||
export async function fetchWidgetData(
|
||||
widgetId: string,
|
||||
): Promise<WidgetDataResponse> {
|
||||
const res = await fetch(`${API_BASE}/widgets/instances/${widgetId}/data`);
|
||||
if (!res.ok) throw new Error("Failed to fetch widget data");
|
||||
return res.json();
|
||||
return get<WidgetDataResponse>(`/api/widgets/instances/${widgetId}/data`);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user