appwrite-utils-cli 0.0.269 → 0.0.271

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
@@ -76,6 +76,9 @@ Replace `--args` with the appropriate options:
76
76
  - `--wipe-users` or `--wipeUsers`: Wipe all user data.
77
77
  - `--write-data` or `--writeData`: Write converted imported data to file
78
78
  - `--sync`: Synchronize your project's config and generate schema for your database
79
+ - `--endpoint`: Set a different endpoint for the migration target
80
+ - `--project`: Set a different project ID for the migration target
81
+ - `--key`: Set a different API key for the migration target
79
82
 
80
83
  For example, to run migrations in a development environment and import data:
81
84
 
@@ -89,16 +92,34 @@ To initialize your project, generate schemas, but not import data:
89
92
  npx --package=appwrite-utils-cli@latest appwrite-migrate --init
90
93
  ```
91
94
 
95
+ To sync:
96
+
97
+ ```bash
98
+ # If you have no appwriteConfig
99
+ npx --package=appwrite-utils-cli@latest appwrite-migrate --init
100
+
101
+ # Otherwise, you can remove everything in the config file down to the word collections, just leave your Databases, then run
102
+ npx --package=appwrite-utils-cli@latest appwrite-migrate --sync
103
+ ```
104
+
105
+ ### OpenAPI Generation (almost done, in progress)
106
+
107
+ Recently, I have also added an optional OpenAPI generation for each attribute in the schema. This is because I needed it and because I felt it would be nice to have. This is done using [this package](https://github.com/asteasolutions/zod-to-openapi), many thanks to them.
108
+
109
+ To use it, add a `description` to any attribute or collection, and it will export that schema to the `appwrite/openapi` folder
110
+
92
111
  This setup ensures that developers have robust tools at their fingertips to manage complex Appwrite projects effectively from the command line. I also have added logging automatically for information and errors as the console can be hard to keep up with.
93
112
 
94
113
  ### Roadmap
95
114
 
96
- - Syncing configuration
115
+ - Syncing configuration (DONE)
97
116
  - Better file format for config (potentially)
98
117
  - Separation of collections and import configuration from main config
99
118
 
100
119
  ### Changelog
101
120
 
121
+ - 0.0.271: Small change to update attributes that are different from each other by deleting the attribute and recreating, as we cannot update most things
122
+ - 0.0.270: Fixed enums in `--sync`, added optional OpenAPI generation (in progress, almost done, but wanted to push other changes), added `--endpoint`, `--project`, `--key` as optional parameters to change the target destination (shoutout to [pingu24k](https://github.com/pingu2k4) for pointing out these bugs and suggesting those changes for endpoint customization)
102
123
  - 0.0.254: Added `--sync` to synchronize your Appwrite instance with your local `appwriteConfig.yaml` and generate schemas
103
124
  - 0.0.253: Added `--writeData` (or `--write-data`) to command to write the output of the import data to a file called dataLoaderOutput in your root dir
104
125
  - 0.0.23: Added batching to user deletion
package/dist/main.js CHANGED
@@ -3,7 +3,6 @@ import { UtilsController } from "./utilsController.js";
3
3
  const args = process.argv.slice(2);
4
4
  async function main() {
5
5
  const controller = new UtilsController();
6
- await controller.init();
7
6
  let sync = false;
8
7
  let runProd = false;
9
8
  let runStaging = false;
@@ -15,6 +14,9 @@ async function main() {
15
14
  let importData = false;
16
15
  let wipeDocuments = false;
17
16
  let shouldWriteFile = false;
17
+ let endpoint;
18
+ let project;
19
+ let key;
18
20
  if (args.includes("--sync")) {
19
21
  sync = true;
20
22
  }
@@ -48,6 +50,15 @@ async function main() {
48
50
  if (args.includes("--write-data") || args.includes("--writeData")) {
49
51
  shouldWriteFile = true;
50
52
  }
53
+ if (args.includes("--endpoint")) {
54
+ endpoint = args[args.indexOf("--endpoint") + 1];
55
+ }
56
+ if (args.includes("--project")) {
57
+ project = args[args.indexOf("--project") + 1];
58
+ }
59
+ if (args.includes("--key")) {
60
+ key = args[args.indexOf("--key") + 1];
61
+ }
51
62
  if (args.includes("--init")) {
52
63
  await controller.run({
53
64
  sync: sync,
@@ -63,6 +74,9 @@ async function main() {
63
74
  importData: false,
64
75
  checkDuplicates: false,
65
76
  shouldWriteFile: shouldWriteFile,
77
+ endpoint: endpoint,
78
+ project: project,
79
+ key: key,
66
80
  });
67
81
  }
68
82
  else {
@@ -80,6 +94,9 @@ async function main() {
80
94
  importData: importData,
81
95
  checkDuplicates: false,
82
96
  shouldWriteFile: shouldWriteFile,
97
+ endpoint: endpoint,
98
+ project: project,
99
+ key: key,
83
100
  });
84
101
  }
85
102
  }
@@ -12,6 +12,8 @@ export declare class AppwriteToX {
12
12
  size: number;
13
13
  xdefault?: string | null | undefined;
14
14
  encrypted?: boolean | undefined;
15
+ format?: string | null | undefined;
16
+ description?: string | Record<string, string> | null | undefined;
15
17
  } | {
16
18
  key: string;
17
19
  type: "integer";
@@ -21,6 +23,7 @@ export declare class AppwriteToX {
21
23
  min?: number | undefined;
22
24
  max?: number | undefined;
23
25
  xdefault?: number | null | undefined;
26
+ description?: string | Record<string, string> | null | undefined;
24
27
  } | {
25
28
  key: string;
26
29
  type: "float";
@@ -30,6 +33,7 @@ export declare class AppwriteToX {
30
33
  min?: number | undefined;
31
34
  max?: number | undefined;
32
35
  xdefault?: number | null | undefined;
36
+ description?: string | Record<string, string> | null | undefined;
33
37
  } | {
34
38
  key: string;
35
39
  type: "boolean";
@@ -37,6 +41,7 @@ export declare class AppwriteToX {
37
41
  required: boolean;
38
42
  array: boolean;
39
43
  xdefault?: boolean | null | undefined;
44
+ description?: string | Record<string, string> | null | undefined;
40
45
  } | {
41
46
  key: string;
42
47
  type: "datetime";
@@ -44,6 +49,7 @@ export declare class AppwriteToX {
44
49
  required: boolean;
45
50
  array: boolean;
46
51
  xdefault?: string | null | undefined;
52
+ description?: string | Record<string, string> | null | undefined;
47
53
  } | {
48
54
  key: string;
49
55
  type: "email";
@@ -51,6 +57,7 @@ export declare class AppwriteToX {
51
57
  required: boolean;
52
58
  array: boolean;
53
59
  xdefault?: string | null | undefined;
60
+ description?: string | Record<string, string> | null | undefined;
54
61
  } | {
55
62
  key: string;
56
63
  type: "ip";
@@ -58,6 +65,7 @@ export declare class AppwriteToX {
58
65
  required: boolean;
59
66
  array: boolean;
60
67
  xdefault?: string | null | undefined;
68
+ description?: string | Record<string, string> | null | undefined;
61
69
  } | {
62
70
  key: string;
63
71
  type: "url";
@@ -65,6 +73,7 @@ export declare class AppwriteToX {
65
73
  required: boolean;
66
74
  array: boolean;
67
75
  xdefault?: string | null | undefined;
76
+ description?: string | Record<string, string> | null | undefined;
68
77
  } | {
69
78
  key: string;
70
79
  type: "enum";
@@ -73,6 +82,7 @@ export declare class AppwriteToX {
73
82
  array: boolean;
74
83
  elements: string[];
75
84
  xdefault?: string | null | undefined;
85
+ description?: string | Record<string, string> | null | undefined;
76
86
  } | {
77
87
  key: string;
78
88
  type: "relationship";
@@ -89,6 +99,7 @@ export declare class AppwriteToX {
89
99
  originalIdField: string;
90
100
  targetField?: string | undefined;
91
101
  } | undefined;
102
+ description?: string | Record<string, string> | null | undefined;
92
103
  })[]>;
93
104
  appwriteFolderPath: string;
94
105
  constructor(config: AppwriteConfig, appwriteFolderPath: string);
@@ -56,7 +56,14 @@ export class AppwriteToX {
56
56
  // Parse the collection permissions and attributes
57
57
  const collPermissions = this.parsePermissionsArray(collection.$permissions);
58
58
  const collAttributes = attributesSchema
59
- .parse(collection.attributes)
59
+ .parse(collection.attributes.map((attr) => {
60
+ if (attr.type === "string" &&
61
+ attr.format &&
62
+ attr.format.length > 0) {
63
+ return { ...attr, type: attr.format };
64
+ }
65
+ return attr;
66
+ }))
60
67
  .filter((attribute) => attribute.type === "relationship"
61
68
  ? attribute.side !== "child"
62
69
  : true);
@@ -1,5 +1,6 @@
1
1
  import { Query } from "node-appwrite";
2
2
  import { nameToIdMapping, enqueueOperation } from "./queue.js";
3
+ import _ from "lodash";
3
4
  export const createOrUpdateAttribute = async (db, dbId, collection, attribute) => {
4
5
  let action = "create";
5
6
  let foundAttribute;
@@ -10,12 +11,13 @@ export const createOrUpdateAttribute = async (db, dbId, collection, attribute) =
10
11
  foundAttribute = undefined;
11
12
  }
12
13
  let numSameAttributes = 0;
13
- if (foundAttribute && foundAttribute.key === attribute.key) {
14
+ if (foundAttribute && _.isEqual(foundAttribute, attribute)) {
14
15
  numSameAttributes++;
15
16
  return;
16
17
  }
17
- else if (foundAttribute) {
18
- action = "update";
18
+ else if (foundAttribute && !_.isEqual(foundAttribute, attribute)) {
19
+ console.log("Deleting attribute with same key but different values, assuming update...");
20
+ await db.deleteAttribute(dbId, collection.$id, attribute.key);
19
21
  }
20
22
  // Relationship attribute logic with adjustments
21
23
  let collectionFoundViaRelatedCollection;
@@ -176,6 +176,7 @@ export type OperationCreate = z.infer<typeof OperationCreateSchema>;
176
176
  export declare const getMigrationCollectionSchemas: () => {
177
177
  CurrentOperations: {
178
178
  collection: {
179
+ name: string;
179
180
  attributes: ({
180
181
  key: string;
181
182
  type: "string";
@@ -185,6 +186,8 @@ export declare const getMigrationCollectionSchemas: () => {
185
186
  size: number;
186
187
  xdefault?: string | null | undefined;
187
188
  encrypted?: boolean | undefined;
189
+ format?: string | null | undefined;
190
+ description?: string | Record<string, string> | null | undefined;
188
191
  } | {
189
192
  key: string;
190
193
  type: "integer";
@@ -194,6 +197,7 @@ export declare const getMigrationCollectionSchemas: () => {
194
197
  min?: number | undefined;
195
198
  max?: number | undefined;
196
199
  xdefault?: number | null | undefined;
200
+ description?: string | Record<string, string> | null | undefined;
197
201
  } | {
198
202
  key: string;
199
203
  type: "float";
@@ -203,6 +207,7 @@ export declare const getMigrationCollectionSchemas: () => {
203
207
  min?: number | undefined;
204
208
  max?: number | undefined;
205
209
  xdefault?: number | null | undefined;
210
+ description?: string | Record<string, string> | null | undefined;
206
211
  } | {
207
212
  key: string;
208
213
  type: "boolean";
@@ -210,6 +215,7 @@ export declare const getMigrationCollectionSchemas: () => {
210
215
  required: boolean;
211
216
  array: boolean;
212
217
  xdefault?: boolean | null | undefined;
218
+ description?: string | Record<string, string> | null | undefined;
213
219
  } | {
214
220
  key: string;
215
221
  type: "datetime";
@@ -217,6 +223,7 @@ export declare const getMigrationCollectionSchemas: () => {
217
223
  required: boolean;
218
224
  array: boolean;
219
225
  xdefault?: string | null | undefined;
226
+ description?: string | Record<string, string> | null | undefined;
220
227
  } | {
221
228
  key: string;
222
229
  type: "email";
@@ -224,6 +231,7 @@ export declare const getMigrationCollectionSchemas: () => {
224
231
  required: boolean;
225
232
  array: boolean;
226
233
  xdefault?: string | null | undefined;
234
+ description?: string | Record<string, string> | null | undefined;
227
235
  } | {
228
236
  key: string;
229
237
  type: "ip";
@@ -231,6 +239,7 @@ export declare const getMigrationCollectionSchemas: () => {
231
239
  required: boolean;
232
240
  array: boolean;
233
241
  xdefault?: string | null | undefined;
242
+ description?: string | Record<string, string> | null | undefined;
234
243
  } | {
235
244
  key: string;
236
245
  type: "url";
@@ -238,6 +247,7 @@ export declare const getMigrationCollectionSchemas: () => {
238
247
  required: boolean;
239
248
  array: boolean;
240
249
  xdefault?: string | null | undefined;
250
+ description?: string | Record<string, string> | null | undefined;
241
251
  } | {
242
252
  key: string;
243
253
  type: "enum";
@@ -246,6 +256,7 @@ export declare const getMigrationCollectionSchemas: () => {
246
256
  array: boolean;
247
257
  elements: string[];
248
258
  xdefault?: string | null | undefined;
259
+ description?: string | Record<string, string> | null | undefined;
249
260
  } | {
250
261
  key: string;
251
262
  type: "relationship";
@@ -262,8 +273,8 @@ export declare const getMigrationCollectionSchemas: () => {
262
273
  originalIdField: string;
263
274
  targetField?: string | undefined;
264
275
  } | undefined;
276
+ description?: string | Record<string, string> | null | undefined;
265
277
  })[];
266
- name: string;
267
278
  $id: string;
268
279
  enabled: boolean;
269
280
  documentSecurity: boolean;
@@ -313,6 +324,7 @@ export declare const getMigrationCollectionSchemas: () => {
313
324
  targetField: string;
314
325
  } | undefined;
315
326
  }[];
327
+ description?: string | undefined;
316
328
  databaseId?: string | undefined;
317
329
  };
318
330
  attributes: ({
@@ -324,6 +336,8 @@ export declare const getMigrationCollectionSchemas: () => {
324
336
  size: number;
325
337
  xdefault?: string | null | undefined;
326
338
  encrypted?: boolean | undefined;
339
+ format?: string | null | undefined;
340
+ description?: string | Record<string, string> | null | undefined;
327
341
  } | {
328
342
  key: string;
329
343
  type: "integer";
@@ -333,6 +347,7 @@ export declare const getMigrationCollectionSchemas: () => {
333
347
  min?: number | undefined;
334
348
  max?: number | undefined;
335
349
  xdefault?: number | null | undefined;
350
+ description?: string | Record<string, string> | null | undefined;
336
351
  } | {
337
352
  key: string;
338
353
  type: "float";
@@ -342,6 +357,7 @@ export declare const getMigrationCollectionSchemas: () => {
342
357
  min?: number | undefined;
343
358
  max?: number | undefined;
344
359
  xdefault?: number | null | undefined;
360
+ description?: string | Record<string, string> | null | undefined;
345
361
  } | {
346
362
  key: string;
347
363
  type: "boolean";
@@ -349,6 +365,7 @@ export declare const getMigrationCollectionSchemas: () => {
349
365
  required: boolean;
350
366
  array: boolean;
351
367
  xdefault?: boolean | null | undefined;
368
+ description?: string | Record<string, string> | null | undefined;
352
369
  } | {
353
370
  key: string;
354
371
  type: "datetime";
@@ -356,6 +373,7 @@ export declare const getMigrationCollectionSchemas: () => {
356
373
  required: boolean;
357
374
  array: boolean;
358
375
  xdefault?: string | null | undefined;
376
+ description?: string | Record<string, string> | null | undefined;
359
377
  } | {
360
378
  key: string;
361
379
  type: "email";
@@ -363,6 +381,7 @@ export declare const getMigrationCollectionSchemas: () => {
363
381
  required: boolean;
364
382
  array: boolean;
365
383
  xdefault?: string | null | undefined;
384
+ description?: string | Record<string, string> | null | undefined;
366
385
  } | {
367
386
  key: string;
368
387
  type: "ip";
@@ -370,6 +389,7 @@ export declare const getMigrationCollectionSchemas: () => {
370
389
  required: boolean;
371
390
  array: boolean;
372
391
  xdefault?: string | null | undefined;
392
+ description?: string | Record<string, string> | null | undefined;
373
393
  } | {
374
394
  key: string;
375
395
  type: "url";
@@ -377,6 +397,7 @@ export declare const getMigrationCollectionSchemas: () => {
377
397
  required: boolean;
378
398
  array: boolean;
379
399
  xdefault?: string | null | undefined;
400
+ description?: string | Record<string, string> | null | undefined;
380
401
  } | {
381
402
  key: string;
382
403
  type: "enum";
@@ -385,6 +406,7 @@ export declare const getMigrationCollectionSchemas: () => {
385
406
  array: boolean;
386
407
  elements: string[];
387
408
  xdefault?: string | null | undefined;
409
+ description?: string | Record<string, string> | null | undefined;
388
410
  } | {
389
411
  key: string;
390
412
  type: "relationship";
@@ -401,10 +423,12 @@ export declare const getMigrationCollectionSchemas: () => {
401
423
  originalIdField: string;
402
424
  targetField?: string | undefined;
403
425
  } | undefined;
426
+ description?: string | Record<string, string> | null | undefined;
404
427
  })[];
405
428
  };
406
429
  Batches: {
407
430
  collection: {
431
+ name: string;
408
432
  attributes: ({
409
433
  key: string;
410
434
  type: "string";
@@ -414,6 +438,8 @@ export declare const getMigrationCollectionSchemas: () => {
414
438
  size: number;
415
439
  xdefault?: string | null | undefined;
416
440
  encrypted?: boolean | undefined;
441
+ format?: string | null | undefined;
442
+ description?: string | Record<string, string> | null | undefined;
417
443
  } | {
418
444
  key: string;
419
445
  type: "integer";
@@ -423,6 +449,7 @@ export declare const getMigrationCollectionSchemas: () => {
423
449
  min?: number | undefined;
424
450
  max?: number | undefined;
425
451
  xdefault?: number | null | undefined;
452
+ description?: string | Record<string, string> | null | undefined;
426
453
  } | {
427
454
  key: string;
428
455
  type: "float";
@@ -432,6 +459,7 @@ export declare const getMigrationCollectionSchemas: () => {
432
459
  min?: number | undefined;
433
460
  max?: number | undefined;
434
461
  xdefault?: number | null | undefined;
462
+ description?: string | Record<string, string> | null | undefined;
435
463
  } | {
436
464
  key: string;
437
465
  type: "boolean";
@@ -439,6 +467,7 @@ export declare const getMigrationCollectionSchemas: () => {
439
467
  required: boolean;
440
468
  array: boolean;
441
469
  xdefault?: boolean | null | undefined;
470
+ description?: string | Record<string, string> | null | undefined;
442
471
  } | {
443
472
  key: string;
444
473
  type: "datetime";
@@ -446,6 +475,7 @@ export declare const getMigrationCollectionSchemas: () => {
446
475
  required: boolean;
447
476
  array: boolean;
448
477
  xdefault?: string | null | undefined;
478
+ description?: string | Record<string, string> | null | undefined;
449
479
  } | {
450
480
  key: string;
451
481
  type: "email";
@@ -453,6 +483,7 @@ export declare const getMigrationCollectionSchemas: () => {
453
483
  required: boolean;
454
484
  array: boolean;
455
485
  xdefault?: string | null | undefined;
486
+ description?: string | Record<string, string> | null | undefined;
456
487
  } | {
457
488
  key: string;
458
489
  type: "ip";
@@ -460,6 +491,7 @@ export declare const getMigrationCollectionSchemas: () => {
460
491
  required: boolean;
461
492
  array: boolean;
462
493
  xdefault?: string | null | undefined;
494
+ description?: string | Record<string, string> | null | undefined;
463
495
  } | {
464
496
  key: string;
465
497
  type: "url";
@@ -467,6 +499,7 @@ export declare const getMigrationCollectionSchemas: () => {
467
499
  required: boolean;
468
500
  array: boolean;
469
501
  xdefault?: string | null | undefined;
502
+ description?: string | Record<string, string> | null | undefined;
470
503
  } | {
471
504
  key: string;
472
505
  type: "enum";
@@ -475,6 +508,7 @@ export declare const getMigrationCollectionSchemas: () => {
475
508
  array: boolean;
476
509
  elements: string[];
477
510
  xdefault?: string | null | undefined;
511
+ description?: string | Record<string, string> | null | undefined;
478
512
  } | {
479
513
  key: string;
480
514
  type: "relationship";
@@ -491,8 +525,8 @@ export declare const getMigrationCollectionSchemas: () => {
491
525
  originalIdField: string;
492
526
  targetField?: string | undefined;
493
527
  } | undefined;
528
+ description?: string | Record<string, string> | null | undefined;
494
529
  })[];
495
- name: string;
496
530
  $id: string;
497
531
  enabled: boolean;
498
532
  documentSecurity: boolean;
@@ -542,6 +576,7 @@ export declare const getMigrationCollectionSchemas: () => {
542
576
  targetField: string;
543
577
  } | undefined;
544
578
  }[];
579
+ description?: string | undefined;
545
580
  databaseId?: string | undefined;
546
581
  };
547
582
  attributes: ({
@@ -553,6 +588,8 @@ export declare const getMigrationCollectionSchemas: () => {
553
588
  size: number;
554
589
  xdefault?: string | null | undefined;
555
590
  encrypted?: boolean | undefined;
591
+ format?: string | null | undefined;
592
+ description?: string | Record<string, string> | null | undefined;
556
593
  } | {
557
594
  key: string;
558
595
  type: "integer";
@@ -562,6 +599,7 @@ export declare const getMigrationCollectionSchemas: () => {
562
599
  min?: number | undefined;
563
600
  max?: number | undefined;
564
601
  xdefault?: number | null | undefined;
602
+ description?: string | Record<string, string> | null | undefined;
565
603
  } | {
566
604
  key: string;
567
605
  type: "float";
@@ -571,6 +609,7 @@ export declare const getMigrationCollectionSchemas: () => {
571
609
  min?: number | undefined;
572
610
  max?: number | undefined;
573
611
  xdefault?: number | null | undefined;
612
+ description?: string | Record<string, string> | null | undefined;
574
613
  } | {
575
614
  key: string;
576
615
  type: "boolean";
@@ -578,6 +617,7 @@ export declare const getMigrationCollectionSchemas: () => {
578
617
  required: boolean;
579
618
  array: boolean;
580
619
  xdefault?: boolean | null | undefined;
620
+ description?: string | Record<string, string> | null | undefined;
581
621
  } | {
582
622
  key: string;
583
623
  type: "datetime";
@@ -585,6 +625,7 @@ export declare const getMigrationCollectionSchemas: () => {
585
625
  required: boolean;
586
626
  array: boolean;
587
627
  xdefault?: string | null | undefined;
628
+ description?: string | Record<string, string> | null | undefined;
588
629
  } | {
589
630
  key: string;
590
631
  type: "email";
@@ -592,6 +633,7 @@ export declare const getMigrationCollectionSchemas: () => {
592
633
  required: boolean;
593
634
  array: boolean;
594
635
  xdefault?: string | null | undefined;
636
+ description?: string | Record<string, string> | null | undefined;
595
637
  } | {
596
638
  key: string;
597
639
  type: "ip";
@@ -599,6 +641,7 @@ export declare const getMigrationCollectionSchemas: () => {
599
641
  required: boolean;
600
642
  array: boolean;
601
643
  xdefault?: string | null | undefined;
644
+ description?: string | Record<string, string> | null | undefined;
602
645
  } | {
603
646
  key: string;
604
647
  type: "url";
@@ -606,6 +649,7 @@ export declare const getMigrationCollectionSchemas: () => {
606
649
  required: boolean;
607
650
  array: boolean;
608
651
  xdefault?: string | null | undefined;
652
+ description?: string | Record<string, string> | null | undefined;
609
653
  } | {
610
654
  key: string;
611
655
  type: "enum";
@@ -614,6 +658,7 @@ export declare const getMigrationCollectionSchemas: () => {
614
658
  array: boolean;
615
659
  elements: string[];
616
660
  xdefault?: string | null | undefined;
661
+ description?: string | Record<string, string> | null | undefined;
617
662
  } | {
618
663
  key: string;
619
664
  type: "relationship";
@@ -630,6 +675,7 @@ export declare const getMigrationCollectionSchemas: () => {
630
675
  originalIdField: string;
631
676
  targetField?: string | undefined;
632
677
  } | undefined;
678
+ description?: string | Record<string, string> | null | undefined;
633
679
  })[];
634
680
  };
635
681
  };