create-fluxstack 1.1.0 → 1.4.1

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 (64) hide show
  1. package/app/server/backend-only.ts +5 -5
  2. package/app/server/index.ts +63 -54
  3. package/app/server/live/FluxStackConfig.ts +43 -39
  4. package/app/server/live/SystemMonitorIntegration.ts +2 -2
  5. package/app/server/live/register-components.ts +1 -1
  6. package/app/server/middleware/errorHandling.ts +6 -4
  7. package/app/server/routes/config.ts +145 -0
  8. package/app/server/routes/index.ts +5 -3
  9. package/config/app.config.ts +113 -0
  10. package/config/build.config.ts +24 -0
  11. package/config/database.config.ts +99 -0
  12. package/config/index.ts +68 -0
  13. package/config/logger.config.ts +27 -0
  14. package/config/runtime.config.ts +92 -0
  15. package/config/server.config.ts +46 -0
  16. package/config/services.config.ts +130 -0
  17. package/config/system.config.ts +105 -0
  18. package/core/build/index.ts +10 -4
  19. package/core/cli/generators/index.ts +5 -2
  20. package/core/cli/generators/plugin.ts +290 -0
  21. package/core/cli/index.ts +117 -15
  22. package/core/config/env.ts +37 -95
  23. package/core/config/runtime-config.ts +61 -58
  24. package/core/config/schema.ts +4 -0
  25. package/core/framework/server.ts +22 -10
  26. package/core/plugins/built-in/index.ts +7 -17
  27. package/core/plugins/built-in/swagger/index.ts +228 -228
  28. package/core/plugins/built-in/vite/index.ts +374 -358
  29. package/core/plugins/dependency-manager.ts +5 -5
  30. package/core/plugins/manager.ts +12 -12
  31. package/core/plugins/registry.ts +3 -3
  32. package/core/server/index.ts +0 -1
  33. package/core/server/live/ComponentRegistry.ts +34 -8
  34. package/core/server/live/LiveComponentPerformanceMonitor.ts +1 -1
  35. package/core/server/live/websocket-plugin.ts +434 -434
  36. package/core/server/middleware/README.md +488 -0
  37. package/core/server/middleware/elysia-helpers.ts +227 -0
  38. package/core/server/middleware/index.ts +25 -9
  39. package/core/server/plugins/static-files-plugin.ts +231 -231
  40. package/core/utils/config-schema.ts +484 -0
  41. package/core/utils/env.ts +306 -0
  42. package/core/utils/helpers.ts +4 -4
  43. package/core/utils/logger/colors.ts +114 -0
  44. package/core/utils/logger/config.ts +35 -0
  45. package/core/utils/logger/formatter.ts +82 -0
  46. package/core/utils/logger/group-logger.ts +101 -0
  47. package/core/utils/logger/index.ts +199 -250
  48. package/core/utils/logger/stack-trace.ts +92 -0
  49. package/core/utils/logger/startup-banner.ts +92 -0
  50. package/core/utils/logger/winston-logger.ts +152 -0
  51. package/core/utils/version.ts +5 -0
  52. package/create-fluxstack.ts +118 -8
  53. package/fluxstack.config.ts +2 -2
  54. package/package.json +117 -115
  55. package/core/config/env-dynamic.ts +0 -326
  56. package/core/plugins/built-in/logger/index.ts +0 -180
  57. package/core/server/plugins/logger.ts +0 -47
  58. package/core/utils/env-runtime-v2.ts +0 -232
  59. package/core/utils/env-runtime.ts +0 -259
  60. package/core/utils/logger/formatters.ts +0 -222
  61. package/core/utils/logger/middleware.ts +0 -253
  62. package/core/utils/logger/performance.ts +0 -384
  63. package/core/utils/logger/transports.ts +0 -365
  64. package/core/utils/logger.ts +0 -106
@@ -1,365 +0,0 @@
1
- /**
2
- * FluxStack Logger Transports
3
- * Multiple transport implementations for different logging needs
4
- */
5
-
6
- import { writeFile, mkdir, stat, readdir, unlink } from 'fs/promises'
7
- import { join, dirname } from 'path'
8
- import { createGzip } from 'zlib'
9
- import { pipeline } from 'stream/promises'
10
- import { createReadStream, createWriteStream } from 'fs'
11
-
12
- export type LogLevel = 'debug' | 'info' | 'warn' | 'error'
13
-
14
- export interface LogEntry {
15
- timestamp: string
16
- level: LogLevel
17
- message: string
18
- meta?: any
19
- context?: any
20
- }
21
-
22
- export interface LogTransport {
23
- name: string
24
- level: LogLevel
25
- write(entry: LogEntry): Promise<void> | void
26
- close?(): Promise<void> | void
27
- }
28
-
29
- export interface ConsoleTransportConfig {
30
- level?: LogLevel
31
- colors?: boolean
32
- timestamp?: boolean
33
- }
34
-
35
- export interface FileTransportConfig {
36
- level?: LogLevel
37
- filename: string
38
- maxSize?: number // in bytes
39
- maxFiles?: number
40
- compress?: boolean
41
- }
42
-
43
- export interface JSONTransportConfig {
44
- level?: LogLevel
45
- filename?: string
46
- pretty?: boolean
47
- }
48
-
49
- /**
50
- * Console Transport with colored output for development
51
- */
52
- export class ConsoleTransport implements LogTransport {
53
- name = 'console'
54
- level: LogLevel
55
- private colors: boolean
56
- private timestamp: boolean
57
-
58
- private colorMap = {
59
- debug: '\x1b[36m', // cyan
60
- info: '\x1b[32m', // green
61
- warn: '\x1b[33m', // yellow
62
- error: '\x1b[31m', // red
63
- reset: '\x1b[0m'
64
- }
65
-
66
- constructor(config: ConsoleTransportConfig = {}) {
67
- this.level = config.level || 'info'
68
- this.colors = config.colors !== false
69
- this.timestamp = config.timestamp !== false
70
- }
71
-
72
- private shouldLog(level: LogLevel): boolean {
73
- const levels: Record<LogLevel, number> = {
74
- debug: 0,
75
- info: 1,
76
- warn: 2,
77
- error: 3
78
- }
79
- return levels[level] >= levels[this.level]
80
- }
81
-
82
- private formatMessage(entry: LogEntry): string {
83
- const { timestamp, level, message, meta, context } = entry
84
-
85
- let formatted = ''
86
-
87
- // Add timestamp
88
- if (this.timestamp) {
89
- const color = this.colors ? '\x1b[90m' : '' // gray
90
- const reset = this.colors ? this.colorMap.reset : ''
91
- formatted += `${color}[${timestamp}]${reset} `
92
- }
93
-
94
- // Add level with color
95
- const levelColor = this.colors ? this.colorMap[level] : ''
96
- const reset = this.colors ? this.colorMap.reset : ''
97
- const levelStr = level.toUpperCase().padEnd(5)
98
- formatted += `${levelColor}${levelStr}${reset} `
99
-
100
- // Add context if available
101
- if (context && Object.keys(context).length > 0) {
102
- const contextStr = Object.entries(context)
103
- .map(([key, value]) => `${key}=${value}`)
104
- .join(' ')
105
- const contextColor = this.colors ? '\x1b[90m' : '' // gray
106
- formatted += `${contextColor}[${contextStr}]${reset} `
107
- }
108
-
109
- // Add message
110
- formatted += message
111
-
112
- // Add meta if available
113
- if (meta && typeof meta === 'object') {
114
- const metaColor = this.colors ? '\x1b[90m' : '' // gray
115
- formatted += ` ${metaColor}${JSON.stringify(meta)}${reset}`
116
- } else if (meta !== undefined) {
117
- formatted += ` ${meta}`
118
- }
119
-
120
- return formatted
121
- }
122
-
123
- write(entry: LogEntry): void {
124
- if (!this.shouldLog(entry.level)) return
125
-
126
- const formatted = this.formatMessage(entry)
127
-
128
- // Use appropriate console method
129
- switch (entry.level) {
130
- case 'debug':
131
- console.debug(formatted)
132
- break
133
- case 'info':
134
- console.info(formatted)
135
- break
136
- case 'warn':
137
- console.warn(formatted)
138
- break
139
- case 'error':
140
- console.error(formatted)
141
- break
142
- }
143
- }
144
- }
145
-
146
- /**
147
- * File Transport with rotation and compression
148
- */
149
- export class FileTransport implements LogTransport {
150
- name = 'file'
151
- level: LogLevel
152
- private filename: string
153
- private maxSize: number
154
- private maxFiles: number
155
- private compress: boolean
156
- private currentSize = 0
157
-
158
- constructor(config: FileTransportConfig) {
159
- this.level = config.level || 'info'
160
- this.filename = config.filename
161
- this.maxSize = config.maxSize || 10 * 1024 * 1024 // 10MB default
162
- this.maxFiles = config.maxFiles || 5
163
- this.compress = config.compress !== false
164
-
165
- this.ensureDirectory()
166
- this.getCurrentSize()
167
- }
168
-
169
- private async ensureDirectory(): Promise<void> {
170
- const dir = dirname(this.filename)
171
- try {
172
- await mkdir(dir, { recursive: true })
173
- } catch (error) {
174
- // Directory might already exist
175
- }
176
- }
177
-
178
- private async getCurrentSize(): Promise<void> {
179
- try {
180
- const stats = await stat(this.filename)
181
- this.currentSize = stats.size
182
- } catch (error) {
183
- this.currentSize = 0
184
- }
185
- }
186
-
187
- private shouldLog(level: LogLevel): boolean {
188
- const levels: Record<LogLevel, number> = {
189
- debug: 0,
190
- info: 1,
191
- warn: 2,
192
- error: 3
193
- }
194
- return levels[level] >= levels[this.level]
195
- }
196
-
197
- private formatMessage(entry: LogEntry): string {
198
- const { timestamp, level, message, meta, context } = entry
199
-
200
- let formatted = `[${timestamp}] ${level.toUpperCase().padEnd(5)}`
201
-
202
- // Add context if available
203
- if (context && Object.keys(context).length > 0) {
204
- const contextStr = Object.entries(context)
205
- .map(([key, value]) => `${key}=${value}`)
206
- .join(' ')
207
- formatted += ` [${contextStr}]`
208
- }
209
-
210
- formatted += ` ${message}`
211
-
212
- // Add meta if available
213
- if (meta && typeof meta === 'object') {
214
- formatted += ` ${JSON.stringify(meta)}`
215
- } else if (meta !== undefined) {
216
- formatted += ` ${meta}`
217
- }
218
-
219
- return formatted + '\n'
220
- }
221
-
222
- private async rotateFile(): Promise<void> {
223
- // Rotate existing files
224
- for (let i = this.maxFiles - 1; i >= 1; i--) {
225
- const oldFile = `${this.filename}.${i}`
226
- const newFile = `${this.filename}.${i + 1}`
227
-
228
- try {
229
- await stat(oldFile)
230
- if (i === this.maxFiles - 1) {
231
- // Delete the oldest file
232
- await unlink(oldFile)
233
- } else {
234
- // Rename to next number
235
- const { rename } = await import('fs/promises')
236
- await rename(oldFile, newFile)
237
- }
238
- } catch (error) {
239
- // File doesn't exist, continue
240
- }
241
- }
242
-
243
- // Move current file to .1
244
- try {
245
- await stat(this.filename)
246
- const rotatedFile = `${this.filename}.1`
247
-
248
- if (this.compress) {
249
- // Compress the rotated file
250
- await this.compressFile(this.filename, `${rotatedFile}.gz`)
251
- await unlink(this.filename)
252
- } else {
253
- const { rename } = await import('fs/promises')
254
- await rename(this.filename, rotatedFile)
255
- }
256
- } catch (error) {
257
- // File doesn't exist, continue
258
- }
259
-
260
- this.currentSize = 0
261
- }
262
-
263
- private async compressFile(source: string, destination: string): Promise<void> {
264
- const gzip = createGzip()
265
- const sourceStream = createReadStream(source)
266
- const destStream = createWriteStream(destination)
267
-
268
- await pipeline(sourceStream, gzip, destStream)
269
- }
270
-
271
- async write(entry: LogEntry): Promise<void> {
272
- if (!this.shouldLog(entry.level)) return
273
-
274
- const formatted = this.formatMessage(entry)
275
- const messageSize = Buffer.byteLength(formatted, 'utf8')
276
-
277
- // Check if rotation is needed
278
- if (this.currentSize + messageSize > this.maxSize) {
279
- await this.rotateFile()
280
- }
281
-
282
- // Write to file
283
- await writeFile(this.filename, formatted, { flag: 'a' })
284
- this.currentSize += messageSize
285
- }
286
-
287
- async close(): Promise<void> {
288
- // Nothing to close for file transport
289
- }
290
- }
291
-
292
- /**
293
- * JSON Transport for structured production logging
294
- */
295
- export class JSONTransport implements LogTransport {
296
- name = 'json'
297
- level: LogLevel
298
- private filename?: string
299
- private pretty: boolean
300
-
301
- constructor(config: JSONTransportConfig = {}) {
302
- this.level = config.level || 'info'
303
- this.filename = config.filename
304
- this.pretty = config.pretty || false
305
-
306
- if (this.filename) {
307
- this.ensureDirectory()
308
- }
309
- }
310
-
311
- private async ensureDirectory(): Promise<void> {
312
- if (!this.filename) return
313
-
314
- const dir = dirname(this.filename)
315
- try {
316
- await mkdir(dir, { recursive: true })
317
- } catch (error) {
318
- // Directory might already exist
319
- }
320
- }
321
-
322
- private shouldLog(level: LogLevel): boolean {
323
- const levels: Record<LogLevel, number> = {
324
- debug: 0,
325
- info: 1,
326
- warn: 2,
327
- error: 3
328
- }
329
- return levels[level] >= levels[this.level]
330
- }
331
-
332
- private formatEntry(entry: LogEntry): string {
333
- const jsonEntry = {
334
- timestamp: entry.timestamp,
335
- level: entry.level,
336
- message: entry.message,
337
- ...(entry.context && { context: entry.context }),
338
- ...(entry.meta && { meta: entry.meta })
339
- }
340
-
341
- const json = this.pretty
342
- ? JSON.stringify(jsonEntry, null, 2)
343
- : JSON.stringify(jsonEntry)
344
-
345
- return json + '\n'
346
- }
347
-
348
- async write(entry: LogEntry): Promise<void> {
349
- if (!this.shouldLog(entry.level)) return
350
-
351
- const formatted = this.formatEntry(entry)
352
-
353
- if (this.filename) {
354
- // Write to file
355
- await writeFile(this.filename, formatted, { flag: 'a' })
356
- } else {
357
- // Write to console as JSON
358
- process.stdout.write(formatted)
359
- }
360
- }
361
-
362
- async close(): Promise<void> {
363
- // Nothing to close for JSON transport
364
- }
365
- }
@@ -1,106 +0,0 @@
1
- /**
2
- * FluxStack Logger
3
- * Environment-aware logging system
4
- */
5
-
6
- type LogLevel = 'debug' | 'info' | 'warn' | 'error'
7
-
8
- class Logger {
9
- private static instance: Logger | null = null
10
- private logLevel: LogLevel
11
-
12
- private constructor() {
13
- this.logLevel = (process.env.LOG_LEVEL as LogLevel) || 'info'
14
- }
15
-
16
- static getInstance(): Logger {
17
- if (Logger.instance === null) {
18
- Logger.instance = new Logger()
19
- }
20
- return Logger.instance
21
- }
22
-
23
- private shouldLog(level: LogLevel): boolean {
24
- const levels: Record<LogLevel, number> = {
25
- debug: 0,
26
- info: 1,
27
- warn: 2,
28
- error: 3
29
- }
30
-
31
- return levels[level] >= levels[this.logLevel]
32
- }
33
-
34
- private formatMessage(level: LogLevel, message: string, meta?: any): string {
35
- const timestamp = new Date().toISOString()
36
- const levelStr = level.toUpperCase().padEnd(5)
37
-
38
- let formatted = `[${timestamp}] ${levelStr} ${message}`
39
-
40
- if (meta && typeof meta === 'object') {
41
- formatted += ` ${JSON.stringify(meta)}`
42
- } else if (meta !== undefined) {
43
- formatted += ` ${meta}`
44
- }
45
-
46
- return formatted
47
- }
48
-
49
- debug(message: string, meta?: any): void {
50
- if (this.shouldLog('debug')) {
51
- console.debug(this.formatMessage('debug', message, meta))
52
- }
53
- }
54
-
55
- info(message: string, meta?: any): void {
56
- if (this.shouldLog('info')) {
57
- console.info(this.formatMessage('info', message, meta))
58
- }
59
- }
60
-
61
- warn(message: string, meta?: any): void {
62
- if (this.shouldLog('warn')) {
63
- console.warn(this.formatMessage('warn', message, meta))
64
- }
65
- }
66
-
67
- error(message: string, meta?: any): void {
68
- if (this.shouldLog('error')) {
69
- console.error(this.formatMessage('error', message, meta))
70
- }
71
- }
72
-
73
- // HTTP request logging
74
- request(method: string, path: string, status?: number, duration?: number): void {
75
- const statusStr = status ? ` ${status}` : ''
76
- const durationStr = duration ? ` (${duration}ms)` : ''
77
- this.info(`${method} ${path}${statusStr}${durationStr}`)
78
- }
79
-
80
- // Plugin logging
81
- plugin(pluginName: string, message: string, meta?: any): void {
82
- this.debug(`[${pluginName}] ${message}`, meta)
83
- }
84
-
85
- // Framework logging
86
- framework(message: string, meta?: any): void {
87
- this.info(`[FluxStack] ${message}`, meta)
88
- }
89
- }
90
-
91
- // Export singleton instance
92
- export const logger = Logger.getInstance()
93
-
94
- // Export convenience functions
95
- export const log = {
96
- debug: (message: string, meta?: any) => logger.debug(message, meta),
97
- info: (message: string, meta?: any) => logger.info(message, meta),
98
- warn: (message: string, meta?: any) => logger.warn(message, meta),
99
- error: (message: string, meta?: any) => logger.error(message, meta),
100
- request: (method: string, path: string, status?: number, duration?: number) =>
101
- logger.request(method, path, status, duration),
102
- plugin: (pluginName: string, message: string, meta?: any) =>
103
- logger.plugin(pluginName, message, meta),
104
- framework: (message: string, meta?: any) =>
105
- logger.framework(message, meta)
106
- }