@friggframework/devtools 2.0.0--canary.548.c8ae0ca.0 → 2.0.0--canary.545.c40eca4.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__/application/use-cases/AddApiModuleToIntegrationUseCase.test.js +326 -0
- package/frigg-cli/__tests__/application/use-cases/CreateApiModuleUseCase.test.js +337 -0
- package/frigg-cli/__tests__/domain/entities/ApiModule.test.js +373 -0
- package/frigg-cli/__tests__/domain/entities/AppDefinition.test.js +313 -0
- package/frigg-cli/__tests__/domain/services/IntegrationValidator.test.js +269 -0
- package/frigg-cli/__tests__/domain/value-objects/IntegrationName.test.js +82 -0
- package/frigg-cli/__tests__/infrastructure/adapters/IntegrationJsUpdater.test.js +408 -0
- package/frigg-cli/__tests__/infrastructure/repositories/FileSystemApiModuleRepository.test.js +583 -0
- package/frigg-cli/__tests__/infrastructure/repositories/FileSystemAppDefinitionRepository.test.js +314 -0
- package/frigg-cli/__tests__/infrastructure/repositories/FileSystemIntegrationRepository.test.js +383 -0
- package/frigg-cli/__tests__/unit/commands/build.test.js +1 -1
- package/frigg-cli/__tests__/unit/commands/doctor.test.js +0 -2
- package/frigg-cli/__tests__/unit/commands/init.test.js +406 -0
- package/frigg-cli/__tests__/unit/commands/install.test.js +23 -19
- package/frigg-cli/__tests__/unit/commands/provider-dispatch.test.js +383 -0
- package/frigg-cli/__tests__/unit/commands/repair.test.js +275 -0
- package/frigg-cli/__tests__/unit/dependencies.test.js +2 -2
- package/frigg-cli/__tests__/unit/start-command/application/RunPreflightChecksUseCase.test.js +411 -0
- package/frigg-cli/__tests__/unit/start-command/infrastructure/DatabaseAdapter.test.js +405 -0
- package/frigg-cli/__tests__/unit/start-command/infrastructure/DockerAdapter.test.js +496 -0
- package/frigg-cli/__tests__/unit/start-command/presentation/InteractivePromptAdapter.test.js +474 -0
- package/frigg-cli/__tests__/unit/utils/output.test.js +196 -0
- package/frigg-cli/application/use-cases/AddApiModuleToIntegrationUseCase.js +93 -0
- package/frigg-cli/application/use-cases/CreateApiModuleUseCase.js +93 -0
- package/frigg-cli/application/use-cases/CreateIntegrationUseCase.js +103 -0
- package/frigg-cli/build-command/index.js +123 -11
- package/frigg-cli/container.js +172 -0
- package/frigg-cli/deploy-command/index.js +83 -1
- package/frigg-cli/docs/OUTPUT_MIGRATION_GUIDE.md +286 -0
- package/frigg-cli/doctor-command/index.js +37 -16
- package/frigg-cli/domain/entities/ApiModule.js +272 -0
- package/frigg-cli/domain/entities/AppDefinition.js +227 -0
- package/frigg-cli/domain/entities/Integration.js +198 -0
- package/frigg-cli/domain/exceptions/DomainException.js +24 -0
- package/frigg-cli/domain/ports/IApiModuleRepository.js +53 -0
- package/frigg-cli/domain/ports/IAppDefinitionRepository.js +43 -0
- package/frigg-cli/domain/ports/IIntegrationRepository.js +61 -0
- package/frigg-cli/domain/services/IntegrationValidator.js +185 -0
- package/frigg-cli/domain/value-objects/IntegrationId.js +42 -0
- package/frigg-cli/domain/value-objects/IntegrationName.js +60 -0
- package/frigg-cli/domain/value-objects/SemanticVersion.js +70 -0
- package/frigg-cli/generate-iam-command.js +21 -1
- package/frigg-cli/index.js +21 -6
- package/frigg-cli/index.test.js +7 -2
- package/frigg-cli/infrastructure/UnitOfWork.js +46 -0
- package/frigg-cli/infrastructure/adapters/BackendJsUpdater.js +197 -0
- package/frigg-cli/infrastructure/adapters/FileSystemAdapter.js +224 -0
- package/frigg-cli/infrastructure/adapters/IntegrationJsUpdater.js +249 -0
- package/frigg-cli/infrastructure/adapters/SchemaValidator.js +92 -0
- package/frigg-cli/infrastructure/repositories/FileSystemApiModuleRepository.js +373 -0
- package/frigg-cli/infrastructure/repositories/FileSystemAppDefinitionRepository.js +116 -0
- package/frigg-cli/infrastructure/repositories/FileSystemIntegrationRepository.js +277 -0
- package/frigg-cli/init-command/backend-first-handler.js +124 -42
- package/frigg-cli/init-command/index.js +2 -1
- package/frigg-cli/init-command/template-handler.js +13 -3
- package/frigg-cli/install-command/backend-js.js +3 -3
- package/frigg-cli/install-command/environment-variables.js +16 -19
- package/frigg-cli/install-command/environment-variables.test.js +12 -13
- package/frigg-cli/install-command/index.js +14 -9
- package/frigg-cli/install-command/integration-file.js +3 -3
- package/frigg-cli/install-command/validate-package.js +5 -9
- package/frigg-cli/jest.config.js +4 -1
- package/frigg-cli/package-lock.json +16226 -0
- package/frigg-cli/repair-command/index.js +121 -128
- package/frigg-cli/start-command/application/RunPreflightChecksUseCase.js +376 -0
- package/frigg-cli/start-command/index.js +324 -2
- package/frigg-cli/start-command/infrastructure/DatabaseAdapter.js +591 -0
- package/frigg-cli/start-command/infrastructure/DockerAdapter.js +306 -0
- package/frigg-cli/start-command/presentation/InteractivePromptAdapter.js +329 -0
- package/frigg-cli/templates/backend/.env.example +62 -0
- package/frigg-cli/templates/backend/.eslintrc.json +12 -0
- package/frigg-cli/templates/backend/.prettierrc +6 -0
- package/frigg-cli/templates/backend/docker-compose.yml +22 -0
- package/frigg-cli/templates/backend/index.js +96 -0
- package/frigg-cli/templates/backend/infrastructure.js +12 -0
- package/frigg-cli/templates/backend/jest.config.js +17 -0
- package/frigg-cli/templates/backend/package.json +50 -0
- package/frigg-cli/templates/backend/src/api-modules/.gitkeep +10 -0
- package/frigg-cli/templates/backend/src/base/.gitkeep +7 -0
- package/frigg-cli/templates/backend/src/integrations/.gitkeep +10 -0
- package/frigg-cli/templates/backend/src/integrations/ExampleIntegration.js +65 -0
- package/frigg-cli/templates/backend/src/utils/.gitkeep +7 -0
- package/frigg-cli/templates/backend/test/setup.js +30 -0
- package/frigg-cli/templates/backend/ui-extensions/.gitkeep +0 -0
- package/frigg-cli/templates/backend/ui-extensions/README.md +77 -0
- package/frigg-cli/ui-command/index.js +58 -36
- package/frigg-cli/utils/__tests__/provider-helper.test.js +55 -0
- package/frigg-cli/utils/__tests__/repo-detection.test.js +436 -0
- package/frigg-cli/utils/output.js +382 -0
- package/frigg-cli/utils/provider-helper.js +75 -0
- package/frigg-cli/utils/repo-detection.js +85 -37
- package/frigg-cli/validate-command/__tests__/adapters/validate-command.test.js +205 -0
- package/frigg-cli/validate-command/__tests__/application/validate-app-use-case.test.js +104 -0
- package/frigg-cli/validate-command/__tests__/domain/fix-suggestion.test.js +153 -0
- package/frigg-cli/validate-command/__tests__/domain/validation-error.test.js +162 -0
- package/frigg-cli/validate-command/__tests__/domain/validation-result.test.js +152 -0
- package/frigg-cli/validate-command/__tests__/infrastructure/api-module-validator.test.js +332 -0
- package/frigg-cli/validate-command/__tests__/infrastructure/app-definition-validator.test.js +191 -0
- package/frigg-cli/validate-command/__tests__/infrastructure/integration-class-validator.test.js +146 -0
- package/frigg-cli/validate-command/__tests__/infrastructure/template-validation.test.js +155 -0
- package/frigg-cli/validate-command/adapters/cli/validate-command.js +199 -0
- package/frigg-cli/validate-command/application/use-cases/validate-app-use-case.js +35 -0
- package/frigg-cli/validate-command/domain/entities/validation-result.js +74 -0
- package/frigg-cli/validate-command/domain/value-objects/fix-suggestion.js +74 -0
- package/frigg-cli/validate-command/domain/value-objects/validation-error.js +68 -0
- package/frigg-cli/validate-command/infrastructure/validators/api-module-validator.js +181 -0
- package/frigg-cli/validate-command/infrastructure/validators/app-definition-validator.js +128 -0
- package/frigg-cli/validate-command/infrastructure/validators/integration-class-validator.js +113 -0
- package/infrastructure/create-frigg-infrastructure.js +93 -0
- package/infrastructure/docs/iam-policy-templates.md +1 -1
- package/infrastructure/domains/admin-scripts/admin-script-builder.js +200 -0
- package/infrastructure/domains/admin-scripts/admin-script-builder.test.js +499 -0
- package/infrastructure/domains/admin-scripts/index.js +5 -0
- package/infrastructure/domains/networking/vpc-builder.test.js +2 -4
- package/infrastructure/domains/networking/vpc-resolver.test.js +1 -1
- package/infrastructure/domains/shared/resource-discovery.js +5 -5
- package/infrastructure/domains/shared/types/app-definition.js +21 -0
- package/infrastructure/domains/shared/types/discovery-result.test.js +1 -1
- package/infrastructure/domains/shared/utilities/base-definition-factory.js +10 -1
- package/infrastructure/domains/shared/utilities/base-definition-factory.test.js +2 -2
- package/infrastructure/infrastructure-composer.js +2 -0
- package/infrastructure/infrastructure-composer.test.js +2 -2
- package/infrastructure/jest.config.js +16 -0
- package/management-ui/README.md +245 -109
- package/package.json +8 -7
- package/frigg-cli/install-command/logger.js +0 -12
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
const { spawn } = require('node:child_process');
|
|
2
2
|
const path = require('node:path');
|
|
3
|
+
const fs = require('node:fs');
|
|
3
4
|
const dotenv = require('dotenv');
|
|
4
5
|
const chalk = require('chalk');
|
|
5
6
|
const {
|
|
@@ -13,6 +14,12 @@ const {
|
|
|
13
14
|
getPrismaClientNotGeneratedError
|
|
14
15
|
} = require('../utils/error-messages');
|
|
15
16
|
|
|
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
|
+
|
|
16
23
|
async function startCommand(options) {
|
|
17
24
|
if (options.verbose) {
|
|
18
25
|
console.log('Verbose mode enabled');
|
|
@@ -25,7 +32,26 @@ async function startCommand(options) {
|
|
|
25
32
|
const envPath = path.join(process.cwd(), '.env');
|
|
26
33
|
dotenv.config({ path: envPath });
|
|
27
34
|
|
|
28
|
-
|
|
35
|
+
const projectPath = process.cwd();
|
|
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)
|
|
29
55
|
try {
|
|
30
56
|
await performDatabaseChecks(options.verbose);
|
|
31
57
|
} catch (error) {
|
|
@@ -34,9 +60,16 @@ async function startCommand(options) {
|
|
|
34
60
|
process.exit(1);
|
|
35
61
|
}
|
|
36
62
|
|
|
37
|
-
console.log(chalk.green('✓
|
|
63
|
+
console.log(chalk.green('✓ Pre-flight checks passed\n'));
|
|
38
64
|
console.log('Starting backend and optional frontend...');
|
|
39
65
|
|
|
66
|
+
// Check if the app uses a non-AWS provider
|
|
67
|
+
const providerResult = loadProviderIfConfigured();
|
|
68
|
+
if (providerResult) {
|
|
69
|
+
return startWithProvider(providerResult, options);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// Default: AWS local development via serverless-offline
|
|
40
73
|
// Suppress AWS SDK warning message about maintenance mode
|
|
41
74
|
process.env.AWS_SDK_JS_SUPPRESS_MAINTENANCE_MODE_MESSAGE = '1';
|
|
42
75
|
// Skip AWS discovery for local development
|
|
@@ -83,6 +116,295 @@ async function startCommand(options) {
|
|
|
83
116
|
});
|
|
84
117
|
}
|
|
85
118
|
|
|
119
|
+
/**
|
|
120
|
+
* Check if the appDefinition specifies a non-AWS provider and resolve it.
|
|
121
|
+
* Returns null for AWS (default) so the caller falls through to existing behavior.
|
|
122
|
+
*/
|
|
123
|
+
function loadProviderIfConfigured() {
|
|
124
|
+
try {
|
|
125
|
+
const { loadProviderForCli } = require('../utils/provider-helper');
|
|
126
|
+
const result = loadProviderForCli();
|
|
127
|
+
if (result && result.provider) {
|
|
128
|
+
return result;
|
|
129
|
+
}
|
|
130
|
+
} catch {
|
|
131
|
+
// Provider helper not available or appDefinition not found — fall through
|
|
132
|
+
}
|
|
133
|
+
return null;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Start local dev server using the provider's recommended approach.
|
|
138
|
+
* Each provider has a different local dev story:
|
|
139
|
+
* - Netlify: `netlify dev` (reads netlify.toml, serves functions locally)
|
|
140
|
+
* - AWS: `osls offline` (serverless-offline, handled by default path above)
|
|
141
|
+
*/
|
|
142
|
+
function startWithProvider({ provider, providerName }, options) {
|
|
143
|
+
const backendPath = path.resolve(process.cwd());
|
|
144
|
+
|
|
145
|
+
// Provider-specific dev server commands
|
|
146
|
+
const DEV_COMMANDS = {
|
|
147
|
+
netlify: { command: 'netlify', args: ['dev'] },
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
const devCmd = DEV_COMMANDS[providerName];
|
|
151
|
+
if (!devCmd) {
|
|
152
|
+
console.error(chalk.red(
|
|
153
|
+
`Provider '${providerName}' does not have a local dev server configured.\n` +
|
|
154
|
+
` Supported providers for local dev: ${Object.keys(DEV_COMMANDS).join(', ')}, aws`
|
|
155
|
+
));
|
|
156
|
+
process.exit(1);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
console.log(chalk.blue(`Starting local dev server (${providerName})...`));
|
|
160
|
+
|
|
161
|
+
const args = [...devCmd.args];
|
|
162
|
+
if (options.verbose) {
|
|
163
|
+
console.log(`Executing command: ${devCmd.command} ${args.join(' ')}`);
|
|
164
|
+
console.log(`Working directory: ${backendPath}`);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
const childProcess = spawn(devCmd.command, args, {
|
|
168
|
+
cwd: backendPath,
|
|
169
|
+
stdio: 'inherit',
|
|
170
|
+
env: { ...process.env },
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
childProcess.on('error', (error) => {
|
|
174
|
+
if (error.code === 'ENOENT') {
|
|
175
|
+
console.error(chalk.red(
|
|
176
|
+
`'${devCmd.command}' not found. Install it with: npm install -g ${devCmd.command}-cli`
|
|
177
|
+
));
|
|
178
|
+
} else {
|
|
179
|
+
console.error(`Error executing command: ${error.message}`);
|
|
180
|
+
}
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
childProcess.on('close', (code) => {
|
|
184
|
+
if (code !== 0) {
|
|
185
|
+
console.log(`Child process exited with code ${code}`);
|
|
186
|
+
}
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* Run interactive pre-flight checks with resolution prompts
|
|
192
|
+
* @param {string} projectPath - Path to the Frigg project
|
|
193
|
+
* @param {object} options - Command options
|
|
194
|
+
* @returns {Promise<boolean>} True if all checks pass or were resolved
|
|
195
|
+
*/
|
|
196
|
+
async function runInteractivePreflightChecks(projectPath, options) {
|
|
197
|
+
// Create adapters and use case
|
|
198
|
+
const dockerAdapter = new DockerAdapter();
|
|
199
|
+
const databaseAdapter = new DatabaseAdapter();
|
|
200
|
+
const preflightUseCase = new RunPreflightChecksUseCase({
|
|
201
|
+
dockerAdapter,
|
|
202
|
+
databaseAdapter
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
// Create prompt adapter based on mode (terminal or IPC)
|
|
206
|
+
const promptMode = options.ipc ? 'ipc' : 'terminal';
|
|
207
|
+
const promptAdapter = InteractivePromptAdapter.create({ mode: promptMode });
|
|
208
|
+
|
|
209
|
+
if (options.verbose) {
|
|
210
|
+
console.log(chalk.gray('Running pre-flight checks...'));
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
// Track which checks we've already processed to avoid infinite loops
|
|
214
|
+
const processedChecks = new Set();
|
|
215
|
+
|
|
216
|
+
// Keep running checks and resolving issues until all pass or no more can be resolved
|
|
217
|
+
let maxIterations = 10; // Safety limit to prevent infinite loops
|
|
218
|
+
while (maxIterations > 0) {
|
|
219
|
+
maxIterations--;
|
|
220
|
+
|
|
221
|
+
// Run checks
|
|
222
|
+
const result = await preflightUseCase.execute({ projectPath });
|
|
223
|
+
|
|
224
|
+
// If all passed, we're done
|
|
225
|
+
if (result.allPassed) {
|
|
226
|
+
return true;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
// Get resolvable checks that we haven't already processed
|
|
230
|
+
const resolvableChecks = preflightUseCase.getResolvableChecks(result)
|
|
231
|
+
.filter(check => !processedChecks.has(check.name));
|
|
232
|
+
|
|
233
|
+
// If no new resolvable checks, show failures and exit
|
|
234
|
+
if (resolvableChecks.length === 0) {
|
|
235
|
+
const failedChecks = result.checks.filter(c => c.status === 'failed');
|
|
236
|
+
for (const check of failedChecks) {
|
|
237
|
+
console.log(chalk.red(` ✗ ${check.name}: ${check.message}`));
|
|
238
|
+
if (check.resolution?.instructions) {
|
|
239
|
+
console.log(chalk.gray(` ${check.resolution.instructions}`));
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
return false;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
// Process the first resolvable check
|
|
246
|
+
const check = resolvableChecks[0];
|
|
247
|
+
processedChecks.add(check.name);
|
|
248
|
+
|
|
249
|
+
// Display the failure
|
|
250
|
+
console.log(chalk.yellow(`\n⚠️ ${check.message}`));
|
|
251
|
+
|
|
252
|
+
// Only prompt if check is resolvable
|
|
253
|
+
if (!check.canResolve) {
|
|
254
|
+
if (check.resolution?.instructions) {
|
|
255
|
+
console.log(chalk.gray(` ${check.resolution.instructions}`));
|
|
256
|
+
}
|
|
257
|
+
continue;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
// Ask user if they want to resolve
|
|
261
|
+
const response = await promptAdapter.promptForResolution(check);
|
|
262
|
+
|
|
263
|
+
if (!response.shouldResolve) {
|
|
264
|
+
console.log(chalk.gray(' Skipping resolution'));
|
|
265
|
+
// User declined, show remaining failures and exit
|
|
266
|
+
const failedChecks = result.checks.filter(c => c.status === 'failed');
|
|
267
|
+
for (const failedCheck of failedChecks) {
|
|
268
|
+
if (failedCheck.name !== check.name) {
|
|
269
|
+
console.log(chalk.red(` ✗ ${failedCheck.name}: ${failedCheck.message}`));
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
return false;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
// Execute the resolution
|
|
276
|
+
const resolved = await executeResolution(check, dockerAdapter, options);
|
|
277
|
+
|
|
278
|
+
if (!resolved) {
|
|
279
|
+
return false;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
// Loop will continue and re-run checks
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
// If we exhausted iterations, something went wrong
|
|
286
|
+
console.log(chalk.yellow(' ⚠️ Pre-flight check loop limit reached'));
|
|
287
|
+
return false;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
/**
|
|
291
|
+
* Execute a resolution action
|
|
292
|
+
* @param {object} check - The check that failed
|
|
293
|
+
* @param {DockerAdapter} dockerAdapter - Docker adapter
|
|
294
|
+
* @param {object} options - Command options
|
|
295
|
+
* @returns {Promise<boolean>} True if resolution succeeded
|
|
296
|
+
*/
|
|
297
|
+
async function executeResolution(check, dockerAdapter, options) {
|
|
298
|
+
const { resolution } = check;
|
|
299
|
+
|
|
300
|
+
switch (resolution.type) {
|
|
301
|
+
case 'start_docker':
|
|
302
|
+
console.log(chalk.blue(' Starting Docker Desktop...'));
|
|
303
|
+
const dockerResult = await dockerAdapter.startDockerDesktop();
|
|
304
|
+
if (!dockerResult.success) {
|
|
305
|
+
console.error(chalk.red(` Failed to start Docker: ${dockerResult.error}`));
|
|
306
|
+
return false;
|
|
307
|
+
}
|
|
308
|
+
// Wait for Docker to be ready
|
|
309
|
+
console.log(chalk.gray(' Waiting for Docker to start...'));
|
|
310
|
+
const isReady = await dockerAdapter.waitForDockerReady({
|
|
311
|
+
maxAttempts: 60,
|
|
312
|
+
intervalMs: 1000
|
|
313
|
+
});
|
|
314
|
+
if (!isReady) {
|
|
315
|
+
console.error(chalk.red(' Docker did not start in time'));
|
|
316
|
+
return false;
|
|
317
|
+
}
|
|
318
|
+
console.log(chalk.green(' ✓ Docker is now running'));
|
|
319
|
+
return true;
|
|
320
|
+
|
|
321
|
+
case 'start_docker_compose':
|
|
322
|
+
console.log(chalk.blue(' Starting Docker Compose services...'));
|
|
323
|
+
const composeResult = await dockerAdapter.startDockerCompose(resolution.composePath);
|
|
324
|
+
if (!composeResult.success) {
|
|
325
|
+
console.error(chalk.red(` Failed to start services: ${composeResult.error}`));
|
|
326
|
+
return false;
|
|
327
|
+
}
|
|
328
|
+
console.log(chalk.green(' ✓ Docker Compose services started'));
|
|
329
|
+
// Poll LocalStack health endpoint until services are ready
|
|
330
|
+
console.log(chalk.gray(' Waiting for LocalStack to initialize...'));
|
|
331
|
+
const localstackResult = await dockerAdapter.waitForLocalStack({
|
|
332
|
+
maxAttempts: 30,
|
|
333
|
+
intervalMs: 2000
|
|
334
|
+
});
|
|
335
|
+
if (localstackResult.ready) {
|
|
336
|
+
console.log(chalk.green(' ✓ LocalStack services ready'));
|
|
337
|
+
if (options.verbose && localstackResult.services) {
|
|
338
|
+
console.log(chalk.gray(` Services: ${Object.keys(localstackResult.services).join(', ')}`));
|
|
339
|
+
}
|
|
340
|
+
} else {
|
|
341
|
+
console.log(chalk.yellow(' ⚠️ LocalStack may not be fully ready'));
|
|
342
|
+
if (localstackResult.error) {
|
|
343
|
+
console.log(chalk.gray(` ${localstackResult.error}`));
|
|
344
|
+
}
|
|
345
|
+
// Continue anyway - the service might still work
|
|
346
|
+
}
|
|
347
|
+
return true;
|
|
348
|
+
|
|
349
|
+
case 'create_env':
|
|
350
|
+
// Try to copy .env.example to .env
|
|
351
|
+
const projectPath = process.cwd();
|
|
352
|
+
const envExamplePath = path.join(projectPath, '.env.example');
|
|
353
|
+
const envPath = path.join(projectPath, '.env');
|
|
354
|
+
|
|
355
|
+
if (fs.existsSync(envExamplePath)) {
|
|
356
|
+
try {
|
|
357
|
+
fs.copyFileSync(envExamplePath, envPath);
|
|
358
|
+
console.log(chalk.green(' ✓ Created .env file from .env.example'));
|
|
359
|
+
console.log(chalk.yellow(' ⚠️ Please edit .env to set your DATABASE_URL'));
|
|
360
|
+
|
|
361
|
+
// Reload environment variables from the new .env file
|
|
362
|
+
dotenv.config({ path: envPath, override: true });
|
|
363
|
+
|
|
364
|
+
// Check if DATABASE_URL is now set
|
|
365
|
+
if (process.env.DATABASE_URL && process.env.DATABASE_URL.trim() !== '') {
|
|
366
|
+
console.log(chalk.green(' ✓ DATABASE_URL is now configured'));
|
|
367
|
+
return true;
|
|
368
|
+
} else {
|
|
369
|
+
console.log(chalk.yellow(' ⚠️ DATABASE_URL is still not set in .env'));
|
|
370
|
+
console.log(chalk.gray(' Please edit .env and set DATABASE_URL, then try again'));
|
|
371
|
+
return false;
|
|
372
|
+
}
|
|
373
|
+
} catch (err) {
|
|
374
|
+
console.error(chalk.red(` Failed to create .env: ${err.message}`));
|
|
375
|
+
return false;
|
|
376
|
+
}
|
|
377
|
+
} else {
|
|
378
|
+
console.log(chalk.yellow(' No .env.example file found'));
|
|
379
|
+
console.log(chalk.gray(' Please create a .env file manually with DATABASE_URL'));
|
|
380
|
+
return false;
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
case 'run_migrations':
|
|
384
|
+
console.log(chalk.blue(' Running PostgreSQL migrations...'));
|
|
385
|
+
const databaseAdapter = new DatabaseAdapter();
|
|
386
|
+
const migrationProjectPath = process.cwd();
|
|
387
|
+
|
|
388
|
+
// Use deploy mode (default) - non-interactive, applies existing migrations
|
|
389
|
+
const migrateResult = await databaseAdapter.runMigrations(migrationProjectPath);
|
|
390
|
+
|
|
391
|
+
if (!migrateResult.success) {
|
|
392
|
+
console.error(chalk.red(` Failed to run migrations: ${migrateResult.error}`));
|
|
393
|
+
console.log(chalk.gray(' Try running "frigg db:setup" manually'));
|
|
394
|
+
return false;
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
console.log(chalk.green(' ✓ Database migrations applied successfully'));
|
|
398
|
+
return true;
|
|
399
|
+
|
|
400
|
+
default:
|
|
401
|
+
if (options.verbose) {
|
|
402
|
+
console.log(chalk.gray(` Unknown resolution type: ${resolution.type}`));
|
|
403
|
+
}
|
|
404
|
+
return false;
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
|
|
86
408
|
/**
|
|
87
409
|
* Performs pre-flight database validation checks
|
|
88
410
|
* @param {boolean} verbose - Enable verbose output
|