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.
- package/CHANGELOG.md +80 -0
- package/app/client/src/App.tsx +8 -0
- package/app/client/src/live/AuthDemo.tsx +4 -4
- package/core/build/bundler.ts +40 -26
- package/core/build/flux-plugins-generator.ts +325 -325
- package/core/build/index.ts +92 -21
- package/core/cli/command-registry.ts +44 -46
- package/core/cli/commands/build.ts +11 -6
- package/core/cli/commands/create.ts +7 -5
- package/core/cli/commands/dev.ts +6 -5
- package/core/cli/commands/help.ts +3 -2
- package/core/cli/commands/make-plugin.ts +8 -7
- package/core/cli/commands/plugin-add.ts +60 -43
- package/core/cli/commands/plugin-deps.ts +73 -57
- package/core/cli/commands/plugin-list.ts +44 -41
- package/core/cli/commands/plugin-remove.ts +33 -22
- package/core/cli/generators/component.ts +770 -769
- package/core/cli/generators/controller.ts +9 -8
- package/core/cli/generators/index.ts +148 -146
- package/core/cli/generators/interactive.ts +228 -227
- package/core/cli/generators/plugin.ts +11 -10
- package/core/cli/generators/prompts.ts +83 -82
- package/core/cli/generators/route.ts +7 -6
- package/core/cli/generators/service.ts +10 -9
- package/core/cli/generators/template-engine.ts +2 -1
- package/core/cli/generators/types.ts +7 -7
- package/core/cli/generators/utils.ts +191 -191
- package/core/cli/index.ts +9 -8
- package/core/cli/plugin-discovery.ts +2 -2
- package/core/client/hooks/useAuth.ts +48 -48
- package/core/client/standalone.ts +18 -17
- package/core/client/state/createStore.ts +192 -192
- package/core/client/state/index.ts +14 -14
- package/core/config/index.ts +1 -0
- package/core/framework/client.ts +131 -131
- package/core/framework/index.ts +7 -7
- package/core/framework/server.ts +72 -112
- package/core/framework/types.ts +2 -2
- package/core/plugins/built-in/live-components/commands/create-live-component.ts +6 -3
- package/core/plugins/built-in/monitoring/index.ts +110 -68
- package/core/plugins/built-in/static/index.ts +2 -2
- package/core/plugins/built-in/swagger/index.ts +9 -9
- package/core/plugins/built-in/vite/index.ts +3 -3
- package/core/plugins/built-in/vite/vite-dev.ts +3 -3
- package/core/plugins/config.ts +50 -47
- package/core/plugins/discovery.ts +10 -4
- package/core/plugins/executor.ts +2 -2
- package/core/plugins/index.ts +206 -203
- package/core/plugins/manager.ts +21 -20
- package/core/plugins/registry.ts +76 -12
- package/core/plugins/types.ts +14 -14
- package/core/server/framework.ts +3 -189
- package/core/server/live/auto-generated-components.ts +11 -29
- package/core/server/live/index.ts +41 -31
- package/core/server/live/websocket-plugin.ts +11 -1
- package/core/server/middleware/elysia-helpers.ts +16 -15
- package/core/server/middleware/errorHandling.ts +14 -14
- package/core/server/middleware/index.ts +31 -31
- package/core/server/plugins/database.ts +181 -180
- package/core/server/plugins/static-files-plugin.ts +4 -3
- package/core/server/plugins/swagger.ts +11 -8
- package/core/server/rooms/RoomBroadcaster.ts +11 -10
- package/core/server/rooms/RoomSystem.ts +14 -11
- package/core/server/services/BaseService.ts +7 -7
- package/core/server/services/ServiceContainer.ts +5 -5
- package/core/server/services/index.ts +8 -8
- package/core/templates/create-project.ts +28 -27
- package/core/testing/index.ts +9 -9
- package/core/testing/setup.ts +73 -73
- package/core/types/api.ts +168 -168
- package/core/types/config.ts +5 -5
- package/core/types/index.ts +1 -1
- package/core/types/plugin.ts +2 -2
- package/core/types/types.ts +3 -3
- package/core/utils/build-logger.ts +324 -324
- package/core/utils/config-schema.ts +480 -480
- package/core/utils/env.ts +10 -8
- package/core/utils/errors/codes.ts +114 -114
- package/core/utils/errors/handlers.ts +30 -20
- package/core/utils/errors/index.ts +54 -46
- package/core/utils/errors/middleware.ts +113 -113
- package/core/utils/helpers.ts +19 -16
- package/core/utils/logger/colors.ts +114 -114
- package/core/utils/logger/config.ts +2 -2
- package/core/utils/logger/formatter.ts +82 -82
- package/core/utils/logger/group-logger.ts +101 -101
- package/core/utils/logger/index.ts +13 -3
- package/core/utils/logger/startup-banner.ts +2 -2
- package/core/utils/logger/winston-logger.ts +152 -152
- package/core/utils/monitoring/index.ts +211 -211
- package/core/utils/sync-version.ts +67 -66
- package/core/utils/version.ts +1 -1
- package/package.json +104 -100
- package/playwright-report/index.html +85 -0
- package/playwright.config.ts +31 -0
- package/plugins/crypto-auth/client/CryptoAuthClient.ts +302 -302
- package/plugins/crypto-auth/client/components/index.ts +11 -11
- package/plugins/crypto-auth/client/index.ts +11 -11
- package/plugins/crypto-auth/package.json +65 -65
- package/plugins/crypto-auth/server/CryptoAuthService.ts +185 -185
- package/plugins/crypto-auth/server/middlewares/cryptoAuthAdmin.ts +6 -5
- package/plugins/crypto-auth/server/middlewares/cryptoAuthPermissions.ts +6 -5
- package/plugins/crypto-auth/server/middlewares/cryptoAuthRequired.ts +3 -3
- package/plugins/crypto-auth/server/middlewares/index.ts +22 -22
- package/plugins/crypto-auth/server/middlewares.ts +19 -19
- package/vite.config.ts +13 -0
- package/app/client/.live-stubs/LiveAdminPanel.js +0 -5
- package/app/client/.live-stubs/LiveCounter.js +0 -9
- package/app/client/.live-stubs/LiveForm.js +0 -11
- package/app/client/.live-stubs/LiveLocalCounter.js +0 -8
- package/app/client/.live-stubs/LivePingPong.js +0 -10
- package/app/client/.live-stubs/LiveRoomChat.js +0 -11
- package/app/client/.live-stubs/LiveSharedCounter.js +0 -10
- package/app/client/.live-stubs/LiveUpload.js +0 -15
- package/app/server/live/register-components.ts +0 -19
- package/core/build/live-components-generator.ts +0 -321
- package/core/live/ComponentRegistry.ts +0 -403
- package/core/live/types.ts +0 -241
- package/workspace.json +0 -6
package/core/build/index.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { copyFileSync, writeFileSync, existsSync, mkdirSync, readFileSync, readdirSync, statSync } from "fs"
|
|
2
2
|
import { join } from "path"
|
|
3
3
|
import type { FluxStackConfig } from "../config"
|
|
4
|
-
import type { BuildResult, BuildManifest } from "../types/build"
|
|
4
|
+
import type { BuildResult, BuildManifest, BundleResult, OptimizationResult } from "../types/build"
|
|
5
5
|
import { Bundler } from "./bundler"
|
|
6
6
|
import { Optimizer } from "./optimizer"
|
|
7
7
|
import { FLUXSTACK_VERSION } from "../utils/version"
|
|
@@ -9,14 +9,69 @@ import { buildLogger } from "../utils/build-logger"
|
|
|
9
9
|
import type { PluginRegistry } from "../plugins/registry"
|
|
10
10
|
import type { BuildContext, BuildAssetContext, BuildErrorContext } from "../plugins/types"
|
|
11
11
|
|
|
12
|
+
/**
|
|
13
|
+
* Runtime shape of config properties - the FluxStackConfig type uses
|
|
14
|
+
* complex conditional inference via defineConfig/defineNestedConfig
|
|
15
|
+
* which causes spread results to collapse to {} at the type level.
|
|
16
|
+
* We declare the actual runtime shapes explicitly.
|
|
17
|
+
*/
|
|
18
|
+
interface BuildConfigRuntime {
|
|
19
|
+
target: string
|
|
20
|
+
outDir: string
|
|
21
|
+
sourceMaps: boolean
|
|
22
|
+
clean: boolean
|
|
23
|
+
mode: string
|
|
24
|
+
external: string[]
|
|
25
|
+
optimize: boolean
|
|
26
|
+
optimization: {
|
|
27
|
+
minify: boolean
|
|
28
|
+
treeshake: boolean
|
|
29
|
+
compress: boolean
|
|
30
|
+
splitChunks: boolean
|
|
31
|
+
bundleAnalyzer: boolean
|
|
32
|
+
removeUnusedCSS: boolean
|
|
33
|
+
optimizeImages: boolean
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
interface OptimizationConfigRuntime {
|
|
38
|
+
minify: boolean
|
|
39
|
+
treeshake: boolean
|
|
40
|
+
compress: boolean
|
|
41
|
+
splitChunks: boolean
|
|
42
|
+
bundleAnalyzer: boolean
|
|
43
|
+
removeUnusedCSS: boolean
|
|
44
|
+
optimizeImages: boolean
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
interface AppConfigRuntime {
|
|
48
|
+
name: string
|
|
49
|
+
version: string
|
|
50
|
+
env: string
|
|
51
|
+
debug: boolean
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
interface ClientBuildRuntime {
|
|
55
|
+
outDir: string
|
|
56
|
+
sourceMaps: boolean
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/** Augmented config type that resolves the spread-collapsed properties */
|
|
60
|
+
type ResolvedFluxStackConfig = FluxStackConfig & {
|
|
61
|
+
build: BuildConfigRuntime
|
|
62
|
+
optimization: OptimizationConfigRuntime
|
|
63
|
+
app: AppConfigRuntime
|
|
64
|
+
clientBuild: ClientBuildRuntime
|
|
65
|
+
}
|
|
66
|
+
|
|
12
67
|
export class FluxStackBuilder {
|
|
13
|
-
private config:
|
|
68
|
+
private config: ResolvedFluxStackConfig
|
|
14
69
|
private bundler: Bundler
|
|
15
70
|
private optimizer: Optimizer
|
|
16
71
|
private pluginRegistry?: PluginRegistry
|
|
17
72
|
|
|
18
73
|
constructor(config: FluxStackConfig, pluginRegistry?: PluginRegistry) {
|
|
19
|
-
this.config = config
|
|
74
|
+
this.config = config as ResolvedFluxStackConfig
|
|
20
75
|
this.pluginRegistry = pluginRegistry
|
|
21
76
|
|
|
22
77
|
const optimization = this.config.optimization || {
|
|
@@ -28,22 +83,24 @@ export class FluxStackBuilder {
|
|
|
28
83
|
bundleAnalyzer: false
|
|
29
84
|
}
|
|
30
85
|
|
|
86
|
+
const buildCfg = this.config.build
|
|
87
|
+
|
|
31
88
|
// Initialize bundler with configuration
|
|
32
89
|
this.bundler = new Bundler({
|
|
33
|
-
target:
|
|
34
|
-
outDir:
|
|
35
|
-
sourceMaps:
|
|
36
|
-
minify: optimization.minify,
|
|
37
|
-
external:
|
|
90
|
+
target: (buildCfg.target ?? 'bun') as 'bun' | 'node' | 'docker',
|
|
91
|
+
outDir: buildCfg.outDir ?? 'dist',
|
|
92
|
+
sourceMaps: buildCfg.sourceMaps ?? false,
|
|
93
|
+
minify: optimization.minify as boolean ?? true,
|
|
94
|
+
external: buildCfg.external || []
|
|
38
95
|
})
|
|
39
96
|
|
|
40
97
|
// Initialize optimizer with configuration
|
|
41
98
|
this.optimizer = new Optimizer({
|
|
42
|
-
treeshake: optimization.treeshake ?? true,
|
|
43
|
-
compress: optimization.compress || false,
|
|
44
|
-
removeUnusedCSS: optimization.removeUnusedCSS || false,
|
|
45
|
-
optimizeImages: optimization.optimizeImages || false,
|
|
46
|
-
bundleAnalysis: optimization.bundleAnalyzer || false
|
|
99
|
+
treeshake: Boolean(optimization.treeshake ?? true),
|
|
100
|
+
compress: Boolean(optimization.compress || false),
|
|
101
|
+
removeUnusedCSS: Boolean(optimization.removeUnusedCSS || false),
|
|
102
|
+
optimizeImages: Boolean(optimization.optimizeImages || false),
|
|
103
|
+
bundleAnalysis: Boolean(optimization.bundleAnalyzer || false)
|
|
47
104
|
})
|
|
48
105
|
}
|
|
49
106
|
|
|
@@ -429,19 +486,33 @@ MONITORING_ENABLED=true
|
|
|
429
486
|
}
|
|
430
487
|
|
|
431
488
|
private async generateManifest(
|
|
432
|
-
clientResult:
|
|
433
|
-
serverResult:
|
|
434
|
-
optimizationResult?:
|
|
489
|
+
clientResult: BundleResult,
|
|
490
|
+
serverResult: BundleResult,
|
|
491
|
+
optimizationResult?: OptimizationResult
|
|
435
492
|
): Promise<BuildManifest> {
|
|
493
|
+
const target = (this.config.build.target ?? 'bun') as import("../types/build").BuildTarget
|
|
494
|
+
const mode = (this.config.build.mode ?? 'production') as import("../types/build").BuildMode
|
|
495
|
+
|
|
496
|
+
// Map string asset paths to AssetManifest objects
|
|
497
|
+
const clientAssets: import("../types/build").AssetManifest[] = (clientResult.assets || []).map(
|
|
498
|
+
(assetPath) => ({
|
|
499
|
+
name: assetPath.split('/').pop() || assetPath,
|
|
500
|
+
file: assetPath,
|
|
501
|
+
size: 0,
|
|
502
|
+
hash: '',
|
|
503
|
+
type: 'asset'
|
|
504
|
+
})
|
|
505
|
+
)
|
|
506
|
+
|
|
436
507
|
return {
|
|
437
508
|
version: this.config.app.version ?? '0.0.0',
|
|
438
509
|
timestamp: new Date().toISOString(),
|
|
439
|
-
target
|
|
440
|
-
mode
|
|
510
|
+
target,
|
|
511
|
+
mode,
|
|
441
512
|
client: {
|
|
442
513
|
entryPoints: [],
|
|
443
514
|
chunks: [],
|
|
444
|
-
assets:
|
|
515
|
+
assets: clientAssets,
|
|
445
516
|
publicPath: '/'
|
|
446
517
|
},
|
|
447
518
|
server: {
|
|
@@ -473,7 +544,7 @@ MONITORING_ENABLED=true
|
|
|
473
544
|
/**
|
|
474
545
|
* Execute plugin hooks for build process
|
|
475
546
|
*/
|
|
476
|
-
private async executePluginHooks(hookName: string, context:
|
|
547
|
+
private async executePluginHooks(hookName: string, context: unknown): Promise<void> {
|
|
477
548
|
if (!this.pluginRegistry) return
|
|
478
549
|
|
|
479
550
|
const loadOrder = this.pluginRegistry.getLoadOrder()
|
|
@@ -482,7 +553,7 @@ MONITORING_ENABLED=true
|
|
|
482
553
|
const plugin = this.pluginRegistry.get(pluginName)
|
|
483
554
|
if (!plugin) continue
|
|
484
555
|
|
|
485
|
-
const hookFn = (plugin as
|
|
556
|
+
const hookFn = (plugin as unknown as Record<string, unknown>)[hookName]
|
|
486
557
|
if (typeof hookFn === 'function') {
|
|
487
558
|
try {
|
|
488
559
|
await hookFn(context)
|
|
@@ -1,7 +1,10 @@
|
|
|
1
|
-
import type { CliCommand, CliContext, CliArgument, CliOption } from "../plugins/types"
|
|
1
|
+
import type { CliCommand, CliContext, CliArgument, CliOption, PluginConfigSchema } from "../plugins/types"
|
|
2
2
|
import { fluxStackConfig } from "@config"
|
|
3
3
|
import { logger } from "@core/utils/logger"
|
|
4
|
+
import { buildLogger } from "@core/utils/build-logger"
|
|
4
5
|
import { createTimer, formatBytes, isProduction, isDevelopment } from "../utils/helpers"
|
|
6
|
+
import { createHash } from "crypto"
|
|
7
|
+
import { createPluginUtils } from "../plugins/config"
|
|
5
8
|
|
|
6
9
|
export class CliCommandRegistry {
|
|
7
10
|
private commands = new Map<string, CliCommand>()
|
|
@@ -13,7 +16,7 @@ export class CliCommandRegistry {
|
|
|
13
16
|
|
|
14
17
|
this.context = {
|
|
15
18
|
config,
|
|
16
|
-
logger
|
|
19
|
+
logger,
|
|
17
20
|
utils: {
|
|
18
21
|
createTimer,
|
|
19
22
|
formatBytes,
|
|
@@ -21,8 +24,7 @@ export class CliCommandRegistry {
|
|
|
21
24
|
isDevelopment,
|
|
22
25
|
getEnvironment: () => process.env.NODE_ENV || 'development',
|
|
23
26
|
createHash: (data: string) => {
|
|
24
|
-
|
|
25
|
-
return crypto.createHash('sha256').update(data).digest('hex')
|
|
27
|
+
return createHash('sha256').update(data).digest('hex')
|
|
26
28
|
},
|
|
27
29
|
deepMerge: (target: Record<string, unknown>, source: Record<string, unknown>) => {
|
|
28
30
|
const result = { ...target }
|
|
@@ -35,12 +37,8 @@ export class CliCommandRegistry {
|
|
|
35
37
|
}
|
|
36
38
|
return result
|
|
37
39
|
},
|
|
38
|
-
validateSchema: (
|
|
39
|
-
|
|
40
|
-
return { valid: true, errors: [] }
|
|
41
|
-
} catch (error) {
|
|
42
|
-
return { valid: false, errors: [error instanceof Error ? error.message : 'Validation failed'] }
|
|
43
|
-
}
|
|
40
|
+
validateSchema: (data: Record<string, unknown>, schema: PluginConfigSchema) => {
|
|
41
|
+
return createPluginUtils(logger).validateSchema(data, schema)
|
|
44
42
|
}
|
|
45
43
|
},
|
|
46
44
|
workingDir: process.cwd(),
|
|
@@ -103,9 +101,9 @@ export class CliCommandRegistry {
|
|
|
103
101
|
|
|
104
102
|
async execute(commandName: string, args: string[]): Promise<number> {
|
|
105
103
|
const command = this.get(commandName)
|
|
106
|
-
|
|
104
|
+
|
|
107
105
|
if (!command) {
|
|
108
|
-
|
|
106
|
+
buildLogger.error(`❌ Unknown command: ${commandName}`)
|
|
109
107
|
this.showHelp()
|
|
110
108
|
return 1
|
|
111
109
|
}
|
|
@@ -113,24 +111,24 @@ export class CliCommandRegistry {
|
|
|
113
111
|
try {
|
|
114
112
|
// Parse arguments and options
|
|
115
113
|
const { parsedArgs, parsedOptions } = this.parseArgs(command, args)
|
|
116
|
-
|
|
114
|
+
|
|
117
115
|
// Validate required arguments
|
|
118
116
|
if (command.arguments) {
|
|
119
117
|
for (let i = 0; i < command.arguments.length; i++) {
|
|
120
118
|
const arg = command.arguments[i]
|
|
121
119
|
if (arg.required && !parsedArgs[i]) {
|
|
122
|
-
|
|
120
|
+
buildLogger.error(`❌ Missing required argument: ${arg.name}`)
|
|
123
121
|
this.showCommandHelp(command)
|
|
124
122
|
return 1
|
|
125
123
|
}
|
|
126
124
|
}
|
|
127
125
|
}
|
|
128
|
-
|
|
126
|
+
|
|
129
127
|
// Validate required options
|
|
130
128
|
if (command.options) {
|
|
131
129
|
for (const option of command.options) {
|
|
132
130
|
if (option.required && !(option.name in parsedOptions)) {
|
|
133
|
-
|
|
131
|
+
buildLogger.error(`❌ Missing required option: --${option.name}`)
|
|
134
132
|
this.showCommandHelp(command)
|
|
135
133
|
return 1
|
|
136
134
|
}
|
|
@@ -140,16 +138,16 @@ export class CliCommandRegistry {
|
|
|
140
138
|
// Execute command
|
|
141
139
|
await command.handler(parsedArgs, parsedOptions, this.context)
|
|
142
140
|
return 0
|
|
143
|
-
|
|
141
|
+
|
|
144
142
|
} catch (error) {
|
|
145
|
-
|
|
143
|
+
buildLogger.error('❌ Command failed:', error instanceof Error ? error.message : String(error))
|
|
146
144
|
return 1
|
|
147
145
|
}
|
|
148
146
|
}
|
|
149
147
|
|
|
150
|
-
private parseArgs(command: CliCommand, args: string[]): { parsedArgs:
|
|
151
|
-
const parsedArgs:
|
|
152
|
-
const parsedOptions:
|
|
148
|
+
private parseArgs(command: CliCommand, args: string[]): { parsedArgs: unknown[], parsedOptions: Record<string, unknown> } {
|
|
149
|
+
const parsedArgs: unknown[] = []
|
|
150
|
+
const parsedOptions: Record<string, unknown> = {}
|
|
153
151
|
|
|
154
152
|
let i = 0
|
|
155
153
|
while (i < args.length) {
|
|
@@ -166,7 +164,7 @@ export class CliCommandRegistry {
|
|
|
166
164
|
} else if (option.type === 'array') {
|
|
167
165
|
parsedOptions[optionName] = parsedOptions[optionName] || []
|
|
168
166
|
if (i + 1 < args.length && !args[i + 1].startsWith('-')) {
|
|
169
|
-
parsedOptions[optionName].push(args[++i])
|
|
167
|
+
(parsedOptions[optionName] as unknown[]).push(args[++i])
|
|
170
168
|
}
|
|
171
169
|
} else {
|
|
172
170
|
if (i + 1 < args.length && !args[i + 1].startsWith('-')) {
|
|
@@ -225,7 +223,7 @@ export class CliCommandRegistry {
|
|
|
225
223
|
return { parsedArgs, parsedOptions }
|
|
226
224
|
}
|
|
227
225
|
|
|
228
|
-
private convertType(value: string, type?: 'string' | 'number' | 'boolean' | 'array'):
|
|
226
|
+
private convertType(value: string, type?: 'string' | 'number' | 'boolean' | 'array'): string | number | boolean | string[] {
|
|
229
227
|
if (!type || type === 'string') return value
|
|
230
228
|
if (type === 'number') return Number(value)
|
|
231
229
|
if (type === 'boolean') return value.toLowerCase() === 'true'
|
|
@@ -234,7 +232,7 @@ export class CliCommandRegistry {
|
|
|
234
232
|
}
|
|
235
233
|
|
|
236
234
|
showHelp(): void {
|
|
237
|
-
|
|
235
|
+
buildLogger.info(`
|
|
238
236
|
⚡ FluxStack Framework CLI
|
|
239
237
|
|
|
240
238
|
Usage:
|
|
@@ -244,16 +242,16 @@ Usage:
|
|
|
244
242
|
Built-in Commands:`)
|
|
245
243
|
|
|
246
244
|
const categories = this.getAllByCategory()
|
|
247
|
-
|
|
245
|
+
|
|
248
246
|
for (const [category, commands] of categories) {
|
|
249
|
-
|
|
247
|
+
buildLogger.info(`\n${category}:`)
|
|
250
248
|
for (const command of commands) {
|
|
251
249
|
const aliases = command.aliases?.length ? ` (${command.aliases.join(', ')})` : ''
|
|
252
|
-
|
|
250
|
+
buildLogger.info(` ${command.name}${aliases.padEnd(20)} ${command.description}`)
|
|
253
251
|
}
|
|
254
252
|
}
|
|
255
253
|
|
|
256
|
-
|
|
254
|
+
buildLogger.info(`
|
|
257
255
|
Examples:
|
|
258
256
|
flux dev # Start development server
|
|
259
257
|
flux build --production # Build for production
|
|
@@ -264,13 +262,13 @@ Use "flux help <command>" for more information about a specific command.`)
|
|
|
264
262
|
}
|
|
265
263
|
|
|
266
264
|
showCommandHelp(command: CliCommand): void {
|
|
267
|
-
|
|
268
|
-
|
|
265
|
+
buildLogger.info(`\n${command.description}`)
|
|
266
|
+
|
|
269
267
|
if (command.usage) {
|
|
270
|
-
|
|
268
|
+
buildLogger.info(`\nUsage:\n ${command.usage}`)
|
|
271
269
|
} else {
|
|
272
270
|
let usage = `flux ${command.name}`
|
|
273
|
-
|
|
271
|
+
|
|
274
272
|
if (command.arguments) {
|
|
275
273
|
for (const arg of command.arguments) {
|
|
276
274
|
if (arg.required) {
|
|
@@ -280,42 +278,42 @@ Use "flux help <command>" for more information about a specific command.`)
|
|
|
280
278
|
}
|
|
281
279
|
}
|
|
282
280
|
}
|
|
283
|
-
|
|
281
|
+
|
|
284
282
|
if (command.options?.length) {
|
|
285
283
|
usage += ` [options]`
|
|
286
284
|
}
|
|
287
|
-
|
|
288
|
-
|
|
285
|
+
|
|
286
|
+
buildLogger.info(`\nUsage:\n ${usage}`)
|
|
289
287
|
}
|
|
290
|
-
|
|
288
|
+
|
|
291
289
|
if (command.arguments?.length) {
|
|
292
|
-
|
|
290
|
+
buildLogger.info(`\nArguments:`)
|
|
293
291
|
for (const arg of command.arguments) {
|
|
294
292
|
const required = arg.required ? ' (required)' : ''
|
|
295
293
|
const defaultValue = arg.default !== undefined ? ` (default: ${arg.default})` : ''
|
|
296
|
-
|
|
294
|
+
buildLogger.info(` ${arg.name.padEnd(15)} ${arg.description}${required}${defaultValue}`)
|
|
297
295
|
}
|
|
298
296
|
}
|
|
299
|
-
|
|
297
|
+
|
|
300
298
|
if (command.options?.length) {
|
|
301
|
-
|
|
299
|
+
buildLogger.info(`\nOptions:`)
|
|
302
300
|
for (const option of command.options) {
|
|
303
301
|
const short = option.short ? `-${option.short}, ` : ' '
|
|
304
302
|
const required = option.required ? ' (required)' : ''
|
|
305
303
|
const defaultValue = option.default !== undefined ? ` (default: ${option.default})` : ''
|
|
306
|
-
|
|
304
|
+
buildLogger.info(` ${short}--${option.name.padEnd(15)} ${option.description}${required}${defaultValue}`)
|
|
307
305
|
}
|
|
308
306
|
}
|
|
309
|
-
|
|
307
|
+
|
|
310
308
|
if (command.examples?.length) {
|
|
311
|
-
|
|
309
|
+
buildLogger.info(`\nExamples:`)
|
|
312
310
|
for (const example of command.examples) {
|
|
313
|
-
|
|
311
|
+
buildLogger.info(` ${example}`)
|
|
314
312
|
}
|
|
315
313
|
}
|
|
316
|
-
|
|
314
|
+
|
|
317
315
|
if (command.aliases?.length) {
|
|
318
|
-
|
|
316
|
+
buildLogger.info(`\nAliases: ${command.aliases.join(', ')}`)
|
|
319
317
|
}
|
|
320
318
|
}
|
|
321
319
|
}
|
|
@@ -48,19 +48,24 @@ export const buildCommand: CLICommand = {
|
|
|
48
48
|
await pluginManager.initialize()
|
|
49
49
|
// Sync plugins to registry (same as framework does)
|
|
50
50
|
const discoveredPlugins = pluginManager.getRegistry().getAll()
|
|
51
|
+
const registryInternals = pluginRegistry as unknown as {
|
|
52
|
+
plugins: Map<string, import('@core/plugins/types').FluxStack.Plugin>
|
|
53
|
+
dependencies: Map<string, string[]>
|
|
54
|
+
loadOrder: string[]
|
|
55
|
+
updateLoadOrder(): void
|
|
56
|
+
}
|
|
51
57
|
for (const plugin of discoveredPlugins) {
|
|
52
58
|
if (!pluginRegistry.has(plugin.name)) {
|
|
53
|
-
|
|
59
|
+
registryInternals.plugins.set(plugin.name, plugin)
|
|
54
60
|
if (plugin.dependencies) {
|
|
55
|
-
|
|
61
|
+
registryInternals.dependencies.set(plugin.name, plugin.dependencies)
|
|
56
62
|
}
|
|
57
63
|
}
|
|
58
64
|
}
|
|
59
65
|
try {
|
|
60
|
-
|
|
61
|
-
} catch
|
|
62
|
-
|
|
63
|
-
;(pluginRegistry as any).loadOrder = Array.from(plugins.keys())
|
|
66
|
+
registryInternals.updateLoadOrder()
|
|
67
|
+
} catch {
|
|
68
|
+
registryInternals.loadOrder = Array.from(registryInternals.plugins.keys())
|
|
64
69
|
}
|
|
65
70
|
} catch (error) {
|
|
66
71
|
context.logger.warn('Failed to load plugins for build hooks', { error })
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
import type { CLICommand } from '../command-registry'
|
|
7
7
|
import { ProjectCreator } from '@core/templates/create-project'
|
|
8
|
+
import { buildLogger } from '@core/utils/build-logger'
|
|
8
9
|
|
|
9
10
|
export const createCommand: CLICommand = {
|
|
10
11
|
name: 'create',
|
|
@@ -32,22 +33,23 @@ export const createCommand: CLICommand = {
|
|
|
32
33
|
}
|
|
33
34
|
],
|
|
34
35
|
handler: async (args, options, context) => {
|
|
35
|
-
const
|
|
36
|
+
const projectName = args[0] as string
|
|
37
|
+
const template = args[1] as string | undefined
|
|
36
38
|
|
|
37
39
|
if (!/^[a-zA-Z0-9-_]+$/.test(projectName)) {
|
|
38
|
-
|
|
40
|
+
buildLogger.error("❌ Project name can only contain letters, numbers, hyphens, and underscores")
|
|
39
41
|
return
|
|
40
42
|
}
|
|
41
43
|
|
|
42
44
|
try {
|
|
43
45
|
const creator = new ProjectCreator({
|
|
44
|
-
name: projectName,
|
|
45
|
-
template: template as 'basic' | 'full' || 'basic'
|
|
46
|
+
name: projectName as string,
|
|
47
|
+
template: (template as 'basic' | 'full') || 'basic'
|
|
46
48
|
})
|
|
47
49
|
|
|
48
50
|
await creator.create()
|
|
49
51
|
} catch (error) {
|
|
50
|
-
|
|
52
|
+
buildLogger.error("❌ Failed to create project:", error instanceof Error ? error.message : String(error))
|
|
51
53
|
throw error
|
|
52
54
|
}
|
|
53
55
|
}
|
package/core/cli/commands/dev.ts
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
import type { CLICommand } from '../command-registry'
|
|
7
7
|
import { serverConfig, clientConfig } from '@config'
|
|
8
|
+
import { buildLogger } from '@core/utils/build-logger'
|
|
8
9
|
|
|
9
10
|
export const devCommand: CLICommand = {
|
|
10
11
|
name: 'dev',
|
|
@@ -53,7 +54,7 @@ export const devCommand: CLICommand = {
|
|
|
53
54
|
const backendOnly = options['backend-only'] === true
|
|
54
55
|
|
|
55
56
|
if (frontendOnly && backendOnly) {
|
|
56
|
-
|
|
57
|
+
buildLogger.error('❌ Cannot use --frontend-only and --backend-only together')
|
|
57
58
|
process.exit(1)
|
|
58
59
|
}
|
|
59
60
|
|
|
@@ -67,21 +68,21 @@ export const devCommand: CLICommand = {
|
|
|
67
68
|
|
|
68
69
|
const fluxstackMode = backendOnly ? 'backend-only' : 'full-stack'
|
|
69
70
|
|
|
70
|
-
|
|
71
|
+
buildLogger.info(`⚡ Starting ${mode} development server...`)
|
|
71
72
|
|
|
72
73
|
const devProcess = spawn("bun", ["--watch", entryPoint], {
|
|
73
74
|
stdio: "inherit",
|
|
74
75
|
cwd: process.cwd(),
|
|
75
76
|
env: {
|
|
76
77
|
...process.env,
|
|
77
|
-
FRONTEND_PORT: options['frontend-port']
|
|
78
|
-
BACKEND_PORT: options.port
|
|
78
|
+
FRONTEND_PORT: String(options['frontend-port']),
|
|
79
|
+
BACKEND_PORT: String(options.port),
|
|
79
80
|
FLUXSTACK_MODE: fluxstackMode
|
|
80
81
|
}
|
|
81
82
|
})
|
|
82
83
|
|
|
83
84
|
process.on('SIGINT', () => {
|
|
84
|
-
|
|
85
|
+
buildLogger.info('\n🛑 Shutting down gracefully...')
|
|
85
86
|
devProcess.kill('SIGTERM')
|
|
86
87
|
setTimeout(() => {
|
|
87
88
|
devProcess.kill('SIGKILL')
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
import type { CLICommand } from '../command-registry'
|
|
7
7
|
import { cliRegistry } from '../command-registry'
|
|
8
|
+
import { buildLogger } from '@core/utils/build-logger'
|
|
8
9
|
|
|
9
10
|
export const helpCommand: CLICommand = {
|
|
10
11
|
name: 'help',
|
|
@@ -20,11 +21,11 @@ export const helpCommand: CLICommand = {
|
|
|
20
21
|
],
|
|
21
22
|
handler: async (args, options, context) => {
|
|
22
23
|
if (args[0]) {
|
|
23
|
-
const targetCommand = cliRegistry.get(args[0])
|
|
24
|
+
const targetCommand = cliRegistry.get(args[0] as string)
|
|
24
25
|
if (targetCommand) {
|
|
25
26
|
cliRegistry.showCommandHelp(targetCommand)
|
|
26
27
|
} else {
|
|
27
|
-
|
|
28
|
+
buildLogger.error(`❌ Unknown command: ${args[0]}`)
|
|
28
29
|
cliRegistry.showHelp()
|
|
29
30
|
}
|
|
30
31
|
} else {
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import type { CLICommand } from '../command-registry'
|
|
7
|
+
import { buildLogger } from '@core/utils/build-logger'
|
|
7
8
|
|
|
8
9
|
export const makePluginCommand: CLICommand = {
|
|
9
10
|
name: 'make:plugin',
|
|
@@ -49,10 +50,10 @@ export const makePluginCommand: CLICommand = {
|
|
|
49
50
|
}
|
|
50
51
|
],
|
|
51
52
|
handler: async (args, options, context) => {
|
|
52
|
-
const
|
|
53
|
+
const name = args[0] as string
|
|
53
54
|
|
|
54
55
|
if (!/^[a-zA-Z0-9-_]+$/.test(name)) {
|
|
55
|
-
|
|
56
|
+
buildLogger.error("❌ Plugin name can only contain letters, numbers, hyphens, and underscores")
|
|
56
57
|
return
|
|
57
58
|
}
|
|
58
59
|
|
|
@@ -61,7 +62,7 @@ export const makePluginCommand: CLICommand = {
|
|
|
61
62
|
const pluginGenerator = generatorRegistry.get('plugin')
|
|
62
63
|
|
|
63
64
|
if (!pluginGenerator) {
|
|
64
|
-
|
|
65
|
+
buildLogger.error("❌ Plugin generator not found")
|
|
65
66
|
return
|
|
66
67
|
}
|
|
67
68
|
|
|
@@ -74,16 +75,16 @@ export const makePluginCommand: CLICommand = {
|
|
|
74
75
|
|
|
75
76
|
const generatorOptions = {
|
|
76
77
|
name,
|
|
77
|
-
template: options.template,
|
|
78
|
-
force: options.force,
|
|
78
|
+
template: options.template as string | undefined,
|
|
79
|
+
force: options.force as boolean | undefined,
|
|
79
80
|
dryRun: false,
|
|
80
|
-
description: options.description
|
|
81
|
+
description: options.description as string | undefined
|
|
81
82
|
}
|
|
82
83
|
|
|
83
84
|
try {
|
|
84
85
|
await pluginGenerator.generate(generatorContext, generatorOptions)
|
|
85
86
|
} catch (error) {
|
|
86
|
-
|
|
87
|
+
buildLogger.error("❌ Failed to create plugin:", error instanceof Error ? error.message : String(error))
|
|
87
88
|
throw error
|
|
88
89
|
}
|
|
89
90
|
}
|