appwrite-utils-cli 0.10.85 → 1.0.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 (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 +261 -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 +196 -52
  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 +156 -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 +377 -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 +230 -63
  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 +212 -0
  160. package/src/utils/loadConfigs.ts +414 -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
@@ -0,0 +1,488 @@
1
+ import { z } from "zod";
2
+ import yaml from "js-yaml";
3
+ import fs from "fs";
4
+ import path from "path";
5
+ import { AppwriteConfigSchema, type AppwriteConfig, RuntimeSchema, FunctionScopes, FunctionSpecifications, permissionsSchema, PermissionToAppwritePermission, type AppwriteFunction } from "appwrite-utils";
6
+
7
+ const YamlConfigSchema = z.object({
8
+ appwrite: z.object({
9
+ endpoint: z.string().default("https://cloud.appwrite.io/v1"),
10
+ project: z.string(),
11
+ key: z.string(),
12
+ }),
13
+ logging: z
14
+ .object({
15
+ enabled: z.boolean().default(false),
16
+ level: z.enum(["error", "warn", "info", "debug"]).default("info"),
17
+ directory: z.string().optional(),
18
+ console: z.boolean().default(false),
19
+ })
20
+ .optional()
21
+ .default({ enabled: false, level: "info", console: false }),
22
+ backups: z
23
+ .object({
24
+ enabled: z.boolean().default(true),
25
+ interval: z.number().default(3600),
26
+ retention: z.number().default(30),
27
+ cleanup: z.boolean().default(true),
28
+ })
29
+ .optional()
30
+ .default({ enabled: true, interval: 3600, retention: 30, cleanup: true }),
31
+ data: z
32
+ .object({
33
+ enableMockData: z.boolean().default(false),
34
+ documentBucketId: z.string().default("documents"),
35
+ usersCollectionName: z.string().default("Members"),
36
+ importDirectory: z.string().default("importData"),
37
+ })
38
+ .optional()
39
+ .default({
40
+ enableMockData: false,
41
+ documentBucketId: "documents",
42
+ usersCollectionName: "Members",
43
+ importDirectory: "importData",
44
+ }),
45
+ schemas: z
46
+ .object({
47
+ outputDirectory: z.string().default("schemas"),
48
+ yamlSchemaDirectory: z.string().default(".yaml_schemas"),
49
+ })
50
+ .optional()
51
+ .default({
52
+ outputDirectory: "schemas",
53
+ yamlSchemaDirectory: ".yaml_schemas",
54
+ }),
55
+ migrations: z
56
+ .object({
57
+ enabled: z.boolean().default(true),
58
+ })
59
+ .optional()
60
+ .default({
61
+ enabled: true,
62
+ }),
63
+ databases: z
64
+ .array(
65
+ z.object({
66
+ id: z.string(),
67
+ name: z.string(),
68
+ bucket: z
69
+ .object({
70
+ id: z.string(),
71
+ name: z.string(),
72
+ permissions: permissionsSchema,
73
+ fileSecurity: z.boolean().optional(),
74
+ enabled: z.boolean().optional(),
75
+ maximumFileSize: z.number().optional(),
76
+ allowedFileExtensions: z.array(z.string()).optional(),
77
+ compression: z.enum(["none", "gzip", "zstd"]).optional(),
78
+ encryption: z.boolean().optional(),
79
+ antivirus: z.boolean().optional(),
80
+ })
81
+ .optional(),
82
+ })
83
+ )
84
+ .optional()
85
+ .default([
86
+ { id: "dev", name: "Development" },
87
+ { id: "main", name: "Main" },
88
+ { id: "staging", name: "Staging" },
89
+ ]),
90
+ buckets: z
91
+ .array(
92
+ z.object({
93
+ id: z.string(),
94
+ name: z.string(),
95
+ permissions: permissionsSchema,
96
+ fileSecurity: z.boolean().optional(),
97
+ enabled: z.boolean().optional(),
98
+ maximumFileSize: z.number().optional(),
99
+ allowedFileExtensions: z.array(z.string()).optional(),
100
+ compression: z.enum(["none", "gzip", "zstd"]).optional(),
101
+ encryption: z.boolean().optional(),
102
+ antivirus: z.boolean().optional(),
103
+ })
104
+ )
105
+ .optional()
106
+ .default([]),
107
+ functions: z
108
+ .array(
109
+ z.object({
110
+ id: z.string(),
111
+ name: z.string(),
112
+ runtime: RuntimeSchema,
113
+ execute: z.array(z.string()).optional(),
114
+ events: z.array(z.string()).optional(),
115
+ schedule: z.string().optional(),
116
+ timeout: z.number().optional(),
117
+ enabled: z.boolean().optional(),
118
+ logging: z.boolean().optional(),
119
+ entrypoint: z.string().optional(),
120
+ commands: z.string().optional(),
121
+ scopes: z.array(FunctionScopes).optional(),
122
+ installationId: z.string().optional(),
123
+ providerRepositoryId: z.string().optional(),
124
+ providerBranch: z.string().optional(),
125
+ providerSilentMode: z.boolean().optional(),
126
+ providerRootDirectory: z.string().optional(),
127
+ templateRepository: z.string().optional(),
128
+ templateOwner: z.string().optional(),
129
+ templateRootDirectory: z.string().optional(),
130
+ templateBranch: z.string().optional(),
131
+ specification: FunctionSpecifications.optional(),
132
+ })
133
+ )
134
+ .optional()
135
+ .default([]),
136
+ });
137
+
138
+ export type YamlConfig = z.infer<typeof YamlConfigSchema>;
139
+
140
+ export const convertYamlToAppwriteConfig = (yamlConfig: YamlConfig): AppwriteConfig => {
141
+ const appwriteConfig: AppwriteConfig = {
142
+ appwriteEndpoint: yamlConfig.appwrite.endpoint,
143
+ appwriteProject: yamlConfig.appwrite.project,
144
+ appwriteKey: yamlConfig.appwrite.key,
145
+ appwriteClient: null,
146
+ logging: {
147
+ enabled: yamlConfig.logging.enabled,
148
+ level: yamlConfig.logging.level,
149
+ logDirectory: yamlConfig.logging.directory,
150
+ console: yamlConfig.logging.console,
151
+ },
152
+ enableBackups: yamlConfig.backups.enabled,
153
+ backupInterval: yamlConfig.backups.interval,
154
+ backupRetention: yamlConfig.backups.retention,
155
+ enableBackupCleanup: yamlConfig.backups.cleanup,
156
+ enableMockData: yamlConfig.data.enableMockData,
157
+ documentBucketId: yamlConfig.data.documentBucketId,
158
+ usersCollectionName: yamlConfig.data.usersCollectionName,
159
+ useMigrations: yamlConfig.migrations.enabled,
160
+ schemaConfig: {
161
+ outputDirectory: yamlConfig.schemas.outputDirectory,
162
+ yamlSchemaDirectory: yamlConfig.schemas.yamlSchemaDirectory,
163
+ importDirectory: yamlConfig.data.importDirectory,
164
+ },
165
+ databases: yamlConfig.databases.map((db) => ({
166
+ $id: db.id,
167
+ name: db.name,
168
+ bucket: db.bucket
169
+ ? {
170
+ $id: db.bucket.id,
171
+ name: db.bucket.name,
172
+ $permissions: PermissionToAppwritePermission(db.bucket.permissions),
173
+ fileSecurity: db.bucket.fileSecurity || false,
174
+ enabled: db.bucket.enabled || true,
175
+ maximumFileSize: db.bucket.maximumFileSize || 30000000,
176
+ allowedFileExtensions: db.bucket.allowedFileExtensions || [],
177
+ compression: (db.bucket.compression as "none" | "gzip" | "zstd") || "none",
178
+ encryption: db.bucket.encryption || false,
179
+ antivirus: db.bucket.antivirus || false,
180
+ }
181
+ : undefined,
182
+ })),
183
+ buckets: yamlConfig.buckets.map((bucket) => ({
184
+ $id: bucket.id,
185
+ name: bucket.name,
186
+ $permissions: PermissionToAppwritePermission(bucket.permissions),
187
+ fileSecurity: bucket.fileSecurity || false,
188
+ enabled: bucket.enabled || true,
189
+ maximumFileSize: bucket.maximumFileSize || 30000000,
190
+ allowedFileExtensions: bucket.allowedFileExtensions || [],
191
+ compression: (bucket.compression as "none" | "gzip" | "zstd") || "none",
192
+ encryption: bucket.encryption || false,
193
+ antivirus: bucket.antivirus || false,
194
+ })),
195
+ functions: yamlConfig.functions?.map((func) => ({
196
+ $id: func.id,
197
+ name: func.name,
198
+ runtime: func.runtime,
199
+ execute: func.execute || [],
200
+ events: func.events || [],
201
+ schedule: func.schedule || "",
202
+ timeout: func.timeout || 15,
203
+ enabled: func.enabled || true,
204
+ logging: func.logging || true,
205
+ entrypoint: func.entrypoint || "",
206
+ commands: func.commands || "",
207
+ scopes: func.scopes || [],
208
+ installationId: func.installationId || "",
209
+ providerRepositoryId: func.providerRepositoryId || "",
210
+ providerBranch: func.providerBranch || "",
211
+ providerSilentMode: func.providerSilentMode || false,
212
+ providerRootDirectory: func.providerRootDirectory || "",
213
+ templateRepository: func.templateRepository || "",
214
+ templateOwner: func.templateOwner || "",
215
+ templateRootDirectory: func.templateRootDirectory || "",
216
+ templateBranch: func.templateBranch || "",
217
+ specification: func.specification || "s-0.5vcpu-512mb",
218
+ })),
219
+ collections: [],
220
+ };
221
+
222
+ return appwriteConfig;
223
+ };
224
+
225
+ export const loadYamlConfig = async (configPath: string): Promise<AppwriteConfig | null> => {
226
+ try {
227
+ const fileContent = fs.readFileSync(configPath, "utf8");
228
+ const yamlData = yaml.load(fileContent) as unknown;
229
+
230
+ const yamlConfig = YamlConfigSchema.parse(yamlData);
231
+ return convertYamlToAppwriteConfig(yamlConfig);
232
+ } catch (error) {
233
+ if (error instanceof z.ZodError) {
234
+ console.error("❌ YAML config validation failed:");
235
+ error.errors.forEach((err) => {
236
+ console.error(` ${err.path.join('.')} → ${err.message}`);
237
+ });
238
+ } else {
239
+ console.error("❌ Error loading YAML config:", error instanceof Error ? error.message : error);
240
+ if (error instanceof Error && error.stack) {
241
+ console.error("Stack trace:", error.stack);
242
+ }
243
+ }
244
+ return null;
245
+ }
246
+ };
247
+
248
+ export const findYamlConfig = (startDir: string): string | null => {
249
+ // First check current directory for YAML configs
250
+ const possiblePaths = [
251
+ path.join(startDir, ".appwrite", "appwriteConfig.yaml"),
252
+ path.join(startDir, ".appwrite", "appwriteConfig.yml"),
253
+ path.join(startDir, ".appwrite", "config.yaml"),
254
+ path.join(startDir, ".appwrite", "config.yml"),
255
+ path.join(startDir, "appwrite.yaml"),
256
+ path.join(startDir, "appwrite.yml"),
257
+ ];
258
+
259
+ for (const configPath of possiblePaths) {
260
+ if (fs.existsSync(configPath)) {
261
+ return configPath;
262
+ }
263
+ }
264
+
265
+ // Recursively search subdirectories for .appwrite folders
266
+ const yamlConfigInSubdirs = findYamlConfigRecursive(startDir);
267
+ if (yamlConfigInSubdirs) {
268
+ return yamlConfigInSubdirs;
269
+ }
270
+
271
+ // Only check one level up to avoid infinite traversal
272
+ const parentDir = path.dirname(startDir);
273
+ if (parentDir !== startDir && path.basename(parentDir) !== 'node_modules') {
274
+ const parentPossiblePaths = [
275
+ path.join(parentDir, ".appwrite", "appwriteConfig.yaml"),
276
+ path.join(parentDir, ".appwrite", "appwriteConfig.yml"),
277
+ path.join(parentDir, "appwrite.yaml"),
278
+ path.join(parentDir, "appwrite.yml"),
279
+ ];
280
+
281
+ for (const configPath of parentPossiblePaths) {
282
+ if (fs.existsSync(configPath)) {
283
+ return configPath;
284
+ }
285
+ }
286
+ }
287
+
288
+ return null;
289
+ };
290
+
291
+ const shouldIgnoreDirectory = (dirName: string): boolean => {
292
+ const ignoredDirs = [
293
+ 'node_modules',
294
+ 'dist',
295
+ 'build',
296
+ 'coverage',
297
+ '.next',
298
+ '.nuxt',
299
+ '.cache',
300
+ '.git',
301
+ '.svn',
302
+ '.hg',
303
+ '__pycache__',
304
+ '.pytest_cache',
305
+ '.mypy_cache',
306
+ 'venv',
307
+ '.venv',
308
+ 'env',
309
+ '.env',
310
+ 'target',
311
+ 'out',
312
+ 'bin',
313
+ 'obj',
314
+ '.vs',
315
+ '.vscode',
316
+ '.idea',
317
+ 'temp',
318
+ 'tmp',
319
+ '.tmp',
320
+ 'logs',
321
+ 'log',
322
+ '.DS_Store',
323
+ 'Thumbs.db'
324
+ ];
325
+
326
+ return ignoredDirs.includes(dirName) ||
327
+ dirName.startsWith('.git') ||
328
+ dirName.startsWith('node_modules') ||
329
+ dirName.startsWith('.');
330
+ };
331
+
332
+ const findYamlConfigRecursive = (dir: string, depth: number = 0): string | null => {
333
+ // Limit search depth to prevent infinite recursion
334
+ if (depth > 5) {
335
+ return null;
336
+ }
337
+
338
+ if (shouldIgnoreDirectory(path.basename(dir))) {
339
+ return null;
340
+ }
341
+
342
+ try {
343
+ const entries = fs.readdirSync(dir, { withFileTypes: true });
344
+
345
+ for (const entry of entries) {
346
+ if (entry.isDirectory() && !shouldIgnoreDirectory(entry.name)) {
347
+ const fullPath = path.join(dir, entry.name);
348
+
349
+ // Check if this is an .appwrite directory
350
+ if (entry.name === ".appwrite") {
351
+ const configPaths = [
352
+ path.join(fullPath, "appwriteConfig.yaml"),
353
+ path.join(fullPath, "appwriteConfig.yml"),
354
+ path.join(fullPath, "config.yaml"),
355
+ path.join(fullPath, "config.yml"),
356
+ ];
357
+
358
+ for (const configPath of configPaths) {
359
+ if (fs.existsSync(configPath)) {
360
+ return configPath;
361
+ }
362
+ }
363
+ }
364
+
365
+ // Recurse into other directories with increased depth
366
+ const result = findYamlConfigRecursive(fullPath, depth + 1);
367
+ if (result) return result;
368
+ }
369
+ }
370
+ } catch (error) {
371
+ // Ignore directory access errors
372
+ }
373
+
374
+ return null;
375
+ };
376
+
377
+ export const generateYamlConfigTemplate = (outputPath: string) => {
378
+ const template: YamlConfig = {
379
+ appwrite: {
380
+ endpoint: "https://cloud.appwrite.io/v1",
381
+ project: "YOUR_PROJECT_ID",
382
+ key: "YOUR_API_KEY",
383
+ },
384
+ logging: {
385
+ enabled: false,
386
+ level: "info",
387
+ console: false,
388
+ },
389
+ backups: {
390
+ enabled: true,
391
+ interval: 3600,
392
+ retention: 30,
393
+ cleanup: true,
394
+ },
395
+ data: {
396
+ enableMockData: false,
397
+ documentBucketId: "documents",
398
+ usersCollectionName: "Members",
399
+ importDirectory: "importData",
400
+ },
401
+ schemas: {
402
+ outputDirectory: "schemas",
403
+ yamlSchemaDirectory: ".yaml_schemas",
404
+ },
405
+ migrations: {
406
+ enabled: true,
407
+ },
408
+ databases: [
409
+ { id: "dev", name: "Development" },
410
+ { id: "main", name: "Main" },
411
+ { id: "staging", name: "Staging" },
412
+ ],
413
+ buckets: [],
414
+ functions: [],
415
+ };
416
+
417
+ const yamlContent = yaml.dump(template, {
418
+ indent: 2,
419
+ lineWidth: 120,
420
+ sortKeys: false,
421
+ });
422
+
423
+ // Add schema reference header
424
+ const schemaReference = "# yaml-language-server: $schema=./.yaml_schemas/appwrite-config.schema.json\n";
425
+ const finalContent = schemaReference + "# Appwrite Project Configuration\n" + yamlContent;
426
+
427
+ fs.writeFileSync(outputPath, finalContent, "utf8");
428
+ };
429
+
430
+ /**
431
+ * Adds a new function to the YAML config file
432
+ * @param configPath Path to the YAML config file
433
+ * @param newFunction The function configuration to add
434
+ */
435
+ export const addFunctionToYamlConfig = async (configPath: string, newFunction: AppwriteFunction): Promise<void> => {
436
+ try {
437
+ // Read current config
438
+ const fileContent = fs.readFileSync(configPath, "utf8");
439
+ const yamlData = yaml.load(fileContent) as any;
440
+
441
+ // Initialize functions array if it doesn't exist
442
+ if (!yamlData.functions) {
443
+ yamlData.functions = [];
444
+ }
445
+
446
+ // Convert AppwriteFunction to YAML format
447
+ const yamlFunction = {
448
+ id: newFunction.$id,
449
+ name: newFunction.name,
450
+ runtime: newFunction.runtime,
451
+ execute: newFunction.execute || ["any"],
452
+ events: newFunction.events || [],
453
+ schedule: newFunction.schedule || "",
454
+ timeout: newFunction.timeout || 15,
455
+ enabled: newFunction.enabled !== false,
456
+ logging: newFunction.logging !== false,
457
+ entrypoint: newFunction.entrypoint || "",
458
+ commands: newFunction.commands || "",
459
+ scopes: newFunction.scopes || [],
460
+ specification: newFunction.specification || "s-0.5vcpu-512mb"
461
+ };
462
+
463
+ // Add new function
464
+ yamlData.functions.push(yamlFunction);
465
+
466
+ // Write back to file
467
+ const updatedYamlContent = yaml.dump(yamlData, {
468
+ indent: 2,
469
+ lineWidth: 120,
470
+ sortKeys: false,
471
+ });
472
+
473
+ // Preserve schema reference if it exists
474
+ const lines = fileContent.split('\n');
475
+ const schemaLine = lines.find(line => line.startsWith('# yaml-language-server:'));
476
+ let finalContent = updatedYamlContent;
477
+
478
+ if (schemaLine) {
479
+ finalContent = schemaLine + '\n' + updatedYamlContent;
480
+ }
481
+
482
+ fs.writeFileSync(configPath, finalContent, "utf8");
483
+ console.log(`✅ Added function "${newFunction.name}" to YAML config`);
484
+ } catch (error) {
485
+ console.error("❌ Error adding function to YAML config:", error instanceof Error ? error.message : error);
486
+ throw error;
487
+ }
488
+ };
@@ -1,6 +1,6 @@
1
1
  import { Databases, Query, type Models } from "node-appwrite";
2
2
  import { createOrUpdateAttribute } from "../collections/attributes.js";
3
- import { getMigrationCollectionSchemas } from "./backup.js";
3
+ import { getMigrationCollectionSchemas } from "../storage/schemas.js";
4
4
  import {
5
5
  areCollectionNamesSame,
6
6
  delay,
@@ -11,6 +11,11 @@ import { type AppwriteConfig } from "appwrite-utils";
11
11
  import { ulid } from "ulidx";
12
12
 
13
13
  export const setupMigrationDatabase = async (config: AppwriteConfig) => {
14
+ if (!config.useMigrations) {
15
+ console.log("Migrations database disabled, skipping setup");
16
+ return;
17
+ }
18
+
14
19
  console.log("---------------------------------");
15
20
  console.log("Starting Migrations Setup");
16
21
  console.log("---------------------------------");
@@ -125,8 +130,8 @@ export const ensureDatabasesExist = async (config: AppwriteConfig, databasesToEn
125
130
  const migrationsDatabase = existingDatabases.databases.find(
126
131
  (d) => d.name.toLowerCase().trim().replace(" ", "") === "migrations"
127
132
  );
128
- if (existingDatabases.databases.length !== 0 && migrationsDatabase) {
129
- console.log("Creating all databases except migrations");
133
+ if (config.useMigrations && existingDatabases.databases.length !== 0 && migrationsDatabase) {
134
+ console.log("Creating all databases including migrations");
130
135
  databasesToCreate.push(migrationsDatabase);
131
136
  }
132
137
 
@@ -142,7 +147,8 @@ export const ensureDatabasesExist = async (config: AppwriteConfig, databasesToEn
142
147
 
143
148
  export const wipeOtherDatabases = async (
144
149
  database: Databases,
145
- databasesToKeep: Models.Database[]
150
+ databasesToKeep: Models.Database[],
151
+ useMigrations: boolean = true
146
152
  ) => {
147
153
  console.log(`Databases to keep: ${databasesToKeep.map(db => db.name).join(", ")}`);
148
154
  const allDatabases = await tryAwaitWithRetry(
@@ -151,7 +157,7 @@ export const wipeOtherDatabases = async (
151
157
  const migrationsDatabase = allDatabases.databases.find(
152
158
  (d) => d.name.toLowerCase().trim().replace(" ", "") === "migrations"
153
159
  );
154
- if (allDatabases.databases.length !== 0 && migrationsDatabase) {
160
+ if (useMigrations && allDatabases.databases.length !== 0 && migrationsDatabase) {
155
161
  console.log("Wiping all databases except migrations");
156
162
  databasesToKeep.push(migrationsDatabase);
157
163
  }
@@ -5,12 +5,14 @@ import {
5
5
  Query,
6
6
  Runtime,
7
7
  } from "node-appwrite";
8
- import { join } from "node:path";
8
+ import { join, dirname } from "node:path";
9
+ import { fileURLToPath } from "node:url";
9
10
  import fs from "node:fs";
10
11
  import {
11
12
  type AppwriteFunction,
12
13
  type FunctionScope,
13
14
  type Specification,
15
+ type Runtime as AppwriteUtilsRuntime,
14
16
  } from "appwrite-utils";
15
17
  import chalk from "chalk";
16
18
  import { extract as extractTar } from "tar";
@@ -136,7 +138,7 @@ export const updateFunctionSpecifications = async (
136
138
  try {
137
139
  const functionResponse = await updateFunction(client, {
138
140
  ...functionFound,
139
- runtime: functionFound.runtime as Runtime,
141
+ runtime: functionFound.runtime as AppwriteUtilsRuntime,
140
142
  scopes: functionFound.scopes as FunctionScope[],
141
143
  specification: specification,
142
144
  });
@@ -193,12 +195,14 @@ export const updateFunction = async (
193
195
  };
194
196
 
195
197
  export const createFunctionTemplate = async (
196
- templateType: "typescript-node" | "poetry" | "count-docs-in-collection",
198
+ templateType: "typescript-node" | "uv" | "count-docs-in-collection",
197
199
  functionName: string,
198
200
  basePath: string = "./functions"
199
201
  ) => {
200
202
  const functionPath = join(basePath, functionName);
201
- const templatesPath = join(__dirname, "templates", templateType);
203
+ const currentFileUrl = import.meta.url;
204
+ const currentDir = dirname(fileURLToPath(currentFileUrl));
205
+ const templatesPath = join(currentDir, "templates", templateType);
202
206
 
203
207
  // Create function directory
204
208
  await fs.promises.mkdir(functionPath, { recursive: true });
@@ -0,0 +1,25 @@
1
+ {
2
+ "name": "{{functionName}}",
3
+ "version": "1.0.0",
4
+ "description": "Appwrite function to count documents in a collection",
5
+ "main": "src/main.ts",
6
+ "type": "module",
7
+ "scripts": {
8
+ "build": "tsc",
9
+ "start": "node dist/main.js",
10
+ "dev": "tsx src/main.ts"
11
+ },
12
+ "dependencies": {
13
+ "node-appwrite": "^13.0.0",
14
+ "appwrite-utils": "latest",
15
+ "zod": "^3.23.0"
16
+ },
17
+ "devDependencies": {
18
+ "@types/node": "^20.0.0",
19
+ "typescript": "^5.0.0",
20
+ "tsx": "^4.0.0"
21
+ },
22
+ "engines": {
23
+ "node": ">=18.0.0"
24
+ }
25
+ }
@@ -0,0 +1,28 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "module": "ESNext",
5
+ "moduleResolution": "node",
6
+ "allowSyntheticDefaultImports": true,
7
+ "esModuleInterop": true,
8
+ "allowJs": true,
9
+ "checkJs": false,
10
+ "outDir": "./dist",
11
+ "rootDir": "./src",
12
+ "strict": true,
13
+ "noImplicitAny": true,
14
+ "strictNullChecks": true,
15
+ "strictFunctionTypes": true,
16
+ "noImplicitThis": true,
17
+ "noImplicitReturns": true,
18
+ "noFallthroughCasesInSwitch": true,
19
+ "moduleDetection": "force",
20
+ "resolveJsonModule": true,
21
+ "isolatedModules": true,
22
+ "verbatimModuleSyntax": false,
23
+ "skipLibCheck": true,
24
+ "forceConsistentCasingInFileNames": true
25
+ },
26
+ "include": ["src/**/*"],
27
+ "exclude": ["node_modules", "dist"]
28
+ }
@@ -0,0 +1,24 @@
1
+ {
2
+ "name": "{{functionName}}",
3
+ "version": "1.0.0",
4
+ "description": "Appwrite TypeScript Node.js function",
5
+ "main": "src/index.ts",
6
+ "type": "module",
7
+ "scripts": {
8
+ "build": "tsc",
9
+ "start": "node dist/index.js",
10
+ "dev": "tsx src/index.ts"
11
+ },
12
+ "dependencies": {
13
+ "node-appwrite": "^13.0.0",
14
+ "appwrite-utils": "latest"
15
+ },
16
+ "devDependencies": {
17
+ "@types/node": "^20.0.0",
18
+ "typescript": "^5.0.0",
19
+ "tsx": "^4.0.0"
20
+ },
21
+ "engines": {
22
+ "node": ">=18.0.0"
23
+ }
24
+ }
@@ -0,0 +1,28 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "module": "ESNext",
5
+ "moduleResolution": "node",
6
+ "allowSyntheticDefaultImports": true,
7
+ "esModuleInterop": true,
8
+ "allowJs": true,
9
+ "checkJs": false,
10
+ "outDir": "./dist",
11
+ "rootDir": "./src",
12
+ "strict": true,
13
+ "noImplicitAny": true,
14
+ "strictNullChecks": true,
15
+ "strictFunctionTypes": true,
16
+ "noImplicitThis": true,
17
+ "noImplicitReturns": true,
18
+ "noFallthroughCasesInSwitch": true,
19
+ "moduleDetection": "force",
20
+ "resolveJsonModule": true,
21
+ "isolatedModules": true,
22
+ "verbatimModuleSyntax": false,
23
+ "skipLibCheck": true,
24
+ "forceConsistentCasingInFileNames": true
25
+ },
26
+ "include": ["src/**/*"],
27
+ "exclude": ["node_modules", "dist"]
28
+ }