appwrite-utils-cli 0.9.993 → 0.9.994

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.
Files changed (46) hide show
  1. package/README.md +1 -2
  2. package/dist/collections/methods.js +6 -4
  3. package/dist/functions/deployments.d.ts +4 -0
  4. package/dist/functions/deployments.js +114 -0
  5. package/dist/functions/methods.d.ts +13 -8
  6. package/dist/functions/methods.js +74 -20
  7. package/dist/functions/templates/count-docs-in-collection/src/main.d.ts +21 -0
  8. package/dist/functions/templates/count-docs-in-collection/src/main.js +114 -0
  9. package/dist/functions/templates/count-docs-in-collection/src/request.d.ts +15 -0
  10. package/dist/functions/templates/count-docs-in-collection/src/request.js +6 -0
  11. package/dist/functions/templates/typescript-node/src/index.d.ts +11 -0
  12. package/dist/functions/templates/typescript-node/src/index.js +11 -0
  13. package/dist/interactiveCLI.d.ts +6 -0
  14. package/dist/interactiveCLI.js +437 -32
  15. package/dist/main.js +0 -0
  16. package/dist/migrations/appwriteToX.js +32 -1
  17. package/dist/migrations/schemaStrings.d.ts +1 -0
  18. package/dist/migrations/schemaStrings.js +74 -2
  19. package/dist/migrations/transfer.js +112 -123
  20. package/dist/utils/loadConfigs.d.ts +1 -0
  21. package/dist/utils/loadConfigs.js +19 -0
  22. package/dist/utils/schemaStrings.js +27 -0
  23. package/dist/utilsController.d.ts +5 -1
  24. package/dist/utilsController.js +54 -2
  25. package/package.json +57 -55
  26. package/src/collections/methods.ts +29 -10
  27. package/src/functions/deployments.ts +190 -0
  28. package/src/functions/methods.ts +295 -235
  29. package/src/functions/templates/count-docs-in-collection/README.md +54 -0
  30. package/src/functions/templates/count-docs-in-collection/src/main.ts +159 -0
  31. package/src/functions/templates/count-docs-in-collection/src/request.ts +9 -0
  32. package/src/functions/templates/poetry/README.md +30 -0
  33. package/src/functions/templates/poetry/pyproject.toml +16 -0
  34. package/src/functions/templates/poetry/src/__init__.py +0 -0
  35. package/src/functions/templates/poetry/src/index.py +16 -0
  36. package/src/functions/templates/typescript-node/README.md +32 -0
  37. package/src/functions/templates/typescript-node/src/index.ts +23 -0
  38. package/src/interactiveCLI.ts +606 -47
  39. package/src/migrations/appwriteToX.ts +44 -1
  40. package/src/migrations/schemaStrings.ts +83 -2
  41. package/src/migrations/transfer.ts +280 -207
  42. package/src/setupController.ts +41 -41
  43. package/src/utils/loadConfigs.ts +24 -0
  44. package/src/utils/schemaStrings.ts +27 -0
  45. package/src/utilsController.ts +63 -3
  46. package/tsconfig.json +8 -1
package/package.json CHANGED
@@ -1,55 +1,57 @@
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.993",
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.96",
35
- "chalk": "^5.3.0",
36
- "commander": "^12.1.0",
37
- "inquirer": "^9.3.6",
38
- "js-yaml": "^4.1.0",
39
- "lodash": "^4.17.21",
40
- "luxon": "^3.5.0",
41
- "nanostores": "^0.10.3",
42
- "node-appwrite": "^14.1.0",
43
- "tar": "^7.4.3",
44
- "tsx": "^4.17.0",
45
- "ulidx": "^2.4.0",
46
- "winston": "^3.14.2",
47
- "zod": "^3.23.8"
48
- },
49
- "devDependencies": {
50
- "@types/js-yaml": "^4.0.9",
51
- "@types/lodash": "^4.17.7",
52
- "@types/luxon": "^3.4.2",
53
- "typescript": "^5.5.4"
54
- }
55
- }
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.994",
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.97",
35
+ "chalk": "^5.3.0",
36
+ "cli-progress": "^3.12.0",
37
+ "commander": "^12.1.0",
38
+ "inquirer": "^9.3.6",
39
+ "js-yaml": "^4.1.0",
40
+ "lodash": "^4.17.21",
41
+ "luxon": "^3.5.0",
42
+ "nanostores": "^0.10.3",
43
+ "node-appwrite": "^14.1.0",
44
+ "tar": "^7.4.3",
45
+ "tsx": "^4.17.0",
46
+ "ulidx": "^2.4.0",
47
+ "winston": "^3.14.2",
48
+ "zod": "^3.23.8"
49
+ },
50
+ "devDependencies": {
51
+ "@types/cli-progress": "^3.11.6",
52
+ "@types/js-yaml": "^4.0.9",
53
+ "@types/lodash": "^4.17.7",
54
+ "@types/luxon": "^3.4.2",
55
+ "typescript": "^5.5.4"
56
+ }
57
+ }
@@ -11,7 +11,7 @@ import { nameToIdMapping, processQueue } from "../migrations/queue.js";
11
11
  import { createUpdateCollectionAttributes } from "./attributes.js";
12
12
  import { createOrUpdateIndexes } from "./indexes.js";
13
13
  import _ from "lodash";
14
- import { SchemaGenerator } from "../utils/schemaStrings.js";
14
+ import { SchemaGenerator } from "../migrations/schemaStrings.js";
15
15
  import { delay, tryAwaitWithRetry } from "../utils/helperFunctions.js";
16
16
 
17
17
  export const documentExists = async (
@@ -124,20 +124,36 @@ export const fetchAndCacheCollectionByName = async (
124
124
  }
125
125
  };
126
126
 
127
- async function wipeDocumentsFromCollection(database: Databases, databaseId: string, collectionId: string) {
128
- const initialDocuments = await database.listDocuments(databaseId, collectionId, [Query.limit(1000)]);
127
+ async function wipeDocumentsFromCollection(
128
+ database: Databases,
129
+ databaseId: string,
130
+ collectionId: string
131
+ ) {
132
+ const initialDocuments = await database.listDocuments(
133
+ databaseId,
134
+ collectionId,
135
+ [Query.limit(1000)]
136
+ );
129
137
  let documents = initialDocuments.documents;
130
138
  while (documents.length === 1000) {
131
- const docsResponse = await database.listDocuments(databaseId, collectionId, [Query.limit(1000)]);
139
+ const docsResponse = await database.listDocuments(
140
+ databaseId,
141
+ collectionId,
142
+ [Query.limit(1000)]
143
+ );
132
144
  documents = documents.concat(docsResponse.documents);
133
145
  }
134
- const batchDeletePromises = documents.map(doc => database.deleteDocument(databaseId, collectionId, doc.$id));
146
+ const batchDeletePromises = documents.map((doc) =>
147
+ database.deleteDocument(databaseId, collectionId, doc.$id)
148
+ );
135
149
  const maxStackSize = 100;
136
150
  for (let i = 0; i < batchDeletePromises.length; i += maxStackSize) {
137
151
  await Promise.all(batchDeletePromises.slice(i, i + maxStackSize));
138
152
  await delay(100);
139
153
  }
140
- console.log(`Deleted ${documents.length} documents from collection ${collectionId}`);
154
+ console.log(
155
+ `Deleted ${documents.length} documents from collection ${collectionId}`
156
+ );
141
157
  }
142
158
 
143
159
  export const wipeDatabase = async (
@@ -167,7 +183,9 @@ export const wipeCollection = async (
167
183
  databaseId: string,
168
184
  collectionId: string
169
185
  ): Promise<void> => {
170
- const collections = await database.listCollections(databaseId, [Query.equal("$id", collectionId)]);
186
+ const collections = await database.listCollections(databaseId, [
187
+ Query.equal("$id", collectionId),
188
+ ]);
171
189
  if (collections.total === 0) {
172
190
  console.log(`Collection ${collectionId} not found`);
173
191
  return;
@@ -191,7 +209,8 @@ export const createOrUpdateCollections = async (
191
209
  deletedCollections?: { collectionId: string; collectionName: string }[],
192
210
  selectedCollections: Models.Collection[] = []
193
211
  ): Promise<void> => {
194
- const collectionsToProcess = selectedCollections.length > 0 ? selectedCollections : config.collections;
212
+ const collectionsToProcess =
213
+ selectedCollections.length > 0 ? selectedCollections : config.collections;
195
214
  if (!collectionsToProcess) {
196
215
  return;
197
216
  }
@@ -204,7 +223,7 @@ export const createOrUpdateCollections = async (
204
223
  const permissions: string[] = [];
205
224
  if (collection.$permissions && collection.$permissions.length > 0) {
206
225
  for (const permission of collection.$permissions) {
207
- if (typeof permission === 'string') {
226
+ if (typeof permission === "string") {
208
227
  permissions.push(permission);
209
228
  } else {
210
229
  switch (permission.permission) {
@@ -319,7 +338,7 @@ export const createOrUpdateCollections = async (
319
338
  databaseId,
320
339
  database,
321
340
  collectionToUse!.$id,
322
- (indexes ?? []) as Indexes,
341
+ (indexes ?? []) as Indexes
323
342
  );
324
343
 
325
344
  // Add delay after creating indexes
@@ -0,0 +1,190 @@
1
+ import { Client, Functions, Runtime } from "node-appwrite";
2
+ import { InputFile } from "node-appwrite/file";
3
+ import { create as createTarball } from "tar";
4
+ import { join } from "node:path";
5
+ import fs from "node:fs";
6
+ import { type AppwriteFunction, type Specification } from "appwrite-utils";
7
+ import chalk from "chalk";
8
+ import cliProgress from "cli-progress";
9
+ import { execSync } from "child_process";
10
+ import {
11
+ createFunction,
12
+ getFunction,
13
+ updateFunctionSpecifications,
14
+ } from "./methods.js";
15
+
16
+ const findFunctionDirectory = (
17
+ basePath: string,
18
+ functionName: string
19
+ ): string | undefined => {
20
+ const normalizedName = functionName.toLowerCase().replace(/\s+/g, "-");
21
+ const dirs = fs.readdirSync(basePath, { withFileTypes: true });
22
+
23
+ for (const dir of dirs) {
24
+ if (dir.isDirectory()) {
25
+ const fullPath = join(basePath, dir.name);
26
+ if (dir.name.toLowerCase() === normalizedName) {
27
+ return fullPath;
28
+ }
29
+
30
+ const nestedResult = findFunctionDirectory(fullPath, functionName);
31
+ if (nestedResult) {
32
+ return nestedResult;
33
+ }
34
+ }
35
+ }
36
+
37
+ return undefined;
38
+ };
39
+
40
+ export const deployFunction = async (
41
+ client: Client,
42
+ functionId: string,
43
+ codePath: string,
44
+ activate: boolean = true,
45
+ entrypoint: string = "index.js",
46
+ commands: string = "npm install"
47
+ ) => {
48
+ const functions = new Functions(client);
49
+ console.log(chalk.blue("📦 Preparing function deployment..."));
50
+
51
+ const progressBar = new cliProgress.SingleBar({
52
+ format:
53
+ "Uploading |" +
54
+ chalk.cyan("{bar}") +
55
+ "| {percentage}% | {value}/{total} Chunks",
56
+ barCompleteChar: "█",
57
+ barIncompleteChar: "░",
58
+ hideCursor: true,
59
+ });
60
+
61
+ const tarPath = join(process.cwd(), `function-${functionId}.tar.gz`);
62
+ await createTarball(
63
+ {
64
+ gzip: true,
65
+ file: tarPath,
66
+ cwd: codePath,
67
+ },
68
+ ["."]
69
+ );
70
+
71
+ const fileBuffer = await fs.promises.readFile(tarPath);
72
+ const fileObject = InputFile.fromBuffer(
73
+ new Uint8Array(fileBuffer),
74
+ `function-${functionId}.tar.gz`
75
+ );
76
+
77
+ try {
78
+ console.log(chalk.blue("🚀 Creating deployment..."));
79
+ const functionResponse = await functions.createDeployment(
80
+ functionId,
81
+ fileObject,
82
+ activate,
83
+ entrypoint,
84
+ commands,
85
+ (progress) => {
86
+ const chunks = progress.chunksUploaded;
87
+ const total = progress.chunksTotal;
88
+ if (chunks && total) {
89
+ if (chunks === 0) {
90
+ progressBar.start(total, 0);
91
+ } else if (chunks === total) {
92
+ progressBar.update(total);
93
+ progressBar.stop();
94
+ console.log(chalk.green("✅ Upload complete!"));
95
+ } else {
96
+ progressBar.update(chunks);
97
+ }
98
+ }
99
+ }
100
+ );
101
+
102
+ await fs.promises.unlink(tarPath);
103
+ console.log(chalk.green("✨ Function deployed successfully!"));
104
+ return functionResponse;
105
+ } catch (error) {
106
+ progressBar.stop();
107
+ console.error(chalk.red("❌ Deployment failed:"), error);
108
+ throw error;
109
+ }
110
+ };
111
+
112
+ export const deployLocalFunction = async (
113
+ client: Client,
114
+ functionName: string,
115
+ functionConfig: AppwriteFunction,
116
+ functionPath?: string
117
+ ) => {
118
+ let functionExists = true;
119
+ try {
120
+ await getFunction(client, functionConfig.$id);
121
+ } catch (error) {
122
+ functionExists = false;
123
+ }
124
+
125
+ const resolvedPath =
126
+ functionPath ||
127
+ functionConfig.dirPath ||
128
+ findFunctionDirectory(process.cwd(), functionName) ||
129
+ join(
130
+ process.cwd(),
131
+ "functions",
132
+ functionName.toLowerCase().replace(/\s+/g, "-")
133
+ );
134
+
135
+ if (functionConfig.predeployCommands?.length) {
136
+ console.log(chalk.blue("Executing predeploy commands..."));
137
+ for (const command of functionConfig.predeployCommands) {
138
+ try {
139
+ console.log(chalk.gray(`Executing: ${command}`));
140
+ execSync(command, {
141
+ cwd: resolvedPath,
142
+ stdio: "inherit",
143
+ });
144
+ } catch (error) {
145
+ console.error(
146
+ chalk.red(`Failed to execute predeploy command: ${command}`)
147
+ );
148
+ throw error;
149
+ }
150
+ }
151
+ }
152
+
153
+ if (!functionExists) {
154
+ await createFunction(
155
+ client,
156
+ functionConfig.$id,
157
+ functionConfig.name,
158
+ functionConfig.runtime as Runtime,
159
+ functionConfig.execute,
160
+ functionConfig.events,
161
+ functionConfig.schedule,
162
+ functionConfig.timeout,
163
+ functionConfig.enabled,
164
+ functionConfig.logging,
165
+ functionConfig.entrypoint,
166
+ functionConfig.commands
167
+ );
168
+ }
169
+
170
+ if (functionConfig.specification) {
171
+ await updateFunctionSpecifications(
172
+ client,
173
+ functionConfig.$id,
174
+ functionConfig.specification
175
+ );
176
+ }
177
+
178
+ const deployPath = functionConfig.deployDir
179
+ ? join(resolvedPath, functionConfig.deployDir)
180
+ : resolvedPath;
181
+
182
+ return deployFunction(
183
+ client,
184
+ functionConfig.$id,
185
+ deployPath,
186
+ true,
187
+ functionConfig.entrypoint,
188
+ functionConfig.commands
189
+ );
190
+ };