Files
bookhoard/web/src/api.ts
T
john-okeefe f85c9c3f66 refactor(reader): Fix reader-context imports and remove dead code
Problem:
- Many format modules imported from '../core/reader-context'
- reader-context.ts was a local interface file, not a true context module
- Confusion between canonical reader-shell.ts and local reader-context.ts
- PDF page-cache.ts was 100% dead code (unused, unregistered, no exports)
- Several unused variables and imports across reader modules

Root Cause:
- reader-context.ts created as temporary file during refactoring
- Modules imported from it instead of canonical reader-shell.ts
- page-cache.ts copied from comic version but never integrated
- Incomplete refactoring left behind unused code

Solution:
- Update all imports to use reader-shell (canonical source)
- Remove unused page-cache.ts (dead code)
- Clean up unused variables and imports
- Consolidate type definitions

Changes:

Import Path Updates:
- comic/*: '../core/reader-context' → '../../reader-shell'
- manga/*: '../core/reader-context' → '../../reader-shell'
- pdf/*: '../core/reader-context' → '../../reader-shell'
- reflowable/ebook/*: '../core/reader-context' → '../../reader-shell'
- All now import UniversalReader from single source

Dead Code Removal:
- pdf/page-cache.ts: Deleted entirely
  - No init() function exported
  - Not registered in reader-shell.ts
  - All functions unused (createPDFPageCache, getCachedPage, etc.)
  - Only 2 lines of executable code (console.log, DOM cleanup)
  - 148 lines of dead code

Clean Up:
- navigator-panel.ts: Remove unused containerRect variable
- api-explorer-docs.ts, api.ts, queue.ts: Fix unused imports
- unlinked_books.ts: Remove unused variables
- panel-dock-system.ts: Remove unused context variables

Impact:
-  All modules use canonical type definitions
-  No more duplicate/conflicting interfaces
-  Dead code removed (148 lines)
-  Cleaner imports, easier maintenance
-  TypeScript compiler warnings resolved

Files changed: 26
Lines changed: +450, -520 (net -70 lines)
2026-04-10 23:21:44 -04:00

153 lines
3.7 KiB
TypeScript

import { Alpine } from "./alpine";
import { showToast } from "./toast";
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";
showToast(message, "error");
}
// ============================================================
// Reader API Functions
// ============================================================
interface ReadingProgress {
current_page: number;
total_pages: number;
cfi?: string;
percentage?: number;
last_read_at: string;
}
async function getReaderMetadata(mediaItemId: string): Promise<ReaderMetadata> {
const response = await apiGet(`/media-items/${mediaItemId}`);
return handleResponse<ReaderMetadata>(response);
}
async function updateReadingProgress(
mediaItemId: string,
progress: ReadingProgress,
): Promise<void> {
const response = await apiPut(
`/media-items/${mediaItemId}/progress`,
progress,
);
await handleVoidResponse(response);
}
async function getReadingProgress(
mediaItemId: string,
): Promise<ReadingProgress | null> {
const response = await apiGet(`/media-items/${mediaItemId}/progress`);
if (response.status === 404) {
return null;
}
return handleResponse<ReadingProgress>(response);
}
export {
apiGet,
apiPost,
apiPut,
apiDelete,
apiPatch,
handleResponse,
handleVoidResponse,
handleError,
getReaderMetadata,
getReadingProgress, // ADD THIS
updateReadingProgress,
ReadingProgress,
};
Alpine.data("api", () => ({
get: apiGet,
post: apiPost,
put: apiPut,
delete: apiDelete,
patch: apiPatch,
handleResponse: handleResponse,
handleVoidResponse: handleVoidResponse,
handleError: handleError,
}));