UNPKG

@kingdiablo/auditor

Version:

A lightweight and customizable audit logger for Node.js apps. Tracks database changes, errors, and user actions with support for external loggers like Winston or Pino.

1,001 lines (991 loc) 32.7 kB
import "./chunk-ZD7AOCMD.mjs"; // src/core/Auditor.ts import chalk4 from "chalk"; // src/database/mongodb/config.ts import chalk2 from "chalk"; // src/core/AppConfigs.ts var AppConfig = /* @__PURE__ */ (() => { let logFilePath = ""; let fileConfig; let auditOption; let isInitialized = false; let captureSystemErrors = true; let useUI = false; let defaultFileConfigs; let framework = "express"; return { setAuditOption(options) { auditOption = options; }, getAuditOption() { return auditOption; }, setLogFilePath(value) { logFilePath = value; }, getLogFilePath() { return logFilePath; }, setFileConfig(config) { fileConfig = config; }, getFileConfig() { return fileConfig; }, setDefaultFileConfig(config) { defaultFileConfigs = config; }, getDefaultFileConfig() { return defaultFileConfigs; }, setIsInitialized(value) { isInitialized = value; }, getIsInitialized() { return isInitialized; }, setCaptureSystemErrors(value) { captureSystemErrors = value; }, getCaptureSystemErrors() { return captureSystemErrors; }, setFrameWork(value) { framework = value; }, getFrameWork() { return framework; }, setUseUI(value) { useUI = value; }, getUseUI() { return useUI; } }; })(); // src/utils/helper.ts import chalk from "chalk"; import fs from "fs"; import path from "path"; import crypto from "crypto"; import { createRequire } from "module"; var getTimeStamp = () => (/* @__PURE__ */ new Date()).toISOString(); var getUserId = (req) => { try { if ("user" in req) { const user = req?.user; if (!user) return "unknown"; if ("id" in user) { return user; } else return "unknown"; } else "unknown"; return "unknown"; } catch (error) { return "unknown"; } }; var handleLog = (fileConfig, content) => { const config = AppConfig.getAuditOption(); if (config.destinations?.includes("console")) logAuditEvent(content); if (config.destinations?.includes("file")) logAuditEvent(content, fileConfig); }; var saveToFile = (file, content) => { const config = AppConfig.getAuditOption(); try { fs.appendFileSync(file.fullPath, `${JSON.stringify(content)} `, { encoding: "utf-8" }); } catch (error) { config?.logger?.error(chalk.red("Failed to save log to file")); } }; var createFile = (config) => { const fullPath = path.join(process.cwd(), config.folderName); if (!fs.existsSync(fullPath)) { fs.mkdirSync(fullPath, { recursive: true }); } const dir = path.join(fullPath, config.fileName); return dir; }; var logAuditEvent = (content, file) => { const config = AppConfig.getAuditOption(); if (file) { saveToFile(file, content); return; } const cleanContent = { ...content }; delete cleanContent.fullStack; config?.logger?.info(cleanContent); }; var getFileLocation = (location) => { const config = AppConfig.getAuditOption(); const defaultFileConfigs = AppConfig.getDefaultFileConfig(); if (config.splitFiles) { const dbFile = defaultFileConfigs.find((x) => x.fileName === location); return dbFile; } return AppConfig.getFileConfig(); }; var generateAuditContent = ({ type, action, message, ...rest }) => { return { id: generateId(), type, action, message, ...rest, ...AppConfig.getAuditOption()?.useTimeStamp ? { timeStamp: getTimeStamp() } : {} }; }; var generateId = () => { const time = Date.now().toString(36); const rand = crypto.randomBytes(3).toString("hex"); return `${time}-${rand}`; }; var checkForModule = (item) => { const requireFromUserProject = createRequire(path.join(process.cwd(), "index.js")); try { AppConfig.getAuditOption()?.logger?.info( chalk.blueBright(`Checking for ${item}`) ); requireFromUserProject.resolve(item); AppConfig.getAuditOption()?.logger?.info( chalk.greenBright(`${item} found.`) ); return true; } catch (error) { AppConfig.getAuditOption()?.logger?.info( chalk.redBright(`Failed to find "${item}"`) ); return false; } }; // src/utils/user.ts var UserProfile = class { constructor() { this.userId = ""; this.endPoint = ""; this.ip = ""; this.userAgent = ""; } BuildProfile(id, url, ip, userAgent) { this.userId = id; this.endPoint = url; this.ip = ip; this.userAgent = userAgent; } getUserId() { return this.userId; } getEndPoint() { return this.endPoint; } getIp() { return this.ip; } getUserAgent() { return this.userAgent; } }; var userProfile = new UserProfile(); // src/database/mongodb/config.ts var hasMongoose = false; var checkForMongodb = () => { hasMongoose = checkForModule("mongoose"); return hasMongoose; }; var auditModel = (schema) => { const config = AppConfig.getAuditOption(); if (config.dbType === "none") { config.logger?.error(chalk2.yellow("Cannot audit db while DB type is set to none")); return; } if (!hasMongoose) { config.logger?.error(chalk2.red("Please install mongoose to use audit")); return; } handleSaveSchema(schema); handleFindSchema(schema); handleUpdateSchema(schema); handleDeletingSchema(schema); }; var handleSaveSchema = (schema) => { const log = generateLog(); schema.pre("save", function(next) { this._wasNew = this.isNew; next(); }); schema.post("save", (doc) => { const { modelName } = doc.constructor; const message = `doc was ${doc._wasNew ? "created" : "updated"}`; log("save", modelName, {}, message); }); }; var handleFindSchema = (schema) => { const log = generateLog(); schema.post("find", function(docs) { const modelName = this.model.collection.name; const message = `looking for ${modelName}`; log("read", modelName, this.getFilter(), message, docs.length); }); schema.post("findOne", function(doc) { const modelName = this.model.collection.name; const message = `looking for a single ${modelName}`; log("read", modelName, this.getFilter(), message); }); }; var handleUpdateSchema = (schema) => { const log = generateLog(); schema.post("updateOne", function(doc) { const modelName = this.model.collection.name; const message = `updating a single ${modelName} doc`; log("update", modelName, this.getFilter(), message); }); schema.post("findOneAndUpdate", function(doc) { const modelName = this.model.collection.name; const message = `finding & updating a single ${modelName} doc`; log("update", modelName, this.getFilter(), message); }); schema.post("updateMany", function(docs) { const modelName = this.model.collection.name; const message = `updating multiple ${modelName} docs`; log("update", modelName, this.getFilter(), message, docs.modifiedCount); }); }; var handleDeletingSchema = (schema) => { const log = generateLog(); schema.post("findOneAndDelete", function() { const modelName = this.model.collection.name; const message = `finding & deleting a single ${modelName} doc`; log("delete", modelName, this.getFilter(), message); }); schema.post("deleteOne", function() { const modelName = this.model.collection.name; const message = `deleting a single ${modelName} doc`; log("delete", modelName, this.getFilter(), message); }); schema.post("deleteMany", function(docs) { const modelName = this.model.collection.name; const message = `deleting multiple ${modelName} docs`; log("delete", modelName, this.getFilter(), message, docs.deletedCount); }); }; var generateLog = () => { const config = AppConfig.getAuditOption(); return (action, modelName, filter, message, length) => { const content = generateAuditContent({ type: "db", action, collection: modelName, criteria: filter, ...length !== void 0 ? { resultCount: length } : {}, message, userId: userProfile.getUserId(), endPoint: userProfile.getEndPoint(), ip: userProfile.getIp(), userAgent: userProfile.getUserAgent(), ...config.useTimeStamp ? { timeStamp: getTimeStamp() } : {} }); if (config.destinations?.includes("console")) logAuditEvent(content); const dbFile = getFileLocation("db.log"); if (!dbFile) return; if (config.destinations?.includes("file")) logAuditEvent(content, dbFile); }; }; // src/middleware/requestLogger.ts var expressLogger = (req, res, next) => { const file = getFileLocation("request.log"); const start = Date.now(); const route = req.originalUrl; const ip = req.ip ?? "unknown"; const userAgent = req.headers["user-agent"] || ""; const user = getUserId(req); const id = typeof user === "string" ? user : user ? user?.id : "unknown"; userProfile.BuildProfile(id, route, ip, userAgent); res.on("finish", () => { const duration = Date.now() - start; if (res._suppressAudit) { const content2 = generateAuditContent({ type: "request", action: "incoming request", message: req.statusMessage ?? res.statusMessage ?? `[${route}]||[${req.method}]||[${[res.statusCode]}]`, outcome: "failure", duration, method: req.method, statusCode: res.statusCode || 500, ip, route, userAgent, userId: id }); handleLog(file, content2); return; } const content = generateAuditContent({ type: "request", action: "incoming request", outcome: "success", duration, method: req.method, statusCode: res.statusCode || 200, message: req.statusMessage ?? res.statusMessage ?? `[${route}]||[${req.method}]||[${[res.statusCode]}]`, route, statusMessage: res.statusMessage || "success", ip, userAgent, userId: id }); handleLog(file, content); }); next(); }; var fastifyLogger = { onRequest: (request, reply, done) => { request.startTime = Date.now(); const id = request.userId ?? "unknown"; const route = request.url; const { ip } = request; const userAgent = request.headers["user-agent"] || ""; userProfile.BuildProfile(id, route, ip, userAgent); done(); }, onResponse: (request, reply, done) => { const file = getFileLocation("request.log"); const duration = Date.now() - (request.startTime || Date.now()); const route = userProfile.getEndPoint() ?? "unknown"; const content = generateAuditContent({ type: "request", action: "incoming request", duration, method: request.method, statusCode: reply.statusCode || 500, message: `[${route}]||[${request.method}]||[${[reply.statusCode]}]`, ip: userProfile.getIp() ?? "unknown", route, userAgent: userProfile.getUserAgent() ?? "unknown", userId: request.userId ?? "unknown" }); handleLog(file, content); done(); } }; var koaLogger = async (ctx, next) => { const file = getFileLocation("request.log"); const start = Date.now(); const userId = ctx.state.userId ?? "unknown"; const route = ctx.request.url; const ip = ctx.request.ip ?? "unknown"; const userAgent = ctx.request.headers["user-agent"] || ""; userProfile.BuildProfile(userId, route, ip, userAgent); try { await next(); } finally { const duration = Date.now() - start; const content = generateAuditContent({ type: "request", action: "incoming request", duration, method: ctx.request.method, statusCode: ctx.res.statusCode || 500, message: ctx.message ?? `[${route}]||[${ctx.request.method}]||[${[ctx.status]}]`, ip, route, userAgent, userId }); handleLog(file, content); } }; var requestLogger = { express: expressLogger, fastify: fastifyLogger, koa: koaLogger }; // src/middleware/errorLogger.ts var expressErrorLogger = (err, req, res, next) => { const file = getFileLocation("error.log"); res._suppressAudit = true; const user = getUserId(req); let stackLine = ""; if (err.stack) { const lines = err.stack.split("\n"); stackLine = lines.length > 1 ? lines[1].trim() : lines[0]?.trim() ?? ""; } const content = generateAuditContent({ type: "error", action: "request failed", method: req.method, statusCode: res.statusCode >= 400 ? res.statusCode : 500, route: req.originalUrl, statusMessage: res.statusMessage || "Internal Server Error", ip: req.ip ?? "unknown", userAgent: req.headers["user-agent"], message: err.message, stack: stackLine, fullStack: err.stack ?? "Invalid", userId: typeof user === "string" ? user : user ? user?.id : "unknown" }); handleLog(file, content); next(err); }; var fastifyErrorLogger = (error, request, reply) => { const file = getFileLocation("error.log"); let stackLine = ""; if (error.stack) { const lines = error.stack?.split("\n"); stackLine = lines ? lines.length > 1 ? lines[1].trim() : lines[0]?.trim() ?? "" : error.message; } const content = generateAuditContent({ type: "error", action: "request failed", method: request.method, statusCode: reply.statusCode || 500, route: request.url, ip: request.ip ?? "unknown", userAgent: request.headers["user-agent"], message: error.message, stack: stackLine, fullStack: error.stack ?? "Invalid", userId: request.userId ?? "unknown" }); handleLog(file, content); return reply.send(error); }; var koaErrorLogger = async (ctx, next) => { const file = getFileLocation("error.log"); const userId = ctx.state.userId ?? "unknown"; try { await next(); } catch (error) { if (ctx.status >= 400) { let stackLine = ""; if (error.stack) { const lines = error.stack.split("\n"); stackLine = lines ? lines.length > 1 ? lines[1].trim() : lines[0]?.trim() ?? null : error.message; } const content = generateAuditContent({ type: "error", action: "request failed", method: ctx.method, statusCode: ctx.statusCode || 500, message: error.message, route: ctx.url, ip: ctx.ip ?? "unknown", userAgent: ctx.headers["user-agent"], stack: stackLine, fullStack: error.stack ?? "Invalid", userId }); handleLog(file, content); } } }; var errorLogger = { express: expressErrorLogger, fastify: fastifyErrorLogger, koa: koaErrorLogger }; // src/router/router.ts import chalk3 from "chalk"; import fs2, { createWriteStream, existsSync } from "fs"; import path2 from "path"; import { Readable } from "stream"; import { pipeline } from "stream/promises"; import { fileURLToPath } from "url"; var __filename = fileURLToPath(import.meta.url); var __dirname = path2.dirname(__filename); var uiPath = path2.join(__dirname, "ui"); var getLogs = () => { const hasSplitFiles = AppConfig.getAuditOption()?.splitFiles; const file = AppConfig.getFileConfig(); if (hasSplitFiles) { const files = AppConfig.getDefaultFileConfig(); if (!files) return []; const data = files.flatMap((item2) => { const logData2 = fs2.readFileSync(item2.fullPath, "utf-8"); return logData2.trim().split("\n").filter(Boolean).map((line, i) => ({ id: i, ...JSON.parse(line) })); }); return data.sort((a, b) => b.timeStamp.localeCompare(a.timeStamp)); } if (!file) return []; const logData = fs2.readFileSync(file.fullPath, "utf-8"); const item = logData.trim().split("\n").filter(Boolean).map((line, i) => ({ id: i, ...JSON.parse(line) })); return item.sort((a, b) => b.timeStamp.localeCompare(a.timeStamp)); }; var expressRouter = async () => { let express; try { express = await import("express"); } catch (error) { AppConfig.getAuditOption()?.logger?.info(chalk3.redBright("Please install express in order to use this module")); return (req, res, next) => next(); } const router = express.Router(); router.use(express.static(uiPath)); router.get("/audit-ui", (_req, res) => { res.sendFile(path2.join(uiPath, "index.html")); }); router.get("/audit-log", (_req, res) => { const logs = getLogs(); res.status(200).json({ logs }); }); return router; }; var fastifyRouter = async () => { let fastifyStatic; try { fastifyStatic = await import("@fastify/static"); } catch { return async () => { }; } return async function(fastify, opts) { await fastify.register(fastifyStatic.default, { root: uiPath, prefix: "/" }); fastify.get("/audit-ui", (_, reply) => { reply.type("text/html").sendFile("index.html"); }); fastify.get("/audit-log", (_, reply) => { reply.send({ logs: getLogs() }); }); }; }; var koaRouter = async () => { let Router, serve, compose; try { Router = (await import("@koa/router")).default; serve = (await import("koa-static")).default; compose = (await import("./koa-compose-JHK7V4NJ.mjs")).default; } catch { AppConfig.getAuditOption()?.logger?.info( chalk3.redBright("Please install koa, @koa/router, koa-static, and koa-compose to use the audit UI.") ); return async (ctx, next) => await next(); } const router = new Router(); router.get("/audit-ui", (ctx) => { ctx.type = "html"; ctx.body = fs2.createReadStream(path2.join(uiPath, "index.html")); }); router.get("/audit-log", (ctx) => { ctx.body = { logs: getLogs() }; }); return compose([ serve(uiPath), router.routes(), router.allowedMethods() ]); }; var checkForFramework = () => { const activeFramework = AppConfig.getFrameWork(); return checkForModule(activeFramework); }; var UIRouter = { express: expressRouter, fastify: fastifyRouter, koa: koaRouter }; var downloadDependency = async () => { const logger = AppConfig.getAuditOption()?.logger; await downloadFile("https://cdn.jsdelivr.net/npm/chart.js", "chart.min.js"); await downloadFile("https://cdn.jsdelivr.net/npm/html2canvas@1.4.1/dist/html2canvas.min.js", "html2canvas.min.js"); logger?.info(chalk3.green("Files downloaded successfully")); }; async function downloadFile(url, fileName) { const location = path2.join(uiPath, fileName); const logger = AppConfig.getAuditOption()?.logger; if (existsSync(location)) { logger?.info(chalk3.gray(`Skipping ${fileName}, already exists.`)); return; } logger?.info(chalk3.yellow(`Downloading ${fileName}`)); const res = await fetch(url); if (!res.ok || !res.body) { logger?.error(chalk3.red(`Failed to fetch ${url}: ${res.status}`)); return; } const nodeStream = Readable.fromWeb(res.body); const fileStream = createWriteStream(location); try { await pipeline(nodeStream, fileStream); logger?.info(chalk3.green(`Downloaded ${fileName} successfully.`)); } catch (err) { logger?.error(chalk3.red(`Error writing ${fileName}: ${err}`)); } } // src/core/Auditor.ts var Audit = class { /** * Creates an instance of the Auditor class with the provided options. * * @param options - Optional configuration object for the auditor. * - `logger`: Custom logger to use; defaults to `console` if not provided. * - `dbType`: Type of database to use; defaults to `"none"`. * - `destinations`: Array of destinations for audit logs; defaults to `["console"]`. * - `framework`: The framework being used (e.g., "express"); defaults to `"express"`. * - `useTimeStamp`: Whether to include timestamps in logs; defaults to `true`. * - `splitFiles`: Whether to split logs into multiple files; defaults to `false`. * - `captureSystemErrors`: Whether to capture system errors; defaults to `false`. * * Initializes the `auditOptions` property by merging the provided options with sensible defaults. */ constructor(options) { this.options = options; this.logFilePath = ""; this.defaultFileConfigs = [ { fileName: "error.log", folderName: "audits", fullPath: "" }, { fileName: "request.log", folderName: "audits", fullPath: "" }, { fileName: "db.log", folderName: "audits", fullPath: "" }, { fileName: "action.log", folderName: "audits", fullPath: "" } ]; this.fileConfig = { fileName: "audit.log", folderName: "audit", fullPath: "" }; this.isInitialized = false; this.auditOptions = { dbType: "none", destinations: ["console"], framework: "express", logger: console, useTimeStamp: true, splitFiles: false, captureSystemErrors: false, useUI: false }; this.CreateFileLocation = (config) => { if (!this.auditOptions.destinations?.includes("file")) return; if (this.auditOptions.splitFiles) { this.defaultFileConfigs.forEach((item) => { this.GenerateFile(item); }); return; } this.GenerateFile(config); }; this.GenerateFile = (config) => { const dir = createFile(config); config.fullPath = dir; this.logFilePath = dir; this.defaultFileConfigs = this.defaultFileConfigs.map((item) => { if (item.fileName === config.fileName) { return { ...item, fullPath: dir }; } return item; }); }; /** * Sets up system error handling and logging for audit purposes. * @example * handleSystemErrors() * Initializes processes to log exceptions, rejections, signals, and exits. * @description * - Listens for Node.js process events such as uncaught exceptions, unhandled rejections, SIGTERM, SIGINT, and exit. * - Utilizes the `generateAuditContent` utility to format the logs. * - Logs generated content using `handleLog` with the error file configuration. * - Only activates if `captureSystemErrors` is true within audit options. */ this.HandleSystemErrors = () => { if (!this.auditOptions.captureSystemErrors) return; const file = getFileLocation("error.log"); process.on("uncaughtException", (error, origin) => { const fullStack = error instanceof Error ? error.stack : void 0; const content = generateAuditContent({ type: "error", action: "unknown", message: error.message ?? "an uncaughtException", outcome: "uncaughtException", error, origin, fullStack }); handleLog(file, content); }); process.on("unhandledRejection", (reason) => { const content = generateAuditContent({ type: "error", action: "unknown", message: "an unhandledRejection", outcome: "unhandledRejection", reason }); handleLog(file, content); }); process.on("SIGTERM", () => { const content = generateAuditContent({ type: "signal", action: "terminated", message: "was terminated", outcome: "SIGTERM", signal: "SIGTERM" }); handleLog(file, content); process.exit(0); }); process.on("SIGINT", () => { const content = generateAuditContent({ type: "signal", action: "terminated", message: "app was terminated", outcome: "SIGINT", signal: "SIGINT" }); handleLog(file, content); process.exit(0); }); process.on("exit", (code) => { const content = generateAuditContent({ type: "system", action: "exit", message: "app was exited", outcome: "exit", code }); handleLog(file, content); }); }; this.auditOptions = { ...options, logger: options?.logger || console, dbType: options?.dbType || "none", destinations: options?.destinations || ["console"], framework: options?.framework ?? "express", useTimeStamp: options?.useTimeStamp ?? true, splitFiles: options?.splitFiles ?? false, captureSystemErrors: options?.captureSystemErrors ?? false, useUI: options?.useUI ?? false }; } /** * Initializes the auditor by creating the necessary file location and logging a success message. * * This method sets up the audit configuration by invoking `CreateFileLocation` with the current file configuration, * and logs a confirmation message using the configured logger. * * @remarks * Should be called before performing any audit operations to ensure the environment is properly configured. */ async Setup() { if (this.isInitialized) { this.auditOptions.logger?.warn(chalk4.yellow("Audit already initialized.")); return; } this.CreateFileLocation(this.fileConfig); AppConfig.setAuditOption(this.auditOptions); AppConfig.setDefaultFileConfig(this.defaultFileConfigs); AppConfig.setFileConfig(this.fileConfig); AppConfig.setLogFilePath(this.logFilePath); AppConfig.setCaptureSystemErrors(this.auditOptions.captureSystemErrors ?? false); AppConfig.setFrameWork(this.auditOptions.framework); AppConfig.setUseUI(this.auditOptions.useUI ?? false); if (this.auditOptions.dbType === "mongoose") { const result = checkForMongodb(); if (!result) return; } if (this.auditOptions.useUI) { const hasFramework = checkForFramework(); if (hasFramework) { AppConfig.getAuditOption()?.logger?.info(chalk4.yellow("In order to use this module some dependency will be downloaded")); await downloadDependency(); } } this.isInitialized = true; AppConfig.setIsInitialized(this.isInitialized); this.HandleSystemErrors(); this.auditOptions.logger?.info(chalk4.green("Default Audit config set successfully")); } /** * Logs an event to the configured destinations (console and/or file). * * Depending on the configuration, this method will: * - Add a timestamp to the event if `useTimeStamp` is enabled. * - Log the event to the console if "console" is included in `destinations`. * - Log the event to a file if "file" is included in `destinations`. * - If `splitFiles` is enabled, logs to a specific action log file. * - Otherwise, logs to the default file configuration. * - If the file path is not set when logging to a file, logs an error. * * @param event - The event object to be logged. */ Log(event) { const item = generateAuditContent({ ...event }); if (!this.isInitialized) { this.auditOptions?.logger?.info(chalk4.red("Not Initialized. Setup Is Required")); return; } if (this.auditOptions.destinations?.includes("console")) { logAuditEvent(item); } if (this.auditOptions.destinations?.includes("file")) { const actionFile = this.defaultFileConfigs.find((x) => x.fileName === "action.log"); const file = this.auditOptions.splitFiles ? actionFile : this.fileConfig; if (!file.fullPath) { this.auditOptions.logger?.error(chalk4.red("Unable to locate file path")); return; } logAuditEvent(item, file); } } /** * Logs an error event to the configured destinations (console and/or file). * @example * LogError(new Error("Unexpected failure")) * Logs error details to the console and file depending on configuration. * @param {any} error - The error object to be logged. * @description * - Extracts the error stack trace to capture informative details. * - Compiles additional user context such as IP and user agent when available. * - Handles uninitialized state by printing a warning message. * - Utilizes timestamp inclusion and log destination logic based on audit options. */ LogError(error) { if (!this.isInitialized) { this.auditOptions?.logger?.info(chalk4.red("Not Initialized. Setup Is Required")); return; } let stackLine = ""; if (error.stack) { const lines = error.stack.split("\n"); stackLine = lines.length > 1 ? lines[1].trim() : lines[0]?.trim() ?? ""; } const item = generateAuditContent({ type: "error", action: "unknown", outcome: "error", method: "user called", statusCode: error.statusCode ?? 500, userId: userProfile.getUserId() ?? "unknown", ip: userProfile.getIp() ?? "unknown", userAgent: userProfile.getUserAgent() ?? "unknown", message: error.message ?? "an error occurred", stack: stackLine ?? "no stack available" }); if (this.auditOptions.destinations?.includes("console")) { logAuditEvent(item); } if (this.auditOptions.destinations?.includes("file")) { const actionFile = this.defaultFileConfigs.find((x) => x.fileName === "error.log"); const file = this.auditOptions.splitFiles ? actionFile : this.fileConfig; if (!file.fullPath) { this.auditOptions.logger?.error(chalk4.red("Unable to locate file path")); return; } logAuditEvent(item, file); } } /** * Audits a given schema model by invoking the `auditModel` function with the current configuration, * a generated timestamp, and the provided schema. * * @template T - The type of the schema being audited. * @param schema - The schema object to be audited. */ AuditModel(schema) { auditModel(schema); } /** * Configures the file logging settings for the auditor. * * This method sets up the file configuration used for logging audit events to a file. * It checks if "file" is included in the destinations and if split file logging is disabled. * If these conditions are not met, it logs appropriate warnings and returns early. * Otherwise, it sets up the file configuration with the provided options or defaults. * * @param config - Optional configuration object for the file logger, excluding the `fullPath` property. * - `folderName` (optional): The folder where the log file will be stored. Defaults to `"audit"`. * - `fileName` (optional): The name of the log file. Defaults to `"audit.log"`. */ SetFileConfig(config) { if (!this.auditOptions.destinations?.includes("file")) { this.auditOptions.logger?.warn(chalk4.yellowBright("You need to add file to destinations for this to work properly")); return; } if (this.auditOptions.splitFiles) { this.auditOptions.logger?.info(chalk4.yellow("Cannot configure file as it is not supported when using splitfile")); return; } const folder = config?.folderName ?? "audit"; const baseFileName = config?.fileName ?? "audit"; const fileName = baseFileName.endsWith(".log") ? baseFileName : `${baseFileName}.log`; this.fileConfig = { ...config, folderName: folder, fileName, fullPath: "" }; } /** * Logs all incoming requests using the configured logger. * * Depending on the `splitFiles` configuration, this method will either: * - Log requests to a dedicated "request.log" file if `splitFiles` is enabled. * - Log requests to the default log file otherwise. * * @returns The result of the `requestLogger` function, which handles the actual logging process. */ RequestLogger() { return requestLogger[this.auditOptions.framework]; } /** * Logs all errors using the configured error logger. * * If the `splitFiles` option is enabled in the configuration, errors are logged to a separate * "error.log" file as specified in the default file configurations. Otherwise, errors are logged * to the main file configuration. * * @returns The result of the error logger function, which handles error logging based on the current configuration. */ ErrorLogger() { return errorLogger[this.auditOptions.framework]; } /** * Asynchronously creates and returns the UI component or handler based on the specified framework * in the audit options. * * @returns {Promise<any>} A promise that resolves to the UI component or handler corresponding to the selected framework. */ CreateUI() { if (!AppConfig.getUseUI()) { AppConfig.getAuditOption()?.logger?.info(chalk4.yellow("Add the useUI option in the constructor to download the dependency")); return UIRouter[this.auditOptions.framework]; } return UIRouter[this.auditOptions.framework]; } }; export { Audit as Auditor }; //# sourceMappingURL=index.mjs.map