@morojs/moro 1.6.1 → 1.6.2
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/README.md +74 -256
- package/dist/core/auth/morojs-adapter.js +20 -20
- package/dist/core/auth/morojs-adapter.js.map +1 -1
- package/dist/core/config/config-manager.d.ts +44 -0
- package/dist/core/config/config-manager.js +104 -0
- package/dist/core/config/config-manager.js.map +1 -0
- package/dist/core/config/config-sources.d.ts +21 -0
- package/dist/core/config/config-sources.js +503 -0
- package/dist/core/config/config-sources.js.map +1 -0
- package/dist/core/config/config-validator.d.ts +21 -0
- package/dist/core/config/config-validator.js +791 -0
- package/dist/core/config/config-validator.js.map +1 -0
- package/dist/core/config/file-loader.d.ts +1 -6
- package/dist/core/config/file-loader.js +21 -249
- package/dist/core/config/file-loader.js.map +1 -1
- package/dist/core/config/index.d.ts +41 -12
- package/dist/core/config/index.js +65 -54
- package/dist/core/config/index.js.map +1 -1
- package/dist/core/config/schema.d.ts +2 -2
- package/dist/core/config/schema.js +55 -44
- package/dist/core/config/schema.js.map +1 -1
- package/dist/core/config/utils.d.ts +10 -3
- package/dist/core/config/utils.js +31 -58
- package/dist/core/config/utils.js.map +1 -1
- package/dist/core/database/adapters/drizzle.d.ts +1 -1
- package/dist/core/database/adapters/drizzle.js +18 -11
- package/dist/core/database/adapters/drizzle.js.map +1 -1
- package/dist/core/database/adapters/index.d.ts +7 -7
- package/dist/core/database/adapters/index.js +19 -29
- package/dist/core/database/adapters/index.js.map +1 -1
- package/dist/core/database/adapters/mongodb.d.ts +13 -1
- package/dist/core/database/adapters/mongodb.js +46 -10
- package/dist/core/database/adapters/mongodb.js.map +1 -1
- package/dist/core/database/adapters/mysql.d.ts +14 -1
- package/dist/core/database/adapters/mysql.js +19 -9
- package/dist/core/database/adapters/mysql.js.map +1 -1
- package/dist/core/database/adapters/postgresql.d.ts +12 -2
- package/dist/core/database/adapters/postgresql.js +19 -9
- package/dist/core/database/adapters/postgresql.js.map +1 -1
- package/dist/core/database/adapters/redis.d.ts +12 -1
- package/dist/core/database/adapters/redis.js +48 -13
- package/dist/core/database/adapters/redis.js.map +1 -1
- package/dist/core/database/adapters/sqlite.d.ts +3 -1
- package/dist/core/database/adapters/sqlite.js +19 -8
- package/dist/core/database/adapters/sqlite.js.map +1 -1
- package/dist/core/database/index.d.ts +2 -2
- package/dist/core/database/index.js +2 -18
- package/dist/core/database/index.js.map +1 -1
- package/dist/core/docs/index.d.ts +9 -9
- package/dist/core/docs/index.js +14 -35
- package/dist/core/docs/index.js.map +1 -1
- package/dist/core/docs/openapi-generator.d.ts +2 -2
- package/dist/core/docs/openapi-generator.js +11 -16
- package/dist/core/docs/openapi-generator.js.map +1 -1
- package/dist/core/docs/schema-to-openapi.d.ts +2 -2
- package/dist/core/docs/schema-to-openapi.js +5 -11
- package/dist/core/docs/schema-to-openapi.js.map +1 -1
- package/dist/core/docs/simple-docs.d.ts +1 -1
- package/dist/core/docs/simple-docs.js +4 -9
- package/dist/core/docs/simple-docs.js.map +1 -1
- package/dist/core/docs/swagger-ui.d.ts +2 -2
- package/dist/core/docs/swagger-ui.js +26 -29
- package/dist/core/docs/swagger-ui.js.map +1 -1
- package/dist/core/docs/zod-to-openapi.js +31 -28
- package/dist/core/docs/zod-to-openapi.js.map +1 -1
- package/dist/core/events/event-bus.d.ts +1 -1
- package/dist/core/events/event-bus.js +7 -11
- package/dist/core/events/event-bus.js.map +1 -1
- package/dist/core/events/index.d.ts +2 -2
- package/dist/core/events/index.js +1 -5
- package/dist/core/events/index.js.map +1 -1
- package/dist/core/framework.d.ts +20 -13
- package/dist/core/framework.js +285 -102
- package/dist/core/framework.js.map +1 -1
- package/dist/core/http/http-server.d.ts +59 -7
- package/dist/core/http/http-server.js +190 -176
- package/dist/core/http/http-server.js.map +1 -1
- package/dist/core/http/index.d.ts +4 -3
- package/dist/core/http/index.js +3 -8
- package/dist/core/http/index.js.map +1 -1
- package/dist/core/http/uws-http-server.d.ts +46 -0
- package/dist/core/http/uws-http-server.js +523 -0
- package/dist/core/http/uws-http-server.js.map +1 -0
- package/dist/core/logger/filters.d.ts +1 -1
- package/dist/core/logger/filters.js +20 -23
- package/dist/core/logger/filters.js.map +1 -1
- package/dist/core/logger/index.d.ts +3 -3
- package/dist/core/logger/index.js +2 -24
- package/dist/core/logger/index.js.map +1 -1
- package/dist/core/logger/logger.d.ts +30 -14
- package/dist/core/logger/logger.js +398 -223
- package/dist/core/logger/logger.js.map +1 -1
- package/dist/core/logger/outputs.d.ts +1 -1
- package/dist/core/logger/outputs.js +8 -17
- package/dist/core/logger/outputs.js.map +1 -1
- package/dist/core/middleware/built-in/adapters/cache/file.d.ts +1 -1
- package/dist/core/middleware/built-in/adapters/cache/file.js +10 -47
- package/dist/core/middleware/built-in/adapters/cache/file.js.map +1 -1
- package/dist/core/middleware/built-in/adapters/cache/index.d.ts +4 -4
- package/dist/core/middleware/built-in/adapters/cache/index.js +10 -17
- package/dist/core/middleware/built-in/adapters/cache/index.js.map +1 -1
- package/dist/core/middleware/built-in/adapters/cache/memory.d.ts +1 -1
- package/dist/core/middleware/built-in/adapters/cache/memory.js +3 -7
- package/dist/core/middleware/built-in/adapters/cache/memory.js.map +1 -1
- package/dist/core/middleware/built-in/adapters/cache/redis.d.ts +3 -1
- package/dist/core/middleware/built-in/adapters/cache/redis.js +11 -9
- package/dist/core/middleware/built-in/adapters/cache/redis.js.map +1 -1
- package/dist/core/middleware/built-in/adapters/cdn/azure.d.ts +1 -1
- package/dist/core/middleware/built-in/adapters/cdn/azure.js +3 -7
- package/dist/core/middleware/built-in/adapters/cdn/azure.js.map +1 -1
- package/dist/core/middleware/built-in/adapters/cdn/cloudflare.d.ts +1 -1
- package/dist/core/middleware/built-in/adapters/cdn/cloudflare.js +3 -7
- package/dist/core/middleware/built-in/adapters/cdn/cloudflare.js.map +1 -1
- package/dist/core/middleware/built-in/adapters/cdn/cloudfront.d.ts +3 -1
- package/dist/core/middleware/built-in/adapters/cdn/cloudfront.js +12 -10
- package/dist/core/middleware/built-in/adapters/cdn/cloudfront.js.map +1 -1
- package/dist/core/middleware/built-in/adapters/cdn/index.d.ts +4 -4
- package/dist/core/middleware/built-in/adapters/cdn/index.js +10 -17
- package/dist/core/middleware/built-in/adapters/cdn/index.js.map +1 -1
- package/dist/core/middleware/built-in/adapters/index.d.ts +4 -4
- package/dist/core/middleware/built-in/adapters/index.js +4 -23
- package/dist/core/middleware/built-in/adapters/index.js.map +1 -1
- package/dist/core/middleware/built-in/auth-helpers.js +11 -22
- package/dist/core/middleware/built-in/auth-helpers.js.map +1 -1
- package/dist/core/middleware/built-in/auth-providers.d.ts +1 -1
- package/dist/core/middleware/built-in/auth-providers.js +4 -9
- package/dist/core/middleware/built-in/auth-providers.js.map +1 -1
- package/dist/core/middleware/built-in/auth.d.ts +2 -2
- package/dist/core/middleware/built-in/auth.js +93 -26
- package/dist/core/middleware/built-in/auth.js.map +1 -1
- package/dist/core/middleware/built-in/cache.d.ts +2 -2
- package/dist/core/middleware/built-in/cache.js +11 -12
- package/dist/core/middleware/built-in/cache.js.map +1 -1
- package/dist/core/middleware/built-in/cdn.d.ts +2 -2
- package/dist/core/middleware/built-in/cdn.js +5 -9
- package/dist/core/middleware/built-in/cdn.js.map +1 -1
- package/dist/core/middleware/built-in/cookie.d.ts +1 -1
- package/dist/core/middleware/built-in/cookie.js +3 -7
- package/dist/core/middleware/built-in/cookie.js.map +1 -1
- package/dist/core/middleware/built-in/cors.d.ts +1 -1
- package/dist/core/middleware/built-in/cors.js +3 -7
- package/dist/core/middleware/built-in/cors.js.map +1 -1
- package/dist/core/middleware/built-in/csp.d.ts +1 -1
- package/dist/core/middleware/built-in/csp.js +5 -8
- package/dist/core/middleware/built-in/csp.js.map +1 -1
- package/dist/core/middleware/built-in/csrf.d.ts +1 -1
- package/dist/core/middleware/built-in/csrf.js +5 -8
- package/dist/core/middleware/built-in/csrf.js.map +1 -1
- package/dist/core/middleware/built-in/error-tracker.js +3 -7
- package/dist/core/middleware/built-in/error-tracker.js.map +1 -1
- package/dist/core/middleware/built-in/index.d.ts +28 -27
- package/dist/core/middleware/built-in/index.js +48 -78
- package/dist/core/middleware/built-in/index.js.map +1 -1
- package/dist/core/middleware/built-in/jwt-helpers.d.ts +118 -0
- package/dist/core/middleware/built-in/jwt-helpers.js +218 -0
- package/dist/core/middleware/built-in/jwt-helpers.js.map +1 -0
- package/dist/core/middleware/built-in/performance-monitor.js +3 -7
- package/dist/core/middleware/built-in/performance-monitor.js.map +1 -1
- package/dist/core/middleware/built-in/rate-limit.d.ts +1 -1
- package/dist/core/middleware/built-in/rate-limit.js +3 -7
- package/dist/core/middleware/built-in/rate-limit.js.map +1 -1
- package/dist/core/middleware/built-in/request-logger.js +5 -8
- package/dist/core/middleware/built-in/request-logger.js.map +1 -1
- package/dist/core/middleware/built-in/session.d.ts +2 -2
- package/dist/core/middleware/built-in/session.js +11 -15
- package/dist/core/middleware/built-in/session.js.map +1 -1
- package/dist/core/middleware/built-in/sse.d.ts +1 -1
- package/dist/core/middleware/built-in/sse.js +12 -14
- package/dist/core/middleware/built-in/sse.js.map +1 -1
- package/dist/core/middleware/built-in/validation.d.ts +1 -1
- package/dist/core/middleware/built-in/validation.js +3 -7
- package/dist/core/middleware/built-in/validation.js.map +1 -1
- package/dist/core/middleware/index.d.ts +4 -4
- package/dist/core/middleware/index.js +8 -28
- package/dist/core/middleware/index.js.map +1 -1
- package/dist/core/modules/auto-discovery.d.ts +19 -2
- package/dist/core/modules/auto-discovery.js +391 -74
- package/dist/core/modules/auto-discovery.js.map +1 -1
- package/dist/core/modules/index.d.ts +2 -2
- package/dist/core/modules/index.js +2 -9
- package/dist/core/modules/index.js.map +1 -1
- package/dist/core/modules/modules.d.ts +3 -3
- package/dist/core/modules/modules.js +23 -54
- package/dist/core/modules/modules.js.map +1 -1
- package/dist/core/networking/adapters/index.d.ts +4 -3
- package/dist/core/networking/adapters/index.js +3 -7
- package/dist/core/networking/adapters/index.js.map +1 -1
- package/dist/core/networking/adapters/socketio-adapter.d.ts +1 -1
- package/dist/core/networking/adapters/socketio-adapter.js +5 -40
- package/dist/core/networking/adapters/socketio-adapter.js.map +1 -1
- package/dist/core/networking/adapters/uws-adapter.d.ts +44 -0
- package/dist/core/networking/adapters/uws-adapter.js +513 -0
- package/dist/core/networking/adapters/uws-adapter.js.map +1 -0
- package/dist/core/networking/adapters/ws-adapter.d.ts +2 -2
- package/dist/core/networking/adapters/ws-adapter.js +8 -43
- package/dist/core/networking/adapters/ws-adapter.js.map +1 -1
- package/dist/core/networking/index.d.ts +3 -2
- package/dist/core/networking/index.js +2 -7
- package/dist/core/networking/index.js.map +1 -1
- package/dist/core/networking/service-discovery.js +8 -12
- package/dist/core/networking/service-discovery.js.map +1 -1
- package/dist/core/networking/websocket-adapter.js +1 -2
- package/dist/core/networking/websocket-adapter.js.map +1 -1
- package/dist/core/networking/websocket-manager.d.ts +3 -3
- package/dist/core/networking/websocket-manager.js +9 -11
- package/dist/core/networking/websocket-manager.js.map +1 -1
- package/dist/core/pooling/object-pool-manager.d.ts +140 -0
- package/dist/core/pooling/object-pool-manager.js +502 -0
- package/dist/core/pooling/object-pool-manager.js.map +1 -0
- package/dist/core/routing/app-integration.d.ts +14 -12
- package/dist/core/routing/app-integration.js +49 -85
- package/dist/core/routing/app-integration.js.map +1 -1
- package/dist/core/routing/index.d.ts +17 -11
- package/dist/core/routing/index.js +48 -237
- package/dist/core/routing/index.js.map +1 -1
- package/dist/core/routing/path-matcher.d.ts +67 -0
- package/dist/core/routing/path-matcher.js +182 -0
- package/dist/core/routing/path-matcher.js.map +1 -0
- package/dist/core/routing/router.d.ts +38 -0
- package/dist/core/routing/router.js +68 -0
- package/dist/core/routing/router.js.map +1 -0
- package/dist/core/routing/unified-router.d.ts +148 -0
- package/dist/core/routing/unified-router.js +684 -0
- package/dist/core/routing/unified-router.js.map +1 -0
- package/dist/core/runtime/aws-lambda-adapter.d.ts +3 -3
- package/dist/core/runtime/aws-lambda-adapter.js +2 -6
- package/dist/core/runtime/aws-lambda-adapter.js.map +1 -1
- package/dist/core/runtime/base-adapter.d.ts +2 -2
- package/dist/core/runtime/base-adapter.js +3 -7
- package/dist/core/runtime/base-adapter.js.map +1 -1
- package/dist/core/runtime/cloudflare-workers-adapter.d.ts +3 -3
- package/dist/core/runtime/cloudflare-workers-adapter.js +2 -6
- package/dist/core/runtime/cloudflare-workers-adapter.js.map +1 -1
- package/dist/core/runtime/index.d.ts +12 -12
- package/dist/core/runtime/index.js +22 -35
- package/dist/core/runtime/index.js.map +1 -1
- package/dist/core/runtime/node-adapter.d.ts +4 -4
- package/dist/core/runtime/node-adapter.js +18 -49
- package/dist/core/runtime/node-adapter.js.map +1 -1
- package/dist/core/runtime/vercel-edge-adapter.d.ts +3 -3
- package/dist/core/runtime/vercel-edge-adapter.js +2 -6
- package/dist/core/runtime/vercel-edge-adapter.js.map +1 -1
- package/dist/core/utilities/circuit-breaker.js +1 -5
- package/dist/core/utilities/circuit-breaker.js.map +1 -1
- package/dist/core/utilities/container.js +12 -22
- package/dist/core/utilities/container.js.map +1 -1
- package/dist/core/utilities/hooks.d.ts +2 -2
- package/dist/core/utilities/hooks.js +7 -12
- package/dist/core/utilities/hooks.js.map +1 -1
- package/dist/core/utilities/index.d.ts +5 -4
- package/dist/core/utilities/index.js +5 -19
- package/dist/core/utilities/index.js.map +1 -1
- package/dist/core/utilities/package-utils.d.ts +38 -0
- package/dist/core/utilities/package-utils.js +57 -0
- package/dist/core/utilities/package-utils.js.map +1 -0
- package/dist/core/validation/adapters.d.ts +1 -1
- package/dist/core/validation/adapters.js +15 -26
- package/dist/core/validation/adapters.js.map +1 -1
- package/dist/core/validation/index.d.ts +6 -4
- package/dist/core/validation/index.js +57 -28
- package/dist/core/validation/index.js.map +1 -1
- package/dist/core/validation/schema-interface.js +3 -9
- package/dist/core/validation/schema-interface.js.map +1 -1
- package/dist/index.d.ts +51 -52
- package/dist/index.js +23 -132
- package/dist/index.js.map +1 -1
- package/dist/moro.d.ts +70 -16
- package/dist/moro.js +658 -271
- package/dist/moro.js.map +1 -1
- package/dist/types/auth.js +3 -9
- package/dist/types/auth.js.map +1 -1
- package/dist/types/cache.js +1 -2
- package/dist/types/cdn.js +1 -2
- package/dist/types/config.d.ts +73 -2
- package/dist/types/config.js +1 -2
- package/dist/types/config.js.map +1 -1
- package/dist/types/core.d.ts +36 -42
- package/dist/types/core.js +1 -2
- package/dist/types/database.js +1 -2
- package/dist/types/discovery.js +1 -2
- package/dist/types/events.js +1 -2
- package/dist/types/hooks.d.ts +1 -1
- package/dist/types/hooks.js +1 -2
- package/dist/types/http.d.ts +16 -1
- package/dist/types/http.js +1 -2
- package/dist/types/logger.d.ts +7 -0
- package/dist/types/logger.js +1 -2
- package/dist/types/module.d.ts +11 -0
- package/dist/types/module.js +1 -2
- package/dist/types/runtime.d.ts +1 -1
- package/dist/types/runtime.js +1 -2
- package/dist/types/session.js +1 -2
- package/jest.config.mjs +41 -0
- package/package.json +19 -52
- package/src/core/auth/morojs-adapter.ts +18 -13
- package/src/core/config/config-manager.ts +133 -0
- package/src/core/config/config-sources.ts +600 -0
- package/src/core/config/config-validator.ts +1116 -0
- package/src/core/config/file-loader.ts +16 -273
- package/src/core/config/index.ts +83 -34
- package/src/core/config/schema.ts +47 -33
- package/src/core/config/utils.ts +24 -31
- package/src/core/database/README.md +26 -16
- package/src/core/database/adapters/drizzle.ts +18 -6
- package/src/core/database/adapters/index.ts +13 -13
- package/src/core/database/adapters/mongodb.ts +53 -5
- package/src/core/database/adapters/mysql.ts +32 -4
- package/src/core/database/adapters/postgresql.ts +30 -5
- package/src/core/database/adapters/redis.ts +61 -8
- package/src/core/database/adapters/sqlite.ts +19 -3
- package/src/core/database/index.ts +2 -2
- package/src/core/docs/index.ts +8 -8
- package/src/core/docs/openapi-generator.ts +4 -4
- package/src/core/docs/schema-to-openapi.ts +3 -6
- package/src/core/docs/simple-docs.ts +2 -2
- package/src/core/docs/swagger-ui.ts +19 -16
- package/src/core/docs/zod-to-openapi.ts +34 -34
- package/src/core/events/event-bus.ts +3 -3
- package/src/core/events/index.ts +2 -2
- package/src/core/framework.ts +320 -71
- package/src/core/http/http-server.ts +203 -143
- package/src/core/http/index.ts +4 -3
- package/src/core/http/uws-http-server.ts +591 -0
- package/src/core/logger/filters.ts +13 -5
- package/src/core/logger/index.ts +4 -3
- package/src/core/logger/logger.ts +435 -216
- package/src/core/logger/outputs.ts +1 -3
- package/src/core/middleware/built-in/adapters/cache/file.ts +3 -3
- package/src/core/middleware/built-in/adapters/cache/index.ts +7 -7
- package/src/core/middleware/built-in/adapters/cache/memory.ts +2 -2
- package/src/core/middleware/built-in/adapters/cache/redis.ts +18 -4
- package/src/core/middleware/built-in/adapters/cdn/azure.ts +2 -2
- package/src/core/middleware/built-in/adapters/cdn/cloudflare.ts +2 -2
- package/src/core/middleware/built-in/adapters/cdn/cloudfront.ts +16 -5
- package/src/core/middleware/built-in/adapters/cdn/index.ts +7 -7
- package/src/core/middleware/built-in/adapters/index.ts +4 -4
- package/src/core/middleware/built-in/auth-helpers.ts +1 -1
- package/src/core/middleware/built-in/auth-providers.ts +1 -1
- package/src/core/middleware/built-in/auth.ts +102 -21
- package/src/core/middleware/built-in/cache.ts +8 -6
- package/src/core/middleware/built-in/cdn.ts +4 -4
- package/src/core/middleware/built-in/cookie.ts +2 -2
- package/src/core/middleware/built-in/cors.ts +2 -2
- package/src/core/middleware/built-in/csp.ts +3 -3
- package/src/core/middleware/built-in/csrf.ts +3 -3
- package/src/core/middleware/built-in/error-tracker.ts +1 -1
- package/src/core/middleware/built-in/index.ts +38 -30
- package/src/core/middleware/built-in/jwt-helpers.ts +243 -0
- package/src/core/middleware/built-in/performance-monitor.ts +1 -1
- package/src/core/middleware/built-in/rate-limit.ts +2 -2
- package/src/core/middleware/built-in/request-logger.ts +3 -1
- package/src/core/middleware/built-in/session.ts +7 -8
- package/src/core/middleware/built-in/sse.ts +11 -9
- package/src/core/middleware/built-in/validation.ts +2 -2
- package/src/core/middleware/index.ts +6 -6
- package/src/core/modules/auto-discovery.ts +478 -15
- package/src/core/modules/index.ts +2 -2
- package/src/core/modules/modules.ts +23 -12
- package/src/core/networking/adapters/index.ts +4 -3
- package/src/core/networking/adapters/socketio-adapter.ts +5 -3
- package/src/core/networking/adapters/uws-adapter.ts +619 -0
- package/src/core/networking/adapters/ws-adapter.ts +8 -9
- package/src/core/networking/index.ts +3 -2
- package/src/core/networking/service-discovery.ts +6 -7
- package/src/core/networking/websocket-manager.ts +7 -7
- package/src/core/pooling/object-pool-manager.ts +630 -0
- package/src/core/routing/app-integration.ts +60 -112
- package/src/core/routing/index.ts +66 -293
- package/src/core/routing/path-matcher.ts +222 -0
- package/src/core/routing/router.ts +97 -0
- package/src/core/routing/unified-router.ts +870 -0
- package/src/core/runtime/aws-lambda-adapter.ts +3 -3
- package/src/core/runtime/base-adapter.ts +2 -2
- package/src/core/runtime/cloudflare-workers-adapter.ts +3 -3
- package/src/core/runtime/index.ts +13 -13
- package/src/core/runtime/node-adapter.ts +16 -10
- package/src/core/runtime/vercel-edge-adapter.ts +3 -3
- package/src/core/utilities/hooks.ts +3 -3
- package/src/core/utilities/index.ts +5 -4
- package/src/core/utilities/package-utils.ts +59 -0
- package/src/core/validation/adapters.ts +1 -1
- package/src/core/validation/index.ts +68 -16
- package/src/index.ts +73 -66
- package/src/moro.ts +784 -253
- package/src/types/config.ts +74 -2
- package/src/types/core.ts +49 -47
- package/src/types/hooks.ts +1 -1
- package/src/types/http.ts +23 -1
- package/src/types/logger.ts +9 -0
- package/src/types/module.ts +12 -0
- package/src/types/runtime.ts +1 -1
- package/tsconfig.json +4 -2
- package/dist/core/config/loader.d.ts +0 -7
- package/dist/core/config/loader.js +0 -269
- package/dist/core/config/loader.js.map +0 -1
- package/dist/core/config/validation.d.ts +0 -17
- package/dist/core/config/validation.js +0 -131
- package/dist/core/config/validation.js.map +0 -1
- package/dist/core/http/router.d.ts +0 -14
- package/dist/core/http/router.js +0 -109
- package/dist/core/http/router.js.map +0 -1
- package/src/core/config/loader.ts +0 -633
- package/src/core/config/validation.ts +0 -140
- package/src/core/http/router.ts +0 -141
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// Moro Logger - Beautiful, Fast, Feature-Rich
|
|
2
2
|
import { performance } from 'perf_hooks';
|
|
3
|
-
|
|
3
|
+
|
|
4
4
|
import {
|
|
5
5
|
LogLevel,
|
|
6
6
|
LogEntry,
|
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
LogFilter,
|
|
11
11
|
LogMetrics,
|
|
12
12
|
ColorScheme,
|
|
13
|
-
} from '../../types/logger';
|
|
13
|
+
} from '../../types/logger.js';
|
|
14
14
|
|
|
15
15
|
export class MoroLogger implements Logger {
|
|
16
16
|
private level: LogLevel = 'info';
|
|
@@ -41,13 +41,27 @@ export class MoroLogger implements Logger {
|
|
|
41
41
|
private lastTimestamp = 0;
|
|
42
42
|
private timestampCacheInterval = 100; // 100ms for better precision
|
|
43
43
|
|
|
44
|
-
//
|
|
44
|
+
// Object pooling for LogEntry objects (Pino's technique)
|
|
45
|
+
private static readonly ENTRY_POOL: LogEntry[] = [];
|
|
46
|
+
private static readonly MAX_POOL_SIZE = 100;
|
|
47
|
+
private static poolIndex = 0;
|
|
48
|
+
|
|
49
|
+
// String builder for efficient concatenation
|
|
50
|
+
private static stringBuilder: string[] = [];
|
|
51
|
+
private static stringBuilderIndex = 0;
|
|
52
|
+
|
|
53
|
+
// Buffered output for performance
|
|
45
54
|
private outputBuffer: string[] = [];
|
|
46
55
|
private bufferSize = 0;
|
|
47
|
-
private maxBufferSize =
|
|
56
|
+
private maxBufferSize = 1000;
|
|
48
57
|
private flushTimeout: NodeJS.Timeout | null = null;
|
|
49
58
|
private flushInterval = 1; // 1ms micro-batching
|
|
50
59
|
|
|
60
|
+
// Buffer overflow protection
|
|
61
|
+
private bufferOverflowThreshold: number;
|
|
62
|
+
private emergencyFlushInProgress = false;
|
|
63
|
+
private isDestroyed = false;
|
|
64
|
+
|
|
51
65
|
// High-performance output methods
|
|
52
66
|
|
|
53
67
|
private static readonly LEVELS: Record<LogLevel, number> = {
|
|
@@ -58,84 +72,6 @@ export class MoroLogger implements Logger {
|
|
|
58
72
|
fatal: 4,
|
|
59
73
|
};
|
|
60
74
|
|
|
61
|
-
// Static pre-allocated strings for maximum performance
|
|
62
|
-
private static readonly LEVEL_STRINGS: Record<LogLevel, string> = {
|
|
63
|
-
debug: 'DEBUG',
|
|
64
|
-
info: 'INFO',
|
|
65
|
-
warn: 'WARN',
|
|
66
|
-
error: 'ERROR',
|
|
67
|
-
fatal: 'FATAL',
|
|
68
|
-
};
|
|
69
|
-
|
|
70
|
-
// Pre-allocated ANSI color codes
|
|
71
|
-
private static readonly ANSI_COLORS = {
|
|
72
|
-
reset: '\x1b[0m',
|
|
73
|
-
bold: '\x1b[1m',
|
|
74
|
-
dim: '\x1b[2m',
|
|
75
|
-
red: '\x1b[31m',
|
|
76
|
-
green: '\x1b[32m',
|
|
77
|
-
yellow: '\x1b[33m',
|
|
78
|
-
blue: '\x1b[34m',
|
|
79
|
-
magenta: '\x1b[35m',
|
|
80
|
-
cyan: '\x1b[36m',
|
|
81
|
-
white: '\x1b[37m',
|
|
82
|
-
gray: '\x1b[90m',
|
|
83
|
-
};
|
|
84
|
-
|
|
85
|
-
// Object pool for LogEntry reuse
|
|
86
|
-
private static readonly ENTRY_POOL: LogEntry[] = [];
|
|
87
|
-
private static readonly MAX_POOL_SIZE = 100;
|
|
88
|
-
private static poolIndex = 0;
|
|
89
|
-
|
|
90
|
-
// Object pool management
|
|
91
|
-
private static getPooledEntry(): LogEntry {
|
|
92
|
-
if (MoroLogger.poolIndex > 0) {
|
|
93
|
-
return MoroLogger.ENTRY_POOL[--MoroLogger.poolIndex];
|
|
94
|
-
}
|
|
95
|
-
return {
|
|
96
|
-
timestamp: new Date(),
|
|
97
|
-
level: 'info',
|
|
98
|
-
message: '',
|
|
99
|
-
context: undefined,
|
|
100
|
-
metadata: undefined,
|
|
101
|
-
};
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
private static returnPooledEntry(entry: LogEntry): void {
|
|
105
|
-
if (MoroLogger.poolIndex < MoroLogger.MAX_POOL_SIZE) {
|
|
106
|
-
// Reset the entry
|
|
107
|
-
entry.timestamp = new Date();
|
|
108
|
-
entry.level = 'info';
|
|
109
|
-
entry.message = '';
|
|
110
|
-
entry.context = undefined;
|
|
111
|
-
entry.metadata = undefined;
|
|
112
|
-
MoroLogger.ENTRY_POOL[MoroLogger.poolIndex++] = entry;
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
// String builder for efficient concatenation
|
|
117
|
-
private static stringBuilder: string[] = [];
|
|
118
|
-
private static stringBuilderIndex = 0;
|
|
119
|
-
|
|
120
|
-
private static resetStringBuilder(): void {
|
|
121
|
-
MoroLogger.stringBuilderIndex = 0;
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
private static appendToBuilder(str: string): void {
|
|
125
|
-
if (MoroLogger.stringBuilderIndex < MoroLogger.stringBuilder.length) {
|
|
126
|
-
MoroLogger.stringBuilder[MoroLogger.stringBuilderIndex++] = str;
|
|
127
|
-
} else {
|
|
128
|
-
MoroLogger.stringBuilder.push(str);
|
|
129
|
-
MoroLogger.stringBuilderIndex++;
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
private static buildString(): string {
|
|
134
|
-
const result = MoroLogger.stringBuilder.slice(0, MoroLogger.stringBuilderIndex).join('');
|
|
135
|
-
MoroLogger.resetStringBuilder();
|
|
136
|
-
return result;
|
|
137
|
-
}
|
|
138
|
-
|
|
139
75
|
private static readonly COLORS: ColorScheme = {
|
|
140
76
|
debug: '\x1b[36m', // Cyan
|
|
141
77
|
info: '\x1b[32m', // Green
|
|
@@ -146,13 +82,23 @@ export class MoroLogger implements Logger {
|
|
|
146
82
|
context: '\x1b[34m', // Blue
|
|
147
83
|
metadata: '\x1b[37m', // White
|
|
148
84
|
performance: '\x1b[36m', // Cyan
|
|
85
|
+
reset: '\x1b[0m', // Reset
|
|
149
86
|
};
|
|
150
87
|
|
|
151
88
|
private static readonly RESET = '\x1b[0m';
|
|
152
89
|
private static readonly BOLD = '\x1b[1m';
|
|
153
90
|
|
|
91
|
+
// Static pre-allocated strings for performance
|
|
92
|
+
private static readonly LEVEL_STRINGS: Record<LogLevel, string> = {
|
|
93
|
+
debug: 'DEBUG',
|
|
94
|
+
info: 'INFO ',
|
|
95
|
+
warn: 'WARN ',
|
|
96
|
+
error: 'ERROR',
|
|
97
|
+
fatal: 'FATAL',
|
|
98
|
+
};
|
|
99
|
+
|
|
154
100
|
constructor(options: LoggerOptions = {}) {
|
|
155
|
-
this.options = {
|
|
101
|
+
this.options = this.validateOptions({
|
|
156
102
|
level: 'info',
|
|
157
103
|
enableColors: true,
|
|
158
104
|
enableTimestamp: true,
|
|
@@ -163,11 +109,18 @@ export class MoroLogger implements Logger {
|
|
|
163
109
|
outputs: [],
|
|
164
110
|
filters: [],
|
|
165
111
|
maxEntries: 1000,
|
|
112
|
+
maxBufferSize: 1000,
|
|
166
113
|
...options,
|
|
167
|
-
};
|
|
114
|
+
});
|
|
168
115
|
|
|
169
116
|
this.level = this.options.level || 'info';
|
|
170
117
|
|
|
118
|
+
// Initialize buffer size from options
|
|
119
|
+
this.maxBufferSize = this.options.maxBufferSize || 1000;
|
|
120
|
+
|
|
121
|
+
// Initialize buffer overflow protection
|
|
122
|
+
this.bufferOverflowThreshold = this.maxBufferSize * 2;
|
|
123
|
+
|
|
171
124
|
// Add default console output
|
|
172
125
|
this.addOutput({
|
|
173
126
|
name: 'console',
|
|
@@ -180,6 +133,58 @@ export class MoroLogger implements Logger {
|
|
|
180
133
|
this.options.filters?.forEach(filter => this.addFilter(filter));
|
|
181
134
|
}
|
|
182
135
|
|
|
136
|
+
// Object pooling methods
|
|
137
|
+
private static getPooledEntry(): LogEntry {
|
|
138
|
+
if (MoroLogger.ENTRY_POOL.length > 0) {
|
|
139
|
+
const entry = MoroLogger.ENTRY_POOL.pop()!;
|
|
140
|
+
// Properly reset ALL properties to prevent memory leaks
|
|
141
|
+
entry.timestamp = new Date();
|
|
142
|
+
entry.level = 'info';
|
|
143
|
+
entry.message = '';
|
|
144
|
+
entry.context = undefined;
|
|
145
|
+
entry.metadata = undefined;
|
|
146
|
+
entry.performance = undefined;
|
|
147
|
+
entry.moduleId = undefined;
|
|
148
|
+
return entry;
|
|
149
|
+
}
|
|
150
|
+
return MoroLogger.createFreshEntry();
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// ADD this new method:
|
|
154
|
+
private static createFreshEntry(): LogEntry {
|
|
155
|
+
return {
|
|
156
|
+
timestamp: new Date(),
|
|
157
|
+
level: 'info',
|
|
158
|
+
message: '',
|
|
159
|
+
context: undefined,
|
|
160
|
+
metadata: undefined,
|
|
161
|
+
performance: undefined,
|
|
162
|
+
moduleId: undefined,
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
private static returnPooledEntry(entry: LogEntry): void {
|
|
167
|
+
if (MoroLogger.ENTRY_POOL.length < MoroLogger.MAX_POOL_SIZE) {
|
|
168
|
+
MoroLogger.ENTRY_POOL.push(entry);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// String builder methods
|
|
173
|
+
private static resetStringBuilder(): void {
|
|
174
|
+
MoroLogger.stringBuilder.length = 0;
|
|
175
|
+
MoroLogger.stringBuilderIndex = 0;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
private static appendToBuilder(str: string): void {
|
|
179
|
+
MoroLogger.stringBuilder[MoroLogger.stringBuilderIndex++] = str;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
private static buildString(): string {
|
|
183
|
+
const result = MoroLogger.stringBuilder.join('');
|
|
184
|
+
MoroLogger.resetStringBuilder();
|
|
185
|
+
return result;
|
|
186
|
+
}
|
|
187
|
+
|
|
183
188
|
debug(message: string, context?: string, metadata?: Record<string, any>): void {
|
|
184
189
|
this.log('debug', message, context, metadata);
|
|
185
190
|
}
|
|
@@ -222,7 +227,9 @@ export class MoroLogger implements Logger {
|
|
|
222
227
|
}
|
|
223
228
|
|
|
224
229
|
child(context: string, metadata?: Record<string, any>): Logger {
|
|
225
|
-
|
|
230
|
+
// Create child logger with current parent level (not original options level)
|
|
231
|
+
const childOptions = { ...this.options, level: this.level };
|
|
232
|
+
const childLogger = new MoroLogger(childOptions);
|
|
226
233
|
childLogger.contextPrefix = this.contextPrefix ? `${this.contextPrefix}:${context}` : context;
|
|
227
234
|
childLogger.contextMetadata = { ...this.contextMetadata, ...metadata };
|
|
228
235
|
childLogger.outputs = this.outputs;
|
|
@@ -238,6 +245,10 @@ export class MoroLogger implements Logger {
|
|
|
238
245
|
this.level = level;
|
|
239
246
|
}
|
|
240
247
|
|
|
248
|
+
getLevel(): LogLevel {
|
|
249
|
+
return this.level;
|
|
250
|
+
}
|
|
251
|
+
|
|
241
252
|
addOutput(output: LogOutput): void {
|
|
242
253
|
this.outputs.set(output.name, output);
|
|
243
254
|
}
|
|
@@ -287,6 +298,17 @@ export class MoroLogger implements Logger {
|
|
|
287
298
|
return this.cachedTimestamp;
|
|
288
299
|
}
|
|
289
300
|
|
|
301
|
+
// Cached timestamp generation (updates once per second)
|
|
302
|
+
private getFastCachedTimestamp(): string {
|
|
303
|
+
const now = Date.now();
|
|
304
|
+
if (now - this.lastTimestamp > 1000) {
|
|
305
|
+
// Update every second
|
|
306
|
+
this.lastTimestamp = now;
|
|
307
|
+
this.cachedTimestamp = new Date(now).toISOString().slice(0, 19).replace('T', ' ');
|
|
308
|
+
}
|
|
309
|
+
return this.cachedTimestamp;
|
|
310
|
+
}
|
|
311
|
+
|
|
290
312
|
getMetrics(): LogMetrics {
|
|
291
313
|
const now = Date.now();
|
|
292
314
|
const uptime = (now - this.startTime) / 1000; // seconds
|
|
@@ -314,62 +336,54 @@ export class MoroLogger implements Logger {
|
|
|
314
336
|
};
|
|
315
337
|
}
|
|
316
338
|
|
|
317
|
-
// Optimized logging method
|
|
339
|
+
// Optimized logging method
|
|
318
340
|
private log(
|
|
319
341
|
level: LogLevel,
|
|
320
342
|
message: string,
|
|
321
343
|
context?: string,
|
|
322
344
|
metadata?: Record<string, any>
|
|
323
345
|
): void {
|
|
324
|
-
//
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
: MoroLogger.LEVELS[this.level];
|
|
346
|
+
// Prevent logging after destroy() is called (important for test cleanup)
|
|
347
|
+
if (this.isDestroyed) {
|
|
348
|
+
return;
|
|
349
|
+
}
|
|
329
350
|
|
|
330
|
-
if (
|
|
331
|
-
|
|
351
|
+
// Quick level check - use parent level if available (for child loggers)
|
|
352
|
+
const effectiveLevel = this.parent ? this.parent.level : this.level;
|
|
353
|
+
if (MoroLogger.LEVELS[level] < MoroLogger.LEVELS[effectiveLevel as LogLevel]) {
|
|
354
|
+
return;
|
|
332
355
|
}
|
|
333
356
|
|
|
334
|
-
//
|
|
357
|
+
// Absolute minimal path for simple logs - pure speed
|
|
335
358
|
if (!metadata && !context && !this.contextPrefix && !this.contextMetadata) {
|
|
336
|
-
|
|
337
|
-
this.output(`${levelStr} ${message}\n`, level);
|
|
359
|
+
this.writeSimpleLog(level, message);
|
|
338
360
|
return;
|
|
339
361
|
}
|
|
340
362
|
|
|
341
|
-
//
|
|
363
|
+
// Minimal path for logs with context but no metadata
|
|
342
364
|
if (!metadata && !this.contextMetadata) {
|
|
343
|
-
|
|
344
|
-
if (context) {
|
|
345
|
-
this.output(`${levelStr} [${context}] ${message}\n`, level);
|
|
346
|
-
} else {
|
|
347
|
-
this.output(`${levelStr} ${message}\n`, level);
|
|
348
|
-
}
|
|
365
|
+
this.writeSimpleLog(level, message, context);
|
|
349
366
|
return;
|
|
350
367
|
}
|
|
351
368
|
|
|
352
|
-
//
|
|
353
|
-
if (metadata && Object.keys(metadata).length
|
|
354
|
-
|
|
355
|
-
const contextStr = context ? `[${context}] ` : '';
|
|
356
|
-
const metaStr = this.stringify(metadata);
|
|
357
|
-
this.output(`${levelStr} ${contextStr}${message} ${metaStr}\n`, level);
|
|
369
|
+
// Path for complex logs
|
|
370
|
+
if (metadata && Object.keys(metadata).length > 0) {
|
|
371
|
+
this.complexLog(level, message, context, metadata);
|
|
358
372
|
return;
|
|
359
373
|
}
|
|
360
374
|
|
|
361
|
-
//
|
|
375
|
+
// Full logging path for complex logs
|
|
362
376
|
this.fullLog(level, message, context, metadata);
|
|
363
377
|
}
|
|
364
378
|
|
|
365
|
-
// Full logging with all features
|
|
379
|
+
// Full logging with all features
|
|
366
380
|
private fullLog(
|
|
367
381
|
level: LogLevel,
|
|
368
382
|
message: string,
|
|
369
383
|
context?: string,
|
|
370
384
|
metadata?: Record<string, any>
|
|
371
385
|
): void {
|
|
372
|
-
//
|
|
386
|
+
// Use object pooling for LogEntry (Pino's technique)
|
|
373
387
|
const entry = MoroLogger.getPooledEntry();
|
|
374
388
|
const now = Date.now();
|
|
375
389
|
|
|
@@ -388,6 +402,7 @@ export class MoroLogger implements Logger {
|
|
|
388
402
|
if (this.filters.size > 0) {
|
|
389
403
|
for (const filter of this.filters.values()) {
|
|
390
404
|
if (!filter.filter(entry)) {
|
|
405
|
+
MoroLogger.returnPooledEntry(entry);
|
|
391
406
|
return;
|
|
392
407
|
}
|
|
393
408
|
}
|
|
@@ -402,8 +417,89 @@ export class MoroLogger implements Logger {
|
|
|
402
417
|
// Write to outputs with batched processing
|
|
403
418
|
this.writeToOutputs(entry, level);
|
|
404
419
|
|
|
405
|
-
// Return entry to pool
|
|
406
|
-
|
|
420
|
+
// Return entry to pool
|
|
421
|
+
MoroLogger.returnPooledEntry(entry);
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
// Absolute minimal logging - pure speed, no overhead
|
|
425
|
+
private complexLog(
|
|
426
|
+
level: LogLevel,
|
|
427
|
+
message: string,
|
|
428
|
+
context?: string,
|
|
429
|
+
metadata?: Record<string, any>
|
|
430
|
+
): void {
|
|
431
|
+
// Use object pooling for LogEntry (Pino's technique)
|
|
432
|
+
const entry = MoroLogger.getPooledEntry();
|
|
433
|
+
const now = Date.now();
|
|
434
|
+
|
|
435
|
+
entry.timestamp = new Date(now);
|
|
436
|
+
entry.level = level;
|
|
437
|
+
entry.message = message;
|
|
438
|
+
entry.context = this.contextPrefix
|
|
439
|
+
? context
|
|
440
|
+
? `${this.contextPrefix}:${context}`
|
|
441
|
+
: this.contextPrefix
|
|
442
|
+
: context;
|
|
443
|
+
entry.metadata = this.createMetadata(metadata);
|
|
444
|
+
entry.performance = this.options.enablePerformance ? this.getPerformanceData(now) : undefined;
|
|
445
|
+
|
|
446
|
+
// Write to outputs with batched processing
|
|
447
|
+
this.writeToOutputs(entry, level);
|
|
448
|
+
|
|
449
|
+
// Return entry to pool
|
|
450
|
+
MoroLogger.returnPooledEntry(entry);
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
// Simple log writer with colors for minimal overhead cases
|
|
454
|
+
private writeSimpleLog(level: LogLevel, message: string, context?: string): void {
|
|
455
|
+
const colors = this.options.enableColors !== false;
|
|
456
|
+
const levelReset = colors ? MoroLogger.RESET : '';
|
|
457
|
+
|
|
458
|
+
MoroLogger.resetStringBuilder();
|
|
459
|
+
|
|
460
|
+
// Timestamp with caching optimization
|
|
461
|
+
if (this.options.enableTimestamp !== false) {
|
|
462
|
+
const timestamp = this.getFastCachedTimestamp();
|
|
463
|
+
if (colors) {
|
|
464
|
+
MoroLogger.appendToBuilder(MoroLogger.COLORS.timestamp);
|
|
465
|
+
MoroLogger.appendToBuilder(timestamp);
|
|
466
|
+
MoroLogger.appendToBuilder(levelReset);
|
|
467
|
+
} else {
|
|
468
|
+
MoroLogger.appendToBuilder(timestamp);
|
|
469
|
+
}
|
|
470
|
+
MoroLogger.appendToBuilder(' ');
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
// Level with pre-allocated strings
|
|
474
|
+
const levelStr = MoroLogger.LEVEL_STRINGS[level];
|
|
475
|
+
if (colors) {
|
|
476
|
+
MoroLogger.appendToBuilder(MoroLogger.COLORS[level]);
|
|
477
|
+
MoroLogger.appendToBuilder(MoroLogger.BOLD);
|
|
478
|
+
MoroLogger.appendToBuilder(levelStr);
|
|
479
|
+
MoroLogger.appendToBuilder(levelReset);
|
|
480
|
+
} else {
|
|
481
|
+
MoroLogger.appendToBuilder(levelStr);
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
// Context
|
|
485
|
+
if (context && this.options.enableContext !== false) {
|
|
486
|
+
MoroLogger.appendToBuilder(' ');
|
|
487
|
+
if (colors) {
|
|
488
|
+
MoroLogger.appendToBuilder(MoroLogger.COLORS.context);
|
|
489
|
+
MoroLogger.appendToBuilder(`[${context}]`);
|
|
490
|
+
MoroLogger.appendToBuilder(levelReset);
|
|
491
|
+
} else {
|
|
492
|
+
MoroLogger.appendToBuilder(`[${context}]`);
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
// Message
|
|
497
|
+
MoroLogger.appendToBuilder(' ');
|
|
498
|
+
MoroLogger.appendToBuilder(message);
|
|
499
|
+
|
|
500
|
+
// Output main log line with high-performance method
|
|
501
|
+
const finalMessage = MoroLogger.buildString();
|
|
502
|
+
this.output(`${finalMessage}\n`, level);
|
|
407
503
|
}
|
|
408
504
|
|
|
409
505
|
private updateMetrics(entry: LogEntry): void {
|
|
@@ -457,24 +553,39 @@ export class MoroLogger implements Logger {
|
|
|
457
553
|
private writeToOutputs(entry: LogEntry, level: LogLevel): void {
|
|
458
554
|
if (this.outputs.size === 0) return;
|
|
459
555
|
|
|
556
|
+
let successCount = 0;
|
|
557
|
+
const errors: Array<{ outputName: string; error: any }> = [];
|
|
558
|
+
|
|
460
559
|
for (const output of this.outputs.values()) {
|
|
461
560
|
if (!output.level || MoroLogger.LEVELS[level] >= MoroLogger.LEVELS[output.level]) {
|
|
462
561
|
try {
|
|
463
562
|
output.write(entry);
|
|
563
|
+
successCount++;
|
|
464
564
|
} catch (error) {
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
console.error('Logger output error:', error);
|
|
565
|
+
errors.push({ outputName: output.name, error });
|
|
566
|
+
this.handleOutputError(output.name, error);
|
|
468
567
|
}
|
|
469
568
|
}
|
|
470
569
|
}
|
|
570
|
+
|
|
571
|
+
// If all outputs fail, use emergency console
|
|
572
|
+
if (successCount === 0 && this.outputs.size > 0) {
|
|
573
|
+
this.emergencyConsoleWrite(entry);
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
// Log output errors (but avoid infinite loops)
|
|
577
|
+
if (errors.length > 0 && level !== 'error') {
|
|
578
|
+
this.error(`Logger output errors: ${errors.length} failed`, 'MoroLogger', {
|
|
579
|
+
errors: errors.map(e => e.outputName),
|
|
580
|
+
});
|
|
581
|
+
}
|
|
471
582
|
}
|
|
472
583
|
|
|
473
584
|
private writeToConsole(entry: LogEntry): void {
|
|
474
585
|
const format = this.options.format || 'pretty';
|
|
475
586
|
|
|
476
587
|
if (format === 'json') {
|
|
477
|
-
this.output(
|
|
588
|
+
this.output(`${this.safeStringify(entry)}\n`, entry.level);
|
|
478
589
|
return;
|
|
479
590
|
}
|
|
480
591
|
|
|
@@ -491,6 +602,8 @@ export class MoroLogger implements Logger {
|
|
|
491
602
|
|
|
492
603
|
private writePrettyLog(entry: LogEntry): void {
|
|
493
604
|
const colors = this.options.enableColors !== false;
|
|
605
|
+
const levelReset = colors ? MoroLogger.RESET : '';
|
|
606
|
+
|
|
494
607
|
MoroLogger.resetStringBuilder();
|
|
495
608
|
|
|
496
609
|
// Timestamp with caching optimization
|
|
@@ -499,37 +612,29 @@ export class MoroLogger implements Logger {
|
|
|
499
612
|
if (colors) {
|
|
500
613
|
MoroLogger.appendToBuilder(MoroLogger.COLORS.timestamp);
|
|
501
614
|
MoroLogger.appendToBuilder(timestamp);
|
|
502
|
-
MoroLogger.appendToBuilder(
|
|
615
|
+
MoroLogger.appendToBuilder(levelReset);
|
|
503
616
|
} else {
|
|
504
617
|
MoroLogger.appendToBuilder(timestamp);
|
|
505
618
|
}
|
|
506
|
-
}
|
|
507
|
-
|
|
508
|
-
// Level with color using pre-allocated strings
|
|
509
|
-
const levelColor = colors ? MoroLogger.COLORS[entry.level] : '';
|
|
510
|
-
const levelReset = colors ? MoroLogger.RESET : '';
|
|
511
|
-
const levelText = MoroLogger.LEVEL_STRINGS[entry.level];
|
|
512
|
-
|
|
513
|
-
// Add space after timestamp if present
|
|
514
|
-
if (this.options.enableTimestamp !== false) {
|
|
515
619
|
MoroLogger.appendToBuilder(' ');
|
|
516
620
|
}
|
|
517
621
|
|
|
622
|
+
// Level with pre-allocated strings
|
|
623
|
+
const levelStr = MoroLogger.LEVEL_STRINGS[entry.level];
|
|
518
624
|
if (colors) {
|
|
519
|
-
MoroLogger.appendToBuilder(
|
|
625
|
+
MoroLogger.appendToBuilder(MoroLogger.COLORS[entry.level]);
|
|
520
626
|
MoroLogger.appendToBuilder(MoroLogger.BOLD);
|
|
521
|
-
MoroLogger.appendToBuilder(
|
|
627
|
+
MoroLogger.appendToBuilder(levelStr);
|
|
522
628
|
MoroLogger.appendToBuilder(levelReset);
|
|
523
629
|
} else {
|
|
524
|
-
MoroLogger.appendToBuilder(
|
|
630
|
+
MoroLogger.appendToBuilder(levelStr);
|
|
525
631
|
}
|
|
526
632
|
|
|
527
633
|
// Context
|
|
528
634
|
if (entry.context && this.options.enableContext !== false) {
|
|
529
|
-
|
|
530
|
-
MoroLogger.appendToBuilder(' '); // Space before context
|
|
635
|
+
MoroLogger.appendToBuilder(' ');
|
|
531
636
|
if (colors) {
|
|
532
|
-
MoroLogger.appendToBuilder(
|
|
637
|
+
MoroLogger.appendToBuilder(MoroLogger.COLORS.context);
|
|
533
638
|
MoroLogger.appendToBuilder(`[${entry.context}]`);
|
|
534
639
|
MoroLogger.appendToBuilder(levelReset);
|
|
535
640
|
} else {
|
|
@@ -538,7 +643,7 @@ export class MoroLogger implements Logger {
|
|
|
538
643
|
}
|
|
539
644
|
|
|
540
645
|
// Message
|
|
541
|
-
MoroLogger.appendToBuilder(' ');
|
|
646
|
+
MoroLogger.appendToBuilder(' ');
|
|
542
647
|
MoroLogger.appendToBuilder(entry.message);
|
|
543
648
|
|
|
544
649
|
// Performance info
|
|
@@ -554,7 +659,7 @@ export class MoroLogger implements Logger {
|
|
|
554
659
|
}
|
|
555
660
|
|
|
556
661
|
if (perfParts.length > 0) {
|
|
557
|
-
MoroLogger.appendToBuilder(' ');
|
|
662
|
+
MoroLogger.appendToBuilder(' ');
|
|
558
663
|
if (colors) {
|
|
559
664
|
MoroLogger.appendToBuilder(perfColor);
|
|
560
665
|
MoroLogger.appendToBuilder(`(${perfParts.join(', ')})`);
|
|
@@ -575,19 +680,20 @@ export class MoroLogger implements Logger {
|
|
|
575
680
|
const cleanMetadata = this.cleanMetadata(entry.metadata);
|
|
576
681
|
|
|
577
682
|
if (Object.keys(cleanMetadata).length > 0) {
|
|
683
|
+
MoroLogger.appendToBuilder(' ');
|
|
578
684
|
if (colors) {
|
|
579
685
|
MoroLogger.appendToBuilder(metaColor);
|
|
580
|
-
MoroLogger.appendToBuilder(this.
|
|
686
|
+
MoroLogger.appendToBuilder(this.safeStringify(cleanMetadata));
|
|
581
687
|
MoroLogger.appendToBuilder(levelReset);
|
|
582
688
|
} else {
|
|
583
|
-
MoroLogger.appendToBuilder(this.
|
|
689
|
+
MoroLogger.appendToBuilder(this.safeStringify(cleanMetadata));
|
|
584
690
|
}
|
|
585
691
|
}
|
|
586
692
|
}
|
|
587
693
|
|
|
588
694
|
// Output main log line with high-performance method
|
|
589
695
|
const finalMessage = MoroLogger.buildString();
|
|
590
|
-
this.output(finalMessage
|
|
696
|
+
this.output(`${finalMessage}\n`, entry.level);
|
|
591
697
|
|
|
592
698
|
// Stack trace for errors
|
|
593
699
|
if (entry.metadata?.stack && (entry.level === 'error' || entry.level === 'fatal')) {
|
|
@@ -607,79 +713,199 @@ export class MoroLogger implements Logger {
|
|
|
607
713
|
return clean;
|
|
608
714
|
}
|
|
609
715
|
|
|
610
|
-
//
|
|
611
|
-
private
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
716
|
+
// High-performance output with buffering
|
|
717
|
+
private output(message: string, level: LogLevel = 'info'): void {
|
|
718
|
+
// Prevent memory exhaustion
|
|
719
|
+
if (
|
|
720
|
+
this.outputBuffer.length >= this.bufferOverflowThreshold &&
|
|
721
|
+
!this.emergencyFlushInProgress
|
|
722
|
+
) {
|
|
723
|
+
this.emergencyFlushInProgress = true;
|
|
724
|
+
this.forceFlushBuffer();
|
|
725
|
+
this.emergencyFlushInProgress = false;
|
|
616
726
|
}
|
|
617
|
-
}
|
|
618
727
|
|
|
619
|
-
// High-performance output with micro-batching
|
|
620
|
-
private output(message: string, level: LogLevel = 'info'): void {
|
|
621
|
-
// Add to buffer
|
|
622
728
|
this.outputBuffer.push(message);
|
|
623
|
-
this.bufferSize
|
|
729
|
+
this.bufferSize++;
|
|
624
730
|
|
|
625
|
-
//
|
|
626
|
-
if (
|
|
731
|
+
// Immediate flush for critical levels or full buffer
|
|
732
|
+
if (level === 'fatal' || level === 'error' || this.bufferSize >= this.maxBufferSize) {
|
|
627
733
|
this.flushBuffer();
|
|
628
734
|
} else {
|
|
629
|
-
// Schedule flush with micro-batching
|
|
630
735
|
this.scheduleFlush();
|
|
631
736
|
}
|
|
632
737
|
}
|
|
633
738
|
|
|
634
739
|
private scheduleFlush(): void {
|
|
635
|
-
if (this.flushTimeout
|
|
740
|
+
if (this.flushTimeout || this.isDestroyed) {
|
|
741
|
+
return; // Already scheduled or destroyed
|
|
742
|
+
}
|
|
636
743
|
|
|
637
744
|
this.flushTimeout = setTimeout(() => {
|
|
638
745
|
this.flushBuffer();
|
|
639
|
-
this.flushTimeout = null;
|
|
640
746
|
}, this.flushInterval);
|
|
747
|
+
|
|
748
|
+
// Unref the timeout so it doesn't prevent process exit (important for tests)
|
|
749
|
+
this.flushTimeout.unref();
|
|
641
750
|
}
|
|
642
751
|
|
|
643
|
-
|
|
644
|
-
if (this.outputBuffer.length === 0)
|
|
752
|
+
public flushBuffer(): void {
|
|
753
|
+
if (this.outputBuffer.length === 0) {
|
|
754
|
+
return;
|
|
755
|
+
}
|
|
645
756
|
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
stdoutMessages.push(message);
|
|
657
|
-
}
|
|
757
|
+
// Group messages by stream type
|
|
758
|
+
const stdoutMessages: string[] = [];
|
|
759
|
+
const stderrMessages: string[] = [];
|
|
760
|
+
|
|
761
|
+
for (const message of this.outputBuffer) {
|
|
762
|
+
// Determine stream based on message content or level
|
|
763
|
+
if (message.includes('ERROR') || message.includes('FATAL')) {
|
|
764
|
+
stderrMessages.push(message);
|
|
765
|
+
} else {
|
|
766
|
+
stdoutMessages.push(message);
|
|
658
767
|
}
|
|
768
|
+
}
|
|
659
769
|
|
|
660
|
-
|
|
661
|
-
|
|
770
|
+
// Write to appropriate streams with error handling
|
|
771
|
+
try {
|
|
772
|
+
if (stdoutMessages.length > 0 && process.stdout.writable) {
|
|
662
773
|
process.stdout.write(stdoutMessages.join(''));
|
|
663
774
|
}
|
|
664
|
-
if (stderrMessages.length > 0) {
|
|
775
|
+
if (stderrMessages.length > 0 && process.stderr.writable) {
|
|
665
776
|
process.stderr.write(stderrMessages.join(''));
|
|
666
777
|
}
|
|
667
778
|
} catch {
|
|
668
|
-
// Fallback to console
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
// eslint-disable-next-line no-console
|
|
675
|
-
console.log(message.trim());
|
|
676
|
-
}
|
|
779
|
+
// Fallback to console if streams fail
|
|
780
|
+
try {
|
|
781
|
+
// eslint-disable-next-line no-console
|
|
782
|
+
console.log(this.outputBuffer.join(''));
|
|
783
|
+
} catch {
|
|
784
|
+
// If even console.log fails, just ignore
|
|
677
785
|
}
|
|
678
786
|
}
|
|
679
787
|
|
|
680
|
-
//
|
|
788
|
+
// Clear buffer
|
|
681
789
|
this.outputBuffer.length = 0;
|
|
682
790
|
this.bufferSize = 0;
|
|
791
|
+
|
|
792
|
+
// Clear timeout
|
|
793
|
+
if (this.flushTimeout) {
|
|
794
|
+
clearTimeout(this.flushTimeout);
|
|
795
|
+
this.flushTimeout = null;
|
|
796
|
+
}
|
|
797
|
+
}
|
|
798
|
+
|
|
799
|
+
// Emergency flush for buffer overflow protection
|
|
800
|
+
private forceFlushBuffer(): void {
|
|
801
|
+
if (this.outputBuffer.length === 0) return;
|
|
802
|
+
|
|
803
|
+
try {
|
|
804
|
+
const message = this.outputBuffer.join('');
|
|
805
|
+
process.stdout.write(message);
|
|
806
|
+
} catch (error) {
|
|
807
|
+
// Emergency fallback - write individual messages
|
|
808
|
+
for (const msg of this.outputBuffer) {
|
|
809
|
+
try {
|
|
810
|
+
process.stdout.write(msg);
|
|
811
|
+
} catch {
|
|
812
|
+
// If even this fails, give up on this batch
|
|
813
|
+
break;
|
|
814
|
+
}
|
|
815
|
+
}
|
|
816
|
+
} finally {
|
|
817
|
+
this.outputBuffer.length = 0;
|
|
818
|
+
this.bufferSize = 0;
|
|
819
|
+
}
|
|
820
|
+
}
|
|
821
|
+
|
|
822
|
+
// Safe stringify with circular reference detection
|
|
823
|
+
private safeStringify(obj: any, maxDepth = 3): string {
|
|
824
|
+
const seen = new WeakSet();
|
|
825
|
+
|
|
826
|
+
const stringify = (value: any, depth: number): any => {
|
|
827
|
+
if (depth > maxDepth) return '[Max Depth Reached]';
|
|
828
|
+
if (value === null || typeof value !== 'object') return value;
|
|
829
|
+
if (seen.has(value)) return '[Circular Reference]';
|
|
830
|
+
|
|
831
|
+
seen.add(value);
|
|
832
|
+
|
|
833
|
+
if (Array.isArray(value)) {
|
|
834
|
+
return value.map(item => stringify(item, depth + 1));
|
|
835
|
+
}
|
|
836
|
+
|
|
837
|
+
const result: any = {};
|
|
838
|
+
for (const [key, val] of Object.entries(value)) {
|
|
839
|
+
if (typeof val !== 'function') {
|
|
840
|
+
// Skip functions
|
|
841
|
+
result[key] = stringify(val, depth + 1);
|
|
842
|
+
}
|
|
843
|
+
}
|
|
844
|
+
return result;
|
|
845
|
+
};
|
|
846
|
+
|
|
847
|
+
try {
|
|
848
|
+
return JSON.stringify(stringify(obj, 0));
|
|
849
|
+
} catch (error) {
|
|
850
|
+
return '[Stringify Error]';
|
|
851
|
+
}
|
|
852
|
+
}
|
|
853
|
+
|
|
854
|
+
// Configuration validation
|
|
855
|
+
private validateOptions(options: LoggerOptions): LoggerOptions {
|
|
856
|
+
const validated = { ...options };
|
|
857
|
+
|
|
858
|
+
// Validate log level
|
|
859
|
+
const validLevels = ['debug', 'info', 'warn', 'error', 'fatal'];
|
|
860
|
+
if (validated.level && !validLevels.includes(validated.level)) {
|
|
861
|
+
console.warn(`[MoroLogger] Invalid log level: ${validated.level}, defaulting to 'info'`);
|
|
862
|
+
validated.level = 'info';
|
|
863
|
+
}
|
|
864
|
+
|
|
865
|
+
// Validate max entries
|
|
866
|
+
if (validated.maxEntries !== undefined) {
|
|
867
|
+
if (validated.maxEntries < 1 || validated.maxEntries > 100000) {
|
|
868
|
+
console.warn(
|
|
869
|
+
`[MoroLogger] Invalid maxEntries: ${validated.maxEntries}, defaulting to 1000`
|
|
870
|
+
);
|
|
871
|
+
validated.maxEntries = 1000;
|
|
872
|
+
}
|
|
873
|
+
}
|
|
874
|
+
|
|
875
|
+
// Validate buffer size
|
|
876
|
+
if (validated.maxBufferSize !== undefined) {
|
|
877
|
+
if (validated.maxBufferSize < 10 || validated.maxBufferSize > 10000) {
|
|
878
|
+
console.warn(
|
|
879
|
+
`[MoroLogger] Invalid maxBufferSize: ${validated.maxBufferSize}, defaulting to 1000`
|
|
880
|
+
);
|
|
881
|
+
validated.maxBufferSize = 1000;
|
|
882
|
+
}
|
|
883
|
+
}
|
|
884
|
+
|
|
885
|
+
return validated;
|
|
886
|
+
}
|
|
887
|
+
|
|
888
|
+
// Error handling methods
|
|
889
|
+
private handleOutputError(outputName: string, error: any): void {
|
|
890
|
+
// Could implement output retry logic, circuit breaker, etc.
|
|
891
|
+
// For now, just track the error
|
|
892
|
+
if (!this.metrics.outputErrors) {
|
|
893
|
+
this.metrics.outputErrors = {};
|
|
894
|
+
}
|
|
895
|
+
this.metrics.outputErrors[outputName] = (this.metrics.outputErrors[outputName] || 0) + 1;
|
|
896
|
+
}
|
|
897
|
+
|
|
898
|
+
private emergencyConsoleWrite(entry: LogEntry): void {
|
|
899
|
+
const message = `${entry.timestamp.toISOString()} ${entry.level.toUpperCase()} ${entry.message}`;
|
|
900
|
+
try {
|
|
901
|
+
if (entry.level === 'error' || entry.level === 'fatal') {
|
|
902
|
+
process.stderr.write(`[EMERGENCY] ${message}\n`);
|
|
903
|
+
} else {
|
|
904
|
+
process.stdout.write(`[EMERGENCY] ${message}\n`);
|
|
905
|
+
}
|
|
906
|
+
} catch {
|
|
907
|
+
// If even emergency write fails, there's nothing more we can do
|
|
908
|
+
}
|
|
683
909
|
}
|
|
684
910
|
|
|
685
911
|
// Force flush streams (useful for shutdown)
|
|
@@ -694,28 +920,40 @@ export class MoroLogger implements Logger {
|
|
|
694
920
|
this.flushBuffer();
|
|
695
921
|
|
|
696
922
|
try {
|
|
697
|
-
// Force flush streams
|
|
923
|
+
// Force flush streams without ending them
|
|
698
924
|
if (process.stdout.writable) {
|
|
699
|
-
process.stdout.
|
|
925
|
+
process.stdout.write(''); // Force flush without ending
|
|
700
926
|
}
|
|
701
927
|
if (process.stderr.writable) {
|
|
702
|
-
process.stderr.
|
|
928
|
+
process.stderr.write(''); // Force flush without ending
|
|
703
929
|
}
|
|
704
930
|
} catch {
|
|
705
931
|
// Ignore flush errors
|
|
706
932
|
}
|
|
707
933
|
}
|
|
708
934
|
|
|
709
|
-
//
|
|
710
|
-
public
|
|
711
|
-
//
|
|
935
|
+
// Destroy logger and clean up all resources (for testing)
|
|
936
|
+
public destroy(): void {
|
|
937
|
+
// Mark as destroyed to prevent new timeouts
|
|
938
|
+
this.isDestroyed = true;
|
|
939
|
+
|
|
940
|
+
// Clear any remaining timeouts
|
|
712
941
|
if (this.flushTimeout) {
|
|
713
942
|
clearTimeout(this.flushTimeout);
|
|
714
943
|
this.flushTimeout = null;
|
|
715
944
|
}
|
|
716
945
|
|
|
717
|
-
// Flush any remaining
|
|
946
|
+
// Flush any remaining buffer
|
|
718
947
|
this.flushBuffer();
|
|
948
|
+
|
|
949
|
+
// Clear outputs and filters
|
|
950
|
+
this.outputs.clear();
|
|
951
|
+
this.filters.clear();
|
|
952
|
+
|
|
953
|
+
// Clear history
|
|
954
|
+
this.history.length = 0;
|
|
955
|
+
this.historyIndex = 0;
|
|
956
|
+
this.historySize = 0;
|
|
719
957
|
}
|
|
720
958
|
}
|
|
721
959
|
|
|
@@ -731,33 +969,6 @@ export const logger = new MoroLogger({
|
|
|
731
969
|
format: (process.env.LOG_FORMAT as any) || 'pretty',
|
|
732
970
|
});
|
|
733
971
|
|
|
734
|
-
// Add cleanup handlers for Jest and other test runners
|
|
735
|
-
if (typeof process !== 'undefined') {
|
|
736
|
-
// Cleanup on process exit
|
|
737
|
-
process.on('beforeExit', () => {
|
|
738
|
-
logger.cleanup();
|
|
739
|
-
});
|
|
740
|
-
|
|
741
|
-
process.on('SIGINT', () => {
|
|
742
|
-
logger.cleanup();
|
|
743
|
-
process.exit(0);
|
|
744
|
-
});
|
|
745
|
-
|
|
746
|
-
process.on('SIGTERM', () => {
|
|
747
|
-
logger.cleanup();
|
|
748
|
-
process.exit(0);
|
|
749
|
-
});
|
|
750
|
-
|
|
751
|
-
// For Jest and other test runners - cleanup on uncaught exceptions
|
|
752
|
-
process.on('uncaughtException', () => {
|
|
753
|
-
logger.cleanup();
|
|
754
|
-
});
|
|
755
|
-
|
|
756
|
-
process.on('unhandledRejection', () => {
|
|
757
|
-
logger.cleanup();
|
|
758
|
-
});
|
|
759
|
-
}
|
|
760
|
-
|
|
761
972
|
/**
|
|
762
973
|
* Configure the global logger with new settings
|
|
763
974
|
* This allows runtime configuration of the logger
|
|
@@ -770,6 +981,14 @@ export function configureGlobalLogger(options: Partial<LoggerOptions>): void {
|
|
|
770
981
|
// For now, focusing on level which is the most critical
|
|
771
982
|
}
|
|
772
983
|
|
|
984
|
+
/**
|
|
985
|
+
* Destroy the global logger and clean up resources (for testing)
|
|
986
|
+
* @internal
|
|
987
|
+
*/
|
|
988
|
+
export function destroyGlobalLogger(): void {
|
|
989
|
+
logger.destroy();
|
|
990
|
+
}
|
|
991
|
+
|
|
773
992
|
/**
|
|
774
993
|
* Apply logging configuration from the config system and/or createApp options
|
|
775
994
|
*/
|