frontend-hamroun 1.2.16 → 1.2.17

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 (158) hide show
  1. package/README.md +4 -0
  2. package/bin/cli.js +673 -0
  3. package/dist/component.d.ts +1 -1
  4. package/dist/context.d.ts +4 -3
  5. package/dist/index.client.d.ts +11 -0
  6. package/dist/index.d.ts +9 -89
  7. package/dist/index.js +396 -67
  8. package/dist/index.js.map +1 -0
  9. package/dist/index.mjs +392 -0
  10. package/dist/index.mjs.map +1 -0
  11. package/dist/jsx-runtime/jsx-runtime.d.ts +0 -1
  12. package/dist/jsx-runtime.d.ts +1 -1
  13. package/dist/renderer.d.ts +0 -10
  14. package/dist/server-renderer.d.ts +0 -3
  15. package/dist/server-types.d.ts +42 -0
  16. package/package.json +69 -41
  17. package/templates/basic-app/index.html +6 -6
  18. package/templates/basic-app/package.json +18 -7
  19. package/templates/basic-app/postcss.config.js +0 -1
  20. package/templates/basic-app/src/main.tsx +1 -10
  21. package/templates/basic-app/tailwind.config.js +2 -23
  22. package/templates/basic-app/tsconfig.json +4 -17
  23. package/templates/basic-app/vite.config.ts +3 -54
  24. package/templates/fullstack-app/api/hello.ts +18 -0
  25. package/templates/fullstack-app/api/users/[id].ts +73 -0
  26. package/templates/fullstack-app/api/users/index.ts +32 -0
  27. package/templates/fullstack-app/package.json +31 -0
  28. package/templates/fullstack-app/server.ts +46 -0
  29. package/templates/fullstack-app/src/pages/index.tsx +59 -0
  30. package/templates/ssr-template/vite.config.ts +1 -11
  31. package/bin/cli.cjs +0 -16
  32. package/bin/cli.mjs +0 -237
  33. package/dist/backend/api-utils.d.ts +0 -38
  34. package/dist/backend/api-utils.js +0 -135
  35. package/dist/backend/auth.d.ts +0 -134
  36. package/dist/backend/auth.js +0 -387
  37. package/dist/backend/database.d.ts +0 -27
  38. package/dist/backend/database.js +0 -91
  39. package/dist/backend/model.d.ts +0 -43
  40. package/dist/backend/model.js +0 -178
  41. package/dist/backend/router.d.ts +0 -27
  42. package/dist/backend/router.js +0 -137
  43. package/dist/backend/server.d.ts +0 -19
  44. package/dist/backend/server.js +0 -268
  45. package/dist/backend/types.d.ts +0 -217
  46. package/dist/backend/types.js +0 -1
  47. package/dist/batch.js +0 -22
  48. package/dist/cli/index.d.ts +0 -2
  49. package/dist/cli/index.js +0 -215
  50. package/dist/component.js +0 -84
  51. package/dist/components/Counter.js +0 -2
  52. package/dist/context.js +0 -18
  53. package/dist/frontend-hamroun.es.js +0 -1378
  54. package/dist/frontend-hamroun.umd.js +0 -66
  55. package/dist/hooks.js +0 -164
  56. package/dist/jsx-runtime/index.d.ts +0 -11
  57. package/dist/jsx-runtime/index.js +0 -19
  58. package/dist/jsx-runtime/jsx-dev-runtime.js +0 -1
  59. package/dist/jsx-runtime/jsx-runtime.js +0 -95
  60. package/dist/jsx-runtime.js +0 -192
  61. package/dist/renderer.js +0 -51
  62. package/dist/server-renderer.js +0 -102
  63. package/dist/types.js +0 -1
  64. package/dist/vdom.js +0 -27
  65. package/scripts/build-cli.js +0 -1199
  66. package/scripts/generate.js +0 -134
  67. package/src/backend/api-utils.ts +0 -178
  68. package/src/backend/auth.ts +0 -544
  69. package/src/backend/database.ts +0 -104
  70. package/src/backend/model.ts +0 -198
  71. package/src/backend/router.ts +0 -176
  72. package/src/backend/server.ts +0 -330
  73. package/src/backend/types.ts +0 -257
  74. package/src/batch.ts +0 -24
  75. package/src/cli/index.js +0 -554
  76. package/src/cli/index.ts +0 -257
  77. package/src/component.ts +0 -98
  78. package/src/components/Counter.tsx +0 -4
  79. package/src/context.ts +0 -29
  80. package/src/hooks.ts +0 -211
  81. package/src/index.ts +0 -144
  82. package/src/jsx-runtime/index.ts +0 -27
  83. package/src/jsx-runtime/jsx-dev-runtime.ts +0 -0
  84. package/src/jsx-runtime/jsx-runtime.ts +0 -104
  85. package/src/jsx-runtime.ts +0 -226
  86. package/src/renderer.ts +0 -55
  87. package/src/server-renderer.ts +0 -114
  88. package/src/shims.d.ts +0 -20
  89. package/src/types/bcrypt.d.ts +0 -30
  90. package/src/types/jsonwebtoken.d.ts +0 -55
  91. package/src/types.d.ts +0 -26
  92. package/src/types.ts +0 -21
  93. package/src/vdom.ts +0 -34
  94. package/templates/basic/.eslintignore +0 -5
  95. package/templates/basic/.eslintrc.json +0 -25
  96. package/templates/basic/docs/rapport_pfe.aux +0 -27
  97. package/templates/basic/docs/rapport_pfe.log +0 -399
  98. package/templates/basic/docs/rapport_pfe.out +0 -10
  99. package/templates/basic/docs/rapport_pfe.pdf +0 -0
  100. package/templates/basic/docs/rapport_pfe.tex +0 -68
  101. package/templates/basic/docs/rapport_pfe.toc +0 -14
  102. package/templates/basic/index.html +0 -12
  103. package/templates/basic/jsconfig.json +0 -14
  104. package/templates/basic/package.json +0 -18
  105. package/templates/basic/postcss.config.js +0 -7
  106. package/templates/basic/src/App.js +0 -105
  107. package/templates/basic/src/App.tsx +0 -65
  108. package/templates/basic/src/api.ts +0 -58
  109. package/templates/basic/src/components/Counter.tsx +0 -26
  110. package/templates/basic/src/components/Header.tsx +0 -9
  111. package/templates/basic/src/components/TodoList.tsx +0 -90
  112. package/templates/basic/src/main.css +0 -3
  113. package/templates/basic/src/main.js +0 -11
  114. package/templates/basic/src/main.ts +0 -20
  115. package/templates/basic/src/main.tsx +0 -144
  116. package/templates/basic/src/server.ts +0 -99
  117. package/templates/basic/tailwind.config.js +0 -32
  118. package/templates/basic/tsconfig.json +0 -20
  119. package/templates/basic/tsconfig.node.json +0 -10
  120. package/templates/basic/vite.config.js +0 -18
  121. package/templates/basic/vite.config.ts +0 -86
  122. package/templates/basic-app/src/App.js +0 -105
  123. package/templates/basic-app/src/App.tsx +0 -143
  124. package/templates/basic-app/src/api.ts +0 -58
  125. package/templates/basic-app/src/components/Counter.tsx +0 -26
  126. package/templates/basic-app/src/components/Header.tsx +0 -9
  127. package/templates/basic-app/src/components/TodoList.tsx +0 -90
  128. package/templates/basic-app/src/main.js +0 -10
  129. package/templates/basic-app/src/main.ts +0 -21
  130. package/templates/basic-app/src/react/index.ts +0 -35
  131. package/templates/basic-app/src/react/jsx-dev-runtime.ts +0 -13
  132. package/templates/basic-app/src/react/jsx-runtime.ts +0 -12
  133. package/templates/basic-app/src/server.ts +0 -99
  134. package/templates/basic-app/src/shims.ts +0 -9
  135. package/templates/basic-app/tsconfig.node.json +0 -10
  136. package/templates/basic-app/vite.config.js +0 -22
  137. package/templates/full-stack/.env.example +0 -11
  138. package/templates/full-stack/README.md +0 -51
  139. package/templates/full-stack/index.html +0 -12
  140. package/templates/full-stack/jsconfig.json +0 -14
  141. package/templates/full-stack/package.json +0 -21
  142. package/templates/full-stack/src/App.js +0 -105
  143. package/templates/full-stack/src/client/App.tsx +0 -50
  144. package/templates/full-stack/src/client/components/Header.tsx +0 -42
  145. package/templates/full-stack/src/client/components/UserList.tsx +0 -29
  146. package/templates/full-stack/src/client/main.tsx +0 -5
  147. package/templates/full-stack/src/main.css +0 -3
  148. package/templates/full-stack/src/main.js +0 -11
  149. package/templates/full-stack/src/main.ts +0 -20
  150. package/templates/full-stack/src/server/index.ts +0 -99
  151. package/templates/full-stack/src/server/routes/auth.ts +0 -39
  152. package/templates/full-stack/src/server/routes/users.ts +0 -48
  153. package/templates/full-stack/src/shims.ts +0 -9
  154. package/templates/full-stack/tsconfig.json +0 -20
  155. package/templates/full-stack/tsconfig.node.json +0 -10
  156. package/templates/full-stack/tsconfig.server.json +0 -15
  157. package/templates/full-stack/vite.config.js +0 -18
  158. package/templates/full-stack/vite.config.ts +0 -85
@@ -1,544 +0,0 @@
1
- import { Request, Response, NextFunction } from 'express';
2
- const jwt =require('jsonwebtoken');
3
- const bcrypt=require('bcrypt');
4
-
5
- const crypto=require('crypto');
6
-
7
- /**
8
- * Authentication configuration options
9
- */
10
- export interface AuthOptions {
11
- /**
12
- * Secret key for JWT signing
13
- */
14
- jwtSecret: string;
15
-
16
- /**
17
- * Secret key for refresh token signing (defaults to jwtSecret if not provided)
18
- */
19
- refreshSecret?: string;
20
-
21
- /**
22
- * JWT token expiration time (default: '15m')
23
- */
24
- tokenExpiration?: string;
25
-
26
- /**
27
- * Refresh token expiration time (default: '7d')
28
- */
29
- refreshExpiration?: string;
30
-
31
- /**
32
- * Number of bcrypt salt rounds (default: 10)
33
- */
34
- saltRounds?: number;
35
-
36
- /**
37
- * Custom user finder function
38
- */
39
- findUser?: (username: string) => Promise<any>;
40
-
41
- /**
42
- * Custom password verification (defaults to bcrypt compare)
43
- */
44
- verifyPassword?: (password: string, hashedPassword: string) => Promise<boolean>;
45
-
46
- /**
47
- * Custom function to save refresh token
48
- */
49
- saveRefreshToken?: (userId: string, token: string, expires: Date) => Promise<void>;
50
-
51
- /**
52
- * Custom function to verify refresh token
53
- */
54
- verifyRefreshToken?: (userId: string, token: string) => Promise<boolean>;
55
-
56
- /**
57
- * Use secure cookies for tokens (default: process.env.NODE_ENV === 'production')
58
- */
59
- secureCookies?: boolean;
60
-
61
- /**
62
- * Cookie domain
63
- */
64
- cookieDomain?: string;
65
-
66
- /**
67
- * Use HTTP-only cookies (default: true)
68
- */
69
- httpOnlyCookies?: boolean;
70
-
71
- /**
72
- * Implement rate limiting for login attempts (default: true)
73
- */
74
- rateLimit?: boolean;
75
- }
76
-
77
- /**
78
- * Token pair containing access and refresh tokens
79
- */
80
- export interface TokenPair {
81
- accessToken: string;
82
- refreshToken: string;
83
- expiresIn: number;
84
- }
85
-
86
- /**
87
- * Authentication service
88
- */
89
- export class Auth {
90
- private options: AuthOptions;
91
- private loginAttempts: Map<string, { count: number, resetTime: number }> = new Map();
92
-
93
- constructor(options: AuthOptions) {
94
- this.options = {
95
- tokenExpiration: '15m',
96
- refreshExpiration: '7d',
97
- saltRounds: 10,
98
- secureCookies: process.env.NODE_ENV === 'production',
99
- httpOnlyCookies: true,
100
- rateLimit: true,
101
- ...options,
102
- refreshSecret: options.refreshSecret || options.jwtSecret
103
- };
104
-
105
- if (!options.jwtSecret) {
106
- throw new Error('JWT secret is required for authentication');
107
- }
108
-
109
- // Set default password verification if not provided
110
- if (!this.options.verifyPassword) {
111
- this.options.verifyPassword = this.verifyPasswordWithBcrypt;
112
- }
113
- }
114
-
115
- /**
116
- * Hash a password using bcrypt
117
- */
118
- async hashPassword(password: string): Promise<string> {
119
- return await bcrypt.hash(password, this.options.saltRounds || 10);
120
- }
121
-
122
- /**
123
- * Verify a password against a hash using bcrypt
124
- */
125
- private async verifyPasswordWithBcrypt(password: string, hashedPassword: string): Promise<boolean> {
126
- return await bcrypt.compare(password, hashedPassword);
127
- }
128
-
129
- /**
130
- * Generate a cryptographically secure random token
131
- */
132
- generateSecureToken(length = 32): string {
133
- return crypto.randomBytes(length).toString('hex');
134
- }
135
-
136
- /**
137
- * Generate token pair (access token + refresh token)
138
- */
139
- generateTokenPair(payload: any): TokenPair {
140
- // Calculate expiration times
141
- const expiresIn = this.getExpirationSeconds(this.options.tokenExpiration || '15m');
142
-
143
- // Generate the access token
144
- const accessToken = jwt.sign(
145
- { ...payload, type: 'access' },
146
- this.options.jwtSecret,
147
- { expiresIn: this.options.tokenExpiration }
148
- );
149
-
150
- // Generate the refresh token
151
- const refreshToken = jwt.sign(
152
- { id: payload.id, type: 'refresh' },
153
- this.options.refreshSecret!,
154
- { expiresIn: this.options.refreshExpiration }
155
- );
156
-
157
- return {
158
- accessToken,
159
- refreshToken,
160
- expiresIn
161
- };
162
- }
163
-
164
- /**
165
- * Convert JWT expiration time to seconds
166
- */
167
- private getExpirationSeconds(expiration: string): number {
168
- const unit = expiration.charAt(expiration.length - 1);
169
- const value = parseInt(expiration.slice(0, -1));
170
-
171
- switch (unit) {
172
- case 's': return value;
173
- case 'm': return value * 60;
174
- case 'h': return value * 60 * 60;
175
- case 'd': return value * 60 * 60 * 24;
176
- default: return 3600; // Default 1 hour
177
- }
178
- }
179
-
180
- /**
181
- * Verify a JWT token
182
- */
183
- verifyToken(token: string, type: 'access' | 'refresh' = 'access'): any {
184
- try {
185
- const secret = type === 'access' ? this.options.jwtSecret : this.options.refreshSecret;
186
- const decoded = jwt.verify(token, secret!);
187
-
188
- // Verify token type matches expected type
189
- if (typeof decoded === 'object' && decoded.type !== type) {
190
- throw new Error('Invalid token type');
191
- }
192
-
193
- return decoded;
194
- } catch (error) {
195
- throw new Error('Invalid or expired token');
196
- }
197
- }
198
-
199
- /**
200
- * Set authentication cookies
201
- */
202
- setAuthCookies(res: Response, tokens: TokenPair): void {
203
- // Set access token cookie
204
- res.cookie('accessToken', tokens.accessToken, {
205
- httpOnly: this.options.httpOnlyCookies,
206
- secure: this.options.secureCookies,
207
- domain: this.options.cookieDomain,
208
- sameSite: 'strict',
209
- maxAge: tokens.expiresIn * 1000
210
- });
211
-
212
- // Set refresh token cookie with longer expiration
213
- const refreshExpiresIn = this.getExpirationSeconds(this.options.refreshExpiration || '7d');
214
- res.cookie('refreshToken', tokens.refreshToken, {
215
- httpOnly: true, // Always HTTP only for refresh tokens
216
- secure: this.options.secureCookies,
217
- domain: this.options.cookieDomain,
218
- sameSite: 'strict',
219
- maxAge: refreshExpiresIn * 1000,
220
- path: '/api/auth/refresh' // Restrict to refresh endpoint
221
- });
222
- }
223
-
224
- /**
225
- * Clear authentication cookies
226
- */
227
- clearAuthCookies(res: Response): void {
228
- res.clearCookie('accessToken');
229
- res.clearCookie('refreshToken', { path: '/api/auth/refresh' });
230
- }
231
-
232
- /**
233
- * Check and handle rate limiting
234
- */
235
- private checkRateLimit(ip: string): boolean {
236
- if (!this.options.rateLimit) {
237
- return true;
238
- }
239
-
240
- const now = Date.now();
241
- const attempt = this.loginAttempts.get(ip);
242
-
243
- if (!attempt) {
244
- this.loginAttempts.set(ip, { count: 1, resetTime: now + 3600000 });
245
- return true;
246
- }
247
-
248
- // Reset if time expired
249
- if (now > attempt.resetTime) {
250
- this.loginAttempts.set(ip, { count: 1, resetTime: now + 3600000 });
251
- return true;
252
- }
253
-
254
- // Check attempts
255
- if (attempt.count >= 5) {
256
- return false;
257
- }
258
-
259
- // Increment counter
260
- attempt.count++;
261
- this.loginAttempts.set(ip, attempt);
262
- return true;
263
- }
264
-
265
- /**
266
- * Login middleware to authenticate users
267
- */
268
- login = async (req: Request, res: Response): Promise<void> => {
269
- try {
270
- const { username, password } = req.body;
271
- const ip = req.ip || req.connection.remoteAddress || '';
272
-
273
- // Check rate limiting
274
- if (!this.checkRateLimit(ip)) {
275
- res.status(429).json({
276
- success: false,
277
- message: 'Too many login attempts. Please try again later.'
278
- });
279
- return;
280
- }
281
-
282
- if (!username || !password) {
283
- res.status(400).json({
284
- success: false,
285
- message: 'Username and password are required'
286
- });
287
- return;
288
- }
289
-
290
- // Use custom find user function if provided
291
- if (!this.options.findUser) {
292
- res.status(500).json({
293
- success: false,
294
- message: 'User finder function not configured'
295
- });
296
- return;
297
- }
298
-
299
- const user = await this.options.findUser(username);
300
-
301
- if (!user) {
302
- res.status(401).json({
303
- success: false,
304
- message: 'Invalid credentials'
305
- });
306
- return;
307
- }
308
-
309
- // Verify password
310
- const isPasswordValid = await this.options.verifyPassword!(
311
- password,
312
- user.password
313
- );
314
-
315
- if (!isPasswordValid) {
316
- res.status(401).json({
317
- success: false,
318
- message: 'Invalid credentials'
319
- });
320
- return;
321
- }
322
-
323
- // Create a sanitized user object (without password)
324
- const userWithoutPassword = { ...user };
325
- delete userWithoutPassword.password;
326
-
327
- // Generate tokens
328
- const tokenPair = this.generateTokenPair({
329
- id: user.id || user._id,
330
- username: user.username,
331
- role: user.role || 'user'
332
- });
333
-
334
- // Save refresh token if the function is provided
335
- if (this.options.saveRefreshToken) {
336
- const refreshExpiry = new Date();
337
- refreshExpiry.setSeconds(refreshExpiry.getSeconds() +
338
- this.getExpirationSeconds(this.options.refreshExpiration || '7d'));
339
-
340
- await this.options.saveRefreshToken(
341
- user.id || user._id,
342
- tokenPair.refreshToken,
343
- refreshExpiry
344
- );
345
- }
346
-
347
- // Set authentication cookies if using cookie-based auth
348
- if (req.body.useCookies) {
349
- this.setAuthCookies(res, tokenPair);
350
- }
351
-
352
- res.json({
353
- success: true,
354
- message: 'Authentication successful',
355
- tokens: tokenPair,
356
- user: userWithoutPassword
357
- });
358
- } catch (error) {
359
- console.error('Authentication error:', error);
360
- res.status(500).json({
361
- success: false,
362
- message: 'Authentication failed',
363
- error: process.env.NODE_ENV !== 'production' ? (error as Error).message : undefined
364
- });
365
- }
366
- };
367
-
368
- /**
369
- * Refresh token handler
370
- */
371
- refreshToken = async (req: Request, res: Response): Promise<void> => {
372
- try {
373
- // Get refresh token from cookies or request body
374
- const refreshToken = req.cookies?.refreshToken || req.body.refreshToken;
375
-
376
- if (!refreshToken) {
377
- res.status(401).json({
378
- success: false,
379
- message: 'Refresh token required'
380
- });
381
- return;
382
- }
383
-
384
- // Verify the refresh token
385
- const decoded = this.verifyToken(refreshToken, 'refresh');
386
-
387
- // Check if token is still valid in database if verification function provided
388
- if (this.options.verifyRefreshToken) {
389
- const isValid = await this.options.verifyRefreshToken(decoded.id, refreshToken);
390
- if (!isValid) {
391
- this.clearAuthCookies(res);
392
- res.status(401).json({
393
- success: false,
394
- message: 'Invalid refresh token'
395
- });
396
- return;
397
- }
398
- }
399
-
400
- // Generate new token pair
401
- const tokenPair = this.generateTokenPair({
402
- id: decoded.id,
403
- // We need to fetch the user data again for complete payload
404
- ...(this.options.findUser ? await this.options.findUser(decoded.id) : {})
405
- });
406
-
407
- // Update refresh token in database if save function provided
408
- if (this.options.saveRefreshToken) {
409
- const refreshExpiry = new Date();
410
- refreshExpiry.setSeconds(refreshExpiry.getSeconds() +
411
- this.getExpirationSeconds(this.options.refreshExpiration || '7d'));
412
-
413
- await this.options.saveRefreshToken(
414
- decoded.id,
415
- tokenPair.refreshToken,
416
- refreshExpiry
417
- );
418
- }
419
-
420
- // Set cookies if cookie-based auth is used
421
- const useCookies = req.cookies?.accessToken || req.body.useCookies;
422
- if (useCookies) {
423
- this.setAuthCookies(res, tokenPair);
424
- }
425
-
426
- res.json({
427
- success: true,
428
- message: 'Token refreshed successfully',
429
- tokens: tokenPair
430
- });
431
- } catch (error) {
432
- this.clearAuthCookies(res);
433
- res.status(401).json({
434
- success: false,
435
- message: 'Invalid or expired refresh token',
436
- error: process.env.NODE_ENV !== 'production' ? (error as Error).message : undefined
437
- });
438
- }
439
- };
440
-
441
- /**
442
- * Logout handler
443
- */
444
- logout = async (req: Request, res: Response): Promise<void> => {
445
- try {
446
- // Clear cookies
447
- this.clearAuthCookies(res);
448
-
449
- // Invalidate refresh token if verification function provided
450
- const refreshToken = req.cookies?.refreshToken || req.body.refreshToken;
451
- if (refreshToken && this.options.saveRefreshToken) {
452
- try {
453
- const decoded = this.verifyToken(refreshToken, 'refresh');
454
-
455
- // Check if invalidateToken function exists, otherwise we just remove it from storage
456
- if (typeof this.options.saveRefreshToken === 'function') {
457
- // We pass null as the token to indicate deletion/invalidation
458
- await this.options.saveRefreshToken(decoded.id, '', new Date());
459
- }
460
- } catch (e) {
461
- // Token already invalid, nothing to do
462
- }
463
- }
464
-
465
- res.json({ success: true, message: 'Logged out successfully' });
466
- } catch (error) {
467
- console.error('Logout error:', error);
468
- res.status(500).json({ success: false, message: 'Logout failed', error: (error as Error).message });
469
- }
470
- };
471
-
472
- /**
473
- * Middleware to verify user is authenticated
474
- */
475
- authenticate = (req: Request, res: Response, next: NextFunction): void => {
476
- try {
477
- // Get token from Authorization header or cookies
478
- let token = req.cookies?.accessToken;
479
-
480
- if (!token) {
481
- const authHeader = req.headers.authorization;
482
- if (authHeader && authHeader.startsWith('Bearer ')) {
483
- token = authHeader.split(' ')[1];
484
- }
485
- }
486
-
487
- if (!token) {
488
- res.status(401).json({
489
- success: false,
490
- message: 'Authentication required'
491
- });
492
- return;
493
- }
494
-
495
- const decoded = this.verifyToken(token, 'access');
496
-
497
- // Add user info to request
498
- (req as any).user = decoded;
499
-
500
- next();
501
- } catch (error) {
502
- res.status(401).json({
503
- success: false,
504
- message: 'Invalid or expired token',
505
- error: process.env.NODE_ENV !== 'production' ? (error as Error).message : undefined
506
- });
507
- }
508
- };
509
-
510
- /**
511
- * Middleware to check if user has required role
512
- */
513
- hasRole = (role: string | string[]) => {
514
- return (req: Request, res: Response, next: NextFunction): void => {
515
- const user = (req as any).user;
516
-
517
- if (!user) {
518
- res.status(401).json({
519
- success: false,
520
- message: 'Authentication required'
521
- });
522
- return;
523
- }
524
-
525
- const roles = Array.isArray(role) ? role : [role];
526
-
527
- if (roles.includes(user.role)) {
528
- next();
529
- } else {
530
- res.status(403).json({
531
- success: false,
532
- message: 'Insufficient permissions'
533
- });
534
- }
535
- };
536
- };
537
- }
538
-
539
- /**
540
- * Create an authentication service
541
- */
542
- export function createAuth(options: AuthOptions): Auth {
543
- return new Auth(options);
544
- }
@@ -1,104 +0,0 @@
1
- import mongoose from 'mongoose';
2
- import { DatabaseOptions } from './types';
3
-
4
- /**
5
- * Database connector for MongoDB using Mongoose
6
- */
7
- export class DatabaseConnector {
8
- private options: DatabaseOptions;
9
- private connection: mongoose.Connection | null = null;
10
- private _connected = false; // Renamed from isConnected to _connected
11
-
12
- constructor(options: DatabaseOptions) {
13
- this.options = {
14
- retryAttempts: 3,
15
- retryDelay: 1000,
16
- connectionTimeout: 10000,
17
- autoIndex: true,
18
- ...options
19
- };
20
- }
21
-
22
- /**
23
- * Connect to the database
24
- */
25
- async connect(): Promise<mongoose.Connection> {
26
- try {
27
- if (this._connected && this.connection) {
28
- return this.connection;
29
- }
30
-
31
- // Set Mongoose options
32
- mongoose.set('strictQuery', true);
33
-
34
- // Connect with retry logic
35
- let attempts = 0;
36
- while (attempts < (this.options.retryAttempts || 3)) {
37
- try {
38
- await mongoose.connect(this.options.uri, {
39
- dbName: this.options.name,
40
- connectTimeoutMS: this.options.connectionTimeout,
41
- autoIndex: this.options.autoIndex,
42
- ...this.options.options
43
- });
44
- break;
45
- } catch (error) {
46
- attempts++;
47
- if (attempts >= (this.options.retryAttempts || 3)) {
48
- throw error;
49
- }
50
- console.log(`Connection attempt ${attempts} failed. Retrying in ${this.options.retryDelay}ms...`);
51
- await new Promise(resolve => setTimeout(resolve, this.options.retryDelay));
52
- }
53
- }
54
-
55
- this.connection = mongoose.connection;
56
- this._connected = true;
57
-
58
- // Log successful connection
59
- console.log(`Connected to MongoDB at ${this.options.uri}/${this.options.name}`);
60
-
61
- // Handle connection events
62
- this.connection.on('error', (err) => {
63
- console.error('MongoDB connection error:', err);
64
- this._connected = false;
65
- });
66
-
67
- this.connection.on('disconnected', () => {
68
- console.log('MongoDB disconnected');
69
- this._connected = false;
70
- });
71
-
72
- return this.connection;
73
- } catch (error) {
74
- console.error('Failed to connect to MongoDB:', error);
75
- throw error;
76
- }
77
- }
78
-
79
- /**
80
- * Disconnect from the database
81
- */
82
- async disconnect(): Promise<void> {
83
- if (this.connection) {
84
- await mongoose.disconnect();
85
- this._connected = false;
86
- this.connection = null;
87
- console.log('Disconnected from MongoDB');
88
- }
89
- }
90
-
91
- /**
92
- * Check if connected to the database
93
- */
94
- isConnected(): boolean {
95
- return this._connected;
96
- }
97
-
98
- /**
99
- * Get the mongoose connection
100
- */
101
- getConnection(): mongoose.Connection | null {
102
- return this.connection;
103
- }
104
- }