create-fluxstack 1.0.13 → 1.0.15
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 +196 -33
- 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
|
@@ -1,297 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Tests for Helper Utilities
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'
|
|
6
|
-
import {
|
|
7
|
-
formatBytes,
|
|
8
|
-
createTimer,
|
|
9
|
-
delay,
|
|
10
|
-
retry,
|
|
11
|
-
debounce,
|
|
12
|
-
throttle,
|
|
13
|
-
isProduction,
|
|
14
|
-
isDevelopment,
|
|
15
|
-
isTest,
|
|
16
|
-
deepMerge,
|
|
17
|
-
pick,
|
|
18
|
-
omit,
|
|
19
|
-
generateId,
|
|
20
|
-
safeJsonParse,
|
|
21
|
-
safeJsonStringify
|
|
22
|
-
} from '../helpers'
|
|
23
|
-
|
|
24
|
-
describe('Helper Utilities', () => {
|
|
25
|
-
describe('formatBytes', () => {
|
|
26
|
-
it('should format bytes correctly', () => {
|
|
27
|
-
expect(formatBytes(0)).toBe('0 Bytes')
|
|
28
|
-
expect(formatBytes(1024)).toBe('1 KB')
|
|
29
|
-
expect(formatBytes(1048576)).toBe('1 MB')
|
|
30
|
-
expect(formatBytes(1073741824)).toBe('1 GB')
|
|
31
|
-
})
|
|
32
|
-
|
|
33
|
-
it('should handle decimal places', () => {
|
|
34
|
-
expect(formatBytes(1536, 1)).toBe('1.5 KB')
|
|
35
|
-
expect(formatBytes(1536, 0)).toBe('2 KB')
|
|
36
|
-
})
|
|
37
|
-
})
|
|
38
|
-
|
|
39
|
-
describe('createTimer', () => {
|
|
40
|
-
it('should measure time correctly', async () => {
|
|
41
|
-
const timer = createTimer('test')
|
|
42
|
-
await delay(10)
|
|
43
|
-
const duration = timer.end()
|
|
44
|
-
|
|
45
|
-
// Be more lenient in CI environments where timing can be variable
|
|
46
|
-
expect(duration).toBeGreaterThanOrEqual(5)
|
|
47
|
-
expect(timer.label).toBe('test')
|
|
48
|
-
})
|
|
49
|
-
})
|
|
50
|
-
|
|
51
|
-
describe('delay', () => {
|
|
52
|
-
it('should delay execution', async () => {
|
|
53
|
-
const start = Date.now()
|
|
54
|
-
await delay(50)
|
|
55
|
-
const end = Date.now()
|
|
56
|
-
|
|
57
|
-
// Be more lenient with timing in CI environments - allow for 10ms variance
|
|
58
|
-
expect(end - start).toBeGreaterThanOrEqual(40)
|
|
59
|
-
expect(end - start).toBeLessThan(200) // Ensure it's not too long
|
|
60
|
-
})
|
|
61
|
-
})
|
|
62
|
-
|
|
63
|
-
describe('retry', () => {
|
|
64
|
-
it('should succeed on first attempt', async () => {
|
|
65
|
-
const fn = vi.fn().mockResolvedValue('success')
|
|
66
|
-
const result = await retry(fn, 3, 10)
|
|
67
|
-
|
|
68
|
-
expect(result).toBe('success')
|
|
69
|
-
expect(fn).toHaveBeenCalledTimes(1)
|
|
70
|
-
})
|
|
71
|
-
|
|
72
|
-
it('should retry on failure and eventually succeed', async () => {
|
|
73
|
-
const fn = vi.fn()
|
|
74
|
-
.mockRejectedValueOnce(new Error('fail 1'))
|
|
75
|
-
.mockRejectedValueOnce(new Error('fail 2'))
|
|
76
|
-
.mockResolvedValue('success')
|
|
77
|
-
|
|
78
|
-
const result = await retry(fn, 3, 10)
|
|
79
|
-
|
|
80
|
-
expect(result).toBe('success')
|
|
81
|
-
expect(fn).toHaveBeenCalledTimes(3)
|
|
82
|
-
})
|
|
83
|
-
|
|
84
|
-
it('should throw after max attempts', async () => {
|
|
85
|
-
const fn = vi.fn().mockRejectedValue(new Error('always fails'))
|
|
86
|
-
|
|
87
|
-
await expect(retry(fn, 2, 10)).rejects.toThrow('always fails')
|
|
88
|
-
expect(fn).toHaveBeenCalledTimes(2)
|
|
89
|
-
})
|
|
90
|
-
})
|
|
91
|
-
|
|
92
|
-
describe('debounce', () => {
|
|
93
|
-
beforeEach(() => {
|
|
94
|
-
vi.useFakeTimers()
|
|
95
|
-
})
|
|
96
|
-
|
|
97
|
-
afterEach(() => {
|
|
98
|
-
vi.useRealTimers()
|
|
99
|
-
})
|
|
100
|
-
|
|
101
|
-
it('should debounce function calls', () => {
|
|
102
|
-
const fn = vi.fn()
|
|
103
|
-
const debouncedFn = debounce(fn, 100)
|
|
104
|
-
|
|
105
|
-
debouncedFn('arg1')
|
|
106
|
-
debouncedFn('arg2')
|
|
107
|
-
debouncedFn('arg3')
|
|
108
|
-
|
|
109
|
-
expect(fn).not.toHaveBeenCalled()
|
|
110
|
-
|
|
111
|
-
vi.advanceTimersByTime(100)
|
|
112
|
-
|
|
113
|
-
expect(fn).toHaveBeenCalledTimes(1)
|
|
114
|
-
expect(fn).toHaveBeenCalledWith('arg3')
|
|
115
|
-
})
|
|
116
|
-
})
|
|
117
|
-
|
|
118
|
-
describe('throttle', () => {
|
|
119
|
-
beforeEach(() => {
|
|
120
|
-
vi.useFakeTimers()
|
|
121
|
-
})
|
|
122
|
-
|
|
123
|
-
afterEach(() => {
|
|
124
|
-
vi.useRealTimers()
|
|
125
|
-
})
|
|
126
|
-
|
|
127
|
-
it('should throttle function calls', () => {
|
|
128
|
-
const fn = vi.fn()
|
|
129
|
-
const throttledFn = throttle(fn, 100)
|
|
130
|
-
|
|
131
|
-
throttledFn('arg1')
|
|
132
|
-
throttledFn('arg2')
|
|
133
|
-
throttledFn('arg3')
|
|
134
|
-
|
|
135
|
-
expect(fn).toHaveBeenCalledTimes(1)
|
|
136
|
-
expect(fn).toHaveBeenCalledWith('arg1')
|
|
137
|
-
|
|
138
|
-
vi.advanceTimersByTime(100)
|
|
139
|
-
|
|
140
|
-
throttledFn('arg4')
|
|
141
|
-
expect(fn).toHaveBeenCalledTimes(2)
|
|
142
|
-
expect(fn).toHaveBeenCalledWith('arg4')
|
|
143
|
-
})
|
|
144
|
-
})
|
|
145
|
-
|
|
146
|
-
describe('Environment Checks', () => {
|
|
147
|
-
const originalEnv = process.env.NODE_ENV
|
|
148
|
-
|
|
149
|
-
afterEach(() => {
|
|
150
|
-
process.env.NODE_ENV = originalEnv
|
|
151
|
-
})
|
|
152
|
-
|
|
153
|
-
it('should detect production environment', () => {
|
|
154
|
-
process.env.NODE_ENV = 'production'
|
|
155
|
-
expect(isProduction()).toBe(true)
|
|
156
|
-
expect(isDevelopment()).toBe(false)
|
|
157
|
-
expect(isTest()).toBe(false)
|
|
158
|
-
})
|
|
159
|
-
|
|
160
|
-
it('should detect development environment', () => {
|
|
161
|
-
process.env.NODE_ENV = 'development'
|
|
162
|
-
expect(isProduction()).toBe(false)
|
|
163
|
-
expect(isDevelopment()).toBe(true)
|
|
164
|
-
expect(isTest()).toBe(false)
|
|
165
|
-
})
|
|
166
|
-
|
|
167
|
-
it('should detect test environment', () => {
|
|
168
|
-
process.env.NODE_ENV = 'test'
|
|
169
|
-
expect(isProduction()).toBe(false)
|
|
170
|
-
expect(isDevelopment()).toBe(false)
|
|
171
|
-
expect(isTest()).toBe(true)
|
|
172
|
-
})
|
|
173
|
-
|
|
174
|
-
it('should default to development when NODE_ENV is not set', () => {
|
|
175
|
-
delete process.env.NODE_ENV
|
|
176
|
-
expect(isDevelopment()).toBe(true)
|
|
177
|
-
})
|
|
178
|
-
})
|
|
179
|
-
|
|
180
|
-
describe('Object Utilities', () => {
|
|
181
|
-
describe('deepMerge', () => {
|
|
182
|
-
it('should merge objects deeply', () => {
|
|
183
|
-
const target = {
|
|
184
|
-
a: 1,
|
|
185
|
-
b: {
|
|
186
|
-
c: 2,
|
|
187
|
-
d: 3
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
const source = {
|
|
192
|
-
b: {
|
|
193
|
-
c: 2, // Keep existing property
|
|
194
|
-
d: 4,
|
|
195
|
-
e: 5
|
|
196
|
-
},
|
|
197
|
-
f: 6
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
const result = deepMerge(target, source)
|
|
201
|
-
|
|
202
|
-
expect(result).toEqual({
|
|
203
|
-
a: 1,
|
|
204
|
-
b: {
|
|
205
|
-
c: 2,
|
|
206
|
-
d: 4,
|
|
207
|
-
e: 5
|
|
208
|
-
},
|
|
209
|
-
f: 6
|
|
210
|
-
})
|
|
211
|
-
})
|
|
212
|
-
|
|
213
|
-
it('should handle arrays correctly', () => {
|
|
214
|
-
const target = { arr: [1, 2, 3] }
|
|
215
|
-
const source = { arr: [4, 5, 6] }
|
|
216
|
-
|
|
217
|
-
const result = deepMerge(target, source)
|
|
218
|
-
|
|
219
|
-
expect(result.arr).toEqual([4, 5, 6])
|
|
220
|
-
})
|
|
221
|
-
})
|
|
222
|
-
|
|
223
|
-
describe('pick', () => {
|
|
224
|
-
it('should pick specified keys', () => {
|
|
225
|
-
const obj = { a: 1, b: 2, c: 3, d: 4 }
|
|
226
|
-
const result = pick(obj, ['a', 'c'])
|
|
227
|
-
|
|
228
|
-
expect(result).toEqual({ a: 1, c: 3 })
|
|
229
|
-
})
|
|
230
|
-
|
|
231
|
-
it('should handle non-existent keys', () => {
|
|
232
|
-
const obj = { a: 1, b: 2 }
|
|
233
|
-
const result = pick(obj, ['a', 'c'] as any)
|
|
234
|
-
|
|
235
|
-
expect(result).toEqual({ a: 1 })
|
|
236
|
-
})
|
|
237
|
-
})
|
|
238
|
-
|
|
239
|
-
describe('omit', () => {
|
|
240
|
-
it('should omit specified keys', () => {
|
|
241
|
-
const obj = { a: 1, b: 2, c: 3, d: 4 }
|
|
242
|
-
const result = omit(obj, ['b', 'd'])
|
|
243
|
-
|
|
244
|
-
expect(result).toEqual({ a: 1, c: 3 })
|
|
245
|
-
})
|
|
246
|
-
})
|
|
247
|
-
})
|
|
248
|
-
|
|
249
|
-
describe('String Utilities', () => {
|
|
250
|
-
describe('generateId', () => {
|
|
251
|
-
it('should generate id with default length', () => {
|
|
252
|
-
const id = generateId()
|
|
253
|
-
expect(id).toHaveLength(8)
|
|
254
|
-
expect(id).toMatch(/^[A-Za-z0-9]+$/)
|
|
255
|
-
})
|
|
256
|
-
|
|
257
|
-
it('should generate id with custom length', () => {
|
|
258
|
-
const id = generateId(16)
|
|
259
|
-
expect(id).toHaveLength(16)
|
|
260
|
-
})
|
|
261
|
-
|
|
262
|
-
it('should generate unique ids', () => {
|
|
263
|
-
const id1 = generateId()
|
|
264
|
-
const id2 = generateId()
|
|
265
|
-
expect(id1).not.toBe(id2)
|
|
266
|
-
})
|
|
267
|
-
})
|
|
268
|
-
|
|
269
|
-
describe('safeJsonParse', () => {
|
|
270
|
-
it('should parse valid JSON', () => {
|
|
271
|
-
const result = safeJsonParse('{"a": 1}', {})
|
|
272
|
-
expect(result).toEqual({ a: 1 })
|
|
273
|
-
})
|
|
274
|
-
|
|
275
|
-
it('should return fallback for invalid JSON', () => {
|
|
276
|
-
const fallback = { error: true }
|
|
277
|
-
const result = safeJsonParse('invalid json', fallback)
|
|
278
|
-
expect(result).toBe(fallback)
|
|
279
|
-
})
|
|
280
|
-
})
|
|
281
|
-
|
|
282
|
-
describe('safeJsonStringify', () => {
|
|
283
|
-
it('should stringify valid objects', () => {
|
|
284
|
-
const result = safeJsonStringify({ a: 1 })
|
|
285
|
-
expect(result).toBe('{"a":1}')
|
|
286
|
-
})
|
|
287
|
-
|
|
288
|
-
it('should return fallback for circular references', () => {
|
|
289
|
-
const circular: any = { a: 1 }
|
|
290
|
-
circular.self = circular
|
|
291
|
-
|
|
292
|
-
const result = safeJsonStringify(circular, '{"error": true}')
|
|
293
|
-
expect(result).toBe('{"error": true}')
|
|
294
|
-
})
|
|
295
|
-
})
|
|
296
|
-
})
|
|
297
|
-
})
|
|
@@ -1,141 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Tests for Logger Utility
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest'
|
|
6
|
-
|
|
7
|
-
// Set test environment
|
|
8
|
-
process.env.NODE_ENV = 'test'
|
|
9
|
-
|
|
10
|
-
// Import the logger
|
|
11
|
-
import { logger as realLogger, log as realLog } from '../logger'
|
|
12
|
-
|
|
13
|
-
describe('Logger', () => {
|
|
14
|
-
let consoleSpy: {
|
|
15
|
-
debug: any
|
|
16
|
-
info: any
|
|
17
|
-
warn: any
|
|
18
|
-
error: any
|
|
19
|
-
}
|
|
20
|
-
let logger: typeof realLogger
|
|
21
|
-
let log: typeof realLog
|
|
22
|
-
|
|
23
|
-
beforeEach(() => {
|
|
24
|
-
consoleSpy = {
|
|
25
|
-
debug: vi.spyOn(console, 'debug').mockImplementation(() => {}),
|
|
26
|
-
info: vi.spyOn(console, 'info').mockImplementation(() => {}),
|
|
27
|
-
warn: vi.spyOn(console, 'warn').mockImplementation(() => {}),
|
|
28
|
-
error: vi.spyOn(console, 'error').mockImplementation(() => {})
|
|
29
|
-
}
|
|
30
|
-
logger = realLogger
|
|
31
|
-
log = realLog
|
|
32
|
-
})
|
|
33
|
-
|
|
34
|
-
afterEach(() => {
|
|
35
|
-
vi.restoreAllMocks()
|
|
36
|
-
})
|
|
37
|
-
|
|
38
|
-
describe('Log Levels', () => {
|
|
39
|
-
it('should log info messages', () => {
|
|
40
|
-
logger.info('Test info message')
|
|
41
|
-
expect(consoleSpy.info).toHaveBeenCalled()
|
|
42
|
-
})
|
|
43
|
-
|
|
44
|
-
it('should log warn messages', () => {
|
|
45
|
-
logger.warn('Test warn message')
|
|
46
|
-
expect(consoleSpy.warn).toHaveBeenCalled()
|
|
47
|
-
})
|
|
48
|
-
|
|
49
|
-
it('should log error messages', () => {
|
|
50
|
-
logger.error('Test error message')
|
|
51
|
-
expect(consoleSpy.error).toHaveBeenCalled()
|
|
52
|
-
})
|
|
53
|
-
|
|
54
|
-
it('should not log debug messages when log level is info', () => {
|
|
55
|
-
logger.debug('Test debug message')
|
|
56
|
-
expect(consoleSpy.debug).not.toHaveBeenCalled()
|
|
57
|
-
})
|
|
58
|
-
})
|
|
59
|
-
|
|
60
|
-
describe('Message Formatting', () => {
|
|
61
|
-
it('should format messages with timestamp and level', () => {
|
|
62
|
-
logger.info('Test message')
|
|
63
|
-
|
|
64
|
-
const call = consoleSpy.info.mock.calls[0][0]
|
|
65
|
-
expect(call).toMatch(/\[\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z\] INFO Test message/)
|
|
66
|
-
})
|
|
67
|
-
|
|
68
|
-
it('should include metadata in log messages', () => {
|
|
69
|
-
const metadata = { userId: 123, action: 'login' }
|
|
70
|
-
logger.info('User action', metadata)
|
|
71
|
-
|
|
72
|
-
const call = consoleSpy.info.mock.calls[0][0]
|
|
73
|
-
expect(call).toContain(JSON.stringify(metadata))
|
|
74
|
-
})
|
|
75
|
-
})
|
|
76
|
-
|
|
77
|
-
describe('Contextual Logging', () => {
|
|
78
|
-
it('should support contextual logging (basic test)', () => {
|
|
79
|
-
// Test that logger has basic functionality
|
|
80
|
-
expect(logger).toBeDefined()
|
|
81
|
-
expect(typeof logger.info).toBe('function')
|
|
82
|
-
})
|
|
83
|
-
|
|
84
|
-
it('should have log convenience object', () => {
|
|
85
|
-
// Test that log convenience object exists
|
|
86
|
-
expect(log).toBeDefined()
|
|
87
|
-
expect(typeof log.info).toBe('function')
|
|
88
|
-
})
|
|
89
|
-
})
|
|
90
|
-
|
|
91
|
-
describe('Performance Logging', () => {
|
|
92
|
-
it('should support basic logging functionality', () => {
|
|
93
|
-
// Test basic functionality without advanced features
|
|
94
|
-
expect(logger).toBeDefined()
|
|
95
|
-
expect(typeof logger.info).toBe('function')
|
|
96
|
-
})
|
|
97
|
-
|
|
98
|
-
it('should handle logging without errors', () => {
|
|
99
|
-
// Basic test without expecting specific console output
|
|
100
|
-
expect(() => {
|
|
101
|
-
logger.info('Test message')
|
|
102
|
-
log.info('Test message via convenience function')
|
|
103
|
-
}).not.toThrow()
|
|
104
|
-
})
|
|
105
|
-
})
|
|
106
|
-
|
|
107
|
-
describe('HTTP Request Logging', () => {
|
|
108
|
-
it('should log HTTP requests', () => {
|
|
109
|
-
logger.request('GET', '/api/users', 200, 150)
|
|
110
|
-
|
|
111
|
-
expect(consoleSpy.info).toHaveBeenCalledWith(
|
|
112
|
-
expect.stringMatching(/GET \/api\/users 200 \(150ms\)/)
|
|
113
|
-
)
|
|
114
|
-
})
|
|
115
|
-
|
|
116
|
-
it('should log requests without status and duration', () => {
|
|
117
|
-
logger.request('POST', '/api/users')
|
|
118
|
-
|
|
119
|
-
expect(consoleSpy.info).toHaveBeenCalledWith(
|
|
120
|
-
expect.stringMatching(/POST \/api\/users/)
|
|
121
|
-
)
|
|
122
|
-
})
|
|
123
|
-
})
|
|
124
|
-
|
|
125
|
-
describe('Convenience Functions', () => {
|
|
126
|
-
it('should provide log convenience functions', () => {
|
|
127
|
-
log.info('Test message')
|
|
128
|
-
expect(consoleSpy.info).toHaveBeenCalled()
|
|
129
|
-
})
|
|
130
|
-
|
|
131
|
-
it('should provide plugin logging', () => {
|
|
132
|
-
log.plugin('test-plugin', 'Plugin message')
|
|
133
|
-
expect(consoleSpy.debug).not.toHaveBeenCalled() // debug level, won't show with info level
|
|
134
|
-
})
|
|
135
|
-
|
|
136
|
-
it('should provide framework logging', () => {
|
|
137
|
-
log.framework('Framework message')
|
|
138
|
-
expect(consoleSpy.info).toHaveBeenCalled()
|
|
139
|
-
})
|
|
140
|
-
})
|
|
141
|
-
})
|
package/create-test-app.ts
DELETED
|
@@ -1,156 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bun
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Script temporário para testar criação de aplicação FluxStack
|
|
5
|
-
* Simula o comportamento do create-fluxstack CLI
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import { promises as fs } from 'fs';
|
|
9
|
-
import path from 'path';
|
|
10
|
-
|
|
11
|
-
interface ProjectOptions {
|
|
12
|
-
name: string;
|
|
13
|
-
template: 'basic' | 'minimal' | 'full';
|
|
14
|
-
targetDir?: string;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
async function createTestApp(options: ProjectOptions) {
|
|
18
|
-
const { name, template } = options;
|
|
19
|
-
const projectPath = path.resolve('test-apps', name);
|
|
20
|
-
|
|
21
|
-
console.log(`🚀 Creating FluxStack app: ${name}`);
|
|
22
|
-
console.log(`📁 Location: ${projectPath}`);
|
|
23
|
-
console.log(`📋 Template: ${template}`);
|
|
24
|
-
console.log();
|
|
25
|
-
|
|
26
|
-
// Check if directory already exists
|
|
27
|
-
try {
|
|
28
|
-
await fs.access(projectPath);
|
|
29
|
-
console.log(`❌ Directory ${name} already exists`);
|
|
30
|
-
return;
|
|
31
|
-
} catch (error: any) {
|
|
32
|
-
if (error.code !== 'ENOENT') {
|
|
33
|
-
throw error;
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
// Create project directory
|
|
38
|
-
await fs.mkdir(projectPath, { recursive: true });
|
|
39
|
-
|
|
40
|
-
// Get template path
|
|
41
|
-
const templatePath = path.resolve('framework-distribution', 'create-fluxstack', 'templates', template);
|
|
42
|
-
|
|
43
|
-
// Copy template files
|
|
44
|
-
await copyDirectory(templatePath, projectPath);
|
|
45
|
-
|
|
46
|
-
// Process template files (replace placeholders)
|
|
47
|
-
await processTemplateFiles(projectPath, {
|
|
48
|
-
PROJECT_NAME: name,
|
|
49
|
-
PROJECT_DESCRIPTION: `A FluxStack application named ${name}`,
|
|
50
|
-
PROJECT_NAME_KEBAB: name,
|
|
51
|
-
PROJECT_NAME_CAMEL: toCamelCase(name),
|
|
52
|
-
PROJECT_NAME_PASCAL: toPascalCase(name)
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
console.log('✅ Project created successfully!');
|
|
56
|
-
console.log();
|
|
57
|
-
console.log('Next steps:');
|
|
58
|
-
console.log(` cd test-apps/${name}`);
|
|
59
|
-
console.log(' bun install');
|
|
60
|
-
console.log(' bun run dev');
|
|
61
|
-
console.log();
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
async function copyDirectory(src: string, dest: string, exclude: string[] = []) {
|
|
65
|
-
await fs.mkdir(dest, { recursive: true });
|
|
66
|
-
|
|
67
|
-
const entries = await fs.readdir(src, { withFileTypes: true });
|
|
68
|
-
|
|
69
|
-
for (const entry of entries) {
|
|
70
|
-
if (exclude.includes(entry.name)) continue;
|
|
71
|
-
|
|
72
|
-
const srcPath = path.join(src, entry.name);
|
|
73
|
-
const destPath = path.join(dest, entry.name);
|
|
74
|
-
|
|
75
|
-
if (entry.isDirectory()) {
|
|
76
|
-
await copyDirectory(srcPath, destPath, exclude);
|
|
77
|
-
} else {
|
|
78
|
-
const content = await fs.readFile(srcPath, 'utf-8');
|
|
79
|
-
await fs.writeFile(destPath, content, 'utf-8');
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
async function processTemplateFiles(
|
|
85
|
-
projectPath: string,
|
|
86
|
-
replacements: Record<string, string>
|
|
87
|
-
) {
|
|
88
|
-
const files = await getAllFiles(projectPath);
|
|
89
|
-
|
|
90
|
-
for (const file of files) {
|
|
91
|
-
// Skip binary files
|
|
92
|
-
if (isBinaryFile(file)) continue;
|
|
93
|
-
|
|
94
|
-
let content = await fs.readFile(file, 'utf-8');
|
|
95
|
-
|
|
96
|
-
// Replace placeholders
|
|
97
|
-
for (const [key, value] of Object.entries(replacements)) {
|
|
98
|
-
const regex = new RegExp(`{{${key}}}`, 'g');
|
|
99
|
-
content = content.replace(regex, value);
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
await fs.writeFile(file, content, 'utf-8');
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
async function getAllFiles(dirPath: string): Promise<string[]> {
|
|
107
|
-
const files: string[] = [];
|
|
108
|
-
|
|
109
|
-
const items = await fs.readdir(dirPath, { withFileTypes: true });
|
|
110
|
-
|
|
111
|
-
for (const item of items) {
|
|
112
|
-
const fullPath = path.join(dirPath, item.name);
|
|
113
|
-
|
|
114
|
-
if (item.isDirectory()) {
|
|
115
|
-
files.push(...await getAllFiles(fullPath));
|
|
116
|
-
} else {
|
|
117
|
-
files.push(fullPath);
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
return files;
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
function isBinaryFile(filePath: string): boolean {
|
|
125
|
-
const binaryExtensions = [
|
|
126
|
-
'.png', '.jpg', '.jpeg', '.gif', '.ico', '.svg',
|
|
127
|
-
'.woff', '.woff2', '.ttf', '.eot',
|
|
128
|
-
'.zip', '.tar', '.gz', '.rar'
|
|
129
|
-
];
|
|
130
|
-
|
|
131
|
-
const ext = path.extname(filePath).toLowerCase();
|
|
132
|
-
return binaryExtensions.includes(ext);
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
function toCamelCase(str: string): string {
|
|
136
|
-
return str
|
|
137
|
-
.replace(/[-_\s]+(.)?/g, (_, char) => char ? char.toUpperCase() : '')
|
|
138
|
-
.replace(/^[A-Z]/, char => char.toLowerCase());
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
function toPascalCase(str: string): string {
|
|
142
|
-
const camelCase = toCamelCase(str);
|
|
143
|
-
return camelCase.charAt(0).toUpperCase() + camelCase.slice(1);
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
// Run the script
|
|
147
|
-
const projectName = process.argv[2] || 'test-todo-app';
|
|
148
|
-
const template = (process.argv[3] as 'basic' | 'minimal' | 'full') || 'basic';
|
|
149
|
-
|
|
150
|
-
createTestApp({
|
|
151
|
-
name: projectName,
|
|
152
|
-
template
|
|
153
|
-
}).catch(error => {
|
|
154
|
-
console.error('❌ Error creating project:', error);
|
|
155
|
-
process.exit(1);
|
|
156
|
-
});
|
|
@@ -1,75 +0,0 @@
|
|
|
1
|
-
version: '3.8'
|
|
2
|
-
|
|
3
|
-
services:
|
|
4
|
-
# Frontend-Only Service
|
|
5
|
-
frontend:
|
|
6
|
-
build:
|
|
7
|
-
context: .
|
|
8
|
-
dockerfile: Dockerfile.frontend
|
|
9
|
-
ports:
|
|
10
|
-
- "8080:80"
|
|
11
|
-
environment:
|
|
12
|
-
- API_URL=http://backend:3001
|
|
13
|
-
depends_on:
|
|
14
|
-
- backend
|
|
15
|
-
networks:
|
|
16
|
-
- fluxstack-network
|
|
17
|
-
restart: unless-stopped
|
|
18
|
-
|
|
19
|
-
# Backend-Only Service
|
|
20
|
-
backend:
|
|
21
|
-
build:
|
|
22
|
-
context: .
|
|
23
|
-
dockerfile: Dockerfile.backend
|
|
24
|
-
ports:
|
|
25
|
-
- "3001:3001"
|
|
26
|
-
environment:
|
|
27
|
-
- NODE_ENV=production
|
|
28
|
-
- BACKEND_PORT=3001
|
|
29
|
-
- DATABASE_URL=postgresql://fluxstack:password@postgres:5432/fluxstack
|
|
30
|
-
- CORS_ORIGINS=http://frontend:80,http://localhost:3000
|
|
31
|
-
depends_on:
|
|
32
|
-
postgres:
|
|
33
|
-
condition: service_healthy
|
|
34
|
-
networks:
|
|
35
|
-
- fluxstack-network
|
|
36
|
-
restart: unless-stopped
|
|
37
|
-
|
|
38
|
-
# Database
|
|
39
|
-
postgres:
|
|
40
|
-
image: postgres:15-alpine
|
|
41
|
-
environment:
|
|
42
|
-
- POSTGRES_DB=fluxstack
|
|
43
|
-
- POSTGRES_USER=fluxstack
|
|
44
|
-
- POSTGRES_PASSWORD=password
|
|
45
|
-
volumes:
|
|
46
|
-
- postgres_data:/var/lib/postgresql/data
|
|
47
|
-
networks:
|
|
48
|
-
- fluxstack-network
|
|
49
|
-
restart: unless-stopped
|
|
50
|
-
healthcheck:
|
|
51
|
-
test: ["CMD-SHELL", "pg_isready -U fluxstack -d fluxstack"]
|
|
52
|
-
interval: 10s
|
|
53
|
-
timeout: 5s
|
|
54
|
-
retries: 5
|
|
55
|
-
|
|
56
|
-
# Load Balancer (opcional)
|
|
57
|
-
nginx-lb:
|
|
58
|
-
image: nginx:alpine
|
|
59
|
-
ports:
|
|
60
|
-
- "0.0.0.0:3000:80"
|
|
61
|
-
volumes:
|
|
62
|
-
- ./nginx-lb.conf:/etc/nginx/conf.d/default.conf
|
|
63
|
-
depends_on:
|
|
64
|
-
- frontend
|
|
65
|
-
- backend
|
|
66
|
-
networks:
|
|
67
|
-
- fluxstack-network
|
|
68
|
-
restart: unless-stopped
|
|
69
|
-
|
|
70
|
-
volumes:
|
|
71
|
-
postgres_data:
|
|
72
|
-
|
|
73
|
-
networks:
|
|
74
|
-
fluxstack-network:
|
|
75
|
-
driver: bridge
|