import { type KeyringEntryFactory } from "./keyringBinding"; import type { TokenSet } from "./tokenResponse"; /** * Whether `KeyringTokenStore` should split the stored blob across * multiple keychain entries on this platform. Windows-only: Credential * Manager has a 2560-byte per-entry cap that large OAuth tokens * routinely exceed. macOS Keychain and Linux libsecret have no * comparable limit, and on macOS each entry is independently lockable * (chunking there would multiply per-entry ACL prompts). Exported * (parameterized for tests) so the chunking path can be exercised * deterministically. */ export declare function shouldChunkForKeyring(platform?: NodeJS.Platform): boolean; /** * Current on-disk blob schema version. Exported so consumers can * display "stored v:N, expected v:M" diagnostics when `load()` returns * a `version-mismatch` result. */ export declare const STORED_BLOB_VERSION = 1; /** * What `KeyringTokenStore` persists: the OAuth tokens plus the * issuer/client coordinates they were minted against. Carrying the * coordinates inside the entry means a verb can recover its full * config from the keychain alone, with no separate "default issuer" * pointer. */ export interface StoredEntry { tokens: TokenSet; /** OIDC issuer URL the tokens were minted against. */ issuerURL: string; /** OAuth client ID used at login. */ clientId: string; /** Whether the original login allowed a non-loopback http issuer. */ allowInsecureIssuer: boolean; /** * Originating axe server (walnut) URL the user supplied (or the * SaaS prod default) at login. */ walnutURL: string; } /** * Outcome of a `TokenStore.load()` call. * * Note on downgrades: the migrator chain only walks *forward*. A user * who downgrades `axe-auth` to a release that predates a schema bump * will see `version-mismatch` on any blob written by the newer * release, even if the change was strictly additive. That is the safe * default for a credentials blob — the older version cannot vouch for * the meaning of fields it has never seen. Callers hitting this case * should treat it as "re-authenticate" rather than attempting to * parse an unknown future shape. */ export type LoadResult = { ok: true; entry: StoredEntry; } | { ok: false; reason: "empty"; } | { ok: false; reason: "corrupt"; } | { ok: false; reason: "version-mismatch"; storedVersion: number; }; /** Persistence layer for an OAuth `StoredEntry`. */ export interface TokenStore { /** Write-through save. Replaces any previously stored entry. */ save(entry: StoredEntry): Promise; /** * Reads the stored entry and returns a structured result. * * Callers should branch on `result.ok` first. When `ok` is `false`, * `reason` tells them *why* there is no usable entry: `empty` * (nothing stored), `corrupt` (unparseable or shape-invalid), or * `version-mismatch` (stored under a schema we cannot migrate from). * The library does not emit output on these cases — surfacing them * to the user is the caller's responsibility. */ load(): Promise; /** Removes any stored entry. No-op if none is present. */ clear(): Promise; } /** * Outcome of `parseAndMigrateBlob`: same set of failure reasons as * `LoadResult`, but on success carries the post-migration blob as an * unknown payload. The caller is responsible for shape-validating * that payload against the latest schema. */ export type BlobChainResult = { ok: true; blob: unknown; } | { ok: false; reason: "empty"; } | { ok: false; reason: "corrupt"; } | { ok: false; reason: "version-mismatch"; storedVersion: number; }; /** * JSON-parses the raw keychain password and walks the migrator chain * until it reaches `expectedVersion`. Exported with `expectedVersion` * and `migrators` parameters only for testing the chain mechanics * against synthetic versions / migrators; production callers use * `KeyringTokenStore.load()`, which feeds in `STORED_BLOB_VERSION` * and `MIGRATORS` and applies the latest-shape check on top. */ export declare function parseAndMigrateBlob(raw: string | null, expectedVersion?: number, migrators?: ReadonlyMap unknown | null>): BlobChainResult; /** * Builds the user-facing keychain error message: the underlying * cause's text plus a per-platform hint. Platform is a parameter * (defaulting to `process.platform`) so tests can drive each branch * without mocking the runtime; mirrors the pattern in * `platformKeyringHint`. */ export declare function keyringErrorMessage(op: string, cause: unknown, platform?: NodeJS.Platform): string; /** * Returns a per-platform hint appended to keychain error messages so * users see actionable guidance for their OS instead of generic or * Linux-only advice. Exported (but not re-exported from the package * index) so tests can exercise each branch without mocking * `process.platform`. */ export declare function platformKeyringHint(platform?: NodeJS.Platform): string; /** * `TokenStore` backed by the operating system's native keychain via * `@napi-rs/keyring` (macOS Keychain, Windows Credential Manager, Linux * Secret Service). On macOS and Linux the blob lives in a single entry * keyed by the fixed `credentials` account name. On Windows the blob * is split across `credentials.0`, `credentials.1`, … entries to fit * under Credential Manager's 2560-byte (1280 UTF-16 char) per-entry * cap; see `shouldChunkForKeyring`. * * The blob carries its own issuer/client coordinates so verbs can * recover full config without per-issuer keying. */ export declare class KeyringTokenStore implements TokenStore { #private; /** * @param entryFactory Injection seam for `@napi-rs/keyring` entries. * Defaults to the production lazy-resolved factory; tests pass a * recording / faking variant. */ constructor(entryFactory?: KeyringEntryFactory); /** * @internal Test seam. Constructs a store with an explicit chunking * decision instead of the platform-determined default, so the * chunked path can be exercised on macOS/Linux CI and the unchunked * path on Windows CI. Production code must use the regular * constructor and let `shouldChunkForKeyring()` decide — passing * `chunked: true` on macOS would write data that the regular * constructor wouldn't be able to read. */ static forTesting(entryFactory: KeyringEntryFactory, chunked: boolean): KeyringTokenStore; save(entry: StoredEntry): Promise; load(): Promise; clear(): Promise; } /** * Splits `blob` into the N parts that `KeyringTokenStore.#saveChunked` * writes to `credentials.0..N-1`. Chunk 0 is prefixed with `\n` so * the reader can learn N from a single getPassword call. Each chunk * stays under `CHUNK_LIMIT` UTF-16 characters; throws if the blob would * require more than `MAX_CHUNKS` chunks. Exported for tests. */ export declare function chunkBlobForKeyring(blob: string): string[];