/** Parsed at:// URI. */ export interface AtUri { did: string collection: string rkey: string } /** site.standard.publication record value. */ export interface PublicationRecord { $type: 'site.standard.publication' url: string name: string description?: string /** * Declared as a blob, but records are third-party data: publishers in the * wild also put a plain path string here. Read it through `isBlobRef`. */ icon?: unknown } /** site.standard.document record value. */ export interface DocumentRecord { $type: 'site.standard.document' site: string title: string publishedAt: string path?: string description?: string /** * Structured body (an open union of publishing-tool formats). Only its * presence matters to us: readers render in-app from `content`, not from * plain `textContent`. */ content?: unknown } export interface BlobRef { $type: 'blob' ref: { $link: string } mimeType: string size: number } /** What we know about the publication behind a tab's page. */ export interface PubInfo { uri: string did: string handle?: string pds: string record: PublicationRecord iconUrl?: string /** Confirmed via .well-known lookup at the publication's URL. */ verified: boolean } export interface DocInfo { uri: string record: DocumentRecord } /** * Why detection could not produce a definite answer. Distinct from "no * publication found": with an error set, pub/doc are unknown, not absent. */ export type DetectionError = 'offline' | 'fetch-failed' /** Per-tab detection result, held by the background worker. */ export interface PageState { url: string fetchedAt: number pub?: PubInfo doc?: DocInfo /** Rkey of our subscription record, if subscribed. Null = known unsubscribed, undefined = unknown (e.g. logged out). */ subscriptionRkey?: string | null /** * The signed-in account blocks the DID this publication belongs to. * Undefined = unknown (signed out, or the block list could not be read); * a block is only ever asserted, never guessed. */ blocked?: boolean /** Set when detection itself failed rather than finding nothing. */ error?: DetectionError } export interface SessionInfo { did: string handle?: string /** Avatar blob URL on the account's PDS; absent when there is none. */ avatarUrl?: string } /** * What the worker answers a `follows` message with. Null means the question * has no answer — signed out, or the walk failed — which every caller draws as * nothing rather than as "you follow nobody". */ export interface FollowSet { /** Whose follows these are. The account can change between ask and answer. */ did: string dids: string[] /** The walk stopped at its cap, so absence from `dids` is not a "no". */ truncated: boolean } /** Messages between content script / popup and the background worker. */ export type Msg = | { type: 'page-hints'; pubHint?: string; docHint?: string } | { type: 'get-state'; tabId: number; refresh?: boolean } | { type: 'signin'; handle: string } | { type: 'follows'; refresh?: boolean } /** Dev channel only: forget every cached read. Answers `{dropped}`. */ | { type: 'drop-caches' } /** * Messages from the worker to the offscreen document that hosts the OAuth * client. `target` routes them: the worker's listener ignores these, and the * offscreen listener handles nothing else. */ export type OffscreenMsg = | { target: 'offscreen'; type: 'oauth-authorize'; handle: string } | { target: 'offscreen'; type: 'oauth-callback'; url: string } | { target: 'offscreen'; type: 'oauth-revoke'; sub: string }