appwrite-utils-cli 1.11.0 → 1.12.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/{src/adapters/index.ts → dist/adapters/index.d.ts} +0 -1
- package/dist/adapters/index.js +10 -0
- package/dist/backups/operations/bucketBackup.d.ts +19 -0
- package/dist/backups/operations/bucketBackup.js +197 -0
- package/dist/backups/operations/collectionBackup.d.ts +30 -0
- package/dist/backups/operations/collectionBackup.js +201 -0
- package/dist/backups/operations/comprehensiveBackup.d.ts +25 -0
- package/dist/backups/operations/comprehensiveBackup.js +238 -0
- package/dist/backups/schemas/bucketManifest.d.ts +93 -0
- package/dist/backups/schemas/bucketManifest.js +33 -0
- package/dist/backups/schemas/comprehensiveManifest.d.ts +108 -0
- package/dist/backups/schemas/comprehensiveManifest.js +32 -0
- package/dist/backups/tracking/centralizedTracking.d.ts +34 -0
- package/dist/backups/tracking/centralizedTracking.js +274 -0
- package/dist/cli/commands/configCommands.d.ts +8 -0
- package/dist/cli/commands/configCommands.js +210 -0
- package/dist/cli/commands/databaseCommands.d.ts +14 -0
- package/dist/cli/commands/databaseCommands.js +696 -0
- package/dist/cli/commands/functionCommands.d.ts +7 -0
- package/dist/cli/commands/functionCommands.js +330 -0
- package/dist/cli/commands/importFileCommands.d.ts +7 -0
- package/dist/cli/commands/importFileCommands.js +674 -0
- package/dist/cli/commands/schemaCommands.d.ts +7 -0
- package/dist/cli/commands/schemaCommands.js +169 -0
- package/dist/cli/commands/storageCommands.d.ts +5 -0
- package/dist/cli/commands/storageCommands.js +142 -0
- package/dist/cli/commands/transferCommands.d.ts +5 -0
- package/dist/cli/commands/transferCommands.js +382 -0
- package/dist/collections/columns.d.ts +13 -0
- package/dist/collections/columns.js +1339 -0
- package/dist/collections/indexes.d.ts +12 -0
- package/dist/collections/indexes.js +215 -0
- package/dist/collections/methods.d.ts +19 -0
- package/dist/collections/methods.js +605 -0
- package/dist/collections/tableOperations.d.ts +87 -0
- package/dist/collections/tableOperations.js +466 -0
- package/dist/collections/transferOperations.d.ts +8 -0
- package/dist/collections/transferOperations.js +411 -0
- package/dist/collections/wipeOperations.d.ts +17 -0
- package/dist/collections/wipeOperations.js +306 -0
- package/dist/databases/methods.d.ts +6 -0
- package/dist/databases/methods.js +35 -0
- package/dist/databases/setup.d.ts +5 -0
- package/dist/databases/setup.js +45 -0
- package/dist/examples/yamlTerminologyExample.d.ts +42 -0
- package/dist/examples/yamlTerminologyExample.js +272 -0
- package/dist/functions/deployments.d.ts +4 -0
- package/dist/functions/deployments.js +146 -0
- package/dist/functions/fnConfigDiscovery.d.ts +3 -0
- package/dist/functions/fnConfigDiscovery.js +108 -0
- package/dist/functions/methods.d.ts +16 -0
- package/dist/functions/methods.js +174 -0
- package/dist/init.d.ts +2 -0
- package/dist/init.js +57 -0
- package/dist/interactiveCLI.d.ts +36 -0
- package/dist/interactiveCLI.js +952 -0
- package/dist/main.d.ts +2 -0
- package/dist/main.js +1125 -0
- package/dist/migrations/afterImportActions.d.ts +17 -0
- package/dist/migrations/afterImportActions.js +305 -0
- package/dist/migrations/appwriteToX.d.ts +211 -0
- package/dist/migrations/appwriteToX.js +493 -0
- package/dist/migrations/comprehensiveTransfer.d.ts +147 -0
- package/dist/migrations/comprehensiveTransfer.js +1315 -0
- package/dist/migrations/dataLoader.d.ts +755 -0
- package/dist/migrations/dataLoader.js +1272 -0
- package/dist/migrations/importController.d.ts +25 -0
- package/dist/migrations/importController.js +283 -0
- package/dist/migrations/importDataActions.d.ts +50 -0
- package/dist/migrations/importDataActions.js +230 -0
- package/dist/migrations/relationships.d.ts +29 -0
- package/dist/migrations/relationships.js +203 -0
- package/dist/migrations/services/DataTransformationService.d.ts +55 -0
- package/dist/migrations/services/DataTransformationService.js +158 -0
- package/dist/migrations/services/FileHandlerService.d.ts +75 -0
- package/dist/migrations/services/FileHandlerService.js +236 -0
- package/dist/migrations/services/ImportOrchestrator.d.ts +99 -0
- package/dist/migrations/services/ImportOrchestrator.js +493 -0
- package/dist/migrations/services/RateLimitManager.d.ts +138 -0
- package/dist/migrations/services/RateLimitManager.js +279 -0
- package/dist/migrations/services/RelationshipResolver.d.ts +120 -0
- package/dist/migrations/services/RelationshipResolver.js +332 -0
- package/dist/migrations/services/UserMappingService.d.ts +109 -0
- package/dist/migrations/services/UserMappingService.js +277 -0
- package/dist/migrations/services/ValidationService.d.ts +74 -0
- package/dist/migrations/services/ValidationService.js +260 -0
- package/dist/migrations/transfer.d.ts +30 -0
- package/dist/migrations/transfer.js +661 -0
- package/dist/migrations/yaml/YamlImportConfigLoader.d.ts +131 -0
- package/dist/migrations/yaml/YamlImportConfigLoader.js +383 -0
- package/dist/migrations/yaml/YamlImportIntegration.d.ts +93 -0
- package/dist/migrations/yaml/YamlImportIntegration.js +341 -0
- package/dist/migrations/yaml/generateImportSchemas.d.ts +30 -0
- package/dist/migrations/yaml/generateImportSchemas.js +1327 -0
- package/dist/schemas/authUser.d.ts +24 -0
- package/dist/schemas/authUser.js +17 -0
- package/dist/setup.d.ts +2 -0
- package/{src/setup.ts → dist/setup.js} +0 -3
- package/dist/setupCommands.d.ts +58 -0
- package/dist/setupCommands.js +489 -0
- package/dist/setupController.d.ts +9 -0
- package/dist/setupController.js +34 -0
- package/dist/shared/backupMetadataSchema.d.ts +94 -0
- package/dist/shared/backupMetadataSchema.js +38 -0
- package/dist/shared/backupTracking.d.ts +18 -0
- package/dist/shared/backupTracking.js +176 -0
- package/dist/shared/confirmationDialogs.d.ts +75 -0
- package/dist/shared/confirmationDialogs.js +236 -0
- package/dist/shared/migrationHelpers.d.ts +61 -0
- package/dist/shared/migrationHelpers.js +145 -0
- package/{src/shared/operationLogger.ts → dist/shared/operationLogger.d.ts} +1 -11
- package/dist/shared/operationLogger.js +12 -0
- package/dist/shared/operationQueue.d.ts +40 -0
- package/dist/shared/operationQueue.js +310 -0
- package/dist/shared/operationsTable.d.ts +26 -0
- package/dist/shared/operationsTable.js +287 -0
- package/dist/shared/operationsTableSchema.d.ts +48 -0
- package/dist/shared/operationsTableSchema.js +35 -0
- package/dist/shared/progressManager.d.ts +62 -0
- package/dist/shared/progressManager.js +215 -0
- package/dist/shared/relationshipExtractor.d.ts +56 -0
- package/dist/shared/relationshipExtractor.js +138 -0
- package/dist/shared/selectionDialogs.d.ts +220 -0
- package/dist/shared/selectionDialogs.js +588 -0
- package/dist/storage/backupCompression.d.ts +20 -0
- package/dist/storage/backupCompression.js +67 -0
- package/dist/storage/methods.d.ts +44 -0
- package/dist/storage/methods.js +475 -0
- package/dist/storage/schemas.d.ts +842 -0
- package/dist/storage/schemas.js +175 -0
- package/dist/tables/indexManager.d.ts +65 -0
- package/dist/tables/indexManager.js +294 -0
- package/{src/types.ts → dist/types.d.ts} +1 -6
- package/dist/types.js +3 -0
- package/dist/users/methods.d.ts +16 -0
- package/dist/users/methods.js +276 -0
- package/dist/utils/configMigration.d.ts +1 -0
- package/dist/utils/configMigration.js +261 -0
- package/dist/utils/index.js +2 -0
- package/dist/utils/loadConfigs.d.ts +50 -0
- package/dist/utils/loadConfigs.js +357 -0
- package/dist/utils/setupFiles.d.ts +4 -0
- package/dist/utils/setupFiles.js +1190 -0
- package/dist/utilsController.d.ts +114 -0
- package/dist/utilsController.js +898 -0
- package/package.json +6 -3
- package/CHANGELOG.md +0 -35
- package/CONFIG_TODO.md +0 -1189
- package/SELECTION_DIALOGS.md +0 -146
- package/SERVICE_IMPLEMENTATION_REPORT.md +0 -462
- package/scripts/copy-templates.ts +0 -23
- package/src/backups/operations/bucketBackup.ts +0 -277
- package/src/backups/operations/collectionBackup.ts +0 -310
- package/src/backups/operations/comprehensiveBackup.ts +0 -342
- package/src/backups/schemas/bucketManifest.ts +0 -78
- package/src/backups/schemas/comprehensiveManifest.ts +0 -76
- package/src/backups/tracking/centralizedTracking.ts +0 -352
- package/src/cli/commands/configCommands.ts +0 -265
- package/src/cli/commands/databaseCommands.ts +0 -931
- package/src/cli/commands/functionCommands.ts +0 -419
- package/src/cli/commands/importFileCommands.ts +0 -815
- package/src/cli/commands/schemaCommands.ts +0 -200
- package/src/cli/commands/storageCommands.ts +0 -151
- package/src/cli/commands/transferCommands.ts +0 -454
- package/src/collections/attributes.ts.backup +0 -1555
- package/src/collections/columns.ts +0 -2025
- package/src/collections/indexes.ts +0 -350
- package/src/collections/methods.ts +0 -714
- package/src/collections/tableOperations.ts +0 -542
- package/src/collections/transferOperations.ts +0 -589
- package/src/collections/wipeOperations.ts +0 -449
- package/src/databases/methods.ts +0 -49
- package/src/databases/setup.ts +0 -77
- package/src/examples/yamlTerminologyExample.ts +0 -346
- package/src/functions/deployments.ts +0 -221
- package/src/functions/fnConfigDiscovery.ts +0 -103
- package/src/functions/methods.ts +0 -284
- package/src/init.ts +0 -62
- package/src/interactiveCLI.ts +0 -1201
- package/src/main.ts +0 -1517
- package/src/migrations/afterImportActions.ts +0 -579
- package/src/migrations/appwriteToX.ts +0 -668
- package/src/migrations/comprehensiveTransfer.ts +0 -2285
- package/src/migrations/dataLoader.ts +0 -1729
- package/src/migrations/importController.ts +0 -440
- package/src/migrations/importDataActions.ts +0 -315
- package/src/migrations/relationships.ts +0 -333
- package/src/migrations/services/DataTransformationService.ts +0 -196
- package/src/migrations/services/FileHandlerService.ts +0 -311
- package/src/migrations/services/ImportOrchestrator.ts +0 -675
- package/src/migrations/services/RateLimitManager.ts +0 -363
- package/src/migrations/services/RelationshipResolver.ts +0 -461
- package/src/migrations/services/UserMappingService.ts +0 -345
- package/src/migrations/services/ValidationService.ts +0 -349
- package/src/migrations/transfer.ts +0 -1113
- package/src/migrations/yaml/YamlImportConfigLoader.ts +0 -439
- package/src/migrations/yaml/YamlImportIntegration.ts +0 -446
- package/src/migrations/yaml/generateImportSchemas.ts +0 -1354
- package/src/schemas/authUser.ts +0 -23
- package/src/setupCommands.ts +0 -602
- package/src/setupController.ts +0 -43
- package/src/shared/backupMetadataSchema.ts +0 -93
- package/src/shared/backupTracking.ts +0 -211
- package/src/shared/confirmationDialogs.ts +0 -327
- package/src/shared/migrationHelpers.ts +0 -232
- package/src/shared/operationQueue.ts +0 -376
- package/src/shared/operationsTable.ts +0 -338
- package/src/shared/operationsTableSchema.ts +0 -60
- package/src/shared/progressManager.ts +0 -278
- package/src/shared/relationshipExtractor.ts +0 -214
- package/src/shared/selectionDialogs.ts +0 -802
- package/src/storage/backupCompression.ts +0 -88
- package/src/storage/methods.ts +0 -711
- package/src/storage/schemas.ts +0 -205
- package/src/tables/indexManager.ts +0 -409
- package/src/types/node-appwrite-tablesdb.d.ts +0 -44
- package/src/users/methods.ts +0 -358
- package/src/utils/configMigration.ts +0 -348
- package/src/utils/loadConfigs.ts +0 -457
- package/src/utils/setupFiles.ts +0 -1236
- package/src/utilsController.ts +0 -1263
- package/tests/README.md +0 -497
- package/tests/adapters/AdapterFactory.test.ts +0 -277
- package/tests/integration/syncOperations.test.ts +0 -463
- package/tests/jest.config.js +0 -25
- package/tests/migration/configMigration.test.ts +0 -546
- package/tests/setup.ts +0 -62
- package/tests/testUtils.ts +0 -340
- package/tests/utils/loadConfigs.test.ts +0 -350
- package/tests/validation/configValidation.test.ts +0 -412
- package/tsconfig.json +0 -44
- /package/{src → dist}/functions/templates/count-docs-in-collection/README.md +0 -0
- /package/{src → dist}/functions/templates/count-docs-in-collection/src/main.ts +0 -0
- /package/{src → dist}/functions/templates/count-docs-in-collection/src/request.ts +0 -0
- /package/{src → dist}/functions/templates/hono-typescript/README.md +0 -0
- /package/{src → dist}/functions/templates/hono-typescript/src/adapters/request.ts +0 -0
- /package/{src → dist}/functions/templates/hono-typescript/src/adapters/response.ts +0 -0
- /package/{src → dist}/functions/templates/hono-typescript/src/app.ts +0 -0
- /package/{src → dist}/functions/templates/hono-typescript/src/context.ts +0 -0
- /package/{src → dist}/functions/templates/hono-typescript/src/main.ts +0 -0
- /package/{src → dist}/functions/templates/hono-typescript/src/middleware/appwrite.ts +0 -0
- /package/{src → dist}/functions/templates/typescript-node/README.md +0 -0
- /package/{src → dist}/functions/templates/typescript-node/src/context.ts +0 -0
- /package/{src → dist}/functions/templates/typescript-node/src/main.ts +0 -0
- /package/{src → dist}/functions/templates/uv/README.md +0 -0
- /package/{src → dist}/functions/templates/uv/pyproject.toml +0 -0
- /package/{src → dist}/functions/templates/uv/src/__init__.py +0 -0
- /package/{src → dist}/functions/templates/uv/src/context.py +0 -0
- /package/{src → dist}/functions/templates/uv/src/main.py +0 -0
- /package/{src/utils/index.ts → dist/utils/index.d.ts} +0 -0
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
/**
|
|
3
|
+
* Schema for centralized backup tracking table (_appwrite_backups)
|
|
4
|
+
*
|
|
5
|
+
* Tracks all backups created for databases, buckets, and comprehensive backups
|
|
6
|
+
*/
|
|
7
|
+
export type BackupType = 'database' | 'bucket' | 'comprehensive';
|
|
8
|
+
export type BackupFormat = 'json' | 'zip';
|
|
9
|
+
export type BackupStatus = 'completed' | 'partial' | 'failed';
|
|
10
|
+
export type RestorationStatus = 'completed' | 'partial' | 'failed' | 'not_restored';
|
|
11
|
+
export declare const BACKUP_TYPES: readonly ["database", "bucket", "comprehensive"];
|
|
12
|
+
export declare const BACKUP_FORMATS: readonly ["json", "zip"];
|
|
13
|
+
export declare const BACKUP_STATUSES: readonly ["completed", "partial", "failed"];
|
|
14
|
+
export declare const RESTORATION_STATUSES: readonly ["completed", "partial", "failed", "not_restored"];
|
|
15
|
+
export declare const BackupTypeSchema: z.ZodEnum<{
|
|
16
|
+
bucket: "bucket";
|
|
17
|
+
database: "database";
|
|
18
|
+
comprehensive: "comprehensive";
|
|
19
|
+
}>;
|
|
20
|
+
export declare const BackupFormatSchema: z.ZodEnum<{
|
|
21
|
+
json: "json";
|
|
22
|
+
zip: "zip";
|
|
23
|
+
}>;
|
|
24
|
+
export declare const BackupStatusSchema: z.ZodEnum<{
|
|
25
|
+
completed: "completed";
|
|
26
|
+
failed: "failed";
|
|
27
|
+
partial: "partial";
|
|
28
|
+
}>;
|
|
29
|
+
export declare const RestorationStatusSchema: z.ZodEnum<{
|
|
30
|
+
completed: "completed";
|
|
31
|
+
failed: "failed";
|
|
32
|
+
partial: "partial";
|
|
33
|
+
not_restored: "not_restored";
|
|
34
|
+
}>;
|
|
35
|
+
export interface BackupMetadata {
|
|
36
|
+
$id: string;
|
|
37
|
+
$createdAt: string;
|
|
38
|
+
$updatedAt: string;
|
|
39
|
+
backupType: BackupType;
|
|
40
|
+
backupId: string;
|
|
41
|
+
manifestFileId?: string;
|
|
42
|
+
format: BackupFormat;
|
|
43
|
+
sizeBytes: number;
|
|
44
|
+
databaseId?: string;
|
|
45
|
+
bucketId?: string;
|
|
46
|
+
comprehensiveBackupId?: string;
|
|
47
|
+
collections?: number;
|
|
48
|
+
documents?: number;
|
|
49
|
+
fileCount?: number;
|
|
50
|
+
status: BackupStatus;
|
|
51
|
+
error?: string;
|
|
52
|
+
restoredAt?: string;
|
|
53
|
+
restorationStatus: RestorationStatus;
|
|
54
|
+
restorationError?: string;
|
|
55
|
+
}
|
|
56
|
+
export declare const BackupMetadataSchema: z.ZodObject<{
|
|
57
|
+
$id: z.ZodString;
|
|
58
|
+
$createdAt: z.ZodString;
|
|
59
|
+
$updatedAt: z.ZodString;
|
|
60
|
+
backupType: z.ZodEnum<{
|
|
61
|
+
bucket: "bucket";
|
|
62
|
+
database: "database";
|
|
63
|
+
comprehensive: "comprehensive";
|
|
64
|
+
}>;
|
|
65
|
+
backupId: z.ZodString;
|
|
66
|
+
manifestFileId: z.ZodOptional<z.ZodString>;
|
|
67
|
+
format: z.ZodEnum<{
|
|
68
|
+
json: "json";
|
|
69
|
+
zip: "zip";
|
|
70
|
+
}>;
|
|
71
|
+
sizeBytes: z.ZodNumber;
|
|
72
|
+
databaseId: z.ZodOptional<z.ZodString>;
|
|
73
|
+
bucketId: z.ZodOptional<z.ZodString>;
|
|
74
|
+
comprehensiveBackupId: z.ZodOptional<z.ZodString>;
|
|
75
|
+
collections: z.ZodOptional<z.ZodNumber>;
|
|
76
|
+
documents: z.ZodOptional<z.ZodNumber>;
|
|
77
|
+
fileCount: z.ZodOptional<z.ZodNumber>;
|
|
78
|
+
status: z.ZodEnum<{
|
|
79
|
+
completed: "completed";
|
|
80
|
+
failed: "failed";
|
|
81
|
+
partial: "partial";
|
|
82
|
+
}>;
|
|
83
|
+
error: z.ZodOptional<z.ZodString>;
|
|
84
|
+
restoredAt: z.ZodOptional<z.ZodString>;
|
|
85
|
+
restorationStatus: z.ZodDefault<z.ZodEnum<{
|
|
86
|
+
completed: "completed";
|
|
87
|
+
failed: "failed";
|
|
88
|
+
partial: "partial";
|
|
89
|
+
not_restored: "not_restored";
|
|
90
|
+
}>>;
|
|
91
|
+
restorationError: z.ZodOptional<z.ZodString>;
|
|
92
|
+
}, z.core.$strip>;
|
|
93
|
+
export declare const BACKUP_TABLE_ID = "appwrite_backups";
|
|
94
|
+
export declare const BACKUP_TABLE_NAME = "Backup Tracking";
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export const BACKUP_TYPES = ['database', 'bucket', 'comprehensive'];
|
|
3
|
+
export const BACKUP_FORMATS = ['json', 'zip'];
|
|
4
|
+
export const BACKUP_STATUSES = ['completed', 'partial', 'failed'];
|
|
5
|
+
export const RESTORATION_STATUSES = ['completed', 'partial', 'failed', 'not_restored'];
|
|
6
|
+
export const BackupTypeSchema = z.enum(['database', 'bucket', 'comprehensive']);
|
|
7
|
+
export const BackupFormatSchema = z.enum(['json', 'zip']);
|
|
8
|
+
export const BackupStatusSchema = z.enum(['completed', 'partial', 'failed']);
|
|
9
|
+
export const RestorationStatusSchema = z.enum(['completed', 'partial', 'failed', 'not_restored']);
|
|
10
|
+
export const BackupMetadataSchema = z.object({
|
|
11
|
+
$id: z.string(),
|
|
12
|
+
$createdAt: z.string(),
|
|
13
|
+
$updatedAt: z.string(),
|
|
14
|
+
// Core backup info
|
|
15
|
+
backupType: BackupTypeSchema,
|
|
16
|
+
backupId: z.string(),
|
|
17
|
+
manifestFileId: z.string().optional(),
|
|
18
|
+
format: BackupFormatSchema,
|
|
19
|
+
sizeBytes: z.number(),
|
|
20
|
+
// Resource identification
|
|
21
|
+
databaseId: z.string().optional(),
|
|
22
|
+
bucketId: z.string().optional(),
|
|
23
|
+
comprehensiveBackupId: z.string().optional(),
|
|
24
|
+
// Database-specific metrics
|
|
25
|
+
collections: z.number().optional(),
|
|
26
|
+
documents: z.number().optional(),
|
|
27
|
+
// Bucket-specific metrics
|
|
28
|
+
fileCount: z.number().optional(),
|
|
29
|
+
// Status tracking
|
|
30
|
+
status: BackupStatusSchema,
|
|
31
|
+
error: z.string().optional(),
|
|
32
|
+
// Restoration tracking
|
|
33
|
+
restoredAt: z.string().optional(),
|
|
34
|
+
restorationStatus: RestorationStatusSchema.default('not_restored'),
|
|
35
|
+
restorationError: z.string().optional()
|
|
36
|
+
});
|
|
37
|
+
export const BACKUP_TABLE_ID = "appwrite_backups";
|
|
38
|
+
export const BACKUP_TABLE_NAME = "Backup Tracking";
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { DatabaseAdapter } from "appwrite-utils-helpers";
|
|
2
|
+
import { type BackupMetadata } from "./backupMetadataSchema.js";
|
|
3
|
+
/**
|
|
4
|
+
* Creates the backup tracking table in the specified database
|
|
5
|
+
*/
|
|
6
|
+
export declare function createBackupTrackingTable(db: DatabaseAdapter, databaseId: string): Promise<void>;
|
|
7
|
+
/**
|
|
8
|
+
* Records backup metadata in the tracking table
|
|
9
|
+
*/
|
|
10
|
+
export declare function recordBackup(db: DatabaseAdapter, databaseId: string, metadata: Omit<BackupMetadata, '$id' | '$createdAt' | '$updatedAt'>): Promise<BackupMetadata>;
|
|
11
|
+
/**
|
|
12
|
+
* Lists all backups for a database, sorted by creation date (newest first)
|
|
13
|
+
*/
|
|
14
|
+
export declare function listBackups(db: DatabaseAdapter, databaseId: string): Promise<BackupMetadata[]>;
|
|
15
|
+
/**
|
|
16
|
+
* Gets the most recent backup for a database
|
|
17
|
+
*/
|
|
18
|
+
export declare function getLastBackup(db: DatabaseAdapter, databaseId: string): Promise<BackupMetadata | null>;
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
import { logger } from 'appwrite-utils-helpers';
|
|
2
|
+
import { tryAwaitWithRetry } from "appwrite-utils-helpers";
|
|
3
|
+
import { Query, ID } from "node-appwrite";
|
|
4
|
+
import { BACKUP_TABLE_ID, BACKUP_TABLE_NAME, BackupMetadataSchema } from "./backupMetadataSchema.js";
|
|
5
|
+
/**
|
|
6
|
+
* Checks if backup tracking table exists in database
|
|
7
|
+
*/
|
|
8
|
+
async function tableExists(db, databaseId) {
|
|
9
|
+
try {
|
|
10
|
+
await db.getTable({ databaseId, tableId: BACKUP_TABLE_ID });
|
|
11
|
+
return true;
|
|
12
|
+
}
|
|
13
|
+
catch (error) {
|
|
14
|
+
return false;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Creates the backup tracking table in the specified database
|
|
19
|
+
*/
|
|
20
|
+
export async function createBackupTrackingTable(db, databaseId) {
|
|
21
|
+
// Check if table already exists
|
|
22
|
+
const exists = await tableExists(db, databaseId);
|
|
23
|
+
if (exists) {
|
|
24
|
+
logger.debug("Backup tracking table already exists", {
|
|
25
|
+
databaseId,
|
|
26
|
+
tableId: BACKUP_TABLE_ID
|
|
27
|
+
});
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
logger.info("Creating backup tracking table", {
|
|
31
|
+
databaseId,
|
|
32
|
+
tableId: BACKUP_TABLE_ID
|
|
33
|
+
});
|
|
34
|
+
// Create table
|
|
35
|
+
await tryAwaitWithRetry(async () => {
|
|
36
|
+
await db.createTable({
|
|
37
|
+
databaseId,
|
|
38
|
+
id: BACKUP_TABLE_ID,
|
|
39
|
+
name: BACKUP_TABLE_NAME
|
|
40
|
+
});
|
|
41
|
+
});
|
|
42
|
+
// Create attributes
|
|
43
|
+
const attributes = [
|
|
44
|
+
{
|
|
45
|
+
key: "backupId",
|
|
46
|
+
type: "string",
|
|
47
|
+
size: 50,
|
|
48
|
+
required: true
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
key: "databaseId",
|
|
52
|
+
type: "string",
|
|
53
|
+
size: 50,
|
|
54
|
+
required: true
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
key: "sizeBytes",
|
|
58
|
+
type: "integer",
|
|
59
|
+
required: true
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
key: "collections",
|
|
63
|
+
type: "integer",
|
|
64
|
+
required: true
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
key: "documents",
|
|
68
|
+
type: "integer",
|
|
69
|
+
required: true
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
key: "format",
|
|
73
|
+
type: "enum",
|
|
74
|
+
elements: ["json", "zip"],
|
|
75
|
+
required: true
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
key: "status",
|
|
79
|
+
type: "enum",
|
|
80
|
+
elements: ["completed", "failed"],
|
|
81
|
+
required: true
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
key: "error",
|
|
85
|
+
type: "string",
|
|
86
|
+
size: 10000,
|
|
87
|
+
required: false
|
|
88
|
+
}
|
|
89
|
+
];
|
|
90
|
+
for (const attr of attributes) {
|
|
91
|
+
await tryAwaitWithRetry(async () => {
|
|
92
|
+
await db.createAttribute({
|
|
93
|
+
databaseId,
|
|
94
|
+
tableId: BACKUP_TABLE_ID,
|
|
95
|
+
...attr
|
|
96
|
+
});
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
logger.info("Backup tracking table created successfully", {
|
|
100
|
+
databaseId,
|
|
101
|
+
tableId: BACKUP_TABLE_ID
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Records backup metadata in the tracking table
|
|
106
|
+
*/
|
|
107
|
+
export async function recordBackup(db, databaseId, metadata) {
|
|
108
|
+
// Ensure tracking table exists
|
|
109
|
+
await createBackupTrackingTable(db, databaseId);
|
|
110
|
+
// Create backup record
|
|
111
|
+
const result = await db.createRow({
|
|
112
|
+
databaseId,
|
|
113
|
+
tableId: BACKUP_TABLE_ID,
|
|
114
|
+
id: ID.unique(),
|
|
115
|
+
data: {
|
|
116
|
+
backupId: metadata.backupId,
|
|
117
|
+
databaseId: metadata.databaseId,
|
|
118
|
+
sizeBytes: metadata.sizeBytes,
|
|
119
|
+
collections: metadata.collections,
|
|
120
|
+
documents: metadata.documents,
|
|
121
|
+
format: metadata.format,
|
|
122
|
+
status: metadata.status,
|
|
123
|
+
error: metadata.error
|
|
124
|
+
}
|
|
125
|
+
});
|
|
126
|
+
logger.info("Recorded backup metadata", {
|
|
127
|
+
backupId: metadata.backupId,
|
|
128
|
+
databaseId: metadata.databaseId,
|
|
129
|
+
format: metadata.format
|
|
130
|
+
});
|
|
131
|
+
return result.data;
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Lists all backups for a database, sorted by creation date (newest first)
|
|
135
|
+
*/
|
|
136
|
+
export async function listBackups(db, databaseId) {
|
|
137
|
+
try {
|
|
138
|
+
const result = await db.listRows({
|
|
139
|
+
databaseId,
|
|
140
|
+
tableId: BACKUP_TABLE_ID,
|
|
141
|
+
queries: [
|
|
142
|
+
Query.orderDesc("$createdAt"),
|
|
143
|
+
Query.limit(100) // Limit to last 100 backups
|
|
144
|
+
]
|
|
145
|
+
});
|
|
146
|
+
return (result.rows || []);
|
|
147
|
+
}
|
|
148
|
+
catch (error) {
|
|
149
|
+
// Table might not exist yet
|
|
150
|
+
logger.debug("No backup tracking table found", { databaseId });
|
|
151
|
+
return [];
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Gets the most recent backup for a database
|
|
156
|
+
*/
|
|
157
|
+
export async function getLastBackup(db, databaseId) {
|
|
158
|
+
try {
|
|
159
|
+
const result = await db.listRows({
|
|
160
|
+
databaseId,
|
|
161
|
+
tableId: BACKUP_TABLE_ID,
|
|
162
|
+
queries: [
|
|
163
|
+
Query.orderDesc("$createdAt"),
|
|
164
|
+
Query.limit(1)
|
|
165
|
+
]
|
|
166
|
+
});
|
|
167
|
+
if (result.rows && result.rows.length > 0) {
|
|
168
|
+
return result.rows[0];
|
|
169
|
+
}
|
|
170
|
+
return null;
|
|
171
|
+
}
|
|
172
|
+
catch (error) {
|
|
173
|
+
logger.debug("No backup found or table doesn't exist", { databaseId });
|
|
174
|
+
return null;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
export interface DestructiveOperationOptions {
|
|
2
|
+
operation: string;
|
|
3
|
+
targets: string[];
|
|
4
|
+
consequences?: string[];
|
|
5
|
+
requireExplicitConfirmation?: boolean;
|
|
6
|
+
confirmationText?: string;
|
|
7
|
+
skipConfirmation?: boolean;
|
|
8
|
+
}
|
|
9
|
+
export interface BackupPromptOptions {
|
|
10
|
+
operation: string;
|
|
11
|
+
targets: string[];
|
|
12
|
+
recommendBackup?: boolean;
|
|
13
|
+
backupMessage?: string;
|
|
14
|
+
}
|
|
15
|
+
export declare class ConfirmationDialogs {
|
|
16
|
+
/**
|
|
17
|
+
* Shows a confirmation dialog for destructive operations
|
|
18
|
+
*/
|
|
19
|
+
static confirmDestructiveOperation(options: DestructiveOperationOptions): Promise<boolean>;
|
|
20
|
+
/**
|
|
21
|
+
* Prompts user about creating a backup before a destructive operation
|
|
22
|
+
*/
|
|
23
|
+
static promptForBackup(options: BackupPromptOptions): Promise<'yes' | 'no' | 'skip'>;
|
|
24
|
+
/**
|
|
25
|
+
* Shows a final confirmation before proceeding with an operation
|
|
26
|
+
*/
|
|
27
|
+
static finalConfirmation(operation: string, details?: string[]): Promise<boolean>;
|
|
28
|
+
/**
|
|
29
|
+
* Specialized confirmation for database wiping
|
|
30
|
+
*/
|
|
31
|
+
static confirmDatabaseWipe(databaseNames: string[], options?: {
|
|
32
|
+
includeStorage?: boolean;
|
|
33
|
+
includeUsers?: boolean;
|
|
34
|
+
skipConfirmation?: boolean;
|
|
35
|
+
}): Promise<boolean>;
|
|
36
|
+
/**
|
|
37
|
+
* Specialized confirmation for collection wiping
|
|
38
|
+
*/
|
|
39
|
+
static confirmCollectionWipe(databaseName: string, collectionNames: string[], options?: {
|
|
40
|
+
skipConfirmation?: boolean;
|
|
41
|
+
}): Promise<boolean>;
|
|
42
|
+
/**
|
|
43
|
+
* Specialized confirmation for function deployment
|
|
44
|
+
*/
|
|
45
|
+
static confirmFunctionDeployment(functionNames: string[], options?: {
|
|
46
|
+
isProduction?: boolean;
|
|
47
|
+
hasBreakingChanges?: boolean;
|
|
48
|
+
skipConfirmation?: boolean;
|
|
49
|
+
}): Promise<boolean>;
|
|
50
|
+
/**
|
|
51
|
+
* Shows operation summary and asks for final confirmation
|
|
52
|
+
*/
|
|
53
|
+
static showOperationSummary(title: string, summary: Record<string, string | number | string[]>, options?: {
|
|
54
|
+
confirmationRequired?: boolean;
|
|
55
|
+
warningMessage?: string;
|
|
56
|
+
}): Promise<boolean>;
|
|
57
|
+
/**
|
|
58
|
+
* Interactive selection with confirmation
|
|
59
|
+
*/
|
|
60
|
+
static selectWithConfirmation<T>(items: T[], options: {
|
|
61
|
+
message: string;
|
|
62
|
+
displayProperty?: keyof T;
|
|
63
|
+
multiSelect?: boolean;
|
|
64
|
+
confirmMessage?: string;
|
|
65
|
+
validator?: (selection: T[]) => string | true;
|
|
66
|
+
}): Promise<T[]>;
|
|
67
|
+
/**
|
|
68
|
+
* Confirms overwriting an existing file or directory
|
|
69
|
+
*/
|
|
70
|
+
static confirmOverwrite(target: string): Promise<boolean>;
|
|
71
|
+
/**
|
|
72
|
+
* Confirms removal of a file
|
|
73
|
+
*/
|
|
74
|
+
static confirmRemoval(target: string): Promise<boolean>;
|
|
75
|
+
}
|
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
import inquirer from "inquirer";
|
|
2
|
+
import chalk from "chalk";
|
|
3
|
+
import { MessageFormatter } from 'appwrite-utils-helpers';
|
|
4
|
+
export class ConfirmationDialogs {
|
|
5
|
+
/**
|
|
6
|
+
* Shows a confirmation dialog for destructive operations
|
|
7
|
+
*/
|
|
8
|
+
static async confirmDestructiveOperation(options) {
|
|
9
|
+
if (options.skipConfirmation) {
|
|
10
|
+
return true;
|
|
11
|
+
}
|
|
12
|
+
MessageFormatter.warning(`You are about to perform a destructive operation:`, { skipLogging: true });
|
|
13
|
+
MessageFormatter.error(`Operation: ${options.operation}`, undefined, { skipLogging: true });
|
|
14
|
+
MessageFormatter.warning(`Targets: ${options.targets.join(", ")}`, { skipLogging: true });
|
|
15
|
+
if (options.consequences && options.consequences.length > 0) {
|
|
16
|
+
MessageFormatter.error("This will:", undefined, { skipLogging: true });
|
|
17
|
+
options.consequences.forEach(consequence => {
|
|
18
|
+
MessageFormatter.error(` • ${consequence}`, undefined, { skipLogging: true });
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
MessageFormatter.error("⚠️ THIS ACTION CANNOT BE UNDONE!", undefined, { skipLogging: true });
|
|
22
|
+
if (options.requireExplicitConfirmation && options.confirmationText) {
|
|
23
|
+
const { confirmation } = await inquirer.prompt([{
|
|
24
|
+
type: 'input',
|
|
25
|
+
name: 'confirmation',
|
|
26
|
+
message: chalk.red(`Type "${options.confirmationText}" to confirm:`),
|
|
27
|
+
validate: (input) => {
|
|
28
|
+
return input === options.confirmationText ||
|
|
29
|
+
chalk.red(`Please type exactly: ${options.confirmationText}`);
|
|
30
|
+
}
|
|
31
|
+
}]);
|
|
32
|
+
return confirmation === options.confirmationText;
|
|
33
|
+
}
|
|
34
|
+
else {
|
|
35
|
+
const { confirmed } = await inquirer.prompt([{
|
|
36
|
+
type: 'confirm',
|
|
37
|
+
name: 'confirmed',
|
|
38
|
+
message: chalk.red('Are you absolutely sure you want to continue?'),
|
|
39
|
+
default: false
|
|
40
|
+
}]);
|
|
41
|
+
return confirmed;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Prompts user about creating a backup before a destructive operation
|
|
46
|
+
*/
|
|
47
|
+
static async promptForBackup(options) {
|
|
48
|
+
const message = options.backupMessage ||
|
|
49
|
+
`Create a backup before performing ${options.operation} on: ${options.targets.join(", ")}?`;
|
|
50
|
+
MessageFormatter.info("🛡️ Backup Recommendation", { skipLogging: true });
|
|
51
|
+
if (options.recommendBackup !== false) {
|
|
52
|
+
MessageFormatter.warning("It's strongly recommended to create a backup before proceeding.", { skipLogging: true });
|
|
53
|
+
}
|
|
54
|
+
const { choice } = await inquirer.prompt([{
|
|
55
|
+
type: 'list',
|
|
56
|
+
name: 'choice',
|
|
57
|
+
message,
|
|
58
|
+
choices: [
|
|
59
|
+
{ name: '🛡️ Yes, create backup first', value: 'yes' },
|
|
60
|
+
{ name: '⚠️ No, proceed without backup', value: 'no' },
|
|
61
|
+
{ name: '❌ Cancel operation', value: 'skip' }
|
|
62
|
+
],
|
|
63
|
+
default: 'yes'
|
|
64
|
+
}]);
|
|
65
|
+
return choice;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Shows a final confirmation before proceeding with an operation
|
|
69
|
+
*/
|
|
70
|
+
static async finalConfirmation(operation, details) {
|
|
71
|
+
MessageFormatter.success(`Ready to perform: ${operation}`, { skipLogging: true });
|
|
72
|
+
if (details && details.length > 0) {
|
|
73
|
+
MessageFormatter.debug("Details:", undefined, { skipLogging: true });
|
|
74
|
+
details.forEach(detail => {
|
|
75
|
+
MessageFormatter.debug(` • ${detail}`, undefined, { skipLogging: true });
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
const { proceed } = await inquirer.prompt([{
|
|
79
|
+
type: 'confirm',
|
|
80
|
+
name: 'proceed',
|
|
81
|
+
message: 'Proceed with this operation?',
|
|
82
|
+
default: true
|
|
83
|
+
}]);
|
|
84
|
+
return proceed;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Specialized confirmation for database wiping
|
|
88
|
+
*/
|
|
89
|
+
static async confirmDatabaseWipe(databaseNames, options = {}) {
|
|
90
|
+
const consequences = [
|
|
91
|
+
"Delete all documents in the specified databases",
|
|
92
|
+
"Remove all collections and their data",
|
|
93
|
+
];
|
|
94
|
+
if (options.includeStorage) {
|
|
95
|
+
consequences.push("Delete all files in associated storage buckets");
|
|
96
|
+
}
|
|
97
|
+
if (options.includeUsers) {
|
|
98
|
+
consequences.push("Delete all user accounts");
|
|
99
|
+
}
|
|
100
|
+
return this.confirmDestructiveOperation({
|
|
101
|
+
operation: "Database Wipe",
|
|
102
|
+
targets: databaseNames,
|
|
103
|
+
consequences,
|
|
104
|
+
requireExplicitConfirmation: true,
|
|
105
|
+
confirmationText: "DELETE ALL DATA",
|
|
106
|
+
skipConfirmation: options.skipConfirmation,
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Specialized confirmation for collection wiping
|
|
111
|
+
*/
|
|
112
|
+
static async confirmCollectionWipe(databaseName, collectionNames, options = {}) {
|
|
113
|
+
return this.confirmDestructiveOperation({
|
|
114
|
+
operation: "Collection Wipe",
|
|
115
|
+
targets: collectionNames.map(name => `${databaseName}.${name}`),
|
|
116
|
+
consequences: [
|
|
117
|
+
"Delete all documents in the specified collections",
|
|
118
|
+
"Keep the collection structure intact",
|
|
119
|
+
],
|
|
120
|
+
requireExplicitConfirmation: collectionNames.length > 5,
|
|
121
|
+
confirmationText: "DELETE DOCUMENTS",
|
|
122
|
+
skipConfirmation: options.skipConfirmation,
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Specialized confirmation for function deployment
|
|
127
|
+
*/
|
|
128
|
+
static async confirmFunctionDeployment(functionNames, options = {}) {
|
|
129
|
+
if (options.skipConfirmation) {
|
|
130
|
+
return true;
|
|
131
|
+
}
|
|
132
|
+
const consequences = ["Replace existing function code"];
|
|
133
|
+
if (options.isProduction) {
|
|
134
|
+
consequences.push("Affect production environment");
|
|
135
|
+
}
|
|
136
|
+
if (options.hasBreakingChanges) {
|
|
137
|
+
consequences.push("Potentially break existing integrations");
|
|
138
|
+
}
|
|
139
|
+
return this.confirmDestructiveOperation({
|
|
140
|
+
operation: "Function Deployment",
|
|
141
|
+
targets: functionNames,
|
|
142
|
+
consequences: consequences.length > 1 ? consequences : undefined,
|
|
143
|
+
requireExplicitConfirmation: options.isProduction || options.hasBreakingChanges,
|
|
144
|
+
confirmationText: options.isProduction ? "DEPLOY TO PRODUCTION" : "DEPLOY",
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Shows operation summary and asks for final confirmation
|
|
149
|
+
*/
|
|
150
|
+
static async showOperationSummary(title, summary, options = {}) {
|
|
151
|
+
MessageFormatter.section(`${title} Summary`);
|
|
152
|
+
Object.entries(summary).forEach(([key, value]) => {
|
|
153
|
+
const formattedKey = key.replace(/([A-Z])/g, ' $1').replace(/^./, str => str.toUpperCase());
|
|
154
|
+
if (Array.isArray(value)) {
|
|
155
|
+
MessageFormatter.info(`● ${formattedKey}:`, { skipLogging: true });
|
|
156
|
+
value.forEach(item => {
|
|
157
|
+
MessageFormatter.debug(` • ${item}`, undefined, { skipLogging: true });
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
else {
|
|
161
|
+
MessageFormatter.info(`● ${formattedKey}: ${String(value)}`, { skipLogging: true });
|
|
162
|
+
}
|
|
163
|
+
});
|
|
164
|
+
if (options.warningMessage) {
|
|
165
|
+
MessageFormatter.warning(`⚠️ ${options.warningMessage}`, { skipLogging: true });
|
|
166
|
+
}
|
|
167
|
+
if (options.confirmationRequired !== false) {
|
|
168
|
+
const { confirmed } = await inquirer.prompt([{
|
|
169
|
+
type: 'confirm',
|
|
170
|
+
name: 'confirmed',
|
|
171
|
+
message: 'Continue with this operation?',
|
|
172
|
+
default: true
|
|
173
|
+
}]);
|
|
174
|
+
return confirmed;
|
|
175
|
+
}
|
|
176
|
+
return true;
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Interactive selection with confirmation
|
|
180
|
+
*/
|
|
181
|
+
static async selectWithConfirmation(items, options) {
|
|
182
|
+
const choices = items.map((item, index) => ({
|
|
183
|
+
name: options.displayProperty ? String(item[options.displayProperty]) : String(item),
|
|
184
|
+
value: item,
|
|
185
|
+
}));
|
|
186
|
+
const prompt = options.multiSelect ? 'checkbox' : 'list';
|
|
187
|
+
const { selection } = await inquirer.prompt([{
|
|
188
|
+
type: prompt,
|
|
189
|
+
name: 'selection',
|
|
190
|
+
message: options.message,
|
|
191
|
+
choices,
|
|
192
|
+
validate: options.validator ? (input) => {
|
|
193
|
+
const result = options.validator(Array.isArray(input) ? input : [input]);
|
|
194
|
+
return result;
|
|
195
|
+
} : undefined,
|
|
196
|
+
}]);
|
|
197
|
+
const selectedItems = Array.isArray(selection) ? selection : [selection];
|
|
198
|
+
if (options.confirmMessage) {
|
|
199
|
+
const confirmMessage = options.confirmMessage.replace('{count}', selectedItems.length.toString());
|
|
200
|
+
const { confirmed } = await inquirer.prompt([{
|
|
201
|
+
type: 'confirm',
|
|
202
|
+
name: 'confirmed',
|
|
203
|
+
message: confirmMessage,
|
|
204
|
+
default: true
|
|
205
|
+
}]);
|
|
206
|
+
if (!confirmed) {
|
|
207
|
+
return [];
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
return selectedItems;
|
|
211
|
+
}
|
|
212
|
+
/**
|
|
213
|
+
* Confirms overwriting an existing file or directory
|
|
214
|
+
*/
|
|
215
|
+
static async confirmOverwrite(target) {
|
|
216
|
+
const { confirmed } = await inquirer.prompt([{
|
|
217
|
+
type: 'confirm',
|
|
218
|
+
name: 'confirmed',
|
|
219
|
+
message: chalk.yellow(`${target} already exists. Overwrite?`),
|
|
220
|
+
default: false
|
|
221
|
+
}]);
|
|
222
|
+
return confirmed;
|
|
223
|
+
}
|
|
224
|
+
/**
|
|
225
|
+
* Confirms removal of a file
|
|
226
|
+
*/
|
|
227
|
+
static async confirmRemoval(target) {
|
|
228
|
+
const { confirmed } = await inquirer.prompt([{
|
|
229
|
+
type: 'confirm',
|
|
230
|
+
name: 'confirmed',
|
|
231
|
+
message: chalk.red(target),
|
|
232
|
+
default: false
|
|
233
|
+
}]);
|
|
234
|
+
return confirmed;
|
|
235
|
+
}
|
|
236
|
+
}
|