appwrite-utils-cli 1.5.1 → 1.6.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/CHANGELOG.md +199 -0
- package/README.md +251 -29
- package/dist/adapters/AdapterFactory.d.ts +10 -3
- package/dist/adapters/AdapterFactory.js +213 -17
- package/dist/adapters/TablesDBAdapter.js +60 -17
- 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 +160 -0
- package/dist/cli/commands/databaseCommands.d.ts +13 -0
- package/dist/cli/commands/databaseCommands.js +478 -0
- package/dist/cli/commands/functionCommands.d.ts +7 -0
- package/dist/cli/commands/functionCommands.js +289 -0
- package/dist/cli/commands/schemaCommands.d.ts +7 -0
- package/dist/cli/commands/schemaCommands.js +134 -0
- package/dist/cli/commands/transferCommands.d.ts +5 -0
- package/dist/cli/commands/transferCommands.js +384 -0
- package/dist/collections/attributes.d.ts +5 -4
- package/dist/collections/attributes.js +539 -246
- package/dist/collections/indexes.js +39 -37
- package/dist/collections/methods.d.ts +2 -16
- package/dist/collections/methods.js +90 -538
- package/dist/collections/transferOperations.d.ts +7 -0
- package/dist/collections/transferOperations.js +331 -0
- package/dist/collections/wipeOperations.d.ts +16 -0
- package/dist/collections/wipeOperations.js +328 -0
- package/dist/config/configMigration.d.ts +87 -0
- package/dist/config/configMigration.js +390 -0
- package/dist/config/configValidation.d.ts +66 -0
- package/dist/config/configValidation.js +358 -0
- package/dist/config/yamlConfig.d.ts +455 -1
- package/dist/config/yamlConfig.js +145 -52
- package/dist/databases/methods.js +3 -2
- package/dist/databases/setup.d.ts +1 -2
- package/dist/databases/setup.js +9 -87
- package/dist/examples/yamlTerminologyExample.d.ts +42 -0
- package/dist/examples/yamlTerminologyExample.js +269 -0
- package/dist/functions/deployments.js +11 -10
- package/dist/functions/methods.d.ts +1 -1
- package/dist/functions/methods.js +5 -4
- package/dist/init.js +9 -9
- package/dist/interactiveCLI.d.ts +8 -17
- package/dist/interactiveCLI.js +186 -1171
- package/dist/main.js +364 -21
- package/dist/migrations/afterImportActions.js +22 -30
- package/dist/migrations/appwriteToX.js +71 -25
- package/dist/migrations/dataLoader.js +35 -26
- package/dist/migrations/importController.js +29 -30
- package/dist/migrations/relationships.js +13 -12
- package/dist/migrations/services/ImportOrchestrator.js +16 -19
- package/dist/migrations/transfer.js +46 -46
- package/dist/migrations/yaml/YamlImportConfigLoader.d.ts +3 -1
- package/dist/migrations/yaml/YamlImportConfigLoader.js +6 -3
- package/dist/migrations/yaml/YamlImportIntegration.d.ts +9 -3
- package/dist/migrations/yaml/YamlImportIntegration.js +22 -11
- package/dist/migrations/yaml/generateImportSchemas.d.ts +14 -1
- package/dist/migrations/yaml/generateImportSchemas.js +736 -7
- package/dist/schemas/authUser.d.ts +1 -1
- package/dist/setupController.js +3 -2
- 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.js +15 -15
- package/dist/shared/errorUtils.d.ts +54 -0
- package/dist/shared/errorUtils.js +95 -0
- package/dist/shared/functionManager.js +20 -19
- package/dist/shared/indexManager.js +12 -11
- package/dist/shared/jsonSchemaGenerator.js +10 -26
- package/dist/shared/logging.d.ts +51 -0
- package/dist/shared/logging.js +70 -0
- package/dist/shared/messageFormatter.d.ts +2 -0
- package/dist/shared/messageFormatter.js +10 -0
- package/dist/shared/migrationHelpers.d.ts +6 -16
- package/dist/shared/migrationHelpers.js +24 -21
- package/dist/shared/operationLogger.d.ts +8 -1
- package/dist/shared/operationLogger.js +11 -24
- package/dist/shared/operationQueue.d.ts +28 -1
- package/dist/shared/operationQueue.js +268 -66
- package/dist/shared/operationsTable.d.ts +26 -0
- package/dist/shared/operationsTable.js +286 -0
- package/dist/shared/operationsTableSchema.d.ts +48 -0
- package/dist/shared/operationsTableSchema.js +35 -0
- package/dist/shared/relationshipExtractor.d.ts +56 -0
- package/dist/shared/relationshipExtractor.js +138 -0
- package/dist/shared/schemaGenerator.d.ts +19 -1
- package/dist/shared/schemaGenerator.js +56 -75
- package/dist/storage/backupCompression.d.ts +20 -0
- package/dist/storage/backupCompression.js +67 -0
- package/dist/storage/methods.d.ts +16 -2
- package/dist/storage/methods.js +98 -14
- package/dist/users/methods.js +9 -8
- package/dist/utils/configDiscovery.d.ts +78 -0
- package/dist/utils/configDiscovery.js +430 -0
- package/dist/utils/directoryUtils.d.ts +22 -0
- package/dist/utils/directoryUtils.js +59 -0
- package/dist/utils/getClientFromConfig.d.ts +17 -8
- package/dist/utils/getClientFromConfig.js +162 -17
- package/dist/utils/helperFunctions.d.ts +16 -2
- package/dist/utils/helperFunctions.js +19 -5
- package/dist/utils/loadConfigs.d.ts +34 -9
- package/dist/utils/loadConfigs.js +236 -316
- package/dist/utils/pathResolvers.d.ts +53 -0
- package/dist/utils/pathResolvers.js +72 -0
- package/dist/utils/projectConfig.d.ts +119 -0
- package/dist/utils/projectConfig.js +171 -0
- package/dist/utils/retryFailedPromises.js +4 -2
- package/dist/utils/sessionAuth.d.ts +48 -0
- package/dist/utils/sessionAuth.js +164 -0
- package/dist/utils/sessionPreservationExample.d.ts +1666 -0
- package/dist/utils/sessionPreservationExample.js +101 -0
- package/dist/utils/setupFiles.js +301 -41
- package/dist/utils/typeGuards.d.ts +35 -0
- package/dist/utils/typeGuards.js +57 -0
- package/dist/utils/versionDetection.js +145 -9
- package/dist/utils/yamlConverter.d.ts +53 -3
- package/dist/utils/yamlConverter.js +232 -13
- package/dist/utils/yamlLoader.d.ts +70 -0
- package/dist/utils/yamlLoader.js +263 -0
- package/dist/utilsController.d.ts +36 -3
- package/dist/utilsController.js +186 -56
- package/package.json +12 -2
- package/src/adapters/AdapterFactory.ts +263 -35
- package/src/adapters/TablesDBAdapter.ts +225 -36
- package/src/backups/operations/bucketBackup.ts +277 -0
- package/src/backups/operations/collectionBackup.ts +310 -0
- package/src/backups/operations/comprehensiveBackup.ts +342 -0
- package/src/backups/schemas/bucketManifest.ts +78 -0
- package/src/backups/schemas/comprehensiveManifest.ts +76 -0
- package/src/backups/tracking/centralizedTracking.ts +352 -0
- package/src/cli/commands/configCommands.ts +194 -0
- package/src/cli/commands/databaseCommands.ts +635 -0
- package/src/cli/commands/functionCommands.ts +379 -0
- package/src/cli/commands/schemaCommands.ts +163 -0
- package/src/cli/commands/transferCommands.ts +457 -0
- package/src/collections/attributes.ts +900 -621
- package/src/collections/attributes.ts.backup +1555 -0
- package/src/collections/indexes.ts +116 -114
- package/src/collections/methods.ts +295 -968
- package/src/collections/transferOperations.ts +516 -0
- package/src/collections/wipeOperations.ts +501 -0
- package/src/config/README.md +274 -0
- package/src/config/configMigration.ts +575 -0
- package/src/config/configValidation.ts +445 -0
- package/src/config/yamlConfig.ts +168 -55
- package/src/databases/methods.ts +3 -2
- package/src/databases/setup.ts +11 -138
- package/src/examples/yamlTerminologyExample.ts +341 -0
- package/src/functions/deployments.ts +14 -12
- package/src/functions/methods.ts +11 -11
- package/src/functions/templates/hono-typescript/README.md +286 -0
- package/src/functions/templates/hono-typescript/package.json +26 -0
- package/src/functions/templates/hono-typescript/src/adapters/request.ts +74 -0
- package/src/functions/templates/hono-typescript/src/adapters/response.ts +106 -0
- package/src/functions/templates/hono-typescript/src/app.ts +180 -0
- package/src/functions/templates/hono-typescript/src/context.ts +103 -0
- package/src/functions/templates/hono-typescript/src/index.ts +54 -0
- package/src/functions/templates/hono-typescript/src/middleware/appwrite.ts +119 -0
- package/src/functions/templates/hono-typescript/tsconfig.json +20 -0
- package/src/functions/templates/typescript-node/package.json +2 -1
- package/src/functions/templates/typescript-node/src/context.ts +103 -0
- package/src/functions/templates/typescript-node/src/index.ts +18 -12
- package/src/functions/templates/uv/pyproject.toml +1 -0
- package/src/functions/templates/uv/src/context.py +125 -0
- package/src/functions/templates/uv/src/index.py +35 -5
- package/src/init.ts +9 -11
- package/src/interactiveCLI.ts +276 -1591
- package/src/main.ts +418 -24
- package/src/migrations/afterImportActions.ts +71 -44
- package/src/migrations/appwriteToX.ts +100 -34
- package/src/migrations/dataLoader.ts +48 -34
- package/src/migrations/importController.ts +44 -39
- package/src/migrations/relationships.ts +28 -18
- package/src/migrations/services/ImportOrchestrator.ts +24 -27
- package/src/migrations/transfer.ts +159 -121
- package/src/migrations/yaml/YamlImportConfigLoader.ts +11 -4
- package/src/migrations/yaml/YamlImportIntegration.ts +47 -20
- package/src/migrations/yaml/generateImportSchemas.ts +751 -12
- package/src/setupController.ts +3 -2
- package/src/shared/backupMetadataSchema.ts +93 -0
- package/src/shared/backupTracking.ts +211 -0
- package/src/shared/confirmationDialogs.ts +19 -19
- package/src/shared/errorUtils.ts +110 -0
- package/src/shared/functionManager.ts +21 -20
- package/src/shared/indexManager.ts +12 -11
- package/src/shared/jsonSchemaGenerator.ts +38 -52
- package/src/shared/logging.ts +75 -0
- package/src/shared/messageFormatter.ts +14 -1
- package/src/shared/migrationHelpers.ts +45 -38
- package/src/shared/operationLogger.ts +11 -36
- package/src/shared/operationQueue.ts +322 -93
- package/src/shared/operationsTable.ts +338 -0
- package/src/shared/operationsTableSchema.ts +60 -0
- package/src/shared/relationshipExtractor.ts +214 -0
- package/src/shared/schemaGenerator.ts +179 -219
- package/src/storage/backupCompression.ts +88 -0
- package/src/storage/methods.ts +131 -34
- package/src/users/methods.ts +11 -9
- package/src/utils/configDiscovery.ts +502 -0
- package/src/utils/directoryUtils.ts +61 -0
- package/src/utils/getClientFromConfig.ts +205 -22
- package/src/utils/helperFunctions.ts +23 -5
- package/src/utils/loadConfigs.ts +313 -345
- package/src/utils/pathResolvers.ts +81 -0
- package/src/utils/projectConfig.ts +299 -0
- package/src/utils/retryFailedPromises.ts +4 -2
- package/src/utils/sessionAuth.ts +230 -0
- package/src/utils/setupFiles.ts +322 -54
- package/src/utils/typeGuards.ts +65 -0
- package/src/utils/versionDetection.ts +218 -64
- package/src/utils/yamlConverter.ts +296 -13
- package/src/utils/yamlLoader.ts +364 -0
- package/src/utilsController.ts +314 -110
- package/tests/README.md +497 -0
- package/tests/adapters/AdapterFactory.test.ts +277 -0
- package/tests/integration/syncOperations.test.ts +463 -0
- package/tests/jest.config.js +25 -0
- package/tests/migration/configMigration.test.ts +546 -0
- package/tests/setup.ts +62 -0
- package/tests/testUtils.ts +340 -0
- package/tests/utils/loadConfigs.test.ts +350 -0
- package/tests/validation/configValidation.test.ts +412 -0
- package/src/utils/schemaStrings.ts +0 -517
@@ -0,0 +1,274 @@
|
|
1
|
+
import { logger } from "../../shared/logging.js";
|
2
|
+
import { tryAwaitWithRetry } from "../../utils/helperFunctions.js";
|
3
|
+
import { Query, ID } from "node-appwrite";
|
4
|
+
import { BACKUP_TABLE_ID, BACKUP_TABLE_NAME, BackupMetadataSchema } from "../../shared/backupMetadataSchema.js";
|
5
|
+
/**
|
6
|
+
* Centralized backup tracking system
|
7
|
+
*
|
8
|
+
* All backups (databases, buckets, comprehensive) are tracked in a single
|
9
|
+
* database selected by the user, providing a centralized backup registry.
|
10
|
+
*/
|
11
|
+
/**
|
12
|
+
* Checks if backup tracking table exists in database
|
13
|
+
*/
|
14
|
+
async function tableExists(db, databaseId) {
|
15
|
+
try {
|
16
|
+
await db.getTable({ databaseId, tableId: BACKUP_TABLE_ID });
|
17
|
+
return true;
|
18
|
+
}
|
19
|
+
catch (error) {
|
20
|
+
return false;
|
21
|
+
}
|
22
|
+
}
|
23
|
+
/**
|
24
|
+
* Creates the centralized backup tracking table with enhanced schema
|
25
|
+
*/
|
26
|
+
export async function createCentralizedBackupTrackingTable(db, databaseId) {
|
27
|
+
// Check if table already exists
|
28
|
+
const exists = await tableExists(db, databaseId);
|
29
|
+
if (exists) {
|
30
|
+
// Table exists - validate its schema
|
31
|
+
try {
|
32
|
+
const tableData = await db.getTable({ databaseId, tableId: BACKUP_TABLE_ID });
|
33
|
+
const existingAttrs = (tableData.data.attributes || []);
|
34
|
+
// Expected attribute keys from our schema
|
35
|
+
const expectedAttrKeys = [
|
36
|
+
"backupType", "backupId", "manifestFileId", "format", "sizeBytes",
|
37
|
+
"databaseId", "bucketId", "comprehensiveBackupId",
|
38
|
+
"collections", "documents", "fileCount",
|
39
|
+
"status", "error",
|
40
|
+
"restoredAt", "restorationStatus", "restorationError"
|
41
|
+
];
|
42
|
+
// Existing attribute keys
|
43
|
+
const existingAttrKeys = new Set(existingAttrs.map((a) => a.key));
|
44
|
+
// Check if they match
|
45
|
+
const hasAllAttributes = expectedAttrKeys.every(key => existingAttrKeys.has(key));
|
46
|
+
// Check if any have wrong sizes (old 10000 vs new 1000)
|
47
|
+
const hasWrongSizes = existingAttrs.some((a) => (a.key === 'error' || a.key === 'restorationError') && a.size === 10000);
|
48
|
+
if (!hasAllAttributes || hasWrongSizes) {
|
49
|
+
logger.warn("Backup table exists but has incorrect schema - recreating", {
|
50
|
+
tableId: BACKUP_TABLE_ID,
|
51
|
+
hasAllAttributes,
|
52
|
+
hasWrongSizes,
|
53
|
+
existingCount: existingAttrKeys.size,
|
54
|
+
expectedCount: expectedAttrKeys.length
|
55
|
+
});
|
56
|
+
// Delete the old table
|
57
|
+
await db.deleteTable({ databaseId, tableId: BACKUP_TABLE_ID });
|
58
|
+
logger.info("Old backup table deleted, will recreate with correct schema");
|
59
|
+
}
|
60
|
+
else {
|
61
|
+
logger.debug("Backup table exists with correct schema", {
|
62
|
+
tableId: BACKUP_TABLE_ID,
|
63
|
+
attributeCount: existingAttrKeys.size
|
64
|
+
});
|
65
|
+
return; // Table is good, no need to recreate
|
66
|
+
}
|
67
|
+
}
|
68
|
+
catch (error) {
|
69
|
+
// Error checking table - continue to create
|
70
|
+
logger.debug("Error checking existing table, will attempt to create", {
|
71
|
+
error: error instanceof Error ? error.message : String(error)
|
72
|
+
});
|
73
|
+
}
|
74
|
+
}
|
75
|
+
// Create table (either first time or after deletion)
|
76
|
+
logger.info("Creating centralized backup tracking table", {
|
77
|
+
databaseId,
|
78
|
+
tableId: BACKUP_TABLE_ID
|
79
|
+
});
|
80
|
+
await tryAwaitWithRetry(async () => {
|
81
|
+
await db.createTable({
|
82
|
+
databaseId,
|
83
|
+
id: BACKUP_TABLE_ID,
|
84
|
+
name: BACKUP_TABLE_NAME,
|
85
|
+
permissions: [],
|
86
|
+
documentSecurity: false,
|
87
|
+
enabled: true
|
88
|
+
});
|
89
|
+
});
|
90
|
+
// Define all attributes for the enhanced schema
|
91
|
+
const attributes = [
|
92
|
+
// Core backup info
|
93
|
+
{ key: "backupType", type: "enum", elements: ["database", "bucket", "comprehensive"], required: true },
|
94
|
+
{ key: "backupId", type: "string", size: 50, required: true },
|
95
|
+
{ key: "manifestFileId", type: "string", size: 50, required: false },
|
96
|
+
{ key: "format", type: "enum", elements: ["json", "zip"], required: true },
|
97
|
+
{ key: "sizeBytes", type: "integer", required: true },
|
98
|
+
// Resource identification (optional, at least one present based on type)
|
99
|
+
{ key: "databaseId", type: "string", size: 50, required: false },
|
100
|
+
{ key: "bucketId", type: "string", size: 50, required: false },
|
101
|
+
{ key: "comprehensiveBackupId", type: "string", size: 50, required: false },
|
102
|
+
// Database-specific metrics
|
103
|
+
{ key: "collections", type: "integer", required: false },
|
104
|
+
{ key: "documents", type: "integer", required: false },
|
105
|
+
// Bucket-specific metrics
|
106
|
+
{ key: "fileCount", type: "integer", required: false },
|
107
|
+
// Status tracking
|
108
|
+
{ key: "status", type: "enum", elements: ["completed", "partial", "failed"], required: true },
|
109
|
+
{ key: "error", type: "string", size: 1000, required: false },
|
110
|
+
// Restoration tracking
|
111
|
+
{ key: "restoredAt", type: "string", size: 50, required: false },
|
112
|
+
{ key: "restorationStatus", type: "enum", elements: ["completed", "partial", "failed", "not_restored"], required: false },
|
113
|
+
{ key: "restorationError", type: "string", size: 1000, required: false }
|
114
|
+
];
|
115
|
+
// Create each attribute with retry logic
|
116
|
+
// No need to check for existing attributes - table is freshly created or validated above
|
117
|
+
for (const attr of attributes) {
|
118
|
+
await tryAwaitWithRetry(async () => {
|
119
|
+
await db.createAttribute({
|
120
|
+
databaseId,
|
121
|
+
tableId: BACKUP_TABLE_ID,
|
122
|
+
...attr
|
123
|
+
});
|
124
|
+
});
|
125
|
+
}
|
126
|
+
logger.info("Centralized backup tracking table created successfully", {
|
127
|
+
databaseId,
|
128
|
+
tableId: BACKUP_TABLE_ID,
|
129
|
+
attributeCount: attributes.length
|
130
|
+
});
|
131
|
+
}
|
132
|
+
/**
|
133
|
+
* Records backup metadata in the centralized tracking table
|
134
|
+
*/
|
135
|
+
export async function recordCentralizedBackup(db, trackingDatabaseId, metadata) {
|
136
|
+
// Ensure tracking table exists with correct schema
|
137
|
+
await createCentralizedBackupTrackingTable(db, trackingDatabaseId);
|
138
|
+
// Create backup record with all fields
|
139
|
+
// Table is guaranteed to have all attributes after createCentralizedBackupTrackingTable
|
140
|
+
const result = await db.createRow({
|
141
|
+
databaseId: trackingDatabaseId,
|
142
|
+
tableId: BACKUP_TABLE_ID,
|
143
|
+
id: ID.unique(),
|
144
|
+
data: {
|
145
|
+
// Core fields
|
146
|
+
backupType: metadata.backupType,
|
147
|
+
backupId: metadata.backupId,
|
148
|
+
manifestFileId: metadata.manifestFileId || null,
|
149
|
+
format: metadata.format,
|
150
|
+
sizeBytes: metadata.sizeBytes,
|
151
|
+
// Resource identification
|
152
|
+
databaseId: metadata.databaseId || null,
|
153
|
+
bucketId: metadata.bucketId || null,
|
154
|
+
comprehensiveBackupId: metadata.comprehensiveBackupId || null,
|
155
|
+
// Metrics
|
156
|
+
collections: metadata.collections || null,
|
157
|
+
documents: metadata.documents || null,
|
158
|
+
fileCount: metadata.fileCount || null,
|
159
|
+
// Status
|
160
|
+
status: metadata.status,
|
161
|
+
error: metadata.error || null,
|
162
|
+
// Restoration
|
163
|
+
restoredAt: metadata.restoredAt || null,
|
164
|
+
restorationStatus: metadata.restorationStatus || 'not_restored',
|
165
|
+
restorationError: metadata.restorationError || null
|
166
|
+
}
|
167
|
+
});
|
168
|
+
logger.info("Recorded centralized backup metadata", {
|
169
|
+
backupType: metadata.backupType,
|
170
|
+
backupId: metadata.backupId,
|
171
|
+
trackingDatabaseId
|
172
|
+
});
|
173
|
+
return result.data;
|
174
|
+
}
|
175
|
+
/**
|
176
|
+
* Lists all backups of a specific type, sorted by creation date (newest first)
|
177
|
+
*/
|
178
|
+
export async function listCentralizedBackups(db, trackingDatabaseId, options) {
|
179
|
+
try {
|
180
|
+
const queries = [
|
181
|
+
Query.orderDesc("$createdAt"),
|
182
|
+
Query.limit(options?.limit || 100)
|
183
|
+
];
|
184
|
+
// Filter by backup type if specified
|
185
|
+
if (options?.backupType) {
|
186
|
+
queries.push(Query.equal("backupType", options.backupType));
|
187
|
+
}
|
188
|
+
// Filter by resource ID if specified
|
189
|
+
if (options?.resourceId) {
|
190
|
+
if (options.backupType === 'database') {
|
191
|
+
queries.push(Query.equal("databaseId", options.resourceId));
|
192
|
+
}
|
193
|
+
else if (options.backupType === 'bucket') {
|
194
|
+
queries.push(Query.equal("bucketId", options.resourceId));
|
195
|
+
}
|
196
|
+
}
|
197
|
+
const result = await db.listRows({
|
198
|
+
databaseId: trackingDatabaseId,
|
199
|
+
tableId: BACKUP_TABLE_ID,
|
200
|
+
queries
|
201
|
+
});
|
202
|
+
return (result.rows || []);
|
203
|
+
}
|
204
|
+
catch (error) {
|
205
|
+
logger.debug("No centralized backup tracking table found", { trackingDatabaseId });
|
206
|
+
return [];
|
207
|
+
}
|
208
|
+
}
|
209
|
+
/**
|
210
|
+
* Gets a specific backup by its backup file ID
|
211
|
+
*/
|
212
|
+
export async function getCentralizedBackup(db, trackingDatabaseId, backupId) {
|
213
|
+
try {
|
214
|
+
const result = await db.listRows({
|
215
|
+
databaseId: trackingDatabaseId,
|
216
|
+
tableId: BACKUP_TABLE_ID,
|
217
|
+
queries: [
|
218
|
+
Query.equal("backupId", backupId),
|
219
|
+
Query.limit(1)
|
220
|
+
]
|
221
|
+
});
|
222
|
+
if (result.rows && result.rows.length > 0) {
|
223
|
+
return result.rows[0];
|
224
|
+
}
|
225
|
+
return null;
|
226
|
+
}
|
227
|
+
catch (error) {
|
228
|
+
logger.debug("Backup not found", { backupId, trackingDatabaseId });
|
229
|
+
return null;
|
230
|
+
}
|
231
|
+
}
|
232
|
+
/**
|
233
|
+
* Updates restoration status for a backup
|
234
|
+
*/
|
235
|
+
export async function updateRestorationStatus(db, trackingDatabaseId, backupRecordId, restorationData) {
|
236
|
+
await db.updateRow({
|
237
|
+
databaseId: trackingDatabaseId,
|
238
|
+
tableId: BACKUP_TABLE_ID,
|
239
|
+
id: backupRecordId,
|
240
|
+
data: {
|
241
|
+
restoredAt: restorationData.restoredAt,
|
242
|
+
restorationStatus: restorationData.restorationStatus,
|
243
|
+
restorationError: restorationData.restorationError || null
|
244
|
+
}
|
245
|
+
});
|
246
|
+
logger.info("Updated restoration status", {
|
247
|
+
backupRecordId,
|
248
|
+
restorationStatus: restorationData.restorationStatus
|
249
|
+
});
|
250
|
+
}
|
251
|
+
/**
|
252
|
+
* Gets the most recent comprehensive backup
|
253
|
+
*/
|
254
|
+
export async function getLastComprehensiveBackup(db, trackingDatabaseId) {
|
255
|
+
try {
|
256
|
+
const result = await db.listRows({
|
257
|
+
databaseId: trackingDatabaseId,
|
258
|
+
tableId: BACKUP_TABLE_ID,
|
259
|
+
queries: [
|
260
|
+
Query.equal("backupType", "comprehensive"),
|
261
|
+
Query.orderDesc("$createdAt"),
|
262
|
+
Query.limit(1)
|
263
|
+
]
|
264
|
+
});
|
265
|
+
if (result.rows && result.rows.length > 0) {
|
266
|
+
return result.rows[0];
|
267
|
+
}
|
268
|
+
return null;
|
269
|
+
}
|
270
|
+
catch (error) {
|
271
|
+
logger.debug("No comprehensive backup found", { trackingDatabaseId });
|
272
|
+
return null;
|
273
|
+
}
|
274
|
+
}
|
@@ -0,0 +1,8 @@
|
|
1
|
+
import type { InteractiveCLI } from "../../interactiveCLI.js";
|
2
|
+
export declare const configCommands: {
|
3
|
+
migrateTypeScriptConfig(cli: InteractiveCLI): Promise<void>;
|
4
|
+
validateConfiguration(cli: InteractiveCLI): Promise<void>;
|
5
|
+
migrateCollectionsToTables(cli: InteractiveCLI): Promise<void>;
|
6
|
+
createCollectionConfig(cli: InteractiveCLI): Promise<void>;
|
7
|
+
reloadConfigWithSessionPreservation(cli: InteractiveCLI): Promise<void>;
|
8
|
+
};
|
@@ -0,0 +1,160 @@
|
|
1
|
+
import inquirer from "inquirer";
|
2
|
+
import { MessageFormatter } from "../../shared/messageFormatter.js";
|
3
|
+
import { migrateConfig } from "../../utils/configMigration.js";
|
4
|
+
import { validateCollectionsTablesConfig, reportValidationResults, } from "../../config/configValidation.js";
|
5
|
+
import { createMigrationPlan, executeMigrationPlan, saveMigrationResult, } from "../../config/configMigration.js";
|
6
|
+
import { createEmptyCollection } from "../../utils/setupFiles.js";
|
7
|
+
import chalk from "chalk";
|
8
|
+
export const configCommands = {
|
9
|
+
async migrateTypeScriptConfig(cli) {
|
10
|
+
try {
|
11
|
+
MessageFormatter.info("Starting TypeScript to YAML configuration migration...", { prefix: "Migration" });
|
12
|
+
// Perform the migration
|
13
|
+
await migrateConfig(cli.currentDir);
|
14
|
+
// Reset the detection flag
|
15
|
+
cli.isUsingTypeScriptConfig = false;
|
16
|
+
// Reset the controller to pick up the new config
|
17
|
+
cli.controller = undefined;
|
18
|
+
MessageFormatter.success("Migration completed successfully!", { prefix: "Migration" });
|
19
|
+
MessageFormatter.info("Your configuration has been migrated to the .appwrite directory structure", { prefix: "Migration" });
|
20
|
+
MessageFormatter.info("You can now use YAML configuration for easier management", { prefix: "Migration" });
|
21
|
+
}
|
22
|
+
catch (error) {
|
23
|
+
MessageFormatter.error("Migration failed", error instanceof Error ? error : new Error(String(error)), { prefix: "Migration" });
|
24
|
+
}
|
25
|
+
},
|
26
|
+
async validateConfiguration(cli) {
|
27
|
+
try {
|
28
|
+
MessageFormatter.info("Starting configuration validation...", { prefix: "Validation" });
|
29
|
+
await cli.initControllerIfNeeded();
|
30
|
+
const config = cli.controller?.config;
|
31
|
+
if (!config) {
|
32
|
+
MessageFormatter.error("No configuration found to validate", undefined, { prefix: "Validation" });
|
33
|
+
return;
|
34
|
+
}
|
35
|
+
const { validateCollectionsTablesConfig, reportValidationResults } = await import("../../config/configValidation.js");
|
36
|
+
const validation = validateCollectionsTablesConfig(config);
|
37
|
+
reportValidationResults(validation, { verbose: true });
|
38
|
+
if (validation.isValid) {
|
39
|
+
MessageFormatter.success("Configuration validation passed!", { prefix: "Validation" });
|
40
|
+
}
|
41
|
+
else {
|
42
|
+
MessageFormatter.error("Configuration validation failed", undefined, { prefix: "Validation" });
|
43
|
+
}
|
44
|
+
}
|
45
|
+
catch (error) {
|
46
|
+
MessageFormatter.error("Validation failed", error instanceof Error ? error : new Error(String(error)), { prefix: "Validation" });
|
47
|
+
}
|
48
|
+
},
|
49
|
+
async migrateCollectionsToTables(cli) {
|
50
|
+
try {
|
51
|
+
MessageFormatter.info("Starting collections to tables migration...", { prefix: "Migration" });
|
52
|
+
await cli.initControllerIfNeeded();
|
53
|
+
// Ensure config is properly loaded with YAML collections
|
54
|
+
if (!cli.controller?.config) {
|
55
|
+
MessageFormatter.error("No configuration found", undefined, { prefix: "Migration" });
|
56
|
+
return;
|
57
|
+
}
|
58
|
+
// Check if collections exist
|
59
|
+
if (!cli.controller.config.collections || cli.controller.config.collections.length === 0) {
|
60
|
+
MessageFormatter.error("No collections found in configuration. Please check your YAML files or appwriteConfig.ts", undefined, { prefix: "Migration" });
|
61
|
+
return;
|
62
|
+
}
|
63
|
+
const { createMigrationPlan, executeMigrationPlan, saveMigrationResult } = await import("../../config/configMigration.js");
|
64
|
+
// Get user's migration strategy preference
|
65
|
+
const { strategy } = await inquirer.prompt([
|
66
|
+
{
|
67
|
+
type: "list",
|
68
|
+
name: "strategy",
|
69
|
+
message: "Choose migration strategy:",
|
70
|
+
choices: [
|
71
|
+
{ name: "Move files (rename collections/ to tables/)", value: "move" },
|
72
|
+
{ name: "Copy files (keep both collections/ and tables/)", value: "copy" },
|
73
|
+
{ name: "Dual format (create both .ts and .yaml versions)", value: "dual" }
|
74
|
+
]
|
75
|
+
}
|
76
|
+
]);
|
77
|
+
// Map user-friendly strategy names to internal MigrationStrategy types
|
78
|
+
const migrationStrategy = strategy === "move" ? "full_migration" :
|
79
|
+
strategy === "copy" || strategy === "dual" ? "dual_format" : "full_migration";
|
80
|
+
const plan = createMigrationPlan(cli.controller.config, migrationStrategy);
|
81
|
+
const { confirmed } = await inquirer.prompt([
|
82
|
+
{
|
83
|
+
type: "confirm",
|
84
|
+
name: "confirmed",
|
85
|
+
message: `Proceed with migration? This will affect ${plan.collectionsToMigrate?.length || 0} files.`,
|
86
|
+
default: false
|
87
|
+
}
|
88
|
+
]);
|
89
|
+
if (confirmed) {
|
90
|
+
const result = executeMigrationPlan(cli.controller.config, plan);
|
91
|
+
await saveMigrationResult(result, cli.currentDir);
|
92
|
+
MessageFormatter.success("Collections to tables migration completed!", { prefix: "Migration" });
|
93
|
+
}
|
94
|
+
else {
|
95
|
+
MessageFormatter.info("Migration cancelled by user", { prefix: "Migration" });
|
96
|
+
}
|
97
|
+
}
|
98
|
+
catch (error) {
|
99
|
+
MessageFormatter.error("Migration failed", error instanceof Error ? error : new Error(String(error)), { prefix: "Migration" });
|
100
|
+
}
|
101
|
+
},
|
102
|
+
async createCollectionConfig(cli) {
|
103
|
+
const { collectionName } = await inquirer.prompt([
|
104
|
+
{
|
105
|
+
type: "input",
|
106
|
+
name: "collectionName",
|
107
|
+
message: chalk.blue("Enter the name of the collection:"),
|
108
|
+
validate: (input) => input.trim() !== "" || "Collection name cannot be empty.",
|
109
|
+
},
|
110
|
+
]);
|
111
|
+
MessageFormatter.progress(`Creating collection config file for '${collectionName}'...`, { prefix: "Collections" });
|
112
|
+
createEmptyCollection(collectionName);
|
113
|
+
MessageFormatter.success(`Collection config file created for '${collectionName}'`, { prefix: "Collections" });
|
114
|
+
},
|
115
|
+
async reloadConfigWithSessionPreservation(cli) {
|
116
|
+
MessageFormatter.progress("Reloading configuration files with session preservation...", { prefix: "Config" });
|
117
|
+
try {
|
118
|
+
const controller = cli.controller;
|
119
|
+
const UtilsController = (await import("../../utilsController.js")).UtilsController;
|
120
|
+
if (controller) {
|
121
|
+
const sessionInfo = controller.getSessionInfo();
|
122
|
+
if (sessionInfo.hasSession) {
|
123
|
+
// Extract session details for preservation
|
124
|
+
const sessionData = {
|
125
|
+
sessionCookie: controller.sessionCookie,
|
126
|
+
sessionMetadata: controller.sessionMetadata
|
127
|
+
};
|
128
|
+
// Store current config values for potential directConfig creation
|
129
|
+
const currentConfig = controller.config;
|
130
|
+
let directConfig = undefined;
|
131
|
+
if (currentConfig?.appwriteEndpoint && currentConfig?.appwriteProject) {
|
132
|
+
directConfig = {
|
133
|
+
appwriteEndpoint: currentConfig.appwriteEndpoint,
|
134
|
+
appwriteProject: currentConfig.appwriteProject,
|
135
|
+
appwriteKey: currentConfig.appwriteKey,
|
136
|
+
...sessionData // Preserve session
|
137
|
+
};
|
138
|
+
}
|
139
|
+
// Reinitialize controller with session preservation
|
140
|
+
cli.controller = new UtilsController(cli.currentDir, directConfig);
|
141
|
+
await cli.controller.init();
|
142
|
+
MessageFormatter.success("Configuration reloaded with session preserved", { prefix: "Config" });
|
143
|
+
}
|
144
|
+
else {
|
145
|
+
// No session to preserve, standard reload
|
146
|
+
await controller.reloadConfig();
|
147
|
+
MessageFormatter.success("Configuration files reloaded successfully", { prefix: "Config" });
|
148
|
+
}
|
149
|
+
}
|
150
|
+
else {
|
151
|
+
// Initialize if no controller exists
|
152
|
+
await cli.initControllerIfNeeded();
|
153
|
+
MessageFormatter.success("Configuration initialized successfully", { prefix: "Config" });
|
154
|
+
}
|
155
|
+
}
|
156
|
+
catch (error) {
|
157
|
+
MessageFormatter.error("Failed to reload configuration files", error instanceof Error ? error : new Error(String(error)), { prefix: "Config" });
|
158
|
+
}
|
159
|
+
}
|
160
|
+
};
|
@@ -0,0 +1,13 @@
|
|
1
|
+
import type { InteractiveCLI } from "../../interactiveCLI.js";
|
2
|
+
export declare const databaseCommands: {
|
3
|
+
syncDb(cli: InteractiveCLI): Promise<void>;
|
4
|
+
synchronizeConfigurations(cli: InteractiveCLI): Promise<void>;
|
5
|
+
backupDatabase(cli: InteractiveCLI): Promise<void>;
|
6
|
+
selectTrackingDatabase(cli: InteractiveCLI): Promise<string>;
|
7
|
+
ensureBackupTrackingTable(cli: InteractiveCLI, trackingDatabaseId: string): Promise<void>;
|
8
|
+
selectBackupScope(cli: InteractiveCLI): Promise<any>;
|
9
|
+
confirmBackupPlan(scope: any): Promise<boolean>;
|
10
|
+
executeUnifiedBackup(cli: InteractiveCLI, trackingDatabaseId: string, scope: any): Promise<void>;
|
11
|
+
wipeDatabase(cli: InteractiveCLI): Promise<void>;
|
12
|
+
wipeCollections(cli: InteractiveCLI): Promise<void>;
|
13
|
+
};
|