appwrite-utils-cli 1.3.1 → 1.3.5

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.
@@ -336,12 +336,12 @@ export const createOrUpdateAttribute = async (db, dbId, collection, attribute) =
336
336
  case "double":
337
337
  case "float": // Backward compatibility
338
338
  if (action === "create") {
339
- await tryAwaitWithRetry(async () => await db.createFloatAttribute(dbId, collection.$id, finalAttribute.key, finalAttribute.required || false, finalAttribute.min !== undefined ? finalAttribute.min : -2147483647, finalAttribute.max !== undefined ? finalAttribute.max : 2147483647, finalAttribute.xdefault !== undefined && !finalAttribute.required
339
+ await tryAwaitWithRetry(async () => await db.createFloatAttribute(dbId, collection.$id, finalAttribute.key, finalAttribute.required || false, finalAttribute.min, finalAttribute.max, finalAttribute.xdefault !== undefined && !finalAttribute.required
340
340
  ? finalAttribute.xdefault
341
341
  : null, finalAttribute.array || false));
342
342
  }
343
343
  else {
344
- await tryAwaitWithRetry(async () => await db.updateFloatAttribute(dbId, collection.$id, finalAttribute.key, finalAttribute.required || false, finalAttribute.min !== undefined ? finalAttribute.min : -2147483647, finalAttribute.max !== undefined ? finalAttribute.max : 2147483647, finalAttribute.xdefault !== undefined && !finalAttribute.required
344
+ await tryAwaitWithRetry(async () => await db.updateFloatAttribute(dbId, collection.$id, finalAttribute.key, finalAttribute.required || false, finalAttribute.min, finalAttribute.max, finalAttribute.xdefault !== undefined && !finalAttribute.required
345
345
  ? finalAttribute.xdefault
346
346
  : null));
347
347
  }
@@ -167,10 +167,14 @@ export const createOrUpdateIndex = async (dbId, db, collectionId, index) => {
167
167
  ]);
168
168
  let createIndex = false;
169
169
  let newIndex = null;
170
- if (existingIndex.total > 0 &&
171
- !existingIndex.indexes.some((existingIndex) => (existingIndex.key === index.key &&
172
- existingIndex.type === index.type &&
173
- existingIndex.attributes === index.attributes))) {
170
+ if (existingIndex.total === 0) {
171
+ // No existing index, create it
172
+ createIndex = true;
173
+ }
174
+ else if (!existingIndex.indexes.some((existingIndex) => (existingIndex.key === index.key &&
175
+ existingIndex.type === index.type &&
176
+ existingIndex.attributes === index.attributes))) {
177
+ // Existing index doesn't match, delete and recreate
174
178
  await db.deleteIndex(dbId, collectionId, existingIndex.indexes[0].key);
175
179
  createIndex = true;
176
180
  }
@@ -5,6 +5,19 @@ import fs from "node:fs";
5
5
  import {} from "appwrite-utils";
6
6
  import chalk from "chalk";
7
7
  import { extract as extractTar } from "tar";
8
+ /**
9
+ * Validates and filters events array for Appwrite functions
10
+ * - Filters out empty/invalid strings
11
+ * - Limits to 100 items maximum (Appwrite limit)
12
+ * - Returns empty array if input is invalid
13
+ */
14
+ const validateEvents = (events) => {
15
+ if (!events || !Array.isArray(events))
16
+ return [];
17
+ return events
18
+ .filter(event => event && typeof event === 'string' && event.trim().length > 0)
19
+ .slice(0, 100);
20
+ };
8
21
  export const listFunctions = async (client, queries, search) => {
9
22
  const functions = new Functions(client);
10
23
  const functionsList = await functions.list(queries, search);
@@ -58,7 +71,7 @@ export const deleteFunction = async (client, functionId) => {
58
71
  };
59
72
  export const createFunction = async (client, functionConfig) => {
60
73
  const functions = new Functions(client);
61
- const functionResponse = await functions.create(functionConfig.$id, functionConfig.name, functionConfig.runtime, functionConfig.execute, functionConfig.events, functionConfig.schedule, functionConfig.timeout, functionConfig.enabled, functionConfig.logging, functionConfig.entrypoint, functionConfig.commands, functionConfig.scopes, functionConfig.installationId, functionConfig.providerRepositoryId, functionConfig.providerBranch, functionConfig.providerSilentMode, functionConfig.providerRootDirectory);
74
+ const functionResponse = await functions.create(functionConfig.$id, functionConfig.name, functionConfig.runtime, functionConfig.execute, validateEvents(functionConfig.events), functionConfig.schedule, functionConfig.timeout, functionConfig.enabled, functionConfig.logging, functionConfig.entrypoint, functionConfig.commands, functionConfig.scopes, functionConfig.installationId, functionConfig.providerRepositoryId, functionConfig.providerBranch, functionConfig.providerSilentMode, functionConfig.providerRootDirectory);
62
75
  return functionResponse;
63
76
  };
64
77
  export const updateFunctionSpecifications = async (client, functionId, specification) => {
@@ -101,7 +114,7 @@ export const listFunctionDeployments = async (client, functionId, queries) => {
101
114
  };
102
115
  export const updateFunction = async (client, functionConfig) => {
103
116
  const functions = new Functions(client);
104
- const functionResponse = await functions.update(functionConfig.$id, functionConfig.name, functionConfig.runtime, functionConfig.execute, functionConfig.events, functionConfig.schedule, functionConfig.timeout, functionConfig.enabled, functionConfig.logging, functionConfig.entrypoint, functionConfig.commands, functionConfig.scopes, functionConfig.installationId, functionConfig.providerRepositoryId, functionConfig.providerBranch, functionConfig.providerSilentMode, functionConfig.providerRootDirectory, functionConfig.specification);
117
+ const functionResponse = await functions.update(functionConfig.$id, functionConfig.name, functionConfig.runtime, functionConfig.execute, validateEvents(functionConfig.events), functionConfig.schedule, functionConfig.timeout, functionConfig.enabled, functionConfig.logging, functionConfig.entrypoint, functionConfig.commands, functionConfig.scopes, functionConfig.installationId, functionConfig.providerRepositoryId, functionConfig.providerBranch, functionConfig.providerSilentMode, functionConfig.providerRootDirectory, functionConfig.specification);
105
118
  return functionResponse;
106
119
  };
107
120
  export const createFunctionTemplate = async (templateType, functionName, basePath = "./functions") => {
@@ -5,6 +5,19 @@ import fs from "node:fs";
5
5
  import chalk from "chalk";
6
6
  import pLimit from "p-limit";
7
7
  import { tryAwaitWithRetry } from "../utils/helperFunctions.js";
8
+ /**
9
+ * Validates and filters events array for Appwrite functions
10
+ * - Filters out empty/invalid strings
11
+ * - Limits to 100 items maximum (Appwrite limit)
12
+ * - Returns empty array if input is invalid
13
+ */
14
+ const validateEvents = (events) => {
15
+ if (!events || !Array.isArray(events))
16
+ return [];
17
+ return events
18
+ .filter(event => event && typeof event === 'string' && event.trim().length > 0)
19
+ .slice(0, 100);
20
+ };
8
21
  // Concurrency limits
9
22
  const functionLimit = pLimit(5); // Moderate limit for function operations
10
23
  const queryLimit = pLimit(25); // Higher limit for read operations
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": "1.3.1",
4
+ "version": "1.3.5",
5
5
  "main": "src/main.ts",
6
6
  "type": "module",
7
7
  "repository": {
@@ -33,7 +33,7 @@
33
33
  "@types/inquirer": "^9.0.8",
34
34
  "@types/json-schema": "^7.0.15",
35
35
  "@types/yargs": "^17.0.33",
36
- "appwrite-utils": "^1.3.1",
36
+ "appwrite-utils": "^1.3.2",
37
37
  "chalk": "^5.4.1",
38
38
  "cli-progress": "^3.12.0",
39
39
  "commander": "^12.1.0",
@@ -43,7 +43,7 @@
43
43
  "js-yaml": "^4.1.0",
44
44
  "luxon": "^3.6.1",
45
45
  "nanostores": "^0.10.3",
46
- "node-appwrite": "^16",
46
+ "node-appwrite": "^17",
47
47
  "p-limit": "^6.2.0",
48
48
  "tar": "^7.4.3",
49
49
  "tsx": "^4.20.3",
@@ -553,8 +553,8 @@ export const createOrUpdateAttribute = async (
553
553
  collection.$id,
554
554
  finalAttribute.key,
555
555
  finalAttribute.required || false,
556
- finalAttribute.min !== undefined ? finalAttribute.min : -2147483647,
557
- finalAttribute.max !== undefined ? finalAttribute.max : 2147483647,
556
+ finalAttribute.min,
557
+ finalAttribute.max,
558
558
  finalAttribute.xdefault !== undefined && !finalAttribute.required
559
559
  ? finalAttribute.xdefault
560
560
  : null,
@@ -569,8 +569,8 @@ export const createOrUpdateAttribute = async (
569
569
  collection.$id,
570
570
  finalAttribute.key,
571
571
  finalAttribute.required || false,
572
- finalAttribute.min !== undefined ? finalAttribute.min : -2147483647,
573
- finalAttribute.max !== undefined ? finalAttribute.max : 2147483647,
572
+ finalAttribute.min,
573
+ finalAttribute.max,
574
574
  finalAttribute.xdefault !== undefined && !finalAttribute.required
575
575
  ? finalAttribute.xdefault
576
576
  : null
@@ -277,10 +277,14 @@ export const createOrUpdateIndex = async (
277
277
  const existingIndex = await db.listIndexes(dbId, collectionId, [
278
278
  Query.equal("key", index.key),
279
279
  ]);
280
+
280
281
  let createIndex = false;
281
282
  let newIndex: Models.Index | null = null;
282
- if (
283
- existingIndex.total > 0 &&
283
+
284
+ if (existingIndex.total === 0) {
285
+ // No existing index, create it
286
+ createIndex = true;
287
+ } else if (
284
288
  !existingIndex.indexes.some(
285
289
  (existingIndex) =>
286
290
  (existingIndex.key === index.key &&
@@ -288,9 +292,11 @@ export const createOrUpdateIndex = async (
288
292
  existingIndex.attributes === index.attributes)
289
293
  )
290
294
  ) {
295
+ // Existing index doesn't match, delete and recreate
291
296
  await db.deleteIndex(dbId, collectionId, existingIndex.indexes[0].key);
292
297
  createIndex = true;
293
298
  }
299
+
294
300
  if (createIndex) {
295
301
  newIndex = await db.createIndex(
296
302
  dbId,
@@ -301,6 +307,7 @@ export const createOrUpdateIndex = async (
301
307
  index.orders
302
308
  );
303
309
  }
310
+
304
311
  return newIndex;
305
312
  };
306
313
 
@@ -17,6 +17,20 @@ import {
17
17
  import chalk from "chalk";
18
18
  import { extract as extractTar } from "tar";
19
19
 
20
+ /**
21
+ * Validates and filters events array for Appwrite functions
22
+ * - Filters out empty/invalid strings
23
+ * - Limits to 100 items maximum (Appwrite limit)
24
+ * - Returns empty array if input is invalid
25
+ */
26
+ const validateEvents = (events?: string[]): string[] => {
27
+ if (!events || !Array.isArray(events)) return [];
28
+
29
+ return events
30
+ .filter(event => event && typeof event === 'string' && event.trim().length > 0)
31
+ .slice(0, 100);
32
+ };
33
+
20
34
  export const listFunctions = async (
21
35
  client: Client,
22
36
  queries?: string[],
@@ -101,7 +115,7 @@ export const createFunction = async (
101
115
  functionConfig.name,
102
116
  functionConfig.runtime as Runtime,
103
117
  functionConfig.execute,
104
- functionConfig.events,
118
+ validateEvents(functionConfig.events),
105
119
  functionConfig.schedule,
106
120
  functionConfig.timeout,
107
121
  functionConfig.enabled,
@@ -181,7 +195,7 @@ export const updateFunction = async (
181
195
  functionConfig.name,
182
196
  functionConfig.runtime as Runtime,
183
197
  functionConfig.execute,
184
- functionConfig.events,
198
+ validateEvents(functionConfig.events),
185
199
  functionConfig.schedule,
186
200
  functionConfig.timeout,
187
201
  functionConfig.enabled,
@@ -6,6 +6,20 @@ import chalk from "chalk";
6
6
  import pLimit from "p-limit";
7
7
  import { tryAwaitWithRetry } from "../utils/helperFunctions.js";
8
8
 
9
+ /**
10
+ * Validates and filters events array for Appwrite functions
11
+ * - Filters out empty/invalid strings
12
+ * - Limits to 100 items maximum (Appwrite limit)
13
+ * - Returns empty array if input is invalid
14
+ */
15
+ const validateEvents = (events?: string[]): string[] => {
16
+ if (!events || !Array.isArray(events)) return [];
17
+
18
+ return events
19
+ .filter(event => event && typeof event === 'string' && event.trim().length > 0)
20
+ .slice(0, 100);
21
+ };
22
+
9
23
  // Concurrency limits
10
24
  const functionLimit = pLimit(5); // Moderate limit for function operations
11
25
  const queryLimit = pLimit(25); // Higher limit for read operations