create-fluxstack 1.0.13 → 1.0.15

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 (214) hide show
  1. package/.env.example +29 -29
  2. package/app/client/README.md +69 -69
  3. package/app/client/index.html +14 -13
  4. package/app/client/src/App.tsx +157 -524
  5. package/app/client/src/components/ErrorBoundary.tsx +107 -0
  6. package/app/client/src/components/ErrorDisplay.css +365 -0
  7. package/app/client/src/components/ErrorDisplay.tsx +258 -0
  8. package/app/client/src/components/FluxStackConfig.tsx +1321 -0
  9. package/app/client/src/components/HybridLiveCounter.tsx +140 -0
  10. package/app/client/src/components/LiveClock.tsx +286 -0
  11. package/app/client/src/components/MainLayout.tsx +390 -0
  12. package/app/client/src/components/SidebarNavigation.tsx +391 -0
  13. package/app/client/src/components/StateDemo.tsx +178 -0
  14. package/app/client/src/components/SystemMonitor.tsx +1038 -0
  15. package/app/client/src/components/Teste.tsx +104 -0
  16. package/app/client/src/components/UserProfile.tsx +809 -0
  17. package/app/client/src/hooks/useAuth.ts +39 -0
  18. package/app/client/src/hooks/useNotifications.ts +56 -0
  19. package/app/client/src/lib/eden-api.ts +189 -53
  20. package/app/client/src/lib/errors.ts +340 -0
  21. package/app/client/src/lib/hooks/useErrorHandler.ts +258 -0
  22. package/app/client/src/lib/index.ts +45 -0
  23. package/app/client/src/main.tsx +3 -2
  24. package/app/client/src/pages/ApiDocs.tsx +182 -0
  25. package/app/client/src/pages/Demo.tsx +174 -0
  26. package/app/client/src/pages/HybridLive.tsx +263 -0
  27. package/app/client/src/pages/Overview.tsx +155 -0
  28. package/app/client/src/store/README.md +43 -0
  29. package/app/client/src/store/index.ts +16 -0
  30. package/app/client/src/store/slices/uiSlice.ts +151 -0
  31. package/app/client/src/store/slices/userSlice.ts +161 -0
  32. package/app/client/src/test/README.md +257 -0
  33. package/app/client/src/test/setup.ts +70 -0
  34. package/app/client/src/test/types.ts +12 -0
  35. package/app/client/src/vite-env.d.ts +1 -1
  36. package/app/client/tsconfig.app.json +44 -43
  37. package/app/client/tsconfig.json +7 -7
  38. package/app/client/tsconfig.node.json +25 -25
  39. package/app/client/zustand-setup.md +65 -0
  40. package/app/server/controllers/users.controller.ts +68 -68
  41. package/app/server/index.ts +9 -1
  42. package/app/server/live/CounterComponent.ts +191 -0
  43. package/app/server/live/FluxStackConfig.ts +529 -0
  44. package/app/server/live/LiveClockComponent.ts +214 -0
  45. package/app/server/live/SidebarNavigation.ts +156 -0
  46. package/app/server/live/SystemMonitor.ts +594 -0
  47. package/app/server/live/SystemMonitorIntegration.ts +151 -0
  48. package/app/server/live/TesteComponent.ts +87 -0
  49. package/app/server/live/UserProfileComponent.ts +135 -0
  50. package/app/server/live/register-components.ts +28 -0
  51. package/app/server/middleware/auth.ts +136 -0
  52. package/app/server/middleware/errorHandling.ts +250 -0
  53. package/app/server/middleware/index.ts +10 -0
  54. package/app/server/middleware/rateLimit.ts +193 -0
  55. package/app/server/middleware/requestLogging.ts +215 -0
  56. package/app/server/middleware/validation.ts +270 -0
  57. package/app/server/routes/index.ts +14 -2
  58. package/app/server/routes/upload.ts +92 -0
  59. package/app/server/routes/users.routes.ts +2 -9
  60. package/app/server/services/NotificationService.ts +302 -0
  61. package/app/server/services/UserService.ts +222 -0
  62. package/app/server/services/index.ts +46 -0
  63. package/core/cli/commands/plugin-deps.ts +263 -0
  64. package/core/cli/generators/README.md +339 -0
  65. package/core/cli/generators/component.ts +770 -0
  66. package/core/cli/generators/controller.ts +299 -0
  67. package/core/cli/generators/index.ts +144 -0
  68. package/core/cli/generators/interactive.ts +228 -0
  69. package/core/cli/generators/prompts.ts +83 -0
  70. package/core/cli/generators/route.ts +513 -0
  71. package/core/cli/generators/service.ts +465 -0
  72. package/core/cli/generators/template-engine.ts +154 -0
  73. package/core/cli/generators/types.ts +71 -0
  74. package/core/cli/generators/utils.ts +192 -0
  75. package/core/cli/index.ts +69 -0
  76. package/core/cli/plugin-discovery.ts +16 -85
  77. package/core/client/fluxstack.ts +17 -0
  78. package/core/client/hooks/index.ts +7 -0
  79. package/core/client/hooks/state-validator.ts +130 -0
  80. package/core/client/hooks/useAuth.ts +49 -0
  81. package/core/client/hooks/useChunkedUpload.ts +258 -0
  82. package/core/client/hooks/useHybridLiveComponent.ts +967 -0
  83. package/core/client/hooks/useWebSocket.ts +373 -0
  84. package/core/client/index.ts +47 -0
  85. package/core/client/state/createStore.ts +193 -0
  86. package/core/client/state/index.ts +15 -0
  87. package/core/config/env-dynamic.ts +1 -1
  88. package/core/config/env.ts +2 -1
  89. package/core/config/runtime-config.ts +3 -3
  90. package/core/config/schema.ts +84 -49
  91. package/core/framework/server.ts +30 -0
  92. package/core/index.ts +25 -0
  93. package/core/live/ComponentRegistry.ts +399 -0
  94. package/core/live/types.ts +164 -0
  95. package/core/plugins/built-in/live-components/commands/create-live-component.ts +1201 -0
  96. package/core/plugins/built-in/live-components/index.ts +27 -0
  97. package/core/plugins/built-in/logger/index.ts +1 -1
  98. package/core/plugins/built-in/monitoring/index.ts +1 -1
  99. package/core/plugins/built-in/static/index.ts +1 -1
  100. package/core/plugins/built-in/swagger/index.ts +1 -1
  101. package/core/plugins/built-in/vite/index.ts +1 -1
  102. package/core/plugins/dependency-manager.ts +384 -0
  103. package/core/plugins/index.ts +5 -1
  104. package/core/plugins/manager.ts +7 -3
  105. package/core/plugins/registry.ts +88 -10
  106. package/core/plugins/types.ts +11 -11
  107. package/core/server/framework.ts +43 -0
  108. package/core/server/index.ts +11 -1
  109. package/core/server/live/ComponentRegistry.ts +1017 -0
  110. package/core/server/live/FileUploadManager.ts +272 -0
  111. package/core/server/live/LiveComponentPerformanceMonitor.ts +930 -0
  112. package/core/server/live/SingleConnectionManager.ts +0 -0
  113. package/core/server/live/StateSignature.ts +644 -0
  114. package/core/server/live/WebSocketConnectionManager.ts +688 -0
  115. package/core/server/live/websocket-plugin.ts +435 -0
  116. package/core/server/middleware/errorHandling.ts +141 -0
  117. package/core/server/middleware/index.ts +16 -0
  118. package/core/server/plugins/static-files-plugin.ts +232 -0
  119. package/core/server/services/BaseService.ts +95 -0
  120. package/core/server/services/ServiceContainer.ts +144 -0
  121. package/core/server/services/index.ts +9 -0
  122. package/core/templates/create-project.ts +196 -33
  123. package/core/testing/index.ts +10 -0
  124. package/core/testing/setup.ts +74 -0
  125. package/core/types/build.ts +38 -14
  126. package/core/types/types.ts +319 -0
  127. package/core/utils/env-runtime.ts +7 -0
  128. package/core/utils/errors/handlers.ts +264 -39
  129. package/core/utils/errors/index.ts +528 -18
  130. package/core/utils/errors/middleware.ts +114 -0
  131. package/core/utils/logger/formatters.ts +222 -0
  132. package/core/utils/logger/index.ts +167 -48
  133. package/core/utils/logger/middleware.ts +253 -0
  134. package/core/utils/logger/performance.ts +384 -0
  135. package/core/utils/logger/transports.ts +365 -0
  136. package/create-fluxstack.ts +296 -296
  137. package/fluxstack.config.ts +17 -1
  138. package/package-template.json +66 -66
  139. package/package.json +31 -6
  140. package/public/README.md +16 -0
  141. package/vite.config.ts +29 -14
  142. package/.claude/settings.local.json +0 -74
  143. package/.github/workflows/ci-build-tests.yml +0 -480
  144. package/.github/workflows/dependency-management.yml +0 -324
  145. package/.github/workflows/release-validation.yml +0 -355
  146. package/.kiro/specs/fluxstack-architecture-optimization/design.md +0 -700
  147. package/.kiro/specs/fluxstack-architecture-optimization/requirements.md +0 -127
  148. package/.kiro/specs/fluxstack-architecture-optimization/tasks.md +0 -330
  149. package/CLAUDE.md +0 -200
  150. package/Dockerfile +0 -58
  151. package/Dockerfile.backend +0 -52
  152. package/Dockerfile.frontend +0 -54
  153. package/README-Docker.md +0 -85
  154. package/ai-context/00-QUICK-START.md +0 -86
  155. package/ai-context/README.md +0 -88
  156. package/ai-context/development/eden-treaty-guide.md +0 -362
  157. package/ai-context/development/patterns.md +0 -382
  158. package/ai-context/development/plugins-guide.md +0 -572
  159. package/ai-context/examples/crud-complete.md +0 -626
  160. package/ai-context/project/architecture.md +0 -399
  161. package/ai-context/project/overview.md +0 -213
  162. package/ai-context/recent-changes/eden-treaty-refactor.md +0 -281
  163. package/ai-context/recent-changes/type-inference-fix.md +0 -223
  164. package/ai-context/reference/environment-vars.md +0 -384
  165. package/ai-context/reference/troubleshooting.md +0 -407
  166. package/app/client/src/components/TestPage.tsx +0 -453
  167. package/bun.lock +0 -1063
  168. package/bunfig.toml +0 -16
  169. package/core/__tests__/integration.test.ts +0 -227
  170. package/core/build/index.ts +0 -186
  171. package/core/config/__tests__/config-loader.test.ts +0 -554
  172. package/core/config/__tests__/config-merger.test.ts +0 -657
  173. package/core/config/__tests__/env-converter.test.ts +0 -372
  174. package/core/config/__tests__/env-processor.test.ts +0 -431
  175. package/core/config/__tests__/env.test.ts +0 -452
  176. package/core/config/__tests__/integration.test.ts +0 -418
  177. package/core/config/__tests__/loader.test.ts +0 -331
  178. package/core/config/__tests__/schema.test.ts +0 -129
  179. package/core/config/__tests__/validator.test.ts +0 -318
  180. package/core/framework/__tests__/server.test.ts +0 -233
  181. package/core/plugins/__tests__/built-in.test.ts.disabled +0 -366
  182. package/core/plugins/__tests__/manager.test.ts +0 -398
  183. package/core/plugins/__tests__/monitoring.test.ts +0 -401
  184. package/core/plugins/__tests__/registry.test.ts +0 -335
  185. package/core/utils/__tests__/errors.test.ts +0 -139
  186. package/core/utils/__tests__/helpers.test.ts +0 -297
  187. package/core/utils/__tests__/logger.test.ts +0 -141
  188. package/create-test-app.ts +0 -156
  189. package/docker-compose.microservices.yml +0 -75
  190. package/docker-compose.simple.yml +0 -57
  191. package/docker-compose.yml +0 -71
  192. package/eslint.config.js +0 -23
  193. package/flux-cli.ts +0 -214
  194. package/nginx-lb.conf +0 -37
  195. package/publish.sh +0 -63
  196. package/run-clean.ts +0 -26
  197. package/run-env-tests.ts +0 -313
  198. package/tailwind.config.js +0 -34
  199. package/tests/__mocks__/api.ts +0 -56
  200. package/tests/fixtures/users.ts +0 -69
  201. package/tests/integration/api/users.routes.test.ts +0 -221
  202. package/tests/setup.ts +0 -29
  203. package/tests/unit/app/client/App-simple.test.tsx +0 -56
  204. package/tests/unit/app/client/App.test.tsx.skip +0 -237
  205. package/tests/unit/app/client/eden-api.test.ts +0 -186
  206. package/tests/unit/app/client/simple.test.tsx +0 -23
  207. package/tests/unit/app/controllers/users.controller.test.ts +0 -150
  208. package/tests/unit/core/create-project.test.ts.skip +0 -95
  209. package/tests/unit/core/framework.test.ts +0 -144
  210. package/tests/unit/core/plugins/logger.test.ts.skip +0 -268
  211. package/tests/unit/core/plugins/vite.test.ts.disabled +0 -188
  212. package/tests/utils/test-helpers.ts +0 -61
  213. package/vitest.config.ts +0 -50
  214. package/workspace.json +0 -6
@@ -0,0 +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))
114
+ }
@@ -0,0 +1,222 @@
1
+ /**
2
+ * FluxStack Logger Formatters
3
+ * Different formatting strategies for log output
4
+ */
5
+
6
+ import type { LogEntry, LogLevel } from './transports'
7
+
8
+ export interface LogFormatter {
9
+ format(entry: LogEntry): string
10
+ }
11
+
12
+ /**
13
+ * Pretty formatter for development with colors and readable layout
14
+ */
15
+ export class PrettyFormatter implements LogFormatter {
16
+ private colors: boolean
17
+ private timestamp: boolean
18
+
19
+ private colorMap = {
20
+ debug: '\x1b[36m', // cyan
21
+ info: '\x1b[32m', // green
22
+ warn: '\x1b[33m', // yellow
23
+ error: '\x1b[31m', // red
24
+ reset: '\x1b[0m',
25
+ gray: '\x1b[90m'
26
+ }
27
+
28
+ constructor(options: { colors?: boolean; timestamp?: boolean } = {}) {
29
+ this.colors = options.colors !== false
30
+ this.timestamp = options.timestamp !== false
31
+ }
32
+
33
+ format(entry: LogEntry): string {
34
+ const { timestamp, level, message, meta, context } = entry
35
+
36
+ let formatted = ''
37
+
38
+ // Add timestamp
39
+ if (this.timestamp) {
40
+ const color = this.colors ? this.colorMap.gray : ''
41
+ const reset = this.colors ? this.colorMap.reset : ''
42
+ formatted += `${color}[${timestamp}]${reset} `
43
+ }
44
+
45
+ // Add level with color and icon
46
+ const levelColor = this.colors ? this.colorMap[level] : ''
47
+ const reset = this.colors ? this.colorMap.reset : ''
48
+ const levelIcon = this.getLevelIcon(level)
49
+ const levelStr = level.toUpperCase().padEnd(5)
50
+ formatted += `${levelColor}${levelIcon} ${levelStr}${reset} `
51
+
52
+ // Add context if available
53
+ if (context && Object.keys(context).length > 0) {
54
+ const contextStr = Object.entries(context)
55
+ .map(([key, value]) => `${key}=${value}`)
56
+ .join(' ')
57
+ const contextColor = this.colors ? this.colorMap.gray : ''
58
+ formatted += `${contextColor}[${contextStr}]${reset} `
59
+ }
60
+
61
+ // Add message
62
+ formatted += message
63
+
64
+ // Add meta if available
65
+ if (meta && typeof meta === 'object') {
66
+ const metaColor = this.colors ? this.colorMap.gray : ''
67
+ const metaStr = this.formatMeta(meta)
68
+ formatted += ` ${metaColor}${metaStr}${reset}`
69
+ } else if (meta !== undefined) {
70
+ formatted += ` ${meta}`
71
+ }
72
+
73
+ return formatted
74
+ }
75
+
76
+ private getLevelIcon(level: LogLevel): string {
77
+ switch (level) {
78
+ case 'debug': return '🔍'
79
+ case 'info': return 'ℹ️ '
80
+ case 'warn': return '⚠️ '
81
+ case 'error': return '❌'
82
+ default: return ' '
83
+ }
84
+ }
85
+
86
+ private formatMeta(meta: any): string {
87
+ if (typeof meta === 'object' && meta !== null) {
88
+ // Pretty print objects with indentation
89
+ return JSON.stringify(meta, null, 2)
90
+ .split('\n')
91
+ .map((line, index) => index === 0 ? line : ` ${line}`)
92
+ .join('\n')
93
+ }
94
+ return String(meta)
95
+ }
96
+ }
97
+
98
+ /**
99
+ * JSON formatter for production with structured output
100
+ */
101
+ export class JSONFormatter implements LogFormatter {
102
+ private pretty: boolean
103
+
104
+ constructor(options: { pretty?: boolean } = {}) {
105
+ this.pretty = options.pretty || false
106
+ }
107
+
108
+ format(entry: LogEntry): string {
109
+ const jsonEntry = {
110
+ '@timestamp': entry.timestamp,
111
+ level: entry.level,
112
+ message: entry.message,
113
+ ...(entry.context && { context: entry.context }),
114
+ ...(entry.meta && { meta: entry.meta })
115
+ }
116
+
117
+ return this.pretty
118
+ ? JSON.stringify(jsonEntry, null, 2)
119
+ : JSON.stringify(jsonEntry)
120
+ }
121
+ }
122
+
123
+ /**
124
+ * Simple formatter for basic text output
125
+ */
126
+ export class SimpleFormatter implements LogFormatter {
127
+ private timestamp: boolean
128
+
129
+ constructor(options: { timestamp?: boolean } = {}) {
130
+ this.timestamp = options.timestamp !== false
131
+ }
132
+
133
+ format(entry: LogEntry): string {
134
+ const { timestamp, level, message, meta, context } = entry
135
+
136
+ let formatted = ''
137
+
138
+ // Add timestamp
139
+ if (this.timestamp) {
140
+ formatted += `[${timestamp}] `
141
+ }
142
+
143
+ // Add level
144
+ formatted += `${level.toUpperCase().padEnd(5)} `
145
+
146
+ // Add context if available
147
+ if (context && Object.keys(context).length > 0) {
148
+ const contextStr = Object.entries(context)
149
+ .map(([key, value]) => `${key}=${value}`)
150
+ .join(' ')
151
+ formatted += `[${contextStr}] `
152
+ }
153
+
154
+ // Add message
155
+ formatted += message
156
+
157
+ // Add meta if available
158
+ if (meta && typeof meta === 'object') {
159
+ formatted += ` ${JSON.stringify(meta)}`
160
+ } else if (meta !== undefined) {
161
+ formatted += ` ${meta}`
162
+ }
163
+
164
+ return formatted
165
+ }
166
+ }
167
+
168
+ /**
169
+ * Syslog formatter for system logging
170
+ */
171
+ export class SyslogFormatter implements LogFormatter {
172
+ private facility: number
173
+ private hostname: string
174
+
175
+ constructor(options: { facility?: number; hostname?: string } = {}) {
176
+ this.facility = options.facility || 16 // local0
177
+ this.hostname = options.hostname || require('os').hostname()
178
+ }
179
+
180
+ format(entry: LogEntry): string {
181
+ const { timestamp, level, message, meta, context } = entry
182
+
183
+ // Calculate priority (facility * 8 + severity)
184
+ const severity = this.getLevelSeverity(level)
185
+ const priority = this.facility * 8 + severity
186
+
187
+ // Format timestamp in RFC3339
188
+ const syslogTime = new Date(timestamp).toISOString()
189
+
190
+ // Build syslog message
191
+ let syslogMessage = `<${priority}>${syslogTime} ${this.hostname} fluxstack: `
192
+
193
+ // Add context if available
194
+ if (context && Object.keys(context).length > 0) {
195
+ const contextStr = Object.entries(context)
196
+ .map(([key, value]) => `${key}=${value}`)
197
+ .join(' ')
198
+ syslogMessage += `[${contextStr}] `
199
+ }
200
+
201
+ syslogMessage += message
202
+
203
+ // Add meta if available
204
+ if (meta && typeof meta === 'object') {
205
+ syslogMessage += ` ${JSON.stringify(meta)}`
206
+ } else if (meta !== undefined) {
207
+ syslogMessage += ` ${meta}`
208
+ }
209
+
210
+ return syslogMessage
211
+ }
212
+
213
+ private getLevelSeverity(level: LogLevel): number {
214
+ switch (level) {
215
+ case 'debug': return 7 // debug
216
+ case 'info': return 6 // info
217
+ case 'warn': return 4 // warning
218
+ case 'error': return 3 // error
219
+ default: return 6
220
+ }
221
+ }
222
+ }
@@ -1,11 +1,15 @@
1
1
  /**
2
2
  * FluxStack Logger
3
- * Environment-aware logging system
3
+ * Enhanced logging system with multiple transports and formatters
4
4
  */
5
5
 
6
- // Environment info is handled via process.env directly
6
+ import { ConsoleTransport, FileTransport, JSONTransport } from './transports'
7
+ import { PrettyFormatter, JSONFormatter, SimpleFormatter } from './formatters'
8
+ import type { LogTransport, LogEntry, LogLevel } from './transports'
9
+ import type { LogFormatter } from './formatters'
7
10
 
8
- type LogLevel = 'debug' | 'info' | 'warn' | 'error'
11
+ export type { LogLevel, LogTransport, LogEntry } from './transports'
12
+ export type { LogFormatter } from './formatters'
9
13
 
10
14
  export interface Logger {
11
15
  debug(message: string, meta?: any): void
@@ -22,6 +26,19 @@ export interface Logger {
22
26
 
23
27
  // Request logging
24
28
  request(method: string, path: string, status?: number, duration?: number): void
29
+
30
+ // Transport management
31
+ addTransport(transport: LogTransport): void
32
+ removeTransport(name: string): void
33
+
34
+ // Cleanup
35
+ close(): Promise<void>
36
+ }
37
+
38
+ export interface LoggerConfig {
39
+ level?: LogLevel
40
+ transports?: LogTransport[]
41
+ defaultMeta?: any
25
42
  }
26
43
 
27
44
  class FluxStackLogger implements Logger {
@@ -29,20 +46,59 @@ class FluxStackLogger implements Logger {
29
46
  private logLevel: LogLevel
30
47
  private context: any = {}
31
48
  private timers: Map<string, number> = new Map()
49
+ private transports: Map<string, LogTransport> = new Map()
50
+ private defaultMeta: any = {}
32
51
 
33
- private constructor(context?: any) {
34
- // Default to 'info' level, can be overridden by config
35
- this.logLevel = (process.env.LOG_LEVEL as LogLevel) || 'info'
36
- this.context = context || {}
52
+ constructor(config?: LoggerConfig) {
53
+ this.logLevel = config?.level || (process.env.LOG_LEVEL as LogLevel) || 'info'
54
+ this.context = {}
55
+ this.defaultMeta = config?.defaultMeta || {}
56
+
57
+ // Setup default transports if none provided
58
+ if (config?.transports) {
59
+ config.transports.forEach(transport => {
60
+ this.transports.set(transport.name, transport)
61
+ })
62
+ } else {
63
+ this.setupDefaultTransports()
64
+ }
37
65
  }
38
66
 
39
- static getInstance(): FluxStackLogger {
67
+ static getInstance(config?: LoggerConfig): FluxStackLogger {
40
68
  if (FluxStackLogger.instance === null) {
41
- FluxStackLogger.instance = new FluxStackLogger()
69
+ FluxStackLogger.instance = new FluxStackLogger(config)
42
70
  }
43
71
  return FluxStackLogger.instance
44
72
  }
45
73
 
74
+ private setupDefaultTransports(): void {
75
+ const isDevelopment = process.env.NODE_ENV !== 'production'
76
+
77
+ if (isDevelopment) {
78
+ // Development: Pretty console output
79
+ this.transports.set('console', new ConsoleTransport({
80
+ level: this.logLevel,
81
+ colors: true,
82
+ timestamp: true
83
+ }))
84
+ } else {
85
+ // Production: JSON output for structured logging
86
+ this.transports.set('json', new JSONTransport({
87
+ level: this.logLevel,
88
+ pretty: false
89
+ }))
90
+
91
+ // Also add file transport for production
92
+ this.transports.set('file', new FileTransport({
93
+ level: this.logLevel,
94
+ filename: 'logs/fluxstack.log',
95
+ maxSize: 10 * 1024 * 1024, // 10MB
96
+ maxFiles: 5,
97
+ compress: true
98
+ }))
99
+ }
100
+ }
101
+
46
102
  private shouldLog(level: LogLevel): boolean {
47
103
  const levels: Record<LogLevel, number> = {
48
104
  debug: 0,
@@ -54,58 +110,63 @@ class FluxStackLogger implements Logger {
54
110
  return levels[level] >= levels[this.logLevel]
55
111
  }
56
112
 
57
- private formatMessage(level: LogLevel, message: string, meta?: any): string {
58
- const timestamp = new Date().toISOString()
59
- const levelStr = level.toUpperCase().padEnd(5)
60
-
61
- let formatted = `[${timestamp}] ${levelStr}`
62
-
63
- // Add context if available
64
- if (Object.keys(this.context).length > 0) {
65
- const contextStr = Object.entries(this.context)
66
- .map(([key, value]) => `${key}=${value}`)
67
- .join(' ')
68
- formatted += ` [${contextStr}]`
69
- }
70
-
71
- formatted += ` ${message}`
72
-
73
- if (meta && typeof meta === 'object') {
74
- formatted += ` ${JSON.stringify(meta)}`
75
- } else if (meta !== undefined) {
76
- formatted += ` ${meta}`
113
+ private async writeToTransports(level: LogLevel, message: string, meta?: any): Promise<void> {
114
+ if (!this.shouldLog(level)) return
115
+
116
+ const entry: LogEntry = {
117
+ timestamp: new Date().toISOString(),
118
+ level,
119
+ message,
120
+ meta: { ...this.defaultMeta, ...meta },
121
+ context: Object.keys(this.context).length > 0 ? this.context : undefined
77
122
  }
78
-
79
- return formatted
123
+
124
+ // Write to all transports
125
+ const writePromises = Array.from(this.transports.values()).map(async transport => {
126
+ try {
127
+ await transport.write(entry)
128
+ } catch (error) {
129
+ // Fallback to console if transport fails
130
+ console.error(`Transport ${transport.name} failed:`, error)
131
+ }
132
+ })
133
+
134
+ await Promise.all(writePromises)
80
135
  }
81
136
 
82
137
  debug(message: string, meta?: any): void {
83
- if (this.shouldLog('debug')) {
84
- console.debug(this.formatMessage('debug', message, meta))
85
- }
138
+ this.writeToTransports('debug', message, meta).catch(err => {
139
+ console.error('Logger error:', err)
140
+ })
86
141
  }
87
142
 
88
143
  info(message: string, meta?: any): void {
89
- if (this.shouldLog('info')) {
90
- console.info(this.formatMessage('info', message, meta))
91
- }
144
+ this.writeToTransports('info', message, meta).catch(err => {
145
+ console.error('Logger error:', err)
146
+ })
92
147
  }
93
148
 
94
149
  warn(message: string, meta?: any): void {
95
- if (this.shouldLog('warn')) {
96
- console.warn(this.formatMessage('warn', message, meta))
97
- }
150
+ this.writeToTransports('warn', message, meta).catch(err => {
151
+ console.error('Logger error:', err)
152
+ })
98
153
  }
99
154
 
100
155
  error(message: string, meta?: any): void {
101
- if (this.shouldLog('error')) {
102
- console.error(this.formatMessage('error', message, meta))
103
- }
156
+ this.writeToTransports('error', message, meta).catch(err => {
157
+ console.error('Logger error:', err)
158
+ })
104
159
  }
105
160
 
106
161
  // Contextual logging
107
162
  child(context: any): FluxStackLogger {
108
- return new FluxStackLogger({ ...this.context, ...context })
163
+ const childLogger = new FluxStackLogger({
164
+ level: this.logLevel,
165
+ transports: Array.from(this.transports.values()),
166
+ defaultMeta: this.defaultMeta
167
+ })
168
+ childLogger.context = { ...this.context, ...context }
169
+ return childLogger
109
170
  }
110
171
 
111
172
  // Performance logging
@@ -124,22 +185,72 @@ class FluxStackLogger implements Logger {
124
185
 
125
186
  // HTTP request logging
126
187
  request(method: string, path: string, status?: number, duration?: number): void {
188
+ const meta: any = { method, path }
189
+ if (status) meta.status = status
190
+ if (duration) meta.duration = duration
191
+
127
192
  const statusStr = status ? ` ${status}` : ''
128
193
  const durationStr = duration ? ` (${duration}ms)` : ''
129
- this.info(`${method} ${path}${statusStr}${durationStr}`)
194
+ this.info(`${method} ${path}${statusStr}${durationStr}`, meta)
195
+ }
196
+
197
+ // Transport management
198
+ addTransport(transport: LogTransport): void {
199
+ this.transports.set(transport.name, transport)
200
+ }
201
+
202
+ removeTransport(name: string): void {
203
+ const transport = this.transports.get(name)
204
+ if (transport && transport.close) {
205
+ const closeResult = transport.close()
206
+ if (closeResult instanceof Promise) {
207
+ closeResult.catch(console.error)
208
+ }
209
+ }
210
+ this.transports.delete(name)
211
+ }
212
+
213
+ // Cleanup
214
+ async close(): Promise<void> {
215
+ const closePromises = Array.from(this.transports.values())
216
+ .filter(transport => transport.close)
217
+ .map(transport => transport.close!())
218
+
219
+ await Promise.all(closePromises)
220
+ this.transports.clear()
130
221
  }
131
222
 
132
223
  // Plugin logging
133
224
  plugin(pluginName: string, message: string, meta?: any): void {
134
- this.debug(`[${pluginName}] ${message}`, meta)
225
+ this.debug(`[${pluginName}] ${message}`, { plugin: pluginName, ...meta })
135
226
  }
136
227
 
137
228
  // Framework logging
138
229
  framework(message: string, meta?: any): void {
139
- this.info(`[FluxStack] ${message}`, meta)
230
+ this.info(`[FluxStack] ${message}`, { component: 'framework', ...meta })
140
231
  }
141
232
  }
142
233
 
234
+ // Export transport and formatter classes
235
+ export { ConsoleTransport, FileTransport, JSONTransport } from './transports'
236
+ export { PrettyFormatter, JSONFormatter, SimpleFormatter } from './formatters'
237
+
238
+ // Export performance utilities
239
+ export {
240
+ RequestLogger,
241
+ PerformanceLogger,
242
+ createRequestLoggingMiddleware
243
+ } from './performance'
244
+ export type { RequestContext, PerformanceTimer } from './performance'
245
+
246
+ // Export middleware utilities
247
+ export {
248
+ createElysiaLoggerMiddleware,
249
+ createDatabaseLoggerMiddleware,
250
+ createPluginLoggerMiddleware,
251
+ createBuildLoggerMiddleware
252
+ } from './middleware'
253
+
143
254
  // Export singleton instance
144
255
  export const logger = FluxStackLogger.getInstance()
145
256
 
@@ -157,5 +268,13 @@ export const log = {
157
268
  logger.framework(message, meta),
158
269
  child: (context: any) => logger.child(context),
159
270
  time: (label: string) => logger.time(label),
160
- timeEnd: (label: string) => logger.timeEnd(label)
271
+ timeEnd: (label: string) => logger.timeEnd(label),
272
+ addTransport: (transport: LogTransport) => logger.addTransport(transport),
273
+ removeTransport: (name: string) => logger.removeTransport(name),
274
+ close: () => logger.close()
275
+ }
276
+
277
+ // Factory function for creating configured loggers
278
+ export function createLogger(config: LoggerConfig): Logger {
279
+ return new FluxStackLogger(config)
161
280
  }