create-fluxstack 1.0.0 → 1.0.2
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/create-fluxstack.ts +32 -17
- package/package-template.json +51 -0
- package/package.json +2 -1
- package/.env +0 -30
- package/LICENSE +0 -21
- package/app/client/README.md +0 -69
- package/app/client/frontend-only.ts +0 -12
- package/app/client/index.html +0 -13
- package/app/client/public/vite.svg +0 -1
- package/app/client/src/App.css +0 -883
- package/app/client/src/App.tsx +0 -669
- package/app/client/src/assets/react.svg +0 -1
- package/app/client/src/components/TestPage.tsx +0 -453
- package/app/client/src/index.css +0 -51
- package/app/client/src/lib/eden-api.ts +0 -110
- package/app/client/src/main.tsx +0 -10
- package/app/client/src/vite-env.d.ts +0 -1
- package/app/client/tsconfig.app.json +0 -43
- package/app/client/tsconfig.json +0 -7
- package/app/client/tsconfig.node.json +0 -25
- package/app/server/app.ts +0 -10
- package/app/server/backend-only.ts +0 -15
- package/app/server/controllers/users.controller.ts +0 -69
- package/app/server/index.ts +0 -104
- package/app/server/routes/index.ts +0 -25
- package/app/server/routes/users.routes.ts +0 -121
- package/app/server/types/index.ts +0 -1
- package/app/shared/types/index.ts +0 -18
- package/bun.lock +0 -1053
- package/core/__tests__/integration.test.ts +0 -227
- package/core/build/index.ts +0 -186
- package/core/cli/command-registry.ts +0 -334
- package/core/cli/index.ts +0 -394
- package/core/cli/plugin-discovery.ts +0 -200
- package/core/client/standalone.ts +0 -57
- package/core/config/__tests__/config-loader.test.ts +0 -591
- package/core/config/__tests__/config-merger.test.ts +0 -657
- package/core/config/__tests__/env-converter.test.ts +0 -372
- package/core/config/__tests__/env-processor.test.ts +0 -431
- package/core/config/__tests__/env.test.ts +0 -452
- package/core/config/__tests__/integration.test.ts +0 -418
- package/core/config/__tests__/loader.test.ts +0 -331
- package/core/config/__tests__/schema.test.ts +0 -129
- package/core/config/__tests__/validator.test.ts +0 -318
- package/core/config/env-dynamic.ts +0 -326
- package/core/config/env.ts +0 -597
- package/core/config/index.ts +0 -317
- package/core/config/loader.ts +0 -546
- package/core/config/runtime-config.ts +0 -322
- package/core/config/schema.ts +0 -694
- package/core/config/validator.ts +0 -540
- package/core/framework/__tests__/server.test.ts +0 -233
- package/core/framework/client.ts +0 -132
- package/core/framework/index.ts +0 -8
- package/core/framework/server.ts +0 -501
- package/core/framework/types.ts +0 -63
- package/core/plugins/__tests__/built-in.test.ts.disabled +0 -366
- package/core/plugins/__tests__/manager.test.ts +0 -398
- package/core/plugins/__tests__/monitoring.test.ts +0 -401
- package/core/plugins/__tests__/registry.test.ts +0 -335
- package/core/plugins/built-in/index.ts +0 -142
- package/core/plugins/built-in/logger/index.ts +0 -180
- package/core/plugins/built-in/monitoring/README.md +0 -193
- package/core/plugins/built-in/monitoring/index.ts +0 -912
- package/core/plugins/built-in/static/index.ts +0 -289
- package/core/plugins/built-in/swagger/index.ts +0 -229
- package/core/plugins/built-in/vite/index.ts +0 -316
- package/core/plugins/config.ts +0 -348
- package/core/plugins/discovery.ts +0 -350
- package/core/plugins/executor.ts +0 -351
- package/core/plugins/index.ts +0 -195
- package/core/plugins/manager.ts +0 -583
- package/core/plugins/registry.ts +0 -424
- package/core/plugins/types.ts +0 -254
- package/core/server/framework.ts +0 -123
- package/core/server/index.ts +0 -8
- package/core/server/plugins/database.ts +0 -182
- package/core/server/plugins/logger.ts +0 -47
- package/core/server/plugins/swagger.ts +0 -34
- package/core/server/standalone.ts +0 -91
- package/core/templates/create-project.ts +0 -455
- package/core/types/api.ts +0 -169
- package/core/types/build.ts +0 -174
- package/core/types/config.ts +0 -68
- package/core/types/index.ts +0 -127
- package/core/types/plugin.ts +0 -94
- package/core/utils/__tests__/errors.test.ts +0 -139
- package/core/utils/__tests__/helpers.test.ts +0 -297
- package/core/utils/__tests__/logger.test.ts +0 -141
- package/core/utils/env-runtime-v2.ts +0 -232
- package/core/utils/env-runtime.ts +0 -252
- package/core/utils/errors/codes.ts +0 -115
- package/core/utils/errors/handlers.ts +0 -63
- package/core/utils/errors/index.ts +0 -81
- package/core/utils/helpers.ts +0 -180
- package/core/utils/index.ts +0 -18
- package/core/utils/logger/index.ts +0 -161
- package/core/utils/logger.ts +0 -106
- package/core/utils/monitoring/index.ts +0 -212
- package/tsconfig.json +0 -51
- package/vite.config.ts +0 -42
|
@@ -1,318 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Tests for Configuration Validator
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import { describe, it, expect } from 'vitest'
|
|
6
|
-
import {
|
|
7
|
-
validateConfig,
|
|
8
|
-
validateConfigStrict,
|
|
9
|
-
createEnvironmentValidator,
|
|
10
|
-
validatePartialConfig,
|
|
11
|
-
getConfigSuggestions
|
|
12
|
-
} from '../validator'
|
|
13
|
-
import { defaultFluxStackConfig } from '../schema'
|
|
14
|
-
import type { FluxStackConfig } from '../schema'
|
|
15
|
-
|
|
16
|
-
describe('Configuration Validator', () => {
|
|
17
|
-
describe('validateConfig', () => {
|
|
18
|
-
it('should validate default configuration successfully', () => {
|
|
19
|
-
const result = validateConfig(defaultFluxStackConfig)
|
|
20
|
-
|
|
21
|
-
expect(result.valid).toBe(true)
|
|
22
|
-
expect(result.errors).toHaveLength(0)
|
|
23
|
-
})
|
|
24
|
-
|
|
25
|
-
it('should detect missing required properties', () => {
|
|
26
|
-
const invalidConfig = {
|
|
27
|
-
app: { name: 'test' }, // missing version
|
|
28
|
-
server: defaultFluxStackConfig.server,
|
|
29
|
-
client: defaultFluxStackConfig.client,
|
|
30
|
-
build: defaultFluxStackConfig.build,
|
|
31
|
-
plugins: defaultFluxStackConfig.plugins,
|
|
32
|
-
logging: defaultFluxStackConfig.logging,
|
|
33
|
-
monitoring: defaultFluxStackConfig.monitoring
|
|
34
|
-
} as FluxStackConfig
|
|
35
|
-
|
|
36
|
-
const result = validateConfig(invalidConfig)
|
|
37
|
-
|
|
38
|
-
expect(result.valid).toBe(false)
|
|
39
|
-
expect(result.errors.some(e => e.includes('version'))).toBe(true)
|
|
40
|
-
})
|
|
41
|
-
|
|
42
|
-
it('should detect invalid port numbers', () => {
|
|
43
|
-
const invalidConfig = {
|
|
44
|
-
...defaultFluxStackConfig,
|
|
45
|
-
server: {
|
|
46
|
-
...defaultFluxStackConfig.server,
|
|
47
|
-
port: 70000 // Invalid port
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
const result = validateConfig(invalidConfig)
|
|
52
|
-
|
|
53
|
-
expect(result.valid).toBe(false)
|
|
54
|
-
expect(result.errors.some(e => e.includes('port'))).toBe(true)
|
|
55
|
-
})
|
|
56
|
-
|
|
57
|
-
it('should detect port conflicts', () => {
|
|
58
|
-
const conflictConfig = {
|
|
59
|
-
...defaultFluxStackConfig,
|
|
60
|
-
server: { ...defaultFluxStackConfig.server, port: 3000 },
|
|
61
|
-
client: { ...defaultFluxStackConfig.client, port: 3000 }
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
const result = validateConfig(conflictConfig)
|
|
65
|
-
|
|
66
|
-
expect(result.valid).toBe(false)
|
|
67
|
-
expect(result.errors.some(e => e.includes('different'))).toBe(true)
|
|
68
|
-
})
|
|
69
|
-
|
|
70
|
-
it('should warn about security issues', () => {
|
|
71
|
-
const insecureConfig = {
|
|
72
|
-
...defaultFluxStackConfig,
|
|
73
|
-
server: {
|
|
74
|
-
...defaultFluxStackConfig.server,
|
|
75
|
-
cors: {
|
|
76
|
-
...defaultFluxStackConfig.server.cors,
|
|
77
|
-
origins: ['*'],
|
|
78
|
-
credentials: true
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
// Mock production environment
|
|
84
|
-
const originalEnv = process.env.NODE_ENV
|
|
85
|
-
process.env.NODE_ENV = 'production'
|
|
86
|
-
|
|
87
|
-
const result = validateConfig(insecureConfig)
|
|
88
|
-
|
|
89
|
-
expect(result.warnings.some(w => w.includes('wildcard'))).toBe(true)
|
|
90
|
-
|
|
91
|
-
// Restore environment
|
|
92
|
-
process.env.NODE_ENV = originalEnv
|
|
93
|
-
})
|
|
94
|
-
|
|
95
|
-
it('should validate enum values', () => {
|
|
96
|
-
const invalidConfig = {
|
|
97
|
-
...defaultFluxStackConfig,
|
|
98
|
-
logging: {
|
|
99
|
-
...defaultFluxStackConfig.logging,
|
|
100
|
-
level: 'invalid' as any
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
const result = validateConfig(invalidConfig)
|
|
105
|
-
|
|
106
|
-
expect(result.valid).toBe(false)
|
|
107
|
-
expect(result.errors.some(e => e.includes('one of'))).toBe(true)
|
|
108
|
-
})
|
|
109
|
-
|
|
110
|
-
it('should validate array constraints', () => {
|
|
111
|
-
const invalidConfig = {
|
|
112
|
-
...defaultFluxStackConfig,
|
|
113
|
-
server: {
|
|
114
|
-
...defaultFluxStackConfig.server,
|
|
115
|
-
cors: {
|
|
116
|
-
...defaultFluxStackConfig.server.cors,
|
|
117
|
-
origins: [] // Empty array
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
const result = validateConfig(invalidConfig)
|
|
123
|
-
|
|
124
|
-
expect(result.valid).toBe(false)
|
|
125
|
-
expect(result.errors.some(e => e.includes('at least'))).toBe(true)
|
|
126
|
-
})
|
|
127
|
-
})
|
|
128
|
-
|
|
129
|
-
describe('validateConfigStrict', () => {
|
|
130
|
-
it('should not throw for valid configuration', () => {
|
|
131
|
-
expect(() => {
|
|
132
|
-
validateConfigStrict(defaultFluxStackConfig)
|
|
133
|
-
}).not.toThrow()
|
|
134
|
-
})
|
|
135
|
-
|
|
136
|
-
it('should throw for invalid configuration', () => {
|
|
137
|
-
const invalidConfig = {
|
|
138
|
-
...defaultFluxStackConfig,
|
|
139
|
-
app: { name: '' } // Invalid empty name
|
|
140
|
-
} as FluxStackConfig
|
|
141
|
-
|
|
142
|
-
expect(() => {
|
|
143
|
-
validateConfigStrict(invalidConfig)
|
|
144
|
-
}).toThrow()
|
|
145
|
-
})
|
|
146
|
-
})
|
|
147
|
-
|
|
148
|
-
describe('createEnvironmentValidator', () => {
|
|
149
|
-
it('should create production validator with additional checks', () => {
|
|
150
|
-
const prodValidator = createEnvironmentValidator('production')
|
|
151
|
-
|
|
152
|
-
const devConfig = {
|
|
153
|
-
...defaultFluxStackConfig,
|
|
154
|
-
logging: { ...defaultFluxStackConfig.logging, level: 'debug' as const }
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
const result = prodValidator(devConfig)
|
|
158
|
-
|
|
159
|
-
expect(result.warnings.some(w => w.includes('Debug logging'))).toBe(true)
|
|
160
|
-
})
|
|
161
|
-
|
|
162
|
-
it('should create development validator with build warnings', () => {
|
|
163
|
-
const devValidator = createEnvironmentValidator('development')
|
|
164
|
-
|
|
165
|
-
const prodConfig = {
|
|
166
|
-
...defaultFluxStackConfig,
|
|
167
|
-
build: {
|
|
168
|
-
...defaultFluxStackConfig.build,
|
|
169
|
-
optimization: {
|
|
170
|
-
...defaultFluxStackConfig.build.optimization,
|
|
171
|
-
minify: true
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
const result = devValidator(prodConfig)
|
|
177
|
-
|
|
178
|
-
expect(result.warnings.some(w => w.includes('Minification enabled'))).toBe(true)
|
|
179
|
-
})
|
|
180
|
-
})
|
|
181
|
-
|
|
182
|
-
describe('validatePartialConfig', () => {
|
|
183
|
-
it('should validate partial configuration against base', () => {
|
|
184
|
-
const partialConfig = {
|
|
185
|
-
server: {
|
|
186
|
-
port: 4000,
|
|
187
|
-
host: 'localhost',
|
|
188
|
-
apiPrefix: '/api',
|
|
189
|
-
cors: {
|
|
190
|
-
origins: ['*'],
|
|
191
|
-
methods: ['GET', 'POST'],
|
|
192
|
-
headers: ['Content-Type'],
|
|
193
|
-
credentials: false,
|
|
194
|
-
maxAge: 86400
|
|
195
|
-
},
|
|
196
|
-
middleware: []
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
const result = validatePartialConfig(partialConfig, defaultFluxStackConfig)
|
|
201
|
-
|
|
202
|
-
expect(result.valid).toBe(true)
|
|
203
|
-
})
|
|
204
|
-
|
|
205
|
-
it('should detect conflicts in partial configuration', () => {
|
|
206
|
-
const partialConfig = {
|
|
207
|
-
server: {
|
|
208
|
-
port: 70000, // Invalid port
|
|
209
|
-
host: 'localhost',
|
|
210
|
-
apiPrefix: '/api',
|
|
211
|
-
cors: {
|
|
212
|
-
origins: ['*'],
|
|
213
|
-
methods: ['GET', 'POST'],
|
|
214
|
-
headers: ['Content-Type'],
|
|
215
|
-
credentials: false,
|
|
216
|
-
maxAge: 86400
|
|
217
|
-
},
|
|
218
|
-
middleware: []
|
|
219
|
-
}
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
const result = validatePartialConfig(partialConfig, defaultFluxStackConfig)
|
|
223
|
-
|
|
224
|
-
expect(result.valid).toBe(false)
|
|
225
|
-
})
|
|
226
|
-
})
|
|
227
|
-
|
|
228
|
-
describe('getConfigSuggestions', () => {
|
|
229
|
-
it('should provide suggestions for improvement', () => {
|
|
230
|
-
const basicConfig = {
|
|
231
|
-
...defaultFluxStackConfig,
|
|
232
|
-
monitoring: { ...defaultFluxStackConfig.monitoring, enabled: false }
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
const suggestions = getConfigSuggestions(basicConfig)
|
|
236
|
-
|
|
237
|
-
expect(suggestions.some(s => s.includes('monitoring'))).toBe(true)
|
|
238
|
-
})
|
|
239
|
-
|
|
240
|
-
it('should suggest database configuration', () => {
|
|
241
|
-
const configWithoutDb = {
|
|
242
|
-
...defaultFluxStackConfig,
|
|
243
|
-
database: undefined
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
const suggestions = getConfigSuggestions(configWithoutDb)
|
|
247
|
-
|
|
248
|
-
expect(suggestions.some(s => s.includes('database'))).toBe(true)
|
|
249
|
-
})
|
|
250
|
-
|
|
251
|
-
it('should suggest plugin enablement', () => {
|
|
252
|
-
const configWithoutPlugins = {
|
|
253
|
-
...defaultFluxStackConfig,
|
|
254
|
-
plugins: { ...defaultFluxStackConfig.plugins, enabled: [] }
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
const suggestions = getConfigSuggestions(configWithoutPlugins)
|
|
258
|
-
|
|
259
|
-
expect(suggestions.some(s => s.includes('plugins'))).toBe(true)
|
|
260
|
-
})
|
|
261
|
-
})
|
|
262
|
-
|
|
263
|
-
describe('Business Logic Validation', () => {
|
|
264
|
-
it('should validate plugin conflicts', () => {
|
|
265
|
-
const conflictConfig = {
|
|
266
|
-
...defaultFluxStackConfig,
|
|
267
|
-
plugins: {
|
|
268
|
-
enabled: ['logger', 'cors'],
|
|
269
|
-
disabled: ['logger'], // Conflict: logger is both enabled and disabled
|
|
270
|
-
config: {}
|
|
271
|
-
}
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
const result = validateConfig(conflictConfig)
|
|
275
|
-
|
|
276
|
-
expect(result.warnings.some(w => w.includes('both enabled and disabled'))).toBe(true)
|
|
277
|
-
})
|
|
278
|
-
|
|
279
|
-
it('should validate authentication security', () => {
|
|
280
|
-
const weakAuthConfig = {
|
|
281
|
-
...defaultFluxStackConfig,
|
|
282
|
-
auth: {
|
|
283
|
-
secret: 'short', // Too short
|
|
284
|
-
expiresIn: '24h'
|
|
285
|
-
}
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
const result = validateConfig(weakAuthConfig)
|
|
289
|
-
|
|
290
|
-
expect(result.warnings.some(w => w.includes('too short'))).toBe(true)
|
|
291
|
-
})
|
|
292
|
-
|
|
293
|
-
it('should validate build optimization settings', () => {
|
|
294
|
-
// Mock production environment
|
|
295
|
-
const originalEnv = process.env.NODE_ENV
|
|
296
|
-
process.env.NODE_ENV = 'production'
|
|
297
|
-
|
|
298
|
-
const unoptimizedConfig = {
|
|
299
|
-
...defaultFluxStackConfig,
|
|
300
|
-
build: {
|
|
301
|
-
...defaultFluxStackConfig.build,
|
|
302
|
-
optimization: {
|
|
303
|
-
...defaultFluxStackConfig.build.optimization,
|
|
304
|
-
minify: false,
|
|
305
|
-
treeshake: false
|
|
306
|
-
}
|
|
307
|
-
}
|
|
308
|
-
}
|
|
309
|
-
|
|
310
|
-
const result = validateConfig(unoptimizedConfig)
|
|
311
|
-
|
|
312
|
-
expect(result.warnings.some(w => w.includes('minification') || w.includes('tree-shaking'))).toBe(true)
|
|
313
|
-
|
|
314
|
-
// Restore environment
|
|
315
|
-
process.env.NODE_ENV = originalEnv
|
|
316
|
-
})
|
|
317
|
-
})
|
|
318
|
-
})
|
|
@@ -1,326 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Dynamic Environment Configuration Adapter for FluxStack
|
|
3
|
-
* Integrates runtime env loader with existing configuration system
|
|
4
|
-
* Solves Bun build issue by using dynamic environment access
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import { env, runtimeEnv, envValidation } from '../utils/env-runtime'
|
|
8
|
-
import type { FluxStackConfig, LogLevel, BuildTarget, LogFormat } from './schema'
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* Enhanced Environment Processor that uses dynamic env access
|
|
12
|
-
* Replaces the original EnvironmentProcessor from env.ts
|
|
13
|
-
*/
|
|
14
|
-
export class DynamicEnvironmentProcessor {
|
|
15
|
-
private precedenceMap: Map<string, any> = new Map()
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* Process environment variables using dynamic runtime access
|
|
19
|
-
* This prevents Bun from fixing env values during build
|
|
20
|
-
*/
|
|
21
|
-
processEnvironmentVariables(): Partial<FluxStackConfig> {
|
|
22
|
-
const config: any = {}
|
|
23
|
-
|
|
24
|
-
// App configuration
|
|
25
|
-
this.setConfigValue(config, 'app.name',
|
|
26
|
-
env.get('FLUXSTACK_APP_NAME') || env.get('APP_NAME'), 'string')
|
|
27
|
-
this.setConfigValue(config, 'app.version',
|
|
28
|
-
env.get('FLUXSTACK_APP_VERSION') || env.get('APP_VERSION'), 'string')
|
|
29
|
-
this.setConfigValue(config, 'app.description',
|
|
30
|
-
env.get('FLUXSTACK_APP_DESCRIPTION') || env.get('APP_DESCRIPTION'), 'string')
|
|
31
|
-
|
|
32
|
-
// Server configuration
|
|
33
|
-
this.setConfigValue(config, 'server.port',
|
|
34
|
-
env.get('PORT') || env.get('FLUXSTACK_PORT'), 'number')
|
|
35
|
-
this.setConfigValue(config, 'server.host',
|
|
36
|
-
env.get('HOST') || env.get('FLUXSTACK_HOST'), 'string')
|
|
37
|
-
this.setConfigValue(config, 'server.apiPrefix',
|
|
38
|
-
env.get('FLUXSTACK_API_PREFIX') || env.get('API_PREFIX'), 'string')
|
|
39
|
-
|
|
40
|
-
// CORS configuration
|
|
41
|
-
this.setConfigValue(config, 'server.cors.origins',
|
|
42
|
-
env.get('CORS_ORIGINS') || env.get('FLUXSTACK_CORS_ORIGINS'), 'array')
|
|
43
|
-
this.setConfigValue(config, 'server.cors.methods',
|
|
44
|
-
env.get('CORS_METHODS') || env.get('FLUXSTACK_CORS_METHODS'), 'array')
|
|
45
|
-
this.setConfigValue(config, 'server.cors.headers',
|
|
46
|
-
env.get('CORS_HEADERS') || env.get('FLUXSTACK_CORS_HEADERS'), 'array')
|
|
47
|
-
this.setConfigValue(config, 'server.cors.credentials',
|
|
48
|
-
env.get('CORS_CREDENTIALS') || env.get('FLUXSTACK_CORS_CREDENTIALS'), 'boolean')
|
|
49
|
-
this.setConfigValue(config, 'server.cors.maxAge',
|
|
50
|
-
env.get('CORS_MAX_AGE') || env.get('FLUXSTACK_CORS_MAX_AGE'), 'number')
|
|
51
|
-
|
|
52
|
-
// Client configuration
|
|
53
|
-
this.setConfigValue(config, 'client.port',
|
|
54
|
-
env.get('VITE_PORT') || env.get('CLIENT_PORT') || env.get('FLUXSTACK_CLIENT_PORT'), 'number')
|
|
55
|
-
this.setConfigValue(config, 'client.proxy.target',
|
|
56
|
-
env.get('VITE_API_URL') || env.get('API_URL') || env.get('FLUXSTACK_PROXY_TARGET'), 'string')
|
|
57
|
-
this.setConfigValue(config, 'client.build.sourceMaps',
|
|
58
|
-
env.get('FLUXSTACK_CLIENT_SOURCEMAPS'), 'boolean')
|
|
59
|
-
this.setConfigValue(config, 'client.build.minify',
|
|
60
|
-
env.get('FLUXSTACK_CLIENT_MINIFY'), 'boolean')
|
|
61
|
-
|
|
62
|
-
// Build configuration
|
|
63
|
-
this.setConfigValue(config, 'build.target',
|
|
64
|
-
env.get('BUILD_TARGET') || env.get('FLUXSTACK_BUILD_TARGET'), 'buildTarget')
|
|
65
|
-
this.setConfigValue(config, 'build.outDir',
|
|
66
|
-
env.get('BUILD_OUTDIR') || env.get('FLUXSTACK_BUILD_OUTDIR'), 'string')
|
|
67
|
-
this.setConfigValue(config, 'build.sourceMaps',
|
|
68
|
-
env.get('BUILD_SOURCEMAPS') || env.get('FLUXSTACK_BUILD_SOURCEMAPS'), 'boolean')
|
|
69
|
-
this.setConfigValue(config, 'build.clean',
|
|
70
|
-
env.get('BUILD_CLEAN') || env.get('FLUXSTACK_BUILD_CLEAN'), 'boolean')
|
|
71
|
-
|
|
72
|
-
// Build optimization
|
|
73
|
-
this.setConfigValue(config, 'build.optimization.minify',
|
|
74
|
-
env.get('BUILD_MINIFY') || env.get('FLUXSTACK_BUILD_MINIFY'), 'boolean')
|
|
75
|
-
this.setConfigValue(config, 'build.optimization.treeshake',
|
|
76
|
-
env.get('BUILD_TREESHAKE') || env.get('FLUXSTACK_BUILD_TREESHAKE'), 'boolean')
|
|
77
|
-
this.setConfigValue(config, 'build.optimization.compress',
|
|
78
|
-
env.get('BUILD_COMPRESS') || env.get('FLUXSTACK_BUILD_COMPRESS'), 'boolean')
|
|
79
|
-
this.setConfigValue(config, 'build.optimization.splitChunks',
|
|
80
|
-
env.get('BUILD_SPLIT_CHUNKS') || env.get('FLUXSTACK_BUILD_SPLIT_CHUNKS'), 'boolean')
|
|
81
|
-
this.setConfigValue(config, 'build.optimization.bundleAnalyzer',
|
|
82
|
-
env.get('BUILD_ANALYZER') || env.get('FLUXSTACK_BUILD_ANALYZER'), 'boolean')
|
|
83
|
-
|
|
84
|
-
// Logging configuration
|
|
85
|
-
this.setConfigValue(config, 'logging.level',
|
|
86
|
-
env.get('LOG_LEVEL') || env.get('FLUXSTACK_LOG_LEVEL'), 'logLevel')
|
|
87
|
-
this.setConfigValue(config, 'logging.format',
|
|
88
|
-
env.get('LOG_FORMAT') || env.get('FLUXSTACK_LOG_FORMAT'), 'logFormat')
|
|
89
|
-
|
|
90
|
-
// Monitoring configuration
|
|
91
|
-
this.setConfigValue(config, 'monitoring.enabled',
|
|
92
|
-
env.get('MONITORING_ENABLED') || env.get('FLUXSTACK_MONITORING_ENABLED'), 'boolean')
|
|
93
|
-
this.setConfigValue(config, 'monitoring.metrics.enabled',
|
|
94
|
-
env.get('METRICS_ENABLED') || env.get('FLUXSTACK_METRICS_ENABLED'), 'boolean')
|
|
95
|
-
this.setConfigValue(config, 'monitoring.metrics.collectInterval',
|
|
96
|
-
env.get('METRICS_INTERVAL') || env.get('FLUXSTACK_METRICS_INTERVAL'), 'number')
|
|
97
|
-
this.setConfigValue(config, 'monitoring.profiling.enabled',
|
|
98
|
-
env.get('PROFILING_ENABLED') || env.get('FLUXSTACK_PROFILING_ENABLED'), 'boolean')
|
|
99
|
-
this.setConfigValue(config, 'monitoring.profiling.sampleRate',
|
|
100
|
-
env.get('PROFILING_SAMPLE_RATE') || env.get('FLUXSTACK_PROFILING_SAMPLE_RATE'), 'number')
|
|
101
|
-
|
|
102
|
-
// Database configuration
|
|
103
|
-
this.setConfigValue(config, 'database.url', env.get('DATABASE_URL'), 'string')
|
|
104
|
-
this.setConfigValue(config, 'database.host', env.get('DATABASE_HOST'), 'string')
|
|
105
|
-
this.setConfigValue(config, 'database.port', env.get('DATABASE_PORT'), 'number')
|
|
106
|
-
this.setConfigValue(config, 'database.database', env.get('DATABASE_NAME'), 'string')
|
|
107
|
-
this.setConfigValue(config, 'database.user', env.get('DATABASE_USER'), 'string')
|
|
108
|
-
this.setConfigValue(config, 'database.password', env.get('DATABASE_PASSWORD'), 'string')
|
|
109
|
-
this.setConfigValue(config, 'database.ssl', env.get('DATABASE_SSL'), 'boolean')
|
|
110
|
-
this.setConfigValue(config, 'database.poolSize', env.get('DATABASE_POOL_SIZE'), 'number')
|
|
111
|
-
|
|
112
|
-
// Auth configuration
|
|
113
|
-
this.setConfigValue(config, 'auth.secret', env.get('JWT_SECRET'), 'string')
|
|
114
|
-
this.setConfigValue(config, 'auth.expiresIn', env.get('JWT_EXPIRES_IN'), 'string')
|
|
115
|
-
this.setConfigValue(config, 'auth.algorithm', env.get('JWT_ALGORITHM'), 'string')
|
|
116
|
-
this.setConfigValue(config, 'auth.issuer', env.get('JWT_ISSUER'), 'string')
|
|
117
|
-
|
|
118
|
-
// Email configuration
|
|
119
|
-
this.setConfigValue(config, 'email.host', env.get('SMTP_HOST'), 'string')
|
|
120
|
-
this.setConfigValue(config, 'email.port', env.get('SMTP_PORT'), 'number')
|
|
121
|
-
this.setConfigValue(config, 'email.user', env.get('SMTP_USER'), 'string')
|
|
122
|
-
this.setConfigValue(config, 'email.password', env.get('SMTP_PASSWORD'), 'string')
|
|
123
|
-
this.setConfigValue(config, 'email.secure', env.get('SMTP_SECURE'), 'boolean')
|
|
124
|
-
this.setConfigValue(config, 'email.from', env.get('SMTP_FROM'), 'string')
|
|
125
|
-
|
|
126
|
-
// Storage configuration
|
|
127
|
-
this.setConfigValue(config, 'storage.uploadPath', env.get('UPLOAD_PATH'), 'string')
|
|
128
|
-
this.setConfigValue(config, 'storage.maxFileSize', env.get('MAX_FILE_SIZE'), 'number')
|
|
129
|
-
this.setConfigValue(config, 'storage.provider', env.get('STORAGE_PROVIDER'), 'string')
|
|
130
|
-
|
|
131
|
-
// Plugin configuration
|
|
132
|
-
this.setConfigValue(config, 'plugins.enabled',
|
|
133
|
-
env.get('FLUXSTACK_PLUGINS_ENABLED'), 'array')
|
|
134
|
-
this.setConfigValue(config, 'plugins.disabled',
|
|
135
|
-
env.get('FLUXSTACK_PLUGINS_DISABLED'), 'array')
|
|
136
|
-
|
|
137
|
-
return this.cleanEmptyObjects(config)
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
private setConfigValue(
|
|
141
|
-
config: any,
|
|
142
|
-
path: string,
|
|
143
|
-
value: string | undefined,
|
|
144
|
-
type: string
|
|
145
|
-
): void {
|
|
146
|
-
if (value === undefined || value === '') return
|
|
147
|
-
|
|
148
|
-
const convertedValue = this.convertValue(value, type)
|
|
149
|
-
if (convertedValue !== undefined) {
|
|
150
|
-
this.setNestedProperty(config, path, convertedValue)
|
|
151
|
-
|
|
152
|
-
// Track precedence
|
|
153
|
-
this.precedenceMap.set(path, {
|
|
154
|
-
source: 'environment',
|
|
155
|
-
path,
|
|
156
|
-
value: convertedValue,
|
|
157
|
-
priority: 3
|
|
158
|
-
})
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
private convertValue(value: string, type: string): any {
|
|
163
|
-
switch (type) {
|
|
164
|
-
case 'string':
|
|
165
|
-
return value
|
|
166
|
-
case 'number':
|
|
167
|
-
const num = parseInt(value, 10)
|
|
168
|
-
return isNaN(num) ? undefined : num
|
|
169
|
-
case 'boolean':
|
|
170
|
-
return ['true', '1', 'yes', 'on'].includes(value.toLowerCase())
|
|
171
|
-
case 'array':
|
|
172
|
-
return value.split(',').map(v => v.trim()).filter(Boolean)
|
|
173
|
-
case 'logLevel':
|
|
174
|
-
const level = value.toLowerCase() as LogLevel
|
|
175
|
-
return ['debug', 'info', 'warn', 'error'].includes(level) ? level : 'info'
|
|
176
|
-
case 'buildTarget':
|
|
177
|
-
const target = value.toLowerCase() as BuildTarget
|
|
178
|
-
return ['bun', 'node', 'docker'].includes(target) ? target : 'bun'
|
|
179
|
-
case 'logFormat':
|
|
180
|
-
const format = value.toLowerCase() as LogFormat
|
|
181
|
-
return ['json', 'pretty'].includes(format) ? format : 'pretty'
|
|
182
|
-
case 'object':
|
|
183
|
-
try {
|
|
184
|
-
return JSON.parse(value)
|
|
185
|
-
} catch {
|
|
186
|
-
return {}
|
|
187
|
-
}
|
|
188
|
-
default:
|
|
189
|
-
return value
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
private setNestedProperty(obj: any, path: string, value: any): void {
|
|
194
|
-
const keys = path.split('.')
|
|
195
|
-
let current = obj
|
|
196
|
-
|
|
197
|
-
for (let i = 0; i < keys.length - 1; i++) {
|
|
198
|
-
const key = keys[i]
|
|
199
|
-
if (!(key in current) || typeof current[key] !== 'object') {
|
|
200
|
-
current[key] = {}
|
|
201
|
-
}
|
|
202
|
-
current = current[key]
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
current[keys[keys.length - 1]] = value
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
private cleanEmptyObjects(obj: any): any {
|
|
209
|
-
if (typeof obj !== 'object' || obj === null) return obj
|
|
210
|
-
|
|
211
|
-
const cleaned: any = {}
|
|
212
|
-
|
|
213
|
-
for (const [key, value] of Object.entries(obj)) {
|
|
214
|
-
if (typeof value === 'object' && value !== null && !Array.isArray(value)) {
|
|
215
|
-
const cleanedValue = this.cleanEmptyObjects(value)
|
|
216
|
-
if (Object.keys(cleanedValue).length > 0) {
|
|
217
|
-
cleaned[key] = cleanedValue
|
|
218
|
-
}
|
|
219
|
-
} else if (value !== undefined && value !== null) {
|
|
220
|
-
cleaned[key] = value
|
|
221
|
-
}
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
return cleaned
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
getPrecedenceInfo(): Map<string, any> {
|
|
228
|
-
return new Map(this.precedenceMap)
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
clearPrecedence(): void {
|
|
232
|
-
this.precedenceMap.clear()
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
/**
|
|
237
|
-
* Enhanced environment info with dynamic access
|
|
238
|
-
*/
|
|
239
|
-
export function getDynamicEnvironmentInfo() {
|
|
240
|
-
const nodeEnv = env.get('NODE_ENV', 'development')
|
|
241
|
-
|
|
242
|
-
return {
|
|
243
|
-
name: nodeEnv,
|
|
244
|
-
isDevelopment: nodeEnv === 'development',
|
|
245
|
-
isProduction: nodeEnv === 'production',
|
|
246
|
-
isTest: nodeEnv === 'test',
|
|
247
|
-
nodeEnv
|
|
248
|
-
}
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
/**
|
|
252
|
-
* Runtime configuration loader that uses dynamic env access
|
|
253
|
-
*/
|
|
254
|
-
export function loadConfigFromDynamicEnv(): Partial<FluxStackConfig> {
|
|
255
|
-
const processor = new DynamicEnvironmentProcessor()
|
|
256
|
-
return processor.processEnvironmentVariables()
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
/**
|
|
260
|
-
* Utility functions for backward compatibility
|
|
261
|
-
*/
|
|
262
|
-
export function isDevelopment(): boolean {
|
|
263
|
-
return getDynamicEnvironmentInfo().isDevelopment
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
export function isProduction(): boolean {
|
|
267
|
-
return getDynamicEnvironmentInfo().isProduction
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
export function isTest(): boolean {
|
|
271
|
-
return getDynamicEnvironmentInfo().isTest
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
/**
|
|
275
|
-
* Validate critical environment variables for production
|
|
276
|
-
*/
|
|
277
|
-
export function validateProductionEnv(): void {
|
|
278
|
-
if (isProduction()) {
|
|
279
|
-
const requiredVars = ['NODE_ENV']
|
|
280
|
-
const missingVars = requiredVars.filter(key => !env.has(key))
|
|
281
|
-
|
|
282
|
-
if (missingVars.length > 0) {
|
|
283
|
-
throw new Error(`Missing required production environment variables: ${missingVars.join(', ')}`)
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
// Validate LOG_LEVEL for production
|
|
287
|
-
const logLevel = env.get('LOG_LEVEL')
|
|
288
|
-
if (logLevel === 'debug') {
|
|
289
|
-
console.warn('⚠️ Production environment should not use debug logging')
|
|
290
|
-
}
|
|
291
|
-
}
|
|
292
|
-
}
|
|
293
|
-
|
|
294
|
-
/**
|
|
295
|
-
* Create environment-aware configuration
|
|
296
|
-
*/
|
|
297
|
-
export function createDynamicConfig(): Partial<FluxStackConfig> {
|
|
298
|
-
const envInfo = getDynamicEnvironmentInfo()
|
|
299
|
-
const envConfig = loadConfigFromDynamicEnv()
|
|
300
|
-
|
|
301
|
-
// Add environment-specific defaults
|
|
302
|
-
const config: any = { ...envConfig }
|
|
303
|
-
|
|
304
|
-
// Ensure proper defaults based on environment
|
|
305
|
-
if (envInfo.isDevelopment) {
|
|
306
|
-
config.logging = {
|
|
307
|
-
level: env.get('LOG_LEVEL', 'debug'),
|
|
308
|
-
format: env.get('LOG_FORMAT', 'pretty'),
|
|
309
|
-
...config.logging
|
|
310
|
-
}
|
|
311
|
-
} else if (envInfo.isProduction) {
|
|
312
|
-
config.logging = {
|
|
313
|
-
level: env.get('LOG_LEVEL', 'warn'),
|
|
314
|
-
format: env.get('LOG_FORMAT', 'json'),
|
|
315
|
-
...config.logging
|
|
316
|
-
}
|
|
317
|
-
}
|
|
318
|
-
|
|
319
|
-
return config
|
|
320
|
-
}
|
|
321
|
-
|
|
322
|
-
// Export singleton instance
|
|
323
|
-
export const dynamicEnvironmentProcessor = new DynamicEnvironmentProcessor()
|
|
324
|
-
|
|
325
|
-
// Export runtime environment access
|
|
326
|
-
export { env, runtimeEnv, envValidation } from '../utils/env-runtime'
|