create-fluxstack 1.10.1 → 1.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (257) hide show
  1. package/.dockerignore +1 -2
  2. package/Dockerfile +8 -8
  3. package/LLMD/INDEX.md +64 -0
  4. package/LLMD/MAINTENANCE.md +197 -0
  5. package/LLMD/MIGRATION.md +156 -0
  6. package/LLMD/config/.gitkeep +1 -0
  7. package/LLMD/config/declarative-system.md +268 -0
  8. package/LLMD/config/environment-vars.md +327 -0
  9. package/LLMD/config/runtime-reload.md +401 -0
  10. package/LLMD/core/.gitkeep +1 -0
  11. package/LLMD/core/build-system.md +599 -0
  12. package/LLMD/core/framework-lifecycle.md +229 -0
  13. package/LLMD/core/plugin-system.md +451 -0
  14. package/LLMD/patterns/.gitkeep +1 -0
  15. package/LLMD/patterns/anti-patterns.md +297 -0
  16. package/LLMD/patterns/project-structure.md +264 -0
  17. package/LLMD/patterns/type-safety.md +440 -0
  18. package/LLMD/reference/.gitkeep +1 -0
  19. package/LLMD/reference/cli-commands.md +250 -0
  20. package/LLMD/reference/plugin-hooks.md +357 -0
  21. package/LLMD/reference/routing.md +39 -0
  22. package/LLMD/reference/troubleshooting.md +364 -0
  23. package/LLMD/resources/.gitkeep +1 -0
  24. package/LLMD/resources/controllers.md +465 -0
  25. package/LLMD/resources/live-components.md +703 -0
  26. package/LLMD/resources/live-rooms.md +482 -0
  27. package/LLMD/resources/live-upload.md +130 -0
  28. package/LLMD/resources/plugins-external.md +617 -0
  29. package/LLMD/resources/routes-eden.md +254 -0
  30. package/README.md +37 -17
  31. package/app/client/index.html +0 -1
  32. package/app/client/src/App.tsx +107 -150
  33. package/app/client/src/components/AppLayout.tsx +68 -0
  34. package/app/client/src/components/BackButton.tsx +13 -0
  35. package/app/client/src/components/DemoPage.tsx +20 -0
  36. package/app/client/src/components/LiveUploadWidget.tsx +204 -0
  37. package/app/client/src/lib/eden-api.ts +85 -60
  38. package/app/client/src/live/ChatDemo.tsx +107 -0
  39. package/app/client/src/live/CounterDemo.tsx +206 -0
  40. package/app/client/src/live/FormDemo.tsx +119 -0
  41. package/app/client/src/live/RoomChatDemo.tsx +242 -0
  42. package/app/client/src/live/UploadDemo.tsx +21 -0
  43. package/app/client/src/main.tsx +4 -1
  44. package/app/client/src/pages/ApiTestPage.tsx +108 -0
  45. package/app/client/src/pages/HomePage.tsx +76 -0
  46. package/app/server/app.ts +1 -4
  47. package/app/server/controllers/users.controller.ts +36 -44
  48. package/app/server/index.ts +25 -35
  49. package/app/server/live/LiveChat.ts +77 -0
  50. package/app/server/live/LiveCounter.ts +67 -0
  51. package/app/server/live/LiveForm.ts +63 -0
  52. package/app/server/live/LiveLocalCounter.ts +32 -0
  53. package/app/server/live/LiveRoomChat.ts +285 -0
  54. package/app/server/live/LiveUpload.ts +81 -0
  55. package/app/server/routes/index.ts +3 -1
  56. package/app/server/routes/room.routes.ts +117 -0
  57. package/app/server/routes/users.routes.ts +35 -27
  58. package/app/shared/types/index.ts +14 -2
  59. package/config/app.config.ts +2 -62
  60. package/config/client.config.ts +2 -95
  61. package/config/database.config.ts +2 -99
  62. package/config/fluxstack.config.ts +25 -45
  63. package/config/index.ts +57 -38
  64. package/config/monitoring.config.ts +2 -114
  65. package/config/plugins.config.ts +2 -80
  66. package/config/server.config.ts +2 -68
  67. package/config/services.config.ts +2 -130
  68. package/config/system/app.config.ts +29 -0
  69. package/config/system/build.config.ts +49 -0
  70. package/config/system/client.config.ts +68 -0
  71. package/config/system/database.config.ts +17 -0
  72. package/config/system/fluxstack.config.ts +114 -0
  73. package/config/{logger.config.ts → system/logger.config.ts} +3 -1
  74. package/config/system/monitoring.config.ts +114 -0
  75. package/config/system/plugins.config.ts +84 -0
  76. package/config/{runtime.config.ts → system/runtime.config.ts} +1 -1
  77. package/config/system/server.config.ts +68 -0
  78. package/config/system/services.config.ts +46 -0
  79. package/config/{system.config.ts → system/system.config.ts} +1 -1
  80. package/core/build/flux-plugins-generator.ts +325 -325
  81. package/core/build/index.ts +39 -27
  82. package/core/build/live-components-generator.ts +3 -3
  83. package/core/build/optimizer.ts +235 -235
  84. package/core/cli/command-registry.ts +6 -4
  85. package/core/cli/commands/build.ts +79 -0
  86. package/core/cli/commands/create.ts +54 -0
  87. package/core/cli/commands/dev.ts +101 -0
  88. package/core/cli/commands/help.ts +34 -0
  89. package/core/cli/commands/index.ts +34 -0
  90. package/core/cli/commands/make-plugin.ts +90 -0
  91. package/core/cli/commands/plugin-add.ts +197 -0
  92. package/core/cli/commands/plugin-deps.ts +2 -2
  93. package/core/cli/commands/plugin-list.ts +208 -0
  94. package/core/cli/commands/plugin-remove.ts +170 -0
  95. package/core/cli/generators/component.ts +769 -769
  96. package/core/cli/generators/controller.ts +1 -1
  97. package/core/cli/generators/index.ts +146 -146
  98. package/core/cli/generators/interactive.ts +227 -227
  99. package/core/cli/generators/plugin.ts +2 -2
  100. package/core/cli/generators/prompts.ts +82 -82
  101. package/core/cli/generators/route.ts +6 -6
  102. package/core/cli/generators/service.ts +2 -2
  103. package/core/cli/generators/template-engine.ts +4 -3
  104. package/core/cli/generators/types.ts +2 -2
  105. package/core/cli/generators/utils.ts +191 -191
  106. package/core/cli/index.ts +115 -686
  107. package/core/cli/plugin-discovery.ts +2 -2
  108. package/core/client/LiveComponentsProvider.tsx +60 -8
  109. package/core/client/api/eden.ts +183 -0
  110. package/core/client/api/index.ts +11 -0
  111. package/core/client/components/Live.tsx +104 -0
  112. package/core/client/fluxstack.ts +1 -9
  113. package/core/client/hooks/AdaptiveChunkSizer.ts +215 -215
  114. package/core/client/hooks/state-validator.ts +1 -1
  115. package/core/client/hooks/useAuth.ts +48 -48
  116. package/core/client/hooks/useChunkedUpload.ts +85 -35
  117. package/core/client/hooks/useLiveChunkedUpload.ts +87 -0
  118. package/core/client/hooks/useLiveComponent.ts +800 -0
  119. package/core/client/hooks/useLiveUpload.ts +71 -0
  120. package/core/client/hooks/useRoom.ts +409 -0
  121. package/core/client/hooks/useRoomProxy.ts +382 -0
  122. package/core/client/index.ts +17 -68
  123. package/core/client/standalone-entry.ts +8 -0
  124. package/core/client/standalone.ts +74 -53
  125. package/core/client/state/createStore.ts +192 -192
  126. package/core/client/state/index.ts +14 -14
  127. package/core/config/index.ts +70 -291
  128. package/core/config/schema.ts +42 -723
  129. package/core/framework/client.ts +131 -131
  130. package/core/framework/index.ts +7 -7
  131. package/core/framework/server.ts +47 -40
  132. package/core/framework/types.ts +2 -2
  133. package/core/index.ts +23 -4
  134. package/core/live/ComponentRegistry.ts +3 -3
  135. package/core/live/types.ts +77 -0
  136. package/core/plugins/built-in/index.ts +134 -134
  137. package/core/plugins/built-in/live-components/commands/create-live-component.ts +242 -1066
  138. package/core/plugins/built-in/live-components/index.ts +1 -1
  139. package/core/plugins/built-in/monitoring/index.ts +111 -47
  140. package/core/plugins/built-in/static/index.ts +1 -1
  141. package/core/plugins/built-in/swagger/index.ts +68 -265
  142. package/core/plugins/built-in/vite/index.ts +85 -185
  143. package/core/plugins/built-in/vite/vite-dev.ts +10 -16
  144. package/core/plugins/config.ts +9 -7
  145. package/core/plugins/dependency-manager.ts +31 -1
  146. package/core/plugins/discovery.ts +19 -7
  147. package/core/plugins/executor.ts +2 -2
  148. package/core/plugins/index.ts +203 -203
  149. package/core/plugins/manager.ts +27 -39
  150. package/core/plugins/module-resolver.ts +19 -8
  151. package/core/plugins/registry.ts +255 -19
  152. package/core/plugins/types.ts +20 -53
  153. package/core/server/framework.ts +66 -43
  154. package/core/server/index.ts +15 -15
  155. package/core/server/live/ComponentRegistry.ts +78 -71
  156. package/core/server/live/FileUploadManager.ts +23 -10
  157. package/core/server/live/LiveComponentPerformanceMonitor.ts +1 -1
  158. package/core/server/live/LiveRoomManager.ts +261 -0
  159. package/core/server/live/RoomEventBus.ts +234 -0
  160. package/core/server/live/RoomStateManager.ts +172 -0
  161. package/core/server/live/StateSignature.ts +643 -643
  162. package/core/server/live/WebSocketConnectionManager.ts +30 -19
  163. package/core/server/live/auto-generated-components.ts +21 -9
  164. package/core/server/live/index.ts +14 -0
  165. package/core/server/live/websocket-plugin.ts +214 -67
  166. package/core/server/middleware/elysia-helpers.ts +7 -2
  167. package/core/server/middleware/errorHandling.ts +1 -1
  168. package/core/server/middleware/index.ts +31 -31
  169. package/core/server/plugins/database.ts +180 -180
  170. package/core/server/plugins/static-files-plugin.ts +69 -69
  171. package/core/server/plugins/swagger.ts +1 -1
  172. package/core/server/rooms/RoomBroadcaster.ts +357 -0
  173. package/core/server/rooms/RoomSystem.ts +463 -0
  174. package/core/server/rooms/index.ts +13 -0
  175. package/core/server/services/BaseService.ts +1 -1
  176. package/core/server/services/ServiceContainer.ts +1 -1
  177. package/core/server/services/index.ts +8 -8
  178. package/core/templates/create-project.ts +12 -12
  179. package/core/testing/index.ts +9 -9
  180. package/core/testing/setup.ts +73 -73
  181. package/core/types/api.ts +168 -168
  182. package/core/types/build.ts +219 -219
  183. package/core/types/config.ts +56 -26
  184. package/core/types/index.ts +4 -4
  185. package/core/types/plugin.ts +107 -107
  186. package/core/types/types.ts +353 -14
  187. package/core/utils/build-logger.ts +324 -324
  188. package/core/utils/config-schema.ts +480 -480
  189. package/core/utils/env.ts +2 -8
  190. package/core/utils/errors/codes.ts +114 -114
  191. package/core/utils/errors/handlers.ts +36 -1
  192. package/core/utils/errors/index.ts +49 -5
  193. package/core/utils/errors/middleware.ts +113 -113
  194. package/core/utils/helpers.ts +6 -16
  195. package/core/utils/index.ts +17 -17
  196. package/core/utils/logger/colors.ts +114 -114
  197. package/core/utils/logger/config.ts +13 -9
  198. package/core/utils/logger/formatter.ts +82 -82
  199. package/core/utils/logger/group-logger.ts +101 -101
  200. package/core/utils/logger/index.ts +6 -1
  201. package/core/utils/logger/stack-trace.ts +3 -1
  202. package/core/utils/logger/startup-banner.ts +82 -82
  203. package/core/utils/logger/winston-logger.ts +152 -152
  204. package/core/utils/monitoring/index.ts +211 -211
  205. package/core/utils/sync-version.ts +66 -66
  206. package/core/utils/version.ts +1 -1
  207. package/create-fluxstack.ts +8 -7
  208. package/package.json +12 -13
  209. package/plugins/crypto-auth/cli/make-protected-route.command.ts +1 -1
  210. package/plugins/crypto-auth/client/CryptoAuthClient.ts +302 -302
  211. package/plugins/crypto-auth/client/components/index.ts +11 -11
  212. package/plugins/crypto-auth/client/index.ts +11 -11
  213. package/plugins/crypto-auth/config/index.ts +1 -1
  214. package/plugins/crypto-auth/index.ts +4 -4
  215. package/plugins/crypto-auth/package.json +65 -65
  216. package/plugins/crypto-auth/server/AuthMiddleware.ts +1 -1
  217. package/plugins/crypto-auth/server/CryptoAuthService.ts +185 -185
  218. package/plugins/crypto-auth/server/index.ts +21 -21
  219. package/plugins/crypto-auth/server/middlewares/cryptoAuthAdmin.ts +3 -3
  220. package/plugins/crypto-auth/server/middlewares/cryptoAuthOptional.ts +1 -1
  221. package/plugins/crypto-auth/server/middlewares/cryptoAuthPermissions.ts +2 -2
  222. package/plugins/crypto-auth/server/middlewares/cryptoAuthRequired.ts +2 -2
  223. package/plugins/crypto-auth/server/middlewares/helpers.ts +1 -1
  224. package/plugins/crypto-auth/server/middlewares/index.ts +22 -22
  225. package/tsconfig.api-strict.json +16 -0
  226. package/tsconfig.json +48 -52
  227. package/{app/client/tsconfig.node.json → tsconfig.node.json} +25 -25
  228. package/types/global.d.ts +29 -29
  229. package/types/vitest.d.ts +8 -8
  230. package/vite.config.ts +38 -62
  231. package/vitest.config.live.ts +10 -9
  232. package/vitest.config.ts +29 -17
  233. package/app/client/README.md +0 -69
  234. package/app/client/SIMPLIFICATION.md +0 -140
  235. package/app/client/frontend-only.ts +0 -12
  236. package/app/client/src/live/FileUploadExample.tsx +0 -359
  237. package/app/client/src/live/MinimalLiveClock.tsx +0 -47
  238. package/app/client/src/live/QuickUploadTest.tsx +0 -193
  239. package/app/client/tsconfig.app.json +0 -45
  240. package/app/client/tsconfig.json +0 -7
  241. package/app/client/zustand-setup.md +0 -65
  242. package/app/server/backend-only.ts +0 -18
  243. package/app/server/live/LiveClockComponent.ts +0 -215
  244. package/app/server/live/LiveFileUploadComponent.ts +0 -77
  245. package/app/server/routes/env-test.ts +0 -110
  246. package/core/client/hooks/index.ts +0 -7
  247. package/core/client/hooks/useHybridLiveComponent.ts +0 -685
  248. package/core/client/hooks/useTypedLiveComponent.ts +0 -133
  249. package/core/client/hooks/useWebSocket.ts +0 -361
  250. package/core/config/env.ts +0 -546
  251. package/core/config/loader.ts +0 -522
  252. package/core/config/runtime-config.ts +0 -327
  253. package/core/config/validator.ts +0 -540
  254. package/core/server/backend-entry.ts +0 -51
  255. package/core/server/standalone.ts +0 -106
  256. package/core/utils/regenerate-files.ts +0 -69
  257. package/fluxstack.config.ts +0 -354
@@ -1,326 +1,326 @@
1
- // 🚀 FluxStack Plugins - Auto Registration Generator
2
- // Automatically generates plugin registration during build time
3
-
4
- import { existsSync, readdirSync, writeFileSync, unlinkSync, readFileSync, statSync } from 'fs'
5
- import { join, extname, basename } from 'path'
6
- import { buildLogger } from '../utils/build-logger'
7
-
8
- export interface PluginInfo {
9
- pluginDir: string
10
- pluginName: string
11
- entryFile: string
12
- relativePath: string
13
- type: 'external' | 'built-in'
14
- }
15
-
16
- export class FluxPluginsGenerator {
17
- private pluginsPath: string
18
- private builtInPluginsPath: string
19
- private registrationFilePath: string
20
- private backupFilePath: string
21
-
22
- constructor() {
23
- this.pluginsPath = join(process.cwd(), 'plugins')
24
- this.builtInPluginsPath = join(process.cwd(), 'core', 'plugins', 'built-in')
25
- this.registrationFilePath = join(process.cwd(), 'core', 'plugins', 'auto-registry.ts')
26
- this.backupFilePath = join(process.cwd(), 'core', 'plugins', 'auto-registry.backup.ts')
27
- }
28
-
29
- /**
30
- * Scan plugin directories and discover external plugins only
31
- * Built-in plugins are handled by the core system
32
- */
33
- discoverPlugins(): PluginInfo[] {
34
- const plugins: PluginInfo[] = []
35
-
36
- // Discover external plugins only
37
- if (existsSync(this.pluginsPath)) {
38
- const externalPlugins = this.discoverPluginsInDirectory(this.pluginsPath, 'external')
39
- plugins.push(...externalPlugins)
40
- }
41
-
42
- // Note: Built-in plugins are automatically loaded by core system
43
- // No need to include them in auto-generation
44
-
45
- return plugins
46
- }
47
-
48
- /**
49
- * Discover plugins in a specific directory
50
- */
51
- private discoverPluginsInDirectory(directory: string, type: 'external' | 'built-in'): PluginInfo[] {
52
- const plugins: PluginInfo[] = []
53
-
54
- try {
55
- const entries = readdirSync(directory)
56
-
57
- for (const entry of entries) {
58
- const pluginDir = join(directory, entry)
59
-
60
- // Skip files, only process directories
61
- if (!statSync(pluginDir).isDirectory()) {
62
- continue
63
- }
64
-
65
- // Look for plugin entry point
66
- const entryFile = this.findPluginEntryFile(pluginDir)
67
- if (entryFile) {
68
- const relativePath = type === 'external'
69
- ? `../../plugins/${entry}`
70
- : `./built-in/${entry}`
71
-
72
- plugins.push({
73
- pluginDir,
74
- pluginName: entry,
75
- entryFile,
76
- relativePath,
77
- type
78
- })
79
-
80
- buildLogger.step(`Discovered ${type} plugin: ${entry} (${entryFile})`)
81
- } else {
82
- buildLogger.warn(`Plugin '${entry}' has no valid entry point`)
83
- }
84
- }
85
- } catch (error) {
86
- // Silently skip directories that can't be scanned
87
- }
88
-
89
- return plugins
90
- }
91
-
92
- /**
93
- * Find the main plugin entry file
94
- */
95
- private findPluginEntryFile(pluginDir: string): string | null {
96
- const possibleFiles = [
97
- 'index.ts',
98
- 'index',
99
- 'plugin.ts',
100
- 'plugin',
101
- 'src/index.ts',
102
- 'src/index',
103
- 'dist/index'
104
- ]
105
-
106
- for (const file of possibleFiles) {
107
- const filePath = join(pluginDir, file)
108
- if (existsSync(filePath)) {
109
- return basename(file)
110
- }
111
- }
112
-
113
- return null
114
- }
115
-
116
- /**
117
- * Generate the registration file with all discovered plugins
118
- */
119
- generateRegistrationFile(plugins: PluginInfo[]): void {
120
- // Backup existing file if it exists
121
- if (existsSync(this.registrationFilePath)) {
122
- const existingContent = readFileSync(this.registrationFilePath, 'utf-8')
123
- writeFileSync(this.backupFilePath, existingContent)
124
- }
125
-
126
- // All discovered plugins are external (built-in are handled by core)
127
- const externalPlugins = plugins
128
-
129
- // Generate imports
130
- const imports = plugins
131
- .map(plugin => {
132
- const importName = this.getImportName(plugin.pluginName)
133
- const importPath = plugin.entryFile === 'index.ts' || plugin.entryFile === 'index'
134
- ? plugin.relativePath
135
- : `${plugin.relativePath}/${plugin.entryFile.replace(/\.(ts|js)$/, '')}`
136
- return `import ${importName} from "${importPath}"`
137
- })
138
- .join('\n')
139
-
140
- // Generate plugin array
141
- const pluginsList = plugins
142
- .map(plugin => {
143
- const importName = this.getImportName(plugin.pluginName)
144
- return ` ${importName}`
145
- })
146
- .join(',\n')
147
-
148
- // Generate file content
149
- const fileContent = `// 🔥 Auto-generated FluxStack External Plugins Registry
150
- // This file is automatically generated during build time - DO NOT EDIT MANUALLY
151
- // Built-in plugins are handled by the core system automatically
152
- // Generated at: ${new Date().toISOString()}
153
-
154
- import type { Plugin } from './types'
155
-
156
- ${imports}
157
-
158
- // Auto-discovered external plugins array
159
- export const discoveredPlugins: Plugin[] = [
160
- ${pluginsList}
161
- ]
162
-
163
- // All discovered plugins are external (built-in handled by core)
164
- export const externalPlugins = discoveredPlugins
165
-
166
- // Plugin registration function
167
- export async function registerDiscoveredPlugins(registry: any): Promise<void> {
168
- if (discoveredPlugins.length === 0) {
169
- console.log('📦 No external plugins to register')
170
- return
171
- }
172
-
173
- console.log(\`📦 Registering \${discoveredPlugins.length} auto-discovered external plugins...\`)
174
-
175
- let registered = 0
176
- let failed = 0
177
-
178
- for (const plugin of discoveredPlugins) {
179
- try {
180
- await registry.register(plugin)
181
- registered++
182
- console.log(\`✅ Registered external plugin: \${plugin.name}\`)
183
- } catch (error) {
184
- failed++
185
- console.error(\`❌ Failed to register external plugin \${plugin.name}:\`, error)
186
- }
187
- }
188
-
189
- console.log(\`📊 External plugin registration complete: \${registered} registered, \${failed} failed\`)
190
- }
191
-
192
- // Export plugin names for easy access
193
- export const pluginNames = discoveredPlugins.map(p => p.name)
194
-
195
- console.log('🔍 Auto-discovered ${plugins.length} external plugins' + (pluginNames.length > 0 ? ': ' + pluginNames.join(', ') : ''))
196
- `
197
-
198
- writeFileSync(this.registrationFilePath, fileContent)
199
- buildLogger.success(`Generated registry for ${plugins.length} plugins`)
200
- }
201
-
202
- /**
203
- * Generate a valid import name from plugin name
204
- */
205
- private getImportName(pluginName: string): string {
206
- // Convert kebab-case to PascalCase for import names
207
- return pluginName
208
- .split('-')
209
- .map(part => part.charAt(0).toUpperCase() + part.slice(1))
210
- .join('') + 'Plugin'
211
- }
212
-
213
- /**
214
- * Restore the original registration file from backup
215
- */
216
- restoreOriginalFile(): void {
217
- if (existsSync(this.backupFilePath)) {
218
- const backupContent = readFileSync(this.backupFilePath, 'utf-8')
219
- writeFileSync(this.registrationFilePath, backupContent)
220
- unlinkSync(this.backupFilePath)
221
- } else {
222
- // If no backup exists, remove the generated file
223
- if (existsSync(this.registrationFilePath)) {
224
- unlinkSync(this.registrationFilePath)
225
- }
226
- }
227
- }
228
-
229
- /**
230
- * Check if the current registration file is auto-generated
231
- */
232
- isAutoGenerated(): boolean {
233
- if (!existsSync(this.registrationFilePath)) {
234
- return false
235
- }
236
-
237
- const content = readFileSync(this.registrationFilePath, 'utf-8')
238
- return content.includes('// 🔥 Auto-generated FluxStack Plugins Registry')
239
- }
240
-
241
- /**
242
- * Pre-build hook: Generate registration file
243
- */
244
- async preBuild(): Promise<PluginInfo[]> {
245
- buildLogger.section('FluxStack Plugins Discovery', '🔌')
246
-
247
- const plugins = this.discoverPlugins()
248
-
249
- if (plugins.length === 0) {
250
- buildLogger.warn('No FluxStack Plugins found')
251
- return []
252
- }
253
-
254
- // Create table of discovered plugins
255
- const pluginData = plugins.map(p => ({
256
- plugin: p.pluginName,
257
- type: p.type,
258
- entry: p.entryFile
259
- }))
260
-
261
- buildLogger.table(
262
- [
263
- { header: 'Plugin', key: 'plugin', width: 25, align: 'left', color: 'cyan' },
264
- { header: 'Type', key: 'type', width: 12, align: 'left', color: 'yellow' },
265
- { header: 'Entry Point', key: 'entry', width: 20, align: 'left', color: 'gray' }
266
- ],
267
- pluginData
268
- )
269
-
270
- this.generateRegistrationFile(plugins)
271
-
272
- return plugins
273
- }
274
-
275
- /**
276
- * Post-build hook: Clean up generated file (optional)
277
- */
278
- async postBuild(keepGenerated: boolean = false): Promise<void> {
279
- buildLogger.step('Cleaning up FluxStack Plugins registry...')
280
-
281
- if (keepGenerated) {
282
- // Remove backup since we're keeping the generated version
283
- if (existsSync(this.backupFilePath)) {
284
- unlinkSync(this.backupFilePath)
285
- }
286
- } else {
287
- this.restoreOriginalFile()
288
- }
289
- }
290
-
291
- /**
292
- * Development mode: Check if registration needs update
293
- */
294
- needsUpdate(): boolean {
295
- if (!this.isAutoGenerated()) {
296
- return false // No auto-generated file, don't touch manual setup
297
- }
298
-
299
- const plugins = this.discoverPlugins()
300
- const currentContent = readFileSync(this.registrationFilePath, 'utf-8')
301
-
302
- // Check if all discovered plugins are in the current file
303
- for (const plugin of plugins) {
304
- const importName = this.getImportName(plugin.pluginName)
305
- if (!currentContent.includes(importName)) {
306
- return true
307
- }
308
- }
309
-
310
- return false
311
- }
312
-
313
- /**
314
- * Development mode: Update registration if needed
315
- */
316
- updateIfNeeded(): void {
317
- if (this.needsUpdate()) {
318
- buildLogger.info('FluxStack Plugins changed, updating registry...')
319
- const plugins = this.discoverPlugins()
320
- this.generateRegistrationFile(plugins)
321
- }
322
- }
323
- }
324
-
325
- // Export singleton instance
1
+ // 🚀 FluxStack Plugins - Auto Registration Generator
2
+ // Automatically generates plugin registration during build time
3
+
4
+ import { existsSync, readdirSync, writeFileSync, unlinkSync, readFileSync, statSync } from 'fs'
5
+ import { join, extname, basename } from 'path'
6
+ import { buildLogger } from '../utils/build-logger'
7
+
8
+ export interface PluginInfo {
9
+ pluginDir: string
10
+ pluginName: string
11
+ entryFile: string
12
+ relativePath: string
13
+ type: 'external' | 'built-in'
14
+ }
15
+
16
+ export class FluxPluginsGenerator {
17
+ private pluginsPath: string
18
+ private builtInPluginsPath: string
19
+ private registrationFilePath: string
20
+ private backupFilePath: string
21
+
22
+ constructor() {
23
+ this.pluginsPath = join(process.cwd(), 'plugins')
24
+ this.builtInPluginsPath = join(process.cwd(), 'core', 'plugins', 'built-in')
25
+ this.registrationFilePath = join(process.cwd(), 'core', 'plugins', 'auto-registry.ts')
26
+ this.backupFilePath = join(process.cwd(), 'core', 'plugins', 'auto-registry.backup.ts')
27
+ }
28
+
29
+ /**
30
+ * Scan plugin directories and discover external plugins only
31
+ * Built-in plugins are handled by the core system
32
+ */
33
+ discoverPlugins(): PluginInfo[] {
34
+ const plugins: PluginInfo[] = []
35
+
36
+ // Discover external plugins only
37
+ if (existsSync(this.pluginsPath)) {
38
+ const externalPlugins = this.discoverPluginsInDirectory(this.pluginsPath, 'external')
39
+ plugins.push(...externalPlugins)
40
+ }
41
+
42
+ // Note: Built-in plugins are automatically loaded by core system
43
+ // No need to include them in auto-generation
44
+
45
+ return plugins
46
+ }
47
+
48
+ /**
49
+ * Discover plugins in a specific directory
50
+ */
51
+ private discoverPluginsInDirectory(directory: string, type: 'external' | 'built-in'): PluginInfo[] {
52
+ const plugins: PluginInfo[] = []
53
+
54
+ try {
55
+ const entries = readdirSync(directory)
56
+
57
+ for (const entry of entries) {
58
+ const pluginDir = join(directory, entry)
59
+
60
+ // Skip files, only process directories
61
+ if (!statSync(pluginDir).isDirectory()) {
62
+ continue
63
+ }
64
+
65
+ // Look for plugin entry point
66
+ const entryFile = this.findPluginEntryFile(pluginDir)
67
+ if (entryFile) {
68
+ const relativePath = type === 'external'
69
+ ? `../../plugins/${entry}`
70
+ : `./built-in/${entry}`
71
+
72
+ plugins.push({
73
+ pluginDir,
74
+ pluginName: entry,
75
+ entryFile,
76
+ relativePath,
77
+ type
78
+ })
79
+
80
+ buildLogger.step(`Discovered ${type} plugin: ${entry} (${entryFile})`)
81
+ } else {
82
+ buildLogger.warn(`Plugin '${entry}' has no valid entry point`)
83
+ }
84
+ }
85
+ } catch (error) {
86
+ // Silently skip directories that can't be scanned
87
+ }
88
+
89
+ return plugins
90
+ }
91
+
92
+ /**
93
+ * Find the main plugin entry file
94
+ */
95
+ private findPluginEntryFile(pluginDir: string): string | null {
96
+ const possibleFiles = [
97
+ 'index.ts',
98
+ 'index',
99
+ 'plugin.ts',
100
+ 'plugin',
101
+ 'src/index.ts',
102
+ 'src/index',
103
+ 'dist/index'
104
+ ]
105
+
106
+ for (const file of possibleFiles) {
107
+ const filePath = join(pluginDir, file)
108
+ if (existsSync(filePath)) {
109
+ return basename(file)
110
+ }
111
+ }
112
+
113
+ return null
114
+ }
115
+
116
+ /**
117
+ * Generate the registration file with all discovered plugins
118
+ */
119
+ generateRegistrationFile(plugins: PluginInfo[]): void {
120
+ // Backup existing file if it exists
121
+ if (existsSync(this.registrationFilePath)) {
122
+ const existingContent = readFileSync(this.registrationFilePath, 'utf-8')
123
+ writeFileSync(this.backupFilePath, existingContent)
124
+ }
125
+
126
+ // All discovered plugins are external (built-in are handled by core)
127
+ const externalPlugins = plugins
128
+
129
+ // Generate imports
130
+ const imports = plugins
131
+ .map(plugin => {
132
+ const importName = this.getImportName(plugin.pluginName)
133
+ const importPath = plugin.entryFile === 'index.ts' || plugin.entryFile === 'index'
134
+ ? plugin.relativePath
135
+ : `${plugin.relativePath}/${plugin.entryFile.replace(/\.(ts|js)$/, '')}`
136
+ return `import ${importName} from "${importPath}"`
137
+ })
138
+ .join('\n')
139
+
140
+ // Generate plugin array
141
+ const pluginsList = plugins
142
+ .map(plugin => {
143
+ const importName = this.getImportName(plugin.pluginName)
144
+ return ` ${importName}`
145
+ })
146
+ .join(',\n')
147
+
148
+ // Generate file content
149
+ const fileContent = `// 🔥 Auto-generated FluxStack External Plugins Registry
150
+ // This file is automatically generated during build time - DO NOT EDIT MANUALLY
151
+ // Built-in plugins are handled by the core system automatically
152
+ // Generated at: ${new Date().toISOString()}
153
+
154
+ import type { Plugin } from './types'
155
+
156
+ ${imports}
157
+
158
+ // Auto-discovered external plugins array
159
+ export const discoveredPlugins: Plugin[] = [
160
+ ${pluginsList}
161
+ ]
162
+
163
+ // All discovered plugins are external (built-in handled by core)
164
+ export const externalPlugins = discoveredPlugins
165
+
166
+ // Plugin registration function
167
+ export async function registerDiscoveredPlugins(registry: any): Promise<void> {
168
+ if (discoveredPlugins.length === 0) {
169
+ console.log('📦 No external plugins to register')
170
+ return
171
+ }
172
+
173
+ console.log(\`📦 Registering \${discoveredPlugins.length} auto-discovered external plugins...\`)
174
+
175
+ let registered = 0
176
+ let failed = 0
177
+
178
+ for (const plugin of discoveredPlugins) {
179
+ try {
180
+ await registry.register(plugin)
181
+ registered++
182
+ console.log(\`✅ Registered external plugin: \${plugin.name}\`)
183
+ } catch (error) {
184
+ failed++
185
+ console.error(\`❌ Failed to register external plugin \${plugin.name}:\`, error)
186
+ }
187
+ }
188
+
189
+ console.log(\`📊 External plugin registration complete: \${registered} registered, \${failed} failed\`)
190
+ }
191
+
192
+ // Export plugin names for easy access
193
+ export const pluginNames = discoveredPlugins.map(p => p.name)
194
+
195
+ console.log('🔍 Auto-discovered ${plugins.length} external plugins' + (pluginNames.length > 0 ? ': ' + pluginNames.join(', ') : ''))
196
+ `
197
+
198
+ writeFileSync(this.registrationFilePath, fileContent)
199
+ buildLogger.success(`Generated registry for ${plugins.length} plugins`)
200
+ }
201
+
202
+ /**
203
+ * Generate a valid import name from plugin name
204
+ */
205
+ private getImportName(pluginName: string): string {
206
+ // Convert kebab-case to PascalCase for import names
207
+ return pluginName
208
+ .split('-')
209
+ .map(part => part.charAt(0).toUpperCase() + part.slice(1))
210
+ .join('') + 'Plugin'
211
+ }
212
+
213
+ /**
214
+ * Restore the original registration file from backup
215
+ */
216
+ restoreOriginalFile(): void {
217
+ if (existsSync(this.backupFilePath)) {
218
+ const backupContent = readFileSync(this.backupFilePath, 'utf-8')
219
+ writeFileSync(this.registrationFilePath, backupContent)
220
+ unlinkSync(this.backupFilePath)
221
+ } else {
222
+ // If no backup exists, remove the generated file
223
+ if (existsSync(this.registrationFilePath)) {
224
+ unlinkSync(this.registrationFilePath)
225
+ }
226
+ }
227
+ }
228
+
229
+ /**
230
+ * Check if the current registration file is auto-generated
231
+ */
232
+ isAutoGenerated(): boolean {
233
+ if (!existsSync(this.registrationFilePath)) {
234
+ return false
235
+ }
236
+
237
+ const content = readFileSync(this.registrationFilePath, 'utf-8')
238
+ return content.includes('// 🔥 Auto-generated FluxStack Plugins Registry')
239
+ }
240
+
241
+ /**
242
+ * Pre-build hook: Generate registration file
243
+ */
244
+ async preBuild(): Promise<PluginInfo[]> {
245
+ buildLogger.section('FluxStack Plugins Discovery', '🔌')
246
+
247
+ const plugins = this.discoverPlugins()
248
+
249
+ if (plugins.length === 0) {
250
+ buildLogger.warn('No FluxStack Plugins found')
251
+ return []
252
+ }
253
+
254
+ // Create table of discovered plugins
255
+ const pluginData = plugins.map(p => ({
256
+ plugin: p.pluginName,
257
+ type: p.type,
258
+ entry: p.entryFile
259
+ }))
260
+
261
+ buildLogger.table(
262
+ [
263
+ { header: 'Plugin', key: 'plugin', width: 25, align: 'left', color: 'cyan' },
264
+ { header: 'Type', key: 'type', width: 12, align: 'left', color: 'yellow' },
265
+ { header: 'Entry Point', key: 'entry', width: 20, align: 'left', color: 'gray' }
266
+ ],
267
+ pluginData
268
+ )
269
+
270
+ this.generateRegistrationFile(plugins)
271
+
272
+ return plugins
273
+ }
274
+
275
+ /**
276
+ * Post-build hook: Clean up generated file (optional)
277
+ */
278
+ async postBuild(keepGenerated: boolean = false): Promise<void> {
279
+ buildLogger.step('Cleaning up FluxStack Plugins registry...')
280
+
281
+ if (keepGenerated) {
282
+ // Remove backup since we're keeping the generated version
283
+ if (existsSync(this.backupFilePath)) {
284
+ unlinkSync(this.backupFilePath)
285
+ }
286
+ } else {
287
+ this.restoreOriginalFile()
288
+ }
289
+ }
290
+
291
+ /**
292
+ * Development mode: Check if registration needs update
293
+ */
294
+ needsUpdate(): boolean {
295
+ if (!this.isAutoGenerated()) {
296
+ return false // No auto-generated file, don't touch manual setup
297
+ }
298
+
299
+ const plugins = this.discoverPlugins()
300
+ const currentContent = readFileSync(this.registrationFilePath, 'utf-8')
301
+
302
+ // Check if all discovered plugins are in the current file
303
+ for (const plugin of plugins) {
304
+ const importName = this.getImportName(plugin.pluginName)
305
+ if (!currentContent.includes(importName)) {
306
+ return true
307
+ }
308
+ }
309
+
310
+ return false
311
+ }
312
+
313
+ /**
314
+ * Development mode: Update registration if needed
315
+ */
316
+ updateIfNeeded(): void {
317
+ if (this.needsUpdate()) {
318
+ buildLogger.info('FluxStack Plugins changed, updating registry...')
319
+ const plugins = this.discoverPlugins()
320
+ this.generateRegistrationFile(plugins)
321
+ }
322
+ }
323
+ }
324
+
325
+ // Export singleton instance
326
326
  export const fluxPluginsGenerator = new FluxPluginsGenerator()