{"version":3,"sources":["../src/core/Auditor.ts","../src/database/mongodb/config.ts","../src/core/AppConfigs.ts","../src/utils/helper.ts","../src/utils/user.ts","../src/middleware/requestLogger.ts","../src/middleware/errorLogger.ts","../src/router/router.ts"],"sourcesContent":["import chalk from \"chalk\";\r\nimport { Schema } from \"mongoose\";\r\nimport { auditModel, checkForMongodb } from \"../database/mongodb\";\r\nimport { errorLogger, requestLogger } from \"../middleware\";\r\nimport { UIRouter, checkForFramework, downloadDependency } from \"../router\";\r\nimport { Framework, SupportedLoggersRequest, TAuditOptions, TEvent, TFileConfig } from \"../types/type\";\r\nimport { createFile, generateAuditContent, getFileLocation, handleLog, logAuditEvent } from \"../utils\";\r\nimport { userProfile } from \"../utils/user\";\r\nimport { AppConfig } from \"./AppConfigs\";\r\n\r\n\r\nexport class Audit<F extends Framework = \"express\"> {\r\n    private logFilePath: string = \"\";\r\n    private defaultFileConfigs: TFileConfig[] = [\r\n        {\r\n            fileName: \"error.log\",\r\n            folderName: \"audits\",\r\n            fullPath: \"\",\r\n        },\r\n        {\r\n            fileName: \"request.log\",\r\n            folderName: \"audits\",\r\n            fullPath: \"\",\r\n        },\r\n        {\r\n            fileName: \"db.log\",\r\n            folderName: \"audits\",\r\n            fullPath: \"\",\r\n        },\r\n        {\r\n            fileName: \"action.log\",\r\n            folderName: \"audits\",\r\n            fullPath: \"\",\r\n        },\r\n    ];\r\n    private fileConfig: TFileConfig = {\r\n        fileName: \"audit.log\",\r\n        folderName: \"audit\",\r\n        fullPath: \"\",\r\n    };\r\n    private isInitialized: boolean = false;\r\n\r\n    private auditOptions: TAuditOptions<F> = {\r\n        dbType: \"none\",\r\n        destinations: [\"console\"],\r\n        framework: \"express\" as F,\r\n        logger: console,\r\n        useTimeStamp: true,\r\n        splitFiles: false,\r\n        captureSystemErrors: false,\r\n        useUI: false,\r\n    };\r\n\r\n\r\n\r\n    /**\r\n     * Creates an instance of the Auditor class with the provided options.\r\n     *\r\n     * @param options - Optional configuration object for the auditor.\r\n     *   - `logger`: Custom logger to use; defaults to `console` if not provided.\r\n     *   - `dbType`: Type of database to use; defaults to `\"none\"`.\r\n     *   - `destinations`: Array of destinations for audit logs; defaults to `[\"console\"]`.\r\n     *   - `framework`: The framework being used (e.g., \"express\"); defaults to `\"express\"`.\r\n     *   - `useTimeStamp`: Whether to include timestamps in logs; defaults to `true`.\r\n     *   - `splitFiles`: Whether to split logs into multiple files; defaults to `false`.\r\n     *   - `captureSystemErrors`: Whether to capture system errors; defaults to `false`.\r\n     *\r\n     * Initializes the `auditOptions` property by merging the provided options with sensible defaults.\r\n     */\r\n    constructor(private options?: TAuditOptions<F>) {\r\n        this.auditOptions = {\r\n            ...options,\r\n            logger: options?.logger || console,\r\n            dbType: options?.dbType || \"none\",\r\n            destinations: options?.destinations || [\"console\"],\r\n            framework: options?.framework as F ?? \"express\" as F,\r\n            useTimeStamp: options?.useTimeStamp ?? true,\r\n            splitFiles: options?.splitFiles ?? false,\r\n            captureSystemErrors: options?.captureSystemErrors ?? false,\r\n            useUI: options?.useUI ?? false,\r\n        };\r\n    }\r\n\r\n\r\n    /**\r\n     * Initializes the auditor by creating the necessary file location and logging a success message.\r\n     *\r\n     * This method sets up the audit configuration by invoking `CreateFileLocation` with the current file configuration,\r\n     * and logs a confirmation message using the configured logger.\r\n     *\r\n     * @remarks\r\n     * Should be called before performing any audit operations to ensure the environment is properly configured.\r\n     */\r\n    async Setup() {\r\n        if (this.isInitialized) {\r\n            this.auditOptions.logger?.warn(chalk.yellow(\"Audit already initialized.\"));\r\n            return;\r\n        }\r\n\r\n        this.CreateFileLocation(this.fileConfig);\r\n\r\n        AppConfig.setAuditOption(this.auditOptions);\r\n        AppConfig.setDefaultFileConfig(this.defaultFileConfigs);\r\n        AppConfig.setFileConfig(this.fileConfig);\r\n        AppConfig.setLogFilePath(this.logFilePath);\r\n        AppConfig.setCaptureSystemErrors(this.auditOptions.captureSystemErrors ?? false);\r\n        AppConfig.setFrameWork(this.auditOptions.framework!);\r\n        AppConfig.setUseUI(this.auditOptions.useUI ?? false);\r\n\r\n        if (this.auditOptions.dbType === \"mongoose\") {\r\n            const result = checkForMongodb();\r\n            if (!result) return;\r\n        }\r\n\r\n        if (this.auditOptions.useUI) {\r\n            const hasFramework = checkForFramework();\r\n            if (hasFramework) {\r\n                AppConfig.getAuditOption()?.logger?.info(chalk.yellow(\"In order to use this module some dependency will be downloaded\"));\r\n                await downloadDependency();\r\n            }\r\n        }\r\n\r\n\r\n\r\n        this.isInitialized = true;\r\n        AppConfig.setIsInitialized(this.isInitialized);\r\n\r\n        this.HandleSystemErrors();\r\n\r\n        this.auditOptions.logger?.info(chalk.green(\"Default Audit config set successfully\"));\r\n    }\r\n\r\n    /**\r\n     * Logs an event to the configured destinations (console and/or file).\r\n     *\r\n     * Depending on the configuration, this method will:\r\n     * - Add a timestamp to the event if `useTimeStamp` is enabled.\r\n     * - Log the event to the console if \"console\" is included in `destinations`.\r\n     * - Log the event to a file if \"file\" is included in `destinations`.\r\n     *   - If `splitFiles` is enabled, logs to a specific action log file.\r\n     *   - Otherwise, logs to the default file configuration.\r\n     * - If the file path is not set when logging to a file, logs an error.\r\n     *\r\n     * @param event - The event object to be logged.\r\n     */\r\n    Log(event: TEvent) {\r\n\r\n        const item = generateAuditContent({ ...event });\r\n\r\n        if (!this.isInitialized) {\r\n            this.auditOptions?.logger?.info(chalk.red(\"Not Initialized. Setup Is Required\"));\r\n            return;\r\n        }\r\n\r\n        if (this.auditOptions.destinations?.includes(\"console\")) {\r\n            logAuditEvent(item);\r\n        }\r\n\r\n        if (this.auditOptions.destinations?.includes(\"file\")) {\r\n\r\n            const actionFile = this.defaultFileConfigs.find(x => x.fileName === \"action.log\") as TFileConfig;\r\n            const file = this.auditOptions.splitFiles ? actionFile : this.fileConfig;\r\n\r\n            if (!file.fullPath) {\r\n                this.auditOptions.logger?.error(chalk.red(\"Unable to locate file path\"));\r\n                return;\r\n            }\r\n\r\n            logAuditEvent(item, file);\r\n        }\r\n\r\n    }\r\n\r\n    /**\r\n        * Logs an error event to the configured destinations (console and/or file).\r\n        * @example\r\n        * LogError(new Error(\"Unexpected failure\"))\r\n        * Logs error details to the console and file depending on configuration.\r\n        * @param {any} error - The error object to be logged.\r\n        * @description\r\n        *   - Extracts the error stack trace to capture informative details.\r\n        *   - Compiles additional user context such as IP and user agent when available.\r\n        *   - Handles uninitialized state by printing a warning message.\r\n        *   - Utilizes timestamp inclusion and log destination logic based on audit options.\r\n        */\r\n    LogError(error: any) {\r\n\r\n        if (!this.isInitialized) {\r\n            this.auditOptions?.logger?.info(chalk.red(\"Not Initialized. Setup Is Required\"));\r\n            return;\r\n        }\r\n\r\n        let stackLine = \"\";\r\n        if (error.stack) {\r\n            const lines = error.stack.split('\\n');\r\n            stackLine = lines.length > 1 ? lines[1].trim() : lines[0]?.trim() ?? \"\";\r\n        }\r\n\r\n        const item = generateAuditContent({\r\n            type: \"error\",\r\n            action: \"unknown\",\r\n            outcome: \"error\",\r\n            method: \"user called\",\r\n            statusCode: error.statusCode ?? 500,\r\n            userId: userProfile.getUserId() ?? \"unknown\",\r\n            ip: userProfile.getIp() ?? \"unknown\",\r\n            userAgent: userProfile.getUserAgent() ?? \"unknown\",\r\n            message: error.message ?? \"an error occurred\",\r\n            stack: stackLine ?? \"no stack available\",\r\n        });\r\n\r\n        if (this.auditOptions.destinations?.includes(\"console\")) {\r\n            logAuditEvent(item);\r\n        }\r\n\r\n        if (this.auditOptions.destinations?.includes(\"file\")) {\r\n\r\n            const actionFile = this.defaultFileConfigs.find(x => x.fileName === \"error.log\") as TFileConfig;\r\n            const file = this.auditOptions.splitFiles ? actionFile : this.fileConfig;\r\n\r\n            if (!file.fullPath) {\r\n                this.auditOptions.logger?.error(chalk.red(\"Unable to locate file path\"));\r\n                return;\r\n            }\r\n\r\n            logAuditEvent(item, file);\r\n        }\r\n\r\n    }\r\n\r\n    /**\r\n     * Audits a given schema model by invoking the `auditModel` function with the current configuration,\r\n     * a generated timestamp, and the provided schema.\r\n     *\r\n     * @template T - The type of the schema being audited.\r\n     * @param schema - The schema object to be audited.\r\n     */\r\n    AuditModel<T>(schema: Schema<T>) {\r\n        auditModel(schema);\r\n    }\r\n\r\n    /**\r\n     * Configures the file logging settings for the auditor.\r\n     *\r\n     * This method sets up the file configuration used for logging audit events to a file.\r\n     * It checks if \"file\" is included in the destinations and if split file logging is disabled.\r\n     * If these conditions are not met, it logs appropriate warnings and returns early.\r\n     * Otherwise, it sets up the file configuration with the provided options or defaults.\r\n     *\r\n     * @param config - Optional configuration object for the file logger, excluding the `fullPath` property.\r\n     *   - `folderName` (optional): The folder where the log file will be stored. Defaults to `\"audit\"`.\r\n     *   - `fileName` (optional): The name of the log file. Defaults to `\"audit.log\"`.\r\n     */\r\n    SetFileConfig(config: Omit<TFileConfig, \"fullPath\">) {\r\n\r\n        if (!this.auditOptions.destinations?.includes(\"file\")) {\r\n            this.auditOptions.logger?.warn(chalk.yellowBright(\"You need to add file to destinations for this to work properly\"));\r\n            return;\r\n        }\r\n\r\n        if (this.auditOptions.splitFiles) {\r\n            this.auditOptions.logger?.info(chalk.yellow(\"Cannot configure file as it is not supported when using splitfile\"));\r\n            return;\r\n        }\r\n\r\n        const folder = config?.folderName ?? \"audit\";\r\n        const baseFileName = config?.fileName ?? \"audit\";\r\n        const fileName = baseFileName.endsWith(\".log\") ? baseFileName : `${baseFileName}.log`;\r\n\r\n        this.fileConfig = {\r\n            ...config,\r\n            folderName: folder,\r\n            fileName,\r\n            fullPath: \"\",\r\n        };\r\n    }\r\n\r\n    /**\r\n     * Logs all incoming requests using the configured logger.\r\n     *\r\n     * Depending on the `splitFiles` configuration, this method will either:\r\n     * - Log requests to a dedicated \"request.log\" file if `splitFiles` is enabled.\r\n     * - Log requests to the default log file otherwise.\r\n     *\r\n     * @returns The result of the `requestLogger` function, which handles the actual logging process.\r\n     */\r\n    RequestLogger(): SupportedLoggersRequest[F] {\r\n        return requestLogger[this.auditOptions.framework!];\r\n    }\r\n\r\n    /**\r\n     * Logs all errors using the configured error logger.\r\n     *\r\n     * If the `splitFiles` option is enabled in the configuration, errors are logged to a separate\r\n     * \"error.log\" file as specified in the default file configurations. Otherwise, errors are logged\r\n     * to the main file configuration.\r\n     *\r\n     * @returns The result of the error logger function, which handles error logging based on the current configuration.\r\n     */\r\n    ErrorLogger() {\r\n        return errorLogger[this.auditOptions.framework!];\r\n    }\r\n\r\n    /**\r\n     * Asynchronously creates and returns the UI component or handler based on the specified framework\r\n     * in the audit options.\r\n     *\r\n     * @returns {Promise<any>} A promise that resolves to the UI component or handler corresponding to the selected framework.\r\n     */\r\n    CreateUI() {\r\n\r\n        if (!AppConfig.getUseUI()) {\r\n            AppConfig.getAuditOption()?.logger?.info(chalk.yellow(\"Add the useUI option in the constructor to download the dependency\"));\r\n            return UIRouter[this.auditOptions.framework!];\r\n        }\r\n\r\n        return UIRouter[this.auditOptions.framework!];\r\n\r\n    }\r\n\r\n\r\n    private CreateFileLocation = (config: TFileConfig) => {\r\n        if (!this.auditOptions.destinations?.includes(\"file\")) return;\r\n\r\n        if (this.auditOptions.splitFiles) {\r\n            this.defaultFileConfigs.forEach(item => {\r\n                this.GenerateFile(item);\r\n            });\r\n            return;\r\n        }\r\n        this.GenerateFile(config);\r\n    };\r\n\r\n\r\n    private GenerateFile = (config: TFileConfig) => {\r\n        const dir = createFile(config);\r\n        config.fullPath = dir;\r\n        this.logFilePath = dir;\r\n        this.defaultFileConfigs = this.defaultFileConfigs.map(item => {\r\n            if (item.fileName === config.fileName) {\r\n                return { ...item, fullPath: dir };\r\n            }\r\n            return item;\r\n        });\r\n    };\r\n\r\n    /**\r\n        * Sets up system error handling and logging for audit purposes.\r\n        * @example\r\n        * handleSystemErrors()\r\n        * Initializes processes to log exceptions, rejections, signals, and exits.\r\n        * @description\r\n        *   - Listens for Node.js process events such as uncaught exceptions, unhandled rejections, SIGTERM, SIGINT, and exit.\r\n        *   - Utilizes the `generateAuditContent` utility to format the logs.\r\n        *   - Logs generated content using `handleLog` with the error file configuration.\r\n        *   - Only activates if `captureSystemErrors` is true within audit options.\r\n        */\r\n    private HandleSystemErrors = () => {\r\n        if (!this.auditOptions.captureSystemErrors) return;\r\n        const file = getFileLocation(\"error.log\");\r\n        process.on(\"uncaughtException\", (error, origin) => {\r\n            const fullStack = error instanceof Error ? error.stack : undefined;\r\n            const content = generateAuditContent({\r\n                type: \"error\",\r\n                action: \"unknown\",\r\n                message: error.message ?? \"an uncaughtException\",\r\n                outcome: \"uncaughtException\",\r\n                error,\r\n                origin,\r\n                fullStack,\r\n            });\r\n            handleLog(file, content);\r\n        });\r\n        process.on(\"unhandledRejection\", (reason) => {\r\n            const content = generateAuditContent({\r\n                type: \"error\",\r\n                action: \"unknown\",\r\n                message: \"an unhandledRejection\",\r\n                outcome: \"unhandledRejection\",\r\n                reason,\r\n            });\r\n            handleLog(file, content);\r\n        });\r\n\r\n        process.on(\"SIGTERM\", () => {\r\n            const content = generateAuditContent({\r\n                type: \"signal\",\r\n                action: \"terminated\",\r\n                message: \"was terminated\",\r\n                outcome: \"SIGTERM\",\r\n                signal: \"SIGTERM\",\r\n            });\r\n            handleLog(file, content);\r\n            process.exit(0);\r\n        });\r\n\r\n        process.on(\"SIGINT\", () => {\r\n            const content = generateAuditContent({\r\n                type: \"signal\",\r\n                action: \"terminated\",\r\n                message: \"app was terminated\",\r\n                outcome: \"SIGINT\",\r\n                signal: \"SIGINT\",\r\n            });\r\n            handleLog(file, content);\r\n            process.exit(0);\r\n        });\r\n\r\n\r\n        process.on(\"exit\", (code) => {\r\n            const content = generateAuditContent({\r\n                type: \"system\",\r\n                action: \"exit\",\r\n                message: \"app was exited\",\r\n                outcome: \"exit\",\r\n                code,\r\n            });\r\n            handleLog(file, content);\r\n        });\r\n\r\n    };\r\n}\r\n","import chalk from \"chalk\";\r\nimport { Schema } from \"mongoose\";\r\nimport { AppConfig } from \"../../core/AppConfigs\";\r\nimport { checkForModule, generateAuditContent, getFileLocation, getTimeStamp, logAuditEvent } from \"../../utils\";\r\nimport { userProfile } from \"../../utils/user\";\r\n\r\n\r\n\r\nlet hasMongoose = false;\r\n\r\n\r\n/**\r\n * Checks if the \"mongoose\" module is available in the current environment.\r\n *\r\n * @returns {boolean} Returns `true` if the \"mongoose\" module is found, otherwise `false`.\r\n */\r\nexport const checkForMongodb = () => {\r\n    hasMongoose = checkForModule(\"mongoose\");\r\n    return hasMongoose;\r\n};\r\n\r\n/**\r\n * Enhances a Mongoose schema with auditing hooks for logging database operations.\r\n *\r\n * @template T - The type of the schema's document.\r\n * @param config - The audit configuration options, including a logger.\r\n * @param timeStamp - A string representing the timestamp to include in audit logs.\r\n * @param schema - The Mongoose schema to augment with audit hooks.\r\n *\r\n * @remarks\r\n * - Requires Mongoose to be installed; logs an error if not present.\r\n * - Adds pre-save and post-save hooks to log \"create\" or \"update\" actions.\r\n * - Adds a post-find hook to log \"find\" actions.\r\n * - Logs include model name, collection name, document ID, and timestamp.\r\n */\r\nexport const auditModel = <T>(schema: Schema<T>) => {\r\n    const config = AppConfig.getAuditOption()!;\r\n    if (config.dbType === \"none\") {\r\n        config.logger?.error(chalk.yellow(\"Cannot audit db while DB type is set to none\"));\r\n        return;\r\n    }\r\n    if (!hasMongoose) {\r\n        config.logger?.error(chalk.red(\"Please install mongoose to use audit\"));\r\n        return;\r\n    }\r\n\r\n    handleSaveSchema(schema);\r\n    handleFindSchema(schema);\r\n    handleUpdateSchema(schema);\r\n    handleDeletingSchema(schema);\r\n};\r\n\r\nconst handleSaveSchema = (schema: Schema) => {\r\n    const log = generateLog();\r\n\r\n    schema.pre('save', function (next) {\r\n        (this as any)._wasNew = this.isNew;\r\n        next();\r\n    });\r\n\r\n    schema.post(\"save\", (doc: any) => {\r\n        const { modelName } = doc.constructor;\r\n        const message = `doc was ${doc._wasNew ? \"created\" : \"updated\"}`;\r\n        log(\"save\", modelName, {}, message);\r\n    });\r\n};\r\n\r\nconst handleFindSchema = (schema: Schema) => {\r\n    const log = generateLog();\r\n\r\n    schema.post(\"find\", function (docs) {\r\n        const modelName = this.model.collection.name;\r\n        const message = `looking for ${modelName}`;\r\n        log(\"read\", modelName, this.getFilter(), message, docs.length);\r\n    });\r\n\r\n    schema.post(\"findOne\", function (doc: any) {\r\n        const modelName = this.model.collection.name;\r\n        const message = `looking for a single ${modelName}`;\r\n        log(\"read\", modelName, this.getFilter(), message);\r\n    });\r\n};\r\n\r\nconst handleUpdateSchema = (schema: Schema) => {\r\n    const log = generateLog();\r\n    schema.post(\"updateOne\", function (doc: any) {\r\n        const modelName = this.model.collection.name;\r\n        const message = `updating a single ${modelName} doc`;\r\n        log(\"update\", modelName, this.getFilter(), message);\r\n    });\r\n\r\n    schema.post(\"findOneAndUpdate\", function (doc: any) {\r\n        const modelName = this.model.collection.name;\r\n        const message = `finding & updating a single ${modelName} doc`;\r\n        log(\"update\", modelName, this.getFilter(), message);\r\n\r\n    });\r\n\r\n    schema.post(\"updateMany\", function (docs) {\r\n        const modelName = this.model.collection.name;\r\n        const message = `updating multiple ${modelName} docs`;\r\n        log(\"update\", modelName, this.getFilter(), message, docs.modifiedCount);\r\n    });\r\n};\r\n\r\n/**\r\n* Sets up Mongoose schema middleware to log deletion operations.\r\n* @example\r\n* handleDeletingSchema(userSchema)\r\n* // No return value; sets up post-hooks on provided schema\r\n* @param {Schema} schema - Represents the Mongoose schema on which to add audit logging for delete operations.\r\n* @returns {void} No return value; sets up middleware on the provided schema.\r\n* @description\r\n*   - Utilizes Mongoose post-hooks to capture delete operations like `findOneAndDelete`, `deleteOne`, and `deleteMany`.\r\n*   - Logs details of delete operations such as model name, filter criteria, action type, and affected document count if applicable.\r\n*   - Requires the `generateLog` function to generate log entries which depend on user profile and configuration settings.\r\n*   - Ensures that information related to each delete operation is audited and possibly persisted based on audit configuration options.\r\n*/\r\nconst handleDeletingSchema = (schema: Schema) => {\r\n    const log = generateLog();\r\n    schema.post(\"findOneAndDelete\", function () {\r\n        const modelName = this.model.collection.name;\r\n        const message = `finding & deleting a single ${modelName} doc`;\r\n        log(\"delete\", modelName, this.getFilter(), message);\r\n    });\r\n\r\n    schema.post(\"deleteOne\", function () {\r\n        const modelName = this.model.collection.name;\r\n        const message = `deleting a single ${modelName} doc`;\r\n        log(\"delete\", modelName, this.getFilter(), message);\r\n    });\r\n\r\n    schema.post(\"deleteMany\", function (docs) {\r\n        const modelName = this.model.collection.name;\r\n        const message = `deleting multiple ${modelName} docs`;\r\n        log(\"delete\", modelName, this.getFilter(), message, docs.deletedCount);\r\n    });\r\n};\r\n\r\n\r\ntype TdbAction = \"save\" | \"read\" | \"update\" | \"delete\";\r\nconst generateLog = () => {\r\n    const config = AppConfig.getAuditOption()!;\r\n\r\n    return (action: TdbAction, modelName: string, filter: any, message: string, length?: number) => {\r\n        const content = generateAuditContent({\r\n            type: \"db\",\r\n            action,\r\n            collection: modelName,\r\n            criteria: filter,\r\n            ...(length !== undefined ? { resultCount: length } : {}),\r\n            message,\r\n            userId: userProfile.getUserId(),\r\n            endPoint: userProfile.getEndPoint(),\r\n            ip: userProfile.getIp(),\r\n            userAgent: userProfile.getUserAgent(),\r\n            ...(config.useTimeStamp ? { timeStamp: getTimeStamp() } : {}),\r\n        });\r\n\r\n        if (config.destinations?.includes(\"console\"))\r\n            logAuditEvent(content);\r\n\r\n        const dbFile = getFileLocation(\"db.log\");\r\n\r\n        if (!dbFile) return;\r\n\r\n        if (config.destinations?.includes(\"file\"))\r\n            logAuditEvent(content, dbFile);\r\n    };\r\n};","import { Framework, TAuditOptions, TFileConfig } from \"../types\";\r\n\r\n/**\r\n * Singleton configuration manager for the application.\r\n * \r\n * Provides getter and setter methods for managing global configuration options such as:\r\n * - Audit options (`TAuditOptions`)\r\n * - Log file path\r\n * - File configuration (`TFileConfig`)\r\n * - Default file configurations (`TFileConfig[]`)\r\n * - Initialization state\r\n * \r\n * @remarks\r\n * This object encapsulates configuration state and exposes methods to mutate and retrieve configuration values.\r\n * \r\n * @example\r\n * ```typescript\r\n * AppConfig.setLogFilePath('/var/log/app.log');\r\n * const logPath = AppConfig.getLogFilePath();\r\n * ```\r\n */\r\nexport const AppConfig = (<F extends Framework>() => {\r\n    let logFilePath: string = '';\r\n    let fileConfig: TFileConfig | undefined;\r\n    let auditOption: TAuditOptions<F> | undefined;\r\n    let isInitialized = false;\r\n    let captureSystemErrors = true;\r\n    let useUI = false;\r\n    let defaultFileConfigs: TFileConfig[] | undefined;\r\n    let framework: Framework = \"express\";\r\n\r\n    return {\r\n        setAuditOption(options: TAuditOptions<F>) {\r\n            auditOption = options;\r\n        },\r\n        getAuditOption() {\r\n            return auditOption;\r\n        },\r\n\r\n        setLogFilePath(value: string) {\r\n            logFilePath = value;\r\n        },\r\n        getLogFilePath() {\r\n            return logFilePath;\r\n        },\r\n\r\n        setFileConfig(config: TFileConfig) {\r\n            fileConfig = config;\r\n        },\r\n        getFileConfig() {\r\n            return fileConfig;\r\n        },\r\n\r\n        setDefaultFileConfig(config: TFileConfig[]) {\r\n            defaultFileConfigs = config;\r\n        },\r\n        getDefaultFileConfig() {\r\n            return defaultFileConfigs;\r\n        },\r\n\r\n        setIsInitialized(value: boolean) {\r\n            isInitialized = value;\r\n        },\r\n        getIsInitialized() {\r\n            return isInitialized;\r\n        },\r\n        setCaptureSystemErrors(value: boolean) {\r\n            captureSystemErrors = value;\r\n        },\r\n        getCaptureSystemErrors() {\r\n            return captureSystemErrors;\r\n        },\r\n        setFrameWork(value: Framework) {\r\n            framework = value;\r\n        },\r\n        getFrameWork() {\r\n            return framework;\r\n        },\r\n        setUseUI(value: boolean) {\r\n            useUI = value;\r\n        },\r\n        getUseUI() {\r\n            return useUI;\r\n        },\r\n    };\r\n})();","import chalk from 'chalk';\r\nimport { Request } from 'express';\r\nimport fs from \"fs\";\r\nimport path from \"path\";\r\nimport { AppConfig } from '../core/AppConfigs';\r\nimport { AuditContentParams, TFileConfig } from '../types';\r\nimport crypto from \"crypto\";\r\nimport { createRequire } from 'module';\r\n\r\nexport const getTimeStamp = () => new Date().toISOString();\r\nexport const getUserId = (req: Request) => {\r\n    try {\r\n        if (\"user\" in req) {\r\n            const user = req?.user as { id: string; } | { _id: string; };\r\n            if (!user) return \"unknown\";\r\n            if (\"id\" in user) {\r\n                return user;\r\n            } else return \"unknown\";\r\n        }\r\n        else \"unknown\";\r\n        return \"unknown\";\r\n    } catch (error) {\r\n        return \"unknown\";\r\n    }\r\n};\r\n\r\nexport const handleLog = (fileConfig: TFileConfig, content: any) => {\r\n    const config = AppConfig.getAuditOption()!;\r\n\r\n    if (config.destinations?.includes(\"console\"))\r\n        logAuditEvent(content);\r\n    if (config.destinations?.includes(\"file\"))\r\n        logAuditEvent(content, fileConfig);\r\n};\r\n\r\nexport const saveToFile = (file: TFileConfig, content: any) => {\r\n    const config = AppConfig.getAuditOption()!;\r\n\r\n    try {\r\n        fs.appendFileSync(file.fullPath, `${JSON.stringify(content)}\\n`, { encoding: \"utf-8\" });\r\n\r\n    } catch (error) {\r\n        config?.logger?.error(chalk.red(\"Failed to save log to file\"));\r\n    }\r\n};\r\n\r\nexport const createFile = (config: TFileConfig) => {\r\n    const fullPath = path.join(process.cwd(), config.folderName);\r\n    if (!fs.existsSync(fullPath)) {\r\n        fs.mkdirSync(fullPath, { recursive: true });\r\n    }\r\n\r\n    const dir = path.join(fullPath, config.fileName);\r\n\r\n    return dir;\r\n};\r\n\r\nexport const logAuditEvent = (content: any, file?: TFileConfig) => {\r\n    const config = AppConfig.getAuditOption()!;\r\n    if (file) {\r\n        saveToFile(file, content);\r\n        return;\r\n    }\r\n\r\n    const cleanContent = { ...content };\r\n    delete cleanContent.fullStack;\r\n\r\n    config?.logger?.info(cleanContent);\r\n};\r\n\r\nexport const getFileLocation = (location: string) => {\r\n    const config = AppConfig.getAuditOption()!;\r\n    const defaultFileConfigs = AppConfig.getDefaultFileConfig()!;\r\n\r\n    if (config.splitFiles) {\r\n        const dbFile = defaultFileConfigs.find(x => x.fileName === location) as TFileConfig;\r\n        return dbFile;\r\n    }\r\n\r\n    return AppConfig.getFileConfig()!;\r\n};\r\n\r\nexport const generateAuditContent = ({\r\n    type,\r\n    action,\r\n    message,\r\n    ...rest\r\n}: AuditContentParams) => {\r\n    return {\r\n        id: generateId(),\r\n        type,\r\n        action,\r\n        message,\r\n        ...rest,\r\n        ...(AppConfig.getAuditOption()?.useTimeStamp ? { timeStamp: getTimeStamp() } : {}),\r\n    };\r\n};\r\n\r\nexport const generateId = () => {\r\n    const time = Date.now().toString(36);\r\n    const rand = crypto.randomBytes(3).toString('hex');\r\n    return `${time}-${rand}`;\r\n};\r\n\r\nexport const checkForModule = (item: string) => {\r\n    const requireFromUserProject = createRequire(path.join(process.cwd(), 'index.js'));\r\n\r\n    try {\r\n        AppConfig.getAuditOption()?.logger?.info(\r\n            chalk.blueBright(`Checking for ${item}`),\r\n        );\r\n        requireFromUserProject.resolve(item);\r\n        AppConfig.getAuditOption()?.logger?.info(\r\n            chalk.greenBright(`${item} found.`),\r\n        );\r\n        return true;\r\n    } catch (error) {\r\n        AppConfig.getAuditOption()?.logger?.info(\r\n            chalk.redBright(`Failed to find \"${item}\"`),\r\n        );\r\n        return false;\r\n    }\r\n};\r\n\r\n\r\n","/**\r\n * Represents a user profile containing identifying and network information.\r\n *\r\n * @remarks\r\n * The `UserProfile` class encapsulates a user's ID, endpoint URL, and IP address.\r\n * It provides methods to build and retrieve these properties.\r\n *\r\n * @example\r\n * ```typescript\r\n * const profile = new UserProfile();\r\n * profile.BuildProfile('123', 'https://api.example.com', '192.168.1.1');\r\n * console.log(profile.getUserId()); // '123'\r\n * ```\r\n */\r\nclass UserProfile {\r\n    private userId: string;\r\n    private endPoint: string;\r\n    private ip: string;\r\n    private userAgent: string;\r\n\r\n    constructor() {\r\n        this.userId = \"\";\r\n        this.endPoint = \"\";\r\n        this.ip = \"\";\r\n        this.userAgent = \"\";\r\n    }\r\n\r\n    BuildProfile(id: string, url: string, ip: string, userAgent: string) {\r\n        this.userId = id;\r\n        this.endPoint = url;\r\n        this.ip = ip;\r\n        this.userAgent = userAgent;\r\n    }\r\n\r\n    getUserId() {\r\n        return this.userId;\r\n    }\r\n    getEndPoint() {\r\n        return this.endPoint;\r\n    }\r\n    getIp() {\r\n        return this.ip;\r\n    }\r\n    getUserAgent() {\r\n        return this.userAgent;\r\n    }\r\n}\r\n\r\n\r\nconst userProfile = new UserProfile();\r\n\r\nexport { userProfile };","import { NextFunction, Request, Response } from 'express';\r\nimport { FastifyReply, HookHandlerDoneFunction } from \"fastify\";\r\nimport { Context, Next } from \"koa\";\r\nimport { SupportedLoggersRequest } from '../types';\r\nimport { generateAuditContent, getFileLocation, getUserId, handleLog } from '../utils';\r\nimport { ExtendedFastifyRequest } from '../utils/interface';\r\nimport { userProfile } from '../utils/user';\r\n\r\n\r\n/**\r\n* Middleware function for logging HTTP request details with express framework.\r\n* @example\r\n* expressLogger(req, res, next)\r\n* No return value as it is middleware.\r\n* @param {Request} req - Express request object containing HTTP request details.\r\n* @param {Response} res - Express response object to capture status and headers.\r\n* @param {NextFunction} next - Callback to pass control to the next middleware or handler.\r\n* @returns {void} This function does not return a value, it passes control to the next middleware.\r\n* @description\r\n*   - The function initializes logging parameters such as start time, route, IP, user agent, and user ID.\r\n*   - Utilizes helper methods like `getUserId`, `BuildProfile`, `getFileLocation`, and `handleLog`.\r\n*   - Suppress audit feature checks the response object flag to alter logging behavior.\r\n*   - Configurable timestamp inclusion based on application settings.\r\n*/\r\nconst expressLogger = (req: Request, res: Response, next: NextFunction) => {\r\n    const file = getFileLocation(\"request.log\");\r\n    const start = Date.now();\r\n    const route = req.originalUrl;\r\n    const ip = req.ip ?? \"unknown\";\r\n    const userAgent = req.headers['user-agent'] || '';\r\n    const user = getUserId(req);\r\n    const id = (typeof user === \"string\") ? user : user ? user?.id : \"unknown\";\r\n\r\n    userProfile.BuildProfile(id, route, ip, userAgent);\r\n\r\n    res.on('finish', () => {\r\n        const duration = Date.now() - start;\r\n\r\n        if ((res as any)._suppressAudit) {\r\n            const content = generateAuditContent({\r\n                type: \"request\",\r\n                action: \"incoming request\",\r\n                message: req.statusMessage ?? res.statusMessage ?? `[${route}]||[${req.method}]||[${[res.statusCode]}]`,\r\n                outcome: \"failure\",\r\n                duration,\r\n                method: req.method,\r\n                statusCode: res.statusCode || 500,\r\n                ip,\r\n                route,\r\n                userAgent,\r\n                userId: id,\r\n            });\r\n            handleLog(file, content);\r\n            return;\r\n        }\r\n        const content = generateAuditContent({\r\n            type: \"request\",\r\n            action: \"incoming request\",\r\n            outcome: \"success\",\r\n            duration,\r\n            method: req.method,\r\n            statusCode: res.statusCode || 200,\r\n            message: req.statusMessage ?? res.statusMessage ?? `[${route}]||[${req.method}]||[${[res.statusCode]}]`,\r\n            route: route,\r\n            statusMessage: res.statusMessage || \"success\",\r\n            ip,\r\n            userAgent,\r\n            userId: id,\r\n        });\r\n        handleLog(file, content);\r\n    });\r\n    next();\r\n};\r\n\r\n/**\r\n* Sets up Fastify request logging middleware functions.\r\n* @example\r\n* fastifyLogger()\r\n* No return value as it is middleware.\r\n* @returns {object} An object with `onRequest` and `OnResponse` methods for lifecycle event handling.\r\n* @description\r\n*   - Initializes request start time and calculates duration for response.\r\n*   - Incorporates failure condition for logging based on status code.\r\n*   - Logs essential request details using `handleLog` function.\r\n*   - Configurable timestamp inclusion via global settings.\r\n*/\r\nconst fastifyLogger = {\r\n    onRequest: (request: ExtendedFastifyRequest, reply: FastifyReply, done: HookHandlerDoneFunction) => {\r\n        request.startTime = Date.now();\r\n        const id = request.userId ?? \"unknown\";\r\n        const route = request.url;\r\n        const { ip } = request;\r\n        const userAgent = request.headers['user-agent'] || '';\r\n\r\n        userProfile.BuildProfile(id, route, ip, userAgent);\r\n\r\n        done();\r\n    },\r\n    onResponse: (request: ExtendedFastifyRequest, reply: FastifyReply, done: HookHandlerDoneFunction) => {\r\n        const file = getFileLocation(\"request.log\");\r\n        const duration = Date.now() - (request.startTime || Date.now());\r\n        const route = userProfile.getEndPoint() ?? \"unknown\";\r\n        const content = generateAuditContent({\r\n            type: \"request\",\r\n            action: \"incoming request\",\r\n            duration,\r\n            method: request.method,\r\n            statusCode: reply.statusCode || 500,\r\n            message: `[${route}]||[${request.method}]||[${[reply.statusCode]}]`,\r\n            ip: userProfile.getIp() ?? \"unknown\",\r\n            route,\r\n            userAgent: userProfile.getUserAgent() ?? \"unknown\",\r\n            userId: request.userId ?? \"unknown\",\r\n        });\r\n        handleLog(file, content);\r\n        done();\r\n    },\r\n};\r\n\r\n/**\r\n* Middleware function for Koa that logs HTTP request details and audits requests.\r\n* @example\r\n* async koaLogger(ctx, next)\r\n* No return value as it is middleware.\r\n* @param {Context} ctx - Koa context object containing HTTP request and response details.\r\n* @param {Next} next - Function to pass control to the next middleware or handler.\r\n* @returns {Promise<void>} This function does not return a value, it awaits the next middleware.\r\n* @description\r\n*   - Extracts user ID from the Koa context state and defaults to \"unknown\" if absent.\r\n*   - Calculates duration of request handling for performance auditing.\r\n*   - Configures log content including request and response details.\r\n*   - Utilizes helper methods like `getTimeStamp` and `handleLog`.\r\n*/\r\nconst koaLogger = async (ctx: Context, next: Next) => {\r\n    const file = getFileLocation(\"request.log\");\r\n    const start = Date.now();\r\n    const userId = ctx.state.userId ?? \"unknown\";\r\n    const route = ctx.request.url;\r\n    const ip = ctx.request.ip ?? \"unknown\";\r\n    const userAgent = ctx.request.headers[\"user-agent\"] || \"\";\r\n    userProfile.BuildProfile(userId, route, ip, userAgent);\r\n\r\n    try {\r\n        await next();\r\n    } finally {\r\n        const duration = Date.now() - start;\r\n\r\n        const content = generateAuditContent({\r\n            type: \"request\",\r\n            action: \"incoming request\",\r\n            duration,\r\n            method: ctx.request.method,\r\n            statusCode: ctx.res.statusCode || 500,\r\n            message: ctx.message ?? `[${route}]||[${ctx.request.method}]||[${[ctx.status]}]`,\r\n            ip,\r\n            route,\r\n            userAgent,\r\n            userId,\r\n        });\r\n        handleLog(file, content);\r\n    }\r\n};\r\n\r\nexport const requestLogger: SupportedLoggersRequest = {\r\n    express: expressLogger,\r\n    fastify: fastifyLogger,\r\n    koa: koaLogger,\r\n};","import { NextFunction, Request, Response } from 'express';\r\nimport { FastifyError, FastifyReply } from 'fastify';\r\nimport { Context, Next } from 'koa';\r\nimport { generateAuditContent, getFileLocation, getUserId, handleLog } from '../utils';\r\nimport { ExtendedFastifyRequest } from '../utils/interface';\r\n\r\n\r\nconst expressErrorLogger = (err: any, req: Request, res: Response, next: NextFunction) => {\r\n    const file = getFileLocation(\"error.log\");\r\n\r\n    (res as any)._suppressAudit = true;\r\n    const user = getUserId(req);\r\n    let stackLine = \"\";\r\n    if (err.stack) {\r\n        const lines = err.stack.split('\\n');\r\n        stackLine = lines.length > 1 ? lines[1].trim() : lines[0]?.trim() ?? \"\";\r\n    }\r\n    const content = generateAuditContent({\r\n        type: \"error\",\r\n        action: \"request failed\",\r\n        method: req.method,\r\n        statusCode: res.statusCode >= 400 ? res.statusCode : 500,\r\n        route: req.originalUrl,\r\n        statusMessage: res.statusMessage || \"Internal Server Error\",\r\n        ip: req.ip ?? \"unknown\",\r\n        userAgent: req.headers['user-agent'],\r\n        message: err.message,\r\n        stack: stackLine,\r\n        fullStack: err.stack ?? \"Invalid\",\r\n        userId: (typeof user === \"string\") ? user : user ? user?.id : \"unknown\",\r\n    });\r\n\r\n    handleLog(file, content);\r\n\r\n    next(err); // pass to default error handler\r\n};\r\n\r\nconst fastifyErrorLogger = (error: FastifyError, request: ExtendedFastifyRequest, reply: FastifyReply) => {\r\n    const file = getFileLocation(\"error.log\");\r\n    let stackLine = \"\";\r\n    if (error.stack) {\r\n        const lines = error.stack?.split('\\n');\r\n        stackLine = lines ? lines.length > 1 ? lines[1].trim() : lines[0]?.trim() ?? \"\" : error.message;\r\n    }\r\n\r\n    const content = generateAuditContent({\r\n        type: \"error\",\r\n        action: \"request failed\",\r\n        method: request.method,\r\n        statusCode: reply.statusCode || 500,\r\n        route: request.url,\r\n        ip: request.ip ?? \"unknown\",\r\n        userAgent: request.headers['user-agent'],\r\n        message: error.message,\r\n        stack: stackLine,\r\n        fullStack: error.stack ?? \"Invalid\",\r\n        userId: request.userId ?? \"unknown\",\r\n    });\r\n\r\n    handleLog(file, content);\r\n    return reply.send(error);\r\n};\r\n\r\nconst koaErrorLogger = async (ctx: Context, next: Next) => {\r\n    const file = getFileLocation(\"error.log\");\r\n    const userId = ctx.state.userId ?? \"unknown\";\r\n\r\n    try {\r\n        await next();\r\n    } catch (error: any) {\r\n\r\n        if (ctx.status >= 400) {\r\n            let stackLine = \"\";\r\n            if ((error as any).stack) {\r\n                const lines = (error as any).stack.split('\\n');\r\n                stackLine = lines ? lines.length > 1 ? lines[1].trim() : lines[0]?.trim() ?? null : (error as any).message;\r\n            }\r\n\r\n            const content = generateAuditContent({\r\n                type: \"error\",\r\n                action: \"request failed\",\r\n                method: ctx.method,\r\n                statusCode: ctx.statusCode || 500,\r\n                message: (error as any).message,\r\n                route: ctx.url,\r\n                ip: ctx.ip ?? \"unknown\",\r\n                userAgent: ctx.headers['user-agent'],\r\n                stack: stackLine,\r\n                fullStack: error.stack ?? \"Invalid\",\r\n                userId,\r\n            });\r\n\r\n            handleLog(file, content);\r\n        }\r\n    }\r\n};\r\n\r\n\r\nexport const errorLogger = {\r\n    express: expressErrorLogger,\r\n    fastify: fastifyErrorLogger,\r\n    koa: koaErrorLogger,\r\n};\r\n\r\n\r\n","import chalk from \"chalk\";\r\nimport fs, { createWriteStream, existsSync } from 'fs';\r\nimport path from \"path\";\r\nimport { Readable } from 'stream';\r\nimport { pipeline } from 'stream/promises';\r\nimport { fileURLToPath } from \"url\";\r\nimport { AppConfig } from \"../core/AppConfigs\";\r\nimport { checkForModule } from \"../utils\";\r\n\r\n\r\nconst __filename = fileURLToPath(import.meta.url);\r\nconst __dirname = path.dirname(__filename);\r\nconst uiPath = path.join(__dirname, \"ui\");\r\n\r\n\r\nconst getLogs = () => {\r\n    const hasSplitFiles = AppConfig.getAuditOption()?.splitFiles;\r\n    const file = AppConfig.getFileConfig();\r\n\r\n    if (hasSplitFiles) {\r\n        const files = AppConfig.getDefaultFileConfig();\r\n        if (!files) return [];\r\n\r\n        const data = files.flatMap((item) => {\r\n            const logData = fs.readFileSync(item.fullPath, \"utf-8\");\r\n            return logData.trim().split(\"\\n\").filter(Boolean).map((line, i) => ({\r\n                id: i,\r\n                ...JSON.parse(line),\r\n            }));\r\n        });\r\n\r\n        return data.sort((a, b) => b.timeStamp.localeCompare(a.timeStamp));\r\n    }\r\n\r\n    if (!file) return [];\r\n\r\n    const logData = fs.readFileSync(file.fullPath, \"utf-8\");\r\n    const item = logData.trim().split(\"\\n\").filter(Boolean).map((line, i) => ({\r\n        id: i,\r\n        ...JSON.parse(line),\r\n    }));\r\n\r\n    return item.sort((a, b) => b.timeStamp.localeCompare(a.timeStamp));\r\n};\r\n\r\n\r\n/**\r\n * Asynchronously creates and configures an Express router for serving the audit UI and logs.\r\n *\r\n * - Dynamically imports the `express` module. If `express` is not installed, logs a message and returns a no-op middleware.\r\n * - Serves static files from the `uiPath` directory.\r\n * - Handles GET requests to `/audit-ui` by serving the main UI HTML file.\r\n * - Handles GET requests to `/audit-log` by returning audit logs as JSON.\r\n *\r\n * @returns {Promise<import(\"express\").Router | import(\"express\").RequestHandler>} \r\n *   A Promise that resolves to an Express router instance, or a no-op middleware if `express` is not available.\r\n */\r\nconst expressRouter = async () => {\r\n    let express;\r\n    try {\r\n        express = await import(\"express\");\r\n    } catch (error) {\r\n        AppConfig.getAuditOption()?.logger?.info(chalk.redBright(\"Please install express in order to use this module\"));\r\n        return (req: any, res: any, next: any) => next();\r\n    }\r\n\r\n    const router = express.Router();\r\n\r\n    router.use(express.static(uiPath));\r\n\r\n    router.get('/audit-ui', (_req, res) => {\r\n        res.sendFile(path.join(uiPath, \"index.html\"));\r\n    });\r\n\r\n    router.get('/audit-log', (_req, res) => {\r\n        const logs = getLogs();\r\n        res.status(200).json({ logs });\r\n    });\r\n\r\n    return router;\r\n};\r\n\r\n/**\r\n * Asynchronously creates a Fastify plugin for serving static files and API endpoints.\r\n *\r\n * This function attempts to dynamically import the `@fastify/static` module. If the import fails,\r\n * it returns a no-op async function. Otherwise, it returns an async function that registers the static\r\n * file handler and sets up two routes:\r\n * \r\n * - `/audit-ui`: Serves the `index.html` file as an HTML response.\r\n * - `/audit-log`: Returns audit logs as a JSON object.\r\n *\r\n * @returns {Promise<(fastify: any, opts: any) => Promise<void>>} A promise that resolves to a Fastify plugin function.\r\n */\r\nconst fastifyRouter = async () => {\r\n\r\n    let fastifyStatic;\r\n    try {\r\n        fastifyStatic = await import('@fastify/static');\r\n    } catch {\r\n        return async () => { };\r\n    }\r\n\r\n    return async function (fastify: any, opts: any) {\r\n        await fastify.register(fastifyStatic.default, {\r\n            root: uiPath,\r\n            prefix: '/',\r\n        });\r\n\r\n        /**\r\n                * Sends an HTML file as the response for the '/audit-ui' route in Fastify.\r\n                * @example\r\n                * (_req, reply) => {\r\n                *   reply.type('text/html').sendFile('index.html');\r\n                * }\r\n                * @param {any} _ - The incoming request object (not used in this function).\r\n                * @param {any} reply - The Fastify reply object used to send responses.\r\n                * @description\r\n                *   - This function sets the response type to 'text/html'.\r\n                *   - It sends 'index.html' located in the static files directory specified in uiPath.\r\n                */\r\n        fastify.get('/audit-ui', (_: any, reply: any) => {\r\n            reply.type('text/html').sendFile('index.html');\r\n        });\r\n\r\n        fastify.get('/audit-log', (_: any, reply: any) => {\r\n            reply.send({ logs: getLogs() });\r\n        });\r\n    };\r\n};\r\n\r\n/**\r\n* Initializes a Koa router for serving audit-related endpoints\r\n* @example\r\n* koaRouter()\r\n* @returns {Function} Middleware function composed with Koa static server and router.\r\n* @description\r\n*   - Dynamically imports necessary Koa modules and registers routes.\r\n*   - Serves the audit UI from a static HTML file.\r\n*   - Returns the audit logs in JSON format.\r\n*   - Logs a message if required packages are not installed.\r\n*/\r\nconst koaRouter = async () => {\r\n    let Router, serve, compose;\r\n\r\n    try {\r\n        Router = (await import('@koa/router')).default;\r\n        serve = (await import('koa-static')).default;\r\n        compose = (await import('koa-compose')).default;\r\n    } catch {\r\n        AppConfig.getAuditOption()?.logger?.info(\r\n            chalk.redBright(\"Please install koa, @koa/router, koa-static, and koa-compose to use the audit UI.\"),\r\n        );\r\n        return async (ctx: any, next: any) => await next();\r\n    }\r\n\r\n    const router = new Router();\r\n\r\n\r\n    router.get('/audit-ui', (ctx: any) => {\r\n        ctx.type = 'html';\r\n        ctx.body = fs.createReadStream(path.join(uiPath, 'index.html'));\r\n    });\r\n\r\n    router.get('/audit-log', (ctx: any) => {\r\n        ctx.body = { logs: getLogs() };\r\n    });\r\n\r\n    return compose([\r\n        serve(uiPath),\r\n        router.routes(),\r\n        router.allowedMethods(),\r\n    ]);\r\n};\r\n\r\n\r\nexport const checkForFramework = () => {\r\n    const activeFramework = AppConfig.getFrameWork() as string;\r\n    return checkForModule(activeFramework);\r\n};\r\n\r\n\r\n/**\r\n * An object that maps supported web frameworks to their corresponding router implementations.\r\n *\r\n * @property {Router} express - The router implementation for Express.js.\r\n * @property {Router} fastify - The router implementation for Fastify.\r\n * @property {Router} koa - The router implementation for Koa.\r\n */\r\nexport const UIRouter = {\r\n    express: expressRouter,\r\n    fastify: fastifyRouter,\r\n    koa: koaRouter,\r\n};\r\n\r\n\r\nexport const downloadDependency = async () => {\r\n    const logger = AppConfig.getAuditOption()?.logger;\r\n    await downloadFile('https://cdn.jsdelivr.net/npm/chart.js', 'chart.min.js');\r\n    await downloadFile('https://cdn.jsdelivr.net/npm/html2canvas@1.4.1/dist/html2canvas.min.js', 'html2canvas.min.js');\r\n    logger?.info((chalk.green(\"Files downloaded successfully\")));\r\n};\r\n\r\nasync function downloadFile(url: string, fileName: string): Promise<void> {\r\n    const location = path.join(uiPath, fileName);\r\n    const logger = AppConfig.getAuditOption()?.logger;\r\n\r\n    if (existsSync(location)) {\r\n        logger?.info(chalk.gray(`Skipping ${fileName}, already exists.`));\r\n        return;\r\n    }\r\n\r\n    logger?.info(chalk.yellow(`Downloading ${fileName}`));\r\n\r\n    const res = await fetch(url);\r\n\r\n    if (!res.ok || !res.body) {\r\n        logger?.error(chalk.red(`Failed to fetch ${url}: ${res.status}`));\r\n        return;\r\n    }\r\n\r\n    const nodeStream = Readable.fromWeb(res.body as any);\r\n    const fileStream = createWriteStream(location);\r\n\r\n    try {\r\n        await pipeline(nodeStream, fileStream);\r\n        logger?.info(chalk.green(`Downloaded ${fileName} successfully.`));\r\n    } catch (err) {\r\n        logger?.error(chalk.red(`Error writing ${fileName}: ${err}`));\r\n    }\r\n}\r\n"],"mappings":"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","names":["chalk","chalk","chalk","content","chalk","fs","path","path","item","logData","fs","chalk","chalk"]}