appwrite-utils-cli 0.9.996 → 0.9.998

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
@@ -147,6 +147,7 @@ This updated CLI ensures that developers have robust tools at their fingertips t
147
147
 
148
148
  ## Changelog
149
149
 
150
+ - 0.9.998: Fixed transfer finally, added `--targetDbId` and `--sourceDbId` as aliases
150
151
  - 0.9.994: Added function deployment management, in BETA, and fixed document transfer between databases
151
152
  - 0.9.993: Fixed `updateFunctionSpecifications` resetting functions to default with undefined values (oops)
152
153
  - 0.9.992: Added `updateFunctionSpecifications` which lists functions and specifications to allow you to update your functions max CPU and RAM usage per-function
package/dist/main.js CHANGED
@@ -79,12 +79,12 @@ const argv = yargs(hideBin(process.argv))
79
79
  description: "Transfer data between databases or collections",
80
80
  })
81
81
  .option("fromDbId", {
82
- alias: ["fromDb"],
82
+ alias: ["fromDb", "sourceDbId", "sourceDb"],
83
83
  type: "string",
84
84
  description: "Set the source database ID for transfer",
85
85
  })
86
86
  .option("toDbId", {
87
- alias: ["toDb"],
87
+ alias: ["toDb", "targetDbId", "targetDb"],
88
88
  type: "string",
89
89
  description: "Set the destination database ID for transfer",
90
90
  })
@@ -141,7 +141,7 @@ const argv = yargs(hideBin(process.argv))
141
141
  "s-4vcpu-4gb",
142
142
  "s-4vcpu-8gb",
143
143
  "s-8vcpu-4gb",
144
- "s-8vcpu-8gb"
144
+ "s-8vcpu-8gb",
145
145
  ],
146
146
  })
147
147
  .parse();
@@ -264,66 +264,65 @@ async function main() {
264
264
  await controller.importData(options);
265
265
  }
266
266
  if (parsedArgv.transfer) {
267
- if (parsedArgv.transfer) {
268
- const isRemote = !!parsedArgv.remoteEndpoint;
269
- let fromDb, toDb;
270
- let targetDatabases;
271
- let targetStorage;
272
- // Only fetch databases if database IDs are provided
273
- if (parsedArgv.fromDbId && parsedArgv.toDbId) {
274
- fromDb = (await controller.getDatabasesByIds([parsedArgv.fromDbId]))[0];
275
- if (isRemote) {
276
- if (!parsedArgv.remoteEndpoint ||
277
- !parsedArgv.remoteProjectId ||
278
- !parsedArgv.remoteApiKey) {
279
- throw new Error("Remote transfer details are missing");
280
- }
281
- const remoteClient = getClient(parsedArgv.remoteEndpoint, parsedArgv.remoteProjectId, parsedArgv.remoteApiKey);
282
- targetDatabases = new Databases(remoteClient);
283
- targetStorage = new Storage(remoteClient);
284
- const remoteDbs = await fetchAllDatabases(targetDatabases);
285
- toDb = remoteDbs.find((db) => db.$id === parsedArgv.toDbId);
286
- }
287
- else {
288
- toDb = (await controller.getDatabasesByIds([parsedArgv.toDbId]))[0];
289
- }
290
- if (!fromDb || !toDb) {
291
- throw new Error("Source or target database not found");
267
+ const isRemote = !!parsedArgv.remoteEndpoint;
268
+ let fromDb, toDb;
269
+ let targetDatabases;
270
+ let targetStorage;
271
+ // Only fetch databases if database IDs are provided
272
+ if (parsedArgv.fromDbId && parsedArgv.toDbId) {
273
+ console.log(chalk.blue(`Starting database transfer from ${parsedArgv.fromDbId} to ${parsedArgv.toDbId}`));
274
+ fromDb = (await controller.getDatabasesByIds([parsedArgv.fromDbId]))[0];
275
+ if (isRemote) {
276
+ if (!parsedArgv.remoteEndpoint ||
277
+ !parsedArgv.remoteProjectId ||
278
+ !parsedArgv.remoteApiKey) {
279
+ throw new Error("Remote transfer details are missing");
292
280
  }
281
+ const remoteClient = getClient(parsedArgv.remoteEndpoint, parsedArgv.remoteProjectId, parsedArgv.remoteApiKey);
282
+ targetDatabases = new Databases(remoteClient);
283
+ targetStorage = new Storage(remoteClient);
284
+ const remoteDbs = await fetchAllDatabases(targetDatabases);
285
+ toDb = remoteDbs.find((db) => db.$id === parsedArgv.toDbId);
293
286
  }
294
- // Handle storage setup
295
- let sourceBucket, targetBucket;
296
- if (parsedArgv.fromBucketId) {
297
- sourceBucket = await controller.storage?.getBucket(parsedArgv.fromBucketId);
287
+ else {
288
+ toDb = (await controller.getDatabasesByIds([parsedArgv.toDbId]))[0];
298
289
  }
299
- if (parsedArgv.toBucketId) {
300
- if (isRemote) {
301
- if (!targetStorage) {
302
- const remoteClient = getClient(parsedArgv.remoteEndpoint, parsedArgv.remoteProjectId, parsedArgv.remoteApiKey);
303
- targetStorage = new Storage(remoteClient);
304
- }
305
- targetBucket = await targetStorage?.getBucket(parsedArgv.toBucketId);
306
- }
307
- else {
308
- targetBucket = await controller.storage?.getBucket(parsedArgv.toBucketId);
290
+ if (!fromDb || !toDb) {
291
+ throw new Error("Source or target database not found");
292
+ }
293
+ }
294
+ // Handle storage setup
295
+ let sourceBucket, targetBucket;
296
+ if (parsedArgv.fromBucketId) {
297
+ sourceBucket = await controller.storage?.getBucket(parsedArgv.fromBucketId);
298
+ }
299
+ if (parsedArgv.toBucketId) {
300
+ if (isRemote) {
301
+ if (!targetStorage) {
302
+ const remoteClient = getClient(parsedArgv.remoteEndpoint, parsedArgv.remoteProjectId, parsedArgv.remoteApiKey);
303
+ targetStorage = new Storage(remoteClient);
309
304
  }
305
+ targetBucket = await targetStorage?.getBucket(parsedArgv.toBucketId);
310
306
  }
311
- // Validate that at least one transfer type is specified
312
- if (!fromDb && !sourceBucket) {
313
- throw new Error("No source database or bucket specified for transfer");
307
+ else {
308
+ targetBucket = await controller.storage?.getBucket(parsedArgv.toBucketId);
314
309
  }
315
- const transferOptions = {
316
- isRemote,
317
- fromDb,
318
- targetDb: toDb,
319
- transferEndpoint: parsedArgv.remoteEndpoint,
320
- transferProject: parsedArgv.remoteProjectId,
321
- transferKey: parsedArgv.remoteApiKey,
322
- sourceBucket: sourceBucket,
323
- targetBucket: targetBucket,
324
- };
325
- await controller.transferData(transferOptions);
326
310
  }
311
+ // Validate that at least one transfer type is specified
312
+ if (!fromDb && !sourceBucket) {
313
+ throw new Error("No source database or bucket specified for transfer");
314
+ }
315
+ const transferOptions = {
316
+ isRemote,
317
+ fromDb,
318
+ targetDb: toDb,
319
+ transferEndpoint: parsedArgv.remoteEndpoint,
320
+ transferProject: parsedArgv.remoteProjectId,
321
+ transferKey: parsedArgv.remoteApiKey,
322
+ sourceBucket: sourceBucket,
323
+ targetBucket: targetBucket,
324
+ };
325
+ await controller.transferData(transferOptions);
327
326
  }
328
327
  }
329
328
  }
@@ -249,6 +249,7 @@ export const transferDocumentsBetweenDbsLocalToRemote = async (localDb, endpoint
249
249
  * @return {Promise<void>} A promise that resolves when the transfer is complete.
250
250
  */
251
251
  export const transferDatabaseLocalToLocal = async (localDb, fromDbId, targetDbId) => {
252
+ console.log(chalk.blue(`Starting database transfer from ${fromDbId} to ${targetDbId}`));
252
253
  // Get all collections from source database
253
254
  const sourceCollections = await fetchAllCollections(fromDbId, localDb);
254
255
  console.log(chalk.blue(`Found ${sourceCollections.length} collections in source database`));
@@ -296,12 +297,12 @@ export const transferDatabaseLocalToLocal = async (localDb, fromDbId, targetDbId
296
297
  for (const index of collection.indexes) {
297
298
  const existingIndex = existingIndexes.indexes.find((idx) => idx.key === index.key);
298
299
  if (!existingIndex) {
299
- await createOrUpdateIndex(targetDbId, localDb, targetCollection.$id, index);
300
+ await tryAwaitWithRetry(async () => createOrUpdateIndex(targetDbId, localDb, targetCollection.$id, index));
300
301
  console.log(chalk.green(`Index ${index.key} created`));
301
302
  }
302
303
  else {
303
304
  console.log(chalk.blue(`Index ${index.key} exists, checking for updates...`));
304
- await createOrUpdateIndex(targetDbId, localDb, targetCollection.$id, index);
305
+ await tryAwaitWithRetry(async () => createOrUpdateIndex(targetDbId, localDb, targetCollection.$id, index));
305
306
  }
306
307
  }
307
308
  // Transfer documents
@@ -314,7 +314,6 @@ export class UtilsController {
314
314
  if (!fromDb || !targetDb) {
315
315
  throw new Error("Source or target database not found");
316
316
  }
317
- console.log(chalk.blue(`Starting database transfer from ${fromDb.$id} to ${targetDb.$id}`));
318
317
  if (options.isRemote && targetClient) {
319
318
  await transferDatabaseLocalToRemote(sourceClient, options.transferEndpoint, options.transferProject, options.transferKey, fromDb.$id, targetDb.$id);
320
319
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "appwrite-utils-cli",
3
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.996",
4
+ "version": "0.9.998",
5
5
  "main": "src/main.ts",
6
6
  "type": "module",
7
7
  "repository": {
package/src/main.ts CHANGED
@@ -120,12 +120,12 @@ const argv = yargs(hideBin(process.argv))
120
120
  description: "Transfer data between databases or collections",
121
121
  })
122
122
  .option("fromDbId", {
123
- alias: ["fromDb"],
123
+ alias: ["fromDb", "sourceDbId", "sourceDb"],
124
124
  type: "string",
125
125
  description: "Set the source database ID for transfer",
126
126
  })
127
127
  .option("toDbId", {
128
- alias: ["toDb"],
128
+ alias: ["toDb", "targetDbId", "targetDb"],
129
129
  type: "string",
130
130
  description: "Set the destination database ID for transfer",
131
131
  })
@@ -182,7 +182,7 @@ const argv = yargs(hideBin(process.argv))
182
182
  "s-4vcpu-4gb",
183
183
  "s-4vcpu-8gb",
184
184
  "s-8vcpu-4gb",
185
- "s-8vcpu-8gb"
185
+ "s-8vcpu-8gb",
186
186
  ],
187
187
  })
188
188
  .parse() as ParsedArgv;
@@ -220,15 +220,32 @@ async function main() {
220
220
 
221
221
  if (parsedArgv.updateFunctionSpec) {
222
222
  if (!parsedArgv.functionId || !parsedArgv.specification) {
223
- throw new Error("Function ID and specification are required for updating function specs");
223
+ throw new Error(
224
+ "Function ID and specification are required for updating function specs"
225
+ );
224
226
  }
225
- console.log(chalk.yellow(`Updating function specification for ${parsedArgv.functionId} to ${parsedArgv.specification}, checking if specification exists...`));
226
- const specifications = await listSpecifications(controller.appwriteServer!);
227
- if (!specifications.specifications.some((s: { slug: string }) => s.slug === parsedArgv.specification)) {
228
- console.log(chalk.red(`Specification ${parsedArgv.specification} not found`));
227
+ console.log(
228
+ chalk.yellow(
229
+ `Updating function specification for ${parsedArgv.functionId} to ${parsedArgv.specification}, checking if specification exists...`
230
+ )
231
+ );
232
+ const specifications = await listSpecifications(
233
+ controller.appwriteServer!
234
+ );
235
+ if (
236
+ !specifications.specifications.some(
237
+ (s: { slug: string }) => s.slug === parsedArgv.specification
238
+ )
239
+ ) {
240
+ console.log(
241
+ chalk.red(`Specification ${parsedArgv.specification} not found`)
242
+ );
229
243
  return;
230
244
  }
231
- await controller.updateFunctionSpecifications(parsedArgv.functionId, parsedArgv.specification as Specification);
245
+ await controller.updateFunctionSpecifications(
246
+ parsedArgv.functionId,
247
+ parsedArgv.specification as Specification
248
+ );
232
249
  }
233
250
 
234
251
  // Add default databases if not specified
@@ -332,91 +349,88 @@ async function main() {
332
349
  }
333
350
 
334
351
  if (parsedArgv.transfer) {
335
- if (parsedArgv.transfer) {
336
- const isRemote = !!parsedArgv.remoteEndpoint;
337
- let fromDb, toDb: Models.Database | undefined;
338
- let targetDatabases: Databases | undefined;
339
- let targetStorage: Storage | undefined;
352
+ const isRemote = !!parsedArgv.remoteEndpoint;
353
+ let fromDb, toDb: Models.Database | undefined;
354
+ let targetDatabases: Databases | undefined;
355
+ let targetStorage: Storage | undefined;
340
356
 
341
- // Only fetch databases if database IDs are provided
342
- if (parsedArgv.fromDbId && parsedArgv.toDbId) {
343
- fromDb = (
344
- await controller.getDatabasesByIds([parsedArgv.fromDbId])
345
- )[0];
357
+ // Only fetch databases if database IDs are provided
358
+ if (parsedArgv.fromDbId && parsedArgv.toDbId) {
359
+ console.log(
360
+ chalk.blue(
361
+ `Starting database transfer from ${parsedArgv.fromDbId} to ${parsedArgv.toDbId}`
362
+ )
363
+ );
364
+ fromDb = (await controller.getDatabasesByIds([parsedArgv.fromDbId]))[0];
346
365
 
347
- if (isRemote) {
348
- if (
349
- !parsedArgv.remoteEndpoint ||
350
- !parsedArgv.remoteProjectId ||
351
- !parsedArgv.remoteApiKey
352
- ) {
353
- throw new Error("Remote transfer details are missing");
354
- }
355
- const remoteClient = getClient(
356
- parsedArgv.remoteEndpoint,
357
- parsedArgv.remoteProjectId,
358
- parsedArgv.remoteApiKey
359
- );
360
- targetDatabases = new Databases(remoteClient);
361
- targetStorage = new Storage(remoteClient);
362
- const remoteDbs = await fetchAllDatabases(targetDatabases);
363
- toDb = remoteDbs.find((db) => db.$id === parsedArgv.toDbId);
364
- } else {
365
- toDb = (await controller.getDatabasesByIds([parsedArgv.toDbId]))[0];
366
- }
367
-
368
- if (!fromDb || !toDb) {
369
- throw new Error("Source or target database not found");
366
+ if (isRemote) {
367
+ if (
368
+ !parsedArgv.remoteEndpoint ||
369
+ !parsedArgv.remoteProjectId ||
370
+ !parsedArgv.remoteApiKey
371
+ ) {
372
+ throw new Error("Remote transfer details are missing");
370
373
  }
374
+ const remoteClient = getClient(
375
+ parsedArgv.remoteEndpoint,
376
+ parsedArgv.remoteProjectId,
377
+ parsedArgv.remoteApiKey
378
+ );
379
+ targetDatabases = new Databases(remoteClient);
380
+ targetStorage = new Storage(remoteClient);
381
+ const remoteDbs = await fetchAllDatabases(targetDatabases);
382
+ toDb = remoteDbs.find((db) => db.$id === parsedArgv.toDbId);
383
+ } else {
384
+ toDb = (await controller.getDatabasesByIds([parsedArgv.toDbId]))[0];
371
385
  }
372
386
 
373
- // Handle storage setup
374
- let sourceBucket, targetBucket;
375
- if (parsedArgv.fromBucketId) {
376
- sourceBucket = await controller.storage?.getBucket(
377
- parsedArgv.fromBucketId
378
- );
387
+ if (!fromDb || !toDb) {
388
+ throw new Error("Source or target database not found");
379
389
  }
380
- if (parsedArgv.toBucketId) {
381
- if (isRemote) {
382
- if (!targetStorage) {
383
- const remoteClient = getClient(
384
- parsedArgv.remoteEndpoint!,
385
- parsedArgv.remoteProjectId!,
386
- parsedArgv.remoteApiKey!
387
- );
388
- targetStorage = new Storage(remoteClient);
389
- }
390
- targetBucket = await targetStorage?.getBucket(
391
- parsedArgv.toBucketId
392
- );
393
- } else {
394
- targetBucket = await controller.storage?.getBucket(
395
- parsedArgv.toBucketId
390
+ }
391
+
392
+ // Handle storage setup
393
+ let sourceBucket, targetBucket;
394
+ if (parsedArgv.fromBucketId) {
395
+ sourceBucket = await controller.storage?.getBucket(
396
+ parsedArgv.fromBucketId
397
+ );
398
+ }
399
+ if (parsedArgv.toBucketId) {
400
+ if (isRemote) {
401
+ if (!targetStorage) {
402
+ const remoteClient = getClient(
403
+ parsedArgv.remoteEndpoint!,
404
+ parsedArgv.remoteProjectId!,
405
+ parsedArgv.remoteApiKey!
396
406
  );
407
+ targetStorage = new Storage(remoteClient);
397
408
  }
398
- }
399
-
400
- // Validate that at least one transfer type is specified
401
- if (!fromDb && !sourceBucket) {
402
- throw new Error(
403
- "No source database or bucket specified for transfer"
409
+ targetBucket = await targetStorage?.getBucket(parsedArgv.toBucketId);
410
+ } else {
411
+ targetBucket = await controller.storage?.getBucket(
412
+ parsedArgv.toBucketId
404
413
  );
405
414
  }
415
+ }
406
416
 
407
- const transferOptions: TransferOptions = {
408
- isRemote,
409
- fromDb,
410
- targetDb: toDb,
411
- transferEndpoint: parsedArgv.remoteEndpoint,
412
- transferProject: parsedArgv.remoteProjectId,
413
- transferKey: parsedArgv.remoteApiKey,
414
- sourceBucket: sourceBucket,
415
- targetBucket: targetBucket,
416
- };
417
-
418
- await controller.transferData(transferOptions);
417
+ // Validate that at least one transfer type is specified
418
+ if (!fromDb && !sourceBucket) {
419
+ throw new Error("No source database or bucket specified for transfer");
419
420
  }
421
+
422
+ const transferOptions: TransferOptions = {
423
+ isRemote,
424
+ fromDb,
425
+ targetDb: toDb,
426
+ transferEndpoint: parsedArgv.remoteEndpoint,
427
+ transferProject: parsedArgv.remoteProjectId,
428
+ transferKey: parsedArgv.remoteApiKey,
429
+ sourceBucket: sourceBucket,
430
+ targetBucket: targetBucket,
431
+ };
432
+
433
+ await controller.transferData(transferOptions);
420
434
  }
421
435
  }
422
436
  }
@@ -439,6 +439,9 @@ export const transferDatabaseLocalToLocal = async (
439
439
  fromDbId: string,
440
440
  targetDbId: string
441
441
  ) => {
442
+ console.log(
443
+ chalk.blue(`Starting database transfer from ${fromDbId} to ${targetDbId}`)
444
+ );
442
445
  // Get all collections from source database
443
446
  const sourceCollections = await fetchAllCollections(fromDbId, localDb);
444
447
  console.log(
@@ -557,22 +560,26 @@ export const transferDatabaseLocalToLocal = async (
557
560
  );
558
561
 
559
562
  if (!existingIndex) {
560
- await createOrUpdateIndex(
561
- targetDbId,
562
- localDb,
563
- targetCollection.$id,
564
- index as any
563
+ await tryAwaitWithRetry(async () =>
564
+ createOrUpdateIndex(
565
+ targetDbId,
566
+ localDb,
567
+ targetCollection.$id,
568
+ index as any
569
+ )
565
570
  );
566
571
  console.log(chalk.green(`Index ${index.key} created`));
567
572
  } else {
568
573
  console.log(
569
574
  chalk.blue(`Index ${index.key} exists, checking for updates...`)
570
575
  );
571
- await createOrUpdateIndex(
572
- targetDbId,
573
- localDb,
574
- targetCollection.$id,
575
- index as any
576
+ await tryAwaitWithRetry(async () =>
577
+ createOrUpdateIndex(
578
+ targetDbId,
579
+ localDb,
580
+ targetCollection.$id,
581
+ index as any
582
+ )
576
583
  );
577
584
  }
578
585
  }
@@ -468,12 +468,6 @@ export class UtilsController {
468
468
  throw new Error("Source or target database not found");
469
469
  }
470
470
 
471
- console.log(
472
- chalk.blue(
473
- `Starting database transfer from ${fromDb.$id} to ${targetDb.$id}`
474
- )
475
- );
476
-
477
471
  if (options.isRemote && targetClient) {
478
472
  await transferDatabaseLocalToRemote(
479
473
  sourceClient,