@morojs/moro 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +233 -0
- package/dist/core/config/index.d.ts +19 -0
- package/dist/core/config/index.js +59 -0
- package/dist/core/config/index.js.map +1 -0
- package/dist/core/config/loader.d.ts +6 -0
- package/dist/core/config/loader.js +288 -0
- package/dist/core/config/loader.js.map +1 -0
- package/dist/core/config/schema.d.ts +335 -0
- package/dist/core/config/schema.js +286 -0
- package/dist/core/config/schema.js.map +1 -0
- package/dist/core/config/utils.d.ts +50 -0
- package/dist/core/config/utils.js +185 -0
- package/dist/core/config/utils.js.map +1 -0
- package/dist/core/database/adapters/drizzle.d.ts +29 -0
- package/dist/core/database/adapters/drizzle.js +366 -0
- package/dist/core/database/adapters/drizzle.js.map +1 -0
- package/dist/core/database/adapters/index.d.ts +8 -0
- package/dist/core/database/adapters/index.js +48 -0
- package/dist/core/database/adapters/index.js.map +1 -0
- package/dist/core/database/adapters/mongodb.d.ts +35 -0
- package/dist/core/database/adapters/mongodb.js +215 -0
- package/dist/core/database/adapters/mongodb.js.map +1 -0
- package/dist/core/database/adapters/mysql.d.ts +23 -0
- package/dist/core/database/adapters/mysql.js +149 -0
- package/dist/core/database/adapters/mysql.js.map +1 -0
- package/dist/core/database/adapters/postgresql.d.ts +24 -0
- package/dist/core/database/adapters/postgresql.js +160 -0
- package/dist/core/database/adapters/postgresql.js.map +1 -0
- package/dist/core/database/adapters/redis.d.ts +50 -0
- package/dist/core/database/adapters/redis.js +266 -0
- package/dist/core/database/adapters/redis.js.map +1 -0
- package/dist/core/database/adapters/sqlite.d.ts +23 -0
- package/dist/core/database/adapters/sqlite.js +194 -0
- package/dist/core/database/adapters/sqlite.js.map +1 -0
- package/dist/core/database/index.d.ts +2 -0
- package/dist/core/database/index.js +20 -0
- package/dist/core/database/index.js.map +1 -0
- package/dist/core/docs/index.d.ts +63 -0
- package/dist/core/docs/index.js +170 -0
- package/dist/core/docs/index.js.map +1 -0
- package/dist/core/docs/openapi-generator.d.ts +124 -0
- package/dist/core/docs/openapi-generator.js +413 -0
- package/dist/core/docs/openapi-generator.js.map +1 -0
- package/dist/core/docs/simple-docs.d.ts +21 -0
- package/dist/core/docs/simple-docs.js +268 -0
- package/dist/core/docs/simple-docs.js.map +1 -0
- package/dist/core/docs/swagger-ui.d.ts +28 -0
- package/dist/core/docs/swagger-ui.js +317 -0
- package/dist/core/docs/swagger-ui.js.map +1 -0
- package/dist/core/docs/zod-to-openapi.d.ts +29 -0
- package/dist/core/docs/zod-to-openapi.js +414 -0
- package/dist/core/docs/zod-to-openapi.js.map +1 -0
- package/dist/core/events/event-bus.d.ts +27 -0
- package/dist/core/events/event-bus.js +193 -0
- package/dist/core/events/event-bus.js.map +1 -0
- package/dist/core/events/index.d.ts +2 -0
- package/dist/core/events/index.js +7 -0
- package/dist/core/events/index.js.map +1 -0
- package/dist/core/framework.d.ts +57 -0
- package/dist/core/framework.js +432 -0
- package/dist/core/framework.js.map +1 -0
- package/dist/core/http/http-server.d.ts +114 -0
- package/dist/core/http/http-server.js +1154 -0
- package/dist/core/http/http-server.js.map +1 -0
- package/dist/core/http/index.d.ts +3 -0
- package/dist/core/http/index.js +10 -0
- package/dist/core/http/index.js.map +1 -0
- package/dist/core/http/router.d.ts +14 -0
- package/dist/core/http/router.js +113 -0
- package/dist/core/http/router.js.map +1 -0
- package/dist/core/logger/filters.d.ts +9 -0
- package/dist/core/logger/filters.js +134 -0
- package/dist/core/logger/filters.js.map +1 -0
- package/dist/core/logger/index.d.ts +3 -0
- package/dist/core/logger/index.js +26 -0
- package/dist/core/logger/index.js.map +1 -0
- package/dist/core/logger/logger.d.ts +49 -0
- package/dist/core/logger/logger.js +332 -0
- package/dist/core/logger/logger.js.map +1 -0
- package/dist/core/logger/outputs.d.ts +42 -0
- package/dist/core/logger/outputs.js +110 -0
- package/dist/core/logger/outputs.js.map +1 -0
- package/dist/core/middleware/built-in/adapters/cache/file.d.ts +15 -0
- package/dist/core/middleware/built-in/adapters/cache/file.js +128 -0
- package/dist/core/middleware/built-in/adapters/cache/file.js.map +1 -0
- package/dist/core/middleware/built-in/adapters/cache/index.d.ts +5 -0
- package/dist/core/middleware/built-in/adapters/cache/index.js +28 -0
- package/dist/core/middleware/built-in/adapters/cache/index.js.map +1 -0
- package/dist/core/middleware/built-in/adapters/cache/memory.d.ts +11 -0
- package/dist/core/middleware/built-in/adapters/cache/memory.js +65 -0
- package/dist/core/middleware/built-in/adapters/cache/memory.js.map +1 -0
- package/dist/core/middleware/built-in/adapters/cache/redis.d.ts +17 -0
- package/dist/core/middleware/built-in/adapters/cache/redis.js +91 -0
- package/dist/core/middleware/built-in/adapters/cache/redis.js.map +1 -0
- package/dist/core/middleware/built-in/adapters/cdn/azure.d.ts +21 -0
- package/dist/core/middleware/built-in/adapters/cdn/azure.js +40 -0
- package/dist/core/middleware/built-in/adapters/cdn/azure.js.map +1 -0
- package/dist/core/middleware/built-in/adapters/cdn/cloudflare.d.ts +14 -0
- package/dist/core/middleware/built-in/adapters/cdn/cloudflare.js +77 -0
- package/dist/core/middleware/built-in/adapters/cdn/cloudflare.js.map +1 -0
- package/dist/core/middleware/built-in/adapters/cdn/cloudfront.d.ts +15 -0
- package/dist/core/middleware/built-in/adapters/cdn/cloudfront.js +73 -0
- package/dist/core/middleware/built-in/adapters/cdn/cloudfront.js.map +1 -0
- package/dist/core/middleware/built-in/adapters/cdn/index.d.ts +5 -0
- package/dist/core/middleware/built-in/adapters/cdn/index.js +28 -0
- package/dist/core/middleware/built-in/adapters/cdn/index.js.map +1 -0
- package/dist/core/middleware/built-in/adapters/index.d.ts +4 -0
- package/dist/core/middleware/built-in/adapters/index.js +26 -0
- package/dist/core/middleware/built-in/adapters/index.js.map +1 -0
- package/dist/core/middleware/built-in/auth.d.ts +2 -0
- package/dist/core/middleware/built-in/auth.js +38 -0
- package/dist/core/middleware/built-in/auth.js.map +1 -0
- package/dist/core/middleware/built-in/cache.d.ts +3 -0
- package/dist/core/middleware/built-in/cache.js +188 -0
- package/dist/core/middleware/built-in/cache.js.map +1 -0
- package/dist/core/middleware/built-in/cdn.d.ts +3 -0
- package/dist/core/middleware/built-in/cdn.js +115 -0
- package/dist/core/middleware/built-in/cdn.js.map +1 -0
- package/dist/core/middleware/built-in/cookie.d.ts +14 -0
- package/dist/core/middleware/built-in/cookie.js +68 -0
- package/dist/core/middleware/built-in/cookie.js.map +1 -0
- package/dist/core/middleware/built-in/cors.d.ts +2 -0
- package/dist/core/middleware/built-in/cors.js +29 -0
- package/dist/core/middleware/built-in/cors.js.map +1 -0
- package/dist/core/middleware/built-in/csp.d.ts +22 -0
- package/dist/core/middleware/built-in/csp.js +74 -0
- package/dist/core/middleware/built-in/csp.js.map +1 -0
- package/dist/core/middleware/built-in/csrf.d.ts +9 -0
- package/dist/core/middleware/built-in/csrf.js +66 -0
- package/dist/core/middleware/built-in/csrf.js.map +1 -0
- package/dist/core/middleware/built-in/error-tracker.d.ts +1 -0
- package/dist/core/middleware/built-in/error-tracker.js +19 -0
- package/dist/core/middleware/built-in/error-tracker.js.map +1 -0
- package/dist/core/middleware/built-in/index.d.ts +70 -0
- package/dist/core/middleware/built-in/index.js +70 -0
- package/dist/core/middleware/built-in/index.js.map +1 -0
- package/dist/core/middleware/built-in/performance-monitor.d.ts +1 -0
- package/dist/core/middleware/built-in/performance-monitor.js +22 -0
- package/dist/core/middleware/built-in/performance-monitor.js.map +1 -0
- package/dist/core/middleware/built-in/rate-limit.d.ts +6 -0
- package/dist/core/middleware/built-in/rate-limit.js +47 -0
- package/dist/core/middleware/built-in/rate-limit.js.map +1 -0
- package/dist/core/middleware/built-in/request-logger.d.ts +1 -0
- package/dist/core/middleware/built-in/request-logger.js +15 -0
- package/dist/core/middleware/built-in/request-logger.js.map +1 -0
- package/dist/core/middleware/built-in/session.d.ts +41 -0
- package/dist/core/middleware/built-in/session.js +209 -0
- package/dist/core/middleware/built-in/session.js.map +1 -0
- package/dist/core/middleware/built-in/sse.d.ts +6 -0
- package/dist/core/middleware/built-in/sse.js +73 -0
- package/dist/core/middleware/built-in/sse.js.map +1 -0
- package/dist/core/middleware/built-in/validation.d.ts +2 -0
- package/dist/core/middleware/built-in/validation.js +31 -0
- package/dist/core/middleware/built-in/validation.js.map +1 -0
- package/dist/core/middleware/index.d.ts +21 -0
- package/dist/core/middleware/index.js +152 -0
- package/dist/core/middleware/index.js.map +1 -0
- package/dist/core/modules/auto-discovery.d.ts +27 -0
- package/dist/core/modules/auto-discovery.js +255 -0
- package/dist/core/modules/auto-discovery.js.map +1 -0
- package/dist/core/modules/index.d.ts +2 -0
- package/dist/core/modules/index.js +11 -0
- package/dist/core/modules/index.js.map +1 -0
- package/dist/core/modules/modules.d.ts +10 -0
- package/dist/core/modules/modules.js +137 -0
- package/dist/core/modules/modules.js.map +1 -0
- package/dist/core/networking/index.d.ts +2 -0
- package/dist/core/networking/index.js +9 -0
- package/dist/core/networking/index.js.map +1 -0
- package/dist/core/networking/service-discovery.d.ts +38 -0
- package/dist/core/networking/service-discovery.js +233 -0
- package/dist/core/networking/service-discovery.js.map +1 -0
- package/dist/core/networking/websocket-manager.d.ts +27 -0
- package/dist/core/networking/websocket-manager.js +211 -0
- package/dist/core/networking/websocket-manager.js.map +1 -0
- package/dist/core/routing/app-integration.d.ts +42 -0
- package/dist/core/routing/app-integration.js +152 -0
- package/dist/core/routing/app-integration.js.map +1 -0
- package/dist/core/routing/index.d.ts +106 -0
- package/dist/core/routing/index.js +343 -0
- package/dist/core/routing/index.js.map +1 -0
- package/dist/core/runtime/aws-lambda-adapter.d.ts +43 -0
- package/dist/core/runtime/aws-lambda-adapter.js +108 -0
- package/dist/core/runtime/aws-lambda-adapter.js.map +1 -0
- package/dist/core/runtime/base-adapter.d.ts +16 -0
- package/dist/core/runtime/base-adapter.js +105 -0
- package/dist/core/runtime/base-adapter.js.map +1 -0
- package/dist/core/runtime/cloudflare-workers-adapter.d.ts +18 -0
- package/dist/core/runtime/cloudflare-workers-adapter.js +131 -0
- package/dist/core/runtime/cloudflare-workers-adapter.js.map +1 -0
- package/dist/core/runtime/index.d.ts +14 -0
- package/dist/core/runtime/index.js +56 -0
- package/dist/core/runtime/index.js.map +1 -0
- package/dist/core/runtime/node-adapter.d.ts +15 -0
- package/dist/core/runtime/node-adapter.js +204 -0
- package/dist/core/runtime/node-adapter.js.map +1 -0
- package/dist/core/runtime/vercel-edge-adapter.d.ts +10 -0
- package/dist/core/runtime/vercel-edge-adapter.js +106 -0
- package/dist/core/runtime/vercel-edge-adapter.js.map +1 -0
- package/dist/core/utilities/circuit-breaker.d.ts +14 -0
- package/dist/core/utilities/circuit-breaker.js +42 -0
- package/dist/core/utilities/circuit-breaker.js.map +1 -0
- package/dist/core/utilities/container.d.ts +116 -0
- package/dist/core/utilities/container.js +529 -0
- package/dist/core/utilities/container.js.map +1 -0
- package/dist/core/utilities/hooks.d.ts +24 -0
- package/dist/core/utilities/hooks.js +131 -0
- package/dist/core/utilities/hooks.js.map +1 -0
- package/dist/core/utilities/index.d.ts +4 -0
- package/dist/core/utilities/index.js +22 -0
- package/dist/core/utilities/index.js.map +1 -0
- package/dist/core/validation/index.d.ts +30 -0
- package/dist/core/validation/index.js +144 -0
- package/dist/core/validation/index.js.map +1 -0
- package/dist/index.d.ts +30 -0
- package/dist/index.js +72 -0
- package/dist/index.js.map +1 -0
- package/dist/moro.d.ts +82 -0
- package/dist/moro.js +679 -0
- package/dist/moro.js.map +1 -0
- package/dist/types/cache.d.ts +34 -0
- package/dist/types/cache.js +3 -0
- package/dist/types/cache.js.map +1 -0
- package/dist/types/cdn.d.ts +19 -0
- package/dist/types/cdn.js +3 -0
- package/dist/types/cdn.js.map +1 -0
- package/dist/types/core.d.ts +13 -0
- package/dist/types/core.js +3 -0
- package/dist/types/core.js.map +1 -0
- package/dist/types/database.d.ts +29 -0
- package/dist/types/database.js +3 -0
- package/dist/types/database.js.map +1 -0
- package/dist/types/discovery.d.ts +6 -0
- package/dist/types/discovery.js +3 -0
- package/dist/types/discovery.js.map +1 -0
- package/dist/types/events.d.ts +116 -0
- package/dist/types/events.js +3 -0
- package/dist/types/events.js.map +1 -0
- package/dist/types/hooks.d.ts +38 -0
- package/dist/types/hooks.js +3 -0
- package/dist/types/hooks.js.map +1 -0
- package/dist/types/http.d.ts +51 -0
- package/dist/types/http.js +3 -0
- package/dist/types/http.js.map +1 -0
- package/dist/types/logger.d.ts +77 -0
- package/dist/types/logger.js +3 -0
- package/dist/types/logger.js.map +1 -0
- package/dist/types/module.d.ts +91 -0
- package/dist/types/module.js +3 -0
- package/dist/types/module.js.map +1 -0
- package/dist/types/runtime.d.ts +48 -0
- package/dist/types/runtime.js +3 -0
- package/dist/types/runtime.js.map +1 -0
- package/dist/types/session.d.ts +66 -0
- package/dist/types/session.js +3 -0
- package/dist/types/session.js.map +1 -0
- package/package.json +176 -0
- package/src/core/config/index.ts +47 -0
- package/src/core/config/loader.ts +366 -0
- package/src/core/config/schema.ts +346 -0
- package/src/core/config/utils.ts +220 -0
- package/src/core/database/README.md +228 -0
- package/src/core/database/adapters/drizzle.ts +425 -0
- package/src/core/database/adapters/index.ts +45 -0
- package/src/core/database/adapters/mongodb.ts +292 -0
- package/src/core/database/adapters/mysql.ts +217 -0
- package/src/core/database/adapters/postgresql.ts +211 -0
- package/src/core/database/adapters/redis.ts +331 -0
- package/src/core/database/adapters/sqlite.ts +255 -0
- package/src/core/database/index.ts +3 -0
- package/src/core/docs/index.ts +245 -0
- package/src/core/docs/openapi-generator.ts +588 -0
- package/src/core/docs/simple-docs.ts +305 -0
- package/src/core/docs/swagger-ui.ts +370 -0
- package/src/core/docs/zod-to-openapi.ts +532 -0
- package/src/core/events/event-bus.ts +249 -0
- package/src/core/events/index.ts +12 -0
- package/src/core/framework.ts +621 -0
- package/src/core/http/http-server.ts +1421 -0
- package/src/core/http/index.ts +11 -0
- package/src/core/http/router.ts +153 -0
- package/src/core/logger/filters.ts +148 -0
- package/src/core/logger/index.ts +20 -0
- package/src/core/logger/logger.ts +434 -0
- package/src/core/logger/outputs.ts +136 -0
- package/src/core/middleware/built-in/adapters/cache/file.ts +106 -0
- package/src/core/middleware/built-in/adapters/cache/index.ts +26 -0
- package/src/core/middleware/built-in/adapters/cache/memory.ts +73 -0
- package/src/core/middleware/built-in/adapters/cache/redis.ts +103 -0
- package/src/core/middleware/built-in/adapters/cdn/azure.ts +68 -0
- package/src/core/middleware/built-in/adapters/cdn/cloudflare.ts +100 -0
- package/src/core/middleware/built-in/adapters/cdn/cloudfront.ts +92 -0
- package/src/core/middleware/built-in/adapters/cdn/index.ts +23 -0
- package/src/core/middleware/built-in/adapters/index.ts +7 -0
- package/src/core/middleware/built-in/auth.ts +39 -0
- package/src/core/middleware/built-in/cache.ts +228 -0
- package/src/core/middleware/built-in/cdn.ts +151 -0
- package/src/core/middleware/built-in/cookie.ts +90 -0
- package/src/core/middleware/built-in/cors.ts +38 -0
- package/src/core/middleware/built-in/csp.ts +107 -0
- package/src/core/middleware/built-in/csrf.ts +87 -0
- package/src/core/middleware/built-in/error-tracker.ts +16 -0
- package/src/core/middleware/built-in/index.ts +57 -0
- package/src/core/middleware/built-in/performance-monitor.ts +25 -0
- package/src/core/middleware/built-in/rate-limit.ts +60 -0
- package/src/core/middleware/built-in/request-logger.ts +14 -0
- package/src/core/middleware/built-in/session.ts +311 -0
- package/src/core/middleware/built-in/sse.ts +91 -0
- package/src/core/middleware/built-in/validation.ts +33 -0
- package/src/core/middleware/index.ts +188 -0
- package/src/core/modules/auto-discovery.ts +265 -0
- package/src/core/modules/index.ts +6 -0
- package/src/core/modules/modules.ts +125 -0
- package/src/core/networking/index.ts +7 -0
- package/src/core/networking/service-discovery.ts +309 -0
- package/src/core/networking/websocket-manager.ts +259 -0
- package/src/core/routing/app-integration.ts +229 -0
- package/src/core/routing/index.ts +519 -0
- package/src/core/runtime/aws-lambda-adapter.ts +157 -0
- package/src/core/runtime/base-adapter.ts +140 -0
- package/src/core/runtime/cloudflare-workers-adapter.ts +166 -0
- package/src/core/runtime/index.ts +74 -0
- package/src/core/runtime/node-adapter.ts +210 -0
- package/src/core/runtime/vercel-edge-adapter.ts +125 -0
- package/src/core/utilities/circuit-breaker.ts +46 -0
- package/src/core/utilities/container.ts +760 -0
- package/src/core/utilities/hooks.ts +148 -0
- package/src/core/utilities/index.ts +16 -0
- package/src/core/validation/index.ts +216 -0
- package/src/index.ts +120 -0
- package/src/moro.ts +842 -0
- package/src/types/cache.ts +38 -0
- package/src/types/cdn.ts +22 -0
- package/src/types/core.ts +17 -0
- package/src/types/database.ts +40 -0
- package/src/types/discovery.ts +7 -0
- package/src/types/events.ts +90 -0
- package/src/types/hooks.ts +47 -0
- package/src/types/http.ts +70 -0
- package/src/types/logger.ts +109 -0
- package/src/types/module.ts +87 -0
- package/src/types/runtime.ts +91 -0
- package/src/types/session.ts +89 -0
- package/tsconfig.json +21 -0
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
// Middleware System for Moro
|
|
2
|
+
import { EventEmitter } from "events";
|
|
3
|
+
import { HookManager } from "../utilities";
|
|
4
|
+
import {
|
|
5
|
+
MiddlewareMetadata,
|
|
6
|
+
MiddlewareContext,
|
|
7
|
+
MiddlewareInterface,
|
|
8
|
+
SimpleMiddlewareFunction,
|
|
9
|
+
MoroMiddleware,
|
|
10
|
+
} from "../../types/hooks";
|
|
11
|
+
import { createFrameworkLogger } from "../logger";
|
|
12
|
+
|
|
13
|
+
// Export types needed by built-in middleware
|
|
14
|
+
export type { MiddlewareInterface, MoroMiddleware } from "../../types/hooks";
|
|
15
|
+
|
|
16
|
+
export class MiddlewareManager extends EventEmitter {
|
|
17
|
+
private middleware = new Map<string, MiddlewareInterface>();
|
|
18
|
+
private simpleMiddleware = new Map<string, SimpleMiddlewareFunction>();
|
|
19
|
+
private hooks: HookManager;
|
|
20
|
+
private logger = createFrameworkLogger("Middleware");
|
|
21
|
+
|
|
22
|
+
constructor() {
|
|
23
|
+
super();
|
|
24
|
+
this.hooks = new HookManager();
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// Register middleware without installing
|
|
28
|
+
register(name: string, middleware: MiddlewareInterface): void {
|
|
29
|
+
if (this.middleware.has(name)) {
|
|
30
|
+
throw new Error(`Middleware ${name} is already registered`);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
this.middleware.set(name, middleware);
|
|
34
|
+
this.logger.debug(`Registered middleware: ${name}`, "Registration");
|
|
35
|
+
this.emit("registered", { name, middleware });
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// Install simple function-style middleware
|
|
39
|
+
install(
|
|
40
|
+
middleware: SimpleMiddlewareFunction | MiddlewareInterface,
|
|
41
|
+
options: any = {},
|
|
42
|
+
): void {
|
|
43
|
+
if (typeof middleware === "function") {
|
|
44
|
+
// Simple function-style middleware
|
|
45
|
+
const simpleName = middleware.name || "anonymous";
|
|
46
|
+
this.logger.debug(
|
|
47
|
+
`Installing simple middleware: ${simpleName}`,
|
|
48
|
+
"Installation",
|
|
49
|
+
);
|
|
50
|
+
|
|
51
|
+
this.simpleMiddleware.set(simpleName, middleware);
|
|
52
|
+
this.emit("installed", { name: simpleName, type: "simple" });
|
|
53
|
+
this.logger.info(
|
|
54
|
+
`Simple middleware installed: ${simpleName}`,
|
|
55
|
+
"Installation",
|
|
56
|
+
);
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Advanced middleware with dependencies and lifecycle
|
|
61
|
+
const name = middleware.metadata?.name || "unknown";
|
|
62
|
+
|
|
63
|
+
if (this.middleware.has(name)) {
|
|
64
|
+
throw new Error(`Middleware ${name} is already installed`);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Check dependencies
|
|
68
|
+
if (middleware.metadata?.dependencies) {
|
|
69
|
+
for (const dep of middleware.metadata.dependencies) {
|
|
70
|
+
if (!this.middleware.has(dep)) {
|
|
71
|
+
throw new Error(`Dependency ${dep} not found for middleware ${name}`);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// Store middleware
|
|
77
|
+
this.middleware.set(name, middleware);
|
|
78
|
+
|
|
79
|
+
this.logger.debug(`Installing middleware: ${name}`, "Installation");
|
|
80
|
+
|
|
81
|
+
// Initialize middleware
|
|
82
|
+
if (middleware.install) {
|
|
83
|
+
middleware.install(this.hooks, options);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
this.emit("installed", { name, middleware, options });
|
|
87
|
+
this.logger.info(`Middleware installed: ${name}`, "Installation");
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// Uninstall middleware and clean up
|
|
91
|
+
uninstall(name: string): void {
|
|
92
|
+
if (!this.middleware.has(name)) {
|
|
93
|
+
throw new Error(`Middleware ${name} is not installed`);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const middleware = this.middleware.get(name)!;
|
|
97
|
+
|
|
98
|
+
this.logger.debug(`Uninstalling middleware: ${name}`, "Uninstallation");
|
|
99
|
+
|
|
100
|
+
// Call cleanup if available
|
|
101
|
+
if (middleware.uninstall) {
|
|
102
|
+
middleware.uninstall(this.hooks);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
this.middleware.delete(name);
|
|
106
|
+
this.emit("uninstalled", { name, middleware });
|
|
107
|
+
this.logger.info(`Middleware uninstalled: ${name}`, "Uninstallation");
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// Get installed middleware
|
|
111
|
+
getInstalled(): string[] {
|
|
112
|
+
return Array.from(this.middleware.keys());
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// Get middleware configuration
|
|
116
|
+
getConfig(name: string): any {
|
|
117
|
+
return this.middleware.get(name)?.metadata;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// Check if middleware is installed
|
|
121
|
+
isInstalled(name: string): boolean {
|
|
122
|
+
return this.middleware.has(name);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// List all registered middleware
|
|
126
|
+
list(): MiddlewareInterface[] {
|
|
127
|
+
return Array.from(this.middleware.values());
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// Dependency resolution with topological sorting for optimal middleware loading
|
|
131
|
+
async installWithDependencies(
|
|
132
|
+
middleware: MiddlewareInterface[],
|
|
133
|
+
options?: Record<string, any>,
|
|
134
|
+
): Promise<void> {
|
|
135
|
+
// Advanced topological sort for dependency resolution
|
|
136
|
+
const resolved = this.topologicalSort(middleware);
|
|
137
|
+
|
|
138
|
+
for (const middlewareItem of resolved) {
|
|
139
|
+
const middlewareOptions = options?.[middlewareItem.name];
|
|
140
|
+
await this.install(middlewareItem, middlewareOptions);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// Optimized topological sort implementation for middleware dependencies
|
|
145
|
+
private topologicalSort(
|
|
146
|
+
middleware: MiddlewareInterface[],
|
|
147
|
+
): MiddlewareInterface[] {
|
|
148
|
+
const visited = new Set<string>();
|
|
149
|
+
const temp = new Set<string>();
|
|
150
|
+
const result: MiddlewareInterface[] = [];
|
|
151
|
+
|
|
152
|
+
const visit = (middlewareItem: MiddlewareInterface) => {
|
|
153
|
+
if (temp.has(middlewareItem.name)) {
|
|
154
|
+
throw new Error(`Circular dependency detected: ${middlewareItem.name}`);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
if (!visited.has(middlewareItem.name)) {
|
|
158
|
+
temp.add(middlewareItem.name);
|
|
159
|
+
|
|
160
|
+
// Visit dependencies first
|
|
161
|
+
if (middlewareItem.dependencies) {
|
|
162
|
+
for (const depName of middlewareItem.dependencies) {
|
|
163
|
+
const dependency = middleware.find((m) => m.name === depName);
|
|
164
|
+
if (dependency) {
|
|
165
|
+
visit(dependency);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
temp.delete(middlewareItem.name);
|
|
171
|
+
visited.add(middlewareItem.name);
|
|
172
|
+
result.push(middlewareItem);
|
|
173
|
+
}
|
|
174
|
+
};
|
|
175
|
+
|
|
176
|
+
for (const middlewareItem of middleware) {
|
|
177
|
+
if (!visited.has(middlewareItem.name)) {
|
|
178
|
+
visit(middlewareItem);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
return result;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// Built-in middleware exports
|
|
187
|
+
export { builtInMiddleware, simpleMiddleware } from "./built-in";
|
|
188
|
+
export * from "./built-in";
|
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
// Auto-discovery system for Moro modules
|
|
2
|
+
import { readdirSync, statSync } from "fs";
|
|
3
|
+
import { join, extname } from "path";
|
|
4
|
+
import { ModuleConfig } from "../../types/module";
|
|
5
|
+
import { DiscoveryOptions } from "../../types/discovery";
|
|
6
|
+
|
|
7
|
+
export class ModuleDiscovery {
|
|
8
|
+
private baseDir: string;
|
|
9
|
+
private options: DiscoveryOptions;
|
|
10
|
+
|
|
11
|
+
constructor(baseDir: string = process.cwd(), options: DiscoveryOptions = {}) {
|
|
12
|
+
this.baseDir = baseDir;
|
|
13
|
+
this.options = {
|
|
14
|
+
pattern: /\.(module|config)\.(ts|js)$/,
|
|
15
|
+
recursive: true,
|
|
16
|
+
extensions: [".ts", ".js"],
|
|
17
|
+
...options,
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// Auto-discover modules in the filesystem
|
|
22
|
+
async discoverModules(): Promise<ModuleConfig[]> {
|
|
23
|
+
const modules: ModuleConfig[] = [];
|
|
24
|
+
const modulePaths = this.findModuleFiles();
|
|
25
|
+
|
|
26
|
+
for (const modulePath of modulePaths) {
|
|
27
|
+
try {
|
|
28
|
+
const module = await this.loadModule(modulePath);
|
|
29
|
+
if (module) {
|
|
30
|
+
modules.push(module);
|
|
31
|
+
console.log(
|
|
32
|
+
`Auto-discovered module: ${module.name}@${module.version} from ${modulePath}`,
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
} catch (error) {
|
|
36
|
+
console.warn(`Failed to load module from ${modulePath}:`, error);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return modules;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Find modules by directory structure
|
|
44
|
+
async discoverModuleDirectories(
|
|
45
|
+
modulesDir: string = "src/modules",
|
|
46
|
+
): Promise<ModuleConfig[]> {
|
|
47
|
+
const modules: ModuleConfig[] = [];
|
|
48
|
+
const fullPath = join(this.baseDir, modulesDir);
|
|
49
|
+
|
|
50
|
+
try {
|
|
51
|
+
if (!statSync(fullPath).isDirectory()) {
|
|
52
|
+
return modules;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const items = readdirSync(fullPath);
|
|
56
|
+
|
|
57
|
+
for (const item of items) {
|
|
58
|
+
const itemPath = join(fullPath, item);
|
|
59
|
+
|
|
60
|
+
if (statSync(itemPath).isDirectory()) {
|
|
61
|
+
const indexPath = join(itemPath, "index.ts");
|
|
62
|
+
|
|
63
|
+
try {
|
|
64
|
+
if (statSync(indexPath).isFile()) {
|
|
65
|
+
const module = await this.loadModule(indexPath);
|
|
66
|
+
if (module) {
|
|
67
|
+
modules.push(module);
|
|
68
|
+
console.log(
|
|
69
|
+
`Auto-discovered module directory: ${module.name} from ${item}/`,
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
} catch {
|
|
74
|
+
// Try alternate patterns
|
|
75
|
+
const alternates = ["module.ts", `${item}.module.ts`, "config.ts"];
|
|
76
|
+
|
|
77
|
+
for (const alt of alternates) {
|
|
78
|
+
const altPath = join(itemPath, alt);
|
|
79
|
+
try {
|
|
80
|
+
if (statSync(altPath).isFile()) {
|
|
81
|
+
const module = await this.loadModule(altPath);
|
|
82
|
+
if (module) {
|
|
83
|
+
modules.push(module);
|
|
84
|
+
console.log(
|
|
85
|
+
`Auto-discovered module: ${module.name} from ${item}/${alt}`,
|
|
86
|
+
);
|
|
87
|
+
break;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
} catch {
|
|
91
|
+
// Continue trying
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
} catch {
|
|
98
|
+
// Directory doesn't exist, that's fine
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
return modules;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// Find all module files matching the pattern
|
|
105
|
+
private findModuleFiles(): string[] {
|
|
106
|
+
const files: string[] = [];
|
|
107
|
+
this.scanDirectory(this.baseDir, files);
|
|
108
|
+
return files.filter((file) => this.options.pattern?.test(file));
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// Recursively scan directories for module files
|
|
112
|
+
private scanDirectory(dir: string, files: string[]): void {
|
|
113
|
+
try {
|
|
114
|
+
const items = readdirSync(dir);
|
|
115
|
+
|
|
116
|
+
for (const item of items) {
|
|
117
|
+
const fullPath = join(dir, item);
|
|
118
|
+
const stat = statSync(fullPath);
|
|
119
|
+
|
|
120
|
+
if (stat.isDirectory()) {
|
|
121
|
+
// Skip node_modules and other common directories
|
|
122
|
+
if (
|
|
123
|
+
!["node_modules", ".git", "dist", "build"].includes(item) &&
|
|
124
|
+
this.options.recursive
|
|
125
|
+
) {
|
|
126
|
+
this.scanDirectory(fullPath, files);
|
|
127
|
+
}
|
|
128
|
+
} else if (stat.isFile()) {
|
|
129
|
+
const ext = extname(item);
|
|
130
|
+
if (this.options.extensions?.includes(ext)) {
|
|
131
|
+
files.push(fullPath);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
} catch {
|
|
136
|
+
// Directory not accessible, skip
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// Load a module from a file path
|
|
141
|
+
private async loadModule(modulePath: string): Promise<ModuleConfig | null> {
|
|
142
|
+
try {
|
|
143
|
+
const module = await import(modulePath);
|
|
144
|
+
|
|
145
|
+
// Try different export patterns
|
|
146
|
+
const candidates = [
|
|
147
|
+
module.default,
|
|
148
|
+
module.module,
|
|
149
|
+
module.config,
|
|
150
|
+
module,
|
|
151
|
+
...Object.values(module).filter(
|
|
152
|
+
(exp) =>
|
|
153
|
+
exp && typeof exp === "object" && "name" in exp && "version" in exp,
|
|
154
|
+
),
|
|
155
|
+
];
|
|
156
|
+
|
|
157
|
+
for (const candidate of candidates) {
|
|
158
|
+
if (this.isValidModule(candidate)) {
|
|
159
|
+
return candidate as ModuleConfig;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
return null;
|
|
164
|
+
} catch (error) {
|
|
165
|
+
throw new Error(`Failed to import module: ${(error as Error).message}`);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// Validate that an object is a valid ModuleConfig
|
|
170
|
+
private isValidModule(obj: any): boolean {
|
|
171
|
+
return (
|
|
172
|
+
obj &&
|
|
173
|
+
typeof obj === "object" &&
|
|
174
|
+
typeof obj.name === "string" &&
|
|
175
|
+
typeof obj.version === "string" &&
|
|
176
|
+
(obj.routes === undefined || Array.isArray(obj.routes)) &&
|
|
177
|
+
(obj.websockets === undefined || Array.isArray(obj.websockets)) &&
|
|
178
|
+
(obj.services === undefined || Array.isArray(obj.services))
|
|
179
|
+
);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
// Watch for module changes (for development)
|
|
183
|
+
watchModules(callback: (modules: ModuleConfig[]) => void): void {
|
|
184
|
+
const fs = require("fs");
|
|
185
|
+
const modulePaths = this.findModuleFiles();
|
|
186
|
+
|
|
187
|
+
modulePaths.forEach((path) => {
|
|
188
|
+
try {
|
|
189
|
+
fs.watchFile(path, async () => {
|
|
190
|
+
console.log(`Module file changed: ${path}`);
|
|
191
|
+
const modules = await this.discoverModules();
|
|
192
|
+
callback(modules);
|
|
193
|
+
});
|
|
194
|
+
} catch {
|
|
195
|
+
// File watching not supported or failed
|
|
196
|
+
}
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// Convenience functions
|
|
202
|
+
export async function autoDiscoverModules(
|
|
203
|
+
baseDir?: string,
|
|
204
|
+
options?: DiscoveryOptions,
|
|
205
|
+
): Promise<ModuleConfig[]> {
|
|
206
|
+
const discovery = new ModuleDiscovery(baseDir, options);
|
|
207
|
+
return discovery.discoverModules();
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
export async function autoDiscoverModuleDirectories(
|
|
211
|
+
baseDir?: string,
|
|
212
|
+
modulesDir?: string,
|
|
213
|
+
): Promise<ModuleConfig[]> {
|
|
214
|
+
const discovery = new ModuleDiscovery(baseDir);
|
|
215
|
+
return discovery.discoverModuleDirectories(modulesDir);
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
// Module registry for tracking loaded modules
|
|
219
|
+
export class ModuleRegistry {
|
|
220
|
+
private modules = new Map<string, ModuleConfig>();
|
|
221
|
+
private loadedModules = new Set<string>();
|
|
222
|
+
|
|
223
|
+
register(module: ModuleConfig): void {
|
|
224
|
+
const key = `${module.name}@${module.version}`;
|
|
225
|
+
this.modules.set(key, module);
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
markLoaded(moduleName: string, version: string): void {
|
|
229
|
+
const key = `${moduleName}@${version}`;
|
|
230
|
+
this.loadedModules.add(key);
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
isLoaded(moduleName: string, version: string): boolean {
|
|
234
|
+
const key = `${moduleName}@${version}`;
|
|
235
|
+
return this.loadedModules.has(key);
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
getModule(moduleName: string, version?: string): ModuleConfig | undefined {
|
|
239
|
+
if (version) {
|
|
240
|
+
return this.modules.get(`${moduleName}@${version}`);
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
// Find latest version if no version specified
|
|
244
|
+
const modules = Array.from(this.modules.entries())
|
|
245
|
+
.filter(([key]) => key.startsWith(`${moduleName}@`))
|
|
246
|
+
.sort(([a], [b]) => b.localeCompare(a)); // Sort by version desc
|
|
247
|
+
|
|
248
|
+
return modules[0]?.[1];
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
getAllModules(): ModuleConfig[] {
|
|
252
|
+
return Array.from(this.modules.values());
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
getLoadedModules(): ModuleConfig[] {
|
|
256
|
+
return Array.from(this.modules.entries())
|
|
257
|
+
.filter(([key]) => this.loadedModules.has(key))
|
|
258
|
+
.map(([, module]) => module);
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
clear(): void {
|
|
262
|
+
this.modules.clear();
|
|
263
|
+
this.loadedModules.clear();
|
|
264
|
+
}
|
|
265
|
+
}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
// Module System - Definition and Loading
|
|
2
|
+
import { promises as fs } from "fs";
|
|
3
|
+
import path from "path";
|
|
4
|
+
import { Container } from "../utilities";
|
|
5
|
+
import { ModuleConfig } from "../../types/module";
|
|
6
|
+
import {
|
|
7
|
+
ModuleDefinition,
|
|
8
|
+
ModuleRoute,
|
|
9
|
+
ModuleSocket,
|
|
10
|
+
} from "../../types/module";
|
|
11
|
+
|
|
12
|
+
// Module Definition Function
|
|
13
|
+
export function defineModule(definition: ModuleDefinition): ModuleConfig {
|
|
14
|
+
const moduleConfig: ModuleConfig = {
|
|
15
|
+
name: definition.name,
|
|
16
|
+
version: definition.version,
|
|
17
|
+
dependencies: definition.dependencies,
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
// Store route definitions and handlers
|
|
21
|
+
if (definition.routes) {
|
|
22
|
+
moduleConfig.routes = definition.routes.map((route, index) => ({
|
|
23
|
+
method: route.method,
|
|
24
|
+
path: route.path,
|
|
25
|
+
handler: `route_handler_${index}`, // Standardized naming
|
|
26
|
+
validation: route.validation,
|
|
27
|
+
cache: route.cache,
|
|
28
|
+
rateLimit: route.rateLimit,
|
|
29
|
+
middleware: route.middleware,
|
|
30
|
+
}));
|
|
31
|
+
|
|
32
|
+
// Store the actual route handler functions
|
|
33
|
+
moduleConfig.routeHandlers = definition.routes.reduce(
|
|
34
|
+
(acc, route, index) => {
|
|
35
|
+
acc[`route_handler_${index}`] = route.handler;
|
|
36
|
+
return acc;
|
|
37
|
+
},
|
|
38
|
+
{} as Record<string, Function>,
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// Store socket definitions and handlers
|
|
43
|
+
if (definition.sockets) {
|
|
44
|
+
moduleConfig.sockets = definition.sockets.map((socket, index) => ({
|
|
45
|
+
event: socket.event,
|
|
46
|
+
handler: `socket_handler_${index}`, // Standardized naming
|
|
47
|
+
validation: socket.validation,
|
|
48
|
+
rateLimit: socket.rateLimit,
|
|
49
|
+
rooms: socket.rooms,
|
|
50
|
+
broadcast: socket.broadcast,
|
|
51
|
+
}));
|
|
52
|
+
|
|
53
|
+
// Store the actual socket handler functions
|
|
54
|
+
moduleConfig.socketHandlers = definition.sockets.reduce(
|
|
55
|
+
(acc, socket, index) => {
|
|
56
|
+
acc[`socket_handler_${index}`] = socket.handler;
|
|
57
|
+
return acc;
|
|
58
|
+
},
|
|
59
|
+
{} as Record<string, Function>,
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Copy config
|
|
64
|
+
if (definition.config) {
|
|
65
|
+
moduleConfig.config = definition.config;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return moduleConfig;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// Module Loader Class
|
|
72
|
+
export class ModuleLoader {
|
|
73
|
+
constructor(private container: Container) {}
|
|
74
|
+
|
|
75
|
+
async discoverModules(directory: string): Promise<ModuleConfig[]> {
|
|
76
|
+
const modules: ModuleConfig[] = [];
|
|
77
|
+
|
|
78
|
+
try {
|
|
79
|
+
const moduleDir = path.resolve(directory);
|
|
80
|
+
const entries = await fs.readdir(moduleDir, { withFileTypes: true });
|
|
81
|
+
|
|
82
|
+
for (const entry of entries) {
|
|
83
|
+
if (entry.isDirectory()) {
|
|
84
|
+
const modulePath = path.join(moduleDir, entry.name, "index.ts");
|
|
85
|
+
|
|
86
|
+
try {
|
|
87
|
+
await fs.access(modulePath);
|
|
88
|
+
const moduleExports = await import(modulePath);
|
|
89
|
+
|
|
90
|
+
// Look for exported module config
|
|
91
|
+
for (const exportName of Object.keys(moduleExports)) {
|
|
92
|
+
const exported = moduleExports[exportName];
|
|
93
|
+
if (
|
|
94
|
+
exported &&
|
|
95
|
+
typeof exported === "object" &&
|
|
96
|
+
exported.name &&
|
|
97
|
+
exported.version
|
|
98
|
+
) {
|
|
99
|
+
modules.push(exported as ModuleConfig);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
} catch (error) {
|
|
103
|
+
console.warn(
|
|
104
|
+
`⚠️ Could not load module from ${modulePath}:`,
|
|
105
|
+
error instanceof Error ? error.message : String(error),
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
} catch (error) {
|
|
111
|
+
console.error("Failed to discover modules:", error);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
return modules;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
validateModule(config: ModuleConfig): boolean {
|
|
118
|
+
if (!config.name || !config.version) {
|
|
119
|
+
return false;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// [TODO] Add more validation logic here
|
|
123
|
+
return true;
|
|
124
|
+
}
|
|
125
|
+
}
|