create-fluxstack 1.16.0 → 1.17.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 (119) hide show
  1. package/CHANGELOG.md +80 -0
  2. package/app/client/src/App.tsx +8 -0
  3. package/app/client/src/live/AuthDemo.tsx +4 -4
  4. package/core/build/bundler.ts +40 -26
  5. package/core/build/flux-plugins-generator.ts +325 -325
  6. package/core/build/index.ts +92 -21
  7. package/core/cli/command-registry.ts +44 -46
  8. package/core/cli/commands/build.ts +11 -6
  9. package/core/cli/commands/create.ts +7 -5
  10. package/core/cli/commands/dev.ts +6 -5
  11. package/core/cli/commands/help.ts +3 -2
  12. package/core/cli/commands/make-plugin.ts +8 -7
  13. package/core/cli/commands/plugin-add.ts +60 -43
  14. package/core/cli/commands/plugin-deps.ts +73 -57
  15. package/core/cli/commands/plugin-list.ts +44 -41
  16. package/core/cli/commands/plugin-remove.ts +33 -22
  17. package/core/cli/generators/component.ts +770 -769
  18. package/core/cli/generators/controller.ts +9 -8
  19. package/core/cli/generators/index.ts +148 -146
  20. package/core/cli/generators/interactive.ts +228 -227
  21. package/core/cli/generators/plugin.ts +11 -10
  22. package/core/cli/generators/prompts.ts +83 -82
  23. package/core/cli/generators/route.ts +7 -6
  24. package/core/cli/generators/service.ts +10 -9
  25. package/core/cli/generators/template-engine.ts +2 -1
  26. package/core/cli/generators/types.ts +7 -7
  27. package/core/cli/generators/utils.ts +191 -191
  28. package/core/cli/index.ts +9 -8
  29. package/core/cli/plugin-discovery.ts +2 -2
  30. package/core/client/hooks/useAuth.ts +48 -48
  31. package/core/client/standalone.ts +18 -17
  32. package/core/client/state/createStore.ts +192 -192
  33. package/core/client/state/index.ts +14 -14
  34. package/core/config/index.ts +1 -0
  35. package/core/framework/client.ts +131 -131
  36. package/core/framework/index.ts +7 -7
  37. package/core/framework/server.ts +72 -112
  38. package/core/framework/types.ts +2 -2
  39. package/core/plugins/built-in/live-components/commands/create-live-component.ts +6 -3
  40. package/core/plugins/built-in/monitoring/index.ts +110 -68
  41. package/core/plugins/built-in/static/index.ts +2 -2
  42. package/core/plugins/built-in/swagger/index.ts +9 -9
  43. package/core/plugins/built-in/vite/index.ts +3 -3
  44. package/core/plugins/built-in/vite/vite-dev.ts +3 -3
  45. package/core/plugins/config.ts +50 -47
  46. package/core/plugins/discovery.ts +10 -4
  47. package/core/plugins/executor.ts +2 -2
  48. package/core/plugins/index.ts +206 -203
  49. package/core/plugins/manager.ts +21 -20
  50. package/core/plugins/registry.ts +76 -12
  51. package/core/plugins/types.ts +14 -14
  52. package/core/server/framework.ts +3 -189
  53. package/core/server/live/auto-generated-components.ts +11 -29
  54. package/core/server/live/index.ts +41 -31
  55. package/core/server/live/websocket-plugin.ts +11 -1
  56. package/core/server/middleware/elysia-helpers.ts +16 -15
  57. package/core/server/middleware/errorHandling.ts +14 -14
  58. package/core/server/middleware/index.ts +31 -31
  59. package/core/server/plugins/database.ts +181 -180
  60. package/core/server/plugins/static-files-plugin.ts +4 -3
  61. package/core/server/plugins/swagger.ts +11 -8
  62. package/core/server/rooms/RoomBroadcaster.ts +11 -10
  63. package/core/server/rooms/RoomSystem.ts +14 -11
  64. package/core/server/services/BaseService.ts +7 -7
  65. package/core/server/services/ServiceContainer.ts +5 -5
  66. package/core/server/services/index.ts +8 -8
  67. package/core/templates/create-project.ts +28 -27
  68. package/core/testing/index.ts +9 -9
  69. package/core/testing/setup.ts +73 -73
  70. package/core/types/api.ts +168 -168
  71. package/core/types/config.ts +5 -5
  72. package/core/types/index.ts +1 -1
  73. package/core/types/plugin.ts +2 -2
  74. package/core/types/types.ts +3 -3
  75. package/core/utils/build-logger.ts +324 -324
  76. package/core/utils/config-schema.ts +480 -480
  77. package/core/utils/env.ts +10 -8
  78. package/core/utils/errors/codes.ts +114 -114
  79. package/core/utils/errors/handlers.ts +30 -20
  80. package/core/utils/errors/index.ts +54 -46
  81. package/core/utils/errors/middleware.ts +113 -113
  82. package/core/utils/helpers.ts +19 -16
  83. package/core/utils/logger/colors.ts +114 -114
  84. package/core/utils/logger/config.ts +2 -2
  85. package/core/utils/logger/formatter.ts +82 -82
  86. package/core/utils/logger/group-logger.ts +101 -101
  87. package/core/utils/logger/index.ts +13 -3
  88. package/core/utils/logger/startup-banner.ts +2 -2
  89. package/core/utils/logger/winston-logger.ts +152 -152
  90. package/core/utils/monitoring/index.ts +211 -211
  91. package/core/utils/sync-version.ts +67 -66
  92. package/core/utils/version.ts +1 -1
  93. package/package.json +104 -100
  94. package/playwright-report/index.html +85 -0
  95. package/playwright.config.ts +31 -0
  96. package/plugins/crypto-auth/client/CryptoAuthClient.ts +302 -302
  97. package/plugins/crypto-auth/client/components/index.ts +11 -11
  98. package/plugins/crypto-auth/client/index.ts +11 -11
  99. package/plugins/crypto-auth/package.json +65 -65
  100. package/plugins/crypto-auth/server/CryptoAuthService.ts +185 -185
  101. package/plugins/crypto-auth/server/middlewares/cryptoAuthAdmin.ts +6 -5
  102. package/plugins/crypto-auth/server/middlewares/cryptoAuthPermissions.ts +6 -5
  103. package/plugins/crypto-auth/server/middlewares/cryptoAuthRequired.ts +3 -3
  104. package/plugins/crypto-auth/server/middlewares/index.ts +22 -22
  105. package/plugins/crypto-auth/server/middlewares.ts +19 -19
  106. package/vite.config.ts +13 -0
  107. package/app/client/.live-stubs/LiveAdminPanel.js +0 -5
  108. package/app/client/.live-stubs/LiveCounter.js +0 -9
  109. package/app/client/.live-stubs/LiveForm.js +0 -11
  110. package/app/client/.live-stubs/LiveLocalCounter.js +0 -8
  111. package/app/client/.live-stubs/LivePingPong.js +0 -10
  112. package/app/client/.live-stubs/LiveRoomChat.js +0 -11
  113. package/app/client/.live-stubs/LiveSharedCounter.js +0 -10
  114. package/app/client/.live-stubs/LiveUpload.js +0 -15
  115. package/app/server/live/register-components.ts +0 -19
  116. package/core/build/live-components-generator.ts +0 -321
  117. package/core/live/ComponentRegistry.ts +0 -403
  118. package/core/live/types.ts +0 -241
  119. package/workspace.json +0 -6
@@ -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: { register: (plugin: Plugin) => Promise<void> }): 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()