@morojs/moro 1.2.1 → 1.4.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.
Files changed (92) hide show
  1. package/LICENSE +2 -2
  2. package/README.md +61 -7
  3. package/dist/core/config/file-loader.js +31 -25
  4. package/dist/core/config/file-loader.js.map +1 -1
  5. package/dist/core/config/schema.d.ts +2 -2
  6. package/dist/core/config/schema.js +1 -1
  7. package/dist/core/config/schema.js.map +1 -1
  8. package/dist/core/config/types.d.ts +147 -0
  9. package/dist/core/config/types.js +124 -0
  10. package/dist/core/config/types.js.map +1 -0
  11. package/dist/core/config/typescript-loader.d.ts +6 -0
  12. package/dist/core/config/typescript-loader.js +268 -0
  13. package/dist/core/config/typescript-loader.js.map +1 -0
  14. package/dist/core/config/validation.d.ts +18 -0
  15. package/dist/core/config/validation.js +134 -0
  16. package/dist/core/config/validation.js.map +1 -0
  17. package/dist/core/docs/openapi-generator.js +6 -6
  18. package/dist/core/docs/openapi-generator.js.map +1 -1
  19. package/dist/core/docs/schema-to-openapi.d.ts +7 -0
  20. package/dist/core/docs/schema-to-openapi.js +124 -0
  21. package/dist/core/docs/schema-to-openapi.js.map +1 -0
  22. package/dist/core/docs/zod-to-openapi.d.ts +2 -0
  23. package/dist/core/docs/zod-to-openapi.js.map +1 -1
  24. package/dist/core/events/event-bus.js +4 -0
  25. package/dist/core/events/event-bus.js.map +1 -1
  26. package/dist/core/framework.d.ts +29 -6
  27. package/dist/core/framework.js +117 -18
  28. package/dist/core/framework.js.map +1 -1
  29. package/dist/core/http/http-server.d.ts +33 -0
  30. package/dist/core/http/http-server.js +329 -28
  31. package/dist/core/http/http-server.js.map +1 -1
  32. package/dist/core/networking/adapters/index.d.ts +3 -0
  33. package/dist/core/networking/adapters/index.js +10 -0
  34. package/dist/core/networking/adapters/index.js.map +1 -0
  35. package/dist/core/networking/adapters/socketio-adapter.d.ts +16 -0
  36. package/dist/core/networking/adapters/socketio-adapter.js +244 -0
  37. package/dist/core/networking/adapters/socketio-adapter.js.map +1 -0
  38. package/dist/core/networking/adapters/ws-adapter.d.ts +54 -0
  39. package/dist/core/networking/adapters/ws-adapter.js +383 -0
  40. package/dist/core/networking/adapters/ws-adapter.js.map +1 -0
  41. package/dist/core/networking/websocket-adapter.d.ts +171 -0
  42. package/dist/core/networking/websocket-adapter.js +5 -0
  43. package/dist/core/networking/websocket-adapter.js.map +1 -0
  44. package/dist/core/networking/websocket-manager.d.ts +53 -17
  45. package/dist/core/networking/websocket-manager.js +166 -108
  46. package/dist/core/networking/websocket-manager.js.map +1 -1
  47. package/dist/core/routing/index.d.ts +13 -13
  48. package/dist/core/routing/index.js.map +1 -1
  49. package/dist/core/utilities/container.d.ts +1 -0
  50. package/dist/core/utilities/container.js +11 -1
  51. package/dist/core/utilities/container.js.map +1 -1
  52. package/dist/core/validation/adapters.d.ts +51 -0
  53. package/dist/core/validation/adapters.js +135 -0
  54. package/dist/core/validation/adapters.js.map +1 -0
  55. package/dist/core/validation/index.d.ts +14 -11
  56. package/dist/core/validation/index.js +37 -26
  57. package/dist/core/validation/index.js.map +1 -1
  58. package/dist/core/validation/schema-interface.d.ts +36 -0
  59. package/dist/core/validation/schema-interface.js +68 -0
  60. package/dist/core/validation/schema-interface.js.map +1 -0
  61. package/dist/index.d.ts +6 -1
  62. package/dist/index.js +14 -3
  63. package/dist/index.js.map +1 -1
  64. package/dist/moro.d.ts +8 -0
  65. package/dist/moro.js +339 -14
  66. package/dist/moro.js.map +1 -1
  67. package/dist/types/core.d.ts +17 -0
  68. package/package.json +42 -14
  69. package/src/core/config/file-loader.ts +34 -25
  70. package/src/core/config/schema.ts +1 -1
  71. package/src/core/config/types.ts +277 -0
  72. package/src/core/config/typescript-loader.ts +571 -0
  73. package/src/core/config/validation.ts +145 -0
  74. package/src/core/docs/openapi-generator.ts +7 -6
  75. package/src/core/docs/schema-to-openapi.ts +148 -0
  76. package/src/core/docs/zod-to-openapi.ts +2 -0
  77. package/src/core/events/event-bus.ts +5 -0
  78. package/src/core/framework.ts +121 -28
  79. package/src/core/http/http-server.ts +377 -28
  80. package/src/core/networking/adapters/index.ts +16 -0
  81. package/src/core/networking/adapters/socketio-adapter.ts +252 -0
  82. package/src/core/networking/adapters/ws-adapter.ts +425 -0
  83. package/src/core/networking/websocket-adapter.ts +217 -0
  84. package/src/core/networking/websocket-manager.ts +185 -127
  85. package/src/core/routing/index.ts +13 -13
  86. package/src/core/utilities/container.ts +14 -1
  87. package/src/core/validation/adapters.ts +147 -0
  88. package/src/core/validation/index.ts +60 -38
  89. package/src/core/validation/schema-interface.ts +100 -0
  90. package/src/index.ts +25 -2
  91. package/src/moro.ts +405 -15
  92. package/src/types/core.ts +18 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@morojs/moro",
3
- "version": "1.2.1",
3
+ "version": "1.4.0",
4
4
  "description": "High-performance Node.js framework with intelligent routing, automatic middleware ordering, enterprise authentication (Auth.js), type-safe Zod validation, and functional architecture",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -14,7 +14,7 @@
14
14
  },
15
15
  "scripts": {
16
16
  "build": "tsc",
17
- "dev": "ts-node-dev --respawn --transpile-only --ignore-watch node_modules src/index.ts",
17
+ "dev": "tsx watch src/index.ts",
18
18
  "dev:watch": "tsc --watch",
19
19
  "clean": "rm -rf dist",
20
20
  "prepare": "husky",
@@ -34,8 +34,11 @@
34
34
  "format": "prettier --write \"src/**/*.ts\"",
35
35
  "format:check": "prettier --check \"src/**/*.ts\"",
36
36
  "lint-staged": "lint-staged",
37
- "docs:build": "typedoc --out docs src/index.ts",
38
- "docs:serve": "http-server docs -p 8080"
37
+ "docs:build": "typedoc --out docs-html src/index.ts",
38
+ "docs:serve": "http-server docs-html -p 8080",
39
+ "docs:json": "typedoc --json docs-json/api.json src/index.ts",
40
+ "docs:markdown": "typedoc --plugin typedoc-plugin-markdown --out docs-md src/index.ts",
41
+ "docs:all": "npm run docs:build && npm run docs:json && npm run docs:markdown"
39
42
  },
40
43
  "keywords": [
41
44
  "nodejs",
@@ -70,10 +73,7 @@
70
73
  "engines": {
71
74
  "node": ">=18.0.0"
72
75
  },
73
- "dependencies": {
74
- "socket.io": "^4.8.1",
75
- "zod": "^4.1.5"
76
- },
76
+ "dependencies": {},
77
77
  "peerDependencies": {
78
78
  "@auth/core": "^0.37.3",
79
79
  "better-sqlite3": "^12.2.0",
@@ -82,8 +82,13 @@
82
82
  "mongodb": "^6.19.0",
83
83
  "mysql2": "^3.14.5",
84
84
  "pg": "^8.16.3",
85
+ "socket.io": "^4.8.1",
85
86
  "swagger-ui-dist": "^5.28.1",
86
- "ts-node": "^10.9.1"
87
+ "ws": "^8.18.0",
88
+ "zod": "^4.1.5",
89
+ "joi": "^17.0.0",
90
+ "yup": "^1.0.0",
91
+ "class-validator": "^0.14.0"
87
92
  },
88
93
  "peerDependenciesMeta": {
89
94
  "@auth/core": {
@@ -95,9 +100,6 @@
95
100
  "swagger-ui-dist": {
96
101
  "optional": true
97
102
  },
98
- "ts-node": {
99
- "optional": true
100
- },
101
103
  "pg": {
102
104
  "optional": true
103
105
  },
@@ -112,6 +114,24 @@
112
114
  },
113
115
  "drizzle-orm": {
114
116
  "optional": true
117
+ },
118
+ "socket.io": {
119
+ "optional": true
120
+ },
121
+ "ws": {
122
+ "optional": true
123
+ },
124
+ "zod": {
125
+ "optional": true
126
+ },
127
+ "joi": {
128
+ "optional": true
129
+ },
130
+ "yup": {
131
+ "optional": true
132
+ },
133
+ "class-validator": {
134
+ "optional": true
115
135
  }
116
136
  },
117
137
  "devDependencies": {
@@ -120,6 +140,7 @@
120
140
  "@types/jest": "^30.0.0",
121
141
  "@types/node": "^24.3.1",
122
142
  "@types/supertest": "^6.0.2",
143
+ "@types/ws": "^8.18.1",
123
144
  "@typescript-eslint/eslint-plugin": "^8.18.2",
124
145
  "@typescript-eslint/parser": "^8.18.2",
125
146
  "depcheck": "^1.4.7",
@@ -131,11 +152,18 @@
131
152
  "jest": "^30.1.3",
132
153
  "lint-staged": "^16.1.6",
133
154
  "prettier": "^3.4.2",
155
+ "socket.io": "^4.8.1",
134
156
  "supertest": "^7.0.0",
135
157
  "ts-jest": "^29.4.1",
136
- "ts-node-dev": "^2.0.0",
158
+ "tsx": "^4.7.0",
137
159
  "typedoc": "^0.28.12",
138
- "typescript": "^5.9.2"
160
+ "typedoc-github-theme": "^0.3.1",
161
+ "typedoc-material-theme": "^1.4.0",
162
+ "typedoc-plugin-extras": "^4.0.1",
163
+ "typedoc-plugin-markdown": "^4.8.1",
164
+ "typedoc-theme-hierarchy": "^6.0.0",
165
+ "typescript": "^5.9.2",
166
+ "ws": "^8.18.3"
139
167
  },
140
168
  "files": [
141
169
  "dist/**/*",
@@ -23,11 +23,35 @@ export function loadConfigFileSync(cwd: string = process.cwd()): Partial<AppConf
23
23
  logger.debug('No configuration file found');
24
24
  return null;
25
25
  }
26
+ // Handle TypeScript files by trying dynamic import (works with tsx/ts-node runtimes)
27
+ if (configFile.endsWith('.ts')) {
28
+ logger.debug('Found TypeScript config file, attempting to load with dynamic import');
29
+ try {
30
+ // When running under tsx/ts-node, dynamic imports work synchronously for TypeScript
31
+ // We can use require() with the current environment that already has TypeScript support
32
+ const config = require(configFile);
33
+ const configData = config.default || config;
34
+
35
+ if (!configData || typeof configData !== 'object') {
36
+ logger.warn(`Configuration file ${configFile} did not export a valid configuration object`);
37
+ return null;
38
+ }
39
+
40
+ logger.info(`TypeScript configuration loaded from: ${configFile}`);
41
+ return configData;
42
+ } catch (error) {
43
+ logger.debug(
44
+ 'TypeScript config loading failed in sync mode, this is expected if not running with tsx/ts-node'
45
+ );
46
+ logger.debug('Error details:', String(error));
47
+ return null;
48
+ }
49
+ }
26
50
 
27
- // Only support .js files for synchronous loading to avoid complexity
51
+ // Only .js files use the standard synchronous loading
28
52
  if (!configFile.endsWith('.js')) {
29
53
  logger.debug(
30
- 'Found config file, but only JavaScript files are supported in sync mode. Use loadConfigFile() for TypeScript support.'
54
+ 'Found config file with unsupported extension. Only .js and .ts files are supported.'
31
55
  );
32
56
  return null;
33
57
  }
@@ -129,7 +153,7 @@ async function importConfigFile(filePath: string): Promise<Partial<AppConfig> |
129
153
  error.message.includes('Unknown file extension')
130
154
  ) {
131
155
  throw new Error(
132
- `Failed to load TypeScript config file. Make sure you have ts-node installed: npm install --save-dev ts-node`
156
+ `Failed to load TypeScript config file. Run your application with tsx or ts-node: "tsx your-app.ts" or "ts-node your-app.ts"`
133
157
  );
134
158
  }
135
159
  throw error;
@@ -138,30 +162,15 @@ async function importConfigFile(filePath: string): Promise<Partial<AppConfig> |
138
162
 
139
163
  /**
140
164
  * Setup TypeScript loader for .ts config files
165
+ * Note: This function is intentionally minimal because TypeScript config files
166
+ * should be handled by the runtime environment (tsx, ts-node, etc.) when the
167
+ * user runs their application, not by the framework itself.
141
168
  */
142
169
  async function setupTypeScriptLoader(): Promise<void> {
143
- try {
144
- // Try to register ts-node if available
145
- const tsNode = await import('ts-node');
146
- if (!tsNode.register) {
147
- // ts-node might already be registered
148
- return;
149
- }
150
-
151
- tsNode.register({
152
- transpileOnly: true,
153
- compilerOptions: {
154
- module: 'commonjs',
155
- target: 'es2020',
156
- moduleResolution: 'node',
157
- allowSyntheticDefaultImports: true,
158
- esModuleInterop: true,
159
- },
160
- });
161
- } catch (error) {
162
- // ts-node not available, try other methods or fail gracefully
163
- logger.debug('ts-node not available for TypeScript config loading');
164
- }
170
+ // No-op: TypeScript loading is handled by the runtime environment
171
+ // When users run `tsx moro.config.ts` or `ts-node moro.config.ts`,
172
+ // the TypeScript transpilation is already handled by those tools.
173
+ logger.debug('TypeScript config loading delegated to runtime environment');
165
174
  }
166
175
 
167
176
  /**
@@ -243,7 +243,7 @@ const PerformanceConfigSchema = z.object({
243
243
 
244
244
  clustering: z.object({
245
245
  enabled: z.coerce.boolean().default(false),
246
- workers: z.coerce.number().min(1).default(1),
246
+ workers: z.union([z.coerce.number().min(1), z.literal('auto')]).default(1),
247
247
  }),
248
248
  });
249
249
 
@@ -0,0 +1,277 @@
1
+ // TypeScript-based Configuration Types for Moro Framework
2
+ // Replaces Zod schemas with pure TypeScript interfaces
3
+
4
+ export interface ServerConfig {
5
+ port: number;
6
+ host: string;
7
+ environment: 'development' | 'staging' | 'production';
8
+ maxConnections: number;
9
+ timeout: number;
10
+ }
11
+
12
+ export interface ServiceDiscoveryConfig {
13
+ enabled: boolean;
14
+ type: 'memory' | 'consul' | 'kubernetes';
15
+ consulUrl: string;
16
+ kubernetesNamespace: string;
17
+ healthCheckInterval: number;
18
+ retryAttempts: number;
19
+ }
20
+
21
+ export interface DatabaseConfig {
22
+ url?: string;
23
+ redis: {
24
+ url: string;
25
+ maxRetries: number;
26
+ retryDelay: number;
27
+ keyPrefix: string;
28
+ };
29
+ mysql?: {
30
+ host: string;
31
+ port: number;
32
+ database?: string;
33
+ username?: string;
34
+ password?: string;
35
+ connectionLimit: number;
36
+ acquireTimeout: number;
37
+ timeout: number;
38
+ };
39
+ }
40
+
41
+ export interface ModuleDefaultsConfig {
42
+ cache: {
43
+ enabled: boolean;
44
+ defaultTtl: number;
45
+ maxSize: number;
46
+ strategy: 'lru' | 'lfu' | 'fifo';
47
+ };
48
+ rateLimit: {
49
+ enabled: boolean;
50
+ defaultRequests: number;
51
+ defaultWindow: number;
52
+ skipSuccessfulRequests: boolean;
53
+ skipFailedRequests: boolean;
54
+ };
55
+ validation: {
56
+ enabled: boolean;
57
+ stripUnknown: boolean;
58
+ abortEarly: boolean;
59
+ };
60
+ }
61
+
62
+ export interface LoggingConfig {
63
+ level: 'debug' | 'info' | 'warn' | 'error' | 'fatal';
64
+ format: 'pretty' | 'json' | 'compact';
65
+ enableColors: boolean;
66
+ enableTimestamp: boolean;
67
+ enableContext: boolean;
68
+ outputs: {
69
+ console: boolean;
70
+ file: {
71
+ enabled: boolean;
72
+ path: string;
73
+ maxSize: string;
74
+ maxFiles: number;
75
+ };
76
+ webhook: {
77
+ enabled: boolean;
78
+ url?: string;
79
+ headers: Record<string, string>;
80
+ };
81
+ };
82
+ }
83
+
84
+ export interface SecurityConfig {
85
+ cors: {
86
+ enabled: boolean;
87
+ origin: string | string[] | boolean;
88
+ methods: string[];
89
+ allowedHeaders: string[];
90
+ credentials: boolean;
91
+ };
92
+ helmet: {
93
+ enabled: boolean;
94
+ contentSecurityPolicy: boolean;
95
+ hsts: boolean;
96
+ noSniff: boolean;
97
+ frameguard: boolean;
98
+ };
99
+ rateLimit: {
100
+ global: {
101
+ enabled: boolean;
102
+ requests: number;
103
+ window: number;
104
+ };
105
+ };
106
+ }
107
+
108
+ export interface ExternalServicesConfig {
109
+ stripe?: {
110
+ secretKey?: string;
111
+ publishableKey?: string;
112
+ webhookSecret?: string;
113
+ apiVersion: string;
114
+ };
115
+ paypal?: {
116
+ clientId?: string;
117
+ clientSecret?: string;
118
+ webhookId?: string;
119
+ environment: 'sandbox' | 'production';
120
+ };
121
+ smtp?: {
122
+ host?: string;
123
+ port: number;
124
+ secure: boolean;
125
+ username?: string;
126
+ password?: string;
127
+ };
128
+ }
129
+
130
+ export interface PerformanceConfig {
131
+ compression: {
132
+ enabled: boolean;
133
+ level: number;
134
+ threshold: number;
135
+ };
136
+ circuitBreaker: {
137
+ enabled: boolean;
138
+ failureThreshold: number;
139
+ resetTimeout: number;
140
+ monitoringPeriod: number;
141
+ };
142
+ clustering: {
143
+ enabled: boolean;
144
+ workers: number | 'auto';
145
+ };
146
+ }
147
+
148
+ // Main configuration interface
149
+ export interface AppConfig {
150
+ server: ServerConfig;
151
+ serviceDiscovery: ServiceDiscoveryConfig;
152
+ database: DatabaseConfig;
153
+ modules: ModuleDefaultsConfig;
154
+ logging: LoggingConfig;
155
+ security: SecurityConfig;
156
+ external: ExternalServicesConfig;
157
+ performance: PerformanceConfig;
158
+ }
159
+
160
+ // Default configuration
161
+ export const DEFAULT_CONFIG: AppConfig = {
162
+ server: {
163
+ port: 3001,
164
+ host: 'localhost',
165
+ environment: 'development',
166
+ maxConnections: 1000,
167
+ timeout: 30000,
168
+ },
169
+ serviceDiscovery: {
170
+ enabled: false,
171
+ type: 'memory',
172
+ consulUrl: 'http://localhost:8500',
173
+ kubernetesNamespace: 'default',
174
+ healthCheckInterval: 30000,
175
+ retryAttempts: 3,
176
+ },
177
+ database: {
178
+ redis: {
179
+ url: 'redis://localhost:6379',
180
+ maxRetries: 3,
181
+ retryDelay: 1000,
182
+ keyPrefix: 'moro:',
183
+ },
184
+ },
185
+ modules: {
186
+ cache: {
187
+ enabled: true,
188
+ defaultTtl: 300,
189
+ maxSize: 1000,
190
+ strategy: 'lru',
191
+ },
192
+ rateLimit: {
193
+ enabled: true,
194
+ defaultRequests: 100,
195
+ defaultWindow: 60000,
196
+ skipSuccessfulRequests: false,
197
+ skipFailedRequests: false,
198
+ },
199
+ validation: {
200
+ enabled: true,
201
+ stripUnknown: true,
202
+ abortEarly: false,
203
+ },
204
+ },
205
+ logging: {
206
+ level: 'info',
207
+ format: 'pretty',
208
+ enableColors: true,
209
+ enableTimestamp: true,
210
+ enableContext: true,
211
+ outputs: {
212
+ console: true,
213
+ file: {
214
+ enabled: false,
215
+ path: './logs/moro.log',
216
+ maxSize: '10MB',
217
+ maxFiles: 5,
218
+ },
219
+ webhook: {
220
+ enabled: false,
221
+ headers: {},
222
+ },
223
+ },
224
+ },
225
+ security: {
226
+ cors: {
227
+ enabled: true,
228
+ origin: '*',
229
+ methods: ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'OPTIONS'],
230
+ allowedHeaders: ['Content-Type', 'Authorization'],
231
+ credentials: false,
232
+ },
233
+ helmet: {
234
+ enabled: true,
235
+ contentSecurityPolicy: true,
236
+ hsts: true,
237
+ noSniff: true,
238
+ frameguard: true,
239
+ },
240
+ rateLimit: {
241
+ global: {
242
+ enabled: false,
243
+ requests: 1000,
244
+ window: 60000,
245
+ },
246
+ },
247
+ },
248
+ external: {
249
+ stripe: {
250
+ apiVersion: '2023-10-16',
251
+ },
252
+ paypal: {
253
+ environment: 'sandbox',
254
+ },
255
+ smtp: {
256
+ port: 587,
257
+ secure: false,
258
+ },
259
+ },
260
+ performance: {
261
+ compression: {
262
+ enabled: true,
263
+ level: 6,
264
+ threshold: 1024,
265
+ },
266
+ circuitBreaker: {
267
+ enabled: true,
268
+ failureThreshold: 5,
269
+ resetTimeout: 60000,
270
+ monitoringPeriod: 10000,
271
+ },
272
+ clustering: {
273
+ enabled: false,
274
+ workers: 1,
275
+ },
276
+ },
277
+ };