create-fluxstack 1.0.13 → 1.0.14
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/.env.example +29 -29
- package/app/client/README.md +69 -69
- package/app/client/index.html +14 -13
- package/app/client/src/App.tsx +157 -524
- package/app/client/src/components/ErrorBoundary.tsx +107 -0
- package/app/client/src/components/ErrorDisplay.css +365 -0
- package/app/client/src/components/ErrorDisplay.tsx +258 -0
- package/app/client/src/components/FluxStackConfig.tsx +1321 -0
- package/app/client/src/components/HybridLiveCounter.tsx +140 -0
- package/app/client/src/components/LiveClock.tsx +286 -0
- package/app/client/src/components/MainLayout.tsx +390 -0
- package/app/client/src/components/SidebarNavigation.tsx +391 -0
- package/app/client/src/components/StateDemo.tsx +178 -0
- package/app/client/src/components/SystemMonitor.tsx +1038 -0
- package/app/client/src/components/Teste.tsx +104 -0
- package/app/client/src/components/UserProfile.tsx +809 -0
- package/app/client/src/hooks/useAuth.ts +39 -0
- package/app/client/src/hooks/useNotifications.ts +56 -0
- package/app/client/src/lib/eden-api.ts +189 -53
- package/app/client/src/lib/errors.ts +340 -0
- package/app/client/src/lib/hooks/useErrorHandler.ts +258 -0
- package/app/client/src/lib/index.ts +45 -0
- package/app/client/src/main.tsx +3 -2
- package/app/client/src/pages/ApiDocs.tsx +182 -0
- package/app/client/src/pages/Demo.tsx +174 -0
- package/app/client/src/pages/HybridLive.tsx +263 -0
- package/app/client/src/pages/Overview.tsx +155 -0
- package/app/client/src/store/README.md +43 -0
- package/app/client/src/store/index.ts +16 -0
- package/app/client/src/store/slices/uiSlice.ts +151 -0
- package/app/client/src/store/slices/userSlice.ts +161 -0
- package/app/client/src/test/README.md +257 -0
- package/app/client/src/test/setup.ts +70 -0
- package/app/client/src/test/types.ts +12 -0
- package/app/client/src/vite-env.d.ts +1 -1
- package/app/client/tsconfig.app.json +44 -43
- package/app/client/tsconfig.json +7 -7
- package/app/client/tsconfig.node.json +25 -25
- package/app/client/zustand-setup.md +65 -0
- package/app/server/controllers/users.controller.ts +68 -68
- package/app/server/index.ts +9 -1
- package/app/server/live/CounterComponent.ts +191 -0
- package/app/server/live/FluxStackConfig.ts +529 -0
- package/app/server/live/LiveClockComponent.ts +214 -0
- package/app/server/live/SidebarNavigation.ts +156 -0
- package/app/server/live/SystemMonitor.ts +594 -0
- package/app/server/live/SystemMonitorIntegration.ts +151 -0
- package/app/server/live/TesteComponent.ts +87 -0
- package/app/server/live/UserProfileComponent.ts +135 -0
- package/app/server/live/register-components.ts +28 -0
- package/app/server/middleware/auth.ts +136 -0
- package/app/server/middleware/errorHandling.ts +250 -0
- package/app/server/middleware/index.ts +10 -0
- package/app/server/middleware/rateLimit.ts +193 -0
- package/app/server/middleware/requestLogging.ts +215 -0
- package/app/server/middleware/validation.ts +270 -0
- package/app/server/routes/index.ts +14 -2
- package/app/server/routes/upload.ts +92 -0
- package/app/server/routes/users.routes.ts +2 -9
- package/app/server/services/NotificationService.ts +302 -0
- package/app/server/services/UserService.ts +222 -0
- package/app/server/services/index.ts +46 -0
- package/core/cli/commands/plugin-deps.ts +263 -0
- package/core/cli/generators/README.md +339 -0
- package/core/cli/generators/component.ts +770 -0
- package/core/cli/generators/controller.ts +299 -0
- package/core/cli/generators/index.ts +144 -0
- package/core/cli/generators/interactive.ts +228 -0
- package/core/cli/generators/prompts.ts +83 -0
- package/core/cli/generators/route.ts +513 -0
- package/core/cli/generators/service.ts +465 -0
- package/core/cli/generators/template-engine.ts +154 -0
- package/core/cli/generators/types.ts +71 -0
- package/core/cli/generators/utils.ts +192 -0
- package/core/cli/index.ts +69 -0
- package/core/cli/plugin-discovery.ts +16 -85
- package/core/client/fluxstack.ts +17 -0
- package/core/client/hooks/index.ts +7 -0
- package/core/client/hooks/state-validator.ts +130 -0
- package/core/client/hooks/useAuth.ts +49 -0
- package/core/client/hooks/useChunkedUpload.ts +258 -0
- package/core/client/hooks/useHybridLiveComponent.ts +967 -0
- package/core/client/hooks/useWebSocket.ts +373 -0
- package/core/client/index.ts +47 -0
- package/core/client/state/createStore.ts +193 -0
- package/core/client/state/index.ts +15 -0
- package/core/config/env-dynamic.ts +1 -1
- package/core/config/env.ts +2 -1
- package/core/config/runtime-config.ts +3 -3
- package/core/config/schema.ts +84 -49
- package/core/framework/server.ts +30 -0
- package/core/index.ts +25 -0
- package/core/live/ComponentRegistry.ts +399 -0
- package/core/live/types.ts +164 -0
- package/core/plugins/built-in/live-components/commands/create-live-component.ts +1201 -0
- package/core/plugins/built-in/live-components/index.ts +27 -0
- package/core/plugins/built-in/logger/index.ts +1 -1
- package/core/plugins/built-in/monitoring/index.ts +1 -1
- package/core/plugins/built-in/static/index.ts +1 -1
- package/core/plugins/built-in/swagger/index.ts +1 -1
- package/core/plugins/built-in/vite/index.ts +1 -1
- package/core/plugins/dependency-manager.ts +384 -0
- package/core/plugins/index.ts +5 -1
- package/core/plugins/manager.ts +7 -3
- package/core/plugins/registry.ts +88 -10
- package/core/plugins/types.ts +11 -11
- package/core/server/framework.ts +43 -0
- package/core/server/index.ts +11 -1
- package/core/server/live/ComponentRegistry.ts +1017 -0
- package/core/server/live/FileUploadManager.ts +272 -0
- package/core/server/live/LiveComponentPerformanceMonitor.ts +930 -0
- package/core/server/live/SingleConnectionManager.ts +0 -0
- package/core/server/live/StateSignature.ts +644 -0
- package/core/server/live/WebSocketConnectionManager.ts +688 -0
- package/core/server/live/websocket-plugin.ts +435 -0
- package/core/server/middleware/errorHandling.ts +141 -0
- package/core/server/middleware/index.ts +16 -0
- package/core/server/plugins/static-files-plugin.ts +232 -0
- package/core/server/services/BaseService.ts +95 -0
- package/core/server/services/ServiceContainer.ts +144 -0
- package/core/server/services/index.ts +9 -0
- package/core/templates/create-project.ts +46 -2
- package/core/testing/index.ts +10 -0
- package/core/testing/setup.ts +74 -0
- package/core/types/build.ts +38 -14
- package/core/types/types.ts +319 -0
- package/core/utils/env-runtime.ts +7 -0
- package/core/utils/errors/handlers.ts +264 -39
- package/core/utils/errors/index.ts +528 -18
- package/core/utils/errors/middleware.ts +114 -0
- package/core/utils/logger/formatters.ts +222 -0
- package/core/utils/logger/index.ts +167 -48
- package/core/utils/logger/middleware.ts +253 -0
- package/core/utils/logger/performance.ts +384 -0
- package/core/utils/logger/transports.ts +365 -0
- package/create-fluxstack.ts +296 -296
- package/fluxstack.config.ts +17 -1
- package/package-template.json +66 -66
- package/package.json +31 -6
- package/public/README.md +16 -0
- package/vite.config.ts +29 -14
- package/.claude/settings.local.json +0 -74
- package/.github/workflows/ci-build-tests.yml +0 -480
- package/.github/workflows/dependency-management.yml +0 -324
- package/.github/workflows/release-validation.yml +0 -355
- package/.kiro/specs/fluxstack-architecture-optimization/design.md +0 -700
- package/.kiro/specs/fluxstack-architecture-optimization/requirements.md +0 -127
- package/.kiro/specs/fluxstack-architecture-optimization/tasks.md +0 -330
- package/CLAUDE.md +0 -200
- package/Dockerfile +0 -58
- package/Dockerfile.backend +0 -52
- package/Dockerfile.frontend +0 -54
- package/README-Docker.md +0 -85
- package/ai-context/00-QUICK-START.md +0 -86
- package/ai-context/README.md +0 -88
- package/ai-context/development/eden-treaty-guide.md +0 -362
- package/ai-context/development/patterns.md +0 -382
- package/ai-context/development/plugins-guide.md +0 -572
- package/ai-context/examples/crud-complete.md +0 -626
- package/ai-context/project/architecture.md +0 -399
- package/ai-context/project/overview.md +0 -213
- package/ai-context/recent-changes/eden-treaty-refactor.md +0 -281
- package/ai-context/recent-changes/type-inference-fix.md +0 -223
- package/ai-context/reference/environment-vars.md +0 -384
- package/ai-context/reference/troubleshooting.md +0 -407
- package/app/client/src/components/TestPage.tsx +0 -453
- package/bun.lock +0 -1063
- package/bunfig.toml +0 -16
- package/core/__tests__/integration.test.ts +0 -227
- package/core/build/index.ts +0 -186
- package/core/config/__tests__/config-loader.test.ts +0 -554
- 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/framework/__tests__/server.test.ts +0 -233
- 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/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/create-test-app.ts +0 -156
- package/docker-compose.microservices.yml +0 -75
- package/docker-compose.simple.yml +0 -57
- package/docker-compose.yml +0 -71
- package/eslint.config.js +0 -23
- package/flux-cli.ts +0 -214
- package/nginx-lb.conf +0 -37
- package/publish.sh +0 -63
- package/run-clean.ts +0 -26
- package/run-env-tests.ts +0 -313
- package/tailwind.config.js +0 -34
- package/tests/__mocks__/api.ts +0 -56
- package/tests/fixtures/users.ts +0 -69
- package/tests/integration/api/users.routes.test.ts +0 -221
- package/tests/setup.ts +0 -29
- package/tests/unit/app/client/App-simple.test.tsx +0 -56
- package/tests/unit/app/client/App.test.tsx.skip +0 -237
- package/tests/unit/app/client/eden-api.test.ts +0 -186
- package/tests/unit/app/client/simple.test.tsx +0 -23
- package/tests/unit/app/controllers/users.controller.test.ts +0 -150
- package/tests/unit/core/create-project.test.ts.skip +0 -95
- package/tests/unit/core/framework.test.ts +0 -144
- package/tests/unit/core/plugins/logger.test.ts.skip +0 -268
- package/tests/unit/core/plugins/vite.test.ts.disabled +0 -188
- package/tests/utils/test-helpers.ts +0 -61
- package/vitest.config.ts +0 -50
- package/workspace.json +0 -6
package/run-env-tests.ts
DELETED
|
@@ -1,313 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bun
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Test Runner for Environment Variable Loading System
|
|
5
|
-
* Comprehensive test suite for FluxStack environment configuration
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import { expect } from 'bun:test'
|
|
9
|
-
import {
|
|
10
|
-
EnvironmentProcessor,
|
|
11
|
-
EnvConverter,
|
|
12
|
-
getEnvironmentInfo,
|
|
13
|
-
ConfigMerger,
|
|
14
|
-
EnvironmentConfigApplier
|
|
15
|
-
} from './core/config/env'
|
|
16
|
-
import { getConfigSync } from './core/config'
|
|
17
|
-
|
|
18
|
-
// ANSI color codes for output
|
|
19
|
-
const colors = {
|
|
20
|
-
green: '\x1b[32m',
|
|
21
|
-
red: '\x1b[31m',
|
|
22
|
-
yellow: '\x1b[33m',
|
|
23
|
-
blue: '\x1b[34m',
|
|
24
|
-
reset: '\x1b[0m',
|
|
25
|
-
bold: '\x1b[1m'
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
let testsPassed = 0
|
|
29
|
-
let testsFailed = 0
|
|
30
|
-
let testsTotal = 0
|
|
31
|
-
|
|
32
|
-
function test(name: string, fn: () => void | Promise<void>) {
|
|
33
|
-
testsTotal++
|
|
34
|
-
try {
|
|
35
|
-
const result = fn()
|
|
36
|
-
if (result instanceof Promise) {
|
|
37
|
-
result.then(() => {
|
|
38
|
-
testsPassed++
|
|
39
|
-
console.log(`${colors.green}✓${colors.reset} ${name}`)
|
|
40
|
-
}).catch((error) => {
|
|
41
|
-
testsFailed++
|
|
42
|
-
console.log(`${colors.red}✗${colors.reset} ${name}`)
|
|
43
|
-
console.log(` ${colors.red}Error: ${error.message}${colors.reset}`)
|
|
44
|
-
})
|
|
45
|
-
} else {
|
|
46
|
-
testsPassed++
|
|
47
|
-
console.log(`${colors.green}✓${colors.reset} ${name}`)
|
|
48
|
-
}
|
|
49
|
-
} catch (error) {
|
|
50
|
-
testsFailed++
|
|
51
|
-
console.log(`${colors.red}✗${colors.reset} ${name}`)
|
|
52
|
-
console.log(` ${colors.red}Error: ${(error as Error).message}${colors.reset}`)
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
function describe(name: string, fn: () => void) {
|
|
57
|
-
console.log(`\n${colors.bold}${colors.blue}${name}${colors.reset}`)
|
|
58
|
-
fn()
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
// Save original environment
|
|
62
|
-
const originalEnv = { ...process.env }
|
|
63
|
-
|
|
64
|
-
function beforeEach() {
|
|
65
|
-
// Clear test environment variables
|
|
66
|
-
for (const key in process.env) {
|
|
67
|
-
if (key.startsWith('FLUXSTACK_') || key.startsWith('PORT') || key.startsWith('HOST') ||
|
|
68
|
-
key.startsWith('CORS_') || key.startsWith('LOG_') || key.startsWith('BUILD_') ||
|
|
69
|
-
key.startsWith('DATABASE_') || key.startsWith('JWT_') || key.startsWith('SMTP_') ||
|
|
70
|
-
key.startsWith('VITE_') || key.startsWith('API_') || key.startsWith('CLIENT_') ||
|
|
71
|
-
key.startsWith('MONITORING_') || key.startsWith('METRICS_') || key.startsWith('PROFILING_')) {
|
|
72
|
-
delete process.env[key]
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
function afterEach() {
|
|
78
|
-
// Restore original environment
|
|
79
|
-
process.env = { ...originalEnv }
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
// Test Suite
|
|
83
|
-
console.log(`${colors.bold}FluxStack Environment Variable Loading Tests${colors.reset}\n`)
|
|
84
|
-
|
|
85
|
-
describe('EnvConverter Type Conversion', () => {
|
|
86
|
-
test('converts numbers correctly', () => {
|
|
87
|
-
expect(EnvConverter.toNumber('123', 0)).toBe(123)
|
|
88
|
-
expect(EnvConverter.toNumber('invalid', 42)).toBe(42)
|
|
89
|
-
expect(EnvConverter.toNumber(undefined, 42)).toBe(42)
|
|
90
|
-
})
|
|
91
|
-
|
|
92
|
-
test('converts booleans correctly', () => {
|
|
93
|
-
expect(EnvConverter.toBoolean('true', false)).toBe(true)
|
|
94
|
-
expect(EnvConverter.toBoolean('1', false)).toBe(true)
|
|
95
|
-
expect(EnvConverter.toBoolean('false', true)).toBe(false)
|
|
96
|
-
expect(EnvConverter.toBoolean('invalid', true)).toBe(false)
|
|
97
|
-
})
|
|
98
|
-
|
|
99
|
-
test('converts arrays correctly', () => {
|
|
100
|
-
expect(EnvConverter.toArray('a,b,c')).toEqual(['a', 'b', 'c'])
|
|
101
|
-
expect(EnvConverter.toArray('a, b , c')).toEqual(['a', 'b', 'c'])
|
|
102
|
-
expect(EnvConverter.toArray('')).toEqual([])
|
|
103
|
-
})
|
|
104
|
-
|
|
105
|
-
test('converts log levels correctly', () => {
|
|
106
|
-
expect(EnvConverter.toLogLevel('debug', 'info')).toBe('debug')
|
|
107
|
-
expect(EnvConverter.toLogLevel('invalid', 'info')).toBe('info')
|
|
108
|
-
})
|
|
109
|
-
})
|
|
110
|
-
|
|
111
|
-
describe('EnvironmentProcessor', () => {
|
|
112
|
-
let processor: EnvironmentProcessor
|
|
113
|
-
|
|
114
|
-
beforeEach()
|
|
115
|
-
processor = new EnvironmentProcessor()
|
|
116
|
-
|
|
117
|
-
test('processes server configuration', () => {
|
|
118
|
-
process.env.PORT = '8080'
|
|
119
|
-
process.env.HOST = 'example.com'
|
|
120
|
-
process.env.FLUXSTACK_API_PREFIX = '/v1'
|
|
121
|
-
|
|
122
|
-
const config = processor.processEnvironmentVariables()
|
|
123
|
-
|
|
124
|
-
expect(config.server?.port).toBe(8080)
|
|
125
|
-
expect(config.server?.host).toBe('example.com')
|
|
126
|
-
expect(config.server?.apiPrefix).toBe('/v1')
|
|
127
|
-
})
|
|
128
|
-
|
|
129
|
-
test('processes CORS configuration', () => {
|
|
130
|
-
process.env.CORS_ORIGINS = 'http://localhost:3000,https://example.com'
|
|
131
|
-
process.env.CORS_METHODS = 'GET,POST,PUT'
|
|
132
|
-
process.env.CORS_CREDENTIALS = 'true'
|
|
133
|
-
|
|
134
|
-
const config = processor.processEnvironmentVariables()
|
|
135
|
-
|
|
136
|
-
expect(config.server?.cors?.origins).toEqual(['http://localhost:3000', 'https://example.com'])
|
|
137
|
-
expect(config.server?.cors?.methods).toEqual(['GET', 'POST', 'PUT'])
|
|
138
|
-
expect(config.server?.cors?.credentials).toBe(true)
|
|
139
|
-
})
|
|
140
|
-
|
|
141
|
-
test('processes database configuration', () => {
|
|
142
|
-
process.env.DATABASE_URL = 'postgresql://user:pass@localhost:5432/db'
|
|
143
|
-
process.env.DATABASE_SSL = 'true'
|
|
144
|
-
process.env.DATABASE_POOL_SIZE = '20'
|
|
145
|
-
|
|
146
|
-
const config = processor.processEnvironmentVariables()
|
|
147
|
-
|
|
148
|
-
expect(config.database?.url).toBe('postgresql://user:pass@localhost:5432/db')
|
|
149
|
-
expect(config.database?.ssl).toBe(true)
|
|
150
|
-
expect(config.database?.poolSize).toBe(20)
|
|
151
|
-
})
|
|
152
|
-
|
|
153
|
-
afterEach()
|
|
154
|
-
})
|
|
155
|
-
|
|
156
|
-
describe('Configuration Loading Integration', () => {
|
|
157
|
-
test('loads complete development configuration', () => {
|
|
158
|
-
beforeEach()
|
|
159
|
-
|
|
160
|
-
process.env.NODE_ENV = 'development'
|
|
161
|
-
process.env.PORT = '3000'
|
|
162
|
-
process.env.HOST = 'localhost'
|
|
163
|
-
process.env.LOG_LEVEL = 'debug'
|
|
164
|
-
process.env.CORS_ORIGINS = 'http://localhost:3000,http://localhost:5173'
|
|
165
|
-
|
|
166
|
-
const config = getConfigSync()
|
|
167
|
-
|
|
168
|
-
expect(getEnvironmentInfo().isDevelopment).toBe(true)
|
|
169
|
-
expect(config.server?.port).toBe(3000)
|
|
170
|
-
expect(config.server?.host).toBe('localhost')
|
|
171
|
-
expect(config.logging?.level).toBe('debug')
|
|
172
|
-
expect(config.server?.cors?.origins).toEqual(['http://localhost:3000', 'http://localhost:5173'])
|
|
173
|
-
|
|
174
|
-
afterEach()
|
|
175
|
-
})
|
|
176
|
-
|
|
177
|
-
test('loads complete production configuration', () => {
|
|
178
|
-
beforeEach()
|
|
179
|
-
|
|
180
|
-
process.env.NODE_ENV = 'production'
|
|
181
|
-
process.env.PORT = '8080'
|
|
182
|
-
process.env.HOST = '0.0.0.0'
|
|
183
|
-
process.env.LOG_LEVEL = 'warn'
|
|
184
|
-
process.env.LOG_FORMAT = 'json'
|
|
185
|
-
process.env.MONITORING_ENABLED = 'true'
|
|
186
|
-
process.env.BUILD_MINIFY = 'true'
|
|
187
|
-
|
|
188
|
-
const config = getConfigSync()
|
|
189
|
-
|
|
190
|
-
expect(getEnvironmentInfo().isProduction).toBe(true)
|
|
191
|
-
expect(config.server?.port).toBe(8080)
|
|
192
|
-
expect(config.server?.host).toBe('0.0.0.0')
|
|
193
|
-
expect(config.logging?.level).toBe('warn')
|
|
194
|
-
expect(config.logging?.format).toBe('json')
|
|
195
|
-
expect(config.monitoring?.enabled).toBe(true)
|
|
196
|
-
expect(config.build?.optimization?.minify).toBe(true)
|
|
197
|
-
|
|
198
|
-
afterEach()
|
|
199
|
-
})
|
|
200
|
-
|
|
201
|
-
test('handles precedence correctly', () => {
|
|
202
|
-
beforeEach()
|
|
203
|
-
|
|
204
|
-
// Test precedence: FLUXSTACK_ prefix vs standard
|
|
205
|
-
process.env.PORT = '3000'
|
|
206
|
-
process.env.FLUXSTACK_PORT = '4000'
|
|
207
|
-
process.env.API_PREFIX = '/api'
|
|
208
|
-
process.env.FLUXSTACK_API_PREFIX = '/v2'
|
|
209
|
-
|
|
210
|
-
const config = getConfigSync()
|
|
211
|
-
|
|
212
|
-
// Current implementation uses || operator, so first non-empty wins
|
|
213
|
-
expect(config.server?.port).toBe(3000) // PORT wins because it's checked first
|
|
214
|
-
expect(config.server?.apiPrefix).toBe('/v2') // FLUXSTACK_API_PREFIX wins
|
|
215
|
-
|
|
216
|
-
afterEach()
|
|
217
|
-
})
|
|
218
|
-
})
|
|
219
|
-
|
|
220
|
-
describe('ConfigMerger', () => {
|
|
221
|
-
test('merges configurations with precedence', () => {
|
|
222
|
-
const merger = new ConfigMerger()
|
|
223
|
-
|
|
224
|
-
const config1 = {
|
|
225
|
-
config: { server: { port: 3000, host: 'localhost' } },
|
|
226
|
-
source: 'default'
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
const config2 = {
|
|
230
|
-
config: { server: { port: 4000 } },
|
|
231
|
-
source: 'environment'
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
const result = merger.merge(config1, config2)
|
|
235
|
-
|
|
236
|
-
expect(result.server?.port).toBe(4000) // Environment overrides default
|
|
237
|
-
expect(result.server?.host).toBe('localhost') // Preserved from default
|
|
238
|
-
})
|
|
239
|
-
})
|
|
240
|
-
|
|
241
|
-
describe('Real-world Scenarios', () => {
|
|
242
|
-
test('Docker deployment scenario', () => {
|
|
243
|
-
beforeEach()
|
|
244
|
-
|
|
245
|
-
process.env.NODE_ENV = 'production'
|
|
246
|
-
process.env.PORT = '8080'
|
|
247
|
-
process.env.HOST = '0.0.0.0'
|
|
248
|
-
process.env.DATABASE_URL = 'postgresql://user:pass@postgres:5432/app'
|
|
249
|
-
process.env.LOG_FORMAT = 'json'
|
|
250
|
-
process.env.MONITORING_ENABLED = 'true'
|
|
251
|
-
|
|
252
|
-
const config = getConfigSync()
|
|
253
|
-
|
|
254
|
-
expect(config.server?.port).toBe(8080)
|
|
255
|
-
expect(config.server?.host).toBe('0.0.0.0')
|
|
256
|
-
expect(config.database?.url).toBe('postgresql://user:pass@postgres:5432/app')
|
|
257
|
-
expect(config.logging?.format).toBe('json')
|
|
258
|
-
expect(config.monitoring?.enabled).toBe(true)
|
|
259
|
-
|
|
260
|
-
afterEach()
|
|
261
|
-
})
|
|
262
|
-
|
|
263
|
-
test('handles complex nested configuration', () => {
|
|
264
|
-
beforeEach()
|
|
265
|
-
|
|
266
|
-
process.env.CORS_ORIGINS = 'http://localhost:3000,https://myapp.com'
|
|
267
|
-
process.env.CORS_METHODS = 'GET,POST,PUT,DELETE'
|
|
268
|
-
process.env.CORS_CREDENTIALS = 'true'
|
|
269
|
-
process.env.CORS_MAX_AGE = '86400'
|
|
270
|
-
|
|
271
|
-
const config = getConfigSync()
|
|
272
|
-
|
|
273
|
-
expect(config.server?.cors?.origins).toEqual(['http://localhost:3000', 'https://myapp.com'])
|
|
274
|
-
expect(config.server?.cors?.methods).toEqual(['GET', 'POST', 'PUT', 'DELETE'])
|
|
275
|
-
expect(config.server?.cors?.credentials).toBe(true)
|
|
276
|
-
expect(config.server?.cors?.maxAge).toBe(86400)
|
|
277
|
-
|
|
278
|
-
afterEach()
|
|
279
|
-
})
|
|
280
|
-
|
|
281
|
-
test('handles invalid environment variables gracefully', () => {
|
|
282
|
-
beforeEach()
|
|
283
|
-
|
|
284
|
-
process.env.PORT = 'invalid'
|
|
285
|
-
process.env.LOG_LEVEL = 'invalid'
|
|
286
|
-
process.env.MONITORING_ENABLED = 'maybe'
|
|
287
|
-
|
|
288
|
-
const config = getConfigSync()
|
|
289
|
-
|
|
290
|
-
expect(typeof config.server?.port).toBe('number')
|
|
291
|
-
// Log level should be valid (invalid falls back to default)
|
|
292
|
-
expect(typeof config.logging?.level).toBe('string')
|
|
293
|
-
expect(typeof config.monitoring?.enabled).toBe('boolean')
|
|
294
|
-
|
|
295
|
-
afterEach()
|
|
296
|
-
})
|
|
297
|
-
})
|
|
298
|
-
|
|
299
|
-
// Run summary
|
|
300
|
-
setTimeout(() => {
|
|
301
|
-
console.log(`\n${colors.bold}Test Results:${colors.reset}`)
|
|
302
|
-
console.log(`${colors.green}✓ Passed: ${testsPassed}${colors.reset}`)
|
|
303
|
-
console.log(`${colors.red}✗ Failed: ${testsFailed}${colors.reset}`)
|
|
304
|
-
console.log(`${colors.blue}Total: ${testsTotal}${colors.reset}`)
|
|
305
|
-
|
|
306
|
-
if (testsFailed === 0) {
|
|
307
|
-
console.log(`\n${colors.green}${colors.bold}🎉 All tests passed!${colors.reset}`)
|
|
308
|
-
process.exit(0)
|
|
309
|
-
} else {
|
|
310
|
-
console.log(`\n${colors.red}${colors.bold}❌ Some tests failed${colors.reset}`)
|
|
311
|
-
process.exit(1)
|
|
312
|
-
}
|
|
313
|
-
}, 100) // Give async tests time to complete
|
package/tailwind.config.js
DELETED
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
/** @type {import('tailwindcss').Config} */
|
|
2
|
-
export default {
|
|
3
|
-
content: [
|
|
4
|
-
"./app/client/index.html",
|
|
5
|
-
"./app/client/src/**/*.{js,ts,jsx,tsx}",
|
|
6
|
-
],
|
|
7
|
-
theme: {
|
|
8
|
-
extend: {
|
|
9
|
-
colors: {
|
|
10
|
-
// Custom colors for FluxStack branding
|
|
11
|
-
flux: {
|
|
12
|
-
50: '#f0f9ff',
|
|
13
|
-
100: '#e0f2fe',
|
|
14
|
-
200: '#bae6fd',
|
|
15
|
-
300: '#7dd3fc',
|
|
16
|
-
400: '#38bdf8',
|
|
17
|
-
500: '#0ea5e9',
|
|
18
|
-
600: '#0284c7',
|
|
19
|
-
700: '#0369a1',
|
|
20
|
-
800: '#075985',
|
|
21
|
-
900: '#0c4a6e',
|
|
22
|
-
}
|
|
23
|
-
},
|
|
24
|
-
fontFamily: {
|
|
25
|
-
sans: ['-apple-system', 'BlinkMacSystemFont', 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', 'sans-serif'],
|
|
26
|
-
},
|
|
27
|
-
animation: {
|
|
28
|
-
'spin-slow': 'spin 3s linear infinite',
|
|
29
|
-
'pulse-slow': 'pulse 3s cubic-bezier(0.4, 0, 0.6, 1) infinite',
|
|
30
|
-
}
|
|
31
|
-
},
|
|
32
|
-
},
|
|
33
|
-
plugins: [],
|
|
34
|
-
}
|
package/tests/__mocks__/api.ts
DELETED
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
// Mock API responses for testing
|
|
2
|
-
export const mockApiResponses = {
|
|
3
|
-
users: {
|
|
4
|
-
list: {
|
|
5
|
-
users: [
|
|
6
|
-
{
|
|
7
|
-
id: 1,
|
|
8
|
-
name: 'Mock User 1',
|
|
9
|
-
email: 'mock1@example.com',
|
|
10
|
-
createdAt: new Date('2024-01-01')
|
|
11
|
-
},
|
|
12
|
-
{
|
|
13
|
-
id: 2,
|
|
14
|
-
name: 'Mock User 2',
|
|
15
|
-
email: 'mock2@example.com',
|
|
16
|
-
createdAt: new Date('2024-01-02')
|
|
17
|
-
}
|
|
18
|
-
]
|
|
19
|
-
},
|
|
20
|
-
create: {
|
|
21
|
-
success: true,
|
|
22
|
-
user: {
|
|
23
|
-
id: 3,
|
|
24
|
-
name: 'New Mock User',
|
|
25
|
-
email: 'newmock@example.com',
|
|
26
|
-
createdAt: new Date()
|
|
27
|
-
}
|
|
28
|
-
},
|
|
29
|
-
error: {
|
|
30
|
-
success: false,
|
|
31
|
-
message: 'Mock error message'
|
|
32
|
-
}
|
|
33
|
-
},
|
|
34
|
-
api: {
|
|
35
|
-
index: {
|
|
36
|
-
message: 'Hello from Mock FluxStack API!'
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
export const mockApi = {
|
|
42
|
-
api: {
|
|
43
|
-
index: {
|
|
44
|
-
get: () => Promise.resolve({ data: mockApiResponses.api.index })
|
|
45
|
-
},
|
|
46
|
-
users: {
|
|
47
|
-
get: () => Promise.resolve({ data: mockApiResponses.users.list }),
|
|
48
|
-
post: (body: any) => {
|
|
49
|
-
if (body.email === 'error@test.com') {
|
|
50
|
-
return Promise.resolve({ data: mockApiResponses.users.error })
|
|
51
|
-
}
|
|
52
|
-
return Promise.resolve({ data: mockApiResponses.users.create })
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
}
|
package/tests/fixtures/users.ts
DELETED
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
import type { User, CreateUserRequest } from '@/app/shared/types'
|
|
2
|
-
|
|
3
|
-
export const mockUsers: User[] = [
|
|
4
|
-
{
|
|
5
|
-
id: 1,
|
|
6
|
-
name: 'João Silva',
|
|
7
|
-
email: 'joao@example.com',
|
|
8
|
-
createdAt: new Date('2024-01-01T10:00:00Z')
|
|
9
|
-
},
|
|
10
|
-
{
|
|
11
|
-
id: 2,
|
|
12
|
-
name: 'Maria Santos',
|
|
13
|
-
email: 'maria@example.com',
|
|
14
|
-
createdAt: new Date('2024-01-02T11:00:00Z')
|
|
15
|
-
},
|
|
16
|
-
{
|
|
17
|
-
id: 3,
|
|
18
|
-
name: 'Pedro Costa',
|
|
19
|
-
email: 'pedro@example.com',
|
|
20
|
-
createdAt: new Date('2024-01-03T12:00:00Z')
|
|
21
|
-
}
|
|
22
|
-
]
|
|
23
|
-
|
|
24
|
-
export const validUserRequests: CreateUserRequest[] = [
|
|
25
|
-
{
|
|
26
|
-
name: 'Ana Lima',
|
|
27
|
-
email: 'ana@example.com'
|
|
28
|
-
},
|
|
29
|
-
{
|
|
30
|
-
name: 'Carlos Oliveira',
|
|
31
|
-
email: 'carlos@example.com'
|
|
32
|
-
},
|
|
33
|
-
{
|
|
34
|
-
name: 'Teste User',
|
|
35
|
-
email: 'teste@example.com'
|
|
36
|
-
}
|
|
37
|
-
]
|
|
38
|
-
|
|
39
|
-
export const invalidUserRequests = [
|
|
40
|
-
{
|
|
41
|
-
name: 'A', // Too short
|
|
42
|
-
email: 'valid@example.com'
|
|
43
|
-
},
|
|
44
|
-
{
|
|
45
|
-
name: 'Valid Name',
|
|
46
|
-
email: 'invalid-email' // Invalid format
|
|
47
|
-
},
|
|
48
|
-
{
|
|
49
|
-
name: '', // Empty name
|
|
50
|
-
email: 'empty@example.com'
|
|
51
|
-
},
|
|
52
|
-
{
|
|
53
|
-
name: 'Valid Name',
|
|
54
|
-
email: '' // Empty email
|
|
55
|
-
},
|
|
56
|
-
{
|
|
57
|
-
name: 'Valid Name'
|
|
58
|
-
// Missing email
|
|
59
|
-
},
|
|
60
|
-
{
|
|
61
|
-
email: 'missing@example.com'
|
|
62
|
-
// Missing name
|
|
63
|
-
}
|
|
64
|
-
]
|
|
65
|
-
|
|
66
|
-
export const duplicateEmailRequest: CreateUserRequest = {
|
|
67
|
-
name: 'Duplicate User',
|
|
68
|
-
email: 'joao@example.com' // Same as first mock user
|
|
69
|
-
}
|
|
@@ -1,221 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, beforeEach } from 'vitest'
|
|
2
|
-
import { Elysia } from 'elysia'
|
|
3
|
-
import { usersRoutes } from '@/app/server/routes/users.routes'
|
|
4
|
-
|
|
5
|
-
describe('Users API Routes', () => {
|
|
6
|
-
let app: Elysia
|
|
7
|
-
|
|
8
|
-
beforeEach(() => {
|
|
9
|
-
// Create a fresh Elysia app for each test
|
|
10
|
-
app = new Elysia().use(usersRoutes)
|
|
11
|
-
})
|
|
12
|
-
|
|
13
|
-
describe('GET /users', () => {
|
|
14
|
-
it('should return users list', async () => {
|
|
15
|
-
const response = await app
|
|
16
|
-
.handle(new Request('http://localhost/users'))
|
|
17
|
-
|
|
18
|
-
expect(response.status).toBe(200)
|
|
19
|
-
|
|
20
|
-
const data = await response.json()
|
|
21
|
-
expect(data).toBeDefined()
|
|
22
|
-
expect(data.users).toBeDefined()
|
|
23
|
-
expect(Array.isArray(data.users)).toBe(true)
|
|
24
|
-
})
|
|
25
|
-
|
|
26
|
-
it('should return users with correct structure', async () => {
|
|
27
|
-
const response = await app
|
|
28
|
-
.handle(new Request('http://localhost/users'))
|
|
29
|
-
|
|
30
|
-
const data = await response.json()
|
|
31
|
-
|
|
32
|
-
if (data.users.length > 0) {
|
|
33
|
-
const user = data.users[0]
|
|
34
|
-
expect(user).toHaveProperty('id')
|
|
35
|
-
expect(user).toHaveProperty('name')
|
|
36
|
-
expect(user).toHaveProperty('email')
|
|
37
|
-
expect(user).toHaveProperty('createdAt')
|
|
38
|
-
}
|
|
39
|
-
})
|
|
40
|
-
})
|
|
41
|
-
|
|
42
|
-
describe('GET /users/:id', () => {
|
|
43
|
-
it('should return user by ID', async () => {
|
|
44
|
-
// First get all users to find a valid ID
|
|
45
|
-
const usersResponse = await app
|
|
46
|
-
.handle(new Request('http://localhost/users'))
|
|
47
|
-
const usersData = await usersResponse.json()
|
|
48
|
-
|
|
49
|
-
if (usersData.users.length > 0) {
|
|
50
|
-
const userId = usersData.users[0].id
|
|
51
|
-
|
|
52
|
-
const response = await app
|
|
53
|
-
.handle(new Request(`http://localhost/users/${userId}`))
|
|
54
|
-
|
|
55
|
-
expect(response.status).toBe(200)
|
|
56
|
-
|
|
57
|
-
const data = await response.json()
|
|
58
|
-
expect(data.user).toBeDefined()
|
|
59
|
-
expect(data.user.id).toBe(userId)
|
|
60
|
-
}
|
|
61
|
-
})
|
|
62
|
-
|
|
63
|
-
it('should return error for non-existent user', async () => {
|
|
64
|
-
const response = await app
|
|
65
|
-
.handle(new Request('http://localhost/users/99999'))
|
|
66
|
-
|
|
67
|
-
expect(response.status).toBe(200) // Elysia returns 200 by default
|
|
68
|
-
|
|
69
|
-
// Check if response has content before parsing JSON
|
|
70
|
-
const text = await response.text()
|
|
71
|
-
if (text) {
|
|
72
|
-
const data = JSON.parse(text)
|
|
73
|
-
expect(data.error).toBe('Usuário não encontrado')
|
|
74
|
-
} else {
|
|
75
|
-
// If no response body, the test still passes as the behavior is expected
|
|
76
|
-
expect(response.status).toBe(200)
|
|
77
|
-
}
|
|
78
|
-
})
|
|
79
|
-
|
|
80
|
-
it('should validate ID parameter', async () => {
|
|
81
|
-
const response = await app
|
|
82
|
-
.handle(new Request('http://localhost/users/invalid-id'))
|
|
83
|
-
|
|
84
|
-
// Should handle invalid ID gracefully
|
|
85
|
-
expect(response.status).toBeGreaterThanOrEqual(200)
|
|
86
|
-
})
|
|
87
|
-
})
|
|
88
|
-
|
|
89
|
-
describe('POST /users', () => {
|
|
90
|
-
it('should create new user with valid data', async () => {
|
|
91
|
-
const userData = {
|
|
92
|
-
name: 'Integration Test User',
|
|
93
|
-
email: 'integration@test.com'
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
const response = await app
|
|
97
|
-
.handle(new Request('http://localhost/users', {
|
|
98
|
-
method: 'POST',
|
|
99
|
-
headers: { 'Content-Type': 'application/json' },
|
|
100
|
-
body: JSON.stringify(userData)
|
|
101
|
-
}))
|
|
102
|
-
|
|
103
|
-
expect(response.status).toBe(200)
|
|
104
|
-
|
|
105
|
-
const data = await response.json()
|
|
106
|
-
expect(data.success).toBe(true)
|
|
107
|
-
expect(data.user).toBeDefined()
|
|
108
|
-
expect(data.user.name).toBe(userData.name)
|
|
109
|
-
expect(data.user.email).toBe(userData.email)
|
|
110
|
-
expect(data.user.id).toBeDefined()
|
|
111
|
-
})
|
|
112
|
-
|
|
113
|
-
it('should reject user with invalid data', async () => {
|
|
114
|
-
const invalidData = {
|
|
115
|
-
name: 'A', // Too short
|
|
116
|
-
email: 'invalid-email' // Invalid format
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
const response = await app
|
|
120
|
-
.handle(new Request('http://localhost/users', {
|
|
121
|
-
method: 'POST',
|
|
122
|
-
headers: { 'Content-Type': 'application/json' },
|
|
123
|
-
body: JSON.stringify(invalidData)
|
|
124
|
-
}))
|
|
125
|
-
|
|
126
|
-
expect(response.status).toBe(400)
|
|
127
|
-
|
|
128
|
-
const data = await response.json()
|
|
129
|
-
expect(data.success).toBe(false)
|
|
130
|
-
expect(data.error).toBeDefined()
|
|
131
|
-
})
|
|
132
|
-
|
|
133
|
-
it('should reject user with missing fields', async () => {
|
|
134
|
-
const incompleteData = {
|
|
135
|
-
name: 'Test User'
|
|
136
|
-
// Missing email
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
const response = await app
|
|
140
|
-
.handle(new Request('http://localhost/users', {
|
|
141
|
-
method: 'POST',
|
|
142
|
-
headers: { 'Content-Type': 'application/json' },
|
|
143
|
-
body: JSON.stringify(incompleteData)
|
|
144
|
-
}))
|
|
145
|
-
|
|
146
|
-
expect(response.status).toBe(400)
|
|
147
|
-
})
|
|
148
|
-
|
|
149
|
-
it('should prevent duplicate emails', async () => {
|
|
150
|
-
const userData = {
|
|
151
|
-
name: 'Duplicate Test User',
|
|
152
|
-
email: 'duplicate@integration.test'
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
// Create first user
|
|
156
|
-
const firstResponse = await app
|
|
157
|
-
.handle(new Request('http://localhost/users', {
|
|
158
|
-
method: 'POST',
|
|
159
|
-
headers: { 'Content-Type': 'application/json' },
|
|
160
|
-
body: JSON.stringify(userData)
|
|
161
|
-
}))
|
|
162
|
-
|
|
163
|
-
expect(firstResponse.status).toBe(200)
|
|
164
|
-
|
|
165
|
-
// Try to create user with same email
|
|
166
|
-
const secondResponse = await app
|
|
167
|
-
.handle(new Request('http://localhost/users', {
|
|
168
|
-
method: 'POST',
|
|
169
|
-
headers: { 'Content-Type': 'application/json' },
|
|
170
|
-
body: JSON.stringify(userData)
|
|
171
|
-
}))
|
|
172
|
-
|
|
173
|
-
const data = await secondResponse.json()
|
|
174
|
-
expect(data.success).toBe(false)
|
|
175
|
-
expect(data.message).toBe('Email já está em uso')
|
|
176
|
-
})
|
|
177
|
-
})
|
|
178
|
-
|
|
179
|
-
describe('DELETE /users/:id', () => {
|
|
180
|
-
it('should delete existing user', async () => {
|
|
181
|
-
// First create a user to delete
|
|
182
|
-
const userData = {
|
|
183
|
-
name: 'User to Delete',
|
|
184
|
-
email: 'delete@test.com'
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
const createResponse = await app
|
|
188
|
-
.handle(new Request('http://localhost/users', {
|
|
189
|
-
method: 'POST',
|
|
190
|
-
headers: { 'Content-Type': 'application/json' },
|
|
191
|
-
body: JSON.stringify(userData)
|
|
192
|
-
}))
|
|
193
|
-
|
|
194
|
-
const createData = await createResponse.json()
|
|
195
|
-
const userId = createData.user.id
|
|
196
|
-
|
|
197
|
-
// Now delete the user
|
|
198
|
-
const deleteResponse = await app
|
|
199
|
-
.handle(new Request(`http://localhost/users/${userId}`, {
|
|
200
|
-
method: 'DELETE'
|
|
201
|
-
}))
|
|
202
|
-
|
|
203
|
-
expect(deleteResponse.status).toBe(200)
|
|
204
|
-
|
|
205
|
-
const deleteData = await deleteResponse.json()
|
|
206
|
-
expect(deleteData.success).toBe(true)
|
|
207
|
-
expect(deleteData.message).toBe('Usuário deletado com sucesso')
|
|
208
|
-
})
|
|
209
|
-
|
|
210
|
-
it('should return error when deleting non-existent user', async () => {
|
|
211
|
-
const response = await app
|
|
212
|
-
.handle(new Request('http://localhost/users/99999', {
|
|
213
|
-
method: 'DELETE'
|
|
214
|
-
}))
|
|
215
|
-
|
|
216
|
-
const data = await response.json()
|
|
217
|
-
expect(data.success).toBe(false)
|
|
218
|
-
expect(data.message).toBe('Usuário não encontrado')
|
|
219
|
-
})
|
|
220
|
-
})
|
|
221
|
-
})
|