appwrite-utils-cli 0.10.86 → 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (178) hide show
  1. package/.appwrite/.yaml_schemas/appwrite-config.schema.json +380 -0
  2. package/.appwrite/.yaml_schemas/collection.schema.json +255 -0
  3. package/.appwrite/collections/Categories.yaml +182 -0
  4. package/.appwrite/collections/ExampleCollection.yaml +36 -0
  5. package/.appwrite/collections/Posts.yaml +227 -0
  6. package/.appwrite/collections/Users.yaml +149 -0
  7. package/.appwrite/config.yaml +109 -0
  8. package/.appwrite/import/README.md +148 -0
  9. package/.appwrite/import/categories-import.yaml +129 -0
  10. package/.appwrite/import/posts-import.yaml +208 -0
  11. package/.appwrite/import/users-import.yaml +130 -0
  12. package/.appwrite/importData/categories.json +194 -0
  13. package/.appwrite/importData/posts.json +270 -0
  14. package/.appwrite/importData/users.json +220 -0
  15. package/.appwrite/schemas/categories.json +128 -0
  16. package/.appwrite/schemas/exampleCollection.json +52 -0
  17. package/.appwrite/schemas/posts.json +173 -0
  18. package/.appwrite/schemas/users.json +125 -0
  19. package/README.md +264 -33
  20. package/dist/collections/attributes.js +3 -2
  21. package/dist/collections/methods.js +56 -38
  22. package/dist/config/yamlConfig.d.ts +501 -0
  23. package/dist/config/yamlConfig.js +452 -0
  24. package/dist/databases/setup.d.ts +6 -0
  25. package/dist/databases/setup.js +119 -0
  26. package/dist/functions/methods.d.ts +1 -1
  27. package/dist/functions/methods.js +5 -2
  28. package/dist/functions/openapi.d.ts +4 -0
  29. package/dist/functions/openapi.js +60 -0
  30. package/dist/interactiveCLI.d.ts +5 -0
  31. package/dist/interactiveCLI.js +194 -49
  32. package/dist/main.js +91 -30
  33. package/dist/migrations/afterImportActions.js +2 -2
  34. package/dist/migrations/appwriteToX.d.ts +10 -0
  35. package/dist/migrations/appwriteToX.js +15 -4
  36. package/dist/migrations/backup.d.ts +16 -16
  37. package/dist/migrations/dataLoader.d.ts +83 -1
  38. package/dist/migrations/dataLoader.js +4 -4
  39. package/dist/migrations/importController.js +25 -18
  40. package/dist/migrations/importDataActions.js +2 -2
  41. package/dist/migrations/logging.d.ts +9 -1
  42. package/dist/migrations/logging.js +41 -22
  43. package/dist/migrations/migrationHelper.d.ts +4 -4
  44. package/dist/migrations/relationships.js +1 -1
  45. package/dist/migrations/services/DataTransformationService.d.ts +55 -0
  46. package/dist/migrations/services/DataTransformationService.js +158 -0
  47. package/dist/migrations/services/FileHandlerService.d.ts +75 -0
  48. package/dist/migrations/services/FileHandlerService.js +236 -0
  49. package/dist/migrations/services/ImportOrchestrator.d.ts +97 -0
  50. package/dist/migrations/services/ImportOrchestrator.js +488 -0
  51. package/dist/migrations/services/RateLimitManager.d.ts +138 -0
  52. package/dist/migrations/services/RateLimitManager.js +279 -0
  53. package/dist/migrations/services/RelationshipResolver.d.ts +120 -0
  54. package/dist/migrations/services/RelationshipResolver.js +332 -0
  55. package/dist/migrations/services/UserMappingService.d.ts +109 -0
  56. package/dist/migrations/services/UserMappingService.js +277 -0
  57. package/dist/migrations/services/ValidationService.d.ts +74 -0
  58. package/dist/migrations/services/ValidationService.js +260 -0
  59. package/dist/migrations/transfer.d.ts +0 -6
  60. package/dist/migrations/transfer.js +16 -132
  61. package/dist/migrations/yaml/YamlImportConfigLoader.d.ts +384 -0
  62. package/dist/migrations/yaml/YamlImportConfigLoader.js +375 -0
  63. package/dist/migrations/yaml/YamlImportIntegration.d.ts +87 -0
  64. package/dist/migrations/yaml/YamlImportIntegration.js +330 -0
  65. package/dist/migrations/yaml/generateImportSchemas.d.ts +17 -0
  66. package/dist/migrations/yaml/generateImportSchemas.js +575 -0
  67. package/dist/schemas/authUser.d.ts +9 -9
  68. package/dist/shared/attributeManager.d.ts +17 -0
  69. package/dist/shared/attributeManager.js +273 -0
  70. package/dist/shared/confirmationDialogs.d.ts +75 -0
  71. package/dist/shared/confirmationDialogs.js +236 -0
  72. package/dist/shared/functionManager.d.ts +48 -0
  73. package/dist/shared/functionManager.js +322 -0
  74. package/dist/shared/indexManager.d.ts +24 -0
  75. package/dist/shared/indexManager.js +150 -0
  76. package/dist/shared/jsonSchemaGenerator.d.ts +51 -0
  77. package/dist/shared/jsonSchemaGenerator.js +313 -0
  78. package/dist/shared/logging.d.ts +10 -0
  79. package/dist/shared/logging.js +46 -0
  80. package/dist/shared/messageFormatter.d.ts +37 -0
  81. package/dist/shared/messageFormatter.js +152 -0
  82. package/dist/shared/migrationHelpers.d.ts +173 -0
  83. package/dist/shared/migrationHelpers.js +142 -0
  84. package/dist/shared/operationLogger.d.ts +3 -0
  85. package/dist/shared/operationLogger.js +25 -0
  86. package/dist/shared/operationQueue.d.ts +13 -0
  87. package/dist/shared/operationQueue.js +79 -0
  88. package/dist/shared/progressManager.d.ts +62 -0
  89. package/dist/shared/progressManager.js +215 -0
  90. package/dist/shared/schemaGenerator.d.ts +18 -0
  91. package/dist/shared/schemaGenerator.js +523 -0
  92. package/dist/storage/methods.d.ts +3 -1
  93. package/dist/storage/methods.js +144 -55
  94. package/dist/storage/schemas.d.ts +56 -16
  95. package/dist/types.d.ts +2 -2
  96. package/dist/types.js +1 -1
  97. package/dist/users/methods.d.ts +16 -0
  98. package/dist/users/methods.js +276 -0
  99. package/dist/utils/configMigration.d.ts +1 -0
  100. package/dist/utils/configMigration.js +262 -0
  101. package/dist/utils/dataConverters.d.ts +46 -0
  102. package/dist/utils/dataConverters.js +139 -0
  103. package/dist/utils/loadConfigs.d.ts +15 -4
  104. package/dist/utils/loadConfigs.js +379 -51
  105. package/dist/utils/schemaStrings.js +2 -1
  106. package/dist/utils/setupFiles.d.ts +2 -1
  107. package/dist/utils/setupFiles.js +723 -28
  108. package/dist/utils/validationRules.d.ts +43 -0
  109. package/dist/utils/validationRules.js +42 -0
  110. package/dist/utils/yamlConverter.d.ts +48 -0
  111. package/dist/utils/yamlConverter.js +98 -0
  112. package/dist/utilsController.js +65 -43
  113. package/package.json +19 -15
  114. package/src/collections/attributes.ts +3 -2
  115. package/src/collections/methods.ts +85 -51
  116. package/src/config/yamlConfig.ts +488 -0
  117. package/src/{migrations/setupDatabase.ts → databases/setup.ts} +11 -5
  118. package/src/functions/methods.ts +8 -4
  119. package/src/functions/templates/count-docs-in-collection/package.json +25 -0
  120. package/src/functions/templates/count-docs-in-collection/tsconfig.json +28 -0
  121. package/src/functions/templates/typescript-node/package.json +24 -0
  122. package/src/functions/templates/typescript-node/tsconfig.json +28 -0
  123. package/src/functions/templates/uv/README.md +31 -0
  124. package/src/functions/templates/uv/pyproject.toml +29 -0
  125. package/src/interactiveCLI.ts +226 -61
  126. package/src/main.ts +111 -37
  127. package/src/migrations/afterImportActions.ts +2 -2
  128. package/src/migrations/appwriteToX.ts +17 -4
  129. package/src/migrations/dataLoader.ts +4 -4
  130. package/src/migrations/importController.ts +30 -22
  131. package/src/migrations/importDataActions.ts +2 -2
  132. package/src/migrations/relationships.ts +1 -1
  133. package/src/migrations/services/DataTransformationService.ts +196 -0
  134. package/src/migrations/services/FileHandlerService.ts +311 -0
  135. package/src/migrations/services/ImportOrchestrator.ts +669 -0
  136. package/src/migrations/services/RateLimitManager.ts +363 -0
  137. package/src/migrations/services/RelationshipResolver.ts +461 -0
  138. package/src/migrations/services/UserMappingService.ts +345 -0
  139. package/src/migrations/services/ValidationService.ts +349 -0
  140. package/src/migrations/transfer.ts +22 -228
  141. package/src/migrations/yaml/YamlImportConfigLoader.ts +427 -0
  142. package/src/migrations/yaml/YamlImportIntegration.ts +419 -0
  143. package/src/migrations/yaml/generateImportSchemas.ts +589 -0
  144. package/src/shared/attributeManager.ts +429 -0
  145. package/src/shared/confirmationDialogs.ts +327 -0
  146. package/src/shared/functionManager.ts +515 -0
  147. package/src/shared/indexManager.ts +253 -0
  148. package/src/shared/jsonSchemaGenerator.ts +403 -0
  149. package/src/shared/logging.ts +74 -0
  150. package/src/shared/messageFormatter.ts +195 -0
  151. package/src/{migrations/migrationHelper.ts → shared/migrationHelpers.ts} +22 -4
  152. package/src/{migrations/helper.ts → shared/operationLogger.ts} +7 -2
  153. package/src/{migrations/queue.ts → shared/operationQueue.ts} +1 -1
  154. package/src/shared/progressManager.ts +278 -0
  155. package/src/{migrations/schemaStrings.ts → shared/schemaGenerator.ts} +71 -17
  156. package/src/storage/methods.ts +199 -78
  157. package/src/types.ts +2 -2
  158. package/src/{migrations/users.ts → users/methods.ts} +2 -2
  159. package/src/utils/configMigration.ts +349 -0
  160. package/src/utils/loadConfigs.ts +416 -52
  161. package/src/utils/schemaStrings.ts +2 -1
  162. package/src/utils/setupFiles.ts +742 -40
  163. package/src/{migrations → utils}/validationRules.ts +1 -1
  164. package/src/utils/yamlConverter.ts +131 -0
  165. package/src/utilsController.ts +75 -54
  166. package/src/functions/templates/poetry/README.md +0 -30
  167. package/src/functions/templates/poetry/pyproject.toml +0 -16
  168. package/src/migrations/attributes.ts +0 -561
  169. package/src/migrations/backup.ts +0 -205
  170. package/src/migrations/databases.ts +0 -39
  171. package/src/migrations/dbHelpers.ts +0 -92
  172. package/src/migrations/indexes.ts +0 -40
  173. package/src/migrations/logging.ts +0 -29
  174. package/src/migrations/storage.ts +0 -538
  175. /package/src/{migrations → functions}/openapi.ts +0 -0
  176. /package/src/functions/templates/{poetry → uv}/src/__init__.py +0 -0
  177. /package/src/functions/templates/{poetry → uv}/src/index.py +0 -0
  178. /package/src/{migrations/converters.ts → utils/dataConverters.ts} +0 -0
@@ -1,99 +1,463 @@
1
1
  import path from "path";
2
2
  import fs from "fs";
3
- import { type AppwriteConfig, type Collection } from "appwrite-utils";
3
+ import { type AppwriteConfig, type Collection, type CollectionCreate } from "appwrite-utils";
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";
8
+ import yaml from "js-yaml";
9
+ import { z } from "zod";
7
10
 
8
11
  /**
9
- * Recursively searches for a file named 'appwriteConfig.ts' starting from the given directory.
12
+ * Recursively searches for configuration files starting from the given directory.
13
+ * Priority: 1) YAML configs in .appwrite directories, 2) appwriteConfig.ts files in subdirectories
10
14
  * @param dir The directory to start the search from.
11
- * @returns The path to the file if found, or null if not found.
15
+ * @returns The directory path where the config was found, suitable for passing to loadConfig().
12
16
  */
13
17
  export const findAppwriteConfig = (dir: string): string | null => {
14
- if (dir === "node_modules") {
18
+ // First try to find YAML config (already searches recursively for .appwrite dirs)
19
+ const yamlConfig = findYamlConfig(dir);
20
+ if (yamlConfig) {
21
+ // Return the directory containing the config file
22
+ return path.dirname(yamlConfig);
23
+ }
24
+
25
+ // Fall back to TypeScript config search
26
+ const tsConfigPath = findAppwriteConfigTS(dir);
27
+ if (tsConfigPath) {
28
+ return path.dirname(tsConfigPath);
29
+ }
30
+
31
+ return null;
32
+ };
33
+
34
+ const shouldIgnoreDirectory = (dirName: string): boolean => {
35
+ const ignoredDirs = [
36
+ 'node_modules',
37
+ 'dist',
38
+ 'build',
39
+ 'coverage',
40
+ '.next',
41
+ '.nuxt',
42
+ '.cache',
43
+ '.git',
44
+ '.svn',
45
+ '.hg',
46
+ '__pycache__',
47
+ '.pytest_cache',
48
+ '.mypy_cache',
49
+ 'venv',
50
+ '.venv',
51
+ 'env',
52
+ '.env',
53
+ 'target',
54
+ 'out',
55
+ 'bin',
56
+ 'obj',
57
+ '.vs',
58
+ '.vscode',
59
+ '.idea',
60
+ 'temp',
61
+ 'tmp',
62
+ '.tmp',
63
+ 'logs',
64
+ 'log',
65
+ '.DS_Store',
66
+ 'Thumbs.db'
67
+ ];
68
+
69
+ return ignoredDirs.includes(dirName) ||
70
+ dirName.startsWith('.git') ||
71
+ dirName.startsWith('node_modules') ||
72
+ dirName.startsWith('.');
73
+ };
74
+
75
+ const findAppwriteConfigTS = (dir: string, depth: number = 0): string | null => {
76
+ // Limit search depth to prevent infinite recursion
77
+ if (depth > 10) {
15
78
  return null;
16
79
  }
17
- const files = fs.readdirSync(dir, { withFileTypes: true });
18
80
 
19
- for (const file of files) {
20
- if (file.isDirectory() && file.name !== "node_modules") {
21
- const result = findAppwriteConfig(path.join(dir, file.name));
22
- if (result) return result;
23
- } else if (file.name === "appwriteConfig.ts") {
24
- return path.join(dir, file.name);
81
+ if (shouldIgnoreDirectory(path.basename(dir))) {
82
+ return null;
83
+ }
84
+
85
+ try {
86
+ const entries = fs.readdirSync(dir, { withFileTypes: true });
87
+
88
+ // First check current directory for appwriteConfig.ts
89
+ for (const entry of entries) {
90
+ if (entry.isFile() && entry.name === "appwriteConfig.ts") {
91
+ console.log(`Found appwriteConfig.ts at: ${path.join(dir, entry.name)}`);
92
+ return path.join(dir, entry.name);
93
+ }
25
94
  }
95
+
96
+ // Then search subdirectories
97
+ for (const entry of entries) {
98
+ if (entry.isDirectory() && !shouldIgnoreDirectory(entry.name)) {
99
+ const result = findAppwriteConfigTS(path.join(dir, entry.name), depth + 1);
100
+ if (result) return result;
101
+ }
102
+ }
103
+ } catch (error) {
104
+ // Ignore directory access errors
105
+ console.log(`Error accessing directory ${dir}:`, error);
26
106
  }
27
107
 
28
108
  return null;
29
109
  };
30
110
 
111
+ /**
112
+ * Loads the Appwrite configuration and returns both config and the path where it was found.
113
+ * @param configDir The directory to search for config files.
114
+ * @returns Object containing the config and the actual path where it was found.
115
+ */
116
+ export const loadConfigWithPath = async (
117
+ configDir: string
118
+ ): Promise<{ config: AppwriteConfig; actualConfigPath: string }> => {
119
+ let config: AppwriteConfig | null = null;
120
+ let actualConfigPath: string | null = null;
121
+
122
+ // Check if we're given the .appwrite directory directly
123
+ if (configDir.endsWith('.appwrite')) {
124
+ // Look for config files directly in this directory
125
+ const possibleYamlFiles = ['config.yaml', 'config.yml', 'appwriteConfig.yaml', 'appwriteConfig.yml'];
126
+ for (const fileName of possibleYamlFiles) {
127
+ const yamlPath = path.join(configDir, fileName);
128
+ if (fs.existsSync(yamlPath)) {
129
+ config = await loadYamlConfig(yamlPath);
130
+ actualConfigPath = yamlPath;
131
+ break;
132
+ }
133
+ }
134
+ } else {
135
+ // Original logic: search for .appwrite directories
136
+ const yamlConfigPath = findYamlConfig(configDir);
137
+ if (yamlConfigPath) {
138
+ config = await loadYamlConfig(yamlConfigPath);
139
+ actualConfigPath = yamlConfigPath;
140
+ }
141
+ }
142
+
143
+ // Fall back to TypeScript config if YAML not found or failed to load
144
+ if (!config) {
145
+ const configPath = path.join(configDir, "appwriteConfig.ts");
146
+
147
+ // Only try to load TypeScript config if the file exists
148
+ if (fs.existsSync(configPath)) {
149
+ const unregister = register(); // Register tsx enhancement
150
+
151
+ try {
152
+ console.log(`Loading TypeScript config from: ${configPath}`);
153
+ const configUrl = pathToFileURL(configPath).href;
154
+ const configModule = (await import(configUrl));
155
+ config = configModule.default?.default || configModule.default || configModule;
156
+ if (!config) {
157
+ throw new Error("Failed to load config");
158
+ }
159
+ actualConfigPath = configPath;
160
+ } finally {
161
+ unregister(); // Unregister tsx when done
162
+ }
163
+ }
164
+ }
165
+
166
+ if (!config || !actualConfigPath) {
167
+ throw new Error("No valid configuration found");
168
+ }
169
+
170
+ // Determine collections directory based on actual config file location
171
+ let collectionsDir: string;
172
+ const configFileDir = path.dirname(actualConfigPath);
173
+
174
+ // Check if config is in .appwrite directory
175
+ if (configFileDir.endsWith('.appwrite')) {
176
+ collectionsDir = path.join(configFileDir, "collections");
177
+ } else {
178
+ // Config is in root or other directory
179
+ collectionsDir = path.join(configFileDir, "collections");
180
+ }
181
+
182
+ // Load collections if they exist
183
+ if (fs.existsSync(collectionsDir)) {
184
+ const unregister = register(); // Register tsx for collections
185
+
186
+ try {
187
+ const collectionFiles = fs.readdirSync(collectionsDir);
188
+ config.collections = [];
189
+
190
+ for (const file of collectionFiles) {
191
+ if (file === "index.ts") {
192
+ continue;
193
+ }
194
+ const filePath = path.join(collectionsDir, file);
195
+
196
+ // Handle YAML collections
197
+ if (file.endsWith('.yaml') || file.endsWith('.yml')) {
198
+ const collection = loadYamlCollection(filePath);
199
+ if (collection) {
200
+ config.collections.push(collection);
201
+ }
202
+ continue;
203
+ }
204
+
205
+ // Handle TypeScript collections
206
+ if (file.endsWith('.ts')) {
207
+ const fileUrl = pathToFileURL(filePath).href;
208
+ const collectionModule = (await import(fileUrl));
209
+ const collection: Collection | undefined = collectionModule.default?.default || collectionModule.default || collectionModule;
210
+ if (collection) {
211
+ // Ensure importDefs are properly loaded
212
+ if (collectionModule.importDefs || collection.importDefs) {
213
+ collection.importDefs = collectionModule.importDefs || collection.importDefs;
214
+ }
215
+ config.collections.push(collection as CollectionCreate);
216
+ }
217
+ }
218
+ }
219
+ } finally {
220
+ unregister(); // Unregister tsx when done
221
+ }
222
+ }
223
+
224
+ return { config, actualConfigPath };
225
+ };
226
+
31
227
  /**
32
228
  * Loads the Appwrite configuration and all collection configurations from a specified directory.
33
- * @param configDir The directory containing the appwriteConfig.ts and collections folder.
229
+ * Supports both YAML and TypeScript config formats with backward compatibility.
230
+ * @param configDir The directory containing the config file and collections folder.
34
231
  * @returns The loaded Appwrite configuration including collections.
35
232
  */
36
233
  export const loadConfig = async (
37
234
  configDir: string
38
235
  ): Promise<AppwriteConfig> => {
39
- const unregister = register(); // Register tsx enhancement
236
+ let config: AppwriteConfig | null = null;
237
+ let actualConfigPath: string | null = null;
40
238
 
41
- try {
239
+ // First try to find and load YAML config
240
+ const yamlConfigPath = findYamlConfig(configDir);
241
+ if (yamlConfigPath) {
242
+ console.log(`Loading YAML config from: ${yamlConfigPath}`);
243
+ config = await loadYamlConfig(yamlConfigPath);
244
+ actualConfigPath = yamlConfigPath;
245
+ }
246
+
247
+ // Fall back to TypeScript config if YAML not found or failed to load
248
+ if (!config) {
42
249
  const configPath = path.join(configDir, "appwriteConfig.ts");
43
- console.log(`Loading config from: ${configPath}`);
44
- const configUrl = pathToFileURL(configPath).href;
45
- const configModule = (await import(configUrl));
46
- const config: AppwriteConfig | undefined = configModule.default?.default || configModule.default || configModule;
47
- if (!config) {
48
- throw new Error("Failed to load config");
250
+
251
+ // Only try to load TypeScript config if the file exists
252
+ if (fs.existsSync(configPath)) {
253
+ const unregister = register(); // Register tsx enhancement
254
+
255
+ try {
256
+ console.log(`Loading TypeScript config from: ${configPath}`);
257
+ const configUrl = pathToFileURL(configPath).href;
258
+ const configModule = (await import(configUrl));
259
+ config = configModule.default?.default || configModule.default || configModule;
260
+ if (!config) {
261
+ throw new Error("Failed to load config");
262
+ }
263
+ actualConfigPath = configPath;
264
+ } finally {
265
+ unregister(); // Unregister tsx when done
266
+ }
49
267
  }
50
- const collectionsDir = path.join(configDir, "collections");
51
- const collectionFiles = fs.readdirSync(collectionsDir);
268
+ }
52
269
 
53
- config.collections = [];
270
+ if (!config) {
271
+ throw new Error("No valid configuration found");
272
+ }
54
273
 
55
- for (const file of collectionFiles) {
56
- if (file === "index.ts") {
57
- continue;
58
- }
59
- const filePath = path.join(collectionsDir, file);
60
- const fileUrl = pathToFileURL(filePath).href;
61
- const collectionModule = (await import(fileUrl));
62
- const collection: Collection | undefined = collectionModule.default?.default || collectionModule.default || collectionModule;
63
- if (collection) {
64
- // Ensure importDefs are properly loaded
65
- if (collectionModule.importDefs || collection.importDefs) {
66
- collection.importDefs = collectionModule.importDefs || collection.importDefs;
274
+ // Determine collections directory based on actual config file location
275
+ let collectionsDir: string;
276
+ if (actualConfigPath) {
277
+ const configFileDir = path.dirname(actualConfigPath);
278
+
279
+ // Check if config is in .appwrite directory
280
+ if (configFileDir.endsWith('.appwrite')) {
281
+ collectionsDir = path.join(configFileDir, "collections");
282
+ } else {
283
+ // Config is in root or other directory
284
+ collectionsDir = path.join(configFileDir, "collections");
285
+ }
286
+ } else {
287
+ // Fallback to original behavior if no actual config path found
288
+ collectionsDir = path.join(configDir, "collections");
289
+ }
290
+
291
+ // Load collections if they exist
292
+ if (fs.existsSync(collectionsDir)) {
293
+ const unregister = register(); // Register tsx for collections
294
+
295
+ try {
296
+ const collectionFiles = fs.readdirSync(collectionsDir);
297
+ config.collections = [];
298
+
299
+ for (const file of collectionFiles) {
300
+ if (file === "index.ts") {
301
+ continue;
302
+ }
303
+ const filePath = path.join(collectionsDir, file);
304
+
305
+ // Handle YAML collections
306
+ if (file.endsWith('.yaml') || file.endsWith('.yml')) {
307
+ const collection = loadYamlCollection(filePath);
308
+ if (collection) {
309
+ config.collections.push(collection);
310
+ }
311
+ continue;
312
+ }
313
+
314
+ // Handle TypeScript collections
315
+ if (file.endsWith('.ts')) {
316
+ const fileUrl = pathToFileURL(filePath).href;
317
+ const collectionModule = (await import(fileUrl));
318
+ const collection: Collection | undefined = collectionModule.default?.default || collectionModule.default || collectionModule;
319
+ if (collection) {
320
+ // Ensure importDefs are properly loaded
321
+ if (collectionModule.importDefs || collection.importDefs) {
322
+ collection.importDefs = collectionModule.importDefs || collection.importDefs;
323
+ }
324
+ config.collections.push(collection);
325
+ }
67
326
  }
68
- config.collections.push(collection);
69
327
  }
328
+ } finally {
329
+ unregister(); // Unregister tsx when done
70
330
  }
71
-
72
- return config;
73
- } finally {
74
- unregister(); // Unregister tsx when done
331
+ } else {
332
+ config.collections = config.collections || [];
75
333
  }
334
+
335
+ return config;
76
336
  };
77
337
 
78
- export const findFunctionsDir = (dir: string): string | null => {
79
- if (dir === "node_modules") {
338
+ export const findFunctionsDir = (dir: string, depth: number = 0): string | null => {
339
+ // Limit search depth to prevent infinite recursion
340
+ if (depth > 5) {
341
+ return null;
342
+ }
343
+
344
+ if (shouldIgnoreDirectory(path.basename(dir))) {
80
345
  return null;
81
346
  }
82
347
 
83
- const files = fs.readdirSync(dir, { withFileTypes: true });
348
+ try {
349
+ const files = fs.readdirSync(dir, { withFileTypes: true });
84
350
 
85
- for (const entry of files) {
86
- if (!entry.isDirectory() || entry.name === "node_modules") {
87
- continue;
88
- }
351
+ for (const entry of files) {
352
+ if (!entry.isDirectory() || shouldIgnoreDirectory(entry.name)) {
353
+ continue;
354
+ }
89
355
 
90
- if (entry.name === "functions") {
91
- return path.join(dir, entry.name);
92
- }
356
+ if (entry.name === "functions") {
357
+ return path.join(dir, entry.name);
358
+ }
93
359
 
94
- const result = findFunctionsDir(path.join(dir, entry.name));
95
- if (result) return result;
360
+ const result = findFunctionsDir(path.join(dir, entry.name), depth + 1);
361
+ if (result) return result;
362
+ }
363
+ } catch (error) {
364
+ // Ignore directory access errors
96
365
  }
97
366
 
98
367
  return null;
368
+ };
369
+
370
+ // YAML Collection Schema
371
+ const YamlCollectionSchema = z.object({
372
+ name: z.string(),
373
+ id: z.string().optional(),
374
+ documentSecurity: z.boolean().default(false),
375
+ enabled: z.boolean().default(true),
376
+ permissions: z.array(
377
+ z.object({
378
+ permission: z.string(),
379
+ target: z.string()
380
+ })
381
+ ).optional().default([]),
382
+ attributes: z.array(
383
+ z.object({
384
+ key: z.string(),
385
+ type: z.string(),
386
+ size: z.number().optional(),
387
+ required: z.boolean().default(false),
388
+ array: z.boolean().optional(),
389
+ default: z.any().optional(),
390
+ description: z.string().optional(),
391
+ min: z.number().optional(),
392
+ max: z.number().optional(),
393
+ elements: z.array(z.string()).optional(),
394
+ relatedCollection: z.string().optional(),
395
+ relationType: z.string().optional(),
396
+ twoWay: z.boolean().optional(),
397
+ twoWayKey: z.string().optional(),
398
+ onDelete: z.string().optional(),
399
+ side: z.string().optional()
400
+ })
401
+ ).optional().default([]),
402
+ indexes: z.array(
403
+ z.object({
404
+ key: z.string(),
405
+ type: z.string(),
406
+ attributes: z.array(z.string()),
407
+ orders: z.array(z.string()).optional()
408
+ })
409
+ ).optional().default([]),
410
+ importDefs: z.array(z.any()).optional().default([])
411
+ });
412
+
413
+ type YamlCollection = z.infer<typeof YamlCollectionSchema>;
414
+
415
+ const loadYamlCollection = (filePath: string): CollectionCreate | null => {
416
+ try {
417
+ const fileContent = fs.readFileSync(filePath, "utf8");
418
+ const yamlData = yaml.load(fileContent) as unknown;
419
+ const parsedCollection = YamlCollectionSchema.parse(yamlData);
420
+
421
+ // Convert YAML collection to CollectionCreate format
422
+ const collection: CollectionCreate = {
423
+ name: parsedCollection.name,
424
+ $id: parsedCollection.id || parsedCollection.name.toLowerCase().replace(/\s+/g, '_'),
425
+ documentSecurity: parsedCollection.documentSecurity,
426
+ enabled: parsedCollection.enabled,
427
+ $permissions: parsedCollection.permissions.map(p => ({
428
+ permission: p.permission as any,
429
+ target: p.target
430
+ })),
431
+ attributes: parsedCollection.attributes.map(attr => ({
432
+ key: attr.key,
433
+ type: attr.type as any,
434
+ size: attr.size,
435
+ required: attr.required,
436
+ array: attr.array,
437
+ xdefault: attr.default,
438
+ description: attr.description,
439
+ min: attr.min,
440
+ max: attr.max,
441
+ elements: attr.elements,
442
+ relatedCollection: attr.relatedCollection,
443
+ relationType: attr.relationType as any,
444
+ twoWay: attr.twoWay,
445
+ twoWayKey: attr.twoWayKey,
446
+ onDelete: attr.onDelete as any,
447
+ side: attr.side as any
448
+ })),
449
+ indexes: parsedCollection.indexes.map(idx => ({
450
+ key: idx.key,
451
+ type: idx.type as any,
452
+ attributes: idx.attributes,
453
+ orders: idx.orders as any
454
+ })),
455
+ importDefs: parsedCollection.importDefs
456
+ };
457
+
458
+ return collection;
459
+ } catch (error) {
460
+ console.error(`Error loading YAML collection from ${filePath}:`, error);
461
+ return null;
462
+ }
99
463
  };
@@ -410,7 +410,8 @@ export class SchemaGenerator {
410
410
  baseSchemaCode += ".nullish()";
411
411
  }
412
412
  break;
413
- case "float":
413
+ case "double":
414
+ case "float": // Backward compatibility
414
415
  baseSchemaCode = "z.number()";
415
416
  if (finalAttribute.min !== undefined) {
416
417
  baseSchemaCode += `.min(${finalAttribute.min}, "Minimum value of ${finalAttribute.min} not met")`;