appwrite-utils-cli 1.8.2 → 1.8.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. package/CHANGELOG.md +6 -1
  2. package/README.md +42 -13
  3. package/dist/adapters/TablesDBAdapter.js +1 -1
  4. package/dist/cli/commands/functionCommands.js +30 -3
  5. package/dist/cli/commands/schemaCommands.js +39 -4
  6. package/dist/cli/commands/storageCommands.d.ts +5 -0
  7. package/dist/cli/commands/storageCommands.js +143 -0
  8. package/dist/collections/attributes.js +7 -7
  9. package/dist/collections/methods.js +1 -1
  10. package/dist/collections/tableOperations.js +2 -2
  11. package/dist/interactiveCLI.d.ts +1 -0
  12. package/dist/interactiveCLI.js +30 -0
  13. package/dist/main.js +17 -0
  14. package/dist/migrations/appwriteToX.js +1 -1
  15. package/dist/migrations/yaml/generateImportSchemas.js +2 -2
  16. package/dist/setupCommands.js +6 -0
  17. package/dist/shared/attributeMapper.js +2 -2
  18. package/dist/shared/jsonSchemaGenerator.js +3 -1
  19. package/dist/shared/pydanticModelGenerator.d.ts +17 -0
  20. package/dist/shared/pydanticModelGenerator.js +615 -0
  21. package/dist/shared/schemaGenerator.d.ts +3 -2
  22. package/dist/shared/schemaGenerator.js +22 -9
  23. package/dist/storage/methods.js +50 -7
  24. package/dist/utils/configDiscovery.js +2 -3
  25. package/dist/utils/constantsGenerator.d.ts +20 -8
  26. package/dist/utils/constantsGenerator.js +37 -25
  27. package/dist/utils/projectConfig.js +1 -1
  28. package/dist/utils/yamlConverter.d.ts +2 -2
  29. package/dist/utils/yamlConverter.js +2 -2
  30. package/package.json +1 -1
  31. package/src/adapters/TablesDBAdapter.ts +1 -1
  32. package/src/cli/commands/functionCommands.ts +28 -3
  33. package/src/cli/commands/schemaCommands.ts +59 -22
  34. package/src/cli/commands/storageCommands.ts +152 -0
  35. package/src/collections/attributes.ts +7 -7
  36. package/src/collections/methods.ts +7 -7
  37. package/src/collections/tableOperations.ts +2 -2
  38. package/src/interactiveCLI.ts +42 -12
  39. package/src/main.ts +32 -9
  40. package/src/migrations/appwriteToX.ts +1 -1
  41. package/src/migrations/yaml/generateImportSchemas.ts +7 -7
  42. package/src/setupCommands.ts +6 -0
  43. package/src/shared/attributeMapper.ts +2 -2
  44. package/src/shared/jsonSchemaGenerator.ts +4 -2
  45. package/src/shared/pydanticModelGenerator.ts +618 -0
  46. package/src/shared/schemaGenerator.ts +38 -25
  47. package/src/storage/methods.ts +67 -23
  48. package/src/utils/configDiscovery.ts +40 -41
  49. package/src/utils/constantsGenerator.ts +43 -26
  50. package/src/utils/projectConfig.ts +11 -11
  51. package/src/utils/yamlConverter.ts +40 -40
@@ -345,28 +345,34 @@ export default appwriteConfig;
345
345
  this.relationshipMap = extractTwoWayRelationships(this.config);
346
346
  }
347
347
 
348
- public generateSchemas(options: {
349
- format?: "zod" | "json" | "both";
350
- verbose?: boolean;
351
- } = {}): void {
352
- const { format = "both", verbose = false } = options;
348
+ public async generateSchemas(options: {
349
+ format?: "zod" | "json" | "pydantic" | "both" | "all";
350
+ verbose?: boolean;
351
+ outputDir?: string;
352
+ } = {}): Promise<void> {
353
+ const { format = "both", verbose = false, outputDir } = options;
353
354
 
354
355
  if (!this.config.collections) {
355
356
  return;
356
357
  }
357
358
 
358
359
  // Create schemas directory using config setting
359
- const outputDir = this.config.schemaConfig?.outputDirectory || "schemas";
360
- const schemasPath = outputDir === "schemas"
361
- ? resolveSchemaDir(this.appwriteFolderPath)
362
- : path.join(this.appwriteFolderPath, outputDir);
360
+ const configuredDir = outputDir || this.config.schemaConfig?.outputDirectory || "schemas";
361
+ let schemasPath: string;
362
+ if (path.isAbsolute(configuredDir)) {
363
+ schemasPath = configuredDir;
364
+ } else if (configuredDir === "schemas") {
365
+ schemasPath = resolveSchemaDir(this.appwriteFolderPath);
366
+ } else {
367
+ schemasPath = path.join(this.appwriteFolderPath, configuredDir);
368
+ }
363
369
  if (!fs.existsSync(schemasPath)) {
364
370
  fs.mkdirSync(schemasPath, { recursive: true });
365
371
  }
366
372
 
367
- // Generate Zod schemas (TypeScript)
368
- if (format === "zod" || format === "both") {
369
- this.config.collections.forEach((collection) => {
373
+ // Generate Zod schemas (TypeScript)
374
+ if (format === "zod" || format === "both" || format === "all") {
375
+ this.config.collections.forEach((collection) => {
370
376
  const schemaString = this.createSchemaStringV4(
371
377
  collection.name,
372
378
  collection.attributes || []
@@ -381,19 +387,26 @@ export default appwriteConfig;
381
387
  }
382
388
 
383
389
  // Generate JSON schemas (all at once)
384
- if (format === "json" || format === "both") {
385
- const jsonSchemaGenerator = new JsonSchemaGenerator(this.config, this.appwriteFolderPath);
386
- jsonSchemaGenerator.generateJsonSchemas({
387
- outputFormat: format === "json" ? "json" : "both",
388
- outputDirectory: outputDir,
389
- verbose: verbose
390
- });
391
- }
392
-
393
- if (verbose) {
394
- MessageFormatter.success(`Schema generation completed (format: ${format})`, { prefix: "Schema" });
395
- }
396
- }
390
+ if (format === "json" || format === "both" || format === "all") {
391
+ const jsonSchemaGenerator = new JsonSchemaGenerator(this.config, this.appwriteFolderPath);
392
+ jsonSchemaGenerator.generateJsonSchemas({
393
+ outputFormat: format === "json" ? "json" : "both",
394
+ outputDirectory: configuredDir,
395
+ verbose: verbose
396
+ });
397
+ }
398
+
399
+ // Generate Python Pydantic models
400
+ if (format === "pydantic" || format === "all") {
401
+ const mod = await import("./pydanticModelGenerator.js");
402
+ const pgen = new mod.PydanticModelGenerator(this.config, this.appwriteFolderPath);
403
+ pgen.generatePydanticModels({ baseOutputDirectory: schemasPath, verbose });
404
+ }
405
+
406
+ if (verbose) {
407
+ MessageFormatter.success(`Schema generation completed (format: ${format})`, { prefix: "Schema" });
408
+ }
409
+ }
397
410
 
398
411
  // Zod v4 recursive getter-based schemas
399
412
  createSchemaStringV4 = (name: string, attributes: Attribute[]): string => {
@@ -105,18 +105,65 @@ export const deleteFile = async (
105
105
  return await storage.deleteFile(bucketId, fileId);
106
106
  };
107
107
 
108
- export const ensureDatabaseConfigBucketsExist = async (
109
- storage: Storage,
110
- config: AppwriteConfig,
111
- databases: Models.Database[] = []
112
- ) => {
113
- for (const db of databases) {
114
- const database = config.databases?.find((d) => d.$id === db.$id);
115
- if (database?.bucket) {
116
- try {
117
- await storage.getBucket(database.bucket.$id);
118
- console.log(`Bucket ${database.bucket.$id} already exists.`);
119
- } catch (e) {
108
+ export const ensureDatabaseConfigBucketsExist = async (
109
+ storage: Storage,
110
+ config: AppwriteConfig,
111
+ databases: Models.Database[] = []
112
+ ) => {
113
+ for (const db of databases) {
114
+ const database = config.databases?.find((d) => d.$id === db.$id);
115
+ if (database?.bucket) {
116
+ try {
117
+ const existing = await storage.getBucket(database.bucket.$id);
118
+ // Compare and update if needed
119
+ const desired = database.bucket;
120
+ // Build desired permissions via Permission helper
121
+ const permissions: string[] = [];
122
+ if (desired.permissions && desired.permissions.length > 0) {
123
+ for (const p of desired.permissions as any[]) {
124
+ switch (p.permission) {
125
+ case 'read': permissions.push(Permission.read(p.target)); break;
126
+ case 'create': permissions.push(Permission.create(p.target)); break;
127
+ case 'update': permissions.push(Permission.update(p.target)); break;
128
+ case 'delete': permissions.push(Permission.delete(p.target)); break;
129
+ case 'write': permissions.push(Permission.write(p.target)); break;
130
+ default: break;
131
+ }
132
+ }
133
+ }
134
+ const diff = (
135
+ existing.name !== desired.name ||
136
+ JSON.stringify(existing.$permissions || []) !== JSON.stringify(permissions) ||
137
+ !!existing.fileSecurity !== !!desired.fileSecurity ||
138
+ !!existing.enabled !== !!desired.enabled ||
139
+ (existing.maximumFileSize ?? undefined) !== (desired.maximumFileSize ?? undefined) ||
140
+ JSON.stringify(existing.allowedFileExtensions || []) !== JSON.stringify(desired.allowedFileExtensions || []) ||
141
+ String(existing.compression || 'none') !== String(desired.compression || 'none') ||
142
+ !!existing.encryption !== !!desired.encryption ||
143
+ !!existing.antivirus !== !!desired.antivirus
144
+ );
145
+ if (diff) {
146
+ try {
147
+ await storage.updateBucket(
148
+ desired.$id,
149
+ desired.name,
150
+ permissions,
151
+ desired.fileSecurity,
152
+ desired.enabled,
153
+ desired.maximumFileSize,
154
+ desired.allowedFileExtensions,
155
+ desired.compression as Compression,
156
+ desired.encryption,
157
+ desired.antivirus
158
+ );
159
+ MessageFormatter.info(`Updated bucket ${desired.$id} to match config`, { prefix: 'Buckets' });
160
+ } catch (updateErr) {
161
+ MessageFormatter.warning(`Failed to update bucket ${desired.$id}: ${updateErr instanceof Error ? updateErr.message : String(updateErr)}`, { prefix: 'Buckets' });
162
+ }
163
+ } else {
164
+ MessageFormatter.debug(`Bucket ${desired.$id} up-to-date`, undefined, { prefix: 'Buckets' });
165
+ }
166
+ } catch (e) {
120
167
  const permissions: string[] = [];
121
168
  if (
122
169
  database.bucket.permissions &&
@@ -158,17 +205,14 @@ export const ensureDatabaseConfigBucketsExist = async (
158
205
  database.bucket.encryption,
159
206
  database.bucket.antivirus
160
207
  );
161
- console.log(`Bucket ${database.bucket.$id} created successfully.`);
162
- } catch (createError) {
163
- // console.error(
164
- // `Failed to create bucket ${database.bucket.$id}:`,
165
- // createError
166
- // );
167
- }
168
- }
169
- }
170
- }
171
- };
208
+ MessageFormatter.success(`Bucket ${database.bucket.$id} created`, { prefix: 'Buckets' });
209
+ } catch (createError) {
210
+ MessageFormatter.error(`Failed to create bucket ${database.bucket.$id}`, createError instanceof Error ? createError : new Error(String(createError)), { prefix: 'Buckets' });
211
+ }
212
+ }
213
+ }
214
+ }
215
+ };
172
216
 
173
217
  export const wipeDocumentStorage = async (
174
218
  storage: Storage,
@@ -173,28 +173,27 @@ const YamlTableSchema = z.object({
173
173
  target: z.string()
174
174
  })
175
175
  ).optional().default([]),
176
- columns: z.array( // Tables use columns terminology
177
- z.object({
178
- key: z.string(),
179
- type: z.string(),
180
- size: z.number().optional(),
181
- required: z.boolean().default(false),
182
- array: z.boolean().optional(),
183
- encrypted: z.boolean().optional(), // Tables support encrypted property
184
- default: z.any().optional(),
185
- min: z.number().optional(),
186
- max: z.number().optional(),
187
- elements: z.array(z.string()).optional(),
188
- relatedTable: z.string().optional(), // Tables use relatedTable
189
- relationType: z.string().optional(),
190
- twoWay: z.boolean().optional(),
191
- twoWayKey: z.string().optional(),
192
- onDelete: z.string().optional(),
193
- side: z.string().optional(),
194
- encrypt: z.boolean().optional(),
195
- format: z.string().optional()
196
- })
197
- ).optional().default([]),
176
+ columns: z.array( // Tables use columns terminology
177
+ z.object({
178
+ key: z.string(),
179
+ type: z.string(),
180
+ size: z.number().optional(),
181
+ required: z.boolean().default(false),
182
+ array: z.boolean().optional(),
183
+ encrypt: z.boolean().optional(), // Tables support encrypt property
184
+ default: z.any().optional(),
185
+ min: z.number().optional(),
186
+ max: z.number().optional(),
187
+ elements: z.array(z.string()).optional(),
188
+ relatedTable: z.string().optional(), // Tables use relatedTable
189
+ relationType: z.string().optional(),
190
+ twoWay: z.boolean().optional(),
191
+ twoWayKey: z.string().optional(),
192
+ onDelete: z.string().optional(),
193
+ side: z.string().optional(),
194
+ format: z.string().optional()
195
+ })
196
+ ).optional().default([]),
198
197
  indexes: z.array(
199
198
  z.object({
200
199
  key: z.string(),
@@ -289,25 +288,25 @@ export const loadYamlTable = (filePath: string): CollectionCreate | null => {
289
288
  permission: p.permission as any,
290
289
  target: p.target
291
290
  })),
292
- attributes: parsedTable.columns.map(col => ({ // Convert columns to attributes
293
- key: col.key,
294
- type: col.type as any,
295
- size: col.size,
296
- required: col.required,
297
- array: col.array,
298
- xdefault: col.default,
299
- min: col.min,
300
- max: col.max,
301
- elements: col.elements,
302
- relatedCollection: col.relatedTable, // Convert relatedTable to relatedCollection
303
- relationType: col.relationType as any,
304
- twoWay: col.twoWay,
305
- twoWayKey: col.twoWayKey,
306
- onDelete: col.onDelete as any,
307
- side: col.side as any,
308
- encrypted: col.encrypted || col.encrypt, // Support both encrypted and encrypt
309
- format: col.format
310
- })),
291
+ attributes: parsedTable.columns.map(col => ({ // Convert columns to attributes
292
+ key: col.key,
293
+ type: col.type as any,
294
+ size: col.size,
295
+ required: col.required,
296
+ array: col.array,
297
+ xdefault: col.default,
298
+ min: col.min,
299
+ max: col.max,
300
+ elements: col.elements,
301
+ relatedCollection: col.relatedTable, // Convert relatedTable to relatedCollection
302
+ relationType: col.relationType as any,
303
+ twoWay: col.twoWay,
304
+ twoWayKey: col.twoWayKey,
305
+ onDelete: col.onDelete as any,
306
+ side: col.side as any,
307
+ encrypt: col.encrypt,
308
+ format: col.format
309
+ })),
311
310
  indexes: parsedTable.indexes.map(idx => ({
312
311
  key: idx.key,
313
312
  type: idx.type as any,
@@ -89,8 +89,8 @@ export class ConstantsGenerator {
89
89
  return name.toLowerCase();
90
90
  }
91
91
 
92
- generateTypeScript(): string {
93
- const { databases, collections, buckets, functions } = this.constants;
92
+ generateTypeScript(constantsOverride?: Constants): string {
93
+ const { databases, collections, buckets, functions } = constantsOverride || this.constants;
94
94
 
95
95
  return `// Auto-generated Appwrite constants
96
96
  // Generated on ${new Date().toISOString()}
@@ -125,8 +125,8 @@ export const ALL_FUNCTION_IDS = Object.values(FUNCTION_IDS);
125
125
  `;
126
126
  }
127
127
 
128
- generateJavaScript(): string {
129
- const { databases, collections, buckets, functions } = this.constants;
128
+ generateJavaScript(constantsOverride?: Constants): string {
129
+ const { databases, collections, buckets, functions } = constantsOverride || this.constants;
130
130
 
131
131
  return `// Auto-generated Appwrite constants
132
132
  // Generated on ${new Date().toISOString()}
@@ -155,8 +155,8 @@ export const ALL_FUNCTION_IDS = Object.values(FUNCTION_IDS);
155
155
  `;
156
156
  }
157
157
 
158
- generatePython(): string {
159
- const { databases, collections, buckets, functions } = this.constants;
158
+ generatePython(constantsOverride?: Constants): string {
159
+ const { databases, collections, buckets, functions } = constantsOverride || this.constants;
160
160
 
161
161
  return `# Auto-generated Appwrite constants
162
162
  # Generated on ${new Date().toISOString()}
@@ -196,8 +196,8 @@ ${Object.entries(functions).map(([key, value]) => ` "${this.toSnakeCase(key)}
196
196
  `;
197
197
  }
198
198
 
199
- generatePHP(): string {
200
- const { databases, collections, buckets, functions } = this.constants;
199
+ generatePHP(constantsOverride?: Constants): string {
200
+ const { databases, collections, buckets, functions } = constantsOverride || this.constants;
201
201
 
202
202
  return `<?php
203
203
  // Auto-generated Appwrite constants
@@ -252,8 +252,8 @@ ${Object.entries(functions).map(([key, value]) => ` '${key}' => '${value}
252
252
  `;
253
253
  }
254
254
 
255
- generateDart(): string {
256
- const { databases, collections, buckets, functions } = this.constants;
255
+ generateDart(constantsOverride?: Constants): string {
256
+ const { databases, collections, buckets, functions } = constantsOverride || this.constants;
257
257
 
258
258
  return `// Auto-generated Appwrite constants
259
259
  // Generated on ${new Date().toISOString()}
@@ -288,21 +288,22 @@ ${Object.entries(functions).map(([key, value]) => ` static String get ${this.to
288
288
  `;
289
289
  }
290
290
 
291
- generateJSON(): string {
291
+ generateJSON(constantsOverride?: Constants): string {
292
+ const c = constantsOverride || this.constants;
292
293
  return JSON.stringify({
293
294
  meta: {
294
295
  generated: new Date().toISOString(),
295
296
  generator: "appwrite-utils-cli"
296
297
  },
297
- databases: this.constants.databases,
298
- collections: this.constants.collections,
299
- buckets: this.constants.buckets,
300
- functions: this.constants.functions
298
+ databases: c.databases,
299
+ collections: c.collections,
300
+ buckets: c.buckets,
301
+ functions: c.functions
301
302
  }, null, 2);
302
303
  }
303
304
 
304
- generateEnv(): string {
305
- const { databases, collections, buckets, functions } = this.constants;
305
+ generateEnv(constantsOverride?: Constants): string {
306
+ const { databases, collections, buckets, functions } = constantsOverride || this.constants;
306
307
 
307
308
  const lines = [
308
309
  "# Auto-generated Appwrite constants",
@@ -324,17 +325,33 @@ ${Object.entries(functions).map(([key, value]) => ` static String get ${this.to
324
325
  return lines.join('\n');
325
326
  }
326
327
 
327
- async generateFiles(languages: SupportedLanguage[], outputDir: string): Promise<void> {
328
+ async generateFiles(
329
+ languages: SupportedLanguage[],
330
+ outputDir: string,
331
+ include?: { databases?: boolean; collections?: boolean; buckets?: boolean; functions?: boolean }
332
+ ): Promise<void> {
328
333
  await fs.mkdir(outputDir, { recursive: true });
329
334
 
335
+ const filterConstants = (): Constants => {
336
+ if (!include) return this.constants;
337
+ return {
338
+ databases: include.databases === false ? {} : this.constants.databases,
339
+ collections: include.collections === false ? {} : this.constants.collections,
340
+ buckets: include.buckets === false ? {} : this.constants.buckets,
341
+ functions: include.functions === false ? {} : this.constants.functions,
342
+ };
343
+ };
344
+
345
+ const subset = filterConstants();
346
+
330
347
  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" })
348
+ typescript: () => ({ content: this.generateTypeScript(subset), filename: "appwrite-constants.ts" }),
349
+ javascript: () => ({ content: this.generateJavaScript(subset), filename: "appwrite-constants.js" }),
350
+ python: () => ({ content: this.generatePython(subset), filename: "appwrite_constants.py" }),
351
+ php: () => ({ content: this.generatePHP(subset), filename: "AppwriteConstants.php" }),
352
+ dart: () => ({ content: this.generateDart(subset), filename: "appwrite_constants.dart" }),
353
+ json: () => ({ content: this.generateJSON(subset), filename: "appwrite-constants.json" }),
354
+ env: () => ({ content: this.generateEnv(subset), filename: ".env.appwrite" })
338
355
  };
339
356
 
340
357
  for (const language of languages) {
@@ -349,4 +366,4 @@ ${Object.entries(functions).map(([key, value]) => ` static String get ${this.to
349
366
  }
350
367
  }
351
368
  }
352
- }
369
+ }
@@ -251,16 +251,16 @@ export function getCollectionsFromProject(projectConfig: AppwriteProjectConfig):
251
251
  documentSecurity: table.rowSecurity || false,
252
252
  enabled: table.enabled !== false,
253
253
  // Convert columns to attributes for compatibility
254
- attributes: table.columns.map(col => ({
255
- key: col.key,
256
- type: col.type,
257
- required: col.required,
258
- array: col.array,
259
- size: col.size,
260
- default: col.default,
261
- encrypted: col.encrypt,
262
- unique: col.unique,
263
- })),
254
+ attributes: table.columns.map(col => ({
255
+ key: col.key,
256
+ type: col.type,
257
+ required: col.required,
258
+ array: col.array,
259
+ size: col.size,
260
+ default: col.default,
261
+ encrypt: col.encrypt,
262
+ unique: col.unique,
263
+ })),
264
264
  indexes: table.indexes || [],
265
265
  // Mark as coming from TablesDB for processing
266
266
  _isFromTablesDir: true,
@@ -296,4 +296,4 @@ export function isTablesDBProject(projectConfig: AppwriteProjectConfig): boolean
296
296
  */
297
297
  export function getProjectDirectoryName(projectConfig: AppwriteProjectConfig): "tables" | "collections" {
298
298
  return isTablesDBProject(projectConfig) ? "tables" : "collections";
299
- }
299
+ }
@@ -101,43 +101,43 @@ export interface YamlCollectionData {
101
101
  permission: string;
102
102
  target: string;
103
103
  }>;
104
- attributes?: Array<{
105
- key: string;
106
- type: string;
107
- size?: number;
108
- required?: boolean;
109
- array?: boolean;
110
- encrypted?: boolean;
111
- default?: any;
112
- min?: number;
113
- max?: number;
114
- elements?: string[];
115
- relatedCollection?: string;
116
- relationType?: string;
117
- twoWay?: boolean;
118
- twoWayKey?: string;
119
- onDelete?: string;
120
- side?: string;
121
- }>;
104
+ attributes?: Array<{
105
+ key: string;
106
+ type: string;
107
+ size?: number;
108
+ required?: boolean;
109
+ array?: boolean;
110
+ encrypt?: boolean;
111
+ default?: any;
112
+ min?: number;
113
+ max?: number;
114
+ elements?: string[];
115
+ relatedCollection?: string;
116
+ relationType?: string;
117
+ twoWay?: boolean;
118
+ twoWayKey?: string;
119
+ onDelete?: string;
120
+ side?: string;
121
+ }>;
122
122
  // Table terminology support (columns is an alias for attributes)
123
- columns?: Array<{
124
- key: string;
125
- type: string;
126
- size?: number;
127
- required?: boolean;
128
- array?: boolean;
129
- encrypted?: boolean;
130
- default?: any;
131
- min?: number;
132
- max?: number;
133
- elements?: string[];
134
- relatedTable?: string;
135
- relationType?: string;
136
- twoWay?: boolean;
137
- twoWayKey?: string;
138
- onDelete?: string;
139
- side?: string;
140
- }>;
123
+ columns?: Array<{
124
+ key: string;
125
+ type: string;
126
+ size?: number;
127
+ required?: boolean;
128
+ array?: boolean;
129
+ encrypt?: boolean;
130
+ default?: any;
131
+ min?: number;
132
+ max?: number;
133
+ elements?: string[];
134
+ relatedTable?: string;
135
+ relationType?: string;
136
+ twoWay?: boolean;
137
+ twoWayKey?: string;
138
+ onDelete?: string;
139
+ side?: string;
140
+ }>;
141
141
  indexes?: Array<{
142
142
  key: string;
143
143
  type: string;
@@ -205,10 +205,10 @@ export function collectionToYaml(
205
205
  if (attr.required !== undefined) yamlAttr.required = attr.required;
206
206
  if (attr.array !== undefined) yamlAttr.array = attr.array;
207
207
 
208
- // Always include encrypted field for string attributes (default to false)
209
- if (attr.type === 'string') {
210
- yamlAttr.encrypted = ('encrypted' in attr && attr.encrypted === true) ? true : false;
211
- }
208
+ // Always include encrypt field for string attributes (default to false)
209
+ if (attr.type === 'string') {
210
+ yamlAttr.encrypt = ('encrypt' in attr && (attr as any).encrypt === true) ? true : false;
211
+ }
212
212
 
213
213
  if ('xdefault' in attr && attr.xdefault !== undefined) yamlAttr.default = attr.xdefault;
214
214