appwrite-utils-cli 0.9.4 → 0.9.51

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/README.md CHANGED
@@ -124,6 +124,8 @@ This updated CLI ensures that developers have robust tools at their fingertips t
124
124
 
125
125
  ## Changelog
126
126
 
127
+ - 0.9.51: Fix transfer databases, remove "ensure duplicates" check
128
+ - 0.9.5: Fixed not checking for storage bucket for each database (checking the creation status) when importing data
127
129
  - 0.9.4: Fixed migrations database ensuring it has the required collections
128
130
  - 0.9.3: Fixed deployment error && fix lack of existing `appwriteConfig.ts` file from causing error (you want to be able to setup yeah? haha)
129
131
  - 0.9.2: Added changelog back, whoops
@@ -416,14 +416,14 @@ export class InteractiveCLI {
416
416
  default: false,
417
417
  },
418
418
  ]);
419
- const { checkDuplicates } = await inquirer.prompt([
420
- {
421
- type: "confirm",
422
- name: "checkDuplicates",
423
- message: "Do you want to check for duplicates during import?",
424
- default: true,
425
- },
426
- ]);
419
+ // const { checkDuplicates } = await inquirer.prompt([
420
+ // {
421
+ // type: "confirm",
422
+ // name: "checkDuplicates",
423
+ // message: "Do you want to check for duplicates during import?",
424
+ // default: true,
425
+ // },
426
+ // ]);
427
427
  console.log("Importing data...");
428
428
  await this.controller.importData({
429
429
  databases: selectedDatabases,
@@ -431,7 +431,8 @@ export class InteractiveCLI {
431
431
  ? selectedCollections.map((c) => c.$id)
432
432
  : undefined,
433
433
  shouldWriteFile,
434
- checkDuplicates,
434
+ checkDuplicates: false,
435
+ // checkDuplicates,
435
436
  });
436
437
  }
437
438
  async transferData() {
@@ -476,10 +477,21 @@ export class InteractiveCLI {
476
477
  }
477
478
  else {
478
479
  targetClient = sourceClient;
479
- sourceDatabases = targetDatabases = await fetchAllDatabases(sourceClient);
480
+ const allDatabases = await fetchAllDatabases(sourceClient);
481
+ sourceDatabases = targetDatabases = allDatabases;
482
+ }
483
+ const fromDbs = await this.selectDatabases(sourceDatabases, "Select the source database:", false);
484
+ console.log(fromDbs);
485
+ const fromDb = fromDbs;
486
+ if (!fromDb) {
487
+ throw new Error("No source database selected");
488
+ }
489
+ const availableDbs = targetDatabases.filter((db) => db.$id !== fromDb.$id);
490
+ const targetDbs = await this.selectDatabases(availableDbs, "Select the target database:", false);
491
+ const targetDb = targetDbs;
492
+ if (!targetDb) {
493
+ throw new Error("No target database selected");
480
494
  }
481
- const [fromDb] = await this.selectDatabases(sourceDatabases, "Select the source database:", false);
482
- const [targetDb] = await this.selectDatabases(targetDatabases.filter((db) => db.$id !== fromDb.$id), "Select the target database:", false);
483
495
  const selectedCollections = await this.selectCollections(fromDb, sourceClient, "Select collections to transfer):");
484
496
  const { transferStorage } = await inquirer.prompt([
485
497
  {
@@ -499,8 +511,10 @@ export class InteractiveCLI {
499
511
  const targetBuckets = isRemote
500
512
  ? await listBuckets(targetStorage)
501
513
  : sourceBuckets;
502
- [sourceBucket] = await this.selectBuckets(sourceBuckets.buckets, "Select the source bucket:", false);
503
- [targetBucket] = await this.selectBuckets(targetBuckets.buckets, "Select the target bucket:", false);
514
+ const sourceBucketPicked = await this.selectBuckets(sourceBuckets.buckets, "Select the source bucket:", false);
515
+ const targetBucketPicked = await this.selectBuckets(targetBuckets.buckets, "Select the target bucket:", false);
516
+ sourceBucket = sourceBucketPicked;
517
+ targetBucket = targetBucketPicked;
504
518
  }
505
519
  let transferOptions = {
506
520
  fromDb,
@@ -100,14 +100,26 @@ export const transferStorageLocalToRemote = async (localStorage, endpoint, proje
100
100
  * within the same Appwrite Project
101
101
  */
102
102
  export const transferDocumentsBetweenDbsLocalToLocal = async (db, fromDbId, toDbId, fromCollId, toCollId) => {
103
- let fromCollDocs = await tryAwaitWithRetry(async () => db.listDocuments(fromDbId, fromCollId, [Query.limit(50)]));
104
103
  let totalDocumentsTransferred = 0;
105
- if (fromCollDocs.documents.length === 0) {
106
- console.log(`No documents found in collection ${fromCollId}`);
107
- return;
108
- }
109
- else if (fromCollDocs.documents.length < 50) {
110
- const batchedPromises = fromCollDocs.documents.map((doc) => {
104
+ let lastDocumentId;
105
+ let hasMoreDocuments = true;
106
+ while (hasMoreDocuments) {
107
+ const queryParams = [Query.limit(50)];
108
+ if (lastDocumentId) {
109
+ queryParams.push(Query.cursorAfter(lastDocumentId));
110
+ }
111
+ const fromCollDocs = await tryAwaitWithRetry(async () => db.listDocuments(fromDbId, fromCollId, queryParams));
112
+ if (fromCollDocs.documents.length === 0) {
113
+ if (totalDocumentsTransferred === 0) {
114
+ console.log(`No documents found in collection ${fromCollId}`);
115
+ }
116
+ break;
117
+ }
118
+ const allDocsToCreateCheck = await tryAwaitWithRetry(async () => await db.listDocuments(toDbId, toCollId, [
119
+ Query.equal("$id", fromCollDocs.documents.map((doc) => doc.$id)),
120
+ ]));
121
+ const docsToCreate = fromCollDocs.documents.filter((doc) => !allDocsToCreateCheck.documents.some((d) => d.$id === doc.$id));
122
+ const batchedPromises = docsToCreate.map((doc) => {
111
123
  const toCreateObject = {
112
124
  ...doc,
113
125
  };
@@ -120,42 +132,13 @@ export const transferDocumentsBetweenDbsLocalToLocal = async (db, fromDbId, toDb
120
132
  return tryAwaitWithRetry(async () => await db.createDocument(toDbId, toCollId, doc.$id, toCreateObject, doc.$permissions));
121
133
  });
122
134
  await Promise.all(batchedPromises);
123
- totalDocumentsTransferred += fromCollDocs.documents.length;
124
- }
125
- else {
126
- const batchedPromises = fromCollDocs.documents.map((doc) => {
127
- const toCreateObject = {
128
- ...doc,
129
- };
130
- delete toCreateObject.$databaseId;
131
- delete toCreateObject.$collectionId;
132
- delete toCreateObject.$createdAt;
133
- delete toCreateObject.$updatedAt;
134
- delete toCreateObject.$id;
135
- delete toCreateObject.$permissions;
136
- return tryAwaitWithRetry(async () => db.createDocument(toDbId, toCollId, doc.$id, toCreateObject, doc.$permissions));
137
- });
138
- await Promise.all(batchedPromises);
139
- totalDocumentsTransferred += fromCollDocs.documents.length;
140
- while (fromCollDocs.documents.length === 50) {
141
- fromCollDocs = await tryAwaitWithRetry(async () => await db.listDocuments(fromDbId, fromCollId, [
142
- Query.limit(50),
143
- Query.cursorAfter(fromCollDocs.documents[fromCollDocs.documents.length - 1].$id),
144
- ]));
145
- const batchedPromises = fromCollDocs.documents.map((doc) => {
146
- const toCreateObject = {
147
- ...doc,
148
- };
149
- delete toCreateObject.$databaseId;
150
- delete toCreateObject.$collectionId;
151
- delete toCreateObject.$createdAt;
152
- delete toCreateObject.$updatedAt;
153
- delete toCreateObject.$id;
154
- delete toCreateObject.$permissions;
155
- return tryAwaitWithRetry(async () => await db.createDocument(toDbId, toCollId, doc.$id, toCreateObject, doc.$permissions));
156
- });
157
- await Promise.all(batchedPromises);
158
- totalDocumentsTransferred += fromCollDocs.documents.length;
135
+ totalDocumentsTransferred += docsToCreate.length;
136
+ if (fromCollDocs.documents.length < 50) {
137
+ hasMoreDocuments = false;
138
+ }
139
+ else {
140
+ lastDocumentId =
141
+ fromCollDocs.documents[fromCollDocs.documents.length - 1].$id;
159
142
  }
160
143
  }
161
144
  console.log(`Transferred ${totalDocumentsTransferred} documents from database ${fromDbId} to database ${toDbId} -- collection ${fromCollId} to collection ${toCollId}`);
@@ -173,7 +156,11 @@ export const transferDocumentsBetweenDbsLocalToRemote = async (localDb, endpoint
173
156
  return;
174
157
  }
175
158
  else if (fromCollDocs.documents.length < 50) {
176
- const batchedPromises = fromCollDocs.documents.map((doc) => {
159
+ const allDocsToCreateCheck = await tryAwaitWithRetry(async () => await remoteDb.listDocuments(toDbId, toCollId, [
160
+ Query.equal("$id", fromCollDocs.documents.map((doc) => doc.$id)),
161
+ ]));
162
+ const docsToCreate = fromCollDocs.documents.filter((doc) => !allDocsToCreateCheck.documents.some((d) => d.$id === doc.$id));
163
+ const batchedPromises = docsToCreate.map((doc) => {
177
164
  const toCreateObject = {
178
165
  ...doc,
179
166
  };
@@ -189,7 +176,11 @@ export const transferDocumentsBetweenDbsLocalToRemote = async (localDb, endpoint
189
176
  totalDocumentsTransferred += fromCollDocs.documents.length;
190
177
  }
191
178
  else {
192
- const batchedPromises = fromCollDocs.documents.map((doc) => {
179
+ const allDocsToCreateCheck = await tryAwaitWithRetry(async () => await remoteDb.listDocuments(toDbId, toCollId, [
180
+ Query.equal("$id", fromCollDocs.documents.map((doc) => doc.$id)),
181
+ ]));
182
+ const docsToCreate = fromCollDocs.documents.filter((doc) => !allDocsToCreateCheck.documents.some((d) => d.$id === doc.$id));
183
+ const batchedPromises = docsToCreate.map((doc) => {
193
184
  const toCreateObject = {
194
185
  ...doc,
195
186
  };
@@ -305,9 +296,7 @@ export const transferDatabaseLocalToRemote = async (localDb, endpoint, projectId
305
296
  let lastCollectionId;
306
297
  let fromCollections = await tryAwaitWithRetry(async () => await localDb.listCollections(fromDbId, [Query.limit(50)]));
307
298
  const allFromCollections = fromCollections.collections;
308
- if (fromCollections.collections.length < 50) {
309
- }
310
- else {
299
+ if (fromCollections.collections.length >= 50) {
311
300
  lastCollectionId =
312
301
  fromCollections.collections[fromCollections.collections.length - 1].$id;
313
302
  while (lastCollectionId) {
@@ -324,13 +313,58 @@ export const transferDatabaseLocalToRemote = async (localDb, endpoint, projectId
324
313
  }
325
314
  }
326
315
  for (const collection of allFromCollections) {
327
- const toCollection = await tryAwaitWithRetry(async () => await remoteDb.createCollection(toDbId, collection.$id, collection.name, collection.$permissions, collection.documentSecurity, collection.enabled));
328
- console.log(`Collection ${toCollection.name} created`);
316
+ let toCollection;
317
+ const toCollectionExists = await tryAwaitWithRetry(async () => await remoteDb.listCollections(toDbId, [
318
+ Query.equal("$id", collection.$id),
319
+ ]));
320
+ if (toCollectionExists.collections.length > 0) {
321
+ console.log(`Collection ${collection.name} already exists. Updating...`);
322
+ toCollection = toCollectionExists.collections[0];
323
+ // Update collection if needed
324
+ if (toCollection.name !== collection.name ||
325
+ toCollection.$permissions !== collection.$permissions ||
326
+ toCollection.documentSecurity !== collection.documentSecurity ||
327
+ toCollection.enabled !== collection.enabled) {
328
+ toCollection = await tryAwaitWithRetry(async () => await remoteDb.updateCollection(toDbId, collection.$id, collection.name, collection.$permissions, collection.documentSecurity, collection.enabled));
329
+ console.log(`Collection ${toCollection.name} updated`);
330
+ }
331
+ }
332
+ else {
333
+ toCollection = await tryAwaitWithRetry(async () => await remoteDb.createCollection(toDbId, collection.$id, collection.name, collection.$permissions, collection.documentSecurity, collection.enabled));
334
+ console.log(`Collection ${toCollection.name} created`);
335
+ }
336
+ // Check and update attributes
337
+ const existingAttributes = await tryAwaitWithRetry(async () => await remoteDb.listAttributes(toDbId, toCollection.$id));
329
338
  for (const attribute of collection.attributes) {
330
- await tryAwaitWithRetry(async () => await createOrUpdateAttribute(remoteDb, toDbId, toCollection, parseAttribute(attribute)));
339
+ const parsedAttribute = parseAttribute(attribute);
340
+ const existingAttribute = existingAttributes.attributes.find(
341
+ // @ts-expect-error
342
+ (attr) => attr.key === parsedAttribute.key);
343
+ if (!existingAttribute) {
344
+ await tryAwaitWithRetry(async () => await createOrUpdateAttribute(remoteDb, toDbId, toCollection, parsedAttribute));
345
+ console.log(`Attribute ${parsedAttribute.key} created`);
346
+ }
347
+ else {
348
+ // Check if attribute needs updating
349
+ // Note: Appwrite doesn't allow updating most attribute properties
350
+ // You might need to delete and recreate the attribute if significant changes are needed
351
+ console.log(`Attribute ${parsedAttribute.key} already exists`);
352
+ }
331
353
  }
354
+ // Check and update indexes
355
+ const existingIndexes = await tryAwaitWithRetry(async () => await remoteDb.listIndexes(toDbId, toCollection.$id));
332
356
  for (const index of collection.indexes) {
333
- await tryAwaitWithRetry(async () => await remoteDb.createIndex(toDbId, toCollection.$id, index.key, index.type, index.attributes, index.orders));
357
+ const existingIndex = existingIndexes.indexes.find((idx) => idx.key === index.key);
358
+ if (!existingIndex) {
359
+ await tryAwaitWithRetry(async () => await remoteDb.createIndex(toDbId, toCollection.$id, index.key, index.type, index.attributes, index.orders));
360
+ console.log(`Index ${index.key} created`);
361
+ }
362
+ else {
363
+ // Check if index needs updating
364
+ // Note: Appwrite doesn't allow updating indexes
365
+ // You might need to delete and recreate the index if changes are needed
366
+ console.log(`Index ${index.key} already exists`);
367
+ }
334
368
  }
335
369
  await transferDocumentsBetweenDbsLocalToRemote(localDb, endpoint, projectId, apiKey, fromDbId, toDbId, collection.$id, toCollection.$id);
336
370
  }
@@ -9,6 +9,7 @@ export declare const deleteBucket: (storage: Storage, bucketId: string) => Promi
9
9
  export declare const getFile: (storage: Storage, bucketId: string, fileId: string) => Promise<Models.File>;
10
10
  export declare const listFiles: (storage: Storage, bucketId: string, queries?: string[], search?: string) => Promise<Models.FileList>;
11
11
  export declare const deleteFile: (storage: Storage, bucketId: string, fileId: string) => Promise<{}>;
12
+ export declare const ensureDatabaseConfigBucketsExist: (storage: Storage, config: AppwriteConfig, databases?: Models.Database[]) => Promise<void>;
12
13
  export declare const wipeDocumentStorage: (storage: Storage, bucketId: string) => Promise<void>;
13
14
  export declare const initOrGetDocumentStorage: (storage: Storage, config: AppwriteConfig, dbId: string, bucketName?: string) => Promise<Models.Bucket>;
14
15
  export declare const initOrGetBackupStorage: (config: AppwriteConfig, storage: Storage) => Promise<Models.Bucket>;
@@ -34,6 +34,52 @@ export const listFiles = async (storage, bucketId, queries, search) => {
34
34
  export const deleteFile = async (storage, bucketId, fileId) => {
35
35
  return await storage.deleteFile(bucketId, fileId);
36
36
  };
37
+ export const ensureDatabaseConfigBucketsExist = async (storage, config, databases = []) => {
38
+ for (const db of databases) {
39
+ const database = config.databases?.find((d) => d.$id === db.$id);
40
+ if (database?.bucket) {
41
+ try {
42
+ await storage.getBucket(database.bucket.$id);
43
+ console.log(`Bucket ${database.bucket.$id} already exists.`);
44
+ }
45
+ catch (e) {
46
+ const permissions = [];
47
+ if (database.bucket.permissions &&
48
+ database.bucket.permissions.length > 0) {
49
+ for (const permission of database.bucket.permissions) {
50
+ switch (permission.permission) {
51
+ case "read":
52
+ permissions.push(Permission.read(permission.target));
53
+ break;
54
+ case "create":
55
+ permissions.push(Permission.create(permission.target));
56
+ break;
57
+ case "update":
58
+ permissions.push(Permission.update(permission.target));
59
+ break;
60
+ case "delete":
61
+ permissions.push(Permission.delete(permission.target));
62
+ break;
63
+ case "write":
64
+ permissions.push(Permission.write(permission.target));
65
+ break;
66
+ default:
67
+ console.warn(`Unknown permission: ${permission.permission}`);
68
+ break;
69
+ }
70
+ }
71
+ }
72
+ try {
73
+ await storage.createBucket(database.bucket.$id, database.bucket.name, permissions, database.bucket.fileSecurity, database.bucket.enabled, database.bucket.maximumFileSize, database.bucket.allowedFileExtensions, database.bucket.compression, database.bucket.encryption, database.bucket.antivirus);
74
+ console.log(`Bucket ${database.bucket.$id} created successfully.`);
75
+ }
76
+ catch (createError) {
77
+ console.error(`Failed to create bucket ${database.bucket.$id}:`, createError);
78
+ }
79
+ }
80
+ }
81
+ }
82
+ };
37
83
  export const wipeDocumentStorage = async (storage, bucketId) => {
38
84
  console.log(`Wiping storage for bucket ID: ${bucketId}`);
39
85
  let moreFiles = true;
@@ -27,6 +27,7 @@ export declare class UtilsController {
27
27
  constructor(currentUserDir: string);
28
28
  init(): Promise<void>;
29
29
  setupMigrationDatabase(): Promise<void>;
30
+ ensureDatabaseConfigBucketsExist(databases?: Models.Database[]): Promise<void>;
30
31
  ensureDatabasesExist(databases?: Models.Database[]): Promise<void>;
31
32
  getDatabasesByIds(ids: string[]): Promise<Models.Database[]>;
32
33
  wipeOtherDatabases(databasesToKeep: Models.Database[]): Promise<void>;
@@ -7,7 +7,7 @@ import { ImportController } from "./migrations/importController.js";
7
7
  import { ImportDataActions } from "./migrations/importDataActions.js";
8
8
  import { setupMigrationDatabase, ensureDatabasesExist, wipeOtherDatabases, } from "./migrations/setupDatabase.js";
9
9
  import { createOrUpdateCollections, wipeDatabase, generateSchemas, fetchAllCollections, } from "./collections/methods.js";
10
- import { backupDatabase, initOrGetBackupStorage, wipeDocumentStorage, } from "./storage/methods.js";
10
+ import { backupDatabase, ensureDatabaseConfigBucketsExist, initOrGetBackupStorage, wipeDocumentStorage, } from "./storage/methods.js";
11
11
  import path from "path";
12
12
  import { converterFunctions, validationRules, } from "appwrite-utils";
13
13
  import { afterImportActions } from "./migrations/afterImportActions.js";
@@ -59,11 +59,20 @@ export class UtilsController {
59
59
  throw new Error("Config not initialized");
60
60
  await setupMigrationDatabase(this.config);
61
61
  }
62
+ async ensureDatabaseConfigBucketsExist(databases = []) {
63
+ await this.init();
64
+ if (!this.storage)
65
+ throw new Error("Storage not initialized");
66
+ if (!this.config)
67
+ throw new Error("Config not initialized");
68
+ await ensureDatabaseConfigBucketsExist(this.storage, this.config, databases);
69
+ }
62
70
  async ensureDatabasesExist(databases) {
63
71
  await this.init();
64
72
  if (!this.config)
65
73
  throw new Error("Config not initialized");
66
74
  await this.setupMigrationDatabase();
75
+ await this.ensureDatabaseConfigBucketsExist(databases);
67
76
  await ensureDatabasesExist(this.config);
68
77
  }
69
78
  async getDatabasesByIds(ids) {
@@ -153,6 +162,7 @@ export class UtilsController {
153
162
  throw new Error("Database not initialized");
154
163
  const databases = await fetchAllDatabases(this.database);
155
164
  await this.ensureDatabasesExist(databases);
165
+ await this.ensureDatabaseConfigBucketsExist(databases);
156
166
  await this.createOrUpdateCollectionsForDatabases(databases);
157
167
  }
158
168
  getAppwriteFolderPath() {
package/package.json CHANGED
@@ -1,53 +1,53 @@
1
- {
2
- "name": "appwrite-utils-cli",
3
- "description": "Appwrite Utility Functions to help with database management, data conversion, data import, migrations, and much more. Meant to be used as a CLI tool, I do not recommend installing this in frontend environments.",
4
- "version": "0.9.4",
5
- "main": "src/main.ts",
6
- "type": "module",
7
- "repository": {
8
- "type": "git",
9
- "url": "https://github.com/zachhandley/AppwriteUtils"
10
- },
11
- "author": "Zach Handley <zach@blackleafdigital.com> (https://zachhandley.com)",
12
- "keywords": [
13
- "appwrite",
14
- "cli",
15
- "utils",
16
- "migrations",
17
- "data",
18
- "database",
19
- "import",
20
- "migration",
21
- "utility"
22
- ],
23
- "bin": {
24
- "appwrite-migrate": "./dist/main.js"
25
- },
26
- "scripts": {
27
- "build": "bun run tsc",
28
- "start": "tsx --no-cache src/main.ts",
29
- "deploy": "bun run build && npm publish --access public",
30
- "postinstall": "echo 'This package is intended for CLI use only and should not be added as a dependency in other projects.'"
31
- },
32
- "dependencies": {
33
- "@types/inquirer": "^9.0.7",
34
- "appwrite-utils": "^0.3.8",
35
- "commander": "^12.1.0",
36
- "inquirer": "^9.3.6",
37
- "js-yaml": "^4.1.0",
38
- "lodash": "^4.17.21",
39
- "luxon": "^3.5.0",
40
- "nanostores": "^0.10.3",
41
- "node-appwrite": "^13.0.0",
42
- "tsx": "^4.17.0",
43
- "ulidx": "^2.4.0",
44
- "winston": "^3.14.1",
45
- "zod": "^3.23.8"
46
- },
47
- "devDependencies": {
48
- "@types/js-yaml": "^4.0.9",
49
- "@types/lodash": "^4.17.7",
50
- "@types/luxon": "^3.4.2",
51
- "typescript": "^5.5.4"
52
- }
53
- }
1
+ {
2
+ "name": "appwrite-utils-cli",
3
+ "description": "Appwrite Utility Functions to help with database management, data conversion, data import, migrations, and much more. Meant to be used as a CLI tool, I do not recommend installing this in frontend environments.",
4
+ "version": "0.9.51",
5
+ "main": "src/main.ts",
6
+ "type": "module",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "https://github.com/zachhandley/AppwriteUtils"
10
+ },
11
+ "author": "Zach Handley <zach@blackleafdigital.com> (https://zachhandley.com)",
12
+ "keywords": [
13
+ "appwrite",
14
+ "cli",
15
+ "utils",
16
+ "migrations",
17
+ "data",
18
+ "database",
19
+ "import",
20
+ "migration",
21
+ "utility"
22
+ ],
23
+ "bin": {
24
+ "appwrite-migrate": "./dist/main.js"
25
+ },
26
+ "scripts": {
27
+ "build": "bun run tsc",
28
+ "start": "tsx --no-cache src/main.ts",
29
+ "deploy": "bun run build && npm publish --access public",
30
+ "postinstall": "echo 'This package is intended for CLI use only and should not be added as a dependency in other projects.'"
31
+ },
32
+ "dependencies": {
33
+ "@types/inquirer": "^9.0.7",
34
+ "appwrite-utils": "^0.3.8",
35
+ "commander": "^12.1.0",
36
+ "inquirer": "^9.3.6",
37
+ "js-yaml": "^4.1.0",
38
+ "lodash": "^4.17.21",
39
+ "luxon": "^3.5.0",
40
+ "nanostores": "^0.10.3",
41
+ "node-appwrite": "^13.0.0",
42
+ "tsx": "^4.17.0",
43
+ "ulidx": "^2.4.0",
44
+ "winston": "^3.14.2",
45
+ "zod": "^3.23.8"
46
+ },
47
+ "devDependencies": {
48
+ "@types/js-yaml": "^4.0.9",
49
+ "@types/lodash": "^4.17.7",
50
+ "@types/luxon": "^3.4.2",
51
+ "typescript": "^5.5.4"
52
+ }
53
+ }
@@ -558,14 +558,14 @@ export class InteractiveCLI {
558
558
  },
559
559
  ]);
560
560
 
561
- const { checkDuplicates } = await inquirer.prompt([
562
- {
563
- type: "confirm",
564
- name: "checkDuplicates",
565
- message: "Do you want to check for duplicates during import?",
566
- default: true,
567
- },
568
- ]);
561
+ // const { checkDuplicates } = await inquirer.prompt([
562
+ // {
563
+ // type: "confirm",
564
+ // name: "checkDuplicates",
565
+ // message: "Do you want to check for duplicates during import?",
566
+ // default: true,
567
+ // },
568
+ // ]);
569
569
 
570
570
  console.log("Importing data...");
571
571
  await this.controller!.importData({
@@ -575,7 +575,8 @@ export class InteractiveCLI {
575
575
  ? selectedCollections.map((c) => c.$id)
576
576
  : undefined,
577
577
  shouldWriteFile,
578
- checkDuplicates,
578
+ checkDuplicates: false,
579
+ // checkDuplicates,
579
580
  });
580
581
  }
581
582
 
@@ -637,19 +638,42 @@ export class InteractiveCLI {
637
638
  targetDatabases = await fetchAllDatabases(targetClient);
638
639
  } else {
639
640
  targetClient = sourceClient;
640
- sourceDatabases = targetDatabases = await fetchAllDatabases(sourceClient);
641
+ const allDatabases = await fetchAllDatabases(sourceClient);
642
+ sourceDatabases = targetDatabases = allDatabases;
641
643
  }
642
644
 
643
- const [fromDb] = await this.selectDatabases(
645
+ const fromDbs = await this.selectDatabases(
644
646
  sourceDatabases,
645
647
  "Select the source database:",
646
648
  false
647
649
  );
648
- const [targetDb] = await this.selectDatabases(
649
- targetDatabases.filter((db) => db.$id !== fromDb.$id),
650
+ console.log(fromDbs);
651
+ const fromDb = fromDbs as unknown as {
652
+ $id: string;
653
+ name: string;
654
+ $createdAt: string;
655
+ $updatedAt: string;
656
+ enabled: boolean;
657
+ };
658
+ if (!fromDb) {
659
+ throw new Error("No source database selected");
660
+ }
661
+ const availableDbs = targetDatabases.filter((db) => db.$id !== fromDb.$id);
662
+ const targetDbs = await this.selectDatabases(
663
+ availableDbs,
650
664
  "Select the target database:",
651
665
  false
652
666
  );
667
+ const targetDb = targetDbs as unknown as {
668
+ $id: string;
669
+ name: string;
670
+ $createdAt: string;
671
+ $updatedAt: string;
672
+ enabled: boolean;
673
+ };
674
+ if (!targetDb) {
675
+ throw new Error("No target database selected");
676
+ }
653
677
 
654
678
  const selectedCollections = await this.selectCollections(
655
679
  fromDb,
@@ -685,16 +709,18 @@ export class InteractiveCLI {
685
709
  ? await listBuckets(targetStorage)
686
710
  : sourceBuckets;
687
711
 
688
- [sourceBucket] = await this.selectBuckets(
712
+ const sourceBucketPicked = await this.selectBuckets(
689
713
  sourceBuckets.buckets,
690
714
  "Select the source bucket:",
691
715
  false
692
716
  );
693
- [targetBucket] = await this.selectBuckets(
717
+ const targetBucketPicked = await this.selectBuckets(
694
718
  targetBuckets.buckets,
695
719
  "Select the target bucket:",
696
720
  false
697
721
  );
722
+ sourceBucket = sourceBucketPicked as unknown as Models.Bucket;
723
+ targetBucket = targetBucketPicked as unknown as Models.Bucket;
698
724
  }
699
725
 
700
726
  let transferOptions: TransferOptions = {