@friggframework/devtools 2.0.0-next.4 → 2.0.0-next.41
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 +30 -4
- package/frigg-cli/start-command/start-command.test.js +155 -0
- 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 +1493 -138
- package/infrastructure/serverless-template.test.js +1804 -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,663 @@
|
|
|
1
|
+
import express from 'express';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import fs from 'fs-extra';
|
|
4
|
+
import TemplateEngine from '../services/template-engine.js';
|
|
5
|
+
import npmRegistry from '../services/npm-registry.js';
|
|
6
|
+
|
|
7
|
+
const router = express.Router();
|
|
8
|
+
const templateEngine = new TemplateEngine();
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Generate code from various types of configurations
|
|
12
|
+
*/
|
|
13
|
+
router.post('/generate', async (req, res) => {
|
|
14
|
+
try {
|
|
15
|
+
const { type, code, metadata, config } = req.body;
|
|
16
|
+
|
|
17
|
+
if (!type) {
|
|
18
|
+
return res.status(400).json({
|
|
19
|
+
error: 'Generation type is required',
|
|
20
|
+
validTypes: ['integration', 'api-endpoint', 'project-scaffold', 'custom']
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
let result;
|
|
25
|
+
|
|
26
|
+
switch (type) {
|
|
27
|
+
case 'integration':
|
|
28
|
+
result = await generateIntegration(config, req);
|
|
29
|
+
break;
|
|
30
|
+
case 'api-endpoint':
|
|
31
|
+
result = await generateAPIEndpoints(config, req);
|
|
32
|
+
break;
|
|
33
|
+
case 'project-scaffold':
|
|
34
|
+
result = await generateProjectScaffold(config, req);
|
|
35
|
+
break;
|
|
36
|
+
case 'custom':
|
|
37
|
+
result = await generateCustomCode(code, metadata, req);
|
|
38
|
+
break;
|
|
39
|
+
default:
|
|
40
|
+
return res.status(400).json({
|
|
41
|
+
error: `Unknown generation type: ${type}`,
|
|
42
|
+
validTypes: ['integration', 'api-endpoint', 'project-scaffold', 'custom']
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
res.json(result);
|
|
47
|
+
} catch (error) {
|
|
48
|
+
console.error('Code generation error:', error);
|
|
49
|
+
res.status(500).json({
|
|
50
|
+
error: 'Code generation failed',
|
|
51
|
+
message: error.message
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Get available templates
|
|
58
|
+
*/
|
|
59
|
+
router.get('/templates', async (req, res) => {
|
|
60
|
+
try {
|
|
61
|
+
const templates = await getAvailableTemplates();
|
|
62
|
+
res.json(templates);
|
|
63
|
+
} catch (error) {
|
|
64
|
+
console.error('Error fetching templates:', error);
|
|
65
|
+
res.status(500).json({
|
|
66
|
+
error: 'Failed to fetch templates',
|
|
67
|
+
message: error.message
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Preview generated code without writing files
|
|
74
|
+
*/
|
|
75
|
+
router.post('/preview', async (req, res) => {
|
|
76
|
+
try {
|
|
77
|
+
const { type, config } = req.body;
|
|
78
|
+
|
|
79
|
+
let result;
|
|
80
|
+
|
|
81
|
+
switch (type) {
|
|
82
|
+
case 'integration':
|
|
83
|
+
result = templateEngine.generateIntegration(config);
|
|
84
|
+
break;
|
|
85
|
+
case 'api-endpoint':
|
|
86
|
+
result = templateEngine.generateAPIEndpoints(config);
|
|
87
|
+
break;
|
|
88
|
+
case 'project-scaffold':
|
|
89
|
+
result = templateEngine.generateProjectScaffold(config);
|
|
90
|
+
break;
|
|
91
|
+
default:
|
|
92
|
+
return res.status(400).json({
|
|
93
|
+
error: `Preview not available for type: ${type}`
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// Return only file contents for preview
|
|
98
|
+
res.json({
|
|
99
|
+
files: result.files.map(file => ({
|
|
100
|
+
name: file.name,
|
|
101
|
+
content: file.content,
|
|
102
|
+
size: file.content.length
|
|
103
|
+
})),
|
|
104
|
+
metadata: result.metadata
|
|
105
|
+
});
|
|
106
|
+
} catch (error) {
|
|
107
|
+
console.error('Code preview error:', error);
|
|
108
|
+
res.status(500).json({
|
|
109
|
+
error: 'Code preview failed',
|
|
110
|
+
message: error.message
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Validate configuration before generation
|
|
117
|
+
*/
|
|
118
|
+
router.post('/validate', async (req, res) => {
|
|
119
|
+
try {
|
|
120
|
+
const { type, config } = req.body;
|
|
121
|
+
const errors = validateConfiguration(type, config);
|
|
122
|
+
|
|
123
|
+
res.json({
|
|
124
|
+
valid: errors.length === 0,
|
|
125
|
+
errors
|
|
126
|
+
});
|
|
127
|
+
} catch (error) {
|
|
128
|
+
console.error('Validation error:', error);
|
|
129
|
+
res.status(500).json({
|
|
130
|
+
error: 'Validation failed',
|
|
131
|
+
message: error.message
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Get CLI status and capabilities
|
|
138
|
+
*/
|
|
139
|
+
router.get('/cli-status', async (req, res) => {
|
|
140
|
+
try {
|
|
141
|
+
const status = await getCLIStatus();
|
|
142
|
+
res.json(status);
|
|
143
|
+
} catch (error) {
|
|
144
|
+
console.error('CLI status error:', error);
|
|
145
|
+
res.status(500).json({
|
|
146
|
+
error: 'Failed to get CLI status',
|
|
147
|
+
message: error.message
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Execute CLI command
|
|
154
|
+
*/
|
|
155
|
+
router.post('/cli-execute', async (req, res) => {
|
|
156
|
+
try {
|
|
157
|
+
const { command, args, workingDirectory } = req.body;
|
|
158
|
+
|
|
159
|
+
if (!command) {
|
|
160
|
+
return res.status(400).json({
|
|
161
|
+
error: 'Command is required'
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
const result = await templateEngine.executeFriggCommand(
|
|
166
|
+
command,
|
|
167
|
+
args || [],
|
|
168
|
+
workingDirectory || process.cwd()
|
|
169
|
+
);
|
|
170
|
+
|
|
171
|
+
res.json({
|
|
172
|
+
success: true,
|
|
173
|
+
output: result.stdout,
|
|
174
|
+
error: result.stderr,
|
|
175
|
+
exitCode: result.code
|
|
176
|
+
});
|
|
177
|
+
} catch (error) {
|
|
178
|
+
console.error('CLI execution error:', error);
|
|
179
|
+
res.status(500).json({
|
|
180
|
+
error: 'CLI command failed',
|
|
181
|
+
message: error.message
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Get available Frigg API modules from NPM
|
|
188
|
+
*/
|
|
189
|
+
router.get('/npm/modules', async (req, res) => {
|
|
190
|
+
try {
|
|
191
|
+
const { includePrerelease, forceRefresh } = req.query;
|
|
192
|
+
|
|
193
|
+
const modules = await npmRegistry.searchApiModules({
|
|
194
|
+
includePrerelease: includePrerelease === 'true',
|
|
195
|
+
forceRefresh: forceRefresh === 'true'
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
res.json({
|
|
199
|
+
success: true,
|
|
200
|
+
count: modules.length,
|
|
201
|
+
modules
|
|
202
|
+
});
|
|
203
|
+
} catch (error) {
|
|
204
|
+
console.error('NPM modules fetch error:', error);
|
|
205
|
+
res.status(500).json({
|
|
206
|
+
error: 'Failed to fetch NPM modules',
|
|
207
|
+
message: error.message
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Get modules grouped by type/category
|
|
214
|
+
*/
|
|
215
|
+
router.get('/npm/modules/grouped', async (req, res) => {
|
|
216
|
+
try {
|
|
217
|
+
const grouped = await npmRegistry.getModulesByType();
|
|
218
|
+
|
|
219
|
+
res.json({
|
|
220
|
+
success: true,
|
|
221
|
+
groups: Object.keys(grouped),
|
|
222
|
+
modules: grouped
|
|
223
|
+
});
|
|
224
|
+
} catch (error) {
|
|
225
|
+
console.error('NPM modules grouping error:', error);
|
|
226
|
+
res.status(500).json({
|
|
227
|
+
error: 'Failed to group NPM modules',
|
|
228
|
+
message: error.message
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* Get detailed information about a specific package
|
|
235
|
+
*/
|
|
236
|
+
router.get('/npm/modules/:packageName', async (req, res) => {
|
|
237
|
+
try {
|
|
238
|
+
const { packageName } = req.params;
|
|
239
|
+
const { version } = req.query;
|
|
240
|
+
|
|
241
|
+
// Validate package name format
|
|
242
|
+
if (!packageName.startsWith('@friggframework/api-module-')) {
|
|
243
|
+
return res.status(400).json({
|
|
244
|
+
error: 'Invalid package name',
|
|
245
|
+
message: 'Package name must start with @friggframework/api-module-'
|
|
246
|
+
});
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
const details = await npmRegistry.getPackageDetails(packageName, version || 'latest');
|
|
250
|
+
|
|
251
|
+
res.json({
|
|
252
|
+
success: true,
|
|
253
|
+
package: details
|
|
254
|
+
});
|
|
255
|
+
} catch (error) {
|
|
256
|
+
console.error('Package details error:', error);
|
|
257
|
+
res.status(500).json({
|
|
258
|
+
error: 'Failed to fetch package details',
|
|
259
|
+
message: error.message
|
|
260
|
+
});
|
|
261
|
+
}
|
|
262
|
+
});
|
|
263
|
+
|
|
264
|
+
/**
|
|
265
|
+
* Get all versions for a specific package
|
|
266
|
+
*/
|
|
267
|
+
router.get('/npm/modules/:packageName/versions', async (req, res) => {
|
|
268
|
+
try {
|
|
269
|
+
const { packageName } = req.params;
|
|
270
|
+
|
|
271
|
+
const versions = await npmRegistry.getPackageVersions(packageName);
|
|
272
|
+
|
|
273
|
+
res.json({
|
|
274
|
+
success: true,
|
|
275
|
+
count: versions.length,
|
|
276
|
+
versions
|
|
277
|
+
});
|
|
278
|
+
} catch (error) {
|
|
279
|
+
console.error('Package versions error:', error);
|
|
280
|
+
res.status(500).json({
|
|
281
|
+
error: 'Failed to fetch package versions',
|
|
282
|
+
message: error.message
|
|
283
|
+
});
|
|
284
|
+
}
|
|
285
|
+
});
|
|
286
|
+
|
|
287
|
+
/**
|
|
288
|
+
* Check compatibility between package and Frigg core
|
|
289
|
+
*/
|
|
290
|
+
router.post('/npm/compatibility', async (req, res) => {
|
|
291
|
+
try {
|
|
292
|
+
const { packageName, packageVersion, friggVersion } = req.body;
|
|
293
|
+
|
|
294
|
+
if (!packageName || !packageVersion || !friggVersion) {
|
|
295
|
+
return res.status(400).json({
|
|
296
|
+
error: 'Missing required parameters',
|
|
297
|
+
required: ['packageName', 'packageVersion', 'friggVersion']
|
|
298
|
+
});
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
const compatibility = await npmRegistry.checkCompatibility(
|
|
302
|
+
packageName,
|
|
303
|
+
packageVersion,
|
|
304
|
+
friggVersion
|
|
305
|
+
);
|
|
306
|
+
|
|
307
|
+
res.json({
|
|
308
|
+
success: true,
|
|
309
|
+
compatibility
|
|
310
|
+
});
|
|
311
|
+
} catch (error) {
|
|
312
|
+
console.error('Compatibility check error:', error);
|
|
313
|
+
res.status(500).json({
|
|
314
|
+
error: 'Failed to check compatibility',
|
|
315
|
+
message: error.message
|
|
316
|
+
});
|
|
317
|
+
}
|
|
318
|
+
});
|
|
319
|
+
|
|
320
|
+
/**
|
|
321
|
+
* Get NPM cache statistics
|
|
322
|
+
*/
|
|
323
|
+
router.get('/npm/cache/stats', async (req, res) => {
|
|
324
|
+
try {
|
|
325
|
+
const stats = npmRegistry.getCacheStats();
|
|
326
|
+
|
|
327
|
+
res.json({
|
|
328
|
+
success: true,
|
|
329
|
+
cache: stats
|
|
330
|
+
});
|
|
331
|
+
} catch (error) {
|
|
332
|
+
console.error('Cache stats error:', error);
|
|
333
|
+
res.status(500).json({
|
|
334
|
+
error: 'Failed to get cache statistics',
|
|
335
|
+
message: error.message
|
|
336
|
+
});
|
|
337
|
+
}
|
|
338
|
+
});
|
|
339
|
+
|
|
340
|
+
/**
|
|
341
|
+
* Clear NPM cache
|
|
342
|
+
*/
|
|
343
|
+
router.delete('/npm/cache', async (req, res) => {
|
|
344
|
+
try {
|
|
345
|
+
const { pattern } = req.query;
|
|
346
|
+
|
|
347
|
+
npmRegistry.clearCache(pattern);
|
|
348
|
+
|
|
349
|
+
res.json({
|
|
350
|
+
success: true,
|
|
351
|
+
message: pattern ? `Cache cleared for pattern: ${pattern}` : 'All cache cleared'
|
|
352
|
+
});
|
|
353
|
+
} catch (error) {
|
|
354
|
+
console.error('Cache clear error:', error);
|
|
355
|
+
res.status(500).json({
|
|
356
|
+
error: 'Failed to clear cache',
|
|
357
|
+
message: error.message
|
|
358
|
+
});
|
|
359
|
+
}
|
|
360
|
+
});
|
|
361
|
+
|
|
362
|
+
// Implementation functions
|
|
363
|
+
|
|
364
|
+
async function generateIntegration(config, req) {
|
|
365
|
+
try {
|
|
366
|
+
// Validate integration configuration
|
|
367
|
+
const errors = validateIntegrationConfig(config);
|
|
368
|
+
if (errors.length > 0) {
|
|
369
|
+
throw new Error(`Configuration errors: ${errors.join(', ')}`);
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
// Generate integration using template engine
|
|
373
|
+
const result = templateEngine.generateIntegration(config);
|
|
374
|
+
|
|
375
|
+
// Determine output directory
|
|
376
|
+
const outputDir = getOutputDirectory(req, 'integrations', config.name);
|
|
377
|
+
|
|
378
|
+
// Write files if requested
|
|
379
|
+
if (req.body.writeFiles !== false) {
|
|
380
|
+
const writtenFiles = await templateEngine.writeFiles(result.files, outputDir);
|
|
381
|
+
result.writtenFiles = writtenFiles;
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
return {
|
|
385
|
+
success: true,
|
|
386
|
+
type: 'integration',
|
|
387
|
+
files: result.files.map(f => f.name),
|
|
388
|
+
outputDirectory: outputDir,
|
|
389
|
+
metadata: result.metadata
|
|
390
|
+
};
|
|
391
|
+
} catch (error) {
|
|
392
|
+
throw new Error(`Integration generation failed: ${error.message}`);
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
async function generateAPIEndpoints(config, req) {
|
|
397
|
+
try {
|
|
398
|
+
// Validate API configuration
|
|
399
|
+
const errors = validateAPIConfig(config);
|
|
400
|
+
if (errors.length > 0) {
|
|
401
|
+
throw new Error(`Configuration errors: ${errors.join(', ')}`);
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
// Generate API endpoints using template engine
|
|
405
|
+
const result = templateEngine.generateAPIEndpoints(config);
|
|
406
|
+
|
|
407
|
+
// Determine output directory
|
|
408
|
+
const outputDir = getOutputDirectory(req, 'api', config.name);
|
|
409
|
+
|
|
410
|
+
// Write files if requested
|
|
411
|
+
if (req.body.writeFiles !== false) {
|
|
412
|
+
const writtenFiles = await templateEngine.writeFiles(result.files, outputDir);
|
|
413
|
+
result.writtenFiles = writtenFiles;
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
return {
|
|
417
|
+
success: true,
|
|
418
|
+
type: 'api-endpoints',
|
|
419
|
+
files: result.files.map(f => f.name),
|
|
420
|
+
outputDirectory: outputDir,
|
|
421
|
+
metadata: result.metadata
|
|
422
|
+
};
|
|
423
|
+
} catch (error) {
|
|
424
|
+
throw new Error(`API generation failed: ${error.message}`);
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
async function generateProjectScaffold(config, req) {
|
|
429
|
+
try {
|
|
430
|
+
// Validate project configuration
|
|
431
|
+
const errors = validateProjectConfig(config);
|
|
432
|
+
if (errors.length > 0) {
|
|
433
|
+
throw new Error(`Configuration errors: ${errors.join(', ')}`);
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
// Generate project scaffold using template engine
|
|
437
|
+
const result = templateEngine.generateProjectScaffold(config);
|
|
438
|
+
|
|
439
|
+
// Determine output directory
|
|
440
|
+
const outputDir = getOutputDirectory(req, 'projects', config.name);
|
|
441
|
+
|
|
442
|
+
// Write files if requested
|
|
443
|
+
if (req.body.writeFiles !== false) {
|
|
444
|
+
const writtenFiles = await templateEngine.writeFiles(result.files, outputDir);
|
|
445
|
+
result.writtenFiles = writtenFiles;
|
|
446
|
+
|
|
447
|
+
// Initialize git repository if requested
|
|
448
|
+
if (config.features?.git) {
|
|
449
|
+
try {
|
|
450
|
+
await templateEngine.executeFriggCommand('init', ['--git'], outputDir);
|
|
451
|
+
} catch (gitError) {
|
|
452
|
+
console.warn('Git initialization failed:', gitError.message);
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
return {
|
|
458
|
+
success: true,
|
|
459
|
+
type: 'project-scaffold',
|
|
460
|
+
files: result.files.map(f => f.name),
|
|
461
|
+
outputDirectory: outputDir,
|
|
462
|
+
metadata: result.metadata
|
|
463
|
+
};
|
|
464
|
+
} catch (error) {
|
|
465
|
+
throw new Error(`Project scaffold generation failed: ${error.message}`);
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
async function generateCustomCode(code, metadata, req) {
|
|
470
|
+
try {
|
|
471
|
+
if (!code) {
|
|
472
|
+
throw new Error('Code content is required for custom generation');
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
// Create file structure from code and metadata
|
|
476
|
+
let files;
|
|
477
|
+
if (metadata?.files) {
|
|
478
|
+
files = metadata.files;
|
|
479
|
+
} else if (typeof code === 'string') {
|
|
480
|
+
files = [{ name: 'index.js', content: code }];
|
|
481
|
+
} else if (typeof code === 'object') {
|
|
482
|
+
files = Object.entries(code).map(([name, content]) => ({
|
|
483
|
+
name,
|
|
484
|
+
content: typeof content === 'string' ? content : JSON.stringify(content, null, 2)
|
|
485
|
+
}));
|
|
486
|
+
} else {
|
|
487
|
+
throw new Error('Invalid code format');
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
// Determine output directory
|
|
491
|
+
const outputDir = getOutputDirectory(req, 'custom', metadata?.name || 'generated');
|
|
492
|
+
|
|
493
|
+
// Write files if requested
|
|
494
|
+
if (req.body.writeFiles !== false) {
|
|
495
|
+
const writtenFiles = await templateEngine.writeFiles(files, outputDir);
|
|
496
|
+
return {
|
|
497
|
+
success: true,
|
|
498
|
+
type: 'custom',
|
|
499
|
+
files: files.map(f => f.name),
|
|
500
|
+
writtenFiles,
|
|
501
|
+
outputDirectory: outputDir,
|
|
502
|
+
metadata
|
|
503
|
+
};
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
return {
|
|
507
|
+
success: true,
|
|
508
|
+
type: 'custom',
|
|
509
|
+
files: files.map(f => f.name),
|
|
510
|
+
outputDirectory: outputDir,
|
|
511
|
+
metadata
|
|
512
|
+
};
|
|
513
|
+
} catch (error) {
|
|
514
|
+
throw new Error(`Custom code generation failed: ${error.message}`);
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
function getOutputDirectory(req, type, name) {
|
|
519
|
+
const baseDir = req.body.outputDirectory || path.join(process.cwd(), 'generated');
|
|
520
|
+
return path.join(baseDir, type, name);
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
function validateConfiguration(type, config) {
|
|
524
|
+
switch (type) {
|
|
525
|
+
case 'integration':
|
|
526
|
+
return validateIntegrationConfig(config);
|
|
527
|
+
case 'api-endpoint':
|
|
528
|
+
return validateAPIConfig(config);
|
|
529
|
+
case 'project-scaffold':
|
|
530
|
+
return validateProjectConfig(config);
|
|
531
|
+
default:
|
|
532
|
+
return [];
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
function validateIntegrationConfig(config) {
|
|
537
|
+
const errors = [];
|
|
538
|
+
|
|
539
|
+
if (!config?.name) {
|
|
540
|
+
errors.push('Integration name is required');
|
|
541
|
+
} else if (!/^[a-z0-9-]+$/.test(config.name)) {
|
|
542
|
+
errors.push('Integration name must contain only lowercase letters, numbers, and hyphens');
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
if (!config?.baseURL) {
|
|
546
|
+
errors.push('Base URL is required');
|
|
547
|
+
} else {
|
|
548
|
+
try {
|
|
549
|
+
new URL(config.baseURL);
|
|
550
|
+
} catch {
|
|
551
|
+
errors.push('Base URL must be a valid URL');
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
if (!config?.type) {
|
|
556
|
+
errors.push('Authentication type is required');
|
|
557
|
+
} else if (!['api', 'oauth2', 'basic-auth', 'oauth1', 'custom'].includes(config.type)) {
|
|
558
|
+
errors.push('Invalid authentication type');
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
if (config.type === 'oauth2') {
|
|
562
|
+
if (!config.authorizationURL) {
|
|
563
|
+
errors.push('Authorization URL is required for OAuth2');
|
|
564
|
+
}
|
|
565
|
+
if (!config.tokenURL) {
|
|
566
|
+
errors.push('Token URL is required for OAuth2');
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
return errors;
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
function validateAPIConfig(config) {
|
|
574
|
+
const errors = [];
|
|
575
|
+
|
|
576
|
+
if (!config?.name) {
|
|
577
|
+
errors.push('API name is required');
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
if (!config?.endpoints || !Array.isArray(config.endpoints)) {
|
|
581
|
+
errors.push('At least one endpoint is required');
|
|
582
|
+
} else {
|
|
583
|
+
config.endpoints.forEach((endpoint, index) => {
|
|
584
|
+
if (!endpoint.path) {
|
|
585
|
+
errors.push(`Endpoint ${index + 1}: Path is required`);
|
|
586
|
+
}
|
|
587
|
+
if (!endpoint.method) {
|
|
588
|
+
errors.push(`Endpoint ${index + 1}: HTTP method is required`);
|
|
589
|
+
}
|
|
590
|
+
});
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
return errors;
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
function validateProjectConfig(config) {
|
|
597
|
+
const errors = [];
|
|
598
|
+
|
|
599
|
+
if (!config?.name) {
|
|
600
|
+
errors.push('Project name is required');
|
|
601
|
+
} else if (!/^[a-zA-Z0-9-_]+$/.test(config.name)) {
|
|
602
|
+
errors.push('Project name must contain only letters, numbers, hyphens, and underscores');
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
if (!config?.template) {
|
|
606
|
+
errors.push('Project template is required');
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
if (!config?.database) {
|
|
610
|
+
errors.push('Database selection is required');
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
return errors;
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
async function getAvailableTemplates() {
|
|
617
|
+
// Return available templates with metadata
|
|
618
|
+
return {
|
|
619
|
+
integration: {
|
|
620
|
+
types: ['api', 'oauth2', 'basic-auth', 'oauth1', 'custom'],
|
|
621
|
+
schemas: ['entity', 'api', 'integration']
|
|
622
|
+
},
|
|
623
|
+
api: {
|
|
624
|
+
methods: ['GET', 'POST', 'PUT', 'DELETE', 'PATCH'],
|
|
625
|
+
authentication: ['bearer', 'api-key', 'basic', 'none']
|
|
626
|
+
},
|
|
627
|
+
project: {
|
|
628
|
+
templates: ['basic-backend', 'microservices', 'serverless', 'full-stack'],
|
|
629
|
+
databases: ['mongodb', 'postgresql', 'mysql', 'dynamodb', 'redis'],
|
|
630
|
+
features: ['authentication', 'logging', 'monitoring', 'testing', 'docker', 'ci']
|
|
631
|
+
}
|
|
632
|
+
};
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
async function getCLIStatus() {
|
|
636
|
+
try {
|
|
637
|
+
const cliPath = path.join(__dirname, '../../../frigg-cli/index.js');
|
|
638
|
+
const exists = await fs.pathExists(cliPath);
|
|
639
|
+
|
|
640
|
+
if (!exists) {
|
|
641
|
+
return {
|
|
642
|
+
available: false,
|
|
643
|
+
error: 'Frigg CLI not found'
|
|
644
|
+
};
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
// Test CLI execution
|
|
648
|
+
const result = await templateEngine.executeFriggCommand('--version');
|
|
649
|
+
|
|
650
|
+
return {
|
|
651
|
+
available: true,
|
|
652
|
+
version: result.stdout.trim(),
|
|
653
|
+
path: cliPath
|
|
654
|
+
};
|
|
655
|
+
} catch (error) {
|
|
656
|
+
return {
|
|
657
|
+
available: false,
|
|
658
|
+
error: error.message
|
|
659
|
+
};
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
export default router;
|