appwrite-utils-cli 1.4.1 → 1.5.1
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 +22 -1
- package/dist/adapters/TablesDBAdapter.js +7 -4
- package/dist/collections/attributes.d.ts +1 -1
- package/dist/collections/attributes.js +42 -7
- package/dist/collections/indexes.js +13 -3
- package/dist/collections/methods.d.ts +9 -0
- package/dist/collections/methods.js +268 -0
- package/dist/databases/setup.js +6 -2
- package/dist/interactiveCLI.js +2 -1
- package/dist/migrations/appwriteToX.d.ts +2 -2
- package/dist/migrations/comprehensiveTransfer.js +12 -0
- package/dist/migrations/dataLoader.d.ts +5 -5
- package/dist/migrations/relationships.d.ts +2 -2
- package/dist/shared/jsonSchemaGenerator.d.ts +1 -0
- package/dist/shared/jsonSchemaGenerator.js +6 -2
- package/dist/shared/operationQueue.js +14 -1
- package/dist/shared/schemaGenerator.d.ts +2 -1
- package/dist/shared/schemaGenerator.js +61 -78
- package/dist/storage/schemas.d.ts +8 -8
- package/dist/utils/loadConfigs.js +44 -19
- package/dist/utils/schemaStrings.d.ts +2 -1
- package/dist/utils/schemaStrings.js +61 -78
- package/dist/utils/setupFiles.js +19 -1
- package/dist/utils/versionDetection.d.ts +6 -0
- package/dist/utils/versionDetection.js +30 -0
- package/dist/utilsController.js +32 -5
- package/package.json +1 -1
- package/src/adapters/TablesDBAdapter.ts +20 -17
- package/src/collections/attributes.ts +198 -156
- package/src/collections/indexes.ts +36 -28
- package/src/collections/methods.ts +292 -19
- package/src/databases/setup.ts +11 -7
- package/src/interactiveCLI.ts +8 -7
- package/src/migrations/comprehensiveTransfer.ts +22 -8
- package/src/shared/jsonSchemaGenerator.ts +36 -29
- package/src/shared/operationQueue.ts +48 -33
- package/src/shared/schemaGenerator.ts +128 -134
- package/src/utils/loadConfigs.ts +48 -29
- package/src/utils/schemaStrings.ts +124 -130
- package/src/utils/setupFiles.ts +21 -5
- package/src/utils/versionDetection.ts +48 -21
- package/src/utilsController.ts +59 -32
@@ -33,39 +33,54 @@ export const processQueue = async (db: Databases, dbId: string) => {
|
|
33
33
|
let collectionFound: Models.Collection | undefined;
|
34
34
|
|
35
35
|
// Handle relationship attribute operations
|
36
|
-
if (operation.attribute?.type === "relationship") {
|
37
|
-
// Attempt to resolve the collection directly if collectionId is specified
|
38
|
-
if (operation.collectionId) {
|
39
|
-
console.log(`\tFetching collection by ID: ${operation.collectionId}`);
|
40
|
-
try {
|
41
|
-
collectionFound = await tryAwaitWithRetry(
|
42
|
-
async () => await db.getCollection(dbId, operation.collectionId!)
|
43
|
-
);
|
44
|
-
} catch (e) {
|
45
|
-
console.log(
|
46
|
-
`\tCollection not found by ID: ${operation.collectionId}`
|
47
|
-
);
|
48
|
-
}
|
49
|
-
}
|
50
|
-
// Attempt to resolve related collection if specified and not already found
|
51
|
-
if (!collectionFound && operation.attribute?.relatedCollection) {
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
36
|
+
if (operation.attribute?.type === "relationship") {
|
37
|
+
// Attempt to resolve the collection directly if collectionId is specified
|
38
|
+
if (operation.collectionId) {
|
39
|
+
console.log(`\tFetching collection by ID: ${operation.collectionId}`);
|
40
|
+
try {
|
41
|
+
collectionFound = await tryAwaitWithRetry(
|
42
|
+
async () => await db.getCollection(dbId, operation.collectionId!)
|
43
|
+
);
|
44
|
+
} catch (e) {
|
45
|
+
console.log(
|
46
|
+
`\tCollection not found by ID: ${operation.collectionId}`
|
47
|
+
);
|
48
|
+
}
|
49
|
+
}
|
50
|
+
// Attempt to resolve related collection if specified and not already found
|
51
|
+
if (!collectionFound && operation.attribute?.relatedCollection) {
|
52
|
+
// First, try treating relatedCollection as an ID
|
53
|
+
try {
|
54
|
+
const relAttr: any = operation.attribute as any;
|
55
|
+
const byId = await tryAwaitWithRetry(
|
56
|
+
async () => await db.getCollection(dbId, relAttr.relatedCollection as string)
|
57
|
+
);
|
58
|
+
// We still need the target collection (operation.collectionId) to create the attribute on,
|
59
|
+
// so only use this branch to warm caches/mappings and continue to dependency checks.
|
60
|
+
// Do not override collectionFound with the related collection.
|
61
|
+
} catch (_) {
|
62
|
+
// Not an ID or not found; fall back to name-based cache
|
63
|
+
}
|
64
|
+
|
65
|
+
// Warm cache by name (used by attribute creation path), but do not use as target collection
|
66
|
+
const relAttr: any = operation.attribute as any;
|
67
|
+
await fetchAndCacheCollectionByName(
|
68
|
+
db,
|
69
|
+
dbId,
|
70
|
+
relAttr.relatedCollection
|
71
|
+
);
|
72
|
+
}
|
73
|
+
// Handle dependencies if collection still not found
|
74
|
+
if (!collectionFound) {
|
75
|
+
for (const dep of operation.dependencies || []) {
|
76
|
+
collectionFound = await fetchAndCacheCollectionByName(
|
77
|
+
db,
|
78
|
+
dbId,
|
79
|
+
dep
|
80
|
+
);
|
81
|
+
if (collectionFound) break; // Break early if collection is found
|
82
|
+
}
|
83
|
+
}
|
69
84
|
} else if (operation.collectionId) {
|
70
85
|
// Handle non-relationship operations with a specified collectionId
|
71
86
|
console.log(`\tFetching collection by ID: ${operation.collectionId}`);
|
@@ -22,16 +22,23 @@ interface RelationshipDetail {
|
|
22
22
|
isChild: boolean;
|
23
23
|
}
|
24
24
|
|
25
|
-
export class SchemaGenerator {
|
26
|
-
private relationshipMap = new Map<string, RelationshipDetail[]>();
|
27
|
-
private config: AppwriteConfig;
|
28
|
-
private appwriteFolderPath: string;
|
29
|
-
|
30
|
-
constructor(config: AppwriteConfig, appwriteFolderPath: string) {
|
31
|
-
this.config = config;
|
32
|
-
this.appwriteFolderPath = appwriteFolderPath;
|
33
|
-
this.extractRelationships();
|
34
|
-
}
|
25
|
+
export class SchemaGenerator {
|
26
|
+
private relationshipMap = new Map<string, RelationshipDetail[]>();
|
27
|
+
private config: AppwriteConfig;
|
28
|
+
private appwriteFolderPath: string;
|
29
|
+
|
30
|
+
constructor(config: AppwriteConfig, appwriteFolderPath: string) {
|
31
|
+
this.config = config;
|
32
|
+
this.appwriteFolderPath = appwriteFolderPath;
|
33
|
+
this.extractRelationships();
|
34
|
+
}
|
35
|
+
|
36
|
+
private resolveCollectionName = (idOrName: string): string => {
|
37
|
+
const col = this.config.collections?.find(
|
38
|
+
(c) => c.$id === (idOrName as any) || c.name === idOrName
|
39
|
+
);
|
40
|
+
return col?.name ?? idOrName;
|
41
|
+
};
|
35
42
|
|
36
43
|
public updateYamlCollections(): void {
|
37
44
|
const collections = this.config.collections;
|
@@ -291,12 +298,12 @@ export default appwriteConfig;
|
|
291
298
|
if (!collection.attributes) {
|
292
299
|
return;
|
293
300
|
}
|
294
|
-
collection.attributes.forEach((attr) => {
|
295
|
-
if (attr.type === "relationship" && attr.twoWay && attr.twoWayKey) {
|
296
|
-
const relationshipAttr = attr as RelationshipAttribute;
|
297
|
-
let isArrayParent = false;
|
298
|
-
let isArrayChild = false;
|
299
|
-
switch (relationshipAttr.relationType) {
|
301
|
+
collection.attributes.forEach((attr) => {
|
302
|
+
if (attr.type === "relationship" && attr.twoWay && attr.twoWayKey) {
|
303
|
+
const relationshipAttr = attr as RelationshipAttribute;
|
304
|
+
let isArrayParent = false;
|
305
|
+
let isArrayChild = false;
|
306
|
+
switch (relationshipAttr.relationType) {
|
300
307
|
case "oneToMany":
|
301
308
|
isArrayParent = true;
|
302
309
|
isArrayChild = false;
|
@@ -316,14 +323,14 @@ export default appwriteConfig;
|
|
316
323
|
default:
|
317
324
|
break;
|
318
325
|
}
|
319
|
-
this.addRelationship(
|
320
|
-
collection.name,
|
321
|
-
relationshipAttr.relatedCollection,
|
322
|
-
attr.key,
|
323
|
-
relationshipAttr.twoWayKey
|
324
|
-
isArrayParent,
|
325
|
-
isArrayChild
|
326
|
-
);
|
326
|
+
this.addRelationship(
|
327
|
+
collection.name,
|
328
|
+
this.resolveCollectionName(relationshipAttr.relatedCollection),
|
329
|
+
attr.key,
|
330
|
+
relationshipAttr.twoWayKey!,
|
331
|
+
isArrayParent,
|
332
|
+
isArrayChild
|
333
|
+
);
|
327
334
|
console.log(
|
328
335
|
`Extracted relationship: ${attr.key}\n\t${collection.name} -> ${relationshipAttr.relatedCollection}, databaseId: ${collection.databaseId}`
|
329
336
|
);
|
@@ -383,10 +390,10 @@ export default appwriteConfig;
|
|
383
390
|
// Generate Zod schemas (TypeScript)
|
384
391
|
if (format === "zod" || format === "both") {
|
385
392
|
this.config.collections.forEach((collection) => {
|
386
|
-
const schemaString = this.
|
387
|
-
collection.name,
|
388
|
-
collection.attributes || []
|
389
|
-
);
|
393
|
+
const schemaString = this.createSchemaStringV4(
|
394
|
+
collection.name,
|
395
|
+
collection.attributes || []
|
396
|
+
);
|
390
397
|
const camelCaseName = toCamelCase(collection.name);
|
391
398
|
const schemaPath = path.join(schemasPath, `${camelCaseName}.ts`);
|
392
399
|
fs.writeFileSync(schemaPath, schemaString, { encoding: "utf-8" });
|
@@ -409,119 +416,106 @@ export default appwriteConfig;
|
|
409
416
|
if (verbose) {
|
410
417
|
console.log(`✓ Schema generation completed (format: ${format})`);
|
411
418
|
}
|
412
|
-
}
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
|
420
|
-
const
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
|
419
|
+
}
|
420
|
+
|
421
|
+
// Zod v4 recursive getter-based schemas
|
422
|
+
createSchemaStringV4 = (name: string, attributes: Attribute[]): string => {
|
423
|
+
const pascalName = toPascalCase(name);
|
424
|
+
let imports = `import { z } from "zod";\n`;
|
425
|
+
|
426
|
+
// Use the relationshipMap to find related collections
|
427
|
+
const relationshipDetails = this.relationshipMap.get(name) || [];
|
428
|
+
let relatedCollections = relationshipDetails
|
429
|
+
.filter((detail, index, self) => {
|
430
|
+
const uniqueKey = `${detail.parentCollection}-${detail.childCollection}-${detail.parentKey}-${detail.childKey}`;
|
431
|
+
return (
|
432
|
+
index ===
|
433
|
+
self.findIndex(
|
426
434
|
(obj) =>
|
427
435
|
`${obj.parentCollection}-${obj.childCollection}-${obj.parentKey}-${obj.childKey}` ===
|
428
436
|
uniqueKey
|
429
437
|
)
|
430
438
|
);
|
431
439
|
})
|
432
|
-
.map((detail) => {
|
433
|
-
const relatedCollectionName = detail.isChild
|
434
|
-
? detail.parentCollection
|
435
|
-
: detail.childCollection;
|
436
|
-
const key = detail.isChild ? detail.childKey : detail.parentKey;
|
437
|
-
const isArray = detail.isArray ? "array" : "";
|
438
|
-
return [relatedCollectionName, key, isArray];
|
439
|
-
});
|
440
|
+
.map((detail) => {
|
441
|
+
const relatedCollectionName = detail.isChild
|
442
|
+
? detail.parentCollection
|
443
|
+
: detail.childCollection;
|
444
|
+
const key = detail.isChild ? detail.childKey : detail.parentKey;
|
445
|
+
const isArray = detail.isArray ? "array" : "";
|
446
|
+
return [relatedCollectionName, key, isArray];
|
447
|
+
});
|
448
|
+
|
449
|
+
// Include one-way relationship attributes directly (no twoWayKey)
|
450
|
+
const oneWayRels: Array<[string, string, string]> = [];
|
451
|
+
for (const attr of attributes) {
|
452
|
+
if (attr.type === "relationship" && attr.relatedCollection) {
|
453
|
+
const relatedName = this.resolveCollectionName(attr.relatedCollection);
|
454
|
+
const isArray =
|
455
|
+
attr.relationType === "oneToMany" || attr.relationType === "manyToMany"
|
456
|
+
? "array"
|
457
|
+
: "";
|
458
|
+
oneWayRels.push([relatedName, attr.key, isArray]);
|
459
|
+
}
|
460
|
+
}
|
461
|
+
|
462
|
+
// Merge and dedupe (by relatedName+key)
|
463
|
+
relatedCollections = [...relatedCollections, ...oneWayRels].filter(
|
464
|
+
(item, idx, self) =>
|
465
|
+
idx === self.findIndex((o) => `${o[0]}::${o[1]}` === `${item[0]}::${item[1]}`)
|
466
|
+
);
|
440
467
|
|
441
|
-
|
442
|
-
|
443
|
-
|
444
|
-
|
445
|
-
|
446
|
-
|
447
|
-
|
448
|
-
|
449
|
-
|
450
|
-
|
451
|
-
|
452
|
-
|
453
|
-
|
454
|
-
|
455
|
-
|
456
|
-
|
457
|
-
|
458
|
-
|
459
|
-
|
460
|
-
|
461
|
-
|
462
|
-
|
463
|
-
|
464
|
-
|
465
|
-
|
466
|
-
|
467
|
-
|
468
|
-
|
469
|
-
|
470
|
-
|
471
|
-
|
472
|
-
|
473
|
-
|
474
|
-
|
475
|
-
|
476
|
-
|
477
|
-
|
478
|
-
|
479
|
-
|
480
|
-
|
481
|
-
|
482
|
-
|
483
|
-
|
484
|
-
|
485
|
-
|
486
|
-
|
487
|
-
|
488
|
-
|
489
|
-
|
490
|
-
|
491
|
-
|
492
|
-
|
493
|
-
// Re-add imports after processing relationships
|
494
|
-
schemaString = `${imports}\n\n`;
|
495
|
-
|
496
|
-
schemaString += `export const ${pascalName}SchemaBase = z.object({\n`;
|
497
|
-
schemaString += ` $id: z.string(),\n`;
|
498
|
-
schemaString += ` $createdAt: z.string(),\n`;
|
499
|
-
schemaString += ` $updatedAt: z.string(),\n`;
|
500
|
-
schemaString += ` $permissions: z.array(z.string()),\n`;
|
501
|
-
for (const attribute of attributes) {
|
502
|
-
if (attribute.type === "relationship") {
|
503
|
-
continue;
|
504
|
-
}
|
505
|
-
schemaString += ` ${attribute.key}: ${this.typeToZod(attribute)},\n`;
|
506
|
-
}
|
507
|
-
schemaString += `});\n\n`;
|
508
|
-
schemaString += `export type ${pascalName}Base = z.infer<typeof ${pascalName}SchemaBase>`;
|
509
|
-
if (relatedTypes.length > 0) {
|
510
|
-
schemaString += ` & {\n ${relatedTypes}};\n\n`;
|
511
|
-
} else {
|
512
|
-
schemaString += `;\n\n`;
|
513
|
-
}
|
514
|
-
schemaString += `export const ${pascalName}Schema: z.ZodType<${pascalName}Base> = ${pascalName}SchemaBase`;
|
515
|
-
if (relatedTypes.length > 0) {
|
516
|
-
schemaString += `.extend({\n ${relatedTypesLazy}});\n\n`;
|
517
|
-
} else {
|
518
|
-
schemaString += `;\n`;
|
519
|
-
}
|
520
|
-
schemaString += `export type ${pascalName} = z.infer<typeof ${pascalName}Schema>;\n\n`;
|
521
|
-
}
|
522
|
-
|
523
|
-
return schemaString;
|
524
|
-
};
|
468
|
+
const hasRelationships = relatedCollections.length > 0;
|
469
|
+
|
470
|
+
// Build imports for related collections
|
471
|
+
if (hasRelationships) {
|
472
|
+
const importLines = relatedCollections.map((rel) => {
|
473
|
+
const relatedPascalName = toPascalCase(rel[0]);
|
474
|
+
const relatedCamelName = toCamelCase(rel[0]);
|
475
|
+
return `import { ${relatedPascalName}Schema } from "./${relatedCamelName}";`;
|
476
|
+
});
|
477
|
+
const unique = Array.from(new Set(importLines));
|
478
|
+
imports += unique.join("\n") + (unique.length ? "\n" : "");
|
479
|
+
}
|
480
|
+
|
481
|
+
let schemaString = `${imports}\n`;
|
482
|
+
|
483
|
+
// Single object schema with recursive getters (Zod v4)
|
484
|
+
schemaString += `export const ${pascalName}Schema = z.object({\n`;
|
485
|
+
schemaString += ` $id: z.string(),\n`;
|
486
|
+
schemaString += ` $createdAt: z.string(),\n`;
|
487
|
+
schemaString += ` $updatedAt: z.string(),\n`;
|
488
|
+
schemaString += ` $permissions: z.array(z.string()),\n`;
|
489
|
+
for (const attribute of attributes) {
|
490
|
+
if (attribute.type === "relationship") continue;
|
491
|
+
schemaString += ` ${attribute.key}: ${this.typeToZod(attribute)},\n`;
|
492
|
+
}
|
493
|
+
|
494
|
+
// Add recursive getters for relationships (respect required flag)
|
495
|
+
relatedCollections.forEach((rel) => {
|
496
|
+
const relatedPascalName = toPascalCase(rel[0]);
|
497
|
+
const isArray = rel[2] === "array";
|
498
|
+
const key = String(rel[1]);
|
499
|
+
const attrMeta = attributes.find(a => a.key === key && a.type === "relationship");
|
500
|
+
const isRequired = !!attrMeta?.required;
|
501
|
+
let getterBody = "";
|
502
|
+
if (isArray) {
|
503
|
+
getterBody = isRequired
|
504
|
+
? `${relatedPascalName}Schema.array()`
|
505
|
+
: `${relatedPascalName}Schema.array().nullish()`;
|
506
|
+
} else {
|
507
|
+
getterBody = isRequired
|
508
|
+
? `${relatedPascalName}Schema`
|
509
|
+
: `${relatedPascalName}Schema.nullish()`;
|
510
|
+
}
|
511
|
+
schemaString += ` get ${key}(){\n return ${getterBody}\n },\n`;
|
512
|
+
});
|
513
|
+
|
514
|
+
schemaString += `});\n\n`;
|
515
|
+
schemaString += `export type ${pascalName} = z.infer<typeof ${pascalName}Schema>;\n\n`;
|
516
|
+
|
517
|
+
return schemaString;
|
518
|
+
};
|
525
519
|
|
526
520
|
typeToZod = (attribute: Attribute) => {
|
527
521
|
let baseSchemaCode = "";
|
package/src/utils/loadConfigs.ts
CHANGED
@@ -4,7 +4,8 @@ import { type AppwriteConfig, type Collection, type CollectionCreate } from "app
|
|
4
4
|
import { register } from "tsx/esm/api"; // Import the register function
|
5
5
|
import { pathToFileURL } from "node:url";
|
6
6
|
import chalk from "chalk";
|
7
|
-
import { findYamlConfig, loadYamlConfig } from "../config/yamlConfig.js";
|
7
|
+
import { findYamlConfig, loadYamlConfig } from "../config/yamlConfig.js";
|
8
|
+
import { detectAppwriteVersionCached, fetchServerVersion, isVersionAtLeast } from "./versionDetection.js";
|
8
9
|
import yaml from "js-yaml";
|
9
10
|
import { z } from "zod";
|
10
11
|
import { MessageFormatter } from "../shared/messageFormatter.js";
|
@@ -165,17 +166,28 @@ export const loadConfigWithPath = async (
|
|
165
166
|
throw new Error("No valid configuration found");
|
166
167
|
}
|
167
168
|
|
168
|
-
// Determine collections
|
169
|
-
let
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
169
|
+
// Determine directory (collections or tables) based on server version / API mode
|
170
|
+
let dirName = "collections";
|
171
|
+
try {
|
172
|
+
const det = await detectAppwriteVersionCached(config.appwriteEndpoint, config.appwriteProject, config.appwriteKey);
|
173
|
+
if (det.apiMode === 'tablesdb' || isVersionAtLeast(det.serverVersion, '1.8.0')) {
|
174
|
+
dirName = 'tables';
|
175
|
+
} else {
|
176
|
+
// Try health version if not provided
|
177
|
+
const ver = await fetchServerVersion(config.appwriteEndpoint);
|
178
|
+
if (isVersionAtLeast(ver || undefined, '1.8.0')) dirName = 'tables';
|
179
|
+
}
|
180
|
+
} catch {}
|
181
|
+
|
182
|
+
// Determine collections directory based on actual config file location and dirName
|
183
|
+
let collectionsDir: string;
|
184
|
+
const configFileDir = path.dirname(actualConfigPath);
|
185
|
+
collectionsDir = path.join(configFileDir, dirName);
|
186
|
+
// Fallback if not found
|
187
|
+
if (!fs.existsSync(collectionsDir)) {
|
188
|
+
const fallback = path.join(configFileDir, dirName === 'tables' ? 'collections' : 'tables');
|
189
|
+
if (fs.existsSync(fallback)) collectionsDir = fallback;
|
190
|
+
}
|
179
191
|
|
180
192
|
// Load collections if they exist
|
181
193
|
if (fs.existsSync(collectionsDir)) {
|
@@ -267,22 +279,29 @@ export const loadConfig = async (
|
|
267
279
|
throw new Error("No valid configuration found");
|
268
280
|
}
|
269
281
|
|
270
|
-
// Determine collections
|
271
|
-
let
|
272
|
-
|
273
|
-
const
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
282
|
+
// Determine directory (collections or tables) based on server version / API mode
|
283
|
+
let dirName2 = "collections";
|
284
|
+
try {
|
285
|
+
const det = await detectAppwriteVersionCached(config.appwriteEndpoint, config.appwriteProject, config.appwriteKey);
|
286
|
+
if (det.apiMode === 'tablesdb' || isVersionAtLeast(det.serverVersion, '1.8.0')) {
|
287
|
+
dirName2 = 'tables';
|
288
|
+
} else {
|
289
|
+
const ver = await fetchServerVersion(config.appwriteEndpoint);
|
290
|
+
if (isVersionAtLeast(ver || undefined, '1.8.0')) dirName2 = 'tables';
|
291
|
+
}
|
292
|
+
} catch {}
|
293
|
+
|
294
|
+
let collectionsDir: string;
|
295
|
+
if (actualConfigPath) {
|
296
|
+
const configFileDir = path.dirname(actualConfigPath);
|
297
|
+
collectionsDir = path.join(configFileDir, dirName2);
|
298
|
+
} else {
|
299
|
+
collectionsDir = path.join(configDir, dirName2);
|
300
|
+
}
|
301
|
+
if (!fs.existsSync(collectionsDir)) {
|
302
|
+
const fallback = path.join(path.dirname(actualConfigPath || configDir), dirName2 === 'tables' ? 'collections' : 'tables');
|
303
|
+
if (fs.existsSync(fallback)) collectionsDir = fallback;
|
304
|
+
}
|
286
305
|
|
287
306
|
// Load collections if they exist
|
288
307
|
if (fs.existsSync(collectionsDir)) {
|
@@ -459,4 +478,4 @@ const loadYamlCollection = (filePath: string): CollectionCreate | null => {
|
|
459
478
|
console.error(`Error loading YAML collection from ${filePath}:`, error);
|
460
479
|
return null;
|
461
480
|
}
|
462
|
-
};
|
481
|
+
};
|