create-fluxstack 1.0.1 → 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 +2 -3
- package/package.json +1 -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,657 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Tests for ConfigMerger and EnvironmentConfigApplier
|
|
3
|
-
* Tests configuration merging with precedence and environment-specific configs
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import { describe, test, expect } from 'vitest'
|
|
7
|
-
import {
|
|
8
|
-
ConfigMerger,
|
|
9
|
-
EnvironmentConfigApplier
|
|
10
|
-
} from '../env'
|
|
11
|
-
import type { FluxStackConfig } from '../schema'
|
|
12
|
-
|
|
13
|
-
describe('ConfigMerger', () => {
|
|
14
|
-
let merger: ConfigMerger
|
|
15
|
-
|
|
16
|
-
beforeEach(() => {
|
|
17
|
-
merger = new ConfigMerger()
|
|
18
|
-
})
|
|
19
|
-
|
|
20
|
-
describe('merge', () => {
|
|
21
|
-
test('merges simple configurations', () => {
|
|
22
|
-
const config1 = {
|
|
23
|
-
config: {
|
|
24
|
-
app: { name: 'TestApp', version: '1.0.0' },
|
|
25
|
-
server: { port: 3000 }
|
|
26
|
-
} as Partial<FluxStackConfig>,
|
|
27
|
-
source: 'default'
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
const config2 = {
|
|
31
|
-
config: {
|
|
32
|
-
app: { version: '2.0.0' },
|
|
33
|
-
server: { host: 'localhost' }
|
|
34
|
-
} as Partial<FluxStackConfig>,
|
|
35
|
-
source: 'file'
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
const result = merger.merge(config1, config2)
|
|
39
|
-
|
|
40
|
-
expect(result.app?.name).toBe('TestApp') // from config1
|
|
41
|
-
expect(result.app?.version).toBe('2.0.0') // overridden by config2
|
|
42
|
-
expect(result.server?.port).toBe(3000) // from config1
|
|
43
|
-
expect(result.server?.host).toBe('localhost') // from config2
|
|
44
|
-
})
|
|
45
|
-
|
|
46
|
-
test('respects precedence order', () => {
|
|
47
|
-
const defaultConfig = {
|
|
48
|
-
config: {
|
|
49
|
-
server: { port: 3000, host: 'localhost' }
|
|
50
|
-
} as Partial<FluxStackConfig>,
|
|
51
|
-
source: 'default'
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
const fileConfig = {
|
|
55
|
-
config: {
|
|
56
|
-
server: { port: 4000 }
|
|
57
|
-
} as Partial<FluxStackConfig>,
|
|
58
|
-
source: 'file'
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
const envConfig = {
|
|
62
|
-
config: {
|
|
63
|
-
server: { port: 5000 }
|
|
64
|
-
} as Partial<FluxStackConfig>,
|
|
65
|
-
source: 'environment'
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
const overrideConfig = {
|
|
69
|
-
config: {
|
|
70
|
-
server: { port: 6000 }
|
|
71
|
-
} as Partial<FluxStackConfig>,
|
|
72
|
-
source: 'override'
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
const result = merger.merge(defaultConfig, fileConfig, envConfig, overrideConfig)
|
|
76
|
-
|
|
77
|
-
// Override should win (highest precedence)
|
|
78
|
-
expect(result.server?.port).toBe(6000)
|
|
79
|
-
expect(result.server?.host).toBe('localhost') // from default (not overridden)
|
|
80
|
-
})
|
|
81
|
-
|
|
82
|
-
test('handles nested object merging', () => {
|
|
83
|
-
const config1 = {
|
|
84
|
-
config: {
|
|
85
|
-
server: {
|
|
86
|
-
cors: {
|
|
87
|
-
origins: ['http://localhost:3000'],
|
|
88
|
-
methods: ['GET', 'POST'],
|
|
89
|
-
credentials: true
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
} as Partial<FluxStackConfig>,
|
|
93
|
-
source: 'default'
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
const config2 = {
|
|
97
|
-
config: {
|
|
98
|
-
server: {
|
|
99
|
-
cors: {
|
|
100
|
-
origins: ['http://localhost:5173'],
|
|
101
|
-
headers: ['Content-Type']
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
} as Partial<FluxStackConfig>,
|
|
105
|
-
source: 'environment'
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
const result = merger.merge(config1, config2)
|
|
109
|
-
|
|
110
|
-
expect(result.server?.cors?.origins).toEqual(['http://localhost:5173']) // overridden
|
|
111
|
-
expect(result.server?.cors?.methods).toEqual(['GET', 'POST']) // preserved
|
|
112
|
-
expect(result.server?.cors?.headers).toEqual(['Content-Type']) // added
|
|
113
|
-
expect(result.server?.cors?.credentials).toBe(true) // preserved
|
|
114
|
-
})
|
|
115
|
-
|
|
116
|
-
test('handles array replacement (not merging)', () => {
|
|
117
|
-
const config1 = {
|
|
118
|
-
config: {
|
|
119
|
-
plugins: {
|
|
120
|
-
enabled: ['plugin1', 'plugin2', 'plugin3']
|
|
121
|
-
}
|
|
122
|
-
} as Partial<FluxStackConfig>,
|
|
123
|
-
source: 'default'
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
const config2 = {
|
|
127
|
-
config: {
|
|
128
|
-
plugins: {
|
|
129
|
-
enabled: ['plugin4', 'plugin5']
|
|
130
|
-
}
|
|
131
|
-
} as Partial<FluxStackConfig>,
|
|
132
|
-
source: 'environment'
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
const result = merger.merge(config1, config2)
|
|
136
|
-
|
|
137
|
-
// Arrays should be replaced, not merged
|
|
138
|
-
expect(result.plugins?.enabled).toEqual(['plugin4', 'plugin5'])
|
|
139
|
-
})
|
|
140
|
-
|
|
141
|
-
test('handles null and undefined values', () => {
|
|
142
|
-
const config1 = {
|
|
143
|
-
config: {
|
|
144
|
-
database: {
|
|
145
|
-
host: 'localhost',
|
|
146
|
-
port: 5432,
|
|
147
|
-
ssl: true
|
|
148
|
-
}
|
|
149
|
-
} as Partial<FluxStackConfig>,
|
|
150
|
-
source: 'default'
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
const config2 = {
|
|
154
|
-
config: {
|
|
155
|
-
database: {
|
|
156
|
-
port: null,
|
|
157
|
-
ssl: undefined
|
|
158
|
-
}
|
|
159
|
-
} as any,
|
|
160
|
-
source: 'environment'
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
const result = merger.merge(config1, config2)
|
|
164
|
-
|
|
165
|
-
expect(result.database?.host).toBe('localhost') // preserved
|
|
166
|
-
expect(result.database?.port).toBe(null) // overridden with null
|
|
167
|
-
expect(result.database?.ssl).toBe(true) // undefined doesn't override
|
|
168
|
-
})
|
|
169
|
-
|
|
170
|
-
test('merges complex nested structures', () => {
|
|
171
|
-
const config1 = {
|
|
172
|
-
config: {
|
|
173
|
-
monitoring: {
|
|
174
|
-
enabled: true,
|
|
175
|
-
metrics: {
|
|
176
|
-
enabled: true,
|
|
177
|
-
collectInterval: 5000,
|
|
178
|
-
httpMetrics: true,
|
|
179
|
-
systemMetrics: false
|
|
180
|
-
},
|
|
181
|
-
profiling: {
|
|
182
|
-
enabled: false,
|
|
183
|
-
sampleRate: 0.1
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
} as Partial<FluxStackConfig>,
|
|
187
|
-
source: 'default'
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
const config2 = {
|
|
191
|
-
config: {
|
|
192
|
-
monitoring: {
|
|
193
|
-
metrics: {
|
|
194
|
-
collectInterval: 10000,
|
|
195
|
-
systemMetrics: true,
|
|
196
|
-
customMetrics: true
|
|
197
|
-
},
|
|
198
|
-
profiling: {
|
|
199
|
-
enabled: true,
|
|
200
|
-
memoryProfiling: true
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
} as Partial<FluxStackConfig>,
|
|
204
|
-
source: 'environment'
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
const result = merger.merge(config1, config2)
|
|
208
|
-
|
|
209
|
-
expect(result.monitoring?.enabled).toBe(true) // from config1
|
|
210
|
-
expect(result.monitoring?.metrics?.enabled).toBe(true) // from config1
|
|
211
|
-
expect(result.monitoring?.metrics?.collectInterval).toBe(10000) // from config2
|
|
212
|
-
expect(result.monitoring?.metrics?.httpMetrics).toBe(true) // from config1
|
|
213
|
-
expect(result.monitoring?.metrics?.systemMetrics).toBe(true) // from config2
|
|
214
|
-
expect((result.monitoring?.metrics as any)?.customMetrics).toBe(true) // from config2
|
|
215
|
-
expect(result.monitoring?.profiling?.enabled).toBe(true) // from config2
|
|
216
|
-
expect(result.monitoring?.profiling?.sampleRate).toBe(0.1) // from config1
|
|
217
|
-
expect((result.monitoring?.profiling as any)?.memoryProfiling).toBe(true) // from config2
|
|
218
|
-
})
|
|
219
|
-
|
|
220
|
-
test('handles empty configurations', () => {
|
|
221
|
-
const emptyConfig = {
|
|
222
|
-
config: {} as Partial<FluxStackConfig>,
|
|
223
|
-
source: 'default'
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
const config2 = {
|
|
227
|
-
config: {
|
|
228
|
-
app: { name: 'TestApp' }
|
|
229
|
-
} as Partial<FluxStackConfig>,
|
|
230
|
-
source: 'file'
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
const result = merger.merge(emptyConfig, config2)
|
|
234
|
-
|
|
235
|
-
expect(result.app?.name).toBe('TestApp')
|
|
236
|
-
})
|
|
237
|
-
|
|
238
|
-
test('precedence works with same source priority', () => {
|
|
239
|
-
const config1 = {
|
|
240
|
-
config: {
|
|
241
|
-
server: { port: 3000 }
|
|
242
|
-
} as Partial<FluxStackConfig>,
|
|
243
|
-
source: 'file'
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
const config2 = {
|
|
247
|
-
config: {
|
|
248
|
-
server: { port: 4000 }
|
|
249
|
-
} as Partial<FluxStackConfig>,
|
|
250
|
-
source: 'file'
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
const result = merger.merge(config1, config2)
|
|
254
|
-
|
|
255
|
-
// Later config should win when precedence is equal
|
|
256
|
-
expect(result.server?.port).toBe(4000)
|
|
257
|
-
})
|
|
258
|
-
})
|
|
259
|
-
})
|
|
260
|
-
|
|
261
|
-
describe('EnvironmentConfigApplier', () => {
|
|
262
|
-
let applier: EnvironmentConfigApplier
|
|
263
|
-
|
|
264
|
-
beforeEach(() => {
|
|
265
|
-
applier = new EnvironmentConfigApplier()
|
|
266
|
-
})
|
|
267
|
-
|
|
268
|
-
describe('applyEnvironmentConfig', () => {
|
|
269
|
-
test('applies environment-specific configuration', () => {
|
|
270
|
-
const baseConfig: FluxStackConfig = {
|
|
271
|
-
app: { name: 'TestApp', version: '1.0.0' },
|
|
272
|
-
server: {
|
|
273
|
-
port: 3000,
|
|
274
|
-
host: 'localhost',
|
|
275
|
-
apiPrefix: '/api',
|
|
276
|
-
cors: {
|
|
277
|
-
origins: ['*'],
|
|
278
|
-
methods: ['GET', 'POST'],
|
|
279
|
-
headers: ['Content-Type'],
|
|
280
|
-
credentials: false,
|
|
281
|
-
maxAge: 86400
|
|
282
|
-
},
|
|
283
|
-
middleware: []
|
|
284
|
-
},
|
|
285
|
-
client: {
|
|
286
|
-
port: 5173,
|
|
287
|
-
proxy: { target: 'http://localhost:3000' },
|
|
288
|
-
build: {
|
|
289
|
-
target: 'es2020',
|
|
290
|
-
outDir: 'dist/client',
|
|
291
|
-
sourceMaps: true,
|
|
292
|
-
minify: false
|
|
293
|
-
}
|
|
294
|
-
},
|
|
295
|
-
build: {
|
|
296
|
-
target: 'bun',
|
|
297
|
-
outDir: 'dist',
|
|
298
|
-
clean: true,
|
|
299
|
-
optimization: {
|
|
300
|
-
minify: false,
|
|
301
|
-
compress: false,
|
|
302
|
-
treeshake: false,
|
|
303
|
-
splitChunks: false,
|
|
304
|
-
bundleAnalyzer: false
|
|
305
|
-
},
|
|
306
|
-
sourceMaps: true
|
|
307
|
-
},
|
|
308
|
-
logging: {
|
|
309
|
-
level: 'info',
|
|
310
|
-
format: 'pretty',
|
|
311
|
-
transports: [
|
|
312
|
-
{ type: 'console', level: 'info', format: 'pretty' }
|
|
313
|
-
]
|
|
314
|
-
},
|
|
315
|
-
monitoring: {
|
|
316
|
-
enabled: false,
|
|
317
|
-
metrics: {
|
|
318
|
-
enabled: false,
|
|
319
|
-
collectInterval: 60000,
|
|
320
|
-
httpMetrics: true,
|
|
321
|
-
systemMetrics: true,
|
|
322
|
-
customMetrics: false
|
|
323
|
-
},
|
|
324
|
-
profiling: {
|
|
325
|
-
enabled: false,
|
|
326
|
-
sampleRate: 0.1,
|
|
327
|
-
memoryProfiling: false,
|
|
328
|
-
cpuProfiling: false
|
|
329
|
-
},
|
|
330
|
-
exporters: []
|
|
331
|
-
},
|
|
332
|
-
plugins: {
|
|
333
|
-
enabled: [],
|
|
334
|
-
disabled: [],
|
|
335
|
-
config: {}
|
|
336
|
-
},
|
|
337
|
-
environments: {
|
|
338
|
-
production: {
|
|
339
|
-
logging: {
|
|
340
|
-
level: 'warn',
|
|
341
|
-
format: 'json'
|
|
342
|
-
},
|
|
343
|
-
build: {
|
|
344
|
-
optimization: {
|
|
345
|
-
minify: true,
|
|
346
|
-
compress: true,
|
|
347
|
-
treeshake: true
|
|
348
|
-
},
|
|
349
|
-
sourceMaps: false
|
|
350
|
-
},
|
|
351
|
-
monitoring: {
|
|
352
|
-
enabled: true,
|
|
353
|
-
metrics: {
|
|
354
|
-
enabled: true,
|
|
355
|
-
collectInterval: 30000
|
|
356
|
-
}
|
|
357
|
-
}
|
|
358
|
-
},
|
|
359
|
-
development: {
|
|
360
|
-
logging: {
|
|
361
|
-
level: 'debug'
|
|
362
|
-
},
|
|
363
|
-
monitoring: {
|
|
364
|
-
enabled: false
|
|
365
|
-
}
|
|
366
|
-
}
|
|
367
|
-
}
|
|
368
|
-
} as FluxStackConfig
|
|
369
|
-
|
|
370
|
-
const result = applier.applyEnvironmentConfig(baseConfig, 'production')
|
|
371
|
-
|
|
372
|
-
expect(result.logging?.level).toBe('warn') // overridden
|
|
373
|
-
expect(result.logging?.format).toBe('json') // overridden
|
|
374
|
-
expect(result.build?.optimization?.minify).toBe(true) // overridden
|
|
375
|
-
expect(result.build?.optimization?.compress).toBe(true) // overridden
|
|
376
|
-
expect(result.build?.optimization?.treeshake).toBe(true) // overridden
|
|
377
|
-
expect(result.build?.sourceMaps).toBe(false) // overridden
|
|
378
|
-
expect(result.monitoring?.enabled).toBe(true) // overridden
|
|
379
|
-
expect(result.monitoring?.metrics?.enabled).toBe(true) // overridden
|
|
380
|
-
expect(result.monitoring?.metrics?.collectInterval).toBe(30000) // overridden
|
|
381
|
-
|
|
382
|
-
// Original values should be preserved where not overridden
|
|
383
|
-
expect(result.app?.name).toBe('TestApp')
|
|
384
|
-
expect(result.server?.port).toBe(3000)
|
|
385
|
-
})
|
|
386
|
-
|
|
387
|
-
test('applies development environment configuration', () => {
|
|
388
|
-
const baseConfig: FluxStackConfig = {
|
|
389
|
-
app: { name: 'TestApp', version: '1.0.0' },
|
|
390
|
-
server: {
|
|
391
|
-
port: 3000,
|
|
392
|
-
host: 'localhost',
|
|
393
|
-
apiPrefix: '/api',
|
|
394
|
-
cors: {
|
|
395
|
-
origins: ['*'],
|
|
396
|
-
methods: ['GET', 'POST'],
|
|
397
|
-
headers: ['Content-Type'],
|
|
398
|
-
credentials: false,
|
|
399
|
-
maxAge: 86400
|
|
400
|
-
},
|
|
401
|
-
middleware: []
|
|
402
|
-
},
|
|
403
|
-
client: {
|
|
404
|
-
port: 5173,
|
|
405
|
-
proxy: { target: 'http://localhost:3000' },
|
|
406
|
-
build: {
|
|
407
|
-
target: 'es2020',
|
|
408
|
-
outDir: 'dist/client',
|
|
409
|
-
sourceMaps: true,
|
|
410
|
-
minify: false
|
|
411
|
-
}
|
|
412
|
-
},
|
|
413
|
-
build: {
|
|
414
|
-
target: 'bun',
|
|
415
|
-
outDir: 'dist',
|
|
416
|
-
clean: true,
|
|
417
|
-
optimization: {
|
|
418
|
-
minify: false,
|
|
419
|
-
compress: false,
|
|
420
|
-
treeshake: false,
|
|
421
|
-
splitChunks: false,
|
|
422
|
-
bundleAnalyzer: false
|
|
423
|
-
},
|
|
424
|
-
sourceMaps: true
|
|
425
|
-
},
|
|
426
|
-
logging: {
|
|
427
|
-
level: 'info',
|
|
428
|
-
format: 'pretty',
|
|
429
|
-
transports: [
|
|
430
|
-
{ type: 'console', level: 'info', format: 'pretty' }
|
|
431
|
-
]
|
|
432
|
-
},
|
|
433
|
-
monitoring: {
|
|
434
|
-
enabled: true,
|
|
435
|
-
metrics: {
|
|
436
|
-
enabled: false,
|
|
437
|
-
collectInterval: 60000,
|
|
438
|
-
httpMetrics: true,
|
|
439
|
-
systemMetrics: true,
|
|
440
|
-
customMetrics: false
|
|
441
|
-
},
|
|
442
|
-
profiling: {
|
|
443
|
-
enabled: false,
|
|
444
|
-
sampleRate: 0.1,
|
|
445
|
-
memoryProfiling: false,
|
|
446
|
-
cpuProfiling: false
|
|
447
|
-
},
|
|
448
|
-
exporters: []
|
|
449
|
-
},
|
|
450
|
-
plugins: {
|
|
451
|
-
enabled: [],
|
|
452
|
-
disabled: [],
|
|
453
|
-
config: {}
|
|
454
|
-
},
|
|
455
|
-
environments: {
|
|
456
|
-
development: {
|
|
457
|
-
logging: {
|
|
458
|
-
level: 'debug'
|
|
459
|
-
},
|
|
460
|
-
monitoring: {
|
|
461
|
-
enabled: false
|
|
462
|
-
}
|
|
463
|
-
}
|
|
464
|
-
}
|
|
465
|
-
} as FluxStackConfig
|
|
466
|
-
|
|
467
|
-
const result = applier.applyEnvironmentConfig(baseConfig, 'development')
|
|
468
|
-
|
|
469
|
-
expect(result.logging?.level).toBe('debug') // overridden
|
|
470
|
-
expect(result.monitoring?.enabled).toBe(false) // overridden
|
|
471
|
-
expect(result.app?.name).toBe('TestApp') // preserved
|
|
472
|
-
})
|
|
473
|
-
|
|
474
|
-
test('returns original config when environment not found', () => {
|
|
475
|
-
const baseConfig: FluxStackConfig = {
|
|
476
|
-
app: { name: 'TestApp', version: '1.0.0' },
|
|
477
|
-
server: {
|
|
478
|
-
port: 3000,
|
|
479
|
-
host: 'localhost',
|
|
480
|
-
apiPrefix: '/api',
|
|
481
|
-
cors: {
|
|
482
|
-
origins: ['*'],
|
|
483
|
-
methods: ['GET', 'POST'],
|
|
484
|
-
headers: ['Content-Type'],
|
|
485
|
-
credentials: false,
|
|
486
|
-
maxAge: 86400
|
|
487
|
-
},
|
|
488
|
-
middleware: []
|
|
489
|
-
},
|
|
490
|
-
client: {
|
|
491
|
-
port: 5173,
|
|
492
|
-
proxy: { target: 'http://localhost:3000' },
|
|
493
|
-
build: {
|
|
494
|
-
target: 'es2020',
|
|
495
|
-
outDir: 'dist/client',
|
|
496
|
-
sourceMaps: true,
|
|
497
|
-
minify: false
|
|
498
|
-
}
|
|
499
|
-
},
|
|
500
|
-
build: {
|
|
501
|
-
target: 'bun',
|
|
502
|
-
outDir: 'dist',
|
|
503
|
-
clean: true,
|
|
504
|
-
optimization: {
|
|
505
|
-
minify: false,
|
|
506
|
-
compress: false,
|
|
507
|
-
treeshake: false,
|
|
508
|
-
splitChunks: false,
|
|
509
|
-
bundleAnalyzer: false
|
|
510
|
-
},
|
|
511
|
-
sourceMaps: true
|
|
512
|
-
},
|
|
513
|
-
logging: {
|
|
514
|
-
level: 'info',
|
|
515
|
-
format: 'pretty',
|
|
516
|
-
transports: [
|
|
517
|
-
{ type: 'console', level: 'info', format: 'pretty' }
|
|
518
|
-
]
|
|
519
|
-
},
|
|
520
|
-
monitoring: {
|
|
521
|
-
enabled: false,
|
|
522
|
-
metrics: {
|
|
523
|
-
enabled: false,
|
|
524
|
-
collectInterval: 60000,
|
|
525
|
-
httpMetrics: true,
|
|
526
|
-
systemMetrics: true,
|
|
527
|
-
customMetrics: false
|
|
528
|
-
},
|
|
529
|
-
profiling: {
|
|
530
|
-
enabled: false,
|
|
531
|
-
sampleRate: 0.1,
|
|
532
|
-
memoryProfiling: false,
|
|
533
|
-
cpuProfiling: false
|
|
534
|
-
},
|
|
535
|
-
exporters: []
|
|
536
|
-
},
|
|
537
|
-
plugins: {
|
|
538
|
-
enabled: [],
|
|
539
|
-
disabled: [],
|
|
540
|
-
config: {}
|
|
541
|
-
}
|
|
542
|
-
} as FluxStackConfig
|
|
543
|
-
|
|
544
|
-
const result = applier.applyEnvironmentConfig(baseConfig, 'nonexistent')
|
|
545
|
-
|
|
546
|
-
expect(result).toBe(baseConfig) // Should return the same object
|
|
547
|
-
})
|
|
548
|
-
})
|
|
549
|
-
|
|
550
|
-
describe('getAvailableEnvironments', () => {
|
|
551
|
-
test('returns available environments', () => {
|
|
552
|
-
const config = {
|
|
553
|
-
environments: {
|
|
554
|
-
development: {},
|
|
555
|
-
production: {},
|
|
556
|
-
staging: {},
|
|
557
|
-
test: {}
|
|
558
|
-
}
|
|
559
|
-
} as FluxStackConfig
|
|
560
|
-
|
|
561
|
-
const environments = applier.getAvailableEnvironments(config)
|
|
562
|
-
|
|
563
|
-
expect(environments).toEqual(['development', 'production', 'staging', 'test'])
|
|
564
|
-
})
|
|
565
|
-
|
|
566
|
-
test('returns empty array when no environments defined', () => {
|
|
567
|
-
const config = {} as FluxStackConfig
|
|
568
|
-
|
|
569
|
-
const environments = applier.getAvailableEnvironments(config)
|
|
570
|
-
|
|
571
|
-
expect(environments).toEqual([])
|
|
572
|
-
})
|
|
573
|
-
})
|
|
574
|
-
|
|
575
|
-
describe('validateEnvironmentConfig', () => {
|
|
576
|
-
test('validates production environment requirements', () => {
|
|
577
|
-
const config = {
|
|
578
|
-
server: { port: 3000 },
|
|
579
|
-
logging: { level: 'info' as const },
|
|
580
|
-
monitoring: { enabled: false },
|
|
581
|
-
environments: {
|
|
582
|
-
production: {
|
|
583
|
-
logging: { level: 'debug' as const }, // Invalid for production
|
|
584
|
-
monitoring: { enabled: false } // Invalid for production
|
|
585
|
-
}
|
|
586
|
-
}
|
|
587
|
-
} as FluxStackConfig
|
|
588
|
-
|
|
589
|
-
const result = applier.validateEnvironmentConfig(config, 'production')
|
|
590
|
-
|
|
591
|
-
expect(result.valid).toBe(false)
|
|
592
|
-
expect(result.errors).toContain('Production environment should not use debug logging')
|
|
593
|
-
expect(result.errors).toContain('Production environment should enable monitoring')
|
|
594
|
-
})
|
|
595
|
-
|
|
596
|
-
test('validates port conflicts', () => {
|
|
597
|
-
const config = {
|
|
598
|
-
server: { port: 3000 },
|
|
599
|
-
environments: {
|
|
600
|
-
staging: {
|
|
601
|
-
server: { port: 3000 } // Same as base - conflict
|
|
602
|
-
}
|
|
603
|
-
}
|
|
604
|
-
} as FluxStackConfig
|
|
605
|
-
|
|
606
|
-
const result = applier.validateEnvironmentConfig(config, 'staging')
|
|
607
|
-
|
|
608
|
-
expect(result.valid).toBe(false)
|
|
609
|
-
expect(result.errors).toContain('Environment staging uses same port as base configuration')
|
|
610
|
-
})
|
|
611
|
-
|
|
612
|
-
test('allows port conflicts in development', () => {
|
|
613
|
-
const config = {
|
|
614
|
-
server: { port: 3000 },
|
|
615
|
-
environments: {
|
|
616
|
-
development: {
|
|
617
|
-
server: { port: 3000 } // Same as base - allowed in development
|
|
618
|
-
}
|
|
619
|
-
}
|
|
620
|
-
} as FluxStackConfig
|
|
621
|
-
|
|
622
|
-
const result = applier.validateEnvironmentConfig(config, 'development')
|
|
623
|
-
|
|
624
|
-
expect(result.valid).toBe(true)
|
|
625
|
-
expect(result.errors).toHaveLength(0)
|
|
626
|
-
})
|
|
627
|
-
|
|
628
|
-
test('passes validation for valid production config', () => {
|
|
629
|
-
const config = {
|
|
630
|
-
server: { port: 3000 },
|
|
631
|
-
logging: { level: 'info' as const },
|
|
632
|
-
monitoring: { enabled: false },
|
|
633
|
-
environments: {
|
|
634
|
-
production: {
|
|
635
|
-
server: { port: 8080 }, // Different port
|
|
636
|
-
logging: { level: 'warn' as const }, // Valid for production
|
|
637
|
-
monitoring: { enabled: true } // Valid for production
|
|
638
|
-
}
|
|
639
|
-
}
|
|
640
|
-
} as FluxStackConfig
|
|
641
|
-
|
|
642
|
-
const result = applier.validateEnvironmentConfig(config, 'production')
|
|
643
|
-
|
|
644
|
-
expect(result.valid).toBe(true)
|
|
645
|
-
expect(result.errors).toHaveLength(0)
|
|
646
|
-
})
|
|
647
|
-
|
|
648
|
-
test('returns valid for non-existent environment', () => {
|
|
649
|
-
const config = {} as FluxStackConfig
|
|
650
|
-
|
|
651
|
-
const result = applier.validateEnvironmentConfig(config, 'nonexistent')
|
|
652
|
-
|
|
653
|
-
expect(result.valid).toBe(true)
|
|
654
|
-
expect(result.errors).toHaveLength(0)
|
|
655
|
-
})
|
|
656
|
-
})
|
|
657
|
-
})
|