The judge's query read all of entries (605 MB, 566 ms) on every wake; an index on each feed's items by date, as the query asks, and the rechecks in a half of their own. Calls ran one at a time, about 150 ms each, so a new Signal's month of about 8,000 items took twenty minutes: six in flight now. On the server's key everyone's Signals on an item share one call. TypeSafe's token counts go to /metrics and each jev span. An item's text is cut at 1,000 characters instead of 2,000: on 55 real items of eight podcast feeds and six Signals, on the development key, 1,000 changed none of 330 verdicts (nor did the same request twice) and saved 12% of the input tokens, 1,266 to 1,112 a call; 500 changed one. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
175 lines
4.6 KiB
TypeScript
175 lines
4.6 KiB
TypeScript
// 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 TypeSafe key is saved for Signals; the key itself never comes back.
|
|
typesafe_key_set: boolean;
|
|
/// Whose TypeSafe key Signals are judged on (#271): the server's, for everyone, or each person's own.
|
|
signals: 'server' | 'own';
|
|
/// How many days back a new Signal reads (#276), an admin's setting.
|
|
signal_days: number;
|
|
}
|
|
|
|
/// A Signal in your sidebar, `/api/signals` (db.rs SignalRow).
|
|
interface Signal {
|
|
id: number;
|
|
name: string;
|
|
keywords: string[];
|
|
/// What its owner means by it, in their words (#259).
|
|
description: string | null;
|
|
/// A Font Awesome Free icon, `solid/robot`, in place of its initials (#261).
|
|
icon: string | null;
|
|
/// The items it holds, read or not, and of those the unread.
|
|
items: number;
|
|
unread: number;
|
|
}
|
|
|
|
/// 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[];
|
|
signals: Signal[];
|
|
/// 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'};
|
|
}
|
|
|
|
/// An account, `/api/users` (web.rs list_users).
|
|
interface Account {
|
|
id: number;
|
|
name: string;
|
|
admin: boolean;
|
|
/// Has a password; none signs in through the proxy.
|
|
password: boolean;
|
|
created: number | null;
|
|
last_login: number | null;
|
|
}
|
|
|
|
/// A line of the daemon's log, `/api/logs` (logbuf.rs LogLine).
|
|
interface LogLine {
|
|
seq: number;
|
|
ts: number;
|
|
level: string;
|
|
target: string;
|
|
msg: string;
|
|
}
|
|
|
|
/// `/api/directory-admin`: the servers sharing with the directory and the feeds it blocks
|
|
/// (directory lib.rs Instance, Blocked).
|
|
interface DirAdmin {
|
|
instances: {name: string, feeds: number, subscribers: number}[];
|
|
blocked: {id: string, url: string | null, title: string | null, at: number}[];
|
|
}
|
|
|
|
/// One of a listed feed's latest items, on its page in the Directory (web.rs ListedItem): never
|
|
/// its files.
|
|
interface ListedItem {
|
|
guid: string;
|
|
title: string | null;
|
|
link: string | null;
|
|
published: number | null;
|
|
duration: number | null;
|
|
description: string | null;
|
|
}
|