create-fluxstack 1.9.1 → 1.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (259) hide show
  1. package/.dockerignore +1 -2
  2. package/Dockerfile +8 -8
  3. package/LIVE_COMPONENTS_REVIEW.md +781 -0
  4. package/LLMD/INDEX.md +64 -0
  5. package/LLMD/MAINTENANCE.md +197 -0
  6. package/LLMD/MIGRATION.md +156 -0
  7. package/LLMD/config/.gitkeep +1 -0
  8. package/LLMD/config/declarative-system.md +268 -0
  9. package/LLMD/config/environment-vars.md +327 -0
  10. package/LLMD/config/runtime-reload.md +401 -0
  11. package/LLMD/core/.gitkeep +1 -0
  12. package/LLMD/core/build-system.md +599 -0
  13. package/LLMD/core/framework-lifecycle.md +229 -0
  14. package/LLMD/core/plugin-system.md +451 -0
  15. package/LLMD/patterns/.gitkeep +1 -0
  16. package/LLMD/patterns/anti-patterns.md +297 -0
  17. package/LLMD/patterns/project-structure.md +264 -0
  18. package/LLMD/patterns/type-safety.md +440 -0
  19. package/LLMD/reference/.gitkeep +1 -0
  20. package/LLMD/reference/cli-commands.md +250 -0
  21. package/LLMD/reference/plugin-hooks.md +357 -0
  22. package/LLMD/reference/routing.md +39 -0
  23. package/LLMD/reference/troubleshooting.md +364 -0
  24. package/LLMD/resources/.gitkeep +1 -0
  25. package/LLMD/resources/controllers.md +465 -0
  26. package/LLMD/resources/live-components.md +703 -0
  27. package/LLMD/resources/live-rooms.md +482 -0
  28. package/LLMD/resources/live-upload.md +130 -0
  29. package/LLMD/resources/plugins-external.md +617 -0
  30. package/LLMD/resources/routes-eden.md +254 -0
  31. package/README.md +37 -17
  32. package/app/client/index.html +0 -1
  33. package/app/client/src/App.tsx +109 -156
  34. package/app/client/src/components/AppLayout.tsx +68 -0
  35. package/app/client/src/components/BackButton.tsx +13 -0
  36. package/app/client/src/components/DemoPage.tsx +20 -0
  37. package/app/client/src/components/LiveUploadWidget.tsx +204 -0
  38. package/app/client/src/lib/eden-api.ts +85 -65
  39. package/app/client/src/live/ChatDemo.tsx +107 -0
  40. package/app/client/src/live/CounterDemo.tsx +206 -0
  41. package/app/client/src/live/FormDemo.tsx +119 -0
  42. package/app/client/src/live/RoomChatDemo.tsx +242 -0
  43. package/app/client/src/live/UploadDemo.tsx +21 -0
  44. package/app/client/src/main.tsx +13 -10
  45. package/app/client/src/pages/ApiTestPage.tsx +108 -0
  46. package/app/client/src/pages/HomePage.tsx +76 -0
  47. package/app/client/src/vite-env.d.ts +1 -1
  48. package/app/server/app.ts +1 -4
  49. package/app/server/controllers/users.controller.ts +36 -44
  50. package/app/server/index.ts +24 -107
  51. package/app/server/live/LiveChat.ts +77 -0
  52. package/app/server/live/LiveCounter.ts +67 -0
  53. package/app/server/live/LiveForm.ts +63 -0
  54. package/app/server/live/LiveLocalCounter.ts +32 -0
  55. package/app/server/live/LiveRoomChat.ts +285 -0
  56. package/app/server/live/LiveUpload.ts +81 -0
  57. package/app/server/live/register-components.ts +19 -19
  58. package/app/server/routes/index.ts +3 -1
  59. package/app/server/routes/room.routes.ts +117 -0
  60. package/app/server/routes/users.routes.ts +35 -27
  61. package/app/shared/types/index.ts +14 -2
  62. package/config/app.config.ts +2 -62
  63. package/config/client.config.ts +2 -95
  64. package/config/database.config.ts +2 -99
  65. package/config/fluxstack.config.ts +25 -45
  66. package/config/index.ts +57 -38
  67. package/config/monitoring.config.ts +2 -114
  68. package/config/plugins.config.ts +2 -80
  69. package/config/server.config.ts +2 -68
  70. package/config/services.config.ts +2 -130
  71. package/config/system/app.config.ts +29 -0
  72. package/config/system/build.config.ts +49 -0
  73. package/config/system/client.config.ts +68 -0
  74. package/config/system/database.config.ts +17 -0
  75. package/config/system/fluxstack.config.ts +114 -0
  76. package/config/{logger.config.ts → system/logger.config.ts} +3 -1
  77. package/config/system/monitoring.config.ts +114 -0
  78. package/config/system/plugins.config.ts +84 -0
  79. package/config/{runtime.config.ts → system/runtime.config.ts} +1 -1
  80. package/config/system/server.config.ts +68 -0
  81. package/config/system/services.config.ts +46 -0
  82. package/config/{system.config.ts → system/system.config.ts} +1 -1
  83. package/core/build/bundler.ts +4 -1
  84. package/core/build/flux-plugins-generator.ts +325 -325
  85. package/core/build/index.ts +159 -27
  86. package/core/build/live-components-generator.ts +70 -3
  87. package/core/build/optimizer.ts +235 -235
  88. package/core/cli/command-registry.ts +6 -4
  89. package/core/cli/commands/build.ts +79 -0
  90. package/core/cli/commands/create.ts +54 -0
  91. package/core/cli/commands/dev.ts +101 -0
  92. package/core/cli/commands/help.ts +34 -0
  93. package/core/cli/commands/index.ts +34 -0
  94. package/core/cli/commands/make-plugin.ts +90 -0
  95. package/core/cli/commands/plugin-add.ts +197 -0
  96. package/core/cli/commands/plugin-deps.ts +2 -2
  97. package/core/cli/commands/plugin-list.ts +208 -0
  98. package/core/cli/commands/plugin-remove.ts +170 -0
  99. package/core/cli/generators/component.ts +769 -769
  100. package/core/cli/generators/controller.ts +1 -1
  101. package/core/cli/generators/index.ts +146 -146
  102. package/core/cli/generators/interactive.ts +227 -227
  103. package/core/cli/generators/plugin.ts +2 -2
  104. package/core/cli/generators/prompts.ts +82 -82
  105. package/core/cli/generators/route.ts +6 -6
  106. package/core/cli/generators/service.ts +2 -2
  107. package/core/cli/generators/template-engine.ts +4 -3
  108. package/core/cli/generators/types.ts +2 -2
  109. package/core/cli/generators/utils.ts +191 -191
  110. package/core/cli/index.ts +115 -558
  111. package/core/cli/plugin-discovery.ts +2 -2
  112. package/core/client/LiveComponentsProvider.tsx +63 -17
  113. package/core/client/api/eden.ts +183 -0
  114. package/core/client/api/index.ts +11 -0
  115. package/core/client/components/Live.tsx +104 -0
  116. package/core/client/fluxstack.ts +1 -9
  117. package/core/client/hooks/AdaptiveChunkSizer.ts +215 -0
  118. package/core/client/hooks/state-validator.ts +1 -1
  119. package/core/client/hooks/useAuth.ts +48 -48
  120. package/core/client/hooks/useChunkedUpload.ts +170 -69
  121. package/core/client/hooks/useLiveChunkedUpload.ts +87 -0
  122. package/core/client/hooks/useLiveComponent.ts +800 -0
  123. package/core/client/hooks/useLiveUpload.ts +71 -0
  124. package/core/client/hooks/useRoom.ts +409 -0
  125. package/core/client/hooks/useRoomProxy.ts +382 -0
  126. package/core/client/index.ts +18 -51
  127. package/core/client/standalone-entry.ts +8 -0
  128. package/core/client/standalone.ts +74 -53
  129. package/core/client/state/createStore.ts +192 -192
  130. package/core/client/state/index.ts +14 -14
  131. package/core/config/index.ts +70 -291
  132. package/core/config/schema.ts +42 -723
  133. package/core/framework/client.ts +131 -131
  134. package/core/framework/index.ts +7 -7
  135. package/core/framework/server.ts +227 -47
  136. package/core/framework/types.ts +2 -2
  137. package/core/index.ts +23 -4
  138. package/core/live/ComponentRegistry.ts +7 -3
  139. package/core/live/types.ts +77 -0
  140. package/core/plugins/built-in/index.ts +134 -131
  141. package/core/plugins/built-in/live-components/commands/create-live-component.ts +242 -1074
  142. package/core/plugins/built-in/live-components/index.ts +1 -1
  143. package/core/plugins/built-in/monitoring/index.ts +111 -47
  144. package/core/plugins/built-in/static/index.ts +1 -1
  145. package/core/plugins/built-in/swagger/index.ts +68 -265
  146. package/core/plugins/built-in/vite/index.ts +94 -306
  147. package/core/plugins/built-in/vite/vite-dev.ts +82 -0
  148. package/core/plugins/config.ts +9 -7
  149. package/core/plugins/dependency-manager.ts +31 -1
  150. package/core/plugins/discovery.ts +19 -7
  151. package/core/plugins/executor.ts +2 -2
  152. package/core/plugins/index.ts +203 -203
  153. package/core/plugins/manager.ts +27 -39
  154. package/core/plugins/module-resolver.ts +19 -8
  155. package/core/plugins/registry.ts +309 -21
  156. package/core/plugins/types.ts +106 -55
  157. package/core/server/framework.ts +66 -43
  158. package/core/server/index.ts +15 -16
  159. package/core/server/live/ComponentRegistry.ts +91 -75
  160. package/core/server/live/FileUploadManager.ts +41 -31
  161. package/core/server/live/LiveComponentPerformanceMonitor.ts +1 -1
  162. package/core/server/live/LiveRoomManager.ts +261 -0
  163. package/core/server/live/RoomEventBus.ts +234 -0
  164. package/core/server/live/RoomStateManager.ts +172 -0
  165. package/core/server/live/StateSignature.ts +643 -643
  166. package/core/server/live/WebSocketConnectionManager.ts +30 -19
  167. package/core/server/live/auto-generated-components.ts +41 -26
  168. package/core/server/live/index.ts +14 -0
  169. package/core/server/live/websocket-plugin.ts +233 -72
  170. package/core/server/middleware/elysia-helpers.ts +7 -2
  171. package/core/server/middleware/errorHandling.ts +1 -1
  172. package/core/server/middleware/index.ts +31 -31
  173. package/core/server/plugins/database.ts +180 -180
  174. package/core/server/plugins/static-files-plugin.ts +69 -260
  175. package/core/server/plugins/swagger.ts +33 -33
  176. package/core/server/rooms/RoomBroadcaster.ts +357 -0
  177. package/core/server/rooms/RoomSystem.ts +463 -0
  178. package/core/server/rooms/index.ts +13 -0
  179. package/core/server/services/BaseService.ts +1 -1
  180. package/core/server/services/ServiceContainer.ts +1 -1
  181. package/core/server/services/index.ts +8 -8
  182. package/core/templates/create-project.ts +12 -12
  183. package/core/testing/index.ts +9 -9
  184. package/core/testing/setup.ts +73 -73
  185. package/core/types/api.ts +168 -168
  186. package/core/types/build.ts +219 -218
  187. package/core/types/config.ts +56 -26
  188. package/core/types/index.ts +4 -4
  189. package/core/types/plugin.ts +107 -99
  190. package/core/types/types.ts +490 -14
  191. package/core/utils/build-logger.ts +324 -324
  192. package/core/utils/config-schema.ts +480 -480
  193. package/core/utils/env.ts +2 -8
  194. package/core/utils/errors/codes.ts +114 -114
  195. package/core/utils/errors/handlers.ts +36 -1
  196. package/core/utils/errors/index.ts +49 -5
  197. package/core/utils/errors/middleware.ts +113 -113
  198. package/core/utils/helpers.ts +6 -16
  199. package/core/utils/index.ts +17 -17
  200. package/core/utils/logger/colors.ts +114 -114
  201. package/core/utils/logger/config.ts +13 -9
  202. package/core/utils/logger/formatter.ts +82 -82
  203. package/core/utils/logger/group-logger.ts +101 -101
  204. package/core/utils/logger/index.ts +6 -1
  205. package/core/utils/logger/stack-trace.ts +3 -1
  206. package/core/utils/logger/startup-banner.ts +82 -66
  207. package/core/utils/logger/winston-logger.ts +152 -152
  208. package/core/utils/monitoring/index.ts +211 -211
  209. package/core/utils/sync-version.ts +66 -66
  210. package/core/utils/version.ts +1 -1
  211. package/create-fluxstack.ts +8 -7
  212. package/eslint.config.js +23 -23
  213. package/package.json +14 -15
  214. package/plugins/crypto-auth/cli/make-protected-route.command.ts +1 -1
  215. package/plugins/crypto-auth/client/CryptoAuthClient.ts +302 -302
  216. package/plugins/crypto-auth/client/components/index.ts +11 -11
  217. package/plugins/crypto-auth/client/index.ts +11 -11
  218. package/plugins/crypto-auth/config/index.ts +1 -1
  219. package/plugins/crypto-auth/index.ts +4 -4
  220. package/plugins/crypto-auth/package.json +65 -65
  221. package/plugins/crypto-auth/server/AuthMiddleware.ts +1 -1
  222. package/plugins/crypto-auth/server/CryptoAuthService.ts +185 -185
  223. package/plugins/crypto-auth/server/index.ts +21 -21
  224. package/plugins/crypto-auth/server/middlewares/cryptoAuthAdmin.ts +3 -3
  225. package/plugins/crypto-auth/server/middlewares/cryptoAuthOptional.ts +1 -1
  226. package/plugins/crypto-auth/server/middlewares/cryptoAuthPermissions.ts +2 -2
  227. package/plugins/crypto-auth/server/middlewares/cryptoAuthRequired.ts +2 -2
  228. package/plugins/crypto-auth/server/middlewares/helpers.ts +1 -1
  229. package/plugins/crypto-auth/server/middlewares/index.ts +22 -22
  230. package/plugins/crypto-auth/server/middlewares.ts +19 -19
  231. package/tsconfig.api-strict.json +16 -0
  232. package/tsconfig.json +10 -14
  233. package/{app/client/tsconfig.node.json → tsconfig.node.json} +1 -1
  234. package/types/global.d.ts +29 -29
  235. package/types/vitest.d.ts +8 -8
  236. package/vite.config.ts +38 -62
  237. package/vitest.config.live.ts +10 -9
  238. package/vitest.config.ts +29 -17
  239. package/workspace.json +5 -5
  240. package/app/client/README.md +0 -69
  241. package/app/client/SIMPLIFICATION.md +0 -140
  242. package/app/client/frontend-only.ts +0 -12
  243. package/app/client/tsconfig.app.json +0 -44
  244. package/app/client/tsconfig.json +0 -7
  245. package/app/client/zustand-setup.md +0 -65
  246. package/app/server/backend-only.ts +0 -18
  247. package/app/server/live/LiveClockComponent.ts +0 -215
  248. package/app/server/routes/env-test.ts +0 -110
  249. package/core/client/hooks/index.ts +0 -7
  250. package/core/client/hooks/useHybridLiveComponent.ts +0 -631
  251. package/core/client/hooks/useWebSocket.ts +0 -373
  252. package/core/config/env.ts +0 -546
  253. package/core/config/loader.ts +0 -522
  254. package/core/config/runtime-config.ts +0 -327
  255. package/core/config/validator.ts +0 -540
  256. package/core/server/backend-entry.ts +0 -51
  257. package/core/server/standalone.ts +0 -106
  258. package/core/utils/regenerate-files.ts +0 -69
  259. package/fluxstack.config.ts +0 -354
@@ -1,343 +1,131 @@
1
- import type { FluxStack, PluginContext, RequestContext } from "@/core/plugins/types"
2
- import { createServer, type ViteDevServer } from 'vite'
3
- import { FLUXSTACK_VERSION } from "@/core/utils/version"
4
- import { clientConfig } from '@/config/client.config'
1
+ import type { FluxStack, PluginContext, RequestContext } from "@core/plugins/types"
2
+ import { FLUXSTACK_VERSION } from "@core/utils/version"
3
+ import { clientConfig } from '@config'
4
+ import { pluginsConfig } from '@config'
5
+ import { isDevelopment } from "@core/utils/helpers"
6
+ import { join } from "path"
7
+ import { statSync, existsSync } from "fs"
5
8
 
6
9
  type Plugin = FluxStack.Plugin
7
10
 
8
- let viteServer: ViteDevServer | null = null
11
+ const PLUGIN_PRIORITY = 800
12
+ const INDEX_FILE = "index.html"
9
13
 
10
- // Default configuration values (uses clientConfig from /config)
11
- const DEFAULTS = {
12
- enabled: true,
13
- port: clientConfig.vite.port,
14
- host: "localhost",
15
- checkInterval: 2000,
16
- maxRetries: 10,
17
- timeout: 5000,
18
- proxyPaths: [] as string[],
19
- excludePaths: [] as string[]
14
+ /** Create static file handler with cached base directory */
15
+ function createStaticFallback() {
16
+ // Discover base directory once
17
+ const baseDir = existsSync('client') ? 'client'
18
+ : existsSync('dist/client') ? 'dist/client'
19
+ : clientConfig.build.outDir ?? 'dist/client'
20
+
21
+ return (c: { request?: Request }) => {
22
+ const req = c.request
23
+ if (!req) return
24
+
25
+ let pathname = decodeURIComponent(new URL(req.url).pathname)
26
+ if (pathname === '/' || pathname === '') {
27
+ pathname = `/${INDEX_FILE}`
28
+ }
29
+
30
+ // Try to serve the requested file
31
+ const filePath = join(baseDir, pathname)
32
+ try {
33
+ if (statSync(filePath).isFile()) {
34
+ return Bun.file(filePath)
35
+ }
36
+ } catch {}
37
+
38
+ // SPA fallback: serve index.html
39
+ const indexPath = join(baseDir, INDEX_FILE)
40
+ try {
41
+ statSync(indexPath)
42
+ return Bun.file(indexPath)
43
+ } catch {}
44
+ }
20
45
  }
21
46
 
22
- /**
23
- * Helper to safely parse request.url which might be relative or absolute
24
- */
25
- function parseRequestURL(request: Request): URL {
47
+ /** Proxy request to Vite dev server */
48
+ async function proxyToVite(ctx: RequestContext): Promise<void> {
49
+ const { host, port } = clientConfig.vite
50
+
26
51
  try {
27
- // Try parsing as absolute URL first
28
- return new URL(request.url)
29
- } catch {
30
- // If relative, use host from headers or default to localhost
31
- const host = request.headers.get('host') || 'localhost'
32
- const protocol = request.headers.get('x-forwarded-proto') || 'http'
33
- return new URL(request.url, `${protocol}://${host}`)
52
+ // Parse URL (handle relative URLs)
53
+ let url: URL
54
+ try {
55
+ url = new URL(ctx.request.url)
56
+ } catch {
57
+ const reqHost = ctx.request.headers.get('host') || 'localhost'
58
+ const protocol = ctx.request.headers.get('x-forwarded-proto') || 'http'
59
+ url = new URL(ctx.request.url, `${protocol}://${reqHost}`)
60
+ }
61
+
62
+ const response = await fetch(`http://${host}:${port}${ctx.path}${url.search}`, {
63
+ method: ctx.method,
64
+ headers: ctx.headers,
65
+ body: ctx.method !== 'GET' && ctx.method !== 'HEAD' ? ctx.request.body : undefined
66
+ })
67
+
68
+ ctx.handled = true
69
+ ctx.response = new Response(await response.arrayBuffer(), {
70
+ status: response.status,
71
+ statusText: response.statusText,
72
+ headers: response.headers
73
+ })
74
+ } catch (error) {
75
+ if (clientConfig.vite.enableLogging) {
76
+ console.warn(`Vite proxy error: ${error}`)
77
+ }
34
78
  }
35
79
  }
36
80
 
37
81
  export const vitePlugin: Plugin = {
38
82
  name: "vite",
39
83
  version: FLUXSTACK_VERSION,
40
- description: "Enhanced Vite integration plugin for FluxStack with improved error handling and monitoring",
84
+ description: "Vite integration plugin for FluxStack",
41
85
  author: "FluxStack Team",
42
- priority: 800, // Should run early to setup proxying
86
+ priority: PLUGIN_PRIORITY,
43
87
  category: "development",
44
88
  tags: ["vite", "development", "hot-reload"],
45
89
  dependencies: [],
46
90
 
47
91
  setup: async (context: PluginContext) => {
48
- if (!DEFAULTS.enabled) {
49
- context.logger.debug('Vite plugin disabled or no client configuration found')
92
+ if (!pluginsConfig.viteEnabled) {
93
+ context.logger.debug('Vite plugin disabled')
50
94
  return
51
95
  }
52
96
 
53
- const vitePort = DEFAULTS.port || clientConfig.vite.port || 5173
54
- const viteHost = DEFAULTS.host || "localhost"
55
-
56
- // Import group logger utilities
57
- const { startGroup, endGroup, logInGroup } = await import('@/core/utils/logger/group-logger')
58
-
59
- try {
60
- // Start Vite dev server programmatically (silently)
61
- viteServer = await createServer({
62
- configFile: './vite.config.ts',
63
- // Don't override root - let vite.config.ts handle it
64
- server: {
65
- port: vitePort,
66
- host: viteHost,
67
- strictPort: true
68
- },
69
- logLevel: 'silent' // Suppress all Vite logs
70
- })
71
-
72
- await viteServer.listen()
73
-
74
- context.logger.debug(`Vite server started on ${viteHost}:${vitePort} (internal proxy)`)
75
- context.logger.debug('Hot reload coordination active')
76
-
77
- // Store Vite config in context for later use
78
- ; (context as any).viteConfig = {
79
- port: vitePort,
80
- host: viteHost,
81
- server: viteServer
82
- }
83
-
84
- // Setup cleanup on process exit
85
- const cleanup = async () => {
86
- if (viteServer) {
87
- context.logger.debug('🛑 Stopping Vite server...')
88
- await viteServer.close()
89
- viteServer = null
90
- }
91
- }
92
-
93
- process.on('SIGINT', cleanup)
94
- process.on('SIGTERM', cleanup)
95
- process.on('exit', cleanup)
96
-
97
- } catch (error) {
98
- // Check if error is related to port already in use
99
- const errorMessage = error instanceof Error ? error.message : String(error)
100
- const isPortInUse = errorMessage.includes('EADDRINUSE') ||
101
- errorMessage.includes('address already in use') ||
102
- errorMessage.includes('Port') && errorMessage.includes('is in use')
103
-
104
- if (isPortInUse) {
105
- endGroup()
106
- console.log('') // Separator line
107
- context.logger.error(`❌ Failed to start Vite: Port ${vitePort} is already in use`)
108
- context.logger.info(`💡 Try one of these solutions:`)
109
- context.logger.info(` 1. Stop the process using port ${vitePort}`)
110
- context.logger.info(` 2. Change VITE_PORT in your .env file`)
111
- context.logger.info(` 3. Kill the process: ${process.platform === 'win32' ? `netstat -ano | findstr :${vitePort}` : `lsof -ti:${vitePort} | xargs kill -9`}`)
112
- process.exit(1)
113
- } else {
114
- context.logger.error('❌ Failed to start Vite server:', errorMessage)
115
- context.logger.debug('Full error:', error)
116
- context.logger.debug('⚠️ Falling back to monitoring mode...')
117
-
118
- // Fallback to monitoring if programmatic start fails
119
- ; (context as any).viteConfig = {
120
- port: vitePort,
121
- host: viteHost
122
- }
123
- monitorVite(context, viteHost, vitePort)
124
- }
125
- }
126
- },
127
-
128
- onServerStart: async (context: PluginContext) => {
129
- const viteConfig = (context as any).viteConfig
130
-
131
- if (DEFAULTS.enabled && viteConfig) {
132
- context.logger.debug(`Vite integration active - monitoring ${viteConfig.host}:${viteConfig.port}`)
133
- }
134
- },
135
-
136
- onBeforeRoute: async (requestContext: RequestContext) => {
137
- // Skip API routes and swagger - let them be handled by backend
138
- if (requestContext.path.startsWith("/api") || requestContext.path.startsWith("/swagger")) {
97
+ if (!isDevelopment()) {
98
+ context.logger.debug("Production mode: static file serving enabled")
99
+ context.app.all('*', createStaticFallback())
139
100
  return
140
101
  }
141
102
 
142
- // For Vite internal routes, proxy directly to Vite server
143
- if (requestContext.path.startsWith("/@") || // All Vite internal routes (/@vite/, /@fs/, /@react-refresh, etc.)
144
- requestContext.path.startsWith("/__vite") || // Vite HMR and dev routes
145
- requestContext.path.startsWith("/node_modules") || // Direct node_modules access
146
- requestContext.path.includes("/.vite/") || // Vite cache and deps
147
- requestContext.path.endsWith(".js.map") || // Source maps
148
- requestContext.path.endsWith(".css.map")) { // CSS source maps
149
-
150
- // Use fixed configuration for Vite proxy
151
- const viteHost = "localhost"
152
- const vitePort = 5173
153
-
154
- try {
155
- const url = parseRequestURL(requestContext.request)
156
- const viteUrl = `http://${viteHost}:${vitePort}${requestContext.path}${url.search}`
157
-
158
- // Forward request to Vite
159
- const response = await fetch(viteUrl, {
160
- method: requestContext.method,
161
- headers: requestContext.headers,
162
- body: requestContext.method !== 'GET' && requestContext.method !== 'HEAD' ? requestContext.request.body : undefined
163
- })
164
-
165
- // Return the Vite response
166
- const body = await response.arrayBuffer()
103
+ const { setupViteDev } = await import('./vite-dev')
104
+ await setupViteDev(context)
105
+ },
167
106
 
168
- requestContext.handled = true
169
- requestContext.response = new Response(body, {
170
- status: response.status,
171
- statusText: response.statusText,
172
- headers: response.headers
173
- })
107
+ onServerStart: async (context: PluginContext) => {
108
+ if (!pluginsConfig.viteEnabled) return
174
109
 
175
- } catch (viteError) {
176
- // If Vite fails, let the request continue to normal routing (will become 404)
177
- // Only log if explicitly enabled for debugging
178
- const { clientConfig } = await import('@/config/client.config')
179
- if (clientConfig.vite.enableLogging) {
180
- console.warn(`Vite proxy error: ${viteError}`)
181
- }
182
- }
110
+ if (!isDevelopment()) {
111
+ context.logger.debug('Static files ready')
183
112
  return
184
113
  }
185
114
 
186
- // Use fixed configuration for simplicity - Vite should be running on port 5173
187
- const viteHost = "localhost"
188
- const vitePort = 5173
189
-
190
- try {
191
- const url = parseRequestURL(requestContext.request)
192
- const viteUrl = `http://${viteHost}:${vitePort}${requestContext.path}${url.search}`
193
-
194
- // Forward request to Vite
195
- const response = await fetch(viteUrl, {
196
- method: requestContext.method,
197
- headers: requestContext.headers,
198
- body: requestContext.method !== 'GET' && requestContext.method !== 'HEAD' ? requestContext.request.body : undefined
199
- })
200
-
201
- // If Vite responds successfully, handle the request
202
- if (response.ok || response.status < 500) {
203
- // Return a proper Response object with all headers and status
204
- const body = await response.arrayBuffer()
205
-
206
- requestContext.handled = true
207
- requestContext.response = new Response(body, {
208
- status: response.status,
209
- statusText: response.statusText,
210
- headers: response.headers
211
- })
212
- }
213
-
214
- } catch (viteError) {
215
- // If Vite fails, let the request continue to normal routing (will become 404)
216
- // Only log if explicitly enabled for debugging
217
- const { clientConfig } = await import('@/config/client.config')
218
- if (clientConfig.vite.enableLogging) {
219
- console.warn(`Vite proxy error: ${viteError}`)
220
- }
221
- }
222
- }
223
- }
224
-
225
- // Monitor Vite server status with automatic port detection
226
- async function monitorVite(
227
- context: PluginContext,
228
- host: string,
229
- initialPort: number
230
- ) {
231
- let retries = 0
232
- let isConnected = false
233
- let actualPort = initialPort
234
- let portDetected = false
235
-
236
- const checkVite = async () => {
237
- try {
238
- // If we haven't found the correct port yet, try to detect it
239
- if (!portDetected) {
240
- const detectedPort = await detectVitePort(host, initialPort)
241
- if (detectedPort !== null) {
242
- actualPort = detectedPort
243
- portDetected = true
244
- // Update the context with the detected port
245
- if ((context as any).viteConfig) {
246
- ; (context as any).viteConfig.port = actualPort
247
- }
248
- }
249
- }
250
-
251
- const isRunning = await checkViteRunning(host, actualPort, DEFAULTS.timeout)
252
-
253
- if (isRunning && !isConnected) {
254
- isConnected = true
255
- retries = 0
256
- if (actualPort !== initialPort) {
257
- context.logger.debug(`✓ Vite server detected on ${host}:${actualPort} (auto-detected from port ${initialPort})`)
258
- } else {
259
- context.logger.debug(`✓ Vite server detected on ${host}:${actualPort}`)
260
- }
261
- context.logger.debug("Hot reload coordination active")
262
- } else if (!isRunning && isConnected) {
263
- isConnected = false
264
- context.logger.warn(`✗ Vite server disconnected from ${host}:${actualPort}`)
265
- // Reset port detection when disconnected
266
- portDetected = false
267
- actualPort = initialPort
268
- } else if (!isRunning) {
269
- retries++
270
- if (retries <= DEFAULTS.maxRetries) {
271
- if (portDetected) {
272
- context.logger.debug(`Waiting for Vite server on ${host}:${actualPort}... (${retries}/${DEFAULTS.maxRetries})`)
273
- } else {
274
- context.logger.debug(`Detecting Vite server port... (${retries}/${DEFAULTS.maxRetries})`)
275
- }
276
- } else if (retries === DEFAULTS.maxRetries + 1) {
277
- context.logger.warn(`Vite server not found after ${DEFAULTS.maxRetries} attempts. Development features may be limited.`)
278
- }
279
- }
280
- } catch (error) {
281
- if (isConnected) {
282
- context.logger.error('Error checking Vite server status', { error })
283
- }
284
- }
285
-
286
- // Continue monitoring
287
- setTimeout(checkVite, DEFAULTS.checkInterval)
288
- }
115
+ context.logger.debug(`Vite active - ${clientConfig.vite.host}:${clientConfig.vite.port}`)
116
+ },
289
117
 
290
- // Start monitoring after a brief delay
291
- setTimeout(checkVite, 1000)
292
- }
118
+ onBeforeRoute: async (ctx: RequestContext) => {
119
+ if (!isDevelopment()) return
293
120
 
294
- // Auto-detect Vite port by trying common ports
295
- async function detectVitePort(host: string, startPort: number): Promise<number | null> {
296
- // Try the initial port first, then common alternatives
297
- const portsToTry = [
298
- startPort,
299
- startPort + 1,
300
- startPort + 2,
301
- startPort + 3,
302
- 5174, // Common Vite alternative
303
- 5175,
304
- 5176,
305
- 3000, // Sometimes Vite might use this
306
- 4173 // Another common alternative
307
- ]
121
+ const shouldSkip = (pluginsConfig.viteExcludePaths ?? []).some(prefix =>
122
+ ctx.path === prefix || ctx.path.startsWith(prefix + '/')
123
+ )
308
124
 
309
- for (const port of portsToTry) {
310
- try {
311
- const isRunning = await checkViteRunning(host, port, 1000)
312
- if (isRunning) {
313
- return port
314
- }
315
- } catch (error) {
316
- // Continue trying other ports
125
+ if (!shouldSkip) {
126
+ await proxyToVite(ctx)
317
127
  }
318
128
  }
319
-
320
- return null
321
- }
322
-
323
- // Check if Vite is running
324
- async function checkViteRunning(host: string, port: number, timeout: number = 1000): Promise<boolean> {
325
- try {
326
- const controller = new AbortController()
327
- const timeoutId = setTimeout(() => controller.abort(), timeout)
328
-
329
- const response = await fetch(`http://${host}:${port}`, {
330
- signal: controller.signal,
331
- method: 'HEAD' // Use HEAD to minimize data transfer
332
- })
333
-
334
- clearTimeout(timeoutId)
335
- return response.status >= 200 && response.status < 500
336
- } catch (error) {
337
- return false
338
- }
339
129
  }
340
130
 
341
- // Note: Proxy logic is now handled directly in the onBeforeRoute hook above
342
-
343
- export default vitePlugin
131
+ export default vitePlugin
@@ -0,0 +1,82 @@
1
+ import type { PluginContext } from "@core/plugins/types"
2
+ import { clientConfig } from '@config'
3
+ import type { LogLevel } from "vite"
4
+ import conf from "@/vite.config"
5
+ // Dynamic import t@ype for vite
6
+ type ViteDevServer = Awaited<ReturnType<typeof import('vite')['createServer']>>
7
+
8
+ // Store vite server instance
9
+ let viteServer: ViteDevServer | null = null
10
+
11
+ /**
12
+ * Setup Vite development server
13
+ * This file is only imported in development mode
14
+ */
15
+ export async function setupViteDev(context: PluginContext): Promise<void> {
16
+ const vitePort = clientConfig.vite.port || 5173
17
+ const viteHost = clientConfig.vite.host || "localhost"
18
+ const logLevel = clientConfig.vite.logLevel as LogLevel
19
+ // Import group logger utilities
20
+ const { endGroup } = await import('@core/utils/logger/group-logger')
21
+
22
+ try {
23
+ // Dynamic import of vite
24
+ const { createServer } = await import('vite')
25
+ // Start Vite dev server programmatically (silently)
26
+ viteServer = await createServer({
27
+ configFile: './vite.config.ts',
28
+ server: {
29
+ port: vitePort,
30
+ host: viteHost,
31
+ strictPort: true
32
+ },
33
+ logLevel: logLevel
34
+ })
35
+
36
+ await viteServer.listen()
37
+
38
+ context.logger.debug(`Vite server started on ${viteHost}:${vitePort} (internal proxy)`)
39
+ context.logger.debug('Hot reload coordination active')
40
+
41
+ // Store Vite config in context for later use
42
+ ;(context as any).viteConfig = {
43
+ port: vitePort,
44
+ host: viteHost,
45
+ server: viteServer
46
+ }
47
+
48
+ // Setup cleanup on process exit
49
+ const cleanup = async () => {
50
+ if (viteServer) {
51
+ context.logger.debug('🛑 Stopping Vite server...')
52
+ await viteServer.close()
53
+ viteServer = null
54
+ }
55
+ }
56
+
57
+ process.on('SIGINT', cleanup)
58
+ process.on('SIGTERM', cleanup)
59
+ process.on('exit', cleanup)
60
+
61
+ } catch (error) {
62
+ // Check if error is related to port already in use
63
+ const errorMessage = error instanceof Error ? error.message : String(error)
64
+ const isPortInUse = errorMessage.includes('EADDRINUSE') ||
65
+ errorMessage.includes('address already in use') ||
66
+ errorMessage.includes('Port') && errorMessage.includes('is in use')
67
+
68
+ if (isPortInUse) {
69
+ endGroup()
70
+ console.log('') // Separator line
71
+ context.logger.error(`❌ Failed to start Vite: Port ${vitePort} is already in use`)
72
+ context.logger.info(`💡 Try one of these solutions:`)
73
+ context.logger.info(` 1. Stop the process using port ${vitePort}`)
74
+ context.logger.info(` 2. Change VITE_PORT in your .env file`)
75
+ context.logger.info(` 3. Kill the process: ${process.platform === 'win32' ? `netstat -ano | findstr :${vitePort}` : `lsof -ti:${vitePort} | xargs kill -9`}`)
76
+ process.exit(1)
77
+ } else {
78
+ context.logger.error('❌ Failed to start Vite server:', errorMessage)
79
+ context.logger.debug('Full error:', error)
80
+ }
81
+ }
82
+ }
@@ -4,8 +4,8 @@
4
4
  */
5
5
 
6
6
  import type { FluxStack, PluginConfigSchema, PluginValidationResult } from "./types"
7
- import type { FluxStackConfig } from "@/core/config/schema"
8
- import type { Logger } from "@/core/utils/logger/index"
7
+ import type { FluxStackConfig } from "@config"
8
+ import type { Logger } from "@core/utils/logger/index"
9
9
 
10
10
  type Plugin = FluxStack.Plugin
11
11
 
@@ -61,19 +61,21 @@ export class DefaultPluginConfigManager implements PluginConfigManager {
61
61
 
62
62
  /**
63
63
  * Get plugin configuration from main config
64
+ * @deprecated Plugin configs are now directly accessed from config.plugins
64
65
  */
65
66
  getPluginConfig(pluginName: string, config: FluxStackConfig): any {
66
- return config.plugins.config[pluginName] || {}
67
+ // Plugin configs are now accessed directly from config.plugins
68
+ // Example: config.plugins.swaggerEnabled
69
+ return {}
67
70
  }
68
71
 
69
72
  /**
70
73
  * Set plugin configuration in main config
74
+ * @deprecated Plugin configs are now set via environment variables and config files
71
75
  */
72
76
  setPluginConfig(pluginName: string, pluginConfig: any, config: FluxStackConfig): void {
73
- if (!config.plugins.config) {
74
- config.plugins.config = {}
75
- }
76
- config.plugins.config[pluginName] = pluginConfig
77
+ // Plugin configs are now set via environment variables and config files
78
+ // This function is deprecated and does nothing
77
79
  }
78
80
 
79
81
  /**
@@ -6,7 +6,7 @@
6
6
  import { existsSync, readFileSync, writeFileSync } from 'fs'
7
7
  import { join, resolve } from 'path'
8
8
  import { execSync } from 'child_process'
9
- import type { Logger } from '@/core/utils/logger'
9
+ import type { Logger } from '@core/utils/logger'
10
10
 
11
11
  export interface PluginDependency {
12
12
  name: string
@@ -230,6 +230,36 @@ export class PluginDependencyManager {
230
230
  }
231
231
  }
232
232
 
233
+ /**
234
+ * Instalar dependências diretamente em um path específico
235
+ */
236
+ async installDependenciesInPath(pluginPath: string, dependencies: Record<string, string>): Promise<void> {
237
+ if (!this.config.autoInstall) {
238
+ this.logger?.debug('Auto-instalação desabilitada')
239
+ return
240
+ }
241
+
242
+ if (Object.keys(dependencies).length === 0) {
243
+ return
244
+ }
245
+
246
+ const pluginDeps: PluginDependency[] = Object.entries(dependencies).map(([name, version]) => ({
247
+ name,
248
+ version,
249
+ type: 'dependency'
250
+ }))
251
+
252
+ this.logger?.debug(`📦 Instalando ${pluginDeps.length} dependência(s) em ${pluginPath}`)
253
+
254
+ try {
255
+ await this.installPluginDependenciesLocally(pluginPath, pluginDeps)
256
+ this.logger?.debug(`✅ Dependências instaladas com sucesso em ${pluginPath}`)
257
+ } catch (error) {
258
+ this.logger?.error(`❌ Erro ao instalar dependências em ${pluginPath}`, { error })
259
+ throw error
260
+ }
261
+ }
262
+
233
263
  /**
234
264
  * Encontrar diretório de um plugin pelo nome
235
265
  */
@@ -4,7 +4,7 @@
4
4
  */
5
5
 
6
6
  import type { FluxStack, PluginManifest, PluginLoadResult, PluginDiscoveryOptions } from "./types"
7
- import type { Logger } from "@/core/utils/logger/index"
7
+ import type { Logger } from "@core/utils/logger/index"
8
8
  import { readdir, readFile } from "fs/promises"
9
9
  import { join, resolve } from "path"
10
10
  import { existsSync } from "fs"
@@ -306,12 +306,24 @@ export class PluginDiscovery {
306
306
  * Validate if an object is a valid plugin
307
307
  */
308
308
  private isValidPlugin(plugin: any): plugin is Plugin {
309
- return (
310
- plugin &&
311
- typeof plugin === 'object' &&
312
- typeof plugin.name === 'string' &&
313
- plugin.name.length > 0
314
- )
309
+ if (!plugin || typeof plugin !== 'object' || typeof plugin.name !== 'string' || plugin.name.length === 0) {
310
+ return false
311
+ }
312
+
313
+ const hookNames = [
314
+ 'setup', 'onConfigLoad', 'onBeforeServerStart', 'onServerStart',
315
+ 'onAfterServerStart', 'onBeforeServerStop', 'onServerStop',
316
+ 'onRequest', 'onResponse', 'onError'
317
+ ]
318
+
319
+ for (const hook of hookNames) {
320
+ if (hook in plugin && typeof plugin[hook] !== 'function') {
321
+ this.logger?.warn(`Plugin "${plugin.name}" has invalid hook "${hook}" (expected function, got ${typeof plugin[hook]})`)
322
+ return false
323
+ }
324
+ }
325
+
326
+ return true
315
327
  }
316
328
 
317
329
  /**
@@ -10,8 +10,8 @@ import type {
10
10
  PluginPriority,
11
11
  HookExecutionOptions
12
12
  } from "./types"
13
- import type { Logger } from "@/core/utils/logger/index"
14
- import { FluxStackError } from "@/core/utils/errors"
13
+ import type { Logger } from "@core/utils/logger/index"
14
+ import { FluxStackError } from "@core/utils/errors"
15
15
 
16
16
  export interface PluginExecutionPlan {
17
17
  hook: PluginHook