appwrite-utils-cli 0.10.74 → 0.10.76
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -0
- package/dist/interactiveCLI.js +2 -2
- package/dist/main.js +28 -4
- package/dist/migrations/schemaStrings.js +1 -1
- package/dist/utils/schemaStrings.js +9 -7
- package/dist/utilsController.d.ts +9 -5
- package/dist/utilsController.js +177 -65
- package/package.json +1 -1
- package/src/interactiveCLI.ts +16 -12
- package/src/main.ts +32 -5
- package/src/migrations/schemaStrings.ts +1 -1
- package/src/utils/schemaStrings.ts +30 -24
- package/src/utilsController.ts +193 -54
package/README.md
CHANGED
@@ -148,6 +148,8 @@ This updated CLI ensures that developers have robust tools at their fingertips t
|
|
148
148
|
|
149
149
|
## Changelog
|
150
150
|
|
151
|
+
- 0.10.76: Updated CLI commands to not require an `appwriteConfig.ts` if you set API Key, ProjectId, and Endpoint
|
152
|
+
- 0.10.75: Fixed slight issue writing ZOD Schema for collection without any attributes
|
151
153
|
- 0.10.74: Fix moving users, should update Labels now
|
152
154
|
- 0.10.73: Fix moving users, passwords should work now (from Appwrite, Argon2)
|
153
155
|
- 0.10.71: Fix create template function `__dirname`
|
package/dist/interactiveCLI.js
CHANGED
@@ -122,9 +122,9 @@ export class InteractiveCLI {
|
|
122
122
|
}
|
123
123
|
}
|
124
124
|
}
|
125
|
-
async initControllerIfNeeded() {
|
125
|
+
async initControllerIfNeeded(directConfig) {
|
126
126
|
if (!this.controller) {
|
127
|
-
this.controller = new UtilsController(this.currentDir);
|
127
|
+
this.controller = new UtilsController(this.currentDir, directConfig);
|
128
128
|
await this.controller.init();
|
129
129
|
}
|
130
130
|
}
|
package/dist/main.js
CHANGED
@@ -159,12 +159,23 @@ async function main() {
|
|
159
159
|
await cli.run();
|
160
160
|
}
|
161
161
|
else {
|
162
|
-
const
|
162
|
+
const directConfig = argv.endpoint || argv.projectId || argv.apiKey
|
163
|
+
? {
|
164
|
+
appwriteEndpoint: argv.endpoint,
|
165
|
+
appwriteProject: argv.projectId,
|
166
|
+
appwriteKey: argv.apiKey,
|
167
|
+
}
|
168
|
+
: undefined;
|
169
|
+
const controller = new UtilsController(process.cwd(), directConfig);
|
163
170
|
await controller.init();
|
164
171
|
if (argv.setup) {
|
165
172
|
await setupDirsFiles(false, process.cwd());
|
166
173
|
return;
|
167
174
|
}
|
175
|
+
if (!controller.config) {
|
176
|
+
console.log(chalk.red("No Appwrite connection found"));
|
177
|
+
return;
|
178
|
+
}
|
168
179
|
const parsedArgv = argv;
|
169
180
|
const options = {
|
170
181
|
databases: parsedArgv.dbIds
|
@@ -280,7 +291,11 @@ async function main() {
|
|
280
291
|
// Only fetch databases if database IDs are provided
|
281
292
|
if (parsedArgv.fromDbId && parsedArgv.toDbId) {
|
282
293
|
console.log(chalk.blue(`Starting database transfer from ${parsedArgv.fromDbId} to ${parsedArgv.toDbId}`));
|
283
|
-
fromDb = (await controller.getDatabasesByIds([parsedArgv.fromDbId]))[0];
|
294
|
+
fromDb = (await controller.getDatabasesByIds([parsedArgv.fromDbId]))?.[0];
|
295
|
+
if (!fromDb) {
|
296
|
+
console.log(chalk.red("Source database not found"));
|
297
|
+
return;
|
298
|
+
}
|
284
299
|
if (isRemote) {
|
285
300
|
if (!parsedArgv.remoteEndpoint ||
|
286
301
|
!parsedArgv.remoteProjectId ||
|
@@ -292,12 +307,21 @@ async function main() {
|
|
292
307
|
targetStorage = new Storage(remoteClient);
|
293
308
|
const remoteDbs = await fetchAllDatabases(targetDatabases);
|
294
309
|
toDb = remoteDbs.find((db) => db.$id === parsedArgv.toDbId);
|
310
|
+
if (!toDb) {
|
311
|
+
console.log(chalk.red("Target database not found"));
|
312
|
+
return;
|
313
|
+
}
|
295
314
|
}
|
296
315
|
else {
|
297
|
-
toDb = (await controller.getDatabasesByIds([parsedArgv.toDbId]))[0];
|
316
|
+
toDb = (await controller.getDatabasesByIds([parsedArgv.toDbId]))?.[0];
|
317
|
+
if (!toDb) {
|
318
|
+
console.log(chalk.red("Target database not found"));
|
319
|
+
return;
|
320
|
+
}
|
298
321
|
}
|
299
322
|
if (!fromDb || !toDb) {
|
300
|
-
|
323
|
+
console.log(chalk.red("Source or target database not found"));
|
324
|
+
return;
|
301
325
|
}
|
302
326
|
}
|
303
327
|
// Handle storage setup
|
@@ -244,7 +244,7 @@ export default appwriteConfig;
|
|
244
244
|
return;
|
245
245
|
}
|
246
246
|
this.config.collections.forEach((collection) => {
|
247
|
-
const schemaString = this.createSchemaString(collection.name, collection.attributes);
|
247
|
+
const schemaString = this.createSchemaString(collection.name, collection.attributes || []);
|
248
248
|
const camelCaseName = toCamelCase(collection.name);
|
249
249
|
const schemaPath = path.join(this.appwriteFolderPath, "schemas", `${camelCaseName}.ts`);
|
250
250
|
fs.writeFileSync(schemaPath, schemaString, { encoding: "utf-8" });
|
@@ -36,19 +36,19 @@ export class SchemaGenerator {
|
|
36
36
|
usersCollectionName: "${this.config.usersCollectionName}",
|
37
37
|
databases: ${JSON.stringify(this.config.databases)},
|
38
38
|
buckets: ${JSON.stringify(this.config.buckets)},
|
39
|
-
functions: ${JSON.stringify(functions.map(func => ({
|
39
|
+
functions: ${JSON.stringify(functions.map((func) => ({
|
40
40
|
functionId: func.$id || ulid(),
|
41
41
|
name: func.name,
|
42
42
|
runtime: func.runtime,
|
43
43
|
path: func.dirPath || `functions/${func.name}`,
|
44
|
-
entrypoint: func.entrypoint ||
|
44
|
+
entrypoint: func.entrypoint || "src/index.ts",
|
45
45
|
execute: func.execute,
|
46
46
|
events: func.events || [],
|
47
|
-
schedule: func.schedule ||
|
47
|
+
schedule: func.schedule || "",
|
48
48
|
timeout: func.timeout || 15,
|
49
49
|
enabled: func.enabled !== false,
|
50
50
|
logging: func.logging !== false,
|
51
|
-
commands: func.commands ||
|
51
|
+
commands: func.commands || "npm install",
|
52
52
|
scopes: func.scopes || [],
|
53
53
|
installationId: func.installationId,
|
54
54
|
providerRepositoryId: func.providerRepositoryId,
|
@@ -56,8 +56,10 @@ export class SchemaGenerator {
|
|
56
56
|
providerSilentMode: func.providerSilentMode,
|
57
57
|
providerRootDirectory: func.providerRootDirectory,
|
58
58
|
specification: func.specification,
|
59
|
-
...(func.predeployCommands
|
60
|
-
|
59
|
+
...(func.predeployCommands
|
60
|
+
? { predeployCommands: func.predeployCommands }
|
61
|
+
: {}),
|
62
|
+
...(func.deployDir ? { deployDir: func.deployDir } : {}),
|
61
63
|
})), null, 2)}
|
62
64
|
};
|
63
65
|
|
@@ -84,7 +86,7 @@ export class SchemaGenerator {
|
|
84
86
|
.join(",\n ")}
|
85
87
|
],
|
86
88
|
attributes: [
|
87
|
-
${collection.attributes
|
89
|
+
${(collection.attributes || [])
|
88
90
|
.map((attr) => {
|
89
91
|
return `{ ${Object.entries(attr)
|
90
92
|
.map(([key, value]) => {
|
@@ -17,8 +17,8 @@ export interface SetupOptions {
|
|
17
17
|
shouldWriteFile?: boolean;
|
18
18
|
}
|
19
19
|
export declare class UtilsController {
|
20
|
-
private appwriteFolderPath
|
21
|
-
private appwriteConfigPath
|
20
|
+
private appwriteFolderPath?;
|
21
|
+
private appwriteConfigPath?;
|
22
22
|
config?: AppwriteConfig;
|
23
23
|
appwriteServer?: Client;
|
24
24
|
database?: Databases;
|
@@ -26,14 +26,18 @@ export declare class UtilsController {
|
|
26
26
|
converterDefinitions: ConverterFunctions;
|
27
27
|
validityRuleDefinitions: ValidationRules;
|
28
28
|
afterImportActionsDefinitions: AfterImportActions;
|
29
|
-
constructor(currentUserDir: string
|
29
|
+
constructor(currentUserDir: string, directConfig?: {
|
30
|
+
appwriteEndpoint?: string;
|
31
|
+
appwriteProject?: string;
|
32
|
+
appwriteKey?: string;
|
33
|
+
});
|
30
34
|
init(): Promise<void>;
|
31
35
|
reloadConfig(): Promise<void>;
|
32
36
|
setupMigrationDatabase(): Promise<void>;
|
33
37
|
ensureDatabaseConfigBucketsExist(databases?: Models.Database[]): Promise<void>;
|
34
38
|
ensureDatabasesExist(databases?: Models.Database[]): Promise<void>;
|
35
39
|
ensureCollectionsExist(database: Models.Database, collections?: Models.Collection[]): Promise<void>;
|
36
|
-
getDatabasesByIds(ids: string[]): Promise<Models.Database[]>;
|
40
|
+
getDatabasesByIds(ids: string[]): Promise<Models.Database[] | undefined>;
|
37
41
|
wipeOtherDatabases(databasesToKeep: Models.Database[]): Promise<void>;
|
38
42
|
wipeUsers(): Promise<void>;
|
39
43
|
backupDatabase(database: Models.Database): Promise<void>;
|
@@ -54,7 +58,7 @@ export declare class UtilsController {
|
|
54
58
|
importData(options?: SetupOptions): Promise<void>;
|
55
59
|
synchronizeConfigurations(databases?: Models.Database[], config?: AppwriteConfig): Promise<void>;
|
56
60
|
syncDb(databases?: Models.Database[], collections?: Models.Collection[]): Promise<void>;
|
57
|
-
getAppwriteFolderPath(): string;
|
61
|
+
getAppwriteFolderPath(): string | undefined;
|
58
62
|
transferData(options: TransferOptions): Promise<void>;
|
59
63
|
updateFunctionSpecifications(functionId: string, specification: Specification): Promise<void>;
|
60
64
|
}
|
package/dist/utilsController.js
CHANGED
@@ -28,37 +28,87 @@ export class UtilsController {
|
|
28
28
|
converterDefinitions = converterFunctions;
|
29
29
|
validityRuleDefinitions = validationRules;
|
30
30
|
afterImportActionsDefinitions = afterImportActions;
|
31
|
-
constructor(currentUserDir) {
|
31
|
+
constructor(currentUserDir, directConfig) {
|
32
32
|
const basePath = currentUserDir;
|
33
|
-
|
34
|
-
|
35
|
-
|
33
|
+
if (directConfig) {
|
34
|
+
let hasErrors = false;
|
35
|
+
if (!directConfig.appwriteEndpoint) {
|
36
|
+
console.log(chalk.red("Appwrite endpoint is required"));
|
37
|
+
hasErrors = true;
|
38
|
+
}
|
39
|
+
if (!directConfig.appwriteProject) {
|
40
|
+
console.log(chalk.red("Appwrite project is required"));
|
41
|
+
hasErrors = true;
|
42
|
+
}
|
43
|
+
if (!directConfig.appwriteKey) {
|
44
|
+
console.log(chalk.red("Appwrite key is required"));
|
45
|
+
hasErrors = true;
|
46
|
+
}
|
47
|
+
if (!hasErrors) {
|
48
|
+
// Only set config if we have all required fields
|
49
|
+
this.appwriteFolderPath = basePath;
|
50
|
+
this.config = {
|
51
|
+
appwriteEndpoint: directConfig.appwriteEndpoint,
|
52
|
+
appwriteProject: directConfig.appwriteProject,
|
53
|
+
appwriteKey: directConfig.appwriteKey,
|
54
|
+
enableBackups: false,
|
55
|
+
backupInterval: 0,
|
56
|
+
backupRetention: 0,
|
57
|
+
enableBackupCleanup: false,
|
58
|
+
enableMockData: false,
|
59
|
+
documentBucketId: "",
|
60
|
+
usersCollectionName: "",
|
61
|
+
databases: [],
|
62
|
+
buckets: [],
|
63
|
+
functions: [],
|
64
|
+
};
|
65
|
+
}
|
36
66
|
}
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
67
|
+
else {
|
68
|
+
// Try to find config file
|
69
|
+
const appwriteConfigFound = findAppwriteConfig(basePath);
|
70
|
+
if (!appwriteConfigFound) {
|
71
|
+
console.log(chalk.yellow("No appwriteConfig.ts found and no direct configuration provided"));
|
72
|
+
return;
|
73
|
+
}
|
74
|
+
this.appwriteConfigPath = appwriteConfigFound;
|
75
|
+
this.appwriteFolderPath = path.dirname(appwriteConfigFound);
|
41
76
|
}
|
42
77
|
}
|
43
78
|
async init() {
|
44
79
|
if (!this.config) {
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
80
|
+
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"));
|
85
|
+
return;
|
86
|
+
}
|
87
|
+
}
|
88
|
+
else {
|
89
|
+
console.log(chalk.red("No configuration available"));
|
90
|
+
return;
|
49
91
|
}
|
50
|
-
this.appwriteServer = new Client();
|
51
|
-
this.appwriteServer
|
52
|
-
.setEndpoint(this.config.appwriteEndpoint)
|
53
|
-
.setProject(this.config.appwriteProject)
|
54
|
-
.setKey(this.config.appwriteKey);
|
55
|
-
this.database = new Databases(this.appwriteServer);
|
56
|
-
this.storage = new Storage(this.appwriteServer);
|
57
|
-
this.config.appwriteClient = this.appwriteServer;
|
58
92
|
}
|
93
|
+
this.appwriteServer = new Client();
|
94
|
+
this.appwriteServer
|
95
|
+
.setEndpoint(this.config.appwriteEndpoint)
|
96
|
+
.setProject(this.config.appwriteProject)
|
97
|
+
.setKey(this.config.appwriteKey);
|
98
|
+
this.database = new Databases(this.appwriteServer);
|
99
|
+
this.storage = new Storage(this.appwriteServer);
|
100
|
+
this.config.appwriteClient = this.appwriteServer;
|
59
101
|
}
|
60
102
|
async reloadConfig() {
|
103
|
+
if (!this.appwriteFolderPath) {
|
104
|
+
console.log(chalk.red("Failed to get appwriteFolderPath"));
|
105
|
+
return;
|
106
|
+
}
|
61
107
|
this.config = await loadConfig(this.appwriteFolderPath);
|
108
|
+
if (!this.config) {
|
109
|
+
console.log(chalk.red("Failed to load config"));
|
110
|
+
return;
|
111
|
+
}
|
62
112
|
this.appwriteServer = new Client();
|
63
113
|
this.appwriteServer
|
64
114
|
.setEndpoint(this.config.appwriteEndpoint)
|
@@ -70,36 +120,48 @@ export class UtilsController {
|
|
70
120
|
}
|
71
121
|
async setupMigrationDatabase() {
|
72
122
|
await this.init();
|
73
|
-
if (!this.config)
|
74
|
-
|
123
|
+
if (!this.config) {
|
124
|
+
console.log(chalk.red("Config not initialized"));
|
125
|
+
return;
|
126
|
+
}
|
75
127
|
await setupMigrationDatabase(this.config);
|
76
128
|
}
|
77
129
|
async ensureDatabaseConfigBucketsExist(databases = []) {
|
78
130
|
await this.init();
|
79
|
-
if (!this.storage)
|
80
|
-
|
81
|
-
|
82
|
-
|
131
|
+
if (!this.storage) {
|
132
|
+
console.log(chalk.red("Storage not initialized"));
|
133
|
+
return;
|
134
|
+
}
|
135
|
+
if (!this.config) {
|
136
|
+
console.log(chalk.red("Config not initialized"));
|
137
|
+
return;
|
138
|
+
}
|
83
139
|
await ensureDatabaseConfigBucketsExist(this.storage, this.config, databases);
|
84
140
|
}
|
85
141
|
async ensureDatabasesExist(databases) {
|
86
142
|
await this.init();
|
87
|
-
if (!this.config)
|
88
|
-
|
143
|
+
if (!this.config) {
|
144
|
+
console.log(chalk.red("Config not initialized"));
|
145
|
+
return;
|
146
|
+
}
|
89
147
|
await this.setupMigrationDatabase();
|
90
148
|
await this.ensureDatabaseConfigBucketsExist(databases);
|
91
149
|
await ensureDatabasesExist(this.config, databases);
|
92
150
|
}
|
93
151
|
async ensureCollectionsExist(database, collections) {
|
94
152
|
await this.init();
|
95
|
-
if (!this.config)
|
96
|
-
|
153
|
+
if (!this.config) {
|
154
|
+
console.log(chalk.red("Config not initialized"));
|
155
|
+
return;
|
156
|
+
}
|
97
157
|
await ensureCollectionsExist(this.config, database, collections);
|
98
158
|
}
|
99
159
|
async getDatabasesByIds(ids) {
|
100
160
|
await this.init();
|
101
|
-
if (!this.database)
|
102
|
-
|
161
|
+
if (!this.database) {
|
162
|
+
console.log(chalk.red("Database not initialized"));
|
163
|
+
return;
|
164
|
+
}
|
103
165
|
if (ids.length === 0)
|
104
166
|
return [];
|
105
167
|
const dbs = await this.database.list([
|
@@ -110,36 +172,50 @@ export class UtilsController {
|
|
110
172
|
}
|
111
173
|
async wipeOtherDatabases(databasesToKeep) {
|
112
174
|
await this.init();
|
113
|
-
if (!this.database)
|
114
|
-
|
175
|
+
if (!this.database) {
|
176
|
+
console.log(chalk.red("Database not initialized"));
|
177
|
+
return;
|
178
|
+
}
|
115
179
|
await wipeOtherDatabases(this.database, databasesToKeep);
|
116
180
|
}
|
117
181
|
async wipeUsers() {
|
118
182
|
await this.init();
|
119
|
-
if (!this.config || !this.database)
|
120
|
-
|
183
|
+
if (!this.config || !this.database) {
|
184
|
+
console.log(chalk.red("Config or database not initialized"));
|
185
|
+
return;
|
186
|
+
}
|
121
187
|
const usersController = new UsersController(this.config, this.database);
|
122
188
|
await usersController.wipeUsers();
|
123
189
|
}
|
124
190
|
async backupDatabase(database) {
|
125
191
|
await this.init();
|
126
|
-
if (!this.database || !this.storage || !this.config)
|
127
|
-
|
192
|
+
if (!this.database || !this.storage || !this.config) {
|
193
|
+
console.log(chalk.red("Database, storage, or config not initialized"));
|
194
|
+
return;
|
195
|
+
}
|
128
196
|
await backupDatabase(this.config, this.database, database.$id, this.storage);
|
129
197
|
}
|
130
198
|
async listAllFunctions() {
|
131
199
|
await this.init();
|
132
|
-
if (!this.appwriteServer)
|
133
|
-
|
200
|
+
if (!this.appwriteServer) {
|
201
|
+
console.log(chalk.red("Appwrite server not initialized"));
|
202
|
+
return [];
|
203
|
+
}
|
134
204
|
const { functions } = await listFunctions(this.appwriteServer, [
|
135
205
|
Query.limit(1000),
|
136
206
|
]);
|
137
207
|
return functions;
|
138
208
|
}
|
139
209
|
async findFunctionDirectories() {
|
210
|
+
if (!this.appwriteFolderPath) {
|
211
|
+
console.log(chalk.red("Failed to get appwriteFolderPath"));
|
212
|
+
return new Map();
|
213
|
+
}
|
140
214
|
const functionsDir = findFunctionsDir(this.appwriteFolderPath);
|
141
|
-
if (!functionsDir)
|
215
|
+
if (!functionsDir) {
|
216
|
+
console.log(chalk.red("Failed to find functions directory"));
|
142
217
|
return new Map();
|
218
|
+
}
|
143
219
|
const functionDirMap = new Map();
|
144
220
|
const entries = fs.readdirSync(functionsDir, { withFileTypes: true });
|
145
221
|
for (const entry of entries) {
|
@@ -158,19 +234,25 @@ export class UtilsController {
|
|
158
234
|
}
|
159
235
|
async deployFunction(functionName, functionPath, functionConfig) {
|
160
236
|
await this.init();
|
161
|
-
if (!this.appwriteServer)
|
162
|
-
|
237
|
+
if (!this.appwriteServer) {
|
238
|
+
console.log(chalk.red("Appwrite server not initialized"));
|
239
|
+
return;
|
240
|
+
}
|
163
241
|
if (!functionConfig) {
|
164
242
|
functionConfig = this.config?.functions?.find((f) => f.name === functionName);
|
165
243
|
}
|
166
|
-
if (!functionConfig)
|
167
|
-
|
244
|
+
if (!functionConfig) {
|
245
|
+
console.log(chalk.red(`Function ${functionName} not found in config`));
|
246
|
+
return;
|
247
|
+
}
|
168
248
|
await deployLocalFunction(this.appwriteServer, functionName, functionConfig, functionPath);
|
169
249
|
}
|
170
250
|
async syncFunctions() {
|
171
251
|
await this.init();
|
172
|
-
if (!this.appwriteServer)
|
173
|
-
|
252
|
+
if (!this.appwriteServer) {
|
253
|
+
console.log(chalk.red("Appwrite server not initialized"));
|
254
|
+
return;
|
255
|
+
}
|
174
256
|
const localFunctions = this.config?.functions || [];
|
175
257
|
const remoteFunctions = await listFunctions(this.appwriteServer, [
|
176
258
|
Query.limit(1000),
|
@@ -243,36 +325,62 @@ export class UtilsController {
|
|
243
325
|
}
|
244
326
|
async generateSchemas() {
|
245
327
|
await this.init();
|
246
|
-
if (!this.config)
|
247
|
-
|
328
|
+
if (!this.config) {
|
329
|
+
console.log(chalk.red("Config not initialized"));
|
330
|
+
return;
|
331
|
+
}
|
332
|
+
if (!this.appwriteFolderPath) {
|
333
|
+
console.log(chalk.red("Failed to get appwriteFolderPath"));
|
334
|
+
return;
|
335
|
+
}
|
248
336
|
await generateSchemas(this.config, this.appwriteFolderPath);
|
249
337
|
}
|
250
338
|
async importData(options = {}) {
|
251
339
|
await this.init();
|
252
|
-
if (!this.database)
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
if (!this.
|
257
|
-
|
340
|
+
if (!this.database) {
|
341
|
+
console.log(chalk.red("Database not initialized"));
|
342
|
+
return;
|
343
|
+
}
|
344
|
+
if (!this.storage) {
|
345
|
+
console.log(chalk.red("Storage not initialized"));
|
346
|
+
return;
|
347
|
+
}
|
348
|
+
if (!this.config) {
|
349
|
+
console.log(chalk.red("Config not initialized"));
|
350
|
+
return;
|
351
|
+
}
|
352
|
+
if (!this.appwriteFolderPath) {
|
353
|
+
console.log(chalk.red("Failed to get appwriteFolderPath"));
|
354
|
+
return;
|
355
|
+
}
|
258
356
|
const importDataActions = new ImportDataActions(this.database, this.storage, this.config, this.converterDefinitions, this.validityRuleDefinitions, this.afterImportActionsDefinitions);
|
259
357
|
const importController = new ImportController(this.config, this.database, this.storage, this.appwriteFolderPath, importDataActions, options, options.databases);
|
260
358
|
await importController.run(options.collections);
|
261
359
|
}
|
262
360
|
async synchronizeConfigurations(databases, config) {
|
263
361
|
await this.init();
|
264
|
-
if (!this.storage)
|
265
|
-
|
362
|
+
if (!this.storage) {
|
363
|
+
console.log(chalk.red("Storage not initialized"));
|
364
|
+
return;
|
365
|
+
}
|
266
366
|
const configToUse = config || this.config;
|
267
|
-
if (!configToUse)
|
268
|
-
|
367
|
+
if (!configToUse) {
|
368
|
+
console.log(chalk.red("Config not initialized"));
|
369
|
+
return;
|
370
|
+
}
|
371
|
+
if (!this.appwriteFolderPath) {
|
372
|
+
console.log(chalk.red("Failed to get appwriteFolderPath"));
|
373
|
+
return;
|
374
|
+
}
|
269
375
|
const appwriteToX = new AppwriteToX(configToUse, this.appwriteFolderPath, this.storage);
|
270
376
|
await appwriteToX.toSchemas(databases);
|
271
377
|
}
|
272
378
|
async syncDb(databases = [], collections = []) {
|
273
379
|
await this.init();
|
274
|
-
if (!this.database)
|
275
|
-
|
380
|
+
if (!this.database) {
|
381
|
+
console.log(chalk.red("Database not initialized"));
|
382
|
+
return;
|
383
|
+
}
|
276
384
|
if (databases.length === 0) {
|
277
385
|
const allDatabases = await fetchAllDatabases(this.database);
|
278
386
|
databases = allDatabases;
|
@@ -290,13 +398,15 @@ export class UtilsController {
|
|
290
398
|
let sourceDatabases = [];
|
291
399
|
let targetDatabases = [];
|
292
400
|
if (!sourceClient) {
|
293
|
-
|
401
|
+
console.log(chalk.red("Source database not initialized"));
|
402
|
+
return;
|
294
403
|
}
|
295
404
|
if (options.isRemote) {
|
296
405
|
if (!options.transferEndpoint ||
|
297
406
|
!options.transferProject ||
|
298
407
|
!options.transferKey) {
|
299
|
-
|
408
|
+
console.log(chalk.red("Remote transfer options are missing"));
|
409
|
+
return;
|
300
410
|
}
|
301
411
|
const remoteClient = getClient(options.transferEndpoint, options.transferProject, options.transferKey);
|
302
412
|
targetClient = new Databases(remoteClient);
|
@@ -312,7 +422,8 @@ export class UtilsController {
|
|
312
422
|
const fromDb = sourceDatabases.find((db) => db.$id === options.fromDb.$id);
|
313
423
|
const targetDb = targetDatabases.find((db) => db.$id === options.targetDb.$id);
|
314
424
|
if (!fromDb || !targetDb) {
|
315
|
-
|
425
|
+
console.log(chalk.red("Source or target database not found"));
|
426
|
+
return;
|
316
427
|
}
|
317
428
|
if (options.isRemote && targetClient) {
|
318
429
|
await transferDatabaseLocalToRemote(sourceClient, options.transferEndpoint, options.transferProject, options.transferKey, fromDb.$id, targetDb.$id);
|
@@ -326,7 +437,8 @@ export class UtilsController {
|
|
326
437
|
console.log(chalk.yellow("User transfer is only supported for remote transfers. Skipping..."));
|
327
438
|
}
|
328
439
|
else if (!this.appwriteServer) {
|
329
|
-
|
440
|
+
console.log(chalk.red("Appwrite server not initialized"));
|
441
|
+
return;
|
330
442
|
}
|
331
443
|
else {
|
332
444
|
console.log(chalk.blue("Starting user transfer..."));
|
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.
|
4
|
+
"version": "0.10.76",
|
5
5
|
"main": "src/main.ts",
|
6
6
|
"type": "module",
|
7
7
|
"repository": {
|
package/src/interactiveCLI.ts
CHANGED
@@ -159,9 +159,13 @@ export class InteractiveCLI {
|
|
159
159
|
}
|
160
160
|
}
|
161
161
|
|
162
|
-
private async initControllerIfNeeded(
|
162
|
+
private async initControllerIfNeeded(directConfig?: {
|
163
|
+
appwriteEndpoint: string;
|
164
|
+
appwriteProject: string;
|
165
|
+
appwriteKey: string;
|
166
|
+
}): Promise<void> {
|
163
167
|
if (!this.controller) {
|
164
|
-
this.controller = new UtilsController(this.currentDir);
|
168
|
+
this.controller = new UtilsController(this.currentDir, directConfig);
|
165
169
|
await this.controller.init();
|
166
170
|
}
|
167
171
|
}
|
@@ -522,7 +526,7 @@ export class InteractiveCLI {
|
|
522
526
|
functionConfig.dirPath,
|
523
527
|
// 2. Appwrite config folder/functions/name
|
524
528
|
join(
|
525
|
-
this.controller.getAppwriteFolderPath()
|
529
|
+
this.controller.getAppwriteFolderPath()!,
|
526
530
|
"functions",
|
527
531
|
functionNameLower
|
528
532
|
),
|
@@ -553,7 +557,7 @@ export class InteractiveCLI {
|
|
553
557
|
|
554
558
|
// Search in both appwrite config directory and current working directory
|
555
559
|
functionPath = await this.findFunctionInSubdirectories(
|
556
|
-
[this.controller.getAppwriteFolderPath()
|
560
|
+
[this.controller.getAppwriteFolderPath()!, process.cwd()],
|
557
561
|
functionNameLower
|
558
562
|
);
|
559
563
|
}
|
@@ -576,7 +580,7 @@ export class InteractiveCLI {
|
|
576
580
|
await downloadLatestFunctionDeployment(
|
577
581
|
this.controller.appwriteServer!,
|
578
582
|
functionConfig.$id,
|
579
|
-
join(this.controller.getAppwriteFolderPath()
|
583
|
+
join(this.controller.getAppwriteFolderPath()!, "functions")
|
580
584
|
);
|
581
585
|
console.log(
|
582
586
|
chalk.green(`✨ Function downloaded to ${downloadedPath}`)
|
@@ -1140,7 +1144,7 @@ export class InteractiveCLI {
|
|
1140
1144
|
if (hasLocal && hasRemote) {
|
1141
1145
|
// First try to find the function locally
|
1142
1146
|
let functionPath = join(
|
1143
|
-
this.controller!.getAppwriteFolderPath()
|
1147
|
+
this.controller!.getAppwriteFolderPath()!,
|
1144
1148
|
"functions",
|
1145
1149
|
func.name
|
1146
1150
|
);
|
@@ -1152,7 +1156,7 @@ export class InteractiveCLI {
|
|
1152
1156
|
)
|
1153
1157
|
);
|
1154
1158
|
const foundPath = await this.findFunctionInSubdirectories(
|
1155
|
-
[this.controller!.getAppwriteFolderPath()
|
1159
|
+
[this.controller!.getAppwriteFolderPath()!, process.cwd()],
|
1156
1160
|
func.name
|
1157
1161
|
);
|
1158
1162
|
|
@@ -1191,7 +1195,7 @@ export class InteractiveCLI {
|
|
1191
1195
|
await downloadLatestFunctionDeployment(
|
1192
1196
|
this.controller!.appwriteServer!,
|
1193
1197
|
func.$id,
|
1194
|
-
join(this.controller!.getAppwriteFolderPath()
|
1198
|
+
join(this.controller!.getAppwriteFolderPath()!, "functions")
|
1195
1199
|
);
|
1196
1200
|
} else if (preference === "config") {
|
1197
1201
|
const remoteFunction = await getFunction(
|
@@ -1236,14 +1240,14 @@ export class InteractiveCLI {
|
|
1236
1240
|
} else if (hasLocal) {
|
1237
1241
|
// Similar check for local-only functions
|
1238
1242
|
let functionPath = join(
|
1239
|
-
this.controller!.getAppwriteFolderPath()
|
1243
|
+
this.controller!.getAppwriteFolderPath()!,
|
1240
1244
|
"functions",
|
1241
1245
|
func.name
|
1242
1246
|
);
|
1243
1247
|
|
1244
1248
|
if (!fs.existsSync(functionPath)) {
|
1245
1249
|
const foundPath = await this.findFunctionInSubdirectories(
|
1246
|
-
[this.controller!.getAppwriteFolderPath()
|
1250
|
+
[this.controller!.getAppwriteFolderPath()!, process.cwd()],
|
1247
1251
|
func.name
|
1248
1252
|
);
|
1249
1253
|
|
@@ -1294,7 +1298,7 @@ export class InteractiveCLI {
|
|
1294
1298
|
await downloadLatestFunctionDeployment(
|
1295
1299
|
this.controller!.appwriteServer!,
|
1296
1300
|
func.$id,
|
1297
|
-
join(this.controller!.getAppwriteFolderPath()
|
1301
|
+
join(this.controller!.getAppwriteFolderPath()!, "functions")
|
1298
1302
|
);
|
1299
1303
|
} else if (action === "config") {
|
1300
1304
|
const remoteFunction = await getFunction(
|
@@ -1336,7 +1340,7 @@ export class InteractiveCLI {
|
|
1336
1340
|
// Update schemas after all changes
|
1337
1341
|
const schemaGenerator = new SchemaGenerator(
|
1338
1342
|
this.controller!.config!,
|
1339
|
-
this.controller!.getAppwriteFolderPath()
|
1343
|
+
this.controller!.getAppwriteFolderPath()!
|
1340
1344
|
);
|
1341
1345
|
schemaGenerator.updateConfig(this.controller!.config!);
|
1342
1346
|
}
|
package/src/main.ts
CHANGED
@@ -202,7 +202,15 @@ async function main() {
|
|
202
202
|
const cli = new InteractiveCLI(process.cwd());
|
203
203
|
await cli.run();
|
204
204
|
} else {
|
205
|
-
const
|
205
|
+
const directConfig =
|
206
|
+
argv.endpoint || argv.projectId || argv.apiKey
|
207
|
+
? {
|
208
|
+
appwriteEndpoint: argv.endpoint,
|
209
|
+
appwriteProject: argv.projectId,
|
210
|
+
appwriteKey: argv.apiKey,
|
211
|
+
}
|
212
|
+
: undefined;
|
213
|
+
const controller = new UtilsController(process.cwd(), directConfig);
|
206
214
|
await controller.init();
|
207
215
|
|
208
216
|
if (argv.setup) {
|
@@ -210,6 +218,11 @@ async function main() {
|
|
210
218
|
return;
|
211
219
|
}
|
212
220
|
|
221
|
+
if (!controller.config) {
|
222
|
+
console.log(chalk.red("No Appwrite connection found"));
|
223
|
+
return;
|
224
|
+
}
|
225
|
+
|
213
226
|
const parsedArgv = argv;
|
214
227
|
|
215
228
|
const options: SetupOptions = {
|
@@ -372,8 +385,13 @@ async function main() {
|
|
372
385
|
`Starting database transfer from ${parsedArgv.fromDbId} to ${parsedArgv.toDbId}`
|
373
386
|
)
|
374
387
|
);
|
375
|
-
fromDb = (
|
376
|
-
|
388
|
+
fromDb = (
|
389
|
+
await controller.getDatabasesByIds([parsedArgv.fromDbId])
|
390
|
+
)?.[0];
|
391
|
+
if (!fromDb) {
|
392
|
+
console.log(chalk.red("Source database not found"));
|
393
|
+
return;
|
394
|
+
}
|
377
395
|
if (isRemote) {
|
378
396
|
if (
|
379
397
|
!parsedArgv.remoteEndpoint ||
|
@@ -391,12 +409,21 @@ async function main() {
|
|
391
409
|
targetStorage = new Storage(remoteClient);
|
392
410
|
const remoteDbs = await fetchAllDatabases(targetDatabases);
|
393
411
|
toDb = remoteDbs.find((db) => db.$id === parsedArgv.toDbId);
|
412
|
+
if (!toDb) {
|
413
|
+
console.log(chalk.red("Target database not found"));
|
414
|
+
return;
|
415
|
+
}
|
394
416
|
} else {
|
395
|
-
toDb = (await controller.getDatabasesByIds([parsedArgv.toDbId]))[0];
|
417
|
+
toDb = (await controller.getDatabasesByIds([parsedArgv.toDbId]))?.[0];
|
418
|
+
if (!toDb) {
|
419
|
+
console.log(chalk.red("Target database not found"));
|
420
|
+
return;
|
421
|
+
}
|
396
422
|
}
|
397
423
|
|
398
424
|
if (!fromDb || !toDb) {
|
399
|
-
|
425
|
+
console.log(chalk.red("Source or target database not found"));
|
426
|
+
return;
|
400
427
|
}
|
401
428
|
}
|
402
429
|
|
@@ -308,7 +308,7 @@ export default appwriteConfig;
|
|
308
308
|
this.config.collections.forEach((collection) => {
|
309
309
|
const schemaString = this.createSchemaString(
|
310
310
|
collection.name,
|
311
|
-
collection.attributes
|
311
|
+
collection.attributes || []
|
312
312
|
);
|
313
313
|
const camelCaseName = toCamelCase(collection.name);
|
314
314
|
const schemaPath = path.join(
|
@@ -55,29 +55,35 @@ export class SchemaGenerator {
|
|
55
55
|
usersCollectionName: "${this.config.usersCollectionName}",
|
56
56
|
databases: ${JSON.stringify(this.config.databases)},
|
57
57
|
buckets: ${JSON.stringify(this.config.buckets)},
|
58
|
-
functions: ${JSON.stringify(
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
58
|
+
functions: ${JSON.stringify(
|
59
|
+
functions.map((func) => ({
|
60
|
+
functionId: func.$id || ulid(),
|
61
|
+
name: func.name,
|
62
|
+
runtime: func.runtime,
|
63
|
+
path: func.dirPath || `functions/${func.name}`,
|
64
|
+
entrypoint: func.entrypoint || "src/index.ts",
|
65
|
+
execute: func.execute,
|
66
|
+
events: func.events || [],
|
67
|
+
schedule: func.schedule || "",
|
68
|
+
timeout: func.timeout || 15,
|
69
|
+
enabled: func.enabled !== false,
|
70
|
+
logging: func.logging !== false,
|
71
|
+
commands: func.commands || "npm install",
|
72
|
+
scopes: func.scopes || [],
|
73
|
+
installationId: func.installationId,
|
74
|
+
providerRepositoryId: func.providerRepositoryId,
|
75
|
+
providerBranch: func.providerBranch,
|
76
|
+
providerSilentMode: func.providerSilentMode,
|
77
|
+
providerRootDirectory: func.providerRootDirectory,
|
78
|
+
specification: func.specification,
|
79
|
+
...(func.predeployCommands
|
80
|
+
? { predeployCommands: func.predeployCommands }
|
81
|
+
: {}),
|
82
|
+
...(func.deployDir ? { deployDir: func.deployDir } : {}),
|
83
|
+
})),
|
84
|
+
null,
|
85
|
+
2
|
86
|
+
)}
|
81
87
|
};
|
82
88
|
|
83
89
|
export default appwriteConfig;
|
@@ -114,7 +120,7 @@ export class SchemaGenerator {
|
|
114
120
|
.join(",\n ")}
|
115
121
|
],
|
116
122
|
attributes: [
|
117
|
-
${collection.attributes
|
123
|
+
${(collection.attributes || [])
|
118
124
|
.map((attr) => {
|
119
125
|
return `{ ${Object.entries(attr)
|
120
126
|
.map(([key, value]) => {
|
package/src/utilsController.ts
CHANGED
@@ -82,8 +82,8 @@ export interface SetupOptions {
|
|
82
82
|
}
|
83
83
|
|
84
84
|
export class UtilsController {
|
85
|
-
private appwriteFolderPath
|
86
|
-
private appwriteConfigPath
|
85
|
+
private appwriteFolderPath?: string;
|
86
|
+
private appwriteConfigPath?: string;
|
87
87
|
public config?: AppwriteConfig;
|
88
88
|
public appwriteServer?: Client;
|
89
89
|
public database?: Databases;
|
@@ -92,39 +92,101 @@ export class UtilsController {
|
|
92
92
|
public validityRuleDefinitions: ValidationRules = validationRules;
|
93
93
|
public afterImportActionsDefinitions: AfterImportActions = afterImportActions;
|
94
94
|
|
95
|
-
constructor(
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
95
|
+
constructor(
|
96
|
+
currentUserDir: string,
|
97
|
+
directConfig?: {
|
98
|
+
appwriteEndpoint?: string;
|
99
|
+
appwriteProject?: string;
|
100
|
+
appwriteKey?: string;
|
100
101
|
}
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
102
|
+
) {
|
103
|
+
const basePath = currentUserDir;
|
104
|
+
|
105
|
+
if (directConfig) {
|
106
|
+
let hasErrors = false;
|
107
|
+
if (!directConfig.appwriteEndpoint) {
|
108
|
+
console.log(chalk.red("Appwrite endpoint is required"));
|
109
|
+
hasErrors = true;
|
110
|
+
}
|
111
|
+
if (!directConfig.appwriteProject) {
|
112
|
+
console.log(chalk.red("Appwrite project is required"));
|
113
|
+
hasErrors = true;
|
114
|
+
}
|
115
|
+
if (!directConfig.appwriteKey) {
|
116
|
+
console.log(chalk.red("Appwrite key is required"));
|
117
|
+
hasErrors = true;
|
118
|
+
}
|
119
|
+
if (!hasErrors) {
|
120
|
+
// Only set config if we have all required fields
|
121
|
+
this.appwriteFolderPath = basePath;
|
122
|
+
this.config = {
|
123
|
+
appwriteEndpoint: directConfig.appwriteEndpoint!,
|
124
|
+
appwriteProject: directConfig.appwriteProject!,
|
125
|
+
appwriteKey: directConfig.appwriteKey!,
|
126
|
+
enableBackups: false,
|
127
|
+
backupInterval: 0,
|
128
|
+
backupRetention: 0,
|
129
|
+
enableBackupCleanup: false,
|
130
|
+
enableMockData: false,
|
131
|
+
documentBucketId: "",
|
132
|
+
usersCollectionName: "",
|
133
|
+
databases: [],
|
134
|
+
buckets: [],
|
135
|
+
functions: [],
|
136
|
+
};
|
137
|
+
}
|
138
|
+
} else {
|
139
|
+
// Try to find config file
|
140
|
+
const appwriteConfigFound = findAppwriteConfig(basePath);
|
141
|
+
if (!appwriteConfigFound) {
|
142
|
+
console.log(
|
143
|
+
chalk.yellow(
|
144
|
+
"No appwriteConfig.ts found and no direct configuration provided"
|
145
|
+
)
|
146
|
+
);
|
147
|
+
return;
|
148
|
+
}
|
149
|
+
this.appwriteConfigPath = appwriteConfigFound;
|
150
|
+
this.appwriteFolderPath = path.dirname(appwriteConfigFound);
|
105
151
|
}
|
106
152
|
}
|
107
153
|
|
108
154
|
async init() {
|
109
155
|
if (!this.config) {
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
156
|
+
if (this.appwriteFolderPath && this.appwriteConfigPath) {
|
157
|
+
console.log("Loading config from file...");
|
158
|
+
this.config = await loadConfig(this.appwriteFolderPath);
|
159
|
+
if (!this.config) {
|
160
|
+
console.log(chalk.red("Failed to load config from file"));
|
161
|
+
return;
|
162
|
+
}
|
163
|
+
} else {
|
164
|
+
console.log(chalk.red("No configuration available"));
|
165
|
+
return;
|
114
166
|
}
|
115
|
-
this.appwriteServer = new Client();
|
116
|
-
this.appwriteServer
|
117
|
-
.setEndpoint(this.config.appwriteEndpoint)
|
118
|
-
.setProject(this.config.appwriteProject)
|
119
|
-
.setKey(this.config.appwriteKey);
|
120
|
-
this.database = new Databases(this.appwriteServer);
|
121
|
-
this.storage = new Storage(this.appwriteServer);
|
122
|
-
this.config.appwriteClient = this.appwriteServer;
|
123
167
|
}
|
168
|
+
|
169
|
+
this.appwriteServer = new Client();
|
170
|
+
this.appwriteServer
|
171
|
+
.setEndpoint(this.config.appwriteEndpoint)
|
172
|
+
.setProject(this.config.appwriteProject)
|
173
|
+
.setKey(this.config.appwriteKey);
|
174
|
+
|
175
|
+
this.database = new Databases(this.appwriteServer);
|
176
|
+
this.storage = new Storage(this.appwriteServer);
|
177
|
+
this.config.appwriteClient = this.appwriteServer;
|
124
178
|
}
|
125
179
|
|
126
180
|
async reloadConfig() {
|
181
|
+
if (!this.appwriteFolderPath) {
|
182
|
+
console.log(chalk.red("Failed to get appwriteFolderPath"));
|
183
|
+
return;
|
184
|
+
}
|
127
185
|
this.config = await loadConfig(this.appwriteFolderPath);
|
186
|
+
if (!this.config) {
|
187
|
+
console.log(chalk.red("Failed to load config"));
|
188
|
+
return;
|
189
|
+
}
|
128
190
|
this.appwriteServer = new Client();
|
129
191
|
this.appwriteServer
|
130
192
|
.setEndpoint(this.config.appwriteEndpoint)
|
@@ -137,14 +199,23 @@ export class UtilsController {
|
|
137
199
|
|
138
200
|
async setupMigrationDatabase() {
|
139
201
|
await this.init();
|
140
|
-
if (!this.config)
|
202
|
+
if (!this.config) {
|
203
|
+
console.log(chalk.red("Config not initialized"));
|
204
|
+
return;
|
205
|
+
}
|
141
206
|
await setupMigrationDatabase(this.config);
|
142
207
|
}
|
143
208
|
|
144
209
|
async ensureDatabaseConfigBucketsExist(databases: Models.Database[] = []) {
|
145
210
|
await this.init();
|
146
|
-
if (!this.storage)
|
147
|
-
|
211
|
+
if (!this.storage) {
|
212
|
+
console.log(chalk.red("Storage not initialized"));
|
213
|
+
return;
|
214
|
+
}
|
215
|
+
if (!this.config) {
|
216
|
+
console.log(chalk.red("Config not initialized"));
|
217
|
+
return;
|
218
|
+
}
|
148
219
|
await ensureDatabaseConfigBucketsExist(
|
149
220
|
this.storage,
|
150
221
|
this.config,
|
@@ -154,7 +225,10 @@ export class UtilsController {
|
|
154
225
|
|
155
226
|
async ensureDatabasesExist(databases?: Models.Database[]) {
|
156
227
|
await this.init();
|
157
|
-
if (!this.config)
|
228
|
+
if (!this.config) {
|
229
|
+
console.log(chalk.red("Config not initialized"));
|
230
|
+
return;
|
231
|
+
}
|
158
232
|
await this.setupMigrationDatabase();
|
159
233
|
await this.ensureDatabaseConfigBucketsExist(databases);
|
160
234
|
await ensureDatabasesExist(this.config, databases);
|
@@ -165,13 +239,19 @@ export class UtilsController {
|
|
165
239
|
collections?: Models.Collection[]
|
166
240
|
) {
|
167
241
|
await this.init();
|
168
|
-
if (!this.config)
|
242
|
+
if (!this.config) {
|
243
|
+
console.log(chalk.red("Config not initialized"));
|
244
|
+
return;
|
245
|
+
}
|
169
246
|
await ensureCollectionsExist(this.config, database, collections);
|
170
247
|
}
|
171
248
|
|
172
249
|
async getDatabasesByIds(ids: string[]) {
|
173
250
|
await this.init();
|
174
|
-
if (!this.database)
|
251
|
+
if (!this.database) {
|
252
|
+
console.log(chalk.red("Database not initialized"));
|
253
|
+
return;
|
254
|
+
}
|
175
255
|
if (ids.length === 0) return [];
|
176
256
|
const dbs = await this.database.list([
|
177
257
|
Query.limit(500),
|
@@ -182,22 +262,29 @@ export class UtilsController {
|
|
182
262
|
|
183
263
|
async wipeOtherDatabases(databasesToKeep: Models.Database[]) {
|
184
264
|
await this.init();
|
185
|
-
if (!this.database)
|
265
|
+
if (!this.database) {
|
266
|
+
console.log(chalk.red("Database not initialized"));
|
267
|
+
return;
|
268
|
+
}
|
186
269
|
await wipeOtherDatabases(this.database, databasesToKeep);
|
187
270
|
}
|
188
271
|
|
189
272
|
async wipeUsers() {
|
190
273
|
await this.init();
|
191
|
-
if (!this.config || !this.database)
|
192
|
-
|
274
|
+
if (!this.config || !this.database) {
|
275
|
+
console.log(chalk.red("Config or database not initialized"));
|
276
|
+
return;
|
277
|
+
}
|
193
278
|
const usersController = new UsersController(this.config, this.database);
|
194
279
|
await usersController.wipeUsers();
|
195
280
|
}
|
196
281
|
|
197
282
|
async backupDatabase(database: Models.Database) {
|
198
283
|
await this.init();
|
199
|
-
if (!this.database || !this.storage || !this.config)
|
200
|
-
|
284
|
+
if (!this.database || !this.storage || !this.config) {
|
285
|
+
console.log(chalk.red("Database, storage, or config not initialized"));
|
286
|
+
return;
|
287
|
+
}
|
201
288
|
await backupDatabase(
|
202
289
|
this.config,
|
203
290
|
this.database,
|
@@ -208,8 +295,10 @@ export class UtilsController {
|
|
208
295
|
|
209
296
|
async listAllFunctions() {
|
210
297
|
await this.init();
|
211
|
-
if (!this.appwriteServer)
|
212
|
-
|
298
|
+
if (!this.appwriteServer) {
|
299
|
+
console.log(chalk.red("Appwrite server not initialized"));
|
300
|
+
return [];
|
301
|
+
}
|
213
302
|
const { functions } = await listFunctions(this.appwriteServer, [
|
214
303
|
Query.limit(1000),
|
215
304
|
]);
|
@@ -217,8 +306,15 @@ export class UtilsController {
|
|
217
306
|
}
|
218
307
|
|
219
308
|
async findFunctionDirectories() {
|
309
|
+
if (!this.appwriteFolderPath) {
|
310
|
+
console.log(chalk.red("Failed to get appwriteFolderPath"));
|
311
|
+
return new Map();
|
312
|
+
}
|
220
313
|
const functionsDir = findFunctionsDir(this.appwriteFolderPath);
|
221
|
-
if (!functionsDir)
|
314
|
+
if (!functionsDir) {
|
315
|
+
console.log(chalk.red("Failed to find functions directory"));
|
316
|
+
return new Map();
|
317
|
+
}
|
222
318
|
|
223
319
|
const functionDirMap = new Map<string, string>();
|
224
320
|
const entries = fs.readdirSync(functionsDir, { withFileTypes: true });
|
@@ -246,16 +342,20 @@ export class UtilsController {
|
|
246
342
|
functionConfig?: AppwriteFunction
|
247
343
|
) {
|
248
344
|
await this.init();
|
249
|
-
if (!this.appwriteServer)
|
250
|
-
|
345
|
+
if (!this.appwriteServer) {
|
346
|
+
console.log(chalk.red("Appwrite server not initialized"));
|
347
|
+
return;
|
348
|
+
}
|
251
349
|
|
252
350
|
if (!functionConfig) {
|
253
351
|
functionConfig = this.config?.functions?.find(
|
254
352
|
(f) => f.name === functionName
|
255
353
|
);
|
256
354
|
}
|
257
|
-
if (!functionConfig)
|
258
|
-
|
355
|
+
if (!functionConfig) {
|
356
|
+
console.log(chalk.red(`Function ${functionName} not found in config`));
|
357
|
+
return;
|
358
|
+
}
|
259
359
|
|
260
360
|
await deployLocalFunction(
|
261
361
|
this.appwriteServer,
|
@@ -267,8 +367,10 @@ export class UtilsController {
|
|
267
367
|
|
268
368
|
async syncFunctions() {
|
269
369
|
await this.init();
|
270
|
-
if (!this.appwriteServer)
|
271
|
-
|
370
|
+
if (!this.appwriteServer) {
|
371
|
+
console.log(chalk.red("Appwrite server not initialized"));
|
372
|
+
return;
|
373
|
+
}
|
272
374
|
|
273
375
|
const localFunctions = this.config?.functions || [];
|
274
376
|
const remoteFunctions = await listFunctions(this.appwriteServer, [
|
@@ -365,15 +467,35 @@ export class UtilsController {
|
|
365
467
|
|
366
468
|
async generateSchemas() {
|
367
469
|
await this.init();
|
368
|
-
if (!this.config)
|
470
|
+
if (!this.config) {
|
471
|
+
console.log(chalk.red("Config not initialized"));
|
472
|
+
return;
|
473
|
+
}
|
474
|
+
if (!this.appwriteFolderPath) {
|
475
|
+
console.log(chalk.red("Failed to get appwriteFolderPath"));
|
476
|
+
return;
|
477
|
+
}
|
369
478
|
await generateSchemas(this.config, this.appwriteFolderPath);
|
370
479
|
}
|
371
480
|
|
372
481
|
async importData(options: SetupOptions = {}) {
|
373
482
|
await this.init();
|
374
|
-
if (!this.database)
|
375
|
-
|
376
|
-
|
483
|
+
if (!this.database) {
|
484
|
+
console.log(chalk.red("Database not initialized"));
|
485
|
+
return;
|
486
|
+
}
|
487
|
+
if (!this.storage) {
|
488
|
+
console.log(chalk.red("Storage not initialized"));
|
489
|
+
return;
|
490
|
+
}
|
491
|
+
if (!this.config) {
|
492
|
+
console.log(chalk.red("Config not initialized"));
|
493
|
+
return;
|
494
|
+
}
|
495
|
+
if (!this.appwriteFolderPath) {
|
496
|
+
console.log(chalk.red("Failed to get appwriteFolderPath"));
|
497
|
+
return;
|
498
|
+
}
|
377
499
|
|
378
500
|
const importDataActions = new ImportDataActions(
|
379
501
|
this.database,
|
@@ -401,9 +523,19 @@ export class UtilsController {
|
|
401
523
|
config?: AppwriteConfig
|
402
524
|
) {
|
403
525
|
await this.init();
|
404
|
-
if (!this.storage)
|
526
|
+
if (!this.storage) {
|
527
|
+
console.log(chalk.red("Storage not initialized"));
|
528
|
+
return;
|
529
|
+
}
|
405
530
|
const configToUse = config || this.config;
|
406
|
-
if (!configToUse)
|
531
|
+
if (!configToUse) {
|
532
|
+
console.log(chalk.red("Config not initialized"));
|
533
|
+
return;
|
534
|
+
}
|
535
|
+
if (!this.appwriteFolderPath) {
|
536
|
+
console.log(chalk.red("Failed to get appwriteFolderPath"));
|
537
|
+
return;
|
538
|
+
}
|
407
539
|
const appwriteToX = new AppwriteToX(
|
408
540
|
configToUse,
|
409
541
|
this.appwriteFolderPath,
|
@@ -417,7 +549,10 @@ export class UtilsController {
|
|
417
549
|
collections: Models.Collection[] = []
|
418
550
|
) {
|
419
551
|
await this.init();
|
420
|
-
if (!this.database)
|
552
|
+
if (!this.database) {
|
553
|
+
console.log(chalk.red("Database not initialized"));
|
554
|
+
return;
|
555
|
+
}
|
421
556
|
if (databases.length === 0) {
|
422
557
|
const allDatabases = await fetchAllDatabases(this.database);
|
423
558
|
databases = allDatabases;
|
@@ -438,7 +573,8 @@ export class UtilsController {
|
|
438
573
|
let targetDatabases: Models.Database[] = [];
|
439
574
|
|
440
575
|
if (!sourceClient) {
|
441
|
-
|
576
|
+
console.log(chalk.red("Source database not initialized"));
|
577
|
+
return;
|
442
578
|
}
|
443
579
|
|
444
580
|
if (options.isRemote) {
|
@@ -447,7 +583,8 @@ export class UtilsController {
|
|
447
583
|
!options.transferProject ||
|
448
584
|
!options.transferKey
|
449
585
|
) {
|
450
|
-
|
586
|
+
console.log(chalk.red("Remote transfer options are missing"));
|
587
|
+
return;
|
451
588
|
}
|
452
589
|
|
453
590
|
const remoteClient = getClient(
|
@@ -474,7 +611,8 @@ export class UtilsController {
|
|
474
611
|
);
|
475
612
|
|
476
613
|
if (!fromDb || !targetDb) {
|
477
|
-
|
614
|
+
console.log(chalk.red("Source or target database not found"));
|
615
|
+
return;
|
478
616
|
}
|
479
617
|
|
480
618
|
if (options.isRemote && targetClient) {
|
@@ -503,7 +641,8 @@ export class UtilsController {
|
|
503
641
|
)
|
504
642
|
);
|
505
643
|
} else if (!this.appwriteServer) {
|
506
|
-
|
644
|
+
console.log(chalk.red("Appwrite server not initialized"));
|
645
|
+
return;
|
507
646
|
} else {
|
508
647
|
console.log(chalk.blue("Starting user transfer..."));
|
509
648
|
const localUsers = new Users(this.appwriteServer);
|