create-fluxstack 1.9.1 → 1.12.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.
- package/.dockerignore +1 -2
- package/Dockerfile +8 -8
- package/LIVE_COMPONENTS_REVIEW.md +781 -0
- package/LLMD/INDEX.md +64 -0
- package/LLMD/MAINTENANCE.md +197 -0
- package/LLMD/MIGRATION.md +156 -0
- package/LLMD/config/.gitkeep +1 -0
- package/LLMD/config/declarative-system.md +268 -0
- package/LLMD/config/environment-vars.md +327 -0
- package/LLMD/config/runtime-reload.md +401 -0
- package/LLMD/core/.gitkeep +1 -0
- package/LLMD/core/build-system.md +599 -0
- package/LLMD/core/framework-lifecycle.md +229 -0
- package/LLMD/core/plugin-system.md +451 -0
- package/LLMD/patterns/.gitkeep +1 -0
- package/LLMD/patterns/anti-patterns.md +297 -0
- package/LLMD/patterns/project-structure.md +264 -0
- package/LLMD/patterns/type-safety.md +440 -0
- package/LLMD/reference/.gitkeep +1 -0
- package/LLMD/reference/cli-commands.md +250 -0
- package/LLMD/reference/plugin-hooks.md +357 -0
- package/LLMD/reference/routing.md +39 -0
- package/LLMD/reference/troubleshooting.md +364 -0
- package/LLMD/resources/.gitkeep +1 -0
- package/LLMD/resources/controllers.md +465 -0
- package/LLMD/resources/live-components.md +703 -0
- package/LLMD/resources/live-rooms.md +482 -0
- package/LLMD/resources/live-upload.md +130 -0
- package/LLMD/resources/plugins-external.md +617 -0
- package/LLMD/resources/routes-eden.md +254 -0
- package/README.md +37 -17
- package/app/client/index.html +0 -1
- package/app/client/src/App.tsx +109 -156
- package/app/client/src/components/AppLayout.tsx +68 -0
- package/app/client/src/components/BackButton.tsx +13 -0
- package/app/client/src/components/DemoPage.tsx +20 -0
- package/app/client/src/components/LiveUploadWidget.tsx +204 -0
- package/app/client/src/lib/eden-api.ts +85 -65
- package/app/client/src/live/ChatDemo.tsx +107 -0
- package/app/client/src/live/CounterDemo.tsx +206 -0
- package/app/client/src/live/FormDemo.tsx +119 -0
- package/app/client/src/live/RoomChatDemo.tsx +242 -0
- package/app/client/src/live/UploadDemo.tsx +21 -0
- package/app/client/src/main.tsx +13 -10
- package/app/client/src/pages/ApiTestPage.tsx +108 -0
- package/app/client/src/pages/HomePage.tsx +76 -0
- package/app/client/src/vite-env.d.ts +1 -1
- package/app/server/app.ts +1 -4
- package/app/server/controllers/users.controller.ts +36 -44
- package/app/server/index.ts +24 -107
- package/app/server/live/LiveChat.ts +77 -0
- package/app/server/live/LiveCounter.ts +67 -0
- package/app/server/live/LiveForm.ts +63 -0
- package/app/server/live/LiveLocalCounter.ts +32 -0
- package/app/server/live/LiveRoomChat.ts +285 -0
- package/app/server/live/LiveUpload.ts +81 -0
- package/app/server/live/register-components.ts +19 -19
- package/app/server/routes/index.ts +3 -1
- package/app/server/routes/room.routes.ts +117 -0
- package/app/server/routes/users.routes.ts +35 -27
- package/app/shared/types/index.ts +14 -2
- package/config/app.config.ts +2 -62
- package/config/client.config.ts +2 -95
- package/config/database.config.ts +2 -99
- package/config/fluxstack.config.ts +25 -45
- package/config/index.ts +57 -38
- package/config/monitoring.config.ts +2 -114
- package/config/plugins.config.ts +2 -80
- package/config/server.config.ts +2 -68
- package/config/services.config.ts +2 -130
- package/config/system/app.config.ts +29 -0
- package/config/system/build.config.ts +49 -0
- package/config/system/client.config.ts +68 -0
- package/config/system/database.config.ts +17 -0
- package/config/system/fluxstack.config.ts +114 -0
- package/config/{logger.config.ts → system/logger.config.ts} +3 -1
- package/config/system/monitoring.config.ts +114 -0
- package/config/system/plugins.config.ts +84 -0
- package/config/{runtime.config.ts → system/runtime.config.ts} +1 -1
- package/config/system/server.config.ts +68 -0
- package/config/system/services.config.ts +46 -0
- package/config/{system.config.ts → system/system.config.ts} +1 -1
- package/core/build/bundler.ts +4 -1
- package/core/build/flux-plugins-generator.ts +325 -325
- package/core/build/index.ts +159 -27
- package/core/build/live-components-generator.ts +70 -3
- package/core/build/optimizer.ts +235 -235
- package/core/cli/command-registry.ts +6 -4
- package/core/cli/commands/build.ts +79 -0
- package/core/cli/commands/create.ts +54 -0
- package/core/cli/commands/dev.ts +101 -0
- package/core/cli/commands/help.ts +34 -0
- package/core/cli/commands/index.ts +34 -0
- package/core/cli/commands/make-plugin.ts +90 -0
- package/core/cli/commands/plugin-add.ts +197 -0
- package/core/cli/commands/plugin-deps.ts +2 -2
- package/core/cli/commands/plugin-list.ts +208 -0
- package/core/cli/commands/plugin-remove.ts +170 -0
- package/core/cli/generators/component.ts +769 -769
- package/core/cli/generators/controller.ts +1 -1
- package/core/cli/generators/index.ts +146 -146
- package/core/cli/generators/interactive.ts +227 -227
- package/core/cli/generators/plugin.ts +2 -2
- package/core/cli/generators/prompts.ts +82 -82
- package/core/cli/generators/route.ts +6 -6
- package/core/cli/generators/service.ts +2 -2
- package/core/cli/generators/template-engine.ts +4 -3
- package/core/cli/generators/types.ts +2 -2
- package/core/cli/generators/utils.ts +191 -191
- package/core/cli/index.ts +115 -558
- package/core/cli/plugin-discovery.ts +2 -2
- package/core/client/LiveComponentsProvider.tsx +63 -17
- package/core/client/api/eden.ts +183 -0
- package/core/client/api/index.ts +11 -0
- package/core/client/components/Live.tsx +104 -0
- package/core/client/fluxstack.ts +1 -9
- package/core/client/hooks/AdaptiveChunkSizer.ts +215 -0
- package/core/client/hooks/state-validator.ts +1 -1
- package/core/client/hooks/useAuth.ts +48 -48
- package/core/client/hooks/useChunkedUpload.ts +170 -69
- package/core/client/hooks/useLiveChunkedUpload.ts +87 -0
- package/core/client/hooks/useLiveComponent.ts +800 -0
- package/core/client/hooks/useLiveUpload.ts +71 -0
- package/core/client/hooks/useRoom.ts +409 -0
- package/core/client/hooks/useRoomProxy.ts +382 -0
- package/core/client/index.ts +18 -51
- package/core/client/standalone-entry.ts +8 -0
- package/core/client/standalone.ts +74 -53
- package/core/client/state/createStore.ts +192 -192
- package/core/client/state/index.ts +14 -14
- package/core/config/index.ts +70 -291
- package/core/config/schema.ts +42 -723
- package/core/framework/client.ts +131 -131
- package/core/framework/index.ts +7 -7
- package/core/framework/server.ts +227 -47
- package/core/framework/types.ts +2 -2
- package/core/index.ts +23 -4
- package/core/live/ComponentRegistry.ts +7 -3
- package/core/live/types.ts +77 -0
- package/core/plugins/built-in/index.ts +134 -131
- package/core/plugins/built-in/live-components/commands/create-live-component.ts +242 -1074
- package/core/plugins/built-in/live-components/index.ts +1 -1
- package/core/plugins/built-in/monitoring/index.ts +111 -47
- package/core/plugins/built-in/static/index.ts +1 -1
- package/core/plugins/built-in/swagger/index.ts +68 -265
- package/core/plugins/built-in/vite/index.ts +94 -306
- package/core/plugins/built-in/vite/vite-dev.ts +82 -0
- package/core/plugins/config.ts +9 -7
- package/core/plugins/dependency-manager.ts +31 -1
- package/core/plugins/discovery.ts +19 -7
- package/core/plugins/executor.ts +2 -2
- package/core/plugins/index.ts +203 -203
- package/core/plugins/manager.ts +27 -39
- package/core/plugins/module-resolver.ts +19 -8
- package/core/plugins/registry.ts +309 -21
- package/core/plugins/types.ts +106 -55
- package/core/server/framework.ts +66 -43
- package/core/server/index.ts +15 -16
- package/core/server/live/ComponentRegistry.ts +91 -75
- package/core/server/live/FileUploadManager.ts +41 -31
- package/core/server/live/LiveComponentPerformanceMonitor.ts +1 -1
- package/core/server/live/LiveRoomManager.ts +261 -0
- package/core/server/live/RoomEventBus.ts +234 -0
- package/core/server/live/RoomStateManager.ts +172 -0
- package/core/server/live/StateSignature.ts +643 -643
- package/core/server/live/WebSocketConnectionManager.ts +30 -19
- package/core/server/live/auto-generated-components.ts +41 -26
- package/core/server/live/index.ts +14 -0
- package/core/server/live/websocket-plugin.ts +233 -72
- package/core/server/middleware/elysia-helpers.ts +7 -2
- package/core/server/middleware/errorHandling.ts +1 -1
- package/core/server/middleware/index.ts +31 -31
- package/core/server/plugins/database.ts +180 -180
- package/core/server/plugins/static-files-plugin.ts +69 -260
- package/core/server/plugins/swagger.ts +33 -33
- package/core/server/rooms/RoomBroadcaster.ts +357 -0
- package/core/server/rooms/RoomSystem.ts +463 -0
- package/core/server/rooms/index.ts +13 -0
- package/core/server/services/BaseService.ts +1 -1
- package/core/server/services/ServiceContainer.ts +1 -1
- package/core/server/services/index.ts +8 -8
- package/core/templates/create-project.ts +12 -12
- package/core/testing/index.ts +9 -9
- package/core/testing/setup.ts +73 -73
- package/core/types/api.ts +168 -168
- package/core/types/build.ts +219 -218
- package/core/types/config.ts +56 -26
- package/core/types/index.ts +4 -4
- package/core/types/plugin.ts +107 -99
- package/core/types/types.ts +490 -14
- package/core/utils/build-logger.ts +324 -324
- package/core/utils/config-schema.ts +480 -480
- package/core/utils/env.ts +2 -8
- package/core/utils/errors/codes.ts +114 -114
- package/core/utils/errors/handlers.ts +36 -1
- package/core/utils/errors/index.ts +49 -5
- package/core/utils/errors/middleware.ts +113 -113
- package/core/utils/helpers.ts +6 -16
- package/core/utils/index.ts +17 -17
- package/core/utils/logger/colors.ts +114 -114
- package/core/utils/logger/config.ts +13 -9
- package/core/utils/logger/formatter.ts +82 -82
- package/core/utils/logger/group-logger.ts +101 -101
- package/core/utils/logger/index.ts +6 -1
- package/core/utils/logger/stack-trace.ts +3 -1
- package/core/utils/logger/startup-banner.ts +82 -66
- package/core/utils/logger/winston-logger.ts +152 -152
- package/core/utils/monitoring/index.ts +211 -211
- package/core/utils/sync-version.ts +66 -66
- package/core/utils/version.ts +1 -1
- package/create-fluxstack.ts +8 -7
- package/eslint.config.js +23 -23
- package/package.json +14 -15
- package/plugins/crypto-auth/cli/make-protected-route.command.ts +1 -1
- package/plugins/crypto-auth/client/CryptoAuthClient.ts +302 -302
- package/plugins/crypto-auth/client/components/index.ts +11 -11
- package/plugins/crypto-auth/client/index.ts +11 -11
- package/plugins/crypto-auth/config/index.ts +1 -1
- package/plugins/crypto-auth/index.ts +4 -4
- package/plugins/crypto-auth/package.json +65 -65
- package/plugins/crypto-auth/server/AuthMiddleware.ts +1 -1
- package/plugins/crypto-auth/server/CryptoAuthService.ts +185 -185
- package/plugins/crypto-auth/server/index.ts +21 -21
- package/plugins/crypto-auth/server/middlewares/cryptoAuthAdmin.ts +3 -3
- package/plugins/crypto-auth/server/middlewares/cryptoAuthOptional.ts +1 -1
- package/plugins/crypto-auth/server/middlewares/cryptoAuthPermissions.ts +2 -2
- package/plugins/crypto-auth/server/middlewares/cryptoAuthRequired.ts +2 -2
- package/plugins/crypto-auth/server/middlewares/helpers.ts +1 -1
- package/plugins/crypto-auth/server/middlewares/index.ts +22 -22
- package/plugins/crypto-auth/server/middlewares.ts +19 -19
- package/tsconfig.api-strict.json +16 -0
- package/tsconfig.json +10 -14
- package/{app/client/tsconfig.node.json → tsconfig.node.json} +1 -1
- package/types/global.d.ts +29 -29
- package/types/vitest.d.ts +8 -8
- package/vite.config.ts +38 -62
- package/vitest.config.live.ts +10 -9
- package/vitest.config.ts +29 -17
- package/workspace.json +5 -5
- package/app/client/README.md +0 -69
- package/app/client/SIMPLIFICATION.md +0 -140
- package/app/client/frontend-only.ts +0 -12
- package/app/client/tsconfig.app.json +0 -44
- package/app/client/tsconfig.json +0 -7
- package/app/client/zustand-setup.md +0 -65
- package/app/server/backend-only.ts +0 -18
- package/app/server/live/LiveClockComponent.ts +0 -215
- package/app/server/routes/env-test.ts +0 -110
- package/core/client/hooks/index.ts +0 -7
- package/core/client/hooks/useHybridLiveComponent.ts +0 -631
- package/core/client/hooks/useWebSocket.ts +0 -373
- package/core/config/env.ts +0 -546
- package/core/config/loader.ts +0 -522
- package/core/config/runtime-config.ts +0 -327
- package/core/config/validator.ts +0 -540
- package/core/server/backend-entry.ts +0 -51
- package/core/server/standalone.ts +0 -106
- package/core/utils/regenerate-files.ts +0 -69
- package/fluxstack.config.ts +0 -354
package/core/utils/env.ts
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
*
|
|
10
10
|
* @example
|
|
11
11
|
* ```ts
|
|
12
|
-
* import { env } from '
|
|
12
|
+
* import { env } from '@core/utils/env'
|
|
13
13
|
*
|
|
14
14
|
* const port = env.PORT // number (3000)
|
|
15
15
|
* const debug = env.DEBUG // boolean (false)
|
|
@@ -51,13 +51,7 @@ class EnvLoader {
|
|
|
51
51
|
return global['process']['env']
|
|
52
52
|
}
|
|
53
53
|
|
|
54
|
-
|
|
55
|
-
try {
|
|
56
|
-
const proc = eval('typeof process !== "undefined" ? process : null')
|
|
57
|
-
return proc?.env || {}
|
|
58
|
-
} catch {
|
|
59
|
-
return {}
|
|
60
|
-
}
|
|
54
|
+
return {}
|
|
61
55
|
}
|
|
62
56
|
}
|
|
63
57
|
|
|
@@ -1,115 +1,115 @@
|
|
|
1
|
-
export const ERROR_CODES = {
|
|
2
|
-
// Validation errors (400)
|
|
3
|
-
VALIDATION_ERROR: 'VALIDATION_ERROR',
|
|
4
|
-
INVALID_INPUT: 'INVALID_INPUT',
|
|
5
|
-
MISSING_REQUIRED_FIELD: 'MISSING_REQUIRED_FIELD',
|
|
6
|
-
INVALID_FORMAT: 'INVALID_FORMAT',
|
|
7
|
-
|
|
8
|
-
// Authentication errors (401)
|
|
9
|
-
UNAUTHORIZED: 'UNAUTHORIZED',
|
|
10
|
-
INVALID_TOKEN: 'INVALID_TOKEN',
|
|
11
|
-
TOKEN_EXPIRED: 'TOKEN_EXPIRED',
|
|
12
|
-
INVALID_CREDENTIALS: 'INVALID_CREDENTIALS',
|
|
13
|
-
|
|
14
|
-
// Authorization errors (403)
|
|
15
|
-
FORBIDDEN: 'FORBIDDEN',
|
|
16
|
-
INSUFFICIENT_PERMISSIONS: 'INSUFFICIENT_PERMISSIONS',
|
|
17
|
-
ACCESS_DENIED: 'ACCESS_DENIED',
|
|
18
|
-
|
|
19
|
-
// Not found errors (404)
|
|
20
|
-
NOT_FOUND: 'NOT_FOUND',
|
|
21
|
-
RESOURCE_NOT_FOUND: 'RESOURCE_NOT_FOUND',
|
|
22
|
-
ENDPOINT_NOT_FOUND: 'ENDPOINT_NOT_FOUND',
|
|
23
|
-
|
|
24
|
-
// Conflict errors (409)
|
|
25
|
-
CONFLICT: 'CONFLICT',
|
|
26
|
-
RESOURCE_ALREADY_EXISTS: 'RESOURCE_ALREADY_EXISTS',
|
|
27
|
-
DUPLICATE_ENTRY: 'DUPLICATE_ENTRY',
|
|
28
|
-
|
|
29
|
-
// Server errors (500)
|
|
30
|
-
INTERNAL_ERROR: 'INTERNAL_ERROR',
|
|
31
|
-
INTERNAL_SERVER_ERROR: 'INTERNAL_SERVER_ERROR',
|
|
32
|
-
DATABASE_ERROR: 'DATABASE_ERROR',
|
|
33
|
-
EXTERNAL_SERVICE_ERROR: 'EXTERNAL_SERVICE_ERROR',
|
|
34
|
-
|
|
35
|
-
// Service unavailable (503)
|
|
36
|
-
SERVICE_UNAVAILABLE: 'SERVICE_UNAVAILABLE',
|
|
37
|
-
MAINTENANCE_MODE: 'MAINTENANCE_MODE',
|
|
38
|
-
RATE_LIMIT_EXCEEDED: 'RATE_LIMIT_EXCEEDED',
|
|
39
|
-
|
|
40
|
-
// Plugin errors
|
|
41
|
-
PLUGIN_ERROR: 'PLUGIN_ERROR',
|
|
42
|
-
PLUGIN_NOT_FOUND: 'PLUGIN_NOT_FOUND',
|
|
43
|
-
PLUGIN_INITIALIZATION_ERROR: 'PLUGIN_INITIALIZATION_ERROR',
|
|
44
|
-
|
|
45
|
-
// Configuration errors
|
|
46
|
-
CONFIG_ERROR: 'CONFIG_ERROR',
|
|
47
|
-
INVALID_CONFIG: 'INVALID_CONFIG',
|
|
48
|
-
MISSING_CONFIG: 'MISSING_CONFIG',
|
|
49
|
-
|
|
50
|
-
// Build errors
|
|
51
|
-
BUILD_ERROR: 'BUILD_ERROR',
|
|
52
|
-
COMPILATION_ERROR: 'COMPILATION_ERROR',
|
|
53
|
-
BUNDLING_ERROR: 'BUNDLING_ERROR'
|
|
54
|
-
} as const
|
|
55
|
-
|
|
56
|
-
export type ErrorCode = typeof ERROR_CODES[keyof typeof ERROR_CODES]
|
|
57
|
-
|
|
58
|
-
export const getErrorMessage = (code: ErrorCode): string => {
|
|
59
|
-
const messages: Record<ErrorCode, string> = {
|
|
60
|
-
// Validation errors
|
|
61
|
-
VALIDATION_ERROR: 'Validation failed',
|
|
62
|
-
INVALID_INPUT: 'Invalid input provided',
|
|
63
|
-
MISSING_REQUIRED_FIELD: 'Required field is missing',
|
|
64
|
-
INVALID_FORMAT: 'Invalid format',
|
|
65
|
-
|
|
66
|
-
// Authentication errors
|
|
67
|
-
UNAUTHORIZED: 'Authentication required',
|
|
68
|
-
INVALID_TOKEN: 'Invalid authentication token',
|
|
69
|
-
TOKEN_EXPIRED: 'Authentication token has expired',
|
|
70
|
-
INVALID_CREDENTIALS: 'Invalid credentials provided',
|
|
71
|
-
|
|
72
|
-
// Authorization errors
|
|
73
|
-
FORBIDDEN: 'Access forbidden',
|
|
74
|
-
INSUFFICIENT_PERMISSIONS: 'Insufficient permissions',
|
|
75
|
-
ACCESS_DENIED: 'Access denied',
|
|
76
|
-
|
|
77
|
-
// Not found errors
|
|
78
|
-
NOT_FOUND: 'Resource not found',
|
|
79
|
-
RESOURCE_NOT_FOUND: 'Requested resource not found',
|
|
80
|
-
ENDPOINT_NOT_FOUND: 'API endpoint not found',
|
|
81
|
-
|
|
82
|
-
// Conflict errors
|
|
83
|
-
CONFLICT: 'Resource conflict',
|
|
84
|
-
RESOURCE_ALREADY_EXISTS: 'Resource already exists',
|
|
85
|
-
DUPLICATE_ENTRY: 'Duplicate entry',
|
|
86
|
-
|
|
87
|
-
// Server errors
|
|
88
|
-
INTERNAL_ERROR: 'Internal server error',
|
|
89
|
-
INTERNAL_SERVER_ERROR: 'Internal server error',
|
|
90
|
-
DATABASE_ERROR: 'Database operation failed',
|
|
91
|
-
EXTERNAL_SERVICE_ERROR: 'External service error',
|
|
92
|
-
|
|
93
|
-
// Service unavailable
|
|
94
|
-
SERVICE_UNAVAILABLE: 'Service temporarily unavailable',
|
|
95
|
-
MAINTENANCE_MODE: 'Service is under maintenance',
|
|
96
|
-
RATE_LIMIT_EXCEEDED: 'Rate limit exceeded',
|
|
97
|
-
|
|
98
|
-
// Plugin errors
|
|
99
|
-
PLUGIN_ERROR: 'Plugin error',
|
|
100
|
-
PLUGIN_NOT_FOUND: 'Plugin not found',
|
|
101
|
-
PLUGIN_INITIALIZATION_ERROR: 'Plugin initialization failed',
|
|
102
|
-
|
|
103
|
-
// Configuration errors
|
|
104
|
-
CONFIG_ERROR: 'Configuration error',
|
|
105
|
-
INVALID_CONFIG: 'Invalid configuration',
|
|
106
|
-
MISSING_CONFIG: 'Missing configuration',
|
|
107
|
-
|
|
108
|
-
// Build errors
|
|
109
|
-
BUILD_ERROR: 'Build error',
|
|
110
|
-
COMPILATION_ERROR: 'Compilation failed',
|
|
111
|
-
BUNDLING_ERROR: 'Bundling failed'
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
return messages[code] || 'Unknown error'
|
|
1
|
+
export const ERROR_CODES = {
|
|
2
|
+
// Validation errors (400)
|
|
3
|
+
VALIDATION_ERROR: 'VALIDATION_ERROR',
|
|
4
|
+
INVALID_INPUT: 'INVALID_INPUT',
|
|
5
|
+
MISSING_REQUIRED_FIELD: 'MISSING_REQUIRED_FIELD',
|
|
6
|
+
INVALID_FORMAT: 'INVALID_FORMAT',
|
|
7
|
+
|
|
8
|
+
// Authentication errors (401)
|
|
9
|
+
UNAUTHORIZED: 'UNAUTHORIZED',
|
|
10
|
+
INVALID_TOKEN: 'INVALID_TOKEN',
|
|
11
|
+
TOKEN_EXPIRED: 'TOKEN_EXPIRED',
|
|
12
|
+
INVALID_CREDENTIALS: 'INVALID_CREDENTIALS',
|
|
13
|
+
|
|
14
|
+
// Authorization errors (403)
|
|
15
|
+
FORBIDDEN: 'FORBIDDEN',
|
|
16
|
+
INSUFFICIENT_PERMISSIONS: 'INSUFFICIENT_PERMISSIONS',
|
|
17
|
+
ACCESS_DENIED: 'ACCESS_DENIED',
|
|
18
|
+
|
|
19
|
+
// Not found errors (404)
|
|
20
|
+
NOT_FOUND: 'NOT_FOUND',
|
|
21
|
+
RESOURCE_NOT_FOUND: 'RESOURCE_NOT_FOUND',
|
|
22
|
+
ENDPOINT_NOT_FOUND: 'ENDPOINT_NOT_FOUND',
|
|
23
|
+
|
|
24
|
+
// Conflict errors (409)
|
|
25
|
+
CONFLICT: 'CONFLICT',
|
|
26
|
+
RESOURCE_ALREADY_EXISTS: 'RESOURCE_ALREADY_EXISTS',
|
|
27
|
+
DUPLICATE_ENTRY: 'DUPLICATE_ENTRY',
|
|
28
|
+
|
|
29
|
+
// Server errors (500)
|
|
30
|
+
INTERNAL_ERROR: 'INTERNAL_ERROR',
|
|
31
|
+
INTERNAL_SERVER_ERROR: 'INTERNAL_SERVER_ERROR',
|
|
32
|
+
DATABASE_ERROR: 'DATABASE_ERROR',
|
|
33
|
+
EXTERNAL_SERVICE_ERROR: 'EXTERNAL_SERVICE_ERROR',
|
|
34
|
+
|
|
35
|
+
// Service unavailable (503)
|
|
36
|
+
SERVICE_UNAVAILABLE: 'SERVICE_UNAVAILABLE',
|
|
37
|
+
MAINTENANCE_MODE: 'MAINTENANCE_MODE',
|
|
38
|
+
RATE_LIMIT_EXCEEDED: 'RATE_LIMIT_EXCEEDED',
|
|
39
|
+
|
|
40
|
+
// Plugin errors
|
|
41
|
+
PLUGIN_ERROR: 'PLUGIN_ERROR',
|
|
42
|
+
PLUGIN_NOT_FOUND: 'PLUGIN_NOT_FOUND',
|
|
43
|
+
PLUGIN_INITIALIZATION_ERROR: 'PLUGIN_INITIALIZATION_ERROR',
|
|
44
|
+
|
|
45
|
+
// Configuration errors
|
|
46
|
+
CONFIG_ERROR: 'CONFIG_ERROR',
|
|
47
|
+
INVALID_CONFIG: 'INVALID_CONFIG',
|
|
48
|
+
MISSING_CONFIG: 'MISSING_CONFIG',
|
|
49
|
+
|
|
50
|
+
// Build errors
|
|
51
|
+
BUILD_ERROR: 'BUILD_ERROR',
|
|
52
|
+
COMPILATION_ERROR: 'COMPILATION_ERROR',
|
|
53
|
+
BUNDLING_ERROR: 'BUNDLING_ERROR'
|
|
54
|
+
} as const
|
|
55
|
+
|
|
56
|
+
export type ErrorCode = typeof ERROR_CODES[keyof typeof ERROR_CODES]
|
|
57
|
+
|
|
58
|
+
export const getErrorMessage = (code: ErrorCode): string => {
|
|
59
|
+
const messages: Record<ErrorCode, string> = {
|
|
60
|
+
// Validation errors
|
|
61
|
+
VALIDATION_ERROR: 'Validation failed',
|
|
62
|
+
INVALID_INPUT: 'Invalid input provided',
|
|
63
|
+
MISSING_REQUIRED_FIELD: 'Required field is missing',
|
|
64
|
+
INVALID_FORMAT: 'Invalid format',
|
|
65
|
+
|
|
66
|
+
// Authentication errors
|
|
67
|
+
UNAUTHORIZED: 'Authentication required',
|
|
68
|
+
INVALID_TOKEN: 'Invalid authentication token',
|
|
69
|
+
TOKEN_EXPIRED: 'Authentication token has expired',
|
|
70
|
+
INVALID_CREDENTIALS: 'Invalid credentials provided',
|
|
71
|
+
|
|
72
|
+
// Authorization errors
|
|
73
|
+
FORBIDDEN: 'Access forbidden',
|
|
74
|
+
INSUFFICIENT_PERMISSIONS: 'Insufficient permissions',
|
|
75
|
+
ACCESS_DENIED: 'Access denied',
|
|
76
|
+
|
|
77
|
+
// Not found errors
|
|
78
|
+
NOT_FOUND: 'Resource not found',
|
|
79
|
+
RESOURCE_NOT_FOUND: 'Requested resource not found',
|
|
80
|
+
ENDPOINT_NOT_FOUND: 'API endpoint not found',
|
|
81
|
+
|
|
82
|
+
// Conflict errors
|
|
83
|
+
CONFLICT: 'Resource conflict',
|
|
84
|
+
RESOURCE_ALREADY_EXISTS: 'Resource already exists',
|
|
85
|
+
DUPLICATE_ENTRY: 'Duplicate entry',
|
|
86
|
+
|
|
87
|
+
// Server errors
|
|
88
|
+
INTERNAL_ERROR: 'Internal server error',
|
|
89
|
+
INTERNAL_SERVER_ERROR: 'Internal server error',
|
|
90
|
+
DATABASE_ERROR: 'Database operation failed',
|
|
91
|
+
EXTERNAL_SERVICE_ERROR: 'External service error',
|
|
92
|
+
|
|
93
|
+
// Service unavailable
|
|
94
|
+
SERVICE_UNAVAILABLE: 'Service temporarily unavailable',
|
|
95
|
+
MAINTENANCE_MODE: 'Service is under maintenance',
|
|
96
|
+
RATE_LIMIT_EXCEEDED: 'Rate limit exceeded',
|
|
97
|
+
|
|
98
|
+
// Plugin errors
|
|
99
|
+
PLUGIN_ERROR: 'Plugin error',
|
|
100
|
+
PLUGIN_NOT_FOUND: 'Plugin not found',
|
|
101
|
+
PLUGIN_INITIALIZATION_ERROR: 'Plugin initialization failed',
|
|
102
|
+
|
|
103
|
+
// Configuration errors
|
|
104
|
+
CONFIG_ERROR: 'Configuration error',
|
|
105
|
+
INVALID_CONFIG: 'Invalid configuration',
|
|
106
|
+
MISSING_CONFIG: 'Missing configuration',
|
|
107
|
+
|
|
108
|
+
// Build errors
|
|
109
|
+
BUILD_ERROR: 'Build error',
|
|
110
|
+
COMPILATION_ERROR: 'Compilation failed',
|
|
111
|
+
BUNDLING_ERROR: 'Bundling failed'
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
return messages[code] || 'Unknown error'
|
|
115
115
|
}
|
|
@@ -120,13 +120,17 @@ export class EnhancedErrorHandler {
|
|
|
120
120
|
|
|
121
121
|
private logError(error: FluxStackError, logger: Logger, isDevelopment: boolean): void {
|
|
122
122
|
const logLevel = this.getLogLevel(error)
|
|
123
|
+
|
|
124
|
+
// Format stack trace properly (handles CallSite objects from Bun)
|
|
125
|
+
const formattedStack = isDevelopment ? this.formatErrorStack(error.stack) : undefined
|
|
126
|
+
|
|
123
127
|
const logData = {
|
|
124
128
|
code: error.code,
|
|
125
129
|
statusCode: error.statusCode,
|
|
126
130
|
context: error.context,
|
|
127
131
|
metadata: error.metadata,
|
|
128
132
|
isOperational: error.isOperational,
|
|
129
|
-
...(
|
|
133
|
+
...(formattedStack && { stack: formattedStack })
|
|
130
134
|
}
|
|
131
135
|
|
|
132
136
|
// Skip logging for certain errors to reduce noise
|
|
@@ -137,6 +141,37 @@ export class EnhancedErrorHandler {
|
|
|
137
141
|
logger[logLevel](error.message, logData)
|
|
138
142
|
}
|
|
139
143
|
|
|
144
|
+
/**
|
|
145
|
+
* Format stack trace to readable string (handles Bun CallSite objects)
|
|
146
|
+
*/
|
|
147
|
+
private formatErrorStack(stack: any): string | undefined {
|
|
148
|
+
if (!stack) return undefined
|
|
149
|
+
|
|
150
|
+
// If stack is already a string, return it
|
|
151
|
+
if (typeof stack === 'string') return stack
|
|
152
|
+
|
|
153
|
+
// If stack is an array of CallSite objects (Bun), format them
|
|
154
|
+
if (Array.isArray(stack)) {
|
|
155
|
+
return stack
|
|
156
|
+
.map((site: any, index: number) => {
|
|
157
|
+
try {
|
|
158
|
+
const fileName = site.getFileName?.() || 'unknown'
|
|
159
|
+
const lineNumber = site.getLineNumber?.() || 0
|
|
160
|
+
const columnNumber = site.getColumnNumber?.() || 0
|
|
161
|
+
const functionName = site.getFunctionName?.() || 'anonymous'
|
|
162
|
+
|
|
163
|
+
return ` at ${functionName} (${fileName}:${lineNumber}:${columnNumber})`
|
|
164
|
+
} catch {
|
|
165
|
+
return ` at ${String(site)}`
|
|
166
|
+
}
|
|
167
|
+
})
|
|
168
|
+
.join('\n')
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// Fallback: convert to string
|
|
172
|
+
return String(stack)
|
|
173
|
+
}
|
|
174
|
+
|
|
140
175
|
private getLogLevel(error: FluxStackError): 'error' | 'warn' | 'info' {
|
|
141
176
|
if (!error.isOperational) {
|
|
142
177
|
return 'error'
|
|
@@ -46,13 +46,45 @@ export class FluxStackError extends Error {
|
|
|
46
46
|
this.metadata = metadata
|
|
47
47
|
this.isOperational = isOperational
|
|
48
48
|
this.userMessage = userMessage
|
|
49
|
-
|
|
49
|
+
|
|
50
50
|
// Maintain proper stack trace
|
|
51
51
|
if (Error.captureStackTrace) {
|
|
52
52
|
Error.captureStackTrace(this, FluxStackError)
|
|
53
53
|
}
|
|
54
54
|
}
|
|
55
55
|
|
|
56
|
+
/**
|
|
57
|
+
* Format stack trace to string (handles both string and CallSite array)
|
|
58
|
+
*/
|
|
59
|
+
private formatStack(): string | undefined {
|
|
60
|
+
if (!this.stack) return undefined
|
|
61
|
+
|
|
62
|
+
// If stack is already a string, return it
|
|
63
|
+
if (typeof this.stack === 'string') return this.stack
|
|
64
|
+
|
|
65
|
+
// If stack is an array of CallSite objects (Bun), format them
|
|
66
|
+
const stackValue = this.stack as unknown
|
|
67
|
+
if (Array.isArray(stackValue)) {
|
|
68
|
+
return stackValue
|
|
69
|
+
.map((site: any) => {
|
|
70
|
+
try {
|
|
71
|
+
const fileName = site.getFileName?.() || 'unknown'
|
|
72
|
+
const lineNumber = site.getLineNumber?.() || 0
|
|
73
|
+
const columnNumber = site.getColumnNumber?.() || 0
|
|
74
|
+
const functionName = site.getFunctionName?.() || 'anonymous'
|
|
75
|
+
|
|
76
|
+
return ` at ${functionName} (${fileName}:${lineNumber}:${columnNumber})`
|
|
77
|
+
} catch {
|
|
78
|
+
return ` at ${String(site)}`
|
|
79
|
+
}
|
|
80
|
+
})
|
|
81
|
+
.join('\n')
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Fallback: convert to string
|
|
85
|
+
return String(this.stack)
|
|
86
|
+
}
|
|
87
|
+
|
|
56
88
|
toJSON() {
|
|
57
89
|
return {
|
|
58
90
|
name: this.name,
|
|
@@ -64,7 +96,7 @@ export class FluxStackError extends Error {
|
|
|
64
96
|
metadata: this.metadata,
|
|
65
97
|
isOperational: this.isOperational,
|
|
66
98
|
userMessage: this.userMessage,
|
|
67
|
-
stack: this.
|
|
99
|
+
stack: this.formatStack()
|
|
68
100
|
}
|
|
69
101
|
}
|
|
70
102
|
|
|
@@ -77,7 +109,7 @@ export class FluxStackError extends Error {
|
|
|
77
109
|
...(this.context && { details: this.context }),
|
|
78
110
|
timestamp: this.timestamp.toISOString(),
|
|
79
111
|
...(this.metadata.correlationId && { correlationId: this.metadata.correlationId }),
|
|
80
|
-
...(isDevelopment && { stack: this.
|
|
112
|
+
...(isDevelopment && { stack: this.formatStack() })
|
|
81
113
|
}
|
|
82
114
|
}
|
|
83
115
|
}
|
|
@@ -583,9 +615,21 @@ export const wrapError = (error: Error, metadata?: ErrorMetadata): FluxStackErro
|
|
|
583
615
|
if (isFluxStackError(error)) {
|
|
584
616
|
return metadata ? error.withMetadata(metadata) : error
|
|
585
617
|
}
|
|
586
|
-
|
|
618
|
+
|
|
619
|
+
// Detect Elysia validation errors (thrown by TypeBox schema validation)
|
|
620
|
+
const errorAny = error as any
|
|
621
|
+
if (
|
|
622
|
+
error.constructor?.name === 'ValidationError' ||
|
|
623
|
+
error.constructor?.name === 'TransformDecodeError' ||
|
|
624
|
+
(typeof errorAny.status === 'number' && errorAny.status >= 400 && errorAny.status < 500)
|
|
625
|
+
) {
|
|
626
|
+
const status = errorAny.status ?? 422
|
|
627
|
+
const message = error.message || 'Validation failed'
|
|
628
|
+
return new ValidationError(message, { originalError: error.name, status }, metadata)
|
|
629
|
+
}
|
|
630
|
+
|
|
587
631
|
return new InternalServerError(error.message, { originalError: error.name }, metadata)
|
|
588
632
|
}
|
|
589
633
|
|
|
590
634
|
// Re-export error codes for convenience
|
|
591
|
-
export { ERROR_CODES, type ErrorCode, getErrorMessage } from './codes'
|
|
635
|
+
export { ERROR_CODES, type ErrorCode, getErrorMessage } from './codes'
|
|
@@ -1,114 +1,114 @@
|
|
|
1
|
-
import { Elysia } from 'elysia'
|
|
2
|
-
import { EnhancedErrorHandler, type ErrorHandlerContext, type ErrorHandlerOptions, type ErrorMetricsCollector } from './handlers'
|
|
3
|
-
import type { Logger } from '../logger/index'
|
|
4
|
-
|
|
5
|
-
export interface ErrorMiddlewareOptions extends ErrorHandlerOptions {
|
|
6
|
-
logger?: Logger
|
|
7
|
-
isDevelopment?: boolean
|
|
8
|
-
enableRequestContext?: boolean
|
|
9
|
-
metricsCollector?: ErrorMetricsCollector
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export const errorMiddleware = (options: ErrorMiddlewareOptions = {}) => {
|
|
13
|
-
const handler = new EnhancedErrorHandler(options)
|
|
14
|
-
|
|
15
|
-
return new Elysia({ name: 'error-handler' })
|
|
16
|
-
.onError(async ({ error, request, path, set }) => {
|
|
17
|
-
// Extract request context
|
|
18
|
-
const context: ErrorHandlerContext = {
|
|
19
|
-
logger: options.logger || console as any, // Fallback to console if no logger provided
|
|
20
|
-
isDevelopment: options.isDevelopment ?? process.env.NODE_ENV === 'development',
|
|
21
|
-
request,
|
|
22
|
-
path,
|
|
23
|
-
method: request.method,
|
|
24
|
-
correlationId: request.headers.get('x-correlation-id') || undefined,
|
|
25
|
-
userId: request.headers.get('x-user-id') || undefined,
|
|
26
|
-
userAgent: request.headers.get('user-agent') || undefined,
|
|
27
|
-
ip: request.headers.get('x-forwarded-for') ||
|
|
28
|
-
request.headers.get('x-real-ip') ||
|
|
29
|
-
'unknown',
|
|
30
|
-
metricsCollector: options.metricsCollector
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
try {
|
|
34
|
-
// Convert Elysia error to standard Error if needed
|
|
35
|
-
const standardError = error instanceof Error ? error : new Error(String(error))
|
|
36
|
-
const errorResponse = await handler.handle(standardError, context)
|
|
37
|
-
|
|
38
|
-
// Set response status code
|
|
39
|
-
set.status = errorResponse.error.statusCode
|
|
40
|
-
|
|
41
|
-
// Set correlation ID header if available
|
|
42
|
-
if (errorResponse.error.correlationId) {
|
|
43
|
-
set.headers['x-correlation-id'] = errorResponse.error.correlationId
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
return errorResponse
|
|
47
|
-
} catch (handlerError) {
|
|
48
|
-
// Fallback error handling if the error handler itself fails
|
|
49
|
-
const fallbackLogger = options.logger || console as any
|
|
50
|
-
fallbackLogger.error('Error handler failed', {
|
|
51
|
-
originalError: error instanceof Error ? error.message : String(error),
|
|
52
|
-
handlerError: handlerError instanceof Error ? handlerError.message : handlerError
|
|
53
|
-
})
|
|
54
|
-
|
|
55
|
-
set.status = 500
|
|
56
|
-
return {
|
|
57
|
-
error: {
|
|
58
|
-
message: 'Internal server error',
|
|
59
|
-
code: 'INTERNAL_ERROR',
|
|
60
|
-
statusCode: 500,
|
|
61
|
-
timestamp: new Date().toISOString()
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
})
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
// Correlation ID middleware to add correlation IDs to requests
|
|
69
|
-
export const correlationIdMiddleware = () => {
|
|
70
|
-
return new Elysia({ name: 'correlation-id' })
|
|
71
|
-
.onRequest(({ request, set }) => {
|
|
72
|
-
// Check if correlation ID already exists in headers
|
|
73
|
-
let correlationId = request.headers.get('x-correlation-id')
|
|
74
|
-
|
|
75
|
-
// Generate new correlation ID if not present
|
|
76
|
-
if (!correlationId) {
|
|
77
|
-
correlationId = crypto.randomUUID()
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
// Add correlation ID to response headers
|
|
81
|
-
set.headers['x-correlation-id'] = correlationId
|
|
82
|
-
|
|
83
|
-
// Store correlation ID in request context for later use
|
|
84
|
-
// Note: This would typically be stored in a request-scoped context
|
|
85
|
-
// For now, we'll rely on the error handler to extract it from headers
|
|
86
|
-
})
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
// Request context middleware to extract and store request information
|
|
90
|
-
export const requestContextMiddleware = () => {
|
|
91
|
-
return new Elysia({ name: 'request-context' })
|
|
92
|
-
.onRequest(({ request, set }) => {
|
|
93
|
-
// Extract useful request information and store in headers for error handling
|
|
94
|
-
const userAgent = request.headers.get('user-agent')
|
|
95
|
-
const ip = request.headers.get('x-forwarded-for') ||
|
|
96
|
-
request.headers.get('x-real-ip') ||
|
|
97
|
-
'unknown'
|
|
98
|
-
|
|
99
|
-
// Store in custom headers for error handler access
|
|
100
|
-
// In a real implementation, this would use request-scoped storage
|
|
101
|
-
if (userAgent) {
|
|
102
|
-
set.headers['x-internal-user-agent'] = userAgent
|
|
103
|
-
}
|
|
104
|
-
set.headers['x-internal-ip'] = ip
|
|
105
|
-
})
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
// Combined error handling middleware with all features
|
|
109
|
-
export const fullErrorHandlingMiddleware = (options: ErrorMiddlewareOptions = {}) => {
|
|
110
|
-
return new Elysia({ name: 'full-error-handling' })
|
|
111
|
-
.use(correlationIdMiddleware())
|
|
112
|
-
.use(requestContextMiddleware())
|
|
113
|
-
.use(errorMiddleware(options))
|
|
1
|
+
import { Elysia } from 'elysia'
|
|
2
|
+
import { EnhancedErrorHandler, type ErrorHandlerContext, type ErrorHandlerOptions, type ErrorMetricsCollector } from './handlers'
|
|
3
|
+
import type { Logger } from '../logger/index'
|
|
4
|
+
|
|
5
|
+
export interface ErrorMiddlewareOptions extends ErrorHandlerOptions {
|
|
6
|
+
logger?: Logger
|
|
7
|
+
isDevelopment?: boolean
|
|
8
|
+
enableRequestContext?: boolean
|
|
9
|
+
metricsCollector?: ErrorMetricsCollector
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export const errorMiddleware = (options: ErrorMiddlewareOptions = {}) => {
|
|
13
|
+
const handler = new EnhancedErrorHandler(options)
|
|
14
|
+
|
|
15
|
+
return new Elysia({ name: 'error-handler' })
|
|
16
|
+
.onError(async ({ error, request, path, set }) => {
|
|
17
|
+
// Extract request context
|
|
18
|
+
const context: ErrorHandlerContext = {
|
|
19
|
+
logger: options.logger || console as any, // Fallback to console if no logger provided
|
|
20
|
+
isDevelopment: options.isDevelopment ?? process.env.NODE_ENV === 'development',
|
|
21
|
+
request,
|
|
22
|
+
path,
|
|
23
|
+
method: request.method,
|
|
24
|
+
correlationId: request.headers.get('x-correlation-id') || undefined,
|
|
25
|
+
userId: request.headers.get('x-user-id') || undefined,
|
|
26
|
+
userAgent: request.headers.get('user-agent') || undefined,
|
|
27
|
+
ip: request.headers.get('x-forwarded-for') ||
|
|
28
|
+
request.headers.get('x-real-ip') ||
|
|
29
|
+
'unknown',
|
|
30
|
+
metricsCollector: options.metricsCollector
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
try {
|
|
34
|
+
// Convert Elysia error to standard Error if needed
|
|
35
|
+
const standardError = error instanceof Error ? error : new Error(String(error))
|
|
36
|
+
const errorResponse = await handler.handle(standardError, context)
|
|
37
|
+
|
|
38
|
+
// Set response status code
|
|
39
|
+
set.status = errorResponse.error.statusCode
|
|
40
|
+
|
|
41
|
+
// Set correlation ID header if available
|
|
42
|
+
if (errorResponse.error.correlationId) {
|
|
43
|
+
set.headers['x-correlation-id'] = errorResponse.error.correlationId
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return errorResponse
|
|
47
|
+
} catch (handlerError) {
|
|
48
|
+
// Fallback error handling if the error handler itself fails
|
|
49
|
+
const fallbackLogger = options.logger || console as any
|
|
50
|
+
fallbackLogger.error('Error handler failed', {
|
|
51
|
+
originalError: error instanceof Error ? error.message : String(error),
|
|
52
|
+
handlerError: handlerError instanceof Error ? handlerError.message : handlerError
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
set.status = 500
|
|
56
|
+
return {
|
|
57
|
+
error: {
|
|
58
|
+
message: 'Internal server error',
|
|
59
|
+
code: 'INTERNAL_ERROR',
|
|
60
|
+
statusCode: 500,
|
|
61
|
+
timestamp: new Date().toISOString()
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
})
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Correlation ID middleware to add correlation IDs to requests
|
|
69
|
+
export const correlationIdMiddleware = () => {
|
|
70
|
+
return new Elysia({ name: 'correlation-id' })
|
|
71
|
+
.onRequest(({ request, set }) => {
|
|
72
|
+
// Check if correlation ID already exists in headers
|
|
73
|
+
let correlationId = request.headers.get('x-correlation-id')
|
|
74
|
+
|
|
75
|
+
// Generate new correlation ID if not present
|
|
76
|
+
if (!correlationId) {
|
|
77
|
+
correlationId = crypto.randomUUID()
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Add correlation ID to response headers
|
|
81
|
+
set.headers['x-correlation-id'] = correlationId
|
|
82
|
+
|
|
83
|
+
// Store correlation ID in request context for later use
|
|
84
|
+
// Note: This would typically be stored in a request-scoped context
|
|
85
|
+
// For now, we'll rely on the error handler to extract it from headers
|
|
86
|
+
})
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// Request context middleware to extract and store request information
|
|
90
|
+
export const requestContextMiddleware = () => {
|
|
91
|
+
return new Elysia({ name: 'request-context' })
|
|
92
|
+
.onRequest(({ request, set }) => {
|
|
93
|
+
// Extract useful request information and store in headers for error handling
|
|
94
|
+
const userAgent = request.headers.get('user-agent')
|
|
95
|
+
const ip = request.headers.get('x-forwarded-for') ||
|
|
96
|
+
request.headers.get('x-real-ip') ||
|
|
97
|
+
'unknown'
|
|
98
|
+
|
|
99
|
+
// Store in custom headers for error handler access
|
|
100
|
+
// In a real implementation, this would use request-scoped storage
|
|
101
|
+
if (userAgent) {
|
|
102
|
+
set.headers['x-internal-user-agent'] = userAgent
|
|
103
|
+
}
|
|
104
|
+
set.headers['x-internal-ip'] = ip
|
|
105
|
+
})
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// Combined error handling middleware with all features
|
|
109
|
+
export const fullErrorHandlingMiddleware = (options: ErrorMiddlewareOptions = {}) => {
|
|
110
|
+
return new Elysia({ name: 'full-error-handling' })
|
|
111
|
+
.use(correlationIdMiddleware())
|
|
112
|
+
.use(requestContextMiddleware())
|
|
113
|
+
.use(errorMiddleware(options))
|
|
114
114
|
}
|
package/core/utils/helpers.ts
CHANGED
|
@@ -91,23 +91,13 @@ export const throttle = <T extends (...args: any[]) => any>(
|
|
|
91
91
|
* Uses declarative config system instead of legacy env
|
|
92
92
|
*/
|
|
93
93
|
|
|
94
|
-
|
|
95
|
-
// Lazy import to avoid circular dependency during module initialization
|
|
96
|
-
const { appConfig } = require('@/config/app.config')
|
|
97
|
-
return appConfig.env === 'production'
|
|
98
|
-
}
|
|
94
|
+
const getNodeEnv = (): string => process.env.NODE_ENV || 'development'
|
|
99
95
|
|
|
100
|
-
export const
|
|
101
|
-
// Lazy import to avoid circular dependency during module initialization
|
|
102
|
-
const { appConfig } = require('@/config/app.config')
|
|
103
|
-
return appConfig.env === 'development'
|
|
104
|
-
}
|
|
96
|
+
export const isProduction = (): boolean => getNodeEnv() === 'production'
|
|
105
97
|
|
|
106
|
-
export const
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
return appConfig.env === 'test'
|
|
110
|
-
}
|
|
98
|
+
export const isDevelopment = (): boolean => getNodeEnv() === 'development'
|
|
99
|
+
|
|
100
|
+
export const isTest = (): boolean => getNodeEnv() === 'test'
|
|
111
101
|
|
|
112
102
|
export const deepMerge = <T extends Record<string, any>>(target: T, source: Partial<T>): T => {
|
|
113
103
|
const result = { ...target }
|
|
@@ -188,4 +178,4 @@ export const safeJsonStringify = (obj: any, fallback: string = '{}'): string =>
|
|
|
188
178
|
} catch {
|
|
189
179
|
return fallback
|
|
190
180
|
}
|
|
191
|
-
}
|
|
181
|
+
}
|