@nmakarov/cli-toolkit 0.14.2 → 0.18.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. package/dist/args.cjs +49 -9
  2. package/dist/args.cjs.map +1 -1
  3. package/dist/args.js +49 -9
  4. package/dist/args.js.map +1 -1
  5. package/dist/cli-runner.cjs +5006 -0
  6. package/dist/cli-runner.cjs.map +1 -0
  7. package/dist/cli-runner.js +4989 -0
  8. package/dist/cli-runner.js.map +1 -0
  9. package/dist/db.cjs +9 -2
  10. package/dist/db.cjs.map +1 -1
  11. package/dist/db.js +9 -2
  12. package/dist/db.js.map +1 -1
  13. package/dist/errors.cjs +17 -0
  14. package/dist/errors.cjs.map +1 -1
  15. package/dist/errors.js +15 -0
  16. package/dist/errors.js.map +1 -1
  17. package/dist/filedatabase.cjs +110 -37
  18. package/dist/filedatabase.cjs.map +1 -1
  19. package/dist/filedatabase.js +110 -36
  20. package/dist/filedatabase.js.map +1 -1
  21. package/dist/http-client.cjs +44 -34
  22. package/dist/http-client.cjs.map +1 -1
  23. package/dist/http-client.js +44 -34
  24. package/dist/http-client.js.map +1 -1
  25. package/dist/http-client2.cjs +1728 -0
  26. package/dist/http-client2.cjs.map +1 -0
  27. package/dist/http-client2.js +1690 -0
  28. package/dist/http-client2.js.map +1 -0
  29. package/dist/index.cjs +1456 -112
  30. package/dist/index.cjs.map +1 -1
  31. package/dist/index.js +1436 -110
  32. package/dist/index.js.map +1 -1
  33. package/dist/init.cjs +199 -82
  34. package/dist/init.cjs.map +1 -1
  35. package/dist/init.js +199 -82
  36. package/dist/init.js.map +1 -1
  37. package/dist/logger.cjs +28 -42
  38. package/dist/logger.cjs.map +1 -1
  39. package/dist/logger.js +28 -42
  40. package/dist/logger.js.map +1 -1
  41. package/dist/mock-server.cjs +205 -359
  42. package/dist/mock-server.cjs.map +1 -1
  43. package/dist/mock-server.js +203 -359
  44. package/dist/mock-server.js.map +1 -1
  45. package/dist/params.cjs +114 -15
  46. package/dist/params.cjs.map +1 -1
  47. package/dist/params.js +114 -15
  48. package/dist/params.js.map +1 -1
  49. package/dist/tasks.cjs +2295 -0
  50. package/dist/tasks.cjs.map +1 -0
  51. package/dist/tasks.js +2240 -0
  52. package/dist/tasks.js.map +1 -0
  53. package/dist/utils.cjs +15 -2
  54. package/dist/utils.cjs.map +1 -1
  55. package/dist/utils.js +12 -1
  56. package/dist/utils.js.map +1 -1
  57. package/package.json +18 -3
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/utils/date-utils.ts","../src/utils/fs-utils.ts","../src/utils/os-utils.ts","../src/utils/format-utils.ts","../src/utils/core-utils.ts","../src/tasks/taskUtils.ts","../src/filedatabase/index.ts","../src/filedatabase/serializers.ts","../src/errors.ts","../src/tasks/taskLogs.ts","../src/tasks/time-matcher.ts","../src/tasks/TaskMaster.ts","../src/tasks/coreTasks/TaskPing.ts","../src/tasks/coreTasks/TaskSampleProcess.ts","../src/tasks/coreTasks/TaskShellCommand.ts","../src/tasks/coreTasks/TaskSystemInfo.ts","../src/tasks/coreTasks/TaskSumAB.ts","../src/tasks/coreTasks/TaskStopRunner.ts","../src/tasks/TasksRegistry.ts","../src/tasks/taskScriptRunner.ts","../src/tasks/index.ts"],"sourcesContent":["/**\n * Date/time utility functions for timestamp formatting and timezone conversions\n */\n\nexport interface DateFormatOptions {\n timezone?: \"UTC\" | \"user\";\n format?: \"iso\" | \"iso-date\" | \"iso-time\" | \"human\";\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: Date | string | number | undefined, options: DateFormatOptions = {}): string {\n if (value === undefined || value === null) {\n return \"\";\n }\n\n const { timezone = \"UTC\", format = \"iso\" } = options;\n \n let date: 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: Date | string | number | undefined): string {\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(): string {\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: string): Date {\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: Date | string,\n end: Date | string\n): {\n milliseconds: number;\n seconds: number;\n minutes: number;\n hours: number;\n days: number;\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: string): boolean {\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: string[] = []): string {\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 * 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: string[]): Promise<string> {\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: string[]): string {\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: string): string {\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: string | URL): string {\n return path.dirname(fileURLToPath(metaUrl));\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: string): number | null {\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 * 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: number): string {\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: string): number {\n const units: Record<string, number> = {\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 * Core lightweight utilities\n */\n\nexport function sleepMs(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nexport function toJsonColumn(value: any): string | null {\n if (value === undefined || value === null) return null;\n return JSON.stringify(value);\n}\n","import { randomUUID } from \"node:crypto\";\nimport type { Context } from \"../init/types.js\";\nimport { toJsonColumn } from \"../utils/index.js\";\nimport type { EnqueueTaskOptions, EnsureTaskTablesOptions } from \"./types.js\";\n\ntype DbLike = any;\n\nfunction getDb(context: Context): DbLike {\n const db = (context as any).db;\n if (!db) {\n throw new Error(\"Tasks component requires context.db. Initialize DB first and attach to context.\");\n }\n return db;\n}\n\nexport function queueToTableNames(queue: string): { tasksTable: string; historyTable: string } {\n if (!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(queue)) {\n throw new Error(`Invalid queue name \"${queue}\". Use letters, numbers, underscore only.`);\n }\n return {\n tasksTable: queue,\n historyTable: `${queue}_history`,\n };\n}\n\nexport async function ensureTaskTables(context: Context, options: EnsureTaskTablesOptions = {}): Promise<void> {\n const queue = options.queue ?? \"tasks\";\n const recreate = options.recreate ?? false;\n const db = getDb(context);\n const { tasksTable, historyTable } = queueToTableNames(queue);\n\n const needsTasks = recreate ? true : !(await db.tableExists(tasksTable));\n const needsHistory = recreate ? true : !(await db.tableExists(historyTable));\n\n if (recreate) {\n await db.schema.dropTableIfExists(historyTable);\n await db.schema.dropTableIfExists(tasksTable);\n }\n\n if (needsTasks) {\n await db.raw(`CREATE EXTENSION IF NOT EXISTS \"uuid-ossp\"`);\n await db.schema.createTable(tasksTable, (t: any) => {\n t.uuid(\"id\").primary().defaultTo(db.raw(\"uuid_generate_v4()\"));\n t.timestamp(\"created_at\").notNullable().defaultTo(db.fn.now());\n t.timestamp(\"started_at\");\n t.timestamp(\"completed_at\");\n t.integer(\"priority\").notNullable().defaultTo(0);\n t.text(\"schedule\");\n t.timestamp(\"past_due\").defaultTo(null);\n t.text(\"target\").notNullable();\n t.text(\"task\").notNullable();\n t.json(\"params\");\n t.text(\"opid\");\n t.timestamp(\"paused_at\").defaultTo(null);\n t.text(\"progress\");\n t.boolean(\"success\");\n t.json(\"results\");\n });\n\n await db.schema.alterTable(tasksTable, (t: any) => {\n t.index([\"target\", \"started_at\", \"created_at\"], `${tasksTable}_target_started_created_idx`);\n t.index([\"target\", \"past_due\", \"priority\", \"created_at\"], `${tasksTable}_target_past_due_priority_created_idx`);\n t.index([\"target\", \"task\"], `${tasksTable}_target_task_idx`);\n });\n }\n const tasksHasOpid = await db.schema.hasColumn(tasksTable, \"opid\");\n if (!tasksHasOpid) {\n await db.schema.alterTable(tasksTable, (t: any) => {\n t.text(\"opid\");\n });\n }\n const tasksHasPausedAt = await db.schema.hasColumn(tasksTable, \"paused_at\");\n if (!tasksHasPausedAt) {\n await db.schema.alterTable(tasksTable, (t: any) => {\n t.timestamp(\"paused_at\").defaultTo(null);\n });\n }\n\n if (needsHistory) {\n await db.schema.createTable(historyTable, (t: any) => {\n t.uuid(\"id\").notNullable();\n t.timestamp(\"created_at\").notNullable();\n t.timestamp(\"started_at\");\n t.timestamp(\"completed_at\");\n t.integer(\"priority\").notNullable().defaultTo(0);\n t.text(\"schedule\");\n t.timestamp(\"past_due\").defaultTo(null);\n t.text(\"target\").notNullable();\n t.text(\"task\").notNullable();\n t.json(\"params\");\n t.text(\"opid\");\n t.text(\"progress\");\n t.boolean(\"success\");\n t.json(\"results\");\n });\n\n await db.schema.alterTable(historyTable, (t: any) => {\n t.index([\"target\", \"created_at\"], `${historyTable}_target_created_idx`);\n t.index([\"task\", \"created_at\"], `${historyTable}_task_created_idx`);\n });\n }\n const historyHasOpid = await db.schema.hasColumn(historyTable, \"opid\");\n if (!historyHasOpid) {\n await db.schema.alterTable(historyTable, (t: any) => {\n t.text(\"opid\");\n });\n }\n}\n\nexport async function enqueueTask(context: Context, options: EnqueueTaskOptions): Promise<string> {\n const db = getDb(context);\n const queue = options.queue ?? \"tasks\";\n const { tasksTable } = queueToTableNames(queue);\n const id = randomUUID();\n\n await db(tasksTable).insert({\n id,\n target: options.target,\n task: options.task,\n params: toJsonColumn(options.params ?? null),\n opid: options.opid ?? null,\n priority: options.priority ?? 0,\n schedule: options.schedule ?? null,\n });\n return id;\n}\n\nexport async function updateTaskProgress(context: Context, tasksTable: string, taskId: string, progress: any): Promise<void> {\n const db = getDb(context);\n await db(tasksTable).where({ id: taskId }).update({\n progress: typeof progress === \"string\" ? progress : JSON.stringify(progress),\n });\n}\n","/**\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\";\nimport type { Context } from \"../init/types.js\";\nimport type {\n FileDatabaseConfig,\n FileDatabaseOptions,\n VersionMetadata,\n FileEntry,\n ReadOptions,\n WriteOptions,\n WriteContext,\n FileSynopsisFunction,\n VersionSynopsisFunction,\n DataType,\n} from \"./types.js\";\nimport { ensurePath, generateVersionName, 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 private basePath: string;\n private namespace: string;\n private tableName: string | null = null;\n private versioned: boolean;\n private maxVersions: number;\n private pageSize: number;\n private useMetadata: boolean;\n private freeSpaceThreshold: number;\n private logger: any;\n\n // Current operation state\n private currentVersion: string | null = null;\n private currentVersionFolder: string | null = null;\n private currentFileNumber: number = 0;\n private currentRecord: number = 0;\n private hasReadFirstPage: boolean = false;\n private lastFileData: any = null;\n private metadata: VersionMetadata;\n\n // Synopsis calculation functions\n private fileSynopsisFunction: FileSynopsisFunction | null = null;\n private versionSynopsisFunction: VersionSynopsisFunction | null = 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: Context | FileDatabaseConfig, options?: FileDatabaseOptions) {\n let config: FileDatabaseConfig;\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 as Context;\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 } as FileDatabaseConfig;\n } else {\n // Legacy pattern: config object\n config = contextOrConfig as FileDatabaseConfig;\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\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: Context, options?: FileDatabaseOptions): FileDatabase {\n return new FileDatabase(context, options ?? {});\n }\n\n /**\n * Get default metadata structure\n */\n private getDefaultMetadata(): VersionMetadata {\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 private getDestinationPath(version?: string): string {\n const errors = [\"basePath\", \"namespace\", \"tableName\"]\n .filter(prop => !this[prop as keyof this])\n .map(prop => `${prop} is not set`);\n if (errors.length) {\n throw new FileDatabaseError(`[FileDatabase] ${errors.join(\"; \")}`);\n }\n\n let 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 private async setCurrentVersion(version: string): Promise<void> {\n this.currentVersion = version;\n this.currentVersionFolder = await ensurePath(this.getDestinationPath(), version);\n }\n\n /**\n * Create a new version folder with comprehensive timestamp logic\n * Only works in versioned mode\n */\n private async makeNewVersion(): Promise<string> {\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 let versionName: string;\n\n if (existingVersions.length > 0) {\n // Find the maximum timestamp among all existing versions\n const maxTimestamp = existingVersions.reduce((max, version) => {\n const versionDate = new Date(version.replace(\"Z\", \"\"));\n const maxDate = new Date(max.replace(\"Z\", \"\"));\n return versionDate > maxDate ? version : max;\n });\n\n // Increment the maximum timestamp by 1 second\n const maxDate = new Date(maxTimestamp.replace(\"Z\", \"\"));\n const nextDate = new Date(maxDate.getTime() + 1000);\n versionName = nextDate.toISOString().split(\".\")[0] + \"Z\";\n } else {\n // No existing versions, use current timestamp\n const now = new Date();\n versionName = now.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(): Promise<string[]> {\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(): Promise<string | null> {\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(): Promise<boolean> {\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(): Promise<{\n versioned: boolean;\n hasMetadata: boolean;\n dataType: DataType | null;\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\n */\n private async loadMetadataJson(version: string): Promise<VersionMetadata | null> {\n const metadataFile = path.join(this.getDestinationPath(), version, \"metadata.json\");\n if (fs.existsSync(metadataFile)) {\n try {\n const rawData = await fs.promises.readFile(metadataFile, \"utf8\");\n return JSON.parse(rawData);\n } catch (e) {\n throw new FileDatabaseError(`Failed to read metadata for version \"${version}\": ${(e as Error).message}`);\n }\n }\n return null;\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 private async figureMetadataFromVersionFiles(version: string): Promise<VersionMetadata> {\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: DataType | null = 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: 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: FileEntry = {\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 as 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 private async buildMetadataOptimized(version: string): Promise<VersionMetadata> {\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: any;\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 private async figureMetadata(version: string, useOptimized: boolean = true): Promise<VersionMetadata> {\n if (this.useMetadata) {\n const metadata = await this.loadMetadataJson(version);\n if (metadata) {\n return metadata;\n }\n }\n \n // Fallback: build from files\n // Use optimized version (only reads first+last) when no synopsis needed\n if (useOptimized && !this.fileSynopsisFunction && !this.versionSynopsisFunction) {\n return await this.buildMetadataOptimized(version);\n }\n \n // Use full version (reads all files) when synopsis calculation needed\n return await this.figureMetadataFromVersionFiles(version);\n }\n\n /**\n * Load version metadata (main entry point for loading)\n */\n private async loadVersionMetadata(version: string): Promise<VersionMetadata> {\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 private async saveVersionMetadata(metadata?: VersionMetadata): Promise<void> {\n if (!this.useMetadata) {\n return;\n }\n\n const metadataToSave = metadata || this.metadata;\n let metadataFile: string;\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 private makeNewFile(): void {\n this.currentFileNumber = (this.currentFileNumber || 0) + 1;\n\n const dataType = this.metadata.dataType || \"json-array\";\n const fileEntry: 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 private figureOutDataAndFileToWrite(data: any, targetFileIndex: number | null = null, forceNewFile: boolean = false): WriteContext {\n let dataToWrite: any;\n let dataLeftOver: any[] | null;\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: number | null = 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 private calculateFileSynopsis(data: any, fileIndex: number = this.metadata.files.length - 1): void {\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 private calculateVersionSynopsis(): void {\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 private updateMetadata(dataToWrite: any, fileName?: string, customMetadata?: Record<string, any>): void {\n let currentFile: FileEntry;\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 private async safeWrite(filePath: string, data: any): Promise<void> {\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 as 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 private async prepare({ write, read, version }: { write?: boolean; read?: boolean; version?: string }): Promise<void> {\n if (write) {\n if (this.versioned) {\n // Versioned mode\n if (this.currentVersion === null) {\n await this.makeNewVersion();\n this.metadata = this.getDefaultMetadata();\n this.metadata.version = this.currentVersion;\n this.makeNewFile();\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 if (version) {\n if (!versions.includes(version)) {\n throw new FileDatabaseError(`[FileDatabase] Version \"${version}\" not found`);\n }\n await this.setCurrentVersion(version);\n } else {\n await this.setCurrentVersion(versions[versions.length - 1]);\n }\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 as Error).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: any, options: WriteOptions = {}): Promise<void> {\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 await this.prepare({ write: true });\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: number | null = 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 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: ReadOptions = {}): Promise<any> {\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 as 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 as Error).message}`);\n }\n }\n\n // Handle paginated data (JSON arrays)\n let effectivePageSize: number;\n\n if (nextPage && this.hasReadFirstPage) {\n // Move to next page\n effectivePageSize = pageSize || this.pageSize;\n this.currentRecord += effectivePageSize;\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: any[] = [];\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\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 const rawData = await fs.promises.readFile(filePath, \"utf8\");\n const fileData = deserializeData(rawData, this.metadata.dataType!);\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 result.push(...recordsFromThisFile);\n recordsRead += recordsFromThisFile.length;\n\n cumulativeRecords += file.recordsCount;\n } catch (error) {\n throw new FileDatabaseError(`Failed to read file ${file.fileName}: ${(error as Error).message}`);\n }\n }\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: number): void {\n this.currentRecord = startRecord - 1;\n this.hasReadFirstPage = false;\n }\n\n /**\n * Reset read pagination state\n */\n resetPagination(): void {\n this.currentRecord = 0;\n this.hasReadFirstPage = false;\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(): Promise<string[]> {\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: any) {\n if (err?.code === \"ENOENT\") return [];\n throw new FileDatabaseError(`Failed to list files: ${(err as Error).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: string): Promise<void> {\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: any) {\n if (err?.code === \"ENOENT\") return;\n throw new FileDatabaseError(`Failed to remove file ${filename}: ${(err as Error).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: string): Promise<void> {\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: any) {\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 as Error).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: FileSynopsisFunction): void {\n this.fileSynopsisFunction = fn;\n }\n\n /**\n * Set version-level synopsis calculation function\n */\n setVersionSynopsisFunction(fn: VersionSynopsisFunction): void {\n this.versionSynopsisFunction = fn;\n }\n\n /**\n * Get current version name\n */\n getCurrentVersion(): string | null {\n return this.currentVersion;\n }\n\n /**\n * Get current metadata\n */\n getMetadata(): VersionMetadata {\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: Record<string, any>): Promise<Array<{\n filePath: string;\n fileName: string;\n version: string | null;\n metadata: FileEntry;\n data: any;\n }>> {\n const results: Array<{\n filePath: string;\n fileName: string;\n version: string | null;\n metadata: FileEntry;\n data: any;\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\nexport type {\n FileDatabaseConfig,\n VersionMetadata,\n FileEntry,\n ReadOptions,\n WriteOptions,\n FileSynopsisFunction,\n VersionSynopsisFunction,\n DataType,\n StorageMode,\n CatalogEntry,\n} from \"./types.js\";\n\n// Export synopsis functions\nexport { defaultFileSynopsisFunction, defaultVersionSynopsisFunction } from \"./synopsis-functions.js\";\n\n/**\n * Initialize FileDatabase from context\n * Similar to mlsClientInit 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: string, namespace: string): string[] {\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: string): string[] {\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 * FileStore Serializers\n * \n * Data type detection and serialization/deserialization utilities\n */\n\nimport type { DataType } from \"./types.js\";\n\n/**\n * Detect the data type of a given value\n */\nexport function detectDataType(data: any): DataType {\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: any): string {\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: string, dataType: DataType): any {\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: string) {\n super(message);\n this.name = \"FrameworkError\";\n }\n}\n\nexport class ParamError extends FrameworkError {\n constructor(message: string) {\n super(message);\n this.name = \"ParamError\";\n }\n}\n\nexport class InitError extends FrameworkError {\n constructor(message: string) {\n super(message);\n this.name = \"InitError\";\n }\n}\n\nexport class CriticalRequestError extends FrameworkError {\n constructor(message: string) {\n super(message);\n this.name = \"CriticalRequestError\";\n }\n}\n\nexport class ControlFlowError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"ControlFlowError\";\n }\n}\n\nexport class HttpClientError extends FrameworkError {\n constructor(message: string, public readonly cause?: Error) {\n super(message);\n this.name = \"HttpClientError\";\n }\n}\n\nexport class FileDatabaseError extends FrameworkError {\n constructor(message: string) {\n super(message);\n this.name = \"FileDatabaseError\";\n }\n}\n\n","import { FileDatabase } from \"../filedatabase/index.js\";\nimport type { Context } from \"../init/types.js\";\nimport type { TaskRow } from \"./types.js\";\n\ntype LogsState = {\n db: FileDatabase;\n errorDb: FileDatabase;\n queue: Promise<void>;\n initialized: boolean;\n errorInitialized: boolean;\n};\n\nfunction getLogsState(context: Context): LogsState {\n const holder = context as any;\n if (holder.__tasksLogsState) return holder.__tasksLogsState as LogsState;\n\n const basePath = holder.params?.get?.(\"tasksLogsBasePath\") || \"./data\";\n const namespace = holder.params?.get?.(\"tasksLogsNamespace\") || \"tasks-logs\";\n const tableName = holder.params?.get?.(\"tasksLogsTable\") || \"runner\";\n const errorTableName = holder.params?.get?.(\"tasksErrorLogsTable\") || `${tableName}-errors`;\n const maxVersionsRaw = Number(holder.params?.get?.(\"tasksLogsMaxVersions\"));\n const pageSizeRaw = Number(holder.params?.get?.(\"tasksLogsPageSize\"));\n\n const errorDb = new FileDatabase({\n basePath,\n namespace,\n tableName: errorTableName,\n versioned: true,\n useMetadata: true,\n maxVersions: Number.isFinite(maxVersionsRaw) && maxVersionsRaw > 0 ? maxVersionsRaw : 20,\n pageSize: Number.isFinite(pageSizeRaw) && pageSizeRaw > 0 ? pageSizeRaw : 2000,\n logger: holder.logger,\n });\n\n const enabledRaw = holder.params?.get?.(\"tasksLogsEnabled\");\n const enabled = enabledRaw === undefined ? true : !!enabledRaw;\n if (!enabled) {\n const disabledState: LogsState = {\n db: null as any,\n errorDb,\n queue: Promise.resolve(),\n initialized: true,\n errorInitialized: false,\n };\n holder.__tasksLogsState = disabledState;\n return disabledState;\n }\n\n const db = new FileDatabase({\n basePath,\n namespace,\n tableName,\n versioned: true,\n useMetadata: true,\n maxVersions: Number.isFinite(maxVersionsRaw) && maxVersionsRaw > 0 ? maxVersionsRaw : 20,\n pageSize: Number.isFinite(pageSizeRaw) && pageSizeRaw > 0 ? pageSizeRaw : 2000,\n logger: holder.logger,\n });\n const state: LogsState = {\n db,\n errorDb,\n queue: Promise.resolve(),\n initialized: false,\n errorInitialized: false,\n };\n holder.__tasksLogsState = state;\n return state;\n}\n\nfunction isErrorPayload(payload: any): boolean {\n if (!payload) return false;\n if (typeof payload === \"object\") {\n const level = typeof payload.level === \"string\" ? payload.level.toLowerCase() : \"\";\n if (level === \"error\" || level === \"fatal\") return true;\n if (typeof payload.message === \"string\" && /\\berror\\b/i.test(payload.message)) return true;\n return false;\n }\n if (typeof payload === \"string\") {\n return /\\berror\\b/i.test(payload);\n }\n return false;\n}\n\nfunction buildLogRecord(task: TaskRow, payload: any): Record<string, any> {\n const params = (task.params && typeof task.params === \"object\") ? task.params : {};\n return {\n ts: new Date().toISOString(),\n opid: task.opid ?? null,\n taskId: task.id,\n taskName: task.task,\n target: task.target,\n source: typeof (params as any).source === \"string\" ? (params as any).source : null,\n resource: typeof (params as any).resource === \"string\" ? (params as any).resource : null,\n payload,\n };\n}\n\nexport function appendTaskIpcLog(context: Context, task: TaskRow, payload: any): void {\n const state = getLogsState(context);\n if (!state.db && !state.errorDb) return;\n\n const record = buildLogRecord(task, payload);\n state.queue = state.queue\n .then(async () => {\n if (state.db) {\n await state.db.write([record], { forceNewVersion: !state.initialized });\n state.initialized = true;\n }\n if (state.errorDb && isErrorPayload(payload)) {\n await state.errorDb.write([record], { forceNewVersion: !state.errorInitialized });\n state.errorInitialized = true;\n }\n })\n .catch((error) => {\n context.logger.warn?.(\"[tasks] failed to persist IPC log entry:\", error);\n });\n}\n","const RANGES = [\"0-59\", \"0-59\", \"0-23\", \"1-31\", \"1-12\", \"0-6\"];\n\nfunction resolveAsterisks(field: string, range: string): string {\n return field.includes(\"*\") ? field.replace(\"*\", range) : field;\n}\n\nfunction resolveRanges(field: string): string {\n const regex = /(\\d+)-(\\d+)/;\n let current = field;\n while (true) {\n const match = regex.exec(current);\n if (!match) break;\n const raw = match[0];\n let first = Number(match[1]);\n let last = Number(match[2]);\n if (last < first) {\n [first, last] = [last, first];\n }\n const values: number[] = [];\n for (let i = first; i <= last; i += 1) {\n values.push(i);\n }\n current = current.replace(raw, values.join(\",\"));\n }\n return current;\n}\n\nfunction resolveSteps(field: string): string {\n const match = /^(.+)\\/(\\d+)$/.exec(field);\n if (!match) return field;\n const base = match[1];\n const step = Number(match[2]);\n if (!Number.isFinite(step) || step <= 0) return field;\n return base\n .split(\",\")\n .map((v) => Number(v))\n .filter((v) => Number.isFinite(v) && v % step === 0)\n .join(\",\");\n}\n\nfunction convertPattern(pattern: string): string[] {\n const parts = pattern.trim().split(/\\s+/);\n if (parts.length !== 6) {\n throw new Error(`Invalid schedule \"${pattern}\". Expected 6 fields: sec min hour day month weekday`);\n }\n return parts\n .map((field, idx) => resolveAsterisks(field, RANGES[idx]))\n .map((field) => resolveRanges(field))\n .map((field) => resolveSteps(field));\n}\n\nfunction fieldMatches(field: string, value: number): boolean {\n const allowed = field.split(\",\").map((v) => Number(v));\n return allowed.includes(value);\n}\n\nexport function timeMatcher(pattern: string, date: Date = new Date()): boolean {\n const parsed = convertPattern(pattern);\n return (\n fieldMatches(parsed[0], date.getSeconds()) &&\n fieldMatches(parsed[1], date.getMinutes()) &&\n fieldMatches(parsed[2], date.getHours()) &&\n fieldMatches(parsed[3], date.getDate()) &&\n fieldMatches(parsed[4], date.getMonth() + 1) &&\n fieldMatches(parsed[5], date.getDay())\n );\n}\n","import type { Context } from \"../init/types.js\";\nimport type { TaskResult, TaskRow } from \"./types.js\";\n\nexport abstract class TaskMaster {\n protected context: Context;\n protected task: TaskRow;\n\n constructor(context: Context, task: TaskRow) {\n this.context = context;\n this.task = task;\n }\n\n cantRunReason(): string | false | null | Promise<string | false | null> {\n return false;\n }\n\n requestStop(_allowanceMs: number): void {\n // Default no-op; long-running tasks can override.\n }\n\n abstract run(reportProgress: (progress: any) => Promise<void>): Promise<TaskResult>;\n}\n","import type { TaskResult } from \"../types.js\";\nimport { TaskMaster } from \"../TaskMaster.js\";\n\nexport class TaskPing extends TaskMaster {\n async run(): Promise<TaskResult> {\n this.context.logger.info?.(`[TaskPing] pong (${this.task.id})`);\n return { success: true, results: \"pong\" };\n }\n}\n","import { sleepMs } from \"../../utils/index.js\";\nimport type { TaskResult } from \"../types.js\";\nimport { TaskMaster } from \"../TaskMaster.js\";\n\nexport class TaskSampleProcess extends TaskMaster {\n private stopRequested = false;\n private stopAllowanceMs = 0;\n private stopDecisionLogged = false;\n\n requestStop(allowanceMs: number): void {\n this.stopRequested = true;\n this.stopAllowanceMs = Number.isFinite(allowanceMs) && allowanceMs > 0 ? allowanceMs : 0;\n this.context.logger.warn?.(\n `[TaskSampleProcess] stop signal received (${this.task.id}), allowanceMs=${this.stopAllowanceMs}`\n );\n }\n\n async run(reportProgress: (progress: any) => Promise<void>): Promise<TaskResult> {\n const totalRaw = this.task?.params?.total ?? 10;\n const delayRaw = this.task?.params?.delay ?? 1000;\n const nameRaw = this.task?.params?.name;\n\n const total = Number(totalRaw);\n const delay = Number(delayRaw);\n const name = typeof nameRaw === \"string\" && nameRaw.trim() ? nameRaw.trim() : \"sampleProcess\";\n\n const errors: string[] = [];\n if (!Number.isInteger(total) || total <= 0) {\n errors.push('param \"total\" must be a positive integer');\n }\n if (!Number.isInteger(delay) || delay < 0) {\n errors.push('param \"delay\" must be an integer >= 0');\n }\n\n if (errors.length > 0) {\n return {\n success: false,\n results: {\n error: `Validation failed: ${errors.join(\", \")}`,\n received: { total: totalRaw, delay: delayRaw, name: nameRaw },\n },\n };\n }\n\n const startedAt = Date.now();\n for (let i = 1; i <= total; i += 1) {\n if (this.stopRequested) {\n const remainingMs = Math.max(0, (total - i + 1) * delay);\n if (remainingMs <= this.stopAllowanceMs) {\n if (!this.stopDecisionLogged) {\n this.stopDecisionLogged = true;\n this.context.logger.warn?.(\n `[TaskSampleProcess] continue to finish (${this.task.id}): remainingMs=${remainingMs} <= allowanceMs=${this.stopAllowanceMs}`\n );\n }\n } else {\n this.context.logger.warn?.(\n `[TaskSampleProcess] stopping gracefully at iteration ${i}/${total} (${this.task.id}), remainingMs=${remainingMs} > allowanceMs=${this.stopAllowanceMs}`\n );\n return {\n success: false,\n results: {\n message: `Stopped before completion at iteration ${i}/${total}`,\n completed: i - 1,\n total,\n name,\n remainingMs,\n allowanceMs: this.stopAllowanceMs,\n },\n };\n }\n }\n\n const elapsed = Date.now() - startedAt;\n const remaining = Math.max(0, (total - i) * delay);\n const progress = {\n name,\n count: i,\n total,\n elapsedMs: elapsed,\n remainingMs: remaining,\n status: `running ${name}: ${i}/${total}`,\n };\n\n this.context.logger.progress(\"running\", {\n prefix: name,\n count: i,\n total,\n });\n await reportProgress(progress);\n await sleepMs(delay);\n }\n\n return {\n success: true,\n results: {\n message: `Completed ${total} iterations`,\n total,\n delay,\n name,\n },\n };\n }\n}\n","import { spawn } from \"node:child_process\";\nimport type { TaskResult } from \"../types.js\";\nimport { TaskMaster } from \"../TaskMaster.js\";\n\ntype CommandExecution = {\n exitCode: number | null;\n output: string;\n stderr: string;\n signal: NodeJS.Signals | null;\n};\n\nfunction runShellCommand(command: string, cwd?: string): Promise<CommandExecution> {\n return new Promise((resolve, reject) => {\n const child = spawn(command, {\n shell: true,\n cwd: cwd || process.cwd(),\n stdio: [\"ignore\", \"pipe\", \"pipe\"],\n });\n\n let output = \"\";\n let stderr = \"\";\n\n child.stdout.on(\"data\", (chunk) => {\n output += String(chunk);\n });\n child.stderr.on(\"data\", (chunk) => {\n stderr += String(chunk);\n });\n\n child.on(\"error\", (error) => {\n reject(error);\n });\n\n child.on(\"close\", (exitCode, signal) => {\n resolve({\n exitCode,\n output: output.trim(),\n stderr: stderr.trim(),\n signal,\n });\n });\n });\n}\n\nexport class TaskShellCommand extends TaskMaster {\n async run(): Promise<TaskResult> {\n const params = this.task?.params as any;\n const commandRaw = typeof params === \"string\" ? params : params?.command;\n const cwdRaw = typeof params === \"string\" ? undefined : params?.cwd;\n const command = typeof commandRaw === \"string\" ? commandRaw.trim() : \"\";\n const cwd = typeof cwdRaw === \"string\" && cwdRaw.trim() ? cwdRaw.trim() : undefined;\n\n if (!command) {\n return {\n success: false,\n results: {\n error: 'Validation failed: param \"command\" must be a non-empty string',\n received: this.task?.params ?? null,\n },\n };\n }\n\n try {\n const result = await runShellCommand(command, cwd);\n const success = result.exitCode === 0;\n\n this.context.logger.info?.(\n `[TaskShellCommand] command=\"${command}\" exitCode=${String(result.exitCode)} (${this.task.id})`\n );\n\n return {\n success,\n results: {\n command,\n cwd: cwd ?? process.cwd(),\n output: result.output,\n stderr: result.stderr,\n exitCode: result.exitCode,\n signal: result.signal,\n },\n };\n } catch (error: any) {\n return {\n success: false,\n results: {\n command,\n cwd: cwd ?? process.cwd(),\n output: \"\",\n stderr: \"\",\n exitCode: null,\n error: error?.message ?? String(error),\n },\n };\n }\n }\n}\n","import os from \"node:os\";\nimport fs from \"node:fs/promises\";\nimport type { TaskResult } from \"../types.js\";\nimport { TaskMaster } from \"../TaskMaster.js\";\n\nfunction toGb(valueBytes: number): string {\n return `${(valueBytes / (1024 ** 3)).toFixed(2)} GB`;\n}\n\nfunction toMb(valueBytes: number): string {\n return `${(valueBytes / (1024 ** 2)).toFixed(2)} MB`;\n}\n\nasync function getDiskStats(): Promise<{ total: string; used: string; free: string }> {\n // Node 20+ statfs; use root path for host-level signal.\n const stats = await fs.statfs(\"/\");\n const total = Number(stats.bsize) * Number(stats.blocks);\n const free = Number(stats.bsize) * Number(stats.bavail);\n const used = total - free;\n return {\n total: toGb(total),\n used: toGb(used),\n free: toGb(free),\n };\n}\n\nexport class TaskSystemInfo extends TaskMaster {\n async run(): Promise<TaskResult> {\n try {\n const totalMemory = os.totalmem();\n const freeMemory = os.freemem();\n const usedMemory = totalMemory - freeMemory;\n\n const cpus = os.cpus();\n const cpuUtilization = cpus.map((cpu) => {\n const total = Object.values(cpu.times).reduce((acc, time) => acc + time, 0);\n const usage = ((total - cpu.times.idle) / total) * 100;\n return Number(usage.toFixed(2));\n });\n\n const processMemory = process.memoryUsage();\n const disk = await getDiskStats();\n\n const results = {\n memory: {\n total: toGb(totalMemory),\n used: toGb(usedMemory),\n free: toGb(freeMemory),\n },\n processMemory: {\n rss: toMb(processMemory.rss),\n heapTotal: toMb(processMemory.heapTotal),\n heapUsed: toMb(processMemory.heapUsed),\n external: toMb(processMemory.external),\n },\n disk,\n cpu: {\n cores: cpuUtilization.length,\n utilization: cpuUtilization,\n },\n runtime: {\n platform: os.platform(),\n arch: os.arch(),\n uptimeSec: os.uptime(),\n hostname: os.hostname(),\n },\n };\n\n this.context.logger.info?.(`[TaskSystemInfo] collected system metrics (${this.task.id})`);\n return { success: true, results };\n } catch (error: any) {\n return {\n success: false,\n results: {\n error: \"Can't collect system stats\",\n message: error?.message ?? String(error),\n },\n };\n }\n }\n}\n","import type { TaskResult } from \"../types.js\";\nimport { TaskMaster } from \"../TaskMaster.js\";\n\nexport class TaskSumAB extends TaskMaster {\n async run(): Promise<TaskResult> {\n const a = this.task?.params?.a;\n const b = this.task?.params?.b;\n\n if (typeof a !== \"number\" || Number.isNaN(a)) {\n return {\n success: false,\n results: {\n error: 'Validation failed: param \"a\" must be a valid number',\n received: { a, b },\n },\n };\n }\n\n if (typeof b !== \"number\" || Number.isNaN(b)) {\n return {\n success: false,\n results: {\n error: 'Validation failed: param \"b\" must be a valid number',\n received: { a, b },\n },\n };\n }\n\n const sum = a + b;\n this.context.logger.info?.(`[TaskSumAB] ${a} + ${b} = ${sum} (${this.task.id})`);\n return {\n success: true,\n results: { a, b, sum },\n };\n }\n}\n","import type { TaskResult } from \"../types.js\";\nimport { TaskMaster } from \"../TaskMaster.js\";\n\nexport class TaskStopRunner extends TaskMaster {\n async run(): Promise<TaskResult> {\n const allowanceMs = Number(this.task?.params?.allowanceMs ?? 5000);\n this.context.logger.warn?.(`[TaskStopRunner] stop requested (allowanceMs=${allowanceMs})`);\n return {\n success: true,\n results: {\n stopRunner: true,\n allowanceMs,\n message: \"Runner stop requested\",\n },\n };\n }\n}\n","import type { TaskClass, TasksRegistryMap } from \"./types.js\";\nimport { TaskPing } from \"./coreTasks/TaskPing.js\";\nimport { TaskSampleProcess } from \"./coreTasks/TaskSampleProcess.js\";\nimport { TaskShellCommand } from \"./coreTasks/TaskShellCommand.js\";\nimport { TaskSystemInfo } from \"./coreTasks/TaskSystemInfo.js\";\nimport { TaskSumAB } from \"./coreTasks/TaskSumAB.js\";\nimport { TaskStopRunner } from \"./coreTasks/TaskStopRunner.js\";\n\nexport class TasksRegistry {\n private readonly map: TasksRegistryMap = {};\n\n constructor(initial?: TasksRegistryMap) {\n if (initial) {\n this.addMany(initial);\n }\n }\n\n static withCoreTasks(): TasksRegistry {\n return new TasksRegistry()\n .add(\"ping\", TaskPing)\n .add(\"sampleProcess\", TaskSampleProcess)\n .add(\"shellCommand\", TaskShellCommand)\n .add(\"systemInfo\", TaskSystemInfo)\n .add(\"taskSumAB\", TaskSumAB)\n .add(\"stopRunner\", TaskStopRunner)\n // Backward-compat alias\n .add(\"stop\", TaskStopRunner);\n }\n\n add(taskName: string, taskClass: TaskClass): TasksRegistry {\n this.map[taskName] = taskClass;\n return this;\n }\n\n addMany(entries: TasksRegistryMap): TasksRegistry {\n for (const [name, klass] of Object.entries(entries)) {\n this.add(name, klass);\n }\n return this;\n }\n\n get(taskName: string): TaskClass | undefined {\n return this.map[taskName];\n }\n\n listSupportedTasks(): string[] {\n return Object.keys(this.map).sort();\n }\n\n toObject(): TasksRegistryMap {\n return { ...this.map };\n }\n}\n","import { spawn } from \"node:child_process\";\nimport type { Context } from \"../init/types.js\";\nimport type { TaskRow } from \"./types.js\";\nimport { appendTaskIpcLog } from \"./taskLogs.js\";\n\nexport type TaskScriptRunResult = {\n exitCode: number | null;\n signal: NodeJS.Signals | null;\n stdout: string;\n stderr: string;\n workerResult: any;\n hadErrorMessage: boolean;\n};\n\ntype TaskScriptRunOptions = {\n scriptPath: string;\n args?: string[];\n cwd?: string;\n task: TaskRow;\n onProgress?: (progress: any) => Promise<void>;\n};\n\nfunction toCliArgs(args: string[] = []): string[] {\n return args.filter((a) => typeof a === \"string\" && a.length > 0);\n}\n\nfunction formatChildLogPrefix(task: TaskRow): string {\n return `${task.task}:${task.id.slice(0, 8)}${task.opid ? `:${task.opid}` : \"\"}`;\n}\n\nexport async function runNodeTaskScript(context: Context, options: TaskScriptRunOptions): Promise<TaskScriptRunResult> {\n const cliArgs = toCliArgs([\"--route=ipc\", \"--mode=json\", ...(options.args || [])]);\n const inheritedExecArgs = Array.isArray(process.execArgv) ? [...process.execArgv] : [];\n const hasTsRuntimeInParent = inheritedExecArgs.some((arg) => /tsx|ts-node/i.test(arg));\n const nodeArgs = hasTsRuntimeInParent\n ? [...inheritedExecArgs, options.scriptPath, ...cliArgs]\n : [\"--import\", \"tsx\", options.scriptPath, ...cliArgs];\n\n const child = spawn(\n process.execPath,\n nodeArgs,\n {\n cwd: options.cwd || process.cwd(),\n stdio: [\"ignore\", \"pipe\", \"pipe\", \"ipc\"],\n env: {\n ...process.env,\n TASK_ID: options.task.id,\n TASK_NAME: options.task.task,\n TASK_OPID: options.task.opid || \"\",\n },\n }\n );\n\n let stdout = \"\";\n let stderr = \"\";\n let workerResult: any = null;\n let hadErrorMessage = false;\n const prefix = formatChildLogPrefix(options.task);\n const db = (context as any).db;\n const tasksTable = (context as any).params?.get?.(\"table\") || \"tasks\";\n let progressWriteChain: Promise<void> = Promise.resolve();\n let progressCallbackChain: Promise<void> = Promise.resolve();\n\n const updateProgress = (text: string): void => {\n if (!db || !text || !text.trim()) return;\n progressWriteChain = progressWriteChain\n .then(async () => {\n await db(tasksTable).where({ id: options.task.id }).update({ progress: text.slice(0, 4000) });\n })\n .catch((error: any) => {\n context.logger.warn?.(\n `[tasks] failed to update progress for task=${options.task.id}: ${error?.message ?? String(error)}`\n );\n });\n if (options.onProgress) {\n progressCallbackChain = progressCallbackChain\n .then(async () => {\n await options.onProgress?.(text.slice(0, 4000));\n })\n .catch((error: any) => {\n context.logger.warn?.(\n `[tasks] reportProgress callback failed for task=${options.task.id}: ${error?.message ?? String(error)}`\n );\n });\n }\n };\n\n const payloadToProgressText = (payload: any): string => {\n if (!payload) return \"\";\n if (typeof payload === \"string\") return payload;\n if (typeof payload.message === \"string\" && payload.level === \"progress\" && payload.count !== undefined && payload.total !== undefined) {\n const pfx = payload.prefix ? `${payload.prefix} ` : \"\";\n return `${pfx}${payload.message} ${payload.count}/${payload.total}`;\n }\n if (typeof payload.message === \"string\") return payload.message;\n if (payload.level === \"progress\" && payload.count !== undefined && payload.total !== undefined) {\n const pfx = payload.prefix ? `${payload.prefix} ` : \"\";\n return `${pfx}${payload.count}/${payload.total}`;\n }\n return \"\";\n };\n\n child.stdout.on(\"data\", (chunk) => {\n const text = String(chunk);\n stdout += text;\n if (text.trim()) {\n context.logger.info?.(`[child:${prefix}] ${text.trimEnd()}`);\n updateProgress(text.trim().replace(/\\s+/g, \" \").slice(0, 400));\n }\n });\n child.stderr.on(\"data\", (chunk) => {\n const text = String(chunk);\n stderr += text;\n if (text.trim()) {\n context.logger.warn?.(`[child:${prefix}] ${text.trimEnd()}`);\n }\n });\n\n child.on(\"message\", (message: any) => {\n if (message && typeof message === \"object\" && \"__taskWorkerResult\" in message) {\n workerResult = message.__taskWorkerResult;\n return;\n }\n if (message && typeof message === \"object\") {\n const level = typeof message.level === \"string\" ? message.level.toLowerCase() : \"\";\n if (level === \"error\" || level === \"fatal\") {\n hadErrorMessage = true;\n }\n }\n appendTaskIpcLog(context, options.task, message);\n const progressText = payloadToProgressText(message);\n if (progressText) {\n updateProgress(progressText);\n if (typeof message === \"object\" && message?.level === \"progress\" && message.count !== undefined && message.total !== undefined) {\n const countNum = Number(String(message.count).trim());\n const totalNum = Number(message.total);\n if (Number.isFinite(countNum) && Number.isFinite(totalNum) && totalNum > 0) {\n context.logger.progress(message.message || \"progress\", {\n prefix: message.prefix || prefix,\n count: countNum,\n total: totalNum,\n });\n } else {\n context.logger.info?.(`[child:${prefix}] ${progressText}`);\n }\n } else {\n context.logger.info?.(`[child:${prefix}] ${progressText}`);\n }\n }\n });\n\n return await new Promise<TaskScriptRunResult>((resolve, reject) => {\n child.on(\"error\", (error) => reject(error));\n child.on(\"close\", (exitCode, signal) => {\n Promise.allSettled([progressWriteChain, progressCallbackChain]).finally(() => {\n resolve({\n exitCode,\n signal,\n stdout: stdout.trim(),\n stderr: stderr.trim(),\n workerResult,\n hadErrorMessage,\n });\n });\n });\n });\n}\n","import type { Context } from \"../init/types.js\";\nimport { sleepMs, toJsonColumn } from \"../utils/index.js\";\nimport { enqueueTask, ensureTaskTables, queueToTableNames, updateTaskProgress } from \"./taskUtils.js\";\nimport { appendTaskIpcLog } from \"./taskLogs.js\";\nimport { timeMatcher } from \"./time-matcher.js\";\nimport { TasksRegistry } from \"./TasksRegistry.js\";\nimport type {\n RunTasksLoopOptions,\n TaskClass,\n TaskInstance,\n TasksManagerInitOptions,\n TaskRow,\n TasksRegistryMap,\n WaitForTaskResultOptions,\n} from \"./types.js\";\n\ntype DbLike = any;\nconst LOCKED_BY_ERROR_MESSAGE = \"locked by error\";\n\nexport { enqueueTask, ensureTaskTables, queueToTableNames, updateTaskProgress } from \"./taskUtils.js\";\nexport { appendTaskIpcLog } from \"./taskLogs.js\";\nexport { runNodeTaskScript } from \"./taskScriptRunner.js\";\nexport { TaskMaster } from \"./TaskMaster.js\";\nexport { TasksRegistry } from \"./TasksRegistry.js\";\nexport { TaskPing } from \"./coreTasks/TaskPing.js\";\nexport { TaskSampleProcess } from \"./coreTasks/TaskSampleProcess.js\";\nexport { TaskShellCommand } from \"./coreTasks/TaskShellCommand.js\";\nexport { TaskSystemInfo } from \"./coreTasks/TaskSystemInfo.js\";\nexport { TaskSumAB } from \"./coreTasks/TaskSumAB.js\";\nexport { TaskStopRunner } from \"./coreTasks/TaskStopRunner.js\";\n\nexport const defaultTasksRegistry = TasksRegistry.withCoreTasks();\n\nfunction getDb(context: Context): DbLike {\n const db = (context as any).db;\n if (!db) {\n throw new Error(\"Tasks component requires context.db. Initialize DB first and attach to context.\");\n }\n return db;\n}\n\nfunction normalizeRegistry(registry: TasksRegistry | TasksRegistryMap | undefined): TasksRegistry {\n if (!registry) return defaultTasksRegistry;\n if (registry instanceof TasksRegistry) return registry;\n return new TasksRegistry().addMany(registry);\n}\n\nfunction normalizeAllowedTasks(value: string[] | string | undefined): string[] | undefined {\n if (!value) return undefined;\n if (Array.isArray(value)) {\n const out = value.map((v) => String(v).trim()).filter(Boolean);\n return out.length ? out : undefined;\n }\n const out = String(value)\n .split(\",\")\n .map((v) => v.trim())\n .filter(Boolean);\n return out.length ? out : undefined;\n}\n\nexport async function enqueueStopTask(context: Context, target: string, queue = \"tasks\", allowanceMs = 5000): Promise<string> {\n return enqueueTask(context, {\n queue,\n target,\n task: \"stopRunner\",\n params: { allowanceMs },\n priority: 1000000,\n });\n}\n\nasync function signalRunningTasksStop(\n context: Context,\n runningTaskInstances: Map<string, TaskInstance>,\n allowanceMs: number\n): Promise<void> {\n context.logger.warn?.(`[tasks] signaling ${runningTaskInstances.size} running task(s) to stop`);\n for (const [, taskInstance] of runningTaskInstances) {\n if (typeof taskInstance.requestStop === \"function\") {\n try {\n await taskInstance.requestStop(allowanceMs);\n } catch (error) {\n context.logger.warn?.(\"[tasks] task requestStop failed:\", error);\n }\n }\n }\n context.emitter.emit(\"stop\", allowanceMs);\n}\n\nasync function executeClaimedTask(\n context: Context,\n tasksTable: string,\n historyTable: string,\n row: TaskRow,\n registry: TasksRegistry,\n runningTaskInstances: Map<string, TaskInstance>\n): Promise<{ stopRunnerRequested: boolean; stopAllowanceMs: number }> {\n const db = getDb(context);\n const taskName = row.task;\n const TaskClass = registry.get(taskName);\n const { paused_at: _pausedAt, ...rowForHistory } = row as any;\n\n if (!TaskClass) {\n const err = { message: `Unknown task \"${taskName}\"` };\n await db(historyTable).insert({\n ...rowForHistory,\n completed_at: new Date(),\n success: false,\n params: toJsonColumn(row.params),\n results: toJsonColumn(err),\n });\n if (row.schedule) {\n await db(tasksTable).where({ id: row.id }).update({\n started_at: null,\n completed_at: new Date(),\n success: false,\n results: toJsonColumn(err),\n past_due: null,\n paused_at: db.fn.now(),\n progress: LOCKED_BY_ERROR_MESSAGE,\n });\n } else {\n await db(tasksTable).where({ id: row.id }).delete();\n }\n return { stopRunnerRequested: false, stopAllowanceMs: 0 };\n }\n\n let success = false;\n let results: any = null;\n let taskInstance: TaskInstance | null = null;\n try {\n taskInstance = new TaskClass(context, row);\n runningTaskInstances.set(row.id, taskInstance);\n const runResult = await taskInstance.run((progress) => updateTaskProgress(context, tasksTable, row.id, progress));\n success = !!runResult?.success;\n results = runResult?.results ?? null;\n } catch (error: any) {\n success = false;\n results = {\n message: error?.message ?? String(error),\n name: error?.name ?? \"Error\",\n stack: error?.stack ?? null,\n };\n } finally {\n runningTaskInstances.delete(row.id);\n }\n\n await db(historyTable).insert({\n ...rowForHistory,\n completed_at: new Date(),\n success,\n params: toJsonColumn(row.params),\n results: toJsonColumn(results),\n });\n if (!success) {\n const dbName = String((context as any)?.params?.get?.(\"dbName\") || \"local\");\n const tableName = String((context as any)?.params?.get?.(\"table\") || \"tasks\");\n const fallbackRecoverCommand = [\n \"npx\",\n \"tsx\",\n \"examples/tasks/recover-task.ts\",\n `--dbName='${dbName.replace(/'/g, `'\\\\''`)}'`,\n `--table='${tableName.replace(/'/g, `'\\\\''`)}'`,\n `--id='${String(row.id).replace(/'/g, `'\\\\''`)}'`,\n ].join(\" \");\n const rerunCommand = results && typeof results === \"object\" && (results as any).rerunCommand\n ? (results as any).rerunCommand\n : fallbackRecoverCommand;\n appendTaskIpcLog(context, row, {\n level: \"error\",\n message: `[tasks] task failed: ${row.task} id=${row.id}. Once problem is fixed, re-run: ${rerunCommand}`,\n details: results,\n });\n }\n\n if (row.schedule) {\n if (success) {\n await db(tasksTable).where({ id: row.id }).update({\n started_at: null,\n completed_at: new Date(),\n success,\n results: toJsonColumn(results),\n progress: null,\n past_due: null,\n });\n } else {\n await db(tasksTable).where({ id: row.id }).update({\n started_at: null,\n completed_at: new Date(),\n success,\n results: toJsonColumn(results),\n paused_at: db.fn.now(),\n progress: LOCKED_BY_ERROR_MESSAGE,\n past_due: null,\n });\n }\n } else {\n await db(tasksTable).where({ id: row.id }).delete();\n }\n\n const stopRunnerRequested = !!(results && typeof results === \"object\" && results.stopRunner === true);\n const stopAllowanceMs = stopRunnerRequested ? Number(results.allowanceMs ?? 5000) : 0;\n return { stopRunnerRequested, stopAllowanceMs };\n}\n\nasync function claimNextRunnableTask(\n context: Context,\n tasksTable: string,\n target: string,\n registry: TasksRegistry,\n scanLimit: number,\n taskNames?: string[]\n): Promise<TaskRow | null> {\n const db = getDb(context);\n\n let query = db(tasksTable)\n .whereNull(\"started_at\")\n .whereNull(\"paused_at\")\n .where({ target })\n .orderByRaw(\"CASE WHEN past_due IS NULL THEN 1 ELSE 0 END ASC\")\n .orderBy([{ column: \"priority\", order: \"desc\" }])\n // Fair rotation for recurring tasks:\n // 1) never-run rows first\n // 2) then least recently completed rows\n // 3) then stable created_at order\n .orderByRaw(\"CASE WHEN completed_at IS NULL THEN 0 ELSE 1 END ASC\")\n .orderBy([{ column: \"completed_at\", order: \"asc\" }, { column: \"created_at\", order: \"asc\" }])\n .limit(scanLimit);\n if (taskNames && taskNames.length > 0) {\n query = query.whereIn(\"task\", taskNames);\n }\n const candidates: TaskRow[] = await query;\n\n for (const row of candidates) {\n if (!row.past_due && row.schedule && !timeMatcher(row.schedule)) {\n continue;\n }\n\n const TaskClass = registry.get(row.task);\n if (TaskClass) {\n const taskInstance = new TaskClass(context, row);\n const reason = taskInstance.cantRunReason ? await taskInstance.cantRunReason() : null;\n if (reason) {\n if (!row.past_due) {\n await db(tasksTable).where({ id: row.id }).update({\n past_due: db.fn.now(),\n progress: String(reason),\n });\n }\n continue;\n }\n }\n\n const updated = await db(tasksTable)\n .where({ id: row.id })\n .whereNull(\"started_at\")\n .whereNull(\"paused_at\")\n .update({ started_at: db.fn.now() })\n .returning(\"*\");\n\n const claimed = Array.isArray(updated) ? updated[0] : null;\n if (claimed) return claimed as TaskRow;\n }\n\n return null;\n}\n\nexport async function runTasksLoop(context: Context, options: RunTasksLoopOptions): Promise<void> {\n const queue = options.queue ?? \"tasks\";\n const target = options.target;\n const pollMs = options.pollMs ?? 1000;\n const maxParallel = options.maxParallel ?? 1;\n const scanLimit = options.scanLimit ?? 100;\n const allowedTasks = normalizeAllowedTasks(options.allowedTasks);\n const registry = normalizeRegistry(options.registry as TasksRegistry | TasksRegistryMap | undefined);\n const { tasksTable, historyTable } = queueToTableNames(queue);\n\n if (!target) throw new Error(\"runTasksLoop: target is required\");\n\n const runningPromises = new Set<Promise<void>>();\n const runningTaskInstances = new Map<string, TaskInstance>();\n let runningStopControlPromise: Promise<void> | null = null;\n let stopRequested = false;\n let stopAllowanceMs = 5000;\n (context as any).__tasksRunnerStop = false;\n\n while (!context.isStop() && !stopRequested && !(context as any).__tasksRunnerStop) {\n // Control lane: always allow stop task to be picked even when workers are busy.\n if (!runningStopControlPromise) {\n const claimedStopTask = await claimNextRunnableTask(\n context,\n tasksTable,\n target,\n registry,\n 10,\n [\"stopRunner\", \"stop\"]\n );\n if (claimedStopTask) {\n runningStopControlPromise = executeClaimedTask(\n context,\n tasksTable,\n historyTable,\n claimedStopTask,\n registry,\n runningTaskInstances\n )\n .then(async (outcome) => {\n if (outcome.stopRunnerRequested && !stopRequested) {\n stopRequested = true;\n stopAllowanceMs = outcome.stopAllowanceMs || 5000;\n (context as any).__tasksRunnerStop = true;\n await signalRunningTasksStop(context, runningTaskInstances, stopAllowanceMs);\n }\n })\n .finally(() => {\n runningStopControlPromise = null;\n });\n }\n }\n\n while (runningPromises.size < maxParallel) {\n const claimed = await claimNextRunnableTask(\n context,\n tasksTable,\n target,\n registry,\n scanLimit,\n allowedTasks\n );\n if (!claimed) break;\n\n const p = executeClaimedTask(context, tasksTable, historyTable, claimed, registry, runningTaskInstances)\n .then(async (outcome) => {\n if (outcome.stopRunnerRequested && !stopRequested) {\n stopRequested = true;\n stopAllowanceMs = outcome.stopAllowanceMs || 5000;\n (context as any).__tasksRunnerStop = true;\n await signalRunningTasksStop(context, runningTaskInstances, stopAllowanceMs);\n }\n })\n .finally(() => {\n runningPromises.delete(p);\n });\n runningPromises.add(p);\n }\n\n await sleepMs(pollMs);\n }\n\n if (context.isStop() && !stopRequested) {\n await signalRunningTasksStop(context, runningTaskInstances, 5000);\n }\n\n if (runningPromises.size > 0) {\n if (stopRequested) {\n await Promise.race([\n Promise.allSettled(Array.from(runningPromises)),\n sleepMs(stopAllowanceMs).then(() => {\n context.logger.warn?.(\n `[tasks] stop allowance (${stopAllowanceMs}ms) reached; ${runningPromises.size} task(s) still running`\n );\n }),\n ]);\n } else {\n await Promise.allSettled(Array.from(runningPromises));\n }\n }\n}\n\nexport async function waitForTaskResult(\n context: Context,\n taskId: string,\n options: WaitForTaskResultOptions = {}\n): Promise<TaskRow | null> {\n const db = getDb(context);\n const queue = options.queue ?? \"tasks\";\n const timeoutMs = options.timeoutMs ?? 60000;\n const pollMs = options.pollMs ?? 500;\n const { tasksTable, historyTable } = queueToTableNames(queue);\n const deadline = Date.now() + timeoutMs;\n\n while (Date.now() <= deadline) {\n const done = await db(historyTable).where({ id: taskId }).orderBy(\"created_at\", \"desc\").first();\n if (done) return done as TaskRow;\n\n const pending = await db(tasksTable).where({ id: taskId }).first();\n if (!pending) {\n const maybeDone = await db(historyTable).where({ id: taskId }).orderBy(\"created_at\", \"desc\").first();\n return (maybeDone as TaskRow) ?? null;\n }\n await sleepMs(pollMs);\n }\n return null;\n}\n\nexport class TasksManager {\n private context: Context;\n private queue: string;\n private target: string;\n private recreateTaskTables: boolean;\n private pollMs: number;\n private maxParallel: number;\n private scanLimit: number;\n private allowedTasks: string[] | undefined;\n private registry: TasksRegistry;\n\n constructor(context: Context, options: TasksManagerInitOptions = {}) {\n this.context = context;\n this.queue = options.queue ?? \"tasks\";\n this.target = options.target ?? \"localRunner\";\n this.recreateTaskTables = options.recreateTaskTables ?? false;\n this.pollMs = options.pollMs ?? 1000;\n this.maxParallel = options.maxParallel ?? 1;\n this.scanLimit = options.scanLimit ?? 100;\n this.allowedTasks = normalizeAllowedTasks(options.allowedTasks);\n this.registry = normalizeRegistry(options.registry as TasksRegistry | TasksRegistryMap | undefined);\n }\n\n static init(context: Context, options: TasksManagerInitOptions = {}): TasksManager {\n const defs = {\n table: \"string default tasks\",\n target: \"string default localRunner\",\n recreateTaskTables: \"boolean default false\",\n pollMs: \"number default 1000\",\n maxParallel: \"number default 1\",\n scanLimit: \"number default 100\",\n allowedTasks: \"string\",\n };\n\n const discovered = (context as any).params.getAllForModule(defs);\n const resolved: TasksManagerInitOptions = {\n queue: discovered.table,\n target: discovered.target,\n recreateTaskTables: discovered.recreateTaskTables,\n pollMs: discovered.pollMs,\n maxParallel: discovered.maxParallel,\n scanLimit: discovered.scanLimit,\n allowedTasks: discovered.allowedTasks,\n ...options,\n };\n return new TasksManager(context, resolved);\n }\n\n async ensureTaskTables(options: { recreate?: boolean } = {}): Promise<void> {\n await ensureTaskTables(this.context, {\n queue: this.queue,\n recreate: options.recreate ?? this.recreateTaskTables,\n });\n }\n\n async runTasksLoop(options: Partial<RunTasksLoopOptions> = {}): Promise<void> {\n await runTasksLoop(this.context, {\n queue: options.queue ?? this.queue,\n target: options.target ?? this.target,\n pollMs: options.pollMs ?? this.pollMs,\n maxParallel: options.maxParallel ?? this.maxParallel,\n scanLimit: options.scanLimit ?? this.scanLimit,\n allowedTasks: options.allowedTasks ?? this.allowedTasks,\n registry: options.registry ?? this.registry,\n });\n }\n}\n"],"mappings":"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","names":["fs","path","fs","path","path","maxDate","fs","destPath","fs","fs","spawn","spawn","getDb","out"]}
package/dist/utils.cjs CHANGED
@@ -45,7 +45,9 @@ __export(utils_exports, {
45
45
  maskValue: () => maskValue,
46
46
  md5: () => md5,
47
47
  nowISO: () => nowISO,
48
- toISOString: () => toISOString
48
+ sleepMs: () => sleepMs,
49
+ toISOString: () => toISOString,
50
+ toJsonColumn: () => toJsonColumn
49
51
  });
50
52
  module.exports = __toCommonJS(utils_exports);
51
53
 
@@ -229,6 +231,15 @@ function md5(value) {
229
231
  function maskValue(value) {
230
232
  return `[md5:${md5(value)}]`;
231
233
  }
234
+
235
+ // src/utils/core-utils.ts
236
+ function sleepMs(ms) {
237
+ return new Promise((resolve) => setTimeout(resolve, ms));
238
+ }
239
+ function toJsonColumn(value) {
240
+ if (value === void 0 || value === null) return null;
241
+ return JSON.stringify(value);
242
+ }
232
243
  // Annotate the CommonJS export names for ESM import in node:
233
244
  0 && (module.exports = {
234
245
  bytesToHumanReadable,
@@ -246,6 +257,8 @@ function maskValue(value) {
246
257
  maskValue,
247
258
  md5,
248
259
  nowISO,
249
- toISOString
260
+ sleepMs,
261
+ toISOString,
262
+ toJsonColumn
250
263
  });
251
264
  //# sourceMappingURL=utils.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/utils.ts","../src/utils/date-utils.ts","../src/utils/fs-utils.ts","../src/utils/os-utils.ts","../src/utils/format-utils.ts","../src/utils/crypto-utils.ts"],"sourcesContent":["// Re-export everything from the utils module directory\nexport * from \"./utils/index.js\";\n\n","/**\n * Date/time utility functions for timestamp formatting and timezone conversions\n */\n\nexport interface DateFormatOptions {\n timezone?: \"UTC\" | \"user\";\n format?: \"iso\" | \"iso-date\" | \"iso-time\" | \"human\";\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: Date | string | number | undefined, options: DateFormatOptions = {}): string {\n if (value === undefined || value === null) {\n return \"\";\n }\n\n const { timezone = \"UTC\", format = \"iso\" } = options;\n \n let date: 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: Date | string | number | undefined): string {\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(): string {\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: string): Date {\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: Date | string,\n end: Date | string\n): {\n milliseconds: number;\n seconds: number;\n minutes: number;\n hours: number;\n days: number;\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: string): boolean {\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: string[] = []): string {\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 * 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: string[]): Promise<string> {\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: string[]): string {\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: string): string {\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: string | URL): string {\n return path.dirname(fileURLToPath(metaUrl));\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: string): number | null {\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 * 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: number): string {\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: string): number {\n const units: Record<string, number> = {\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 * Cryptography Utilities\n * \n * Helper functions for hashing, encryption, and data masking\n */\n\nimport crypto from \"crypto\";\n\n/**\n * Calculate MD5 hash of a string (useful for content fingerprinting)\n */\nexport function md5(value: string): string {\n return crypto.createHash(\"md5\").update(value).digest(\"hex\");\n}\n\n/**\n * Sanitize sensitive data by replacing with MD5 hash\n * Useful for logging sensitive information while maintaining traceability\n */\nexport function maskValue(value: string): string {\n return `[md5:${md5(value)}]`;\n}\n\n"],"mappings":"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","names":["maxDate","path","fs","import_fs","import_path","fs","path","crypto"]}
1
+ {"version":3,"sources":["../src/utils.ts","../src/utils/date-utils.ts","../src/utils/fs-utils.ts","../src/utils/os-utils.ts","../src/utils/format-utils.ts","../src/utils/crypto-utils.ts","../src/utils/core-utils.ts"],"sourcesContent":["// Re-export everything from the utils module directory\nexport * from \"./utils/index.js\";\n\n","/**\n * Date/time utility functions for timestamp formatting and timezone conversions\n */\n\nexport interface DateFormatOptions {\n timezone?: \"UTC\" | \"user\";\n format?: \"iso\" | \"iso-date\" | \"iso-time\" | \"human\";\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: Date | string | number | undefined, options: DateFormatOptions = {}): string {\n if (value === undefined || value === null) {\n return \"\";\n }\n\n const { timezone = \"UTC\", format = \"iso\" } = options;\n \n let date: 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: Date | string | number | undefined): string {\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(): string {\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: string): Date {\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: Date | string,\n end: Date | string\n): {\n milliseconds: number;\n seconds: number;\n minutes: number;\n hours: number;\n days: number;\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: string): boolean {\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: string[] = []): string {\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 * 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: string[]): Promise<string> {\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: string[]): string {\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: string): string {\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: string | URL): string {\n return path.dirname(fileURLToPath(metaUrl));\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: string): number | null {\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 * 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: number): string {\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: string): number {\n const units: Record<string, number> = {\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 * Cryptography Utilities\n * \n * Helper functions for hashing, encryption, and data masking\n */\n\nimport crypto from \"crypto\";\n\n/**\n * Calculate MD5 hash of a string (useful for content fingerprinting)\n */\nexport function md5(value: string): string {\n return crypto.createHash(\"md5\").update(value).digest(\"hex\");\n}\n\n/**\n * Sanitize sensitive data by replacing with MD5 hash\n * Useful for logging sensitive information while maintaining traceability\n */\nexport function maskValue(value: string): string {\n return `[md5:${md5(value)}]`;\n}\n\n","/**\n * Core lightweight utilities\n */\n\nexport function sleepMs(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nexport function toJsonColumn(value: any): string | null {\n if (value === undefined || value === null) return null;\n return JSON.stringify(value);\n}\n"],"mappings":"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","names":["maxDate","path","fs","import_fs","import_path","fs","path","crypto"]}
package/dist/utils.js CHANGED
@@ -178,6 +178,15 @@ function md5(value) {
178
178
  function maskValue(value) {
179
179
  return `[md5:${md5(value)}]`;
180
180
  }
181
+
182
+ // src/utils/core-utils.ts
183
+ function sleepMs(ms) {
184
+ return new Promise((resolve) => setTimeout(resolve, ms));
185
+ }
186
+ function toJsonColumn(value) {
187
+ if (value === void 0 || value === null) return null;
188
+ return JSON.stringify(value);
189
+ }
181
190
  export {
182
191
  bytesToHumanReadable,
183
192
  dateDiff,
@@ -194,6 +203,8 @@ export {
194
203
  maskValue,
195
204
  md5,
196
205
  nowISO,
197
- toISOString
206
+ sleepMs,
207
+ toISOString,
208
+ toJsonColumn
198
209
  };
199
210
  //# sourceMappingURL=utils.js.map