Files
yellowjacket/frontend/bindings/yellowjacket/backend/download/models.ts
T
yonluandClaude Opus 5 162c68769f feat(wails): move the frontend onto v3's generated bindings
frontend/wailsjs/ is deleted and frontend/bindings/ takes its place —
a real TypeScript module tree nested by Go import path, generated by
wails3's static analyser rather than by building the app and running
it.  The @go alias absorbs the constant prefix, so a call site imports
'@go/library/library.js' and the codemod over all 93 sites was a
specifier rewrite plus splitting @go/models' namespaces into one
import per package.

The 12 SetContext bindings and the fake `context` model are gone, as
Phase 2's ServiceStartup port promised: 272 methods across 12
services, none of them plumbing.

@runtime/runtime is now a local shim (src/wails/runtime.ts) over
@wailsio/runtime, so the 22 EventsOn imports are untouched.  It
unwraps v3's WailsEvent into v2's callback shape, which is exact here:
nothing in backend/events passes more than one data argument, and v3
only packs arguments into a slice when there is more than one.

v3 tells the truth about two things v2 lied about, and that is most of
the diff.  A Go nil slice really does arrive as JSON null, and a Go
named string type really is an enum; v2 typed them as T[] and string.
utils/binding.ts states the app's actual contract — an absent list is
an empty list — once, at the boundary where it is true, and also drops
the CancellablePromise the app never cancels.  Four test fixtures
widen an enum field back to its value union.

Not done, and Phase 5's to fix: frontend/test/support/wails-fake.ts
still fakes window.go, which v3 does not have, so `make ui-test` is
broken and harness.test.ts fails to compile on EventsEmit.  That test
also asserts v2 ordering that no longer holds — v3's Events.Emit calls
the backend and does not notify in-page listeners at all.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UDCbcCZQepnpSQYJ6SxxZm
2026-08-14 17:48:38 -04:00

733 lines
18 KiB
TypeScript

// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
// This file is automatically generated. DO NOT EDIT
/**
* AutoDownloadPrefs gates and scores what AutoPickable may choose
* without asking. Zero values are permissive: no size window and no
* format restriction.
*/
export interface AutoDownloadPrefs {
/**
* MinSizeMB and MaxSizeMB bound what auto-pick will grab. Zero
* means no bound on that side. A candidate outside the window is
* filtered out of auto-pick entirely, not merely scored down — a
* tiny "sampler" torrent or a boxset ten times the expected size is
* usually the wrong thing entirely, not a worse copy of the right
* thing.
*/
"minSizeMb": number;
"maxSizeMb": number;
/**
* PreferredSizeMB nudges the score toward a target size within the
* min/max window (a lossless rip and a heavily-padded lossless rip
* can both pass the window). Zero disables the nudge; sizeFit then
* returns a neutral value that does not affect ranking.
*/
"preferredSizeMb": number;
/**
* AllowedFormats restricts auto-pick to candidates whose audio
* files are all in one of these formats. Empty means no
* restriction.
*/
"allowedFormats": Format[] | null;
}
/**
* Candidate is one acquirable thing a provider found: a Soulseek user's
* folder, a torrent, a YouTube playlist. Providers fill the descriptive
* fields; the ranker fills Match, Quality and Score.
*/
export interface Candidate {
/**
* ID is unique within the provider that produced it, and is what
* gets handed back to Grab.
*/
"id": string;
"providerId": number;
"kind": Kind;
/**
* Protocol determines which transport can fetch this.
*/
"protocol": Protocol;
/**
* Descriptive.
*/
"title": string;
"artist"?: string;
/**
* peer username, indexer name, channel
*/
"origin"?: string;
"files": CandidateFile[] | null;
"totalSize": number;
/**
* Health is the provider's own availability signal, normalized to
* 0..1: seeder count for torrents, free upload slots and queue
* length for Soulseek. 0.5 when the provider has no signal.
*/
"health": number;
/**
* Scores, filled by the ranker.
*/
"match": MatchScore;
"quality": QualityScore;
"score": number;
}
/**
* CandidateFile is one file inside a candidate. Soulseek and torrent
* results give paths and sizes but no tags, so Format and duration are
* inferred from the path and size where possible.
*/
export interface CandidateFile {
"path": string;
"size": number;
"format": Format;
/**
* kbps, 0 when unknown
*/
"bitrate"?: number;
"isAudio": boolean;
/**
* expected track position
*/
"matchedTo"?: number;
}
/**
* Caps declares which roles a provider fills and which optional
* behaviours it supports. The frontend renders controls from this
* rather than switching on Kind, so a provider that gains resume
* support later needs no frontend change.
*/
export interface Caps {
/**
* Roles.
*/
"canSearch": boolean;
"canTransport": boolean;
"canDelegate": boolean;
/**
* CanList marks a provider that keeps a persistent wanted list of
* its own, which the reconciler mirrors this app's list into.
*/
"canList": boolean;
/**
* Optional behaviours.
*/
"canResume": boolean;
"canCancel": boolean;
"reportsSize": boolean;
/**
* Protocols this provider can transport. Empty for providers that
* only fetch their own search results.
*/
"transports": Protocol[] | null;
}
/**
* Config is a provider's stored settings. Secret values are not held
* here — they live in the secrets store keyed by provider ID, so a
* config blob can be logged or shown in the UI without redaction.
*/
export interface Config {
"id": number;
"kind": Kind;
"name": string;
"enabled": boolean;
"priority": number;
"settings": { [_ in string]?: string } | null;
/**
* SetSecrets names which of the descriptor's secret fields already
* have a stored value, without exposing it. Populated only when a
* Config is built for the frontend (see Service.withSecretFlags);
* empty when read from or written to the store.
*/
"setSecrets"?: { [_ in string]?: boolean } | null;
}
/**
* Descriptor is the static, instance-independent description of a
* provider kind: what it is called, what it can do, and which settings
* it needs. The settings page renders its form from this, so a new
* provider gets a config UI without any frontend work.
*/
export interface Descriptor {
"kind": Kind;
"name": string;
/**
* Summary is one line explaining what connecting this gets you.
*/
"summary": string;
/**
* Caps are the kind's inherent capabilities, before configuration.
*/
"caps": Caps;
/**
* Fields are the settings the user must supply.
*/
"fields": Field[] | null;
/**
* RequiresExternal names the software the user must run themselves
* (a slskd daemon, a Lidarr instance), or is empty for providers
* that need nothing but a binary on PATH.
*/
"requiresExternal"?: string;
}
/**
* DownloadItem is one grab attempt, as stored.
*
* deliberate: distinguishes it from download.Download (the attempt) and
* download.Request (the durable record) at every call site, which a bare
* "Item" would not.
*/
export interface DownloadItem {
"id": string;
"downloadId": string;
"providerId": number;
"transportId"?: number;
"externalId"?: string;
"candidate": Candidate;
"state": State;
"bytesDone": number;
"bytesTotal": number;
"error"?: string;
"createdAt": string;
"updatedAt": string;
}
/**
* DownloadView is one row of the downloads list.
*
* would stop reading as "one row of the Downloads list" the moment this
* package also has a Requests list — see RequestInput/Request nearby.
*/
export interface DownloadView {
"id": string;
/**
* Anchors. Any may be empty; all empty means free-text.
*/
"releaseMbid"?: string;
"releaseGroupMbid"?: string;
/**
* RecordingMBID anchors a single-track download. Its Expected holds
* exactly that one track, which is what lets a track download be
* scored — and therefore auto-picked — on the same footing as an
* album.
*/
"recordingMbid"?: string;
/**
* RequestID links back to the durable Request row this download was
* raised for or attached to, or 0 for a free-text download with
* nothing stable to attach to. The reconciler and manual anchored
* downloads both write the outcome back through it.
*/
"requestId"?: number;
/**
* Source records where the download came from, for the downloads
* list. Empty means "manual".
*/
"source"?: string;
/**
* Display and query text. Artist/Album are what searches are built
* from; Query overrides them when the user typed something raw.
*/
"artist": string;
"album": string;
"query"?: string;
/**
* Expected is the tracklist the anchor resolves to, used for
* completeness scoring and for the autotag match at import. Empty
* for free-text downloads.
*/
"expected"?: ExpectedTrack[] | null;
/**
* LibraryID is the library imported files belong to.
*/
"libraryId": number;
"createdAt": string;
"state": State;
"error"?: string;
"items": DownloadItem[] | null;
}
/**
* Entity says what a request's MBID names, and is the only type
* distinction the durable request list makes.
*/
export enum Entity {
/**
* The Go zero value for the underlying type of the enum.
*/
$zero = "",
/**
* Request entity types.
*
* EntityArtist is a subscription rather than a thing to fetch: it
* is never satisfied, and each reconcile expands the artist's
* discography into child requests.
*/
EntityArtist = "artist",
/**
* EntityReleaseGroup is an album in the abstract — any release of
* it satisfies the request, which is what a user means by "I want
* this album".
*/
EntityReleaseGroup = "release-group",
/**
* EntityRelease is one specific edition, used when the user picked
* a particular pressing.
*/
EntityRelease = "release",
/**
* EntityRecording is a single track.
*/
EntityRecording = "recording",
};
/**
* ExpectedTrack is one track of the release the user asked for.
*/
export interface ExpectedTrack {
"position": number;
"discNumber": number;
"title": string;
"artist": string;
"lengthMillis": number;
}
/**
* Field describes one provider setting for the settings form.
*/
export interface Field {
"key": string;
"label": string;
"placeholder"?: string;
"help"?: string;
/**
* Secret marks a value stored in the secrets store rather than the
* provider config row, and rendered as a password input.
*/
"secret": boolean;
/**
* Path marks a value that names a local filesystem directory, so
* the settings form can offer a native folder picker beside the
* text input rather than making the user type or paste it.
*/
"path": boolean;
"required": boolean;
"default"?: string;
}
/**
* Format is a normalized audio container/codec name.
*/
export enum Format {
/**
* The Go zero value for the underlying type of the enum.
*/
$zero = "",
/**
* Audio formats, ordered by the quality ranking in formatRank.
*/
FormatUnknown = "",
FormatFLAC = "flac",
FormatALAC = "alac",
FormatWAV = "wav",
FormatMP3 = "mp3",
FormatAAC = "aac",
FormatOGG = "ogg",
FormatOpus = "opus",
FormatWMA = "wma",
};
/**
* Kind identifies a provider implementation. It is stored in the
* database and used to look up the constructor in the registry, so
* values are stable strings and never renamed.
*/
export enum Kind {
/**
* The Go zero value for the underlying type of the enum.
*/
$zero = "",
/**
* Provider kinds.
*/
KindSlskd = "slskd",
KindYtDlp = "yt-dlp",
KindLidarr = "lidarr",
KindProwlarr = "prowlarr",
KindQBittorrent = "qbittorrent",
KindSABnzbd = "sabnzbd",
/**
* KindFake is an in-memory provider used by tests. It is never
* offered in the UI.
*/
KindFake = "fake",
};
/**
* MatchScore answers "is this the release the user asked for?" It is
* deliberately separate from QualityScore: a perfect match at 128kbps
* and a mediocre match in FLAC are different failures, and collapsing
* them into one number makes the ranking impossible to explain.
*/
export interface MatchScore {
/**
* Overall is 0..1.
*/
"overall": number;
/**
* filenames vs expected titles
*/
"titleFit": number;
/**
* path/origin vs expected artist
*/
"artistFit": number;
/**
* folder name vs album title
*/
"albumFit": number;
/**
* audio files vs expected count
*/
"completeness": number;
/**
* Anchored records whether an MBID drove this score. Unanchored
* matches are capped, because there is nothing to be right about.
*/
"anchored": boolean;
}
/**
* Protocol is how a candidate's bytes are moved. Search-only providers
* report it so the pipeline can pick a compatible transport; providers
* that transport their own results use ProtocolDirect.
*/
export enum Protocol {
/**
* The Go zero value for the underlying type of the enum.
*/
$zero = "",
/**
* Transport protocols.
*
* ProtocolDirect means the finding provider also does the fetch.
*/
ProtocolDirect = "direct",
ProtocolTorrent = "torrent",
ProtocolUsenet = "usenet",
};
/**
* QualityScore answers "is this a good copy?".
*/
export interface QualityScore {
/**
* Overall is 0..1.
*/
"overall": number;
/**
* FLAC > V0 > 320 > lower
*/
"formatRank": number;
"bitrate": number;
/**
* seeders, free slots
*/
"health": number;
/**
* user's per-provider preference
*/
"priority": number;
/**
* closeness to the preferred download size
*/
"sizeFit": number;
/**
* Mixed marks a candidate whose files are not all the same format,
* which usually means a hand-assembled folder rather than a rip.
*/
"mixed": boolean;
}
/**
* Reconciler works the request list.
*/
export interface Reconciler {
}
/**
* Request is one row of the durable request list.
*/
export interface Request {
"id": number;
"mbid": string;
"entity": Entity;
"libraryId": number;
/**
* Artist and Title are display cache only. Matching always uses
* the MBID.
*/
"artist": string;
"title": string;
"scope": RequestScope;
/**
* Secondary includes compilations, live albums and remixes in an
* artist request's expansion.
*/
"secondary": boolean;
"state": RequestState;
/**
* ParentID is set on requests the reconciler derived from an artist
* subscription. A request the user pinned directly has none, so
* removing the artist leaves it alone.
*/
"parentId"?: number;
"attempts": number;
"lastError"?: string;
"lastTriedAt"?: string;
"nextTryAt"?: string;
/**
* ExternalIDs maps provider row ID (as a string, because JSON
* object keys are strings) to that provider's own identifier for
* this request. Only set for providers that keep a persistent
* list of their own.
*/
"externalIds"?: { [_ in string]?: string } | null;
"createdAt": string;
"updatedAt": string;
}
/**
* RequestInput is what the frontend submits to request something. It
* is one MBID and the type of thing it names, because that is
* genuinely all a durable request is.
*/
export interface RequestInput {
"mbid": string;
"entity": string;
"libraryId": number;
/**
* Artist and Title are display text only, and optional: the
* reconciler fills them in from the catalog when the caller has
* nothing but an MBID.
*/
"artist": string;
"title": string;
/**
* Scope and Secondary apply to artist requests.
*/
"scope": string;
"secondary": boolean;
}
/**
* RequestScope applies to artist requests only.
*/
export enum RequestScope {
/**
* The Go zero value for the underlying type of the enum.
*/
$zero = "",
/**
* Artist request scopes.
*
* ScopeFuture takes only releases first published after the artist
* was added. Default, because subscribing to an artist should not
* silently queue their entire back catalogue.
*/
ScopeFuture = "future",
/**
* ScopeAll backfills the whole discography as well.
*/
ScopeAll = "all",
};
/**
* RequestState is where a request sits. There is deliberately no
* "failed": an attempt can fail, a request cannot. A request that has
* tried and not found anything is still wanted, with attempts and
* last_error recording why it is taking a while.
*/
export enum RequestState {
/**
* The Go zero value for the underlying type of the enum.
*/
$zero = "",
/**
* Request states.
*
* RequestStateWanted is the active state: due for another attempt
* when its backoff elapses.
*/
RequestStateWanted = "wanted",
/**
* RequestStateSatisfied means the library owns it. How it got
* there — downloaded here, ripped, bought elsewhere — does not
* matter.
*/
RequestStateSatisfied = "satisfied",
/**
* RequestStatePaused is the user saying "keep this on the list but
* stop trying".
*/
RequestStatePaused = "paused",
};
/**
* SearchRequest is what the frontend submits to start a download.
*/
export interface SearchRequest {
"libraryId": number;
"releaseMbid": string;
"releaseGroupMbid": string;
"artist": string;
"album": string;
"query": string;
"expected": ExpectedTrack[] | null;
}
/**
* StartResult is what the picker needs after a search.
*/
export interface StartResult {
"downloadId": string;
"candidates": Candidate[] | null;
/**
* AutoPicked reports that the pipeline already chose and is
* downloading, so the picker should show progress rather than a
* list of choices.
*/
"autoPicked": boolean;
}
/**
* State is the lifecycle position of a download item.
*/
export enum State {
/**
* The Go zero value for the underlying type of the enum.
*/
$zero = "",
/**
* Download item states. Searching through Importing are live;
* Complete, Cancelled and Failed are terminal.
*/
StateSearching = "searching",
StateFound = "found",
StateQueued = "queued",
StateGrabbing = "grabbing",
StateVerifying = "verifying",
StateTagging = "tagging",
StateImporting = "importing",
StateComplete = "complete",
StateCancelled = "cancelled",
StateFailed = "failed",
};
/**
* Summary reports what a pass did, for logging and for the UI.
*/
export interface Summary {
/**
* Expanded is how many child requests artist subscriptions produced.
*/
"expanded": number;
/**
* Satisfied is how many requests the library turned out to own.
*/
"satisfied": number;
/**
* Attempted is how many requests were searched for.
*/
"attempted": number;
/**
* Started is how many of those found a clear enough winner to
* download unattended.
*/
"started": number;
/**
* Synced is how many requests were pushed to an external list.
*/
"synced": number;
/**
* Waiting is how many requests are on the list and still being
* looked for. A pass that did nothing is the normal case, and the
* UI can only say so honestly if it knows the list was not empty.
*/
"waiting": number;
/**
* NoProviders reports that nothing could be searched because no
* download client is enabled — the one "nothing happened" the user
* can actually fix.
*/
"noProviders": boolean;
}