/** * The suffix every quarantined file on this platform gets. Exported so the * other producer of these files (the transcript journal's corrupt-tail * quarantine) and the reclaim sweep below all agree on one spelling. */ export declare const UNRECOGNIZED_SUFFIX = ".unrecognized"; /** * A migration function that transforms data from version N to N+1. * Receives the raw parsed object and must return the upgraded object. */ export type VersionMigration = (data: Record) => Record; export interface ReadVersionedOptions { /** * The version number this reader expects. When the file version equals * `currentVersion`, no migrations are run. When it is lower, migrations * are applied stepwise. When it is higher or unrecognised, `onUnknown` * behaviour fires. */ readonly currentVersion: number; /** * Optional stepwise migrations indexed by the FROM version. * `migrations[1]` upgrades version-1 data to version-2 data. * Applied in ascending order until `currentVersion` is reached. */ readonly migrations?: Readonly>; /** * What to do when the file version is unrecognised (higher than * `currentVersion` or missing/non-numeric). * * `'quarantine'`, rename the file to `.unrecognized` and return null. */ readonly onUnknown: 'quarantine'; } /** * Migration-aware, quarantine-on-failure versioned file reader. * * Parse flow: * 1. If the file does not exist → return null. * 2. If JSON is corrupt → quarantine to `.unrecognized`, return null. * 3. If the version field is missing or higher than currentVersion → * quarantine, return null. * 4. If the version is lower than currentVersion → apply stepwise migrations. * If no migration exists for a version gap, or a migration throws, * quarantine and return null. * 5. Return the (possibly migrated) object. Callers are responsible for * narrowing the returned value, this helper handles versioning and * corruption only, not schema validation. */ export declare function readVersioned(path: string, options: ReadVersionedOptions): T | null; /** * How long a quarantined file is kept before it is reclaimed: 30 days * (2_592_000_000 ms). These files exist so a person can look at what went * wrong, so the window is a month rather than the hours-to-days retention the * live durability artefacts get, long enough to survive a holiday, short * enough that a recurring corruption cannot fill a disk. */ export declare const QUARANTINE_RETENTION_MS: number; /** * Hard ceiling on quarantined files kept per swept directory, newest kept. * The age rule alone cannot bound a fast repeating corruption (a boot loop * quarantining the same file every restart), so a count cap runs alongside it. */ export declare const QUARANTINE_MAX_FILES_PER_DIR = 50; export interface QuarantineReapResult { /** Quarantined files examined across every directory. */ readonly scanned: number; /** Quarantined files deleted. */ readonly reaped: number; } export interface QuarantineReapOptions { readonly now?: () => number; /** Override the age window (tests). */ readonly maxAgeMs?: number; /** Override the per-directory count cap (tests). */ readonly maxFilesPerDir?: number; } /** * Delete `.unrecognized` quarantine files that are past the retention window, * plus any beyond the per-directory count cap (newest kept). * * Each directory is scanned non-recursively; a missing or unreadable directory * contributes nothing and is not an error. Idempotent, and safe to run * concurrently from several processes, a file another sweeper already * unlinked (ENOENT) counts as reclaimed rather than failing the sweep. */ export declare function reapQuarantinedFiles(directories: readonly string[], options?: QuarantineReapOptions): QuarantineReapResult; //# sourceMappingURL=read-versioned.d.ts.map