create-fluxstack 1.10.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.
Files changed (257) hide show
  1. package/.dockerignore +1 -2
  2. package/Dockerfile +8 -8
  3. package/LLMD/INDEX.md +64 -0
  4. package/LLMD/MAINTENANCE.md +197 -0
  5. package/LLMD/MIGRATION.md +156 -0
  6. package/LLMD/config/.gitkeep +1 -0
  7. package/LLMD/config/declarative-system.md +268 -0
  8. package/LLMD/config/environment-vars.md +327 -0
  9. package/LLMD/config/runtime-reload.md +401 -0
  10. package/LLMD/core/.gitkeep +1 -0
  11. package/LLMD/core/build-system.md +599 -0
  12. package/LLMD/core/framework-lifecycle.md +229 -0
  13. package/LLMD/core/plugin-system.md +451 -0
  14. package/LLMD/patterns/.gitkeep +1 -0
  15. package/LLMD/patterns/anti-patterns.md +297 -0
  16. package/LLMD/patterns/project-structure.md +264 -0
  17. package/LLMD/patterns/type-safety.md +440 -0
  18. package/LLMD/reference/.gitkeep +1 -0
  19. package/LLMD/reference/cli-commands.md +250 -0
  20. package/LLMD/reference/plugin-hooks.md +357 -0
  21. package/LLMD/reference/routing.md +39 -0
  22. package/LLMD/reference/troubleshooting.md +364 -0
  23. package/LLMD/resources/.gitkeep +1 -0
  24. package/LLMD/resources/controllers.md +465 -0
  25. package/LLMD/resources/live-components.md +703 -0
  26. package/LLMD/resources/live-rooms.md +482 -0
  27. package/LLMD/resources/live-upload.md +130 -0
  28. package/LLMD/resources/plugins-external.md +617 -0
  29. package/LLMD/resources/routes-eden.md +254 -0
  30. package/README.md +37 -17
  31. package/app/client/index.html +0 -1
  32. package/app/client/src/App.tsx +107 -150
  33. package/app/client/src/components/AppLayout.tsx +68 -0
  34. package/app/client/src/components/BackButton.tsx +13 -0
  35. package/app/client/src/components/DemoPage.tsx +20 -0
  36. package/app/client/src/components/LiveUploadWidget.tsx +204 -0
  37. package/app/client/src/lib/eden-api.ts +85 -60
  38. package/app/client/src/live/ChatDemo.tsx +107 -0
  39. package/app/client/src/live/CounterDemo.tsx +206 -0
  40. package/app/client/src/live/FormDemo.tsx +119 -0
  41. package/app/client/src/live/RoomChatDemo.tsx +242 -0
  42. package/app/client/src/live/UploadDemo.tsx +21 -0
  43. package/app/client/src/main.tsx +4 -1
  44. package/app/client/src/pages/ApiTestPage.tsx +108 -0
  45. package/app/client/src/pages/HomePage.tsx +76 -0
  46. package/app/server/app.ts +1 -4
  47. package/app/server/controllers/users.controller.ts +36 -44
  48. package/app/server/index.ts +25 -35
  49. package/app/server/live/LiveChat.ts +77 -0
  50. package/app/server/live/LiveCounter.ts +67 -0
  51. package/app/server/live/LiveForm.ts +63 -0
  52. package/app/server/live/LiveLocalCounter.ts +32 -0
  53. package/app/server/live/LiveRoomChat.ts +285 -0
  54. package/app/server/live/LiveUpload.ts +81 -0
  55. package/app/server/routes/index.ts +3 -1
  56. package/app/server/routes/room.routes.ts +117 -0
  57. package/app/server/routes/users.routes.ts +35 -27
  58. package/app/shared/types/index.ts +14 -2
  59. package/config/app.config.ts +2 -62
  60. package/config/client.config.ts +2 -95
  61. package/config/database.config.ts +2 -99
  62. package/config/fluxstack.config.ts +25 -45
  63. package/config/index.ts +57 -38
  64. package/config/monitoring.config.ts +2 -114
  65. package/config/plugins.config.ts +2 -80
  66. package/config/server.config.ts +2 -68
  67. package/config/services.config.ts +2 -130
  68. package/config/system/app.config.ts +29 -0
  69. package/config/system/build.config.ts +49 -0
  70. package/config/system/client.config.ts +68 -0
  71. package/config/system/database.config.ts +17 -0
  72. package/config/system/fluxstack.config.ts +114 -0
  73. package/config/{logger.config.ts → system/logger.config.ts} +3 -1
  74. package/config/system/monitoring.config.ts +114 -0
  75. package/config/system/plugins.config.ts +84 -0
  76. package/config/{runtime.config.ts → system/runtime.config.ts} +1 -1
  77. package/config/system/server.config.ts +68 -0
  78. package/config/system/services.config.ts +46 -0
  79. package/config/{system.config.ts → system/system.config.ts} +1 -1
  80. package/core/build/flux-plugins-generator.ts +325 -325
  81. package/core/build/index.ts +39 -27
  82. package/core/build/live-components-generator.ts +3 -3
  83. package/core/build/optimizer.ts +235 -235
  84. package/core/cli/command-registry.ts +6 -4
  85. package/core/cli/commands/build.ts +79 -0
  86. package/core/cli/commands/create.ts +54 -0
  87. package/core/cli/commands/dev.ts +101 -0
  88. package/core/cli/commands/help.ts +34 -0
  89. package/core/cli/commands/index.ts +34 -0
  90. package/core/cli/commands/make-plugin.ts +90 -0
  91. package/core/cli/commands/plugin-add.ts +197 -0
  92. package/core/cli/commands/plugin-deps.ts +2 -2
  93. package/core/cli/commands/plugin-list.ts +208 -0
  94. package/core/cli/commands/plugin-remove.ts +170 -0
  95. package/core/cli/generators/component.ts +769 -769
  96. package/core/cli/generators/controller.ts +1 -1
  97. package/core/cli/generators/index.ts +146 -146
  98. package/core/cli/generators/interactive.ts +227 -227
  99. package/core/cli/generators/plugin.ts +2 -2
  100. package/core/cli/generators/prompts.ts +82 -82
  101. package/core/cli/generators/route.ts +6 -6
  102. package/core/cli/generators/service.ts +2 -2
  103. package/core/cli/generators/template-engine.ts +4 -3
  104. package/core/cli/generators/types.ts +2 -2
  105. package/core/cli/generators/utils.ts +191 -191
  106. package/core/cli/index.ts +115 -686
  107. package/core/cli/plugin-discovery.ts +2 -2
  108. package/core/client/LiveComponentsProvider.tsx +60 -8
  109. package/core/client/api/eden.ts +183 -0
  110. package/core/client/api/index.ts +11 -0
  111. package/core/client/components/Live.tsx +104 -0
  112. package/core/client/fluxstack.ts +1 -9
  113. package/core/client/hooks/AdaptiveChunkSizer.ts +215 -215
  114. package/core/client/hooks/state-validator.ts +1 -1
  115. package/core/client/hooks/useAuth.ts +48 -48
  116. package/core/client/hooks/useChunkedUpload.ts +85 -35
  117. package/core/client/hooks/useLiveChunkedUpload.ts +87 -0
  118. package/core/client/hooks/useLiveComponent.ts +800 -0
  119. package/core/client/hooks/useLiveUpload.ts +71 -0
  120. package/core/client/hooks/useRoom.ts +409 -0
  121. package/core/client/hooks/useRoomProxy.ts +382 -0
  122. package/core/client/index.ts +17 -68
  123. package/core/client/standalone-entry.ts +8 -0
  124. package/core/client/standalone.ts +74 -53
  125. package/core/client/state/createStore.ts +192 -192
  126. package/core/client/state/index.ts +14 -14
  127. package/core/config/index.ts +70 -291
  128. package/core/config/schema.ts +42 -723
  129. package/core/framework/client.ts +131 -131
  130. package/core/framework/index.ts +7 -7
  131. package/core/framework/server.ts +47 -40
  132. package/core/framework/types.ts +2 -2
  133. package/core/index.ts +23 -4
  134. package/core/live/ComponentRegistry.ts +3 -3
  135. package/core/live/types.ts +77 -0
  136. package/core/plugins/built-in/index.ts +134 -134
  137. package/core/plugins/built-in/live-components/commands/create-live-component.ts +242 -1066
  138. package/core/plugins/built-in/live-components/index.ts +1 -1
  139. package/core/plugins/built-in/monitoring/index.ts +111 -47
  140. package/core/plugins/built-in/static/index.ts +1 -1
  141. package/core/plugins/built-in/swagger/index.ts +68 -265
  142. package/core/plugins/built-in/vite/index.ts +85 -185
  143. package/core/plugins/built-in/vite/vite-dev.ts +10 -16
  144. package/core/plugins/config.ts +9 -7
  145. package/core/plugins/dependency-manager.ts +31 -1
  146. package/core/plugins/discovery.ts +19 -7
  147. package/core/plugins/executor.ts +2 -2
  148. package/core/plugins/index.ts +203 -203
  149. package/core/plugins/manager.ts +27 -39
  150. package/core/plugins/module-resolver.ts +19 -8
  151. package/core/plugins/registry.ts +255 -19
  152. package/core/plugins/types.ts +20 -53
  153. package/core/server/framework.ts +66 -43
  154. package/core/server/index.ts +15 -15
  155. package/core/server/live/ComponentRegistry.ts +78 -71
  156. package/core/server/live/FileUploadManager.ts +23 -10
  157. package/core/server/live/LiveComponentPerformanceMonitor.ts +1 -1
  158. package/core/server/live/LiveRoomManager.ts +261 -0
  159. package/core/server/live/RoomEventBus.ts +234 -0
  160. package/core/server/live/RoomStateManager.ts +172 -0
  161. package/core/server/live/StateSignature.ts +643 -643
  162. package/core/server/live/WebSocketConnectionManager.ts +30 -19
  163. package/core/server/live/auto-generated-components.ts +21 -9
  164. package/core/server/live/index.ts +14 -0
  165. package/core/server/live/websocket-plugin.ts +214 -67
  166. package/core/server/middleware/elysia-helpers.ts +7 -2
  167. package/core/server/middleware/errorHandling.ts +1 -1
  168. package/core/server/middleware/index.ts +31 -31
  169. package/core/server/plugins/database.ts +180 -180
  170. package/core/server/plugins/static-files-plugin.ts +69 -69
  171. package/core/server/plugins/swagger.ts +1 -1
  172. package/core/server/rooms/RoomBroadcaster.ts +357 -0
  173. package/core/server/rooms/RoomSystem.ts +463 -0
  174. package/core/server/rooms/index.ts +13 -0
  175. package/core/server/services/BaseService.ts +1 -1
  176. package/core/server/services/ServiceContainer.ts +1 -1
  177. package/core/server/services/index.ts +8 -8
  178. package/core/templates/create-project.ts +12 -12
  179. package/core/testing/index.ts +9 -9
  180. package/core/testing/setup.ts +73 -73
  181. package/core/types/api.ts +168 -168
  182. package/core/types/build.ts +219 -219
  183. package/core/types/config.ts +56 -26
  184. package/core/types/index.ts +4 -4
  185. package/core/types/plugin.ts +107 -107
  186. package/core/types/types.ts +353 -14
  187. package/core/utils/build-logger.ts +324 -324
  188. package/core/utils/config-schema.ts +480 -480
  189. package/core/utils/env.ts +2 -8
  190. package/core/utils/errors/codes.ts +114 -114
  191. package/core/utils/errors/handlers.ts +36 -1
  192. package/core/utils/errors/index.ts +49 -5
  193. package/core/utils/errors/middleware.ts +113 -113
  194. package/core/utils/helpers.ts +6 -16
  195. package/core/utils/index.ts +17 -17
  196. package/core/utils/logger/colors.ts +114 -114
  197. package/core/utils/logger/config.ts +13 -9
  198. package/core/utils/logger/formatter.ts +82 -82
  199. package/core/utils/logger/group-logger.ts +101 -101
  200. package/core/utils/logger/index.ts +6 -1
  201. package/core/utils/logger/stack-trace.ts +3 -1
  202. package/core/utils/logger/startup-banner.ts +82 -82
  203. package/core/utils/logger/winston-logger.ts +152 -152
  204. package/core/utils/monitoring/index.ts +211 -211
  205. package/core/utils/sync-version.ts +66 -66
  206. package/core/utils/version.ts +1 -1
  207. package/create-fluxstack.ts +8 -7
  208. package/package.json +12 -13
  209. package/plugins/crypto-auth/cli/make-protected-route.command.ts +1 -1
  210. package/plugins/crypto-auth/client/CryptoAuthClient.ts +302 -302
  211. package/plugins/crypto-auth/client/components/index.ts +11 -11
  212. package/plugins/crypto-auth/client/index.ts +11 -11
  213. package/plugins/crypto-auth/config/index.ts +1 -1
  214. package/plugins/crypto-auth/index.ts +4 -4
  215. package/plugins/crypto-auth/package.json +65 -65
  216. package/plugins/crypto-auth/server/AuthMiddleware.ts +1 -1
  217. package/plugins/crypto-auth/server/CryptoAuthService.ts +185 -185
  218. package/plugins/crypto-auth/server/index.ts +21 -21
  219. package/plugins/crypto-auth/server/middlewares/cryptoAuthAdmin.ts +3 -3
  220. package/plugins/crypto-auth/server/middlewares/cryptoAuthOptional.ts +1 -1
  221. package/plugins/crypto-auth/server/middlewares/cryptoAuthPermissions.ts +2 -2
  222. package/plugins/crypto-auth/server/middlewares/cryptoAuthRequired.ts +2 -2
  223. package/plugins/crypto-auth/server/middlewares/helpers.ts +1 -1
  224. package/plugins/crypto-auth/server/middlewares/index.ts +22 -22
  225. package/tsconfig.api-strict.json +16 -0
  226. package/tsconfig.json +48 -52
  227. package/{app/client/tsconfig.node.json → tsconfig.node.json} +25 -25
  228. package/types/global.d.ts +29 -29
  229. package/types/vitest.d.ts +8 -8
  230. package/vite.config.ts +38 -62
  231. package/vitest.config.live.ts +10 -9
  232. package/vitest.config.ts +29 -17
  233. package/app/client/README.md +0 -69
  234. package/app/client/SIMPLIFICATION.md +0 -140
  235. package/app/client/frontend-only.ts +0 -12
  236. package/app/client/src/live/FileUploadExample.tsx +0 -359
  237. package/app/client/src/live/MinimalLiveClock.tsx +0 -47
  238. package/app/client/src/live/QuickUploadTest.tsx +0 -193
  239. package/app/client/tsconfig.app.json +0 -45
  240. package/app/client/tsconfig.json +0 -7
  241. package/app/client/zustand-setup.md +0 -65
  242. package/app/server/backend-only.ts +0 -18
  243. package/app/server/live/LiveClockComponent.ts +0 -215
  244. package/app/server/live/LiveFileUploadComponent.ts +0 -77
  245. package/app/server/routes/env-test.ts +0 -110
  246. package/core/client/hooks/index.ts +0 -7
  247. package/core/client/hooks/useHybridLiveComponent.ts +0 -685
  248. package/core/client/hooks/useTypedLiveComponent.ts +0 -133
  249. package/core/client/hooks/useWebSocket.ts +0 -361
  250. package/core/config/env.ts +0 -546
  251. package/core/config/loader.ts +0 -522
  252. package/core/config/runtime-config.ts +0 -327
  253. package/core/config/validator.ts +0 -540
  254. package/core/server/backend-entry.ts +0 -51
  255. package/core/server/standalone.ts +0 -106
  256. package/core/utils/regenerate-files.ts +0 -69
  257. 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 '@/core/utils/env'
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
- // Last resort: eval to bypass static analysis
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
- ...(isDevelopment && { stack: error.stack })
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.stack
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.stack })
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
  }
@@ -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
- export const isProduction = (): boolean => {
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 isDevelopment = (): boolean => {
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 isTest = (): boolean => {
107
- // Lazy import to avoid circular dependency during module initialization
108
- const { appConfig } = require('@/config/app.config')
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
+ }