@friggframework/devtools 2.0.0--canary.398.7664c46.0 → 2.0.0--canary.400.bed3308.0
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/frigg-cli/.eslintrc.js +141 -0
- package/frigg-cli/__tests__/jest.config.js +102 -0
- package/frigg-cli/__tests__/unit/commands/build.test.js +483 -0
- package/frigg-cli/__tests__/unit/commands/install.test.js +418 -0
- package/frigg-cli/__tests__/unit/commands/ui.test.js +592 -0
- package/frigg-cli/__tests__/utils/command-tester.js +170 -0
- package/frigg-cli/__tests__/utils/mock-factory.js +270 -0
- package/frigg-cli/__tests__/utils/test-fixtures.js +463 -0
- package/frigg-cli/__tests__/utils/test-setup.js +286 -0
- package/frigg-cli/build-command/index.js +15 -2
- package/frigg-cli/deploy-command/index.js +15 -2
- package/frigg-cli/generate-command/__tests__/generate-command.test.js +312 -0
- package/frigg-cli/generate-command/azure-generator.js +43 -0
- package/frigg-cli/generate-command/gcp-generator.js +47 -0
- package/frigg-cli/generate-command/index.js +350 -0
- package/frigg-cli/generate-command/terraform-generator.js +555 -0
- package/frigg-cli/index.js +66 -4
- package/frigg-cli/install-command/index.js +15 -2
- package/frigg-cli/package.json +75 -0
- package/frigg-cli/start-command/index.js +17 -2
- package/frigg-cli/ui-command/index.js +167 -0
- package/frigg-cli/utils/app-resolver.js +319 -0
- package/frigg-cli/utils/backend-path.js +38 -0
- package/frigg-cli/utils/process-manager.js +199 -0
- package/frigg-cli/utils/repo-detection.js +405 -0
- package/infrastructure/AWS-IAM-CREDENTIAL-NEEDS.md +43 -19
- package/infrastructure/IAM-POLICY-TEMPLATES.md +1 -1
- package/infrastructure/frigg-deployment-iam-stack.yaml +16 -2
- package/infrastructure/iam-generator.js +129 -6
- package/infrastructure/iam-policy-basic.json +29 -5
- package/infrastructure/iam-policy-full.json +28 -5
- package/infrastructure/serverless-template.js +209 -3
- package/infrastructure/serverless-template.test.js +12 -0
- package/management-ui/.eslintrc.js +22 -0
- package/management-ui/README.md +203 -0
- package/management-ui/components.json +21 -0
- package/management-ui/{dist/index.html → index.html} +1 -2
- package/management-ui/merge-conflict-cleaner.py +371 -0
- package/management-ui/package-lock.json +10997 -0
- package/management-ui/package.json +76 -0
- package/management-ui/postcss.config.js +6 -0
- package/management-ui/server/api/backend.js +256 -0
- package/management-ui/server/api/cli.js +315 -0
- package/management-ui/server/api/codegen.js +663 -0
- package/management-ui/server/api/connections.js +857 -0
- package/management-ui/server/api/discovery.js +185 -0
- package/management-ui/server/api/environment/index.js +1 -0
- package/management-ui/server/api/environment/router.js +378 -0
- package/management-ui/server/api/environment.js +328 -0
- package/management-ui/server/api/integrations.js +479 -0
- package/management-ui/server/api/logs.js +248 -0
- package/management-ui/server/api/monitoring.js +282 -0
- package/management-ui/server/api/open-ide.js +31 -0
- package/management-ui/server/api/project.js +553 -0
- package/management-ui/server/api/users/sessions.js +371 -0
- package/management-ui/server/api/users/simulation.js +254 -0
- package/management-ui/server/api/users.js +362 -0
- package/management-ui/server/api-contract.md +275 -0
- package/management-ui/server/index.js +428 -0
- package/management-ui/server/middleware/errorHandler.js +70 -0
- package/management-ui/server/middleware/security.js +32 -0
- package/management-ui/server/processManager.js +296 -0
- package/management-ui/server/server.js +188 -0
- package/management-ui/server/services/aws-monitor.js +413 -0
- package/management-ui/server/services/npm-registry.js +347 -0
- package/management-ui/server/services/template-engine.js +538 -0
- package/management-ui/server/utils/cliIntegration.js +220 -0
- package/management-ui/server/utils/environment/auditLogger.js +471 -0
- package/management-ui/server/utils/environment/awsParameterStore.js +264 -0
- package/management-ui/server/utils/environment/encryption.js +278 -0
- package/management-ui/server/utils/environment/envFileManager.js +286 -0
- package/management-ui/server/utils/import-commonjs.js +28 -0
- package/management-ui/server/utils/response.js +83 -0
- package/management-ui/server/websocket/handler.js +325 -0
- package/management-ui/src/App.jsx +51 -0
- package/management-ui/src/components/AppRouter.jsx +65 -0
- package/management-ui/src/components/Button.jsx +2 -0
- package/management-ui/src/components/Card.jsx +9 -0
- package/management-ui/src/components/EnvironmentCompare.jsx +400 -0
- package/management-ui/src/components/EnvironmentEditor.jsx +372 -0
- package/management-ui/src/components/EnvironmentImportExport.jsx +469 -0
- package/management-ui/src/components/EnvironmentSchema.jsx +491 -0
- package/management-ui/src/components/EnvironmentSecurity.jsx +463 -0
- package/management-ui/src/components/ErrorBoundary.jsx +73 -0
- package/management-ui/src/components/IntegrationCard.jsx +199 -0
- package/management-ui/src/components/IntegrationCardEnhanced.jsx +490 -0
- package/management-ui/src/components/IntegrationExplorer.jsx +379 -0
- package/management-ui/src/components/IntegrationStatus.jsx +235 -0
- package/management-ui/src/components/Layout.jsx +250 -0
- package/management-ui/src/components/LoadingSpinner.jsx +45 -0
- package/management-ui/src/components/RepositoryPicker.jsx +248 -0
- package/management-ui/src/components/SessionMonitor.jsx +255 -0
- package/management-ui/src/components/StatusBadge.jsx +70 -0
- package/management-ui/src/components/UserContextSwitcher.jsx +154 -0
- package/management-ui/src/components/UserSimulation.jsx +299 -0
- package/management-ui/src/components/Welcome.jsx +434 -0
- package/management-ui/src/components/codegen/APIEndpointGenerator.jsx +637 -0
- package/management-ui/src/components/codegen/APIModuleSelector.jsx +227 -0
- package/management-ui/src/components/codegen/CodeGenerationWizard.jsx +247 -0
- package/management-ui/src/components/codegen/CodePreviewEditor.jsx +316 -0
- package/management-ui/src/components/codegen/DynamicModuleForm.jsx +271 -0
- package/management-ui/src/components/codegen/FormBuilder.jsx +737 -0
- package/management-ui/src/components/codegen/IntegrationGenerator.jsx +855 -0
- package/management-ui/src/components/codegen/ProjectScaffoldWizard.jsx +797 -0
- package/management-ui/src/components/codegen/SchemaBuilder.jsx +303 -0
- package/management-ui/src/components/codegen/TemplateSelector.jsx +586 -0
- package/management-ui/src/components/codegen/index.js +10 -0
- package/management-ui/src/components/connections/ConnectionConfigForm.jsx +362 -0
- package/management-ui/src/components/connections/ConnectionHealthMonitor.jsx +182 -0
- package/management-ui/src/components/connections/ConnectionTester.jsx +200 -0
- package/management-ui/src/components/connections/EntityRelationshipMapper.jsx +292 -0
- package/management-ui/src/components/connections/OAuthFlow.jsx +204 -0
- package/management-ui/src/components/connections/index.js +5 -0
- package/management-ui/src/components/index.js +21 -0
- package/management-ui/src/components/monitoring/APIGatewayMetrics.jsx +222 -0
- package/management-ui/src/components/monitoring/LambdaMetrics.jsx +169 -0
- package/management-ui/src/components/monitoring/MetricsChart.jsx +197 -0
- package/management-ui/src/components/monitoring/MonitoringDashboard.jsx +393 -0
- package/management-ui/src/components/monitoring/SQSMetrics.jsx +246 -0
- package/management-ui/src/components/monitoring/index.js +6 -0
- package/management-ui/src/components/monitoring/monitoring.css +218 -0
- package/management-ui/src/components/theme-provider.jsx +52 -0
- package/management-ui/src/components/theme-toggle.jsx +39 -0
- package/management-ui/src/components/ui/badge.tsx +36 -0
- package/management-ui/src/components/ui/button.test.jsx +56 -0
- package/management-ui/src/components/ui/button.tsx +57 -0
- package/management-ui/src/components/ui/card.tsx +76 -0
- package/management-ui/src/components/ui/dropdown-menu.tsx +199 -0
- package/management-ui/src/components/ui/select.tsx +157 -0
- package/management-ui/src/components/ui/skeleton.jsx +15 -0
- package/management-ui/src/hooks/useFrigg.jsx +387 -0
- package/management-ui/src/hooks/useSocket.jsx +58 -0
- package/management-ui/src/index.css +194 -0
- package/management-ui/src/lib/utils.ts +6 -0
- package/management-ui/src/main.jsx +10 -0
- package/management-ui/src/pages/CodeGeneration.jsx +14 -0
- package/management-ui/src/pages/Connections.jsx +252 -0
- package/management-ui/src/pages/ConnectionsEnhanced.jsx +427 -0
- package/management-ui/src/pages/Dashboard.jsx +311 -0
- package/management-ui/src/pages/Environment.jsx +314 -0
- package/management-ui/src/pages/IntegrationConfigure.jsx +544 -0
- package/management-ui/src/pages/IntegrationDiscovery.jsx +479 -0
- package/management-ui/src/pages/IntegrationTest.jsx +494 -0
- package/management-ui/src/pages/Integrations.jsx +254 -0
- package/management-ui/src/pages/Monitoring.jsx +17 -0
- package/management-ui/src/pages/Simulation.jsx +155 -0
- package/management-ui/src/pages/Users.jsx +492 -0
- package/management-ui/src/services/api.js +41 -0
- package/management-ui/src/services/apiModuleService.js +193 -0
- package/management-ui/src/services/websocket-handlers.js +120 -0
- package/management-ui/src/test/api/project.test.js +273 -0
- package/management-ui/src/test/components/Welcome.test.jsx +378 -0
- package/management-ui/src/test/mocks/server.js +178 -0
- package/management-ui/src/test/setup.js +61 -0
- package/management-ui/src/test/utils/test-utils.jsx +134 -0
- package/management-ui/src/utils/repository.js +98 -0
- package/management-ui/src/utils/repository.test.js +118 -0
- package/management-ui/src/workflows/phase2-integration-workflows.js +884 -0
- package/management-ui/tailwind.config.js +63 -0
- package/management-ui/tsconfig.json +37 -0
- package/management-ui/tsconfig.node.json +10 -0
- package/management-ui/vite.config.js +26 -0
- package/management-ui/vitest.config.js +38 -0
- package/package.json +5 -5
- package/management-ui/dist/assets/index-CbM64Oba.js +0 -1221
- package/management-ui/dist/assets/index-CkvseXTC.css +0 -1
- /package/management-ui/{dist/assets/FriggLogo-B7Xx8ZW1.svg → src/assets/FriggLogo.svg} +0 -0
|
@@ -0,0 +1,296 @@
|
|
|
1
|
+
import { spawn } from 'child_process'
|
|
2
|
+
import path from 'path'
|
|
3
|
+
import fs from 'fs/promises'
|
|
4
|
+
|
|
5
|
+
class FriggProcessManager {
|
|
6
|
+
constructor() {
|
|
7
|
+
this.process = null
|
|
8
|
+
this.status = 'stopped'
|
|
9
|
+
this.listeners = new Set()
|
|
10
|
+
this.logs = []
|
|
11
|
+
this.maxLogs = 1000
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
// Add status change listener
|
|
15
|
+
addStatusListener(listener) {
|
|
16
|
+
this.listeners.add(listener)
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// Remove status change listener
|
|
20
|
+
removeStatusListener(listener) {
|
|
21
|
+
this.listeners.delete(listener)
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// Notify all listeners of status change
|
|
25
|
+
notifyListeners(status, data = {}) {
|
|
26
|
+
this.status = status
|
|
27
|
+
this.listeners.forEach(listener => {
|
|
28
|
+
try {
|
|
29
|
+
listener({ status, ...data })
|
|
30
|
+
} catch (error) {
|
|
31
|
+
console.error('Error notifying status listener:', error)
|
|
32
|
+
}
|
|
33
|
+
})
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// Add log entry
|
|
37
|
+
addLog(type, message) {
|
|
38
|
+
const logEntry = {
|
|
39
|
+
timestamp: new Date().toISOString(),
|
|
40
|
+
type, // 'stdout', 'stderr', 'system'
|
|
41
|
+
message
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
this.logs.push(logEntry)
|
|
45
|
+
|
|
46
|
+
// Keep only the last maxLogs entries
|
|
47
|
+
if (this.logs.length > this.maxLogs) {
|
|
48
|
+
this.logs = this.logs.slice(-this.maxLogs)
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Notify listeners of new log
|
|
52
|
+
this.listeners.forEach(listener => {
|
|
53
|
+
try {
|
|
54
|
+
listener({ status: this.status, log: logEntry })
|
|
55
|
+
} catch (error) {
|
|
56
|
+
console.error('Error notifying log listener:', error)
|
|
57
|
+
}
|
|
58
|
+
})
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// Get current status
|
|
62
|
+
getStatus() {
|
|
63
|
+
return {
|
|
64
|
+
status: this.status,
|
|
65
|
+
pid: this.process?.pid || null,
|
|
66
|
+
uptime: this.process ? Date.now() - this.startTime : 0
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// Get recent logs
|
|
71
|
+
getLogs(limit = 100) {
|
|
72
|
+
return this.logs.slice(-limit)
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// Find project root with infrastructure.js
|
|
76
|
+
async findProjectRoot(startPath = process.cwd()) {
|
|
77
|
+
let currentPath = startPath
|
|
78
|
+
|
|
79
|
+
while (currentPath !== path.dirname(currentPath)) {
|
|
80
|
+
try {
|
|
81
|
+
const infraPath = path.join(currentPath, 'infrastructure.js')
|
|
82
|
+
await fs.access(infraPath)
|
|
83
|
+
return currentPath
|
|
84
|
+
} catch {
|
|
85
|
+
currentPath = path.dirname(currentPath)
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
throw new Error('Could not find infrastructure.js file in project hierarchy')
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// Start Frigg process
|
|
93
|
+
async start(options = {}) {
|
|
94
|
+
if (this.status === 'running') {
|
|
95
|
+
throw new Error('Frigg is already running')
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
if (this.status === 'starting') {
|
|
99
|
+
throw new Error('Frigg is already starting')
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
try {
|
|
103
|
+
this.notifyListeners('starting')
|
|
104
|
+
this.addLog('system', 'Starting Frigg server...')
|
|
105
|
+
|
|
106
|
+
// Find project root
|
|
107
|
+
const projectRoot = await this.findProjectRoot()
|
|
108
|
+
this.addLog('system', `Project root found: ${projectRoot}`)
|
|
109
|
+
|
|
110
|
+
// Suppress AWS SDK warning
|
|
111
|
+
const env = {
|
|
112
|
+
...process.env,
|
|
113
|
+
AWS_SDK_JS_SUPPRESS_MAINTENANCE_MODE_MESSAGE: '1'
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// Build serverless command
|
|
117
|
+
const command = 'serverless'
|
|
118
|
+
const args = [
|
|
119
|
+
'offline',
|
|
120
|
+
'--config',
|
|
121
|
+
'infrastructure.js',
|
|
122
|
+
'--stage',
|
|
123
|
+
options.stage || 'dev'
|
|
124
|
+
]
|
|
125
|
+
|
|
126
|
+
if (options.verbose) {
|
|
127
|
+
args.push('--verbose')
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
this.addLog('system', `Executing: ${command} ${args.join(' ')}`)
|
|
131
|
+
this.addLog('system', `Working directory: ${projectRoot}`)
|
|
132
|
+
|
|
133
|
+
// Spawn the process
|
|
134
|
+
this.process = spawn(command, args, {
|
|
135
|
+
cwd: projectRoot,
|
|
136
|
+
env,
|
|
137
|
+
stdio: ['pipe', 'pipe', 'pipe']
|
|
138
|
+
})
|
|
139
|
+
|
|
140
|
+
this.startTime = Date.now()
|
|
141
|
+
|
|
142
|
+
// Handle stdout
|
|
143
|
+
this.process.stdout.on('data', (data) => {
|
|
144
|
+
const message = data.toString().trim()
|
|
145
|
+
if (message) {
|
|
146
|
+
this.addLog('stdout', message)
|
|
147
|
+
}
|
|
148
|
+
})
|
|
149
|
+
|
|
150
|
+
// Handle stderr
|
|
151
|
+
this.process.stderr.on('data', (data) => {
|
|
152
|
+
const message = data.toString().trim()
|
|
153
|
+
if (message) {
|
|
154
|
+
this.addLog('stderr', message)
|
|
155
|
+
}
|
|
156
|
+
})
|
|
157
|
+
|
|
158
|
+
// Handle process events
|
|
159
|
+
this.process.on('spawn', () => {
|
|
160
|
+
this.addLog('system', `Process spawned with PID: ${this.process.pid}`)
|
|
161
|
+
this.notifyListeners('running', { pid: this.process.pid })
|
|
162
|
+
})
|
|
163
|
+
|
|
164
|
+
this.process.on('error', (error) => {
|
|
165
|
+
this.addLog('system', `Process error: ${error.message}`)
|
|
166
|
+
this.notifyListeners('stopped', { error: error.message })
|
|
167
|
+
this.cleanup()
|
|
168
|
+
})
|
|
169
|
+
|
|
170
|
+
this.process.on('close', (code, signal) => {
|
|
171
|
+
const message = signal
|
|
172
|
+
? `Process terminated by signal: ${signal}`
|
|
173
|
+
: `Process exited with code: ${code}`
|
|
174
|
+
|
|
175
|
+
this.addLog('system', message)
|
|
176
|
+
this.notifyListeners('stopped', { code, signal })
|
|
177
|
+
this.cleanup()
|
|
178
|
+
})
|
|
179
|
+
|
|
180
|
+
// Return promise that resolves when process is fully started
|
|
181
|
+
return new Promise((resolve, reject) => {
|
|
182
|
+
const timeout = setTimeout(() => {
|
|
183
|
+
reject(new Error('Timeout waiting for Frigg to start'))
|
|
184
|
+
}, 30000) // 30 second timeout
|
|
185
|
+
|
|
186
|
+
const checkStarted = () => {
|
|
187
|
+
if (this.status === 'running') {
|
|
188
|
+
clearTimeout(timeout)
|
|
189
|
+
resolve(this.getStatus())
|
|
190
|
+
} else if (this.status === 'stopped') {
|
|
191
|
+
clearTimeout(timeout)
|
|
192
|
+
reject(new Error('Failed to start Frigg'))
|
|
193
|
+
} else {
|
|
194
|
+
setTimeout(checkStarted, 100)
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
checkStarted()
|
|
199
|
+
})
|
|
200
|
+
|
|
201
|
+
} catch (error) {
|
|
202
|
+
this.addLog('system', `Failed to start: ${error.message}`)
|
|
203
|
+
this.notifyListeners('stopped', { error: error.message })
|
|
204
|
+
this.cleanup()
|
|
205
|
+
throw error
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
// Stop Frigg process
|
|
210
|
+
async stop(force = false) {
|
|
211
|
+
if (this.status === 'stopped') {
|
|
212
|
+
throw new Error('Frigg is already stopped')
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
return new Promise((resolve) => {
|
|
216
|
+
if (!this.process) {
|
|
217
|
+
this.notifyListeners('stopped')
|
|
218
|
+
resolve()
|
|
219
|
+
return
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
this.addLog('system', force ? 'Force stopping Frigg server...' : 'Stopping Frigg server...')
|
|
223
|
+
this.notifyListeners('stopping')
|
|
224
|
+
|
|
225
|
+
// Set up cleanup timeout
|
|
226
|
+
const timeout = setTimeout(() => {
|
|
227
|
+
if (this.process && !this.process.killed) {
|
|
228
|
+
this.addLog('system', 'Force killing process after timeout')
|
|
229
|
+
this.process.kill('SIGKILL')
|
|
230
|
+
}
|
|
231
|
+
}, 5000) // 5 second timeout for graceful shutdown
|
|
232
|
+
|
|
233
|
+
// Listen for process to actually exit
|
|
234
|
+
const onClose = () => {
|
|
235
|
+
clearTimeout(timeout)
|
|
236
|
+
resolve()
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
if (this.process.exitCode !== null || this.process.killed) {
|
|
240
|
+
// Process already exited
|
|
241
|
+
onClose()
|
|
242
|
+
} else {
|
|
243
|
+
this.process.once('close', onClose)
|
|
244
|
+
|
|
245
|
+
// Send termination signal
|
|
246
|
+
if (force) {
|
|
247
|
+
this.process.kill('SIGKILL')
|
|
248
|
+
} else {
|
|
249
|
+
this.process.kill('SIGTERM')
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
})
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
// Restart Frigg process
|
|
256
|
+
async restart(options = {}) {
|
|
257
|
+
this.addLog('system', 'Restarting Frigg server...')
|
|
258
|
+
|
|
259
|
+
if (this.status !== 'stopped') {
|
|
260
|
+
await this.stop()
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
// Wait a bit before restarting
|
|
264
|
+
await new Promise(resolve => setTimeout(resolve, 1000))
|
|
265
|
+
|
|
266
|
+
return this.start(options)
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
// Clean up process references
|
|
270
|
+
cleanup() {
|
|
271
|
+
if (this.process) {
|
|
272
|
+
this.process.removeAllListeners()
|
|
273
|
+
this.process = null
|
|
274
|
+
}
|
|
275
|
+
this.startTime = null
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
// Get process metrics
|
|
279
|
+
getMetrics() {
|
|
280
|
+
if (!this.process || this.status !== 'running') {
|
|
281
|
+
return null
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
return {
|
|
285
|
+
pid: this.process.pid,
|
|
286
|
+
uptime: Date.now() - this.startTime,
|
|
287
|
+
memoryUsage: process.memoryUsage(), // This is the manager's memory, not the child's
|
|
288
|
+
status: this.status
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
// Create singleton instance
|
|
294
|
+
const processManager = new FriggProcessManager()
|
|
295
|
+
|
|
296
|
+
export default processManager
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
import express from 'express'
|
|
2
|
+
import { createServer } from 'http'
|
|
3
|
+
import { Server } from 'socket.io'
|
|
4
|
+
import cors from 'cors'
|
|
5
|
+
import path from 'path'
|
|
6
|
+
import { fileURLToPath } from 'url'
|
|
7
|
+
|
|
8
|
+
// Import middleware and utilities
|
|
9
|
+
import { errorHandler } from './middleware/errorHandler.js'
|
|
10
|
+
import { createStandardResponse } from './utils/response.js'
|
|
11
|
+
import { setupWebSocket } from './websocket/handler.js'
|
|
12
|
+
import { addLogEntry, LOG_LEVELS } from './api/logs.js'
|
|
13
|
+
|
|
14
|
+
// Import API routes
|
|
15
|
+
import projectRouter from './api/project.js'
|
|
16
|
+
import integrationsRouter from './api/integrations.js'
|
|
17
|
+
import environmentRouter from './api/environment.js'
|
|
18
|
+
import usersRouter from './api/users.js'
|
|
19
|
+
import connectionsRouter from './api/connections.js'
|
|
20
|
+
import cliRouter from './api/cli.js'
|
|
21
|
+
import logsRouter from './api/logs.js'
|
|
22
|
+
import codegenRouter from './api/codegen.js'
|
|
23
|
+
import discoveryRouter from './api/discovery.js'
|
|
24
|
+
import monitoringRouter from './api/monitoring.js'
|
|
25
|
+
import openIdeHandler from './api/open-ide.js'
|
|
26
|
+
|
|
27
|
+
const __filename = fileURLToPath(import.meta.url)
|
|
28
|
+
const __dirname = path.dirname(__filename)
|
|
29
|
+
|
|
30
|
+
const app = express()
|
|
31
|
+
const httpServer = createServer(app)
|
|
32
|
+
const io = new Server(httpServer, {
|
|
33
|
+
cors: {
|
|
34
|
+
origin: ["http://localhost:5173", "http://localhost:3000"],
|
|
35
|
+
methods: ["GET", "POST", "PUT", "DELETE"],
|
|
36
|
+
credentials: true
|
|
37
|
+
}
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
// Store io instance in app for route access
|
|
41
|
+
app.set('io', io)
|
|
42
|
+
|
|
43
|
+
// Middleware
|
|
44
|
+
app.use(cors({
|
|
45
|
+
origin: ["http://localhost:5173", "http://localhost:3000"],
|
|
46
|
+
credentials: true
|
|
47
|
+
}))
|
|
48
|
+
app.use(express.json({ limit: '10mb' }))
|
|
49
|
+
app.use(express.urlencoded({ extended: true }))
|
|
50
|
+
|
|
51
|
+
// Request logging middleware
|
|
52
|
+
app.use((req, res, next) => {
|
|
53
|
+
const timestamp = new Date().toISOString()
|
|
54
|
+
console.log(`${timestamp} - ${req.method} ${req.path}`)
|
|
55
|
+
|
|
56
|
+
// Log API requests
|
|
57
|
+
addLogEntry(LOG_LEVELS.INFO, `${req.method} ${req.path}`, 'api', {
|
|
58
|
+
method: req.method,
|
|
59
|
+
path: req.path,
|
|
60
|
+
query: req.query,
|
|
61
|
+
userAgent: req.get('User-Agent')
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
next()
|
|
65
|
+
})
|
|
66
|
+
|
|
67
|
+
// Setup WebSocket handling
|
|
68
|
+
setupWebSocket(io)
|
|
69
|
+
|
|
70
|
+
// Health check endpoint
|
|
71
|
+
app.get('/health', (req, res) => {
|
|
72
|
+
res.json(createStandardResponse({
|
|
73
|
+
status: 'healthy',
|
|
74
|
+
timestamp: new Date().toISOString(),
|
|
75
|
+
uptime: process.uptime(),
|
|
76
|
+
version: process.env.npm_package_version || '1.0.0'
|
|
77
|
+
}))
|
|
78
|
+
})
|
|
79
|
+
|
|
80
|
+
// Get initial repository info
|
|
81
|
+
app.get('/api/repository/current', (req, res) => {
|
|
82
|
+
const repoInfo = process.env.REPOSITORY_INFO ?
|
|
83
|
+
JSON.parse(process.env.REPOSITORY_INFO) :
|
|
84
|
+
null
|
|
85
|
+
res.json(createStandardResponse({ repository: repoInfo }))
|
|
86
|
+
})
|
|
87
|
+
// API endpoints
|
|
88
|
+
app.use('/api/project', projectRouter)
|
|
89
|
+
app.use('/api/integrations', integrationsRouter)
|
|
90
|
+
app.use('/api/environment', environmentRouter)
|
|
91
|
+
app.use('/api/users', usersRouter)
|
|
92
|
+
app.use('/api/connections', connectionsRouter)
|
|
93
|
+
app.use('/api/cli', cliRouter)
|
|
94
|
+
app.use('/api/logs', logsRouter)
|
|
95
|
+
app.use('/api/monitoring', monitoringRouter)
|
|
96
|
+
app.use('/api/codegen', codegenRouter)
|
|
97
|
+
app.use('/api/discovery', discoveryRouter)
|
|
98
|
+
app.post('/api/open-in-ide', openIdeHandler)
|
|
99
|
+
|
|
100
|
+
// API documentation endpoint
|
|
101
|
+
app.get('/api', (req, res) => {
|
|
102
|
+
res.json(createStandardResponse({
|
|
103
|
+
name: 'Frigg Management UI API',
|
|
104
|
+
version: '1.0.0',
|
|
105
|
+
description: 'REST API for Frigg CLI-GUI communication',
|
|
106
|
+
endpoints: {
|
|
107
|
+
project: '/api/project',
|
|
108
|
+
integrations: '/api/integrations',
|
|
109
|
+
environment: '/api/environment',
|
|
110
|
+
users: '/api/users',
|
|
111
|
+
connections: '/api/connections',
|
|
112
|
+
cli: '/api/cli',
|
|
113
|
+
logs: '/api/logs',
|
|
114
|
+
monitoring: '/api/monitoring',
|
|
115
|
+
codegen: '/api/codegen'
|
|
116
|
+
},
|
|
117
|
+
websocket: {
|
|
118
|
+
url: 'ws://localhost:3001',
|
|
119
|
+
events: [
|
|
120
|
+
'project:status',
|
|
121
|
+
'project:logs',
|
|
122
|
+
'integrations:update',
|
|
123
|
+
'environment:update',
|
|
124
|
+
'cli:output',
|
|
125
|
+
'cli:complete',
|
|
126
|
+
'logs:new',
|
|
127
|
+
'monitoring:metrics',
|
|
128
|
+
'monitoring:error'
|
|
129
|
+
]
|
|
130
|
+
},
|
|
131
|
+
documentation: '/api-contract.md'
|
|
132
|
+
}))
|
|
133
|
+
})
|
|
134
|
+
|
|
135
|
+
// Serve static files in production
|
|
136
|
+
if (process.env.NODE_ENV === 'production') {
|
|
137
|
+
app.use(express.static(path.join(__dirname, '../dist')))
|
|
138
|
+
app.get('*', (req, res) => {
|
|
139
|
+
res.sendFile(path.join(__dirname, '../dist/index.html'))
|
|
140
|
+
})
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// 404 handler for API routes
|
|
144
|
+
app.use('/api/*', (req, res) => {
|
|
145
|
+
res.status(404).json(createStandardResponse(null, `API endpoint not found: ${req.path}`))
|
|
146
|
+
})
|
|
147
|
+
|
|
148
|
+
// Error handling middleware (must be last)
|
|
149
|
+
app.use(errorHandler)
|
|
150
|
+
|
|
151
|
+
// Start server
|
|
152
|
+
const PORT = process.env.PORT || 3001
|
|
153
|
+
httpServer.listen(PORT, () => {
|
|
154
|
+
console.log(`🚀 Frigg Management UI server running on port ${PORT}`)
|
|
155
|
+
console.log(`📡 WebSocket server ready for connections`)
|
|
156
|
+
console.log(`📚 API documentation: http://localhost:${PORT}/api`)
|
|
157
|
+
console.log(`🏥 Health check: http://localhost:${PORT}/health`)
|
|
158
|
+
|
|
159
|
+
// Log server startup
|
|
160
|
+
addLogEntry(LOG_LEVELS.INFO, `Server started on port ${PORT}`, 'server', {
|
|
161
|
+
port: PORT,
|
|
162
|
+
nodeVersion: process.version,
|
|
163
|
+
environment: process.env.NODE_ENV || 'development'
|
|
164
|
+
})
|
|
165
|
+
})
|
|
166
|
+
|
|
167
|
+
// Graceful shutdown
|
|
168
|
+
process.on('SIGTERM', () => {
|
|
169
|
+
console.log('SIGTERM received, shutting down gracefully...')
|
|
170
|
+
addLogEntry(LOG_LEVELS.INFO, 'Server shutting down gracefully', 'server')
|
|
171
|
+
|
|
172
|
+
httpServer.close(() => {
|
|
173
|
+
console.log('Server closed')
|
|
174
|
+
process.exit(0)
|
|
175
|
+
})
|
|
176
|
+
})
|
|
177
|
+
|
|
178
|
+
process.on('SIGINT', () => {
|
|
179
|
+
console.log('SIGINT received, shutting down gracefully...')
|
|
180
|
+
addLogEntry(LOG_LEVELS.INFO, 'Server interrupted, shutting down', 'server')
|
|
181
|
+
|
|
182
|
+
httpServer.close(() => {
|
|
183
|
+
console.log('Server closed')
|
|
184
|
+
process.exit(0)
|
|
185
|
+
})
|
|
186
|
+
})
|
|
187
|
+
|
|
188
|
+
export default app
|