appwrite-utils-cli 1.0.5 → 1.0.6

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 CHANGED
@@ -23,6 +23,7 @@
23
23
  ### Development Tools
24
24
  - **Database Migrations**: Full migration control with progress tracking and operation summaries
25
25
  - **Schema Generation**: Generate TypeScript and JSON schemas from database configurations
26
+ - **Constants Generation**: Generate cross-language constants files (TypeScript, Python, PHP, Dart, JSON, Env) for database, collection, bucket, and function IDs
26
27
  - **Data Transfer**: Transfer data between databases, collections, and instances with real-time progress
27
28
  - **Configuration Sync**: Bidirectional synchronization between local YAML configs and Appwrite projects
28
29
  - **Function Management**: Deploy and manage Appwrite Functions with specification updates
@@ -218,8 +219,53 @@ Available options:
218
219
  - `--functionId`: Function ID to update
219
220
  - `--specification`: New function specification (s-0.5vcpu-512mb to s-8vcpu-8gb)
220
221
 
222
+ ### Constants Generation
223
+ - `--generateConstants` / `--constants`: Generate cross-language constants files with database, collection, bucket, and function IDs
224
+ - `--constantsLanguages`: Comma-separated list of languages for constants generation (default: typescript)
225
+ - Available languages: `typescript`, `javascript`, `python`, `php`, `dart`, `json`, `env`
226
+ - `--constantsOutput`: Output directory for generated constants files (default: config-folder/constants)
227
+
221
228
  ## Examples
222
229
 
230
+ ### Generate Constants
231
+
232
+ Generate cross-language constants files for all your Appwrite resource IDs:
233
+
234
+ ```bash
235
+ # Generate TypeScript constants (default)
236
+ npx appwrite-utils-cli appwrite-migrate --generateConstants
237
+
238
+ # Generate multiple language formats
239
+ npx appwrite-utils-cli appwrite-migrate --generateConstants --constantsLanguages="typescript,python,php,json"
240
+
241
+ # Generate all available formats
242
+ npx appwrite-utils-cli appwrite-migrate --generateConstants --constantsLanguages="typescript,javascript,python,php,dart,json,env"
243
+
244
+ # Generate with custom output directory
245
+ npx appwrite-utils-cli appwrite-migrate --generateConstants --constantsOutput="./my-constants"
246
+ ```
247
+
248
+ This generates constants files in your configuration directory (e.g., `.appwrite/constants/`) containing:
249
+ - Database IDs
250
+ - Collection IDs
251
+ - Bucket IDs
252
+ - Function IDs
253
+
254
+ **Example TypeScript output:**
255
+ ```typescript
256
+ export const DATABASE_IDS = {
257
+ MAIN_DATABASE: "main"
258
+ } as const;
259
+
260
+ export const COLLECTION_IDS = {
261
+ USERS: "01JYDBQTB5W8SCBAYB654CCADQ",
262
+ POSTS: "01JYDBQTB5W8SCBAYB654POSTS"
263
+ } as const;
264
+
265
+ // Type helpers and utility arrays included
266
+ export type DatabaseId = typeof DATABASE_IDS[keyof typeof DATABASE_IDS];
267
+ ```
268
+
223
269
  ### Transfer Databases
224
270
 
225
271
  Transfer databases within the same project or from a local to a remote project:
@@ -281,6 +327,54 @@ This updated CLI ensures that developers have robust tools at their fingertips t
281
327
 
282
328
  ## Changelog
283
329
 
330
+ ### 1.0.6 - Cross-Language Constants Generation
331
+
332
+ **🚀 Enhanced Developer Experience with Multi-Language Constants**
333
+
334
+ #### Constants Generation System
335
+ - **Cross-Language Support**: Generate constants in 7 languages for seamless multi-platform development
336
+ - **TypeScript**: Type-safe constants with `as const` and helper types
337
+ - **JavaScript**: ES6 modules with utility arrays
338
+ - **Python**: Class-based constants with snake_case dictionaries
339
+ - **PHP**: Static class methods and associative arrays
340
+ - **Dart**: Maps with individual getter methods (camelCase)
341
+ - **JSON**: Structured data with metadata for cross-platform integration
342
+ - **Environment Variables**: Prefixed environment variables for deployment
343
+ - **Smart Directory Structure**: Constants generated in `{config-folder}/constants/` by default
344
+ - **CLI Integration**: Both command-line and interactive mode support
345
+ - **Custom Output**: Support for custom output directories when needed
346
+
347
+ #### Resource ID Extraction
348
+ - **Database IDs**: Extract all configured database identifiers
349
+ - **Collection IDs**: Generate constants for all collection ULIDs/names
350
+ - **Bucket IDs**: Include storage bucket identifiers
351
+ - **Function IDs**: Support for Appwrite Function identifiers
352
+ - **Naming Conventions**: Language-appropriate naming (UPPER_CASE, camelCase, snake_case)
353
+
354
+ #### Developer Experience Improvements
355
+ - **Interactive Mode**: Checkbox selection for languages with smart defaults
356
+ - **CLI Commands**: Simple `--generateConstants` with language and output options
357
+ - **Type Safety**: Full TypeScript support with generated types and helpers
358
+ - **Cross-Platform Compatibility**: Enable seamless development across different tech stacks
359
+
360
+ #### Usage Examples
361
+ ```bash
362
+ # Default TypeScript generation
363
+ npx appwrite-utils-cli appwrite-migrate --generateConstants
364
+
365
+ # Multi-language generation
366
+ npx appwrite-utils-cli appwrite-migrate --generateConstants --constantsLanguages="typescript,python,php,json"
367
+
368
+ # All formats with custom output
369
+ npx appwrite-utils-cli appwrite-migrate --generateConstants --constantsLanguages="typescript,javascript,python,php,dart,json,env" --constantsOutput="./constants"
370
+ ```
371
+
372
+ **Migration Benefits**:
373
+ - Eliminates hardcoded resource IDs across codebases
374
+ - Enables type-safe resource access in TypeScript projects
375
+ - Supports multi-language development workflows
376
+ - Maintains constants alongside configuration for easy maintenance
377
+
284
378
  ### 1.0.1 - Function Templates & Attribute Type Improvements
285
379
 
286
380
  **🚀 Enhanced Function Management & Type System Fixes**
@@ -24,6 +24,7 @@ export declare class InteractiveCLI {
24
24
  private wipeDatabase;
25
25
  private wipeCollections;
26
26
  private generateSchemas;
27
+ private generateConstants;
27
28
  private importData;
28
29
  private transferData;
29
30
  private getLocalCollections;
@@ -13,6 +13,7 @@ import { DateTime } from "luxon";
13
13
  import { createFunctionTemplate, deleteFunction, downloadLatestFunctionDeployment, getFunction, listFunctions, listSpecifications, } from "./functions/methods.js";
14
14
  import { deployLocalFunction } from "./functions/deployments.js";
15
15
  import { join } from "node:path";
16
+ import path from "path";
16
17
  import fs from "node:fs";
17
18
  import { SchemaGenerator } from "./shared/schemaGenerator.js";
18
19
  import { ConfirmationDialogs } from "./shared/confirmationDialogs.js";
@@ -36,6 +37,7 @@ var CHOICES;
36
37
  CHOICES["WIPE_DATABASE"] = "Wipe database";
37
38
  CHOICES["WIPE_COLLECTIONS"] = "Wipe collections";
38
39
  CHOICES["GENERATE_SCHEMAS"] = "Generate schemas";
40
+ CHOICES["GENERATE_CONSTANTS"] = "\uD83D\uDCCB Generate cross-language constants (TypeScript, Python, PHP, Dart, etc.)";
39
41
  CHOICES["IMPORT_DATA"] = "Import data";
40
42
  CHOICES["RELOAD_CONFIG"] = "Reload configuration files";
41
43
  CHOICES["UPDATE_FUNCTION_SPEC"] = "Update function specifications";
@@ -123,6 +125,10 @@ export class InteractiveCLI {
123
125
  await this.initControllerIfNeeded();
124
126
  await this.generateSchemas();
125
127
  break;
128
+ case CHOICES.GENERATE_CONSTANTS:
129
+ await this.initControllerIfNeeded();
130
+ await this.generateConstants();
131
+ break;
126
132
  case CHOICES.IMPORT_DATA:
127
133
  await this.initControllerIfNeeded();
128
134
  await this.importData();
@@ -1167,6 +1173,66 @@ export class InteractiveCLI {
1167
1173
  schemaGenerator.generateSchemas({ format: schemaType, verbose: true });
1168
1174
  MessageFormatter.success("Schema generation completed", { prefix: "Schemas" });
1169
1175
  }
1176
+ async generateConstants() {
1177
+ console.log(chalk.yellow("Generating cross-language constants..."));
1178
+ if (!this.controller?.config) {
1179
+ MessageFormatter.error("No configuration found", undefined, { prefix: "Constants" });
1180
+ return;
1181
+ }
1182
+ // Prompt for languages
1183
+ const { languages } = await inquirer.prompt([
1184
+ {
1185
+ type: "checkbox",
1186
+ name: "languages",
1187
+ message: "Select languages for constants generation:",
1188
+ choices: [
1189
+ { name: "TypeScript", value: "typescript", checked: true },
1190
+ { name: "JavaScript", value: "javascript" },
1191
+ { name: "Python", value: "python" },
1192
+ { name: "PHP", value: "php" },
1193
+ { name: "Dart", value: "dart" },
1194
+ { name: "JSON", value: "json" },
1195
+ { name: "Environment Variables", value: "env" },
1196
+ ],
1197
+ validate: (input) => {
1198
+ if (input.length === 0) {
1199
+ return "Please select at least one language";
1200
+ }
1201
+ return true;
1202
+ },
1203
+ },
1204
+ ]);
1205
+ // Determine default output directory based on config location
1206
+ const configPath = this.controller.getAppwriteFolderPath();
1207
+ const defaultOutputDir = configPath
1208
+ ? path.join(configPath, "constants")
1209
+ : path.join(process.cwd(), "constants");
1210
+ // Prompt for output directory
1211
+ const { outputDir } = await inquirer.prompt([
1212
+ {
1213
+ type: "input",
1214
+ name: "outputDir",
1215
+ message: "Output directory for constants files:",
1216
+ default: defaultOutputDir,
1217
+ validate: (input) => {
1218
+ if (!input.trim()) {
1219
+ return "Output directory cannot be empty";
1220
+ }
1221
+ return true;
1222
+ },
1223
+ },
1224
+ ]);
1225
+ try {
1226
+ const { ConstantsGenerator } = await import("./utils/constantsGenerator.js");
1227
+ const generator = new ConstantsGenerator(this.controller.config);
1228
+ MessageFormatter.info(`Generating constants for: ${languages.join(", ")}`, { prefix: "Constants" });
1229
+ await generator.generateFiles(languages, outputDir);
1230
+ MessageFormatter.success(`Constants generated in ${outputDir}`, { prefix: "Constants" });
1231
+ }
1232
+ catch (error) {
1233
+ MessageFormatter.error("Failed to generate constants", error instanceof Error ? error : new Error(String(error)), { prefix: "Constants" });
1234
+ }
1235
+ }
1170
1236
  async importData() {
1171
1237
  console.log(chalk.yellow("Importing data..."));
1172
1238
  const { doBackup } = await inquirer.prompt([
package/dist/main.js CHANGED
@@ -13,6 +13,7 @@ import chalk from "chalk";
13
13
  import { listSpecifications } from "./functions/methods.js";
14
14
  import { MessageFormatter } from "./shared/messageFormatter.js";
15
15
  import { ConfirmationDialogs } from "./shared/confirmationDialogs.js";
16
+ import path from "path";
16
17
  const argv = yargs(hideBin(process.argv))
17
18
  .option("config", {
18
19
  type: "string",
@@ -158,6 +159,21 @@ const argv = yargs(hideBin(process.argv))
158
159
  alias: ["migrate"],
159
160
  type: "boolean",
160
161
  description: "Migrate appwriteConfig.ts to .appwrite structure with YAML configuration",
162
+ })
163
+ .option("generateConstants", {
164
+ alias: ["constants"],
165
+ type: "boolean",
166
+ description: "Generate cross-language constants file with database, collection, bucket, and function IDs",
167
+ })
168
+ .option("constantsLanguages", {
169
+ type: "string",
170
+ description: "Comma-separated list of languages for constants (typescript,javascript,python,php,dart,json,env)",
171
+ default: "typescript",
172
+ })
173
+ .option("constantsOutput", {
174
+ type: "string",
175
+ description: "Output directory for generated constants files (default: config-folder/constants)",
176
+ default: "auto",
161
177
  })
162
178
  .parse();
163
179
  async function main() {
@@ -186,6 +202,33 @@ async function main() {
186
202
  await migrateConfig(process.cwd());
187
203
  return;
188
204
  }
205
+ if (argv.generateConstants) {
206
+ const { ConstantsGenerator } = await import("./utils/constantsGenerator.js");
207
+ if (!controller.config) {
208
+ MessageFormatter.error("No Appwrite configuration found", undefined, { prefix: "Constants" });
209
+ return;
210
+ }
211
+ const languages = argv.constantsLanguages.split(",").map(l => l.trim());
212
+ // Determine output directory - use config folder/constants by default, or custom path if specified
213
+ let outputDir;
214
+ if (argv.constantsOutput === "auto") {
215
+ // Default case: use config directory + constants, fallback to current directory
216
+ const configPath = controller.getAppwriteFolderPath();
217
+ outputDir = configPath
218
+ ? path.join(configPath, "constants")
219
+ : path.join(process.cwd(), "constants");
220
+ }
221
+ else {
222
+ // Custom output directory specified
223
+ outputDir = argv.constantsOutput;
224
+ }
225
+ MessageFormatter.info(`Generating constants for languages: ${languages.join(", ")}`, { prefix: "Constants" });
226
+ const generator = new ConstantsGenerator(controller.config);
227
+ await generator.generateFiles(languages, outputDir);
228
+ operationStats.generatedConstants = languages.length;
229
+ MessageFormatter.success(`Constants generated in ${outputDir}`, { prefix: "Constants" });
230
+ return;
231
+ }
189
232
  if (!controller.config) {
190
233
  MessageFormatter.error("No Appwrite connection found", undefined, { prefix: "CLI" });
191
234
  return;
@@ -0,0 +1,19 @@
1
+ import { type AppwriteConfig } from "appwrite-utils";
2
+ export type SupportedLanguage = "typescript" | "javascript" | "python" | "php" | "dart" | "json" | "env";
3
+ export declare class ConstantsGenerator {
4
+ private config;
5
+ private constants;
6
+ constructor(config: AppwriteConfig);
7
+ private extractConstants;
8
+ private toConstantName;
9
+ private toCamelCase;
10
+ private toSnakeCase;
11
+ generateTypeScript(): string;
12
+ generateJavaScript(): string;
13
+ generatePython(): string;
14
+ generatePHP(): string;
15
+ generateDart(): string;
16
+ generateJSON(): string;
17
+ generateEnv(): string;
18
+ generateFiles(languages: SupportedLanguage[], outputDir: string): Promise<void>;
19
+ }
@@ -0,0 +1,309 @@
1
+ import fs from "fs/promises";
2
+ import path from "path";
3
+ import {} from "appwrite-utils";
4
+ import { MessageFormatter } from "../shared/messageFormatter.js";
5
+ export class ConstantsGenerator {
6
+ config;
7
+ constants;
8
+ constructor(config) {
9
+ this.config = config;
10
+ this.constants = this.extractConstants();
11
+ }
12
+ extractConstants() {
13
+ const constants = {
14
+ databases: {},
15
+ collections: {},
16
+ buckets: {},
17
+ functions: {}
18
+ };
19
+ // Extract database IDs
20
+ this.config.databases?.forEach(db => {
21
+ if (db.$id) {
22
+ const key = this.toConstantName(db.name || db.$id);
23
+ constants.databases[key] = db.$id;
24
+ }
25
+ });
26
+ // Extract collection IDs
27
+ this.config.collections?.forEach(collection => {
28
+ if (collection.$id) {
29
+ const key = this.toConstantName(collection.name || collection.$id);
30
+ constants.collections[key] = collection.$id;
31
+ }
32
+ });
33
+ // Extract bucket IDs
34
+ this.config.buckets?.forEach(bucket => {
35
+ if (bucket.$id) {
36
+ const key = this.toConstantName(bucket.name || bucket.$id);
37
+ constants.buckets[key] = bucket.$id;
38
+ }
39
+ });
40
+ // Extract function IDs
41
+ this.config.functions?.forEach(func => {
42
+ if (func.$id) {
43
+ const key = this.toConstantName(func.name || func.$id);
44
+ constants.functions[key] = func.$id;
45
+ }
46
+ });
47
+ return constants;
48
+ }
49
+ toConstantName(name) {
50
+ return name
51
+ .replace(/[^a-zA-Z0-9]/g, '_')
52
+ .replace(/_+/g, '_')
53
+ .replace(/^_|_$/g, '')
54
+ .toUpperCase();
55
+ }
56
+ toCamelCase(name) {
57
+ return name
58
+ .toLowerCase()
59
+ .replace(/_([a-z])/g, (_, letter) => letter.toUpperCase());
60
+ }
61
+ toSnakeCase(name) {
62
+ return name.toLowerCase();
63
+ }
64
+ generateTypeScript() {
65
+ const { databases, collections, buckets, functions } = this.constants;
66
+ return `// Auto-generated Appwrite constants
67
+ // Generated on ${new Date().toISOString()}
68
+
69
+ export const DATABASE_IDS = {
70
+ ${Object.entries(databases).map(([key, value]) => ` ${key}: "${value}"`).join(',\n')}
71
+ } as const;
72
+
73
+ export const COLLECTION_IDS = {
74
+ ${Object.entries(collections).map(([key, value]) => ` ${key}: "${value}"`).join(',\n')}
75
+ } as const;
76
+
77
+ export const BUCKET_IDS = {
78
+ ${Object.entries(buckets).map(([key, value]) => ` ${key}: "${value}"`).join(',\n')}
79
+ } as const;
80
+
81
+ export const FUNCTION_IDS = {
82
+ ${Object.entries(functions).map(([key, value]) => ` ${key}: "${value}"`).join(',\n')}
83
+ } as const;
84
+
85
+ // Type helpers
86
+ export type DatabaseId = typeof DATABASE_IDS[keyof typeof DATABASE_IDS];
87
+ export type CollectionId = typeof COLLECTION_IDS[keyof typeof COLLECTION_IDS];
88
+ export type BucketId = typeof BUCKET_IDS[keyof typeof BUCKET_IDS];
89
+ export type FunctionId = typeof FUNCTION_IDS[keyof typeof FUNCTION_IDS];
90
+
91
+ // Helper objects for runtime use
92
+ export const ALL_DATABASE_IDS = Object.values(DATABASE_IDS);
93
+ export const ALL_COLLECTION_IDS = Object.values(COLLECTION_IDS);
94
+ export const ALL_BUCKET_IDS = Object.values(BUCKET_IDS);
95
+ export const ALL_FUNCTION_IDS = Object.values(FUNCTION_IDS);
96
+ `;
97
+ }
98
+ generateJavaScript() {
99
+ const { databases, collections, buckets, functions } = this.constants;
100
+ return `// Auto-generated Appwrite constants
101
+ // Generated on ${new Date().toISOString()}
102
+
103
+ export const DATABASE_IDS = {
104
+ ${Object.entries(databases).map(([key, value]) => ` ${key}: "${value}"`).join(',\n')}
105
+ };
106
+
107
+ export const COLLECTION_IDS = {
108
+ ${Object.entries(collections).map(([key, value]) => ` ${key}: "${value}"`).join(',\n')}
109
+ };
110
+
111
+ export const BUCKET_IDS = {
112
+ ${Object.entries(buckets).map(([key, value]) => ` ${key}: "${value}"`).join(',\n')}
113
+ };
114
+
115
+ export const FUNCTION_IDS = {
116
+ ${Object.entries(functions).map(([key, value]) => ` ${key}: "${value}"`).join(',\n')}
117
+ };
118
+
119
+ // Helper arrays for runtime use
120
+ export const ALL_DATABASE_IDS = Object.values(DATABASE_IDS);
121
+ export const ALL_COLLECTION_IDS = Object.values(COLLECTION_IDS);
122
+ export const ALL_BUCKET_IDS = Object.values(BUCKET_IDS);
123
+ export const ALL_FUNCTION_IDS = Object.values(FUNCTION_IDS);
124
+ `;
125
+ }
126
+ generatePython() {
127
+ const { databases, collections, buckets, functions } = this.constants;
128
+ return `# Auto-generated Appwrite constants
129
+ # Generated on ${new Date().toISOString()}
130
+
131
+ class DatabaseIds:
132
+ """Database ID constants"""
133
+ ${Object.entries(databases).map(([key, value]) => ` ${key} = "${value}"`).join('\n')}
134
+
135
+ class CollectionIds:
136
+ """Collection ID constants"""
137
+ ${Object.entries(collections).map(([key, value]) => ` ${key} = "${value}"`).join('\n')}
138
+
139
+ class BucketIds:
140
+ """Bucket ID constants"""
141
+ ${Object.entries(buckets).map(([key, value]) => ` ${key} = "${value}"`).join('\n')}
142
+
143
+ class FunctionIds:
144
+ """Function ID constants"""
145
+ ${Object.entries(functions).map(([key, value]) => ` ${key} = "${value}"`).join('\n')}
146
+
147
+ # Helper dictionaries for runtime use
148
+ DATABASE_ID_MAP = {
149
+ ${Object.entries(databases).map(([key, value]) => ` "${this.toSnakeCase(key)}": "${value}"`).join(',\n')}
150
+ }
151
+
152
+ COLLECTION_ID_MAP = {
153
+ ${Object.entries(collections).map(([key, value]) => ` "${this.toSnakeCase(key)}": "${value}"`).join(',\n')}
154
+ }
155
+
156
+ BUCKET_ID_MAP = {
157
+ ${Object.entries(buckets).map(([key, value]) => ` "${this.toSnakeCase(key)}": "${value}"`).join(',\n')}
158
+ }
159
+
160
+ FUNCTION_ID_MAP = {
161
+ ${Object.entries(functions).map(([key, value]) => ` "${this.toSnakeCase(key)}": "${value}"`).join(',\n')}
162
+ }
163
+ `;
164
+ }
165
+ generatePHP() {
166
+ const { databases, collections, buckets, functions } = this.constants;
167
+ return `<?php
168
+ // Auto-generated Appwrite constants
169
+ // Generated on ${new Date().toISOString()}
170
+
171
+ class AppwriteConstants {
172
+
173
+ const DATABASE_IDS = [
174
+ ${Object.entries(databases).map(([key, value]) => ` '${key}' => '${value}'`).join(',\n')}
175
+ ];
176
+
177
+ const COLLECTION_IDS = [
178
+ ${Object.entries(collections).map(([key, value]) => ` '${key}' => '${value}'`).join(',\n')}
179
+ ];
180
+
181
+ const BUCKET_IDS = [
182
+ ${Object.entries(buckets).map(([key, value]) => ` '${key}' => '${value}'`).join(',\n')}
183
+ ];
184
+
185
+ const FUNCTION_IDS = [
186
+ ${Object.entries(functions).map(([key, value]) => ` '${key}' => '${value}'`).join(',\n')}
187
+ ];
188
+
189
+ /**
190
+ * Get all database IDs as array
191
+ */
192
+ public static function getAllDatabaseIds(): array {
193
+ return array_values(self::DATABASE_IDS);
194
+ }
195
+
196
+ /**
197
+ * Get all collection IDs as array
198
+ */
199
+ public static function getAllCollectionIds(): array {
200
+ return array_values(self::COLLECTION_IDS);
201
+ }
202
+
203
+ /**
204
+ * Get all bucket IDs as array
205
+ */
206
+ public static function getAllBucketIds(): array {
207
+ return array_values(self::BUCKET_IDS);
208
+ }
209
+
210
+ /**
211
+ * Get all function IDs as array
212
+ */
213
+ public static function getAllFunctionIds(): array {
214
+ return array_values(self::FUNCTION_IDS);
215
+ }
216
+ }
217
+ `;
218
+ }
219
+ generateDart() {
220
+ const { databases, collections, buckets, functions } = this.constants;
221
+ return `// Auto-generated Appwrite constants
222
+ // Generated on ${new Date().toISOString()}
223
+
224
+ class AppwriteConstants {
225
+
226
+ static const Map<String, String> databaseIds = {
227
+ ${Object.entries(databases).map(([key, value]) => ` '${this.toCamelCase(key)}': '${value}'`).join(',\n')}
228
+ };
229
+
230
+ static const Map<String, String> collectionIds = {
231
+ ${Object.entries(collections).map(([key, value]) => ` '${this.toCamelCase(key)}': '${value}'`).join(',\n')}
232
+ };
233
+
234
+ static const Map<String, String> bucketIds = {
235
+ ${Object.entries(buckets).map(([key, value]) => ` '${this.toCamelCase(key)}': '${value}'`).join(',\n')}
236
+ };
237
+
238
+ static const Map<String, String> functionIds = {
239
+ ${Object.entries(functions).map(([key, value]) => ` '${this.toCamelCase(key)}': '${value}'`).join(',\n')}
240
+ };
241
+
242
+ // Helper getters for individual IDs
243
+ ${Object.entries(databases).map(([key, value]) => ` static String get ${this.toCamelCase(key)}DatabaseId => '${value}';`).join('\n')}
244
+
245
+ ${Object.entries(collections).map(([key, value]) => ` static String get ${this.toCamelCase(key)}CollectionId => '${value}';`).join('\n')}
246
+
247
+ ${Object.entries(buckets).map(([key, value]) => ` static String get ${this.toCamelCase(key)}BucketId => '${value}';`).join('\n')}
248
+
249
+ ${Object.entries(functions).map(([key, value]) => ` static String get ${this.toCamelCase(key)}FunctionId => '${value}';`).join('\n')}
250
+ }
251
+ `;
252
+ }
253
+ generateJSON() {
254
+ return JSON.stringify({
255
+ meta: {
256
+ generated: new Date().toISOString(),
257
+ generator: "appwrite-utils-cli"
258
+ },
259
+ databases: this.constants.databases,
260
+ collections: this.constants.collections,
261
+ buckets: this.constants.buckets,
262
+ functions: this.constants.functions
263
+ }, null, 2);
264
+ }
265
+ generateEnv() {
266
+ const { databases, collections, buckets, functions } = this.constants;
267
+ const lines = [
268
+ "# Auto-generated Appwrite constants",
269
+ `# Generated on ${new Date().toISOString()}`,
270
+ "",
271
+ "# Database IDs",
272
+ ...Object.entries(databases).map(([key, value]) => `DATABASE_${key}=${value}`),
273
+ "",
274
+ "# Collection IDs",
275
+ ...Object.entries(collections).map(([key, value]) => `COLLECTION_${key}=${value}`),
276
+ "",
277
+ "# Bucket IDs",
278
+ ...Object.entries(buckets).map(([key, value]) => `BUCKET_${key}=${value}`),
279
+ "",
280
+ "# Function IDs",
281
+ ...Object.entries(functions).map(([key, value]) => `FUNCTION_${key}=${value}`)
282
+ ];
283
+ return lines.join('\n');
284
+ }
285
+ async generateFiles(languages, outputDir) {
286
+ await fs.mkdir(outputDir, { recursive: true });
287
+ const generators = {
288
+ typescript: () => ({ content: this.generateTypeScript(), filename: "appwrite-constants.ts" }),
289
+ javascript: () => ({ content: this.generateJavaScript(), filename: "appwrite-constants.js" }),
290
+ python: () => ({ content: this.generatePython(), filename: "appwrite_constants.py" }),
291
+ php: () => ({ content: this.generatePHP(), filename: "AppwriteConstants.php" }),
292
+ dart: () => ({ content: this.generateDart(), filename: "appwrite_constants.dart" }),
293
+ json: () => ({ content: this.generateJSON(), filename: "appwrite-constants.json" }),
294
+ env: () => ({ content: this.generateEnv(), filename: ".env.appwrite" })
295
+ };
296
+ for (const language of languages) {
297
+ const generator = generators[language];
298
+ if (generator) {
299
+ const { content, filename } = generator();
300
+ const filePath = path.join(outputDir, filename);
301
+ await fs.writeFile(filePath, content, 'utf-8');
302
+ MessageFormatter.success(`Generated ${language} constants: ${filePath}`, { prefix: "Constants" });
303
+ }
304
+ else {
305
+ MessageFormatter.error(`Unsupported language: ${language}`, undefined, { prefix: "Constants" });
306
+ }
307
+ }
308
+ }
309
+ }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "appwrite-utils-cli",
3
3
  "description": "Appwrite Utility Functions to help with database management, data conversion, data import, migrations, and much more. Meant to be used as a CLI tool, I do not recommend installing this in frontend environments.",
4
- "version": "1.0.5",
4
+ "version": "1.0.6",
5
5
  "main": "src/main.ts",
6
6
  "type": "module",
7
7
  "repository": {
@@ -41,6 +41,7 @@ import {
41
41
  } from "./functions/methods.js";
42
42
  import { deployLocalFunction } from "./functions/deployments.js";
43
43
  import { join } from "node:path";
44
+ import path from "path";
44
45
  import fs from "node:fs";
45
46
  import { SchemaGenerator } from "./shared/schemaGenerator.js";
46
47
  import { ConfirmationDialogs } from "./shared/confirmationDialogs.js";
@@ -64,6 +65,7 @@ enum CHOICES {
64
65
  WIPE_DATABASE = "Wipe database",
65
66
  WIPE_COLLECTIONS = "Wipe collections",
66
67
  GENERATE_SCHEMAS = "Generate schemas",
68
+ GENERATE_CONSTANTS = "📋 Generate cross-language constants (TypeScript, Python, PHP, Dart, etc.)",
67
69
  IMPORT_DATA = "Import data",
68
70
  RELOAD_CONFIG = "Reload configuration files",
69
71
  UPDATE_FUNCTION_SPEC = "Update function specifications",
@@ -159,6 +161,10 @@ export class InteractiveCLI {
159
161
  await this.initControllerIfNeeded();
160
162
  await this.generateSchemas();
161
163
  break;
164
+ case CHOICES.GENERATE_CONSTANTS:
165
+ await this.initControllerIfNeeded();
166
+ await this.generateConstants();
167
+ break;
162
168
  case CHOICES.IMPORT_DATA:
163
169
  await this.initControllerIfNeeded();
164
170
  await this.importData();
@@ -1595,6 +1601,73 @@ export class InteractiveCLI {
1595
1601
  MessageFormatter.success("Schema generation completed", { prefix: "Schemas" });
1596
1602
  }
1597
1603
 
1604
+ private async generateConstants(): Promise<void> {
1605
+ console.log(chalk.yellow("Generating cross-language constants..."));
1606
+
1607
+ if (!this.controller?.config) {
1608
+ MessageFormatter.error("No configuration found", undefined, { prefix: "Constants" });
1609
+ return;
1610
+ }
1611
+
1612
+ // Prompt for languages
1613
+ const { languages } = await inquirer.prompt([
1614
+ {
1615
+ type: "checkbox",
1616
+ name: "languages",
1617
+ message: "Select languages for constants generation:",
1618
+ choices: [
1619
+ { name: "TypeScript", value: "typescript", checked: true },
1620
+ { name: "JavaScript", value: "javascript" },
1621
+ { name: "Python", value: "python" },
1622
+ { name: "PHP", value: "php" },
1623
+ { name: "Dart", value: "dart" },
1624
+ { name: "JSON", value: "json" },
1625
+ { name: "Environment Variables", value: "env" },
1626
+ ],
1627
+ validate: (input) => {
1628
+ if (input.length === 0) {
1629
+ return "Please select at least one language";
1630
+ }
1631
+ return true;
1632
+ },
1633
+ },
1634
+ ]);
1635
+
1636
+ // Determine default output directory based on config location
1637
+ const configPath = this.controller!.getAppwriteFolderPath();
1638
+ const defaultOutputDir = configPath
1639
+ ? path.join(configPath, "constants")
1640
+ : path.join(process.cwd(), "constants");
1641
+
1642
+ // Prompt for output directory
1643
+ const { outputDir } = await inquirer.prompt([
1644
+ {
1645
+ type: "input",
1646
+ name: "outputDir",
1647
+ message: "Output directory for constants files:",
1648
+ default: defaultOutputDir,
1649
+ validate: (input) => {
1650
+ if (!input.trim()) {
1651
+ return "Output directory cannot be empty";
1652
+ }
1653
+ return true;
1654
+ },
1655
+ },
1656
+ ]);
1657
+
1658
+ try {
1659
+ const { ConstantsGenerator } = await import("./utils/constantsGenerator.js");
1660
+ const generator = new ConstantsGenerator(this.controller.config);
1661
+
1662
+ MessageFormatter.info(`Generating constants for: ${languages.join(", ")}`, { prefix: "Constants" });
1663
+ await generator.generateFiles(languages, outputDir);
1664
+
1665
+ MessageFormatter.success(`Constants generated in ${outputDir}`, { prefix: "Constants" });
1666
+ } catch (error) {
1667
+ MessageFormatter.error("Failed to generate constants", error instanceof Error ? error : new Error(String(error)), { prefix: "Constants" });
1668
+ }
1669
+ }
1670
+
1598
1671
  private async importData(): Promise<void> {
1599
1672
  console.log(chalk.yellow("Importing data..."));
1600
1673
 
package/src/main.ts CHANGED
@@ -15,6 +15,7 @@ import chalk from "chalk";
15
15
  import { listSpecifications } from "./functions/methods.js";
16
16
  import { MessageFormatter } from "./shared/messageFormatter.js";
17
17
  import { ConfirmationDialogs } from "./shared/confirmationDialogs.js";
18
+ import path from "path";
18
19
 
19
20
  interface CliOptions {
20
21
  config?: string;
@@ -49,6 +50,9 @@ interface CliOptions {
49
50
  functionId?: string;
50
51
  specification?: string;
51
52
  migrateConfig?: boolean;
53
+ generateConstants?: boolean;
54
+ constantsLanguages?: string;
55
+ constantsOutput?: string;
52
56
  }
53
57
 
54
58
  type ParsedArgv = ArgumentsCamelCase<CliOptions>;
@@ -203,6 +207,21 @@ const argv = yargs(hideBin(process.argv))
203
207
  type: "boolean",
204
208
  description: "Migrate appwriteConfig.ts to .appwrite structure with YAML configuration",
205
209
  })
210
+ .option("generateConstants", {
211
+ alias: ["constants"],
212
+ type: "boolean",
213
+ description: "Generate cross-language constants file with database, collection, bucket, and function IDs",
214
+ })
215
+ .option("constantsLanguages", {
216
+ type: "string",
217
+ description: "Comma-separated list of languages for constants (typescript,javascript,python,php,dart,json,env)",
218
+ default: "typescript",
219
+ })
220
+ .option("constantsOutput", {
221
+ type: "string",
222
+ description: "Output directory for generated constants files (default: config-folder/constants)",
223
+ default: "auto",
224
+ })
206
225
  .parse() as ParsedArgv;
207
226
 
208
227
  async function main() {
@@ -235,6 +254,40 @@ async function main() {
235
254
  return;
236
255
  }
237
256
 
257
+ if (argv.generateConstants) {
258
+ const { ConstantsGenerator } = await import("./utils/constantsGenerator.js");
259
+ type SupportedLanguage = import("./utils/constantsGenerator.js").SupportedLanguage;
260
+
261
+ if (!controller.config) {
262
+ MessageFormatter.error("No Appwrite configuration found", undefined, { prefix: "Constants" });
263
+ return;
264
+ }
265
+
266
+ const languages = argv.constantsLanguages!.split(",").map(l => l.trim()) as SupportedLanguage[];
267
+
268
+ // Determine output directory - use config folder/constants by default, or custom path if specified
269
+ let outputDir: string;
270
+ if (argv.constantsOutput === "auto") {
271
+ // Default case: use config directory + constants, fallback to current directory
272
+ const configPath = controller.getAppwriteFolderPath();
273
+ outputDir = configPath
274
+ ? path.join(configPath, "constants")
275
+ : path.join(process.cwd(), "constants");
276
+ } else {
277
+ // Custom output directory specified
278
+ outputDir = argv.constantsOutput!;
279
+ }
280
+
281
+ MessageFormatter.info(`Generating constants for languages: ${languages.join(", ")}`, { prefix: "Constants" });
282
+
283
+ const generator = new ConstantsGenerator(controller.config);
284
+ await generator.generateFiles(languages, outputDir);
285
+
286
+ operationStats.generatedConstants = languages.length;
287
+ MessageFormatter.success(`Constants generated in ${outputDir}`, { prefix: "Constants" });
288
+ return;
289
+ }
290
+
238
291
  if (!controller.config) {
239
292
  MessageFormatter.error("No Appwrite connection found", undefined, { prefix: "CLI" });
240
293
  return;
@@ -0,0 +1,352 @@
1
+ import fs from "fs/promises";
2
+ import path from "path";
3
+ import { type AppwriteConfig } from "appwrite-utils";
4
+ import { MessageFormatter } from "../shared/messageFormatter.js";
5
+
6
+ export type SupportedLanguage =
7
+ | "typescript"
8
+ | "javascript"
9
+ | "python"
10
+ | "php"
11
+ | "dart"
12
+ | "json"
13
+ | "env";
14
+
15
+ interface Constants {
16
+ databases: Record<string, string>;
17
+ collections: Record<string, string>;
18
+ buckets: Record<string, string>;
19
+ functions: Record<string, string>;
20
+ }
21
+
22
+ export class ConstantsGenerator {
23
+ private config: AppwriteConfig;
24
+ private constants: Constants;
25
+
26
+ constructor(config: AppwriteConfig) {
27
+ this.config = config;
28
+ this.constants = this.extractConstants();
29
+ }
30
+
31
+ private extractConstants(): Constants {
32
+ const constants: Constants = {
33
+ databases: {},
34
+ collections: {},
35
+ buckets: {},
36
+ functions: {}
37
+ };
38
+
39
+ // Extract database IDs
40
+ this.config.databases?.forEach(db => {
41
+ if (db.$id) {
42
+ const key = this.toConstantName(db.name || db.$id);
43
+ constants.databases[key] = db.$id;
44
+ }
45
+ });
46
+
47
+ // Extract collection IDs
48
+ this.config.collections?.forEach(collection => {
49
+ if (collection.$id) {
50
+ const key = this.toConstantName(collection.name || collection.$id);
51
+ constants.collections[key] = collection.$id;
52
+ }
53
+ });
54
+
55
+ // Extract bucket IDs
56
+ this.config.buckets?.forEach(bucket => {
57
+ if (bucket.$id) {
58
+ const key = this.toConstantName(bucket.name || bucket.$id);
59
+ constants.buckets[key] = bucket.$id;
60
+ }
61
+ });
62
+
63
+ // Extract function IDs
64
+ this.config.functions?.forEach(func => {
65
+ if (func.$id) {
66
+ const key = this.toConstantName(func.name || func.$id);
67
+ constants.functions[key] = func.$id;
68
+ }
69
+ });
70
+
71
+ return constants;
72
+ }
73
+
74
+ private toConstantName(name: string): string {
75
+ return name
76
+ .replace(/[^a-zA-Z0-9]/g, '_')
77
+ .replace(/_+/g, '_')
78
+ .replace(/^_|_$/g, '')
79
+ .toUpperCase();
80
+ }
81
+
82
+ private toCamelCase(name: string): string {
83
+ return name
84
+ .toLowerCase()
85
+ .replace(/_([a-z])/g, (_, letter) => letter.toUpperCase());
86
+ }
87
+
88
+ private toSnakeCase(name: string): string {
89
+ return name.toLowerCase();
90
+ }
91
+
92
+ generateTypeScript(): string {
93
+ const { databases, collections, buckets, functions } = this.constants;
94
+
95
+ return `// Auto-generated Appwrite constants
96
+ // Generated on ${new Date().toISOString()}
97
+
98
+ export const DATABASE_IDS = {
99
+ ${Object.entries(databases).map(([key, value]) => ` ${key}: "${value}"`).join(',\n')}
100
+ } as const;
101
+
102
+ export const COLLECTION_IDS = {
103
+ ${Object.entries(collections).map(([key, value]) => ` ${key}: "${value}"`).join(',\n')}
104
+ } as const;
105
+
106
+ export const BUCKET_IDS = {
107
+ ${Object.entries(buckets).map(([key, value]) => ` ${key}: "${value}"`).join(',\n')}
108
+ } as const;
109
+
110
+ export const FUNCTION_IDS = {
111
+ ${Object.entries(functions).map(([key, value]) => ` ${key}: "${value}"`).join(',\n')}
112
+ } as const;
113
+
114
+ // Type helpers
115
+ export type DatabaseId = typeof DATABASE_IDS[keyof typeof DATABASE_IDS];
116
+ export type CollectionId = typeof COLLECTION_IDS[keyof typeof COLLECTION_IDS];
117
+ export type BucketId = typeof BUCKET_IDS[keyof typeof BUCKET_IDS];
118
+ export type FunctionId = typeof FUNCTION_IDS[keyof typeof FUNCTION_IDS];
119
+
120
+ // Helper objects for runtime use
121
+ export const ALL_DATABASE_IDS = Object.values(DATABASE_IDS);
122
+ export const ALL_COLLECTION_IDS = Object.values(COLLECTION_IDS);
123
+ export const ALL_BUCKET_IDS = Object.values(BUCKET_IDS);
124
+ export const ALL_FUNCTION_IDS = Object.values(FUNCTION_IDS);
125
+ `;
126
+ }
127
+
128
+ generateJavaScript(): string {
129
+ const { databases, collections, buckets, functions } = this.constants;
130
+
131
+ return `// Auto-generated Appwrite constants
132
+ // Generated on ${new Date().toISOString()}
133
+
134
+ export const DATABASE_IDS = {
135
+ ${Object.entries(databases).map(([key, value]) => ` ${key}: "${value}"`).join(',\n')}
136
+ };
137
+
138
+ export const COLLECTION_IDS = {
139
+ ${Object.entries(collections).map(([key, value]) => ` ${key}: "${value}"`).join(',\n')}
140
+ };
141
+
142
+ export const BUCKET_IDS = {
143
+ ${Object.entries(buckets).map(([key, value]) => ` ${key}: "${value}"`).join(',\n')}
144
+ };
145
+
146
+ export const FUNCTION_IDS = {
147
+ ${Object.entries(functions).map(([key, value]) => ` ${key}: "${value}"`).join(',\n')}
148
+ };
149
+
150
+ // Helper arrays for runtime use
151
+ export const ALL_DATABASE_IDS = Object.values(DATABASE_IDS);
152
+ export const ALL_COLLECTION_IDS = Object.values(COLLECTION_IDS);
153
+ export const ALL_BUCKET_IDS = Object.values(BUCKET_IDS);
154
+ export const ALL_FUNCTION_IDS = Object.values(FUNCTION_IDS);
155
+ `;
156
+ }
157
+
158
+ generatePython(): string {
159
+ const { databases, collections, buckets, functions } = this.constants;
160
+
161
+ return `# Auto-generated Appwrite constants
162
+ # Generated on ${new Date().toISOString()}
163
+
164
+ class DatabaseIds:
165
+ """Database ID constants"""
166
+ ${Object.entries(databases).map(([key, value]) => ` ${key} = "${value}"`).join('\n')}
167
+
168
+ class CollectionIds:
169
+ """Collection ID constants"""
170
+ ${Object.entries(collections).map(([key, value]) => ` ${key} = "${value}"`).join('\n')}
171
+
172
+ class BucketIds:
173
+ """Bucket ID constants"""
174
+ ${Object.entries(buckets).map(([key, value]) => ` ${key} = "${value}"`).join('\n')}
175
+
176
+ class FunctionIds:
177
+ """Function ID constants"""
178
+ ${Object.entries(functions).map(([key, value]) => ` ${key} = "${value}"`).join('\n')}
179
+
180
+ # Helper dictionaries for runtime use
181
+ DATABASE_ID_MAP = {
182
+ ${Object.entries(databases).map(([key, value]) => ` "${this.toSnakeCase(key)}": "${value}"`).join(',\n')}
183
+ }
184
+
185
+ COLLECTION_ID_MAP = {
186
+ ${Object.entries(collections).map(([key, value]) => ` "${this.toSnakeCase(key)}": "${value}"`).join(',\n')}
187
+ }
188
+
189
+ BUCKET_ID_MAP = {
190
+ ${Object.entries(buckets).map(([key, value]) => ` "${this.toSnakeCase(key)}": "${value}"`).join(',\n')}
191
+ }
192
+
193
+ FUNCTION_ID_MAP = {
194
+ ${Object.entries(functions).map(([key, value]) => ` "${this.toSnakeCase(key)}": "${value}"`).join(',\n')}
195
+ }
196
+ `;
197
+ }
198
+
199
+ generatePHP(): string {
200
+ const { databases, collections, buckets, functions } = this.constants;
201
+
202
+ return `<?php
203
+ // Auto-generated Appwrite constants
204
+ // Generated on ${new Date().toISOString()}
205
+
206
+ class AppwriteConstants {
207
+
208
+ const DATABASE_IDS = [
209
+ ${Object.entries(databases).map(([key, value]) => ` '${key}' => '${value}'`).join(',\n')}
210
+ ];
211
+
212
+ const COLLECTION_IDS = [
213
+ ${Object.entries(collections).map(([key, value]) => ` '${key}' => '${value}'`).join(',\n')}
214
+ ];
215
+
216
+ const BUCKET_IDS = [
217
+ ${Object.entries(buckets).map(([key, value]) => ` '${key}' => '${value}'`).join(',\n')}
218
+ ];
219
+
220
+ const FUNCTION_IDS = [
221
+ ${Object.entries(functions).map(([key, value]) => ` '${key}' => '${value}'`).join(',\n')}
222
+ ];
223
+
224
+ /**
225
+ * Get all database IDs as array
226
+ */
227
+ public static function getAllDatabaseIds(): array {
228
+ return array_values(self::DATABASE_IDS);
229
+ }
230
+
231
+ /**
232
+ * Get all collection IDs as array
233
+ */
234
+ public static function getAllCollectionIds(): array {
235
+ return array_values(self::COLLECTION_IDS);
236
+ }
237
+
238
+ /**
239
+ * Get all bucket IDs as array
240
+ */
241
+ public static function getAllBucketIds(): array {
242
+ return array_values(self::BUCKET_IDS);
243
+ }
244
+
245
+ /**
246
+ * Get all function IDs as array
247
+ */
248
+ public static function getAllFunctionIds(): array {
249
+ return array_values(self::FUNCTION_IDS);
250
+ }
251
+ }
252
+ `;
253
+ }
254
+
255
+ generateDart(): string {
256
+ const { databases, collections, buckets, functions } = this.constants;
257
+
258
+ return `// Auto-generated Appwrite constants
259
+ // Generated on ${new Date().toISOString()}
260
+
261
+ class AppwriteConstants {
262
+
263
+ static const Map<String, String> databaseIds = {
264
+ ${Object.entries(databases).map(([key, value]) => ` '${this.toCamelCase(key)}': '${value}'`).join(',\n')}
265
+ };
266
+
267
+ static const Map<String, String> collectionIds = {
268
+ ${Object.entries(collections).map(([key, value]) => ` '${this.toCamelCase(key)}': '${value}'`).join(',\n')}
269
+ };
270
+
271
+ static const Map<String, String> bucketIds = {
272
+ ${Object.entries(buckets).map(([key, value]) => ` '${this.toCamelCase(key)}': '${value}'`).join(',\n')}
273
+ };
274
+
275
+ static const Map<String, String> functionIds = {
276
+ ${Object.entries(functions).map(([key, value]) => ` '${this.toCamelCase(key)}': '${value}'`).join(',\n')}
277
+ };
278
+
279
+ // Helper getters for individual IDs
280
+ ${Object.entries(databases).map(([key, value]) => ` static String get ${this.toCamelCase(key)}DatabaseId => '${value}';`).join('\n')}
281
+
282
+ ${Object.entries(collections).map(([key, value]) => ` static String get ${this.toCamelCase(key)}CollectionId => '${value}';`).join('\n')}
283
+
284
+ ${Object.entries(buckets).map(([key, value]) => ` static String get ${this.toCamelCase(key)}BucketId => '${value}';`).join('\n')}
285
+
286
+ ${Object.entries(functions).map(([key, value]) => ` static String get ${this.toCamelCase(key)}FunctionId => '${value}';`).join('\n')}
287
+ }
288
+ `;
289
+ }
290
+
291
+ generateJSON(): string {
292
+ return JSON.stringify({
293
+ meta: {
294
+ generated: new Date().toISOString(),
295
+ generator: "appwrite-utils-cli"
296
+ },
297
+ databases: this.constants.databases,
298
+ collections: this.constants.collections,
299
+ buckets: this.constants.buckets,
300
+ functions: this.constants.functions
301
+ }, null, 2);
302
+ }
303
+
304
+ generateEnv(): string {
305
+ const { databases, collections, buckets, functions } = this.constants;
306
+
307
+ const lines = [
308
+ "# Auto-generated Appwrite constants",
309
+ `# Generated on ${new Date().toISOString()}`,
310
+ "",
311
+ "# Database IDs",
312
+ ...Object.entries(databases).map(([key, value]) => `DATABASE_${key}=${value}`),
313
+ "",
314
+ "# Collection IDs",
315
+ ...Object.entries(collections).map(([key, value]) => `COLLECTION_${key}=${value}`),
316
+ "",
317
+ "# Bucket IDs",
318
+ ...Object.entries(buckets).map(([key, value]) => `BUCKET_${key}=${value}`),
319
+ "",
320
+ "# Function IDs",
321
+ ...Object.entries(functions).map(([key, value]) => `FUNCTION_${key}=${value}`)
322
+ ];
323
+
324
+ return lines.join('\n');
325
+ }
326
+
327
+ async generateFiles(languages: SupportedLanguage[], outputDir: string): Promise<void> {
328
+ await fs.mkdir(outputDir, { recursive: true });
329
+
330
+ const generators = {
331
+ typescript: () => ({ content: this.generateTypeScript(), filename: "appwrite-constants.ts" }),
332
+ javascript: () => ({ content: this.generateJavaScript(), filename: "appwrite-constants.js" }),
333
+ python: () => ({ content: this.generatePython(), filename: "appwrite_constants.py" }),
334
+ php: () => ({ content: this.generatePHP(), filename: "AppwriteConstants.php" }),
335
+ dart: () => ({ content: this.generateDart(), filename: "appwrite_constants.dart" }),
336
+ json: () => ({ content: this.generateJSON(), filename: "appwrite-constants.json" }),
337
+ env: () => ({ content: this.generateEnv(), filename: ".env.appwrite" })
338
+ };
339
+
340
+ for (const language of languages) {
341
+ const generator = generators[language];
342
+ if (generator) {
343
+ const { content, filename } = generator();
344
+ const filePath = path.join(outputDir, filename);
345
+ await fs.writeFile(filePath, content, 'utf-8');
346
+ MessageFormatter.success(`Generated ${language} constants: ${filePath}`, { prefix: "Constants" });
347
+ } else {
348
+ MessageFormatter.error(`Unsupported language: ${language}`, undefined, { prefix: "Constants" });
349
+ }
350
+ }
351
+ }
352
+ }