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.
Files changed (101) hide show
  1. package/create-fluxstack.ts +32 -17
  2. package/package-template.json +51 -0
  3. package/package.json +2 -1
  4. package/.env +0 -30
  5. package/LICENSE +0 -21
  6. package/app/client/README.md +0 -69
  7. package/app/client/frontend-only.ts +0 -12
  8. package/app/client/index.html +0 -13
  9. package/app/client/public/vite.svg +0 -1
  10. package/app/client/src/App.css +0 -883
  11. package/app/client/src/App.tsx +0 -669
  12. package/app/client/src/assets/react.svg +0 -1
  13. package/app/client/src/components/TestPage.tsx +0 -453
  14. package/app/client/src/index.css +0 -51
  15. package/app/client/src/lib/eden-api.ts +0 -110
  16. package/app/client/src/main.tsx +0 -10
  17. package/app/client/src/vite-env.d.ts +0 -1
  18. package/app/client/tsconfig.app.json +0 -43
  19. package/app/client/tsconfig.json +0 -7
  20. package/app/client/tsconfig.node.json +0 -25
  21. package/app/server/app.ts +0 -10
  22. package/app/server/backend-only.ts +0 -15
  23. package/app/server/controllers/users.controller.ts +0 -69
  24. package/app/server/index.ts +0 -104
  25. package/app/server/routes/index.ts +0 -25
  26. package/app/server/routes/users.routes.ts +0 -121
  27. package/app/server/types/index.ts +0 -1
  28. package/app/shared/types/index.ts +0 -18
  29. package/bun.lock +0 -1053
  30. package/core/__tests__/integration.test.ts +0 -227
  31. package/core/build/index.ts +0 -186
  32. package/core/cli/command-registry.ts +0 -334
  33. package/core/cli/index.ts +0 -394
  34. package/core/cli/plugin-discovery.ts +0 -200
  35. package/core/client/standalone.ts +0 -57
  36. package/core/config/__tests__/config-loader.test.ts +0 -591
  37. package/core/config/__tests__/config-merger.test.ts +0 -657
  38. package/core/config/__tests__/env-converter.test.ts +0 -372
  39. package/core/config/__tests__/env-processor.test.ts +0 -431
  40. package/core/config/__tests__/env.test.ts +0 -452
  41. package/core/config/__tests__/integration.test.ts +0 -418
  42. package/core/config/__tests__/loader.test.ts +0 -331
  43. package/core/config/__tests__/schema.test.ts +0 -129
  44. package/core/config/__tests__/validator.test.ts +0 -318
  45. package/core/config/env-dynamic.ts +0 -326
  46. package/core/config/env.ts +0 -597
  47. package/core/config/index.ts +0 -317
  48. package/core/config/loader.ts +0 -546
  49. package/core/config/runtime-config.ts +0 -322
  50. package/core/config/schema.ts +0 -694
  51. package/core/config/validator.ts +0 -540
  52. package/core/framework/__tests__/server.test.ts +0 -233
  53. package/core/framework/client.ts +0 -132
  54. package/core/framework/index.ts +0 -8
  55. package/core/framework/server.ts +0 -501
  56. package/core/framework/types.ts +0 -63
  57. package/core/plugins/__tests__/built-in.test.ts.disabled +0 -366
  58. package/core/plugins/__tests__/manager.test.ts +0 -398
  59. package/core/plugins/__tests__/monitoring.test.ts +0 -401
  60. package/core/plugins/__tests__/registry.test.ts +0 -335
  61. package/core/plugins/built-in/index.ts +0 -142
  62. package/core/plugins/built-in/logger/index.ts +0 -180
  63. package/core/plugins/built-in/monitoring/README.md +0 -193
  64. package/core/plugins/built-in/monitoring/index.ts +0 -912
  65. package/core/plugins/built-in/static/index.ts +0 -289
  66. package/core/plugins/built-in/swagger/index.ts +0 -229
  67. package/core/plugins/built-in/vite/index.ts +0 -316
  68. package/core/plugins/config.ts +0 -348
  69. package/core/plugins/discovery.ts +0 -350
  70. package/core/plugins/executor.ts +0 -351
  71. package/core/plugins/index.ts +0 -195
  72. package/core/plugins/manager.ts +0 -583
  73. package/core/plugins/registry.ts +0 -424
  74. package/core/plugins/types.ts +0 -254
  75. package/core/server/framework.ts +0 -123
  76. package/core/server/index.ts +0 -8
  77. package/core/server/plugins/database.ts +0 -182
  78. package/core/server/plugins/logger.ts +0 -47
  79. package/core/server/plugins/swagger.ts +0 -34
  80. package/core/server/standalone.ts +0 -91
  81. package/core/templates/create-project.ts +0 -455
  82. package/core/types/api.ts +0 -169
  83. package/core/types/build.ts +0 -174
  84. package/core/types/config.ts +0 -68
  85. package/core/types/index.ts +0 -127
  86. package/core/types/plugin.ts +0 -94
  87. package/core/utils/__tests__/errors.test.ts +0 -139
  88. package/core/utils/__tests__/helpers.test.ts +0 -297
  89. package/core/utils/__tests__/logger.test.ts +0 -141
  90. package/core/utils/env-runtime-v2.ts +0 -232
  91. package/core/utils/env-runtime.ts +0 -252
  92. package/core/utils/errors/codes.ts +0 -115
  93. package/core/utils/errors/handlers.ts +0 -63
  94. package/core/utils/errors/index.ts +0 -81
  95. package/core/utils/helpers.ts +0 -180
  96. package/core/utils/index.ts +0 -18
  97. package/core/utils/logger/index.ts +0 -161
  98. package/core/utils/logger.ts +0 -106
  99. package/core/utils/monitoring/index.ts +0 -212
  100. package/tsconfig.json +0 -51
  101. 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'