// State shared between popup and vault surfaces. Kept here (not in popup/) so // shared/state.ts can import without creating a popup→shared circular dep. import type { Item, ItemId, ItemType, ManifestEntry, GeneratorRequest, VaultSettings, } from './types'; export type View = | 'locked' | 'list' | 'detail' | 'add' | 'edit' | 'settings' | 'settings-vault' | 'trash' | 'devices' | 'field-history' // Vault-tab-only views; popup never navigates to these. Kept in the union so // a single typed StateHost contract serves both surfaces (popup + vault). | 'history' | 'backup' | 'import'; export interface PopupState { view: View; entries: Array<[ItemId, ManifestEntry]>; selectedId: ItemId | null; selectedItem: Item | null; selectedIndex: number; searchQuery: string; activeGroup: string | null; error: string | null; loading: boolean; // Captured tab snapshot taken at popup-open. Used by fill_credentials // to guard against TOCTOU navigation — the SW re-checks this URL's // hostname against the tab's live URL before forwarding fill_credentials // to the content script. See router/popup-only.ts#handleFillCredentials. capturedTabId: number | null; capturedUrl: string; newType: ItemType | null; vaultSettings: VaultSettings | null; generatorDefaults: GeneratorRequest | null; historyItemId: ItemId | null; // Vault-tab-only fields. The popup surface leaves these at their defaults // (unlocked=false implicit via separate lock-screen view, drawer/panel false). // Kept on the shared shape so VaultState satisfies StateHost.getState() // without a cast. unlocked?: boolean; drawerOpen?: boolean; typePanelOpen?: boolean; }