appwrite-utils-cli 0.0.37 → 0.0.39
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 +1 -0
- package/dist/migrations/attributes.js +21 -20
- package/dist/migrations/collections.js +10 -13
- package/dist/migrations/converters.js +15 -1
- package/dist/migrations/dataLoader.d.ts +12 -21
- package/dist/migrations/dataLoader.js +168 -58
- package/dist/migrations/databases.js +2 -1
- package/dist/migrations/importController.js +6 -24
- package/dist/migrations/importDataActions.d.ts +9 -1
- package/dist/migrations/importDataActions.js +14 -2
- package/dist/migrations/indexes.js +2 -1
- package/dist/migrations/migrationHelper.js +2 -1
- package/dist/migrations/queue.js +3 -2
- package/dist/migrations/setupDatabase.js +10 -12
- package/dist/migrations/storage.js +14 -13
- package/dist/migrations/users.js +14 -36
- package/dist/utils/helperFunctions.d.ts +10 -1
- package/dist/utils/helperFunctions.js +27 -0
- package/dist/utilsController.js +2 -1
- package/package.json +2 -2
- package/src/migrations/attributes.ts +204 -143
- package/src/migrations/collections.ts +49 -33
- package/src/migrations/converters.ts +17 -1
- package/src/migrations/dataLoader.ts +232 -63
- package/src/migrations/databases.ts +4 -1
- package/src/migrations/importController.ts +13 -27
- package/src/migrations/importDataActions.ts +17 -3
- package/src/migrations/indexes.ts +4 -1
- package/src/migrations/migrationHelper.ts +9 -5
- package/src/migrations/queue.ts +5 -6
- package/src/migrations/setupDatabase.ts +35 -18
- package/src/migrations/storage.ts +50 -36
- package/src/migrations/users.ts +28 -38
- package/src/utils/helperFunctions.ts +33 -1
- package/src/utilsController.ts +3 -1
|
@@ -2,7 +2,7 @@ import { Databases, ID, Query, Storage } from "node-appwrite";
|
|
|
2
2
|
import { createOrUpdateAttribute } from "./attributes.js";
|
|
3
3
|
import { createOrUpdateCollections, generateSchemas, wipeDatabase, } from "./collections.js";
|
|
4
4
|
import { getMigrationCollectionSchemas } from "./backup.js";
|
|
5
|
-
import { areCollectionNamesSame, toCamelCase } from "../utils/index.js";
|
|
5
|
+
import { areCollectionNamesSame, toCamelCase, tryAwaitWithRetry, } from "../utils/index.js";
|
|
6
6
|
import { backupDatabase, initOrGetBackupStorage, initOrGetDocumentStorage, wipeDocumentStorage, } from "./storage.js";
|
|
7
7
|
import {} from "appwrite-utils";
|
|
8
8
|
import { nameToIdMapping } from "./queue.js";
|
|
@@ -17,17 +17,15 @@ export const setupMigrationDatabase = async (config) => {
|
|
|
17
17
|
const dbCollections = [];
|
|
18
18
|
const migrationCollectionsSetup = getMigrationCollectionSchemas();
|
|
19
19
|
try {
|
|
20
|
-
db = await database.get("migrations");
|
|
20
|
+
db = await tryAwaitWithRetry(async () => await database.get("migrations"));
|
|
21
21
|
console.log("Migrations database found");
|
|
22
22
|
}
|
|
23
23
|
catch (e) {
|
|
24
|
-
db = await database.create("migrations", "Migrations", true);
|
|
24
|
+
db = await tryAwaitWithRetry(async () => await database.create("migrations", "Migrations", true));
|
|
25
25
|
console.log("Migrations database created");
|
|
26
26
|
}
|
|
27
27
|
if (db) {
|
|
28
|
-
const collectionsPulled = await database.listCollections(db.$id, [
|
|
29
|
-
Query.limit(25),
|
|
30
|
-
]);
|
|
28
|
+
const collectionsPulled = await tryAwaitWithRetry(async () => await database.listCollections(db.$id, [Query.limit(25)]));
|
|
31
29
|
dbCollections.push(...collectionsPulled.collections);
|
|
32
30
|
}
|
|
33
31
|
console.log(`Collections in migrations database: ${dbCollections.length}`);
|
|
@@ -36,14 +34,14 @@ export const setupMigrationDatabase = async (config) => {
|
|
|
36
34
|
const collectionId = toCamelCase(collectionName); // Convert name to toCamelCase for the ID
|
|
37
35
|
let collectionFound = null;
|
|
38
36
|
try {
|
|
39
|
-
collectionFound = await database.getCollection(db.$id, collectionId);
|
|
37
|
+
collectionFound = await tryAwaitWithRetry(async () => await database.getCollection(db.$id, collectionId));
|
|
40
38
|
}
|
|
41
39
|
catch (e) {
|
|
42
40
|
console.log(`Collection not found: ${collectionId}`);
|
|
43
41
|
}
|
|
44
42
|
if (!collectionFound) {
|
|
45
43
|
// Create the collection with the provided configuration
|
|
46
|
-
collectionFound = await database.createCollection(db.$id, collectionId, collectionName, undefined, collection.documentSecurity, collection.enabled);
|
|
44
|
+
collectionFound = await tryAwaitWithRetry(async () => await database.createCollection(db.$id, collectionId, collectionName, undefined, collection.documentSecurity, collection.enabled));
|
|
47
45
|
}
|
|
48
46
|
for (const attribute of attributes) {
|
|
49
47
|
await createOrUpdateAttribute(database, db.$id, collectionFound, attribute);
|
|
@@ -61,10 +59,10 @@ export const ensureDatabasesExist = async (config) => {
|
|
|
61
59
|
name: "Migrations",
|
|
62
60
|
});
|
|
63
61
|
const dbNames = databasesToEnsure.map((db) => db.name);
|
|
64
|
-
const existingDatabases = await database.list([Query.equal("name", dbNames)]);
|
|
62
|
+
const existingDatabases = await tryAwaitWithRetry(async () => await database.list([Query.equal("name", dbNames)]));
|
|
65
63
|
for (const db of databasesToEnsure) {
|
|
66
64
|
if (!existingDatabases.databases.some((d) => d.name === db.name)) {
|
|
67
|
-
await database.create(db.$id || ID.unique(), db.name, true);
|
|
65
|
+
await tryAwaitWithRetry(async () => await database.create(db.$id || ID.unique(), db.name, true));
|
|
68
66
|
console.log(`${db.name} database created`);
|
|
69
67
|
}
|
|
70
68
|
}
|
|
@@ -73,10 +71,10 @@ export const wipeOtherDatabases = async (database, config) => {
|
|
|
73
71
|
const databasesToKeep = config.databases.map((db) => db.name.toLowerCase().trim().replace(" ", ""));
|
|
74
72
|
databasesToKeep.push("migrations");
|
|
75
73
|
console.log(`Databases to keep: ${databasesToKeep.join(", ")}`);
|
|
76
|
-
const allDatabases = await database.list([Query.limit(500)]);
|
|
74
|
+
const allDatabases = await tryAwaitWithRetry(async () => await database.list([Query.limit(500)]));
|
|
77
75
|
for (const db of allDatabases.databases) {
|
|
78
76
|
if (!databasesToKeep.includes(db.name.toLowerCase().trim().replace(" ", ""))) {
|
|
79
|
-
await database.delete(db.$id);
|
|
77
|
+
await tryAwaitWithRetry(async () => await database.delete(db.$id));
|
|
80
78
|
console.log(`Deleted database: ${db.name}`);
|
|
81
79
|
}
|
|
82
80
|
}
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { Storage, Databases, Query, InputFile, ID, Permission, } from "node-appwrite";
|
|
2
2
|
import {} from "./backup.js";
|
|
3
3
|
import { splitIntoBatches } from "./migrationHelper.js";
|
|
4
|
+
import { tryAwaitWithRetry } from "../utils/helperFunctions.js";
|
|
4
5
|
export const logOperation = async (db, dbId, operationDetails, operationId) => {
|
|
5
6
|
try {
|
|
6
7
|
let operation;
|
|
7
8
|
if (operationId) {
|
|
8
9
|
// Update existing operation log
|
|
9
|
-
operation = await db.updateDocument("migrations", "currentOperations", operationId, operationDetails);
|
|
10
|
+
operation = await tryAwaitWithRetry(async () => await db.updateDocument("migrations", "currentOperations", operationId, operationDetails));
|
|
10
11
|
}
|
|
11
12
|
else {
|
|
12
13
|
// Create new operation log
|
|
@@ -22,29 +23,29 @@ export const logOperation = async (db, dbId, operationDetails, operationId) => {
|
|
|
22
23
|
};
|
|
23
24
|
export const initOrGetBackupStorage = async (storage) => {
|
|
24
25
|
try {
|
|
25
|
-
const backupStorage = await storage.getBucket("backupStorage");
|
|
26
|
+
const backupStorage = await tryAwaitWithRetry(async () => await storage.getBucket("backupStorage"));
|
|
26
27
|
return backupStorage;
|
|
27
28
|
}
|
|
28
29
|
catch (e) {
|
|
29
30
|
// ID backupStorage
|
|
30
31
|
// Name Backups Storage
|
|
31
|
-
const backupStorage = await storage.createBucket("backupStorage", "Backups Storage");
|
|
32
|
+
const backupStorage = await tryAwaitWithRetry(async () => await storage.createBucket("backupStorage", "Backups Storage"));
|
|
32
33
|
return backupStorage;
|
|
33
34
|
}
|
|
34
35
|
};
|
|
35
36
|
export const initOrGetDocumentStorage = async (storage, config, dbName) => {
|
|
36
37
|
try {
|
|
37
|
-
await storage.getBucket(`${config.documentBucketId}_${dbName.toLowerCase().replace(" ", "")}`);
|
|
38
|
+
await tryAwaitWithRetry(async () => await storage.getBucket(`${config.documentBucketId}_${dbName.toLowerCase().replace(" ", "")}`));
|
|
38
39
|
}
|
|
39
40
|
catch (e) {
|
|
40
41
|
// ID documentStorage
|
|
41
42
|
// Name Document Storage
|
|
42
|
-
const documentStorage = await storage.createBucket(`${config.documentBucketId}_${dbName.toLowerCase().replace(" ", "")}`, `Document Storage ${dbName}`, [
|
|
43
|
+
const documentStorage = await tryAwaitWithRetry(async () => await storage.createBucket(`${config.documentBucketId}_${dbName.toLowerCase().replace(" ", "")}`, `Document Storage ${dbName}`, [
|
|
43
44
|
Permission.read("any"),
|
|
44
45
|
Permission.create("users"),
|
|
45
46
|
Permission.update("users"),
|
|
46
47
|
Permission.delete("users"),
|
|
47
|
-
]);
|
|
48
|
+
]));
|
|
48
49
|
return documentStorage;
|
|
49
50
|
}
|
|
50
51
|
};
|
|
@@ -61,7 +62,7 @@ export const wipeDocumentStorage = async (storage, config, dbName) => {
|
|
|
61
62
|
if (lastFileId) {
|
|
62
63
|
queries.push(Query.cursorAfter(lastFileId));
|
|
63
64
|
}
|
|
64
|
-
const filesPulled = await storage.listFiles(bucketId, queries);
|
|
65
|
+
const filesPulled = await tryAwaitWithRetry(async () => await storage.listFiles(bucketId, queries));
|
|
65
66
|
if (filesPulled.files.length === 0) {
|
|
66
67
|
console.log("No files found, done!");
|
|
67
68
|
moreFiles = false;
|
|
@@ -124,7 +125,7 @@ export const backupDatabase = async (database, databaseId, storage) => {
|
|
|
124
125
|
// Fetch and backup the database details
|
|
125
126
|
let db;
|
|
126
127
|
try {
|
|
127
|
-
db = await database.get(databaseId);
|
|
128
|
+
db = await tryAwaitWithRetry(async () => await database.get(databaseId));
|
|
128
129
|
}
|
|
129
130
|
catch (e) {
|
|
130
131
|
console.error(`Error fetching database: ${e}`);
|
|
@@ -146,25 +147,25 @@ export const backupDatabase = async (database, databaseId, storage) => {
|
|
|
146
147
|
let progress = 0;
|
|
147
148
|
let total = 0; // Initialize total to 0, will be updated dynamically
|
|
148
149
|
while (moreCollections) {
|
|
149
|
-
const collectionResponse = await database.listCollections(databaseId, [
|
|
150
|
+
const collectionResponse = await tryAwaitWithRetry(async () => await database.listCollections(databaseId, [
|
|
150
151
|
Query.limit(500), // Adjust the limit as needed
|
|
151
152
|
...(lastCollectionId ? [Query.cursorAfter(lastCollectionId)] : []),
|
|
152
|
-
]);
|
|
153
|
+
]));
|
|
153
154
|
total += collectionResponse.collections.length; // Update total with number of collections
|
|
154
155
|
for (const { $id: collectionId, name: collectionName, } of collectionResponse.collections) {
|
|
155
156
|
let collectionDocumentCount = 0; // Initialize document count for the current collection
|
|
156
157
|
try {
|
|
157
|
-
const collection = await database.getCollection(databaseId, collectionId);
|
|
158
|
+
const collection = await tryAwaitWithRetry(async () => await database.getCollection(databaseId, collectionId));
|
|
158
159
|
progress++;
|
|
159
160
|
data.collections.push(JSON.stringify(collection));
|
|
160
161
|
// Initialize pagination for documents within the current collection
|
|
161
162
|
let lastDocumentId = "";
|
|
162
163
|
let moreDocuments = true;
|
|
163
164
|
while (moreDocuments) {
|
|
164
|
-
const documentResponse = await database.listDocuments(databaseId, collectionId, [
|
|
165
|
+
const documentResponse = await tryAwaitWithRetry(async () => await database.listDocuments(databaseId, collectionId, [
|
|
165
166
|
Query.limit(500), // Adjust the limit as needed
|
|
166
167
|
...(lastDocumentId ? [Query.cursorAfter(lastDocumentId)] : []),
|
|
167
|
-
]);
|
|
168
|
+
]));
|
|
168
169
|
total += documentResponse.documents.length; // Update total with number of documents
|
|
169
170
|
collectionDocumentCount += documentResponse.documents.length; // Update document count for the current collection
|
|
170
171
|
let documentPromises = [];
|
package/dist/migrations/users.js
CHANGED
|
@@ -3,6 +3,7 @@ import { AuthUserSchema, } from "../schemas/authUser.js";
|
|
|
3
3
|
import _ from "lodash";
|
|
4
4
|
import { logger } from "./logging.js";
|
|
5
5
|
import { splitIntoBatches } from "./migrationHelper.js";
|
|
6
|
+
import { tryAwaitWithRetry } from "../utils/helperFunctions.js";
|
|
6
7
|
export class UsersController {
|
|
7
8
|
config;
|
|
8
9
|
users;
|
|
@@ -22,49 +23,25 @@ export class UsersController {
|
|
|
22
23
|
this.users = new Users(this.config.appwriteClient);
|
|
23
24
|
}
|
|
24
25
|
async wipeUsers() {
|
|
25
|
-
const
|
|
26
|
-
const allUsers = users.users;
|
|
27
|
-
let lastDocumentId;
|
|
28
|
-
if (users.users.length >= 200) {
|
|
29
|
-
lastDocumentId = users.users[users.users.length - 1].$id;
|
|
30
|
-
}
|
|
31
|
-
while (lastDocumentId) {
|
|
32
|
-
const moreUsers = await this.users.list([
|
|
33
|
-
Query.limit(200),
|
|
34
|
-
Query.cursorAfter(lastDocumentId),
|
|
35
|
-
]);
|
|
36
|
-
allUsers.push(...moreUsers.users);
|
|
37
|
-
if (moreUsers.users.length < 200) {
|
|
38
|
-
break;
|
|
39
|
-
}
|
|
40
|
-
lastDocumentId = moreUsers.users[moreUsers.users.length - 1].$id;
|
|
41
|
-
}
|
|
26
|
+
const allUsers = await this.getAllUsers();
|
|
42
27
|
console.log("Deleting all users...");
|
|
43
|
-
const createBatches = (finalData) => {
|
|
44
|
-
let maxBatchLength = 5;
|
|
28
|
+
const createBatches = (finalData, batchSize) => {
|
|
45
29
|
const finalBatches = [];
|
|
46
|
-
for (let i = 0; i < finalData.length; i
|
|
47
|
-
|
|
48
|
-
finalBatches.push([]);
|
|
49
|
-
}
|
|
50
|
-
finalBatches[finalBatches.length - 1].push(finalData[i]);
|
|
30
|
+
for (let i = 0; i < finalData.length; i += batchSize) {
|
|
31
|
+
finalBatches.push(finalData.slice(i, i + batchSize));
|
|
51
32
|
}
|
|
52
33
|
return finalBatches;
|
|
53
34
|
};
|
|
54
|
-
// const userPromises: Promise<string>[] = [];
|
|
55
35
|
let usersDeleted = 0;
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
36
|
+
const batchedUserPromises = createBatches(allUsers, 50); // Batch size of 10
|
|
37
|
+
for (const batch of batchedUserPromises) {
|
|
38
|
+
console.log(`Deleting ${batch.length} users...`);
|
|
39
|
+
await Promise.all(batch.map((user) => tryAwaitWithRetry(async () => await this.users.delete(user.$id))));
|
|
40
|
+
usersDeleted += batch.length;
|
|
59
41
|
if (usersDeleted % 100 === 0) {
|
|
60
42
|
console.log(`Deleted ${usersDeleted} users...`);
|
|
61
43
|
}
|
|
62
44
|
}
|
|
63
|
-
// const batchedUserPromises = createBatches(userPromises);
|
|
64
|
-
// for (const batch of batchedUserPromises) {
|
|
65
|
-
// console.log(`Deleting ${batch.length} users...`);
|
|
66
|
-
// await Promise.all(batch);
|
|
67
|
-
// }
|
|
68
45
|
}
|
|
69
46
|
async getAllUsers() {
|
|
70
47
|
const allUsers = [];
|
|
@@ -76,10 +53,10 @@ export class UsersController {
|
|
|
76
53
|
let lastDocumentId = users.users[users.users.length - 1].$id;
|
|
77
54
|
allUsers.push(...users.users);
|
|
78
55
|
while (lastDocumentId) {
|
|
79
|
-
const moreUsers = await this.users.list([
|
|
56
|
+
const moreUsers = await tryAwaitWithRetry(async () => await this.users.list([
|
|
80
57
|
Query.limit(200),
|
|
81
58
|
Query.cursorAfter(lastDocumentId),
|
|
82
|
-
]);
|
|
59
|
+
]));
|
|
83
60
|
allUsers.push(...moreUsers.users);
|
|
84
61
|
lastDocumentId = moreUsers.users[moreUsers.users.length - 1].$id;
|
|
85
62
|
if (moreUsers.users.length < 200) {
|
|
@@ -113,7 +90,8 @@ export class UsersController {
|
|
|
113
90
|
}
|
|
114
91
|
catch (e) {
|
|
115
92
|
if (e instanceof AppwriteException) {
|
|
116
|
-
if (e.message.includes("fetch failed")
|
|
93
|
+
if (e.message.toLowerCase().includes("fetch failed") ||
|
|
94
|
+
e.message.toLowerCase().includes("server error")) {
|
|
117
95
|
const numberOfAttempts = numAttempts || 0;
|
|
118
96
|
if (numberOfAttempts > 5) {
|
|
119
97
|
throw e;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type Models } from "node-appwrite";
|
|
2
2
|
import type { CollectionImportData } from "../migrations/dataLoader.js";
|
|
3
3
|
import type { ConfigCollection } from "appwrite-utils";
|
|
4
4
|
export declare const toPascalCase: (str: string) => string;
|
|
@@ -35,3 +35,12 @@ export declare const getFileViewUrl: (endpoint: string, projectId: string, bucke
|
|
|
35
35
|
*/
|
|
36
36
|
export declare const getFileDownloadUrl: (endpoint: string, projectId: string, bucketId: string, fileId: string, jwt?: Models.Jwt) => string;
|
|
37
37
|
export declare const finalizeByAttributeMap: (appwriteFolderPath: string, collection: ConfigCollection, item: CollectionImportData["data"][number]) => Promise<any>;
|
|
38
|
+
export declare let numTimesFailedTotal: number;
|
|
39
|
+
/**
|
|
40
|
+
* Tries to execute the given createFunction and retries up to 5 times if it fails.
|
|
41
|
+
*
|
|
42
|
+
* @param {() => Promise<any>} createFunction - The function to be executed.
|
|
43
|
+
* @param {number} [attemptNum=0] - The number of attempts made so far (default: 0).
|
|
44
|
+
* @return {Promise<any>} - A promise that resolves to the result of the createFunction or rejects with an error if it fails after 5 attempts.
|
|
45
|
+
*/
|
|
46
|
+
export declare const tryAwaitWithRetry: <T>(createFunction: () => Promise<T>, attemptNum?: number) => Promise<T>;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { AppwriteException } from "node-appwrite";
|
|
1
2
|
import fs from "node:fs";
|
|
2
3
|
import path from "node:path";
|
|
3
4
|
export const toPascalCase = (str) => {
|
|
@@ -78,3 +79,29 @@ export const finalizeByAttributeMap = async (appwriteFolderPath, collection, ite
|
|
|
78
79
|
...item.finalData,
|
|
79
80
|
});
|
|
80
81
|
};
|
|
82
|
+
export let numTimesFailedTotal = 0;
|
|
83
|
+
/**
|
|
84
|
+
* Tries to execute the given createFunction and retries up to 5 times if it fails.
|
|
85
|
+
*
|
|
86
|
+
* @param {() => Promise<any>} createFunction - The function to be executed.
|
|
87
|
+
* @param {number} [attemptNum=0] - The number of attempts made so far (default: 0).
|
|
88
|
+
* @return {Promise<any>} - A promise that resolves to the result of the createFunction or rejects with an error if it fails after 5 attempts.
|
|
89
|
+
*/
|
|
90
|
+
export const tryAwaitWithRetry = async (createFunction, attemptNum = 0) => {
|
|
91
|
+
try {
|
|
92
|
+
return await createFunction();
|
|
93
|
+
}
|
|
94
|
+
catch (error) {
|
|
95
|
+
if (error instanceof AppwriteException &&
|
|
96
|
+
(error.message.toLowerCase().includes("fetch failed") ||
|
|
97
|
+
error.message.toLowerCase().includes("server error"))) {
|
|
98
|
+
numTimesFailedTotal++;
|
|
99
|
+
console.log(`Fetch failed on attempt ${attemptNum}. Retrying...`);
|
|
100
|
+
if (attemptNum > 5) {
|
|
101
|
+
throw error;
|
|
102
|
+
}
|
|
103
|
+
return tryAwaitWithRetry(createFunction, attemptNum + 1);
|
|
104
|
+
}
|
|
105
|
+
throw error;
|
|
106
|
+
}
|
|
107
|
+
};
|
package/dist/utilsController.js
CHANGED
|
@@ -4,7 +4,7 @@ import path from "path";
|
|
|
4
4
|
import fs from "fs";
|
|
5
5
|
import { load } from "js-yaml";
|
|
6
6
|
import { ImportDataActions } from "./migrations/importDataActions.js";
|
|
7
|
-
import {
|
|
7
|
+
import { numTimesFailedTotal } from "./utils/helperFunctions.js";
|
|
8
8
|
import { afterImportActions } from "./migrations/afterImportActions.js";
|
|
9
9
|
import { converterFunctions, validationRules, AppwriteConfigSchema, } from "appwrite-utils";
|
|
10
10
|
import { ImportController } from "./migrations/importController.js";
|
|
@@ -117,6 +117,7 @@ export class UtilsController {
|
|
|
117
117
|
await importController.run();
|
|
118
118
|
console.log("Import data complete.");
|
|
119
119
|
}
|
|
120
|
+
console.log("Total number of times Fetch failed: ", numTimesFailedTotal);
|
|
120
121
|
// if (options.checkDuplicates) {
|
|
121
122
|
// await this.checkDuplicates();
|
|
122
123
|
// }
|
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.0.
|
|
4
|
+
"version": "0.0.39",
|
|
5
5
|
"main": "src/main.ts",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"repository": {
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
},
|
|
34
34
|
"dependencies": {
|
|
35
35
|
"@types/inquirer": "^9.0.7",
|
|
36
|
-
"appwrite-utils": "^0.2.
|
|
36
|
+
"appwrite-utils": "^0.2.6",
|
|
37
37
|
"commander": "^12.0.0",
|
|
38
38
|
"inquirer": "^9.2.20",
|
|
39
39
|
"js-yaml": "^4.1.0",
|