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.
- package/.appwrite/.yaml_schemas/appwrite-config.schema.json +380 -0
- package/.appwrite/.yaml_schemas/collection.schema.json +255 -0
- package/.appwrite/collections/Categories.yaml +182 -0
- package/.appwrite/collections/ExampleCollection.yaml +36 -0
- package/.appwrite/collections/Posts.yaml +227 -0
- package/.appwrite/collections/Users.yaml +149 -0
- package/.appwrite/config.yaml +109 -0
- package/.appwrite/import/README.md +148 -0
- package/.appwrite/import/categories-import.yaml +129 -0
- package/.appwrite/import/posts-import.yaml +208 -0
- package/.appwrite/import/users-import.yaml +130 -0
- package/.appwrite/importData/categories.json +194 -0
- package/.appwrite/importData/posts.json +270 -0
- package/.appwrite/importData/users.json +220 -0
- package/.appwrite/schemas/categories.json +128 -0
- package/.appwrite/schemas/exampleCollection.json +52 -0
- package/.appwrite/schemas/posts.json +173 -0
- package/.appwrite/schemas/users.json +125 -0
- package/README.md +260 -33
- package/dist/collections/attributes.js +3 -2
- package/dist/collections/methods.js +56 -38
- package/dist/config/yamlConfig.d.ts +501 -0
- package/dist/config/yamlConfig.js +452 -0
- package/dist/databases/setup.d.ts +6 -0
- package/dist/databases/setup.js +119 -0
- package/dist/functions/methods.d.ts +1 -1
- package/dist/functions/methods.js +5 -2
- package/dist/functions/openapi.d.ts +4 -0
- package/dist/functions/openapi.js +60 -0
- package/dist/interactiveCLI.d.ts +5 -0
- package/dist/interactiveCLI.js +194 -49
- package/dist/main.js +91 -30
- package/dist/migrations/afterImportActions.js +2 -2
- package/dist/migrations/appwriteToX.d.ts +10 -0
- package/dist/migrations/appwriteToX.js +15 -4
- package/dist/migrations/backup.d.ts +16 -16
- package/dist/migrations/dataLoader.d.ts +83 -1
- package/dist/migrations/dataLoader.js +4 -4
- package/dist/migrations/importController.js +25 -18
- package/dist/migrations/importDataActions.js +2 -2
- package/dist/migrations/logging.d.ts +9 -1
- package/dist/migrations/logging.js +41 -22
- package/dist/migrations/migrationHelper.d.ts +4 -4
- package/dist/migrations/relationships.js +1 -1
- package/dist/migrations/services/DataTransformationService.d.ts +55 -0
- package/dist/migrations/services/DataTransformationService.js +158 -0
- package/dist/migrations/services/FileHandlerService.d.ts +75 -0
- package/dist/migrations/services/FileHandlerService.js +236 -0
- package/dist/migrations/services/ImportOrchestrator.d.ts +97 -0
- package/dist/migrations/services/ImportOrchestrator.js +488 -0
- package/dist/migrations/services/RateLimitManager.d.ts +138 -0
- package/dist/migrations/services/RateLimitManager.js +279 -0
- package/dist/migrations/services/RelationshipResolver.d.ts +120 -0
- package/dist/migrations/services/RelationshipResolver.js +332 -0
- package/dist/migrations/services/UserMappingService.d.ts +109 -0
- package/dist/migrations/services/UserMappingService.js +277 -0
- package/dist/migrations/services/ValidationService.d.ts +74 -0
- package/dist/migrations/services/ValidationService.js +260 -0
- package/dist/migrations/transfer.d.ts +0 -6
- package/dist/migrations/transfer.js +16 -132
- package/dist/migrations/yaml/YamlImportConfigLoader.d.ts +384 -0
- package/dist/migrations/yaml/YamlImportConfigLoader.js +375 -0
- package/dist/migrations/yaml/YamlImportIntegration.d.ts +87 -0
- package/dist/migrations/yaml/YamlImportIntegration.js +330 -0
- package/dist/migrations/yaml/generateImportSchemas.d.ts +17 -0
- package/dist/migrations/yaml/generateImportSchemas.js +575 -0
- package/dist/schemas/authUser.d.ts +9 -9
- package/dist/shared/attributeManager.d.ts +17 -0
- package/dist/shared/attributeManager.js +273 -0
- package/dist/shared/confirmationDialogs.d.ts +75 -0
- package/dist/shared/confirmationDialogs.js +236 -0
- package/dist/shared/functionManager.d.ts +48 -0
- package/dist/shared/functionManager.js +322 -0
- package/dist/shared/indexManager.d.ts +24 -0
- package/dist/shared/indexManager.js +150 -0
- package/dist/shared/jsonSchemaGenerator.d.ts +51 -0
- package/dist/shared/jsonSchemaGenerator.js +313 -0
- package/dist/shared/logging.d.ts +10 -0
- package/dist/shared/logging.js +46 -0
- package/dist/shared/messageFormatter.d.ts +37 -0
- package/dist/shared/messageFormatter.js +152 -0
- package/dist/shared/migrationHelpers.d.ts +173 -0
- package/dist/shared/migrationHelpers.js +142 -0
- package/dist/shared/operationLogger.d.ts +3 -0
- package/dist/shared/operationLogger.js +25 -0
- package/dist/shared/operationQueue.d.ts +13 -0
- package/dist/shared/operationQueue.js +79 -0
- package/dist/shared/progressManager.d.ts +62 -0
- package/dist/shared/progressManager.js +215 -0
- package/dist/shared/schemaGenerator.d.ts +18 -0
- package/dist/shared/schemaGenerator.js +523 -0
- package/dist/storage/methods.d.ts +3 -1
- package/dist/storage/methods.js +144 -55
- package/dist/storage/schemas.d.ts +56 -16
- package/dist/types.d.ts +2 -2
- package/dist/types.js +1 -1
- package/dist/users/methods.d.ts +16 -0
- package/dist/users/methods.js +276 -0
- package/dist/utils/configMigration.d.ts +1 -0
- package/dist/utils/configMigration.js +156 -0
- package/dist/utils/dataConverters.d.ts +46 -0
- package/dist/utils/dataConverters.js +139 -0
- package/dist/utils/loadConfigs.d.ts +15 -4
- package/dist/utils/loadConfigs.js +377 -51
- package/dist/utils/schemaStrings.js +2 -1
- package/dist/utils/setupFiles.d.ts +2 -1
- package/dist/utils/setupFiles.js +723 -28
- package/dist/utils/validationRules.d.ts +43 -0
- package/dist/utils/validationRules.js +42 -0
- package/dist/utils/yamlConverter.d.ts +48 -0
- package/dist/utils/yamlConverter.js +98 -0
- package/dist/utilsController.js +65 -43
- package/package.json +19 -15
- package/src/collections/attributes.ts +3 -2
- package/src/collections/methods.ts +85 -51
- package/src/config/yamlConfig.ts +488 -0
- package/src/{migrations/setupDatabase.ts → databases/setup.ts} +11 -5
- package/src/functions/methods.ts +8 -4
- package/src/functions/templates/count-docs-in-collection/package.json +25 -0
- package/src/functions/templates/count-docs-in-collection/tsconfig.json +28 -0
- package/src/functions/templates/typescript-node/package.json +24 -0
- package/src/functions/templates/typescript-node/tsconfig.json +28 -0
- package/src/functions/templates/uv/README.md +31 -0
- package/src/functions/templates/uv/pyproject.toml +29 -0
- package/src/interactiveCLI.ts +226 -61
- package/src/main.ts +111 -37
- package/src/migrations/afterImportActions.ts +2 -2
- package/src/migrations/appwriteToX.ts +17 -4
- package/src/migrations/dataLoader.ts +4 -4
- package/src/migrations/importController.ts +30 -22
- package/src/migrations/importDataActions.ts +2 -2
- package/src/migrations/relationships.ts +1 -1
- package/src/migrations/services/DataTransformationService.ts +196 -0
- package/src/migrations/services/FileHandlerService.ts +311 -0
- package/src/migrations/services/ImportOrchestrator.ts +669 -0
- package/src/migrations/services/RateLimitManager.ts +363 -0
- package/src/migrations/services/RelationshipResolver.ts +461 -0
- package/src/migrations/services/UserMappingService.ts +345 -0
- package/src/migrations/services/ValidationService.ts +349 -0
- package/src/migrations/transfer.ts +22 -228
- package/src/migrations/yaml/YamlImportConfigLoader.ts +427 -0
- package/src/migrations/yaml/YamlImportIntegration.ts +419 -0
- package/src/migrations/yaml/generateImportSchemas.ts +589 -0
- package/src/shared/attributeManager.ts +429 -0
- package/src/shared/confirmationDialogs.ts +327 -0
- package/src/shared/functionManager.ts +515 -0
- package/src/shared/indexManager.ts +253 -0
- package/src/shared/jsonSchemaGenerator.ts +403 -0
- package/src/shared/logging.ts +74 -0
- package/src/shared/messageFormatter.ts +195 -0
- package/src/{migrations/migrationHelper.ts → shared/migrationHelpers.ts} +22 -4
- package/src/{migrations/helper.ts → shared/operationLogger.ts} +7 -2
- package/src/{migrations/queue.ts → shared/operationQueue.ts} +1 -1
- package/src/shared/progressManager.ts +278 -0
- package/src/{migrations/schemaStrings.ts → shared/schemaGenerator.ts} +71 -17
- package/src/storage/methods.ts +199 -78
- package/src/types.ts +2 -2
- package/src/{migrations/users.ts → users/methods.ts} +2 -2
- package/src/utils/configMigration.ts +212 -0
- package/src/utils/loadConfigs.ts +414 -52
- package/src/utils/schemaStrings.ts +2 -1
- package/src/utils/setupFiles.ts +742 -40
- package/src/{migrations → utils}/validationRules.ts +1 -1
- package/src/utils/yamlConverter.ts +131 -0
- package/src/utilsController.ts +75 -54
- package/src/functions/templates/poetry/README.md +0 -30
- package/src/functions/templates/poetry/pyproject.toml +0 -16
- package/src/migrations/attributes.ts +0 -561
- package/src/migrations/backup.ts +0 -205
- package/src/migrations/databases.ts +0 -39
- package/src/migrations/dbHelpers.ts +0 -92
- package/src/migrations/indexes.ts +0 -40
- package/src/migrations/logging.ts +0 -29
- package/src/migrations/storage.ts +0 -538
- /package/src/{migrations → functions}/openapi.ts +0 -0
- /package/src/functions/templates/{poetry → uv}/src/__init__.py +0 -0
- /package/src/functions/templates/{poetry → uv}/src/index.py +0 -0
- /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
|
+
}
|
package/dist/utilsController.js
CHANGED
@@ -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 "./
|
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 "./
|
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 "./
|
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
|
-
|
38
|
+
MessageFormatter.error("Appwrite endpoint is required", undefined, { prefix: "Config" });
|
37
39
|
hasErrors = true;
|
38
40
|
}
|
39
41
|
if (!directConfig.appwriteProject) {
|
40
|
-
|
42
|
+
MessageFormatter.error("Appwrite project is required", undefined, { prefix: "Config" });
|
41
43
|
hasErrors = true;
|
42
44
|
}
|
43
45
|
if (!directConfig.appwriteKey) {
|
44
|
-
|
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
|
-
|
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 =
|
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
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
154
|
+
MessageFormatter.error("Storage not initialized", undefined, { prefix: "Controller" });
|
133
155
|
return;
|
134
156
|
}
|
135
157
|
if (!this.config) {
|
136
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
283
|
+
MessageFormatter.progress(`Syncing function ${localFunction.name}...`, { prefix: "Functions" });
|
262
284
|
await this.deployFunction(localFunction.name);
|
263
285
|
}
|
264
|
-
|
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
|
-
|
351
|
+
MessageFormatter.error("Config not initialized", undefined, { prefix: "Controller" });
|
330
352
|
return;
|
331
353
|
}
|
332
354
|
if (!this.appwriteFolderPath) {
|
333
|
-
|
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
|
-
|
363
|
+
MessageFormatter.error("Database not initialized", undefined, { prefix: "Controller" });
|
342
364
|
return;
|
343
365
|
}
|
344
366
|
if (!this.storage) {
|
345
|
-
|
367
|
+
MessageFormatter.error("Storage not initialized", undefined, { prefix: "Controller" });
|
346
368
|
return;
|
347
369
|
}
|
348
370
|
if (!this.config) {
|
349
|
-
|
371
|
+
MessageFormatter.error("Config not initialized", undefined, { prefix: "Controller" });
|
350
372
|
return;
|
351
373
|
}
|
352
374
|
if (!this.appwriteFolderPath) {
|
353
|
-
|
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
|
-
|
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
|
-
|
390
|
+
MessageFormatter.error("Config not initialized", undefined, { prefix: "Controller" });
|
369
391
|
return;
|
370
392
|
}
|
371
393
|
if (!this.appwriteFolderPath) {
|
372
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
504
|
+
MessageFormatter.progress(`Updating function specifications for ${functionId} to ${specification}`, { prefix: "Functions" });
|
483
505
|
await updateFunctionSpecifications(this.appwriteServer, functionId, specification);
|
484
|
-
|
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.
|
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.
|
34
|
-
"
|
35
|
-
"
|
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.
|
40
|
+
"es-toolkit": "^1.39.4",
|
39
41
|
"ignore": "^6.0.2",
|
40
|
-
"inquirer": "^9.3.
|
42
|
+
"inquirer": "^9.3.7",
|
41
43
|
"js-yaml": "^4.1.0",
|
42
|
-
"luxon": "^3.
|
44
|
+
"luxon": "^3.6.1",
|
43
45
|
"nanostores": "^0.10.3",
|
44
|
-
"node-appwrite": "^14.
|
46
|
+
"node-appwrite": "^14.2.0",
|
47
|
+
"p-limit": "^6.2.0",
|
45
48
|
"tar": "^7.4.3",
|
46
|
-
"tsx": "^4.
|
47
|
-
"ulidx": "^2.4.
|
48
|
-
"winston": "^3.
|
49
|
-
"
|
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.
|
55
|
-
"@types/luxon": "^3.
|
56
|
-
"typescript": "^5.
|
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 "../
|
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 "
|
267
|
+
case "double":
|
268
|
+
case "float": // Backward compatibility
|
268
269
|
if (action === "create") {
|
269
270
|
await tryAwaitWithRetry(
|
270
271
|
async () =>
|