import type { Pool as MysqlPool } from "mysql2/promise"; import type { Pool as PgPool } from "pg"; import type { IssuedFileLink } from "./send-user-file.js"; /** Ledger scope sentinel for single-user issuance (no principal) — mirrors scopeSegment's "_" key segment. */ export declare const SENDFILE_SINGLE_USER_SCOPE = "_"; export interface SendFileLedgerEntry { /** uuidv7 — PK and the keyset cursor (time-ordered, newest = lexicographically greatest). */ id: string; /** Verified principal verbatim ("_" = single-user). NEVER derived from the hashed key segment (one-way). */ scope: string; bucket: string; objectKey: string; track: "public" | "presigned"; filename: string; size: number; /** 0 = permanent (public track). */ ttlSec: number; taskId?: string; sessionId?: string; createdAt: number; } export interface SendFileLedger { /** Record one issued link. Idempotent on `id` (a retry after a lost ack must not duplicate). */ record(entry: SendFileLedgerEntry): Promise; /** Newest-first page of one scope's links; keyset = `id < beforeId` (listSessions posture: fetch limit+1 * to detect more). `beforeId` absent = first page. */ listByScope(scope: string, limit: number, beforeId?: string): Promise; } export declare class TiDBSendFileLedger implements SendFileLedger { private readonly pool; constructor(pool: MysqlPool); record(entry: SendFileLedgerEntry): Promise; listByScope(scope: string, limit: number, beforeId?: string): Promise; } export declare class PgSendFileLedger implements SendFileLedger { private readonly pool; constructor(pool: PgPool); record(entry: SendFileLedgerEntry): Promise; listByScope(scope: string, limit: number, beforeId?: string): Promise; } export declare class MemorySendFileLedger implements SendFileLedger { private readonly byScope; record(entry: SendFileLedgerEntry): Promise; listByScope(scope: string, limit: number, beforeId?: string): Promise; } export declare class FileSendFileLedger implements SendFileLedger { private readonly path; private readonly mem; private log; constructor(root: string); record(entry: SendFileLedgerEntry): Promise; listByScope(scope: string, limit: number, beforeId?: string): Promise; /** Release the append-log fd (LocalBackend.close → graceful-restart re-open). */ dispose(): void; } export interface LedgerRecordingDeps { ledger: SendFileLedger; /** Best-effort reclaim of the uploaded object when the record fails (issuer.deleteObject). */ deleteObject: (bucket: string, key: string) => Promise; warn?: (msg: string, meta?: Record) => void; now?: () => number; newId?: () => string; } /** * Wrap a lane `send` with the ledger write point: upload+verify succeed (the inner send resolved) → record → * only then return (the tool emits the file_link frame strictly after). Record failure ⇒ fail-loud for THIS * file + delete of the uploaded object with ONE retry; the throw is the contract either way, and its message * states the true reclaim outcome (F2: a failed reclaim = permanent orphan, warned with coordinates). */ export declare function withLedgerRecording(send: (path: string, ctx: { taskId?: string; sessionId?: string; principal?: string; }) => Promise, deps: LedgerRecordingDeps): (path: string, ctx: { taskId?: string; sessionId?: string; principal?: string; }) => Promise; //# sourceMappingURL=send-file-ledger.d.ts.map