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(() => {
|
||||
const prefs = meQuery.data?.preferences;
|
||||
if (!prefs) return;
|
||||
const prefsRec = prefs as Record<string, unknown>;
|
||||
(["feed", "plex", "playlists"] as PanelId[]).forEach((p) => {
|
||||
const raw = prefsRec[PREF_KEY[p]];
|
||||
const raw = prefs[PREF_KEY[p]];
|
||||
if (raw) {
|
||||
const l = normalizeLayout(p, raw);
|
||||
setPanelLayouts((prev) => ({ ...prev, [p]: l }));
|
||||
@@ -245,9 +244,9 @@ export default function App() {
|
||||
setFilterCollapsedState(prefs.filterCollapsed);
|
||||
writeAccount(LS.filterCollapsed, prefs.filterCollapsed);
|
||||
}
|
||||
if (typeof prefsRec.playlistsCollapsed === "boolean") {
|
||||
setPlaylistsCollapsedState(prefsRec.playlistsCollapsed);
|
||||
writeAccount(LS.playlistsCollapsed, prefsRec.playlistsCollapsed);
|
||||
if (typeof prefs.playlistsCollapsed === "boolean") {
|
||||
setPlaylistsCollapsedState(prefs.playlistsCollapsed);
|
||||
writeAccount(LS.playlistsCollapsed, prefs.playlistsCollapsed);
|
||||
}
|
||||
const lang = prefs.language;
|
||||
if (typeof lang === "string" && isSupported(lang)) setLanguage(lang);
|
||||
|
||||
@@ -18,14 +18,18 @@ export {
|
||||
setUnauthorizedHandler,
|
||||
};
|
||||
|
||||
// Domain modules split out of this file, re-exported so their types + the `api` façade stay
|
||||
// importable from "./api". Their method slices are spread into `api` below.
|
||||
// Domain modules split out of this file. Their TYPES are re-exported so consumers keep importing
|
||||
// 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";
|
||||
export * from "./api/downloads";
|
||||
export type * from "./api/downloads";
|
||||
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";
|
||||
export * from "./api/messaging";
|
||||
export type * from "./api/messaging";
|
||||
|
||||
export interface Me {
|
||||
id: number;
|
||||
|
||||
@@ -460,6 +460,8 @@ export const plexApi = {
|
||||
duration_seconds,
|
||||
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> =>
|
||||
req(`/api/plex/item/${encodeURIComponent(id)}/state`, {
|
||||
method: "POST",
|
||||
|
||||
Reference in New Issue
Block a user