appwrite-utils-cli 0.10.86 → 1.0.1

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 (178) hide show
  1. package/.appwrite/.yaml_schemas/appwrite-config.schema.json +380 -0
  2. package/.appwrite/.yaml_schemas/collection.schema.json +255 -0
  3. package/.appwrite/collections/Categories.yaml +182 -0
  4. package/.appwrite/collections/ExampleCollection.yaml +36 -0
  5. package/.appwrite/collections/Posts.yaml +227 -0
  6. package/.appwrite/collections/Users.yaml +149 -0
  7. package/.appwrite/config.yaml +109 -0
  8. package/.appwrite/import/README.md +148 -0
  9. package/.appwrite/import/categories-import.yaml +129 -0
  10. package/.appwrite/import/posts-import.yaml +208 -0
  11. package/.appwrite/import/users-import.yaml +130 -0
  12. package/.appwrite/importData/categories.json +194 -0
  13. package/.appwrite/importData/posts.json +270 -0
  14. package/.appwrite/importData/users.json +220 -0
  15. package/.appwrite/schemas/categories.json +128 -0
  16. package/.appwrite/schemas/exampleCollection.json +52 -0
  17. package/.appwrite/schemas/posts.json +173 -0
  18. package/.appwrite/schemas/users.json +125 -0
  19. package/README.md +260 -33
  20. package/dist/collections/attributes.js +3 -2
  21. package/dist/collections/methods.js +56 -38
  22. package/dist/config/yamlConfig.d.ts +501 -0
  23. package/dist/config/yamlConfig.js +452 -0
  24. package/dist/databases/setup.d.ts +6 -0
  25. package/dist/databases/setup.js +119 -0
  26. package/dist/functions/methods.d.ts +1 -1
  27. package/dist/functions/methods.js +5 -2
  28. package/dist/functions/openapi.d.ts +4 -0
  29. package/dist/functions/openapi.js +60 -0
  30. package/dist/interactiveCLI.d.ts +5 -0
  31. package/dist/interactiveCLI.js +194 -49
  32. package/dist/main.js +91 -30
  33. package/dist/migrations/afterImportActions.js +2 -2
  34. package/dist/migrations/appwriteToX.d.ts +10 -0
  35. package/dist/migrations/appwriteToX.js +15 -4
  36. package/dist/migrations/backup.d.ts +16 -16
  37. package/dist/migrations/dataLoader.d.ts +83 -1
  38. package/dist/migrations/dataLoader.js +4 -4
  39. package/dist/migrations/importController.js +25 -18
  40. package/dist/migrations/importDataActions.js +2 -2
  41. package/dist/migrations/logging.d.ts +9 -1
  42. package/dist/migrations/logging.js +41 -22
  43. package/dist/migrations/migrationHelper.d.ts +4 -4
  44. package/dist/migrations/relationships.js +1 -1
  45. package/dist/migrations/services/DataTransformationService.d.ts +55 -0
  46. package/dist/migrations/services/DataTransformationService.js +158 -0
  47. package/dist/migrations/services/FileHandlerService.d.ts +75 -0
  48. package/dist/migrations/services/FileHandlerService.js +236 -0
  49. package/dist/migrations/services/ImportOrchestrator.d.ts +97 -0
  50. package/dist/migrations/services/ImportOrchestrator.js +488 -0
  51. package/dist/migrations/services/RateLimitManager.d.ts +138 -0
  52. package/dist/migrations/services/RateLimitManager.js +279 -0
  53. package/dist/migrations/services/RelationshipResolver.d.ts +120 -0
  54. package/dist/migrations/services/RelationshipResolver.js +332 -0
  55. package/dist/migrations/services/UserMappingService.d.ts +109 -0
  56. package/dist/migrations/services/UserMappingService.js +277 -0
  57. package/dist/migrations/services/ValidationService.d.ts +74 -0
  58. package/dist/migrations/services/ValidationService.js +260 -0
  59. package/dist/migrations/transfer.d.ts +0 -6
  60. package/dist/migrations/transfer.js +16 -132
  61. package/dist/migrations/yaml/YamlImportConfigLoader.d.ts +384 -0
  62. package/dist/migrations/yaml/YamlImportConfigLoader.js +375 -0
  63. package/dist/migrations/yaml/YamlImportIntegration.d.ts +87 -0
  64. package/dist/migrations/yaml/YamlImportIntegration.js +330 -0
  65. package/dist/migrations/yaml/generateImportSchemas.d.ts +17 -0
  66. package/dist/migrations/yaml/generateImportSchemas.js +575 -0
  67. package/dist/schemas/authUser.d.ts +9 -9
  68. package/dist/shared/attributeManager.d.ts +17 -0
  69. package/dist/shared/attributeManager.js +273 -0
  70. package/dist/shared/confirmationDialogs.d.ts +75 -0
  71. package/dist/shared/confirmationDialogs.js +236 -0
  72. package/dist/shared/functionManager.d.ts +48 -0
  73. package/dist/shared/functionManager.js +322 -0
  74. package/dist/shared/indexManager.d.ts +24 -0
  75. package/dist/shared/indexManager.js +150 -0
  76. package/dist/shared/jsonSchemaGenerator.d.ts +51 -0
  77. package/dist/shared/jsonSchemaGenerator.js +313 -0
  78. package/dist/shared/logging.d.ts +10 -0
  79. package/dist/shared/logging.js +46 -0
  80. package/dist/shared/messageFormatter.d.ts +37 -0
  81. package/dist/shared/messageFormatter.js +152 -0
  82. package/dist/shared/migrationHelpers.d.ts +173 -0
  83. package/dist/shared/migrationHelpers.js +142 -0
  84. package/dist/shared/operationLogger.d.ts +3 -0
  85. package/dist/shared/operationLogger.js +25 -0
  86. package/dist/shared/operationQueue.d.ts +13 -0
  87. package/dist/shared/operationQueue.js +79 -0
  88. package/dist/shared/progressManager.d.ts +62 -0
  89. package/dist/shared/progressManager.js +215 -0
  90. package/dist/shared/schemaGenerator.d.ts +18 -0
  91. package/dist/shared/schemaGenerator.js +523 -0
  92. package/dist/storage/methods.d.ts +3 -1
  93. package/dist/storage/methods.js +144 -55
  94. package/dist/storage/schemas.d.ts +56 -16
  95. package/dist/types.d.ts +2 -2
  96. package/dist/types.js +1 -1
  97. package/dist/users/methods.d.ts +16 -0
  98. package/dist/users/methods.js +276 -0
  99. package/dist/utils/configMigration.d.ts +1 -0
  100. package/dist/utils/configMigration.js +156 -0
  101. package/dist/utils/dataConverters.d.ts +46 -0
  102. package/dist/utils/dataConverters.js +139 -0
  103. package/dist/utils/loadConfigs.d.ts +15 -4
  104. package/dist/utils/loadConfigs.js +377 -51
  105. package/dist/utils/schemaStrings.js +2 -1
  106. package/dist/utils/setupFiles.d.ts +2 -1
  107. package/dist/utils/setupFiles.js +723 -28
  108. package/dist/utils/validationRules.d.ts +43 -0
  109. package/dist/utils/validationRules.js +42 -0
  110. package/dist/utils/yamlConverter.d.ts +48 -0
  111. package/dist/utils/yamlConverter.js +98 -0
  112. package/dist/utilsController.js +65 -43
  113. package/package.json +19 -15
  114. package/src/collections/attributes.ts +3 -2
  115. package/src/collections/methods.ts +85 -51
  116. package/src/config/yamlConfig.ts +488 -0
  117. package/src/{migrations/setupDatabase.ts → databases/setup.ts} +11 -5
  118. package/src/functions/methods.ts +8 -4
  119. package/src/functions/templates/count-docs-in-collection/package.json +25 -0
  120. package/src/functions/templates/count-docs-in-collection/tsconfig.json +28 -0
  121. package/src/functions/templates/typescript-node/package.json +24 -0
  122. package/src/functions/templates/typescript-node/tsconfig.json +28 -0
  123. package/src/functions/templates/uv/README.md +31 -0
  124. package/src/functions/templates/uv/pyproject.toml +29 -0
  125. package/src/interactiveCLI.ts +226 -61
  126. package/src/main.ts +111 -37
  127. package/src/migrations/afterImportActions.ts +2 -2
  128. package/src/migrations/appwriteToX.ts +17 -4
  129. package/src/migrations/dataLoader.ts +4 -4
  130. package/src/migrations/importController.ts +30 -22
  131. package/src/migrations/importDataActions.ts +2 -2
  132. package/src/migrations/relationships.ts +1 -1
  133. package/src/migrations/services/DataTransformationService.ts +196 -0
  134. package/src/migrations/services/FileHandlerService.ts +311 -0
  135. package/src/migrations/services/ImportOrchestrator.ts +669 -0
  136. package/src/migrations/services/RateLimitManager.ts +363 -0
  137. package/src/migrations/services/RelationshipResolver.ts +461 -0
  138. package/src/migrations/services/UserMappingService.ts +345 -0
  139. package/src/migrations/services/ValidationService.ts +349 -0
  140. package/src/migrations/transfer.ts +22 -228
  141. package/src/migrations/yaml/YamlImportConfigLoader.ts +427 -0
  142. package/src/migrations/yaml/YamlImportIntegration.ts +419 -0
  143. package/src/migrations/yaml/generateImportSchemas.ts +589 -0
  144. package/src/shared/attributeManager.ts +429 -0
  145. package/src/shared/confirmationDialogs.ts +327 -0
  146. package/src/shared/functionManager.ts +515 -0
  147. package/src/shared/indexManager.ts +253 -0
  148. package/src/shared/jsonSchemaGenerator.ts +403 -0
  149. package/src/shared/logging.ts +74 -0
  150. package/src/shared/messageFormatter.ts +195 -0
  151. package/src/{migrations/migrationHelper.ts → shared/migrationHelpers.ts} +22 -4
  152. package/src/{migrations/helper.ts → shared/operationLogger.ts} +7 -2
  153. package/src/{migrations/queue.ts → shared/operationQueue.ts} +1 -1
  154. package/src/shared/progressManager.ts +278 -0
  155. package/src/{migrations/schemaStrings.ts → shared/schemaGenerator.ts} +71 -17
  156. package/src/storage/methods.ts +199 -78
  157. package/src/types.ts +2 -2
  158. package/src/{migrations/users.ts → users/methods.ts} +2 -2
  159. package/src/utils/configMigration.ts +212 -0
  160. package/src/utils/loadConfigs.ts +414 -52
  161. package/src/utils/schemaStrings.ts +2 -1
  162. package/src/utils/setupFiles.ts +742 -40
  163. package/src/{migrations → utils}/validationRules.ts +1 -1
  164. package/src/utils/yamlConverter.ts +131 -0
  165. package/src/utilsController.ts +75 -54
  166. package/src/functions/templates/poetry/README.md +0 -30
  167. package/src/functions/templates/poetry/pyproject.toml +0 -16
  168. package/src/migrations/attributes.ts +0 -561
  169. package/src/migrations/backup.ts +0 -205
  170. package/src/migrations/databases.ts +0 -39
  171. package/src/migrations/dbHelpers.ts +0 -92
  172. package/src/migrations/indexes.ts +0 -40
  173. package/src/migrations/logging.ts +0 -29
  174. package/src/migrations/storage.ts +0 -538
  175. /package/src/{migrations → functions}/openapi.ts +0 -0
  176. /package/src/functions/templates/{poetry → uv}/src/__init__.py +0 -0
  177. /package/src/functions/templates/{poetry → uv}/src/index.py +0 -0
  178. /package/src/{migrations/converters.ts → utils/dataConverters.ts} +0 -0
@@ -0,0 +1,43 @@
1
+ export interface ValidationRules {
2
+ [key: string]: (value: any, ...args: any[]) => boolean;
3
+ }
4
+ export declare const validationRules: {
5
+ isNumber: (value: any) => boolean;
6
+ isString: (value: any) => boolean;
7
+ isBoolean: (value: any) => boolean;
8
+ isArray: (value: any) => boolean;
9
+ isObject: (value: any) => boolean;
10
+ isNull: (value: any) => boolean;
11
+ isValidEmail: (value: string) => boolean;
12
+ isValidPhone: (value: string) => boolean;
13
+ isValidPassword: (value: string) => boolean;
14
+ isValidUrl: (value: string) => boolean;
15
+ isValidHex: (value: string) => boolean;
16
+ isValidHexColor: (value: string) => boolean;
17
+ isValidHexAlpha: (value: string) => boolean;
18
+ isValidDate: (value: string) => boolean;
19
+ isValidTime: (value: string) => boolean;
20
+ isNullish: (value: any) => boolean;
21
+ isUndefined: (value: any) => boolean;
22
+ isDefined: (value: any) => boolean;
23
+ isDate: (value: any) => boolean;
24
+ isEmpty: (value: any) => boolean;
25
+ isInteger: (value: any) => boolean;
26
+ isFloat: (value: any) => boolean;
27
+ isArrayLike: (value: any) => boolean;
28
+ isArrayLikeObject: (value: any) => boolean;
29
+ isFunction: (value: any) => boolean;
30
+ isLength: (value: any) => boolean;
31
+ isMap: (value: any) => boolean;
32
+ isSet: (value: any) => boolean;
33
+ isRegExp: (value: any) => boolean;
34
+ isSymbol: (value: any) => boolean;
35
+ isObjectLike: (value: any) => boolean;
36
+ isPlainObject: (value: any) => boolean;
37
+ isSafeInteger: (value: any) => boolean;
38
+ isTypedArray: (value: any) => boolean;
39
+ isEqual: (value: any, other: any) => boolean;
40
+ isMatch: (object: any, source: any) => boolean;
41
+ has: (object: any, path: string) => boolean;
42
+ get: (object: any, path: string, defaultValue: any) => any;
43
+ };
@@ -0,0 +1,42 @@
1
+ import { isNumber, isString, isBoolean, isArray, isPlainObject, isNull, isUndefined, isDate, isEmpty, isInteger, isArrayLike, isArrayLikeObject, isFunction, isLength, isMap, isSet, isRegExp, isSymbol, isObjectLike, isSafeInteger, isTypedArray, isEqual, isMatch, has, get, } from "es-toolkit/compat";
2
+ export const validationRules = {
3
+ isNumber: (value) => isNumber(value),
4
+ isString: (value) => isString(value),
5
+ isBoolean: (value) => isBoolean(value),
6
+ isArray: (value) => isArray(value),
7
+ isObject: (value) => isPlainObject(value) && !isArray(value) && !isFunction(value),
8
+ isNull: (value) => isNull(value),
9
+ isValidEmail: (value) => value.match(/^[\w\-\.]+@([\w-]+\.)+[\w-]{2,}$/) !== null,
10
+ isValidPhone: (value) => value.match(/^[+]?[(]?[0-9]{3}[)]?[-\s.]?[0-9]{3}[-\s.]?[0-9]{4,6}$/im) !==
11
+ null,
12
+ isValidPassword: (value) => value.match(/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*#?&])[A-Za-z\d@$!%*#?&]{8,}$/) !== null,
13
+ isValidUrl: (value) => value.match(/^(https?:\/\/)?([\da-z\.-]+)\.([a-z\.]{2,6})([\/\w \.-]*)*\/?$/) !== null,
14
+ isValidHex: (value) => value.match(/^#([a-f0-9]{6}|[a-f0-9]{3})$/i) !== null,
15
+ isValidHexColor: (value) => value.match(/^#([a-f0-9]{6}|[a-f0-9]{3})$/i) !== null,
16
+ isValidHexAlpha: (value) => value.match(/^#([a-f0-9]{8}|[a-f0-9]{4})$/i) !== null,
17
+ isValidDate: (value) => value.match(/^\d{4}-\d{2}-\d{2}$/) !== null,
18
+ isValidTime: (value) => value.match(/^\d{2}:\d{2}(:\d{2})?$/) !== null,
19
+ isNullish: (value) => isNull(value) || isUndefined(value),
20
+ isUndefined: (value) => isUndefined(value),
21
+ isDefined: (value) => !isUndefined(value) && !isNull(value) && !isEmpty(value),
22
+ isDate: (value) => isDate(value),
23
+ isEmpty: (value) => isEmpty(value),
24
+ isInteger: (value) => isInteger(value),
25
+ isFloat: (value) => isNumber(value) && !isInteger(value), // Note: Works for double precision numbers
26
+ isArrayLike: (value) => isArrayLike(value),
27
+ isArrayLikeObject: (value) => isArrayLikeObject(value),
28
+ isFunction: (value) => isFunction(value),
29
+ isLength: (value) => isLength(value),
30
+ isMap: (value) => isMap(value),
31
+ isSet: (value) => isSet(value),
32
+ isRegExp: (value) => isRegExp(value),
33
+ isSymbol: (value) => isSymbol(value),
34
+ isObjectLike: (value) => isObjectLike(value),
35
+ isPlainObject: (value) => isPlainObject(value),
36
+ isSafeInteger: (value) => isSafeInteger(value),
37
+ isTypedArray: (value) => isTypedArray(value),
38
+ isEqual: (value, other) => isEqual(value, other),
39
+ isMatch: (object, source) => isMatch(object, source),
40
+ has: (object, path) => has(object, path),
41
+ get: (object, path, defaultValue) => get(object, path, defaultValue),
42
+ };
@@ -0,0 +1,48 @@
1
+ import type { Collection, CollectionCreate } from "appwrite-utils";
2
+ export interface YamlCollectionData {
3
+ name: string;
4
+ id?: string;
5
+ documentSecurity?: boolean;
6
+ enabled?: boolean;
7
+ permissions?: Array<{
8
+ permission: string;
9
+ target: string;
10
+ }>;
11
+ attributes?: Array<{
12
+ key: string;
13
+ type: string;
14
+ size?: number;
15
+ required?: boolean;
16
+ array?: boolean;
17
+ default?: any;
18
+ description?: string;
19
+ min?: number;
20
+ max?: number;
21
+ elements?: string[];
22
+ relatedCollection?: string;
23
+ relationType?: string;
24
+ twoWay?: boolean;
25
+ twoWayKey?: string;
26
+ onDelete?: string;
27
+ side?: string;
28
+ }>;
29
+ indexes?: Array<{
30
+ key: string;
31
+ type: string;
32
+ attributes: string[];
33
+ orders?: string[];
34
+ }>;
35
+ importDefs?: any[];
36
+ }
37
+ /**
38
+ * Converts a Collection object to YAML format with proper schema reference
39
+ */
40
+ export declare function collectionToYaml(collection: Collection | CollectionCreate, schemaPath?: string): string;
41
+ /**
42
+ * Sanitizes a collection name for use as a filename
43
+ */
44
+ export declare function sanitizeFilename(name: string): string;
45
+ /**
46
+ * Generates the filename for a collection YAML file
47
+ */
48
+ export declare function getCollectionYamlFilename(collection: Collection | CollectionCreate): string;
@@ -0,0 +1,98 @@
1
+ import yaml from "js-yaml";
2
+ /**
3
+ * Converts a Collection object to YAML format with proper schema reference
4
+ */
5
+ export function collectionToYaml(collection, schemaPath = "../.yaml_schemas/collection.schema.json") {
6
+ // Convert Collection to YamlCollectionData format
7
+ const yamlData = {
8
+ name: collection.name,
9
+ id: collection.$id,
10
+ documentSecurity: collection.documentSecurity,
11
+ enabled: collection.enabled,
12
+ };
13
+ // Convert permissions
14
+ if (collection.$permissions && collection.$permissions.length > 0) {
15
+ yamlData.permissions = collection.$permissions.map(p => ({
16
+ permission: p.permission,
17
+ target: p.target
18
+ }));
19
+ }
20
+ // Convert attributes
21
+ if (collection.attributes && collection.attributes.length > 0) {
22
+ yamlData.attributes = collection.attributes.map(attr => {
23
+ const yamlAttr = {
24
+ key: attr.key,
25
+ type: attr.type,
26
+ };
27
+ // Add optional properties only if they exist (safely access with 'in' operator)
28
+ if ('size' in attr && attr.size !== undefined)
29
+ yamlAttr.size = attr.size;
30
+ if (attr.required !== undefined)
31
+ yamlAttr.required = attr.required;
32
+ if (attr.array !== undefined)
33
+ yamlAttr.array = attr.array;
34
+ if ('xdefault' in attr && attr.xdefault !== undefined)
35
+ yamlAttr.default = attr.xdefault;
36
+ if (attr.description !== undefined)
37
+ yamlAttr.description = attr.description;
38
+ if ('min' in attr && attr.min !== undefined)
39
+ yamlAttr.min = attr.min;
40
+ if ('max' in attr && attr.max !== undefined)
41
+ yamlAttr.max = attr.max;
42
+ if ('elements' in attr && attr.elements !== undefined)
43
+ yamlAttr.elements = attr.elements;
44
+ if ('relatedCollection' in attr && attr.relatedCollection !== undefined)
45
+ yamlAttr.relatedCollection = attr.relatedCollection;
46
+ if ('relationType' in attr && attr.relationType !== undefined)
47
+ yamlAttr.relationType = attr.relationType;
48
+ if ('twoWay' in attr && attr.twoWay !== undefined)
49
+ yamlAttr.twoWay = attr.twoWay;
50
+ if ('twoWayKey' in attr && attr.twoWayKey !== undefined)
51
+ yamlAttr.twoWayKey = attr.twoWayKey;
52
+ if ('onDelete' in attr && attr.onDelete !== undefined)
53
+ yamlAttr.onDelete = attr.onDelete;
54
+ if ('side' in attr && attr.side !== undefined)
55
+ yamlAttr.side = attr.side;
56
+ return yamlAttr;
57
+ });
58
+ }
59
+ // Convert indexes
60
+ if (collection.indexes && collection.indexes.length > 0) {
61
+ yamlData.indexes = collection.indexes.map(idx => ({
62
+ key: idx.key,
63
+ type: idx.type,
64
+ attributes: idx.attributes,
65
+ ...(idx.orders && idx.orders.length > 0 ? { orders: idx.orders } : {})
66
+ }));
67
+ }
68
+ // Add import definitions if they exist
69
+ if (collection.importDefs && collection.importDefs.length > 0) {
70
+ yamlData.importDefs = collection.importDefs;
71
+ }
72
+ else {
73
+ yamlData.importDefs = [];
74
+ }
75
+ // Generate YAML with schema reference
76
+ const yamlContent = yaml.dump(yamlData, {
77
+ indent: 2,
78
+ lineWidth: 120,
79
+ sortKeys: false,
80
+ quotingType: '"',
81
+ forceQuotes: false,
82
+ });
83
+ return `# yaml-language-server: $schema=${schemaPath}
84
+ # Collection Definition: ${collection.name}
85
+ ${yamlContent}`;
86
+ }
87
+ /**
88
+ * Sanitizes a collection name for use as a filename
89
+ */
90
+ export function sanitizeFilename(name) {
91
+ return name.replace(/[^a-zA-Z0-9_-]/g, '_');
92
+ }
93
+ /**
94
+ * Generates the filename for a collection YAML file
95
+ */
96
+ export function getCollectionYamlFilename(collection) {
97
+ return `${sanitizeFilename(collection.name)}.yaml`;
98
+ }
@@ -1,11 +1,11 @@
1
1
  import { Client, Databases, Query, Storage, Users, } from "node-appwrite";
2
2
  import {} from "appwrite-utils";
3
- import { loadConfig, findAppwriteConfig, findFunctionsDir, } from "./utils/loadConfigs.js";
4
- import { UsersController } from "./migrations/users.js";
3
+ import { loadConfig, loadConfigWithPath, findAppwriteConfig, findFunctionsDir, } from "./utils/loadConfigs.js";
4
+ import { UsersController } from "./users/methods.js";
5
5
  import { AppwriteToX } from "./migrations/appwriteToX.js";
6
6
  import { ImportController } from "./migrations/importController.js";
7
7
  import { ImportDataActions } from "./migrations/importDataActions.js";
8
- import { setupMigrationDatabase, ensureDatabasesExist, wipeOtherDatabases, ensureCollectionsExist, } from "./migrations/setupDatabase.js";
8
+ import { setupMigrationDatabase, ensureDatabasesExist, wipeOtherDatabases, ensureCollectionsExist, } from "./databases/setup.js";
9
9
  import { createOrUpdateCollections, wipeDatabase, generateSchemas, fetchAllCollections, wipeCollection, } from "./collections/methods.js";
10
10
  import { backupDatabase, ensureDatabaseConfigBucketsExist, initOrGetBackupStorage, wipeDocumentStorage, } from "./storage/methods.js";
11
11
  import path from "path";
@@ -13,11 +13,13 @@ import { converterFunctions, validationRules, } from "appwrite-utils";
13
13
  import { afterImportActions } from "./migrations/afterImportActions.js";
14
14
  import { transferDatabaseLocalToLocal, transferDatabaseLocalToRemote, transferStorageLocalToLocal, transferStorageLocalToRemote, transferUsersLocalToRemote, } from "./migrations/transfer.js";
15
15
  import { getClient } from "./utils/getClientFromConfig.js";
16
- import { fetchAllDatabases } from "./migrations/databases.js";
16
+ import { fetchAllDatabases } from "./databases/methods.js";
17
17
  import { listFunctions, updateFunctionSpecifications, } from "./functions/methods.js";
18
18
  import chalk from "chalk";
19
19
  import { deployLocalFunction } from "./functions/deployments.js";
20
20
  import fs from "node:fs";
21
+ import { configureLogging, updateLogger } from "./shared/logging.js";
22
+ import { MessageFormatter, Messages } from "./shared/messageFormatter.js";
21
23
  export class UtilsController {
22
24
  appwriteFolderPath;
23
25
  appwriteConfigPath;
@@ -33,15 +35,15 @@ export class UtilsController {
33
35
  if (directConfig) {
34
36
  let hasErrors = false;
35
37
  if (!directConfig.appwriteEndpoint) {
36
- console.log(chalk.red("Appwrite endpoint is required"));
38
+ MessageFormatter.error("Appwrite endpoint is required", undefined, { prefix: "Config" });
37
39
  hasErrors = true;
38
40
  }
39
41
  if (!directConfig.appwriteProject) {
40
- console.log(chalk.red("Appwrite project is required"));
42
+ MessageFormatter.error("Appwrite project is required", undefined, { prefix: "Config" });
41
43
  hasErrors = true;
42
44
  }
43
45
  if (!directConfig.appwriteKey) {
44
- console.log(chalk.red("Appwrite key is required"));
46
+ MessageFormatter.error("Appwrite key is required", undefined, { prefix: "Config" });
45
47
  hasErrors = true;
46
48
  }
47
49
  if (!hasErrors) {
@@ -58,9 +60,15 @@ export class UtilsController {
58
60
  enableMockData: false,
59
61
  documentBucketId: "",
60
62
  usersCollectionName: "",
63
+ useMigrations: true,
61
64
  databases: [],
62
65
  buckets: [],
63
66
  functions: [],
67
+ logging: {
68
+ enabled: false,
69
+ level: "info",
70
+ console: false,
71
+ },
64
72
  };
65
73
  }
66
74
  }
@@ -68,28 +76,37 @@ export class UtilsController {
68
76
  // Try to find config file
69
77
  const appwriteConfigFound = findAppwriteConfig(basePath);
70
78
  if (!appwriteConfigFound) {
71
- console.log(chalk.yellow("No appwriteConfig.ts found and no direct configuration provided"));
79
+ MessageFormatter.warning("No appwriteConfig.ts found and no direct configuration provided", { prefix: "Config" });
72
80
  return;
73
81
  }
74
82
  this.appwriteConfigPath = appwriteConfigFound;
75
- this.appwriteFolderPath = path.dirname(appwriteConfigFound);
83
+ this.appwriteFolderPath = appwriteConfigFound; // For YAML configs, findAppwriteConfig already returns the correct directory
76
84
  }
77
85
  }
78
86
  async init() {
79
87
  if (!this.config) {
80
88
  if (this.appwriteFolderPath && this.appwriteConfigPath) {
81
- console.log("Loading config from file...");
82
- this.config = await loadConfig(this.appwriteFolderPath);
83
- if (!this.config) {
84
- console.log(chalk.red("Failed to load config from file"));
89
+ MessageFormatter.progress("Loading config from file...", { prefix: "Config" });
90
+ try {
91
+ const { config, actualConfigPath } = await loadConfigWithPath(this.appwriteFolderPath);
92
+ this.config = config;
93
+ MessageFormatter.info(`Loaded config from: ${actualConfigPath}`, { prefix: "Config" });
94
+ }
95
+ catch (error) {
96
+ MessageFormatter.error("Failed to load config from file", undefined, { prefix: "Config" });
85
97
  return;
86
98
  }
87
99
  }
88
100
  else {
89
- console.log(chalk.red("No configuration available"));
101
+ MessageFormatter.error("No configuration available", undefined, { prefix: "Config" });
90
102
  return;
91
103
  }
92
104
  }
105
+ // Configure logging based on config
106
+ if (this.config.logging) {
107
+ configureLogging(this.config.logging);
108
+ updateLogger();
109
+ }
93
110
  this.appwriteServer = new Client();
94
111
  this.appwriteServer
95
112
  .setEndpoint(this.config.appwriteEndpoint)
@@ -101,7 +118,7 @@ export class UtilsController {
101
118
  }
102
119
  async reloadConfig() {
103
120
  if (!this.appwriteFolderPath) {
104
- console.log(chalk.red("Failed to get appwriteFolderPath"));
121
+ MessageFormatter.error("Failed to get appwriteFolderPath", undefined, { prefix: "Controller" });
105
122
  return;
106
123
  }
107
124
  this.config = await loadConfig(this.appwriteFolderPath);
@@ -109,6 +126,11 @@ export class UtilsController {
109
126
  console.log(chalk.red("Failed to load config"));
110
127
  return;
111
128
  }
129
+ // Configure logging based on updated config
130
+ if (this.config.logging) {
131
+ configureLogging(this.config.logging);
132
+ updateLogger();
133
+ }
112
134
  this.appwriteServer = new Client();
113
135
  this.appwriteServer
114
136
  .setEndpoint(this.config.appwriteEndpoint)
@@ -121,7 +143,7 @@ export class UtilsController {
121
143
  async setupMigrationDatabase() {
122
144
  await this.init();
123
145
  if (!this.config) {
124
- console.log(chalk.red("Config not initialized"));
146
+ MessageFormatter.error("Config not initialized", undefined, { prefix: "Controller" });
125
147
  return;
126
148
  }
127
149
  await setupMigrationDatabase(this.config);
@@ -129,11 +151,11 @@ export class UtilsController {
129
151
  async ensureDatabaseConfigBucketsExist(databases = []) {
130
152
  await this.init();
131
153
  if (!this.storage) {
132
- console.log(chalk.red("Storage not initialized"));
154
+ MessageFormatter.error("Storage not initialized", undefined, { prefix: "Controller" });
133
155
  return;
134
156
  }
135
157
  if (!this.config) {
136
- console.log(chalk.red("Config not initialized"));
158
+ MessageFormatter.error("Config not initialized", undefined, { prefix: "Controller" });
137
159
  return;
138
160
  }
139
161
  await ensureDatabaseConfigBucketsExist(this.storage, this.config, databases);
@@ -141,7 +163,7 @@ export class UtilsController {
141
163
  async ensureDatabasesExist(databases) {
142
164
  await this.init();
143
165
  if (!this.config) {
144
- console.log(chalk.red("Config not initialized"));
166
+ MessageFormatter.error("Config not initialized", undefined, { prefix: "Controller" });
145
167
  return;
146
168
  }
147
169
  await this.setupMigrationDatabase();
@@ -151,7 +173,7 @@ export class UtilsController {
151
173
  async ensureCollectionsExist(database, collections) {
152
174
  await this.init();
153
175
  if (!this.config) {
154
- console.log(chalk.red("Config not initialized"));
176
+ MessageFormatter.error("Config not initialized", undefined, { prefix: "Controller" });
155
177
  return;
156
178
  }
157
179
  await ensureCollectionsExist(this.config, database, collections);
@@ -159,7 +181,7 @@ export class UtilsController {
159
181
  async getDatabasesByIds(ids) {
160
182
  await this.init();
161
183
  if (!this.database) {
162
- console.log(chalk.red("Database not initialized"));
184
+ MessageFormatter.error("Database not initialized", undefined, { prefix: "Controller" });
163
185
  return;
164
186
  }
165
187
  if (ids.length === 0)
@@ -173,10 +195,10 @@ export class UtilsController {
173
195
  async wipeOtherDatabases(databasesToKeep) {
174
196
  await this.init();
175
197
  if (!this.database) {
176
- console.log(chalk.red("Database not initialized"));
198
+ MessageFormatter.error("Database not initialized", undefined, { prefix: "Controller" });
177
199
  return;
178
200
  }
179
- await wipeOtherDatabases(this.database, databasesToKeep);
201
+ await wipeOtherDatabases(this.database, databasesToKeep, this.config?.useMigrations ?? true);
180
202
  }
181
203
  async wipeUsers() {
182
204
  await this.init();
@@ -208,7 +230,7 @@ export class UtilsController {
208
230
  }
209
231
  async findFunctionDirectories() {
210
232
  if (!this.appwriteFolderPath) {
211
- console.log(chalk.red("Failed to get appwriteFolderPath"));
233
+ MessageFormatter.error("Failed to get appwriteFolderPath", undefined, { prefix: "Controller" });
212
234
  return new Map();
213
235
  }
214
236
  const functionsDir = findFunctionsDir(this.appwriteFolderPath);
@@ -258,10 +280,10 @@ export class UtilsController {
258
280
  Query.limit(1000),
259
281
  ]);
260
282
  for (const localFunction of localFunctions) {
261
- console.log(chalk.blue(`Syncing function ${localFunction.name}...`));
283
+ MessageFormatter.progress(`Syncing function ${localFunction.name}...`, { prefix: "Functions" });
262
284
  await this.deployFunction(localFunction.name);
263
285
  }
264
- console.log(chalk.green("All functions synchronized successfully!"));
286
+ MessageFormatter.success("All functions synchronized successfully!", { prefix: "Functions" });
265
287
  }
266
288
  async wipeDatabase(database, wipeBucket = false) {
267
289
  await this.init();
@@ -312,7 +334,7 @@ export class UtilsController {
312
334
  if (!this.database || !this.config)
313
335
  throw new Error("Database or config not initialized");
314
336
  for (const database of databases) {
315
- if (database.$id === "migrations")
337
+ if (!this.config.useMigrations && database.$id === "migrations")
316
338
  continue;
317
339
  await this.createOrUpdateCollections(database, undefined, collections);
318
340
  }
@@ -326,11 +348,11 @@ export class UtilsController {
326
348
  async generateSchemas() {
327
349
  await this.init();
328
350
  if (!this.config) {
329
- console.log(chalk.red("Config not initialized"));
351
+ MessageFormatter.error("Config not initialized", undefined, { prefix: "Controller" });
330
352
  return;
331
353
  }
332
354
  if (!this.appwriteFolderPath) {
333
- console.log(chalk.red("Failed to get appwriteFolderPath"));
355
+ MessageFormatter.error("Failed to get appwriteFolderPath", undefined, { prefix: "Controller" });
334
356
  return;
335
357
  }
336
358
  await generateSchemas(this.config, this.appwriteFolderPath);
@@ -338,19 +360,19 @@ export class UtilsController {
338
360
  async importData(options = {}) {
339
361
  await this.init();
340
362
  if (!this.database) {
341
- console.log(chalk.red("Database not initialized"));
363
+ MessageFormatter.error("Database not initialized", undefined, { prefix: "Controller" });
342
364
  return;
343
365
  }
344
366
  if (!this.storage) {
345
- console.log(chalk.red("Storage not initialized"));
367
+ MessageFormatter.error("Storage not initialized", undefined, { prefix: "Controller" });
346
368
  return;
347
369
  }
348
370
  if (!this.config) {
349
- console.log(chalk.red("Config not initialized"));
371
+ MessageFormatter.error("Config not initialized", undefined, { prefix: "Controller" });
350
372
  return;
351
373
  }
352
374
  if (!this.appwriteFolderPath) {
353
- console.log(chalk.red("Failed to get appwriteFolderPath"));
375
+ MessageFormatter.error("Failed to get appwriteFolderPath", undefined, { prefix: "Controller" });
354
376
  return;
355
377
  }
356
378
  const importDataActions = new ImportDataActions(this.database, this.storage, this.config, this.converterDefinitions, this.validityRuleDefinitions, this.afterImportActionsDefinitions);
@@ -360,16 +382,16 @@ export class UtilsController {
360
382
  async synchronizeConfigurations(databases, config) {
361
383
  await this.init();
362
384
  if (!this.storage) {
363
- console.log(chalk.red("Storage not initialized"));
385
+ MessageFormatter.error("Storage not initialized", undefined, { prefix: "Controller" });
364
386
  return;
365
387
  }
366
388
  const configToUse = config || this.config;
367
389
  if (!configToUse) {
368
- console.log(chalk.red("Config not initialized"));
390
+ MessageFormatter.error("Config not initialized", undefined, { prefix: "Controller" });
369
391
  return;
370
392
  }
371
393
  if (!this.appwriteFolderPath) {
372
- console.log(chalk.red("Failed to get appwriteFolderPath"));
394
+ MessageFormatter.error("Failed to get appwriteFolderPath", undefined, { prefix: "Controller" });
373
395
  return;
374
396
  }
375
397
  const appwriteToX = new AppwriteToX(configToUse, this.appwriteFolderPath, this.storage);
@@ -378,7 +400,7 @@ export class UtilsController {
378
400
  async syncDb(databases = [], collections = []) {
379
401
  await this.init();
380
402
  if (!this.database) {
381
- console.log(chalk.red("Database not initialized"));
403
+ MessageFormatter.error("Database not initialized", undefined, { prefix: "Controller" });
382
404
  return;
383
405
  }
384
406
  if (databases.length === 0) {
@@ -441,10 +463,10 @@ export class UtilsController {
441
463
  return;
442
464
  }
443
465
  else {
444
- console.log(chalk.blue("Starting user transfer..."));
466
+ MessageFormatter.progress("Starting user transfer...", { prefix: "Transfer" });
445
467
  const localUsers = new Users(this.appwriteServer);
446
468
  await transferUsersLocalToRemote(localUsers, options.transferEndpoint, options.transferProject, options.transferKey);
447
- console.log(chalk.green("User transfer completed"));
469
+ MessageFormatter.success("User transfer completed", { prefix: "Transfer" });
448
470
  }
449
471
  }
450
472
  // Handle storage transfer
@@ -464,7 +486,7 @@ export class UtilsController {
464
486
  .trim()
465
487
  .replace(/\s+/g, "")}`);
466
488
  if (sourceBucketId && targetBucketId) {
467
- console.log(chalk.blue(`Starting storage transfer from ${sourceBucketId} to ${targetBucketId}`));
489
+ MessageFormatter.progress(`Starting storage transfer from ${sourceBucketId} to ${targetBucketId}`, { prefix: "Transfer" });
468
490
  if (options.isRemote) {
469
491
  await transferStorageLocalToRemote(this.storage, options.transferEndpoint, options.transferProject, options.transferKey, sourceBucketId, targetBucketId);
470
492
  }
@@ -473,14 +495,14 @@ export class UtilsController {
473
495
  }
474
496
  }
475
497
  }
476
- console.log(chalk.green("Transfer completed"));
498
+ MessageFormatter.success("Transfer completed", { prefix: "Transfer" });
477
499
  }
478
500
  async updateFunctionSpecifications(functionId, specification) {
479
501
  await this.init();
480
502
  if (!this.appwriteServer)
481
503
  throw new Error("Appwrite server not initialized");
482
- console.log(chalk.green(`Updating function specifications for ${functionId} to ${specification}`));
504
+ MessageFormatter.progress(`Updating function specifications for ${functionId} to ${specification}`, { prefix: "Functions" });
483
505
  await updateFunctionSpecifications(this.appwriteServer, functionId, specification);
484
- console.log(chalk.green(`Successfully updated function specifications for ${functionId} to ${specification}`));
506
+ MessageFormatter.success(`Successfully updated function specifications for ${functionId} to ${specification}`, { prefix: "Functions" });
485
507
  }
486
508
  }
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.10.86",
4
+ "version": "1.0.1",
5
5
  "main": "src/main.ts",
6
6
  "type": "module",
7
7
  "repository": {
@@ -30,29 +30,33 @@
30
30
  "postinstall": "echo 'This package is intended for CLI use only and should not be added as a dependency in other projects.'"
31
31
  },
32
32
  "dependencies": {
33
- "@types/inquirer": "^9.0.7",
34
- "appwrite-utils": "^0.4.1",
35
- "chalk": "^5.3.0",
33
+ "@types/inquirer": "^9.0.8",
34
+ "@types/json-schema": "^7.0.15",
35
+ "@types/yargs": "^17.0.33",
36
+ "appwrite-utils": "^1.0.0",
37
+ "chalk": "^5.4.1",
36
38
  "cli-progress": "^3.12.0",
37
39
  "commander": "^12.1.0",
38
- "es-toolkit": "^1.32.0",
40
+ "es-toolkit": "^1.39.4",
39
41
  "ignore": "^6.0.2",
40
- "inquirer": "^9.3.6",
42
+ "inquirer": "^9.3.7",
41
43
  "js-yaml": "^4.1.0",
42
- "luxon": "^3.5.0",
44
+ "luxon": "^3.6.1",
43
45
  "nanostores": "^0.10.3",
44
- "node-appwrite": "^14.1.0",
46
+ "node-appwrite": "^14.2.0",
47
+ "p-limit": "^6.2.0",
45
48
  "tar": "^7.4.3",
46
- "tsx": "^4.17.0",
47
- "ulidx": "^2.4.0",
48
- "winston": "^3.14.2",
49
- "zod": "^3.23.8"
49
+ "tsx": "^4.20.3",
50
+ "ulidx": "^2.4.1",
51
+ "winston": "^3.17.0",
52
+ "yargs": "^18.0.0",
53
+ "zod": "^3.25.67"
50
54
  },
51
55
  "devDependencies": {
52
56
  "@types/cli-progress": "^3.11.6",
53
57
  "@types/js-yaml": "^4.0.9",
54
- "@types/lodash": "^4.17.7",
55
- "@types/luxon": "^3.4.2",
56
- "typescript": "^5.5.4"
58
+ "@types/lodash": "^4.17.18",
59
+ "@types/luxon": "^3.6.2",
60
+ "typescript": "^5.8.3"
57
61
  }
58
62
  }
@@ -4,7 +4,7 @@ import {
4
4
  parseAttribute,
5
5
  type Attribute,
6
6
  } from "appwrite-utils";
7
- import { nameToIdMapping, enqueueOperation } from "../migrations/queue.js";
7
+ import { nameToIdMapping, enqueueOperation } from "../shared/operationQueue.js";
8
8
  import { delay, tryAwaitWithRetry } from "../utils/helperFunctions.js";
9
9
  import chalk from "chalk";
10
10
 
@@ -264,7 +264,8 @@ export const createOrUpdateAttribute = async (
264
264
  );
265
265
  }
266
266
  break;
267
- case "float":
267
+ case "double":
268
+ case "float": // Backward compatibility
268
269
  if (action === "create") {
269
270
  await tryAwaitWithRetry(
270
271
  async () =>