create-fluxstack 1.7.5 → 1.8.3

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 (154) hide show
  1. package/.dockerignore +82 -0
  2. package/.env.example +19 -0
  3. package/Dockerfile +70 -0
  4. package/README.md +6 -3
  5. package/app/client/SIMPLIFICATION.md +140 -0
  6. package/app/client/frontend-only.ts +1 -1
  7. package/app/client/src/App.tsx +148 -283
  8. package/app/client/src/index.css +5 -20
  9. package/app/client/src/lib/eden-api.ts +53 -220
  10. package/app/client/src/main.tsx +2 -3
  11. package/app/server/app.ts +20 -5
  12. package/app/server/backend-only.ts +15 -12
  13. package/app/server/controllers/users.controller.ts +57 -31
  14. package/app/server/index.ts +86 -96
  15. package/app/server/live/register-components.ts +18 -7
  16. package/app/server/routes/env-test.ts +110 -0
  17. package/app/server/routes/index.ts +1 -8
  18. package/app/server/routes/users.routes.ts +192 -91
  19. package/config/app.config.ts +2 -54
  20. package/config/client.config.ts +95 -0
  21. package/config/fluxstack.config.ts +2 -2
  22. package/config/index.ts +57 -22
  23. package/config/monitoring.config.ts +114 -0
  24. package/config/plugins.config.ts +80 -0
  25. package/config/runtime.config.ts +0 -17
  26. package/config/server.config.ts +50 -30
  27. package/core/build/bundler.ts +17 -16
  28. package/core/build/flux-plugins-generator.ts +34 -23
  29. package/core/build/index.ts +32 -31
  30. package/core/build/live-components-generator.ts +44 -30
  31. package/core/build/optimizer.ts +37 -17
  32. package/core/cli/command-registry.ts +4 -14
  33. package/core/cli/commands/plugin-deps.ts +8 -8
  34. package/core/cli/generators/component.ts +3 -3
  35. package/core/cli/generators/controller.ts +4 -4
  36. package/core/cli/generators/index.ts +8 -8
  37. package/core/cli/generators/interactive.ts +4 -4
  38. package/core/cli/generators/plugin.ts +3 -3
  39. package/core/cli/generators/prompts.ts +1 -1
  40. package/core/cli/generators/route.ts +27 -11
  41. package/core/cli/generators/service.ts +5 -5
  42. package/core/cli/generators/template-engine.ts +1 -1
  43. package/core/cli/generators/types.ts +1 -1
  44. package/core/cli/index.ts +158 -189
  45. package/core/cli/plugin-discovery.ts +3 -3
  46. package/core/client/hooks/index.ts +2 -2
  47. package/core/client/hooks/state-validator.ts +1 -1
  48. package/core/client/hooks/useAuth.ts +1 -1
  49. package/core/client/hooks/useChunkedUpload.ts +1 -1
  50. package/core/client/hooks/useHybridLiveComponent.ts +1 -1
  51. package/core/client/hooks/useWebSocket.ts +1 -1
  52. package/core/config/env.ts +5 -1
  53. package/core/config/runtime-config.ts +12 -10
  54. package/core/config/schema.ts +33 -2
  55. package/core/framework/server.ts +30 -14
  56. package/core/framework/types.ts +2 -2
  57. package/core/index.ts +31 -23
  58. package/core/live/ComponentRegistry.ts +1 -1
  59. package/core/plugins/built-in/live-components/commands/create-live-component.ts +1 -1
  60. package/core/plugins/built-in/live-components/index.ts +1 -1
  61. package/core/plugins/built-in/monitoring/index.ts +65 -161
  62. package/core/plugins/built-in/static/index.ts +75 -277
  63. package/core/plugins/built-in/swagger/index.ts +301 -231
  64. package/core/plugins/built-in/vite/index.ts +342 -377
  65. package/core/plugins/config.ts +2 -2
  66. package/core/plugins/dependency-manager.ts +2 -2
  67. package/core/plugins/discovery.ts +1 -1
  68. package/core/plugins/executor.ts +2 -2
  69. package/core/plugins/manager.ts +19 -4
  70. package/core/plugins/module-resolver.ts +1 -1
  71. package/core/plugins/registry.ts +25 -21
  72. package/core/plugins/types.ts +147 -5
  73. package/core/server/backend-entry.ts +51 -0
  74. package/core/server/framework.ts +2 -2
  75. package/core/server/live/ComponentRegistry.ts +9 -26
  76. package/core/server/live/FileUploadManager.ts +1 -1
  77. package/core/server/live/auto-generated-components.ts +26 -0
  78. package/core/server/live/websocket-plugin.ts +211 -19
  79. package/core/server/middleware/errorHandling.ts +1 -1
  80. package/core/server/middleware/index.ts +4 -4
  81. package/core/server/plugins/database.ts +1 -2
  82. package/core/server/plugins/static-files-plugin.ts +259 -231
  83. package/core/server/plugins/swagger.ts +1 -1
  84. package/core/server/services/BaseService.ts +1 -1
  85. package/core/server/services/ServiceContainer.ts +1 -1
  86. package/core/server/services/index.ts +4 -4
  87. package/core/server/standalone.ts +16 -1
  88. package/core/testing/index.ts +1 -1
  89. package/core/testing/setup.ts +1 -1
  90. package/core/types/plugin.ts +6 -0
  91. package/core/utils/build-logger.ts +324 -0
  92. package/core/utils/config-schema.ts +2 -6
  93. package/core/utils/helpers.ts +14 -9
  94. package/core/utils/logger/startup-banner.ts +7 -33
  95. package/core/utils/regenerate-files.ts +69 -0
  96. package/core/utils/version.ts +6 -6
  97. package/create-fluxstack.ts +68 -25
  98. package/fluxstack.config.ts +138 -252
  99. package/package.json +3 -18
  100. package/plugins/crypto-auth/index.ts +52 -47
  101. package/plugins/crypto-auth/server/AuthMiddleware.ts +1 -1
  102. package/plugins/crypto-auth/server/middlewares/helpers.ts +16 -1
  103. package/vitest.config.ts +17 -26
  104. package/app/client/src/App.css +0 -883
  105. package/app/client/src/components/ErrorBoundary.tsx +0 -107
  106. package/app/client/src/components/ErrorDisplay.css +0 -365
  107. package/app/client/src/components/ErrorDisplay.tsx +0 -258
  108. package/app/client/src/components/FluxStackConfig.tsx +0 -1321
  109. package/app/client/src/components/HybridLiveCounter.tsx +0 -140
  110. package/app/client/src/components/LiveClock.tsx +0 -286
  111. package/app/client/src/components/MainLayout.tsx +0 -388
  112. package/app/client/src/components/SidebarNavigation.tsx +0 -391
  113. package/app/client/src/components/StateDemo.tsx +0 -178
  114. package/app/client/src/components/SystemMonitor.tsx +0 -1044
  115. package/app/client/src/components/UserProfile.tsx +0 -809
  116. package/app/client/src/hooks/useAuth.ts +0 -39
  117. package/app/client/src/hooks/useNotifications.ts +0 -56
  118. package/app/client/src/lib/errors.ts +0 -340
  119. package/app/client/src/lib/hooks/useErrorHandler.ts +0 -258
  120. package/app/client/src/lib/index.ts +0 -45
  121. package/app/client/src/pages/ApiDocs.tsx +0 -182
  122. package/app/client/src/pages/CryptoAuthPage.tsx +0 -394
  123. package/app/client/src/pages/Demo.tsx +0 -174
  124. package/app/client/src/pages/HybridLive.tsx +0 -263
  125. package/app/client/src/pages/Overview.tsx +0 -155
  126. package/app/client/src/store/README.md +0 -43
  127. package/app/client/src/store/index.ts +0 -16
  128. package/app/client/src/store/slices/uiSlice.ts +0 -151
  129. package/app/client/src/store/slices/userSlice.ts +0 -161
  130. package/app/client/src/test/README.md +0 -257
  131. package/app/client/src/test/setup.ts +0 -70
  132. package/app/client/src/test/types.ts +0 -12
  133. package/app/server/live/CounterComponent.ts +0 -191
  134. package/app/server/live/FluxStackConfig.ts +0 -534
  135. package/app/server/live/SidebarNavigation.ts +0 -157
  136. package/app/server/live/SystemMonitor.ts +0 -595
  137. package/app/server/live/SystemMonitorIntegration.ts +0 -151
  138. package/app/server/live/UserProfileComponent.ts +0 -141
  139. package/app/server/middleware/auth.ts +0 -136
  140. package/app/server/middleware/errorHandling.ts +0 -252
  141. package/app/server/middleware/index.ts +0 -10
  142. package/app/server/middleware/rateLimit.ts +0 -193
  143. package/app/server/middleware/requestLogging.ts +0 -215
  144. package/app/server/middleware/validation.ts +0 -270
  145. package/app/server/routes/config.ts +0 -145
  146. package/app/server/routes/crypto-auth-demo.routes.ts +0 -167
  147. package/app/server/routes/example-with-crypto-auth.routes.ts +0 -235
  148. package/app/server/routes/exemplo-posts.routes.ts +0 -161
  149. package/app/server/routes/upload.ts +0 -92
  150. package/app/server/services/NotificationService.ts +0 -302
  151. package/app/server/services/UserService.ts +0 -222
  152. package/app/server/services/index.ts +0 -46
  153. package/app/server/types/index.ts +0 -1
  154. package/config/build.config.ts +0 -24
@@ -1,151 +0,0 @@
1
- // 🔥 System Monitor Integration - Auto-capture metrics from Live Components
2
-
3
- import { componentRegistry } from '../../../core/server/live/ComponentRegistry'
4
-
5
- export class SystemMonitorIntegration {
6
- private static instance: SystemMonitorIntegration | null = null
7
- private systemMonitorId: string | null = null
8
-
9
- private constructor() {
10
- this.setupHooks()
11
- }
12
-
13
- public static getInstance(): SystemMonitorIntegration {
14
- if (!SystemMonitorIntegration.instance) {
15
- SystemMonitorIntegration.instance = new SystemMonitorIntegration()
16
- }
17
- return SystemMonitorIntegration.instance
18
- }
19
-
20
- // Set the system monitor component ID
21
- public setSystemMonitorId(componentId: string) {
22
- this.systemMonitorId = componentId
23
- console.log(`📊 SystemMonitor integration activated: ${componentId}`)
24
- }
25
-
26
- // Get system monitor component
27
- private getSystemMonitor() {
28
- if (!this.systemMonitorId) return null
29
- return componentRegistry.getComponent(this.systemMonitorId)
30
- }
31
-
32
- // Setup hooks to capture Live Component events
33
- private setupHooks() {
34
- // Override the original mountComponent method
35
- const originalMountComponent = componentRegistry.mountComponent.bind(componentRegistry)
36
- componentRegistry.mountComponent = async (...args) => {
37
- const result = await originalMountComponent(...args)
38
-
39
- // Record connection event
40
- this.recordConnection(args[1], 'connected')
41
-
42
- return result
43
- }
44
-
45
- // Override the original unmountComponent method
46
- const originalUnmountComponent = componentRegistry.unmountComponent.bind(componentRegistry)
47
- componentRegistry.unmountComponent = async (componentId) => {
48
- const component = componentRegistry.getComponent(componentId)
49
- const componentType = component?.constructor.name || 'Unknown'
50
-
51
- await originalUnmountComponent(componentId)
52
-
53
- // Record disconnection event
54
- this.recordConnection(componentType, 'disconnected')
55
- }
56
-
57
- // Override the original rehydrateComponent method
58
- const originalRehydrateComponent = componentRegistry.rehydrateComponent.bind(componentRegistry)
59
- componentRegistry.rehydrateComponent = async (...args) => {
60
- const result = await originalRehydrateComponent(...args)
61
-
62
- if (result.success) {
63
- // Record rehydration event
64
- this.recordConnection(args[1], 'rehydrated')
65
- }
66
-
67
- return result
68
- }
69
-
70
- // Override the original executeAction method
71
- const originalExecuteAction = componentRegistry.executeAction.bind(componentRegistry)
72
- componentRegistry.executeAction = async (componentId, action, payload) => {
73
- const startTime = Date.now()
74
- let success = false
75
-
76
- try {
77
- const result = await originalExecuteAction(componentId, action, payload)
78
- success = true
79
- return result
80
- } catch (error) {
81
- success = false
82
- throw error
83
- } finally {
84
- const responseTime = Date.now() - startTime
85
-
86
- // Record message event
87
- this.recordMessage(action, componentId, success, responseTime)
88
- }
89
- }
90
-
91
- // Setup completed - logged in auto-discovery group
92
- }
93
-
94
- // Record a connection event
95
- private recordConnection(componentType: string, status: 'connected' | 'disconnected' | 'rehydrated') {
96
- const monitor = this.getSystemMonitor()
97
- if (!monitor) return
98
-
99
- try {
100
- monitor.executeAction('recordConnection', {
101
- componentType,
102
- status
103
- }).catch(error => {
104
- console.warn('⚠️ Failed to record connection event:', error.message)
105
- })
106
- } catch (error) {
107
- console.warn('⚠️ Error recording connection event:', error)
108
- }
109
- }
110
-
111
- // Record a message event
112
- private recordMessage(type: string, componentId: string, success: boolean, responseTime?: number) {
113
- const monitor = this.getSystemMonitor()
114
- if (!monitor) return
115
-
116
- try {
117
- monitor.executeAction('recordMessage', {
118
- type,
119
- componentId,
120
- success,
121
- responseTime
122
- }).catch(error => {
123
- console.warn('⚠️ Failed to record message event:', error.message)
124
- })
125
- } catch (error) {
126
- console.warn('⚠️ Error recording message event:', error)
127
- }
128
- }
129
-
130
- // Manually trigger metrics collection for all monitors
131
- public triggerMetricsCollection() {
132
- const monitor = this.getSystemMonitor()
133
- if (!monitor) return
134
-
135
- try {
136
- monitor.executeAction('collectMetrics', {}).catch(error => {
137
- console.warn('⚠️ Failed to trigger metrics collection:', error.message)
138
- })
139
- } catch (error) {
140
- console.warn('⚠️ Error triggering metrics collection:', error)
141
- }
142
- }
143
-
144
- // Get current system stats
145
- public getSystemStats() {
146
- return componentRegistry.getStats()
147
- }
148
- }
149
-
150
- // Export singleton instance
151
- export const systemMonitorIntegration = SystemMonitorIntegration.getInstance()
@@ -1,141 +0,0 @@
1
- // 🔥 User Profile - Live Component
2
- import { LiveComponent } from "@/core/types/types";
3
-
4
- interface UserProfileState {
5
- name: string;
6
- email: string;
7
- avatar: string;
8
- status: 'online' | 'away' | 'busy' | 'offline';
9
- bio: string;
10
- location: string;
11
- joinedDate: string;
12
- followers: number;
13
- following: number;
14
- posts: number;
15
- isEditing: boolean;
16
- lastUpdated: Date; // ✅ Padronizado para Date
17
- theme: 'light' | 'dark';
18
- notifications: number;
19
- }
20
-
21
- export class UserProfileComponent extends LiveComponent<UserProfileState> {
22
- constructor(initialState: UserProfileState, ws: any, options?: { room?: string; userId?: string }) {
23
- const defaultState: UserProfileState = {
24
- name: "João Silva",
25
- email: "joao.silva@example.com",
26
- avatar: "https://images.unsplash.com/photo-1472099645785-5658abf4ff4e?w=150&h=150&fit=crop&crop=face",
27
- status: "online",
28
- bio: "Desenvolvedor Full-Stack apaixonado por tecnologia e inovação. Sempre em busca de novos desafios!",
29
- location: "São Paulo, Brasil",
30
- joinedDate: "Janeiro 2023",
31
- followers: 1234,
32
- following: 567,
33
- posts: 89,
34
- isEditing: false,
35
- lastUpdated: new Date(),
36
- theme: "light",
37
- notifications: 5,
38
- ...initialState
39
- };
40
-
41
- super(defaultState, ws, options);
42
- console.log('👤 UserProfile component created:', this.id, { initialState: defaultState });
43
- }
44
-
45
- async updateProfile(payload: { name?: string; bio?: string; location?: string }) {
46
- const updates: Partial<UserProfileState> = {
47
- lastUpdated: new Date()
48
- };
49
-
50
- if (payload.name) updates.name = payload.name;
51
- if (payload.bio) updates.bio = payload.bio;
52
- if (payload.location) updates.location = payload.location;
53
-
54
- this.setState(updates);
55
- console.log('👤 Profile updated:', this.id, updates);
56
- return { success: true, updated: Object.keys(updates) };
57
- }
58
-
59
- async toggleStatus() {
60
- const statuses: UserProfileState['status'][] = ['online', 'away', 'busy', 'offline'];
61
- const currentIndex = statuses.indexOf(this.state.status);
62
- const nextStatus = statuses[(currentIndex + 1) % statuses.length];
63
-
64
- this.setState({
65
- status: nextStatus,
66
- lastUpdated: new Date()
67
- });
68
-
69
- console.log('👤 Status changed:', this.id, { from: this.state.status, to: nextStatus });
70
- return { success: true, newStatus: nextStatus };
71
- }
72
-
73
- async toggleTheme() {
74
- const newTheme = this.state.theme === 'light' ? 'dark' : 'light';
75
- this.setState({
76
- theme: newTheme,
77
- lastUpdated: new Date()
78
- });
79
-
80
- console.log('👤 Theme changed:', this.id, { to: newTheme });
81
- return { success: true, theme: newTheme };
82
- }
83
-
84
- async followUser() {
85
- this.setState({
86
- followers: this.state.followers + 1,
87
- lastUpdated: new Date()
88
- });
89
-
90
- console.log('👤 New follower:', this.id, { followers: this.state.followers + 1 });
91
- return { success: true, followers: this.state.followers };
92
- }
93
-
94
- async toggleEdit() {
95
- this.setState({
96
- isEditing: !this.state.isEditing,
97
- lastUpdated: new Date()
98
- });
99
-
100
- console.log('👤 Edit mode toggled:', this.id, { isEditing: !this.state.isEditing });
101
- return { success: true, isEditing: this.state.isEditing };
102
- }
103
-
104
- async clearNotifications() {
105
- this.setState({
106
- notifications: 0,
107
- lastUpdated: new Date()
108
- });
109
-
110
- console.log('👤 Notifications cleared:', this.id);
111
- return { success: true };
112
- }
113
-
114
- async updateAvatar(payload: { imageUrl: string }) {
115
- if (!payload.imageUrl) {
116
- throw new Error('Invalid image URL');
117
- }
118
-
119
- this.setState({
120
- avatar: payload.imageUrl,
121
- lastUpdated: new Date()
122
- });
123
-
124
- console.log('👤 Avatar updated:', this.id, {
125
- newAvatar: payload.imageUrl,
126
- previousAvatar: this.state.avatar
127
- });
128
-
129
- return {
130
- success: true,
131
- avatar: payload.imageUrl,
132
- message: 'Avatar updated successfully!'
133
- };
134
- }
135
-
136
- // Override destroy for cleanup
137
- public destroy() {
138
- console.log(`🗑️ UserProfile component ${this.id} destroyed`)
139
- super.destroy()
140
- }
141
- }
@@ -1,136 +0,0 @@
1
- /**
2
- * Authentication Middleware
3
- * Handles user authentication and authorization
4
- */
5
-
6
- import type { Context } from 'elysia'
7
-
8
- export interface AuthUser {
9
- id: number
10
- email: string
11
- name: string
12
- role: 'admin' | 'user'
13
- }
14
-
15
- export interface AuthContext extends Context {
16
- user?: AuthUser
17
- }
18
-
19
- /**
20
- * Authentication middleware
21
- * Validates JWT tokens and sets user context
22
- */
23
- export const authMiddleware = {
24
- name: 'auth',
25
-
26
- beforeHandle: async (context: AuthContext) => {
27
- const authHeader = context.headers.authorization
28
-
29
- if (!authHeader || !authHeader.startsWith('Bearer ')) {
30
- return new Response(
31
- JSON.stringify({ error: 'Missing or invalid authorization header' }),
32
- { status: 401, headers: { 'Content-Type': 'application/json' } }
33
- )
34
- }
35
-
36
- const token = authHeader.substring(7) // Remove 'Bearer ' prefix
37
-
38
- try {
39
- // In a real application, you would validate the JWT token here
40
- // For demo purposes, we'll simulate token validation
41
- const user = await validateToken(token)
42
-
43
- if (!user) {
44
- return new Response(
45
- JSON.stringify({ error: 'Invalid or expired token' }),
46
- { status: 401, headers: { 'Content-Type': 'application/json' } }
47
- )
48
- }
49
-
50
- // Set user in context
51
- context.user = user
52
- } catch (error) {
53
- return new Response(
54
- JSON.stringify({ error: 'Token validation failed' }),
55
- { status: 401, headers: { 'Content-Type': 'application/json' } }
56
- )
57
- }
58
- }
59
- }
60
-
61
- /**
62
- * Optional authentication middleware
63
- * Sets user context if token is present, but doesn't require it
64
- */
65
- export const optionalAuthMiddleware = {
66
- name: 'optional-auth',
67
-
68
- beforeHandle: async (context: AuthContext) => {
69
- const authHeader = context.headers.authorization
70
-
71
- if (authHeader && authHeader.startsWith('Bearer ')) {
72
- const token = authHeader.substring(7)
73
-
74
- try {
75
- const user = await validateToken(token)
76
- if (user) {
77
- context.user = user
78
- }
79
- } catch (error) {
80
- // Ignore errors for optional auth
81
- }
82
- }
83
- }
84
- }
85
-
86
- /**
87
- * Role-based authorization middleware
88
- */
89
- export const requireRole = (requiredRole: 'admin' | 'user') => ({
90
- name: `require-${requiredRole}`,
91
-
92
- beforeHandle: async (context: AuthContext) => {
93
- if (!context.user) {
94
- return new Response(
95
- JSON.stringify({ error: 'Authentication required' }),
96
- { status: 401, headers: { 'Content-Type': 'application/json' } }
97
- )
98
- }
99
-
100
- if (requiredRole === 'admin' && context.user.role !== 'admin') {
101
- return new Response(
102
- JSON.stringify({ error: 'Admin access required' }),
103
- { status: 403, headers: { 'Content-Type': 'application/json' } }
104
- )
105
- }
106
- }
107
- })
108
-
109
- /**
110
- * Validate JWT token (mock implementation)
111
- * In a real application, this would use a proper JWT library
112
- */
113
- async function validateToken(token: string): Promise<AuthUser | null> {
114
- // Mock token validation
115
- // In reality, you would decode and verify the JWT
116
-
117
- if (token === 'valid-admin-token') {
118
- return {
119
- id: 1,
120
- email: 'admin@example.com',
121
- name: 'Admin User',
122
- role: 'admin'
123
- }
124
- }
125
-
126
- if (token === 'valid-user-token') {
127
- return {
128
- id: 2,
129
- email: 'user@example.com',
130
- name: 'Regular User',
131
- role: 'user'
132
- }
133
- }
134
-
135
- return null
136
- }
@@ -1,252 +0,0 @@
1
- /**
2
- * Error Handling Middleware
3
- * Provides centralized error handling for the application
4
- */
5
-
6
- import type { Context } from 'elysia'
7
- import { appConfig } from '@/config/app.config'
8
-
9
- export interface ErrorResponse {
10
- error: string
11
- message: string
12
- code?: string
13
- details?: any
14
- timestamp: string
15
- requestId?: string
16
- }
17
-
18
- /**
19
- * Custom application errors
20
- */
21
- export class AppError extends Error {
22
- constructor(
23
- message: string,
24
- public statusCode: number = 500,
25
- public code?: string,
26
- public details?: any
27
- ) {
28
- super(message)
29
- this.name = 'AppError'
30
- }
31
- }
32
-
33
- export class ValidationError extends AppError {
34
- constructor(message: string, details?: any) {
35
- super(message, 400, 'VALIDATION_ERROR', details)
36
- this.name = 'ValidationError'
37
- }
38
- }
39
-
40
- export class NotFoundError extends AppError {
41
- constructor(resource: string = 'Resource') {
42
- super(`${resource} not found`, 404, 'NOT_FOUND')
43
- this.name = 'NotFoundError'
44
- }
45
- }
46
-
47
- export class UnauthorizedError extends AppError {
48
- constructor(message: string = 'Unauthorized') {
49
- super(message, 401, 'UNAUTHORIZED')
50
- this.name = 'UnauthorizedError'
51
- }
52
- }
53
-
54
- export class ForbiddenError extends AppError {
55
- constructor(message: string = 'Forbidden') {
56
- super(message, 403, 'FORBIDDEN')
57
- this.name = 'ForbiddenError'
58
- }
59
- }
60
-
61
- export class ConflictError extends AppError {
62
- constructor(message: string, details?: any) {
63
- super(message, 409, 'CONFLICT', details)
64
- this.name = 'ConflictError'
65
- }
66
- }
67
-
68
- /**
69
- * Error handling middleware
70
- */
71
- export const errorHandlingMiddleware = {
72
- name: 'error-handling',
73
-
74
- onError: async (context: Context, error: Error): Promise<Response> => {
75
- const requestId = context.store?.requestId || 'unknown'
76
-
77
- // Log the error
78
- console.error('🚨 Error occurred', {
79
- requestId,
80
- method: context.request.method,
81
- path: context.path,
82
- error: error.message,
83
- stack: error.stack,
84
- timestamp: new Date().toISOString()
85
- })
86
-
87
- // Handle different error types
88
- if (error instanceof AppError) {
89
- return createErrorResponse(
90
- error.statusCode,
91
- error.message,
92
- error.code,
93
- error.details,
94
- requestId
95
- )
96
- }
97
-
98
- // Handle validation errors from Elysia
99
- if (error.name === 'ValidationError' || error.message.includes('validation')) {
100
- return createErrorResponse(
101
- 400,
102
- 'Validation failed',
103
- 'VALIDATION_ERROR',
104
- { originalError: error.message },
105
- requestId
106
- )
107
- }
108
-
109
- // Handle syntax errors (malformed JSON, etc.)
110
- if (error instanceof SyntaxError) {
111
- return createErrorResponse(
112
- 400,
113
- 'Invalid request format',
114
- 'SYNTAX_ERROR',
115
- undefined,
116
- requestId
117
- )
118
- }
119
-
120
- // Handle network/timeout errors
121
- if (error.name === 'TimeoutError' || error.message.includes('timeout')) {
122
- return createErrorResponse(
123
- 408,
124
- 'Request timeout',
125
- 'TIMEOUT_ERROR',
126
- undefined,
127
- requestId
128
- )
129
- }
130
-
131
- // Handle database/external service errors
132
- if (error.message.includes('ECONNREFUSED') || error.message.includes('connection')) {
133
- return createErrorResponse(
134
- 503,
135
- 'Service temporarily unavailable',
136
- 'SERVICE_UNAVAILABLE',
137
- undefined,
138
- requestId
139
- )
140
- }
141
-
142
- // Default to internal server error
143
- const isProduction = appConfig.env === 'production'
144
- return createErrorResponse(
145
- 500,
146
- isProduction
147
- ? 'Internal server error'
148
- : error.message,
149
- 'INTERNAL_ERROR',
150
- isProduction
151
- ? undefined
152
- : { stack: error.stack },
153
- requestId
154
- )
155
- }
156
- }
157
-
158
- /**
159
- * Create standardized error response
160
- */
161
- function createErrorResponse(
162
- statusCode: number,
163
- message: string,
164
- code?: string,
165
- details?: any,
166
- requestId?: string
167
- ): Response {
168
- const errorResponse: ErrorResponse = {
169
- error: getErrorName(statusCode),
170
- message,
171
- code,
172
- details,
173
- timestamp: new Date().toISOString(),
174
- requestId
175
- }
176
-
177
- // Remove undefined fields
178
- Object.keys(errorResponse).forEach(key => {
179
- if (errorResponse[key as keyof ErrorResponse] === undefined) {
180
- delete errorResponse[key as keyof ErrorResponse]
181
- }
182
- })
183
-
184
- return new Response(
185
- JSON.stringify(errorResponse),
186
- {
187
- status: statusCode,
188
- headers: {
189
- 'Content-Type': 'application/json'
190
- }
191
- }
192
- )
193
- }
194
-
195
- /**
196
- * Get error name from status code
197
- */
198
- function getErrorName(statusCode: number): string {
199
- const errorNames: Record<number, string> = {
200
- 400: 'Bad Request',
201
- 401: 'Unauthorized',
202
- 403: 'Forbidden',
203
- 404: 'Not Found',
204
- 405: 'Method Not Allowed',
205
- 408: 'Request Timeout',
206
- 409: 'Conflict',
207
- 422: 'Unprocessable Entity',
208
- 429: 'Too Many Requests',
209
- 500: 'Internal Server Error',
210
- 502: 'Bad Gateway',
211
- 503: 'Service Unavailable',
212
- 504: 'Gateway Timeout'
213
- }
214
-
215
- return errorNames[statusCode] || 'Unknown Error'
216
- }
217
-
218
- /**
219
- * Async error wrapper for route handlers
220
- */
221
- export const asyncHandler = (fn: Function) => {
222
- return async (context: Context) => {
223
- try {
224
- return await fn(context)
225
- } catch (error) {
226
- throw error // Let the error middleware handle it
227
- }
228
- }
229
- }
230
-
231
- /**
232
- * Create error response helper
233
- */
234
- export const createError = {
235
- badRequest: (message: string, details?: any) =>
236
- new ValidationError(message, details),
237
-
238
- unauthorized: (message?: string) =>
239
- new UnauthorizedError(message),
240
-
241
- forbidden: (message?: string) =>
242
- new ForbiddenError(message),
243
-
244
- notFound: (resource?: string) =>
245
- new NotFoundError(resource),
246
-
247
- conflict: (message: string, details?: any) =>
248
- new ConflictError(message, details),
249
-
250
- internal: (message: string, details?: any) =>
251
- new AppError(message, 500, 'INTERNAL_ERROR', details)
252
- }
@@ -1,10 +0,0 @@
1
- /**
2
- * Middleware Index
3
- * Exports all custom middleware for the application
4
- */
5
-
6
- export { authMiddleware } from './auth'
7
- export { validationMiddleware } from './validation'
8
- export { rateLimitMiddleware } from './rateLimit'
9
- export { requestLoggingMiddleware } from './requestLogging'
10
- export { errorHandlingMiddleware } from './errorHandling'