build(frontend): knip also checks what ships; strict indexing in every project

`npm run knip` now runs a second, --production pass, which asks whether the
code that ships uses an export, not just whether anything does. Of the 47
exports only tests reached:
- 34 are exported for their test and say so with @internal, naming the test.
- 11 were module-private names with a stray `export`. Two of them were not
  used at all and are deleted.
- The unused alreadyReported re-export is gone.
Test kits, the e2e suite and the two build-tooling modules are excluded from
the production project, each named in knip.jsonc.

noUncheckedIndexedAccess is now on for the node and e2e tsconfigs too (0
errors), matching the app project. tsconfig.node.json listed a
tailwind.config.js that has not existed since Tailwind 4. That entry is now
playwright.config.ts, which the typed lint finds through this project.
This commit is contained in:
2026-10-03 16:44:28 +02:00
parent cff8fe9a6a
commit 7ed2ac4e95
34 changed files with 84 additions and 33 deletions
+2 -2
View File
@@ -19,11 +19,11 @@ export type HeroTier = "resume" | "comfort" | "surprise";
* leads with `HERO_TIERS[start % 3]`, which is how a press can ASK for a tier. */
export const HERO_TIERS: readonly HeroTier[] = ["resume", "comfort", "surprise"];
export type DiscoverKind = "video" | "movie" | "show" | "episode" | "channel" | "playlist";
type DiscoverKind = "video" | "movie" | "show" | "episode" | "channel" | "playlist";
// What can go on the comfort shelf. `plex_item` covers a movie or a single episode; a show is pinned
// as `plex_show` because "put that show on" resolves to whichever episode is next.
export const PIN_KINDS = ["video", "channel", "plex_item", "plex_show", "playlist"] as const;
const PIN_KINDS = ["video", "channel", "plex_item", "plex_show", "playlist"] as const;
export type PinKind = (typeof PIN_KINDS)[number];
export interface DiscoverCard {
+1 -1
View File
@@ -58,7 +58,7 @@ export interface PlexCard {
// TMDB enrichment block (E5 S2), served from OUR DB (never a live TMDB call) on a movie/show detail.
// null until the row has been enriched. Powers the S5 enriched detail page: multi-source ratings row,
// facts sidebar, keyword chips (→ filter), and the full crew.
export interface PlexTmdbCrew {
interface PlexTmdbCrew {
name: string;
job: string;
tmdb_id?: number | null;
+5 -2
View File
@@ -2,8 +2,11 @@
// URL (de)serializer, the sidebar comboboxes, and the saved-view migration. Kept in its own leaf (no
// imports) so node-env tests and any module can pull it in without dragging the HTTP/i18n machinery.
/** A tag category's match: "or" = a channel with ANY selected tag passes, "and" = it must carry ALL. */
export type TagMode = "or" | "and";
/**
* A tag category's match: "or" = a channel with ANY selected tag passes, "and" = it must carry ALL.
* @internal exported for its test
*/
type TagMode = "or" | "and";
/** The three tag categories, each with its OWN independent match mode. */
export type TagCategory = "language" | "topic" | "other";
export type TagModes = Record<TagCategory, TagMode>;
+1 -1
View File
@@ -11,7 +11,7 @@ export interface Tag {
}
// One suggested user-tag for a channel, learned from the user's own manual-tag pattern (E8·S4).
export interface TagSuggestion {
interface TagSuggestion {
tag_id: number;
confidence: number;
}