{"version":3,"sources":["../src/filedatabase/index.js","../src/utils/os-utils.js","../src/utils/fs-utils.js","../src/utils/format-utils.js","../src/utils/date-utils.js","../src/filedatabase/serializers.js","../src/errors.js","../src/filedatabase/synopsis-functions.js"],"sourcesContent":["/**\n * FileDatabase - Versioned, file-based data storage system\n * \n * Provides organized file storage with:\n * - Timestamp-based versioning\n * - Chunked/paginated file writes for large datasets\n * - Metadata tracking\n * - Backward compatibility with legacy structures\n * - Multiple storage modes (versioned, catalog, logs)\n */\n\nimport fs from \"fs\";\nimport path from \"path\";\n\n\n\n\n\n\n\n\n\n\n\n\n\nimport { ensurePath, getFileExtension, getFreeDiskSpace, bytesToHumanReadable, isTimestampFolder } from \"./utils.js\";\nimport { detectDataType, serializeData, deserializeData } from \"./serializers.js\";\nimport { ParamError, FileDatabaseError } from \"../errors.js\";\n\nexport { FileDatabaseError };\n\nexport class FileDatabase {\n    basePath;\n    namespace;\n    tableName = null;\n    versioned;\n    maxVersions;\n    pageSize;\n    useMetadata;\n    freeSpaceThreshold;\n    logger;\n\n    // Current operation state\n    currentVersion = null;\n    currentVersionFolder = null;\n    currentFileNumber = 0;\n    currentRecord = 0;\n    hasReadFirstPage = false;\n    lastFileData = null;\n    /** Cache of the last JSON file parsed during paginated reads (avoid re-parse per page). */\n    readFileCache = null; // { filePath: string, data: any[] } | null\n    metadata;\n\n    // Synopsis calculation functions\n    fileSynopsisFunction = null;\n    versionSynopsisFunction = null;\n\n    /**\n     * Constructor - accepts context as first parameter (new pattern)\n     * or config object (legacy pattern for backward compatibility)\n     */\n    constructor(contextOrConfig, options) {\n        let config;\n        \n        // Check if first parameter is Context (has params property)\n        if (contextOrConfig && typeof contextOrConfig === \"object\" && \"params\" in contextOrConfig) {\n            // New pattern: context is first parameter\n            const context = contextOrConfig ;\n            const opts = options || {};\n            \n            // Get configuration from context.params (module \"filedatabase\" for --showUsedParams grouping)\n            const defs = {\n                basePath: \"string default ./data\",\n                namespace: \"string default default\",\n                tableName: \"string\",\n                maxVersions: \"number default 5\",\n                pageSize: \"number default 5000\",\n            };\n            const discovered = context.params.getAllForModule(defs);\n            config = { ...discovered, ...opts, logger: context.logger } ;\n        } else {\n            // Legacy pattern: config object\n            config = contextOrConfig ;\n        }\n        \n        // Validate required configuration\n        if (!config.basePath) {\n            throw new ParamError(\"[FileDatabase] basePath is required\");\n        }\n\n        this.basePath = config.basePath;\n        this.namespace = config.namespace || \"default\";\n        this.tableName = config.tableName || null;\n        this.versioned = config.versioned ?? true; // Default true for backward compatibility\n        this.maxVersions = config.maxVersions || 5;\n        this.pageSize = config.pageSize || 5000;\n        this.useMetadata = config.useMetadata !== false; // Default true\n        this.freeSpaceThreshold = config.freeSpaceThreshold || 100 * 1024 * 1024; // 100MB\n        this.logger = config.logger || console;\n        this.lastReadMissingFiles = [];\n\n        // Initialize metadata\n        this.metadata = this.getDefaultMetadata();\n    }\n\n    /**\n     * Initialize FileDatabase from context and options.\n     * Params are read via getAllForModule(\"filedatabase\", defs) for --showUsedParams grouping.\n     */\n    static init(context, options) {\n        return new FileDatabase(context, options ?? {});\n    }\n\n    /**\n     * Get default metadata structure\n     */\n    getDefaultMetadata() {\n        return {\n            version: this.currentVersion || null,\n            files: [],\n            createdAt: new Date().toISOString(),\n            modifiedAt: new Date().toISOString(),\n            totalRecords: 0,\n            synopsis: null,\n            dataType: null,\n        };\n    }\n\n    /**\n     * Get the destination path (basePath/namespace/tableName[/version])\n     */\n    getDestinationPath(version) {\n        const errors = [\"basePath\", \"namespace\", \"tableName\"]\n            .filter(prop => !this[prop ])\n            .map(prop => `${prop} is not set`);\n        if (errors.length) {\n            throw new FileDatabaseError(`[FileDatabase] ${errors.join(\"; \")}`);\n        }\n\n        const parts = [this.basePath, this.namespace];\n        if (this.tableName) {\n            parts.push(...this.tableName.split(\"/\"));\n        }\n\n        // Only add version folder if in versioned mode and version is specified\n        if (this.versioned && version) {\n            parts.push(version);\n        }\n\n        return path.resolve(...parts);\n    }\n\n    /**\n     * Set current version and version folder\n     */\n    async setCurrentVersion(version) {\n        this.currentVersion = version;\n        this.currentVersionFolder = await ensurePath(this.getDestinationPath(), version);\n    }\n\n    /**\n     * Create a new version folder named with the current UTC second.\n     * Only works in versioned mode.\n     *\n     * Clash protection: if that name already exists (two writers in the same\n     * second, or wall clock behind the latest version), advance +1s until free.\n     * Do NOT always derive from max(existing)+1s — that made successive harvests\n     * hours apart still land one second apart on disk.\n     */\n    async makeNewVersion() {\n        if (!this.versioned) {\n            throw new FileDatabaseError(\"makeNewVersion() only works in versioned mode\");\n        }\n\n        // Reset in-memory metadata when creating a new version\n        this.metadata = this.getDefaultMetadata();\n\n        const existingVersions = await this.getVersions();\n        const existingSet = new Set(existingVersions);\n\n        let candidateMs = Date.now();\n        if (existingVersions.length > 0) {\n            let maxMs = 0;\n            for (const version of existingVersions) {\n                const ms = new Date(version).getTime();\n                if (Number.isFinite(ms) && ms > maxMs) maxMs = ms;\n            }\n            // Same-second clash or clock behind latest folder — start just after it.\n            if (candidateMs <= maxMs) {\n                candidateMs = maxMs + 1000;\n            }\n        }\n\n        let versionName = new Date(candidateMs).toISOString().split(\".\")[0] + \"Z\";\n        while (existingSet.has(versionName)) {\n            candidateMs += 1000;\n            versionName = new Date(candidateMs).toISOString().split(\".\")[0] + \"Z\";\n        }\n\n        await this.setCurrentVersion(versionName);\n\n        // Reset file numbering for new version\n        this.currentFileNumber = 0;\n\n        // Delete old versions if we exceed maxVersions\n        const versions = await this.getVersions();\n        while (versions.length > this.maxVersions) {\n            const versionToDelete = path.resolve(this.getDestinationPath(), versions.shift());\n            this.logger.silly?.(`[FileDatabase] Deleting old version: ${versionToDelete}`);\n            await fs.promises.rm(versionToDelete, { recursive: true, force: true });\n        }\n\n        return versionName;\n    }\n\n    /**\n     * Get list of all versions (sorted chronologically)\n     * Only works in versioned mode\n     */\n    async getVersions() {\n        if (!this.versioned) {\n            return []; // No versions in non-versioned mode\n        }\n\n        const destPath = this.getDestinationPath();\n\n        try {\n            await ensurePath(destPath);\n            const items = await fs.promises.readdir(destPath);\n            const versions = items.filter(item => {\n                const itemPath = path.join(destPath, item);\n                const stat = fs.statSync(itemPath);\n                return stat.isDirectory() && isTimestampFolder(item);\n            });\n\n            return versions.sort();\n        } catch (error) {\n            return [];\n        }\n    }\n\n    /**\n     * Get the latest version (most recent timestamp)\n     * Only works in versioned mode\n     * @returns Latest version string or null if no versions\n     */\n    async getLatestVersion() {\n        if (!this.versioned) {\n            throw new FileDatabaseError(\"getLatestVersion() only works in versioned mode\");\n        }\n\n        const versions = await this.getVersions();\n        if (versions.length === 0) {\n            return null;\n        }\n\n        return versions[versions.length - 1];\n    }\n\n    /**\n     * Check if any data exists in this table\n     * Works for both versioned and non-versioned modes\n     * @returns true if data exists\n     */\n    async hasData() {\n        const tablePath = this.getDestinationPath();\n\n        if (!fs.existsSync(tablePath)) {\n            return false;\n        }\n\n        if (this.versioned) {\n            // Check for version folders\n            const versions = await this.getVersions();\n            return versions.length > 0;\n        } else {\n            // Check for any data files or metadata\n            const items = await fs.promises.readdir(tablePath);\n            return items.some(item =>\n                item === \"metadata.json\" ||\n                item.match(/^\\d{6}\\.(json|txt|xml)$/) ||\n                item.endsWith(\".json\")\n            );\n        }\n    }\n\n    /**\n     * Auto-detect the data format in this table\n     * Used when reading existing data\n     * @returns Format detection result\n     */\n    async detectDataFormat()\n\n\n\n    {\n        const tablePath = this.getDestinationPath();\n\n        if (!fs.existsSync(tablePath)) {\n            return { versioned: false, hasMetadata: false, dataType: null };\n        }\n\n        const items = await fs.promises.readdir(tablePath);\n\n        // Check for metadata.json in root (non-versioned with metadata)\n        if (items.includes(\"metadata.json\")) {\n            const metadata = JSON.parse(\n                await fs.promises.readFile(path.join(tablePath, \"metadata.json\"), \"utf8\")\n            );\n            return {\n                versioned: false,\n                hasMetadata: true,\n                dataType: metadata.dataType || null\n            };\n        }\n\n        // Check for version folders\n        const versionFolders = items.filter(item => {\n            const itemPath = path.join(tablePath, item);\n            const stat = fs.statSync(itemPath);\n            return stat.isDirectory() && isTimestampFolder(item);\n        });\n\n        if (versionFolders.length > 0) {\n            // Check if latest version has metadata\n            const latestVersion = versionFolders.sort().pop();\n            const versionMetadataPath = path.join(tablePath, latestVersion, \"metadata.json\");\n\n            return {\n                versioned: true,\n                hasMetadata: fs.existsSync(versionMetadataPath),\n                dataType: null\n            };\n        }\n\n        // Check for sequential files (legacy non-versioned)\n        const dataFiles = items.filter(f => f.match(/^\\d{6}\\.(json|txt|xml)$/));\n        if (dataFiles.length > 0) {\n            return {\n                versioned: false,\n                hasMetadata: false,\n                dataType: null\n            };\n        }\n\n        return { versioned: false, hasMetadata: false, dataType: null };\n    }\n\n    /**\n     * Load metadata from JSON file. Distinguishes missing vs unreadable so\n     * callers can rewrite a truncated file once instead of warning on every read.\n     */\n    async loadMetadataJson(version) {\n        const loaded = await this.readMetadataJsonFile(version);\n        return loaded.metadata;\n    }\n\n    async readMetadataJsonFile(version) {\n        const metadataFile = path.join(this.getDestinationPath(), version, \"metadata.json\");\n        if (!fs.existsSync(metadataFile)) {\n            return { metadata: null, unreadable: false };\n        }\n        try {\n            const rawData = await fs.promises.readFile(metadataFile, \"utf8\");\n            return { metadata: JSON.parse(rawData), unreadable: false };\n        } catch {\n            return { metadata: null, unreadable: true };\n        }\n    }\n\n    async persistMetadataJson(version, metadata) {\n        if (!this.useMetadata || !metadata) {\n            return;\n        }\n        const metadataFile = path.join(this.getDestinationPath(), version, \"metadata.json\");\n        try {\n            await fs.promises.writeFile(metadataFile, JSON.stringify(metadata, null, 4), \"utf8\");\n        } catch (e) {\n            this.logger.silly?.(`[FileDatabase] Could not rewrite metadata for \"${version}\": ${e.message}`);\n        }\n    }\n\n    /**\n     * Build metadata by scanning files in a version folder (backward compatibility)\n     * Reads all files to get accurate counts - used when synopsis calculation is needed\n     */\n    async figureMetadataFromVersionFiles(version) {\n        const versionPath = path.join(this.getDestinationPath(), version);\n\n        if (!fs.existsSync(versionPath)) {\n            return this.getDefaultMetadata();\n        }\n\n        const files = (await fs.promises.readdir(versionPath))\n            .filter(file => file !== \"metadata.json\" && !file.startsWith(\".\"))\n            .sort();\n\n        const metadata = this.getDefaultMetadata();\n        metadata.version = version;\n        metadata.files = [];\n\n        let totalRecords = 0;\n        let detectedDataType = null;\n\n        for (let i = 0; i < files.length; i++) {\n            const fileName = files[i];\n            const filePath = path.join(versionPath, fileName);\n\n            try {\n                const rawData = await fs.promises.readFile(filePath, \"utf8\");\n                const extension = path.extname(fileName).toLowerCase();\n                let dataType = \"text\";\n\n                if (extension === \".json\") {\n                    dataType = \"json-array\";\n                } else if (extension === \".xml\") {\n                    dataType = \"xml\";\n                }\n\n                const fileData = deserializeData(rawData, dataType);\n                const recordsCount = Array.isArray(fileData) ? fileData.length : 1;\n\n                if (detectedDataType === null) {\n                    detectedDataType = detectDataType(fileData);\n                }\n\n                const fileInfo = {\n                    number: i + 1,\n                    recordsCount,\n                    fileName,\n                };\n\n                metadata.files.push(fileInfo);\n                totalRecords += recordsCount;\n            } catch (error) {\n                this.logger.error?.(`[FileDatabase] Failed to read file ${fileName}: ${(error ).message}`);\n            }\n        }\n\n        metadata.totalRecords = totalRecords;\n        metadata.dataType = detectedDataType;\n\n        return metadata;\n    }\n\n    /**\n     * Build metadata optimized - only reads first and last files\n     * Assumes all middle files have the same record count as the first file\n     * Much faster for large datasets with many files\n     */\n    async buildMetadataOptimized(version) {\n        const versionPath = path.join(this.getDestinationPath(), version);\n\n        if (!fs.existsSync(versionPath)) {\n            return this.getDefaultMetadata();\n        }\n\n        const files = (await fs.promises.readdir(versionPath))\n            .filter(file => file !== \"metadata.json\" && !file.startsWith(\".\"))\n            .sort();\n\n        if (files.length === 0) {\n            return this.getDefaultMetadata();\n        }\n\n        const metadata = this.getDefaultMetadata();\n        metadata.version = version;\n        metadata.files = files.map((fileName, index) => ({\n            number: index + 1,\n            recordsCount: 0,\n            fileName,\n        }));\n\n        // Read first file to determine data type and standard record count\n        const firstFile = metadata.files[0];\n        const firstFilePath = path.join(versionPath, firstFile.fileName);\n        const firstFileRaw = await fs.promises.readFile(firstFilePath, \"utf8\");\n\n        let firstFileData;\n        try {\n            firstFileData = JSON.parse(firstFileRaw);\n        } catch (e) {\n            firstFileData = firstFileRaw;\n        }\n\n        metadata.dataType = detectDataType(firstFileData);\n\n        // Only proceed with optimization for json-array data\n        if (metadata.dataType === \"json-array\") {\n            const firstFileCount = Array.isArray(firstFileData) ? firstFileData.length : 1;\n            firstFile.recordsCount = firstFileCount;\n\n            // Assume all middle files have the same count as the first\n            for (let i = 1; i < metadata.files.length - 1; i++) {\n                metadata.files[i].recordsCount = firstFileCount;\n            }\n\n            // Read last file to get its actual count (might be partial)\n            if (files.length > 1) {\n                const lastFile = metadata.files[metadata.files.length - 1];\n                const lastFilePath = path.join(versionPath, lastFile.fileName);\n                const lastFileRaw = await fs.promises.readFile(lastFilePath, \"utf8\");\n                const lastFileData = deserializeData(lastFileRaw, metadata.dataType);\n                lastFile.recordsCount = Array.isArray(lastFileData) ? lastFileData.length : 1;\n            }\n\n            // Calculate total records\n            metadata.totalRecords = metadata.files.reduce((sum, file) => sum + file.recordsCount, 0);\n        } else {\n            // For non-array data, count each file as 1 record\n            metadata.files.forEach(file => {\n                file.recordsCount = 1;\n            });\n            metadata.totalRecords = files.length;\n        }\n\n        return metadata;\n    }\n\n    /**\n     * Figure out metadata - tries JSON first, then builds from files\n     * Uses optimized building when no synopsis calculation is needed\n     */\n    async figureMetadata(version, useOptimized = true) {\n        let unreadable = false;\n        if (this.useMetadata) {\n            const loaded = await this.readMetadataJsonFile(version);\n            if (loaded.metadata) {\n                return loaded.metadata;\n            }\n            unreadable = loaded.unreadable;\n        }\n\n        // Fallback: build from files\n        // Use optimized version (only reads first+last) when no synopsis needed\n        const rebuilt = (useOptimized && !this.fileSynopsisFunction && !this.versionSynopsisFunction)\n            ? await this.buildMetadataOptimized(version)\n            : await this.figureMetadataFromVersionFiles(version);\n\n        if (unreadable) {\n            await this.persistMetadataJson(version, rebuilt);\n        }\n        return rebuilt;\n    }\n\n    /**\n     * Load version metadata (main entry point for loading)\n     */\n    async loadVersionMetadata(version) {\n        const metadata = await this.figureMetadata(version);\n        this.metadata = metadata;\n        return metadata;\n    }\n\n    /**\n     * Save version metadata to file\n     */\n    async saveVersionMetadata(metadata) {\n        if (!this.useMetadata) {\n            return;\n        }\n\n        const metadataToSave = metadata || this.metadata;\n        let metadataFile;\n\n        if (this.versioned) {\n            // Versioned mode: metadata in version folder\n            if (!this.currentVersion) {\n                return;\n            }\n            metadataFile = path.join(this.getDestinationPath(), this.currentVersion, \"metadata.json\");\n        } else {\n            // Non-versioned mode: metadata in root table folder\n            metadataFile = path.join(this.getDestinationPath(), \"metadata.json\");\n        }\n\n        await fs.promises.writeFile(metadataFile, JSON.stringify(metadataToSave, null, 4), \"utf8\");\n    }\n\n    /**\n     * Create a new file entry in metadata\n     */\n    makeNewFile() {\n        this.currentFileNumber = (this.currentFileNumber || 0) + 1;\n\n        const dataType = this.metadata.dataType || \"json-array\";\n        const fileEntry = {\n            number: this.currentFileNumber,\n            recordsCount: 0,\n            fileName: `${this.currentFileNumber.toString().padStart(6, \"0\")}.${getFileExtension(dataType)}`,\n        };\n\n        this.metadata.files.push(fileEntry);\n        this.lastFileData = null;\n\n        this.logger.silly?.(`[FileDatabase] Created new file: ${fileEntry.fileName}, fileNumber: ${this.currentFileNumber}`);\n    }\n\n    /**\n     * Figure out what data to write and which file to use (for pagination)\n     * @param data - Data to write\n     * @param targetFileIndex - Optional index of existing file to overwrite (when customMetadata matches)\n     * @param forceNewFile - If true, always create a new file (when customMetadata provided but no match)\n     */\n    figureOutDataAndFileToWrite(data, targetFileIndex = null, forceNewFile = false) {\n        let dataToWrite;\n        let dataLeftOver;\n\n        // Detect data type from incoming data\n        // Always use the incoming data's type to ensure correct file extension\n        const incomingDataType = detectDataType(data);\n        if (this.metadata.dataType !== incomingDataType) {\n            this.metadata.dataType = incomingDataType;\n        }\n\n        // If targetFileIndex is provided, use that file (overwrite existing file with matching customMetadata)\n        if (targetFileIndex !== null && targetFileIndex < this.metadata.files.length) {\n            const targetFile = this.metadata.files[targetFileIndex];\n            // For non-array data, overwrite the file\n            if (!Array.isArray(data)) {\n                dataToWrite = data;\n                dataLeftOver = null;\n                return { dataToWrite, dataLeftOver, fileName: targetFile.fileName };\n            } else {\n                // For arrays, start fresh in the target file (don't append)\n                dataToWrite = data.slice(0, this.pageSize);\n                dataLeftOver = data.slice(this.pageSize);\n                this.lastFileData = dataToWrite;\n                return { dataToWrite, dataLeftOver, fileName: targetFile.fileName };\n            }\n        }\n\n        // If forceNewFile is true (customMetadata provided but no match), create a new file\n        // Skip the initial file creation if forceNewFile is true to avoid creating an extra empty file\n        let newlyCreatedFileIndex = null;\n        if (forceNewFile) {\n            const filesBeforeCreate = this.metadata.files.length;\n            this.makeNewFile();\n            newlyCreatedFileIndex = filesBeforeCreate; // Index of the newly created file\n            this.logger.silly?.(`[FileDatabase] Creating new file for unique custom metadata combination, fileNumber: ${this.currentFileNumber}`);\n        } else if (this.metadata.files.length === 0) {\n            // If no files exist yet and we're not forcing a new file, create the first file\n            this.makeNewFile();\n        }\n\n        // Get the last file (which might be the one we just created)\n        const lastFile = this.metadata.files[this.metadata.files.length - 1];\n        const lastFileRecordsCount = lastFile.recordsCount;\n        \n        // Verify that if we created a new file, we're using it\n        if (forceNewFile && newlyCreatedFileIndex !== null) {\n            const newlyCreatedFile = this.metadata.files[newlyCreatedFileIndex];\n            if (newlyCreatedFile && newlyCreatedFile.fileName !== lastFile.fileName) {\n                this.logger.warn?.(`[FileDatabase] Warning: Newly created file ${newlyCreatedFile.fileName} doesn't match last file ${lastFile.fileName}`);\n            }\n        }\n        \n        // For non-array data (text/xml/object), check if we need a new file with correct extension\n        // But skip this check if forceNewFile is true - we already created the file we need\n        if (!Array.isArray(data) && !forceNewFile) {\n            const lastFileExtension = path.extname(lastFile.fileName);\n            const expectedExtension = `.${getFileExtension(incomingDataType)}`;\n            // If the last file has wrong extension, create a new file with correct extension\n            // Check even if recordsCount is 0 (empty file) - we want correct extension for new writes\n            if (lastFileExtension !== expectedExtension) {\n                // Only create new file if the existing one has content, otherwise we'll use it\n                if (lastFileRecordsCount > 0) {\n                    this.makeNewFile();\n                } else {\n                    // File is empty, update its name to have correct extension\n                    lastFile.fileName = `${this.currentFileNumber.toString().padStart(6, \"0\")}.${getFileExtension(incomingDataType)}`;\n                }\n            }\n        } else if (!Array.isArray(data) && forceNewFile) {\n            // If forceNewFile is true, ensure the newly created file has the correct extension\n            const lastFileExtension = path.extname(lastFile.fileName);\n            const expectedExtension = `.${getFileExtension(incomingDataType)}`;\n            if (lastFileExtension !== expectedExtension) {\n                lastFile.fileName = `${this.currentFileNumber.toString().padStart(6, \"0\")}.${getFileExtension(incomingDataType)}`;\n            }\n        }\n\n        if (Array.isArray(data)) {\n            // For arrays, handle pagination\n            // If forceNewFile is true, write fresh data to the new file (don't append)\n            if (forceNewFile) {\n                // Write fresh data to the newly created file\n                dataToWrite = data.slice(0, this.pageSize);\n                dataLeftOver = data.slice(this.pageSize);\n                this.lastFileData = dataToWrite;\n            } else if (lastFileRecordsCount < this.pageSize) {\n                // Try to append to existing file if there's space\n                dataToWrite = [...(this.lastFileData || []), ...data.slice(0, this.pageSize - lastFileRecordsCount)];\n                dataLeftOver = data.slice(this.pageSize - lastFileRecordsCount);\n                this.lastFileData = dataToWrite;\n            } else {\n                // Last file is full, create a new file\n                this.makeNewFile();\n                dataToWrite = data.slice(0, this.pageSize);\n                dataLeftOver = data.slice(this.pageSize);\n                this.lastFileData = dataToWrite;\n            }\n        } else {\n            // For non-arrays, write as-is\n            dataToWrite = data;\n            dataLeftOver = null;\n        }\n\n        // Get the file name - if forceNewFile is true, we just created a new file, so use that one\n        // Otherwise, use the last file (which might have been created earlier or is being reused)\n        const fileName = this.metadata.files[this.metadata.files.length - 1].fileName;\n\n        this.logger.silly?.(\n            `[FileDatabase] figureOutDataAndFileToWrite: filename=${fileName}, forceNewFile=${forceNewFile}, targetFileIndex=${targetFileIndex}, dataToWrite.length=${Array.isArray(dataToWrite) ? dataToWrite.length : \"N/A\"}, lastFileRecordsCount=${lastFileRecordsCount}`\n        );\n\n        return { dataToWrite, dataLeftOver, fileName };\n    }\n\n    /**\n     * Calculate file-level synopsis if function is set\n     */\n    calculateFileSynopsis(data, fileIndex = this.metadata.files.length - 1) {\n        if (!this.fileSynopsisFunction) {\n            return;\n        }\n        const fileInfo = this.metadata.files[fileIndex];\n        const enhancedFileInfo = this.fileSynopsisFunction(fileInfo, data);\n        this.metadata.files[fileIndex] = enhancedFileInfo;\n    }\n\n    /**\n     * Calculate version-level synopsis if function is set\n     */\n    calculateVersionSynopsis() {\n        if (!this.versionSynopsisFunction) {\n            return;\n        }\n        const enhancedMetadata = this.versionSynopsisFunction(this.metadata);\n        this.metadata = enhancedMetadata;\n    }\n\n    /**\n     * Update metadata after writing data\n     */\n    updateMetadata(dataToWrite, fileName, customMetadata) {\n        let currentFile;\n\n        if (fileName) {\n            // Find the specific file by filename\n            const foundFile = this.metadata.files.find(file => file.fileName === fileName);\n            if (!foundFile) {\n                this.logger.warn?.(`[FileDatabase] File ${fileName} not found in metadata, using last file`);\n                currentFile = this.metadata.files[this.metadata.files.length - 1];\n            } else {\n                currentFile = foundFile;\n            }\n        } else {\n            // Get the current file info from metadata (always the last file)\n            currentFile = this.metadata.files[this.metadata.files.length - 1];\n        }\n\n        // Calculate the actual records count for the data being written\n        const recordsCount = Array.isArray(dataToWrite) ? dataToWrite.length : 1;\n\n        // Update existing file entry with the correct records count\n        currentFile.recordsCount = recordsCount;\n\n        // Add custom metadata fields if provided\n        if (customMetadata) {\n            Object.assign(currentFile, customMetadata);\n        }\n\n        // Find the file index for synopsis calculation\n        const fileIndex = this.metadata.files.indexOf(currentFile);\n        if (fileIndex !== -1) {\n            this.calculateFileSynopsis(dataToWrite, fileIndex);\n        }\n\n        // Update version metadata\n        this.metadata.version = this.currentVersion;\n        this.metadata.modifiedAt = new Date().toISOString();\n        this.metadata.dataType = detectDataType(dataToWrite);\n\n        // Recalculate total records by summing all file records counts\n        this.metadata.totalRecords = this.metadata.files.reduce((sum, file) => sum + (file.recordsCount || 0), 0);\n\n        this.logger.silly?.(\n            `[FileDatabase] Updated metadata for file ${currentFile.fileName}: recordsCount=${recordsCount}, totalRecords=${this.metadata.totalRecords}`\n        );\n    }\n\n    /**\n     * Safe write with disk space check\n     */\n    async safeWrite(filePath, data) {\n        const serializedData = serializeData(data);\n        const dir = path.dirname(filePath);\n        const requiredBytes = Buffer.byteLength(serializedData, \"utf8\");\n\n        // Check disk space\n        const freeBytes = getFreeDiskSpace(dir);\n        if (freeBytes !== null) {\n            if (freeBytes < requiredBytes) {\n                throw new FileDatabaseError(\n                    `Not enough disk space. Required: ${bytesToHumanReadable(requiredBytes)}, Free: ${bytesToHumanReadable(freeBytes)}`\n                );\n            }\n\n            if (freeBytes < this.freeSpaceThreshold) {\n                this.logger.warn?.(`Low disk space warning: only ${bytesToHumanReadable(freeBytes)} left`);\n            }\n        }\n\n        try {\n            await fs.promises.writeFile(filePath, serializedData, \"utf8\");\n            this.logger.silly?.(`[FileDatabase] Wrote ${bytesToHumanReadable(requiredBytes)} to ${filePath}`);\n        } catch (error) {\n            throw new FileDatabaseError(`Failed to write file ${filePath}: ${(error ).message}`);\n        }\n    }\n\n    /**\n     * Prepare the instance for read or write operations\n     * This discovers state and sets up internal members based on mode and current data\n     */\n    async prepare(options\n\n\n\n\n\n\n\n\n\n    ) {\n        const { write, read, version, deferInitialVersion } = options;\n        if (write) {\n            if (this.versioned) {\n                // Versioned mode\n                if (this.currentVersion === null) {\n                    if (!deferInitialVersion) {\n                        await this.makeNewVersion();\n                        this.metadata = this.getDefaultMetadata();\n                        this.metadata.version = this.currentVersion;\n                        this.makeNewFile();\n                    }\n                } else {\n                    // For existing versions, load the metadata if not already loaded\n                    if (!this.metadata.files.length) {\n                        this.metadata = await this.figureMetadata(this.currentVersion);\n                        // Initialize currentFileNumber from existing files\n                        if (this.metadata.files && this.metadata.files.length > 0) {\n                            this.currentFileNumber = Math.max(...this.metadata.files.map(f => f.number || 0));\n                        } else {\n                            this.currentFileNumber = 0;\n                        }\n                    }\n                }\n            } else {\n                // Non-versioned mode - ensure table directory exists\n                await ensurePath(this.getDestinationPath());\n\n                // Non-versioned mode - auto-detect useMetadata if not set\n                if (this.useMetadata === true) {\n                    // Try to load existing metadata, create new if doesn't exist\n                    const metadataPath = path.join(this.getDestinationPath(), \"metadata.json\");\n                    if (fs.existsSync(metadataPath)) {\n                        try {\n                            const rawData = await fs.promises.readFile(metadataPath, \"utf8\");\n                            this.metadata = JSON.parse(rawData);\n                            // Initialize currentFileNumber from existing files\n                            if (this.metadata.files && this.metadata.files.length > 0) {\n                                this.currentFileNumber = Math.max(...this.metadata.files.map(f => f.number || 0));\n                            } else {\n                                this.currentFileNumber = 0;\n                            }\n                        } catch (e) {\n                            this.metadata = this.getDefaultMetadata();\n                            this.currentFileNumber = 0;\n                        }\n                    } else {\n                        // Don't create a file here - let the write logic handle it\n                        // This prevents creating an empty file when customMetadata is provided\n                        this.metadata = this.getDefaultMetadata();\n                        this.currentFileNumber = 0;\n                    }\n                } else {\n                    // No metadata mode - just create default metadata\n                    // Don't create a file here either - let the write logic handle it\n                    this.metadata = this.getDefaultMetadata();\n                    this.currentFileNumber = 0;\n                }\n            }\n        } else if (read) {\n            if (this.versioned) {\n                // Versioned mode\n                const versions = await this.getVersions();\n                if (versions.length === 0) {\n                    throw new FileDatabaseError(\"[FileDatabase] No versions found, cannot read\");\n                }\n\n                const targetVersion = version || versions[versions.length - 1];\n                if (version && !versions.includes(version)) {\n                    throw new FileDatabaseError(`[FileDatabase] Version \"${version}\" not found`);\n                }\n                if (this.metadata.version !== targetVersion) {\n                    this.metadata = this.getDefaultMetadata();\n                    this.currentRecord = 0;\n                    this.hasReadFirstPage = false;\n                }\n                await this.setCurrentVersion(targetVersion);\n\n                if (!this.metadata.files.length) {\n                    this.metadata = await this.figureMetadata(this.currentVersion);\n                    // Initialize currentFileNumber from existing files\n                    if (this.metadata.files && this.metadata.files.length > 0) {\n                        this.currentFileNumber = Math.max(...this.metadata.files.map(f => f.number || 0));\n                    } else {\n                        this.currentFileNumber = 0;\n                    }\n                }\n            } else {\n                // Non-versioned mode\n                this.currentVersion = null; // No version concept\n\n                // Auto-detect useMetadata if not explicitly set\n                if (this.useMetadata === undefined) {\n                    const format = await this.detectDataFormat();\n                    this.useMetadata = format.hasMetadata;\n                }\n\n                if (this.useMetadata) {\n                    // Load metadata from root\n                    const destPath = this.getDestinationPath();\n                    const metadataPath = path.join(destPath, \"metadata.json\");\n                    if (fs.existsSync(metadataPath)) {\n                        try {\n                            const rawData = await fs.promises.readFile(metadataPath, \"utf8\");\n                            this.metadata = JSON.parse(rawData);\n                            // Initialize currentFileNumber from existing files\n                            if (this.metadata.files && this.metadata.files.length > 0) {\n                                this.currentFileNumber = Math.max(...this.metadata.files.map(f => f.number || 0));\n                            } else {\n                                this.currentFileNumber = 0;\n                            }\n                        } catch (e) {\n                            throw new FileDatabaseError(`Failed to read metadata: ${(e ).message}`);\n                        }\n                    } else {\n                        throw new FileDatabaseError(\n                            `[FileDatabase] No metadata found in non-versioned mode. Looked for: ${metadataPath} (table path: ${destPath})`\n                        );\n                    }\n                } else {\n                    // Figure metadata from files\n                    this.metadata = await this.figureMetadataFromVersionFiles(\"\");\n                    // Initialize currentFileNumber from existing files\n                    if (this.metadata.files && this.metadata.files.length > 0) {\n                        this.currentFileNumber = Math.max(...this.metadata.files.map(f => f.number || 0));\n                    } else {\n                        this.currentFileNumber = 0;\n                    }\n                }\n            }\n        }\n    }\n\n    /**\n     * Write data to the file database\n     */\n    async write(data, options = {}) {\n        // Catalog mode: write to specific filename in destination path\n        if (options.filename) {\n            const destPath = this.getDestinationPath();\n            await ensurePath(destPath);\n            const filePath = path.join(destPath, options.filename);\n            await this.safeWrite(filePath, data);\n            return;\n        }\n\n        // Check for forceNewVersion in non-versioned mode\n        if (options.forceNewVersion && !this.versioned) {\n            throw new FileDatabaseError(\"Cannot use forceNewVersion in non-versioned mode\");\n        }\n\n        // Prepare for writing (this may load existing metadata).\n        // If this write will force a new version on an empty store, defer the initial version in\n        // prepare so we only call makeNewVersion() once (in the forceNewVersion block below).\n        await this.prepare({ write: true, deferInitialVersion: !!(options.forceNewVersion && this.versioned) });\n\n        // Always detect data type from incoming data AFTER prepare()\n        // This ensures we use the correct type even if existing metadata has a different type\n        const incomingDataType = detectDataType(data);\n        this.metadata.dataType = incomingDataType;\n\n        // Force new version if requested (versioned mode only)\n        if (options.forceNewVersion) {\n            await this.makeNewVersion();\n            this.metadata = this.getDefaultMetadata();\n            this.metadata.version = this.currentVersion;\n            // Set data type from incoming data\n            this.metadata.dataType = incomingDataType;\n            this.makeNewFile();\n        }\n\n        // Check if customMetadata is provided and find existing file with matching metadata\n        let targetFileIndex = null;\n        const hasCustomMetadata = options.customMetadata && Object.keys(options.customMetadata).length > 0;\n        \n        if (hasCustomMetadata) {\n            // Search through existing files for matching custom metadata\n            for (let i = 0; i < this.metadata.files.length; i++) {\n                const fileEntry = this.metadata.files[i];\n                // Check if all customMetadata fields match\n                // A file matches if it has all the customMetadata keys and their values match\n                const matches = Object.keys(options.customMetadata).every(key => {\n                    // File must have the key and the value must match\n                    return key in fileEntry && fileEntry[key] === options.customMetadata[key];\n                });\n                if (matches) {\n                    targetFileIndex = i;\n                    this.logger.silly?.(`[FileDatabase] Found existing file with matching custom metadata: ${fileEntry.fileName}, metadata: ${JSON.stringify(options.customMetadata)}`);\n                    break;\n                } else {\n                    this.logger.silly?.(`[FileDatabase] File ${fileEntry.fileName} does not match custom metadata: ${JSON.stringify(options.customMetadata)}`);\n                }\n            }\n            if (targetFileIndex === null) {\n                this.logger.silly?.(`[FileDatabase] No existing file found with custom metadata: ${JSON.stringify(options.customMetadata)}, will create new file`);\n            }\n        } else {\n            this.logger.silly?.(`[FileDatabase] No custom metadata provided, will create new file`);\n        }\n\n        // If we found a matching file, prepare to overwrite it\n        if (targetFileIndex !== null) {\n            const targetFile = this.metadata.files[targetFileIndex];\n            // Set current file number to match the target file\n            this.currentFileNumber = targetFile.number;\n            // Reset pagination state since we're overwriting\n            this.lastFileData = null;\n            this.currentRecord = 0;\n            this.hasReadFirstPage = false;\n        }\n\n        // Pass flag indicating if we should force a new file (when customMetadata provided but no match)\n        const forceNewFile = hasCustomMetadata && targetFileIndex === null;\n        // eslint-disable-next-line prefer-const\n        let { dataToWrite, dataLeftOver, fileName } = this.figureOutDataAndFileToWrite(data, targetFileIndex, forceNewFile);\n\n        // Write first batch\n        const destPath = this.getDestinationPath(this.currentVersion || undefined);\n        await this.safeWrite(path.join(destPath, fileName), dataToWrite);\n        this.updateMetadata(dataToWrite, fileName, options.customMetadata);\n\n        // Handle pagination for remaining data (arrays only)\n        // Note: For customMetadata matches, we only write to the target file, so no pagination needed\n        while (dataLeftOver && dataLeftOver.length > 0 && targetFileIndex === null) {\n            const writeContext = this.figureOutDataAndFileToWrite(dataLeftOver);\n            await this.safeWrite(path.join(destPath, writeContext.fileName), writeContext.dataToWrite);\n            this.updateMetadata(writeContext.dataToWrite, writeContext.fileName, options.customMetadata);\n            dataLeftOver = writeContext.dataLeftOver;\n        }\n\n        // Calculate version synopsis\n        this.calculateVersionSynopsis();\n\n        // Save metadata to file\n        if (this.useMetadata) {\n            await this.saveVersionMetadata(this.metadata);\n        }\n    }\n\n    /**\n     * Read data from the file database\n     */\n    async read(options = {}) {\n        const { version, nextPage = false, pageSize, filename } = options;\n\n        // Catalog mode: read specific file by name\n        if (filename) {\n            const destPath = this.getDestinationPath(version);\n            const filePath = path.join(destPath, filename);\n            try {\n                const rawData = await fs.promises.readFile(filePath, \"utf8\");\n                return JSON.parse(rawData);\n            } catch (error) {\n                throw new FileDatabaseError(`Failed to read file ${filename}: ${(error ).message}`);\n            }\n        }\n\n        // Prepare for reading\n        await this.prepare({ read: true, version });\n\n        // Check for non-paginated data types\n        const isNonPaginatedData =\n            this.metadata.dataType === \"text\" || this.metadata.dataType === \"xml\" || this.metadata.dataType === \"json-object\";\n\n        if (isNonPaginatedData) {\n            // For text/xml/object data, return all content\n            const file = this.metadata.files[0];\n            const filePath = path.join(this.getDestinationPath(this.currentVersion || undefined), file.fileName);\n            try {\n                const rawData = await fs.promises.readFile(filePath, \"utf8\");\n                return deserializeData(rawData, this.metadata.dataType);\n            } catch (error) {\n                throw new FileDatabaseError(`Failed to read file ${file.fileName}: ${(error ).message}`);\n            }\n        }\n\n        // Handle paginated data (JSON arrays)\n        let effectivePageSize;\n\n        if (nextPage && this.hasReadFirstPage) {\n            // currentRecord was already advanced by records actually returned\n            // at the end of the previous read (not by requested pageSize — that\n            // skipped records when a read ended mid-file / short final page).\n            effectivePageSize = pageSize || this.pageSize;\n        } else if (!nextPage) {\n            // If not paginating, read all records (unless pageSize is explicitly provided)\n            effectivePageSize = pageSize !== undefined ? pageSize : this.metadata.totalRecords;\n            this.currentRecord = 0;\n        } else {\n            // First call with nextPage=true (no previous page read)\n            effectivePageSize = pageSize || this.pageSize;\n        }\n\n        // If beyond total records, return empty array\n        if (this.currentRecord >= this.metadata.totalRecords) {\n            return [];\n        }\n\n        const result = [];\n        this.lastReadMissingFiles = [];\n        let recordsRead = 0;\n        let currentFileIndex = 0;\n        let currentFileOffset = 0;\n\n        // Calculate which file and offset to start from\n        let totalRecords = 0;\n        for (let i = 0; i < this.metadata.files.length; i++) {\n            const file = this.metadata.files[i];\n            if (this.currentRecord < totalRecords + file.recordsCount) {\n                currentFileIndex = i;\n                currentFileOffset = totalRecords;\n                break;\n            }\n            totalRecords += file.recordsCount;\n        }\n\n        // Read from files (cache parsed JSON — harvest chunks are often 50–60MB;\n        // re-parsing on every nextPage with pageSize=200 is catastrophic).\n        let cumulativeRecords = currentFileOffset;\n        for (let i = currentFileIndex; i < this.metadata.files.length && recordsRead < effectivePageSize; i++) {\n            const file = this.metadata.files[i];\n            const filePath = path.join(this.getDestinationPath(this.currentVersion || undefined), file.fileName);\n\n            try {\n                let fileData;\n                if (this.readFileCache?.filePath === filePath && Array.isArray(this.readFileCache.data)) {\n                    fileData = this.readFileCache.data;\n                } else {\n                    const rawData = await fs.promises.readFile(filePath, \"utf8\");\n                    fileData = deserializeData(rawData, this.metadata.dataType);\n                    this.readFileCache = { filePath, data: fileData };\n                }\n\n                let startIndex = 0;\n                if (i === currentFileIndex) {\n                    startIndex = this.currentRecord - cumulativeRecords;\n                }\n\n                const endIndex = Math.min(startIndex + (effectivePageSize - recordsRead), fileData.length);\n                const recordsFromThisFile = fileData.slice(startIndex, endIndex);\n\n                for (let r = 0; r < recordsFromThisFile.length; r++) {\n                    result.push(recordsFromThisFile[r]);\n                }\n                recordsRead += recordsFromThisFile.length;\n\n                cumulativeRecords += file.recordsCount;\n            } catch (error) {\n                if (error?.code === \"ENOENT\") {\n                    if (!this.lastReadMissingFiles) this.lastReadMissingFiles = [];\n                    this.lastReadMissingFiles.push(file.fileName);\n                    cumulativeRecords += file.recordsCount;\n                    continue;\n                }\n                throw new FileDatabaseError(`Failed to read file ${file.fileName}: ${(error ).message}`);\n            }\n        }\n\n        // Advance by what we actually returned so mid-file seeks + short pages\n        // don't skip records on the next nextPage call.\n        this.currentRecord += recordsRead;\n\n        // Mark page as read for pagination tracking\n        // When nextPage=true, we're explicitly paginating\n        // When nextPage=false with explicit pageSize, we're also paginating (starting from beginning)\n        if (result.length > 0) {\n            if (nextPage || (pageSize !== undefined && pageSize < this.metadata.totalRecords)) {\n                this.hasReadFirstPage = true;\n            }\n        }\n\n        return result;\n    }\n\n    /**\n     * Set the starting record for pagination (1-based index)\n     */\n    setStartRecord(startRecord) {\n        this.currentRecord = startRecord - 1;\n        this.hasReadFirstPage = false;\n        this.readFileCache = null;\n    }\n\n    /**\n     * Reset read pagination state\n     */\n    resetPagination() {\n        this.currentRecord = 0;\n        this.hasReadFirstPage = false;\n        this.readFileCache = null;\n    }\n\n    /**\n     * List filenames in the table directory.\n     * For catalog/key-value usage (files written with { filename }).\n     * Returns data file names (.json, .txt, .xml) excluding metadata.json.\n     */\n    async listFilenames() {\n        const destPath = this.versioned && this.currentVersion\n            ? path.join(this.getDestinationPath(), this.currentVersion)\n            : this.getDestinationPath();\n        try {\n            const entries = await fs.promises.readdir(destPath, { withFileTypes: true });\n            return entries\n                .filter((e) => e.isFile() && e.name !== \"metadata.json\" && /\\.(json|txt|xml)$/i.test(e.name))\n                .map((e) => e.name);\n        } catch (err) {\n            if (err?.code === \"ENOENT\") return [];\n            throw new FileDatabaseError(`Failed to list files: ${(err ).message}`);\n        }\n    }\n\n    /**\n     * Remove a file from the table directory (catalog mode).\n     * Use with listFilenames() to manage individual files.\n     */\n    async removeFile(filename) {\n        const destPath = this.versioned && this.currentVersion\n            ? path.join(this.getDestinationPath(), this.currentVersion)\n            : this.getDestinationPath();\n        const filePath = path.join(destPath, filename);\n        try {\n            await fs.promises.unlink(filePath);\n        } catch (err) {\n            if (err?.code === \"ENOENT\") return;\n            throw new FileDatabaseError(`Failed to remove file ${filename}: ${(err ).message}`);\n        }\n    }\n\n    /**\n     * Remove a file and its metadata entry (non-versioned mode with useMetadata).\n     * Use with findData() to get fileName, then call removeFileEntry to delete.\n     */\n    async removeFileEntry(filename) {\n        if (this.versioned) {\n            throw new FileDatabaseError(\"removeFileEntry is only supported in non-versioned mode\");\n        }\n        await this.prepare({ read: true });\n        const idx = this.metadata.files.findIndex((f) => f.fileName === filename);\n        if (idx === -1) {\n            throw new FileDatabaseError(`File entry ${filename} not found in metadata`);\n        }\n        const entry = this.metadata.files[idx];\n        const recordsCount = entry.recordsCount || 0;\n        this.metadata.files.splice(idx, 1);\n        this.metadata.totalRecords = Math.max(0, (this.metadata.totalRecords || 0) - recordsCount);\n        const destPath = this.getDestinationPath();\n        const filePath = path.join(destPath, filename);\n        try {\n            await fs.promises.unlink(filePath);\n        } catch (err) {\n            if (err?.code === \"ENOENT\") {\n                this.logger.warn?.(`[FileDatabase] File ${filename} already missing on disk`);\n            } else {\n                throw new FileDatabaseError(`Failed to remove file ${filename}: ${(err ).message}`);\n            }\n        }\n        if (this.useMetadata) {\n            await this.saveVersionMetadata(this.metadata);\n        }\n    }\n\n    /**\n     * Set file-level synopsis calculation function\n     */\n    setFileSynopsisFunction(fn) {\n        this.fileSynopsisFunction = fn;\n    }\n\n    /**\n     * Set version-level synopsis calculation function\n     */\n    setVersionSynopsisFunction(fn) {\n        this.versionSynopsisFunction = fn;\n    }\n\n    /**\n     * Get current version name\n     */\n    getCurrentVersion() {\n        return this.currentVersion;\n    }\n\n    /**\n     * Max retained version folders (used by harvest_sync.loaded_versions cap, etc.).\n     */\n    getMaxVersions() {\n        return this.maxVersions;\n    }\n\n    /**\n     * Get current metadata\n     */\n    getMetadata() {\n        return { ...this.metadata };\n    }\n\n    /**\n     * Find data by custom metadata fields\n     * Searches through all versions and files to find entries matching the search criteria\n     * \n     * @param searchCriteria - Object with field names and values to search for (e.g., { ListingKey: \"123\", id: \"456\" })\n     * @returns Array of found entries with their file paths and metadata\n     */\n    async findData(searchCriteria)\n\n\n\n\n\n    {\n        const results\n\n\n\n\n\n = [];\n\n        // Handle non-versioned mode separately\n        if (!this.versioned) {\n            // Load metadata for non-versioned mode\n            await this.prepare({ read: true });\n            const metadata = this.getMetadata();\n            \n            // Search through files\n            for (const fileEntry of metadata.files) {\n                // Check if file entry matches search criteria\n                const matches = Object.keys(searchCriteria).every(key => {\n                    return fileEntry[key] === searchCriteria[key];\n                });\n\n                if (matches) {\n                    // Read the file data\n                    const destPath = this.getDestinationPath();\n                    const filePath = path.join(destPath, fileEntry.fileName);\n                    const fileData = await fs.promises.readFile(filePath, \"utf8\");\n                    const data = deserializeData(fileData, metadata.dataType || \"json-object\");\n\n                    results.push({\n                        filePath,\n                        fileName: fileEntry.fileName,\n                        version: null,\n                        metadata: fileEntry,\n                        data,\n                    });\n                }\n            }\n        } else {\n            // Versioned mode: search through all versions\n            const versions = await this.getVersions();\n            \n            for (const version of versions) {\n                // Load metadata for this version\n                await this.prepare({ read: true, version });\n                const metadata = this.getMetadata();\n\n                // Search through files in this version\n                for (const fileEntry of metadata.files) {\n                    // Check if file entry matches search criteria\n                    const matches = Object.keys(searchCriteria).every(key => {\n                        return fileEntry[key] === searchCriteria[key];\n                    });\n\n                    if (matches) {\n                        // Read the file data\n                        const destPath = this.getDestinationPath(version);\n                        const filePath = path.join(destPath, fileEntry.fileName);\n                        const fileData = await fs.promises.readFile(filePath, \"utf8\");\n                        const data = deserializeData(fileData, metadata.dataType || \"json-object\");\n\n                        results.push({\n                            filePath,\n                            fileName: fileEntry.fileName,\n                            version,\n                            metadata: fileEntry,\n                            data,\n                        });\n                    }\n                }\n            }\n        }\n\n        return results;\n    }\n}\n\n// Export types\n\n\n\n\n\n\n\n\n\n\n\n;\n\n// Export synopsis functions\nexport { defaultFileSynopsisFunction, defaultVersionSynopsisFunction } from \"./synopsis-functions.js\";\n\n/**\n * Initialize FileDatabase from context\n * Similar to MlsClient.init pattern\n * \n * @param context - Context from init()\n * @param options - Optional configuration (takes precedence over context.params)\n * @returns Initialized FileDatabase instance\n */\n/**\n * List all table names in a given namespace\n * Scans the filesystem to find all table directories\n *\n * @param basePath - Base path for file storage\n * @param namespace - Namespace to scan (e.g., \"harvested\", \"fromMLS\")\n * @returns Array of table names (directory names)\n */\nexport function listTables(basePath, namespace) {\n    const namespacePath = path.join(basePath, namespace);\n\n    if (!fs.existsSync(namespacePath)) {\n        return [];\n    }\n\n    try {\n        return fs.readdirSync(namespacePath, { withFileTypes: true })\n            .filter(dirent => dirent.isDirectory())\n            .map(dirent => dirent.name);\n    } catch (error) {\n        // Return empty array if can't read directory\n        return [];\n    }\n}\n\n/**\n * List all sources (namespaces) in a given base path\n * Scans the filesystem to find all namespace directories\n *\n * @param basePath - Base path for file storage\n * @returns Array of source names (directory names)\n */\nexport function listSources(basePath) {\n    if (!fs.existsSync(basePath)) {\n        return [];\n    }\n\n    try {\n        return fs.readdirSync(basePath, { withFileTypes: true })\n            .filter(dirent => dirent.isDirectory())\n            .map(dirent => dirent.name);\n    } catch (error) {\n        // Return empty array if can't read directory\n        return [];\n    }\n}\n","/**\n * Operating System Utilities\n * \n * Helper functions for interacting with the operating system\n * to get system statistics and information\n */\n\nimport fs from \"fs\";\nimport path from \"path\";\nimport { execSync } from \"child_process\";\n\n/**\n * Get free disk space for a given path (in bytes)\n * Returns null if unable to determine\n * Uses `df` command on Unix-like systems\n */\nexport function getFreeDiskSpace(targetPath) {\n    try {\n        // If the target path doesn't exist, use its parent directory\n        let pathToCheck = targetPath;\n        if (!fs.existsSync(targetPath)) {\n            const parentDir = path.dirname(targetPath);\n            if (fs.existsSync(parentDir)) {\n                pathToCheck = parentDir;\n            } else {\n                // If parent doesn't exist either, use the root directory\n                pathToCheck = process.platform === \"win32\" ? \"C:\\\\\" : \"/\";\n            }\n        }\n\n        if (process.platform === \"win32\") {\n            // Windows: use wmic command\n            // Note: This is a simplified implementation, may need adjustments\n            return null; // TODO: Implement robust Windows support\n        } else {\n            // Unix-like systems: use df command\n            const stdout = execSync(`df -k \"${pathToCheck}\"`, { encoding: \"utf8\" });\n            const lines = stdout.trim().split(\"\\n\");\n            const parts = lines[1].split(/\\s+/); // second line, split on whitespace\n            const freeKb = parseInt(parts[3], 10); // 4th column is \"Available\"\n            return freeKb * 1024; // Convert to bytes\n        }\n    } catch (error) {\n        // Silently fail and return null\n        return null;\n    }\n}\n\n/**\n * Free / total bytes for the volume that holds `targetPath` (Node `fs.statfs`).\n * Returns null when the call is unavailable or fails.\n *\n * @param {string} targetPath\n * @returns {Promise<{ free: number, total: number, freeRatio: number } | null>}\n */\nexport async function getDiskUsage(targetPath) {\n    const fsPromises = await import(\"node:fs/promises\");\n    try {\n        let pathToCheck = targetPath;\n        if (!fs.existsSync(pathToCheck)) {\n            const parentDir = path.dirname(pathToCheck);\n            pathToCheck = fs.existsSync(parentDir)\n                ? parentDir\n                : process.platform === \"win32\"\n                  ? \"C:\\\\\"\n                  : \"/\";\n        }\n        if (typeof fsPromises.statfs !== \"function\") return null;\n        const stats = await fsPromises.statfs(pathToCheck);\n        const total = Number(stats.bsize) * Number(stats.blocks);\n        const free = Number(stats.bsize) * Number(stats.bavail);\n        if (!Number.isFinite(total) || total <= 0) return null;\n        return { free, total, freeRatio: free / total };\n    } catch {\n        return null;\n    }\n}\n\n","/**\n * File System Utilities\n * \n * Helper functions for file system operations like path management,\n * directory creation, and file type detection\n */\n\nimport fs from \"fs\";\nimport path from \"path\";\nimport { fileURLToPath } from \"url\";\n\n/**\n * Ensure a directory path exists, creating it if necessary\n * Returns the absolute path\n */\nexport async function ensurePath(...pathParts) {\n    const fullPath = path.resolve(...pathParts);\n    \n    if (!fs.existsSync(fullPath)) {\n        await fs.promises.mkdir(fullPath, { recursive: true });\n    }\n    \n    return fullPath;\n}\n\n/**\n * Synchronous version of ensurePath\n */\nexport function ensurePathSync(...pathParts) {\n    const fullPath = path.resolve(...pathParts);\n    \n    if (!fs.existsSync(fullPath)) {\n        fs.mkdirSync(fullPath, { recursive: true });\n    }\n    \n    return fullPath;\n}\n\n/**\n * Get file extension for a given data type\n */\nexport function getFileExtension(dataType) {\n    switch (dataType) {\n        case \"json-array\":\n        case \"json-object\":\n            return \"json\";\n        case \"text\":\n            return \"txt\";\n        case \"xml\":\n            return \"xml\";\n        default:\n            return \"json\";\n    }\n}\n\n/**\n * Get __dirname equivalent for ES modules\n * \n * Returns the directory path of the module file\n * Useful for resolving relative paths in ES modules where __dirname is not available\n * \n * @param metaUrl - The import.meta.url from the calling module (must be passed from calling module)\n * @returns The directory path of the module\n * \n * @example\n * ```typescript\n * import { getDirname } from \"@nmakarov/cli-toolkit/utils\";\n * const __dirname = getDirname(import.meta.url);\n * ```\n */\nexport function getDirname(metaUrl) {\n    return path.dirname(fileURLToPath(metaUrl));\n}\n\n","/**\n * Formatting Utilities\n * \n * Helper functions for converting between different data formats\n * and human-readable representations\n */\n\n/**\n * Convert bytes to human-readable format (e.g., \"1.5 MB\")\n */\nexport function bytesToHumanReadable(bytes) {\n    if (bytes === 0) return \"0 B\";\n    \n    const k = 1024;\n    const sizes = [\"B\", \"KB\", \"MB\", \"GB\", \"TB\", \"PB\"];\n    const i = Math.floor(Math.log(bytes) / Math.log(k));\n    \n    return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + \" \" + sizes[i];\n}\n\n/**\n * Convert human-readable format to bytes (e.g., \"1.5 MB\" -> 1572864)\n */\nexport function humanReadableToBytes(humanString) {\n    const units = {\n        \"B\": 1,\n        \"KB\": 1024,\n        \"MB\": 1024 * 1024,\n        \"GB\": 1024 * 1024 * 1024,\n        \"TB\": 1024 * 1024 * 1024 * 1024,\n        \"PB\": 1024 * 1024 * 1024 * 1024 * 1024,\n    };\n    \n    const match = humanString.trim().match(/^([\\d.]+)\\s*([A-Z]+)$/i);\n    if (!match) {\n        throw new Error(`Invalid format: ${humanString}. Expected format like \"2MB\" or \"1.5 GB\"`);\n    }\n    \n    const value = parseFloat(match[1]);\n    const unit = match[2].toUpperCase();\n    \n    if (!units[unit]) {\n        throw new Error(`Unknown unit: ${unit}. Supported units: ${Object.keys(units).join(\", \")}`);\n    }\n    \n    return Math.round(value * units[unit]);\n}\n\n","/**\n * Date/time utility functions for timestamp formatting and timezone conversions\n */\n\n\n\n\n\n\n/**\n * Format a date string or Date object to ISO8601 format in specified timezone\n * Always returns UTC-based ISO strings (YYYY-MM-DDTHH:mm:ssZ) as internal representation\n * \n * @param value - Date object, ISO string, or timestamp\n * @param options - Formatting options\n * @returns ISO8601 formatted string\n */\nexport function formatDate(value, options = {}) {\n    if (value === undefined || value === null) {\n        return \"\";\n    }\n\n    const { timezone = \"UTC\", format = \"iso\" } = options;\n    \n    let date;\n    if (value instanceof Date) {\n        date = value;\n    } else if (typeof value === \"string\") {\n        date = new Date(value);\n    } else if (typeof value === \"number\") {\n        date = new Date(value);\n    } else {\n        return \"\";\n    }\n\n    if (isNaN(date.getTime())) {\n        return \"\";\n    }\n\n    // Format based on requested format\n    switch (format) {\n        case \"iso\":\n            // Full ISO8601: 2025-01-01T01:01:01Z\n            return date.toISOString();\n        \n        case \"iso-date\":\n            // Date only: 2025-01-01\n            return date.toISOString().split(\"T\")[0];\n        \n        case \"iso-time\":\n            // Time only: 01:01:01Z\n            return date.toISOString().split(\"T\")[1];\n        \n        case \"human\":\n            // Human-readable: Jan 1, 2025 01:01:01 UTC\n            if (timezone === \"user\") {\n                return date.toLocaleString();\n            }\n            return date.toUTCString();\n        \n        default:\n            return date.toISOString();\n    }\n}\n\n/**\n * Parse a date value and return ISO8601 string in UTC\n * This is the canonical format for internal storage\n * \n * @param value - Date object or string\n * @returns ISO8601 string in UTC timezone\n */\nexport function toISOString(value) {\n    return formatDate(value, { timezone: \"UTC\", format: \"iso\" });\n}\n\n/**\n * Get current timestamp as ISO8601 string in UTC\n * @returns Current time as ISO8601 string\n */\nexport function nowISO() {\n    return new Date().toISOString();\n}\n\n/**\n * Parse ISO8601 string to Date object\n * @param isoString - ISO8601 formatted string\n * @returns Date object\n */\nexport function fromISOString(isoString) {\n    return new Date(isoString);\n}\n\n/**\n * Calculate difference between two dates in various units\n * @param start - Start date (ISO string or Date)\n * @param end - End date (ISO string or Date)\n * @returns Object with duration in multiple units\n */\nexport function dateDiff(\n    start,\n    end\n)\n\n\n\n\n\n{\n    const startDate = start instanceof Date ? start : new Date(start);\n    const endDate = end instanceof Date ? end : new Date(end);\n    \n    const diffMs = endDate.getTime() - startDate.getTime();\n    \n    return {\n        milliseconds: diffMs,\n        seconds: Math.floor(diffMs / 1000),\n        minutes: Math.floor(diffMs / (1000 * 60)),\n        hours: Math.floor(diffMs / (1000 * 60 * 60)),\n        days: Math.floor(diffMs / (1000 * 60 * 60 * 24))\n    };\n}\n\n/**\n * Check if a folder name looks like an ISO8601 timestamp\n * Used to identify version folders vs regular folders\n * @param folderName - Folder name to check\n * @returns true if the folder name is a valid ISO8601 timestamp\n */\nexport function isTimestampFolder(folderName) {\n    // Match ISO8601 format: YYYY-MM-DDTHH:mm:ssZ\n    const isoRegex = /^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}(Z|\\.\\d{3}Z)$/;\n    \n    if (!isoRegex.test(folderName)) {\n        return false;\n    }\n    \n    const date = new Date(folderName);\n    return !isNaN(date.getTime()) && date.getTime() > 0;\n}\n\n/**\n * Generate a new version name (ISO8601 timestamp)\n * If existingVersions provided, ensures the new version is later than all existing ones\n * @param existingVersions - Array of existing version timestamps\n * @returns New version timestamp that is unique and later than existing ones\n */\nexport function generateVersionName(existingVersions = []) {\n    if (existingVersions.length === 0) {\n        // No existing versions, use current timestamp\n        const now = new Date();\n        return now.toISOString().split(\".\")[0] + \"Z\";\n    }\n    \n    // Find the maximum timestamp among all existing versions\n    const maxTimestamp = existingVersions.reduce((max, version) => {\n        const versionDate = new Date(version);\n        const maxDate = new Date(max);\n        return versionDate > maxDate ? version : max;\n    });\n    \n    // Increment by 1 second to ensure uniqueness\n    const maxDate = new Date(maxTimestamp);\n    const nextDate = new Date(maxDate.getTime() + 1000);\n    \n    return nextDate.toISOString().split(\".\")[0] + \"Z\";\n}\n\n","\n\n\n\n\n\n\n\n/**\n * Detect the data type of a given value\n */\nexport function detectDataType(data) {\n    if (Array.isArray(data)) {\n        return \"json-array\";\n    } else if (typeof data === \"object\" && data !== null) {\n        return \"json-object\";\n    } else if (typeof data === \"string\") {\n        // Try to detect if it's XML\n        const trimmed = data.trim();\n        if (trimmed.startsWith(\"<?xml\") || trimmed.startsWith(\"<\")) {\n            return \"xml\";\n        }\n        return \"text\";\n    } else {\n        return \"text\";\n    }\n}\n\n/**\n * Serialize data to a string for file storage\n */\nexport function serializeData(data) {\n    const dataType = detectDataType(data);\n    \n    if (dataType === \"json-array\" || dataType === \"json-object\") {\n        return JSON.stringify(data, null, 4);\n    } else {\n        // For text and XML, return as-is\n        return String(data);\n    }\n}\n\n/**\n * Deserialize data from a string based on data type\n */\nexport function deserializeData(rawData, dataType) {\n    if (dataType === \"json-array\" || dataType === \"json-object\") {\n        return JSON.parse(rawData);\n    } else {\n        // For text and XML, return as-is\n        return rawData;\n    }\n}\n\n","/**\n * Error classes for the CLI toolkit\n */\n\nexport class FrameworkError extends Error {\n    constructor(message) {\n        super(message);\n        this.name = \"FrameworkError\";\n    }\n}\n\nexport class ParamError extends FrameworkError {\n    constructor(message) {\n        super(message);\n        this.name = \"ParamError\";\n    }\n}\n\nexport class InitError extends FrameworkError {\n    constructor(message) {\n        super(message);\n        this.name = \"InitError\";\n    }\n}\n\nexport class CriticalRequestError extends FrameworkError {\n    constructor(message) {\n        super(message);\n        this.name = \"CriticalRequestError\";\n    }\n}\n\nexport class ControlFlowError extends Error {\n    constructor(message) {\n        super(message);\n        this.name = \"ControlFlowError\";\n    }\n}\n\nexport class HttpClientError extends FrameworkError {\n    constructor(message,   cause) {\n        super(message);this.cause = cause;;\n        this.name = \"HttpClientError\";\n    }\n}\n\nexport class FileDatabaseError extends FrameworkError {\n    constructor(message) {\n        super(message);\n        this.name = \"FileDatabaseError\";\n    }\n}\n\n","/**\n * Legacy MLS-oriented synopsis helpers.\n *\n * @deprecated MLS harvest digests (ModificationTimestamp min/max + StandardStatus\n * counts) live in mlsfarm `v2/mls-toolkit/src/harvest/synopsis.js`\n * (`attachHarvestSynopsis`). FileDatabase stays domain-agnostic — attach a\n * synopsis plugin from the app layer. These exports remain for older callers /\n * tests; prefer mls-toolkit for new harvest code.\n */\n\n/**\n * Default file-level synopsis function\n * Extracts min/max *ModificationTimestamp and StandardStatus counts from records.\n * Matches ModificationTimestamp and MediaModificationTimestamp (any key ending\n * with \"modificationtimestamp\", case-insensitive).\n */\nexport function defaultFileSynopsisFunction(fileEntry, data) {\n    if (!Array.isArray(data) || data.length === 0) {\n        return { ...fileEntry };\n    }\n\n    const timestamps = [];\n    const statusCounts = {};\n\n    for (const item of data) {\n        if (!item || typeof item !== \"object\") continue;\n\n        for (const [key, value] of Object.entries(item)) {\n            const k = key.toLowerCase();\n            if (k.endsWith(\"modificationtimestamp\") && value != null && value !== \"\") {\n                const ts = new Date(value).getTime();\n                if (!Number.isNaN(ts)) timestamps.push(ts);\n            }\n            if (k === \"standardstatus\" && value != null && value !== \"\") {\n                const status = String(value);\n                statusCounts[status] = (statusCounts[status] || 0) + 1;\n            }\n        }\n    }\n\n    const result = { ...fileEntry };\n\n    if (timestamps.length) {\n        result.minModificationTimestamp = new Date(Math.min(...timestamps)).toISOString();\n        result.maxModificationTimestamp = new Date(Math.max(...timestamps)).toISOString();\n    }\n\n    if (Object.keys(statusCounts).length) {\n        result.StandardStatuses = statusCounts;\n    }\n\n    return result;\n}\n\n/**\n * Default version-level synopsis function\n * Aggregates min/max timestamps and status counts across all files in a version\n */\nexport function defaultVersionSynopsisFunction(metadata) {\n    if (!metadata?.files || !Array.isArray(metadata.files)) {\n        return metadata;\n    }\n\n    const timestamps = [];\n    const statusCounts = {};\n\n    for (const file of metadata.files) {\n        if (file?.minModificationTimestamp) {\n            const minTs = new Date(file.minModificationTimestamp).getTime();\n            if (!Number.isNaN(minTs)) timestamps.push(minTs);\n        }\n        if (file?.maxModificationTimestamp) {\n            const maxTs = new Date(file.maxModificationTimestamp).getTime();\n            if (!Number.isNaN(maxTs)) timestamps.push(maxTs);\n        }\n\n        if (file?.StandardStatuses && typeof file.StandardStatuses === \"object\") {\n            for (const [status, count] of Object.entries(file.StandardStatuses)) {\n                statusCounts[status] = (statusCounts[status] || 0) + Number(count || 0);\n            }\n        }\n    }\n\n    const result = { ...metadata };\n    const synopsis = {\n        ...(metadata.synopsis && typeof metadata.synopsis === \"object\" ? metadata.synopsis : {}),\n    };\n\n    if (timestamps.length) {\n        const minIso = new Date(Math.min(...timestamps)).toISOString();\n        const maxIso = new Date(Math.max(...timestamps)).toISOString();\n        result.minModificationTimestamp = minIso;\n        result.maxModificationTimestamp = maxIso;\n        synopsis.minModificationTimestamp = minIso;\n        synopsis.maxModificationTimestamp = maxIso;\n    }\n\n    if (Object.keys(statusCounts).length > 0) {\n        result.StandardStatuses = statusCounts;\n        synopsis.StandardStatuses = statusCounts;\n    }\n\n    if (Object.keys(synopsis).length) {\n        result.synopsis = synopsis;\n    }\n    return result;\n}\n"],"mappings":"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","names":["import_fs","import_path","fs","path","import_fs","import_path","path","fs","path","fs","destPath","path","fs"]}