@morojs/moro 1.7.30 → 1.8.1
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 +89 -46
- package/dist/core/auth/morojs-adapter.js +95 -45
- package/dist/core/auth/morojs-adapter.js.map +1 -1
- package/dist/core/config/config-manager.js.map +1 -1
- package/dist/core/config/config-sources.js +119 -48
- package/dist/core/config/config-sources.js.map +1 -1
- package/dist/core/config/config-validator.js +189 -8
- package/dist/core/config/config-validator.js.map +1 -1
- package/dist/core/config/file-loader.js.map +1 -1
- package/dist/core/config/index.js.map +1 -1
- package/dist/core/config/schema.js +35 -4
- package/dist/core/config/schema.js.map +1 -1
- package/dist/core/config/utils.js.map +1 -1
- package/dist/core/database/adapters/drizzle.js +2 -2
- package/dist/core/database/adapters/drizzle.js.map +1 -1
- package/dist/core/database/adapters/index.js.map +1 -1
- package/dist/core/database/adapters/mongodb.d.ts +1 -0
- package/dist/core/database/adapters/mongodb.js +16 -0
- package/dist/core/database/adapters/mongodb.js.map +1 -1
- package/dist/core/database/adapters/mysql.d.ts +1 -0
- package/dist/core/database/adapters/mysql.js +13 -2
- package/dist/core/database/adapters/mysql.js.map +1 -1
- package/dist/core/database/adapters/postgresql.js +2 -2
- package/dist/core/database/adapters/postgresql.js.map +1 -1
- package/dist/core/database/adapters/redis.js.map +1 -1
- package/dist/core/database/adapters/sql-safety.js +5 -4
- package/dist/core/database/adapters/sql-safety.js.map +1 -1
- package/dist/core/database/adapters/sqlite.js.map +1 -1
- package/dist/core/database/index.js.map +1 -1
- package/dist/core/docs/index.js +11 -7
- package/dist/core/docs/index.js.map +1 -1
- package/dist/core/docs/openapi-generator.js +8 -6
- package/dist/core/docs/openapi-generator.js.map +1 -1
- package/dist/core/docs/schema-to-openapi.js +3 -3
- package/dist/core/docs/schema-to-openapi.js.map +1 -1
- package/dist/core/docs/simple-docs.js.map +1 -1
- package/dist/core/docs/swagger-ui.js.map +1 -1
- package/dist/core/docs/zod-to-openapi.js +2 -2
- package/dist/core/docs/zod-to-openapi.js.map +1 -1
- package/dist/core/events/event-bus.js +14 -5
- package/dist/core/events/event-bus.js.map +1 -1
- package/dist/core/events/index.js.map +1 -1
- package/dist/core/framework.d.ts +41 -3
- package/dist/core/framework.js +342 -95
- package/dist/core/framework.js.map +1 -1
- package/dist/core/graphql/adapter.js.map +1 -1
- package/dist/core/graphql/adapters/graphql-js-adapter.js.map +1 -1
- package/dist/core/graphql/core.js.map +1 -1
- package/dist/core/graphql/index.js.map +1 -1
- package/dist/core/graphql/loader.js.map +1 -1
- package/dist/core/graphql/types.js.map +1 -1
- package/dist/core/grpc/adapters/grpc-js-adapter.js +4 -0
- package/dist/core/grpc/adapters/grpc-js-adapter.js.map +1 -1
- package/dist/core/grpc/adapters/index.js.map +1 -1
- package/dist/core/grpc/grpc-adapter.js.map +1 -1
- package/dist/core/grpc/grpc-manager.js.map +1 -1
- package/dist/core/grpc/index.js.map +1 -1
- package/dist/core/grpc/middleware/auth.js +1 -1
- package/dist/core/grpc/middleware/auth.js.map +1 -1
- package/dist/core/grpc/middleware/logging.js.map +1 -1
- package/dist/core/grpc/middleware/validation.js +1 -1
- package/dist/core/grpc/middleware/validation.js.map +1 -1
- package/dist/core/grpc/types.d.ts +7 -7
- package/dist/core/grpc/types.js.map +1 -1
- package/dist/core/http/http-server.d.ts +17 -23
- package/dist/core/http/http-server.js +109 -249
- package/dist/core/http/http-server.js.map +1 -1
- package/dist/core/http/http2-server.d.ts +6 -16
- package/dist/core/http/http2-server.js +40 -83
- package/dist/core/http/http2-server.js.map +1 -1
- package/dist/core/http/index.d.ts +1 -0
- package/dist/core/http/index.js +3 -0
- package/dist/core/http/index.js.map +1 -1
- package/dist/core/http/moro-engine-server.d.ts +263 -0
- package/dist/core/http/moro-engine-server.js +1962 -0
- package/dist/core/http/moro-engine-server.js.map +1 -0
- package/dist/core/http/utils/compression.d.ts +47 -0
- package/dist/core/http/utils/compression.js +132 -0
- package/dist/core/http/utils/compression.js.map +1 -0
- package/dist/core/http/utils/lazy-event-emitter.d.ts +11 -0
- package/dist/core/http/utils/lazy-event-emitter.js +69 -0
- package/dist/core/http/utils/lazy-event-emitter.js.map +1 -0
- package/dist/core/http/utils/multipart-parser.d.ts +32 -0
- package/dist/core/http/utils/multipart-parser.js +215 -0
- package/dist/core/http/utils/multipart-parser.js.map +1 -0
- package/dist/core/http/utils/query-parser.d.ts +1 -0
- package/dist/core/http/utils/query-parser.js +44 -0
- package/dist/core/http/utils/query-parser.js.map +1 -0
- package/dist/core/http/utils/size.d.ts +33 -0
- package/dist/core/http/utils/size.js +37 -0
- package/dist/core/http/utils/size.js.map +1 -0
- package/dist/core/http/utils/ssl-config.d.ts +69 -0
- package/dist/core/http/utils/ssl-config.js +116 -0
- package/dist/core/http/utils/ssl-config.js.map +1 -0
- package/dist/core/http/utils/uws-worker-clustering.js +45 -32
- package/dist/core/http/utils/uws-worker-clustering.js.map +1 -1
- package/dist/core/http/uws-http-server.d.ts +25 -3
- package/dist/core/http/uws-http-server.js +465 -86
- package/dist/core/http/uws-http-server.js.map +1 -1
- package/dist/core/jobs/cron-parser.js +7 -5
- package/dist/core/jobs/cron-parser.js.map +1 -1
- package/dist/core/jobs/index.js.map +1 -1
- package/dist/core/jobs/job-executor.d.ts +1 -1
- package/dist/core/jobs/job-executor.js.map +1 -1
- package/dist/core/jobs/job-scheduler.d.ts +3 -3
- package/dist/core/jobs/job-scheduler.js.map +1 -1
- package/dist/core/jobs/job-state-manager.d.ts +3 -3
- package/dist/core/jobs/job-state-manager.js +25 -4
- package/dist/core/jobs/job-state-manager.js.map +1 -1
- package/dist/core/jobs/leader-election.d.ts +15 -0
- package/dist/core/jobs/leader-election.js +158 -69
- package/dist/core/jobs/leader-election.js.map +1 -1
- package/dist/core/jobs/types.d.ts +4 -4
- package/dist/core/jobs/types.js.map +1 -1
- package/dist/core/jobs/utils.d.ts +1 -1
- package/dist/core/jobs/utils.js +7 -3
- package/dist/core/jobs/utils.js.map +1 -1
- package/dist/core/logger/filters.js +3 -2
- package/dist/core/logger/filters.js.map +1 -1
- package/dist/core/logger/index.js.map +1 -1
- package/dist/core/logger/logger.js +56 -25
- package/dist/core/logger/logger.js.map +1 -1
- package/dist/core/logger/outputs.js.map +1 -1
- package/dist/core/mail/adapters/console-adapter.js.map +1 -1
- package/dist/core/mail/adapters/index.js.map +1 -1
- package/dist/core/mail/adapters/nodemailer-adapter.js.map +1 -1
- package/dist/core/mail/adapters/resend-adapter.js.map +1 -1
- package/dist/core/mail/adapters/sendgrid-adapter.js.map +1 -1
- package/dist/core/mail/adapters/ses-adapter.js.map +1 -1
- package/dist/core/mail/index.js.map +1 -1
- package/dist/core/mail/mail-adapter.js.map +1 -1
- package/dist/core/mail/mail-manager.d.ts +10 -0
- package/dist/core/mail/mail-manager.js +21 -5
- package/dist/core/mail/mail-manager.js.map +1 -1
- package/dist/core/mail/template-engine.js.map +1 -1
- package/dist/core/mail/types.js.map +1 -1
- package/dist/core/middleware/built-in/auth/core.js +3 -3
- package/dist/core/middleware/built-in/auth/core.js.map +1 -1
- package/dist/core/middleware/built-in/auth/helpers.js +4 -4
- package/dist/core/middleware/built-in/auth/helpers.js.map +1 -1
- package/dist/core/middleware/built-in/auth/hook.js.map +1 -1
- package/dist/core/middleware/built-in/auth/index.js.map +1 -1
- package/dist/core/middleware/built-in/auth/jwt-helpers.d.ts +4 -4
- package/dist/core/middleware/built-in/auth/jwt-helpers.js.map +1 -1
- package/dist/core/middleware/built-in/auth/middleware.js.map +1 -1
- package/dist/core/middleware/built-in/auth/providers.js.map +1 -1
- package/dist/core/middleware/built-in/body-parsers/index.js.map +1 -1
- package/dist/core/middleware/built-in/body-size/core.js +2 -2
- package/dist/core/middleware/built-in/body-size/core.js.map +1 -1
- package/dist/core/middleware/built-in/body-size/hook.js.map +1 -1
- package/dist/core/middleware/built-in/body-size/index.js.map +1 -1
- package/dist/core/middleware/built-in/body-size/middleware.js.map +1 -1
- package/dist/core/middleware/built-in/cache/adapters/cache/file.js +3 -1
- package/dist/core/middleware/built-in/cache/adapters/cache/file.js.map +1 -1
- package/dist/core/middleware/built-in/cache/adapters/cache/index.js.map +1 -1
- package/dist/core/middleware/built-in/cache/adapters/cache/memory.js.map +1 -1
- package/dist/core/middleware/built-in/cache/adapters/cache/redis.js.map +1 -1
- package/dist/core/middleware/built-in/cache/adapters/index.js.map +1 -1
- package/dist/core/middleware/built-in/cache/core.js.map +1 -1
- package/dist/core/middleware/built-in/cache/hook.js +3 -3
- package/dist/core/middleware/built-in/cache/hook.js.map +1 -1
- package/dist/core/middleware/built-in/cache/index.js.map +1 -1
- package/dist/core/middleware/built-in/cache/middleware.js.map +1 -1
- package/dist/core/middleware/built-in/cdn/adapters/cdn/azure.js.map +1 -1
- package/dist/core/middleware/built-in/cdn/adapters/cdn/cloudflare.js.map +1 -1
- package/dist/core/middleware/built-in/cdn/adapters/cdn/cloudfront.js.map +1 -1
- package/dist/core/middleware/built-in/cdn/adapters/cdn/index.js.map +1 -1
- package/dist/core/middleware/built-in/cdn/adapters/index.js.map +1 -1
- package/dist/core/middleware/built-in/cdn/core.js.map +1 -1
- package/dist/core/middleware/built-in/cdn/hook.js.map +1 -1
- package/dist/core/middleware/built-in/cdn/index.js.map +1 -1
- package/dist/core/middleware/built-in/cdn/middleware.js.map +1 -1
- package/dist/core/middleware/built-in/compression/core.d.ts +3 -0
- package/dist/core/middleware/built-in/compression/core.js +28 -34
- package/dist/core/middleware/built-in/compression/core.js.map +1 -1
- package/dist/core/middleware/built-in/compression/hook.js.map +1 -1
- package/dist/core/middleware/built-in/compression/index.js.map +1 -1
- package/dist/core/middleware/built-in/compression/middleware.js.map +1 -1
- package/dist/core/middleware/built-in/cookie/core.js.map +1 -1
- package/dist/core/middleware/built-in/cookie/hook.js.map +1 -1
- package/dist/core/middleware/built-in/cookie/index.js.map +1 -1
- package/dist/core/middleware/built-in/cookie/middleware.js.map +1 -1
- package/dist/core/middleware/built-in/cors/core.js.map +1 -1
- package/dist/core/middleware/built-in/cors/hook.js.map +1 -1
- package/dist/core/middleware/built-in/cors/index.js.map +1 -1
- package/dist/core/middleware/built-in/cors/middleware.js.map +1 -1
- package/dist/core/middleware/built-in/csp/core.js.map +1 -1
- package/dist/core/middleware/built-in/csp/hook.js.map +1 -1
- package/dist/core/middleware/built-in/csp/index.js.map +1 -1
- package/dist/core/middleware/built-in/csp/middleware.js.map +1 -1
- package/dist/core/middleware/built-in/csrf/core.js +1 -1
- package/dist/core/middleware/built-in/csrf/core.js.map +1 -1
- package/dist/core/middleware/built-in/csrf/hook.js.map +1 -1
- package/dist/core/middleware/built-in/csrf/index.js.map +1 -1
- package/dist/core/middleware/built-in/csrf/middleware.js.map +1 -1
- package/dist/core/middleware/built-in/error-tracker/index.js.map +1 -1
- package/dist/core/middleware/built-in/error-tracker/middleware.js.map +1 -1
- package/dist/core/middleware/built-in/graphql/core.js.map +1 -1
- package/dist/core/middleware/built-in/graphql/helpers.js.map +1 -1
- package/dist/core/middleware/built-in/graphql/hook.js.map +1 -1
- package/dist/core/middleware/built-in/graphql/index.js.map +1 -1
- package/dist/core/middleware/built-in/graphql/middleware.js.map +1 -1
- package/dist/core/middleware/built-in/graphql/subscriptions.js.map +1 -1
- package/dist/core/middleware/built-in/helmet/core.js.map +1 -1
- package/dist/core/middleware/built-in/helmet/hook.js.map +1 -1
- package/dist/core/middleware/built-in/helmet/index.js.map +1 -1
- package/dist/core/middleware/built-in/helmet/middleware.js.map +1 -1
- package/dist/core/middleware/built-in/http2/core.js.map +1 -1
- package/dist/core/middleware/built-in/http2/hook.js.map +1 -1
- package/dist/core/middleware/built-in/http2/index.js.map +1 -1
- package/dist/core/middleware/built-in/http2/middleware.js.map +1 -1
- package/dist/core/middleware/built-in/index.js.map +1 -1
- package/dist/core/middleware/built-in/performance-monitor/index.js.map +1 -1
- package/dist/core/middleware/built-in/performance-monitor/middleware.js.map +1 -1
- package/dist/core/middleware/built-in/range/core.js +4 -1
- package/dist/core/middleware/built-in/range/core.js.map +1 -1
- package/dist/core/middleware/built-in/range/hook.js.map +1 -1
- package/dist/core/middleware/built-in/range/index.js.map +1 -1
- package/dist/core/middleware/built-in/range/middleware.js.map +1 -1
- package/dist/core/middleware/built-in/rate-limit/core.js.map +1 -1
- package/dist/core/middleware/built-in/rate-limit/hook.js.map +1 -1
- package/dist/core/middleware/built-in/rate-limit/index.js.map +1 -1
- package/dist/core/middleware/built-in/rate-limit/middleware.js.map +1 -1
- package/dist/core/middleware/built-in/request-logger/index.js.map +1 -1
- package/dist/core/middleware/built-in/request-logger/middleware.js.map +1 -1
- package/dist/core/middleware/built-in/session/core.js +4 -4
- package/dist/core/middleware/built-in/session/core.js.map +1 -1
- package/dist/core/middleware/built-in/session/hook.js.map +1 -1
- package/dist/core/middleware/built-in/session/index.js.map +1 -1
- package/dist/core/middleware/built-in/session/middleware.js.map +1 -1
- package/dist/core/middleware/built-in/sse/core.js.map +1 -1
- package/dist/core/middleware/built-in/sse/hook.js.map +1 -1
- package/dist/core/middleware/built-in/sse/index.js.map +1 -1
- package/dist/core/middleware/built-in/sse/middleware.js.map +1 -1
- package/dist/core/middleware/built-in/static/core.js.map +1 -1
- package/dist/core/middleware/built-in/static/hook.js.map +1 -1
- package/dist/core/middleware/built-in/static/index.js.map +1 -1
- package/dist/core/middleware/built-in/static/middleware.js.map +1 -1
- package/dist/core/middleware/built-in/template/core.js +1 -1
- package/dist/core/middleware/built-in/template/core.js.map +1 -1
- package/dist/core/middleware/built-in/template/hook.js.map +1 -1
- package/dist/core/middleware/built-in/template/index.js.map +1 -1
- package/dist/core/middleware/built-in/template/middleware.js.map +1 -1
- package/dist/core/middleware/built-in/upload/core.js.map +1 -1
- package/dist/core/middleware/built-in/upload/hook.js.map +1 -1
- package/dist/core/middleware/built-in/upload/index.js.map +1 -1
- package/dist/core/middleware/built-in/upload/middleware.js.map +1 -1
- package/dist/core/middleware/built-in/validation/core.js.map +1 -1
- package/dist/core/middleware/built-in/validation/hook.js.map +1 -1
- package/dist/core/middleware/built-in/validation/index.js.map +1 -1
- package/dist/core/middleware/built-in/validation/middleware.js.map +1 -1
- package/dist/core/middleware/index.js +2 -2
- package/dist/core/middleware/index.js.map +1 -1
- package/dist/core/modules/auto-discovery.js +11 -7
- package/dist/core/modules/auto-discovery.js.map +1 -1
- package/dist/core/modules/index.js.map +1 -1
- package/dist/core/modules/modules.js +18 -13
- package/dist/core/modules/modules.js.map +1 -1
- package/dist/core/networking/adapters/engine-adapter.d.ts +23 -0
- package/dist/core/networking/adapters/engine-adapter.js +365 -0
- package/dist/core/networking/adapters/engine-adapter.js.map +1 -0
- package/dist/core/networking/adapters/index.d.ts +1 -0
- package/dist/core/networking/adapters/index.js +1 -0
- package/dist/core/networking/adapters/index.js.map +1 -1
- package/dist/core/networking/adapters/socketio-adapter.d.ts +1 -0
- package/dist/core/networking/adapters/socketio-adapter.js +12 -1
- package/dist/core/networking/adapters/socketio-adapter.js.map +1 -1
- package/dist/core/networking/adapters/uws-adapter.js +27 -16
- package/dist/core/networking/adapters/uws-adapter.js.map +1 -1
- package/dist/core/networking/adapters/ws-adapter.d.ts +15 -0
- package/dist/core/networking/adapters/ws-adapter.js +120 -6
- package/dist/core/networking/adapters/ws-adapter.js.map +1 -1
- package/dist/core/networking/index.js.map +1 -1
- package/dist/core/networking/service-discovery.js +7 -5
- package/dist/core/networking/service-discovery.js.map +1 -1
- package/dist/core/networking/websocket-adapter.d.ts +22 -3
- package/dist/core/networking/websocket-adapter.js.map +1 -1
- package/dist/core/networking/websocket-manager.js +70 -67
- package/dist/core/networking/websocket-manager.js.map +1 -1
- package/dist/core/pooling/object-pool-manager.js +6 -0
- package/dist/core/pooling/object-pool-manager.js.map +1 -1
- package/dist/core/queue/adapters/bull-adapter.js.map +1 -1
- package/dist/core/queue/adapters/index.js.map +1 -1
- package/dist/core/queue/adapters/kafka-adapter.js +2 -2
- package/dist/core/queue/adapters/kafka-adapter.js.map +1 -1
- package/dist/core/queue/adapters/memory-adapter.js +6 -6
- package/dist/core/queue/adapters/memory-adapter.js.map +1 -1
- package/dist/core/queue/adapters/rabbitmq-adapter.d.ts +50 -0
- package/dist/core/queue/adapters/rabbitmq-adapter.js +176 -20
- package/dist/core/queue/adapters/rabbitmq-adapter.js.map +1 -1
- package/dist/core/queue/adapters/sqs-adapter.d.ts +12 -2
- package/dist/core/queue/adapters/sqs-adapter.js +75 -24
- package/dist/core/queue/adapters/sqs-adapter.js.map +1 -1
- package/dist/core/queue/index.js.map +1 -1
- package/dist/core/queue/middleware/index.js.map +1 -1
- package/dist/core/queue/middleware/monitoring.d.ts +1 -1
- package/dist/core/queue/middleware/monitoring.js.map +1 -1
- package/dist/core/queue/middleware/priority.js +2 -1
- package/dist/core/queue/middleware/priority.js.map +1 -1
- package/dist/core/queue/middleware/rate-limit.js.map +1 -1
- package/dist/core/queue/queue-adapter.js.map +1 -1
- package/dist/core/queue/queue-manager.js.map +1 -1
- package/dist/core/queue/types.d.ts +8 -8
- package/dist/core/queue/types.js.map +1 -1
- package/dist/core/routing/app-integration.js.map +1 -1
- package/dist/core/routing/create-router.js.map +1 -1
- package/dist/core/routing/index.js.map +1 -1
- package/dist/core/routing/path-matcher.js.map +1 -1
- package/dist/core/routing/radix-tree.js.map +1 -1
- package/dist/core/routing/router.js.map +1 -1
- package/dist/core/routing/unified-router.js +12 -4
- package/dist/core/routing/unified-router.js.map +1 -1
- package/dist/core/runtime/aws-lambda-adapter.js.map +1 -1
- package/dist/core/runtime/base-adapter.js +2 -2
- package/dist/core/runtime/base-adapter.js.map +1 -1
- package/dist/core/runtime/cloudflare-workers-adapter.js +2 -0
- package/dist/core/runtime/cloudflare-workers-adapter.js.map +1 -1
- package/dist/core/runtime/index.js.map +1 -1
- package/dist/core/runtime/node-adapter.js +19 -17
- package/dist/core/runtime/node-adapter.js.map +1 -1
- package/dist/core/runtime/vercel-edge-adapter.js +2 -0
- package/dist/core/runtime/vercel-edge-adapter.js.map +1 -1
- package/dist/core/utilities/circuit-breaker.d.ts +1 -0
- package/dist/core/utilities/circuit-breaker.js +25 -2
- package/dist/core/utilities/circuit-breaker.js.map +1 -1
- package/dist/core/utilities/container.js +9 -9
- package/dist/core/utilities/container.js.map +1 -1
- package/dist/core/utilities/hooks.js +28 -6
- package/dist/core/utilities/hooks.js.map +1 -1
- package/dist/core/utilities/index.js.map +1 -1
- package/dist/core/utilities/module-path.js.map +1 -1
- package/dist/core/utilities/package-utils.d.ts +68 -0
- package/dist/core/utilities/package-utils.js +198 -1
- package/dist/core/utilities/package-utils.js.map +1 -1
- package/dist/core/utilities/response-helpers.js +1 -1
- package/dist/core/utilities/response-helpers.js.map +1 -1
- package/dist/core/validation/adapters.js.map +1 -1
- package/dist/core/validation/error-handler.js.map +1 -1
- package/dist/core/validation/index.js.map +1 -1
- package/dist/core/validation/schema-interface.js.map +1 -1
- package/dist/core/workers/facade.js.map +1 -1
- package/dist/core/workers/index.js.map +1 -1
- package/dist/core/workers/worker-entry.d.ts +1 -0
- package/dist/core/workers/worker-entry.js +12 -0
- package/dist/core/workers/worker-entry.js.map +1 -0
- package/dist/core/workers/worker-manager.d.ts +23 -2
- package/dist/core/workers/worker-manager.js +117 -17
- package/dist/core/workers/worker-manager.js.map +1 -1
- package/dist/core/workers/worker.js +8 -6
- package/dist/core/workers/worker.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +5 -2
- package/dist/index.js.map +1 -1
- package/dist/moro.d.ts +20 -1
- package/dist/moro.js +230 -70
- package/dist/moro.js.map +1 -1
- package/dist/types/auth.d.ts +4 -4
- package/dist/types/auth.js.map +1 -1
- package/dist/types/cache.js.map +1 -1
- package/dist/types/cdn.js.map +1 -1
- package/dist/types/config.d.ts +100 -15
- package/dist/types/config.js.map +1 -1
- package/dist/types/core.js.map +1 -1
- package/dist/types/database.js.map +1 -1
- package/dist/types/discovery.js.map +1 -1
- package/dist/types/events.js.map +1 -1
- package/dist/types/hooks.js.map +1 -1
- package/dist/types/http.js.map +1 -1
- package/dist/types/logger.js.map +1 -1
- package/dist/types/module.js.map +1 -1
- package/dist/types/runtime.js.map +1 -1
- package/dist/types/session.js.map +1 -1
- package/package.json +32 -17
package/dist/moro.js
CHANGED
|
@@ -242,21 +242,29 @@ export class Moro extends EventEmitter {
|
|
|
242
242
|
// Default to enabled (true) unless explicitly disabled
|
|
243
243
|
const jobsEnabled = this.config.jobs?.enabled !== false && options.jobs?.enabled !== false;
|
|
244
244
|
if (jobsEnabled) {
|
|
245
|
-
const
|
|
245
|
+
const le = this.config.jobs?.leaderElection;
|
|
246
|
+
const leaderElectionOptions = le?.enabled !== false
|
|
246
247
|
? {
|
|
247
|
-
strategy:
|
|
248
|
-
lockPath:
|
|
249
|
-
lockTimeout:
|
|
250
|
-
heartbeatInterval
|
|
248
|
+
strategy: le?.strategy ?? 'file',
|
|
249
|
+
...(le?.lockPath !== undefined ? { lockPath: le.lockPath } : {}),
|
|
250
|
+
...(le?.lockTimeout !== undefined ? { lockTimeout: le.lockTimeout } : {}),
|
|
251
|
+
...(le?.heartbeatInterval !== undefined
|
|
252
|
+
? { heartbeatInterval: le.heartbeatInterval }
|
|
253
|
+
: {}),
|
|
251
254
|
}
|
|
252
255
|
: undefined;
|
|
256
|
+
const jobs = this.config.jobs;
|
|
253
257
|
const jobSchedulerOptions = {
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
258
|
+
enableLeaderElection: jobs?.leaderElection?.enabled !== false,
|
|
259
|
+
...(jobs?.maxConcurrentJobs !== undefined
|
|
260
|
+
? { maxConcurrentJobs: jobs.maxConcurrentJobs }
|
|
261
|
+
: {}),
|
|
262
|
+
...(leaderElectionOptions !== undefined ? { leaderElection: leaderElectionOptions } : {}),
|
|
263
|
+
...(jobs?.executor !== undefined ? { executor: jobs.executor } : {}),
|
|
264
|
+
...(jobs?.stateManager !== undefined ? { stateManager: jobs.stateManager } : {}),
|
|
265
|
+
...(jobs?.gracefulShutdownTimeout !== undefined
|
|
266
|
+
? { gracefulShutdownTimeout: jobs.gracefulShutdownTimeout }
|
|
267
|
+
: {}),
|
|
260
268
|
};
|
|
261
269
|
this.jobScheduler = new JobScheduler(createFrameworkLogger('Jobs'), jobSchedulerOptions);
|
|
262
270
|
this.jobHealthChecker = new JobHealthChecker(this.jobScheduler, createFrameworkLogger('JobHealth'));
|
|
@@ -277,7 +285,7 @@ export class Moro extends EventEmitter {
|
|
|
277
285
|
// is registered before module middleware that might bypass it
|
|
278
286
|
this.autoDiscoveryOptions = options.autoDiscover !== false ? options : null;
|
|
279
287
|
// Emit initialization event through enterprise event bus
|
|
280
|
-
this.eventBus.emit('framework:initialized', {
|
|
288
|
+
void this.eventBus.emit('framework:initialized', {
|
|
281
289
|
options,
|
|
282
290
|
config: this.config,
|
|
283
291
|
runtime: this.runtimeType,
|
|
@@ -459,7 +467,7 @@ export class Moro extends EventEmitter {
|
|
|
459
467
|
enableDocs(config) {
|
|
460
468
|
this.documentation.enableDocs(config, this.intelligentRouting);
|
|
461
469
|
this.logger.info(`API Documentation enabled at ${config.basePath || '/docs'}`, 'Documentation');
|
|
462
|
-
this.eventBus.emit('docs:enabled', { config });
|
|
470
|
+
void this.eventBus.emit('docs:enabled', { config });
|
|
463
471
|
}
|
|
464
472
|
// Get OpenAPI specification
|
|
465
473
|
getOpenAPISpec() {
|
|
@@ -499,7 +507,7 @@ export class Moro extends EventEmitter {
|
|
|
499
507
|
// Standard middleware integration (req, res, next pattern)
|
|
500
508
|
if (typeof middlewareOrFunction === 'function' && middlewareOrFunction.length >= 3) {
|
|
501
509
|
this.coreFramework.addMiddleware(middlewareOrFunction);
|
|
502
|
-
this.eventBus.emit('middleware:registered', {
|
|
510
|
+
void this.eventBus.emit('middleware:registered', {
|
|
503
511
|
type: 'standard',
|
|
504
512
|
middleware: middlewareOrFunction,
|
|
505
513
|
});
|
|
@@ -508,7 +516,7 @@ export class Moro extends EventEmitter {
|
|
|
508
516
|
// Function-style middleware execution
|
|
509
517
|
if (typeof middlewareOrFunction === 'function' && middlewareOrFunction.length <= 1) {
|
|
510
518
|
await middlewareOrFunction(this);
|
|
511
|
-
this.eventBus.emit('middleware:executed', {
|
|
519
|
+
void this.eventBus.emit('middleware:executed', {
|
|
512
520
|
type: 'function',
|
|
513
521
|
middleware: middlewareOrFunction,
|
|
514
522
|
});
|
|
@@ -525,7 +533,7 @@ export class Moro extends EventEmitter {
|
|
|
525
533
|
return this;
|
|
526
534
|
}
|
|
527
535
|
// Fallback: emit event for unknown middleware types
|
|
528
|
-
this.eventBus.emit('middleware:advanced', {
|
|
536
|
+
void this.eventBus.emit('middleware:advanced', {
|
|
529
537
|
middleware: middlewareOrFunction,
|
|
530
538
|
config,
|
|
531
539
|
});
|
|
@@ -595,14 +603,14 @@ export class Moro extends EventEmitter {
|
|
|
595
603
|
}
|
|
596
604
|
// Module loading with events
|
|
597
605
|
async loadModule(moduleOrPath) {
|
|
598
|
-
this.eventBus.emit('module:loading', {
|
|
606
|
+
void this.eventBus.emit('module:loading', {
|
|
599
607
|
moduleId: typeof moduleOrPath === 'string' ? moduleOrPath : moduleOrPath.name,
|
|
600
608
|
});
|
|
601
609
|
if (typeof moduleOrPath === 'string') {
|
|
602
610
|
const module = await this.importModule(moduleOrPath);
|
|
603
611
|
await this.coreFramework.loadModule(module);
|
|
604
612
|
this.loadedModules.add(moduleOrPath);
|
|
605
|
-
this.eventBus.emit('module:loaded', {
|
|
613
|
+
void this.eventBus.emit('module:loaded', {
|
|
606
614
|
moduleId: module.name,
|
|
607
615
|
version: module.version || '1.0.0',
|
|
608
616
|
});
|
|
@@ -610,7 +618,7 @@ export class Moro extends EventEmitter {
|
|
|
610
618
|
else {
|
|
611
619
|
await this.coreFramework.loadModule(moduleOrPath);
|
|
612
620
|
this.loadedModules.add(moduleOrPath.name);
|
|
613
|
-
this.eventBus.emit('module:loaded', {
|
|
621
|
+
void this.eventBus.emit('module:loaded', {
|
|
614
622
|
moduleId: moduleOrPath.name,
|
|
615
623
|
version: moduleOrPath.version || '1.0.0',
|
|
616
624
|
});
|
|
@@ -624,7 +632,7 @@ export class Moro extends EventEmitter {
|
|
|
624
632
|
}
|
|
625
633
|
// Database helper with events
|
|
626
634
|
database(adapter) {
|
|
627
|
-
this.eventBus.emit('database:connected', {
|
|
635
|
+
void this.eventBus.emit('database:connected', {
|
|
628
636
|
adapter: adapter.constructor.name,
|
|
629
637
|
config: 'hidden',
|
|
630
638
|
});
|
|
@@ -747,7 +755,11 @@ export class Moro extends EventEmitter {
|
|
|
747
755
|
this.startWithClustering(port, host, callback);
|
|
748
756
|
return;
|
|
749
757
|
}
|
|
750
|
-
|
|
758
|
+
// Single-process graceful shutdown: SIGINT/SIGTERM (Ctrl-C) drain in-flight
|
|
759
|
+
// work via close() by default; a second signal force-exits. Opt out with
|
|
760
|
+
// `server.gracefulShutdown: false`. (Cluster mode wires its own handlers.)
|
|
761
|
+
this.registerProcessShutdownHandlers();
|
|
762
|
+
void this.eventBus.emit('server:starting', { port, runtime: this.runtimeType });
|
|
751
763
|
// Add documentation middleware first (if enabled)
|
|
752
764
|
try {
|
|
753
765
|
const docsMiddleware = this.documentation.getDocsMiddleware();
|
|
@@ -767,8 +779,11 @@ export class Moro extends EventEmitter {
|
|
|
767
779
|
const startServer = () => {
|
|
768
780
|
const actualCallback = () => {
|
|
769
781
|
const displayHost = host || 'localhost';
|
|
782
|
+
const serverKind = this.engine;
|
|
770
783
|
this.logger.info('Moro Server Started', 'Server');
|
|
771
784
|
this.logger.info(`Runtime: ${this.runtimeType}`, 'Server');
|
|
785
|
+
this.logger.info(`HTTP engine: ${serverKind.server}` +
|
|
786
|
+
(serverKind.enginePackage ? ` (${serverKind.enginePackage})` : ''), 'Server');
|
|
772
787
|
this.logger.info(`HTTP API: http://${displayHost}:${port}`, 'Server');
|
|
773
788
|
if (this.config.websocket.enabled) {
|
|
774
789
|
this.logger.info(`WebSocket: ws://${displayHost}:${port}`, 'Server');
|
|
@@ -781,7 +796,11 @@ export class Moro extends EventEmitter {
|
|
|
781
796
|
// Log performance stats
|
|
782
797
|
this.unifiedRouter.logPerformanceStats();
|
|
783
798
|
}
|
|
784
|
-
this.eventBus.emit('server:started', {
|
|
799
|
+
void this.eventBus.emit('server:started', {
|
|
800
|
+
port,
|
|
801
|
+
runtime: this.runtimeType,
|
|
802
|
+
engine: serverKind,
|
|
803
|
+
});
|
|
785
804
|
// Start job scheduler after server starts
|
|
786
805
|
this.startJobScheduler().catch(err => {
|
|
787
806
|
this.logger.error(`Failed to start job scheduler: ${String(err)}`);
|
|
@@ -813,20 +832,30 @@ export class Moro extends EventEmitter {
|
|
|
813
832
|
this.ensureAutoDiscoveryComplete().then(() => this.ensureRoutesLoaded()),
|
|
814
833
|
this.processQueuedWebSocketRegistrations(),
|
|
815
834
|
])
|
|
816
|
-
.then(() => {
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
835
|
+
.then(() => startServer(), initError => {
|
|
836
|
+
// Initialization (auto-discovery / WebSocket setup) failed — this is
|
|
837
|
+
// NOT the listen() call. Handle it here so a subsequent listen()
|
|
838
|
+
// failure can't be misdiagnosed as an init failure and retried.
|
|
820
839
|
this.logger.error('Initialization failed during server start', 'Framework', {
|
|
821
|
-
error:
|
|
840
|
+
error: initError instanceof Error ? initError.message : String(initError),
|
|
822
841
|
});
|
|
823
|
-
//
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
throw error;
|
|
842
|
+
// WebSocket-adapter misconfiguration is fatal; propagate it.
|
|
843
|
+
if (initError instanceof Error &&
|
|
844
|
+
initError.message.includes('WebSocket features require a WebSocket adapter')) {
|
|
845
|
+
throw initError;
|
|
828
846
|
}
|
|
847
|
+
// A non-fatal init issue (e.g. auto-discovery) — start the server anyway.
|
|
829
848
|
startServer();
|
|
849
|
+
})
|
|
850
|
+
.catch(error => {
|
|
851
|
+
// startServer()/listen() failed — e.g. EADDRINUSE thrown synchronously
|
|
852
|
+
// by the native engine. Retrying would fail identically, so surface it
|
|
853
|
+
// via the 'error' event (Node's server convention) instead of retrying
|
|
854
|
+
// into an unhandled rejection. With no 'error' listener, EventEmitter
|
|
855
|
+
// rethrows — the desired visible crash for a fatal bind failure.
|
|
856
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
857
|
+
this.logger.error(`Failed to start server on port ${port}: ${message}`, 'Framework');
|
|
858
|
+
this.emit('error', error);
|
|
830
859
|
});
|
|
831
860
|
}
|
|
832
861
|
// Public method to manually initialize auto-discovery
|
|
@@ -997,7 +1026,7 @@ export class Moro extends EventEmitter {
|
|
|
997
1026
|
if (matches) {
|
|
998
1027
|
req.params = {};
|
|
999
1028
|
route.paramNames.forEach((name, index) => {
|
|
1000
|
-
req.params[name] = matches[index + 1];
|
|
1029
|
+
req.params[name] = matches[index + 1] ?? '';
|
|
1001
1030
|
});
|
|
1002
1031
|
}
|
|
1003
1032
|
// Get handler function
|
|
@@ -1113,6 +1142,15 @@ export class Moro extends EventEmitter {
|
|
|
1113
1142
|
get core() {
|
|
1114
1143
|
return this.coreFramework;
|
|
1115
1144
|
}
|
|
1145
|
+
// Which HTTP server actually booted (engine/node/http2), the package
|
|
1146
|
+
// backing a native engine, and the fallback reason when one was requested
|
|
1147
|
+
// but the Node server booted instead. Stable surface for logs/tests/benchmarks.
|
|
1148
|
+
get engine() {
|
|
1149
|
+
return this.coreFramework.getServerKind();
|
|
1150
|
+
}
|
|
1151
|
+
getServerKind() {
|
|
1152
|
+
return this.coreFramework.getServerKind();
|
|
1153
|
+
}
|
|
1116
1154
|
// Public API for accessing the DI container
|
|
1117
1155
|
getContainer() {
|
|
1118
1156
|
return this.coreFramework.getContainer();
|
|
@@ -1203,6 +1241,8 @@ export class Moro extends EventEmitter {
|
|
|
1203
1241
|
// This provides the intuitive developer experience users expect
|
|
1204
1242
|
for (const route of this.routes) {
|
|
1205
1243
|
const handler = this.routeHandlers[route.handler];
|
|
1244
|
+
if (!handler)
|
|
1245
|
+
continue;
|
|
1206
1246
|
// Get direct access to the HTTP server through the core framework
|
|
1207
1247
|
const httpServer = this.coreFramework.httpServer;
|
|
1208
1248
|
// Create a wrapper handler that handles validation, rate limiting, and return values
|
|
@@ -1278,7 +1318,7 @@ export class Moro extends EventEmitter {
|
|
|
1278
1318
|
}
|
|
1279
1319
|
// Rate limiting middleware
|
|
1280
1320
|
if (route.rateLimit) {
|
|
1281
|
-
const clientId = req.ip || req.connection
|
|
1321
|
+
const clientId = req.ip || req.connection?.remoteAddress || 'unknown';
|
|
1282
1322
|
const key = `${route.method}:${route.path}:${clientId}`;
|
|
1283
1323
|
if (!this.checkRateLimit(key, route.rateLimit)) {
|
|
1284
1324
|
res.status(429).json({
|
|
@@ -1506,20 +1546,20 @@ export class Moro extends EventEmitter {
|
|
|
1506
1546
|
this.logger.info('Module changes detected, reloading...', 'ModuleDiscovery');
|
|
1507
1547
|
// Unload existing modules (if supported)
|
|
1508
1548
|
// For now, just log the change
|
|
1509
|
-
this.eventBus.emit('modules:changed', {
|
|
1549
|
+
void this.eventBus.emit('modules:changed', {
|
|
1510
1550
|
modules: modules.map(m => ({ name: m.name, version: m.version })),
|
|
1511
1551
|
timestamp: new Date(),
|
|
1512
1552
|
});
|
|
1513
1553
|
}
|
|
1514
1554
|
// Legacy method for backward compatibility
|
|
1515
1555
|
autoDiscoverModules(modulesPath) {
|
|
1516
|
-
// Redirect to new system
|
|
1517
|
-
this.initializeAutoDiscovery({
|
|
1556
|
+
// Redirect to new system (legacy sync shim over the async discovery path).
|
|
1557
|
+
void this.initializeAutoDiscovery({
|
|
1518
1558
|
autoDiscover: {
|
|
1519
1559
|
enabled: true,
|
|
1520
1560
|
paths: [modulesPath],
|
|
1521
1561
|
},
|
|
1522
|
-
});
|
|
1562
|
+
}).catch(err => this.logger.error(`Auto-discovery failed: ${String(err)}`, 'ModuleDiscovery'));
|
|
1523
1563
|
}
|
|
1524
1564
|
async importModule(modulePath) {
|
|
1525
1565
|
// Convert file path to proper file URL for Windows compatibility
|
|
@@ -1694,7 +1734,7 @@ export class Moro extends EventEmitter {
|
|
|
1694
1734
|
process.on('SIGTERM', workerShutdown);
|
|
1695
1735
|
process.on('SIGINT', workerShutdown);
|
|
1696
1736
|
// Continue with normal server startup for this worker
|
|
1697
|
-
this.eventBus.emit('server:starting', {
|
|
1737
|
+
void this.eventBus.emit('server:starting', {
|
|
1698
1738
|
port,
|
|
1699
1739
|
runtime: this.runtimeType,
|
|
1700
1740
|
worker: process.pid,
|
|
@@ -1716,37 +1756,53 @@ export class Moro extends EventEmitter {
|
|
|
1716
1756
|
const workerCallback = () => {
|
|
1717
1757
|
const displayHost = host || 'localhost';
|
|
1718
1758
|
this.logger.info(`Worker ${process.pid} ready on ${displayHost}:${port}`, 'Worker');
|
|
1719
|
-
this.eventBus.emit('server:started', {
|
|
1759
|
+
void this.eventBus.emit('server:started', {
|
|
1720
1760
|
port,
|
|
1721
1761
|
runtime: this.runtimeType,
|
|
1722
1762
|
worker: process.pid,
|
|
1763
|
+
engine: this.engine,
|
|
1723
1764
|
});
|
|
1724
1765
|
};
|
|
1725
1766
|
// Ensure WebSocket setup is complete before starting worker
|
|
1726
|
-
|
|
1727
|
-
.then(() => {
|
|
1767
|
+
const startWorkerListening = () => {
|
|
1728
1768
|
if (host) {
|
|
1729
1769
|
this.coreFramework.listen(port, host, workerCallback);
|
|
1730
1770
|
}
|
|
1731
1771
|
else {
|
|
1732
1772
|
this.coreFramework.listen(port, workerCallback);
|
|
1733
1773
|
}
|
|
1734
|
-
}
|
|
1774
|
+
};
|
|
1775
|
+
this.processQueuedWebSocketRegistrations()
|
|
1776
|
+
.then(startWorkerListening)
|
|
1735
1777
|
.catch(error => {
|
|
1778
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
1779
|
+
const code = error?.code;
|
|
1780
|
+
// listen() itself failed (EADDRINUSE etc.): retrying is guaranteed to
|
|
1781
|
+
// fail again and would surface as an unhandled rejection crash-loop.
|
|
1782
|
+
// Log fatally and exit so the cluster primary sees a clean death.
|
|
1783
|
+
// Prefer the code the native/Node servers set; fall back to message.
|
|
1784
|
+
if (code === 'EADDRINUSE' ||
|
|
1785
|
+
code === 'EACCES' ||
|
|
1786
|
+
/EADDRINUSE|failed to bind/i.test(message)) {
|
|
1787
|
+
this.logger.error(`Worker ${process.pid} could not bind port ${port}: ${message}`, 'Worker');
|
|
1788
|
+
process.exit(1);
|
|
1789
|
+
}
|
|
1736
1790
|
this.logger.error('WebSocket initialization failed in worker', 'Worker', {
|
|
1737
|
-
error:
|
|
1791
|
+
error: message,
|
|
1738
1792
|
});
|
|
1739
1793
|
// For WebSocket failures with queued registrations, error will propagate
|
|
1740
1794
|
if (error instanceof Error &&
|
|
1741
1795
|
error.message.includes('WebSocket features require a WebSocket adapter')) {
|
|
1742
1796
|
throw error;
|
|
1743
1797
|
}
|
|
1744
|
-
//
|
|
1745
|
-
|
|
1746
|
-
|
|
1798
|
+
// WebSocket setup failed but the HTTP server can still serve: start
|
|
1799
|
+
// anyway, and surface (not swallow) a listen failure from this path.
|
|
1800
|
+
try {
|
|
1801
|
+
startWorkerListening();
|
|
1747
1802
|
}
|
|
1748
|
-
|
|
1749
|
-
this.
|
|
1803
|
+
catch (listenError) {
|
|
1804
|
+
this.logger.error(`Worker ${process.pid} failed to start: ${listenError instanceof Error ? listenError.message : String(listenError)}`, 'Worker');
|
|
1805
|
+
process.exit(1);
|
|
1750
1806
|
}
|
|
1751
1807
|
});
|
|
1752
1808
|
}
|
|
@@ -1765,8 +1821,93 @@ export class Moro extends EventEmitter {
|
|
|
1765
1821
|
* Gracefully close the application and clean up resources
|
|
1766
1822
|
* This should be called in tests and during shutdown
|
|
1767
1823
|
*/
|
|
1824
|
+
shutdownHandlersRegistered = false;
|
|
1825
|
+
isShuttingDown = false;
|
|
1826
|
+
// Per-instance opt-in uncaught-error listeners (removed by close()).
|
|
1827
|
+
processListeners = [];
|
|
1828
|
+
// Graceful shutdown is driven by ONE process-level SIGINT/SIGTERM handler
|
|
1829
|
+
// shared across every Moro instance (installed once), so creating many apps
|
|
1830
|
+
// never accumulates process listeners. Instances register here on listen()
|
|
1831
|
+
// and deregister on close().
|
|
1832
|
+
static activeInstances = new Set();
|
|
1833
|
+
static globalSignalsInstalled = false;
|
|
1834
|
+
static globalShuttingDown = false;
|
|
1835
|
+
static installGlobalShutdownSignals() {
|
|
1836
|
+
if (Moro.globalSignalsInstalled)
|
|
1837
|
+
return;
|
|
1838
|
+
Moro.globalSignalsInstalled = true;
|
|
1839
|
+
const handle = (signal, code) => {
|
|
1840
|
+
// A second signal while already draining forces an immediate exit, so a
|
|
1841
|
+
// stuck shutdown can never make the process unkillable via Ctrl-C.
|
|
1842
|
+
if (Moro.globalShuttingDown) {
|
|
1843
|
+
process.exit(code);
|
|
1844
|
+
return;
|
|
1845
|
+
}
|
|
1846
|
+
Moro.globalShuttingDown = true;
|
|
1847
|
+
const instances = Array.from(Moro.activeInstances);
|
|
1848
|
+
instances[0]?.logger.info(`Received ${signal}, shutting down gracefully...`, 'Server');
|
|
1849
|
+
Promise.allSettled(instances.map(inst => inst.close()))
|
|
1850
|
+
.then(() => process.exit(code))
|
|
1851
|
+
.catch(() => process.exit(1));
|
|
1852
|
+
};
|
|
1853
|
+
process.on('SIGINT', () => handle('SIGINT', 0));
|
|
1854
|
+
process.on('SIGTERM', () => handle('SIGTERM', 0));
|
|
1855
|
+
}
|
|
1856
|
+
/**
|
|
1857
|
+
* Enable graceful shutdown for this instance. SIGINT/SIGTERM (Ctrl-C) drain
|
|
1858
|
+
* in-flight work via close() by default; a second signal force-exits. Opt out
|
|
1859
|
+
* with `server.gracefulShutdown: false` (e.g. when the host app owns signals).
|
|
1860
|
+
* Uncaught-error draining is separate and opt-in (`server.handleUncaught`).
|
|
1861
|
+
*/
|
|
1862
|
+
registerProcessShutdownHandlers() {
|
|
1863
|
+
if (this.shutdownHandlersRegistered)
|
|
1864
|
+
return;
|
|
1865
|
+
const serverCfg = this.config.server;
|
|
1866
|
+
if (serverCfg?.gracefulShutdown === false)
|
|
1867
|
+
return; // default ON; opt out here
|
|
1868
|
+
this.shutdownHandlersRegistered = true;
|
|
1869
|
+
Moro.activeInstances.add(this);
|
|
1870
|
+
Moro.installGlobalShutdownSignals();
|
|
1871
|
+
// Opt-in uncaught-error draining (per instance, removed on close()).
|
|
1872
|
+
if (serverCfg?.handleUncaught === true) {
|
|
1873
|
+
const add = (event, handler) => {
|
|
1874
|
+
process.on(event, handler);
|
|
1875
|
+
this.processListeners.push([event, handler]);
|
|
1876
|
+
};
|
|
1877
|
+
add('unhandledRejection', reason => {
|
|
1878
|
+
this.logger.error(`Unhandled promise rejection: ${String(reason)}`, 'Server');
|
|
1879
|
+
this.drainAndExit(1);
|
|
1880
|
+
});
|
|
1881
|
+
add('uncaughtException', err => {
|
|
1882
|
+
this.logger.error(`Uncaught exception: ${err instanceof Error ? err.stack || err.message : String(err)}`, 'Server');
|
|
1883
|
+
this.drainAndExit(1);
|
|
1884
|
+
});
|
|
1885
|
+
}
|
|
1886
|
+
}
|
|
1887
|
+
drainAndExit(code) {
|
|
1888
|
+
if (this.isShuttingDown) {
|
|
1889
|
+
process.exit(code);
|
|
1890
|
+
return;
|
|
1891
|
+
}
|
|
1892
|
+
this.isShuttingDown = true;
|
|
1893
|
+
this.close()
|
|
1894
|
+
.then(() => process.exit(code))
|
|
1895
|
+
.catch(() => process.exit(1));
|
|
1896
|
+
}
|
|
1897
|
+
/** Deregister this instance from process shutdown handling (called by close()). */
|
|
1898
|
+
removeProcessShutdownHandlers() {
|
|
1899
|
+
Moro.activeInstances.delete(this);
|
|
1900
|
+
for (const [event, handler] of this.processListeners) {
|
|
1901
|
+
process.removeListener(event, handler);
|
|
1902
|
+
}
|
|
1903
|
+
this.processListeners = [];
|
|
1904
|
+
this.shutdownHandlersRegistered = false;
|
|
1905
|
+
}
|
|
1768
1906
|
async close() {
|
|
1769
1907
|
this.logger.debug('Closing Moro application...');
|
|
1908
|
+
// Detach our process signal listeners so repeated create/close cycles
|
|
1909
|
+
// (tests, or a host that spins up many apps) don't leak process listeners.
|
|
1910
|
+
this.removeProcessShutdownHandlers();
|
|
1770
1911
|
// Run user-registered onClose hooks first, while subsystems are still alive.
|
|
1771
1912
|
// Failures in one hook don't prevent subsequent hooks or Moro's own teardown.
|
|
1772
1913
|
if (this.closeHooks.length > 0) {
|
|
@@ -1834,6 +1975,13 @@ export class Moro extends EventEmitter {
|
|
|
1834
1975
|
// Only wait for close if the server is actually listening
|
|
1835
1976
|
const isListening = server?.listening || server?.address?.() !== null;
|
|
1836
1977
|
if (isListening) {
|
|
1978
|
+
// Stop accepting new connections and let in-flight requests finish,
|
|
1979
|
+
// but don't hang on idle keep-alive / WebSocket connections: close
|
|
1980
|
+
// idle sockets right away, then force-close whatever remains at the
|
|
1981
|
+
// deadline so this promise reflects a real close instead of only the
|
|
1982
|
+
// timer firing. (closeIdle/closeAllConnections exist on the Node http
|
|
1983
|
+
// server; the uWS/engine backends ignore the optional calls.)
|
|
1984
|
+
server?.closeIdleConnections?.();
|
|
1837
1985
|
await Promise.race([
|
|
1838
1986
|
new Promise(resolve => {
|
|
1839
1987
|
httpServer.close(() => {
|
|
@@ -1841,7 +1989,15 @@ export class Moro extends EventEmitter {
|
|
|
1841
1989
|
});
|
|
1842
1990
|
}),
|
|
1843
1991
|
new Promise(resolve => {
|
|
1844
|
-
const timer = setTimeout(
|
|
1992
|
+
const timer = setTimeout(() => {
|
|
1993
|
+
try {
|
|
1994
|
+
server?.closeAllConnections?.();
|
|
1995
|
+
}
|
|
1996
|
+
catch {
|
|
1997
|
+
// best-effort force-close
|
|
1998
|
+
}
|
|
1999
|
+
resolve();
|
|
2000
|
+
}, 2000); // 2 second grace period
|
|
1845
2001
|
timer.unref(); // Don't keep process alive
|
|
1846
2002
|
}),
|
|
1847
2003
|
]);
|
|
@@ -1951,19 +2107,21 @@ export class Moro extends EventEmitter {
|
|
|
1951
2107
|
}
|
|
1952
2108
|
const jobOptions = {
|
|
1953
2109
|
name: options.name || name,
|
|
1954
|
-
enabled: options.enabled,
|
|
1955
|
-
priority: options.priority,
|
|
1956
|
-
timezone: options.timezone,
|
|
1957
|
-
maxConcurrent: options.maxConcurrent,
|
|
1958
|
-
timeout: options.timeout,
|
|
1959
|
-
maxRetries: options.maxRetries,
|
|
1960
|
-
retryDelay: options.retryDelay,
|
|
1961
|
-
retryBackoff: options.retryBackoff,
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
|
|
1966
|
-
|
|
2110
|
+
...(options.enabled !== undefined ? { enabled: options.enabled } : {}),
|
|
2111
|
+
...(options.priority !== undefined ? { priority: options.priority } : {}),
|
|
2112
|
+
...(options.timezone !== undefined ? { timezone: options.timezone } : {}),
|
|
2113
|
+
...(options.maxConcurrent !== undefined ? { maxConcurrent: options.maxConcurrent } : {}),
|
|
2114
|
+
...(options.timeout !== undefined ? { timeout: options.timeout } : {}),
|
|
2115
|
+
...(options.maxRetries !== undefined ? { maxRetries: options.maxRetries } : {}),
|
|
2116
|
+
...(options.retryDelay !== undefined ? { retryDelay: options.retryDelay } : {}),
|
|
2117
|
+
...(options.retryBackoff !== undefined ? { retryBackoff: options.retryBackoff } : {}),
|
|
2118
|
+
...(options.enableCircuitBreaker !== undefined
|
|
2119
|
+
? { enableCircuitBreaker: options.enableCircuitBreaker }
|
|
2120
|
+
: {}),
|
|
2121
|
+
...(options.metadata !== undefined ? { metadata: options.metadata } : {}),
|
|
2122
|
+
...(options.onStart !== undefined ? { onStart: options.onStart } : {}),
|
|
2123
|
+
...(options.onComplete !== undefined ? { onComplete: options.onComplete } : {}),
|
|
2124
|
+
...(options.onError !== undefined ? { onError: options.onError } : {}),
|
|
1967
2125
|
};
|
|
1968
2126
|
const jobId = this.jobScheduler.registerJob(name, jobSchedule, handler, jobOptions);
|
|
1969
2127
|
this.logger.info(`Job registered: ${name} (${jobId})`);
|
|
@@ -2131,7 +2289,7 @@ export class Moro extends EventEmitter {
|
|
|
2131
2289
|
// Store config and trigger initialization immediately
|
|
2132
2290
|
this.graphqlConfig = options;
|
|
2133
2291
|
this.graphqlInitPromise = this.initializeGraphQL(options);
|
|
2134
|
-
this.eventBus.emit('graphql:configured', { options });
|
|
2292
|
+
void this.eventBus.emit('graphql:configured', { options });
|
|
2135
2293
|
return this;
|
|
2136
2294
|
}
|
|
2137
2295
|
/**
|
|
@@ -2786,7 +2944,7 @@ export class Moro extends EventEmitter {
|
|
|
2786
2944
|
// Store config for lazy initialization
|
|
2787
2945
|
this.mailConfig = config;
|
|
2788
2946
|
this.logger.debug('Mail system configured (will initialize on first use)', 'Mail');
|
|
2789
|
-
this.eventBus.emit('mail:configured', { config });
|
|
2947
|
+
void this.eventBus.emit('mail:configured', { config });
|
|
2790
2948
|
return this;
|
|
2791
2949
|
}
|
|
2792
2950
|
/**
|
|
@@ -2816,7 +2974,9 @@ export class Moro extends EventEmitter {
|
|
|
2816
2974
|
await this.ensureQueueInitialized();
|
|
2817
2975
|
await this.processQueue(queueName, async (job) => {
|
|
2818
2976
|
if (this.mailManager) {
|
|
2819
|
-
|
|
2977
|
+
// deliver() bypasses the queue check; send() would re-enqueue the
|
|
2978
|
+
// job forever and never actually transmit the email.
|
|
2979
|
+
return await this.mailManager.deliver(job.data);
|
|
2820
2980
|
}
|
|
2821
2981
|
throw new Error('Mail manager not initialized');
|
|
2822
2982
|
});
|
|
@@ -2864,19 +3024,19 @@ export class Moro extends EventEmitter {
|
|
|
2864
3024
|
async sendMail(options) {
|
|
2865
3025
|
// Lazy initialize on first use
|
|
2866
3026
|
await this.ensureMailInitialized();
|
|
2867
|
-
this.eventBus.emit('mail:sending', { options });
|
|
3027
|
+
void this.eventBus.emit('mail:sending', { options });
|
|
2868
3028
|
try {
|
|
2869
3029
|
const result = await this.mailManager.send(options);
|
|
2870
3030
|
if (result.success) {
|
|
2871
|
-
this.eventBus.emit('mail:sent', { result, options });
|
|
3031
|
+
void this.eventBus.emit('mail:sent', { result, options });
|
|
2872
3032
|
}
|
|
2873
3033
|
else {
|
|
2874
|
-
this.eventBus.emit('mail:failed', { error: new Error(result.error), options });
|
|
3034
|
+
void this.eventBus.emit('mail:failed', { error: new Error(result.error), options });
|
|
2875
3035
|
}
|
|
2876
3036
|
return result;
|
|
2877
3037
|
}
|
|
2878
3038
|
catch (error) {
|
|
2879
|
-
this.eventBus.emit('mail:failed', { error, options });
|
|
3039
|
+
void this.eventBus.emit('mail:failed', { error, options });
|
|
2880
3040
|
throw error;
|
|
2881
3041
|
}
|
|
2882
3042
|
}
|