appwrite-utils-cli 1.7.9 → 1.8.2

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 (70) hide show
  1. package/CHANGELOG.md +14 -199
  2. package/README.md +87 -30
  3. package/dist/adapters/AdapterFactory.js +5 -25
  4. package/dist/adapters/DatabaseAdapter.d.ts +17 -2
  5. package/dist/adapters/LegacyAdapter.d.ts +2 -1
  6. package/dist/adapters/LegacyAdapter.js +212 -16
  7. package/dist/adapters/TablesDBAdapter.d.ts +2 -12
  8. package/dist/adapters/TablesDBAdapter.js +261 -57
  9. package/dist/cli/commands/databaseCommands.js +4 -3
  10. package/dist/cli/commands/functionCommands.js +17 -8
  11. package/dist/collections/attributes.js +447 -125
  12. package/dist/collections/methods.js +197 -186
  13. package/dist/collections/tableOperations.d.ts +86 -0
  14. package/dist/collections/tableOperations.js +434 -0
  15. package/dist/collections/transferOperations.d.ts +3 -2
  16. package/dist/collections/transferOperations.js +93 -12
  17. package/dist/config/yamlConfig.d.ts +221 -88
  18. package/dist/examples/yamlTerminologyExample.d.ts +1 -1
  19. package/dist/examples/yamlTerminologyExample.js +6 -3
  20. package/dist/functions/fnConfigDiscovery.d.ts +3 -0
  21. package/dist/functions/fnConfigDiscovery.js +108 -0
  22. package/dist/interactiveCLI.js +18 -15
  23. package/dist/main.js +211 -73
  24. package/dist/migrations/appwriteToX.d.ts +88 -23
  25. package/dist/migrations/comprehensiveTransfer.d.ts +2 -0
  26. package/dist/migrations/comprehensiveTransfer.js +83 -6
  27. package/dist/migrations/dataLoader.d.ts +227 -69
  28. package/dist/migrations/dataLoader.js +3 -3
  29. package/dist/migrations/importController.js +3 -3
  30. package/dist/migrations/relationships.d.ts +8 -2
  31. package/dist/migrations/services/ImportOrchestrator.js +3 -3
  32. package/dist/migrations/transfer.js +159 -37
  33. package/dist/shared/attributeMapper.d.ts +20 -0
  34. package/dist/shared/attributeMapper.js +203 -0
  35. package/dist/shared/selectionDialogs.js +8 -4
  36. package/dist/storage/schemas.d.ts +354 -92
  37. package/dist/utils/configDiscovery.js +4 -3
  38. package/dist/utils/versionDetection.d.ts +0 -4
  39. package/dist/utils/versionDetection.js +41 -173
  40. package/dist/utils/yamlConverter.js +89 -16
  41. package/dist/utils/yamlLoader.d.ts +1 -1
  42. package/dist/utils/yamlLoader.js +6 -2
  43. package/dist/utilsController.js +56 -19
  44. package/package.json +4 -4
  45. package/src/adapters/AdapterFactory.ts +119 -143
  46. package/src/adapters/DatabaseAdapter.ts +18 -3
  47. package/src/adapters/LegacyAdapter.ts +236 -105
  48. package/src/adapters/TablesDBAdapter.ts +773 -643
  49. package/src/cli/commands/databaseCommands.ts +13 -12
  50. package/src/cli/commands/functionCommands.ts +23 -14
  51. package/src/collections/attributes.ts +2054 -1611
  52. package/src/collections/methods.ts +208 -293
  53. package/src/collections/tableOperations.ts +506 -0
  54. package/src/collections/transferOperations.ts +218 -144
  55. package/src/examples/yamlTerminologyExample.ts +10 -5
  56. package/src/functions/fnConfigDiscovery.ts +103 -0
  57. package/src/interactiveCLI.ts +25 -20
  58. package/src/main.ts +549 -194
  59. package/src/migrations/comprehensiveTransfer.ts +126 -50
  60. package/src/migrations/dataLoader.ts +3 -3
  61. package/src/migrations/importController.ts +3 -3
  62. package/src/migrations/services/ImportOrchestrator.ts +3 -3
  63. package/src/migrations/transfer.ts +148 -131
  64. package/src/shared/attributeMapper.ts +229 -0
  65. package/src/shared/selectionDialogs.ts +29 -25
  66. package/src/utils/configDiscovery.ts +9 -3
  67. package/src/utils/versionDetection.ts +74 -228
  68. package/src/utils/yamlConverter.ts +94 -17
  69. package/src/utils/yamlLoader.ts +11 -4
  70. package/src/utilsController.ts +80 -30
@@ -239,100 +239,165 @@ export declare const createSessionPreservingYamlConfig: (configPath: string, ses
239
239
  name: string;
240
240
  attributes: ({
241
241
  key: string;
242
- type: "string";
243
- size: number;
244
- error?: string | undefined;
245
- required?: boolean | undefined;
246
- array?: boolean | undefined;
247
- xdefault?: string | null | undefined;
248
- encrypted?: boolean | undefined;
249
- format?: string | null | undefined;
250
- } | {
251
- key: string;
242
+ required: boolean;
252
243
  type: "integer";
253
- error?: string | undefined;
254
- required?: boolean | undefined;
255
244
  array?: boolean | undefined;
245
+ format?: string | undefined;
246
+ status?: string | undefined;
247
+ attributes?: string[] | undefined;
248
+ orders?: string[] | undefined;
249
+ $createdAt?: string | undefined;
250
+ $updatedAt?: string | undefined;
251
+ error?: string | undefined;
256
252
  min?: number | undefined;
257
253
  max?: number | undefined;
258
254
  xdefault?: number | null | undefined;
259
255
  } | {
260
256
  key: string;
261
- type: "double";
257
+ required: boolean;
258
+ type: "relationship";
259
+ relatedCollection: string;
260
+ relationType: "oneToMany" | "manyToOne" | "oneToOne" | "manyToMany";
261
+ twoWay: boolean;
262
+ onDelete: "setNull" | "cascade" | "restrict";
263
+ array?: boolean | undefined;
264
+ format?: string | undefined;
265
+ status?: string | undefined;
266
+ attributes?: string[] | undefined;
267
+ orders?: string[] | undefined;
268
+ $createdAt?: string | undefined;
269
+ $updatedAt?: string | undefined;
262
270
  error?: string | undefined;
263
- required?: boolean | undefined;
271
+ twoWayKey?: string | undefined;
272
+ side?: "parent" | "child" | undefined;
273
+ importMapping?: {
274
+ originalIdField: string;
275
+ targetField?: string | undefined;
276
+ } | undefined;
277
+ } | {
278
+ key: string;
279
+ required: boolean;
280
+ type: "string";
281
+ size: number;
264
282
  array?: boolean | undefined;
283
+ format?: string | undefined;
284
+ status?: string | undefined;
285
+ attributes?: string[] | undefined;
286
+ orders?: string[] | undefined;
287
+ $createdAt?: string | undefined;
288
+ $updatedAt?: string | undefined;
289
+ error?: string | undefined;
290
+ xdefault?: string | null | undefined;
291
+ encrypted?: boolean | undefined;
292
+ } | {
293
+ key: string;
294
+ required: boolean;
295
+ type: "double";
296
+ array?: boolean | undefined;
297
+ format?: string | undefined;
298
+ status?: string | undefined;
299
+ attributes?: string[] | undefined;
300
+ orders?: string[] | undefined;
301
+ $createdAt?: string | undefined;
302
+ $updatedAt?: string | undefined;
303
+ error?: string | undefined;
265
304
  min?: number | undefined;
266
305
  max?: number | undefined;
267
306
  xdefault?: number | null | undefined;
268
307
  } | {
269
308
  key: string;
309
+ required: boolean;
270
310
  type: "float";
271
- error?: string | undefined;
272
- required?: boolean | undefined;
273
311
  array?: boolean | undefined;
312
+ format?: string | undefined;
313
+ status?: string | undefined;
314
+ attributes?: string[] | undefined;
315
+ orders?: string[] | undefined;
316
+ $createdAt?: string | undefined;
317
+ $updatedAt?: string | undefined;
318
+ error?: string | undefined;
274
319
  min?: number | undefined;
275
320
  max?: number | undefined;
276
321
  xdefault?: number | null | undefined;
277
322
  } | {
278
323
  key: string;
324
+ required: boolean;
279
325
  type: "boolean";
280
- error?: string | undefined;
281
- required?: boolean | undefined;
282
326
  array?: boolean | undefined;
327
+ format?: string | undefined;
328
+ status?: string | undefined;
329
+ attributes?: string[] | undefined;
330
+ orders?: string[] | undefined;
331
+ $createdAt?: string | undefined;
332
+ $updatedAt?: string | undefined;
333
+ error?: string | undefined;
283
334
  xdefault?: boolean | null | undefined;
284
335
  } | {
285
336
  key: string;
337
+ required: boolean;
286
338
  type: "datetime";
287
- error?: string | undefined;
288
- required?: boolean | undefined;
289
339
  array?: boolean | undefined;
340
+ format?: string | undefined;
341
+ status?: string | undefined;
342
+ attributes?: string[] | undefined;
343
+ orders?: string[] | undefined;
344
+ $createdAt?: string | undefined;
345
+ $updatedAt?: string | undefined;
346
+ error?: string | undefined;
290
347
  xdefault?: string | null | undefined;
291
348
  } | {
292
349
  key: string;
350
+ required: boolean;
293
351
  type: "email";
294
- error?: string | undefined;
295
- required?: boolean | undefined;
296
352
  array?: boolean | undefined;
353
+ format?: string | undefined;
354
+ status?: string | undefined;
355
+ attributes?: string[] | undefined;
356
+ orders?: string[] | undefined;
357
+ $createdAt?: string | undefined;
358
+ $updatedAt?: string | undefined;
359
+ error?: string | undefined;
297
360
  xdefault?: string | null | undefined;
298
361
  } | {
299
362
  key: string;
363
+ required: boolean;
300
364
  type: "ip";
301
- error?: string | undefined;
302
- required?: boolean | undefined;
303
365
  array?: boolean | undefined;
366
+ format?: string | undefined;
367
+ status?: string | undefined;
368
+ attributes?: string[] | undefined;
369
+ orders?: string[] | undefined;
370
+ $createdAt?: string | undefined;
371
+ $updatedAt?: string | undefined;
372
+ error?: string | undefined;
304
373
  xdefault?: string | null | undefined;
305
374
  } | {
306
375
  key: string;
376
+ required: boolean;
307
377
  type: "url";
308
- error?: string | undefined;
309
- required?: boolean | undefined;
310
378
  array?: boolean | undefined;
379
+ format?: string | undefined;
380
+ status?: string | undefined;
381
+ attributes?: string[] | undefined;
382
+ orders?: string[] | undefined;
383
+ $createdAt?: string | undefined;
384
+ $updatedAt?: string | undefined;
385
+ error?: string | undefined;
311
386
  xdefault?: string | null | undefined;
312
387
  } | {
313
388
  key: string;
389
+ required: boolean;
314
390
  type: "enum";
315
391
  elements: string[];
316
- error?: string | undefined;
317
- required?: boolean | undefined;
318
392
  array?: boolean | undefined;
319
- xdefault?: string | null | undefined;
320
- } | {
321
- key: string;
322
- type: "relationship";
323
- relatedCollection: string;
324
- relationType: "oneToMany" | "manyToOne" | "oneToOne" | "manyToMany";
325
- twoWay: boolean;
326
- onDelete: "setNull" | "cascade" | "restrict";
393
+ format?: string | undefined;
394
+ status?: string | undefined;
395
+ attributes?: string[] | undefined;
396
+ orders?: string[] | undefined;
397
+ $createdAt?: string | undefined;
398
+ $updatedAt?: string | undefined;
327
399
  error?: string | undefined;
328
- required?: boolean | undefined;
329
- array?: boolean | undefined;
330
- twoWayKey?: string | undefined;
331
- side?: "parent" | "child" | undefined;
332
- importMapping?: {
333
- originalIdField: string;
334
- targetField?: string | undefined;
335
- } | undefined;
400
+ xdefault?: string | null | undefined;
336
401
  })[];
337
402
  $permissions: {
338
403
  permission: string;
@@ -387,104 +452,170 @@ export declare const createSessionPreservingYamlConfig: (configPath: string, ses
387
452
  enabled?: boolean | undefined;
388
453
  documentSecurity?: boolean | undefined;
389
454
  databaseId?: string | undefined;
455
+ databaseIds?: string[] | undefined;
390
456
  }[] | undefined;
391
457
  tables?: {
392
458
  attributes: ({
393
459
  key: string;
394
- type: "string";
395
- size: number;
396
- error?: string | undefined;
397
- required?: boolean | undefined;
398
- array?: boolean | undefined;
399
- xdefault?: string | null | undefined;
400
- encrypted?: boolean | undefined;
401
- format?: string | null | undefined;
402
- } | {
403
- key: string;
460
+ required: boolean;
404
461
  type: "integer";
405
- error?: string | undefined;
406
- required?: boolean | undefined;
407
462
  array?: boolean | undefined;
463
+ format?: string | undefined;
464
+ status?: string | undefined;
465
+ attributes?: string[] | undefined;
466
+ orders?: string[] | undefined;
467
+ $createdAt?: string | undefined;
468
+ $updatedAt?: string | undefined;
469
+ error?: string | undefined;
408
470
  min?: number | undefined;
409
471
  max?: number | undefined;
410
472
  xdefault?: number | null | undefined;
411
473
  } | {
412
474
  key: string;
413
- type: "double";
475
+ required: boolean;
476
+ type: "relationship";
477
+ relatedCollection: string;
478
+ relationType: "oneToMany" | "manyToOne" | "oneToOne" | "manyToMany";
479
+ twoWay: boolean;
480
+ onDelete: "setNull" | "cascade" | "restrict";
481
+ array?: boolean | undefined;
482
+ format?: string | undefined;
483
+ status?: string | undefined;
484
+ attributes?: string[] | undefined;
485
+ orders?: string[] | undefined;
486
+ $createdAt?: string | undefined;
487
+ $updatedAt?: string | undefined;
414
488
  error?: string | undefined;
415
- required?: boolean | undefined;
489
+ twoWayKey?: string | undefined;
490
+ side?: "parent" | "child" | undefined;
491
+ importMapping?: {
492
+ originalIdField: string;
493
+ targetField?: string | undefined;
494
+ } | undefined;
495
+ } | {
496
+ key: string;
497
+ required: boolean;
498
+ type: "string";
499
+ size: number;
416
500
  array?: boolean | undefined;
501
+ format?: string | undefined;
502
+ status?: string | undefined;
503
+ attributes?: string[] | undefined;
504
+ orders?: string[] | undefined;
505
+ $createdAt?: string | undefined;
506
+ $updatedAt?: string | undefined;
507
+ error?: string | undefined;
508
+ xdefault?: string | null | undefined;
509
+ encrypted?: boolean | undefined;
510
+ } | {
511
+ key: string;
512
+ required: boolean;
513
+ type: "double";
514
+ array?: boolean | undefined;
515
+ format?: string | undefined;
516
+ status?: string | undefined;
517
+ attributes?: string[] | undefined;
518
+ orders?: string[] | undefined;
519
+ $createdAt?: string | undefined;
520
+ $updatedAt?: string | undefined;
521
+ error?: string | undefined;
417
522
  min?: number | undefined;
418
523
  max?: number | undefined;
419
524
  xdefault?: number | null | undefined;
420
525
  } | {
421
526
  key: string;
527
+ required: boolean;
422
528
  type: "float";
423
- error?: string | undefined;
424
- required?: boolean | undefined;
425
529
  array?: boolean | undefined;
530
+ format?: string | undefined;
531
+ status?: string | undefined;
532
+ attributes?: string[] | undefined;
533
+ orders?: string[] | undefined;
534
+ $createdAt?: string | undefined;
535
+ $updatedAt?: string | undefined;
536
+ error?: string | undefined;
426
537
  min?: number | undefined;
427
538
  max?: number | undefined;
428
539
  xdefault?: number | null | undefined;
429
540
  } | {
430
541
  key: string;
542
+ required: boolean;
431
543
  type: "boolean";
432
- error?: string | undefined;
433
- required?: boolean | undefined;
434
544
  array?: boolean | undefined;
545
+ format?: string | undefined;
546
+ status?: string | undefined;
547
+ attributes?: string[] | undefined;
548
+ orders?: string[] | undefined;
549
+ $createdAt?: string | undefined;
550
+ $updatedAt?: string | undefined;
551
+ error?: string | undefined;
435
552
  xdefault?: boolean | null | undefined;
436
553
  } | {
437
554
  key: string;
555
+ required: boolean;
438
556
  type: "datetime";
439
- error?: string | undefined;
440
- required?: boolean | undefined;
441
557
  array?: boolean | undefined;
558
+ format?: string | undefined;
559
+ status?: string | undefined;
560
+ attributes?: string[] | undefined;
561
+ orders?: string[] | undefined;
562
+ $createdAt?: string | undefined;
563
+ $updatedAt?: string | undefined;
564
+ error?: string | undefined;
442
565
  xdefault?: string | null | undefined;
443
566
  } | {
444
567
  key: string;
568
+ required: boolean;
445
569
  type: "email";
446
- error?: string | undefined;
447
- required?: boolean | undefined;
448
570
  array?: boolean | undefined;
571
+ format?: string | undefined;
572
+ status?: string | undefined;
573
+ attributes?: string[] | undefined;
574
+ orders?: string[] | undefined;
575
+ $createdAt?: string | undefined;
576
+ $updatedAt?: string | undefined;
577
+ error?: string | undefined;
449
578
  xdefault?: string | null | undefined;
450
579
  } | {
451
580
  key: string;
581
+ required: boolean;
452
582
  type: "ip";
453
- error?: string | undefined;
454
- required?: boolean | undefined;
455
583
  array?: boolean | undefined;
584
+ format?: string | undefined;
585
+ status?: string | undefined;
586
+ attributes?: string[] | undefined;
587
+ orders?: string[] | undefined;
588
+ $createdAt?: string | undefined;
589
+ $updatedAt?: string | undefined;
590
+ error?: string | undefined;
456
591
  xdefault?: string | null | undefined;
457
592
  } | {
458
593
  key: string;
594
+ required: boolean;
459
595
  type: "url";
460
- error?: string | undefined;
461
- required?: boolean | undefined;
462
596
  array?: boolean | undefined;
597
+ format?: string | undefined;
598
+ status?: string | undefined;
599
+ attributes?: string[] | undefined;
600
+ orders?: string[] | undefined;
601
+ $createdAt?: string | undefined;
602
+ $updatedAt?: string | undefined;
603
+ error?: string | undefined;
463
604
  xdefault?: string | null | undefined;
464
605
  } | {
465
606
  key: string;
607
+ required: boolean;
466
608
  type: "enum";
467
609
  elements: string[];
468
- error?: string | undefined;
469
- required?: boolean | undefined;
470
610
  array?: boolean | undefined;
471
- xdefault?: string | null | undefined;
472
- } | {
473
- key: string;
474
- type: "relationship";
475
- relatedCollection: string;
476
- relationType: "oneToMany" | "manyToOne" | "oneToOne" | "manyToMany";
477
- twoWay: boolean;
478
- onDelete: "setNull" | "cascade" | "restrict";
611
+ format?: string | undefined;
612
+ status?: string | undefined;
613
+ attributes?: string[] | undefined;
614
+ orders?: string[] | undefined;
615
+ $createdAt?: string | undefined;
616
+ $updatedAt?: string | undefined;
479
617
  error?: string | undefined;
480
- required?: boolean | undefined;
481
- array?: boolean | undefined;
482
- twoWayKey?: string | undefined;
483
- side?: "parent" | "child" | undefined;
484
- importMapping?: {
485
- originalIdField: string;
486
- targetField?: string | undefined;
487
- } | undefined;
618
+ xdefault?: string | null | undefined;
488
619
  })[];
489
620
  columns: undefined;
490
621
  indexes: {
@@ -541,7 +672,9 @@ export declare const createSessionPreservingYamlConfig: (configPath: string, ses
541
672
  enabled?: boolean | undefined;
542
673
  documentSecurity?: boolean | undefined;
543
674
  databaseId?: string | undefined;
675
+ databaseIds?: string[] | undefined;
544
676
  tableId?: string | undefined;
677
+ rowSecurity?: boolean | undefined;
545
678
  }[] | undefined;
546
679
  functions?: {
547
680
  $id: string;
@@ -7,7 +7,7 @@
7
7
  * 3. Validate terminology consistency
8
8
  * 4. Migrate between formats
9
9
  */
10
- import type { CollectionCreate } from "appwrite-utils";
10
+ import { type CollectionCreate } from "appwrite-utils";
11
11
  /**
12
12
  * Example 1: Generate YAML templates for both collection and table formats
13
13
  */
@@ -11,6 +11,7 @@ import { collectionToYaml, generateYamlTemplate, generateExampleYamls, convertTe
11
11
  import { createYamlLoader } from "../utils/yamlLoader.js";
12
12
  import { YamlImportIntegration } from "../migrations/yaml/YamlImportIntegration.js";
13
13
  import { createImportSchemas } from "../migrations/yaml/generateImportSchemas.js";
14
+ import { CollectionCreateSchema } from "appwrite-utils";
14
15
  import fs from "fs";
15
16
  import path from "path";
16
17
  /**
@@ -208,7 +209,7 @@ export async function runYamlTerminologyExamples(outputDir) {
208
209
  console.log("🎯 Running YAML Terminology Examples\\n");
209
210
  try {
210
211
  // Example collection for demonstrations
211
- const exampleCollection = {
212
+ const exampleCollectionInput = {
212
213
  name: "Product",
213
214
  $id: "product",
214
215
  enabled: true,
@@ -223,7 +224,7 @@ export async function runYamlTerminologyExamples(outputDir) {
223
224
  },
224
225
  {
225
226
  key: "price",
226
- type: "float",
227
+ type: "double",
227
228
  required: true,
228
229
  min: 0
229
230
  },
@@ -233,7 +234,8 @@ export async function runYamlTerminologyExamples(outputDir) {
233
234
  relationType: "manyToOne",
234
235
  relatedCollection: "Categories",
235
236
  twoWay: false,
236
- onDelete: "setNull"
237
+ onDelete: "setNull",
238
+ required: false
237
239
  }
238
240
  ],
239
241
  indexes: [
@@ -245,6 +247,7 @@ export async function runYamlTerminologyExamples(outputDir) {
245
247
  ],
246
248
  importDefs: []
247
249
  };
250
+ const exampleCollection = CollectionCreateSchema.parse(exampleCollectionInput);
248
251
  // Run examples
249
252
  await generateTemplateExamples(outputDir);
250
253
  console.log("\\n" + "=".repeat(60) + "\\n");
@@ -0,0 +1,3 @@
1
+ import { type AppwriteFunction } from 'appwrite-utils';
2
+ export declare function discoverFnConfigs(startDir: string): AppwriteFunction[];
3
+ export declare function mergeDiscoveredFunctions(central?: AppwriteFunction[], discovered?: AppwriteFunction[]): AppwriteFunction[];
@@ -0,0 +1,108 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import yaml from 'js-yaml';
4
+ import { homedir } from 'node:os';
5
+ import { AppwriteFunctionSchema } from 'appwrite-utils';
6
+ import { shouldIgnoreDirectory } from '../utils/directoryUtils.js';
7
+ import { MessageFormatter } from '../shared/messageFormatter.js';
8
+ function findGitRoot(startDir) {
9
+ let dir = path.resolve(startDir);
10
+ while (dir !== path.parse(dir).root) {
11
+ if (fs.existsSync(path.join(dir, '.git')))
12
+ return dir;
13
+ const parent = path.dirname(dir);
14
+ if (parent === dir)
15
+ break;
16
+ dir = parent;
17
+ }
18
+ return path.resolve(startDir);
19
+ }
20
+ function expandTilde(p) {
21
+ if (!p)
22
+ return p;
23
+ if (p === '~' || p.startsWith('~/'))
24
+ return p.replace(/^~(?=$|\/|\\)/, homedir());
25
+ return p;
26
+ }
27
+ export function discoverFnConfigs(startDir) {
28
+ const root = findGitRoot(startDir);
29
+ const results = [];
30
+ const visit = (dir, depth = 0) => {
31
+ if (depth > 5)
32
+ return; // cap depth
33
+ const base = path.basename(dir);
34
+ if (shouldIgnoreDirectory(base))
35
+ return;
36
+ let entries = [];
37
+ try {
38
+ entries = fs.readdirSync(dir, { withFileTypes: true });
39
+ }
40
+ catch {
41
+ return;
42
+ }
43
+ // Check for .fnconfig.yaml / .fnconfig.yml
44
+ for (const fname of ['.fnconfig.yaml', '.fnconfig.yml']) {
45
+ const cfgPath = path.join(dir, fname);
46
+ if (fs.existsSync(cfgPath)) {
47
+ try {
48
+ const raw = fs.readFileSync(cfgPath, 'utf8');
49
+ const data = yaml.load(raw);
50
+ const parsed = AppwriteFunctionSchema.parse({
51
+ $id: data.id || data.$id,
52
+ name: data.name,
53
+ runtime: data.runtime,
54
+ execute: data.execute || [],
55
+ events: data.events || [],
56
+ schedule: data.schedule,
57
+ timeout: data.timeout,
58
+ enabled: data.enabled,
59
+ logging: data.logging,
60
+ entrypoint: data.entrypoint,
61
+ commands: data.commands,
62
+ scopes: data.scopes,
63
+ installationId: data.installationId,
64
+ providerRepositoryId: data.providerRepositoryId,
65
+ providerBranch: data.providerBranch,
66
+ providerSilentMode: data.providerSilentMode,
67
+ providerRootDirectory: data.providerRootDirectory,
68
+ templateRepository: data.templateRepository,
69
+ templateOwner: data.templateOwner,
70
+ templateRootDirectory: data.templateRootDirectory,
71
+ templateVersion: data.templateVersion,
72
+ specification: data.specification,
73
+ dirPath: data.dirPath,
74
+ predeployCommands: data.predeployCommands,
75
+ deployDir: data.deployDir,
76
+ ignore: data.ignore,
77
+ });
78
+ // Resolve dirPath relative to the config file directory
79
+ let dirPath = parsed.dirPath || '.';
80
+ dirPath = expandTilde(dirPath);
81
+ if (!path.isAbsolute(dirPath))
82
+ dirPath = path.resolve(path.dirname(cfgPath), dirPath);
83
+ const merged = { ...parsed, dirPath };
84
+ results.push(merged);
85
+ }
86
+ catch (e) {
87
+ MessageFormatter.warning(`Failed to parse ${cfgPath}: ${e instanceof Error ? e.message : String(e)}`, { prefix: 'Functions' });
88
+ }
89
+ }
90
+ }
91
+ for (const entry of entries) {
92
+ if (entry.isDirectory())
93
+ visit(path.join(dir, entry.name), depth + 1);
94
+ }
95
+ };
96
+ visit(root, 0);
97
+ return results;
98
+ }
99
+ export function mergeDiscoveredFunctions(central = [], discovered = []) {
100
+ const map = new Map();
101
+ for (const f of central)
102
+ if (f?.$id)
103
+ map.set(f.$id, f);
104
+ for (const f of discovered)
105
+ if (f?.$id)
106
+ map.set(f.$id, f); // discovered overrides
107
+ return Array.from(map.values());
108
+ }