@friggframework/devtools 2.0.0-next.4 → 2.0.0-next.40
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 +54 -0
- package/frigg-cli/deploy-command/index.js +175 -0
- 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 +332 -0
- package/frigg-cli/generate-command/terraform-generator.js +555 -0
- package/frigg-cli/generate-iam-command.js +115 -0
- package/frigg-cli/index.js +47 -1
- package/frigg-cli/index.test.js +1 -4
- package/frigg-cli/init-command/backend-first-handler.js +756 -0
- package/frigg-cli/init-command/index.js +93 -0
- package/frigg-cli/init-command/template-handler.js +143 -0
- package/frigg-cli/install-command/index.js +1 -4
- package/frigg-cli/package.json +51 -0
- package/frigg-cli/start-command/index.js +24 -4
- package/frigg-cli/test/init-command.test.js +180 -0
- package/frigg-cli/test/npm-registry.test.js +319 -0
- package/frigg-cli/ui-command/index.js +154 -0
- package/frigg-cli/utils/app-resolver.js +319 -0
- package/frigg-cli/utils/backend-path.js +16 -17
- package/frigg-cli/utils/npm-registry.js +167 -0
- package/frigg-cli/utils/process-manager.js +199 -0
- package/frigg-cli/utils/repo-detection.js +405 -0
- package/infrastructure/DEPLOYMENT-INSTRUCTIONS.md +268 -0
- package/infrastructure/GENERATE-IAM-DOCS.md +278 -0
- package/infrastructure/IAM-POLICY-TEMPLATES.md +176 -0
- package/infrastructure/README.md +443 -0
- package/infrastructure/WEBSOCKET-CONFIGURATION.md +105 -0
- package/infrastructure/__tests__/fixtures/mock-aws-resources.js +391 -0
- package/infrastructure/__tests__/helpers/test-utils.js +277 -0
- package/infrastructure/aws-discovery.js +1176 -0
- package/infrastructure/aws-discovery.test.js +1220 -0
- package/infrastructure/build-time-discovery.js +206 -0
- package/infrastructure/build-time-discovery.test.js +378 -0
- package/infrastructure/create-frigg-infrastructure.js +3 -5
- package/infrastructure/env-validator.js +77 -0
- package/infrastructure/frigg-deployment-iam-stack.yaml +401 -0
- package/infrastructure/iam-generator.js +836 -0
- package/infrastructure/iam-generator.test.js +172 -0
- package/infrastructure/iam-policy-basic.json +218 -0
- package/infrastructure/iam-policy-full.json +288 -0
- package/infrastructure/integration.test.js +383 -0
- package/infrastructure/run-discovery.js +110 -0
- package/infrastructure/serverless-template.js +1472 -138
- package/infrastructure/serverless-template.test.js +1759 -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/docs/phase2-integration-guide.md +320 -0
- package/management-ui/index.html +13 -0
- package/management-ui/package-lock.json +16517 -0
- package/management-ui/package.json +76 -0
- package/management-ui/packages/devtools/frigg-cli/ui-command/index.js +302 -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 +876 -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 +1029 -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 +873 -0
- package/management-ui/server/middleware/errorHandler.js +93 -0
- package/management-ui/server/middleware/security.js +32 -0
- package/management-ui/server/processManager.js +296 -0
- package/management-ui/server/server.js +346 -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 +109 -0
- package/management-ui/src/assets/FriggLogo.svg +1 -0
- package/management-ui/src/components/AppRouter.jsx +65 -0
- package/management-ui/src/components/Button.jsx +70 -0
- package/management-ui/src/components/Card.jsx +97 -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 +481 -0
- package/management-ui/src/components/IntegrationCardEnhanced.jsx +770 -0
- package/management-ui/src/components/IntegrationExplorer.jsx +379 -0
- package/management-ui/src/components/IntegrationStatus.jsx +336 -0
- package/management-ui/src/components/Layout.jsx +716 -0
- package/management-ui/src/components/LoadingSpinner.jsx +113 -0
- package/management-ui/src/components/RepositoryPicker.jsx +248 -0
- package/management-ui/src/components/SessionMonitor.jsx +350 -0
- package/management-ui/src/components/StatusBadge.jsx +208 -0
- package/management-ui/src/components/UserContextSwitcher.jsx +212 -0
- package/management-ui/src/components/UserSimulation.jsx +327 -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 +601 -0
- package/management-ui/src/hooks/useSocket.jsx +58 -0
- package/management-ui/src/index.css +193 -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 +633 -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 +669 -0
- package/management-ui/src/pages/IntegrationDiscovery.jsx +567 -0
- package/management-ui/src/pages/IntegrationTest.jsx +742 -0
- package/management-ui/src/pages/Integrations.jsx +253 -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 +20 -9
- package/infrastructure/app-handler-helpers.js +0 -57
- package/infrastructure/backend-utils.js +0 -90
- package/infrastructure/routers/auth.js +0 -26
- package/infrastructure/routers/integration-defined-routers.js +0 -37
- package/infrastructure/routers/middleware/loadUser.js +0 -15
- package/infrastructure/routers/middleware/requireLoggedInUser.js +0 -12
- package/infrastructure/routers/user.js +0 -41
- package/infrastructure/routers/websocket.js +0 -55
- package/infrastructure/workers/integration-defined-workers.js +0 -24
|
@@ -0,0 +1,328 @@
|
|
|
1
|
+
import express from 'express'
|
|
2
|
+
import path from 'path'
|
|
3
|
+
import fs from 'fs-extra'
|
|
4
|
+
import { createStandardResponse, createErrorResponse, ERROR_CODES, asyncHandler } from '../utils/response.js'
|
|
5
|
+
import { wsHandler } from '../websocket/handler.js'
|
|
6
|
+
|
|
7
|
+
const router = express.Router();
|
|
8
|
+
|
|
9
|
+
// Helper to get .env file path
|
|
10
|
+
async function getEnvFilePath() {
|
|
11
|
+
const possiblePaths = [
|
|
12
|
+
path.join(process.cwd(), '../../../backend/.env'),
|
|
13
|
+
path.join(process.cwd(), '../../backend/.env'),
|
|
14
|
+
path.join(process.cwd(), 'backend/.env'),
|
|
15
|
+
path.join(process.cwd(), '.env')
|
|
16
|
+
];
|
|
17
|
+
|
|
18
|
+
for (const envPath of possiblePaths) {
|
|
19
|
+
if (await fs.pathExists(envPath)) {
|
|
20
|
+
return envPath;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// If no .env exists, create one in the most likely location
|
|
25
|
+
const defaultPath = possiblePaths[0];
|
|
26
|
+
await fs.ensureFile(defaultPath);
|
|
27
|
+
return defaultPath;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// Parse .env file content
|
|
31
|
+
function parseEnvFile(content) {
|
|
32
|
+
const lines = content.split('\n');
|
|
33
|
+
const variables = [];
|
|
34
|
+
|
|
35
|
+
lines.forEach((line, index) => {
|
|
36
|
+
const trimmedLine = line.trim();
|
|
37
|
+
|
|
38
|
+
// Skip empty lines and comments
|
|
39
|
+
if (!trimmedLine || trimmedLine.startsWith('#')) {
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const equalIndex = trimmedLine.indexOf('=');
|
|
44
|
+
if (equalIndex > 0) {
|
|
45
|
+
const key = trimmedLine.substring(0, equalIndex).trim();
|
|
46
|
+
const value = trimmedLine.substring(equalIndex + 1).trim();
|
|
47
|
+
|
|
48
|
+
variables.push({
|
|
49
|
+
key,
|
|
50
|
+
value: value.replace(/^["']|["']$/g, ''), // Remove quotes
|
|
51
|
+
line: index + 1
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
return variables;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// Build .env file content from variables
|
|
60
|
+
function buildEnvContent(variables) {
|
|
61
|
+
return variables
|
|
62
|
+
.map(({ key, value }) => {
|
|
63
|
+
// Add quotes if value contains spaces or special characters
|
|
64
|
+
if (value && (value.includes(' ') || value.includes('#'))) {
|
|
65
|
+
return `${key}="${value}"`;
|
|
66
|
+
}
|
|
67
|
+
return `${key}=${value}`;
|
|
68
|
+
})
|
|
69
|
+
.join('\n');
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// Get all environment variables
|
|
73
|
+
router.get('/', async (req, res) => {
|
|
74
|
+
try {
|
|
75
|
+
const envPath = await getEnvFilePath();
|
|
76
|
+
const content = await fs.readFile(envPath, 'utf8');
|
|
77
|
+
const variables = parseEnvFile(content);
|
|
78
|
+
|
|
79
|
+
// Mask sensitive values
|
|
80
|
+
const maskedVariables = variables.map(variable => {
|
|
81
|
+
const isSensitive = [
|
|
82
|
+
'KEY', 'SECRET', 'PASSWORD', 'TOKEN', 'API', 'PRIVATE'
|
|
83
|
+
].some(keyword => variable.key.toUpperCase().includes(keyword));
|
|
84
|
+
|
|
85
|
+
return {
|
|
86
|
+
...variable,
|
|
87
|
+
value: isSensitive ? '***' : variable.value,
|
|
88
|
+
masked: isSensitive
|
|
89
|
+
};
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
res.json({
|
|
93
|
+
variables: maskedVariables,
|
|
94
|
+
path: envPath
|
|
95
|
+
});
|
|
96
|
+
} catch (error) {
|
|
97
|
+
res.status(500).json({
|
|
98
|
+
error: error.message,
|
|
99
|
+
details: 'Failed to read environment variables'
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
// Get specific environment variable
|
|
105
|
+
router.get('/:key', async (req, res) => {
|
|
106
|
+
const { key } = req.params;
|
|
107
|
+
|
|
108
|
+
try {
|
|
109
|
+
const envPath = await getEnvFilePath();
|
|
110
|
+
const content = await fs.readFile(envPath, 'utf8');
|
|
111
|
+
const variables = parseEnvFile(content);
|
|
112
|
+
|
|
113
|
+
const variable = variables.find(v => v.key === key);
|
|
114
|
+
|
|
115
|
+
if (!variable) {
|
|
116
|
+
return res.status(404).json({
|
|
117
|
+
error: `Environment variable ${key} not found`
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// Check if it's sensitive
|
|
122
|
+
const isSensitive = [
|
|
123
|
+
'KEY', 'SECRET', 'PASSWORD', 'TOKEN', 'API', 'PRIVATE'
|
|
124
|
+
].some(keyword => key.toUpperCase().includes(keyword));
|
|
125
|
+
|
|
126
|
+
res.json({
|
|
127
|
+
key: variable.key,
|
|
128
|
+
value: isSensitive ? '***' : variable.value,
|
|
129
|
+
masked: isSensitive
|
|
130
|
+
});
|
|
131
|
+
} catch (error) {
|
|
132
|
+
res.status(500).json({
|
|
133
|
+
error: error.message,
|
|
134
|
+
details: 'Failed to read environment variable'
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
// Set environment variable
|
|
140
|
+
router.post('/', async (req, res) => {
|
|
141
|
+
const { key, value } = req.body;
|
|
142
|
+
|
|
143
|
+
if (!key) {
|
|
144
|
+
return res.status(400).json({
|
|
145
|
+
error: 'Key is required'
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
try {
|
|
150
|
+
const envPath = await getEnvFilePath();
|
|
151
|
+
const content = await fs.readFile(envPath, 'utf8');
|
|
152
|
+
const variables = parseEnvFile(content);
|
|
153
|
+
|
|
154
|
+
// Check if variable exists
|
|
155
|
+
const existingIndex = variables.findIndex(v => v.key === key);
|
|
156
|
+
|
|
157
|
+
if (existingIndex >= 0) {
|
|
158
|
+
variables[existingIndex].value = value;
|
|
159
|
+
} else {
|
|
160
|
+
variables.push({ key, value });
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// Write back to file
|
|
164
|
+
const newContent = buildEnvContent(variables);
|
|
165
|
+
await fs.writeFile(envPath, newContent);
|
|
166
|
+
|
|
167
|
+
// Broadcast update
|
|
168
|
+
wsHandler.broadcast('env-update', {
|
|
169
|
+
action: existingIndex >= 0 ? 'updated' : 'created',
|
|
170
|
+
key,
|
|
171
|
+
timestamp: new Date().toISOString()
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
res.json({
|
|
175
|
+
status: 'success',
|
|
176
|
+
message: `Environment variable ${key} ${existingIndex >= 0 ? 'updated' : 'created'}`,
|
|
177
|
+
key,
|
|
178
|
+
value: value.includes('SECRET') || value.includes('KEY') ? '***' : value
|
|
179
|
+
});
|
|
180
|
+
} catch (error) {
|
|
181
|
+
res.status(500).json({
|
|
182
|
+
error: error.message,
|
|
183
|
+
details: 'Failed to set environment variable'
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
// Update multiple environment variables
|
|
189
|
+
router.put('/batch', async (req, res) => {
|
|
190
|
+
const { variables } = req.body;
|
|
191
|
+
|
|
192
|
+
if (!Array.isArray(variables)) {
|
|
193
|
+
return res.status(400).json({
|
|
194
|
+
error: 'Variables must be an array'
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
try {
|
|
199
|
+
const envPath = await getEnvFilePath();
|
|
200
|
+
const content = await fs.readFile(envPath, 'utf8');
|
|
201
|
+
const existingVariables = parseEnvFile(content);
|
|
202
|
+
|
|
203
|
+
// Update or add variables
|
|
204
|
+
variables.forEach(({ key, value }) => {
|
|
205
|
+
const existingIndex = existingVariables.findIndex(v => v.key === key);
|
|
206
|
+
|
|
207
|
+
if (existingIndex >= 0) {
|
|
208
|
+
existingVariables[existingIndex].value = value;
|
|
209
|
+
} else {
|
|
210
|
+
existingVariables.push({ key, value });
|
|
211
|
+
}
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
// Write back to file
|
|
215
|
+
const newContent = buildEnvContent(existingVariables);
|
|
216
|
+
await fs.writeFile(envPath, newContent);
|
|
217
|
+
|
|
218
|
+
// Broadcast update
|
|
219
|
+
wsHandler.broadcast('env-update', {
|
|
220
|
+
action: 'batch-update',
|
|
221
|
+
count: variables.length,
|
|
222
|
+
timestamp: new Date().toISOString()
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
res.json({
|
|
226
|
+
status: 'success',
|
|
227
|
+
message: `Updated ${variables.length} environment variables`,
|
|
228
|
+
updated: variables.length
|
|
229
|
+
});
|
|
230
|
+
} catch (error) {
|
|
231
|
+
res.status(500).json({
|
|
232
|
+
error: error.message,
|
|
233
|
+
details: 'Failed to update environment variables'
|
|
234
|
+
});
|
|
235
|
+
}
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
// Delete environment variable
|
|
239
|
+
router.delete('/:key', async (req, res) => {
|
|
240
|
+
const { key } = req.params;
|
|
241
|
+
|
|
242
|
+
try {
|
|
243
|
+
const envPath = await getEnvFilePath();
|
|
244
|
+
const content = await fs.readFile(envPath, 'utf8');
|
|
245
|
+
const variables = parseEnvFile(content);
|
|
246
|
+
|
|
247
|
+
const filteredVariables = variables.filter(v => v.key !== key);
|
|
248
|
+
|
|
249
|
+
if (filteredVariables.length === variables.length) {
|
|
250
|
+
return res.status(404).json({
|
|
251
|
+
error: `Environment variable ${key} not found`
|
|
252
|
+
});
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
// Write back to file
|
|
256
|
+
const newContent = buildEnvContent(filteredVariables);
|
|
257
|
+
await fs.writeFile(envPath, newContent);
|
|
258
|
+
|
|
259
|
+
// Broadcast update
|
|
260
|
+
wsHandler.broadcast('env-update', {
|
|
261
|
+
action: 'deleted',
|
|
262
|
+
key,
|
|
263
|
+
timestamp: new Date().toISOString()
|
|
264
|
+
});
|
|
265
|
+
|
|
266
|
+
res.json({
|
|
267
|
+
status: 'success',
|
|
268
|
+
message: `Environment variable ${key} deleted`
|
|
269
|
+
});
|
|
270
|
+
} catch (error) {
|
|
271
|
+
res.status(500).json({
|
|
272
|
+
error: error.message,
|
|
273
|
+
details: 'Failed to delete environment variable'
|
|
274
|
+
});
|
|
275
|
+
}
|
|
276
|
+
});
|
|
277
|
+
|
|
278
|
+
// Validate environment variables
|
|
279
|
+
router.post('/validate', async (req, res) => {
|
|
280
|
+
try {
|
|
281
|
+
const envPath = await getEnvFilePath();
|
|
282
|
+
const content = await fs.readFile(envPath, 'utf8');
|
|
283
|
+
const variables = parseEnvFile(content);
|
|
284
|
+
|
|
285
|
+
const issues = [];
|
|
286
|
+
|
|
287
|
+
// Check for required variables
|
|
288
|
+
const requiredVars = [
|
|
289
|
+
'DATABASE_URL',
|
|
290
|
+
'JWT_SECRET',
|
|
291
|
+
'NODE_ENV'
|
|
292
|
+
];
|
|
293
|
+
|
|
294
|
+
requiredVars.forEach(reqVar => {
|
|
295
|
+
if (!variables.find(v => v.key === reqVar)) {
|
|
296
|
+
issues.push({
|
|
297
|
+
type: 'missing',
|
|
298
|
+
key: reqVar,
|
|
299
|
+
message: `Required variable ${reqVar} is missing`
|
|
300
|
+
});
|
|
301
|
+
}
|
|
302
|
+
});
|
|
303
|
+
|
|
304
|
+
// Check for empty values
|
|
305
|
+
variables.forEach(variable => {
|
|
306
|
+
if (!variable.value || variable.value.trim() === '') {
|
|
307
|
+
issues.push({
|
|
308
|
+
type: 'empty',
|
|
309
|
+
key: variable.key,
|
|
310
|
+
message: `Variable ${variable.key} has an empty value`
|
|
311
|
+
});
|
|
312
|
+
}
|
|
313
|
+
});
|
|
314
|
+
|
|
315
|
+
res.json({
|
|
316
|
+
valid: issues.length === 0,
|
|
317
|
+
issues,
|
|
318
|
+
totalVariables: variables.length
|
|
319
|
+
});
|
|
320
|
+
} catch (error) {
|
|
321
|
+
res.status(500).json({
|
|
322
|
+
error: error.message,
|
|
323
|
+
details: 'Failed to validate environment variables'
|
|
324
|
+
});
|
|
325
|
+
}
|
|
326
|
+
});
|
|
327
|
+
|
|
328
|
+
export default router
|