@morojs/moro 1.0.3 → 1.2.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 (55) hide show
  1. package/README.md +57 -2
  2. package/dist/core/auth/morojs-adapter.d.ts +94 -0
  3. package/dist/core/auth/morojs-adapter.js +288 -0
  4. package/dist/core/auth/morojs-adapter.js.map +1 -0
  5. package/dist/core/config/file-loader.d.ts +18 -0
  6. package/dist/core/config/file-loader.js +345 -0
  7. package/dist/core/config/file-loader.js.map +1 -0
  8. package/dist/core/config/index.d.ts +6 -0
  9. package/dist/core/config/index.js +15 -0
  10. package/dist/core/config/index.js.map +1 -1
  11. package/dist/core/config/loader.d.ts +2 -1
  12. package/dist/core/config/loader.js +15 -2
  13. package/dist/core/config/loader.js.map +1 -1
  14. package/dist/core/config/utils.js +50 -3
  15. package/dist/core/config/utils.js.map +1 -1
  16. package/dist/core/http/http-server.d.ts +2 -0
  17. package/dist/core/http/http-server.js +52 -9
  18. package/dist/core/http/http-server.js.map +1 -1
  19. package/dist/core/middleware/built-in/auth-helpers.d.ts +124 -0
  20. package/dist/core/middleware/built-in/auth-helpers.js +338 -0
  21. package/dist/core/middleware/built-in/auth-helpers.js.map +1 -0
  22. package/dist/core/middleware/built-in/auth-providers.d.ts +125 -0
  23. package/dist/core/middleware/built-in/auth-providers.js +394 -0
  24. package/dist/core/middleware/built-in/auth-providers.js.map +1 -0
  25. package/dist/core/middleware/built-in/auth.d.ts +29 -1
  26. package/dist/core/middleware/built-in/auth.js +259 -16
  27. package/dist/core/middleware/built-in/auth.js.map +1 -1
  28. package/dist/core/middleware/built-in/index.d.ts +3 -1
  29. package/dist/core/middleware/built-in/index.js +19 -1
  30. package/dist/core/middleware/built-in/index.js.map +1 -1
  31. package/dist/index.d.ts +5 -1
  32. package/dist/index.js +11 -2
  33. package/dist/index.js.map +1 -1
  34. package/dist/moro.d.ts +1 -0
  35. package/dist/moro.js +19 -1
  36. package/dist/moro.js.map +1 -1
  37. package/dist/types/auth.d.ts +367 -0
  38. package/dist/types/auth.js +28 -0
  39. package/dist/types/auth.js.map +1 -0
  40. package/package.json +6 -2
  41. package/src/core/auth/README.md +339 -0
  42. package/src/core/auth/morojs-adapter.ts +402 -0
  43. package/src/core/config/file-loader.ts +398 -0
  44. package/src/core/config/index.ts +18 -0
  45. package/src/core/config/loader.ts +18 -2
  46. package/src/core/config/utils.ts +53 -3
  47. package/src/core/http/http-server.ts +61 -10
  48. package/src/core/middleware/built-in/auth-helpers.ts +401 -0
  49. package/src/core/middleware/built-in/auth-providers.ts +480 -0
  50. package/src/core/middleware/built-in/auth.ts +306 -16
  51. package/src/core/middleware/built-in/index.ts +22 -0
  52. package/src/index.ts +30 -1
  53. package/src/moro.ts +29 -1
  54. package/src/types/auth.ts +440 -0
  55. package/tsconfig.json +1 -1
@@ -1,39 +1,329 @@
1
- // Authentication Middleware
1
+ // Auth.js Authentication Middleware
2
+
2
3
  import { MiddlewareInterface, HookContext } from '../../../types/hooks';
3
4
  import { createFrameworkLogger } from '../../logger';
5
+ import {
6
+ AuthOptions,
7
+ AuthProvider,
8
+ AuthUser,
9
+ AuthSession,
10
+ AuthRequest,
11
+ OAuthProvider,
12
+ CredentialsProvider,
13
+ EmailProvider,
14
+ } from '../../../types/auth';
4
15
 
5
16
  const logger = createFrameworkLogger('AuthMiddleware');
6
17
 
7
- export const auth = (options: any = {}): MiddlewareInterface => ({
18
+ // Auth.js provider factory functions
19
+ export const providers = {
20
+ google: (options: { clientId: string; clientSecret: string }): AuthProvider => ({
21
+ id: 'google',
22
+ name: 'Google',
23
+ type: 'oauth' as const,
24
+ authorization: 'https://accounts.google.com/oauth/authorize',
25
+ token: 'https://oauth2.googleapis.com/token',
26
+ userinfo: 'https://www.googleapis.com/oauth2/v2/userinfo',
27
+ ...options,
28
+ }),
29
+
30
+ github: (options: { clientId: string; clientSecret: string }): AuthProvider => ({
31
+ id: 'github',
32
+ name: 'GitHub',
33
+ type: 'oauth' as const,
34
+ authorization: 'https://github.com/login/oauth/authorize',
35
+ token: 'https://github.com/login/oauth/access_token',
36
+ userinfo: 'https://api.github.com/user',
37
+ ...options,
38
+ }),
39
+
40
+ discord: (options: { clientId: string; clientSecret: string }): AuthProvider => ({
41
+ id: 'discord',
42
+ name: 'Discord',
43
+ type: 'oauth' as const,
44
+ authorization: 'https://discord.com/api/oauth2/authorize',
45
+ token: 'https://discord.com/api/oauth2/token',
46
+ userinfo: 'https://discord.com/api/users/@me',
47
+ ...options,
48
+ }),
49
+
50
+ credentials: (options: {
51
+ name?: string;
52
+ credentials: Record<string, any>;
53
+ authorize: (credentials: any) => Promise<any>;
54
+ }): AuthProvider => ({
55
+ id: 'credentials',
56
+ name: options.name || 'Credentials',
57
+ type: 'credentials' as const,
58
+ ...options,
59
+ }),
60
+
61
+ email: (options: {
62
+ server: string | { host: string; port: number; auth: any };
63
+ from: string;
64
+ }): AuthProvider => ({
65
+ id: 'email',
66
+ name: 'Email',
67
+ type: 'email' as const,
68
+ ...options,
69
+ }),
70
+ };
71
+
72
+ // Auth.js middleware that integrates with MoroJS's hooks system
73
+ export const auth = (options: AuthOptions): MiddlewareInterface => ({
8
74
  name: 'auth',
9
- version: '1.0.0',
75
+ version: '2.0.0',
10
76
  metadata: {
11
77
  name: 'auth',
12
- version: '1.0.0',
13
- description: 'JWT authentication middleware with token validation',
78
+ version: '2.0.0',
79
+ description: 'Auth.js authentication middleware with OAuth, JWT, and session support',
14
80
  author: 'MoroJS Team',
81
+ dependencies: [], // No dependencies - auth middleware is self-contained
82
+ tags: ['authentication', 'oauth', 'jwt', 'security'],
15
83
  },
16
84
 
17
- install: async (hooks: any, options: any = {}) => {
18
- logger.debug(`Installing auth middleware with options`, 'Installation', {
19
- options,
20
- });
85
+ install: async (hooks: any, middlewareOptions: Partial<AuthOptions> = {}) => {
86
+ logger.debug('Installing Auth.js middleware', 'Installation', { options: middlewareOptions });
21
87
 
88
+ // Merge configuration
89
+ const config: AuthOptions = {
90
+ secret: process.env.NEXTAUTH_SECRET || process.env.AUTH_SECRET || 'default-secret',
91
+ session: {
92
+ strategy: 'jwt',
93
+ maxAge: 30 * 24 * 60 * 60, // 30 days
94
+ updateAge: 24 * 60 * 60, // 24 hours
95
+ },
96
+ basePath: '/api/auth',
97
+ trustHost: true,
98
+ debug: process.env.NODE_ENV === 'development',
99
+ ...options,
100
+ ...middlewareOptions,
101
+ };
102
+
103
+ if (!config.providers || config.providers.length === 0) {
104
+ throw new Error('At least one authentication provider must be configured');
105
+ }
106
+
107
+ // Initialize Auth.js
108
+ let authInstance: any;
109
+ try {
110
+ authInstance = await initializeAuthJS(config);
111
+ logger.info('Auth.js initialized successfully', 'Initialization');
112
+ } catch (error) {
113
+ logger.error('Failed to initialize Auth.js', 'InitializationError', { error });
114
+ throw error;
115
+ }
116
+
117
+ // Register hooks for request processing
22
118
  hooks.before('request', async (context: HookContext) => {
23
119
  const req = context.request as any;
24
- const token = req.headers?.authorization?.replace('Bearer ', '');
120
+ const res = context.response as any;
121
+
122
+ // Handle Auth.js API routes first
123
+ if (req.url?.startsWith(config.basePath!)) {
124
+ try {
125
+ const response = await authInstance.handler(req, res);
126
+ if (response) {
127
+ // Auth.js handled the request, don't call next()
128
+ return response;
129
+ }
130
+ } catch (error) {
131
+ logger.error('Auth.js handler error', 'HandlerError', { error });
132
+ throw error;
133
+ }
134
+ }
135
+
136
+ // Add auth object to request for all other routes
137
+
138
+ // Extend request with auth methods
139
+ const authRequest: AuthRequest = {
140
+ user: undefined,
141
+ session: undefined,
142
+ token: undefined,
143
+ isAuthenticated: false,
144
+ signIn: async (provider?: string, options?: any) => {
145
+ return authInstance.signIn(provider, options);
146
+ },
147
+ signOut: async (options?: any) => {
148
+ return authInstance.signOut(options);
149
+ },
150
+ getSession: async () => {
151
+ return authInstance.getSession({ req });
152
+ },
153
+ getToken: async () => {
154
+ return authInstance.verifyJWT(authRequest.token || '');
155
+ },
156
+ getCsrfToken: async () => {
157
+ return authInstance.getCsrfToken();
158
+ },
159
+ getProviders: async () => {
160
+ return config.providers.reduce((acc: Record<string, AuthProvider>, provider) => {
161
+ acc[provider.id] = provider;
162
+ return acc;
163
+ }, {});
164
+ },
165
+ };
25
166
 
26
- if (token) {
167
+ // Get session/token from request
168
+ let session: AuthSession | null = null;
169
+ let token: string | null = null;
170
+
171
+ // Try JWT token first (Authorization header)
172
+ const authHeader = req.headers?.authorization;
173
+ if (authHeader?.startsWith('Bearer ')) {
174
+ token = authHeader.substring(7);
27
175
  try {
28
- // Simple token validation (in production, use proper JWT verification)
29
- if (token.startsWith('valid_')) {
30
- req.user = { id: 1, role: 'user' };
31
- logger.debug(`Auth: Verified token for request`, 'TokenValidation');
176
+ const decoded = await authInstance.verifyJWT(token);
177
+ if (decoded) {
178
+ session = await authInstance.getSession({ req: { ...req, token } });
32
179
  }
33
180
  } catch (error) {
34
- throw new Error('Invalid token');
181
+ logger.debug('Invalid JWT token', 'TokenValidation', { error });
182
+ }
183
+ }
184
+
185
+ // Try session cookie if no valid token
186
+ if (!session) {
187
+ try {
188
+ session = await authInstance.getSession({ req });
189
+ } catch (error) {
190
+ logger.debug('No valid session found', 'SessionValidation', { error });
35
191
  }
36
192
  }
193
+
194
+ // Populate auth request
195
+ if (session?.user) {
196
+ authRequest.user = session.user;
197
+ authRequest.session = session;
198
+ authRequest.token = token || undefined;
199
+ authRequest.isAuthenticated = true;
200
+
201
+ logger.debug('User authenticated', 'Authentication', {
202
+ userId: session.user.id,
203
+ provider: session.user.provider || 'unknown',
204
+ });
205
+ }
206
+
207
+ // Attach auth to request
208
+ req.auth = authRequest;
37
209
  });
210
+
211
+ // Response processing hook
212
+ hooks.after('response', async (context: HookContext) => {
213
+ const req = context.request as any;
214
+
215
+ if (req.auth?.session) {
216
+ // Update session activity if needed
217
+ try {
218
+ await authInstance.updateSession(req.auth.session);
219
+ } catch (error) {
220
+ logger.warn('Failed to update session', 'SessionUpdate', { error });
221
+ }
222
+ }
223
+ });
224
+
225
+ logger.info(
226
+ `Auth.js middleware installed with ${config.providers.length} providers`,
227
+ 'Installation'
228
+ );
38
229
  },
39
230
  });
231
+
232
+ // Mock Auth.js implementation (would be replaced with actual Auth.js)
233
+ async function initializeAuthJS(config: AuthOptions): Promise<any> {
234
+ return {
235
+ handler: async (req: any, res: any) => {
236
+ // Mock Auth.js request handler
237
+ const path = req.url.replace(config.basePath!, '');
238
+
239
+ if (path.startsWith('/signin')) {
240
+ // Handle sign in
241
+ return handleSignIn(req, res, config);
242
+ } else if (path.startsWith('/signout')) {
243
+ // Handle sign out
244
+ return handleSignOut(req, res, config);
245
+ } else if (path.startsWith('/callback')) {
246
+ // Handle OAuth callback
247
+ return handleCallback(req, res, config);
248
+ } else if (path.startsWith('/session')) {
249
+ // Handle session endpoint
250
+ return handleSession(req, res, config);
251
+ }
252
+
253
+ return null;
254
+ },
255
+
256
+ getSession: async ({ req }: { req: any }) => {
257
+ // Mock session retrieval
258
+ const sessionId =
259
+ req.cookies?.['next-auth.session-token'] ||
260
+ req.cookies?.['__Secure-next-auth.session-token'];
261
+
262
+ if (sessionId && req.session) {
263
+ return {
264
+ user: req.session.user || null,
265
+ expires: new Date(Date.now() + config.session!.maxAge! * 1000).toISOString(),
266
+ };
267
+ }
268
+
269
+ return null;
270
+ },
271
+
272
+ verifyJWT: async (token: string) => {
273
+ // Mock JWT verification
274
+ try {
275
+ // In real implementation, use jose or jsonwebtoken
276
+ const payload = JSON.parse(Buffer.from(token.split('.')[1], 'base64').toString());
277
+ return payload;
278
+ } catch {
279
+ return null;
280
+ }
281
+ },
282
+
283
+ signIn: async (provider?: string, options?: any) => {
284
+ // Mock sign in
285
+ return { url: `${config.basePath}/signin${provider ? `/${provider}` : ''}` };
286
+ },
287
+
288
+ signOut: async (options?: any) => {
289
+ // Mock sign out
290
+ return { url: `${config.basePath}/signout` };
291
+ },
292
+
293
+ updateSession: async (session: any) => {
294
+ // Mock session update
295
+ return session;
296
+ },
297
+
298
+ getCsrfToken: async () => {
299
+ // Mock CSRF token generation
300
+ const crypto = require('crypto');
301
+ return crypto.randomBytes(32).toString('hex');
302
+ },
303
+ };
304
+ }
305
+
306
+ // Mock Auth.js handlers
307
+ async function handleSignIn(req: any, res: any, config: AuthOptions) {
308
+ // Implementation would depend on the provider
309
+ logger.debug('Handling sign in request', 'SignIn');
310
+ return null;
311
+ }
312
+
313
+ async function handleSignOut(req: any, res: any, config: AuthOptions) {
314
+ // Clear session and redirect
315
+ logger.debug('Handling sign out request', 'SignOut');
316
+ return null;
317
+ }
318
+
319
+ async function handleCallback(req: any, res: any, config: AuthOptions) {
320
+ // Handle OAuth callback
321
+ logger.debug('Handling OAuth callback', 'Callback');
322
+ return null;
323
+ }
324
+
325
+ async function handleSession(req: any, res: any, config: AuthOptions) {
326
+ // Return current session
327
+ logger.debug('Handling session request', 'Session');
328
+ return null;
329
+ }
@@ -18,6 +18,28 @@ export { session } from './session';
18
18
  export { cache } from './cache';
19
19
  export { cdn } from './cdn';
20
20
 
21
+ // Auth Helpers and Extended Providers
22
+ export {
23
+ requireAuth,
24
+ requireRole,
25
+ requirePermission,
26
+ requireAdmin,
27
+ guestOnly,
28
+ optionalAuth,
29
+ withAuth,
30
+ protectedRoute,
31
+ authUtils,
32
+ authResponses,
33
+ sessionHelpers,
34
+ } from './auth-helpers';
35
+
36
+ export {
37
+ extendedProviders,
38
+ enterpriseProviders,
39
+ createCustomOAuthProvider,
40
+ createCustomOIDCProvider,
41
+ } from './auth-providers';
42
+
21
43
  // Import for collections
22
44
  import { auth } from './auth';
23
45
  import { rateLimit } from './rate-limit';
package/src/index.ts CHANGED
@@ -11,6 +11,32 @@ export {
11
11
 
12
12
  export type { MoroOptions } from './core/framework';
13
13
 
14
+ // Export auth types and middleware
15
+ export type {
16
+ AuthOptions,
17
+ AuthProvider,
18
+ AuthUser,
19
+ AuthSession,
20
+ AuthRequest,
21
+ AuthAccount,
22
+ AuthJWT,
23
+ AuthCallbacks,
24
+ AuthEvents,
25
+ AuthPages,
26
+ AuthAdapter,
27
+ OAuthProvider,
28
+ CredentialsProvider,
29
+ EmailProvider,
30
+ SignInOptions,
31
+ SignOutOptions,
32
+ } from './types/auth';
33
+
34
+ // Export native @auth/morojs adapter
35
+ export { createAuthMiddleware, MoroJSAuth } from './core/auth/morojs-adapter';
36
+
37
+ // Export Auth.js middleware and providers
38
+ export { auth, providers } from './core/middleware/built-in/auth';
39
+
14
40
  // Runtime system exports
15
41
  export type {
16
42
  RuntimeType,
@@ -136,7 +162,10 @@ export {
136
162
  getConfigValue,
137
163
  } from './core/config/utils';
138
164
 
139
- export { initializeConfig, getGlobalConfig, isConfigInitialized } from './core/config';
165
+ export { initializeConfig, getGlobalConfig, isConfigInitialized, resetConfig } from './core/config';
166
+
167
+ // Export configuration types for TypeScript users
168
+ export type { AppConfig } from './core/config';
140
169
 
141
170
  // Middleware System
142
171
  export { MiddlewareManager } from './core/middleware';
package/src/moro.ts CHANGED
@@ -11,6 +11,7 @@ import {
11
11
  logger as globalLogger,
12
12
  applyLoggingConfiguration,
13
13
  } from './core/logger';
14
+ import { MiddlewareManager } from './core/middleware';
14
15
  import { IntelligentRoutingManager } from './core/routing/app-integration';
15
16
  import { RouteBuilder, RouteSchema, CompiledRoute } from './core/routing';
16
17
  import { AppDocumentationManager, DocsConfig } from './core/docs';
@@ -46,6 +47,8 @@ export class Moro extends EventEmitter {
46
47
  // Runtime system
47
48
  private runtimeAdapter: RuntimeAdapter;
48
49
  private runtimeType: RuntimeType;
50
+ // Middleware system
51
+ private middlewareManager: MiddlewareManager;
49
52
 
50
53
  constructor(options: MoroOptions = {}) {
51
54
  super(); // Call EventEmitter constructor
@@ -77,6 +80,15 @@ export class Moro extends EventEmitter {
77
80
 
78
81
  this.coreFramework = new MoroCore();
79
82
 
83
+ // Initialize middleware system
84
+ this.middlewareManager = new MiddlewareManager();
85
+
86
+ // Integrate hooks system with HTTP server
87
+ const httpServer = (this.coreFramework as any).httpServer;
88
+ if (httpServer && httpServer.setHookManager) {
89
+ httpServer.setHookManager((this.middlewareManager as any).hooks);
90
+ }
91
+
80
92
  // Access enterprise event bus from core framework
81
93
  this.eventBus = (this.coreFramework as any).eventBus;
82
94
 
@@ -263,7 +275,23 @@ export class Moro extends EventEmitter {
263
275
  return this;
264
276
  }
265
277
 
266
- // Advanced middleware pipeline integration
278
+ // Advanced middleware pipeline integration - check if it's a MiddlewareInterface
279
+ if (
280
+ middlewareOrFunction &&
281
+ typeof middlewareOrFunction === 'object' &&
282
+ middlewareOrFunction.install &&
283
+ middlewareOrFunction.metadata
284
+ ) {
285
+ // This is a MiddlewareInterface object - install it with the MiddlewareManager
286
+ this.logger.debug(
287
+ `Installing MiddlewareInterface: ${middlewareOrFunction.metadata.name}`,
288
+ 'Middleware'
289
+ );
290
+ this.middlewareManager.install(middlewareOrFunction, config);
291
+ return this;
292
+ }
293
+
294
+ // Fallback: emit event for unknown middleware types
267
295
  this.eventBus.emit('middleware:advanced', {
268
296
  middleware: middlewareOrFunction,
269
297
  config,