/** * Per-account registry of Outlook mailboxes. * * A sub-account can hold N mailboxes at once. Each mailbox is its own encrypted * `tokens.enc` under `secrets/outlook/mailboxes//`, sharing the one * account-level AES `.key`. This registry enumerates them, migrates the legacy * single-mailbox layout on first read, and resolves a caller's mailbox selector * down to the right TokenStore. * * Migration preserves the AES key, so the legacy ciphertext is valid as-is under * the new path — migration is a file move, never a re-encrypt, and never forces * a re-auth. */ import { TokenStore } from "./token-store.js"; /** * A mailbox's usability at a glance, so a bare directory count is never read as * "connected". Distinct from `readable`: a blob can decrypt cleanly yet still be * unusable for addressing. * - `unreadable` — the blob failed to decrypt or parse. * - `blank-email` — readable, but `mail` is blank, so it cannot be resolved * by its email address (the record reads as present but is * not addressable). * - `refresh-expired` — readable with an email, but the refresh token has * lapsed, so tokens can no longer be minted without re-auth. * - `ok` — readable, addressable by email, refresh token valid. */ export type MailboxStatus = "unreadable" | "blank-email" | "refresh-expired" | "ok"; export interface MailboxDescriptor { /** Sanitized directory name under `mailboxes/` — an opaque handle. */ mailboxKey: string; graphUserId: string | null; mail: string | null; scopes: string[]; tokenExpSec: number | null; refreshExpired: boolean; /** false when the blob failed to decrypt or parse — surfaced, not hidden. */ readable: boolean; /** Derived usability — see MailboxStatus. Only `ok` is addressable now. */ status: MailboxStatus; } /** * Classify a mailbox's usability from its readable/mail/refresh facts. Pure and * total, evaluated in precedence order so the most blocking condition wins: * unreadable → blank-email → refresh-expired → ok. Kept separate from * `describe()` so the classification is unit-testable without a store on disk. */ export declare function mailboxStatus(d: { readable: boolean; mail: string | null; refreshExpired: boolean; }): MailboxStatus; export type ResolveResult = { kind: "ok"; store: TokenStore; descriptor: MailboxDescriptor; } | { kind: "none"; } | { kind: "ambiguous"; identities: string[]; } | { kind: "notfound"; selector: string; identities: string[]; }; export interface CredResolveEvent { event: "cred-resolve"; account: string; mailbox: string; source: "arg" | "sole" | "none" | "refused"; } /** * The observability line for a resolution: names the *resolved* mailbox and how * it was chosen, so a wrong or absent selector is diagnosable from one line * without decrypting the store. Pure — computed from the resolve result and the * caller's selector, so selection (not a silent default) is testable. */ export declare function credResolveEvent(resolved: ResolveResult, account: string, selector?: string): CredResolveEvent; export declare class MailboxRegistry { readonly accountId: string; private readonly accountsDir; private readonly secretsDir; private readonly mailboxesDir; private readonly legacyTokensPath; constructor(accountId: string, accountsDir: string); /** * Move a pre-migration `secrets/outlook/tokens.enc` into * `mailboxes//tokens.enc`. Idempotent: a no-op once the legacy * file is gone. Reads the blob only to learn its mailbox key; the ciphertext * itself is moved unchanged (same account key). */ private migrateLegacy; /** Every mailbox attached to this account, migrating legacy on first read. */ list(): MailboxDescriptor[]; private describe; /** * Resolve a mailbox selector to a TokenStore. Order: explicit selector * (matched against graphUserId or mail, case-insensitive) → the sole readable * mailbox → ambiguous (≥2 readable, none named) → none (zero readable). * Unreadable mailboxes are never addressable. */ resolve(selector?: string): ResolveResult; /** A TokenStore for a specific mailbox key (a graphUserId at register time, or * a descriptor's mailboxKey). Overwrites that mailbox in place on store(). */ storeFor(mailboxKey: string): TokenStore; } //# sourceMappingURL=mailbox-registry.d.ts.map