appwrite-utils-cli 1.8.3 → 1.8.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/CHANGELOG.md +6 -1
- package/README.md +42 -13
- package/dist/adapters/TablesDBAdapter.js +1 -1
- package/dist/cli/commands/functionCommands.js +30 -3
- package/dist/cli/commands/schemaCommands.js +39 -4
- package/dist/cli/commands/storageCommands.d.ts +5 -0
- package/dist/cli/commands/storageCommands.js +143 -0
- package/dist/collections/attributes.js +7 -7
- package/dist/collections/methods.js +122 -1
- package/dist/collections/tableOperations.js +2 -2
- package/dist/interactiveCLI.d.ts +1 -0
- package/dist/interactiveCLI.js +30 -0
- package/dist/main.js +17 -0
- package/dist/migrations/appwriteToX.js +1 -1
- package/dist/migrations/yaml/generateImportSchemas.js +2 -2
- package/dist/setupCommands.js +6 -0
- package/dist/shared/attributeMapper.js +2 -2
- package/dist/shared/jsonSchemaGenerator.js +3 -1
- package/dist/shared/pydanticModelGenerator.d.ts +17 -0
- package/dist/shared/pydanticModelGenerator.js +615 -0
- package/dist/shared/schemaGenerator.d.ts +3 -2
- package/dist/shared/schemaGenerator.js +22 -9
- package/dist/storage/methods.js +50 -7
- package/dist/utils/configDiscovery.js +2 -3
- package/dist/utils/constantsGenerator.d.ts +20 -8
- package/dist/utils/constantsGenerator.js +37 -25
- package/dist/utils/projectConfig.js +1 -1
- package/dist/utils/yamlConverter.d.ts +2 -2
- package/dist/utils/yamlConverter.js +2 -2
- package/dist/utilsController.js +11 -1
- package/package.json +1 -1
- package/src/adapters/TablesDBAdapter.ts +1 -1
- package/src/cli/commands/functionCommands.ts +28 -3
- package/src/cli/commands/schemaCommands.ts +59 -22
- package/src/cli/commands/storageCommands.ts +152 -0
- package/src/collections/attributes.ts +7 -7
- package/src/collections/methods.ts +125 -11
- package/src/collections/tableOperations.ts +2 -2
- package/src/interactiveCLI.ts +42 -12
- package/src/main.ts +32 -9
- package/src/migrations/appwriteToX.ts +1 -1
- package/src/migrations/yaml/generateImportSchemas.ts +7 -7
- package/src/setupCommands.ts +6 -0
- package/src/shared/attributeMapper.ts +2 -2
- package/src/shared/jsonSchemaGenerator.ts +4 -2
- package/src/shared/pydanticModelGenerator.ts +618 -0
- package/src/shared/schemaGenerator.ts +38 -25
- package/src/storage/methods.ts +67 -23
- package/src/utils/configDiscovery.ts +40 -41
- package/src/utils/constantsGenerator.ts +43 -26
- package/src/utils/projectConfig.ts +11 -11
- package/src/utils/yamlConverter.ts +40 -40
- package/src/utilsController.ts +30 -20
package/dist/storage/methods.js
CHANGED
|
@@ -44,8 +44,54 @@ export const ensureDatabaseConfigBucketsExist = async (storage, config, database
|
|
|
44
44
|
const database = config.databases?.find((d) => d.$id === db.$id);
|
|
45
45
|
if (database?.bucket) {
|
|
46
46
|
try {
|
|
47
|
-
await storage.getBucket(database.bucket.$id);
|
|
48
|
-
|
|
47
|
+
const existing = await storage.getBucket(database.bucket.$id);
|
|
48
|
+
// Compare and update if needed
|
|
49
|
+
const desired = database.bucket;
|
|
50
|
+
// Build desired permissions via Permission helper
|
|
51
|
+
const permissions = [];
|
|
52
|
+
if (desired.permissions && desired.permissions.length > 0) {
|
|
53
|
+
for (const p of desired.permissions) {
|
|
54
|
+
switch (p.permission) {
|
|
55
|
+
case 'read':
|
|
56
|
+
permissions.push(Permission.read(p.target));
|
|
57
|
+
break;
|
|
58
|
+
case 'create':
|
|
59
|
+
permissions.push(Permission.create(p.target));
|
|
60
|
+
break;
|
|
61
|
+
case 'update':
|
|
62
|
+
permissions.push(Permission.update(p.target));
|
|
63
|
+
break;
|
|
64
|
+
case 'delete':
|
|
65
|
+
permissions.push(Permission.delete(p.target));
|
|
66
|
+
break;
|
|
67
|
+
case 'write':
|
|
68
|
+
permissions.push(Permission.write(p.target));
|
|
69
|
+
break;
|
|
70
|
+
default: break;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
const diff = (existing.name !== desired.name ||
|
|
75
|
+
JSON.stringify(existing.$permissions || []) !== JSON.stringify(permissions) ||
|
|
76
|
+
!!existing.fileSecurity !== !!desired.fileSecurity ||
|
|
77
|
+
!!existing.enabled !== !!desired.enabled ||
|
|
78
|
+
(existing.maximumFileSize ?? undefined) !== (desired.maximumFileSize ?? undefined) ||
|
|
79
|
+
JSON.stringify(existing.allowedFileExtensions || []) !== JSON.stringify(desired.allowedFileExtensions || []) ||
|
|
80
|
+
String(existing.compression || 'none') !== String(desired.compression || 'none') ||
|
|
81
|
+
!!existing.encryption !== !!desired.encryption ||
|
|
82
|
+
!!existing.antivirus !== !!desired.antivirus);
|
|
83
|
+
if (diff) {
|
|
84
|
+
try {
|
|
85
|
+
await storage.updateBucket(desired.$id, desired.name, permissions, desired.fileSecurity, desired.enabled, desired.maximumFileSize, desired.allowedFileExtensions, desired.compression, desired.encryption, desired.antivirus);
|
|
86
|
+
MessageFormatter.info(`Updated bucket ${desired.$id} to match config`, { prefix: 'Buckets' });
|
|
87
|
+
}
|
|
88
|
+
catch (updateErr) {
|
|
89
|
+
MessageFormatter.warning(`Failed to update bucket ${desired.$id}: ${updateErr instanceof Error ? updateErr.message : String(updateErr)}`, { prefix: 'Buckets' });
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
else {
|
|
93
|
+
MessageFormatter.debug(`Bucket ${desired.$id} up-to-date`, undefined, { prefix: 'Buckets' });
|
|
94
|
+
}
|
|
49
95
|
}
|
|
50
96
|
catch (e) {
|
|
51
97
|
const permissions = [];
|
|
@@ -76,13 +122,10 @@ export const ensureDatabaseConfigBucketsExist = async (storage, config, database
|
|
|
76
122
|
}
|
|
77
123
|
try {
|
|
78
124
|
await storage.createBucket(database.bucket.$id, database.bucket.name, permissions, database.bucket.fileSecurity, database.bucket.enabled, database.bucket.maximumFileSize, database.bucket.allowedFileExtensions, database.bucket.compression, database.bucket.encryption, database.bucket.antivirus);
|
|
79
|
-
|
|
125
|
+
MessageFormatter.success(`Bucket ${database.bucket.$id} created`, { prefix: 'Buckets' });
|
|
80
126
|
}
|
|
81
127
|
catch (createError) {
|
|
82
|
-
|
|
83
|
-
// `Failed to create bucket ${database.bucket.$id}:`,
|
|
84
|
-
// createError
|
|
85
|
-
// );
|
|
128
|
+
MessageFormatter.error(`Failed to create bucket ${database.bucket.$id}`, createError instanceof Error ? createError : new Error(String(createError)), { prefix: 'Buckets' });
|
|
86
129
|
}
|
|
87
130
|
}
|
|
88
131
|
}
|
|
@@ -152,7 +152,7 @@ const YamlTableSchema = z.object({
|
|
|
152
152
|
size: z.number().optional(),
|
|
153
153
|
required: z.boolean().default(false),
|
|
154
154
|
array: z.boolean().optional(),
|
|
155
|
-
|
|
155
|
+
encrypt: z.boolean().optional(), // Tables support encrypt property
|
|
156
156
|
default: z.any().optional(),
|
|
157
157
|
min: z.number().optional(),
|
|
158
158
|
max: z.number().optional(),
|
|
@@ -163,7 +163,6 @@ const YamlTableSchema = z.object({
|
|
|
163
163
|
twoWayKey: z.string().optional(),
|
|
164
164
|
onDelete: z.string().optional(),
|
|
165
165
|
side: z.string().optional(),
|
|
166
|
-
encrypt: z.boolean().optional(),
|
|
167
166
|
format: z.string().optional()
|
|
168
167
|
})).optional().default([]),
|
|
169
168
|
indexes: z.array(z.object({
|
|
@@ -266,7 +265,7 @@ export const loadYamlTable = (filePath) => {
|
|
|
266
265
|
twoWayKey: col.twoWayKey,
|
|
267
266
|
onDelete: col.onDelete,
|
|
268
267
|
side: col.side,
|
|
269
|
-
|
|
268
|
+
encrypt: col.encrypt,
|
|
270
269
|
format: col.format
|
|
271
270
|
})),
|
|
272
271
|
indexes: parsedTable.indexes.map(idx => ({
|
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
import { type AppwriteConfig } from "appwrite-utils";
|
|
2
2
|
export type SupportedLanguage = "typescript" | "javascript" | "python" | "php" | "dart" | "json" | "env";
|
|
3
|
+
interface Constants {
|
|
4
|
+
databases: Record<string, string>;
|
|
5
|
+
collections: Record<string, string>;
|
|
6
|
+
buckets: Record<string, string>;
|
|
7
|
+
functions: Record<string, string>;
|
|
8
|
+
}
|
|
3
9
|
export declare class ConstantsGenerator {
|
|
4
10
|
private config;
|
|
5
11
|
private constants;
|
|
@@ -8,12 +14,18 @@ export declare class ConstantsGenerator {
|
|
|
8
14
|
private toConstantName;
|
|
9
15
|
private toCamelCase;
|
|
10
16
|
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
|
|
17
|
+
generateTypeScript(constantsOverride?: Constants): string;
|
|
18
|
+
generateJavaScript(constantsOverride?: Constants): string;
|
|
19
|
+
generatePython(constantsOverride?: Constants): string;
|
|
20
|
+
generatePHP(constantsOverride?: Constants): string;
|
|
21
|
+
generateDart(constantsOverride?: Constants): string;
|
|
22
|
+
generateJSON(constantsOverride?: Constants): string;
|
|
23
|
+
generateEnv(constantsOverride?: Constants): string;
|
|
24
|
+
generateFiles(languages: SupportedLanguage[], outputDir: string, include?: {
|
|
25
|
+
databases?: boolean;
|
|
26
|
+
collections?: boolean;
|
|
27
|
+
buckets?: boolean;
|
|
28
|
+
functions?: boolean;
|
|
29
|
+
}): Promise<void>;
|
|
19
30
|
}
|
|
31
|
+
export {};
|
|
@@ -61,8 +61,8 @@ export class ConstantsGenerator {
|
|
|
61
61
|
toSnakeCase(name) {
|
|
62
62
|
return name.toLowerCase();
|
|
63
63
|
}
|
|
64
|
-
generateTypeScript() {
|
|
65
|
-
const { databases, collections, buckets, functions } = this.constants;
|
|
64
|
+
generateTypeScript(constantsOverride) {
|
|
65
|
+
const { databases, collections, buckets, functions } = constantsOverride || this.constants;
|
|
66
66
|
return `// Auto-generated Appwrite constants
|
|
67
67
|
// Generated on ${new Date().toISOString()}
|
|
68
68
|
|
|
@@ -95,8 +95,8 @@ export const ALL_BUCKET_IDS = Object.values(BUCKET_IDS);
|
|
|
95
95
|
export const ALL_FUNCTION_IDS = Object.values(FUNCTION_IDS);
|
|
96
96
|
`;
|
|
97
97
|
}
|
|
98
|
-
generateJavaScript() {
|
|
99
|
-
const { databases, collections, buckets, functions } = this.constants;
|
|
98
|
+
generateJavaScript(constantsOverride) {
|
|
99
|
+
const { databases, collections, buckets, functions } = constantsOverride || this.constants;
|
|
100
100
|
return `// Auto-generated Appwrite constants
|
|
101
101
|
// Generated on ${new Date().toISOString()}
|
|
102
102
|
|
|
@@ -123,8 +123,8 @@ export const ALL_BUCKET_IDS = Object.values(BUCKET_IDS);
|
|
|
123
123
|
export const ALL_FUNCTION_IDS = Object.values(FUNCTION_IDS);
|
|
124
124
|
`;
|
|
125
125
|
}
|
|
126
|
-
generatePython() {
|
|
127
|
-
const { databases, collections, buckets, functions } = this.constants;
|
|
126
|
+
generatePython(constantsOverride) {
|
|
127
|
+
const { databases, collections, buckets, functions } = constantsOverride || this.constants;
|
|
128
128
|
return `# Auto-generated Appwrite constants
|
|
129
129
|
# Generated on ${new Date().toISOString()}
|
|
130
130
|
|
|
@@ -162,8 +162,8 @@ ${Object.entries(functions).map(([key, value]) => ` "${this.toSnakeCase(key)}
|
|
|
162
162
|
}
|
|
163
163
|
`;
|
|
164
164
|
}
|
|
165
|
-
generatePHP() {
|
|
166
|
-
const { databases, collections, buckets, functions } = this.constants;
|
|
165
|
+
generatePHP(constantsOverride) {
|
|
166
|
+
const { databases, collections, buckets, functions } = constantsOverride || this.constants;
|
|
167
167
|
return `<?php
|
|
168
168
|
// Auto-generated Appwrite constants
|
|
169
169
|
// Generated on ${new Date().toISOString()}
|
|
@@ -216,8 +216,8 @@ ${Object.entries(functions).map(([key, value]) => ` '${key}' => '${value}
|
|
|
216
216
|
}
|
|
217
217
|
`;
|
|
218
218
|
}
|
|
219
|
-
generateDart() {
|
|
220
|
-
const { databases, collections, buckets, functions } = this.constants;
|
|
219
|
+
generateDart(constantsOverride) {
|
|
220
|
+
const { databases, collections, buckets, functions } = constantsOverride || this.constants;
|
|
221
221
|
return `// Auto-generated Appwrite constants
|
|
222
222
|
// Generated on ${new Date().toISOString()}
|
|
223
223
|
|
|
@@ -250,20 +250,21 @@ ${Object.entries(functions).map(([key, value]) => ` static String get ${this.to
|
|
|
250
250
|
}
|
|
251
251
|
`;
|
|
252
252
|
}
|
|
253
|
-
generateJSON() {
|
|
253
|
+
generateJSON(constantsOverride) {
|
|
254
|
+
const c = constantsOverride || this.constants;
|
|
254
255
|
return JSON.stringify({
|
|
255
256
|
meta: {
|
|
256
257
|
generated: new Date().toISOString(),
|
|
257
258
|
generator: "appwrite-utils-cli"
|
|
258
259
|
},
|
|
259
|
-
databases:
|
|
260
|
-
collections:
|
|
261
|
-
buckets:
|
|
262
|
-
functions:
|
|
260
|
+
databases: c.databases,
|
|
261
|
+
collections: c.collections,
|
|
262
|
+
buckets: c.buckets,
|
|
263
|
+
functions: c.functions
|
|
263
264
|
}, null, 2);
|
|
264
265
|
}
|
|
265
|
-
generateEnv() {
|
|
266
|
-
const { databases, collections, buckets, functions } = this.constants;
|
|
266
|
+
generateEnv(constantsOverride) {
|
|
267
|
+
const { databases, collections, buckets, functions } = constantsOverride || this.constants;
|
|
267
268
|
const lines = [
|
|
268
269
|
"# Auto-generated Appwrite constants",
|
|
269
270
|
`# Generated on ${new Date().toISOString()}`,
|
|
@@ -282,16 +283,27 @@ ${Object.entries(functions).map(([key, value]) => ` static String get ${this.to
|
|
|
282
283
|
];
|
|
283
284
|
return lines.join('\n');
|
|
284
285
|
}
|
|
285
|
-
async generateFiles(languages, outputDir) {
|
|
286
|
+
async generateFiles(languages, outputDir, include) {
|
|
286
287
|
await fs.mkdir(outputDir, { recursive: true });
|
|
288
|
+
const filterConstants = () => {
|
|
289
|
+
if (!include)
|
|
290
|
+
return this.constants;
|
|
291
|
+
return {
|
|
292
|
+
databases: include.databases === false ? {} : this.constants.databases,
|
|
293
|
+
collections: include.collections === false ? {} : this.constants.collections,
|
|
294
|
+
buckets: include.buckets === false ? {} : this.constants.buckets,
|
|
295
|
+
functions: include.functions === false ? {} : this.constants.functions,
|
|
296
|
+
};
|
|
297
|
+
};
|
|
298
|
+
const subset = filterConstants();
|
|
287
299
|
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" })
|
|
300
|
+
typescript: () => ({ content: this.generateTypeScript(subset), filename: "appwrite-constants.ts" }),
|
|
301
|
+
javascript: () => ({ content: this.generateJavaScript(subset), filename: "appwrite-constants.js" }),
|
|
302
|
+
python: () => ({ content: this.generatePython(subset), filename: "appwrite_constants.py" }),
|
|
303
|
+
php: () => ({ content: this.generatePHP(subset), filename: "AppwriteConstants.php" }),
|
|
304
|
+
dart: () => ({ content: this.generateDart(subset), filename: "appwrite_constants.dart" }),
|
|
305
|
+
json: () => ({ content: this.generateJSON(subset), filename: "appwrite-constants.json" }),
|
|
306
|
+
env: () => ({ content: this.generateEnv(subset), filename: ".env.appwrite" })
|
|
295
307
|
};
|
|
296
308
|
for (const language of languages) {
|
|
297
309
|
const generator = generators[language];
|
|
@@ -15,7 +15,7 @@ export interface YamlCollectionData {
|
|
|
15
15
|
size?: number;
|
|
16
16
|
required?: boolean;
|
|
17
17
|
array?: boolean;
|
|
18
|
-
|
|
18
|
+
encrypt?: boolean;
|
|
19
19
|
default?: any;
|
|
20
20
|
min?: number;
|
|
21
21
|
max?: number;
|
|
@@ -33,7 +33,7 @@ export interface YamlCollectionData {
|
|
|
33
33
|
size?: number;
|
|
34
34
|
required?: boolean;
|
|
35
35
|
array?: boolean;
|
|
36
|
-
|
|
36
|
+
encrypt?: boolean;
|
|
37
37
|
default?: any;
|
|
38
38
|
min?: number;
|
|
39
39
|
max?: number;
|
|
@@ -125,9 +125,9 @@ export function collectionToYaml(collection, config = {
|
|
|
125
125
|
yamlAttr.required = attr.required;
|
|
126
126
|
if (attr.array !== undefined)
|
|
127
127
|
yamlAttr.array = attr.array;
|
|
128
|
-
// Always include
|
|
128
|
+
// Always include encrypt field for string attributes (default to false)
|
|
129
129
|
if (attr.type === 'string') {
|
|
130
|
-
yamlAttr.
|
|
130
|
+
yamlAttr.encrypt = ('encrypt' in attr && attr.encrypt === true) ? true : false;
|
|
131
131
|
}
|
|
132
132
|
if ('xdefault' in attr && attr.xdefault !== undefined)
|
|
133
133
|
yamlAttr.default = attr.xdefault;
|
package/dist/utilsController.js
CHANGED
|
@@ -619,6 +619,15 @@ export class UtilsController {
|
|
|
619
619
|
MessageFormatter.error("Database not initialized", undefined, { prefix: "Controller" });
|
|
620
620
|
return;
|
|
621
621
|
}
|
|
622
|
+
// Always reload config from disk so pushes use current local YAML/Ts definitions
|
|
623
|
+
try {
|
|
624
|
+
await this.reloadConfig();
|
|
625
|
+
MessageFormatter.info("Reloaded config from disk for push", { prefix: "Controller" });
|
|
626
|
+
}
|
|
627
|
+
catch (e) {
|
|
628
|
+
// Non-fatal; continue with existing config
|
|
629
|
+
MessageFormatter.warning("Could not reload config; continuing with current in-memory config", { prefix: "Controller" });
|
|
630
|
+
}
|
|
622
631
|
MessageFormatter.progress("Starting selective push (local config → Appwrite)...", { prefix: "Controller" });
|
|
623
632
|
// Convert database selections to Models.Database format
|
|
624
633
|
const selectedDatabases = [];
|
|
@@ -665,7 +674,8 @@ export class UtilsController {
|
|
|
665
674
|
// Check if this collection was selected for THIS database
|
|
666
675
|
if (dbSelection.tableIds.includes(collectionId)) {
|
|
667
676
|
collectionsForDatabase.push(collection);
|
|
668
|
-
|
|
677
|
+
const source = collection._isFromTablesDir ? 'tables/' : 'collections/';
|
|
678
|
+
MessageFormatter.info(` - Selected collection: ${collection.name || collectionId} for database ${dbSelection.databaseId} [source: ${source}]`, { prefix: "Controller" });
|
|
669
679
|
}
|
|
670
680
|
}
|
|
671
681
|
databaseCollectionsMap.set(dbSelection.databaseId, collectionsForDatabase);
|
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.8.
|
|
4
|
+
"version": "1.8.6",
|
|
5
5
|
"main": "src/main.ts",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"repository": {
|
|
@@ -315,7 +315,7 @@ export class TablesDBAdapter extends BaseAdapter {
|
|
|
315
315
|
const type = (params.type || "").toLowerCase();
|
|
316
316
|
const required = params.required ?? false;
|
|
317
317
|
const array = params.array ?? false;
|
|
318
|
-
const encrypt = params.encrypt ??
|
|
318
|
+
const encrypt = params.encrypt ?? false;
|
|
319
319
|
const normalizedDefault =
|
|
320
320
|
params.default === null || params.default === undefined
|
|
321
321
|
? undefined
|
|
@@ -138,11 +138,36 @@ export const functionCommands = {
|
|
|
138
138
|
return;
|
|
139
139
|
}
|
|
140
140
|
|
|
141
|
-
//
|
|
141
|
+
// Offer choice of function config sources: central YAML, .fnconfig.yaml, or both
|
|
142
|
+
let sourceChoice: 'central' | 'fnconfig' | 'both' = 'both';
|
|
143
|
+
try {
|
|
144
|
+
const answer = await inquirer.prompt([
|
|
145
|
+
{
|
|
146
|
+
type: 'list',
|
|
147
|
+
name: 'source',
|
|
148
|
+
message: 'Select function config source:',
|
|
149
|
+
choices: [
|
|
150
|
+
{ name: 'config.yaml functions (central)', value: 'central' },
|
|
151
|
+
{ name: '.fnconfig.yaml (discovered per-function)', value: 'fnconfig' },
|
|
152
|
+
{ name: 'Both (merge; .fnconfig overrides)', value: 'both' },
|
|
153
|
+
],
|
|
154
|
+
default: 'both'
|
|
155
|
+
}
|
|
156
|
+
]);
|
|
157
|
+
sourceChoice = answer.source;
|
|
158
|
+
} catch {}
|
|
159
|
+
|
|
142
160
|
try {
|
|
143
161
|
const discovered = discoverFnConfigs((cli as any).currentDir);
|
|
144
|
-
const
|
|
145
|
-
(
|
|
162
|
+
const central = (cli as any).controller!.config!.functions || [];
|
|
163
|
+
if (sourceChoice === 'central') {
|
|
164
|
+
(cli as any).controller!.config!.functions = central as any;
|
|
165
|
+
} else if (sourceChoice === 'fnconfig') {
|
|
166
|
+
(cli as any).controller!.config!.functions = discovered as any;
|
|
167
|
+
} else {
|
|
168
|
+
const merged = mergeDiscoveredFunctions(central, discovered);
|
|
169
|
+
(cli as any).controller!.config!.functions = merged as any;
|
|
170
|
+
}
|
|
146
171
|
} catch {}
|
|
147
172
|
|
|
148
173
|
const functions = await (cli as any).selectFunctions(
|
|
@@ -12,19 +12,21 @@ export const schemaCommands = {
|
|
|
12
12
|
MessageFormatter.progress("Generating schemas...", { prefix: "Schemas" });
|
|
13
13
|
|
|
14
14
|
// Prompt user for schema type preference
|
|
15
|
-
const { schemaType } = await inquirer.prompt([
|
|
16
|
-
{
|
|
17
|
-
type: "list",
|
|
18
|
-
name: "schemaType",
|
|
19
|
-
message: "What type of schemas would you like to generate?",
|
|
20
|
-
choices: [
|
|
21
|
-
{ name: "TypeScript (Zod) schemas", value: "zod" },
|
|
22
|
-
{ name: "JSON schemas", value: "json" },
|
|
23
|
-
{ name: "
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
15
|
+
const { schemaType } = await inquirer.prompt([
|
|
16
|
+
{
|
|
17
|
+
type: "list",
|
|
18
|
+
name: "schemaType",
|
|
19
|
+
message: "What type of schemas would you like to generate?",
|
|
20
|
+
choices: [
|
|
21
|
+
{ name: "TypeScript (Zod) schemas", value: "zod" },
|
|
22
|
+
{ name: "JSON schemas", value: "json" },
|
|
23
|
+
{ name: "Python (Pydantic) models", value: "pydantic" },
|
|
24
|
+
{ name: "TypeScript + JSON", value: "both" },
|
|
25
|
+
{ name: "All (Zod, JSON, Pydantic)", value: "all" },
|
|
26
|
+
],
|
|
27
|
+
default: "all",
|
|
28
|
+
},
|
|
29
|
+
]);
|
|
28
30
|
|
|
29
31
|
// Get the config folder path (where the config file is located)
|
|
30
32
|
const configFolderPath = (cli as any).controller!.getAppwriteFolderPath();
|
|
@@ -33,14 +35,27 @@ export const schemaCommands = {
|
|
|
33
35
|
return;
|
|
34
36
|
}
|
|
35
37
|
|
|
36
|
-
//
|
|
37
|
-
const
|
|
38
|
-
|
|
38
|
+
// Prompt for schema output directory (optional override)
|
|
39
|
+
const defaultSchemaOut = path.join(configFolderPath, (cli as any).controller!.config?.schemaConfig?.outputDirectory || 'schemas');
|
|
40
|
+
const { schemaOutDir } = await inquirer.prompt([
|
|
41
|
+
{
|
|
42
|
+
type: 'input',
|
|
43
|
+
name: 'schemaOutDir',
|
|
44
|
+
message: 'Output directory for schemas:',
|
|
45
|
+
default: defaultSchemaOut,
|
|
46
|
+
validate: (input: string) => input && input.trim().length > 0 ? true : 'Please provide an output directory',
|
|
47
|
+
}
|
|
48
|
+
]);
|
|
49
|
+
|
|
50
|
+
// Create SchemaGenerator with the correct base path and generate schemas
|
|
51
|
+
const schemaGenerator = new SchemaGenerator((cli as any).controller!.config!, configFolderPath);
|
|
52
|
+
const outDirRel = path.isAbsolute(schemaOutDir) ? schemaOutDir : path.relative(configFolderPath, schemaOutDir);
|
|
53
|
+
await schemaGenerator.generateSchemas({ format: schemaType as any, verbose: true, outputDir: outDirRel });
|
|
39
54
|
|
|
40
55
|
MessageFormatter.success("Schema generation completed", { prefix: "Schemas" });
|
|
41
56
|
},
|
|
42
57
|
|
|
43
|
-
async generateConstants(cli: InteractiveCLI): Promise<void> {
|
|
58
|
+
async generateConstants(cli: InteractiveCLI): Promise<void> {
|
|
44
59
|
MessageFormatter.progress("Generating cross-language constants...", { prefix: "Constants" });
|
|
45
60
|
|
|
46
61
|
if (!(cli as any).controller?.config) {
|
|
@@ -48,8 +63,8 @@ export const schemaCommands = {
|
|
|
48
63
|
return;
|
|
49
64
|
}
|
|
50
65
|
|
|
51
|
-
// Prompt for languages
|
|
52
|
-
const { languages } = await inquirer.prompt([
|
|
66
|
+
// Prompt for languages
|
|
67
|
+
const { languages } = await inquirer.prompt([
|
|
53
68
|
{
|
|
54
69
|
type: "checkbox",
|
|
55
70
|
name: "languages",
|
|
@@ -70,7 +85,23 @@ export const schemaCommands = {
|
|
|
70
85
|
return true;
|
|
71
86
|
},
|
|
72
87
|
},
|
|
73
|
-
]);
|
|
88
|
+
]);
|
|
89
|
+
|
|
90
|
+
// Prompt for which constants to include
|
|
91
|
+
const { includeWhat } = await inquirer.prompt([
|
|
92
|
+
{
|
|
93
|
+
type: 'checkbox',
|
|
94
|
+
name: 'includeWhat',
|
|
95
|
+
message: 'Select which constants to generate:',
|
|
96
|
+
choices: [
|
|
97
|
+
{ name: 'Databases', value: 'databases', checked: true },
|
|
98
|
+
{ name: 'Collections/Tables', value: 'collections', checked: true },
|
|
99
|
+
{ name: 'Buckets', value: 'buckets', checked: true },
|
|
100
|
+
{ name: 'Functions', value: 'functions', checked: true },
|
|
101
|
+
],
|
|
102
|
+
validate: (input) => input.length > 0 ? true : 'Select at least one category',
|
|
103
|
+
}
|
|
104
|
+
]);
|
|
74
105
|
|
|
75
106
|
// Determine default output directory based on config location
|
|
76
107
|
const configPath = (cli as any).controller!.getAppwriteFolderPath();
|
|
@@ -98,8 +129,14 @@ export const schemaCommands = {
|
|
|
98
129
|
const { ConstantsGenerator } = await import("../../utils/constantsGenerator.js");
|
|
99
130
|
const generator = new ConstantsGenerator((cli as any).controller.config);
|
|
100
131
|
|
|
101
|
-
|
|
102
|
-
|
|
132
|
+
const include = {
|
|
133
|
+
databases: includeWhat.includes('databases'),
|
|
134
|
+
collections: includeWhat.includes('collections'),
|
|
135
|
+
buckets: includeWhat.includes('buckets'),
|
|
136
|
+
functions: includeWhat.includes('functions'),
|
|
137
|
+
};
|
|
138
|
+
MessageFormatter.info(`Generating constants for: ${languages.join(", ")}`, { prefix: "Constants" });
|
|
139
|
+
await generator.generateFiles(languages, outputDir, include);
|
|
103
140
|
|
|
104
141
|
MessageFormatter.success(`Constants generated in ${outputDir}`, { prefix: "Constants" });
|
|
105
142
|
} catch (error) {
|