Files
ersatztv/web/src/api/index.ts
T
timothyandClaude Opus 5 39c4e8df0a fix(651): review round 8 — put the selection-id predicate at the boundary, not the site
Round 7 added the int32 check inside `isSearchPickerOption` — the place the defect was found
— which left every other door into editor state open. A malformed successful response
carrying `1.5` or `2147483648` still entered `draft` through list-backed options and through
the selection restored from the detail read, keeping Save enabled and sending a value the API
cannot bind, while the identical value arriving via SearchPicker was correctly rejected.

The predicate now lives once, in `web/src/api/selectionId.ts`, and sits on every path by
which an id from the wire becomes editor state. The class crosses all three screens, not just
the one the finding named, so all three are covered:
- RerunCollectionsScreen: `toPickerOptions` (3 list branches) + `draftFromRerun`
- PlaylistsScreen: `toPickerOptions` (3 list branches) + `draftFromItem` (4 id fields)
- FillerPresetsScreen: `draftFromPreset` (5 id fields) + the collection-family browse options
- pickers.tsx: `isSearchPickerOption` now delegates rather than carrying its own copy

An unbindable id is treated as ABSENT, never coerced — rounding 1.5 to 1 would submit a
DIFFERENT record — so it surfaces as "no selection" with Save disabled and a visible reason;
an option that cannot be selected safely is dropped rather than rendered. Five regressions
assert zero writes are reachable via each previously-unguarded path.

Also corrects two of my own test descriptions, per the review: the padded-ETag test is a
regression guard rather than a round-7 defect demonstration (Headers strips outer whitespace
before the app sees it), and the late-settlement test guards the abort/race COMPOSITION —
what it actually fails is an abort-only implementation whose fetch ignores its signal, which
is why its stub ignores `init.signal`.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-27 04:25:14 +02:00

41 lines
1.2 KiB
TypeScript

export * from './artwork';
export * from './auth';
export * from './autoTune';
export * from './blocks';
export * from './channels';
export * from './channelTemplates';
export * from './client';
export * from './collections';
export * from './dashboard';
export * from './decos';
export * from './decoTemplates';
export * from './ffmpegProfiles';
export * from './fillerPresets';
export * from './graphicsElements';
export * from './guide';
export * from './imageFolders';
export * from './languages';
export * from './libraries';
export * from './libraryBrowse';
export * from './selectionId';
export * from './logs';
export * from './maintenance';
export * from './mediaDetail';
export * from './mediaItems';
export * from './mediaSources';
export * from './multiCollections';
export * from './paging';
export * from './pickers';
export * from './playlists';
export * from './playoutHistory';
export * from './playouts';
export * from './rerunCollections';
export * from './schedules';
export * from './search';
export * from './settings';
export * from './templates';
export * from './trakt';
export * from './troubleshoot';
export * from './useChannelsQuery';
export * from './watermarks';