@tamyla/clodo-framework 2.0.20 → 3.0.3

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 (54) hide show
  1. package/CHANGELOG.md +74 -0
  2. package/bin/clodo-service.js +1 -1
  3. package/bin/database/README.md +33 -0
  4. package/bin/database/deployment-db-manager.js +527 -0
  5. package/bin/database/enterprise-db-manager.js +736 -0
  6. package/bin/database/wrangler-d1-manager.js +775 -0
  7. package/bin/shared/cloudflare/domain-discovery.js +636 -0
  8. package/bin/shared/cloudflare/domain-manager.js +952 -0
  9. package/bin/shared/cloudflare/index.js +8 -0
  10. package/bin/shared/cloudflare/ops.js +359 -0
  11. package/bin/shared/config/index.js +1 -1
  12. package/bin/shared/database/connection-manager.js +374 -0
  13. package/bin/shared/database/index.js +7 -0
  14. package/bin/shared/database/orchestrator.js +726 -0
  15. package/bin/shared/deployment/auditor.js +969 -0
  16. package/bin/shared/deployment/index.js +10 -0
  17. package/bin/shared/deployment/rollback-manager.js +570 -0
  18. package/bin/shared/deployment/validator.js +779 -0
  19. package/bin/shared/index.js +32 -0
  20. package/bin/shared/monitoring/health-checker.js +484 -0
  21. package/bin/shared/monitoring/index.js +8 -0
  22. package/bin/shared/monitoring/memory-manager.js +387 -0
  23. package/bin/shared/monitoring/production-monitor.js +391 -0
  24. package/bin/shared/production-tester/api-tester.js +82 -0
  25. package/bin/shared/production-tester/auth-tester.js +132 -0
  26. package/bin/shared/production-tester/core.js +197 -0
  27. package/bin/shared/production-tester/database-tester.js +109 -0
  28. package/bin/shared/production-tester/index.js +77 -0
  29. package/bin/shared/production-tester/load-tester.js +131 -0
  30. package/bin/shared/production-tester/performance-tester.js +103 -0
  31. package/bin/shared/security/api-token-manager.js +312 -0
  32. package/bin/shared/security/index.js +8 -0
  33. package/bin/shared/security/secret-generator.js +937 -0
  34. package/bin/shared/security/secure-token-manager.js +398 -0
  35. package/bin/shared/utils/error-recovery.js +225 -0
  36. package/bin/shared/utils/graceful-shutdown-manager.js +390 -0
  37. package/bin/shared/utils/index.js +9 -0
  38. package/bin/shared/utils/interactive-prompts.js +146 -0
  39. package/bin/shared/utils/interactive-utils.js +530 -0
  40. package/bin/shared/utils/rate-limiter.js +246 -0
  41. package/dist/database/database-orchestrator.js +34 -12
  42. package/dist/deployment/index.js +2 -2
  43. package/dist/orchestration/multi-domain-orchestrator.js +26 -10
  44. package/dist/service-management/GenerationEngine.js +76 -28
  45. package/dist/service-management/ServiceInitializer.js +5 -3
  46. package/dist/shared/cloudflare/domain-manager.js +1 -1
  47. package/dist/shared/cloudflare/ops.js +27 -12
  48. package/dist/shared/config/index.js +1 -1
  49. package/dist/shared/deployment/index.js +2 -2
  50. package/dist/shared/security/secret-generator.js +4 -2
  51. package/dist/shared/utils/error-recovery.js +1 -1
  52. package/dist/shared/utils/graceful-shutdown-manager.js +4 -3
  53. package/dist/utils/deployment/secret-generator.js +19 -6
  54. package/package.json +4 -2
package/CHANGELOG.md CHANGED
@@ -1,3 +1,77 @@
1
+ ## [3.0.3](https://github.com/tamylaa/clodo-framework/compare/v3.0.2...v3.0.3) (2025-10-14)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+ * resolve database creation redundancy in deployments ([4a54f2c](https://github.com/tamylaa/clodo-framework/commit/4a54f2ce4bd1bb17d49c4d911171a01179fbd519))
7
+
8
+ ## [3.0.2](https://github.com/tamylaa/clodo-framework/compare/v3.0.1...v3.0.2) (2025-10-14)
9
+
10
+
11
+ ### Bug Fixes
12
+
13
+ * suppress secret audit logging in test/CI environments ([daa58e0](https://github.com/tamylaa/clodo-framework/commit/daa58e013f8c3c37bb251a658b78f011a56dab3f))
14
+
15
+ ## [3.0.1](https://github.com/tamylaa/clodo-framework/compare/v3.0.0...v3.0.1) (2025-10-14)
16
+
17
+
18
+ ### Bug Fixes
19
+
20
+ * reset version to 2.0.20 for clean semantic release ([724df16](https://github.com/tamylaa/clodo-framework/commit/724df162d3fdb4a35cfc50a2cc045a714c56ba6f))
21
+
22
+ # [3.0.0](https://github.com/tamylaa/clodo-framework/compare/v2.0.20...v3.0.0) (2025-10-14)
23
+
24
+
25
+ ### Bug Fixes
26
+
27
+ * include all bin/shared files and correct imports to use dist/ ([268b525](https://github.com/tamylaa/clodo-framework/commit/268b5254d269951e78d481840a9a0fbba486c879)), closes [#deploy-v3](https://github.com/tamylaa/clodo-framework/issues/deploy-v3)
28
+ * resolve async logging and migration command issues (v3.0.2) ([0ed0112](https://github.com/tamylaa/clodo-framework/commit/0ed0112b2d26983fbd1329dce88286d4eca6d63b))
29
+ * resolve test failures and add comprehensive validation ([5abcacb](https://github.com/tamylaa/clodo-framework/commit/5abcacb39f97bcf58f92a75a8ed2602381b6c266))
30
+ * use temp directory in generation-engine-unit test for CI/CD compatibility ([a28a923](https://github.com/tamylaa/clodo-framework/commit/a28a92311fa6d8b1c6bd95a354c5e7cd4ada3b48))
31
+
32
+
33
+ ### BREAKING CHANGES
34
+
35
+ * none
36
+ VALIDATION: Dry-run test PASSED with real Cloudflare API integration
37
+
38
+ Validation Reports:
39
+ - PRODUCTION_VALIDATION_REPORT.md - Full validation analysis
40
+ - DEPLOY_COMMAND_VALIDATION.md - Deploy command documentation
41
+ - DRY_RUN_TEST_RESULTS.md - Dry-run test with real API
42
+ - VALIDATION_SUMMARY.md - Executive summary
43
+
44
+ Confidence: 95% - Ready for production deployment
45
+
46
+ ## [3.0.1](https://github.com/tamylaa/clodo-framework/compare/v3.0.0...v3.0.1) (2025-10-14)
47
+
48
+
49
+ ### Bug Fixes
50
+
51
+ * include all bin/shared files and correct imports to use dist/ ([268b525](https://github.com/tamylaa/clodo-framework/commit/268b5254d269951e78d481840a9a0fbba486c879)), closes [#deploy-v3](https://github.com/tamylaa/clodo-framework/issues/deploy-v3)
52
+
53
+ # [3.0.0](https://github.com/tamylaa/clodo-framework/compare/v2.0.20...v3.0.0) (2025-10-14)
54
+
55
+
56
+ ### Bug Fixes
57
+
58
+ * resolve test failures and add comprehensive validation ([5abcacb](https://github.com/tamylaa/clodo-framework/commit/5abcacb39f97bcf58f92a75a8ed2602381b6c266))
59
+ * use temp directory in generation-engine-unit test for CI/CD compatibility ([a28a923](https://github.com/tamylaa/clodo-framework/commit/a28a92311fa6d8b1c6bd95a354c5e7cd4ada3b48))
60
+
61
+
62
+ ### BREAKING CHANGES
63
+
64
+ * none
65
+ VALIDATION: Dry-run test PASSED with real Cloudflare API integration
66
+
67
+ Validation Reports:
68
+ - PRODUCTION_VALIDATION_REPORT.md - Full validation analysis
69
+ - DEPLOY_COMMAND_VALIDATION.md - Deploy command documentation
70
+ - DRY_RUN_TEST_RESULTS.md - Dry-run test with real API
71
+ - VALIDATION_SUMMARY.md - Executive summary
72
+
73
+ Confidence: 95% - Ready for production deployment
74
+
1
75
  ## [2.0.20](https://github.com/tamylaa/clodo-framework/compare/v2.0.19...v2.0.20) (2025-10-13)
2
76
 
3
77
 
@@ -1,4 +1,4 @@
1
- #!/usr/bin/env node
1
+ #!/usr/bin/env node
2
2
 
3
3
  /**
4
4
  * Clodo Framework - Unified Three-Tier Service Management CLI
@@ -0,0 +1,33 @@
1
+ # Database Tools
2
+
3
+ Database management and operations tools for Clodo Framework services.
4
+
5
+ ## Tools
6
+
7
+ ### enterprise-db-manager.js
8
+ Enterprise database management CLI for Cloudflare D1 and other databases.
9
+
10
+ **Features:**
11
+ - Multi-database orchestration
12
+ - Schema management and migrations
13
+ - Backup and restore operations
14
+ - Performance monitoring and optimization
15
+ - Connection pooling and management
16
+ - Security and access control
17
+ - Audit logging and compliance
18
+
19
+ **Usage:**
20
+ ```bash
21
+ # Database operations
22
+ node bin/database/enterprise-db-manager.js migrate --service my-service
23
+ node bin/database/enterprise-db-manager.js backup --database my-db
24
+ node bin/database/enterprise-db-manager.js monitor --service my-service
25
+ ```
26
+
27
+ **Commands:**
28
+ - `migrate` - Run database migrations
29
+ - `backup` - Create database backups
30
+ - `restore` - Restore from backups
31
+ - `monitor` - Monitor database performance
32
+ - `schema` - Manage database schemas
33
+ - `connections` - Manage database connections
@@ -0,0 +1,527 @@
1
+ /**
2
+ * Deployment Database Manager Module
3
+ * Handles D1 database operations specifically during service deployment context.
4
+ *
5
+ * This module is focused on single-service deployment operations and works in coordination
6
+ * with the enterprise-db-manager.js for broader portfolio management tasks.
7
+ *
8
+ * Scope:
9
+ * - D1 database validation during deployment
10
+ * - Database configuration for specific service deployments
11
+ * - Deployment-time migrations and health checks
12
+ * - Integration with deployment orchestration
13
+ *
14
+ * For broader database management (monitoring, backups, multi-domain operations),
15
+ * use the enterprise-db-manager.js CLI tool.
16
+ */
17
+
18
+ import { promisify } from 'util';
19
+ import { exec } from 'child_process';
20
+ import { askYesNo, askChoice, askUser } from '../shared/utils/interactive-prompts.js';
21
+ import {
22
+ databaseExists,
23
+ createDatabase,
24
+ getDatabaseId,
25
+ runMigrations,
26
+ executeSql,
27
+ listDatabases,
28
+ deleteDatabase
29
+ } from '../shared/cloudflare/ops.js';
30
+
31
+ const execAsync = promisify(exec);
32
+
33
+ /**
34
+ * Manages all D1 database operations including creation, validation,
35
+ * migration management, and health checks
36
+ */
37
+ export class DeploymentDatabaseManager {
38
+ constructor(options = {}) {
39
+ this.options = options;
40
+ this.state = {
41
+ databasesChecked: [],
42
+ migrationsRun: false,
43
+ validationComplete: false
44
+ };
45
+ }
46
+
47
+ /**
48
+ * Handle comprehensive database setup and configuration
49
+ */
50
+ async handleDatabase(config) {
51
+ console.log('\nšŸ—„ļø Database Configuration');
52
+ console.log('=========================');
53
+
54
+ // Generate database name if not provided
55
+ if (!config.database.name) {
56
+ config.database.name = `${config.domain}-auth-db`;
57
+ }
58
+
59
+ console.log(`\nšŸ“‹ Database name: ${config.database.name}`);
60
+
61
+ const useGeneratedName = await askYesNo('Use this database name?', true);
62
+ if (!useGeneratedName) {
63
+ config.database.name = await askUser(
64
+ 'Enter custom database name',
65
+ config.database.name
66
+ );
67
+ }
68
+
69
+ // Check for existing database
70
+ console.log('\nšŸ” Checking for existing database...');
71
+
72
+ try {
73
+ const dbExists = await databaseExists(config.database.name);
74
+
75
+ if (dbExists) {
76
+ return await this.handleExistingDatabase(config);
77
+ } else {
78
+ return await this.handleNewDatabase(config);
79
+ }
80
+ } catch (error) {
81
+ throw new Error(`Database check failed: ${error.message}`);
82
+ }
83
+ }
84
+
85
+ /**
86
+ * Handle existing database scenario
87
+ */
88
+ async handleExistingDatabase(config) {
89
+ console.log(` šŸ“‹ Database '${config.database.name}' already exists`);
90
+
91
+ const databaseChoice = await askChoice(
92
+ 'What would you like to do with the existing database?',
93
+ [
94
+ 'Use the existing database (recommended)',
95
+ 'Create a new database with different name',
96
+ 'Delete existing and create new (DANGER: DATA LOSS)'
97
+ ],
98
+ 0
99
+ );
100
+
101
+ switch (databaseChoice) {
102
+ case 0: {
103
+ // Use existing database
104
+ return await this.useExistingDatabase(config);
105
+ }
106
+ case 1: {
107
+ // Create new database with different name
108
+ return await this.createNewDatabaseWithDifferentName(config);
109
+ }
110
+ case 2: {
111
+ // Delete existing and create new
112
+ return await this.deleteAndRecreateDatabase(config);
113
+ }
114
+ }
115
+ }
116
+
117
+ /**
118
+ * Use existing database
119
+ */
120
+ async useExistingDatabase(config) {
121
+ try {
122
+ // Extract database ID from the list command output
123
+ const dbListResult = await execAsync('npx wrangler d1 list');
124
+ const lines = dbListResult.stdout.split('\n');
125
+
126
+ for (const line of lines) {
127
+ if (line.includes(config.database.name)) {
128
+ const match = line.match(/([a-f0-9-]{36})/);
129
+ if (match) {
130
+ config.database.id = match[1];
131
+ console.log(` āœ… Using existing database ID: ${config.database.id}`);
132
+ break;
133
+ }
134
+ }
135
+ }
136
+
137
+ if (!config.database.id) {
138
+ throw new Error('Could not extract database ID from existing database');
139
+ }
140
+
141
+ // Check if migrations should be run
142
+ if (config.database.enableMigrations) {
143
+ const runMigs = await askYesNo(
144
+ 'Run pending migrations on existing database?',
145
+ true
146
+ );
147
+
148
+ if (runMigs) {
149
+ await this.runDatabaseMigrations(config);
150
+ }
151
+ }
152
+
153
+ return config.database;
154
+ } catch (error) {
155
+ throw new Error(`Failed to use existing database: ${error.message}`);
156
+ }
157
+ }
158
+
159
+ /**
160
+ * Create new database with different name
161
+ */
162
+ async createNewDatabaseWithDifferentName(config) {
163
+ const newName = await askUser('Enter new database name');
164
+ config.database.name = newName;
165
+ config.database.createNew = true;
166
+
167
+ return await this.handleNewDatabase(config);
168
+ }
169
+
170
+ /**
171
+ * Delete existing database and create new one
172
+ */
173
+ async deleteAndRecreateDatabase(config) {
174
+ const confirmDelete = await askYesNo(
175
+ 'āš ļø Are you ABSOLUTELY SURE? This will permanently delete ALL data!',
176
+ false
177
+ );
178
+
179
+ if (!confirmDelete) {
180
+ console.log(' āœ… Database deletion cancelled');
181
+ return await this.handleExistingDatabase(config);
182
+ }
183
+
184
+ // Additional confirmation
185
+ const doubleConfirm = await askUser(
186
+ `Type "${config.database.name}" to confirm deletion`
187
+ );
188
+
189
+ if (doubleConfirm !== config.database.name) {
190
+ console.log(' āŒ Database name mismatch. Deletion cancelled for safety.');
191
+ return await this.handleExistingDatabase(config);
192
+ }
193
+
194
+ try {
195
+ console.log(' šŸ—‘ļø Deleting existing database...');
196
+ await deleteDatabase(config.database.name);
197
+ console.log(' āœ… Database deleted');
198
+
199
+ // Now create new database
200
+ return await this.handleNewDatabase(config);
201
+ } catch (error) {
202
+ throw new Error(`Database deletion failed: ${error.message}`);
203
+ }
204
+ }
205
+
206
+ /**
207
+ * Handle new database creation
208
+ */
209
+ async handleNewDatabase(config) {
210
+ console.log(` āœ… Database name '${config.database.name}' is available`);
211
+
212
+ const shouldCreate = await askYesNo(
213
+ `Create new D1 database '${config.database.name}'?`,
214
+ true
215
+ );
216
+
217
+ if (!shouldCreate) {
218
+ throw new Error('Database creation cancelled by user');
219
+ }
220
+
221
+ try {
222
+ console.log(' šŸ”Ø Creating database...');
223
+ const createResult = await createDatabase(config.database.name);
224
+
225
+ if (createResult && createResult.success) {
226
+ config.database.id = createResult.id || await getDatabaseId(config.database.name);
227
+ console.log(` āœ… Database created successfully: ${config.database.id}`);
228
+
229
+ // Run initial migrations if enabled
230
+ if (config.database.enableMigrations) {
231
+ const runInitialMigrations = await askYesNo(
232
+ 'Run initial database migrations?',
233
+ true
234
+ );
235
+
236
+ if (runInitialMigrations) {
237
+ await this.runDatabaseMigrations(config);
238
+ }
239
+ }
240
+
241
+ return config.database;
242
+ } else {
243
+ throw new Error('Database creation returned unsuccessful result');
244
+ }
245
+ } catch (error) {
246
+ console.log(` āŒ Database creation failed: ${error.message}`);
247
+ throw new Error(`Database creation failed: ${error.message}`);
248
+ }
249
+ }
250
+
251
+ /**
252
+ * Run database migrations
253
+ */
254
+ async runDatabaseMigrations(config) {
255
+ console.log('\nšŸ”„ Running database migrations...');
256
+
257
+ try {
258
+ await runMigrations(config.database.name);
259
+ console.log(' āœ… Database migrations completed');
260
+ this.state.migrationsRun = true;
261
+ } catch (error) {
262
+ console.log(` āš ļø Migration warning: ${error.message}`);
263
+
264
+ const continueAnyway = await askYesNo(
265
+ 'Continue deployment despite migration issues?',
266
+ false
267
+ );
268
+
269
+ if (!continueAnyway) {
270
+ throw new Error(`Migration failed: ${error.message}`);
271
+ }
272
+
273
+ console.log(' āš ļø Continuing with migration warnings');
274
+ }
275
+ }
276
+
277
+ /**
278
+ * Validate database configuration and connectivity
279
+ */
280
+ async validateDatabaseConfiguration(config) {
281
+ console.log('\nšŸ” Validating database configuration...');
282
+
283
+ const validationResults = {
284
+ exists: false,
285
+ accessible: false,
286
+ migrationsApplied: false,
287
+ issues: []
288
+ };
289
+
290
+ try {
291
+ // Check if database exists
292
+ const exists = await databaseExists(config.database.name);
293
+ validationResults.exists = exists;
294
+
295
+ if (!exists) {
296
+ validationResults.issues.push(`Database '${config.database.name}' does not exist`);
297
+ return validationResults;
298
+ }
299
+
300
+ console.log(` āœ… Database '${config.database.name}' exists`);
301
+
302
+ // Test basic connectivity
303
+ try {
304
+ await executeSql(config.database.name, 'SELECT 1 as test');
305
+ validationResults.accessible = true;
306
+ console.log(' āœ… Database is accessible');
307
+ } catch (error) {
308
+ validationResults.issues.push(`Database connectivity test failed: ${error.message}`);
309
+ }
310
+
311
+ // Check migrations status if enabled
312
+ if (config.database.enableMigrations) {
313
+ try {
314
+ const migrationsResult = await execAsync(
315
+ `npx wrangler d1 migrations list ${config.database.name}`
316
+ );
317
+
318
+ if (migrationsResult.stdout.includes('Applied')) {
319
+ validationResults.migrationsApplied = true;
320
+ console.log(' āœ… Migrations are applied');
321
+ } else {
322
+ validationResults.issues.push('No migrations have been applied');
323
+ }
324
+ } catch (error) {
325
+ validationResults.issues.push(`Migration status check failed: ${error.message}`);
326
+ }
327
+ }
328
+
329
+ } catch (error) {
330
+ validationResults.issues.push(`Database validation failed: ${error.message}`);
331
+ }
332
+
333
+ this.state.validationComplete = true;
334
+ this.state.databasesChecked.push({
335
+ name: config.database.name,
336
+ results: validationResults,
337
+ timestamp: new Date().toISOString()
338
+ });
339
+
340
+ return validationResults;
341
+ }
342
+
343
+ /**
344
+ * Perform database health check
345
+ */
346
+ async performHealthCheck(config) {
347
+ console.log('\nšŸ„ Database Health Check');
348
+ console.log('========================');
349
+
350
+ const healthResults = {
351
+ overall: 'unknown',
352
+ connectivity: false,
353
+ responseTime: 0,
354
+ tableCount: 0,
355
+ issues: []
356
+ };
357
+
358
+ const startTime = Date.now();
359
+
360
+ try {
361
+ // Test basic query
362
+ await executeSql(config.database.name, 'SELECT 1 as health_check');
363
+ healthResults.connectivity = true;
364
+ healthResults.responseTime = Date.now() - startTime;
365
+
366
+ console.log(` āœ… Database responding (${healthResults.responseTime}ms)`);
367
+
368
+ // Count tables
369
+ try {
370
+ const tablesResult = await executeSql(
371
+ config.database.name,
372
+ "SELECT COUNT(*) as table_count FROM sqlite_master WHERE type='table'"
373
+ );
374
+
375
+ // Parse table count from result
376
+ if (tablesResult && tablesResult.results && tablesResult.results.length > 0) {
377
+ healthResults.tableCount = tablesResult.results[0].table_count || 0;
378
+ console.log(` šŸ“Š Database contains ${healthResults.tableCount} tables`);
379
+ }
380
+ } catch (error) {
381
+ healthResults.issues.push(`Table count check failed: ${error.message}`);
382
+ }
383
+
384
+ // Overall health determination
385
+ if (healthResults.connectivity && healthResults.responseTime < 5000) {
386
+ healthResults.overall = 'healthy';
387
+ } else if (healthResults.connectivity) {
388
+ healthResults.overall = 'slow';
389
+ } else {
390
+ healthResults.overall = 'unhealthy';
391
+ }
392
+
393
+ } catch (error) {
394
+ healthResults.overall = 'unhealthy';
395
+ healthResults.responseTime = Date.now() - startTime;
396
+ healthResults.issues.push(`Health check failed: ${error.message}`);
397
+ console.log(` āŒ Database health check failed: ${error.message}`);
398
+ }
399
+
400
+ return healthResults;
401
+ }
402
+
403
+ /**
404
+ * Get database management summary
405
+ */
406
+ getDatabaseSummary() {
407
+ return {
408
+ databasesManaged: this.state.databasesChecked.length,
409
+ migrationsRun: this.state.migrationsRun,
410
+ validationComplete: this.state.validationComplete,
411
+ lastCheck: this.state.databasesChecked.length > 0
412
+ ? this.state.databasesChecked[this.state.databasesChecked.length - 1].timestamp
413
+ : null
414
+ };
415
+ }
416
+
417
+ /**
418
+ * List all available databases
419
+ */
420
+ async listAvailableDatabases() {
421
+ try {
422
+ console.log('\nšŸ“‹ Available D1 Databases:');
423
+ const databases = await listDatabases();
424
+
425
+ if (databases && databases.length > 0) {
426
+ databases.forEach((db, index) => {
427
+ console.log(` ${index + 1}. ${db.name} (${db.id})`);
428
+ });
429
+ return databases;
430
+ } else {
431
+ console.log(' ā„¹ļø No D1 databases found in your account');
432
+ return [];
433
+ }
434
+ } catch (error) {
435
+ console.log(` āŒ Failed to list databases: ${error.message}`);
436
+ return [];
437
+ }
438
+ }
439
+
440
+ /**
441
+ * Interactive database selection from existing databases
442
+ */
443
+ async selectFromExistingDatabases(config) {
444
+ const databases = await this.listAvailableDatabases();
445
+
446
+ if (databases.length === 0) {
447
+ const createNew = await askYesNo(
448
+ 'No existing databases found. Create a new one?',
449
+ true
450
+ );
451
+
452
+ if (createNew) {
453
+ return await this.handleNewDatabase(config);
454
+ } else {
455
+ throw new Error('Database selection cancelled');
456
+ }
457
+ }
458
+
459
+ const dbOptions = databases.map(db => `${db.name} (${db.id})`);
460
+ dbOptions.push('Create new database');
461
+
462
+ const choice = await askChoice(
463
+ 'Select a database to use:',
464
+ dbOptions
465
+ );
466
+
467
+ if (choice === dbOptions.length - 1) {
468
+ // Create new database option selected
469
+ return await this.handleNewDatabase(config);
470
+ }
471
+
472
+ // Existing database selected
473
+ const selectedDb = databases[choice];
474
+ config.database.name = selectedDb.name;
475
+ config.database.id = selectedDb.id;
476
+
477
+ console.log(` āœ… Selected database: ${selectedDb.name} (${selectedDb.id})`);
478
+
479
+ // Check if migrations should be run
480
+ if (config.database.enableMigrations) {
481
+ const runMigrations = await askYesNo(
482
+ 'Run migrations on selected database?',
483
+ false
484
+ );
485
+
486
+ if (runMigrations) {
487
+ await this.runDatabaseMigrations(config);
488
+ }
489
+ }
490
+
491
+ return config.database;
492
+ }
493
+
494
+ /**
495
+ * Cleanup and rollback database operations
496
+ */
497
+ async rollbackDatabaseChanges(rollbackActions) {
498
+ console.log('\nšŸ”„ Rolling back database changes...');
499
+
500
+ const databaseRollbacks = rollbackActions.filter(action =>
501
+ action.type.includes('database') || action.type.includes('migration')
502
+ );
503
+
504
+ for (const action of databaseRollbacks) {
505
+ try {
506
+ console.log(` šŸ”„ ${action.description}`);
507
+
508
+ switch (action.type) {
509
+ case 'delete-database':
510
+ await deleteDatabase(action.name);
511
+ console.log(` āœ… Database '${action.name}' deleted`);
512
+ break;
513
+
514
+ case 'rollback-migration':
515
+ // Note: D1 doesn't support migration rollback, so we log this
516
+ console.log(` āš ļø Migration rollback not supported by D1: ${action.migration}`);
517
+ break;
518
+
519
+ default:
520
+ console.log(` āš ļø Unknown rollback action: ${action.type}`);
521
+ }
522
+ } catch (error) {
523
+ console.log(` āŒ Rollback failed: ${error.message}`);
524
+ }
525
+ }
526
+ }
527
+ }