/** * WorkbookReader - Browser Streaming Workbook Reader * * This module contains the full shared implementation for the streaming * workbook reader and a browser-compatible `WorkbookReader` that buffers * waiting worksheets in memory. * * Node.js uses `workbook-reader.ts`, which extends the same base implementation * with filesystem-specific features (filename input + temp-file buffering). */ import type { ZipEntry } from "../../archive/unzip/stream.js"; import { HyperlinkReader, type Hyperlink } from "./hyperlink-reader.js"; import { WorksheetReader } from "./worksheet-reader.js"; import type { WorksheetState, Font, WorkbookProperties } from "../types.js"; import { StylesXform } from "../xlsx/xform/style/styles-xform.js"; import { Readable } from "../../stream/index.js"; import { EventEmitter } from "../../../utils/event-emitter.js"; export interface InternalWorksheetOptions { worksheets?: "emit" | "ignore" | "prep"; sharedStrings?: "cache" | "emit" | "ignore"; hyperlinks?: "cache" | "emit" | "ignore"; styles?: "cache" | "ignore"; entries?: "emit" | "ignore"; } export interface SharedStringRichText { richText: Array<{ font: Partial | null; text: string | null; }>; } export type SharedStringValue = string | SharedStringRichText; export interface WorkbookRelationship { Id: string; Target: string; Type?: string; } export interface SheetMetadata { id: number; name: string; state?: WorksheetState; rId: string; } export interface WorkbookModel { sheets?: SheetMetadata[]; properties?: Partial; views?: unknown[]; definedNames?: unknown[]; } export interface WorkbookPropertiesXform { model?: Partial; } export interface EntryPayload { type: "shared-strings" | "styles" | "workbook" | "worksheet" | "hyperlinks"; id?: string; } export type ParseEventType = "shared-strings" | "worksheet" | "hyperlinks"; export interface SharedStringEvent { eventType: "shared-strings"; value: { index: number; text: SharedStringValue; }; } export interface WorksheetReadyEvent { eventType: "worksheet"; value: TWorksheetReader; } export interface HyperlinksEvent { eventType: "hyperlinks"; value: THyperlinkReader; } export type ParseEvent = SharedStringEvent | WorksheetReadyEvent | HyperlinksEvent; export interface WaitingWorksheetEntry { eventType: "waiting-worksheet"; sheetNo: string; entry: ZipEntry; } export type CommonInput = Uint8Array | ArrayBuffer | Readable | ReadableStream; export interface WorkbookReaderOptions { worksheets?: "emit" | "ignore"; sharedStrings?: "cache" | "emit" | "ignore"; hyperlinks?: "cache" | "emit" | "ignore"; styles?: "cache" | "ignore"; entries?: "emit" | "ignore"; /** * Maximum total bytes to buffer for worksheets that arrive before * workbook metadata / shared strings are ready. * Prevents memory exhaustion from malicious XLSX files with * adversarial ZIP entry ordering. * @default 256MB (268435456) */ maxBufferedWorksheetBytes?: number; } /** Constructor type for WorksheetReader/HyperlinkReader */ export interface ReaderConstructor { new (params: { workbook: TWorkbook; id: number; iterator: AsyncIterable; options: InternalWorksheetOptions; }): TReader; } export declare abstract class WorkbookReaderBase; }, TWaitingWorksheet = unknown> extends EventEmitter { input: TInput; options: { worksheets: "emit" | "ignore"; sharedStrings: "cache" | "emit" | "ignore"; hyperlinks: "cache" | "emit" | "ignore"; styles: "cache" | "ignore"; entries: "emit" | "ignore"; }; styles: StylesXform; stream?: Readable; sharedStrings?: SharedStringValue[]; workbookRels?: WorkbookRelationship[]; properties?: WorkbookPropertiesXform; model?: WorkbookModel; /** Whether xl/metadata.xml contains XLDAPR dynamic array metadata */ hasDynamicArrayMetadata: boolean; /** Precise set of cm values (1-indexed) that map to XLDAPR metadataType */ dynamicArrayCmIndices?: Set; /** Maximum bytes to buffer for worksheets waiting on prerequisites. Default: 256 MB. */ protected _maxBufferedBytes: number; /** Running total of bytes buffered for waiting worksheets. */ protected _totalBufferedBytes: number; protected _hyperlinkReadersBySheetNo?: Record; protected _workbookRelIdByTarget?: Record; protected _sheetByRelId?: Record; getHyperlinkReader(sheetNo: number | string): THyperlinkReader | undefined; getHyperlink(sheetNo: number | string, rId: string): Hyperlink | undefined; getHyperlinkTarget(sheetNo: number | string, rId: string): string | undefined; protected WorksheetReaderClass: ReaderConstructor; protected HyperlinkReaderClass: ReaderConstructor; constructor(input: TInput, options: WorkbookReaderOptions, WorksheetReaderClass: ReaderConstructor, HyperlinkReaderClass: ReaderConstructor); protected _getStream(input: TInput): Readable; abstract _storeWaitingWorksheet(sheetNo: string, entry: ZipEntry): Promise; abstract _processWaitingWorksheets(waitingWorksheets: TWaitingWorksheet[]): AsyncIterableIterator>; protected _cleanupWaitingWorksheets(_waitingWorksheets: TWaitingWorksheet[]): void; private _createWorksheetReader; private _createHyperlinkReader; read(input?: TInput, options?: WorkbookReaderOptions): Promise; [Symbol.asyncIterator](): AsyncIterableIterator; parse(input?: TInput, options?: WorkbookReaderOptions): AsyncIterableIterator>; private _emitEntry; private _parseRels; private _parseWorkbook; private _parseSharedStrings; private _parseStyles; private _parseMetadata; protected _parseWorksheet(iterator: AsyncIterable, sheetNo: string): IterableIterator>; protected _parseHyperlinks(iterator: AsyncIterable, sheetNo: string): AsyncIterableIterator>; protected _parseEntries(stream: Readable): AsyncIterableIterator | WaitingWorksheetEntry>; } export declare const WorkbookReaderOptionsSchema: { readonly worksheets: readonly ["emit", "ignore"]; readonly sharedStrings: readonly ["cache", "emit", "ignore"]; readonly hyperlinks: readonly ["cache", "emit", "ignore"]; readonly styles: readonly ["cache", "ignore"]; readonly entries: readonly ["emit", "ignore"]; }; interface WaitingWorksheet { sheetNo: string; data: Uint8Array[]; } declare class WorkbookReader extends WorkbookReaderBase { constructor(input: CommonInput, options?: WorkbookReaderOptions); _storeWaitingWorksheet(sheetNo: string, entry: ZipEntry): Promise; _processWaitingWorksheets(waitingWorksheets: WaitingWorksheet[]): AsyncIterableIterator>; } export { WorkbookReader };