import type { Document as MupdfDocument } from 'mupdf'; import { type AtomicTextRange } from '../chunker/index.js'; import { AppError } from '../utils/errors.js'; import type { HeadingAnchor, SourceMap } from '../utils/source-context.js'; import type { EmbedderInterface, FilteredTextFragment } from './pdf-filter.js'; /** * File extensions supported by the parser module (parseFile + parsePdf). * Exported so other modules (e.g. list_files) stay in sync automatically * when new formats are added here. */ export declare const SUPPORTED_EXTENSIONS: Set; /** * Result from parsing a document, containing both content and extracted title. * Title is display metadata; it reaches search only through the opt-in * embedding title prefix. */ export interface ParseResult { sourceMap?: SourceMap; content: string; title: string; /** * Title for the embedding prefix; `title` is used when absent. PDFs set it * so a display title taken from page-1 body text embeds as the file name. */ embeddingTitle?: string; atomicRanges?: readonly AtomicTextRange[]; imageAnchors?: readonly ParsedImageAnchor[]; } export interface ParsedImageAnchor { offset: number; imageIndex: number; mimeType: 'image/png' | 'image/jpeg'; bytes: Uint8Array; } export interface ParseFileOptions { images?: boolean; } /** * DocumentParser configuration. Exactly one of `baseDir` (legacy single root) * or `baseDirs` must be supplied; the constructor rejects both, so a * misconfiguration cannot silently pick one. */ export type ParserConfig = { /** Security: single allowed base directory (legacy shape). */ baseDir: string; baseDirs?: undefined; /** Maximum file size (100MB). */ maxFileSize: number; } | { /** Security: one or more allowed base directories (multi-root shape). */ baseDirs: readonly string[]; baseDir?: undefined; /** Maximum file size (100MB). */ maxFileSize: number; }; /** * Validation error (equivalent to 400) */ export declare class ValidationError extends AppError { constructor(message: string, options?: { cause?: Error; }); } /** * File operation error (equivalent to 500) */ export declare class FileOperationError extends AppError { constructor(message: string, options?: { cause?: Error; }); } /** Path and size validation plus PDF/DOCX/TXT/MD parsing. */ export declare class DocumentParser { private readonly config; /** Raw allowed roots in input order (pre-realpath). Always non-empty. */ private readonly rawBaseDirs; /** * Realpath-normalized allowed roots, each with a trailing separator so the * `startsWith` check cannot match a sibling (`/foo/bar/` vs `/foo/barista/`). * Cached for the process lifetime. */ private resolvedBaseDirs; constructor(config: ParserConfig); /** * THE place realpath is used: following symlinks here is what makes prefix * containment unforgeable. Everything else stores and looks up resolve() * paths — see {@link BaseDirsConfig}. * * A file is accepted iff its realpath — or, for a not-yet-existing * non-symlink, its resolve()d path — sits under any allowed root. A broken * symlink is rejected outright. */ validateFilePath(filePath: string): Promise; /** @throws ValidationError when the file exceeds the configured size limit. */ validateFileSize(filePath: string): void; /** Parse a file, detecting the format from its extension. */ parseFile(filePath: string, options?: ParseFileOptions): Promise; /** * PDF parsing. Headers and footers are detected semantically by embedding * similarity across pages, not by position alone, and the title comes from * PDF metadata with a first-page largest-font fallback. */ parsePdf(filePath: string, embedder: EmbedderInterface): Promise; /** * Per-page PDF parsing for the visual path. Adds `preserve-images` so mupdf * emits the image blocks the visual detector needs, and returns the open * `Document` so the renderer can work on the same handle. * * Disposal is asymmetric: on success the CALLER owns `doc` and must * `finally { doc.destroy() }`; on throw `doc` is already destroyed here, so * the caller must NOT destroy it. */ parsePdfPages(filePath: string, embedder: EmbedderInterface): Promise<{ doc: MupdfDocument; title: string; embeddingTitle: string; pages: Array<{ pageNum: number; headings?: HeadingAnchor[]; text: string; textFragments: FilteredTextFragment[]; stextJson: unknown; }>; }>; /** * DOCX parsing. One Mammoth HTML conversion serves both title and body, so * the document is not converted twice. */ private parseDocx; /** TXT parsing. */ private parseTxt; /** MD parsing. */ private parseMd; } //# sourceMappingURL=index.d.ts.map