Page type-check: types for what the API sends, and for S (#235)
web/src/types.ts mirrors FeedRow, EntryRow, EncRow, /api/me and PopularRow; types only, so swc strips it and it is not in build.mjs's list. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
115
web/src/types.ts
Normal file
115
web/src/types.ts
Normal file
@@ -0,0 +1,115 @@
|
|||||||
|
// What ipx's API sends the page, as types for the type-check (#235), each named after the Rust
|
||||||
|
// struct it mirrors in crates/ipx/src. Types only: swc strips this file to nothing, so it is not
|
||||||
|
// in web/build.mjs's list; tsconfig.json's glob reads it. A field added there goes here too.
|
||||||
|
// An Option is `T | null`, as serde writes None.
|
||||||
|
|
||||||
|
/// A feed in your list, `/api/feeds` and the live `feed_row` (web.rs FeedRow).
|
||||||
|
interface Feed {
|
||||||
|
id: string;
|
||||||
|
url: string;
|
||||||
|
title: string | null;
|
||||||
|
image: string | null;
|
||||||
|
folder: string | null;
|
||||||
|
category: string | null;
|
||||||
|
feed_category: string | null;
|
||||||
|
keywords: string[];
|
||||||
|
blocked: string[];
|
||||||
|
deadair: boolean;
|
||||||
|
deadair_pause: number;
|
||||||
|
allow_explicit: boolean;
|
||||||
|
auto_download: boolean;
|
||||||
|
max_new_per_check: number | null;
|
||||||
|
/// The OPML subscription it came from.
|
||||||
|
group: string | null;
|
||||||
|
orphaned: boolean;
|
||||||
|
managed: boolean;
|
||||||
|
schedule: string | null;
|
||||||
|
schedule_mins: number | null;
|
||||||
|
every_mins: number;
|
||||||
|
last_checked: number | null;
|
||||||
|
next_check: number | null;
|
||||||
|
last_error: string | null;
|
||||||
|
failing: {reason: string, new_url: string | null} | null;
|
||||||
|
entries: number;
|
||||||
|
downloaded: number;
|
||||||
|
unread: number;
|
||||||
|
subscribers: number;
|
||||||
|
pinned: boolean;
|
||||||
|
private: boolean;
|
||||||
|
private_by_address: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// An item, in a page of `/api/entries` (db.rs EntryRow).
|
||||||
|
interface Entry {
|
||||||
|
guid: string;
|
||||||
|
feed_id: string;
|
||||||
|
title: string | null;
|
||||||
|
link: string | null;
|
||||||
|
published: number | null;
|
||||||
|
description: string | null;
|
||||||
|
read: boolean;
|
||||||
|
flagged: boolean;
|
||||||
|
image: string | null;
|
||||||
|
duration: number | null;
|
||||||
|
episode: number | null;
|
||||||
|
season: number | null;
|
||||||
|
position: number;
|
||||||
|
enclosures: Enclosure[];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// An item's file (db.rs EncRow).
|
||||||
|
interface Enclosure {
|
||||||
|
id: number;
|
||||||
|
/// Seconds DeadAir's copy saves, when you play it from one.
|
||||||
|
deadair?: number | null;
|
||||||
|
deadair_pending?: boolean;
|
||||||
|
feed_id: string;
|
||||||
|
guid: string;
|
||||||
|
url: string;
|
||||||
|
mime: string | null;
|
||||||
|
length: number | null;
|
||||||
|
path: string | null;
|
||||||
|
state: string;
|
||||||
|
last_error: string | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// `/api/me`.
|
||||||
|
interface Me {
|
||||||
|
name: string;
|
||||||
|
admin: boolean;
|
||||||
|
sign_out: string;
|
||||||
|
blocked: string[];
|
||||||
|
deadair_saved: number;
|
||||||
|
theme: {name: string, mode: string} | null;
|
||||||
|
version: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A feed as the Directory lists it (web.rs PopularRow): never its address.
|
||||||
|
interface DirFeed {
|
||||||
|
id: string;
|
||||||
|
title: string | null;
|
||||||
|
image: string | null;
|
||||||
|
subscribers: number;
|
||||||
|
subscribed: boolean;
|
||||||
|
/// Its id in your list, when it is yours.
|
||||||
|
feed: string | null;
|
||||||
|
category: string | null;
|
||||||
|
subcategory: string | null;
|
||||||
|
podcast: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The page's own state (util.ts `S`).
|
||||||
|
interface State {
|
||||||
|
feeds: Feed[];
|
||||||
|
/// The feed or place open: a feed's id, or a view such as ':all'.
|
||||||
|
feed: string | null;
|
||||||
|
entries: Entry[];
|
||||||
|
total: number;
|
||||||
|
offset: number;
|
||||||
|
filter: string;
|
||||||
|
q: string;
|
||||||
|
/// The selected item's guid.
|
||||||
|
sel: string | null;
|
||||||
|
me: Me | null;
|
||||||
|
sort: {col: string, dir: 'asc' | 'desc'};
|
||||||
|
}
|
||||||
@@ -215,7 +215,7 @@ function folderArt(f,kids){
|
|||||||
function nav(on){ $('#sidebar').classList.toggle('open',on); $('#scrim').hidden=!on; }
|
function nav(on){ $('#sidebar').classList.toggle('open',on); $('#scrim').hidden=!on; }
|
||||||
|
|
||||||
/* ---------------- state ---------------- */
|
/* ---------------- state ---------------- */
|
||||||
const S = {
|
const S: State = {
|
||||||
feeds:[],
|
feeds:[],
|
||||||
// Which feed (or place) and which tab were open last time, so a refresh lands back where
|
// Which feed (or place) and which tab were open last time, so a refresh lands back where
|
||||||
// you were instead of jumping to the first feed alphabetically.
|
// you were instead of jumping to the first feed alphabetically.
|
||||||
|
|||||||
Reference in New Issue
Block a user