appwrite-utils-cli 0.10.86 → 1.0.1
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/.appwrite/.yaml_schemas/appwrite-config.schema.json +380 -0
- package/.appwrite/.yaml_schemas/collection.schema.json +255 -0
- package/.appwrite/collections/Categories.yaml +182 -0
- package/.appwrite/collections/ExampleCollection.yaml +36 -0
- package/.appwrite/collections/Posts.yaml +227 -0
- package/.appwrite/collections/Users.yaml +149 -0
- package/.appwrite/config.yaml +109 -0
- package/.appwrite/import/README.md +148 -0
- package/.appwrite/import/categories-import.yaml +129 -0
- package/.appwrite/import/posts-import.yaml +208 -0
- package/.appwrite/import/users-import.yaml +130 -0
- package/.appwrite/importData/categories.json +194 -0
- package/.appwrite/importData/posts.json +270 -0
- package/.appwrite/importData/users.json +220 -0
- package/.appwrite/schemas/categories.json +128 -0
- package/.appwrite/schemas/exampleCollection.json +52 -0
- package/.appwrite/schemas/posts.json +173 -0
- package/.appwrite/schemas/users.json +125 -0
- package/README.md +260 -33
- package/dist/collections/attributes.js +3 -2
- package/dist/collections/methods.js +56 -38
- package/dist/config/yamlConfig.d.ts +501 -0
- package/dist/config/yamlConfig.js +452 -0
- package/dist/databases/setup.d.ts +6 -0
- package/dist/databases/setup.js +119 -0
- package/dist/functions/methods.d.ts +1 -1
- package/dist/functions/methods.js +5 -2
- package/dist/functions/openapi.d.ts +4 -0
- package/dist/functions/openapi.js +60 -0
- package/dist/interactiveCLI.d.ts +5 -0
- package/dist/interactiveCLI.js +194 -49
- package/dist/main.js +91 -30
- package/dist/migrations/afterImportActions.js +2 -2
- package/dist/migrations/appwriteToX.d.ts +10 -0
- package/dist/migrations/appwriteToX.js +15 -4
- package/dist/migrations/backup.d.ts +16 -16
- package/dist/migrations/dataLoader.d.ts +83 -1
- package/dist/migrations/dataLoader.js +4 -4
- package/dist/migrations/importController.js +25 -18
- package/dist/migrations/importDataActions.js +2 -2
- package/dist/migrations/logging.d.ts +9 -1
- package/dist/migrations/logging.js +41 -22
- package/dist/migrations/migrationHelper.d.ts +4 -4
- package/dist/migrations/relationships.js +1 -1
- 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 +97 -0
- package/dist/migrations/services/ImportOrchestrator.js +488 -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 +0 -6
- package/dist/migrations/transfer.js +16 -132
- package/dist/migrations/yaml/YamlImportConfigLoader.d.ts +384 -0
- package/dist/migrations/yaml/YamlImportConfigLoader.js +375 -0
- package/dist/migrations/yaml/YamlImportIntegration.d.ts +87 -0
- package/dist/migrations/yaml/YamlImportIntegration.js +330 -0
- package/dist/migrations/yaml/generateImportSchemas.d.ts +17 -0
- package/dist/migrations/yaml/generateImportSchemas.js +575 -0
- package/dist/schemas/authUser.d.ts +9 -9
- package/dist/shared/attributeManager.d.ts +17 -0
- package/dist/shared/attributeManager.js +273 -0
- package/dist/shared/confirmationDialogs.d.ts +75 -0
- package/dist/shared/confirmationDialogs.js +236 -0
- package/dist/shared/functionManager.d.ts +48 -0
- package/dist/shared/functionManager.js +322 -0
- package/dist/shared/indexManager.d.ts +24 -0
- package/dist/shared/indexManager.js +150 -0
- package/dist/shared/jsonSchemaGenerator.d.ts +51 -0
- package/dist/shared/jsonSchemaGenerator.js +313 -0
- package/dist/shared/logging.d.ts +10 -0
- package/dist/shared/logging.js +46 -0
- package/dist/shared/messageFormatter.d.ts +37 -0
- package/dist/shared/messageFormatter.js +152 -0
- package/dist/shared/migrationHelpers.d.ts +173 -0
- package/dist/shared/migrationHelpers.js +142 -0
- package/dist/shared/operationLogger.d.ts +3 -0
- package/dist/shared/operationLogger.js +25 -0
- package/dist/shared/operationQueue.d.ts +13 -0
- package/dist/shared/operationQueue.js +79 -0
- package/dist/shared/progressManager.d.ts +62 -0
- package/dist/shared/progressManager.js +215 -0
- package/dist/shared/schemaGenerator.d.ts +18 -0
- package/dist/shared/schemaGenerator.js +523 -0
- package/dist/storage/methods.d.ts +3 -1
- package/dist/storage/methods.js +144 -55
- package/dist/storage/schemas.d.ts +56 -16
- package/dist/types.d.ts +2 -2
- package/dist/types.js +1 -1
- 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 +156 -0
- package/dist/utils/dataConverters.d.ts +46 -0
- package/dist/utils/dataConverters.js +139 -0
- package/dist/utils/loadConfigs.d.ts +15 -4
- package/dist/utils/loadConfigs.js +377 -51
- package/dist/utils/schemaStrings.js +2 -1
- package/dist/utils/setupFiles.d.ts +2 -1
- package/dist/utils/setupFiles.js +723 -28
- package/dist/utils/validationRules.d.ts +43 -0
- package/dist/utils/validationRules.js +42 -0
- package/dist/utils/yamlConverter.d.ts +48 -0
- package/dist/utils/yamlConverter.js +98 -0
- package/dist/utilsController.js +65 -43
- package/package.json +19 -15
- package/src/collections/attributes.ts +3 -2
- package/src/collections/methods.ts +85 -51
- package/src/config/yamlConfig.ts +488 -0
- package/src/{migrations/setupDatabase.ts → databases/setup.ts} +11 -5
- package/src/functions/methods.ts +8 -4
- package/src/functions/templates/count-docs-in-collection/package.json +25 -0
- package/src/functions/templates/count-docs-in-collection/tsconfig.json +28 -0
- package/src/functions/templates/typescript-node/package.json +24 -0
- package/src/functions/templates/typescript-node/tsconfig.json +28 -0
- package/src/functions/templates/uv/README.md +31 -0
- package/src/functions/templates/uv/pyproject.toml +29 -0
- package/src/interactiveCLI.ts +226 -61
- package/src/main.ts +111 -37
- package/src/migrations/afterImportActions.ts +2 -2
- package/src/migrations/appwriteToX.ts +17 -4
- package/src/migrations/dataLoader.ts +4 -4
- package/src/migrations/importController.ts +30 -22
- package/src/migrations/importDataActions.ts +2 -2
- package/src/migrations/relationships.ts +1 -1
- package/src/migrations/services/DataTransformationService.ts +196 -0
- package/src/migrations/services/FileHandlerService.ts +311 -0
- package/src/migrations/services/ImportOrchestrator.ts +669 -0
- package/src/migrations/services/RateLimitManager.ts +363 -0
- package/src/migrations/services/RelationshipResolver.ts +461 -0
- package/src/migrations/services/UserMappingService.ts +345 -0
- package/src/migrations/services/ValidationService.ts +349 -0
- package/src/migrations/transfer.ts +22 -228
- package/src/migrations/yaml/YamlImportConfigLoader.ts +427 -0
- package/src/migrations/yaml/YamlImportIntegration.ts +419 -0
- package/src/migrations/yaml/generateImportSchemas.ts +589 -0
- package/src/shared/attributeManager.ts +429 -0
- package/src/shared/confirmationDialogs.ts +327 -0
- package/src/shared/functionManager.ts +515 -0
- package/src/shared/indexManager.ts +253 -0
- package/src/shared/jsonSchemaGenerator.ts +403 -0
- package/src/shared/logging.ts +74 -0
- package/src/shared/messageFormatter.ts +195 -0
- package/src/{migrations/migrationHelper.ts → shared/migrationHelpers.ts} +22 -4
- package/src/{migrations/helper.ts → shared/operationLogger.ts} +7 -2
- package/src/{migrations/queue.ts → shared/operationQueue.ts} +1 -1
- package/src/shared/progressManager.ts +278 -0
- package/src/{migrations/schemaStrings.ts → shared/schemaGenerator.ts} +71 -17
- package/src/storage/methods.ts +199 -78
- package/src/types.ts +2 -2
- package/src/{migrations/users.ts → users/methods.ts} +2 -2
- package/src/utils/configMigration.ts +212 -0
- package/src/utils/loadConfigs.ts +414 -52
- package/src/utils/schemaStrings.ts +2 -1
- package/src/utils/setupFiles.ts +742 -40
- package/src/{migrations → utils}/validationRules.ts +1 -1
- package/src/utils/yamlConverter.ts +131 -0
- package/src/utilsController.ts +75 -54
- package/src/functions/templates/poetry/README.md +0 -30
- package/src/functions/templates/poetry/pyproject.toml +0 -16
- package/src/migrations/attributes.ts +0 -561
- package/src/migrations/backup.ts +0 -205
- package/src/migrations/databases.ts +0 -39
- package/src/migrations/dbHelpers.ts +0 -92
- package/src/migrations/indexes.ts +0 -40
- package/src/migrations/logging.ts +0 -29
- package/src/migrations/storage.ts +0 -538
- /package/src/{migrations → functions}/openapi.ts +0 -0
- /package/src/functions/templates/{poetry → uv}/src/__init__.py +0 -0
- /package/src/functions/templates/{poetry → uv}/src/index.py +0 -0
- /package/src/{migrations/converters.ts → utils/dataConverters.ts} +0 -0
@@ -1,538 +0,0 @@
|
|
1
|
-
import {
|
2
|
-
Storage,
|
3
|
-
Databases,
|
4
|
-
Query,
|
5
|
-
type Models,
|
6
|
-
ID,
|
7
|
-
Permission,
|
8
|
-
} from "node-appwrite";
|
9
|
-
import { InputFile } from "node-appwrite/file";
|
10
|
-
import { type OperationCreate, type BackupCreate } from "./backup.js";
|
11
|
-
import { splitIntoBatches } from "./migrationHelper.js";
|
12
|
-
import type { AppwriteConfig } from "appwrite-utils";
|
13
|
-
import {
|
14
|
-
getAppwriteClient,
|
15
|
-
tryAwaitWithRetry,
|
16
|
-
} from "../utils/helperFunctions.js";
|
17
|
-
|
18
|
-
export const logOperation = async (
|
19
|
-
db: Databases,
|
20
|
-
dbId: string,
|
21
|
-
operationDetails: OperationCreate,
|
22
|
-
operationId?: string
|
23
|
-
): Promise<Models.Document> => {
|
24
|
-
try {
|
25
|
-
let operation;
|
26
|
-
if (operationId) {
|
27
|
-
// Update existing operation log
|
28
|
-
operation = await tryAwaitWithRetry(
|
29
|
-
async () =>
|
30
|
-
await db.updateDocument(
|
31
|
-
"migrations",
|
32
|
-
"currentOperations",
|
33
|
-
operationId,
|
34
|
-
operationDetails
|
35
|
-
)
|
36
|
-
);
|
37
|
-
} else {
|
38
|
-
// Create new operation log
|
39
|
-
operation = await db.createDocument(
|
40
|
-
"migrations",
|
41
|
-
"currentOperations",
|
42
|
-
ID.unique(),
|
43
|
-
operationDetails
|
44
|
-
);
|
45
|
-
}
|
46
|
-
console.log(`Operation logged: ${operation.$id}`);
|
47
|
-
return operation;
|
48
|
-
} catch (error) {
|
49
|
-
console.error(`Error logging operation: ${error}`);
|
50
|
-
throw error;
|
51
|
-
}
|
52
|
-
};
|
53
|
-
|
54
|
-
export const initOrGetBackupStorage = async (storage: Storage) => {
|
55
|
-
try {
|
56
|
-
const backupStorage = await tryAwaitWithRetry(
|
57
|
-
async () => await storage.getBucket("backupStorage")
|
58
|
-
);
|
59
|
-
return backupStorage;
|
60
|
-
} catch (e) {
|
61
|
-
// ID backupStorage
|
62
|
-
// Name Backups Storage
|
63
|
-
const backupStorage = await tryAwaitWithRetry(
|
64
|
-
async () => await storage.createBucket("backupStorage", "Backups Storage")
|
65
|
-
);
|
66
|
-
return backupStorage;
|
67
|
-
}
|
68
|
-
};
|
69
|
-
|
70
|
-
export const initOrGetDocumentStorage = async (
|
71
|
-
storage: Storage,
|
72
|
-
config: AppwriteConfig,
|
73
|
-
dbId: string,
|
74
|
-
bucketName?: string
|
75
|
-
) => {
|
76
|
-
try {
|
77
|
-
await tryAwaitWithRetry(
|
78
|
-
async () =>
|
79
|
-
await storage.getBucket(
|
80
|
-
bucketName ??
|
81
|
-
`${config.documentBucketId}_${dbId.toLowerCase().replace(" ", "")}`
|
82
|
-
)
|
83
|
-
);
|
84
|
-
} catch (e) {
|
85
|
-
// ID documentStorage
|
86
|
-
// Name Document Storage
|
87
|
-
const documentStorage = await tryAwaitWithRetry(
|
88
|
-
async () =>
|
89
|
-
await storage.createBucket(
|
90
|
-
`${config.documentBucketId}_${dbId.toLowerCase().replace(" ", "")}`,
|
91
|
-
`${dbId} Storage`,
|
92
|
-
[
|
93
|
-
Permission.read("any"),
|
94
|
-
Permission.create("users"),
|
95
|
-
Permission.update("users"),
|
96
|
-
Permission.delete("users"),
|
97
|
-
]
|
98
|
-
)
|
99
|
-
);
|
100
|
-
return documentStorage;
|
101
|
-
}
|
102
|
-
};
|
103
|
-
|
104
|
-
export const wipeDocumentStorage = async (
|
105
|
-
storage: Storage,
|
106
|
-
config: AppwriteConfig,
|
107
|
-
dbName: string
|
108
|
-
): Promise<void> => {
|
109
|
-
const bucketId = `${config.documentBucketId
|
110
|
-
.toLowerCase()
|
111
|
-
.replace(" ", "")}_${dbName.toLowerCase().replace(" ", "")}`;
|
112
|
-
console.log(`Wiping storage for bucket ID: ${bucketId}`);
|
113
|
-
let moreFiles = true;
|
114
|
-
let lastFileId: string | undefined;
|
115
|
-
const allFiles: string[] = [];
|
116
|
-
while (moreFiles) {
|
117
|
-
const queries = [Query.limit(100)]; // Adjust the limit as needed
|
118
|
-
if (lastFileId) {
|
119
|
-
queries.push(Query.cursorAfter(lastFileId));
|
120
|
-
}
|
121
|
-
const filesPulled = await tryAwaitWithRetry(
|
122
|
-
async () => await storage.listFiles(bucketId, queries)
|
123
|
-
);
|
124
|
-
if (filesPulled.files.length === 0) {
|
125
|
-
console.log("No files found, done!");
|
126
|
-
moreFiles = false;
|
127
|
-
break;
|
128
|
-
} else if (filesPulled.files.length > 0) {
|
129
|
-
const fileIds = filesPulled.files.map((file) => file.$id);
|
130
|
-
allFiles.push(...fileIds);
|
131
|
-
}
|
132
|
-
moreFiles = filesPulled.files.length === 100; // Adjust based on the limit
|
133
|
-
if (moreFiles) {
|
134
|
-
lastFileId = filesPulled.files[filesPulled.files.length - 1].$id;
|
135
|
-
}
|
136
|
-
}
|
137
|
-
|
138
|
-
for (const fileId of allFiles) {
|
139
|
-
console.log(`Deleting file: ${fileId}`);
|
140
|
-
await tryAwaitWithRetry(
|
141
|
-
async () => await storage.deleteFile(bucketId, fileId)
|
142
|
-
);
|
143
|
-
}
|
144
|
-
console.log(`All files in bucket ${bucketId} have been deleted.`);
|
145
|
-
};
|
146
|
-
|
147
|
-
async function retryFailedPromises(
|
148
|
-
batch: Promise<Models.Document>[],
|
149
|
-
maxRetries = 3
|
150
|
-
): Promise<PromiseSettledResult<Models.Document>[]> {
|
151
|
-
const results = await Promise.allSettled(batch);
|
152
|
-
const toRetry: Promise<any>[] = [];
|
153
|
-
|
154
|
-
results.forEach((result, index) => {
|
155
|
-
if (result.status === "rejected") {
|
156
|
-
console.error("Promise rejected with reason:", result.reason);
|
157
|
-
if (maxRetries > 0) {
|
158
|
-
toRetry.push(batch[index]);
|
159
|
-
}
|
160
|
-
}
|
161
|
-
});
|
162
|
-
|
163
|
-
if (toRetry.length > 0) {
|
164
|
-
console.log(`Retrying ${toRetry.length} promises`);
|
165
|
-
return retryFailedPromises(toRetry, maxRetries - 1);
|
166
|
-
} else {
|
167
|
-
return results
|
168
|
-
.filter((result) => result.status === "fulfilled")
|
169
|
-
.map((result) => result);
|
170
|
-
}
|
171
|
-
}
|
172
|
-
|
173
|
-
export const backupDatabase = async (
|
174
|
-
database: Databases,
|
175
|
-
databaseId: string,
|
176
|
-
storage: Storage
|
177
|
-
): Promise<void> => {
|
178
|
-
console.log("---------------------------------");
|
179
|
-
console.log("Starting Database Backup of " + databaseId);
|
180
|
-
console.log("---------------------------------");
|
181
|
-
let data: BackupCreate = {
|
182
|
-
database: "",
|
183
|
-
collections: [],
|
184
|
-
documents: [],
|
185
|
-
};
|
186
|
-
|
187
|
-
const backupOperation = await logOperation(database, databaseId, {
|
188
|
-
operationType: "backup",
|
189
|
-
collectionId: "",
|
190
|
-
data: "Starting backup...",
|
191
|
-
progress: 0,
|
192
|
-
total: 100, // This will be dynamically updated later
|
193
|
-
error: "",
|
194
|
-
status: "in_progress",
|
195
|
-
});
|
196
|
-
|
197
|
-
// Fetch and backup the database details
|
198
|
-
let db: Models.Database;
|
199
|
-
try {
|
200
|
-
db = await tryAwaitWithRetry(async () => await database.get(databaseId));
|
201
|
-
} catch (e) {
|
202
|
-
console.error(`Error fetching database: ${e}`);
|
203
|
-
await logOperation(
|
204
|
-
database,
|
205
|
-
databaseId,
|
206
|
-
{
|
207
|
-
operationType: "backup",
|
208
|
-
collectionId: "",
|
209
|
-
data: "Error fetching database, skipping...",
|
210
|
-
progress: 0,
|
211
|
-
total: 100, // This will be dynamically updated later
|
212
|
-
error: `Error fetching database: ${e}`,
|
213
|
-
status: "error",
|
214
|
-
},
|
215
|
-
backupOperation.$id
|
216
|
-
);
|
217
|
-
return;
|
218
|
-
}
|
219
|
-
data.database = JSON.stringify(db);
|
220
|
-
|
221
|
-
// Initialize pagination for collections
|
222
|
-
let lastCollectionId = "";
|
223
|
-
let moreCollections = true;
|
224
|
-
let progress = 0;
|
225
|
-
let total = 0; // Initialize total to 0, will be updated dynamically
|
226
|
-
|
227
|
-
while (moreCollections) {
|
228
|
-
const collectionResponse = await tryAwaitWithRetry(
|
229
|
-
async () =>
|
230
|
-
await database.listCollections(databaseId, [
|
231
|
-
Query.limit(500), // Adjust the limit as needed
|
232
|
-
...(lastCollectionId ? [Query.cursorAfter(lastCollectionId)] : []),
|
233
|
-
])
|
234
|
-
);
|
235
|
-
|
236
|
-
total += collectionResponse.collections.length; // Update total with number of collections
|
237
|
-
|
238
|
-
for (const {
|
239
|
-
$id: collectionId,
|
240
|
-
name: collectionName,
|
241
|
-
} of collectionResponse.collections) {
|
242
|
-
let collectionDocumentCount = 0; // Initialize document count for the current collection
|
243
|
-
try {
|
244
|
-
const collection = await tryAwaitWithRetry(
|
245
|
-
async () => await database.getCollection(databaseId, collectionId)
|
246
|
-
);
|
247
|
-
progress++;
|
248
|
-
data.collections.push(JSON.stringify(collection));
|
249
|
-
|
250
|
-
// Initialize pagination for documents within the current collection
|
251
|
-
let lastDocumentId = "";
|
252
|
-
let moreDocuments = true;
|
253
|
-
|
254
|
-
while (moreDocuments) {
|
255
|
-
const documentResponse = await tryAwaitWithRetry(
|
256
|
-
async () =>
|
257
|
-
await database.listDocuments(databaseId, collectionId, [
|
258
|
-
Query.limit(500), // Adjust the limit as needed
|
259
|
-
...(lastDocumentId ? [Query.cursorAfter(lastDocumentId)] : []),
|
260
|
-
])
|
261
|
-
);
|
262
|
-
|
263
|
-
total += documentResponse.documents.length; // Update total with number of documents
|
264
|
-
collectionDocumentCount += documentResponse.documents.length; // Update document count for the current collection
|
265
|
-
let documentPromises: Promise<Models.Document>[] = [];
|
266
|
-
for (const { $id: documentId } of documentResponse.documents) {
|
267
|
-
documentPromises.push(
|
268
|
-
database.getDocument(databaseId, collectionId, documentId)
|
269
|
-
);
|
270
|
-
}
|
271
|
-
const promiseBatches = splitIntoBatches(documentPromises);
|
272
|
-
const documentsPulled = [];
|
273
|
-
for (const batch of promiseBatches) {
|
274
|
-
const successfulDocuments = await retryFailedPromises(batch);
|
275
|
-
documentsPulled.push(...successfulDocuments);
|
276
|
-
}
|
277
|
-
const documents = documentsPulled;
|
278
|
-
data.documents.push({
|
279
|
-
collectionId: collectionId,
|
280
|
-
data: JSON.stringify(documents),
|
281
|
-
});
|
282
|
-
progress += documents.length;
|
283
|
-
|
284
|
-
console.log(
|
285
|
-
`Collection ${collectionName} backed up ${collectionDocumentCount} documents (so far)`
|
286
|
-
);
|
287
|
-
|
288
|
-
// Update the operation log with the current progress
|
289
|
-
await logOperation(
|
290
|
-
database,
|
291
|
-
databaseId,
|
292
|
-
{
|
293
|
-
operationType: "backup",
|
294
|
-
collectionId: collectionId,
|
295
|
-
data: `Still backing up, ${data.collections.length} collections so far`,
|
296
|
-
progress: progress,
|
297
|
-
total: total,
|
298
|
-
error: "",
|
299
|
-
status: "in_progress",
|
300
|
-
},
|
301
|
-
backupOperation.$id
|
302
|
-
);
|
303
|
-
|
304
|
-
// Check if there are more documents to fetch
|
305
|
-
moreDocuments = documentResponse.documents.length === 500;
|
306
|
-
if (moreDocuments) {
|
307
|
-
lastDocumentId =
|
308
|
-
documentResponse.documents[documentResponse.documents.length - 1]
|
309
|
-
.$id;
|
310
|
-
}
|
311
|
-
}
|
312
|
-
console.log(
|
313
|
-
`Collection ${collectionName} backed up with ${collectionDocumentCount} documents.`
|
314
|
-
);
|
315
|
-
} catch (error) {
|
316
|
-
console.log(
|
317
|
-
`Collection ${collectionName} must not exist, continuing...`
|
318
|
-
);
|
319
|
-
continue;
|
320
|
-
}
|
321
|
-
}
|
322
|
-
|
323
|
-
// Check if there are more collections to fetch
|
324
|
-
moreCollections = collectionResponse.collections.length === 500;
|
325
|
-
if (moreCollections) {
|
326
|
-
lastCollectionId =
|
327
|
-
collectionResponse.collections[
|
328
|
-
collectionResponse.collections.length - 1
|
329
|
-
].$id;
|
330
|
-
}
|
331
|
-
}
|
332
|
-
|
333
|
-
// Update the backup operation with the current progress and total
|
334
|
-
await logOperation(
|
335
|
-
database,
|
336
|
-
databaseId,
|
337
|
-
{
|
338
|
-
operationType: "backup",
|
339
|
-
collectionId: "",
|
340
|
-
data: `Still backing up, ${data.collections.length} collections so far`,
|
341
|
-
progress: progress,
|
342
|
-
total: total,
|
343
|
-
error: "",
|
344
|
-
status: "in_progress",
|
345
|
-
},
|
346
|
-
backupOperation.$id
|
347
|
-
);
|
348
|
-
|
349
|
-
// Create the backup with the accumulated data
|
350
|
-
const bucket = await initOrGetBackupStorage(storage);
|
351
|
-
const inputFile = InputFile.fromPlainText(
|
352
|
-
JSON.stringify(data),
|
353
|
-
`${new Date().toISOString()}-${databaseId}.json`
|
354
|
-
);
|
355
|
-
const fileCreated = await storage.createFile(
|
356
|
-
bucket.$id,
|
357
|
-
ID.unique(),
|
358
|
-
inputFile
|
359
|
-
);
|
360
|
-
|
361
|
-
// Final update to the backup operation marking it as completed
|
362
|
-
await logOperation(
|
363
|
-
database,
|
364
|
-
databaseId,
|
365
|
-
{
|
366
|
-
operationType: "backup",
|
367
|
-
collectionId: "",
|
368
|
-
data: fileCreated.$id,
|
369
|
-
progress: 100,
|
370
|
-
total: total, // Ensure the total reflects the actual total processed
|
371
|
-
error: "",
|
372
|
-
status: "completed",
|
373
|
-
},
|
374
|
-
backupOperation.$id
|
375
|
-
);
|
376
|
-
console.log("---------------------------------");
|
377
|
-
console.log("Database Backup Complete");
|
378
|
-
console.log("---------------------------------");
|
379
|
-
};
|
380
|
-
|
381
|
-
export const transferStorageLocalToLocal = async (
|
382
|
-
storage: Storage,
|
383
|
-
fromBucketId: string,
|
384
|
-
toBucketId: string
|
385
|
-
) => {
|
386
|
-
console.log(`Transferring files from ${fromBucketId} to ${toBucketId}`);
|
387
|
-
let lastFileId: string | undefined;
|
388
|
-
let fromFiles = await tryAwaitWithRetry(
|
389
|
-
async () => await storage.listFiles(fromBucketId, [Query.limit(100)])
|
390
|
-
);
|
391
|
-
const allFromFiles = fromFiles.files;
|
392
|
-
let numberOfFiles = 0;
|
393
|
-
|
394
|
-
const downloadFileWithRetry = async (bucketId: string, fileId: string) => {
|
395
|
-
let attempts = 3;
|
396
|
-
while (attempts > 0) {
|
397
|
-
try {
|
398
|
-
return await storage.getFileDownload(bucketId, fileId);
|
399
|
-
} catch (error) {
|
400
|
-
console.error(`Error downloading file ${fileId}: ${error}`);
|
401
|
-
attempts--;
|
402
|
-
if (attempts === 0) throw error;
|
403
|
-
}
|
404
|
-
}
|
405
|
-
};
|
406
|
-
|
407
|
-
if (fromFiles.files.length < 100) {
|
408
|
-
for (const file of allFromFiles) {
|
409
|
-
const fileData = await tryAwaitWithRetry(
|
410
|
-
async () => await downloadFileWithRetry(file.bucketId, file.$id)
|
411
|
-
);
|
412
|
-
if (!fileData) {
|
413
|
-
console.error(`Error downloading file ${file.$id}`);
|
414
|
-
continue;
|
415
|
-
}
|
416
|
-
const fileToCreate = InputFile.fromBuffer(
|
417
|
-
new Uint8Array(fileData),
|
418
|
-
file.name
|
419
|
-
);
|
420
|
-
console.log(`Creating file: ${file.name}`);
|
421
|
-
tryAwaitWithRetry(
|
422
|
-
async () =>
|
423
|
-
await storage.createFile(
|
424
|
-
toBucketId,
|
425
|
-
file.$id,
|
426
|
-
fileToCreate,
|
427
|
-
file.$permissions
|
428
|
-
)
|
429
|
-
);
|
430
|
-
numberOfFiles++;
|
431
|
-
}
|
432
|
-
} else {
|
433
|
-
lastFileId = fromFiles.files[fromFiles.files.length - 1].$id;
|
434
|
-
while (lastFileId) {
|
435
|
-
const files = await tryAwaitWithRetry(
|
436
|
-
async () =>
|
437
|
-
await storage.listFiles(fromBucketId, [
|
438
|
-
Query.limit(100),
|
439
|
-
Query.cursorAfter(lastFileId!),
|
440
|
-
])
|
441
|
-
);
|
442
|
-
allFromFiles.push(...files.files);
|
443
|
-
if (files.files.length < 100) {
|
444
|
-
lastFileId = undefined;
|
445
|
-
} else {
|
446
|
-
lastFileId = files.files[files.files.length - 1].$id;
|
447
|
-
}
|
448
|
-
}
|
449
|
-
for (const file of allFromFiles) {
|
450
|
-
const fileData = await tryAwaitWithRetry(
|
451
|
-
async () => await downloadFileWithRetry(file.bucketId, file.$id)
|
452
|
-
);
|
453
|
-
if (!fileData) {
|
454
|
-
console.error(`Error downloading file ${file.$id}`);
|
455
|
-
continue;
|
456
|
-
}
|
457
|
-
const fileToCreate = InputFile.fromBuffer(
|
458
|
-
new Uint8Array(fileData),
|
459
|
-
file.name
|
460
|
-
);
|
461
|
-
await tryAwaitWithRetry(
|
462
|
-
async () =>
|
463
|
-
await storage.createFile(
|
464
|
-
toBucketId,
|
465
|
-
file.$id,
|
466
|
-
fileToCreate,
|
467
|
-
file.$permissions
|
468
|
-
)
|
469
|
-
);
|
470
|
-
numberOfFiles++;
|
471
|
-
}
|
472
|
-
}
|
473
|
-
|
474
|
-
console.log(
|
475
|
-
`Transferred ${numberOfFiles} files from ${fromBucketId} to ${toBucketId}`
|
476
|
-
);
|
477
|
-
};
|
478
|
-
|
479
|
-
export const transferStorageLocalToRemote = async (
|
480
|
-
localStorage: Storage,
|
481
|
-
endpoint: string,
|
482
|
-
projectId: string,
|
483
|
-
apiKey: string,
|
484
|
-
fromBucketId: string,
|
485
|
-
toBucketId: string
|
486
|
-
) => {
|
487
|
-
console.log(
|
488
|
-
`Transferring files from current storage ${fromBucketId} to ${endpoint} bucket ${toBucketId}`
|
489
|
-
);
|
490
|
-
const client = getAppwriteClient(endpoint, apiKey, projectId);
|
491
|
-
const remoteStorage = new Storage(client);
|
492
|
-
let numberOfFiles = 0;
|
493
|
-
let lastFileId: string | undefined;
|
494
|
-
let fromFiles = await tryAwaitWithRetry(
|
495
|
-
async () => await localStorage.listFiles(fromBucketId, [Query.limit(100)])
|
496
|
-
);
|
497
|
-
const allFromFiles = fromFiles.files;
|
498
|
-
if (fromFiles.files.length === 100) {
|
499
|
-
lastFileId = fromFiles.files[fromFiles.files.length - 1].$id;
|
500
|
-
while (lastFileId) {
|
501
|
-
const files = await tryAwaitWithRetry(
|
502
|
-
async () =>
|
503
|
-
await localStorage.listFiles(fromBucketId, [
|
504
|
-
Query.limit(100),
|
505
|
-
Query.cursorAfter(lastFileId!),
|
506
|
-
])
|
507
|
-
);
|
508
|
-
allFromFiles.push(...files.files);
|
509
|
-
if (files.files.length < 100) {
|
510
|
-
break;
|
511
|
-
}
|
512
|
-
lastFileId = files.files[files.files.length - 1].$id;
|
513
|
-
}
|
514
|
-
}
|
515
|
-
|
516
|
-
for (const file of allFromFiles) {
|
517
|
-
const fileData = await tryAwaitWithRetry(
|
518
|
-
async () => await localStorage.getFileDownload(file.bucketId, file.$id)
|
519
|
-
);
|
520
|
-
const fileToCreate = InputFile.fromBuffer(
|
521
|
-
new Uint8Array(fileData),
|
522
|
-
file.name
|
523
|
-
);
|
524
|
-
await tryAwaitWithRetry(
|
525
|
-
async () =>
|
526
|
-
await remoteStorage.createFile(
|
527
|
-
toBucketId,
|
528
|
-
file.$id,
|
529
|
-
fileToCreate,
|
530
|
-
file.$permissions
|
531
|
-
)
|
532
|
-
);
|
533
|
-
numberOfFiles++;
|
534
|
-
}
|
535
|
-
console.log(
|
536
|
-
`Transferred ${numberOfFiles} files from ${fromBucketId} to ${toBucketId}`
|
537
|
-
);
|
538
|
-
};
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|