refactor(api): code-review fixes (R7 S3b review round 1)
- barrel re-exports domains with `export type *` (not `export *`) so the internal downloadsApi/plexApi/messagingApi slices stay behind the façade; plex's runtime value exports (EMPTY_PLEX_FILTERS/plexFilterCount) re-exported explicitly - App.tsx: drop the now-redundant `prefs as Record<string, unknown>` self-cast (Me.preferences is already that type) and its `prefsRec` alias - plex.ts: comment why plexSetState keeps its status union inline (reusing VideoStatus would make an api.ts↔plex.ts type cycle) Behaviour-identical. Gate green: typecheck, eslint 0, prettier, 74 vitest.
This commit is contained in:
@@ -228,9 +228,8 @@ export default function App() {
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const prefs = meQuery.data?.preferences;
|
const prefs = meQuery.data?.preferences;
|
||||||
if (!prefs) return;
|
if (!prefs) return;
|
||||||
const prefsRec = prefs as Record<string, unknown>;
|
|
||||||
(["feed", "plex", "playlists"] as PanelId[]).forEach((p) => {
|
(["feed", "plex", "playlists"] as PanelId[]).forEach((p) => {
|
||||||
const raw = prefsRec[PREF_KEY[p]];
|
const raw = prefs[PREF_KEY[p]];
|
||||||
if (raw) {
|
if (raw) {
|
||||||
const l = normalizeLayout(p, raw);
|
const l = normalizeLayout(p, raw);
|
||||||
setPanelLayouts((prev) => ({ ...prev, [p]: l }));
|
setPanelLayouts((prev) => ({ ...prev, [p]: l }));
|
||||||
@@ -245,9 +244,9 @@ export default function App() {
|
|||||||
setFilterCollapsedState(prefs.filterCollapsed);
|
setFilterCollapsedState(prefs.filterCollapsed);
|
||||||
writeAccount(LS.filterCollapsed, prefs.filterCollapsed);
|
writeAccount(LS.filterCollapsed, prefs.filterCollapsed);
|
||||||
}
|
}
|
||||||
if (typeof prefsRec.playlistsCollapsed === "boolean") {
|
if (typeof prefs.playlistsCollapsed === "boolean") {
|
||||||
setPlaylistsCollapsedState(prefsRec.playlistsCollapsed);
|
setPlaylistsCollapsedState(prefs.playlistsCollapsed);
|
||||||
writeAccount(LS.playlistsCollapsed, prefsRec.playlistsCollapsed);
|
writeAccount(LS.playlistsCollapsed, prefs.playlistsCollapsed);
|
||||||
}
|
}
|
||||||
const lang = prefs.language;
|
const lang = prefs.language;
|
||||||
if (typeof lang === "string" && isSupported(lang)) setLanguage(lang);
|
if (typeof lang === "string" && isSupported(lang)) setLanguage(lang);
|
||||||
|
|||||||
@@ -18,14 +18,18 @@ export {
|
|||||||
setUnauthorizedHandler,
|
setUnauthorizedHandler,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Domain modules split out of this file, re-exported so their types + the `api` façade stay
|
// Domain modules split out of this file. Their TYPES are re-exported so consumers keep importing
|
||||||
// importable from "./api". Their method slices are spread into `api` below.
|
// them from "./api" unchanged; their method slices stay internal (`export type *`, not `export *`)
|
||||||
|
// and reach consumers only through the `api` façade they're spread into below. Runtime value
|
||||||
|
// exports a domain genuinely owns (e.g. plex's EMPTY_PLEX_FILTERS/plexFilterCount) are re-exported
|
||||||
|
// explicitly.
|
||||||
import { downloadsApi } from "./api/downloads";
|
import { downloadsApi } from "./api/downloads";
|
||||||
export * from "./api/downloads";
|
export type * from "./api/downloads";
|
||||||
import { plexApi } from "./api/plex";
|
import { plexApi } from "./api/plex";
|
||||||
export * from "./api/plex";
|
export type * from "./api/plex";
|
||||||
|
export { EMPTY_PLEX_FILTERS, plexFilterCount } from "./api/plex";
|
||||||
import { messagingApi } from "./api/messaging";
|
import { messagingApi } from "./api/messaging";
|
||||||
export * from "./api/messaging";
|
export type * from "./api/messaging";
|
||||||
|
|
||||||
export interface Me {
|
export interface Me {
|
||||||
id: number;
|
id: number;
|
||||||
|
|||||||
@@ -460,6 +460,8 @@ export const plexApi = {
|
|||||||
duration_seconds,
|
duration_seconds,
|
||||||
final,
|
final,
|
||||||
}),
|
}),
|
||||||
|
// Inline union (matches api.ts's VideoStatus by design) rather than importing VideoStatus — that
|
||||||
|
// lives in the api.ts barrel, which imports this module, so reusing it would make a type cycle.
|
||||||
plexSetState: (id: string, status: "new" | "watched" | "hidden"): Promise<unknown> =>
|
plexSetState: (id: string, status: "new" | "watched" | "hidden"): Promise<unknown> =>
|
||||||
req(`/api/plex/item/${encodeURIComponent(id)}/state`, {
|
req(`/api/plex/item/${encodeURIComponent(id)}/state`, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
|
|||||||
Reference in New Issue
Block a user