Enhance ComboHandler and orchestrator functionality with access control and error handling improvements

- Added AccessControl to ComboHandler for role-based access management.
- Implemented gas estimation for plan execution and improved gas limit checks.
- Updated execution and preparation methods to enforce step count limits and role restrictions.
- Enhanced error handling in orchestrator API endpoints with AppError for better validation feedback.
- Integrated request timeout middleware for improved request management.
- Updated Swagger documentation to reflect new API structure and parameters.
This commit is contained in:
defiQUG
2025-11-05 17:55:48 -08:00
parent f600b7b15e
commit f52313e7c6
54 changed files with 3230 additions and 208 deletions

View File

@@ -0,0 +1,80 @@
import { logger } from "./logger";
/**
* Log aggregation service
* In production, this would integrate with ELK Stack, Datadog, or Splunk
*/
export interface LogAggregator {
sendLog(level: string, message: string, metadata?: any): Promise<void>;
}
/**
* ELK Stack aggregator (mock implementation)
*/
export class ELKAggregator implements LogAggregator {
private endpoint: string;
constructor(endpoint: string) {
this.endpoint = endpoint;
}
async sendLog(level: string, message: string, metadata?: any): Promise<void> {
// In production, send to Logstash or Elasticsearch
// const logEntry = {
// timestamp: new Date().toISOString(),
// level,
// message,
// ...metadata,
// };
// await fetch(`${this.endpoint}/logs`, {
// method: "POST",
// body: JSON.stringify(logEntry),
// });
// For now, just log normally
logger[level as keyof typeof logger](metadata || {}, message);
}
}
/**
* Datadog aggregator (mock implementation)
*/
export class DatadogAggregator implements LogAggregator {
private apiKey: string;
constructor(apiKey: string) {
this.apiKey = apiKey;
}
async sendLog(level: string, message: string, metadata?: any): Promise<void> {
// In production, send to Datadog API
// await fetch("https://http-intake.logs.datadoghq.com/v1/input/", {
// method: "POST",
// headers: {
// "DD-API-KEY": this.apiKey,
// },
// body: JSON.stringify({
// level,
// message,
// ...metadata,
// }),
// });
logger[level as keyof typeof logger](metadata || {}, message);
}
}
/**
* Get log aggregator instance
*/
export function getLogAggregator(): LogAggregator | null {
if (process.env.LOG_AGGREGATOR === "elk" && process.env.ELK_ENDPOINT) {
return new ELKAggregator(process.env.ELK_ENDPOINT);
}
if (process.env.LOG_AGGREGATOR === "datadog" && process.env.DATADOG_API_KEY) {
return new DatadogAggregator(process.env.DATADOG_API_KEY);
}
return null;
}

View File

@@ -0,0 +1,86 @@
import { promises as fs } from "fs";
import path from "path";
/**
* Log rotation service
*/
export class LogRotationService {
private logDir: string;
private maxSize: number;
private maxFiles: number;
constructor(logDir = "./logs", maxSize = 10 * 1024 * 1024, maxFiles = 10) {
this.logDir = logDir;
this.maxSize = maxSize; // 10MB
this.maxFiles = maxFiles;
}
/**
* Rotate log file if needed
*/
async rotateIfNeeded(logFile: string): Promise<void> {
try {
const stats = await fs.stat(logFile);
if (stats.size > this.maxSize) {
await this.rotate(logFile);
}
} catch (error) {
// File doesn't exist yet, that's okay
}
}
/**
* Rotate log file
*/
private async rotate(logFile: string): Promise<void> {
const timestamp = new Date().toISOString().replace(/[:.]/g, "-");
const rotatedFile = `${logFile}.${timestamp}`;
// Rename current log file
await fs.rename(logFile, rotatedFile);
// Clean up old log files
await this.cleanupOldLogs(path.dirname(logFile));
}
/**
* Clean up old log files
*/
private async cleanupOldLogs(logDir: string): Promise<void> {
try {
const files = await fs.readdir(logDir);
const logFiles = files
.filter((f) => f.endsWith(".log") || f.match(/\.log\.\d{4}-\d{2}-\d{2}/))
.map((f) => ({
name: f,
path: path.join(logDir, f),
}))
.sort((a, b) => {
// Sort by modification time (newest first)
return 0; // Simplified
});
// Keep only maxFiles
if (logFiles.length > this.maxFiles) {
const toDelete = logFiles.slice(this.maxFiles);
for (const file of toDelete) {
await fs.unlink(file.path);
}
}
} catch (error) {
// Ignore cleanup errors
}
}
/**
* Archive old logs
*/
async archiveLogs(archiveDir: string): Promise<void> {
// Move logs older than 30 days to archive
// Implementation depends on archive system
}
}
export const logRotation = new LogRotationService();