@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
@@ -699,6 +699,7 @@ export class ServiceRegistrationBuilder<T> {
699
699
  // Standard Container class
700
700
  export class Container {
701
701
  private functionalContainer = new FunctionalContainer();
702
+ private resolutionCache = new Map<string, any>();
702
703
 
703
704
  register<T>(name: string, factory: () => T, singleton = false): void {
704
705
  this.functionalContainer
@@ -709,7 +710,19 @@ export class Container {
709
710
  }
710
711
 
711
712
  resolve<T>(name: string): T {
712
- return this.functionalContainer.resolveSync<T>(name);
713
+ // Fast path for cached resolutions
714
+ if (this.resolutionCache.has(name)) {
715
+ return this.resolutionCache.get(name);
716
+ }
717
+
718
+ const resolved = this.functionalContainer.resolveSync<T>(name);
719
+
720
+ // Cache result (limit cache size)
721
+ if (this.resolutionCache.size < 50) {
722
+ this.resolutionCache.set(name, resolved);
723
+ }
724
+
725
+ return resolved;
713
726
  }
714
727
 
715
728
  has(name: string): boolean {
@@ -0,0 +1,147 @@
1
+ // Validation Library Adapters for Moro Framework
2
+ // Makes Joi, Yup, and other libraries compatible with ValidationSchema interface
3
+
4
+ import { ValidationSchema, ValidationError, normalizeValidationError } from './schema-interface';
5
+
6
+ /**
7
+ * Zod Compatibility Check
8
+ * Zod ALREADY implements ValidationSchema interface natively!
9
+ * No adapter needed - it just works.
10
+ */
11
+
12
+ /**
13
+ * Joi Adapter - makes Joi schemas compatible with ValidationSchema
14
+ */
15
+ export class JoiAdapter<T = any> implements ValidationSchema<T> {
16
+ constructor(private joiSchema: any) {
17
+ if (!joiSchema || typeof joiSchema.validateAsync !== 'function') {
18
+ throw new Error('Invalid Joi schema provided to JoiAdapter');
19
+ }
20
+ }
21
+
22
+ async parseAsync(data: unknown): Promise<T> {
23
+ try {
24
+ const result = await this.joiSchema.validateAsync(data, { abortEarly: false });
25
+ return result as T;
26
+ } catch (error) {
27
+ throw normalizeValidationError(error);
28
+ }
29
+ }
30
+ }
31
+
32
+ /**
33
+ * Yup Adapter - makes Yup schemas compatible with ValidationSchema
34
+ */
35
+ export class YupAdapter<T = any> implements ValidationSchema<T> {
36
+ constructor(private yupSchema: any) {
37
+ if (!yupSchema || typeof yupSchema.validate !== 'function') {
38
+ throw new Error('Invalid Yup schema provided to YupAdapter');
39
+ }
40
+ }
41
+
42
+ async parseAsync(data: unknown): Promise<T> {
43
+ try {
44
+ const result = await this.yupSchema.validate(data, { abortEarly: false });
45
+ return result as T;
46
+ } catch (error) {
47
+ throw normalizeValidationError(error);
48
+ }
49
+ }
50
+ }
51
+
52
+ /**
53
+ * Custom Validation Function Adapter
54
+ * Allows users to use simple validation functions
55
+ */
56
+ export class FunctionAdapter<T = any> implements ValidationSchema<T> {
57
+ constructor(
58
+ private validateFn: (data: unknown) => T | Promise<T>,
59
+ private name: string = 'custom'
60
+ ) {
61
+ if (typeof validateFn !== 'function') {
62
+ throw new Error('Validation function is required for FunctionAdapter');
63
+ }
64
+ }
65
+
66
+ async parseAsync(data: unknown): Promise<T> {
67
+ try {
68
+ return await this.validateFn(data);
69
+ } catch (error) {
70
+ throw new ValidationError([
71
+ {
72
+ path: [],
73
+ message: error instanceof Error ? error.message : String(error),
74
+ code: this.name,
75
+ },
76
+ ]);
77
+ }
78
+ }
79
+ }
80
+
81
+ /**
82
+ * Class Validator Adapter (for TypeScript decorators)
83
+ */
84
+ export class ClassValidatorAdapter<T extends object = any> implements ValidationSchema<T> {
85
+ constructor(
86
+ private ClassType: new () => T,
87
+ private validate?: (obj: any) => Promise<any[]>
88
+ ) {
89
+ if (typeof ClassType !== 'function') {
90
+ throw new Error('Class constructor is required for ClassValidatorAdapter');
91
+ }
92
+ }
93
+
94
+ async parseAsync(data: unknown): Promise<T> {
95
+ try {
96
+ const instance = Object.assign(new this.ClassType(), data as Record<string, any>);
97
+
98
+ if (this.validate) {
99
+ const errors = await this.validate(instance);
100
+ if (errors && errors.length > 0) {
101
+ throw new ValidationError(
102
+ errors.map((error: any, index: number) => ({
103
+ path: error.property ? [error.property] : [index],
104
+ message: Object.values(error.constraints || {}).join(', ') || 'Validation failed',
105
+ code: 'class_validator',
106
+ }))
107
+ );
108
+ }
109
+ }
110
+
111
+ return instance as T;
112
+ } catch (error) {
113
+ if (error instanceof ValidationError) throw error;
114
+ throw normalizeValidationError(error);
115
+ }
116
+ }
117
+ }
118
+
119
+ /**
120
+ * Utility functions for creating adapters
121
+ */
122
+ export function joi<T = any>(joiSchema: any): ValidationSchema<T> {
123
+ return new JoiAdapter<T>(joiSchema);
124
+ }
125
+
126
+ export function yup<T = any>(yupSchema: any): ValidationSchema<T> {
127
+ return new YupAdapter<T>(yupSchema);
128
+ }
129
+
130
+ export function fn<T = any>(
131
+ validateFn: (data: unknown) => T | Promise<T>,
132
+ name?: string
133
+ ): ValidationSchema<T> {
134
+ return new FunctionAdapter<T>(validateFn, name);
135
+ }
136
+
137
+ export function classValidator<T extends object = any>(
138
+ ClassType: new () => T,
139
+ validate?: (obj: any) => Promise<any[]>
140
+ ): ValidationSchema<T> {
141
+ return new ClassValidatorAdapter<T>(ClassType, validate);
142
+ }
143
+
144
+ // Type helpers
145
+ export type JoiSchema<T> = ValidationSchema<T>;
146
+ export type YupSchema<T> = ValidationSchema<T>;
147
+ export type CustomValidator<T> = ValidationSchema<T>;
@@ -1,28 +1,41 @@
1
- // Functional Validation System for Moro Framework
2
- // Elegant, type-safe validation using Zod with functional composition
1
+ // Universal Validation System for Moro Framework
2
+ // Works with Zod, Joi, Yup, and any validation library via adapters
3
3
 
4
- import { z, ZodSchema, ZodError } from 'zod';
5
4
  import { HttpRequest, HttpResponse } from '../http';
6
5
  import { createFrameworkLogger } from '../logger';
6
+ import {
7
+ ValidationSchema,
8
+ ValidationError,
9
+ normalizeValidationError,
10
+ InferSchemaType,
11
+ } from './schema-interface';
12
+
13
+ // Re-export zod if available (for backward compatibility)
14
+ let z: any;
15
+ try {
16
+ z = require('zod').z;
17
+ } catch {
18
+ // Zod not available - that's fine!
19
+ }
7
20
 
8
21
  const logger = createFrameworkLogger('Validation');
9
22
 
10
- // Validation configuration interface
23
+ // Universal validation configuration interface
11
24
  export interface ValidationConfig {
12
- body?: ZodSchema;
13
- query?: ZodSchema;
14
- params?: ZodSchema;
15
- headers?: ZodSchema;
25
+ body?: ValidationSchema;
26
+ query?: ValidationSchema;
27
+ params?: ValidationSchema;
28
+ headers?: ValidationSchema;
16
29
  }
17
30
 
18
31
  // Validation result types
19
32
  export interface ValidationResult<T = any> {
20
33
  success: boolean;
21
34
  data?: T;
22
- errors?: ValidationError[];
35
+ errors?: ValidationErrorDetail[];
23
36
  }
24
37
 
25
- export interface ValidationError {
38
+ export interface ValidationErrorDetail {
26
39
  field: string;
27
40
  message: string;
28
41
  code: string;
@@ -110,9 +123,9 @@ export function validate<TBody = any, TQuery = any, TParams = any>(
110
123
  };
111
124
  }
112
125
 
113
- // Validate individual field
126
+ // Validate individual field using universal schema interface
114
127
  async function validateField(
115
- schema: ZodSchema,
128
+ schema: ValidationSchema,
116
129
  data: any,
117
130
  fieldName: string
118
131
  ): Promise<ValidationResult> {
@@ -123,32 +136,32 @@ async function validateField(
123
136
  data: validated,
124
137
  };
125
138
  } catch (error) {
126
- if (error instanceof ZodError) {
127
- const errors: ValidationError[] = error.issues.map((err: any) => ({
128
- field: err.path.length > 0 ? err.path.join('.') : fieldName,
129
- message: err.message,
130
- code: err.code,
131
- }));
132
-
133
- logger.debug('Field validation failed', 'ValidationFailed', {
134
- field: fieldName,
135
- errors: errors.length,
136
- details: errors,
137
- });
138
-
139
- return {
140
- success: false,
141
- errors,
142
- };
143
- }
139
+ const normalizedError = normalizeValidationError(error);
140
+ const errors: ValidationErrorDetail[] = normalizedError.issues.map(issue => ({
141
+ field: issue.path.length > 0 ? issue.path.join('.') : fieldName,
142
+ message: issue.message,
143
+ code: issue.code,
144
+ }));
145
+
146
+ logger.debug('Field validation failed', 'ValidationFailed', {
147
+ field: fieldName,
148
+ errors: errors.length,
149
+ details: errors,
150
+ });
144
151
 
145
- // Re-throw unexpected errors
146
- throw error;
152
+ return {
153
+ success: false,
154
+ errors,
155
+ };
147
156
  }
148
157
  }
149
158
 
150
159
  // Send validation error response
151
- function sendValidationError(res: HttpResponse, errors: ValidationError[], field: string): void {
160
+ function sendValidationError(
161
+ res: HttpResponse,
162
+ errors: ValidationErrorDetail[],
163
+ field: string
164
+ ): void {
152
165
  logger.debug('Sending validation error response', 'ValidationResponse', {
153
166
  field,
154
167
  errorCount: errors.length,
@@ -163,19 +176,19 @@ function sendValidationError(res: HttpResponse, errors: ValidationError[], field
163
176
  }
164
177
 
165
178
  // Convenience functions for single-field validation
166
- export function body<T>(schema: ZodSchema<T>) {
179
+ export function body<T>(schema: ValidationSchema<T>) {
167
180
  return (handler: (req: ValidatedRequest<T>, res: HttpResponse) => any | Promise<any>) => {
168
181
  return validate({ body: schema }, handler);
169
182
  };
170
183
  }
171
184
 
172
- export function query<T>(schema: ZodSchema<T>) {
185
+ export function query<T>(schema: ValidationSchema<T>) {
173
186
  return (handler: (req: ValidatedRequest<any>, res: HttpResponse) => any | Promise<any>) => {
174
187
  return validate({ query: schema }, handler);
175
188
  };
176
189
  }
177
190
 
178
- export function params<T>(schema: ZodSchema<T>) {
191
+ export function params<T>(schema: ValidationSchema<T>) {
179
192
  return (handler: (req: ValidatedRequest<any>, res: HttpResponse) => any | Promise<any>) => {
180
193
  return validate({ params: schema }, handler);
181
194
  };
@@ -186,5 +199,14 @@ export function combineSchemas(schemas: ValidationConfig): ValidationConfig {
186
199
  return schemas;
187
200
  }
188
201
 
189
- // Re-export Zod for convenience
190
- export { z } from 'zod';
202
+ // Re-export common validation tools
203
+ export {
204
+ ValidationSchema,
205
+ ValidationError,
206
+ normalizeValidationError,
207
+ InferSchemaType,
208
+ } from './schema-interface';
209
+ export { joi, yup, fn as customValidator, classValidator } from './adapters';
210
+
211
+ // Re-export Zod if available (optional dependency)
212
+ export { z };
@@ -0,0 +1,100 @@
1
+ // Universal Validation Schema Interface for Moro Framework
2
+ // Allows Zod, Joi, Yup, and other validation libraries to work seamlessly
3
+
4
+ /**
5
+ * Standard validation error structure
6
+ */
7
+ export interface ValidationIssue {
8
+ path: (string | number)[];
9
+ message: string;
10
+ code: string;
11
+ }
12
+
13
+ /**
14
+ * Standard validation error class
15
+ * Compatible with ZodError structure
16
+ */
17
+ export class ValidationError extends Error {
18
+ public readonly issues: ValidationIssue[];
19
+
20
+ constructor(issues: ValidationIssue[]) {
21
+ const message = `Validation failed: ${issues.map(i => i.message).join(', ')}`;
22
+ super(message);
23
+ this.name = 'ValidationError';
24
+ this.issues = issues;
25
+ }
26
+ }
27
+
28
+ /**
29
+ * Universal validation schema interface
30
+ * This is what Zod naturally implements! No breaking changes needed.
31
+ */
32
+ export interface ValidationSchema<T = any> {
33
+ /**
34
+ * Parse data asynchronously and return validated result
35
+ * Throws ValidationError on validation failure
36
+ */
37
+ parseAsync(data: unknown): Promise<T>;
38
+ }
39
+
40
+ /**
41
+ * Check if an object implements the ValidationSchema interface
42
+ */
43
+ export function isValidationSchema(obj: any): obj is ValidationSchema {
44
+ return obj && typeof obj.parseAsync === 'function';
45
+ }
46
+
47
+ /**
48
+ * Convert various error formats to our standard ValidationError
49
+ */
50
+ export function normalizeValidationError(error: any): ValidationError {
51
+ // Already our format
52
+ if (error instanceof ValidationError) {
53
+ return error;
54
+ }
55
+
56
+ // Zod error format
57
+ if (error && error.issues && Array.isArray(error.issues)) {
58
+ return new ValidationError(
59
+ error.issues.map((issue: any) => ({
60
+ path: issue.path || [],
61
+ message: issue.message || 'Validation failed',
62
+ code: issue.code || 'invalid',
63
+ }))
64
+ );
65
+ }
66
+
67
+ // Joi error format
68
+ if (error && error.details && Array.isArray(error.details)) {
69
+ return new ValidationError(
70
+ error.details.map((detail: any) => ({
71
+ path: detail.path || [],
72
+ message: detail.message || 'Validation failed',
73
+ code: detail.type || 'invalid',
74
+ }))
75
+ );
76
+ }
77
+
78
+ // Yup error format
79
+ if (error && error.errors && Array.isArray(error.errors)) {
80
+ return new ValidationError(
81
+ error.errors.map((msg: string, index: number) => ({
82
+ path: error.path ? [error.path] : [index],
83
+ message: msg,
84
+ code: error.type || 'invalid',
85
+ }))
86
+ );
87
+ }
88
+
89
+ // Generic error
90
+ return new ValidationError([
91
+ {
92
+ path: [],
93
+ message: error.message || String(error),
94
+ code: 'unknown',
95
+ },
96
+ ]);
97
+ }
98
+
99
+ // Type helper for inferring types from validation schemas
100
+ export type InferSchemaType<T> = T extends ValidationSchema<infer U> ? U : never;
package/src/index.ts CHANGED
@@ -105,15 +105,24 @@ export type {
105
105
  // Logger System
106
106
  export { createFrameworkLogger, logger } from './core/logger';
107
107
 
108
- // Validation System (Zod-based)
108
+ // Universal Validation System
109
109
  export { validate, body, query, params, combineSchemas, z } from './core/validation';
110
110
  export type {
111
111
  ValidationConfig,
112
112
  ValidationResult,
113
- ValidationError,
113
+ ValidationErrorDetail,
114
114
  ValidatedRequest,
115
115
  } from './core/validation';
116
116
 
117
+ // Universal Validation Interfaces and Adapters
118
+ export type {
119
+ ValidationSchema,
120
+ ValidationError,
121
+ InferSchemaType,
122
+ } from './core/validation/schema-interface';
123
+ export { normalizeValidationError } from './core/validation/schema-interface';
124
+ export { joi, yup, fn as customValidator, classValidator } from './core/validation/adapters';
125
+
117
126
  // Module System
118
127
  export {
119
128
  defineModule,
@@ -123,6 +132,20 @@ export {
123
132
  } from './core/modules';
124
133
  export type { ModuleDefinition, ModuleRoute, ModuleSocket, ModuleConfig } from './types/module';
125
134
 
135
+ // WebSocket Adapter System
136
+ export type {
137
+ WebSocketAdapter,
138
+ WebSocketAdapterOptions,
139
+ WebSocketNamespace,
140
+ WebSocketConnection,
141
+ WebSocketEmitter,
142
+ WebSocketMiddleware,
143
+ WebSocketEventHandler,
144
+ } from './core/networking/websocket-adapter';
145
+
146
+ // Built-in WebSocket Adapters
147
+ export { SocketIOAdapter, WSAdapter } from './core/networking/adapters';
148
+
126
149
  // Intelligent Routing System
127
150
  export { createRoute, defineRoute, EXECUTION_PHASES } from './core/routing';
128
151
  export { IntelligentRoutingManager, RouteRegistry } from './core/routing/app-integration';