feat: add reading settings sync
This commit is contained in:
@@ -0,0 +1,53 @@
|
||||
/**
|
||||
* Browser-side client for the user's roaming reading preferences.
|
||||
*
|
||||
* The BFF stores prefs as opaque JSONB keyed off the user. This module
|
||||
* just round-trips that blob — it makes no claim about its shape (that
|
||||
* contract is owned by components/reading-settings.tsx). All calls run
|
||||
* with `credentials: "include"` so the auth cookie comes along.
|
||||
*/
|
||||
|
||||
const BFF_BASE =
|
||||
process.env.NEXT_PUBLIC_BFF_URL || "http://localhost:8080";
|
||||
|
||||
type Envelope<T> = {
|
||||
success?: boolean;
|
||||
data?: T;
|
||||
error?: { code: number; message: string };
|
||||
};
|
||||
|
||||
async function call<T>(path: string, init?: RequestInit): Promise<T | null> {
|
||||
const res = await fetch(`${BFF_BASE}/api/v1${path}`, {
|
||||
credentials: "include",
|
||||
headers: { "Content-Type": "application/json", ...(init?.headers ?? {}) },
|
||||
...init,
|
||||
});
|
||||
if (res.status === 401 || res.status === 403) return null;
|
||||
if (!res.ok) {
|
||||
throw new Error(`reading-prefs ${path}: ${res.status}`);
|
||||
}
|
||||
const body = (await res.json().catch(() => ({}))) as Envelope<T>;
|
||||
return (body.data ?? null) as T | null;
|
||||
}
|
||||
|
||||
export const readingPrefsApi = {
|
||||
/** Fetches the caller's reading prefs blob. Returns `null` if the
|
||||
* request is unauthenticated (treat as "no remote prefs"). The blob
|
||||
* is the raw JSON object the frontend wrote last; an empty object
|
||||
* on first load. */
|
||||
async get(): Promise<Record<string, unknown> | null> {
|
||||
const data = await call<Record<string, unknown>>("/users/me/reading-prefs");
|
||||
return data ?? null;
|
||||
},
|
||||
|
||||
/** Overwrites the caller's reading prefs blob. The server stores the
|
||||
* payload verbatim (after canonicalising via re-marshal) — schema is
|
||||
* client-owned. Errors are swallowed by the caller; reading prefs
|
||||
* should never block a UI interaction. */
|
||||
async put(prefs: Record<string, unknown>): Promise<void> {
|
||||
await call<Record<string, unknown>>("/users/me/reading-prefs", {
|
||||
method: "PUT",
|
||||
body: JSON.stringify(prefs),
|
||||
});
|
||||
},
|
||||
};
|
||||
Reference in New Issue
Block a user