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
@@ -0,0 +1,79 @@
1
+ /**
2
+ * FluxStack CLI - Build Command
3
+ * Build the application for production
4
+ */
5
+
6
+ import type { CLICommand } from '../command-registry'
7
+ import { FluxStackBuilder } from '@core/build'
8
+ import { fluxStackConfig } from '@config'
9
+
10
+ export const buildCommand: CLICommand = {
11
+ name: 'build',
12
+ description: 'Build the application for production',
13
+ category: 'Build',
14
+ usage: 'flux build [options]',
15
+ examples: [
16
+ 'flux build # Build both frontend and backend',
17
+ 'flux build --frontend-only # Build only frontend',
18
+ 'flux build --backend-only # Build only backend'
19
+ ],
20
+ options: [
21
+ {
22
+ name: 'frontend-only',
23
+ description: 'Build only frontend',
24
+ type: 'boolean'
25
+ },
26
+ {
27
+ name: 'backend-only',
28
+ description: 'Build only backend',
29
+ type: 'boolean'
30
+ },
31
+ {
32
+ name: 'production',
33
+ description: 'Build for production (minified)',
34
+ type: 'boolean',
35
+ default: true
36
+ }
37
+ ],
38
+ handler: async (args, options, context) => {
39
+ const config = fluxStackConfig
40
+
41
+ // Load plugins for build hooks
42
+ const { PluginRegistry } = await import('@core/plugins/registry')
43
+ const { PluginManager } = await import('@core/plugins/manager')
44
+ const pluginRegistry = new PluginRegistry({ config, logger: context.logger })
45
+ const pluginManager = new PluginManager({ config, logger: context.logger })
46
+
47
+ try {
48
+ await pluginManager.initialize()
49
+ // Sync plugins to registry (same as framework does)
50
+ const discoveredPlugins = pluginManager.getRegistry().getAll()
51
+ for (const plugin of discoveredPlugins) {
52
+ if (!pluginRegistry.has(plugin.name)) {
53
+ (pluginRegistry as any).plugins.set(plugin.name, plugin)
54
+ if (plugin.dependencies) {
55
+ (pluginRegistry as any).dependencies.set(plugin.name, plugin.dependencies)
56
+ }
57
+ }
58
+ }
59
+ try {
60
+ (pluginRegistry as any).updateLoadOrder()
61
+ } catch (error) {
62
+ const plugins = (pluginRegistry as any).plugins as Map<string, any>
63
+ ;(pluginRegistry as any).loadOrder = Array.from(plugins.keys())
64
+ }
65
+ } catch (error) {
66
+ context.logger.warn('Failed to load plugins for build hooks', { error })
67
+ }
68
+
69
+ const builder = new FluxStackBuilder(config, pluginRegistry)
70
+
71
+ if (options['frontend-only']) {
72
+ await builder.buildClient()
73
+ } else if (options['backend-only']) {
74
+ await builder.buildServer()
75
+ } else {
76
+ await builder.build()
77
+ }
78
+ }
79
+ }
@@ -0,0 +1,54 @@
1
+ /**
2
+ * FluxStack CLI - Create Command
3
+ * Create a new FluxStack project
4
+ */
5
+
6
+ import type { CLICommand } from '../command-registry'
7
+ import { ProjectCreator } from '@core/templates/create-project'
8
+
9
+ export const createCommand: CLICommand = {
10
+ name: 'create',
11
+ description: 'Create a new FluxStack project',
12
+ category: 'Project',
13
+ usage: 'flux create <project-name> [template]',
14
+ examples: [
15
+ 'flux create my-app # Create basic project',
16
+ 'flux create my-app full # Create full-featured project'
17
+ ],
18
+ arguments: [
19
+ {
20
+ name: 'project-name',
21
+ description: 'Name of the project to create',
22
+ required: true,
23
+ type: 'string'
24
+ },
25
+ {
26
+ name: 'template',
27
+ description: 'Project template to use',
28
+ required: false,
29
+ type: 'string',
30
+ default: 'basic',
31
+ choices: ['basic', 'full']
32
+ }
33
+ ],
34
+ handler: async (args, options, context) => {
35
+ const [projectName, template] = args
36
+
37
+ if (!/^[a-zA-Z0-9-_]+$/.test(projectName)) {
38
+ console.error("❌ Project name can only contain letters, numbers, hyphens, and underscores")
39
+ return
40
+ }
41
+
42
+ try {
43
+ const creator = new ProjectCreator({
44
+ name: projectName,
45
+ template: template as 'basic' | 'full' || 'basic'
46
+ })
47
+
48
+ await creator.create()
49
+ } catch (error) {
50
+ console.error("❌ Failed to create project:", error instanceof Error ? error.message : String(error))
51
+ throw error
52
+ }
53
+ }
54
+ }
@@ -0,0 +1,101 @@
1
+ /**
2
+ * FluxStack CLI - Dev Command
3
+ * Start full-stack development server with hot reload
4
+ */
5
+
6
+ import type { CLICommand } from '../command-registry'
7
+ import { serverConfig, clientConfig } from '@config'
8
+
9
+ export const devCommand: CLICommand = {
10
+ name: 'dev',
11
+ description: 'Start full-stack development server',
12
+ category: 'Development',
13
+ usage: 'flux dev [options]',
14
+ examples: [
15
+ 'flux dev # Start full-stack development',
16
+ 'flux dev --port 4000 # Start on custom port',
17
+ 'flux dev --frontend-only # Start only frontend (Vite)',
18
+ 'flux dev --backend-only # Start only backend (Elysia)'
19
+ ],
20
+ options: [
21
+ {
22
+ name: 'port',
23
+ short: 'p',
24
+ description: 'Port for backend server',
25
+ type: 'number',
26
+ default: serverConfig.server.port
27
+ },
28
+ {
29
+ name: 'frontend-port',
30
+ description: 'Port for frontend server',
31
+ type: 'number',
32
+ default: clientConfig.vite.port
33
+ },
34
+ {
35
+ name: 'frontend-only',
36
+ short: 'f',
37
+ description: 'Start only the frontend (Vite dev server)',
38
+ type: 'boolean',
39
+ default: false
40
+ },
41
+ {
42
+ name: 'backend-only',
43
+ short: 'b',
44
+ description: 'Start only the backend (Elysia server)',
45
+ type: 'boolean',
46
+ default: false
47
+ }
48
+ ],
49
+ handler: async (args, options, context) => {
50
+ const { spawn } = await import("child_process")
51
+
52
+ const frontendOnly = options['frontend-only'] === true
53
+ const backendOnly = options['backend-only'] === true
54
+
55
+ if (frontendOnly && backendOnly) {
56
+ console.error('❌ Cannot use --frontend-only and --backend-only together')
57
+ process.exit(1)
58
+ }
59
+
60
+ // Determine mode and entry point
61
+ const mode = frontendOnly ? 'Frontend only' : backendOnly ? 'Backend only' : 'Full-stack'
62
+
63
+ // Frontend-only: roda direto do core (não passa pelo app/server/index.ts)
64
+ const entryPoint = frontendOnly
65
+ ? 'core/client/standalone-entry.ts'
66
+ : 'app/server/index.ts'
67
+
68
+ const fluxstackMode = backendOnly ? 'backend-only' : 'full-stack'
69
+
70
+ console.log(`⚡ Starting ${mode} development server...`)
71
+
72
+ const devProcess = spawn("bun", ["--watch", entryPoint], {
73
+ stdio: "inherit",
74
+ cwd: process.cwd(),
75
+ env: {
76
+ ...process.env,
77
+ FRONTEND_PORT: options['frontend-port'].toString(),
78
+ BACKEND_PORT: options.port.toString(),
79
+ FLUXSTACK_MODE: fluxstackMode
80
+ }
81
+ })
82
+
83
+ process.on('SIGINT', () => {
84
+ console.log('\n🛑 Shutting down gracefully...')
85
+ devProcess.kill('SIGTERM')
86
+ setTimeout(() => {
87
+ devProcess.kill('SIGKILL')
88
+ process.exit(0)
89
+ }, 5000)
90
+ })
91
+
92
+ devProcess.on('close', (code) => {
93
+ process.exit(code || 0)
94
+ })
95
+
96
+ // Keep the CLI running until the child process exits
97
+ return new Promise((resolve) => {
98
+ devProcess.on('exit', resolve)
99
+ })
100
+ }
101
+ }
@@ -0,0 +1,34 @@
1
+ /**
2
+ * FluxStack CLI - Help Command
3
+ * Display help information for commands
4
+ */
5
+
6
+ import type { CLICommand } from '../command-registry'
7
+ import { cliRegistry } from '../command-registry'
8
+
9
+ export const helpCommand: CLICommand = {
10
+ name: 'help',
11
+ description: 'Show help information',
12
+ category: 'General',
13
+ aliases: ['h', '--help', '-h'],
14
+ arguments: [
15
+ {
16
+ name: 'command',
17
+ description: 'Command to show help for',
18
+ required: false
19
+ }
20
+ ],
21
+ handler: async (args, options, context) => {
22
+ if (args[0]) {
23
+ const targetCommand = cliRegistry.get(args[0])
24
+ if (targetCommand) {
25
+ cliRegistry.showCommandHelp(targetCommand)
26
+ } else {
27
+ console.error(`❌ Unknown command: ${args[0]}`)
28
+ cliRegistry.showHelp()
29
+ }
30
+ } else {
31
+ cliRegistry.showHelp()
32
+ }
33
+ }
34
+ }
@@ -0,0 +1,34 @@
1
+ /**
2
+ * FluxStack CLI Commands
3
+ * Central export for all command modules
4
+ */
5
+
6
+ // General commands
7
+ export { helpCommand } from './help'
8
+
9
+ // Development commands
10
+ export { devCommand } from './dev'
11
+
12
+ // Build commands
13
+ export { buildCommand } from './build'
14
+
15
+ // Project commands
16
+ export { createCommand } from './create'
17
+
18
+ // Plugin commands (management)
19
+ export { makePluginCommand } from './make-plugin'
20
+
21
+ // Export all commands as an array for easy registration
22
+ import { helpCommand } from './help'
23
+ import { devCommand } from './dev'
24
+ import { buildCommand } from './build'
25
+ import { createCommand } from './create'
26
+ import { makePluginCommand } from './make-plugin'
27
+
28
+ export const builtInCommands = [
29
+ helpCommand,
30
+ devCommand,
31
+ buildCommand,
32
+ createCommand,
33
+ makePluginCommand,
34
+ ]
@@ -0,0 +1,90 @@
1
+ /**
2
+ * FluxStack CLI - Make Plugin Command
3
+ * Create a new FluxStack plugin
4
+ */
5
+
6
+ import type { CLICommand } from '../command-registry'
7
+
8
+ export const makePluginCommand: CLICommand = {
9
+ name: 'make:plugin',
10
+ description: 'Create a new FluxStack plugin',
11
+ category: 'Plugins',
12
+ usage: 'flux make:plugin <name> [options]',
13
+ aliases: ['create:plugin'],
14
+ examples: [
15
+ 'flux make:plugin my-plugin # Create basic plugin',
16
+ 'flux make:plugin my-plugin --template full # Create full plugin with server/client',
17
+ 'flux make:plugin auth --template server # Create server-only plugin'
18
+ ],
19
+ arguments: [
20
+ {
21
+ name: 'name',
22
+ description: 'Name of the plugin to create',
23
+ required: true,
24
+ type: 'string'
25
+ }
26
+ ],
27
+ options: [
28
+ {
29
+ name: 'template',
30
+ short: 't',
31
+ description: 'Plugin template to use',
32
+ type: 'string',
33
+ choices: ['basic', 'full', 'server', 'client'],
34
+ default: 'basic'
35
+ },
36
+ {
37
+ name: 'description',
38
+ short: 'd',
39
+ description: 'Plugin description',
40
+ type: 'string',
41
+ default: 'A FluxStack plugin'
42
+ },
43
+ {
44
+ name: 'force',
45
+ short: 'f',
46
+ description: 'Overwrite existing plugin',
47
+ type: 'boolean',
48
+ default: false
49
+ }
50
+ ],
51
+ handler: async (args, options, context) => {
52
+ const [name] = args
53
+
54
+ if (!/^[a-zA-Z0-9-_]+$/.test(name)) {
55
+ console.error("❌ Plugin name can only contain letters, numbers, hyphens, and underscores")
56
+ return
57
+ }
58
+
59
+ // Use the plugin generator
60
+ const { generatorRegistry } = await import('../generators/index')
61
+ const pluginGenerator = generatorRegistry.get('plugin')
62
+
63
+ if (!pluginGenerator) {
64
+ console.error("❌ Plugin generator not found")
65
+ return
66
+ }
67
+
68
+ const generatorContext = {
69
+ workingDir: context.workingDir,
70
+ config: context.config,
71
+ logger: context.logger,
72
+ utils: context.utils
73
+ }
74
+
75
+ const generatorOptions = {
76
+ name,
77
+ template: options.template,
78
+ force: options.force,
79
+ dryRun: false,
80
+ description: options.description
81
+ }
82
+
83
+ try {
84
+ await pluginGenerator.generate(generatorContext, generatorOptions)
85
+ } catch (error) {
86
+ console.error("❌ Failed to create plugin:", error instanceof Error ? error.message : String(error))
87
+ throw error
88
+ }
89
+ }
90
+ }
@@ -0,0 +1,197 @@
1
+ /**
2
+ * FluxStack CLI - Plugin Add Command
3
+ * Safely install and whitelist NPM plugins
4
+ */
5
+
6
+ import { Command } from 'commander'
7
+ import { readFileSync, writeFileSync, existsSync } from 'fs'
8
+ import { join } from 'path'
9
+ import { $ } from 'bun'
10
+ import chalk from 'chalk'
11
+
12
+ interface PluginAddOptions {
13
+ skipAudit?: boolean
14
+ skipConfirmation?: boolean
15
+ }
16
+
17
+ export function createPluginAddCommand(): Command {
18
+ const command = new Command('plugin:add')
19
+ .description('Install and whitelist an NPM plugin securely')
20
+ .argument('<plugin-name>', 'Name of the plugin to install (e.g., fluxstack-plugin-auth)')
21
+ .option('--skip-audit', 'Skip npm audit check')
22
+ .option('--skip-confirmation', 'Skip confirmation prompt')
23
+ .action(async (pluginName: string, options: PluginAddOptions) => {
24
+ console.log(chalk.blue('\n🔌 FluxStack Plugin Installer\n'))
25
+
26
+ try {
27
+ // 1. Validate plugin name
28
+ if (!isValidPluginName(pluginName)) {
29
+ console.error(chalk.red(`❌ Invalid plugin name: ${pluginName}`))
30
+ console.log(chalk.yellow('\n📝 Valid plugin names:'))
31
+ console.log(' - fluxstack-plugin-*')
32
+ console.log(' - fplugin-*')
33
+ console.log(' - @fluxstack/plugin-*')
34
+ console.log(' - @fplugin/*')
35
+ console.log(' - @org/fluxstack-plugin-*')
36
+ console.log(' - @org/fplugin-*')
37
+ process.exit(1)
38
+ }
39
+
40
+ // 2. Check if plugin already installed
41
+ const packageJsonPath = join(process.cwd(), 'package.json')
42
+ if (!existsSync(packageJsonPath)) {
43
+ console.error(chalk.red('❌ package.json not found'))
44
+ process.exit(1)
45
+ }
46
+
47
+ const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf-8'))
48
+ const isAlreadyInstalled =
49
+ packageJson.dependencies?.[pluginName] ||
50
+ packageJson.devDependencies?.[pluginName]
51
+
52
+ if (isAlreadyInstalled && !options.skipConfirmation) {
53
+ console.log(chalk.yellow(`⚠️ Plugin ${pluginName} is already installed`))
54
+ console.log(chalk.yellow(' Will only update whitelist\n'))
55
+ }
56
+
57
+ // 3. Audit plugin (unless skipped)
58
+ if (!options.skipAudit && !isAlreadyInstalled) {
59
+ console.log(chalk.blue('🔍 Auditing plugin security...\n'))
60
+
61
+ try {
62
+ // Get plugin info
63
+ const info = await $`npm view ${pluginName} repository homepage version description`.text()
64
+ console.log(chalk.gray(info))
65
+
66
+ // Run audit
67
+ console.log(chalk.blue('\n🛡️ Running npm audit...\n'))
68
+ const auditResult = await $`npm audit ${pluginName}`.text()
69
+ console.log(chalk.gray(auditResult))
70
+ } catch (error) {
71
+ console.warn(chalk.yellow(`⚠️ Could not audit plugin: ${error instanceof Error ? error.message : 'Unknown error'}`))
72
+ }
73
+ }
74
+
75
+ // 4. Confirmation prompt (unless skipped)
76
+ if (!options.skipConfirmation) {
77
+ console.log(chalk.yellow('\n⚠️ Security Warning:'))
78
+ console.log(chalk.yellow(' NPM plugins can execute arbitrary code'))
79
+ console.log(chalk.yellow(' Only install plugins from trusted sources\n'))
80
+
81
+ const answer = prompt(chalk.blue('Continue with installation? (yes/no): '))
82
+ if (answer?.toLowerCase() !== 'yes' && answer?.toLowerCase() !== 'y') {
83
+ console.log(chalk.red('❌ Installation cancelled'))
84
+ process.exit(0)
85
+ }
86
+ }
87
+
88
+ // 5. Install plugin
89
+ if (!isAlreadyInstalled) {
90
+ console.log(chalk.blue(`\n📦 Installing ${pluginName}...\n`))
91
+ await $`bun add ${pluginName}`.quiet()
92
+ console.log(chalk.green(`✅ Plugin installed successfully`))
93
+ }
94
+
95
+ // 6. Update .env file
96
+ console.log(chalk.blue('\n🔧 Updating configuration...\n'))
97
+ updateEnvFile(pluginName)
98
+
99
+ // 7. Success message
100
+ console.log(chalk.green('\n✅ Plugin setup complete!\n'))
101
+ console.log(chalk.blue('📋 What was done:'))
102
+ if (!isAlreadyInstalled) {
103
+ console.log(chalk.gray(` • Installed ${pluginName}`))
104
+ }
105
+ console.log(chalk.gray(' • Enabled NPM plugin discovery (PLUGINS_DISCOVER_NPM=true)'))
106
+ console.log(chalk.gray(` • Added ${pluginName} to whitelist (PLUGINS_ALLOWED)`))
107
+
108
+ console.log(chalk.blue('\n🚀 Next steps:'))
109
+ console.log(chalk.gray(' 1. Restart your dev server: bun run dev'))
110
+ console.log(chalk.gray(' 2. Plugin will be auto-discovered and loaded'))
111
+ console.log(chalk.gray(' 3. Check logs for plugin initialization'))
112
+
113
+ } catch (error) {
114
+ console.error(chalk.red('\n❌ Failed to install plugin:'))
115
+ console.error(chalk.red(error instanceof Error ? error.message : String(error)))
116
+ process.exit(1)
117
+ }
118
+ })
119
+
120
+ return command
121
+ }
122
+
123
+ /**
124
+ * Validate plugin name against FluxStack naming conventions
125
+ */
126
+ function isValidPluginName(name: string): boolean {
127
+ const patterns = [
128
+ /^fluxstack-plugin-/,
129
+ /^fplugin-/,
130
+ /^@fluxstack\/plugin-/,
131
+ /^@fplugin\//,
132
+ /^@[\w-]+\/fluxstack-plugin-/,
133
+ /^@[\w-]+\/fplugin-/,
134
+ ]
135
+
136
+ return patterns.some(pattern => pattern.test(name))
137
+ }
138
+
139
+ /**
140
+ * Update .env file with plugin configuration
141
+ */
142
+ function updateEnvFile(pluginName: string): void {
143
+ const envPath = join(process.cwd(), '.env')
144
+
145
+ if (!existsSync(envPath)) {
146
+ console.warn(chalk.yellow('⚠️ .env file not found, creating...'))
147
+ writeFileSync(envPath, '', 'utf-8')
148
+ }
149
+
150
+ let envContent = readFileSync(envPath, 'utf-8')
151
+ let updated = false
152
+
153
+ // 1. Enable NPM plugin discovery
154
+ if (/^PLUGINS_DISCOVER_NPM=false/m.test(envContent)) {
155
+ envContent = envContent.replace(
156
+ /^PLUGINS_DISCOVER_NPM=false/m,
157
+ 'PLUGINS_DISCOVER_NPM=true'
158
+ )
159
+ updated = true
160
+ console.log(chalk.gray(' • Set PLUGINS_DISCOVER_NPM=true'))
161
+ } else if (!/^PLUGINS_DISCOVER_NPM=/m.test(envContent)) {
162
+ envContent += '\n# Plugin Discovery\nPLUGINS_DISCOVER_NPM=true\n'
163
+ updated = true
164
+ console.log(chalk.gray(' • Added PLUGINS_DISCOVER_NPM=true'))
165
+ }
166
+
167
+ // 2. Add plugin to whitelist
168
+ const allowedPluginsRegex = /^PLUGINS_ALLOWED=(.*)$/m
169
+ const match = envContent.match(allowedPluginsRegex)
170
+
171
+ if (match) {
172
+ const currentPlugins = match[1]
173
+ .split(',')
174
+ .map(p => p.trim())
175
+ .filter(p => p.length > 0)
176
+
177
+ if (!currentPlugins.includes(pluginName)) {
178
+ const newPlugins = [...currentPlugins, pluginName].join(',')
179
+ envContent = envContent.replace(
180
+ allowedPluginsRegex,
181
+ `PLUGINS_ALLOWED=${newPlugins}`
182
+ )
183
+ updated = true
184
+ console.log(chalk.gray(` • Added ${pluginName} to PLUGINS_ALLOWED`))
185
+ } else {
186
+ console.log(chalk.gray(` • ${pluginName} already in PLUGINS_ALLOWED`))
187
+ }
188
+ } else {
189
+ envContent += `PLUGINS_ALLOWED=${pluginName}\n`
190
+ updated = true
191
+ console.log(chalk.gray(` • Created PLUGINS_ALLOWED with ${pluginName}`))
192
+ }
193
+
194
+ if (updated) {
195
+ writeFileSync(envPath, envContent, 'utf-8')
196
+ }
197
+ }
@@ -4,8 +4,8 @@
4
4
 
5
5
  import { Command } from 'commander'
6
6
  import chalk from 'chalk'
7
- import { PluginDependencyManager } from '@/core/plugins/dependency-manager'
8
- import { PluginRegistry } from '@/core/plugins/registry'
7
+ import { PluginDependencyManager } from '@core/plugins/dependency-manager'
8
+ import { PluginRegistry } from '@core/plugins/registry'
9
9
  import { existsSync, readFileSync } from 'fs'
10
10
  import { join } from 'path'
11
11