/** * SQLite-backed cache for rendered `github` issue/PR view output, plus a * generic cache-aware wrapper that the tool ops and the `issue://`/`pr://` * protocol handlers share. * * Storage: * One process-wide connection opens lazily on first hit and stays open. All * helpers swallow open/IO failures and degrade to "no cache" so a corrupt or * unreadable DB never blocks a `gh` call. * * TTL: * Soft TTL → return cached row directly. * Past soft TTL but within hard TTL → return cached row AND schedule a * background refresh (errors logged, never thrown). * Past hard TTL → treat as miss and fetch fresh. */ import { Database } from "bun:sqlite"; import type { Settings } from "../config/settings"; export type CacheKind = "issue" | "pr" | "pr-diff"; export interface CachedView { authKey: string; repo: string; kind: CacheKind; number: number; includeComments: boolean; fetchedAt: number; payload: T; rendered: string; sourceUrl: string | undefined; } export declare function openDb(): Database | null; /** * Best-effort local fingerprint for the active GitHub CLI credentials. * * Cache hits must not cross account/token boundaries, but doing a `gh api user` * probe before every cached read would defeat the soft-TTL contract that cache * hits avoid a gh round-trip. Instead, key rows by credential material that the * GitHub CLI itself consumes: token environment variables and/or hosts.yml. * The DB stores only a hash, never the token or hosts.yml contents. If no * credential source is visible, callers should pass `null` to bypass caching. */ export declare function resolveGithubCacheAuthKey(host?: string): string | undefined; export declare function getCached(repo: string, kind: CacheKind, number: number, includeComments: boolean, authKey?: string): CachedView | null; export interface PutCachedInput { authKey?: string; repo: string; kind: CacheKind; number: number; includeComments: boolean; payload: T; rendered: string; sourceUrl?: string; fetchedAt?: number; } export declare function putCached(input: PutCachedInput): void; /** Drop a specific cache entry. */ export declare function invalidate(repo: string, kind: CacheKind, number: number, includeComments?: boolean, authKey?: string): void; /** Drop every cached row. Test helper. */ export declare function clearAll(): void; /** * Test/maintenance helper. Closes and forgets the cached connection so the * next access reopens against (possibly) a different DB path. */ export declare function resetForTests(): void; export interface FreshResult { rendered: string; sourceUrl: string | undefined; payload: T; } export interface CacheLookupOptions { repo: string; kind: CacheKind; number: number; includeComments: boolean; /** * Auth/credential namespace for cache rows. Omit only in storage-layer * tests; pass `null` when production code cannot determine an identity and * must bypass persistent cache reads/writes. */ authKey?: string | null; fetchFresh: () => Promise>; settings?: Settings | undefined; now?: number; } export type CacheStatus = "miss" | "fresh" | "stale" | "disabled"; export interface CacheLookupResult { rendered: string; sourceUrl: string | undefined; payload: T; status: CacheStatus; fetchedAt: number; } export interface CacheTtl { softMs: number; hardMs: number; enabled: boolean; } export declare function resolveCacheTtl(settings?: Settings): CacheTtl; export declare function getOrFetchView(options: CacheLookupOptions): Promise>; /** * Human-friendly freshness note for protocol-handler `notes[]` rendering. */ export declare function formatFreshnessNote(status: CacheStatus, fetchedAtMs: number, now?: number): string;