@friggframework/devtools 2.0.0--canary.474.2ad4ebc.0 → 2.0.0--canary.474.a0b734c.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.
Files changed (56) hide show
  1. package/management-ui/server/utils/cliIntegration.js +1 -1
  2. package/package.json +6 -6
  3. package/frigg-cli/.eslintrc.js +0 -141
  4. package/frigg-cli/README.md +0 -1290
  5. package/frigg-cli/__tests__/unit/commands/build.test.js +0 -279
  6. package/frigg-cli/__tests__/unit/commands/db-setup.test.js +0 -548
  7. package/frigg-cli/__tests__/unit/commands/deploy.test.js +0 -320
  8. package/frigg-cli/__tests__/unit/commands/install.test.js +0 -400
  9. package/frigg-cli/__tests__/unit/commands/ui.test.js +0 -346
  10. package/frigg-cli/__tests__/unit/utils/database-validator.test.js +0 -366
  11. package/frigg-cli/__tests__/unit/utils/error-messages.test.js +0 -304
  12. package/frigg-cli/__tests__/unit/version-detection.test.js +0 -171
  13. package/frigg-cli/__tests__/utils/mock-factory.js +0 -270
  14. package/frigg-cli/__tests__/utils/prisma-mock.js +0 -194
  15. package/frigg-cli/__tests__/utils/test-fixtures.js +0 -463
  16. package/frigg-cli/__tests__/utils/test-setup.js +0 -287
  17. package/frigg-cli/build-command/index.js +0 -66
  18. package/frigg-cli/db-setup-command/index.js +0 -193
  19. package/frigg-cli/deploy-command/index.js +0 -302
  20. package/frigg-cli/doctor-command/index.js +0 -249
  21. package/frigg-cli/generate-command/__tests__/generate-command.test.js +0 -301
  22. package/frigg-cli/generate-command/azure-generator.js +0 -43
  23. package/frigg-cli/generate-command/gcp-generator.js +0 -47
  24. package/frigg-cli/generate-command/index.js +0 -332
  25. package/frigg-cli/generate-command/terraform-generator.js +0 -555
  26. package/frigg-cli/generate-iam-command.js +0 -118
  27. package/frigg-cli/index.js +0 -173
  28. package/frigg-cli/index.test.js +0 -158
  29. package/frigg-cli/init-command/backend-first-handler.js +0 -756
  30. package/frigg-cli/init-command/index.js +0 -93
  31. package/frigg-cli/init-command/template-handler.js +0 -143
  32. package/frigg-cli/install-command/backend-js.js +0 -33
  33. package/frigg-cli/install-command/commit-changes.js +0 -16
  34. package/frigg-cli/install-command/environment-variables.js +0 -127
  35. package/frigg-cli/install-command/environment-variables.test.js +0 -136
  36. package/frigg-cli/install-command/index.js +0 -54
  37. package/frigg-cli/install-command/install-package.js +0 -13
  38. package/frigg-cli/install-command/integration-file.js +0 -30
  39. package/frigg-cli/install-command/logger.js +0 -12
  40. package/frigg-cli/install-command/template.js +0 -90
  41. package/frigg-cli/install-command/validate-package.js +0 -75
  42. package/frigg-cli/jest.config.js +0 -124
  43. package/frigg-cli/package.json +0 -58
  44. package/frigg-cli/repair-command/index.js +0 -341
  45. package/frigg-cli/start-command/index.js +0 -149
  46. package/frigg-cli/start-command/start-command.test.js +0 -297
  47. package/frigg-cli/test/init-command.test.js +0 -180
  48. package/frigg-cli/test/npm-registry.test.js +0 -319
  49. package/frigg-cli/ui-command/index.js +0 -154
  50. package/frigg-cli/utils/app-resolver.js +0 -319
  51. package/frigg-cli/utils/backend-path.js +0 -25
  52. package/frigg-cli/utils/database-validator.js +0 -154
  53. package/frigg-cli/utils/error-messages.js +0 -257
  54. package/frigg-cli/utils/npm-registry.js +0 -167
  55. package/frigg-cli/utils/process-manager.js +0 -199
  56. package/frigg-cli/utils/repo-detection.js +0 -405
@@ -1,302 +0,0 @@
1
- const { spawn } = require('child_process');
2
- const path = require('path');
3
- const fs = require('fs');
4
-
5
- // Import doctor command for post-deployment health check
6
- const { doctorCommand } = require('../doctor-command');
7
-
8
- // Configuration constants
9
- const PATHS = {
10
- APP_DEFINITION: 'index.js',
11
- INFRASTRUCTURE: 'infrastructure.js'
12
- };
13
-
14
- const COMMANDS = {
15
- SERVERLESS: 'osls' // OSS-Serverless (drop-in replacement for serverless v3)
16
- };
17
-
18
- /**
19
- * Constructs filtered environment variables for serverless deployment
20
- * @param {string[]} appDefinedVariables - Array of environment variable names from app definition
21
- * @returns {Object} Filtered environment variables object
22
- */
23
- function buildFilteredEnvironment(appDefinedVariables) {
24
- return {
25
- // Essential system variables needed to run serverless
26
- PATH: process.env.PATH,
27
- HOME: process.env.HOME,
28
- USER: process.env.USER,
29
-
30
- // AWS credentials and configuration (all AWS_ prefixed variables)
31
- ...Object.fromEntries(
32
- Object.entries(process.env).filter(([key]) =>
33
- key.startsWith('AWS_')
34
- )
35
- ),
36
-
37
- // App-defined environment variables
38
- ...Object.fromEntries(
39
- appDefinedVariables
40
- .map((key) => [key, process.env[key]])
41
- .filter(([_, value]) => value !== undefined)
42
- ),
43
- };
44
- }
45
-
46
- /**
47
- * Loads and parses the app definition from index.js
48
- * @returns {Object|null} App definition object or null if not found
49
- */
50
- function loadAppDefinition() {
51
- const appDefPath = path.join(process.cwd(), PATHS.APP_DEFINITION);
52
-
53
- if (!fs.existsSync(appDefPath)) {
54
- return null;
55
- }
56
-
57
- try {
58
- const { Definition } = require(appDefPath);
59
- return Definition;
60
- } catch (error) {
61
- console.warn('Could not load appDefinition environment config:', error.message);
62
- return null;
63
- }
64
- }
65
-
66
- /**
67
- * Extracts environment variable names from app definition
68
- * @param {Object} appDefinition - App definition object
69
- * @returns {string[]} Array of environment variable names
70
- */
71
- function extractEnvironmentVariables(appDefinition) {
72
- if (!appDefinition?.environment) {
73
- return [];
74
- }
75
-
76
- console.log('🔧 Loading environment configuration from appDefinition...');
77
-
78
- const appDefinedVariables = Object.keys(appDefinition.environment).filter(
79
- (key) => appDefinition.environment[key] === true
80
- );
81
-
82
- console.log(` Found ${appDefinedVariables.length} environment variables: ${appDefinedVariables.join(', ')}`);
83
- return appDefinedVariables;
84
- }
85
-
86
- /**
87
- * Handles environment validation warnings
88
- * @param {Object} validation - Validation result object
89
- * @param {Object} options - Deploy command options
90
- */
91
- function handleValidationWarnings(validation, options) {
92
- if (validation.missing.length === 0 || options.skipEnvValidation) {
93
- return;
94
- }
95
-
96
- console.warn(`⚠️ Warning: Missing ${validation.missing.length} environment variables: ${validation.missing.join(', ')}`);
97
- console.warn(' These variables are optional and deployment will continue');
98
- console.warn(' Run with --skip-env-validation to bypass this check');
99
- }
100
-
101
- /**
102
- * Validates environment variables and builds filtered environment
103
- * @param {Object} appDefinition - App definition object
104
- * @param {Object} options - Deploy command options
105
- * @returns {Object} Filtered environment variables
106
- */
107
- function validateAndBuildEnvironment(appDefinition, options) {
108
- if (!appDefinition) {
109
- return buildFilteredEnvironment([]);
110
- }
111
-
112
- const appDefinedVariables = extractEnvironmentVariables(appDefinition);
113
-
114
- // Try to use the env-validator if available
115
- try {
116
- const { validateEnvironmentVariables } = require('@friggframework/devtools/infrastructure/env-validator');
117
- const validation = validateEnvironmentVariables(appDefinition);
118
-
119
- handleValidationWarnings(validation, options);
120
- return buildFilteredEnvironment(appDefinedVariables);
121
-
122
- } catch (validatorError) {
123
- // Validator not available, do basic validation
124
- const missingVariables = appDefinedVariables.filter((variable) => !process.env[variable]);
125
-
126
- if (missingVariables.length > 0) {
127
- console.warn(`⚠️ Warning: Missing ${missingVariables.length} environment variables: ${missingVariables.join(', ')}`);
128
- console.warn(' These variables are optional and deployment will continue');
129
- console.warn(' Set them in your CI/CD environment or .env file if needed');
130
- }
131
-
132
- return buildFilteredEnvironment(appDefinedVariables);
133
- }
134
- }
135
-
136
- /**
137
- * Executes the serverless deployment command
138
- * @param {Object} environment - Environment variables to pass to serverless
139
- * @param {Object} options - Deploy command options
140
- * @returns {Promise<number>} Exit code
141
- */
142
- function executeServerlessDeployment(environment, options) {
143
- return new Promise((resolve, reject) => {
144
- console.log('🚀 Deploying serverless application...');
145
-
146
- const serverlessArgs = [
147
- 'deploy',
148
- '--config',
149
- PATHS.INFRASTRUCTURE,
150
- '--stage',
151
- options.stage,
152
- ];
153
-
154
- // Add --force flag if force option is true
155
- if (options.force === true) {
156
- serverlessArgs.push('--force');
157
- }
158
-
159
- const childProcess = spawn(COMMANDS.SERVERLESS, serverlessArgs, {
160
- cwd: path.resolve(process.cwd()),
161
- stdio: 'inherit',
162
- env: {
163
- ...environment,
164
- SLS_STAGE: options.stage, // Set stage for resource discovery
165
- },
166
- });
167
-
168
- childProcess.on('error', (error) => {
169
- console.error(`Error executing command: ${error.message}`);
170
- reject(error);
171
- });
172
-
173
- childProcess.on('close', (code) => {
174
- if (code !== 0) {
175
- console.log(`Child process exited with code ${code}`);
176
- resolve(code);
177
- } else {
178
- resolve(0);
179
- }
180
- });
181
- });
182
- }
183
-
184
- /**
185
- * Get stack name from app definition
186
- * @param {Object} appDefinition - App definition
187
- * @param {Object} options - Deploy options
188
- * @returns {string|null} Stack name
189
- */
190
- function getStackName(appDefinition, options) {
191
- // Try to get from app definition
192
- if (appDefinition?.name) {
193
- const stage = options.stage || 'dev';
194
- return `${appDefinition.name}-${stage}`;
195
- }
196
-
197
- // Try to get from infrastructure.js
198
- const infraPath = path.join(process.cwd(), PATHS.INFRASTRUCTURE);
199
- if (fs.existsSync(infraPath)) {
200
- try {
201
- const infraModule = require(infraPath);
202
- if (infraModule.service) {
203
- const stage = options.stage || 'dev';
204
- return `${infraModule.service}-${stage}`;
205
- }
206
- } catch (error) {
207
- // Ignore errors reading infrastructure file
208
- }
209
- }
210
-
211
- return null;
212
- }
213
-
214
- /**
215
- * Run post-deployment health check
216
- * @param {string} stackName - CloudFormation stack name
217
- * @param {Object} options - Deploy options
218
- */
219
- async function runPostDeploymentHealthCheck(stackName, options) {
220
- console.log('\n' + '═'.repeat(80));
221
- console.log('Running post-deployment health check...');
222
- console.log('═'.repeat(80));
223
-
224
- try {
225
- // Run doctor command (will exit process on its own)
226
- // Note: We need to catch the exit to prevent deploy from exiting
227
- const originalExit = process.exit;
228
- let doctorExitCode = 0;
229
-
230
- // Temporarily override process.exit to capture exit code
231
- process.exit = (code) => {
232
- doctorExitCode = code || 0;
233
- };
234
-
235
- try {
236
- await doctorCommand(stackName, {
237
- region: options.region,
238
- format: 'console',
239
- verbose: options.verbose,
240
- });
241
- } catch (error) {
242
- console.log(`\n⚠️ Health check encountered an error: ${error.message}`);
243
- if (options.verbose) {
244
- console.error(error.stack);
245
- }
246
- } finally {
247
- // Restore original process.exit
248
- process.exit = originalExit;
249
- }
250
-
251
- // Inform user about health check results
252
- if (doctorExitCode === 0) {
253
- console.log('\n✓ Post-deployment health check: PASSED');
254
- } else if (doctorExitCode === 2) {
255
- console.log('\n⚠️ Post-deployment health check: DEGRADED');
256
- console.log(' Run "frigg repair" to fix detected issues');
257
- } else {
258
- console.log('\n✗ Post-deployment health check: FAILED');
259
- console.log(' Run "frigg doctor" for detailed report');
260
- console.log(' Run "frigg repair" to fix detected issues');
261
- }
262
- } catch (error) {
263
- console.log(`\n⚠️ Post-deployment health check failed: ${error.message}`);
264
- if (options.verbose) {
265
- console.error(error.stack);
266
- }
267
- }
268
- }
269
-
270
- async function deployCommand(options) {
271
- console.log('Deploying the serverless application...');
272
-
273
- const appDefinition = loadAppDefinition();
274
- const environment = validateAndBuildEnvironment(appDefinition, options);
275
-
276
- // Execute deployment
277
- const exitCode = await executeServerlessDeployment(environment, options);
278
-
279
- // Check if deployment was successful
280
- if (exitCode !== 0) {
281
- console.error(`\n✗ Deployment failed with exit code ${exitCode}`);
282
- process.exit(exitCode);
283
- }
284
-
285
- console.log('\n✓ Deployment completed successfully!');
286
-
287
- // Run post-deployment health check (unless --skip-doctor)
288
- if (!options.skipDoctor) {
289
- const stackName = getStackName(appDefinition, options);
290
-
291
- if (stackName) {
292
- await runPostDeploymentHealthCheck(stackName, options);
293
- } else {
294
- console.log('\n⚠️ Could not determine stack name - skipping health check');
295
- console.log(' Run "frigg doctor <stack-name>" manually to check stack health');
296
- }
297
- } else {
298
- console.log('\n⏭️ Skipping post-deployment health check (--skip-doctor)');
299
- }
300
- }
301
-
302
- module.exports = { deployCommand };
@@ -1,249 +0,0 @@
1
- /**
2
- * Frigg Doctor Command
3
- *
4
- * Performs comprehensive health check on deployed CloudFormation stack
5
- * and reports issues like property drift, orphaned resources, and missing resources.
6
- *
7
- * Usage:
8
- * frigg doctor <stack-name>
9
- * frigg doctor my-app-prod --region us-east-1
10
- * frigg doctor my-app-prod --format json --output report.json
11
- */
12
-
13
- const path = require('path');
14
- const fs = require('fs');
15
-
16
- // Domain and Application Layer
17
- const StackIdentifier = require('@friggframework/devtools/infrastructure/domains/health/domain/value-objects/stack-identifier');
18
- const RunHealthCheckUseCase = require('@friggframework/devtools/infrastructure/domains/health/application/use-cases/run-health-check-use-case');
19
-
20
- // Infrastructure Layer - AWS Adapters
21
- const AWSStackRepository = require('@friggframework/devtools/infrastructure/domains/health/infrastructure/adapters/aws-stack-repository');
22
- const AWSResourceDetector = require('@friggframework/devtools/infrastructure/domains/health/infrastructure/adapters/aws-resource-detector');
23
-
24
- // Domain Services
25
- const MismatchAnalyzer = require('@friggframework/devtools/infrastructure/domains/health/domain/services/mismatch-analyzer');
26
- const HealthScoreCalculator = require('@friggframework/devtools/infrastructure/domains/health/domain/services/health-score-calculator');
27
-
28
- /**
29
- * Format health report for console output
30
- * @param {StackHealthReport} report - Health check report
31
- * @param {Object} options - Formatting options
32
- * @returns {string} Formatted output
33
- */
34
- function formatConsoleOutput(report, options = {}) {
35
- const lines = [];
36
- const summary = report.getSummary();
37
-
38
- // Header
39
- lines.push('');
40
- lines.push('═'.repeat(80));
41
- lines.push(` FRIGG DOCTOR - Stack Health Report`);
42
- lines.push('═'.repeat(80));
43
- lines.push('');
44
-
45
- // Stack Information
46
- lines.push(`Stack: ${summary.stackName}`);
47
- lines.push(`Region: ${summary.region}`);
48
- lines.push(`Timestamp: ${summary.timestamp}`);
49
- lines.push('');
50
-
51
- // Health Score
52
- const scoreIcon = report.healthScore.isHealthy() ? '✓' : report.healthScore.isUnhealthy() ? '✗' : '⚠';
53
- const scoreColor = report.healthScore.isHealthy() ? '' : '';
54
- lines.push(`Health Score: ${scoreIcon} ${summary.healthScore}/100 (${summary.qualitativeAssessment})`);
55
- lines.push('');
56
-
57
- // Summary Statistics
58
- lines.push('─'.repeat(80));
59
- lines.push('Resources:');
60
- lines.push(` Total: ${summary.resourceCount}`);
61
- lines.push(` In Stack: ${report.getResourcesInStack().length}`);
62
- lines.push(` Drifted: ${summary.driftedResourceCount}`);
63
- lines.push(` Orphaned: ${summary.orphanedResourceCount}`);
64
- lines.push(` Missing: ${summary.missingResourceCount}`);
65
- lines.push('');
66
-
67
- lines.push('Issues:');
68
- lines.push(` Total: ${summary.issueCount}`);
69
- lines.push(` Critical: ${summary.criticalIssueCount}`);
70
- lines.push(` Warnings: ${summary.warningCount}`);
71
- lines.push('');
72
-
73
- // Issues Detail
74
- if (report.issues.length > 0) {
75
- lines.push('─'.repeat(80));
76
- lines.push('Issue Details:');
77
- lines.push('');
78
-
79
- // Group issues by type
80
- const criticalIssues = report.getCriticalIssues();
81
- const warnings = report.getWarnings();
82
-
83
- if (criticalIssues.length > 0) {
84
- lines.push(' CRITICAL ISSUES:');
85
- criticalIssues.forEach((issue, idx) => {
86
- lines.push(` ${idx + 1}. [${issue.type}] ${issue.description}`);
87
- lines.push(` Resource: ${issue.resourceType} (${issue.resourceId})`);
88
- if (issue.resolution) {
89
- lines.push(` Fix: ${issue.resolution}`);
90
- }
91
- lines.push('');
92
- });
93
- }
94
-
95
- if (warnings.length > 0) {
96
- lines.push(' WARNINGS:');
97
- warnings.forEach((issue, idx) => {
98
- lines.push(` ${idx + 1}. [${issue.type}] ${issue.description}`);
99
- lines.push(` Resource: ${issue.resourceType} (${issue.resourceId})`);
100
- if (issue.resolution) {
101
- lines.push(` Fix: ${issue.resolution}`);
102
- }
103
- lines.push('');
104
- });
105
- }
106
- } else {
107
- lines.push('─'.repeat(80));
108
- lines.push('✓ No issues detected - stack is healthy!');
109
- lines.push('');
110
- }
111
-
112
- // Recommendations
113
- if (report.issues.length > 0) {
114
- lines.push('─'.repeat(80));
115
- lines.push('Recommended Actions:');
116
- lines.push('');
117
-
118
- if (report.getOrphanedResourceCount() > 0) {
119
- lines.push(` • Import ${report.getOrphanedResourceCount()} orphaned resource(s):`);
120
- lines.push(` $ frigg repair --import <stack-name>`);
121
- lines.push('');
122
- }
123
-
124
- if (report.getDriftedResourceCount() > 0) {
125
- lines.push(` • Reconcile property drift for ${report.getDriftedResourceCount()} resource(s):`);
126
- lines.push(` $ frigg repair --reconcile <stack-name>`);
127
- lines.push('');
128
- }
129
-
130
- if (report.getMissingResourceCount() > 0) {
131
- lines.push(` • Investigate ${report.getMissingResourceCount()} missing resource(s) and redeploy:`);
132
- lines.push(` $ frigg deploy --stage <stage>`);
133
- lines.push('');
134
- }
135
- }
136
-
137
- lines.push('═'.repeat(80));
138
- lines.push('');
139
-
140
- return lines.join('\n');
141
- }
142
-
143
- /**
144
- * Format health report as JSON
145
- * @param {StackHealthReport} report - Health check report
146
- * @returns {string} JSON output
147
- */
148
- function formatJsonOutput(report) {
149
- return JSON.stringify(report.toJSON(), null, 2);
150
- }
151
-
152
- /**
153
- * Write output to file
154
- * @param {string} content - Content to write
155
- * @param {string} filePath - Output file path
156
- */
157
- function writeOutputFile(content, filePath) {
158
- try {
159
- fs.writeFileSync(filePath, content, 'utf8');
160
- console.log(`\n✓ Report saved to: ${filePath}`);
161
- } catch (error) {
162
- console.error(`\n✗ Failed to write output file: ${error.message}`);
163
- process.exit(1);
164
- }
165
- }
166
-
167
- /**
168
- * Execute health check
169
- * @param {string} stackName - CloudFormation stack name
170
- * @param {Object} options - Command options
171
- */
172
- async function doctorCommand(stackName, options = {}) {
173
- try {
174
- // Validate required parameter
175
- if (!stackName) {
176
- console.error('Error: Stack name is required');
177
- console.log('Usage: frigg doctor <stack-name> [options]');
178
- process.exit(1);
179
- }
180
-
181
- // Extract options with defaults
182
- const region = options.region || process.env.AWS_REGION || 'us-east-1';
183
- const format = options.format || 'console';
184
- const verbose = options.verbose || false;
185
-
186
- if (verbose) {
187
- console.log(`\n🔍 Running health check on stack: ${stackName} (${region})`);
188
- }
189
-
190
- // 1. Create stack identifier
191
- const stackIdentifier = new StackIdentifier({ stackName, region });
192
-
193
- // 2. Wire up infrastructure layer (AWS adapters)
194
- const stackRepository = new AWSStackRepository({ region });
195
- const resourceDetector = new AWSResourceDetector({ region });
196
-
197
- // 3. Wire up domain services
198
- const mismatchAnalyzer = new MismatchAnalyzer();
199
- const healthScoreCalculator = new HealthScoreCalculator();
200
-
201
- // 4. Create and execute use case
202
- const runHealthCheckUseCase = new RunHealthCheckUseCase({
203
- stackRepository,
204
- resourceDetector,
205
- mismatchAnalyzer,
206
- healthScoreCalculator,
207
- });
208
-
209
- const report = await runHealthCheckUseCase.execute({ stackIdentifier });
210
-
211
- // 5. Format and output results
212
- if (format === 'json') {
213
- const jsonOutput = formatJsonOutput(report);
214
-
215
- if (options.output) {
216
- writeOutputFile(jsonOutput, options.output);
217
- } else {
218
- console.log(jsonOutput);
219
- }
220
- } else {
221
- const consoleOutput = formatConsoleOutput(report, options);
222
- console.log(consoleOutput);
223
-
224
- if (options.output) {
225
- writeOutputFile(consoleOutput, options.output);
226
- }
227
- }
228
-
229
- // 6. Exit with appropriate code
230
- // Exit code 0 = healthy, 1 = unhealthy, 2 = degraded
231
- if (report.healthScore.isUnhealthy()) {
232
- process.exit(1);
233
- } else if (report.healthScore.isDegraded()) {
234
- process.exit(2);
235
- } else {
236
- process.exit(0);
237
- }
238
- } catch (error) {
239
- console.error(`\n✗ Health check failed: ${error.message}`);
240
-
241
- if (options.verbose && error.stack) {
242
- console.error(`\nStack trace:\n${error.stack}`);
243
- }
244
-
245
- process.exit(1);
246
- }
247
- }
248
-
249
- module.exports = { doctorCommand };