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,398 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Tests for Plugin Manager
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import { describe, it, expect, beforeEach, vi, afterEach } from 'vitest'
|
|
6
|
-
import { PluginManager } from '../manager'
|
|
7
|
-
import type { Plugin, PluginContext } from '../types'
|
|
8
|
-
import type { Logger } from '../../utils/logger/index'
|
|
9
|
-
import type { FluxStackConfig } from '../../config/schema'
|
|
10
|
-
|
|
11
|
-
// Mock logger
|
|
12
|
-
const mockLogger: Logger = {
|
|
13
|
-
debug: vi.fn(),
|
|
14
|
-
info: vi.fn(),
|
|
15
|
-
warn: vi.fn(),
|
|
16
|
-
error: vi.fn(),
|
|
17
|
-
child: vi.fn(() => mockLogger),
|
|
18
|
-
time: vi.fn(),
|
|
19
|
-
timeEnd: vi.fn(),
|
|
20
|
-
request: vi.fn()
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
// Mock config
|
|
24
|
-
const mockConfig: FluxStackConfig = {
|
|
25
|
-
app: { name: 'test-app', version: '1.0.0' },
|
|
26
|
-
server: {
|
|
27
|
-
port: 3000,
|
|
28
|
-
host: 'localhost',
|
|
29
|
-
apiPrefix: '/api',
|
|
30
|
-
cors: {
|
|
31
|
-
origins: ['*'],
|
|
32
|
-
methods: ['GET', 'POST'],
|
|
33
|
-
headers: ['Content-Type']
|
|
34
|
-
},
|
|
35
|
-
middleware: []
|
|
36
|
-
},
|
|
37
|
-
client: {
|
|
38
|
-
port: 5173,
|
|
39
|
-
proxy: { target: 'http://localhost:3000' },
|
|
40
|
-
build: {
|
|
41
|
-
sourceMaps: true,
|
|
42
|
-
minify: false,
|
|
43
|
-
target: 'esnext',
|
|
44
|
-
outDir: 'dist/client'
|
|
45
|
-
}
|
|
46
|
-
},
|
|
47
|
-
build: {
|
|
48
|
-
target: 'bun',
|
|
49
|
-
outDir: 'dist',
|
|
50
|
-
optimization: {
|
|
51
|
-
minify: false,
|
|
52
|
-
treeshake: false,
|
|
53
|
-
compress: false,
|
|
54
|
-
splitChunks: false,
|
|
55
|
-
bundleAnalyzer: false
|
|
56
|
-
},
|
|
57
|
-
sourceMaps: true,
|
|
58
|
-
clean: true
|
|
59
|
-
},
|
|
60
|
-
plugins: {
|
|
61
|
-
enabled: [], // Enable all plugins by default for testing
|
|
62
|
-
disabled: [],
|
|
63
|
-
config: {}
|
|
64
|
-
},
|
|
65
|
-
logging: {
|
|
66
|
-
level: 'info',
|
|
67
|
-
format: 'pretty',
|
|
68
|
-
transports: []
|
|
69
|
-
},
|
|
70
|
-
monitoring: {
|
|
71
|
-
enabled: false,
|
|
72
|
-
metrics: {
|
|
73
|
-
enabled: false,
|
|
74
|
-
collectInterval: 5000,
|
|
75
|
-
httpMetrics: false,
|
|
76
|
-
systemMetrics: false,
|
|
77
|
-
customMetrics: false
|
|
78
|
-
},
|
|
79
|
-
profiling: {
|
|
80
|
-
enabled: false,
|
|
81
|
-
sampleRate: 0.1,
|
|
82
|
-
memoryProfiling: false,
|
|
83
|
-
cpuProfiling: false
|
|
84
|
-
},
|
|
85
|
-
exporters: []
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
describe('PluginManager', () => {
|
|
90
|
-
let manager: PluginManager
|
|
91
|
-
let mockApp: any
|
|
92
|
-
|
|
93
|
-
beforeEach(() => {
|
|
94
|
-
mockApp = { use: vi.fn(), get: vi.fn(), post: vi.fn() }
|
|
95
|
-
manager = new PluginManager({
|
|
96
|
-
config: mockConfig,
|
|
97
|
-
logger: mockLogger,
|
|
98
|
-
app: mockApp
|
|
99
|
-
})
|
|
100
|
-
vi.clearAllMocks()
|
|
101
|
-
})
|
|
102
|
-
|
|
103
|
-
afterEach(async () => {
|
|
104
|
-
if (manager) {
|
|
105
|
-
await manager.shutdown()
|
|
106
|
-
}
|
|
107
|
-
})
|
|
108
|
-
|
|
109
|
-
describe('Initialization', () => {
|
|
110
|
-
it('should initialize successfully', async () => {
|
|
111
|
-
await manager.initialize()
|
|
112
|
-
expect(mockLogger.info).toHaveBeenCalledWith('Initializing plugin manager')
|
|
113
|
-
expect(mockLogger.info).toHaveBeenCalledWith('Plugin manager initialized successfully', expect.any(Object))
|
|
114
|
-
})
|
|
115
|
-
|
|
116
|
-
it('should not initialize twice', async () => {
|
|
117
|
-
await manager.initialize()
|
|
118
|
-
await manager.initialize() // Second call should be ignored
|
|
119
|
-
|
|
120
|
-
// Should only log initialization once
|
|
121
|
-
expect(mockLogger.info).toHaveBeenCalledTimes(3) // discovery + init start + init complete
|
|
122
|
-
})
|
|
123
|
-
})
|
|
124
|
-
|
|
125
|
-
describe('Plugin Registration', () => {
|
|
126
|
-
it('should register a plugin', async () => {
|
|
127
|
-
const plugin: Plugin = {
|
|
128
|
-
name: 'test-plugin',
|
|
129
|
-
setup: vi.fn()
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
await manager.registerPlugin(plugin)
|
|
133
|
-
|
|
134
|
-
const registry = manager.getRegistry()
|
|
135
|
-
expect(registry.get('test-plugin')).toBe(plugin)
|
|
136
|
-
})
|
|
137
|
-
|
|
138
|
-
it('should execute setup hook when registering after initialization', async () => {
|
|
139
|
-
const setupSpy = vi.fn()
|
|
140
|
-
const plugin: Plugin = {
|
|
141
|
-
name: 'test-plugin',
|
|
142
|
-
setup: setupSpy
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
await manager.initialize()
|
|
146
|
-
await manager.registerPlugin(plugin)
|
|
147
|
-
|
|
148
|
-
expect(setupSpy).toHaveBeenCalled()
|
|
149
|
-
})
|
|
150
|
-
|
|
151
|
-
it('should unregister a plugin', async () => {
|
|
152
|
-
const plugin: Plugin = {
|
|
153
|
-
name: 'removable-plugin'
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
await manager.registerPlugin(plugin)
|
|
157
|
-
manager.unregisterPlugin('removable-plugin')
|
|
158
|
-
|
|
159
|
-
const registry = manager.getRegistry()
|
|
160
|
-
expect(registry.get('removable-plugin')).toBeUndefined()
|
|
161
|
-
})
|
|
162
|
-
})
|
|
163
|
-
|
|
164
|
-
describe('Hook Execution', () => {
|
|
165
|
-
it('should execute setup hook on all plugins', async () => {
|
|
166
|
-
const setupSpy1 = vi.fn()
|
|
167
|
-
const setupSpy2 = vi.fn()
|
|
168
|
-
|
|
169
|
-
const plugin1: Plugin = {
|
|
170
|
-
name: 'plugin-1',
|
|
171
|
-
setup: setupSpy1
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
const plugin2: Plugin = {
|
|
175
|
-
name: 'plugin-2',
|
|
176
|
-
setup: setupSpy2
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
await manager.registerPlugin(plugin1)
|
|
180
|
-
await manager.registerPlugin(plugin2)
|
|
181
|
-
|
|
182
|
-
const results = await manager.executeHook('setup')
|
|
183
|
-
|
|
184
|
-
expect(results).toHaveLength(2)
|
|
185
|
-
expect(results.every(r => r.success)).toBe(true)
|
|
186
|
-
expect(setupSpy1).toHaveBeenCalled()
|
|
187
|
-
expect(setupSpy2).toHaveBeenCalled()
|
|
188
|
-
})
|
|
189
|
-
|
|
190
|
-
it('should execute hooks in dependency order', async () => {
|
|
191
|
-
const executionOrder: string[] = []
|
|
192
|
-
|
|
193
|
-
const pluginA: Plugin = {
|
|
194
|
-
name: 'plugin-a',
|
|
195
|
-
setup: () => { executionOrder.push('plugin-a') }
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
const pluginB: Plugin = {
|
|
199
|
-
name: 'plugin-b',
|
|
200
|
-
dependencies: ['plugin-a'],
|
|
201
|
-
setup: () => { executionOrder.push('plugin-b') }
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
await manager.registerPlugin(pluginA)
|
|
205
|
-
await manager.registerPlugin(pluginB)
|
|
206
|
-
|
|
207
|
-
await manager.executeHook('setup')
|
|
208
|
-
|
|
209
|
-
expect(executionOrder).toEqual(['plugin-a', 'plugin-b'])
|
|
210
|
-
})
|
|
211
|
-
|
|
212
|
-
it('should respect plugin priorities', async () => {
|
|
213
|
-
const executionOrder: string[] = []
|
|
214
|
-
|
|
215
|
-
const lowPriorityPlugin: Plugin = {
|
|
216
|
-
name: 'low-priority',
|
|
217
|
-
priority: 1,
|
|
218
|
-
setup: () => { executionOrder.push('low-priority') }
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
const highPriorityPlugin: Plugin = {
|
|
222
|
-
name: 'high-priority',
|
|
223
|
-
priority: 10,
|
|
224
|
-
setup: () => { executionOrder.push('high-priority') }
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
await manager.registerPlugin(lowPriorityPlugin)
|
|
228
|
-
await manager.registerPlugin(highPriorityPlugin)
|
|
229
|
-
|
|
230
|
-
await manager.executeHook('setup')
|
|
231
|
-
|
|
232
|
-
expect(executionOrder.indexOf('high-priority')).toBeLessThan(executionOrder.indexOf('low-priority'))
|
|
233
|
-
})
|
|
234
|
-
|
|
235
|
-
it('should handle plugin hook errors gracefully', async () => {
|
|
236
|
-
const errorPlugin: Plugin = {
|
|
237
|
-
name: 'error-plugin',
|
|
238
|
-
setup: () => {
|
|
239
|
-
throw new Error('Plugin setup failed')
|
|
240
|
-
}
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
const goodPlugin: Plugin = {
|
|
244
|
-
name: 'good-plugin',
|
|
245
|
-
setup: vi.fn()
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
await manager.registerPlugin(errorPlugin)
|
|
249
|
-
await manager.registerPlugin(goodPlugin)
|
|
250
|
-
|
|
251
|
-
const results = await manager.executeHook('setup')
|
|
252
|
-
|
|
253
|
-
expect(results).toHaveLength(2)
|
|
254
|
-
expect(results.find(r => r.plugin === 'error-plugin')?.success).toBe(false)
|
|
255
|
-
expect(results.find(r => r.plugin === 'good-plugin')?.success).toBe(true)
|
|
256
|
-
})
|
|
257
|
-
|
|
258
|
-
it('should execute hooks in parallel when specified', async () => {
|
|
259
|
-
const startTimes: Record<string, number> = {}
|
|
260
|
-
const endTimes: Record<string, number> = {}
|
|
261
|
-
|
|
262
|
-
const plugin1: Plugin = {
|
|
263
|
-
name: 'plugin-1',
|
|
264
|
-
setup: async () => {
|
|
265
|
-
startTimes['plugin-1'] = Date.now()
|
|
266
|
-
await new Promise(resolve => setTimeout(resolve, 50))
|
|
267
|
-
endTimes['plugin-1'] = Date.now()
|
|
268
|
-
}
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
const plugin2: Plugin = {
|
|
272
|
-
name: 'plugin-2',
|
|
273
|
-
setup: async () => {
|
|
274
|
-
startTimes['plugin-2'] = Date.now()
|
|
275
|
-
await new Promise(resolve => setTimeout(resolve, 50))
|
|
276
|
-
endTimes['plugin-2'] = Date.now()
|
|
277
|
-
}
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
await manager.registerPlugin(plugin1)
|
|
281
|
-
await manager.registerPlugin(plugin2)
|
|
282
|
-
|
|
283
|
-
await manager.executeHook('setup', undefined, { parallel: true })
|
|
284
|
-
|
|
285
|
-
// In parallel execution, both should start around the same time
|
|
286
|
-
const timeDiff = Math.abs(startTimes['plugin-1'] - startTimes['plugin-2'])
|
|
287
|
-
expect(timeDiff).toBeLessThan(20) // Allow for small timing differences
|
|
288
|
-
})
|
|
289
|
-
|
|
290
|
-
it('should handle hook timeout', async () => {
|
|
291
|
-
const slowPlugin: Plugin = {
|
|
292
|
-
name: 'slow-plugin',
|
|
293
|
-
setup: async () => {
|
|
294
|
-
await new Promise(resolve => setTimeout(resolve, 200))
|
|
295
|
-
}
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
await manager.registerPlugin(slowPlugin)
|
|
299
|
-
|
|
300
|
-
const results = await manager.executeHook('setup', undefined, { timeout: 100 })
|
|
301
|
-
|
|
302
|
-
expect(results).toHaveLength(1)
|
|
303
|
-
expect(results[0].success).toBe(false)
|
|
304
|
-
expect(results[0].error?.message).toContain('timed out')
|
|
305
|
-
})
|
|
306
|
-
})
|
|
307
|
-
|
|
308
|
-
describe('Plugin Context', () => {
|
|
309
|
-
it('should provide correct context to plugins', async () => {
|
|
310
|
-
let receivedContext: PluginContext | undefined
|
|
311
|
-
|
|
312
|
-
const plugin: Plugin = {
|
|
313
|
-
name: 'context-plugin',
|
|
314
|
-
setup: (context) => {
|
|
315
|
-
receivedContext = context
|
|
316
|
-
}
|
|
317
|
-
}
|
|
318
|
-
|
|
319
|
-
await manager.registerPlugin(plugin)
|
|
320
|
-
await manager.executeHook('setup')
|
|
321
|
-
|
|
322
|
-
expect(receivedContext).toBeDefined()
|
|
323
|
-
expect(receivedContext?.config).toBe(mockConfig)
|
|
324
|
-
expect(receivedContext?.app).toBe(mockApp)
|
|
325
|
-
expect(receivedContext?.logger).toBeDefined()
|
|
326
|
-
expect(receivedContext?.utils).toBeDefined()
|
|
327
|
-
})
|
|
328
|
-
|
|
329
|
-
it('should provide plugin-specific logger', async () => {
|
|
330
|
-
const plugin: Plugin = {
|
|
331
|
-
name: 'logger-plugin',
|
|
332
|
-
setup: (_context) => {
|
|
333
|
-
// Logger context is available but not used in this test
|
|
334
|
-
}
|
|
335
|
-
}
|
|
336
|
-
|
|
337
|
-
await manager.registerPlugin(plugin)
|
|
338
|
-
await manager.executeHook('setup')
|
|
339
|
-
|
|
340
|
-
expect(mockLogger.child).toHaveBeenCalledWith({ plugin: 'logger-plugin' })
|
|
341
|
-
})
|
|
342
|
-
})
|
|
343
|
-
|
|
344
|
-
describe('Plugin Metrics', () => {
|
|
345
|
-
it('should track plugin metrics', async () => {
|
|
346
|
-
const plugin: Plugin = {
|
|
347
|
-
name: 'metrics-plugin',
|
|
348
|
-
setup: async () => {
|
|
349
|
-
await new Promise(resolve => setTimeout(resolve, 10))
|
|
350
|
-
}
|
|
351
|
-
}
|
|
352
|
-
|
|
353
|
-
await manager.registerPlugin(plugin)
|
|
354
|
-
await manager.executeHook('setup')
|
|
355
|
-
|
|
356
|
-
const metrics = manager.getPluginMetrics('metrics-plugin')
|
|
357
|
-
expect(metrics).toBeDefined()
|
|
358
|
-
expect(typeof metrics).toBe('object')
|
|
359
|
-
expect((metrics as any).hookExecutions).toBeDefined()
|
|
360
|
-
})
|
|
361
|
-
|
|
362
|
-
it('should get all plugin metrics', async () => {
|
|
363
|
-
const plugin1: Plugin = { name: 'plugin-1', setup: vi.fn() }
|
|
364
|
-
const plugin2: Plugin = { name: 'plugin-2', setup: vi.fn() }
|
|
365
|
-
|
|
366
|
-
await manager.registerPlugin(plugin1)
|
|
367
|
-
await manager.registerPlugin(plugin2)
|
|
368
|
-
await manager.executeHook('setup')
|
|
369
|
-
|
|
370
|
-
const allMetrics = manager.getPluginMetrics()
|
|
371
|
-
expect(allMetrics instanceof Map).toBe(true)
|
|
372
|
-
expect((allMetrics as Map<string, any>).size).toBe(2)
|
|
373
|
-
})
|
|
374
|
-
})
|
|
375
|
-
|
|
376
|
-
describe('Shutdown', () => {
|
|
377
|
-
it('should shutdown gracefully', async () => {
|
|
378
|
-
const shutdownSpy = vi.fn()
|
|
379
|
-
|
|
380
|
-
const plugin: Plugin = {
|
|
381
|
-
name: 'shutdown-plugin',
|
|
382
|
-
onServerStop: shutdownSpy
|
|
383
|
-
}
|
|
384
|
-
|
|
385
|
-
await manager.registerPlugin(plugin)
|
|
386
|
-
await manager.initialize()
|
|
387
|
-
await manager.shutdown()
|
|
388
|
-
|
|
389
|
-
expect(shutdownSpy).toHaveBeenCalled()
|
|
390
|
-
expect(mockLogger.info).toHaveBeenCalledWith('Shutting down plugin manager')
|
|
391
|
-
})
|
|
392
|
-
|
|
393
|
-
it('should not shutdown if not initialized', async () => {
|
|
394
|
-
await manager.shutdown()
|
|
395
|
-
expect(mockLogger.info).not.toHaveBeenCalledWith('Shutting down plugin manager')
|
|
396
|
-
})
|
|
397
|
-
})
|
|
398
|
-
})
|