@friggframework/devtools 2.0.0--canary.522.923dfae.0 → 2.0.0--canary.540.c5ef83f.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/README.md +1 -1
- package/frigg-cli/__tests__/unit/commands/doctor.test.js +2 -0
- package/frigg-cli/__tests__/unit/commands/install.test.js +19 -23
- package/frigg-cli/__tests__/unit/dependencies.test.js +2 -2
- package/frigg-cli/doctor-command/index.js +16 -17
- package/frigg-cli/index.js +6 -21
- package/frigg-cli/index.test.js +2 -7
- package/frigg-cli/init-command/backend-first-handler.js +42 -124
- package/frigg-cli/init-command/index.js +1 -2
- package/frigg-cli/init-command/template-handler.js +3 -13
- package/frigg-cli/install-command/backend-js.js +3 -3
- package/frigg-cli/install-command/environment-variables.js +19 -16
- package/frigg-cli/install-command/environment-variables.test.js +13 -12
- package/frigg-cli/install-command/index.js +9 -14
- package/frigg-cli/install-command/integration-file.js +3 -3
- package/frigg-cli/install-command/logger.js +12 -0
- package/frigg-cli/install-command/validate-package.js +9 -5
- package/frigg-cli/jest.config.js +1 -4
- package/frigg-cli/repair-command/index.js +128 -101
- package/frigg-cli/start-command/index.js +2 -246
- package/frigg-cli/ui-command/index.js +36 -58
- package/frigg-cli/utils/repo-detection.js +37 -85
- package/infrastructure/docs/iam-policy-templates.md +1 -1
- package/infrastructure/domains/networking/vpc-builder.test.js +4 -2
- package/infrastructure/domains/networking/vpc-resolver.test.js +1 -1
- package/infrastructure/domains/shared/cloudformation-discovery.test.js +7 -4
- package/infrastructure/domains/shared/resource-discovery.js +5 -5
- package/infrastructure/domains/shared/types/app-definition.js +0 -21
- package/infrastructure/domains/shared/types/discovery-result.test.js +1 -1
- package/infrastructure/domains/shared/utilities/base-definition-factory.js +1 -10
- package/infrastructure/domains/shared/utilities/base-definition-factory.test.js +2 -2
- package/infrastructure/infrastructure-composer.test.js +2 -2
- package/management-ui/README.md +109 -245
- package/package.json +7 -8
- package/frigg-cli/__tests__/application/use-cases/AddApiModuleToIntegrationUseCase.test.js +0 -326
- package/frigg-cli/__tests__/application/use-cases/CreateApiModuleUseCase.test.js +0 -337
- package/frigg-cli/__tests__/domain/entities/ApiModule.test.js +0 -373
- package/frigg-cli/__tests__/domain/entities/AppDefinition.test.js +0 -313
- package/frigg-cli/__tests__/domain/services/IntegrationValidator.test.js +0 -269
- package/frigg-cli/__tests__/domain/value-objects/IntegrationName.test.js +0 -82
- package/frigg-cli/__tests__/infrastructure/adapters/IntegrationJsUpdater.test.js +0 -408
- package/frigg-cli/__tests__/infrastructure/repositories/FileSystemApiModuleRepository.test.js +0 -583
- package/frigg-cli/__tests__/infrastructure/repositories/FileSystemAppDefinitionRepository.test.js +0 -314
- package/frigg-cli/__tests__/infrastructure/repositories/FileSystemIntegrationRepository.test.js +0 -383
- package/frigg-cli/__tests__/unit/commands/init.test.js +0 -406
- package/frigg-cli/__tests__/unit/commands/repair.test.js +0 -275
- package/frigg-cli/__tests__/unit/start-command/application/RunPreflightChecksUseCase.test.js +0 -411
- package/frigg-cli/__tests__/unit/start-command/infrastructure/DatabaseAdapter.test.js +0 -405
- package/frigg-cli/__tests__/unit/start-command/infrastructure/DockerAdapter.test.js +0 -496
- package/frigg-cli/__tests__/unit/start-command/presentation/InteractivePromptAdapter.test.js +0 -474
- package/frigg-cli/__tests__/unit/utils/output.test.js +0 -196
- package/frigg-cli/application/use-cases/AddApiModuleToIntegrationUseCase.js +0 -93
- package/frigg-cli/application/use-cases/CreateApiModuleUseCase.js +0 -93
- package/frigg-cli/application/use-cases/CreateIntegrationUseCase.js +0 -103
- package/frigg-cli/container.js +0 -172
- package/frigg-cli/docs/OUTPUT_MIGRATION_GUIDE.md +0 -286
- package/frigg-cli/domain/entities/ApiModule.js +0 -272
- package/frigg-cli/domain/entities/AppDefinition.js +0 -227
- package/frigg-cli/domain/entities/Integration.js +0 -198
- package/frigg-cli/domain/exceptions/DomainException.js +0 -24
- package/frigg-cli/domain/ports/IApiModuleRepository.js +0 -53
- package/frigg-cli/domain/ports/IAppDefinitionRepository.js +0 -43
- package/frigg-cli/domain/ports/IIntegrationRepository.js +0 -61
- package/frigg-cli/domain/services/IntegrationValidator.js +0 -185
- package/frigg-cli/domain/value-objects/IntegrationId.js +0 -42
- package/frigg-cli/domain/value-objects/IntegrationName.js +0 -60
- package/frigg-cli/domain/value-objects/SemanticVersion.js +0 -70
- package/frigg-cli/infrastructure/UnitOfWork.js +0 -46
- package/frigg-cli/infrastructure/adapters/BackendJsUpdater.js +0 -197
- package/frigg-cli/infrastructure/adapters/FileSystemAdapter.js +0 -224
- package/frigg-cli/infrastructure/adapters/IntegrationJsUpdater.js +0 -249
- package/frigg-cli/infrastructure/adapters/SchemaValidator.js +0 -92
- package/frigg-cli/infrastructure/repositories/FileSystemApiModuleRepository.js +0 -373
- package/frigg-cli/infrastructure/repositories/FileSystemAppDefinitionRepository.js +0 -116
- package/frigg-cli/infrastructure/repositories/FileSystemIntegrationRepository.js +0 -277
- package/frigg-cli/package-lock.json +0 -16226
- package/frigg-cli/start-command/application/RunPreflightChecksUseCase.js +0 -376
- package/frigg-cli/start-command/infrastructure/DatabaseAdapter.js +0 -591
- package/frigg-cli/start-command/infrastructure/DockerAdapter.js +0 -306
- package/frigg-cli/start-command/presentation/InteractivePromptAdapter.js +0 -329
- package/frigg-cli/templates/backend/.env.example +0 -62
- package/frigg-cli/templates/backend/.eslintrc.json +0 -12
- package/frigg-cli/templates/backend/.prettierrc +0 -6
- package/frigg-cli/templates/backend/docker-compose.yml +0 -22
- package/frigg-cli/templates/backend/index.js +0 -96
- package/frigg-cli/templates/backend/infrastructure.js +0 -12
- package/frigg-cli/templates/backend/jest.config.js +0 -17
- package/frigg-cli/templates/backend/package.json +0 -50
- package/frigg-cli/templates/backend/src/api-modules/.gitkeep +0 -10
- package/frigg-cli/templates/backend/src/base/.gitkeep +0 -7
- package/frigg-cli/templates/backend/src/integrations/.gitkeep +0 -10
- package/frigg-cli/templates/backend/src/integrations/ExampleIntegration.js +0 -65
- package/frigg-cli/templates/backend/src/utils/.gitkeep +0 -7
- package/frigg-cli/templates/backend/test/setup.js +0 -30
- package/frigg-cli/templates/backend/ui-extensions/.gitkeep +0 -0
- package/frigg-cli/templates/backend/ui-extensions/README.md +0 -77
- package/frigg-cli/utils/__tests__/repo-detection.test.js +0 -436
- package/frigg-cli/utils/output.js +0 -382
- package/frigg-cli/validate-command/__tests__/adapters/validate-command.test.js +0 -205
- package/frigg-cli/validate-command/__tests__/application/validate-app-use-case.test.js +0 -104
- package/frigg-cli/validate-command/__tests__/domain/fix-suggestion.test.js +0 -153
- package/frigg-cli/validate-command/__tests__/domain/validation-error.test.js +0 -162
- package/frigg-cli/validate-command/__tests__/domain/validation-result.test.js +0 -152
- package/frigg-cli/validate-command/__tests__/infrastructure/api-module-validator.test.js +0 -332
- package/frigg-cli/validate-command/__tests__/infrastructure/app-definition-validator.test.js +0 -191
- package/frigg-cli/validate-command/__tests__/infrastructure/integration-class-validator.test.js +0 -146
- package/frigg-cli/validate-command/__tests__/infrastructure/template-validation.test.js +0 -155
- package/frigg-cli/validate-command/adapters/cli/validate-command.js +0 -199
- package/frigg-cli/validate-command/application/use-cases/validate-app-use-case.js +0 -35
- package/frigg-cli/validate-command/domain/entities/validation-result.js +0 -74
- package/frigg-cli/validate-command/domain/value-objects/fix-suggestion.js +0 -74
- package/frigg-cli/validate-command/domain/value-objects/validation-error.js +0 -68
- package/frigg-cli/validate-command/infrastructure/validators/api-module-validator.js +0 -181
- package/frigg-cli/validate-command/infrastructure/validators/app-definition-validator.js +0 -128
- package/frigg-cli/validate-command/infrastructure/validators/integration-class-validator.js +0 -113
- package/infrastructure/domains/admin-scripts/admin-script-builder.js +0 -200
- package/infrastructure/domains/admin-scripts/admin-script-builder.test.js +0 -499
- package/infrastructure/domains/admin-scripts/index.js +0 -5
- package/infrastructure/jest.config.js +0 -16
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
const { spawn } = require('node:child_process');
|
|
2
2
|
const path = require('node:path');
|
|
3
|
-
const fs = require('node:fs');
|
|
4
3
|
const dotenv = require('dotenv');
|
|
5
4
|
const chalk = require('chalk');
|
|
6
5
|
const {
|
|
@@ -14,12 +13,6 @@ const {
|
|
|
14
13
|
getPrismaClientNotGeneratedError
|
|
15
14
|
} = require('../utils/error-messages');
|
|
16
15
|
|
|
17
|
-
// Import new pre-flight infrastructure
|
|
18
|
-
const { DockerAdapter } = require('./infrastructure/DockerAdapter');
|
|
19
|
-
const { DatabaseAdapter } = require('./infrastructure/DatabaseAdapter');
|
|
20
|
-
const { RunPreflightChecksUseCase } = require('./application/RunPreflightChecksUseCase');
|
|
21
|
-
const { InteractivePromptAdapter } = require('./presentation/InteractivePromptAdapter');
|
|
22
|
-
|
|
23
16
|
async function startCommand(options) {
|
|
24
17
|
if (options.verbose) {
|
|
25
18
|
console.log('Verbose mode enabled');
|
|
@@ -32,26 +25,7 @@ async function startCommand(options) {
|
|
|
32
25
|
const envPath = path.join(process.cwd(), '.env');
|
|
33
26
|
dotenv.config({ path: envPath });
|
|
34
27
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
// Run interactive pre-flight checks if enabled (default: true)
|
|
38
|
-
if (options.interactive !== false) {
|
|
39
|
-
try {
|
|
40
|
-
const preflightPassed = await runInteractivePreflightChecks(projectPath, options);
|
|
41
|
-
if (!preflightPassed) {
|
|
42
|
-
console.error(chalk.red('\n❌ Pre-flight checks failed'));
|
|
43
|
-
console.error(chalk.gray('Fix the issues above before starting the application.\n'));
|
|
44
|
-
process.exit(1);
|
|
45
|
-
}
|
|
46
|
-
} catch (error) {
|
|
47
|
-
if (options.verbose) {
|
|
48
|
-
console.error(chalk.yellow(`Pre-flight check error: ${error.message}`));
|
|
49
|
-
}
|
|
50
|
-
// Fall back to legacy checks if new system fails
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
// Legacy pre-flight database checks (still run for Prisma validation)
|
|
28
|
+
// Pre-flight database checks
|
|
55
29
|
try {
|
|
56
30
|
await performDatabaseChecks(options.verbose);
|
|
57
31
|
} catch (error) {
|
|
@@ -60,7 +34,7 @@ async function startCommand(options) {
|
|
|
60
34
|
process.exit(1);
|
|
61
35
|
}
|
|
62
36
|
|
|
63
|
-
console.log(chalk.green('✓
|
|
37
|
+
console.log(chalk.green('✓ Database checks passed\n'));
|
|
64
38
|
console.log('Starting backend and optional frontend...');
|
|
65
39
|
|
|
66
40
|
// Suppress AWS SDK warning message about maintenance mode
|
|
@@ -109,224 +83,6 @@ async function startCommand(options) {
|
|
|
109
83
|
});
|
|
110
84
|
}
|
|
111
85
|
|
|
112
|
-
/**
|
|
113
|
-
* Run interactive pre-flight checks with resolution prompts
|
|
114
|
-
* @param {string} projectPath - Path to the Frigg project
|
|
115
|
-
* @param {object} options - Command options
|
|
116
|
-
* @returns {Promise<boolean>} True if all checks pass or were resolved
|
|
117
|
-
*/
|
|
118
|
-
async function runInteractivePreflightChecks(projectPath, options) {
|
|
119
|
-
// Create adapters and use case
|
|
120
|
-
const dockerAdapter = new DockerAdapter();
|
|
121
|
-
const databaseAdapter = new DatabaseAdapter();
|
|
122
|
-
const preflightUseCase = new RunPreflightChecksUseCase({
|
|
123
|
-
dockerAdapter,
|
|
124
|
-
databaseAdapter
|
|
125
|
-
});
|
|
126
|
-
|
|
127
|
-
// Create prompt adapter based on mode (terminal or IPC)
|
|
128
|
-
const promptMode = options.ipc ? 'ipc' : 'terminal';
|
|
129
|
-
const promptAdapter = InteractivePromptAdapter.create({ mode: promptMode });
|
|
130
|
-
|
|
131
|
-
if (options.verbose) {
|
|
132
|
-
console.log(chalk.gray('Running pre-flight checks...'));
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
// Track which checks we've already processed to avoid infinite loops
|
|
136
|
-
const processedChecks = new Set();
|
|
137
|
-
|
|
138
|
-
// Keep running checks and resolving issues until all pass or no more can be resolved
|
|
139
|
-
let maxIterations = 10; // Safety limit to prevent infinite loops
|
|
140
|
-
while (maxIterations > 0) {
|
|
141
|
-
maxIterations--;
|
|
142
|
-
|
|
143
|
-
// Run checks
|
|
144
|
-
const result = await preflightUseCase.execute({ projectPath });
|
|
145
|
-
|
|
146
|
-
// If all passed, we're done
|
|
147
|
-
if (result.allPassed) {
|
|
148
|
-
return true;
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
// Get resolvable checks that we haven't already processed
|
|
152
|
-
const resolvableChecks = preflightUseCase.getResolvableChecks(result)
|
|
153
|
-
.filter(check => !processedChecks.has(check.name));
|
|
154
|
-
|
|
155
|
-
// If no new resolvable checks, show failures and exit
|
|
156
|
-
if (resolvableChecks.length === 0) {
|
|
157
|
-
const failedChecks = result.checks.filter(c => c.status === 'failed');
|
|
158
|
-
for (const check of failedChecks) {
|
|
159
|
-
console.log(chalk.red(` ✗ ${check.name}: ${check.message}`));
|
|
160
|
-
if (check.resolution?.instructions) {
|
|
161
|
-
console.log(chalk.gray(` ${check.resolution.instructions}`));
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
return false;
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
// Process the first resolvable check
|
|
168
|
-
const check = resolvableChecks[0];
|
|
169
|
-
processedChecks.add(check.name);
|
|
170
|
-
|
|
171
|
-
// Display the failure
|
|
172
|
-
console.log(chalk.yellow(`\n⚠️ ${check.message}`));
|
|
173
|
-
|
|
174
|
-
// Only prompt if check is resolvable
|
|
175
|
-
if (!check.canResolve) {
|
|
176
|
-
if (check.resolution?.instructions) {
|
|
177
|
-
console.log(chalk.gray(` ${check.resolution.instructions}`));
|
|
178
|
-
}
|
|
179
|
-
continue;
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
// Ask user if they want to resolve
|
|
183
|
-
const response = await promptAdapter.promptForResolution(check);
|
|
184
|
-
|
|
185
|
-
if (!response.shouldResolve) {
|
|
186
|
-
console.log(chalk.gray(' Skipping resolution'));
|
|
187
|
-
// User declined, show remaining failures and exit
|
|
188
|
-
const failedChecks = result.checks.filter(c => c.status === 'failed');
|
|
189
|
-
for (const failedCheck of failedChecks) {
|
|
190
|
-
if (failedCheck.name !== check.name) {
|
|
191
|
-
console.log(chalk.red(` ✗ ${failedCheck.name}: ${failedCheck.message}`));
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
return false;
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
// Execute the resolution
|
|
198
|
-
const resolved = await executeResolution(check, dockerAdapter, options);
|
|
199
|
-
|
|
200
|
-
if (!resolved) {
|
|
201
|
-
return false;
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
// Loop will continue and re-run checks
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
// If we exhausted iterations, something went wrong
|
|
208
|
-
console.log(chalk.yellow(' ⚠️ Pre-flight check loop limit reached'));
|
|
209
|
-
return false;
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
/**
|
|
213
|
-
* Execute a resolution action
|
|
214
|
-
* @param {object} check - The check that failed
|
|
215
|
-
* @param {DockerAdapter} dockerAdapter - Docker adapter
|
|
216
|
-
* @param {object} options - Command options
|
|
217
|
-
* @returns {Promise<boolean>} True if resolution succeeded
|
|
218
|
-
*/
|
|
219
|
-
async function executeResolution(check, dockerAdapter, options) {
|
|
220
|
-
const { resolution } = check;
|
|
221
|
-
|
|
222
|
-
switch (resolution.type) {
|
|
223
|
-
case 'start_docker':
|
|
224
|
-
console.log(chalk.blue(' Starting Docker Desktop...'));
|
|
225
|
-
const dockerResult = await dockerAdapter.startDockerDesktop();
|
|
226
|
-
if (!dockerResult.success) {
|
|
227
|
-
console.error(chalk.red(` Failed to start Docker: ${dockerResult.error}`));
|
|
228
|
-
return false;
|
|
229
|
-
}
|
|
230
|
-
// Wait for Docker to be ready
|
|
231
|
-
console.log(chalk.gray(' Waiting for Docker to start...'));
|
|
232
|
-
const isReady = await dockerAdapter.waitForDockerReady({
|
|
233
|
-
maxAttempts: 60,
|
|
234
|
-
intervalMs: 1000
|
|
235
|
-
});
|
|
236
|
-
if (!isReady) {
|
|
237
|
-
console.error(chalk.red(' Docker did not start in time'));
|
|
238
|
-
return false;
|
|
239
|
-
}
|
|
240
|
-
console.log(chalk.green(' ✓ Docker is now running'));
|
|
241
|
-
return true;
|
|
242
|
-
|
|
243
|
-
case 'start_docker_compose':
|
|
244
|
-
console.log(chalk.blue(' Starting Docker Compose services...'));
|
|
245
|
-
const composeResult = await dockerAdapter.startDockerCompose(resolution.composePath);
|
|
246
|
-
if (!composeResult.success) {
|
|
247
|
-
console.error(chalk.red(` Failed to start services: ${composeResult.error}`));
|
|
248
|
-
return false;
|
|
249
|
-
}
|
|
250
|
-
console.log(chalk.green(' ✓ Docker Compose services started'));
|
|
251
|
-
// Poll LocalStack health endpoint until services are ready
|
|
252
|
-
console.log(chalk.gray(' Waiting for LocalStack to initialize...'));
|
|
253
|
-
const localstackResult = await dockerAdapter.waitForLocalStack({
|
|
254
|
-
maxAttempts: 30,
|
|
255
|
-
intervalMs: 2000
|
|
256
|
-
});
|
|
257
|
-
if (localstackResult.ready) {
|
|
258
|
-
console.log(chalk.green(' ✓ LocalStack services ready'));
|
|
259
|
-
if (options.verbose && localstackResult.services) {
|
|
260
|
-
console.log(chalk.gray(` Services: ${Object.keys(localstackResult.services).join(', ')}`));
|
|
261
|
-
}
|
|
262
|
-
} else {
|
|
263
|
-
console.log(chalk.yellow(' ⚠️ LocalStack may not be fully ready'));
|
|
264
|
-
if (localstackResult.error) {
|
|
265
|
-
console.log(chalk.gray(` ${localstackResult.error}`));
|
|
266
|
-
}
|
|
267
|
-
// Continue anyway - the service might still work
|
|
268
|
-
}
|
|
269
|
-
return true;
|
|
270
|
-
|
|
271
|
-
case 'create_env':
|
|
272
|
-
// Try to copy .env.example to .env
|
|
273
|
-
const projectPath = process.cwd();
|
|
274
|
-
const envExamplePath = path.join(projectPath, '.env.example');
|
|
275
|
-
const envPath = path.join(projectPath, '.env');
|
|
276
|
-
|
|
277
|
-
if (fs.existsSync(envExamplePath)) {
|
|
278
|
-
try {
|
|
279
|
-
fs.copyFileSync(envExamplePath, envPath);
|
|
280
|
-
console.log(chalk.green(' ✓ Created .env file from .env.example'));
|
|
281
|
-
console.log(chalk.yellow(' ⚠️ Please edit .env to set your DATABASE_URL'));
|
|
282
|
-
|
|
283
|
-
// Reload environment variables from the new .env file
|
|
284
|
-
dotenv.config({ path: envPath, override: true });
|
|
285
|
-
|
|
286
|
-
// Check if DATABASE_URL is now set
|
|
287
|
-
if (process.env.DATABASE_URL && process.env.DATABASE_URL.trim() !== '') {
|
|
288
|
-
console.log(chalk.green(' ✓ DATABASE_URL is now configured'));
|
|
289
|
-
return true;
|
|
290
|
-
} else {
|
|
291
|
-
console.log(chalk.yellow(' ⚠️ DATABASE_URL is still not set in .env'));
|
|
292
|
-
console.log(chalk.gray(' Please edit .env and set DATABASE_URL, then try again'));
|
|
293
|
-
return false;
|
|
294
|
-
}
|
|
295
|
-
} catch (err) {
|
|
296
|
-
console.error(chalk.red(` Failed to create .env: ${err.message}`));
|
|
297
|
-
return false;
|
|
298
|
-
}
|
|
299
|
-
} else {
|
|
300
|
-
console.log(chalk.yellow(' No .env.example file found'));
|
|
301
|
-
console.log(chalk.gray(' Please create a .env file manually with DATABASE_URL'));
|
|
302
|
-
return false;
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
case 'run_migrations':
|
|
306
|
-
console.log(chalk.blue(' Running PostgreSQL migrations...'));
|
|
307
|
-
const databaseAdapter = new DatabaseAdapter();
|
|
308
|
-
const migrationProjectPath = process.cwd();
|
|
309
|
-
|
|
310
|
-
// Use deploy mode (default) - non-interactive, applies existing migrations
|
|
311
|
-
const migrateResult = await databaseAdapter.runMigrations(migrationProjectPath);
|
|
312
|
-
|
|
313
|
-
if (!migrateResult.success) {
|
|
314
|
-
console.error(chalk.red(` Failed to run migrations: ${migrateResult.error}`));
|
|
315
|
-
console.log(chalk.gray(' Try running "frigg db:setup" manually'));
|
|
316
|
-
return false;
|
|
317
|
-
}
|
|
318
|
-
|
|
319
|
-
console.log(chalk.green(' ✓ Database migrations applied successfully'));
|
|
320
|
-
return true;
|
|
321
|
-
|
|
322
|
-
default:
|
|
323
|
-
if (options.verbose) {
|
|
324
|
-
console.log(chalk.gray(` Unknown resolution type: ${resolution.type}`));
|
|
325
|
-
}
|
|
326
|
-
return false;
|
|
327
|
-
}
|
|
328
|
-
}
|
|
329
|
-
|
|
330
86
|
/**
|
|
331
87
|
* Performs pre-flight database validation checks
|
|
332
88
|
* @param {boolean} verbose - Enable verbose output
|
|
@@ -2,19 +2,16 @@ const open = require('open');
|
|
|
2
2
|
const chalk = require('chalk');
|
|
3
3
|
const path = require('path');
|
|
4
4
|
const ProcessManager = require('../utils/process-manager');
|
|
5
|
-
const {
|
|
6
|
-
getCurrentRepositoryInfo,
|
|
7
|
-
discoverFriggRepositories,
|
|
5
|
+
const {
|
|
6
|
+
getCurrentRepositoryInfo,
|
|
7
|
+
discoverFriggRepositories,
|
|
8
8
|
promptRepositorySelection,
|
|
9
|
-
formatRepositoryInfo
|
|
9
|
+
formatRepositoryInfo
|
|
10
10
|
} = require('../utils/repo-detection');
|
|
11
11
|
|
|
12
12
|
async function uiCommand(options) {
|
|
13
|
-
const { port =
|
|
14
|
-
|
|
15
|
-
// Fix: --no-open should set open to false, not use the default true
|
|
16
|
-
const shouldOpenBrowser = options.open !== false;
|
|
17
|
-
|
|
13
|
+
const { port = 3001, open: shouldOpen = true, repo: specifiedRepo, dev = false } = options;
|
|
14
|
+
|
|
18
15
|
let targetRepo = null;
|
|
19
16
|
let workingDirectory = process.cwd();
|
|
20
17
|
|
|
@@ -28,7 +25,7 @@ async function uiCommand(options) {
|
|
|
28
25
|
// Check if we're already in a Frigg repository
|
|
29
26
|
console.log(chalk.blue('Detecting Frigg repository...'));
|
|
30
27
|
const currentRepo = await getCurrentRepositoryInfo();
|
|
31
|
-
|
|
28
|
+
|
|
32
29
|
if (currentRepo) {
|
|
33
30
|
console.log(chalk.green(`✓ Found Frigg repository: ${formatRepositoryInfo(currentRepo)}`));
|
|
34
31
|
if (currentRepo.currentSubPath) {
|
|
@@ -40,40 +37,40 @@ async function uiCommand(options) {
|
|
|
40
37
|
// Discover Frigg repositories
|
|
41
38
|
console.log(chalk.yellow('Current directory is not a Frigg repository.'));
|
|
42
39
|
console.log(chalk.blue('Searching for Frigg repositories...'));
|
|
43
|
-
|
|
40
|
+
|
|
44
41
|
const discoveredRepos = await discoverFriggRepositories();
|
|
45
|
-
|
|
42
|
+
|
|
46
43
|
if (discoveredRepos.length === 0) {
|
|
47
44
|
console.log(chalk.red('No Frigg repositories found. Please create one first.'));
|
|
48
45
|
process.exit(1);
|
|
49
46
|
}
|
|
50
|
-
|
|
47
|
+
|
|
51
48
|
// For UI command, we'll let the UI handle repository selection
|
|
52
49
|
// Set a placeholder and pass the discovered repos via environment
|
|
53
|
-
targetRepo = {
|
|
54
|
-
name: 'Multiple Repositories Available',
|
|
50
|
+
targetRepo = {
|
|
51
|
+
name: 'Multiple Repositories Available',
|
|
55
52
|
path: process.cwd(),
|
|
56
53
|
isMultiRepo: true,
|
|
57
54
|
availableRepos: discoveredRepos
|
|
58
55
|
};
|
|
59
56
|
workingDirectory = process.cwd();
|
|
60
|
-
|
|
57
|
+
|
|
61
58
|
console.log(chalk.blue(`Found ${discoveredRepos.length} Frigg repositories. You'll be able to select one in the UI.`));
|
|
62
59
|
}
|
|
63
60
|
}
|
|
64
61
|
|
|
65
62
|
console.log(chalk.blue('🚀 Starting Frigg Management UI...'));
|
|
66
|
-
|
|
63
|
+
|
|
67
64
|
const processManager = new ProcessManager();
|
|
68
|
-
|
|
65
|
+
|
|
69
66
|
try {
|
|
70
67
|
const managementUiPath = path.join(__dirname, '../../management-ui');
|
|
71
|
-
|
|
68
|
+
|
|
72
69
|
// Check if we're in development mode
|
|
73
70
|
// For CLI usage, we prefer development mode unless explicitly set to production
|
|
74
71
|
const fs = require('fs');
|
|
75
72
|
const isDevelopment = dev || process.env.NODE_ENV !== 'production';
|
|
76
|
-
|
|
73
|
+
|
|
77
74
|
if (isDevelopment) {
|
|
78
75
|
const env = {
|
|
79
76
|
...process.env,
|
|
@@ -83,15 +80,15 @@ async function uiCommand(options) {
|
|
|
83
80
|
REPOSITORY_INFO: JSON.stringify(targetRepo),
|
|
84
81
|
AVAILABLE_REPOSITORIES: targetRepo.isMultiRepo ? JSON.stringify(targetRepo.availableRepos) : null
|
|
85
82
|
};
|
|
86
|
-
|
|
87
|
-
// Start backend server
|
|
83
|
+
|
|
84
|
+
// Start backend server
|
|
88
85
|
processManager.spawnProcess(
|
|
89
86
|
'backend',
|
|
90
87
|
'npm',
|
|
91
|
-
['run', 'server
|
|
88
|
+
['run', 'server'],
|
|
92
89
|
{ cwd: managementUiPath, env }
|
|
93
90
|
);
|
|
94
|
-
|
|
91
|
+
|
|
95
92
|
// Start frontend dev server
|
|
96
93
|
processManager.spawnProcess(
|
|
97
94
|
'frontend',
|
|
@@ -99,71 +96,52 @@ async function uiCommand(options) {
|
|
|
99
96
|
['run', 'dev'],
|
|
100
97
|
{ cwd: managementUiPath, env }
|
|
101
98
|
);
|
|
102
|
-
|
|
103
|
-
// Wait for
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
let backendReady = false;
|
|
107
|
-
|
|
108
|
-
for (let attempt = 0; attempt < maxAttempts; attempt++) {
|
|
109
|
-
try {
|
|
110
|
-
const response = await fetch(`http://localhost:${port}/api/health`);
|
|
111
|
-
if (response.ok) {
|
|
112
|
-
backendReady = true;
|
|
113
|
-
break;
|
|
114
|
-
}
|
|
115
|
-
} catch (err) {
|
|
116
|
-
// Backend not ready yet, wait and retry
|
|
117
|
-
}
|
|
118
|
-
await new Promise(resolve => setTimeout(resolve, delayMs));
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
if (!backendReady) {
|
|
122
|
-
console.warn('⚠️ Backend health check timed out, but continuing anyway...');
|
|
123
|
-
}
|
|
124
|
-
|
|
99
|
+
|
|
100
|
+
// Wait for servers to start
|
|
101
|
+
await new Promise(resolve => setTimeout(resolve, 2000));
|
|
102
|
+
|
|
125
103
|
// Display clean status
|
|
126
104
|
processManager.printStatus(
|
|
127
105
|
'http://localhost:5173',
|
|
128
106
|
`http://localhost:${port}`,
|
|
129
107
|
targetRepo.name
|
|
130
108
|
);
|
|
131
|
-
|
|
109
|
+
|
|
132
110
|
// Open browser if requested
|
|
133
|
-
if (
|
|
111
|
+
if (shouldOpen) {
|
|
134
112
|
setTimeout(() => {
|
|
135
113
|
open('http://localhost:5173');
|
|
136
114
|
}, 1000);
|
|
137
115
|
}
|
|
138
|
-
|
|
116
|
+
|
|
139
117
|
} else {
|
|
140
118
|
// Production mode - just start the backend server
|
|
141
119
|
const { FriggManagementServer } = await import('../../management-ui/server/index.js');
|
|
142
|
-
|
|
143
|
-
const server = new FriggManagementServer({
|
|
144
|
-
port,
|
|
120
|
+
|
|
121
|
+
const server = new FriggManagementServer({
|
|
122
|
+
port,
|
|
145
123
|
projectRoot: workingDirectory,
|
|
146
124
|
repositoryInfo: targetRepo,
|
|
147
125
|
availableRepositories: targetRepo.isMultiRepo ? targetRepo.availableRepos : null
|
|
148
126
|
});
|
|
149
127
|
await server.start();
|
|
150
|
-
|
|
128
|
+
|
|
151
129
|
processManager.printStatus(
|
|
152
130
|
`http://localhost:${port}`,
|
|
153
131
|
`http://localhost:${port}/api`,
|
|
154
132
|
targetRepo.name
|
|
155
133
|
);
|
|
156
|
-
|
|
157
|
-
if (
|
|
134
|
+
|
|
135
|
+
if (shouldOpen) {
|
|
158
136
|
setTimeout(() => {
|
|
159
137
|
open(`http://localhost:${port}`);
|
|
160
138
|
}, 1000);
|
|
161
139
|
}
|
|
162
140
|
}
|
|
163
|
-
|
|
141
|
+
|
|
164
142
|
// Keep the process running
|
|
165
143
|
process.stdin.resume();
|
|
166
|
-
|
|
144
|
+
|
|
167
145
|
} catch (error) {
|
|
168
146
|
console.error(chalk.red('Failed to start Management UI:'), error.message);
|
|
169
147
|
if (error.code === 'EADDRINUSE') {
|
|
@@ -37,70 +37,17 @@ async function isFriggRepository(directory) {
|
|
|
37
37
|
friggDependencies: []
|
|
38
38
|
};
|
|
39
39
|
|
|
40
|
-
// Check for @friggframework
|
|
41
|
-
// Check both root package.json and backend/package.json for workspace projects
|
|
40
|
+
// Check for @friggframework dependencies
|
|
42
41
|
const allDeps = {
|
|
43
42
|
...packageJson.dependencies,
|
|
44
|
-
...packageJson.devDependencies
|
|
43
|
+
...packageJson.devDependencies,
|
|
44
|
+
...packageJson.peerDependencies
|
|
45
45
|
};
|
|
46
46
|
|
|
47
|
-
// Check root package.json for core dependency
|
|
48
|
-
let coreVersion = allDeps['@friggframework/core'];
|
|
49
|
-
let hasFriggCore = coreVersion && (
|
|
50
|
-
coreVersion === 'next' ||
|
|
51
|
-
coreVersion.includes('2.0.0') ||
|
|
52
|
-
coreVersion.includes('next') ||
|
|
53
|
-
coreVersion.startsWith('^2.') ||
|
|
54
|
-
coreVersion.startsWith('~2.') ||
|
|
55
|
-
coreVersion.startsWith('2.')
|
|
56
|
-
);
|
|
57
|
-
|
|
58
|
-
// If not in root, check backend/package.json for workspace projects
|
|
59
|
-
if (!hasFriggCore) {
|
|
60
|
-
const backendPackagePath = path.join(directory, 'backend', 'package.json');
|
|
61
|
-
if (fs.existsSync(backendPackagePath)) {
|
|
62
|
-
try {
|
|
63
|
-
const backendPackageJson = await fs.readJson(backendPackagePath);
|
|
64
|
-
const backendDeps = {
|
|
65
|
-
...backendPackageJson.dependencies,
|
|
66
|
-
...backendPackageJson.devDependencies
|
|
67
|
-
};
|
|
68
|
-
coreVersion = backendDeps['@friggframework/core'];
|
|
69
|
-
hasFriggCore = coreVersion && (
|
|
70
|
-
coreVersion === 'next' ||
|
|
71
|
-
coreVersion.includes('2.0.0') ||
|
|
72
|
-
coreVersion.includes('next') ||
|
|
73
|
-
coreVersion.startsWith('^2.') ||
|
|
74
|
-
coreVersion.startsWith('~2.') ||
|
|
75
|
-
coreVersion.startsWith('2.')
|
|
76
|
-
);
|
|
77
|
-
} catch (error) {
|
|
78
|
-
// Ignore errors reading backend package.json
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
if (hasFriggCore) {
|
|
84
|
-
indicators.hasFriggDependencies = true;
|
|
85
|
-
indicators.friggDependencies.push('@friggframework/core');
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
// Also track other Frigg dependencies for reference
|
|
89
47
|
for (const dep in allDeps) {
|
|
90
|
-
if (dep.startsWith('@friggframework/')
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
version === 'next' ||
|
|
94
|
-
version.includes('2.0.0') ||
|
|
95
|
-
version.includes('next') ||
|
|
96
|
-
version.startsWith('^2.') ||
|
|
97
|
-
version.startsWith('~2.') ||
|
|
98
|
-
version.startsWith('2.')
|
|
99
|
-
);
|
|
100
|
-
|
|
101
|
-
if (isV2Plus) {
|
|
102
|
-
indicators.friggDependencies.push(dep);
|
|
103
|
-
}
|
|
48
|
+
if (dep.startsWith('@friggframework/')) {
|
|
49
|
+
indicators.hasFriggDependencies = true;
|
|
50
|
+
indicators.friggDependencies.push(dep);
|
|
104
51
|
}
|
|
105
52
|
}
|
|
106
53
|
|
|
@@ -189,33 +136,42 @@ async function isFriggRepository(directory) {
|
|
|
189
136
|
}
|
|
190
137
|
}
|
|
191
138
|
|
|
192
|
-
//
|
|
193
|
-
// 1.
|
|
194
|
-
// 2.
|
|
195
|
-
// 3.
|
|
196
|
-
|
|
197
|
-
//
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
const
|
|
201
|
-
|
|
139
|
+
// A directory is considered a Frigg repo if it has:
|
|
140
|
+
// 1. Frigg dependencies (MANDATORY - most reliable indicator) OR
|
|
141
|
+
// 2. Frigg-specific configuration files OR
|
|
142
|
+
// 3. Frigg-specific directories OR
|
|
143
|
+
// 4. Frigg-specific scripts in package.json OR
|
|
144
|
+
// 5. Serverless config with explicit Frigg references AND proper structure
|
|
145
|
+
//
|
|
146
|
+
// For Zapier apps, we require explicit Frigg indicators
|
|
147
|
+
const hasFriggIndicators = indicators.hasFriggDependencies ||
|
|
148
|
+
indicators.hasFriggConfig ||
|
|
149
|
+
indicators.hasFriggDirectories ||
|
|
150
|
+
indicators.hasFriggScripts ||
|
|
151
|
+
hasFriggServerlessIndicators;
|
|
152
|
+
|
|
153
|
+
// Determine if it's a Frigg repository
|
|
154
|
+
let isFriggRepo = false;
|
|
155
|
+
|
|
156
|
+
if (isZapierApp) {
|
|
157
|
+
// For Zapier apps, require explicit Frigg dependencies or config
|
|
158
|
+
isFriggRepo = indicators.hasFriggDependencies || indicators.hasFriggConfig;
|
|
159
|
+
} else {
|
|
160
|
+
// For non-Zapier apps, any Frigg indicator is sufficient
|
|
161
|
+
isFriggRepo = hasFriggIndicators;
|
|
162
|
+
}
|
|
202
163
|
|
|
203
|
-
//
|
|
204
|
-
|
|
164
|
+
// Additional validation for edge cases
|
|
165
|
+
if (isZapierApp && !indicators.hasFriggDependencies && !indicators.hasFriggConfig) {
|
|
166
|
+
return { isFriggRepo: false, repoInfo: null };
|
|
167
|
+
}
|
|
205
168
|
|
|
206
169
|
if (isFriggRepo) {
|
|
207
|
-
// IMPORTANT: If backend/ has a Frigg app structure, use backend/ as the path
|
|
208
|
-
// This handles workspace projects where the actual app is in backend/
|
|
209
|
-
let actualPath = directory;
|
|
210
|
-
if (hasBackendIndexJs || hasBackendServerless) {
|
|
211
|
-
actualPath = path.join(directory, 'backend');
|
|
212
|
-
}
|
|
213
|
-
|
|
214
170
|
return {
|
|
215
171
|
isFriggRepo: true,
|
|
216
172
|
repoInfo: {
|
|
217
173
|
name: packageJson.name || path.basename(directory),
|
|
218
|
-
path:
|
|
174
|
+
path: directory,
|
|
219
175
|
version: packageJson.version,
|
|
220
176
|
framework: detectFramework(directory, existingFrontendDirs),
|
|
221
177
|
hasBackend: fs.existsSync(path.join(directory, 'backend')),
|
|
@@ -289,16 +245,12 @@ async function discoverFriggRepositories(options = {}) {
|
|
|
289
245
|
searchPaths = [
|
|
290
246
|
process.cwd(),
|
|
291
247
|
path.join(os.homedir(), 'Documents'),
|
|
292
|
-
path.join(os.homedir(), 'Documents', 'GitHub'), // Common GitHub Desktop location
|
|
293
248
|
path.join(os.homedir(), 'Projects'),
|
|
294
249
|
path.join(os.homedir(), 'Development'),
|
|
295
250
|
path.join(os.homedir(), 'dev'),
|
|
296
|
-
path.join(os.homedir(), 'Code')
|
|
297
|
-
path.join(os.homedir(), 'GitHub'), // Alternative GitHub location
|
|
298
|
-
path.join(os.homedir(), 'repos'), // Common repos folder
|
|
299
|
-
path.join(os.homedir(), 'src') // Common source folder
|
|
251
|
+
path.join(os.homedir(), 'Code')
|
|
300
252
|
],
|
|
301
|
-
maxDepth =
|
|
253
|
+
maxDepth = 3,
|
|
302
254
|
excludePatterns = ['node_modules', '.git', 'dist', 'build', '.next', 'coverage']
|
|
303
255
|
} = options;
|
|
304
256
|
|
|
@@ -160,7 +160,7 @@ Consider separate policies for different environments:
|
|
|
160
160
|
### Validation
|
|
161
161
|
Test your policy by deploying a simple Frigg app:
|
|
162
162
|
```bash
|
|
163
|
-
frigg
|
|
163
|
+
npx create-frigg-app test-deployment
|
|
164
164
|
cd test-deployment
|
|
165
165
|
frigg deploy
|
|
166
166
|
```
|
|
@@ -1500,9 +1500,10 @@ describe('VpcBuilder', () => {
|
|
|
1500
1500
|
}
|
|
1501
1501
|
};
|
|
1502
1502
|
|
|
1503
|
+
// Discovery results matching ACTUAL Frontify production stack
|
|
1503
1504
|
const discoveredResources = {
|
|
1504
1505
|
fromCloudFormationStack: true,
|
|
1505
|
-
stackName: 'frigg-app-production',
|
|
1506
|
+
stackName: 'create-frigg-app-production',
|
|
1506
1507
|
existingLogicalIds: [
|
|
1507
1508
|
'FriggLambdaRouteTable',
|
|
1508
1509
|
'FriggNATRoute', // OLD naming
|
|
@@ -1565,9 +1566,10 @@ describe('VpcBuilder', () => {
|
|
|
1565
1566
|
});
|
|
1566
1567
|
|
|
1567
1568
|
it('should convert OLD logical IDs to structured discovery stackManaged array', () => {
|
|
1569
|
+
// TDD test: Verify that VPCEndpointS3 in existingLogicalIds gets added to stackManaged
|
|
1568
1570
|
const flatDiscovery = {
|
|
1569
1571
|
fromCloudFormationStack: true,
|
|
1570
|
-
stackName: 'frigg-app-production',
|
|
1572
|
+
stackName: 'create-frigg-app-production',
|
|
1571
1573
|
existingLogicalIds: [
|
|
1572
1574
|
'VPCEndpointS3', // OLD naming
|
|
1573
1575
|
'VPCEndpointDynamoDB', // OLD naming
|
|
@@ -746,7 +746,7 @@ describe('VpcResourceResolver', () => {
|
|
|
746
746
|
],
|
|
747
747
|
external: [],
|
|
748
748
|
fromCloudFormation: true,
|
|
749
|
-
stackName: 'frigg-app-production'
|
|
749
|
+
stackName: 'create-frigg-app-production'
|
|
750
750
|
};
|
|
751
751
|
|
|
752
752
|
const decisions = resolver.resolveAll(appDefinition, discovery);
|