books-ui: library, detail page, EPUB/PDF reader, reading status/rating/sessions migration, progress/notes APIs, owner gating and tests

This commit is contained in:
2026-10-24 01:06:33 +00:00
parent 8b2dfed239
commit 9c46e281c2
65 changed files with 25709 additions and 24 deletions

View File

@@ -19,9 +19,32 @@ export function requireOwner(event: OwnerEvent) {
}
/** Paths that only the owner may see (checked in hooks.server.ts before any route runs). */
export const ownerOnlyPrefixes = ['/trackers/health'] as const;
export const ownerOnlyPrefixes = ['/trackers/health', '/trackers/books/files'] as const;
/**
* Owner-only paths inside otherwise public areas: the book reader and its progress/notes
* APIs. /trackers/books and /trackers/books/<id> themselves are public catalogue pages.
*/
export const ownerOnlyPatterns = [/^\/trackers\/books\/\d+\/(read|progress|notes)(\/|$)/] as const;
/**
* Areas where only the owner may write: any non-GET request from anyone else is refused
* (404) in hooks.server.ts, which also covers form actions on the public book pages.
*/
export const ownerWritePrefixes = ['/trackers/health', '/trackers/books'] as const;
const normalise = (pathname: string) => pathname.toLowerCase().replace(/\/+$/, '');
const under = (path: string, prefix: string) => path === prefix || path.startsWith(`${prefix}/`);
export function isOwnerOnlyPath(pathname: string): boolean {
const path = pathname.toLowerCase().replace(/\/+$/, '');
return ownerOnlyPrefixes.some((prefix) => path === prefix || path.startsWith(`${prefix}/`));
const path = normalise(pathname);
return (
ownerOnlyPrefixes.some((prefix) => under(path, prefix)) ||
ownerOnlyPatterns.some((pattern) => pattern.test(path))
);
}
export function isOwnerWritePath(pathname: string): boolean {
const path = normalise(pathname);
return ownerWritePrefixes.some((prefix) => under(path, prefix));
}