appwrite-utils-cli 1.3.4 → 1.4.0
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/dist/adapters/AdapterFactory.d.ts +87 -0
- package/dist/adapters/AdapterFactory.js +217 -0
- package/dist/adapters/DatabaseAdapter.d.ts +217 -0
- package/dist/adapters/DatabaseAdapter.js +50 -0
- package/dist/adapters/LegacyAdapter.d.ts +49 -0
- package/dist/adapters/LegacyAdapter.js +382 -0
- package/dist/adapters/TablesDBAdapter.d.ts +55 -0
- package/dist/adapters/TablesDBAdapter.js +302 -0
- package/dist/adapters/index.d.ts +11 -0
- package/dist/adapters/index.js +12 -0
- package/dist/collections/attributes.js +43 -24
- package/dist/collections/methods.d.ts +4 -3
- package/dist/collections/methods.js +34 -14
- package/dist/config/yamlConfig.d.ts +40 -437
- package/dist/config/yamlConfig.js +8 -2
- package/dist/databases/setup.js +2 -2
- package/dist/main.js +0 -0
- package/dist/migrations/appwriteToX.d.ts +26 -37
- package/dist/migrations/comprehensiveTransfer.js +4 -4
- package/dist/migrations/dataLoader.d.ts +124 -1484
- package/dist/migrations/dataLoader.js +2 -1
- package/dist/migrations/relationships.d.ts +2 -3
- package/dist/migrations/relationships.js +1 -1
- package/dist/migrations/services/UserMappingService.js +1 -1
- package/dist/migrations/yaml/YamlImportConfigLoader.d.ts +24 -279
- package/dist/migrations/yaml/YamlImportConfigLoader.js +7 -2
- package/dist/schemas/authUser.d.ts +7 -47
- package/dist/schemas/authUser.js +1 -1
- package/dist/shared/jsonSchemaGenerator.d.ts +0 -2
- package/dist/shared/jsonSchemaGenerator.js +4 -17
- package/dist/shared/migrationHelpers.d.ts +17 -119
- package/dist/shared/operationQueue.js +16 -7
- package/dist/shared/schemaGenerator.js +2 -17
- package/dist/storage/schemas.d.ts +149 -296
- package/dist/users/methods.d.ts +2 -2
- package/dist/utils/configMigration.js +0 -1
- package/dist/utils/getClientFromConfig.d.ts +26 -0
- package/dist/utils/getClientFromConfig.js +37 -0
- package/dist/utils/loadConfigs.js +0 -2
- package/dist/utils/schemaStrings.js +2 -17
- package/dist/utils/setupFiles.js +2 -0
- package/dist/utils/versionDetection.d.ts +56 -0
- package/dist/utils/versionDetection.js +217 -0
- package/dist/utils/yamlConverter.d.ts +0 -1
- package/dist/utils/yamlConverter.js +0 -2
- package/dist/utilsController.js +2 -0
- package/package.json +3 -2
- package/src/adapters/AdapterFactory.ts +296 -0
- package/src/adapters/DatabaseAdapter.ts +290 -0
- package/src/adapters/LegacyAdapter.ts +667 -0
- package/src/adapters/TablesDBAdapter.ts +429 -0
- package/src/adapters/index.ts +37 -0
- package/src/collections/attributes.ts +351 -157
- package/src/collections/methods.ts +43 -28
- package/src/config/yamlConfig.ts +8 -2
- package/src/databases/setup.ts +2 -2
- package/src/migrations/afterImportActions.ts +2 -2
- package/src/migrations/comprehensiveTransfer.ts +4 -0
- package/src/migrations/dataLoader.ts +2 -1
- package/src/migrations/relationships.ts +1 -1
- package/src/migrations/services/UserMappingService.ts +1 -1
- package/src/migrations/yaml/YamlImportConfigLoader.ts +7 -2
- package/src/schemas/authUser.ts +1 -1
- package/src/shared/jsonSchemaGenerator.ts +4 -19
- package/src/shared/operationQueue.ts +20 -13
- package/src/shared/schemaGenerator.ts +2 -16
- package/src/types/node-appwrite-tablesdb.d.ts +44 -0
- package/src/users/methods.ts +2 -2
- package/src/utils/configMigration.ts +0 -1
- package/src/utils/getClientFromConfig.ts +56 -0
- package/src/utils/loadConfigs.ts +0 -2
- package/src/utils/schemaStrings.ts +2 -16
- package/src/utils/setupFiles.ts +2 -0
- package/src/utils/versionDetection.ts +265 -0
- package/src/utils/yamlConverter.ts +0 -2
- package/src/utilsController.ts +2 -0
- package/dist/functions/openapi.d.ts +0 -4
- package/dist/functions/openapi.js +0 -60
- package/dist/migrations/attributes.d.ts +0 -4
- package/dist/migrations/attributes.js +0 -301
- package/dist/migrations/backup.d.ts +0 -687
- package/dist/migrations/backup.js +0 -175
- package/dist/migrations/collections.d.ts +0 -22
- package/dist/migrations/collections.js +0 -347
- package/dist/migrations/converters.d.ts +0 -46
- package/dist/migrations/converters.js +0 -139
- package/dist/migrations/databases.d.ts +0 -2
- package/dist/migrations/databases.js +0 -28
- package/dist/migrations/dbHelpers.d.ts +0 -5
- package/dist/migrations/dbHelpers.js +0 -57
- package/dist/migrations/helper.d.ts +0 -3
- package/dist/migrations/helper.js +0 -21
- package/dist/migrations/indexes.d.ts +0 -4
- package/dist/migrations/indexes.js +0 -19
- package/dist/migrations/logging.d.ts +0 -10
- package/dist/migrations/logging.js +0 -46
- package/dist/migrations/migrationHelper.d.ts +0 -173
- package/dist/migrations/migrationHelper.js +0 -130
- package/dist/migrations/openapi.d.ts +0 -4
- package/dist/migrations/openapi.js +0 -60
- package/dist/migrations/queue.d.ts +0 -13
- package/dist/migrations/queue.js +0 -79
- package/dist/migrations/schemaStrings.d.ts +0 -14
- package/dist/migrations/schemaStrings.js +0 -478
- package/dist/migrations/setupDatabase.d.ts +0 -6
- package/dist/migrations/setupDatabase.js +0 -115
- package/dist/migrations/storage.d.ts +0 -10
- package/dist/migrations/storage.js +0 -340
- package/dist/migrations/users.d.ts +0 -16
- package/dist/migrations/users.js +0 -276
- package/dist/migrations/validationRules.d.ts +0 -43
- package/dist/migrations/validationRules.js +0 -42
- package/dist/shared/attributeManager.d.ts +0 -17
- package/dist/shared/attributeManager.js +0 -272
- package/src/functions/openapi.ts +0 -83
- package/src/shared/attributeManager.ts +0 -428
@@ -7,7 +7,9 @@ import {
|
|
7
7
|
type Models,
|
8
8
|
} from "node-appwrite";
|
9
9
|
import type { AppwriteConfig, CollectionCreate, Indexes } from "appwrite-utils";
|
10
|
-
import {
|
10
|
+
import type { DatabaseAdapter } from "../adapters/DatabaseAdapter.js";
|
11
|
+
import { getAdapterFromConfig } from "../utils/getClientFromConfig.js";
|
12
|
+
import { nameToIdMapping, processQueue, queuedOperations } from "../shared/operationQueue.js";
|
11
13
|
import { createUpdateCollectionAttributes, createUpdateCollectionAttributesWithStatusCheck } from "./attributes.js";
|
12
14
|
import { createOrUpdateIndexes, createOrUpdateIndexesWithStatusCheck } from "./indexes.js";
|
13
15
|
import { SchemaGenerator } from "../shared/schemaGenerator.js";
|
@@ -26,13 +28,15 @@ import { ProgressManager } from "../shared/progressManager.js";
|
|
26
28
|
import chalk from "chalk";
|
27
29
|
|
28
30
|
export const documentExists = async (
|
29
|
-
db: Databases,
|
31
|
+
db: Databases | DatabaseAdapter,
|
30
32
|
dbId: string,
|
31
33
|
targetCollectionId: string,
|
32
34
|
toCreateObject: any
|
33
35
|
): Promise<Models.Document | null> => {
|
34
|
-
const collection = await db
|
35
|
-
|
36
|
+
const collection = await (db instanceof Databases ?
|
37
|
+
db.getCollection(dbId, targetCollectionId) :
|
38
|
+
db.getTable({ databaseId: dbId, tableId: targetCollectionId }));
|
39
|
+
const attributes = (collection as any).attributes as any[];
|
36
40
|
let arrayTypeAttributes = attributes
|
37
41
|
.filter((attribute: any) => attribute.array === true)
|
38
42
|
.map((attribute: any) => attribute.key);
|
@@ -77,28 +81,30 @@ export const documentExists = async (
|
|
77
81
|
);
|
78
82
|
|
79
83
|
// Execute the query with the validated and prepared parameters
|
80
|
-
const result = await db
|
81
|
-
dbId,
|
82
|
-
targetCollectionId,
|
83
|
-
|
84
|
-
);
|
85
|
-
return
|
84
|
+
const result = await (db instanceof Databases ?
|
85
|
+
db.listDocuments(dbId, targetCollectionId, validQueryParams) :
|
86
|
+
db.listRows({ databaseId: dbId, tableId: targetCollectionId, queries: validQueryParams }));
|
87
|
+
|
88
|
+
const items = db instanceof Databases ? result.documents : ((result as any).rows || result.documents);
|
89
|
+
return items?.[0] || null;
|
86
90
|
};
|
87
91
|
|
88
92
|
export const checkForCollection = async (
|
89
|
-
db: Databases,
|
93
|
+
db: Databases | DatabaseAdapter,
|
90
94
|
dbId: string,
|
91
95
|
collection: Partial<CollectionCreate>
|
92
96
|
): Promise<Models.Collection | null> => {
|
93
97
|
try {
|
94
98
|
MessageFormatter.progress(`Checking for collection with name: ${collection.name}`, { prefix: "Collections" });
|
95
99
|
const response = await tryAwaitWithRetry(
|
96
|
-
async () =>
|
97
|
-
await db.listCollections(dbId, [Query.equal("name", collection.name!)])
|
100
|
+
async () => db instanceof Databases ?
|
101
|
+
await db.listCollections(dbId, [Query.equal("name", collection.name!)]) :
|
102
|
+
await db.listTables({ databaseId: dbId, queries: [Query.equal("name", collection.name!)] })
|
98
103
|
);
|
99
|
-
|
100
|
-
|
101
|
-
|
104
|
+
const items = db instanceof Databases ? response.collections : ((response as any).tables || response.collections);
|
105
|
+
if (items && items.length > 0) {
|
106
|
+
MessageFormatter.info(`Collection found: ${items[0].$id}`, { prefix: "Collections" });
|
107
|
+
return { ...collection, ...items[0] } as Models.Collection;
|
102
108
|
} else {
|
103
109
|
MessageFormatter.info(`No collection found with name: ${collection.name}`, { prefix: "Collections" });
|
104
110
|
return null;
|
@@ -111,7 +117,7 @@ export const checkForCollection = async (
|
|
111
117
|
|
112
118
|
// Helper function to fetch and cache collection by name
|
113
119
|
export const fetchAndCacheCollectionByName = async (
|
114
|
-
db: Databases,
|
120
|
+
db: Databases | DatabaseAdapter,
|
115
121
|
dbId: string,
|
116
122
|
collectionName: string
|
117
123
|
): Promise<Models.Collection | undefined> => {
|
@@ -119,16 +125,20 @@ export const fetchAndCacheCollectionByName = async (
|
|
119
125
|
const collectionId = nameToIdMapping.get(collectionName);
|
120
126
|
MessageFormatter.debug(`Collection found in cache: ${collectionId}`, undefined, { prefix: "Collections" });
|
121
127
|
return await tryAwaitWithRetry(
|
122
|
-
async () =>
|
123
|
-
|
128
|
+
async () => db instanceof Databases ?
|
129
|
+
await db.getCollection(dbId, collectionId!) :
|
130
|
+
await db.getTable({ databaseId: dbId, tableId: collectionId! })
|
131
|
+
) as Models.Collection;
|
124
132
|
} else {
|
125
133
|
MessageFormatter.progress(`Fetching collection by name: ${collectionName}`, { prefix: "Collections" });
|
126
134
|
const collectionsPulled = await tryAwaitWithRetry(
|
127
|
-
async () =>
|
128
|
-
await db.listCollections(dbId, [Query.equal("name", collectionName)])
|
135
|
+
async () => db instanceof Databases ?
|
136
|
+
await db.listCollections(dbId, [Query.equal("name", collectionName)]) :
|
137
|
+
await db.listTables({ databaseId: dbId, queries: [Query.equal("name", collectionName)] })
|
129
138
|
);
|
130
|
-
|
131
|
-
|
139
|
+
const items = db instanceof Databases ? collectionsPulled.collections : ((collectionsPulled as any).tables || collectionsPulled.collections);
|
140
|
+
if ((collectionsPulled.total || items?.length) > 0) {
|
141
|
+
const collection = items[0];
|
132
142
|
MessageFormatter.info(`Collection found: ${collection.$id}`, { prefix: "Collections" });
|
133
143
|
nameToIdMapping.set(collectionName, collection.$id);
|
134
144
|
return collection;
|
@@ -455,8 +465,13 @@ export const createOrUpdateCollections = async (
|
|
455
465
|
// Add delay after creating indexes
|
456
466
|
await delay(250);
|
457
467
|
}
|
458
|
-
// Process any remaining tasks in the queue
|
459
|
-
|
468
|
+
// Process any remaining tasks in the queue (only if there are operations to process)
|
469
|
+
if (queuedOperations.length > 0) {
|
470
|
+
MessageFormatter.info(`Processing ${queuedOperations.length} queued operations (relationship dependencies)`, { prefix: "Collections" });
|
471
|
+
await processQueue(database, databaseId);
|
472
|
+
} else {
|
473
|
+
MessageFormatter.info("No queued operations to process", { prefix: "Collections" });
|
474
|
+
}
|
460
475
|
};
|
461
476
|
|
462
477
|
export const generateMockData = async (
|
@@ -530,7 +545,7 @@ export const transferDocumentsBetweenDbsLocalToLocal = async (
|
|
530
545
|
return;
|
531
546
|
} else if (fromCollDocs.documents.length < 50) {
|
532
547
|
const batchedPromises = fromCollDocs.documents.map((doc) => {
|
533
|
-
const toCreateObject:
|
548
|
+
const toCreateObject: any = {
|
534
549
|
...doc,
|
535
550
|
};
|
536
551
|
delete toCreateObject.$databaseId;
|
@@ -554,7 +569,7 @@ export const transferDocumentsBetweenDbsLocalToLocal = async (
|
|
554
569
|
totalDocumentsTransferred += fromCollDocs.documents.length;
|
555
570
|
} else {
|
556
571
|
const batchedPromises = fromCollDocs.documents.map((doc) => {
|
557
|
-
const toCreateObject:
|
572
|
+
const toCreateObject: any = {
|
558
573
|
...doc,
|
559
574
|
};
|
560
575
|
delete toCreateObject.$databaseId;
|
@@ -586,7 +601,7 @@ export const transferDocumentsBetweenDbsLocalToLocal = async (
|
|
586
601
|
])
|
587
602
|
);
|
588
603
|
const batchedPromises = fromCollDocs.documents.map((doc) => {
|
589
|
-
const toCreateObject:
|
604
|
+
const toCreateObject: any = {
|
590
605
|
...doc,
|
591
606
|
};
|
592
607
|
delete toCreateObject.$databaseId;
|
package/src/config/yamlConfig.ts
CHANGED
@@ -46,15 +46,17 @@ const YamlConfigSchema = z.object({
|
|
46
46
|
.object({
|
47
47
|
outputDirectory: z.string().default("schemas"),
|
48
48
|
yamlSchemaDirectory: z.string().default(".yaml_schemas"),
|
49
|
+
collectionsDirectory: z.string().default("collections"),
|
49
50
|
})
|
50
51
|
.optional()
|
51
52
|
.default({
|
52
53
|
outputDirectory: "schemas",
|
53
54
|
yamlSchemaDirectory: ".yaml_schemas",
|
55
|
+
collectionsDirectory: "collections",
|
54
56
|
}),
|
55
57
|
migrations: z
|
56
58
|
.object({
|
57
|
-
enabled: z.boolean().default(
|
59
|
+
enabled: z.boolean().default(false),
|
58
60
|
})
|
59
61
|
.optional()
|
60
62
|
.default({
|
@@ -148,6 +150,7 @@ export const convertYamlToAppwriteConfig = (yamlConfig: YamlConfig): AppwriteCon
|
|
148
150
|
appwriteEndpoint: yamlConfig.appwrite.endpoint,
|
149
151
|
appwriteProject: yamlConfig.appwrite.project,
|
150
152
|
appwriteKey: yamlConfig.appwrite.key,
|
153
|
+
apiMode: "auto", // Default to auto-detect for dual API support
|
151
154
|
appwriteClient: null,
|
152
155
|
logging: {
|
153
156
|
enabled: yamlConfig.logging.enabled,
|
@@ -167,6 +170,7 @@ export const convertYamlToAppwriteConfig = (yamlConfig: YamlConfig): AppwriteCon
|
|
167
170
|
outputDirectory: yamlConfig.schemas.outputDirectory,
|
168
171
|
yamlSchemaDirectory: yamlConfig.schemas.yamlSchemaDirectory,
|
169
172
|
importDirectory: yamlConfig.data.importDirectory,
|
173
|
+
collectionsDirectory: yamlConfig.schemas.collectionsDirectory || "collections",
|
170
174
|
},
|
171
175
|
databases: yamlConfig.databases.map((db) => ({
|
172
176
|
$id: db.id,
|
@@ -244,7 +248,7 @@ export const loadYamlConfig = async (configPath: string): Promise<AppwriteConfig
|
|
244
248
|
} catch (error) {
|
245
249
|
if (error instanceof z.ZodError) {
|
246
250
|
console.error("❌ YAML config validation failed:");
|
247
|
-
error.
|
251
|
+
error.issues.forEach((err) => {
|
248
252
|
console.error(` ${err.path.join('.')} → ${err.message}`);
|
249
253
|
});
|
250
254
|
} else {
|
@@ -415,6 +419,7 @@ export const generateYamlConfigTemplate = (outputPath: string) => {
|
|
415
419
|
schemas: {
|
416
420
|
outputDirectory: "schemas",
|
417
421
|
yamlSchemaDirectory: ".yaml_schemas",
|
422
|
+
collectionsDirectory: "collections",
|
418
423
|
},
|
419
424
|
migrations: {
|
420
425
|
enabled: true,
|
@@ -476,6 +481,7 @@ export const writeYamlConfig = async (configPath: string, config: AppwriteConfig
|
|
476
481
|
schemas: {
|
477
482
|
outputDirectory: config.schemaConfig?.outputDirectory || "schemas",
|
478
483
|
yamlSchemaDirectory: config.schemaConfig?.yamlSchemaDirectory || ".yaml_schemas",
|
484
|
+
collectionsDirectory: config.schemaConfig?.collectionsDirectory || "collections",
|
479
485
|
},
|
480
486
|
migrations: {
|
481
487
|
enabled: config.useMigrations !== false,
|
package/src/databases/setup.ts
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
import { Databases, Query, type Models } from "node-appwrite";
|
2
|
-
import {
|
2
|
+
import { createOrUpdateAttributeWithStatusCheck } from "../collections/attributes.js";
|
3
3
|
import { getMigrationCollectionSchemas } from "../storage/schemas.js";
|
4
4
|
import {
|
5
5
|
areCollectionNamesSame,
|
@@ -90,7 +90,7 @@ export const setupMigrationDatabase = async (config: AppwriteConfig) => {
|
|
90
90
|
|
91
91
|
for (const attribute of attributes) {
|
92
92
|
try {
|
93
|
-
await
|
93
|
+
await createOrUpdateAttributeWithStatusCheck(
|
94
94
|
database,
|
95
95
|
db.$id,
|
96
96
|
collectionFound,
|
@@ -219,7 +219,7 @@ export const afterImportActions = {
|
|
219
219
|
}
|
220
220
|
const nextCursor = documents[documents.length - 1].$id;
|
221
221
|
const nextBatch = await fetchAllMatchingDocuments(nextCursor);
|
222
|
-
return documents.concat(nextBatch);
|
222
|
+
return documents.concat(nextBatch as any);
|
223
223
|
};
|
224
224
|
|
225
225
|
const matchingDocuments = await fetchAllMatchingDocuments();
|
@@ -316,7 +316,7 @@ export const afterImportActions = {
|
|
316
316
|
}
|
317
317
|
const nextCursor = documents[documents.length - 1].$id;
|
318
318
|
const nextBatch = await fetchAllMatchingDocuments(nextCursor);
|
319
|
-
return documents.concat(nextBatch);
|
319
|
+
return documents.concat(nextBatch as any);
|
320
320
|
};
|
321
321
|
|
322
322
|
const matchingDocuments = await fetchAllMatchingDocuments();
|
@@ -1682,6 +1682,7 @@ export class ComprehensiveTransfer {
|
|
1682
1682
|
$permissions,
|
1683
1683
|
$databaseId,
|
1684
1684
|
$collectionId,
|
1685
|
+
$sequence,
|
1685
1686
|
...docData
|
1686
1687
|
} = doc;
|
1687
1688
|
return {
|
@@ -1799,6 +1800,7 @@ export class ComprehensiveTransfer {
|
|
1799
1800
|
$permissions,
|
1800
1801
|
$databaseId,
|
1801
1802
|
$collectionId,
|
1803
|
+
$sequence,
|
1802
1804
|
...docData
|
1803
1805
|
} = doc;
|
1804
1806
|
|
@@ -1827,6 +1829,7 @@ export class ComprehensiveTransfer {
|
|
1827
1829
|
$permissions,
|
1828
1830
|
$databaseId,
|
1829
1831
|
$collectionId,
|
1832
|
+
$sequence,
|
1830
1833
|
...docData
|
1831
1834
|
} = doc;
|
1832
1835
|
await tryAwaitWithRetry(async () =>
|
@@ -1889,6 +1892,7 @@ export class ComprehensiveTransfer {
|
|
1889
1892
|
$permissions,
|
1890
1893
|
$databaseId,
|
1891
1894
|
$collectionId,
|
1895
|
+
$sequence,
|
1892
1896
|
...docData
|
1893
1897
|
} = doc;
|
1894
1898
|
|
@@ -806,7 +806,7 @@ export class DataLoader {
|
|
806
806
|
if (!userData.success || !(userData.data.email || userData.data.phone)) {
|
807
807
|
logger.error(
|
808
808
|
`Invalid user data: ${JSON.stringify(
|
809
|
-
userData.error?.
|
809
|
+
userData.error?.issues,
|
810
810
|
undefined,
|
811
811
|
2
|
812
812
|
)} or missing email/phone`
|
@@ -908,6 +908,7 @@ export class DataLoader {
|
|
908
908
|
const userDataToAdd = {
|
909
909
|
rawData: item,
|
910
910
|
finalData: userData.data,
|
911
|
+
context: {},
|
911
912
|
};
|
912
913
|
this.importMap.set(this.getCollectionKey("users"), {
|
913
914
|
data: [...(usersMap?.data || []), userDataToAdd],
|
@@ -138,7 +138,7 @@ export class UserMappingService {
|
|
138
138
|
if (!userData.success || !(userData.data.email || userData.data.phone)) {
|
139
139
|
logger.error(
|
140
140
|
`Invalid user data: ${JSON.stringify(
|
141
|
-
userData.error?.
|
141
|
+
userData.error?.issues,
|
142
142
|
undefined,
|
143
143
|
2
|
144
144
|
)} or missing email/phone`
|
@@ -70,7 +70,12 @@ export const YamlImportConfigSchema = z.object({
|
|
70
70
|
originalIdField: z.string().describe("Field in source data for matching"),
|
71
71
|
targetField: z.string().describe("Field in collection to match against"),
|
72
72
|
}).optional().describe("Configuration for update operations"),
|
73
|
-
}).default({
|
73
|
+
}).default(() => ({
|
74
|
+
batchSize: 50,
|
75
|
+
skipValidation: false,
|
76
|
+
dryRun: false,
|
77
|
+
continueOnError: true
|
78
|
+
})),
|
74
79
|
});
|
75
80
|
|
76
81
|
export type YamlImportConfig = z.infer<typeof YamlImportConfigSchema>;
|
@@ -112,7 +117,7 @@ export class YamlImportConfigLoader {
|
|
112
117
|
|
113
118
|
} catch (error) {
|
114
119
|
if (error instanceof z.ZodError) {
|
115
|
-
const errorMessages = error.
|
120
|
+
const errorMessages = error.issues.map(err => `${err.path.join('.')}: ${err.message}`);
|
116
121
|
throw new Error(`Invalid import configuration in ${configPath}:\n${errorMessages.join('\n')}`);
|
117
122
|
}
|
118
123
|
throw new Error(`Failed to load import configuration ${configPath}: ${error}`);
|
package/src/schemas/authUser.ts
CHANGED
@@ -7,7 +7,7 @@ export const AuthUserSchema = z.object({
|
|
7
7
|
name: z.string().nullish(),
|
8
8
|
email: z.string().email("Invalid Email Address").nullish(),
|
9
9
|
phone: z.string().nullish(),
|
10
|
-
prefs: z.record(z.string()).optional().default({}),
|
10
|
+
prefs: z.record(z.string(), z.string()).optional().default({}),
|
11
11
|
labels: z.array(z.string()).optional().default([]),
|
12
12
|
});
|
13
13
|
|
@@ -6,7 +6,6 @@ import chalk from "chalk";
|
|
6
6
|
|
7
7
|
export interface JsonSchemaProperty {
|
8
8
|
type: string | string[];
|
9
|
-
description?: string;
|
10
9
|
format?: string;
|
11
10
|
minimum?: number;
|
12
11
|
maximum?: number;
|
@@ -27,7 +26,6 @@ export interface JsonSchema {
|
|
27
26
|
$schema: string;
|
28
27
|
$id: string;
|
29
28
|
title: string;
|
30
|
-
description?: string;
|
31
29
|
type: "object";
|
32
30
|
properties: Record<string, JsonSchemaProperty>;
|
33
31
|
required: string[];
|
@@ -72,12 +70,6 @@ export class JsonSchemaGenerator {
|
|
72
70
|
type: "string" // Default type
|
73
71
|
};
|
74
72
|
|
75
|
-
// Set description if available
|
76
|
-
if (attribute.description) {
|
77
|
-
property.description = typeof attribute.description === 'string'
|
78
|
-
? attribute.description
|
79
|
-
: JSON.stringify(attribute.description);
|
80
|
-
}
|
81
73
|
|
82
74
|
// Handle array attributes
|
83
75
|
if (attribute.array) {
|
@@ -167,7 +159,6 @@ export class JsonSchemaGenerator {
|
|
167
159
|
schema.$ref = `#/definitions/${toPascalCase(attribute.relatedCollection)}`;
|
168
160
|
} else {
|
169
161
|
schema.type = "string";
|
170
|
-
schema.description = "Document ID reference";
|
171
162
|
}
|
172
163
|
break;
|
173
164
|
|
@@ -184,31 +175,26 @@ export class JsonSchemaGenerator {
|
|
184
175
|
$schema: "https://json-schema.org/draft/2020-12/schema",
|
185
176
|
$id: `https://example.com/schemas/${toCamelCase(collection.name)}.json`,
|
186
177
|
title: pascalName,
|
187
|
-
description: collection.description || `Schema for ${collection.name} collection`,
|
188
178
|
type: "object",
|
189
179
|
properties: {
|
190
180
|
// Standard Appwrite document fields
|
191
181
|
$id: {
|
192
182
|
type: "string",
|
193
|
-
description: "Document ID",
|
194
183
|
pattern: "^[a-zA-Z0-9][a-zA-Z0-9._-]{0,35}$"
|
195
184
|
},
|
196
185
|
$createdAt: {
|
197
186
|
type: "string",
|
198
|
-
format: "date-time"
|
199
|
-
description: "Document creation date"
|
187
|
+
format: "date-time"
|
200
188
|
},
|
201
189
|
$updatedAt: {
|
202
190
|
type: "string",
|
203
|
-
format: "date-time"
|
204
|
-
description: "Document last update date"
|
191
|
+
format: "date-time"
|
205
192
|
},
|
206
193
|
$permissions: {
|
207
194
|
type: "array",
|
208
195
|
items: {
|
209
196
|
type: "string"
|
210
|
-
}
|
211
|
-
description: "Document permissions"
|
197
|
+
}
|
212
198
|
}
|
213
199
|
},
|
214
200
|
required: ["$id", "$createdAt", "$updatedAt"],
|
@@ -244,8 +230,7 @@ export class JsonSchemaGenerator {
|
|
244
230
|
$createdAt: { type: "string", format: "date-time" },
|
245
231
|
$updatedAt: { type: "string", format: "date-time" }
|
246
232
|
},
|
247
|
-
additionalProperties: true
|
248
|
-
description: `Reference to ${rel.relatedCollection} document`
|
233
|
+
additionalProperties: true
|
249
234
|
};
|
250
235
|
});
|
251
236
|
}
|
@@ -1,8 +1,9 @@
|
|
1
1
|
import { Query, type Databases, type Models } from "node-appwrite";
|
2
2
|
import type { Attribute } from "appwrite-utils";
|
3
|
-
import {
|
3
|
+
import { createOrUpdateAttributeWithStatusCheck } from "../collections/attributes.js";
|
4
4
|
import { fetchAndCacheCollectionByName } from "../collections/methods.js";
|
5
5
|
import { tryAwaitWithRetry } from "../utils/helperFunctions.js";
|
6
|
+
import chalk from "chalk";
|
6
7
|
|
7
8
|
export interface QueuedOperation {
|
8
9
|
type: "attribute";
|
@@ -81,24 +82,30 @@ export const processQueue = async (db: Databases, dbId: string) => {
|
|
81
82
|
|
82
83
|
// Process the operation if the collection is found
|
83
84
|
if (collectionFound && operation.attribute) {
|
84
|
-
console.log(
|
85
|
-
`\
|
86
|
-
);
|
87
|
-
await
|
85
|
+
console.log(chalk.cyan(
|
86
|
+
`\t📋 Queue processing relationship attribute: ${operation.attribute.key} for collection: ${collectionFound.name}`
|
87
|
+
));
|
88
|
+
const success = await createOrUpdateAttributeWithStatusCheck(
|
88
89
|
db,
|
89
90
|
dbId,
|
90
91
|
collectionFound,
|
91
92
|
operation.attribute
|
92
93
|
);
|
93
|
-
|
94
|
-
|
95
|
-
|
94
|
+
|
95
|
+
if (success) {
|
96
|
+
console.log(chalk.green(`\t✅ Successfully processed queued attribute: ${operation.attribute.key}`));
|
97
|
+
queuedOperations.splice(i, 1);
|
98
|
+
i--; // Adjust index since we're modifying the array
|
99
|
+
progress = true;
|
100
|
+
} else {
|
101
|
+
console.log(chalk.red(`\t❌ Failed to process queued attribute: ${operation.attribute.key}, removing from queue`));
|
102
|
+
queuedOperations.splice(i, 1);
|
103
|
+
i--; // Adjust index since we're modifying the array
|
104
|
+
}
|
96
105
|
} else {
|
97
|
-
console.
|
98
|
-
`\
|
99
|
-
|
100
|
-
)}`
|
101
|
-
);
|
106
|
+
console.log(chalk.yellow(
|
107
|
+
`\t⚠️ Collection not found for queued operation, removing from queue: ${operation.attribute?.key || 'unknown'}`
|
108
|
+
));
|
102
109
|
queuedOperations.splice(i, 1);
|
103
110
|
i--; // Adjust index since we're modifying the array
|
104
111
|
}
|
@@ -414,11 +414,6 @@ export default appwriteConfig;
|
|
414
414
|
createSchemaString = (name: string, attributes: Attribute[]): string => {
|
415
415
|
const pascalName = toPascalCase(name);
|
416
416
|
let imports = `import { z } from "zod";\n`;
|
417
|
-
const hasDescription = attributes.some((attr) => attr.description);
|
418
|
-
if (hasDescription) {
|
419
|
-
imports += `import { extendZodWithOpenApi } from "@asteasolutions/zod-to-openapi";\n`;
|
420
|
-
imports += `extendZodWithOpenApi(z);\n`;
|
421
|
-
}
|
422
417
|
|
423
418
|
// Use the relationshipMap to find related collections
|
424
419
|
const relationshipDetails = this.relationshipMap.get(name) || [];
|
@@ -555,14 +550,14 @@ export default appwriteConfig;
|
|
555
550
|
baseSchemaCode = "z.number().int()";
|
556
551
|
if (finalAttribute.min !== undefined) {
|
557
552
|
if (BigInt(finalAttribute.min) === BigInt(-9223372036854776000)) {
|
558
|
-
|
553
|
+
finalAttribute.min = undefined;
|
559
554
|
} else {
|
560
555
|
baseSchemaCode += `.min(${finalAttribute.min}, "Minimum value of ${finalAttribute.min} not met")`;
|
561
556
|
}
|
562
557
|
}
|
563
558
|
if (finalAttribute.max !== undefined) {
|
564
559
|
if (BigInt(finalAttribute.max) === BigInt(9223372036854776000)) {
|
565
|
-
|
560
|
+
finalAttribute.max = undefined;
|
566
561
|
} else {
|
567
562
|
baseSchemaCode += `.max(${finalAttribute.max}, "Maximum value of ${finalAttribute.max} exceeded")`;
|
568
563
|
}
|
@@ -659,15 +654,6 @@ export default appwriteConfig;
|
|
659
654
|
if (attribute.array && !attribute.required) {
|
660
655
|
baseSchemaCode += ".nullish()";
|
661
656
|
}
|
662
|
-
if (attribute.description) {
|
663
|
-
if (typeof attribute.description === "string") {
|
664
|
-
baseSchemaCode += `.openapi({ description: "${attribute.description}" })`;
|
665
|
-
} else {
|
666
|
-
baseSchemaCode += `.openapi(${Object.entries(attribute.description)
|
667
|
-
.map(([key, value]) => `"${key}": ${value}`)
|
668
|
-
.join(", ")})`;
|
669
|
-
}
|
670
|
-
}
|
671
657
|
|
672
658
|
return baseSchemaCode;
|
673
659
|
};
|
@@ -0,0 +1,44 @@
|
|
1
|
+
/**
|
2
|
+
* Type declarations for optional node-appwrite-tablesdb module
|
3
|
+
* This allows compilation when the module is not installed
|
4
|
+
*/
|
5
|
+
|
6
|
+
declare module 'node-appwrite-tablesdb' {
|
7
|
+
export class Client {
|
8
|
+
setEndpoint(endpoint: string): this;
|
9
|
+
setProject(project: string): this;
|
10
|
+
setKey(key: string): this;
|
11
|
+
}
|
12
|
+
|
13
|
+
export class TablesDB {
|
14
|
+
constructor(client: Client);
|
15
|
+
|
16
|
+
// Core methods based on TablesDB API
|
17
|
+
listTables(databaseId: string, queries?: any[]): Promise<any>;
|
18
|
+
createTable(databaseId: string, id: string, name: string, permissions?: string[], documentSecurity?: boolean, enabled?: boolean): Promise<any>;
|
19
|
+
updateTable(databaseId: string, id: string, name: string, permissions?: string[], documentSecurity?: boolean, enabled?: boolean): Promise<any>;
|
20
|
+
deleteTable(databaseId: string, tableId: string): Promise<void>;
|
21
|
+
getTable(databaseId: string, tableId: string): Promise<any>;
|
22
|
+
|
23
|
+
listRows(databaseId: string, tableId: string, queries?: any[]): Promise<any>;
|
24
|
+
createRow(databaseId: string, tableId: string, id: string, data: any, permissions?: string[]): Promise<any>;
|
25
|
+
updateRow(databaseId: string, tableId: string, id: string, data?: any, permissions?: string[]): Promise<any>;
|
26
|
+
deleteRow(databaseId: string, tableId: string, id: string): Promise<void>;
|
27
|
+
getRow(databaseId: string, tableId: string, id: string): Promise<any>;
|
28
|
+
|
29
|
+
// Bulk operations (if supported)
|
30
|
+
bulkCreateRows?(databaseId: string, tableId: string, rows: any[]): Promise<any>;
|
31
|
+
bulkUpsertRows?(databaseId: string, tableId: string, rows: any[]): Promise<any>;
|
32
|
+
bulkDeleteRows?(databaseId: string, tableId: string, rowIds: string[]): Promise<any>;
|
33
|
+
|
34
|
+
// Index operations
|
35
|
+
listIndexes(databaseId: string, tableId: string, queries?: any[]): Promise<any>;
|
36
|
+
createIndex(databaseId: string, tableId: string, key: string, type: string, attributes: string[], orders?: string[]): Promise<any>;
|
37
|
+
deleteIndex(databaseId: string, tableId: string, key: string): Promise<void>;
|
38
|
+
|
39
|
+
// Attribute operations
|
40
|
+
createAttribute(databaseId: string, tableId: string, key: string, type: string, ...args: any[]): Promise<any>;
|
41
|
+
updateAttribute(databaseId: string, tableId: string, key: string, required?: boolean, defaultValue?: any): Promise<any>;
|
42
|
+
deleteAttribute(databaseId: string, tableId: string, key: string): Promise<void>;
|
43
|
+
}
|
44
|
+
}
|
package/src/users/methods.ts
CHANGED
@@ -105,14 +105,14 @@ export class UsersController {
|
|
105
105
|
return allUsers;
|
106
106
|
}
|
107
107
|
|
108
|
-
async createUsersAndReturn(items: AuthUserCreate[]) {
|
108
|
+
async createUsersAndReturn(items: AuthUserCreate[]): Promise<any[]> {
|
109
109
|
const users = await Promise.all(
|
110
110
|
items.map((item) => this.createUserAndReturn(item))
|
111
111
|
);
|
112
112
|
return users;
|
113
113
|
}
|
114
114
|
|
115
|
-
async createUserAndReturn(item: AuthUserCreate) {
|
115
|
+
async createUserAndReturn(item: AuthUserCreate): Promise<any> {
|
116
116
|
try {
|
117
117
|
const user = await tryAwaitWithRetry(async () => {
|
118
118
|
const createdUser = await this.users.create(
|
@@ -303,7 +303,6 @@ async function convertCollectionToYaml(tsFilePath: string, targetDir: string): P
|
|
303
303
|
required: attr.required ?? false,
|
304
304
|
array: attr.array,
|
305
305
|
default: attr.xdefault || attr.default,
|
306
|
-
description: attr.description,
|
307
306
|
min: attr.min,
|
308
307
|
max: attr.max,
|
309
308
|
elements: attr.elements,
|