appwrite-utils-cli 1.5.2 → 1.6.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.
Files changed (233) hide show
  1. package/CHANGELOG.md +199 -0
  2. package/README.md +251 -29
  3. package/dist/adapters/AdapterFactory.d.ts +10 -3
  4. package/dist/adapters/AdapterFactory.js +213 -17
  5. package/dist/adapters/TablesDBAdapter.js +60 -17
  6. package/dist/backups/operations/bucketBackup.d.ts +19 -0
  7. package/dist/backups/operations/bucketBackup.js +197 -0
  8. package/dist/backups/operations/collectionBackup.d.ts +30 -0
  9. package/dist/backups/operations/collectionBackup.js +201 -0
  10. package/dist/backups/operations/comprehensiveBackup.d.ts +25 -0
  11. package/dist/backups/operations/comprehensiveBackup.js +238 -0
  12. package/dist/backups/schemas/bucketManifest.d.ts +93 -0
  13. package/dist/backups/schemas/bucketManifest.js +33 -0
  14. package/dist/backups/schemas/comprehensiveManifest.d.ts +108 -0
  15. package/dist/backups/schemas/comprehensiveManifest.js +32 -0
  16. package/dist/backups/tracking/centralizedTracking.d.ts +34 -0
  17. package/dist/backups/tracking/centralizedTracking.js +274 -0
  18. package/dist/cli/commands/configCommands.d.ts +8 -0
  19. package/dist/cli/commands/configCommands.js +160 -0
  20. package/dist/cli/commands/databaseCommands.d.ts +13 -0
  21. package/dist/cli/commands/databaseCommands.js +478 -0
  22. package/dist/cli/commands/functionCommands.d.ts +7 -0
  23. package/dist/cli/commands/functionCommands.js +289 -0
  24. package/dist/cli/commands/schemaCommands.d.ts +7 -0
  25. package/dist/cli/commands/schemaCommands.js +134 -0
  26. package/dist/cli/commands/transferCommands.d.ts +5 -0
  27. package/dist/cli/commands/transferCommands.js +384 -0
  28. package/dist/collections/attributes.d.ts +5 -4
  29. package/dist/collections/attributes.js +539 -246
  30. package/dist/collections/indexes.js +39 -37
  31. package/dist/collections/methods.d.ts +2 -16
  32. package/dist/collections/methods.js +90 -538
  33. package/dist/collections/transferOperations.d.ts +7 -0
  34. package/dist/collections/transferOperations.js +331 -0
  35. package/dist/collections/wipeOperations.d.ts +16 -0
  36. package/dist/collections/wipeOperations.js +328 -0
  37. package/dist/config/configMigration.d.ts +87 -0
  38. package/dist/config/configMigration.js +390 -0
  39. package/dist/config/configValidation.d.ts +66 -0
  40. package/dist/config/configValidation.js +358 -0
  41. package/dist/config/yamlConfig.d.ts +455 -1
  42. package/dist/config/yamlConfig.js +145 -52
  43. package/dist/databases/methods.js +3 -2
  44. package/dist/databases/setup.d.ts +1 -2
  45. package/dist/databases/setup.js +9 -87
  46. package/dist/examples/yamlTerminologyExample.d.ts +42 -0
  47. package/dist/examples/yamlTerminologyExample.js +269 -0
  48. package/dist/functions/deployments.js +11 -10
  49. package/dist/functions/methods.d.ts +1 -1
  50. package/dist/functions/methods.js +5 -4
  51. package/dist/init.js +9 -9
  52. package/dist/interactiveCLI.d.ts +8 -17
  53. package/dist/interactiveCLI.js +181 -1172
  54. package/dist/main.js +364 -21
  55. package/dist/migrations/afterImportActions.js +22 -30
  56. package/dist/migrations/appwriteToX.js +71 -25
  57. package/dist/migrations/dataLoader.js +35 -26
  58. package/dist/migrations/importController.js +29 -30
  59. package/dist/migrations/relationships.js +13 -12
  60. package/dist/migrations/services/ImportOrchestrator.js +16 -19
  61. package/dist/migrations/transfer.js +46 -46
  62. package/dist/migrations/yaml/YamlImportConfigLoader.d.ts +3 -1
  63. package/dist/migrations/yaml/YamlImportConfigLoader.js +6 -3
  64. package/dist/migrations/yaml/YamlImportIntegration.d.ts +9 -3
  65. package/dist/migrations/yaml/YamlImportIntegration.js +22 -11
  66. package/dist/migrations/yaml/generateImportSchemas.d.ts +14 -1
  67. package/dist/migrations/yaml/generateImportSchemas.js +736 -7
  68. package/dist/schemas/authUser.d.ts +1 -1
  69. package/dist/setupController.js +3 -2
  70. package/dist/shared/backupMetadataSchema.d.ts +94 -0
  71. package/dist/shared/backupMetadataSchema.js +38 -0
  72. package/dist/shared/backupTracking.d.ts +18 -0
  73. package/dist/shared/backupTracking.js +176 -0
  74. package/dist/shared/confirmationDialogs.js +15 -15
  75. package/dist/shared/errorUtils.d.ts +54 -0
  76. package/dist/shared/errorUtils.js +95 -0
  77. package/dist/shared/functionManager.js +20 -19
  78. package/dist/shared/indexManager.js +12 -11
  79. package/dist/shared/jsonSchemaGenerator.js +10 -26
  80. package/dist/shared/logging.d.ts +51 -0
  81. package/dist/shared/logging.js +70 -0
  82. package/dist/shared/messageFormatter.d.ts +2 -0
  83. package/dist/shared/messageFormatter.js +10 -0
  84. package/dist/shared/migrationHelpers.d.ts +6 -16
  85. package/dist/shared/migrationHelpers.js +24 -21
  86. package/dist/shared/operationLogger.d.ts +8 -1
  87. package/dist/shared/operationLogger.js +11 -24
  88. package/dist/shared/operationQueue.d.ts +28 -1
  89. package/dist/shared/operationQueue.js +268 -66
  90. package/dist/shared/operationsTable.d.ts +26 -0
  91. package/dist/shared/operationsTable.js +286 -0
  92. package/dist/shared/operationsTableSchema.d.ts +48 -0
  93. package/dist/shared/operationsTableSchema.js +35 -0
  94. package/dist/shared/relationshipExtractor.d.ts +56 -0
  95. package/dist/shared/relationshipExtractor.js +138 -0
  96. package/dist/shared/schemaGenerator.d.ts +19 -1
  97. package/dist/shared/schemaGenerator.js +56 -75
  98. package/dist/storage/backupCompression.d.ts +20 -0
  99. package/dist/storage/backupCompression.js +67 -0
  100. package/dist/storage/methods.d.ts +16 -2
  101. package/dist/storage/methods.js +98 -14
  102. package/dist/users/methods.js +9 -8
  103. package/dist/utils/configDiscovery.d.ts +78 -0
  104. package/dist/utils/configDiscovery.js +430 -0
  105. package/dist/utils/directoryUtils.d.ts +22 -0
  106. package/dist/utils/directoryUtils.js +59 -0
  107. package/dist/utils/getClientFromConfig.d.ts +17 -8
  108. package/dist/utils/getClientFromConfig.js +162 -17
  109. package/dist/utils/helperFunctions.d.ts +16 -2
  110. package/dist/utils/helperFunctions.js +19 -5
  111. package/dist/utils/loadConfigs.d.ts +34 -9
  112. package/dist/utils/loadConfigs.js +236 -316
  113. package/dist/utils/pathResolvers.d.ts +53 -0
  114. package/dist/utils/pathResolvers.js +72 -0
  115. package/dist/utils/projectConfig.d.ts +119 -0
  116. package/dist/utils/projectConfig.js +171 -0
  117. package/dist/utils/retryFailedPromises.js +4 -2
  118. package/dist/utils/sessionAuth.d.ts +48 -0
  119. package/dist/utils/sessionAuth.js +164 -0
  120. package/dist/utils/sessionPreservationExample.d.ts +1666 -0
  121. package/dist/utils/sessionPreservationExample.js +101 -0
  122. package/dist/utils/setupFiles.js +301 -41
  123. package/dist/utils/typeGuards.d.ts +35 -0
  124. package/dist/utils/typeGuards.js +57 -0
  125. package/dist/utils/versionDetection.js +145 -9
  126. package/dist/utils/yamlConverter.d.ts +53 -3
  127. package/dist/utils/yamlConverter.js +232 -13
  128. package/dist/utils/yamlLoader.d.ts +70 -0
  129. package/dist/utils/yamlLoader.js +263 -0
  130. package/dist/utilsController.d.ts +36 -3
  131. package/dist/utilsController.js +186 -56
  132. package/package.json +12 -2
  133. package/src/adapters/AdapterFactory.ts +263 -35
  134. package/src/adapters/TablesDBAdapter.ts +225 -36
  135. package/src/backups/operations/bucketBackup.ts +277 -0
  136. package/src/backups/operations/collectionBackup.ts +310 -0
  137. package/src/backups/operations/comprehensiveBackup.ts +342 -0
  138. package/src/backups/schemas/bucketManifest.ts +78 -0
  139. package/src/backups/schemas/comprehensiveManifest.ts +76 -0
  140. package/src/backups/tracking/centralizedTracking.ts +352 -0
  141. package/src/cli/commands/configCommands.ts +194 -0
  142. package/src/cli/commands/databaseCommands.ts +635 -0
  143. package/src/cli/commands/functionCommands.ts +379 -0
  144. package/src/cli/commands/schemaCommands.ts +163 -0
  145. package/src/cli/commands/transferCommands.ts +457 -0
  146. package/src/collections/attributes.ts +900 -621
  147. package/src/collections/attributes.ts.backup +1555 -0
  148. package/src/collections/indexes.ts +116 -114
  149. package/src/collections/methods.ts +295 -968
  150. package/src/collections/transferOperations.ts +516 -0
  151. package/src/collections/wipeOperations.ts +501 -0
  152. package/src/config/README.md +274 -0
  153. package/src/config/configMigration.ts +575 -0
  154. package/src/config/configValidation.ts +445 -0
  155. package/src/config/yamlConfig.ts +168 -55
  156. package/src/databases/methods.ts +3 -2
  157. package/src/databases/setup.ts +11 -138
  158. package/src/examples/yamlTerminologyExample.ts +341 -0
  159. package/src/functions/deployments.ts +14 -12
  160. package/src/functions/methods.ts +11 -11
  161. package/src/functions/templates/hono-typescript/README.md +286 -0
  162. package/src/functions/templates/hono-typescript/package.json +26 -0
  163. package/src/functions/templates/hono-typescript/src/adapters/request.ts +74 -0
  164. package/src/functions/templates/hono-typescript/src/adapters/response.ts +106 -0
  165. package/src/functions/templates/hono-typescript/src/app.ts +180 -0
  166. package/src/functions/templates/hono-typescript/src/context.ts +103 -0
  167. package/src/functions/templates/hono-typescript/src/index.ts +54 -0
  168. package/src/functions/templates/hono-typescript/src/middleware/appwrite.ts +119 -0
  169. package/src/functions/templates/hono-typescript/tsconfig.json +20 -0
  170. package/src/functions/templates/typescript-node/package.json +2 -1
  171. package/src/functions/templates/typescript-node/src/context.ts +103 -0
  172. package/src/functions/templates/typescript-node/src/index.ts +18 -12
  173. package/src/functions/templates/uv/pyproject.toml +1 -0
  174. package/src/functions/templates/uv/src/context.py +125 -0
  175. package/src/functions/templates/uv/src/index.py +35 -5
  176. package/src/init.ts +9 -11
  177. package/src/interactiveCLI.ts +278 -1596
  178. package/src/main.ts +418 -24
  179. package/src/migrations/afterImportActions.ts +71 -44
  180. package/src/migrations/appwriteToX.ts +100 -34
  181. package/src/migrations/dataLoader.ts +48 -34
  182. package/src/migrations/importController.ts +44 -39
  183. package/src/migrations/relationships.ts +28 -18
  184. package/src/migrations/services/ImportOrchestrator.ts +24 -27
  185. package/src/migrations/transfer.ts +159 -121
  186. package/src/migrations/yaml/YamlImportConfigLoader.ts +11 -4
  187. package/src/migrations/yaml/YamlImportIntegration.ts +47 -20
  188. package/src/migrations/yaml/generateImportSchemas.ts +751 -12
  189. package/src/setupController.ts +3 -2
  190. package/src/shared/backupMetadataSchema.ts +93 -0
  191. package/src/shared/backupTracking.ts +211 -0
  192. package/src/shared/confirmationDialogs.ts +19 -19
  193. package/src/shared/errorUtils.ts +110 -0
  194. package/src/shared/functionManager.ts +21 -20
  195. package/src/shared/indexManager.ts +12 -11
  196. package/src/shared/jsonSchemaGenerator.ts +38 -52
  197. package/src/shared/logging.ts +75 -0
  198. package/src/shared/messageFormatter.ts +14 -1
  199. package/src/shared/migrationHelpers.ts +45 -38
  200. package/src/shared/operationLogger.ts +11 -36
  201. package/src/shared/operationQueue.ts +322 -93
  202. package/src/shared/operationsTable.ts +338 -0
  203. package/src/shared/operationsTableSchema.ts +60 -0
  204. package/src/shared/relationshipExtractor.ts +214 -0
  205. package/src/shared/schemaGenerator.ts +179 -219
  206. package/src/storage/backupCompression.ts +88 -0
  207. package/src/storage/methods.ts +131 -34
  208. package/src/users/methods.ts +11 -9
  209. package/src/utils/configDiscovery.ts +502 -0
  210. package/src/utils/directoryUtils.ts +61 -0
  211. package/src/utils/getClientFromConfig.ts +205 -22
  212. package/src/utils/helperFunctions.ts +23 -5
  213. package/src/utils/loadConfigs.ts +313 -345
  214. package/src/utils/pathResolvers.ts +81 -0
  215. package/src/utils/projectConfig.ts +299 -0
  216. package/src/utils/retryFailedPromises.ts +4 -2
  217. package/src/utils/sessionAuth.ts +230 -0
  218. package/src/utils/setupFiles.ts +322 -54
  219. package/src/utils/typeGuards.ts +65 -0
  220. package/src/utils/versionDetection.ts +218 -64
  221. package/src/utils/yamlConverter.ts +296 -13
  222. package/src/utils/yamlLoader.ts +364 -0
  223. package/src/utilsController.ts +314 -110
  224. package/tests/README.md +497 -0
  225. package/tests/adapters/AdapterFactory.test.ts +277 -0
  226. package/tests/integration/syncOperations.test.ts +463 -0
  227. package/tests/jest.config.js +25 -0
  228. package/tests/migration/configMigration.test.ts +546 -0
  229. package/tests/setup.ts +62 -0
  230. package/tests/testUtils.ts +340 -0
  231. package/tests/utils/loadConfigs.test.ts +350 -0
  232. package/tests/validation/configValidation.test.ts +412 -0
  233. package/src/utils/schemaStrings.ts +0 -517
@@ -0,0 +1,277 @@
1
+ import { jest } from '@jest/globals';
2
+ import { TestUtils } from '../testUtils';
3
+ import { AdapterFactory } from '../../src/adapters/AdapterFactory';
4
+ import { LegacyAdapter } from '../../src/adapters/LegacyAdapter';
5
+ import { TablesDBAdapter } from '../../src/adapters/TablesDBAdapter';
6
+ import { DatabaseAdapter } from '../../src/adapters/DatabaseAdapter';
7
+
8
+ // Mock the adapters
9
+ jest.mock('../../src/adapters/LegacyAdapter');
10
+ jest.mock('../../src/adapters/TablesDBAdapter');
11
+ jest.mock('../../src/adapters/DatabaseAdapter');
12
+
13
+ // Mock version detection
14
+ jest.mock('../../src/utils/versionDetection', () => ({
15
+ detectAppwriteVersionCached: jest.fn(),
16
+ fetchServerVersion: jest.fn(),
17
+ isVersionAtLeast: jest.fn(),
18
+ }));
19
+
20
+ import { detectAppwriteVersionCached, isVersionAtLeast } from '../../src/utils/versionDetection';
21
+
22
+ describe('AdapterFactory - Dual API Support', () => {
23
+ let mockConfig: any;
24
+
25
+ beforeEach(() => {
26
+ jest.clearAllMocks();
27
+ mockConfig = TestUtils.createTestAppwriteConfig();
28
+ });
29
+
30
+ describe('Adapter Selection Logic', () => {
31
+ it('should create LegacyAdapter for old Appwrite versions', async () => {
32
+ (detectAppwriteVersionCached as jest.Mock).mockResolvedValue({
33
+ serverVersion: '1.5.0',
34
+ apiMode: 'database',
35
+ });
36
+ (isVersionAtLeast as jest.Mock).mockReturnValue(false);
37
+
38
+ const adapter = await AdapterFactory.createAdapter(mockConfig);
39
+
40
+ expect(LegacyAdapter).toHaveBeenCalledWith(expect.anything(), mockConfig);
41
+ expect(adapter).toBeInstanceOf(LegacyAdapter);
42
+ });
43
+
44
+ it('should create DatabaseAdapter for Appwrite 1.6.0+ in database mode', async () => {
45
+ (detectAppwriteVersionCached as jest.Mock).mockResolvedValue({
46
+ serverVersion: '1.6.0',
47
+ apiMode: 'database',
48
+ });
49
+ (isVersionAtLeast as jest.Mock).mockReturnValue(true);
50
+
51
+ const adapter = await AdapterFactory.createAdapter(mockConfig);
52
+
53
+ expect(DatabaseAdapter).toHaveBeenCalledWith(expect.anything(), mockConfig);
54
+ expect(adapter).toBeInstanceOf(DatabaseAdapter);
55
+ });
56
+
57
+ it('should create TablesDBAdapter for Appwrite 1.8.0+ in tablesdb mode', async () => {
58
+ (detectAppwriteVersionCached as jest.Mock).mockResolvedValue({
59
+ serverVersion: '1.8.0',
60
+ apiMode: 'tablesdb',
61
+ });
62
+ (isVersionAtLeast as jest.Mock).mockReturnValue(true);
63
+
64
+ const adapter = await AdapterFactory.createAdapter(mockConfig);
65
+
66
+ expect(TablesDBAdapter).toHaveBeenCalledWith(expect.anything(), mockConfig);
67
+ expect(adapter).toBeInstanceOf(TablesDBAdapter);
68
+ });
69
+
70
+ it('should force TablesDBAdapter when explicitly specified in config', async () => {
71
+ (detectAppwriteVersionCached as jest.Mock).mockResolvedValue({
72
+ serverVersion: '1.6.0',
73
+ apiMode: 'database',
74
+ });
75
+
76
+ const configWithForce = {
77
+ ...mockConfig,
78
+ forceTablesAPI: true,
79
+ };
80
+
81
+ const adapter = await AdapterFactory.createAdapter(configWithForce);
82
+
83
+ expect(TablesDBAdapter).toHaveBeenCalledWith(expect.anything(), configWithForce);
84
+ expect(adapter).toBeInstanceOf(TablesDBAdapter);
85
+ });
86
+
87
+ it('should force DatabaseAdapter when explicitly specified in config', async () => {
88
+ (detectAppwriteVersionCached as jest.Mock).mockResolvedValue({
89
+ serverVersion: '1.8.0',
90
+ apiMode: 'tablesdb',
91
+ });
92
+
93
+ const configWithForce = {
94
+ ...mockConfig,
95
+ forceDatabaseAPI: true,
96
+ };
97
+
98
+ const adapter = await AdapterFactory.createAdapter(configWithForce);
99
+
100
+ expect(DatabaseAdapter).toHaveBeenCalledWith(expect.anything(), configWithForce);
101
+ expect(adapter).toBeInstanceOf(DatabaseAdapter);
102
+ });
103
+ });
104
+
105
+ describe('Configuration Validation', () => {
106
+ it('should validate database configuration for DatabaseAdapter', async () => {
107
+ (detectAppwriteVersionCached as jest.Mock).mockResolvedValue({
108
+ serverVersion: '1.6.0',
109
+ apiMode: 'database',
110
+ });
111
+
112
+ const configWithMissingDB = {
113
+ ...mockConfig,
114
+ databases: [],
115
+ };
116
+
117
+ await expect(AdapterFactory.createAdapter(configWithMissingDB))
118
+ .rejects.toThrow('Database configuration required');
119
+ });
120
+
121
+ it('should validate table configurations for TablesDBAdapter', async () => {
122
+ (detectAppwriteVersionCached as jest.Mock).mockResolvedValue({
123
+ serverVersion: '1.8.0',
124
+ apiMode: 'tablesdb',
125
+ });
126
+
127
+ const configWithTablesButNoDatabaseIds = {
128
+ ...mockConfig,
129
+ collections: [
130
+ TestUtils.createTestTable({
131
+ databaseId: undefined, // Missing required databaseId
132
+ })
133
+ ],
134
+ };
135
+
136
+ await expect(AdapterFactory.createAdapter(configWithTablesButNoDatabaseIds))
137
+ .rejects.toThrow('Table configurations must include databaseId');
138
+ });
139
+ });
140
+
141
+ describe('Mixed Configuration Handling', () => {
142
+ it('should handle mixed collections and tables for appropriate adapter', async () => {
143
+ (detectAppwriteVersionCached as jest.Mock).mockResolvedValue({
144
+ serverVersion: '1.8.0',
145
+ apiMode: 'tablesdb',
146
+ });
147
+
148
+ const mixedConfig = {
149
+ ...mockConfig,
150
+ collections: [
151
+ TestUtils.createTestCollection(), // Regular collection
152
+ TestUtils.createTestTable(), // Table with _isFromTablesDir
153
+ ],
154
+ };
155
+
156
+ const adapter = await AdapterFactory.createAdapter(mixedConfig);
157
+
158
+ expect(TablesDBAdapter).toHaveBeenCalledWith(expect.anything(), mixedConfig);
159
+ expect(adapter).toBeInstanceOf(TablesDBAdapter);
160
+ });
161
+
162
+ it('should filter out inappropriate configurations per adapter', async () => {
163
+ (detectAppwriteVersionCached as jest.Mock).mockResolvedValue({
164
+ serverVersion: '1.6.0',
165
+ apiMode: 'database',
166
+ });
167
+
168
+ const mixedConfig = {
169
+ ...mockConfig,
170
+ collections: [
171
+ TestUtils.createTestCollection(), // Regular collection
172
+ TestUtils.createTestTable(), // Table (should be filtered for DatabaseAdapter)
173
+ ],
174
+ };
175
+
176
+ const adapter = await AdapterFactory.createAdapter(mixedConfig);
177
+
178
+ expect(DatabaseAdapter).toHaveBeenCalledWith(
179
+ expect.anything(),
180
+ expect.objectContaining({
181
+ collections: expect.arrayContaining([
182
+ expect.not.objectContaining({ _isFromTablesDir: true })
183
+ ])
184
+ })
185
+ );
186
+ });
187
+ });
188
+
189
+ describe('Error Handling', () => {
190
+ it('should handle version detection failures gracefully', async () => {
191
+ (detectAppwriteVersionCached as jest.Mock).mockRejectedValue(new Error('Network error'));
192
+
193
+ // Should fall back to LegacyAdapter
194
+ const adapter = await AdapterFactory.createAdapter(mockConfig);
195
+
196
+ expect(LegacyAdapter).toHaveBeenCalledWith(expect.anything(), mockConfig);
197
+ expect(adapter).toBeInstanceOf(LegacyAdapter);
198
+ });
199
+
200
+ it('should handle invalid server versions', async () => {
201
+ (detectAppwriteVersionCached as jest.Mock).mockResolvedValue({
202
+ serverVersion: 'invalid-version',
203
+ apiMode: 'unknown',
204
+ });
205
+
206
+ const adapter = await AdapterFactory.createAdapter(mockConfig);
207
+
208
+ expect(LegacyAdapter).toHaveBeenCalledWith(expect.anything(), mockConfig);
209
+ expect(adapter).toBeInstanceOf(LegacyAdapter);
210
+ });
211
+ });
212
+
213
+ describe('Client Configuration', () => {
214
+ it('should pass correct client configuration to each adapter', async () => {
215
+ (detectAppwriteVersionCached as jest.Mock).mockResolvedValue({
216
+ serverVersion: '1.8.0',
217
+ apiMode: 'tablesdb',
218
+ });
219
+
220
+ await AdapterFactory.createAdapter(mockConfig);
221
+
222
+ expect(TablesDBAdapter).toHaveBeenCalledWith(
223
+ expect.objectContaining({
224
+ setEndpoint: expect.any(Function),
225
+ setProject: expect.any(Function),
226
+ setKey: expect.any(Function),
227
+ }),
228
+ mockConfig
229
+ );
230
+ });
231
+
232
+ it('should handle custom endpoint configurations', async () => {
233
+ const customConfig = {
234
+ ...mockConfig,
235
+ appwriteEndpoint: 'https://custom.appwrite.server/v1',
236
+ };
237
+
238
+ await AdapterFactory.createAdapter(customConfig);
239
+
240
+ // Verify that the adapter receives the custom endpoint configuration
241
+ expect(TablesDBAdapter || DatabaseAdapter || LegacyAdapter).toHaveBeenCalledWith(
242
+ expect.anything(),
243
+ expect.objectContaining({
244
+ appwriteEndpoint: 'https://custom.appwrite.server/v1',
245
+ })
246
+ );
247
+ });
248
+ });
249
+
250
+ describe('Caching and Performance', () => {
251
+ it('should cache adapter instances for same configuration', async () => {
252
+ (detectAppwriteVersionCached as jest.Mock).mockResolvedValue({
253
+ serverVersion: '1.6.0',
254
+ apiMode: 'database',
255
+ });
256
+
257
+ const adapter1 = await AdapterFactory.createAdapter(mockConfig);
258
+ const adapter2 = await AdapterFactory.createAdapter(mockConfig);
259
+
260
+ // Should reuse the same instance or create efficiently
261
+ expect(DatabaseAdapter).toHaveBeenCalledTimes(2);
262
+ });
263
+
264
+ it('should use cached version detection results', async () => {
265
+ (detectAppwriteVersionCached as jest.Mock).mockResolvedValue({
266
+ serverVersion: '1.6.0',
267
+ apiMode: 'database',
268
+ });
269
+
270
+ await AdapterFactory.createAdapter(mockConfig);
271
+ await AdapterFactory.createAdapter(mockConfig);
272
+
273
+ // Version detection should be called but may be cached
274
+ expect(detectAppwriteVersionCached).toHaveBeenCalled();
275
+ });
276
+ });
277
+ });