appwrite-utils-cli 1.3.5 → 1.4.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.
Files changed (116) hide show
  1. package/dist/adapters/AdapterFactory.d.ts +87 -0
  2. package/dist/adapters/AdapterFactory.js +217 -0
  3. package/dist/adapters/DatabaseAdapter.d.ts +217 -0
  4. package/dist/adapters/DatabaseAdapter.js +50 -0
  5. package/dist/adapters/LegacyAdapter.d.ts +49 -0
  6. package/dist/adapters/LegacyAdapter.js +382 -0
  7. package/dist/adapters/TablesDBAdapter.d.ts +55 -0
  8. package/dist/adapters/TablesDBAdapter.js +302 -0
  9. package/dist/adapters/index.d.ts +11 -0
  10. package/dist/adapters/index.js +12 -0
  11. package/dist/collections/attributes.js +41 -22
  12. package/dist/collections/methods.d.ts +4 -3
  13. package/dist/collections/methods.js +34 -14
  14. package/dist/config/yamlConfig.d.ts +40 -437
  15. package/dist/config/yamlConfig.js +8 -2
  16. package/dist/databases/setup.js +2 -2
  17. package/dist/main.js +0 -0
  18. package/dist/migrations/appwriteToX.d.ts +26 -37
  19. package/dist/migrations/comprehensiveTransfer.js +4 -4
  20. package/dist/migrations/dataLoader.d.ts +124 -1484
  21. package/dist/migrations/dataLoader.js +2 -1
  22. package/dist/migrations/relationships.d.ts +2 -3
  23. package/dist/migrations/relationships.js +1 -1
  24. package/dist/migrations/services/UserMappingService.js +1 -1
  25. package/dist/migrations/yaml/YamlImportConfigLoader.d.ts +24 -279
  26. package/dist/migrations/yaml/YamlImportConfigLoader.js +7 -2
  27. package/dist/schemas/authUser.d.ts +7 -47
  28. package/dist/schemas/authUser.js +1 -1
  29. package/dist/shared/jsonSchemaGenerator.d.ts +0 -2
  30. package/dist/shared/jsonSchemaGenerator.js +4 -17
  31. package/dist/shared/migrationHelpers.d.ts +17 -119
  32. package/dist/shared/operationQueue.js +16 -7
  33. package/dist/shared/schemaGenerator.js +2 -17
  34. package/dist/storage/schemas.d.ts +149 -296
  35. package/dist/users/methods.d.ts +2 -2
  36. package/dist/utils/configMigration.js +0 -1
  37. package/dist/utils/getClientFromConfig.d.ts +26 -0
  38. package/dist/utils/getClientFromConfig.js +37 -0
  39. package/dist/utils/loadConfigs.js +0 -2
  40. package/dist/utils/schemaStrings.js +2 -17
  41. package/dist/utils/setupFiles.js +2 -0
  42. package/dist/utils/versionDetection.d.ts +56 -0
  43. package/dist/utils/versionDetection.js +217 -0
  44. package/dist/utils/yamlConverter.d.ts +0 -1
  45. package/dist/utils/yamlConverter.js +0 -2
  46. package/dist/utilsController.js +2 -0
  47. package/package.json +3 -2
  48. package/src/adapters/AdapterFactory.ts +296 -0
  49. package/src/adapters/DatabaseAdapter.ts +290 -0
  50. package/src/adapters/LegacyAdapter.ts +667 -0
  51. package/src/adapters/TablesDBAdapter.ts +429 -0
  52. package/src/adapters/index.ts +37 -0
  53. package/src/collections/attributes.ts +347 -153
  54. package/src/collections/methods.ts +43 -28
  55. package/src/config/yamlConfig.ts +8 -2
  56. package/src/databases/setup.ts +2 -2
  57. package/src/migrations/afterImportActions.ts +2 -2
  58. package/src/migrations/comprehensiveTransfer.ts +4 -0
  59. package/src/migrations/dataLoader.ts +2 -1
  60. package/src/migrations/relationships.ts +1 -1
  61. package/src/migrations/services/UserMappingService.ts +1 -1
  62. package/src/migrations/yaml/YamlImportConfigLoader.ts +7 -2
  63. package/src/schemas/authUser.ts +1 -1
  64. package/src/shared/jsonSchemaGenerator.ts +4 -19
  65. package/src/shared/operationQueue.ts +20 -13
  66. package/src/shared/schemaGenerator.ts +2 -16
  67. package/src/types/node-appwrite-tablesdb.d.ts +44 -0
  68. package/src/users/methods.ts +2 -2
  69. package/src/utils/configMigration.ts +0 -1
  70. package/src/utils/getClientFromConfig.ts +56 -0
  71. package/src/utils/loadConfigs.ts +0 -2
  72. package/src/utils/schemaStrings.ts +2 -16
  73. package/src/utils/setupFiles.ts +2 -0
  74. package/src/utils/versionDetection.ts +265 -0
  75. package/src/utils/yamlConverter.ts +0 -2
  76. package/src/utilsController.ts +2 -0
  77. package/dist/functions/openapi.d.ts +0 -4
  78. package/dist/functions/openapi.js +0 -60
  79. package/dist/migrations/attributes.d.ts +0 -4
  80. package/dist/migrations/attributes.js +0 -301
  81. package/dist/migrations/backup.d.ts +0 -687
  82. package/dist/migrations/backup.js +0 -175
  83. package/dist/migrations/collections.d.ts +0 -22
  84. package/dist/migrations/collections.js +0 -347
  85. package/dist/migrations/converters.d.ts +0 -46
  86. package/dist/migrations/converters.js +0 -139
  87. package/dist/migrations/databases.d.ts +0 -2
  88. package/dist/migrations/databases.js +0 -28
  89. package/dist/migrations/dbHelpers.d.ts +0 -5
  90. package/dist/migrations/dbHelpers.js +0 -57
  91. package/dist/migrations/helper.d.ts +0 -3
  92. package/dist/migrations/helper.js +0 -21
  93. package/dist/migrations/indexes.d.ts +0 -4
  94. package/dist/migrations/indexes.js +0 -19
  95. package/dist/migrations/logging.d.ts +0 -10
  96. package/dist/migrations/logging.js +0 -46
  97. package/dist/migrations/migrationHelper.d.ts +0 -173
  98. package/dist/migrations/migrationHelper.js +0 -130
  99. package/dist/migrations/openapi.d.ts +0 -4
  100. package/dist/migrations/openapi.js +0 -60
  101. package/dist/migrations/queue.d.ts +0 -13
  102. package/dist/migrations/queue.js +0 -79
  103. package/dist/migrations/schemaStrings.d.ts +0 -14
  104. package/dist/migrations/schemaStrings.js +0 -478
  105. package/dist/migrations/setupDatabase.d.ts +0 -6
  106. package/dist/migrations/setupDatabase.js +0 -115
  107. package/dist/migrations/storage.d.ts +0 -10
  108. package/dist/migrations/storage.js +0 -340
  109. package/dist/migrations/users.d.ts +0 -16
  110. package/dist/migrations/users.js +0 -276
  111. package/dist/migrations/validationRules.d.ts +0 -43
  112. package/dist/migrations/validationRules.js +0 -42
  113. package/dist/shared/attributeManager.d.ts +0 -17
  114. package/dist/shared/attributeManager.js +0 -272
  115. package/src/functions/openapi.ts +0 -83
  116. 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 { nameToIdMapping, processQueue } from "../shared/operationQueue.js";
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.getCollection(dbId, targetCollectionId);
35
- const attributes = collection.attributes as any[];
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.listDocuments(
81
- dbId,
82
- targetCollectionId,
83
- validQueryParams
84
- );
85
- return result.documents[0] || null;
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
- if (response.collections.length > 0) {
100
- MessageFormatter.info(`Collection found: ${response.collections[0].$id}`, { prefix: "Collections" });
101
- return { ...collection, ...response.collections[0] };
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 () => await db.getCollection(dbId, collectionId!)
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
- if (collectionsPulled.total > 0) {
131
- const collection = collectionsPulled.collections[0];
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
- await processQueue(database, databaseId);
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: Partial<typeof doc> = {
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: Partial<typeof doc> = {
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: Partial<typeof doc> = {
604
+ const toCreateObject: any = {
590
605
  ...doc,
591
606
  };
592
607
  delete toCreateObject.$databaseId;
@@ -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(true),
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.errors.forEach((err) => {
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,
@@ -1,5 +1,5 @@
1
1
  import { Databases, Query, type Models } from "node-appwrite";
2
- import { createOrUpdateAttribute } from "../collections/attributes.js";
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 createOrUpdateAttribute(
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?.errors,
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],
@@ -218,7 +218,7 @@ async function prepareDocumentUpdates(
218
218
  dbId,
219
219
  relatedCollection,
220
220
  targetField!,
221
- originalId
221
+ String(originalId)
222
222
  );
223
223
 
224
224
  if (foundDocuments && foundDocuments.length > 0) {
@@ -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?.errors,
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.errors.map(err => `${err.path.join('.')}: ${err.message}`);
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}`);
@@ -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 { createOrUpdateAttribute } from "../collections/attributes.js";
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
- `\tProcessing attribute: ${operation.attribute.key} for collection ID: ${collectionFound.$id}`
86
- );
87
- await createOrUpdateAttribute(
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
- queuedOperations.splice(i, 1);
94
- i--; // Adjust index since we're modifying the array
95
- progress = true;
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.error(
98
- `\tCollection not found for operation, removing from queue: ${JSON.stringify(
99
- operation
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
- delete finalAttribute.min;
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
- delete finalAttribute.max;
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
+ }
@@ -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,