import type { AppBskyActorDefs } from '@atcute/bluesky';
import type { Did, GenericUri, Handle } from '@atcute/lexicons';
import type { JsonValue } from 'type-fest';
import type { Gif } from '#/lib/gif';
import type { Locale } from '#/paraglide/runtime';
/** emoji skin tone: 1 = default/yellow, 2–6 = the five Fitzpatrick tones. */
export type SkinTone = 1 | 2 | 3 | 4 | 5 | 6;
/** Data that's specific to the device and does not vary based account */
export type Device = {
/** The paraglide locale for UI translations. Resolved once into `LOCALE`; changing it reloads. */
appLanguage?: Locale;
colorMode?: 'dark' | 'light' | 'system';
/** BCP-47 2-letter language codes the user can read, passed to feeds. */
contentLanguages?: string[];
darkTheme?: 'dark' | 'dim';
debugFeedContextEnabled?: boolean;
/**
* Formerly managed by StatSig, this is the migrated stable ID for the device, used with our logging and
* metrics tracking.
*/
deviceId?: string;
devMode: boolean;
disableAutoplay?: boolean;
/** selected emoji skin tone. */
emojiSkinTone?: SkinTone;
fontFamily: 'system' | 'theme';
fontScale: '-2' | '-1' | '0' | '1' | '2';
largeAltBadgeEnabled?: boolean;
/** The user's own OpenRouter API key. */
openrouterApiKey?: string;
/** OpenRouter model slug used to draft image descriptions, e.g. `google/gemini-2.5-flash`. */
openrouterImageDescriptionModel?: string;
/** OpenRouter model slug used to translate posts, e.g. `google/gemini-2.5-flash`. */
openrouterTranslationModel?: string;
pdsAddressHistory?: string[];
/** Comma-separated BCP-47 2-letter language code(s) the user is currently posting in. */
postLanguage?: string;
/** Previously used {@link Device.postLanguage} values, used to pre-populate the composer selector. */
postLanguageHistory?: string[];
/** BCP-47 2-letter language code to translate posts into. */
primaryLanguage?: string;
queryCacheBuster?: string;
/** recently picked emoji ids, most recent first. */
recentEmojis?: string[];
requireAltTextEnabled?: boolean;
subtitlesEnabled?: boolean;
trendingEnabled?: boolean;
};
/**
* One entry in the unified, recency-ordered search history. New entry kinds (feeds, starter packs, …) extend
* this union without splitting the stored list.
*/
export type SearchHistoryEntry = { kind: 'profile'; did: Did } | { kind: 'query'; query: string };
export type Account = {
labelers?: Did[];
/** selected feed URI, or `'following'`. */
lastSelectedHomeFeed?: string;
/** Recently selected GIFs in the GIF picker. Most recent first, capped at 20. */
recentGifs?: Gif[];
/** Unified search history (queries and visited profiles), most recent first. */
searchHistory?: SearchHistoryEntry[];
};
export type Auth = {
session?: AuthSession;
};
export type AuthSession = {
accounts: AuthAccount[];
currentAccountDid?: Did;
};
export type AuthAccount = {
did: Did;
handle: Handle;
/** cached display data. */
profile?: AuthAccountProfile;
};
/** profile fields cached for account UI. */
export type AuthAccountProfile = {
/** labeler flag used for avatar shape. */
associated?: Pick<AppBskyActorDefs.ProfileAssociated, 'labeler'>;
/** avatar URI. */
avatar?: GenericUri;
/** display name. */
displayName?: string;
/** statuses used by verification badges. */
verification?: Pick<AppBskyActorDefs.VerificationState, 'trustedVerifierStatus' | 'verifiedStatus'>;
};
export type QueryCacheScope = Did | 'logged-out';
export type QueryCache = {
[queryHash: string]: PersistedQueryEntry;
};
export type PersistedQueryEntry = {
data: JsonValue;
dataUpdatedAt: number;
expiresAt: number;
version: number;
};