create-fluxstack 1.7.5 → 1.8.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (154) hide show
  1. package/.dockerignore +82 -0
  2. package/.env.example +19 -0
  3. package/Dockerfile +70 -0
  4. package/README.md +6 -3
  5. package/app/client/SIMPLIFICATION.md +140 -0
  6. package/app/client/frontend-only.ts +1 -1
  7. package/app/client/src/App.tsx +148 -283
  8. package/app/client/src/index.css +5 -20
  9. package/app/client/src/lib/eden-api.ts +53 -220
  10. package/app/client/src/main.tsx +2 -3
  11. package/app/server/app.ts +20 -5
  12. package/app/server/backend-only.ts +15 -12
  13. package/app/server/controllers/users.controller.ts +57 -31
  14. package/app/server/index.ts +86 -96
  15. package/app/server/live/register-components.ts +18 -7
  16. package/app/server/routes/env-test.ts +110 -0
  17. package/app/server/routes/index.ts +1 -8
  18. package/app/server/routes/users.routes.ts +192 -91
  19. package/config/app.config.ts +2 -54
  20. package/config/client.config.ts +95 -0
  21. package/config/fluxstack.config.ts +2 -2
  22. package/config/index.ts +57 -22
  23. package/config/monitoring.config.ts +114 -0
  24. package/config/plugins.config.ts +80 -0
  25. package/config/runtime.config.ts +0 -17
  26. package/config/server.config.ts +50 -30
  27. package/core/build/bundler.ts +17 -16
  28. package/core/build/flux-plugins-generator.ts +34 -23
  29. package/core/build/index.ts +32 -31
  30. package/core/build/live-components-generator.ts +44 -30
  31. package/core/build/optimizer.ts +37 -17
  32. package/core/cli/command-registry.ts +4 -14
  33. package/core/cli/commands/plugin-deps.ts +8 -8
  34. package/core/cli/generators/component.ts +3 -3
  35. package/core/cli/generators/controller.ts +4 -4
  36. package/core/cli/generators/index.ts +8 -8
  37. package/core/cli/generators/interactive.ts +4 -4
  38. package/core/cli/generators/plugin.ts +3 -3
  39. package/core/cli/generators/prompts.ts +1 -1
  40. package/core/cli/generators/route.ts +27 -11
  41. package/core/cli/generators/service.ts +5 -5
  42. package/core/cli/generators/template-engine.ts +1 -1
  43. package/core/cli/generators/types.ts +1 -1
  44. package/core/cli/index.ts +158 -189
  45. package/core/cli/plugin-discovery.ts +3 -3
  46. package/core/client/hooks/index.ts +2 -2
  47. package/core/client/hooks/state-validator.ts +1 -1
  48. package/core/client/hooks/useAuth.ts +1 -1
  49. package/core/client/hooks/useChunkedUpload.ts +1 -1
  50. package/core/client/hooks/useHybridLiveComponent.ts +1 -1
  51. package/core/client/hooks/useWebSocket.ts +1 -1
  52. package/core/config/env.ts +5 -1
  53. package/core/config/runtime-config.ts +12 -10
  54. package/core/config/schema.ts +33 -2
  55. package/core/framework/server.ts +30 -14
  56. package/core/framework/types.ts +2 -2
  57. package/core/index.ts +31 -23
  58. package/core/live/ComponentRegistry.ts +1 -1
  59. package/core/plugins/built-in/live-components/commands/create-live-component.ts +1 -1
  60. package/core/plugins/built-in/live-components/index.ts +1 -1
  61. package/core/plugins/built-in/monitoring/index.ts +65 -161
  62. package/core/plugins/built-in/static/index.ts +75 -277
  63. package/core/plugins/built-in/swagger/index.ts +301 -231
  64. package/core/plugins/built-in/vite/index.ts +342 -377
  65. package/core/plugins/config.ts +2 -2
  66. package/core/plugins/dependency-manager.ts +2 -2
  67. package/core/plugins/discovery.ts +1 -1
  68. package/core/plugins/executor.ts +2 -2
  69. package/core/plugins/manager.ts +19 -4
  70. package/core/plugins/module-resolver.ts +1 -1
  71. package/core/plugins/registry.ts +25 -21
  72. package/core/plugins/types.ts +147 -5
  73. package/core/server/backend-entry.ts +51 -0
  74. package/core/server/framework.ts +2 -2
  75. package/core/server/live/ComponentRegistry.ts +9 -26
  76. package/core/server/live/FileUploadManager.ts +1 -1
  77. package/core/server/live/auto-generated-components.ts +26 -0
  78. package/core/server/live/websocket-plugin.ts +211 -19
  79. package/core/server/middleware/errorHandling.ts +1 -1
  80. package/core/server/middleware/index.ts +4 -4
  81. package/core/server/plugins/database.ts +1 -2
  82. package/core/server/plugins/static-files-plugin.ts +259 -231
  83. package/core/server/plugins/swagger.ts +1 -1
  84. package/core/server/services/BaseService.ts +1 -1
  85. package/core/server/services/ServiceContainer.ts +1 -1
  86. package/core/server/services/index.ts +4 -4
  87. package/core/server/standalone.ts +16 -1
  88. package/core/testing/index.ts +1 -1
  89. package/core/testing/setup.ts +1 -1
  90. package/core/types/plugin.ts +6 -0
  91. package/core/utils/build-logger.ts +324 -0
  92. package/core/utils/config-schema.ts +2 -6
  93. package/core/utils/helpers.ts +14 -9
  94. package/core/utils/logger/startup-banner.ts +7 -33
  95. package/core/utils/regenerate-files.ts +69 -0
  96. package/core/utils/version.ts +6 -6
  97. package/create-fluxstack.ts +68 -25
  98. package/fluxstack.config.ts +138 -252
  99. package/package.json +3 -18
  100. package/plugins/crypto-auth/index.ts +52 -47
  101. package/plugins/crypto-auth/server/AuthMiddleware.ts +1 -1
  102. package/plugins/crypto-auth/server/middlewares/helpers.ts +16 -1
  103. package/vitest.config.ts +17 -26
  104. package/app/client/src/App.css +0 -883
  105. package/app/client/src/components/ErrorBoundary.tsx +0 -107
  106. package/app/client/src/components/ErrorDisplay.css +0 -365
  107. package/app/client/src/components/ErrorDisplay.tsx +0 -258
  108. package/app/client/src/components/FluxStackConfig.tsx +0 -1321
  109. package/app/client/src/components/HybridLiveCounter.tsx +0 -140
  110. package/app/client/src/components/LiveClock.tsx +0 -286
  111. package/app/client/src/components/MainLayout.tsx +0 -388
  112. package/app/client/src/components/SidebarNavigation.tsx +0 -391
  113. package/app/client/src/components/StateDemo.tsx +0 -178
  114. package/app/client/src/components/SystemMonitor.tsx +0 -1044
  115. package/app/client/src/components/UserProfile.tsx +0 -809
  116. package/app/client/src/hooks/useAuth.ts +0 -39
  117. package/app/client/src/hooks/useNotifications.ts +0 -56
  118. package/app/client/src/lib/errors.ts +0 -340
  119. package/app/client/src/lib/hooks/useErrorHandler.ts +0 -258
  120. package/app/client/src/lib/index.ts +0 -45
  121. package/app/client/src/pages/ApiDocs.tsx +0 -182
  122. package/app/client/src/pages/CryptoAuthPage.tsx +0 -394
  123. package/app/client/src/pages/Demo.tsx +0 -174
  124. package/app/client/src/pages/HybridLive.tsx +0 -263
  125. package/app/client/src/pages/Overview.tsx +0 -155
  126. package/app/client/src/store/README.md +0 -43
  127. package/app/client/src/store/index.ts +0 -16
  128. package/app/client/src/store/slices/uiSlice.ts +0 -151
  129. package/app/client/src/store/slices/userSlice.ts +0 -161
  130. package/app/client/src/test/README.md +0 -257
  131. package/app/client/src/test/setup.ts +0 -70
  132. package/app/client/src/test/types.ts +0 -12
  133. package/app/server/live/CounterComponent.ts +0 -191
  134. package/app/server/live/FluxStackConfig.ts +0 -534
  135. package/app/server/live/SidebarNavigation.ts +0 -157
  136. package/app/server/live/SystemMonitor.ts +0 -595
  137. package/app/server/live/SystemMonitorIntegration.ts +0 -151
  138. package/app/server/live/UserProfileComponent.ts +0 -141
  139. package/app/server/middleware/auth.ts +0 -136
  140. package/app/server/middleware/errorHandling.ts +0 -252
  141. package/app/server/middleware/index.ts +0 -10
  142. package/app/server/middleware/rateLimit.ts +0 -193
  143. package/app/server/middleware/requestLogging.ts +0 -215
  144. package/app/server/middleware/validation.ts +0 -270
  145. package/app/server/routes/config.ts +0 -145
  146. package/app/server/routes/crypto-auth-demo.routes.ts +0 -167
  147. package/app/server/routes/example-with-crypto-auth.routes.ts +0 -235
  148. package/app/server/routes/exemplo-posts.routes.ts +0 -161
  149. package/app/server/routes/upload.ts +0 -92
  150. package/app/server/services/NotificationService.ts +0 -302
  151. package/app/server/services/UserService.ts +0 -222
  152. package/app/server/services/index.ts +0 -46
  153. package/app/server/types/index.ts +0 -1
  154. package/config/build.config.ts +0 -24
@@ -0,0 +1,324 @@
1
+ /**
2
+ * FluxStack Build Logger - Beautiful terminal output for build process
3
+ * Provides formatted tables, boxes, and colored output
4
+ */
5
+
6
+ // ANSI Color codes
7
+ const colors = {
8
+ reset: '\x1b[0m',
9
+ bright: '\x1b[1m',
10
+ dim: '\x1b[2m',
11
+
12
+ // Text colors
13
+ cyan: '\x1b[36m',
14
+ blue: '\x1b[34m',
15
+ green: '\x1b[32m',
16
+ yellow: '\x1b[33m',
17
+ red: '\x1b[31m',
18
+ magenta: '\x1b[35m',
19
+ white: '\x1b[37m',
20
+ gray: '\x1b[90m',
21
+
22
+ // Background colors
23
+ bgCyan: '\x1b[46m',
24
+ bgBlue: '\x1b[44m',
25
+ bgGreen: '\x1b[42m',
26
+ bgYellow: '\x1b[43m',
27
+ bgRed: '\x1b[41m',
28
+ }
29
+
30
+ // Box drawing characters
31
+ const box = {
32
+ topLeft: 'ā•­',
33
+ topRight: 'ā•®',
34
+ bottomLeft: 'ā•°',
35
+ bottomRight: '╯',
36
+ horizontal: '─',
37
+ vertical: '│',
38
+ verticalRight: 'ā”œ',
39
+ verticalLeft: '┤',
40
+ horizontalDown: '┬',
41
+ horizontalUp: '┓',
42
+ cross: '┼',
43
+ }
44
+
45
+ export interface TableColumn {
46
+ header: string
47
+ key: string
48
+ width?: number
49
+ align?: 'left' | 'right' | 'center'
50
+ color?: keyof typeof colors
51
+ }
52
+
53
+ export interface TableRow {
54
+ [key: string]: string | number
55
+ }
56
+
57
+ export class BuildLogger {
58
+ private indent = ''
59
+ private startTime = Date.now()
60
+
61
+ /**
62
+ * Print a beautiful header banner
63
+ */
64
+ header(title: string) {
65
+ const width = 60
66
+ const padding = Math.floor((width - title.length - 2) / 2)
67
+ const paddingRight = width - title.length - 2 - padding
68
+
69
+ console.log()
70
+ console.log(colors.cyan + colors.bright + box.topLeft + box.horizontal.repeat(width) + box.topRight + colors.reset)
71
+ console.log(colors.cyan + box.vertical + ' '.repeat(padding) + colors.bright + colors.white + title + colors.cyan + ' '.repeat(paddingRight) + box.vertical + colors.reset)
72
+ console.log(colors.cyan + box.bottomLeft + box.horizontal.repeat(width) + box.bottomRight + colors.reset)
73
+ console.log()
74
+ }
75
+
76
+ /**
77
+ * Print a section header
78
+ */
79
+ section(title: string, icon: string = 'šŸ“¦') {
80
+ console.log()
81
+ console.log(colors.bright + colors.blue + `${icon} ${title}` + colors.reset)
82
+ console.log(colors.dim + colors.gray + box.horizontal.repeat(50) + colors.reset)
83
+ }
84
+
85
+ /**
86
+ * Print a success message
87
+ */
88
+ success(message: string) {
89
+ console.log(colors.green + 'āœ“ ' + colors.reset + message)
90
+ }
91
+
92
+ /**
93
+ * Print an error message
94
+ */
95
+ error(message: string) {
96
+ console.log(colors.red + 'āœ— ' + colors.reset + message)
97
+ }
98
+
99
+ /**
100
+ * Print a warning message
101
+ */
102
+ warn(message: string) {
103
+ console.log(colors.yellow + '⚠ ' + colors.reset + message)
104
+ }
105
+
106
+ /**
107
+ * Print an info message
108
+ */
109
+ info(message: string, icon: string = '→') {
110
+ console.log(colors.cyan + icon + ' ' + colors.reset + message)
111
+ }
112
+
113
+ /**
114
+ * Print a step message
115
+ */
116
+ step(message: string, icon: string = 'ā–ø') {
117
+ console.log(colors.dim + colors.gray + icon + ' ' + colors.reset + message)
118
+ }
119
+
120
+ /**
121
+ * Print a table
122
+ */
123
+ table(columns: TableColumn[], rows: TableRow[]) {
124
+ if (rows.length === 0) {
125
+ this.warn('No data to display')
126
+ return
127
+ }
128
+
129
+ // Calculate column widths
130
+ const widths = columns.map(col => {
131
+ if (col.width) return col.width
132
+ const maxContentWidth = Math.max(
133
+ col.header.length,
134
+ ...rows.map(row => String(row[col.key] || '').length)
135
+ )
136
+ return Math.min(maxContentWidth, 40) // Max 40 chars per column
137
+ })
138
+
139
+ const totalWidth = widths.reduce((sum, w) => sum + w, 0) + (columns.length - 1) * 3 + 4
140
+
141
+ // Print top border
142
+ console.log(
143
+ colors.gray + box.topLeft +
144
+ widths.map((w, i) =>
145
+ box.horizontal.repeat(w + 2) + (i < widths.length - 1 ? box.horizontalDown : '')
146
+ ).join('') +
147
+ box.topRight + colors.reset
148
+ )
149
+
150
+ // Print header
151
+ const headerRow = columns.map((col, i) => {
152
+ const content = this.padContent(col.header, widths[i], 'center')
153
+ return colors.bright + colors.white + content + colors.reset
154
+ }).join(colors.gray + ' │ ' + colors.reset)
155
+
156
+ console.log(colors.gray + box.vertical + ' ' + colors.reset + headerRow + colors.gray + ' ' + box.vertical + colors.reset)
157
+
158
+ // Print header separator
159
+ console.log(
160
+ colors.gray + box.verticalRight +
161
+ widths.map((w, i) =>
162
+ box.horizontal.repeat(w + 2) + (i < widths.length - 1 ? box.cross : '')
163
+ ).join('') +
164
+ box.verticalLeft + colors.reset
165
+ )
166
+
167
+ // Print rows
168
+ rows.forEach((row, rowIndex) => {
169
+ const rowContent = columns.map((col, i) => {
170
+ const value = String(row[col.key] || '')
171
+ const content = this.padContent(value, widths[i], col.align || 'left')
172
+ const color = col.color ? colors[col.color] : ''
173
+ return color + content + colors.reset
174
+ }).join(colors.gray + ' │ ' + colors.reset)
175
+
176
+ console.log(colors.gray + box.vertical + ' ' + colors.reset + rowContent + colors.gray + ' ' + box.vertical + colors.reset)
177
+ })
178
+
179
+ // Print bottom border
180
+ console.log(
181
+ colors.gray + box.bottomLeft +
182
+ widths.map((w, i) =>
183
+ box.horizontal.repeat(w + 2) + (i < widths.length - 1 ? box.horizontalUp : '')
184
+ ).join('') +
185
+ box.bottomRight + colors.reset
186
+ )
187
+ }
188
+
189
+ /**
190
+ * Print a simple info box
191
+ */
192
+ box(title: string, items: Array<{ label: string; value: string | number; color?: keyof typeof colors }>) {
193
+ const maxLabelWidth = Math.max(...items.map(i => i.label.length))
194
+ const maxValueWidth = Math.max(...items.map(i => String(i.value).length))
195
+ const contentWidth = maxLabelWidth + maxValueWidth + 3
196
+ const boxWidth = Math.max(contentWidth, title.length) + 4
197
+
198
+ // Top border with title
199
+ console.log()
200
+ console.log(colors.cyan + box.topLeft + box.horizontal.repeat(2) + colors.bright + colors.white + title + colors.cyan + box.horizontal.repeat(boxWidth - title.length - 2) + box.topRight + colors.reset)
201
+
202
+ // Content
203
+ items.forEach(item => {
204
+ const label = item.label.padEnd(maxLabelWidth)
205
+ const value = String(item.value)
206
+ const valueColor = item.color ? colors[item.color] : colors.white
207
+ console.log(
208
+ colors.cyan + box.vertical + ' ' + colors.reset +
209
+ colors.gray + label + colors.reset +
210
+ colors.dim + ' : ' + colors.reset +
211
+ valueColor + colors.bright + value + colors.reset +
212
+ ' '.repeat(boxWidth - label.length - value.length - 3) +
213
+ colors.cyan + box.vertical + colors.reset
214
+ )
215
+ })
216
+
217
+ // Bottom border
218
+ console.log(colors.cyan + box.bottomLeft + box.horizontal.repeat(boxWidth) + box.bottomRight + colors.reset)
219
+ console.log()
220
+ }
221
+
222
+ /**
223
+ * Print a progress indicator
224
+ */
225
+ progress(current: number, total: number, label: string) {
226
+ const percentage = Math.round((current / total) * 100)
227
+ const barLength = 30
228
+ const filled = Math.round((percentage / 100) * barLength)
229
+ const empty = barLength - filled
230
+
231
+ const bar = colors.green + 'ā–ˆ'.repeat(filled) + colors.gray + 'ā–‘'.repeat(empty) + colors.reset
232
+ console.log(`${label} [${bar}] ${percentage}% (${current}/${total})`)
233
+ }
234
+
235
+ /**
236
+ * Start a timer
237
+ */
238
+ startTimer(label?: string) {
239
+ this.startTime = Date.now()
240
+ if (label) {
241
+ this.info(label, 'ā±')
242
+ }
243
+ }
244
+
245
+ /**
246
+ * End timer and print elapsed time
247
+ */
248
+ endTimer(label: string = 'Completed') {
249
+ const elapsed = Date.now() - this.startTime
250
+ const seconds = (elapsed / 1000).toFixed(2)
251
+ this.success(`${label} in ${colors.bright}${seconds}s${colors.reset}`)
252
+ }
253
+
254
+ /**
255
+ * Print a summary box
256
+ */
257
+ summary(title: string, stats: Array<{ label: string; value: string | number; highlight?: boolean }>) {
258
+ console.log()
259
+ console.log(colors.bright + colors.green + '╔═══════════════════════════════════════════════════════════╗' + colors.reset)
260
+ console.log(colors.bright + colors.green + 'ā•‘' + colors.reset + colors.bright + colors.white + ` ${title}`.padEnd(60) + colors.bright + colors.green + 'ā•‘' + colors.reset)
261
+ console.log(colors.bright + colors.green + '╠═══════════════════════════════════════════════════════════╣' + colors.reset)
262
+
263
+ stats.forEach(stat => {
264
+ const label = ` ${stat.label}:`
265
+ const value = String(stat.value)
266
+ const valueColor = stat.highlight ? colors.yellow + colors.bright : colors.white
267
+ const padding = 60 - label.length - value.length - 1
268
+ console.log(
269
+ colors.bright + colors.green + 'ā•‘' + colors.reset +
270
+ colors.cyan + label + colors.reset +
271
+ ' '.repeat(Math.max(padding, 1)) +
272
+ valueColor + value + colors.reset +
273
+ colors.bright + colors.green + ' ā•‘' + colors.reset
274
+ )
275
+ })
276
+
277
+ console.log(colors.bright + colors.green + 'ā•šā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•' + colors.reset)
278
+ console.log()
279
+ }
280
+
281
+ /**
282
+ * Pad content based on alignment
283
+ */
284
+ private padContent(content: string, width: number, align: 'left' | 'right' | 'center' = 'left'): string {
285
+ if (content.length >= width) {
286
+ return content.slice(0, width)
287
+ }
288
+
289
+ const padding = width - content.length
290
+
291
+ switch (align) {
292
+ case 'right':
293
+ return ' '.repeat(padding) + content
294
+ case 'center':
295
+ const leftPad = Math.floor(padding / 2)
296
+ const rightPad = padding - leftPad
297
+ return ' '.repeat(leftPad) + content + ' '.repeat(rightPad)
298
+ default:
299
+ return content + ' '.repeat(padding)
300
+ }
301
+ }
302
+
303
+ /**
304
+ * Format file size
305
+ */
306
+ formatSize(bytes: number): string {
307
+ if (bytes === 0) return '0 B'
308
+ const k = 1024
309
+ const sizes = ['B', 'KB', 'MB', 'GB']
310
+ const i = Math.floor(Math.log(bytes) / Math.log(k))
311
+ return `${(bytes / Math.pow(k, i)).toFixed(2)} ${sizes[i]}`
312
+ }
313
+
314
+ /**
315
+ * Format duration
316
+ */
317
+ formatDuration(ms: number): string {
318
+ if (ms < 1000) return `${ms}ms`
319
+ return `${(ms / 1000).toFixed(2)}s`
320
+ }
321
+ }
322
+
323
+ // Export singleton instance
324
+ export const buildLogger = new BuildLogger()
@@ -23,17 +23,13 @@
23
23
  * default: 3000,
24
24
  * validate: (value) => value > 0 && value < 65536
25
25
  * },
26
- * debug: {
27
- * type: 'boolean',
28
- * env: 'DEBUG',
29
- * default: false
30
- * }
26
+ * env: config.enum('NODE_ENV', ['development', 'production', 'test'] as const, 'development', true)
31
27
  * })
32
28
  *
33
29
  * // Access with full type safety
34
30
  * appConfig.name // string
35
31
  * appConfig.port // number
36
- * appConfig.debug // boolean
32
+ * appConfig.env // "development" | "production" | "test"
37
33
  * ```
38
34
  */
39
35
 
@@ -86,22 +86,27 @@ export const throttle = <T extends (...args: any[]) => any>(
86
86
  }
87
87
  }
88
88
 
89
+ /**
90
+ * Environment detection utilities
91
+ * Uses declarative config system instead of legacy env
92
+ */
93
+
89
94
  export const isProduction = (): boolean => {
90
- // Import here to avoid circular dependency
91
- const { env } = require('./env')
92
- return env.NODE_ENV === 'production'
95
+ // Lazy import to avoid circular dependency during module initialization
96
+ const { appConfig } = require('@/config/app.config')
97
+ return appConfig.env === 'production'
93
98
  }
94
99
 
95
100
  export const isDevelopment = (): boolean => {
96
- // Import here to avoid circular dependency
97
- const { env } = require('./env')
98
- return env.NODE_ENV === 'development' || !env.NODE_ENV
101
+ // Lazy import to avoid circular dependency during module initialization
102
+ const { appConfig } = require('@/config/app.config')
103
+ return appConfig.env === 'development'
99
104
  }
100
105
 
101
106
  export const isTest = (): boolean => {
102
- // Import here to avoid circular dependency
103
- const { env } = require('./env')
104
- return env.NODE_ENV === 'test'
107
+ // Lazy import to avoid circular dependency during module initialization
108
+ const { appConfig } = require('@/config/app.config')
109
+ return appConfig.env === 'test'
105
110
  }
106
111
 
107
112
  export const deepMerge = <T extends Record<string, any>>(target: T, source: Partial<T>): T => {
@@ -33,43 +33,17 @@ export function displayStartupBanner(info: StartupInfo): void {
33
33
  pluginCount = 0,
34
34
  vitePort,
35
35
  viteEmbedded = false,
36
- swaggerPath
37
36
  } = info
38
37
 
39
- console.log('\n' + chalk.cyan.bold('⚔ FluxStack') + chalk.gray(` v${FLUXSTACK_VERSION}\n`))
40
-
41
- // Server info
42
- console.log(chalk.bold('šŸš€ Server'))
43
- console.log(` ${chalk.gray('→')} http://localhost:${port}`)
44
- console.log(` ${chalk.gray('→')} API: http://localhost:${port}${apiPrefix}`)
45
- console.log(` ${chalk.gray('→')} Health: http://localhost:${port}${apiPrefix}/health`)
46
-
47
- // Frontend info (only if Vite is running standalone, NOT embedded)
48
- if (vitePort && !viteEmbedded) {
49
- console.log('')
50
- console.log(chalk.bold('āš›ļø Frontend'))
51
- console.log(` ${chalk.gray('→')} http://localhost:${vitePort}`)
52
- }
53
-
54
- // Swagger docs (if enabled)
55
- if (swaggerPath) {
56
- console.log('')
57
- console.log(chalk.bold('šŸ“‹ Documentation'))
58
- console.log(` ${chalk.gray('→')} Swagger: http://localhost:${port}${swaggerPath}`)
59
- }
60
-
61
- // Environment and plugins
62
- console.log('')
63
- console.log(chalk.bold('ā„¹ļø Info'))
64
- console.log(` ${chalk.gray('→')} Environment: ${chalk.green(environment)}`)
65
- console.log(` ${chalk.gray('→')} Plugins: ${chalk.yellow(pluginCount)}`)
66
-
67
- // Show Vite embedded status when applicable
68
- if (viteEmbedded && vitePort) {
69
- console.log(` ${chalk.gray('→')} Vite: ${chalk.magenta('embedded')} ${chalk.gray(`(port ${vitePort})`)}`)
38
+ // Display plugins in compact format
39
+ const plugins = (global as any).__fluxstackPlugins || []
40
+ if (plugins.length > 0) {
41
+ const pluginList = plugins.map((p: any) => `${p.name} (${p.details})`).join(', ')
42
+ console.log(`Plugins (${plugins.length}): ${pluginList}\n`)
70
43
  }
71
44
 
72
- console.log('\n' + chalk.green('✨ Ready!') + chalk.gray(' Press Ctrl+C to stop\n'))
45
+ // Simple ready message
46
+ console.log(chalk.green('Server ready!') + chalk.gray(` Environment: ${environment}${viteEmbedded ? ' | Vite: embedded' : ''}\n`))
73
47
  }
74
48
 
75
49
  /**
@@ -0,0 +1,69 @@
1
+ /**
2
+ * File Regeneration Utilities
3
+ *
4
+ * Provides functions to regenerate critical application files that might be
5
+ * accidentally deleted by developers.
6
+ */
7
+
8
+ import { join } from "path"
9
+ import { existsSync } from "fs"
10
+
11
+ const BACKEND_ONLY_TEMPLATE = `/**
12
+ * Backend Standalone Entry Point
13
+ *
14
+ * This is a minimal wrapper for starting the backend in standalone mode.
15
+ * The core logic is protected in @/core/server/backend-entry.ts
16
+ *
17
+ * You can customize the configuration here if needed.
18
+ */
19
+
20
+ import { startBackend, createBackendConfig } from "@/core/server/backend-entry"
21
+ import { apiRoutes } from "./routes"
22
+ import { serverConfig } from "@/config/server.config"
23
+
24
+ // Create backend configuration from declarative config
25
+ const backendConfig = createBackendConfig(serverConfig)
26
+
27
+ // Start backend in standalone mode
28
+ startBackend(apiRoutes, backendConfig)
29
+ `
30
+
31
+ /**
32
+ * Check if backend-only.ts exists, regenerate if missing
33
+ */
34
+ export async function ensureBackendEntry(projectRoot: string = process.cwd()): Promise<boolean> {
35
+ const backendOnlyPath = join(projectRoot, "app/server/backend-only.ts")
36
+
37
+ if (!existsSync(backendOnlyPath)) {
38
+ console.log("āš ļø backend-only.ts not found, regenerating...")
39
+
40
+ try {
41
+ await Bun.write(backendOnlyPath, BACKEND_ONLY_TEMPLATE)
42
+ console.log("āœ… backend-only.ts regenerated successfully")
43
+ return true
44
+ } catch (error) {
45
+ console.error("āŒ Failed to regenerate backend-only.ts:", error)
46
+ return false
47
+ }
48
+ }
49
+
50
+ return true
51
+ }
52
+
53
+ /**
54
+ * Regenerate backend-only.ts file
55
+ */
56
+ export async function regenerateBackendEntry(projectRoot: string = process.cwd()): Promise<boolean> {
57
+ const backendOnlyPath = join(projectRoot, "app/server/backend-only.ts")
58
+
59
+ console.log("šŸ”„ Regenerating backend-only.ts...")
60
+
61
+ try {
62
+ await Bun.write(backendOnlyPath, BACKEND_ONLY_TEMPLATE)
63
+ console.log("āœ… backend-only.ts regenerated successfully")
64
+ return true
65
+ } catch (error) {
66
+ console.error("āŒ Failed to regenerate backend-only.ts:", error)
67
+ return false
68
+ }
69
+ }
@@ -1,6 +1,6 @@
1
- /**
2
- * FluxStack Framework Version
3
- * Single source of truth for version number
4
- * Auto-synced with package.json
5
- */
6
- export const FLUXSTACK_VERSION = '1.7.5'
1
+ /**
2
+ * FluxStack Framework Version
3
+ * Single source of truth for version number
4
+ * Auto-synced with package.json
5
+ */
6
+ export const FLUXSTACK_VERSION = '1.8.3'
@@ -1,8 +1,8 @@
1
1
  #!/usr/bin/env bun
2
2
 
3
3
  import { program } from 'commander'
4
- import { resolve, join } from 'path'
5
- import { existsSync, mkdirSync, cpSync, writeFileSync, readFileSync } from 'fs'
4
+ import { resolve, join, basename } from 'path'
5
+ import { existsSync, mkdirSync, cpSync, writeFileSync, readFileSync, readdirSync } from 'fs'
6
6
  import chalk from 'chalk'
7
7
  import ora from 'ora'
8
8
  import { FLUXSTACK_VERSION } from './core/utils/version'
@@ -28,30 +28,62 @@ program
28
28
  .action(async (projectName, options) => {
29
29
  console.clear()
30
30
  console.log(chalk.magenta(logo))
31
-
31
+
32
32
  if (!projectName || projectName.trim().length === 0) {
33
33
  console.log(chalk.red('āŒ Project name is required'))
34
- console.log(chalk.gray('Usage: ./create-fluxstack.ts my-app'))
34
+ console.log(chalk.gray('Usage: bunx create-fluxstack@latest my-app'))
35
+ console.log(chalk.gray(' or: bunx create-fluxstack@latest .'))
35
36
  process.exit(1)
36
37
  }
37
-
38
+
38
39
  const currentDir = import.meta.dir
39
- const projectPath = resolve(projectName)
40
-
41
- // Check if directory already exists
42
- if (existsSync(projectPath)) {
40
+
41
+ // Normalize path: remove trailing slashes (which may indicate current dir usage like path/.)
42
+ let normalizedName = projectName
43
+ const hasTrailingSlash = normalizedName.endsWith('/') || normalizedName.endsWith('\\')
44
+
45
+ if (hasTrailingSlash) {
46
+ normalizedName = normalizedName.slice(0, -1)
47
+ }
48
+
49
+ // Check if it's current directory
50
+ // - Explicit '.'
51
+ // - Path ending with /. or \. (e.g., /path/to/dir/.)
52
+ // - Path ending with / or \ (Bun normalizes path/. to path/)
53
+ const isCurrentDir = normalizedName === '.' ||
54
+ projectName.endsWith('/.') ||
55
+ projectName.endsWith('\\.') ||
56
+ hasTrailingSlash
57
+
58
+ const projectPath = resolve(normalizedName)
59
+ const displayName = isCurrentDir ? 'current directory' : projectName
60
+
61
+ // Check if directory already exists (skip for current dir)
62
+ if (!isCurrentDir && existsSync(projectPath)) {
43
63
  console.log(chalk.red(`āŒ Directory ${projectName} already exists`))
44
64
  process.exit(1)
45
65
  }
46
-
47
- console.log(chalk.cyan(`\nšŸš€ Creating FluxStack project: ${chalk.bold(projectName)}`))
66
+
67
+ // Check if current directory is not empty (when using '.')
68
+ if (isCurrentDir) {
69
+ const files = readdirSync(projectPath).filter(f => !f.startsWith('.'))
70
+ if (files.length > 0) {
71
+ console.log(chalk.yellow('āš ļø Current directory is not empty'))
72
+ console.log(chalk.gray(`Found ${files.length} file(s). FluxStack will be initialized here.`))
73
+ }
74
+ }
75
+
76
+ console.log(chalk.cyan(`\nšŸš€ Creating FluxStack project: ${chalk.bold(displayName)}`))
48
77
  console.log(chalk.gray(`šŸ“ Location: ${projectPath}`))
49
78
 
50
79
  // Create project directory
51
80
  const spinner = ora('Creating project structure...').start()
52
-
81
+
53
82
  try {
54
- mkdirSync(projectPath, { recursive: true })
83
+ // Only create directory if not using current directory
84
+ if (!isCurrentDir) {
85
+ mkdirSync(projectPath, { recursive: true })
86
+ }
55
87
 
56
88
  // Copy only essential FluxStack files (not node_modules, not test apps, etc.)
57
89
  const frameworkDir = currentDir // Use current directory (framework root)
@@ -142,7 +174,14 @@ export class MyPlugin implements FluxStackPlugin {
142
174
  // Intercept every request
143
175
  async onRequest(context: PluginContext, request: Request): Promise<void> {
144
176
  // Example: Add custom headers
145
- const url = new URL(request.url)
177
+ const url = (() => {
178
+ try {
179
+ return new URL(request.url)
180
+ } catch {
181
+ const host = request.headers.get('host') || 'localhost'
182
+ return new URL(request.url, \`http://\${host}\`)
183
+ }
184
+ })()
146
185
  console.log(\`[\${this.name}] Request to: \${url.pathname}\`)
147
186
 
148
187
  // Example: Validate authentication
@@ -305,18 +344,20 @@ bun.lockb
305
344
 
306
345
  // Customize package.json with project name
307
346
  const packageJsonPath = join(projectPath, 'package.json')
347
+ const actualProjectName = isCurrentDir ? basename(projectPath) : normalizedName
348
+
308
349
  if (existsSync(packageJsonPath)) {
309
350
  const packageContent = readFileSync(packageJsonPath, 'utf-8')
310
351
  const packageJson = JSON.parse(packageContent)
311
-
352
+
312
353
  // Update project-specific fields
313
- packageJson.name = projectName
314
- packageJson.description = `${projectName} - FluxStack application`
354
+ packageJson.name = actualProjectName
355
+ packageJson.description = `${actualProjectName} - FluxStack application`
315
356
  packageJson.version = "1.0.0"
316
-
357
+
317
358
  writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2))
318
359
  }
319
-
360
+
320
361
  // Create .env from .env.example and set development mode + project name
321
362
  const envExamplePath = join(projectPath, '.env.example')
322
363
  const envPath = join(projectPath, '.env')
@@ -325,14 +366,14 @@ bun.lockb
325
366
  // Set development mode
326
367
  envContent = envContent.replace('NODE_ENV=production', 'NODE_ENV=development')
327
368
  // Customize app name to match project name
328
- envContent = envContent.replace('VITE_APP_NAME=FluxStack', `VITE_APP_NAME=${projectName}`)
369
+ envContent = envContent.replace('VITE_APP_NAME=FluxStack', `VITE_APP_NAME=${actualProjectName}`)
329
370
  writeFileSync(envPath, envContent)
330
371
  }
331
-
372
+
332
373
  // Customize README.md
333
374
  const readmePath = join(projectPath, 'README.md')
334
375
  if (existsSync(readmePath)) {
335
- const readmeContent = `# ${projectName}
376
+ const readmeContent = `# ${actualProjectName}
336
377
 
337
378
  ⚔ **FluxStack Application** - Modern full-stack TypeScript framework
338
379
 
@@ -352,7 +393,7 @@ bun run start
352
393
  ## šŸ“ Project Structure
353
394
 
354
395
  \`\`\`
355
- ${projectName}/
396
+ ${actualProjectName}/
356
397
  ā”œā”€ā”€ core/ # FluxStack framework (don't modify)
357
398
  ā”œā”€ā”€ app/ # Your application code
358
399
  │ ā”œā”€ā”€ server/ # Backend API routes
@@ -471,7 +512,7 @@ Built with ā¤ļø using FluxStack
471
512
  })
472
513
  await addProc.exited
473
514
 
474
- const commitProc = Bun.spawn(['git', 'commit', '-m', `feat: initial ${projectName} with FluxStack`], {
515
+ const commitProc = Bun.spawn(['git', 'commit', '-m', `feat: initial ${actualProjectName} with FluxStack`], {
475
516
  cwd: projectPath,
476
517
  stdio: ['ignore', 'pipe', 'pipe']
477
518
  })
@@ -487,7 +528,9 @@ Built with ā¤ļø using FluxStack
487
528
  // Success message
488
529
  console.log(chalk.green('\nšŸŽ‰ Project created successfully!'))
489
530
  console.log(chalk.cyan('\nNext steps:'))
490
- console.log(chalk.white(` cd ${projectName}`))
531
+ if (!isCurrentDir) {
532
+ console.log(chalk.white(` cd ${projectName}`))
533
+ }
491
534
  if (!options.install) {
492
535
  console.log(chalk.white(` bun install`))
493
536
  }