@morojs/moro 1.0.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.
- package/LICENSE +21 -0
- package/README.md +233 -0
- package/dist/core/config/index.d.ts +19 -0
- package/dist/core/config/index.js +59 -0
- package/dist/core/config/index.js.map +1 -0
- package/dist/core/config/loader.d.ts +6 -0
- package/dist/core/config/loader.js +288 -0
- package/dist/core/config/loader.js.map +1 -0
- package/dist/core/config/schema.d.ts +335 -0
- package/dist/core/config/schema.js +286 -0
- package/dist/core/config/schema.js.map +1 -0
- package/dist/core/config/utils.d.ts +50 -0
- package/dist/core/config/utils.js +185 -0
- package/dist/core/config/utils.js.map +1 -0
- package/dist/core/database/adapters/drizzle.d.ts +29 -0
- package/dist/core/database/adapters/drizzle.js +366 -0
- package/dist/core/database/adapters/drizzle.js.map +1 -0
- package/dist/core/database/adapters/index.d.ts +8 -0
- package/dist/core/database/adapters/index.js +48 -0
- package/dist/core/database/adapters/index.js.map +1 -0
- package/dist/core/database/adapters/mongodb.d.ts +35 -0
- package/dist/core/database/adapters/mongodb.js +215 -0
- package/dist/core/database/adapters/mongodb.js.map +1 -0
- package/dist/core/database/adapters/mysql.d.ts +23 -0
- package/dist/core/database/adapters/mysql.js +149 -0
- package/dist/core/database/adapters/mysql.js.map +1 -0
- package/dist/core/database/adapters/postgresql.d.ts +24 -0
- package/dist/core/database/adapters/postgresql.js +160 -0
- package/dist/core/database/adapters/postgresql.js.map +1 -0
- package/dist/core/database/adapters/redis.d.ts +50 -0
- package/dist/core/database/adapters/redis.js +266 -0
- package/dist/core/database/adapters/redis.js.map +1 -0
- package/dist/core/database/adapters/sqlite.d.ts +23 -0
- package/dist/core/database/adapters/sqlite.js +194 -0
- package/dist/core/database/adapters/sqlite.js.map +1 -0
- package/dist/core/database/index.d.ts +2 -0
- package/dist/core/database/index.js +20 -0
- package/dist/core/database/index.js.map +1 -0
- package/dist/core/docs/index.d.ts +63 -0
- package/dist/core/docs/index.js +170 -0
- package/dist/core/docs/index.js.map +1 -0
- package/dist/core/docs/openapi-generator.d.ts +124 -0
- package/dist/core/docs/openapi-generator.js +413 -0
- package/dist/core/docs/openapi-generator.js.map +1 -0
- package/dist/core/docs/simple-docs.d.ts +21 -0
- package/dist/core/docs/simple-docs.js +268 -0
- package/dist/core/docs/simple-docs.js.map +1 -0
- package/dist/core/docs/swagger-ui.d.ts +28 -0
- package/dist/core/docs/swagger-ui.js +317 -0
- package/dist/core/docs/swagger-ui.js.map +1 -0
- package/dist/core/docs/zod-to-openapi.d.ts +29 -0
- package/dist/core/docs/zod-to-openapi.js +414 -0
- package/dist/core/docs/zod-to-openapi.js.map +1 -0
- package/dist/core/events/event-bus.d.ts +27 -0
- package/dist/core/events/event-bus.js +193 -0
- package/dist/core/events/event-bus.js.map +1 -0
- package/dist/core/events/index.d.ts +2 -0
- package/dist/core/events/index.js +7 -0
- package/dist/core/events/index.js.map +1 -0
- package/dist/core/framework.d.ts +57 -0
- package/dist/core/framework.js +432 -0
- package/dist/core/framework.js.map +1 -0
- package/dist/core/http/http-server.d.ts +114 -0
- package/dist/core/http/http-server.js +1154 -0
- package/dist/core/http/http-server.js.map +1 -0
- package/dist/core/http/index.d.ts +3 -0
- package/dist/core/http/index.js +10 -0
- package/dist/core/http/index.js.map +1 -0
- package/dist/core/http/router.d.ts +14 -0
- package/dist/core/http/router.js +113 -0
- package/dist/core/http/router.js.map +1 -0
- package/dist/core/logger/filters.d.ts +9 -0
- package/dist/core/logger/filters.js +134 -0
- package/dist/core/logger/filters.js.map +1 -0
- package/dist/core/logger/index.d.ts +3 -0
- package/dist/core/logger/index.js +26 -0
- package/dist/core/logger/index.js.map +1 -0
- package/dist/core/logger/logger.d.ts +49 -0
- package/dist/core/logger/logger.js +332 -0
- package/dist/core/logger/logger.js.map +1 -0
- package/dist/core/logger/outputs.d.ts +42 -0
- package/dist/core/logger/outputs.js +110 -0
- package/dist/core/logger/outputs.js.map +1 -0
- package/dist/core/middleware/built-in/adapters/cache/file.d.ts +15 -0
- package/dist/core/middleware/built-in/adapters/cache/file.js +128 -0
- package/dist/core/middleware/built-in/adapters/cache/file.js.map +1 -0
- package/dist/core/middleware/built-in/adapters/cache/index.d.ts +5 -0
- package/dist/core/middleware/built-in/adapters/cache/index.js +28 -0
- package/dist/core/middleware/built-in/adapters/cache/index.js.map +1 -0
- package/dist/core/middleware/built-in/adapters/cache/memory.d.ts +11 -0
- package/dist/core/middleware/built-in/adapters/cache/memory.js +65 -0
- package/dist/core/middleware/built-in/adapters/cache/memory.js.map +1 -0
- package/dist/core/middleware/built-in/adapters/cache/redis.d.ts +17 -0
- package/dist/core/middleware/built-in/adapters/cache/redis.js +91 -0
- package/dist/core/middleware/built-in/adapters/cache/redis.js.map +1 -0
- package/dist/core/middleware/built-in/adapters/cdn/azure.d.ts +21 -0
- package/dist/core/middleware/built-in/adapters/cdn/azure.js +40 -0
- package/dist/core/middleware/built-in/adapters/cdn/azure.js.map +1 -0
- package/dist/core/middleware/built-in/adapters/cdn/cloudflare.d.ts +14 -0
- package/dist/core/middleware/built-in/adapters/cdn/cloudflare.js +77 -0
- package/dist/core/middleware/built-in/adapters/cdn/cloudflare.js.map +1 -0
- package/dist/core/middleware/built-in/adapters/cdn/cloudfront.d.ts +15 -0
- package/dist/core/middleware/built-in/adapters/cdn/cloudfront.js +73 -0
- package/dist/core/middleware/built-in/adapters/cdn/cloudfront.js.map +1 -0
- package/dist/core/middleware/built-in/adapters/cdn/index.d.ts +5 -0
- package/dist/core/middleware/built-in/adapters/cdn/index.js +28 -0
- package/dist/core/middleware/built-in/adapters/cdn/index.js.map +1 -0
- package/dist/core/middleware/built-in/adapters/index.d.ts +4 -0
- package/dist/core/middleware/built-in/adapters/index.js +26 -0
- package/dist/core/middleware/built-in/adapters/index.js.map +1 -0
- package/dist/core/middleware/built-in/auth.d.ts +2 -0
- package/dist/core/middleware/built-in/auth.js +38 -0
- package/dist/core/middleware/built-in/auth.js.map +1 -0
- package/dist/core/middleware/built-in/cache.d.ts +3 -0
- package/dist/core/middleware/built-in/cache.js +188 -0
- package/dist/core/middleware/built-in/cache.js.map +1 -0
- package/dist/core/middleware/built-in/cdn.d.ts +3 -0
- package/dist/core/middleware/built-in/cdn.js +115 -0
- package/dist/core/middleware/built-in/cdn.js.map +1 -0
- package/dist/core/middleware/built-in/cookie.d.ts +14 -0
- package/dist/core/middleware/built-in/cookie.js +68 -0
- package/dist/core/middleware/built-in/cookie.js.map +1 -0
- package/dist/core/middleware/built-in/cors.d.ts +2 -0
- package/dist/core/middleware/built-in/cors.js +29 -0
- package/dist/core/middleware/built-in/cors.js.map +1 -0
- package/dist/core/middleware/built-in/csp.d.ts +22 -0
- package/dist/core/middleware/built-in/csp.js +74 -0
- package/dist/core/middleware/built-in/csp.js.map +1 -0
- package/dist/core/middleware/built-in/csrf.d.ts +9 -0
- package/dist/core/middleware/built-in/csrf.js +66 -0
- package/dist/core/middleware/built-in/csrf.js.map +1 -0
- package/dist/core/middleware/built-in/error-tracker.d.ts +1 -0
- package/dist/core/middleware/built-in/error-tracker.js +19 -0
- package/dist/core/middleware/built-in/error-tracker.js.map +1 -0
- package/dist/core/middleware/built-in/index.d.ts +70 -0
- package/dist/core/middleware/built-in/index.js +70 -0
- package/dist/core/middleware/built-in/index.js.map +1 -0
- package/dist/core/middleware/built-in/performance-monitor.d.ts +1 -0
- package/dist/core/middleware/built-in/performance-monitor.js +22 -0
- package/dist/core/middleware/built-in/performance-monitor.js.map +1 -0
- package/dist/core/middleware/built-in/rate-limit.d.ts +6 -0
- package/dist/core/middleware/built-in/rate-limit.js +47 -0
- package/dist/core/middleware/built-in/rate-limit.js.map +1 -0
- package/dist/core/middleware/built-in/request-logger.d.ts +1 -0
- package/dist/core/middleware/built-in/request-logger.js +15 -0
- package/dist/core/middleware/built-in/request-logger.js.map +1 -0
- package/dist/core/middleware/built-in/session.d.ts +41 -0
- package/dist/core/middleware/built-in/session.js +209 -0
- package/dist/core/middleware/built-in/session.js.map +1 -0
- package/dist/core/middleware/built-in/sse.d.ts +6 -0
- package/dist/core/middleware/built-in/sse.js +73 -0
- package/dist/core/middleware/built-in/sse.js.map +1 -0
- package/dist/core/middleware/built-in/validation.d.ts +2 -0
- package/dist/core/middleware/built-in/validation.js +31 -0
- package/dist/core/middleware/built-in/validation.js.map +1 -0
- package/dist/core/middleware/index.d.ts +21 -0
- package/dist/core/middleware/index.js +152 -0
- package/dist/core/middleware/index.js.map +1 -0
- package/dist/core/modules/auto-discovery.d.ts +27 -0
- package/dist/core/modules/auto-discovery.js +255 -0
- package/dist/core/modules/auto-discovery.js.map +1 -0
- package/dist/core/modules/index.d.ts +2 -0
- package/dist/core/modules/index.js +11 -0
- package/dist/core/modules/index.js.map +1 -0
- package/dist/core/modules/modules.d.ts +10 -0
- package/dist/core/modules/modules.js +137 -0
- package/dist/core/modules/modules.js.map +1 -0
- package/dist/core/networking/index.d.ts +2 -0
- package/dist/core/networking/index.js +9 -0
- package/dist/core/networking/index.js.map +1 -0
- package/dist/core/networking/service-discovery.d.ts +38 -0
- package/dist/core/networking/service-discovery.js +233 -0
- package/dist/core/networking/service-discovery.js.map +1 -0
- package/dist/core/networking/websocket-manager.d.ts +27 -0
- package/dist/core/networking/websocket-manager.js +211 -0
- package/dist/core/networking/websocket-manager.js.map +1 -0
- package/dist/core/routing/app-integration.d.ts +42 -0
- package/dist/core/routing/app-integration.js +152 -0
- package/dist/core/routing/app-integration.js.map +1 -0
- package/dist/core/routing/index.d.ts +106 -0
- package/dist/core/routing/index.js +343 -0
- package/dist/core/routing/index.js.map +1 -0
- package/dist/core/runtime/aws-lambda-adapter.d.ts +43 -0
- package/dist/core/runtime/aws-lambda-adapter.js +108 -0
- package/dist/core/runtime/aws-lambda-adapter.js.map +1 -0
- package/dist/core/runtime/base-adapter.d.ts +16 -0
- package/dist/core/runtime/base-adapter.js +105 -0
- package/dist/core/runtime/base-adapter.js.map +1 -0
- package/dist/core/runtime/cloudflare-workers-adapter.d.ts +18 -0
- package/dist/core/runtime/cloudflare-workers-adapter.js +131 -0
- package/dist/core/runtime/cloudflare-workers-adapter.js.map +1 -0
- package/dist/core/runtime/index.d.ts +14 -0
- package/dist/core/runtime/index.js +56 -0
- package/dist/core/runtime/index.js.map +1 -0
- package/dist/core/runtime/node-adapter.d.ts +15 -0
- package/dist/core/runtime/node-adapter.js +204 -0
- package/dist/core/runtime/node-adapter.js.map +1 -0
- package/dist/core/runtime/vercel-edge-adapter.d.ts +10 -0
- package/dist/core/runtime/vercel-edge-adapter.js +106 -0
- package/dist/core/runtime/vercel-edge-adapter.js.map +1 -0
- package/dist/core/utilities/circuit-breaker.d.ts +14 -0
- package/dist/core/utilities/circuit-breaker.js +42 -0
- package/dist/core/utilities/circuit-breaker.js.map +1 -0
- package/dist/core/utilities/container.d.ts +116 -0
- package/dist/core/utilities/container.js +529 -0
- package/dist/core/utilities/container.js.map +1 -0
- package/dist/core/utilities/hooks.d.ts +24 -0
- package/dist/core/utilities/hooks.js +131 -0
- package/dist/core/utilities/hooks.js.map +1 -0
- package/dist/core/utilities/index.d.ts +4 -0
- package/dist/core/utilities/index.js +22 -0
- package/dist/core/utilities/index.js.map +1 -0
- package/dist/core/validation/index.d.ts +30 -0
- package/dist/core/validation/index.js +144 -0
- package/dist/core/validation/index.js.map +1 -0
- package/dist/index.d.ts +30 -0
- package/dist/index.js +72 -0
- package/dist/index.js.map +1 -0
- package/dist/moro.d.ts +82 -0
- package/dist/moro.js +679 -0
- package/dist/moro.js.map +1 -0
- package/dist/types/cache.d.ts +34 -0
- package/dist/types/cache.js +3 -0
- package/dist/types/cache.js.map +1 -0
- package/dist/types/cdn.d.ts +19 -0
- package/dist/types/cdn.js +3 -0
- package/dist/types/cdn.js.map +1 -0
- package/dist/types/core.d.ts +13 -0
- package/dist/types/core.js +3 -0
- package/dist/types/core.js.map +1 -0
- package/dist/types/database.d.ts +29 -0
- package/dist/types/database.js +3 -0
- package/dist/types/database.js.map +1 -0
- package/dist/types/discovery.d.ts +6 -0
- package/dist/types/discovery.js +3 -0
- package/dist/types/discovery.js.map +1 -0
- package/dist/types/events.d.ts +116 -0
- package/dist/types/events.js +3 -0
- package/dist/types/events.js.map +1 -0
- package/dist/types/hooks.d.ts +38 -0
- package/dist/types/hooks.js +3 -0
- package/dist/types/hooks.js.map +1 -0
- package/dist/types/http.d.ts +51 -0
- package/dist/types/http.js +3 -0
- package/dist/types/http.js.map +1 -0
- package/dist/types/logger.d.ts +77 -0
- package/dist/types/logger.js +3 -0
- package/dist/types/logger.js.map +1 -0
- package/dist/types/module.d.ts +91 -0
- package/dist/types/module.js +3 -0
- package/dist/types/module.js.map +1 -0
- package/dist/types/runtime.d.ts +48 -0
- package/dist/types/runtime.js +3 -0
- package/dist/types/runtime.js.map +1 -0
- package/dist/types/session.d.ts +66 -0
- package/dist/types/session.js +3 -0
- package/dist/types/session.js.map +1 -0
- package/package.json +176 -0
- package/src/core/config/index.ts +47 -0
- package/src/core/config/loader.ts +366 -0
- package/src/core/config/schema.ts +346 -0
- package/src/core/config/utils.ts +220 -0
- package/src/core/database/README.md +228 -0
- package/src/core/database/adapters/drizzle.ts +425 -0
- package/src/core/database/adapters/index.ts +45 -0
- package/src/core/database/adapters/mongodb.ts +292 -0
- package/src/core/database/adapters/mysql.ts +217 -0
- package/src/core/database/adapters/postgresql.ts +211 -0
- package/src/core/database/adapters/redis.ts +331 -0
- package/src/core/database/adapters/sqlite.ts +255 -0
- package/src/core/database/index.ts +3 -0
- package/src/core/docs/index.ts +245 -0
- package/src/core/docs/openapi-generator.ts +588 -0
- package/src/core/docs/simple-docs.ts +305 -0
- package/src/core/docs/swagger-ui.ts +370 -0
- package/src/core/docs/zod-to-openapi.ts +532 -0
- package/src/core/events/event-bus.ts +249 -0
- package/src/core/events/index.ts +12 -0
- package/src/core/framework.ts +621 -0
- package/src/core/http/http-server.ts +1421 -0
- package/src/core/http/index.ts +11 -0
- package/src/core/http/router.ts +153 -0
- package/src/core/logger/filters.ts +148 -0
- package/src/core/logger/index.ts +20 -0
- package/src/core/logger/logger.ts +434 -0
- package/src/core/logger/outputs.ts +136 -0
- package/src/core/middleware/built-in/adapters/cache/file.ts +106 -0
- package/src/core/middleware/built-in/adapters/cache/index.ts +26 -0
- package/src/core/middleware/built-in/adapters/cache/memory.ts +73 -0
- package/src/core/middleware/built-in/adapters/cache/redis.ts +103 -0
- package/src/core/middleware/built-in/adapters/cdn/azure.ts +68 -0
- package/src/core/middleware/built-in/adapters/cdn/cloudflare.ts +100 -0
- package/src/core/middleware/built-in/adapters/cdn/cloudfront.ts +92 -0
- package/src/core/middleware/built-in/adapters/cdn/index.ts +23 -0
- package/src/core/middleware/built-in/adapters/index.ts +7 -0
- package/src/core/middleware/built-in/auth.ts +39 -0
- package/src/core/middleware/built-in/cache.ts +228 -0
- package/src/core/middleware/built-in/cdn.ts +151 -0
- package/src/core/middleware/built-in/cookie.ts +90 -0
- package/src/core/middleware/built-in/cors.ts +38 -0
- package/src/core/middleware/built-in/csp.ts +107 -0
- package/src/core/middleware/built-in/csrf.ts +87 -0
- package/src/core/middleware/built-in/error-tracker.ts +16 -0
- package/src/core/middleware/built-in/index.ts +57 -0
- package/src/core/middleware/built-in/performance-monitor.ts +25 -0
- package/src/core/middleware/built-in/rate-limit.ts +60 -0
- package/src/core/middleware/built-in/request-logger.ts +14 -0
- package/src/core/middleware/built-in/session.ts +311 -0
- package/src/core/middleware/built-in/sse.ts +91 -0
- package/src/core/middleware/built-in/validation.ts +33 -0
- package/src/core/middleware/index.ts +188 -0
- package/src/core/modules/auto-discovery.ts +265 -0
- package/src/core/modules/index.ts +6 -0
- package/src/core/modules/modules.ts +125 -0
- package/src/core/networking/index.ts +7 -0
- package/src/core/networking/service-discovery.ts +309 -0
- package/src/core/networking/websocket-manager.ts +259 -0
- package/src/core/routing/app-integration.ts +229 -0
- package/src/core/routing/index.ts +519 -0
- package/src/core/runtime/aws-lambda-adapter.ts +157 -0
- package/src/core/runtime/base-adapter.ts +140 -0
- package/src/core/runtime/cloudflare-workers-adapter.ts +166 -0
- package/src/core/runtime/index.ts +74 -0
- package/src/core/runtime/node-adapter.ts +210 -0
- package/src/core/runtime/vercel-edge-adapter.ts +125 -0
- package/src/core/utilities/circuit-breaker.ts +46 -0
- package/src/core/utilities/container.ts +760 -0
- package/src/core/utilities/hooks.ts +148 -0
- package/src/core/utilities/index.ts +16 -0
- package/src/core/validation/index.ts +216 -0
- package/src/index.ts +120 -0
- package/src/moro.ts +842 -0
- package/src/types/cache.ts +38 -0
- package/src/types/cdn.ts +22 -0
- package/src/types/core.ts +17 -0
- package/src/types/database.ts +40 -0
- package/src/types/discovery.ts +7 -0
- package/src/types/events.ts +90 -0
- package/src/types/hooks.ts +47 -0
- package/src/types/http.ts +70 -0
- package/src/types/logger.ts +109 -0
- package/src/types/module.ts +87 -0
- package/src/types/runtime.ts +91 -0
- package/src/types/session.ts +89 -0
- package/tsconfig.json +21 -0
|
@@ -0,0 +1,434 @@
|
|
|
1
|
+
// Moro Logger - Beautiful, Fast, Feature-Rich
|
|
2
|
+
import { performance } from "perf_hooks";
|
|
3
|
+
import {
|
|
4
|
+
LogLevel,
|
|
5
|
+
LogEntry,
|
|
6
|
+
LoggerOptions,
|
|
7
|
+
Logger,
|
|
8
|
+
LogOutput,
|
|
9
|
+
LogFilter,
|
|
10
|
+
LogMetrics,
|
|
11
|
+
ColorScheme,
|
|
12
|
+
} from "../../types/logger";
|
|
13
|
+
|
|
14
|
+
export class MoroLogger implements Logger {
|
|
15
|
+
private level: LogLevel = "info";
|
|
16
|
+
private options: LoggerOptions;
|
|
17
|
+
private outputs: Map<string, LogOutput> = new Map();
|
|
18
|
+
private filters: Map<string, LogFilter> = new Map();
|
|
19
|
+
private history: LogEntry[] = [];
|
|
20
|
+
private timers: Map<string, number> = new Map();
|
|
21
|
+
private metrics: LogMetrics = {
|
|
22
|
+
totalLogs: 0,
|
|
23
|
+
logsByLevel: { debug: 0, info: 0, warn: 0, error: 0, fatal: 0 },
|
|
24
|
+
logsByContext: {},
|
|
25
|
+
averageLogRate: 0,
|
|
26
|
+
errorRate: 0,
|
|
27
|
+
memoryUsage: 0,
|
|
28
|
+
};
|
|
29
|
+
private startTime = Date.now();
|
|
30
|
+
private contextPrefix?: string;
|
|
31
|
+
private contextMetadata?: Record<string, any>;
|
|
32
|
+
|
|
33
|
+
private static readonly LEVELS: Record<LogLevel, number> = {
|
|
34
|
+
debug: 0,
|
|
35
|
+
info: 1,
|
|
36
|
+
warn: 2,
|
|
37
|
+
error: 3,
|
|
38
|
+
fatal: 4,
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
private static readonly COLORS: ColorScheme = {
|
|
42
|
+
debug: "\x1b[36m", // Cyan
|
|
43
|
+
info: "\x1b[32m", // Green
|
|
44
|
+
warn: "\x1b[33m", // Yellow
|
|
45
|
+
error: "\x1b[31m", // Red
|
|
46
|
+
fatal: "\x1b[35m", // Magenta
|
|
47
|
+
timestamp: "\x1b[90m", // Gray
|
|
48
|
+
context: "\x1b[34m", // Blue
|
|
49
|
+
metadata: "\x1b[37m", // White
|
|
50
|
+
performance: "\x1b[36m", // Cyan
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
private static readonly RESET = "\x1b[0m";
|
|
54
|
+
private static readonly BOLD = "\x1b[1m";
|
|
55
|
+
|
|
56
|
+
constructor(options: LoggerOptions = {}) {
|
|
57
|
+
this.options = {
|
|
58
|
+
level: "info",
|
|
59
|
+
enableColors: true,
|
|
60
|
+
enableTimestamp: true,
|
|
61
|
+
enableContext: true,
|
|
62
|
+
enableMetadata: true,
|
|
63
|
+
enablePerformance: true,
|
|
64
|
+
format: "pretty",
|
|
65
|
+
outputs: [],
|
|
66
|
+
filters: [],
|
|
67
|
+
maxEntries: 1000,
|
|
68
|
+
...options,
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
this.level = this.options.level || "info";
|
|
72
|
+
|
|
73
|
+
// Add default console output
|
|
74
|
+
this.addOutput({
|
|
75
|
+
name: "console",
|
|
76
|
+
write: this.writeToConsole.bind(this),
|
|
77
|
+
format: this.options.format,
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
// Add custom outputs
|
|
81
|
+
this.options.outputs?.forEach((output) => this.addOutput(output));
|
|
82
|
+
this.options.filters?.forEach((filter) => this.addFilter(filter));
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
debug(
|
|
86
|
+
message: string,
|
|
87
|
+
context?: string,
|
|
88
|
+
metadata?: Record<string, any>,
|
|
89
|
+
): void {
|
|
90
|
+
this.log("debug", message, context, metadata);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
info(
|
|
94
|
+
message: string,
|
|
95
|
+
context?: string,
|
|
96
|
+
metadata?: Record<string, any>,
|
|
97
|
+
): void {
|
|
98
|
+
this.log("info", message, context, metadata);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
warn(
|
|
102
|
+
message: string,
|
|
103
|
+
context?: string,
|
|
104
|
+
metadata?: Record<string, any>,
|
|
105
|
+
): void {
|
|
106
|
+
this.log("warn", message, context, metadata);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
error(
|
|
110
|
+
message: string | Error,
|
|
111
|
+
context?: string,
|
|
112
|
+
metadata?: Record<string, any>,
|
|
113
|
+
): void {
|
|
114
|
+
const msg = message instanceof Error ? message.message : message;
|
|
115
|
+
const stack = message instanceof Error ? message.stack : undefined;
|
|
116
|
+
this.log("error", msg, context, { ...metadata, stack });
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
fatal(
|
|
120
|
+
message: string | Error,
|
|
121
|
+
context?: string,
|
|
122
|
+
metadata?: Record<string, any>,
|
|
123
|
+
): void {
|
|
124
|
+
const msg = message instanceof Error ? message.message : message;
|
|
125
|
+
const stack = message instanceof Error ? message.stack : undefined;
|
|
126
|
+
this.log("fatal", msg, context, { ...metadata, stack });
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
time(label: string): void {
|
|
130
|
+
this.timers.set(label, performance.now());
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
timeEnd(
|
|
134
|
+
label: string,
|
|
135
|
+
context?: string,
|
|
136
|
+
metadata?: Record<string, any>,
|
|
137
|
+
): void {
|
|
138
|
+
const startTime = this.timers.get(label);
|
|
139
|
+
if (startTime !== undefined) {
|
|
140
|
+
const duration = performance.now() - startTime;
|
|
141
|
+
this.timers.delete(label);
|
|
142
|
+
|
|
143
|
+
this.log("info", `Timer: ${label}`, context, {
|
|
144
|
+
...metadata,
|
|
145
|
+
performance: { duration: Math.round(duration * 100) / 100 },
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
child(context: string, metadata?: Record<string, any>): Logger {
|
|
151
|
+
const childLogger = new MoroLogger(this.options);
|
|
152
|
+
childLogger.contextPrefix = this.contextPrefix
|
|
153
|
+
? `${this.contextPrefix}:${context}`
|
|
154
|
+
: context;
|
|
155
|
+
childLogger.contextMetadata = { ...this.contextMetadata, ...metadata };
|
|
156
|
+
childLogger.outputs = this.outputs;
|
|
157
|
+
childLogger.filters = this.filters;
|
|
158
|
+
return childLogger;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
setLevel(level: LogLevel): void {
|
|
162
|
+
this.level = level;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
addOutput(output: LogOutput): void {
|
|
166
|
+
this.outputs.set(output.name, output);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
removeOutput(name: string): void {
|
|
170
|
+
this.outputs.delete(name);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
addFilter(filter: LogFilter): void {
|
|
174
|
+
this.filters.set(filter.name, filter);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
removeFilter(name: string): void {
|
|
178
|
+
this.filters.delete(name);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
getHistory(count?: number): LogEntry[] {
|
|
182
|
+
const entries = [...this.history];
|
|
183
|
+
return count ? entries.slice(-count) : entries;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
getMetrics(): LogMetrics {
|
|
187
|
+
const now = Date.now();
|
|
188
|
+
const uptime = (now - this.startTime) / 1000; // seconds
|
|
189
|
+
const avgRate = uptime > 0 ? this.metrics.totalLogs / uptime : 0;
|
|
190
|
+
const errorCount =
|
|
191
|
+
this.metrics.logsByLevel.error + this.metrics.logsByLevel.fatal;
|
|
192
|
+
const errorRate =
|
|
193
|
+
this.metrics.totalLogs > 0
|
|
194
|
+
? (errorCount / this.metrics.totalLogs) * 100
|
|
195
|
+
: 0;
|
|
196
|
+
|
|
197
|
+
return {
|
|
198
|
+
...this.metrics,
|
|
199
|
+
averageLogRate: Math.round(avgRate * 100) / 100,
|
|
200
|
+
errorRate: Math.round(errorRate * 100) / 100,
|
|
201
|
+
memoryUsage: process.memoryUsage().heapUsed / 1024 / 1024, // MB
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
clear(): void {
|
|
206
|
+
this.history = [];
|
|
207
|
+
this.metrics = {
|
|
208
|
+
totalLogs: 0,
|
|
209
|
+
logsByLevel: { debug: 0, info: 0, warn: 0, error: 0, fatal: 0 },
|
|
210
|
+
logsByContext: {},
|
|
211
|
+
averageLogRate: 0,
|
|
212
|
+
errorRate: 0,
|
|
213
|
+
memoryUsage: 0,
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
private log(
|
|
218
|
+
level: LogLevel,
|
|
219
|
+
message: string,
|
|
220
|
+
context?: string,
|
|
221
|
+
metadata?: Record<string, any>,
|
|
222
|
+
): void {
|
|
223
|
+
// Check level threshold
|
|
224
|
+
if (MoroLogger.LEVELS[level] < MoroLogger.LEVELS[this.level]) {
|
|
225
|
+
return;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
// Create log entry
|
|
229
|
+
const entry: LogEntry = {
|
|
230
|
+
timestamp: new Date(),
|
|
231
|
+
level,
|
|
232
|
+
message,
|
|
233
|
+
context: this.contextPrefix
|
|
234
|
+
? context
|
|
235
|
+
? `${this.contextPrefix}:${context}`
|
|
236
|
+
: this.contextPrefix
|
|
237
|
+
: context,
|
|
238
|
+
metadata: { ...this.contextMetadata, ...metadata },
|
|
239
|
+
performance: this.options.enablePerformance
|
|
240
|
+
? {
|
|
241
|
+
memory: process.memoryUsage().heapUsed / 1024 / 1024,
|
|
242
|
+
}
|
|
243
|
+
: undefined,
|
|
244
|
+
};
|
|
245
|
+
|
|
246
|
+
// Apply filters
|
|
247
|
+
for (const filter of this.filters.values()) {
|
|
248
|
+
if (!filter.filter(entry)) {
|
|
249
|
+
return;
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
// Update metrics
|
|
254
|
+
this.updateMetrics(entry);
|
|
255
|
+
|
|
256
|
+
// Store in history
|
|
257
|
+
this.history.push(entry);
|
|
258
|
+
if (this.history.length > (this.options.maxEntries || 1000)) {
|
|
259
|
+
this.history.shift();
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
// Write to outputs
|
|
263
|
+
for (const output of this.outputs.values()) {
|
|
264
|
+
if (
|
|
265
|
+
!output.level ||
|
|
266
|
+
MoroLogger.LEVELS[level] >= MoroLogger.LEVELS[output.level]
|
|
267
|
+
) {
|
|
268
|
+
try {
|
|
269
|
+
output.write(entry);
|
|
270
|
+
} catch (error) {
|
|
271
|
+
console.error("Logger output error:", error);
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
private updateMetrics(entry: LogEntry): void {
|
|
278
|
+
this.metrics.totalLogs++;
|
|
279
|
+
this.metrics.logsByLevel[entry.level]++;
|
|
280
|
+
|
|
281
|
+
if (entry.context) {
|
|
282
|
+
this.metrics.logsByContext[entry.context] =
|
|
283
|
+
(this.metrics.logsByContext[entry.context] || 0) + 1;
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
private writeToConsole(entry: LogEntry): void {
|
|
288
|
+
const format = this.options.format || "pretty";
|
|
289
|
+
|
|
290
|
+
if (format === "json") {
|
|
291
|
+
console.log(JSON.stringify(entry));
|
|
292
|
+
return;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
if (format === "compact") {
|
|
296
|
+
const level = entry.level.toUpperCase().padEnd(5);
|
|
297
|
+
const context = entry.context ? `[${entry.context}] ` : "";
|
|
298
|
+
console.log(`${level} ${context}${entry.message}`);
|
|
299
|
+
return;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
// Pretty format (default)
|
|
303
|
+
this.writePrettyLog(entry);
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
private writePrettyLog(entry: LogEntry): void {
|
|
307
|
+
const colors = this.options.enableColors !== false;
|
|
308
|
+
const parts: string[] = [];
|
|
309
|
+
|
|
310
|
+
// Timestamp
|
|
311
|
+
if (this.options.enableTimestamp !== false) {
|
|
312
|
+
const timestamp = entry.timestamp
|
|
313
|
+
.toISOString()
|
|
314
|
+
.replace("T", " ")
|
|
315
|
+
.slice(0, 19);
|
|
316
|
+
parts.push(
|
|
317
|
+
colors
|
|
318
|
+
? `${MoroLogger.COLORS.timestamp}${timestamp}${MoroLogger.RESET}`
|
|
319
|
+
: timestamp,
|
|
320
|
+
);
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
// Level with color (remove icons)
|
|
324
|
+
const levelColor = colors ? MoroLogger.COLORS[entry.level] : "";
|
|
325
|
+
const levelReset = colors ? MoroLogger.RESET : "";
|
|
326
|
+
const levelText = entry.level.toUpperCase();
|
|
327
|
+
parts.push(`${levelColor}${MoroLogger.BOLD}${levelText}${levelReset}`);
|
|
328
|
+
|
|
329
|
+
// Context
|
|
330
|
+
if (entry.context && this.options.enableContext !== false) {
|
|
331
|
+
const contextColor = colors ? MoroLogger.COLORS.context : "";
|
|
332
|
+
parts.push(`${contextColor}[${entry.context}]${levelReset}`);
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
// Message
|
|
336
|
+
parts.push(entry.message);
|
|
337
|
+
|
|
338
|
+
// Performance info
|
|
339
|
+
if (entry.performance && this.options.enablePerformance !== false) {
|
|
340
|
+
const perfColor = colors ? MoroLogger.COLORS.performance : "";
|
|
341
|
+
const perfParts: string[] = [];
|
|
342
|
+
|
|
343
|
+
if (entry.performance.duration !== undefined) {
|
|
344
|
+
perfParts.push(`${entry.performance.duration}ms`);
|
|
345
|
+
}
|
|
346
|
+
if (entry.performance.memory !== undefined) {
|
|
347
|
+
perfParts.push(`${Math.round(entry.performance.memory)}MB`);
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
if (perfParts.length > 0) {
|
|
351
|
+
parts.push(`${perfColor}(${perfParts.join(", ")})${levelReset}`);
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
// Metadata
|
|
356
|
+
if (
|
|
357
|
+
entry.metadata &&
|
|
358
|
+
Object.keys(entry.metadata).length > 0 &&
|
|
359
|
+
this.options.enableMetadata !== false
|
|
360
|
+
) {
|
|
361
|
+
const metaColor = colors ? MoroLogger.COLORS.metadata : "";
|
|
362
|
+
const cleanMetadata = { ...entry.metadata };
|
|
363
|
+
delete cleanMetadata.stack; // Handle stack separately
|
|
364
|
+
|
|
365
|
+
if (Object.keys(cleanMetadata).length > 0) {
|
|
366
|
+
parts.push(`${metaColor}${JSON.stringify(cleanMetadata)}${levelReset}`);
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
// Output main log line
|
|
371
|
+
console.log(parts.join(" "));
|
|
372
|
+
|
|
373
|
+
// Stack trace for errors
|
|
374
|
+
if (
|
|
375
|
+
entry.metadata?.stack &&
|
|
376
|
+
(entry.level === "error" || entry.level === "fatal")
|
|
377
|
+
) {
|
|
378
|
+
const stackColor = colors ? MoroLogger.COLORS.error : "";
|
|
379
|
+
console.log(`${stackColor}${entry.metadata.stack}${levelReset}`);
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
// Global logger instance
|
|
385
|
+
const initialLogLevel =
|
|
386
|
+
process.env.LOG_LEVEL ||
|
|
387
|
+
process.env.MORO_LOG_LEVEL ||
|
|
388
|
+
(process.env.NODE_ENV === "production" ? "warn" : "debug");
|
|
389
|
+
|
|
390
|
+
export const logger = new MoroLogger({
|
|
391
|
+
level: initialLogLevel as LogLevel,
|
|
392
|
+
enableColors: !process.env.NO_COLOR,
|
|
393
|
+
format: (process.env.LOG_FORMAT as any) || "pretty",
|
|
394
|
+
});
|
|
395
|
+
|
|
396
|
+
/**
|
|
397
|
+
* Configure the global logger with new settings
|
|
398
|
+
* This allows runtime configuration of the logger
|
|
399
|
+
*/
|
|
400
|
+
export function configureGlobalLogger(options: Partial<LoggerOptions>): void {
|
|
401
|
+
if (options.level) {
|
|
402
|
+
logger.setLevel(options.level);
|
|
403
|
+
}
|
|
404
|
+
// Additional configuration options can be added here as needed
|
|
405
|
+
// For now, focusing on level which is the most critical
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
/**
|
|
409
|
+
* Apply logging configuration from the config system and/or createApp options
|
|
410
|
+
*/
|
|
411
|
+
export function applyLoggingConfiguration(
|
|
412
|
+
configLogging?: any,
|
|
413
|
+
appOptions?: Partial<LoggerOptions> | boolean,
|
|
414
|
+
): void {
|
|
415
|
+
// First apply config system settings (from environment variables)
|
|
416
|
+
if (configLogging?.level) {
|
|
417
|
+
configureGlobalLogger({ level: configLogging.level });
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
// Then apply createApp options (these take precedence)
|
|
421
|
+
if (appOptions !== undefined) {
|
|
422
|
+
if (appOptions === false) {
|
|
423
|
+
// Disable logging by setting to fatal level
|
|
424
|
+
configureGlobalLogger({ level: "fatal" });
|
|
425
|
+
} else if (typeof appOptions === "object") {
|
|
426
|
+
configureGlobalLogger(appOptions);
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
// Framework-specific logger
|
|
432
|
+
export const createFrameworkLogger = (context: string) => {
|
|
433
|
+
return logger.child("Moro", { framework: "moro", context });
|
|
434
|
+
};
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
// Advanced Logger Outputs
|
|
2
|
+
import { writeFile, appendFile, mkdir } from "fs/promises";
|
|
3
|
+
import { join, dirname } from "path";
|
|
4
|
+
import { LogEntry, LogOutput } from "../../types/logger";
|
|
5
|
+
|
|
6
|
+
// File output for persistent logging
|
|
7
|
+
export class FileOutput implements LogOutput {
|
|
8
|
+
name = "file";
|
|
9
|
+
|
|
10
|
+
constructor(
|
|
11
|
+
private filePath: string,
|
|
12
|
+
private options: {
|
|
13
|
+
format?: "json" | "pretty";
|
|
14
|
+
maxSize?: number; // MB
|
|
15
|
+
rotate?: boolean;
|
|
16
|
+
} = {},
|
|
17
|
+
) {}
|
|
18
|
+
|
|
19
|
+
async write(entry: LogEntry): Promise<void> {
|
|
20
|
+
try {
|
|
21
|
+
// Ensure directory exists
|
|
22
|
+
await mkdir(dirname(this.filePath), { recursive: true });
|
|
23
|
+
|
|
24
|
+
const format = this.options.format || "json";
|
|
25
|
+
const line =
|
|
26
|
+
format === "json"
|
|
27
|
+
? JSON.stringify(entry) + "\n"
|
|
28
|
+
: this.formatPretty(entry) + "\n";
|
|
29
|
+
|
|
30
|
+
await appendFile(this.filePath, line, "utf8");
|
|
31
|
+
|
|
32
|
+
// TODO: Implement log rotation if needed
|
|
33
|
+
} catch (error) {
|
|
34
|
+
console.error("File logger error:", error);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
private formatPretty(entry: LogEntry): string {
|
|
39
|
+
const timestamp = entry.timestamp.toISOString();
|
|
40
|
+
const level = entry.level.toUpperCase().padEnd(5);
|
|
41
|
+
const context = entry.context ? `[${entry.context}] ` : "";
|
|
42
|
+
const metadata =
|
|
43
|
+
entry.metadata && Object.keys(entry.metadata).length > 0
|
|
44
|
+
? ` ${JSON.stringify(entry.metadata)}`
|
|
45
|
+
: "";
|
|
46
|
+
|
|
47
|
+
return `${timestamp} ${level} ${context}${entry.message}${metadata}`;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// HTTP webhook output for external logging services
|
|
52
|
+
export class WebhookOutput implements LogOutput {
|
|
53
|
+
name = "webhook";
|
|
54
|
+
|
|
55
|
+
constructor(
|
|
56
|
+
private url: string,
|
|
57
|
+
private options: {
|
|
58
|
+
headers?: Record<string, string>;
|
|
59
|
+
batch?: boolean;
|
|
60
|
+
batchSize?: number;
|
|
61
|
+
timeout?: number;
|
|
62
|
+
} = {},
|
|
63
|
+
) {}
|
|
64
|
+
|
|
65
|
+
async write(entry: LogEntry): Promise<void> {
|
|
66
|
+
try {
|
|
67
|
+
const response = await fetch(this.url, {
|
|
68
|
+
method: "POST",
|
|
69
|
+
headers: {
|
|
70
|
+
"Content-Type": "application/json",
|
|
71
|
+
...this.options.headers,
|
|
72
|
+
},
|
|
73
|
+
body: JSON.stringify(entry),
|
|
74
|
+
signal: AbortSignal.timeout(this.options.timeout || 5000),
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
if (!response.ok) {
|
|
78
|
+
throw new Error(`Webhook failed: ${response.status}`);
|
|
79
|
+
}
|
|
80
|
+
} catch (error) {
|
|
81
|
+
console.error("Webhook logger error:", error);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// Memory buffer output for testing and debugging
|
|
87
|
+
export class MemoryOutput implements LogOutput {
|
|
88
|
+
name = "memory";
|
|
89
|
+
private buffer: LogEntry[] = [];
|
|
90
|
+
|
|
91
|
+
constructor(private maxSize: number = 1000) {}
|
|
92
|
+
|
|
93
|
+
write(entry: LogEntry): void {
|
|
94
|
+
this.buffer.push(entry);
|
|
95
|
+
if (this.buffer.length > this.maxSize) {
|
|
96
|
+
this.buffer.shift();
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
getEntries(): LogEntry[] {
|
|
101
|
+
return [...this.buffer];
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
clear(): void {
|
|
105
|
+
this.buffer = [];
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// Stream output for custom processing
|
|
110
|
+
export class StreamOutput implements LogOutput {
|
|
111
|
+
name = "stream";
|
|
112
|
+
format?: "pretty" | "json" | "compact";
|
|
113
|
+
|
|
114
|
+
constructor(
|
|
115
|
+
private stream: NodeJS.WritableStream,
|
|
116
|
+
format: "json" | "pretty" = "json",
|
|
117
|
+
) {
|
|
118
|
+
this.format = format;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
write(entry: LogEntry): void {
|
|
122
|
+
const data =
|
|
123
|
+
this.format === "json"
|
|
124
|
+
? JSON.stringify(entry) + "\n"
|
|
125
|
+
: this.formatPretty(entry) + "\n";
|
|
126
|
+
|
|
127
|
+
this.stream.write(data);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
private formatPretty(entry: LogEntry): string {
|
|
131
|
+
const timestamp = entry.timestamp.toISOString();
|
|
132
|
+
const level = entry.level.toUpperCase().padEnd(5);
|
|
133
|
+
const context = entry.context ? `[${entry.context}] ` : "";
|
|
134
|
+
return `${timestamp} ${level} ${context}${entry.message}`;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
// File System Cache Adapter
|
|
2
|
+
import { CacheAdapter } from "../../../../../types/cache";
|
|
3
|
+
import { createFrameworkLogger } from "../../../../logger";
|
|
4
|
+
|
|
5
|
+
const logger = createFrameworkLogger("FileCacheAdapter");
|
|
6
|
+
|
|
7
|
+
export class FileCacheAdapter implements CacheAdapter {
|
|
8
|
+
private cacheDir: string;
|
|
9
|
+
|
|
10
|
+
constructor(options: { cacheDir?: string } = {}) {
|
|
11
|
+
this.cacheDir = options.cacheDir || "./cache";
|
|
12
|
+
this.ensureCacheDir();
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
private async ensureCacheDir(): Promise<void> {
|
|
16
|
+
const fs = await import("fs/promises");
|
|
17
|
+
try {
|
|
18
|
+
await fs.mkdir(this.cacheDir, { recursive: true });
|
|
19
|
+
} catch (error) {
|
|
20
|
+
logger.error("Failed to create cache directory", "FileCache", { error });
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
private getFilePath(key: string): string {
|
|
25
|
+
const crypto = require("crypto");
|
|
26
|
+
const hash = crypto.createHash("md5").update(key).digest("hex");
|
|
27
|
+
return `${this.cacheDir}/${hash}.json`;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
async get(key: string): Promise<any> {
|
|
31
|
+
try {
|
|
32
|
+
const fs = await import("fs/promises");
|
|
33
|
+
const filePath = this.getFilePath(key);
|
|
34
|
+
const data = await fs.readFile(filePath, "utf-8");
|
|
35
|
+
const parsed = JSON.parse(data);
|
|
36
|
+
|
|
37
|
+
if (Date.now() > parsed.expires) {
|
|
38
|
+
await this.del(key);
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return parsed.value;
|
|
43
|
+
} catch (error) {
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
async set(key: string, value: any, ttl: number = 3600): Promise<void> {
|
|
49
|
+
try {
|
|
50
|
+
const fs = await import("fs/promises");
|
|
51
|
+
const filePath = this.getFilePath(key);
|
|
52
|
+
const expires = Date.now() + ttl * 1000;
|
|
53
|
+
const data = JSON.stringify({ value, expires });
|
|
54
|
+
|
|
55
|
+
await fs.writeFile(filePath, data);
|
|
56
|
+
logger.debug(`Cached item to file: ${key} (TTL: ${ttl}s)`, "FileCache");
|
|
57
|
+
} catch (error) {
|
|
58
|
+
logger.error("File cache set error", "FileCache", { key, error });
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
async del(key: string): Promise<void> {
|
|
63
|
+
try {
|
|
64
|
+
const fs = await import("fs/promises");
|
|
65
|
+
const filePath = this.getFilePath(key);
|
|
66
|
+
await fs.unlink(filePath);
|
|
67
|
+
logger.debug(`Deleted file cache item: ${key}`, "FileCache");
|
|
68
|
+
} catch (error) {
|
|
69
|
+
// File might not exist, which is okay
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
async clear(): Promise<void> {
|
|
74
|
+
try {
|
|
75
|
+
const fs = await import("fs/promises");
|
|
76
|
+
const files = await fs.readdir(this.cacheDir);
|
|
77
|
+
|
|
78
|
+
await Promise.all(
|
|
79
|
+
files.map((file) => fs.unlink(`${this.cacheDir}/${file}`)),
|
|
80
|
+
);
|
|
81
|
+
|
|
82
|
+
logger.debug("Cleared all file cache items", "FileCache");
|
|
83
|
+
} catch (error) {
|
|
84
|
+
logger.error("File cache clear error", "FileCache", { error });
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
async exists(key: string): Promise<boolean> {
|
|
89
|
+
const value = await this.get(key);
|
|
90
|
+
return value !== null;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
async ttl(key: string): Promise<number> {
|
|
94
|
+
try {
|
|
95
|
+
const fs = await import("fs/promises");
|
|
96
|
+
const filePath = this.getFilePath(key);
|
|
97
|
+
const data = await fs.readFile(filePath, "utf-8");
|
|
98
|
+
const parsed = JSON.parse(data);
|
|
99
|
+
|
|
100
|
+
const remaining = Math.floor((parsed.expires - Date.now()) / 1000);
|
|
101
|
+
return remaining > 0 ? remaining : -1;
|
|
102
|
+
} catch (error) {
|
|
103
|
+
return -1;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
// Cache Adapters
|
|
2
|
+
export { MemoryCacheAdapter } from "./memory";
|
|
3
|
+
export { RedisCacheAdapter } from "./redis";
|
|
4
|
+
export { FileCacheAdapter } from "./file";
|
|
5
|
+
|
|
6
|
+
import { MemoryCacheAdapter } from "./memory";
|
|
7
|
+
import { RedisCacheAdapter } from "./redis";
|
|
8
|
+
import { FileCacheAdapter } from "./file";
|
|
9
|
+
import { CacheAdapter } from "../../../../../types/cache";
|
|
10
|
+
|
|
11
|
+
// Adapter factory function for auto-loading
|
|
12
|
+
export function createCacheAdapter(
|
|
13
|
+
type: string,
|
|
14
|
+
options: any = {},
|
|
15
|
+
): CacheAdapter {
|
|
16
|
+
switch (type.toLowerCase()) {
|
|
17
|
+
case "memory":
|
|
18
|
+
return new MemoryCacheAdapter();
|
|
19
|
+
case "redis":
|
|
20
|
+
return new RedisCacheAdapter(options);
|
|
21
|
+
case "file":
|
|
22
|
+
return new FileCacheAdapter(options);
|
|
23
|
+
default:
|
|
24
|
+
throw new Error(`Unknown cache adapter type: ${type}`);
|
|
25
|
+
}
|
|
26
|
+
}
|