Files
bookhoard/web/src/api.ts
T
john-okeefe 149d14f5eb refactor(ts): Add ES module exports to core utilities
Phase 0/1 of ESBuild migration: Add ES exports to all utility modules
while maintaining Alpine.js registration for template compatibility.

Core utility modules now support both:
- ES module imports for TypeScript→TypeScript dependencies
- Alpine.js global namespace for template onclick handlers

Modules updated:
- api.ts: Export apiGet, apiPost, apiPut, apiDelete, apiPatch, and handlers
- toast.ts: Export showToast function (Alpine namespace already present)
- storage.ts: Export localStorage helpers (already had exports)
- dom.ts: Export DOM manipulation helpers (already had exports)
- events.ts: Export event delegation helpers
- theme.ts: Export theme management functions
- woodPaneling.ts: Export wood paneling functions

Pattern: Each module now has dual exports
- ES module exports for internal TS dependencies
- Alpine.global() registration for template access
- Removed direct window exports where Alpine registration exists

This enables Phase 1 (converting internal window reads to imports) while
maintaining template functionality through Alpine.

Migration progress: Phase 0 complete, Phase 1 in progress
Next: Convert 193+ internal window reads across consumer modules
2026-03-08 01:14:20 -05:00

100 lines
2.4 KiB
TypeScript

function getAuthHeader(): string {
const token = localStorage.getItem("token");
return token ? `Bearer ${token}` : "";
}
async function apiGet(url: string): Promise<Response> {
return fetch(`/api${url}`, {
headers: {
Authorization: getAuthHeader(),
"Content-Type": "application/json",
},
});
}
async function apiPost(url: string, data?: unknown): Promise<Response> {
return fetch(`/api${url}`, {
method: "POST",
headers: {
Authorization: getAuthHeader(),
"Content-Type": "application/json",
},
body: data ? JSON.stringify(data) : undefined,
});
}
async function apiPut(url: string, data?: unknown): Promise<Response> {
return fetch(`/api${url}`, {
method: "PUT",
headers: {
Authorization: getAuthHeader(),
"Content-Type": "application/json",
},
body: data ? JSON.stringify(data) : undefined,
});
}
async function apiDelete<T extends object>(
url: string,
data?: T,
): Promise<Response> {
return fetch(`/api${url}`, {
method: "DELETE",
headers: {
Authorization: getAuthHeader(),
"Content-Type": "application/json",
},
body: data ? JSON.stringify(data) : undefined,
});
}
async function apiPatch(url: string, data?: unknown): Promise<Response> {
return fetch(`/api${url}`, {
method: "PATCH",
headers: {
Authorization: getAuthHeader(),
"Content-Type": "application/json",
},
body: data ? JSON.stringify(data) : undefined,
});
}
async function handleResponse<T>(response: Response): Promise<T> {
if (!response.ok) {
const errorData = await response
.json()
.catch(() => ({ error: "Unknown error" }));
throw new Error(errorData.error || `HTTP ${response.status}`);
}
return response.json();
}
async function handleVoidResponse(response: Response): Promise<void> {
if (!response.ok) {
const errorData = await response
.json()
.catch(() => ({ error: "Unknown error" }));
throw new Error(errorData.error || `HTTP ${response.status}`);
}
}
function handleError(error: unknown, context: string): void {
console.error(`${context}:`, error);
const message =
error instanceof Error ? error.message : "An unexpected error occurred";
if ((window as any).showToast?.error) {
(window as any).showToast.error(message);
}
}
export {
apiGet,
apiPost,
apiPut,
apiDelete,
apiPatch,
handleResponse,
handleVoidResponse,
handleError,
};