appwrite-utils-cli 1.5.1 → 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 +186 -1171
  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 +276 -1591
  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
@@ -3,12 +3,21 @@ import yaml from "js-yaml";
3
3
  import fs from "fs";
4
4
  import path from "path";
5
5
  import { AppwriteConfigSchema, type AppwriteConfig, RuntimeSchema, FunctionScopes, FunctionSpecifications, permissionsSchema, PermissionToAppwritePermission, type AppwriteFunction } from "appwrite-utils";
6
+ import { shouldIgnoreDirectory } from "../utils/directoryUtils.js";
7
+ import { MessageFormatter } from "../shared/messageFormatter.js";
6
8
 
7
9
  const YamlConfigSchema = z.object({
8
10
  appwrite: z.object({
9
11
  endpoint: z.string().default("https://cloud.appwrite.io/v1"),
10
12
  project: z.string(),
11
13
  key: z.string(),
14
+ // Session authentication support
15
+ sessionCookie: z.string().optional(),
16
+ authMethod: z.enum(["session", "apikey", "auto"]).optional().default("auto"),
17
+ sessionMetadata: z.object({
18
+ email: z.string().optional(),
19
+ expiresAt: z.string().optional(),
20
+ }).optional(),
12
21
  }),
13
22
  logging: z
14
23
  .object({
@@ -47,12 +56,14 @@ const YamlConfigSchema = z.object({
47
56
  outputDirectory: z.string().default("schemas"),
48
57
  yamlSchemaDirectory: z.string().default(".yaml_schemas"),
49
58
  collectionsDirectory: z.string().default("collections"),
59
+ tablesDirectory: z.string().default("tables"),
50
60
  })
51
61
  .optional()
52
62
  .default({
53
63
  outputDirectory: "schemas",
54
64
  yamlSchemaDirectory: ".yaml_schemas",
55
65
  collectionsDirectory: "collections",
66
+ tablesDirectory: "tables",
56
67
  }),
57
68
  migrations: z
58
69
  .object({
@@ -150,6 +161,10 @@ export const convertYamlToAppwriteConfig = (yamlConfig: YamlConfig): AppwriteCon
150
161
  appwriteEndpoint: yamlConfig.appwrite.endpoint,
151
162
  appwriteProject: yamlConfig.appwrite.project,
152
163
  appwriteKey: yamlConfig.appwrite.key,
164
+ // Session authentication support from YAML
165
+ sessionCookie: yamlConfig.appwrite.sessionCookie,
166
+ authMethod: yamlConfig.appwrite.authMethod || "auto",
167
+ sessionMetadata: yamlConfig.appwrite.sessionMetadata,
153
168
  apiMode: "auto", // Default to auto-detect for dual API support
154
169
  appwriteClient: null,
155
170
  logging: {
@@ -165,12 +180,12 @@ export const convertYamlToAppwriteConfig = (yamlConfig: YamlConfig): AppwriteCon
165
180
  enableMockData: yamlConfig.data.enableMockData,
166
181
  documentBucketId: yamlConfig.data.documentBucketId,
167
182
  usersCollectionName: yamlConfig.data.usersCollectionName,
168
- useMigrations: yamlConfig.migrations.enabled,
169
183
  schemaConfig: {
170
184
  outputDirectory: yamlConfig.schemas.outputDirectory,
171
185
  yamlSchemaDirectory: yamlConfig.schemas.yamlSchemaDirectory,
172
186
  importDirectory: yamlConfig.data.importDirectory,
173
187
  collectionsDirectory: yamlConfig.schemas.collectionsDirectory || "collections",
188
+ tablesDirectory: yamlConfig.schemas.tablesDirectory || "tables",
174
189
  },
175
190
  databases: yamlConfig.databases.map((db) => ({
176
191
  $id: db.id,
@@ -238,23 +253,78 @@ export const convertYamlToAppwriteConfig = (yamlConfig: YamlConfig): AppwriteCon
238
253
  return appwriteConfig;
239
254
  };
240
255
 
256
+ /**
257
+ * Enhanced config loading with session authentication support
258
+ * Supports session override options for preserving session state
259
+ */
260
+ export interface YamlSessionOptions {
261
+ sessionCookie?: string;
262
+ authMethod?: "session" | "apikey" | "auto";
263
+ sessionMetadata?: { email?: string; expiresAt?: string; };
264
+ }
265
+
266
+ /**
267
+ * Load YAML config with optional session preservation
268
+ * Maintains authentication priority: explicit session > YAML file > system prefs
269
+ */
270
+ export const loadYamlConfigWithSession = async (
271
+ configPath: string,
272
+ sessionOptions?: YamlSessionOptions
273
+ ): Promise<AppwriteConfig | null> => {
274
+ try {
275
+ const fileContent = fs.readFileSync(configPath, "utf8");
276
+ const yamlData = yaml.load(fileContent) as unknown;
277
+
278
+ const yamlConfig = YamlConfigSchema.parse(yamlData);
279
+ const appwriteConfig = convertYamlToAppwriteConfig(yamlConfig);
280
+
281
+ // Apply session preservation if provided (explicit overrides take priority)
282
+ if (sessionOptions) {
283
+ if (sessionOptions.sessionCookie) {
284
+ appwriteConfig.sessionCookie = sessionOptions.sessionCookie;
285
+ }
286
+ if (sessionOptions.authMethod) {
287
+ appwriteConfig.authMethod = sessionOptions.authMethod;
288
+ }
289
+ if (sessionOptions.sessionMetadata) {
290
+ appwriteConfig.sessionMetadata = sessionOptions.sessionMetadata;
291
+ }
292
+ }
293
+
294
+ return appwriteConfig;
295
+ } catch (error) {
296
+ if (error instanceof z.ZodError) {
297
+ MessageFormatter.error("YAML config validation failed", undefined, { prefix: "Config" });
298
+ error.issues.forEach((err) => {
299
+ MessageFormatter.error(`${err.path.join('.')} → ${err.message}`, undefined, { prefix: "Config" });
300
+ });
301
+ } else {
302
+ MessageFormatter.error("Error loading YAML config", error instanceof Error ? error : undefined, { prefix: "Config" });
303
+ if (error instanceof Error && error.stack) {
304
+ MessageFormatter.debug("Stack trace", error.stack, { prefix: "Config" });
305
+ }
306
+ }
307
+ return null;
308
+ }
309
+ };
310
+
241
311
  export const loadYamlConfig = async (configPath: string): Promise<AppwriteConfig | null> => {
242
312
  try {
243
313
  const fileContent = fs.readFileSync(configPath, "utf8");
244
314
  const yamlData = yaml.load(fileContent) as unknown;
245
-
315
+
246
316
  const yamlConfig = YamlConfigSchema.parse(yamlData);
247
317
  return convertYamlToAppwriteConfig(yamlConfig);
248
318
  } catch (error) {
249
319
  if (error instanceof z.ZodError) {
250
- console.error("YAML config validation failed:");
320
+ MessageFormatter.error("YAML config validation failed", undefined, { prefix: "Config" });
251
321
  error.issues.forEach((err) => {
252
- console.error(` ${err.path.join('.')} → ${err.message}`);
322
+ MessageFormatter.error(`${err.path.join('.')} → ${err.message}`, undefined, { prefix: "Config" });
253
323
  });
254
324
  } else {
255
- console.error("Error loading YAML config:", error instanceof Error ? error.message : error);
325
+ MessageFormatter.error("Error loading YAML config", error instanceof Error ? error : undefined, { prefix: "Config" });
256
326
  if (error instanceof Error && error.stack) {
257
- console.error("Stack trace:", error.stack);
327
+ MessageFormatter.debug("Stack trace", error.stack, { prefix: "Config" });
258
328
  }
259
329
  }
260
330
  return null;
@@ -306,47 +376,6 @@ export const findYamlConfig = (startDir: string): string | null => {
306
376
  return null;
307
377
  };
308
378
 
309
- const shouldIgnoreDirectory = (dirName: string): boolean => {
310
- const ignoredDirs = [
311
- 'node_modules',
312
- 'dist',
313
- 'build',
314
- 'coverage',
315
- '.next',
316
- '.nuxt',
317
- '.cache',
318
- '.git',
319
- '.svn',
320
- '.hg',
321
- '__pycache__',
322
- '.pytest_cache',
323
- '.mypy_cache',
324
- 'venv',
325
- '.venv',
326
- 'env',
327
- '.env',
328
- 'target',
329
- 'out',
330
- 'bin',
331
- 'obj',
332
- '.vs',
333
- '.vscode',
334
- '.idea',
335
- 'temp',
336
- 'tmp',
337
- '.tmp',
338
- 'logs',
339
- 'log',
340
- '.DS_Store',
341
- 'Thumbs.db'
342
- ];
343
-
344
- return ignoredDirs.includes(dirName) ||
345
- dirName.startsWith('.git') ||
346
- dirName.startsWith('node_modules') ||
347
- (dirName.startsWith('.') && dirName !== '.appwrite');
348
- };
349
-
350
379
  const findYamlConfigRecursive = (dir: string, depth: number = 0): string | null => {
351
380
  // Limit search depth to prevent infinite recursion
352
381
  if (depth > 5) {
@@ -398,6 +427,9 @@ export const generateYamlConfigTemplate = (outputPath: string) => {
398
427
  endpoint: "https://cloud.appwrite.io/v1",
399
428
  project: "YOUR_PROJECT_ID",
400
429
  key: "YOUR_API_KEY",
430
+ authMethod: "auto" as const,
431
+ // Optional session authentication (leave empty to use API key)
432
+ // sessionCookie: "session_cookie_from_appwrite_cli",
401
433
  },
402
434
  logging: {
403
435
  enabled: false,
@@ -420,6 +452,7 @@ export const generateYamlConfigTemplate = (outputPath: string) => {
420
452
  outputDirectory: "schemas",
421
453
  yamlSchemaDirectory: ".yaml_schemas",
422
454
  collectionsDirectory: "collections",
455
+ tablesDirectory: "tables",
423
456
  },
424
457
  migrations: {
425
458
  enabled: true,
@@ -433,15 +466,43 @@ export const generateYamlConfigTemplate = (outputPath: string) => {
433
466
  functions: [],
434
467
  };
435
468
 
436
- const yamlContent = yaml.dump(template, {
469
+ let yamlContent = yaml.dump(template, {
437
470
  indent: 2,
438
471
  lineWidth: 120,
439
472
  sortKeys: false,
440
473
  });
441
474
 
442
- // Add schema reference header
475
+ // Add inline comments to the schemas section
476
+ yamlContent = yamlContent.replace(
477
+ /schemas:\s*\n(\s*)outputDirectory: schemas\n(\s*)yamlSchemaDirectory: \.yaml_schemas\n(\s*)collectionsDirectory: collections\n(\s*)tablesDirectory: tables/,
478
+ `schemas:
479
+ $1outputDirectory: schemas
480
+ $2yamlSchemaDirectory: .yaml_schemas
481
+ $3# Directory for legacy Databases API collection definitions
482
+ $3collectionsDirectory: collections
483
+ $4# Directory for new TablesDB API table definitions
484
+ $4tablesDirectory: tables`
485
+ );
486
+
487
+ // Add schema reference header and documentation
443
488
  const schemaReference = "# yaml-language-server: $schema=./.yaml_schemas/appwrite-config.schema.json\n";
444
- const finalContent = schemaReference + "# Appwrite Project Configuration\n" + yamlContent;
489
+ const documentation = `# Appwrite Project Configuration
490
+ #
491
+ # Authentication Configuration:
492
+ # - key: Standard API key authentication
493
+ # - sessionCookie: Session cookie from Appwrite CLI authentication
494
+ # - authMethod: "auto" (detects available method), "session" (prefer session), "apikey" (prefer API key)
495
+ # - Priority: Explicit CLI args > YAML config > ~/.appwrite/prefs.json > Error
496
+ #
497
+ # Directory Configuration:
498
+ # - collectionsDirectory: Use for legacy Databases API (default: "collections")
499
+ # - tablesDirectory: Use for new TablesDB API (default: "tables")
500
+ # - API mode is auto-detected based on server version, or set explicitly via apiMode
501
+ #
502
+ # For dual API support, both directories can coexist with different definitions
503
+
504
+ `;
505
+ const finalContent = schemaReference + documentation + yamlContent;
445
506
 
446
507
  fs.writeFileSync(outputPath, finalContent, "utf8");
447
508
  };
@@ -459,6 +520,10 @@ export const writeYamlConfig = async (configPath: string, config: AppwriteConfig
459
520
  endpoint: config.appwriteEndpoint,
460
521
  project: config.appwriteProject,
461
522
  key: config.appwriteKey,
523
+ // Include session authentication fields
524
+ sessionCookie: config.sessionCookie,
525
+ authMethod: config.authMethod || "auto",
526
+ sessionMetadata: config.sessionMetadata,
462
527
  },
463
528
  logging: {
464
529
  enabled: config.logging?.enabled || false,
@@ -482,9 +547,10 @@ export const writeYamlConfig = async (configPath: string, config: AppwriteConfig
482
547
  outputDirectory: config.schemaConfig?.outputDirectory || "schemas",
483
548
  yamlSchemaDirectory: config.schemaConfig?.yamlSchemaDirectory || ".yaml_schemas",
484
549
  collectionsDirectory: config.schemaConfig?.collectionsDirectory || "collections",
550
+ tablesDirectory: config.schemaConfig?.tablesDirectory || "tables",
485
551
  },
486
552
  migrations: {
487
- enabled: config.useMigrations !== false,
553
+ enabled: true,
488
554
  },
489
555
  databases: config.databases?.map(db => ({
490
556
  id: db.$id,
@@ -574,9 +640,9 @@ export const writeYamlConfig = async (configPath: string, config: AppwriteConfig
574
640
  }
575
641
 
576
642
  fs.writeFileSync(configPath, finalContent, "utf8");
577
- console.log(`✅ Updated YAML configuration at ${configPath}`);
643
+ MessageFormatter.success(`Updated YAML configuration at ${configPath}`, { prefix: "Config" });
578
644
  } catch (error) {
579
- console.error("Error writing YAML config:", error instanceof Error ? error.message : error);
645
+ MessageFormatter.error("Error writing YAML config", error instanceof Error ? error : undefined, { prefix: "Config" });
580
646
  throw error;
581
647
  }
582
648
  };
@@ -640,9 +706,56 @@ export const addFunctionToYamlConfig = async (configPath: string, newFunction: A
640
706
  }
641
707
 
642
708
  fs.writeFileSync(configPath, finalContent, "utf8");
643
- console.log(`✅ Added function "${newFunction.name}" to YAML config`);
709
+ MessageFormatter.success(`Added function "${newFunction.name}" to YAML config`, { prefix: "Config" });
644
710
  } catch (error) {
645
- console.error("Error adding function to YAML config:", error instanceof Error ? error.message : error);
711
+ MessageFormatter.error("Error adding function to YAML config", error instanceof Error ? error : undefined, { prefix: "Config" });
646
712
  throw error;
647
713
  }
714
+ };
715
+
716
+ /**
717
+ * Extract session options from AppwriteConfig for YAML operations
718
+ * Useful for preserving session state during config reloads
719
+ */
720
+ export const extractSessionOptionsFromConfig = (config: AppwriteConfig): YamlSessionOptions => {
721
+ return {
722
+ sessionCookie: config.sessionCookie,
723
+ authMethod: config.authMethod,
724
+ sessionMetadata: config.sessionMetadata,
725
+ };
726
+ };
727
+
728
+ /**
729
+ * Create session-preserved YAML config operations
730
+ * Maintains authentication state during config file updates
731
+ */
732
+ export const createSessionPreservingYamlConfig = (configPath: string, sessionOptions: YamlSessionOptions) => {
733
+ return {
734
+ load: () => loadYamlConfigWithSession(configPath, sessionOptions),
735
+ write: (config: AppwriteConfig) => {
736
+ // Merge session options into config before writing
737
+ const enhancedConfig = {
738
+ ...config,
739
+ sessionCookie: sessionOptions.sessionCookie || config.sessionCookie,
740
+ authMethod: sessionOptions.authMethod || config.authMethod,
741
+ sessionMetadata: sessionOptions.sessionMetadata || config.sessionMetadata,
742
+ };
743
+ return writeYamlConfig(configPath, enhancedConfig);
744
+ },
745
+ addFunction: (func: AppwriteFunction) => addFunctionToYamlConfig(configPath, func),
746
+ };
747
+ };
748
+
749
+ /**
750
+ * Determine if YAML config has session authentication configured
751
+ */
752
+ export const hasYamlSessionAuth = (configPath: string): boolean => {
753
+ try {
754
+ const fileContent = fs.readFileSync(configPath, "utf8");
755
+ const yamlData = yaml.load(fileContent) as any;
756
+
757
+ return !!(yamlData?.appwrite?.sessionCookie && yamlData.appwrite.sessionCookie.trim());
758
+ } catch (error) {
759
+ return false;
760
+ }
648
761
  };
@@ -1,6 +1,7 @@
1
1
  import { Databases, Query, type Models } from "node-appwrite";
2
2
  import { delay, tryAwaitWithRetry } from "../utils/helperFunctions.js";
3
3
  import { fetchAllCollections } from "../collections/methods.js";
4
+ import { MessageFormatter } from "../shared/messageFormatter.js";
4
5
 
5
6
  export const fetchAllDatabases = async (
6
7
  database: Databases
@@ -30,13 +31,13 @@ export const wipeDatabase = async (
30
31
  database: Databases,
31
32
  databaseId: string
32
33
  ): Promise<{ collectionId: string; collectionName: string }[]> => {
33
- console.log(`Wiping database: ${databaseId}`);
34
+ MessageFormatter.info(`Wiping database: ${databaseId}`, { prefix: "Database" });
34
35
  const existingCollections = await fetchAllCollections(databaseId, database);
35
36
  let collectionsDeleted: { collectionId: string; collectionName: string }[] =
36
37
  [];
37
38
 
38
39
  for (const { $id: collectionId, name } of existingCollections) {
39
- console.log(`Deleting collection: ${collectionId}`);
40
+ MessageFormatter.info(`Deleting collection: ${collectionId}`, { prefix: "Database" });
40
41
  collectionsDeleted.push({ collectionId, collectionName: name });
41
42
  await tryAwaitWithRetry(
42
43
  async () => await database.deleteCollection(databaseId, collectionId)
@@ -1,126 +1,18 @@
1
1
  import { Databases, Query, type Models } from "node-appwrite";
2
- import { createOrUpdateAttributeWithStatusCheck } from "../collections/attributes.js";
3
- import { getMigrationCollectionSchemas } from "../storage/schemas.js";
4
- import {
5
- areCollectionNamesSame,
6
- delay,
7
- toCamelCase,
8
- tryAwaitWithRetry,
9
- } from "../utils/index.js";
2
+ import { tryAwaitWithRetry } from "../utils/index.js";
10
3
  import { type AppwriteConfig } from "appwrite-utils";
11
4
  import { ulid } from "ulidx";
5
+ import { MessageFormatter } from "../shared/messageFormatter.js";
12
6
 
13
- export const setupMigrationDatabase = async (config: AppwriteConfig) => {
14
- if (!config.useMigrations) {
15
- console.log("Migrations database disabled, skipping setup");
16
- return;
17
- }
18
-
19
- console.log("---------------------------------");
20
- console.log("Starting Migrations Setup");
21
- console.log("---------------------------------");
22
- const database = new Databases(config.appwriteClient);
7
+ export const ensureDatabasesExist = async (config: AppwriteConfig, databasesToEnsure?: Models.Database[]) => {
23
8
  if (!config.appwriteClient) {
24
9
  throw new Error("Appwrite client is not initialized in the config");
25
10
  }
26
- let db: Models.Database | undefined;
27
- const migrationCollectionsSetup = getMigrationCollectionSchemas();
28
-
29
- try {
30
- db = await tryAwaitWithRetry(
31
- async () => await database.get("migrations"),
32
- undefined,
33
- true
34
- );
35
- console.log("Migrations database found");
36
- } catch (e) {
37
- db = await tryAwaitWithRetry(
38
- async () => await database.create("migrations", "Migrations", true)
39
- );
40
- console.log("Migrations database created");
41
- }
42
-
43
- if (!db) {
44
- console.error("Failed to create or retrieve the migrations database");
45
- return;
46
- }
47
-
48
- for (const [collectionName, { collection, attributes }] of Object.entries(
49
- migrationCollectionsSetup
50
- )) {
51
- const collectionId = toCamelCase(collectionName);
52
- let collectionFound: Models.Collection | undefined;
53
- try {
54
- collectionFound = await tryAwaitWithRetry(
55
- async () => await database.getCollection(db.$id, collectionId),
56
- undefined,
57
- true
58
- );
59
- console.log(`Collection found: ${collectionId}`);
60
- } catch (e) {
61
- console.log(`Collection not found: ${collectionId}`);
62
- try {
63
- collectionFound = await tryAwaitWithRetry(
64
- async () =>
65
- await database.createCollection(
66
- db.$id,
67
- collectionId,
68
- collectionName,
69
- undefined,
70
- collection.documentSecurity,
71
- collection.enabled
72
- ),
73
- undefined,
74
- true
75
- );
76
- console.log(`Collection created: ${collectionId}`);
77
- } catch (createError) {
78
- console.error(
79
- `Failed to create collection: ${collectionId}`,
80
- createError
81
- );
82
- continue;
83
- }
84
- }
85
-
86
- if (!collectionFound) {
87
- console.error(`Failed to create or retrieve collection: ${collectionId}`);
88
- continue;
89
- }
90
-
91
- for (const attribute of attributes) {
92
- try {
93
- await createOrUpdateAttributeWithStatusCheck(
94
- database,
95
- db.$id,
96
- collectionFound,
97
- attribute
98
- );
99
- await delay(100);
100
- console.log(`Attribute created/updated: ${attribute.key}`);
101
- } catch (attrError) {
102
- console.error(
103
- `Failed to create/update attribute: ${attribute.key}`,
104
- attrError
105
- );
106
- }
107
- }
108
- }
109
- console.log("---------------------------------");
110
- console.log("Migrations Setup Complete");
111
- console.log("---------------------------------");
112
- };
113
-
114
- export const ensureDatabasesExist = async (config: AppwriteConfig, databasesToEnsure?: Models.Database[]) => {
115
- if (!config.appwriteClient) {
116
- throw new Error("Appwrite client is not initialized in the config");
117
- }
118
- const database = new Databases(config.appwriteClient);
119
- // Work on a shallow copy so we don't mutate caller-provided arrays
120
- const databasesToCreate = [...(databasesToEnsure || config.databases || [])];
11
+ const database = new Databases(config.appwriteClient);
12
+ const databasesToCreate = databasesToEnsure || config.databases || [];
121
13
 
122
14
  if (!databasesToCreate.length) {
123
- console.log("No databases to create");
15
+ MessageFormatter.info("No databases to create");
124
16
  return;
125
17
  }
126
18
 
@@ -128,47 +20,28 @@ export const ensureDatabasesExist = async (config: AppwriteConfig, databasesToEn
128
20
  async () => await database.list([Query.limit(500)])
129
21
  );
130
22
 
131
- const migrationsDatabase = existingDatabases.databases.find(
132
- (d) => d.name.toLowerCase().trim().replace(" ", "") === "migrations"
133
- );
134
- if (config.useMigrations && existingDatabases.databases.length !== 0 && migrationsDatabase) {
135
- console.log("Creating all databases including migrations");
136
- // Ensure migrations exists, but do not mutate the caller's array
137
- if (!databasesToCreate.some((d) => d.$id === migrationsDatabase.$id)) {
138
- databasesToCreate.push(migrationsDatabase);
139
- }
140
- }
141
-
142
23
  for (const db of databasesToCreate) {
143
24
  if (!existingDatabases.databases.some((d) => d.name === db.name)) {
144
25
  await tryAwaitWithRetry(
145
26
  async () => await database.create(db.$id || ulid(), db.name, true)
146
27
  );
147
- console.log(`${db.name} database created`);
28
+ MessageFormatter.success(`${db.name} database created`);
148
29
  }
149
30
  }
150
31
  };
151
32
 
152
33
  export const wipeOtherDatabases = async (
153
34
  database: Databases,
154
- databasesToKeep: Models.Database[],
155
- useMigrations: boolean = true
35
+ databasesToKeep: Models.Database[]
156
36
  ) => {
157
- console.log(`Databases to keep: ${databasesToKeep.map(db => db.name).join(", ")}`);
37
+ MessageFormatter.info(`Databases to keep: ${databasesToKeep.map(db => db.name).join(", ")}`);
158
38
  const allDatabases = await tryAwaitWithRetry(
159
39
  async () => await database.list([Query.limit(500)])
160
40
  );
161
- const migrationsDatabase = allDatabases.databases.find(
162
- (d) => d.name.toLowerCase().trim().replace(" ", "") === "migrations"
163
- );
164
- if (useMigrations && allDatabases.databases.length !== 0 && migrationsDatabase) {
165
- console.log("Wiping all databases except migrations");
166
- databasesToKeep.push(migrationsDatabase);
167
- }
168
41
  for (const db of allDatabases.databases) {
169
42
  if (!databasesToKeep.some((d) => d.name === db.name)) {
170
43
  await tryAwaitWithRetry(async () => await database.delete(db.$id));
171
- console.log(`Deleted database: ${db.name}`);
44
+ MessageFormatter.success(`Deleted database: ${db.name}`);
172
45
  }
173
46
  }
174
47
  };
@@ -198,7 +71,7 @@ export const ensureCollectionsExist = async (
198
71
  true
199
72
  )
200
73
  );
201
- console.log(`${collection.name} collection created in ${database.name}`);
74
+ MessageFormatter.success(`${collection.name} collection created in ${database.name}`);
202
75
  }
203
76
  }
204
77
  };