appwrite-utils-cli 1.7.7 → 1.7.8

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.
@@ -0,0 +1,146 @@
1
+ # Selection Dialogs System
2
+
3
+ ## Overview
4
+
5
+ The `SelectionDialogs` class provides a comprehensive interactive selection system for the enhanced sync flow in the Appwrite Utils CLI. It enables users to select databases, tables/collections, and storage buckets with visual indicators for configured vs new items.
6
+
7
+ ## Features
8
+
9
+ - **Visual Indicators**: ✅ for configured items, ○ for new items
10
+ - **Multi-Selection Support**: Checkbox-style selection with "Select All" functionality
11
+ - **Configuration Awareness**: Detects and highlights existing configurations
12
+ - **Grouped Display**: Organizes buckets by database for better context
13
+ - **Comprehensive Confirmation**: Shows detailed summary before sync execution
14
+ - **Graceful Error Handling**: Proper error messages and cancellation support
15
+ - **Type Safety**: Full TypeScript support with proper interfaces
16
+
17
+ ## Main Functions
18
+
19
+ ### `promptForExistingConfig(configuredItems: any[])`
20
+ Prompts user about existing configuration with options to:
21
+ - Sync existing configured items
22
+ - Add/remove items from configuration
23
+
24
+ ### `selectDatabases(availableDatabases, configuredDatabases, options?)`
25
+ Interactive database selection with:
26
+ - Visual indicators for configured vs new databases
27
+ - "Select All" functionality
28
+ - Filtering options (new only, default selections)
29
+
30
+ ### `selectTablesForDatabase(databaseId, databaseName, availableTables, configuredTables, options?)`
31
+ Table/collection selection for a specific database with:
32
+ - Database context display
33
+ - Table selection with indicators
34
+ - Multi-selection support
35
+
36
+ ### `selectBucketsForDatabases(selectedDatabaseIds, availableBuckets, configuredBuckets, options?)`
37
+ Storage bucket selection with:
38
+ - Grouping by database
39
+ - Relevance filtering (only buckets for selected databases)
40
+ - Ungrouped/general storage support
41
+
42
+ ### `confirmSyncSelection(selectionSummary: SyncSelectionSummary)`
43
+ Final confirmation dialog showing:
44
+ - Complete selection summary
45
+ - Statistics (total, new, existing items)
46
+ - Detailed breakdown by category
47
+
48
+ ## Usage Example
49
+
50
+ ```typescript
51
+ import { SelectionDialogs } from './shared/selectionDialogs.js';
52
+ import type { Models } from 'node-appwrite';
53
+
54
+ // 1. Check for existing configuration
55
+ const { syncExisting, modifyConfiguration } = await SelectionDialogs.promptForExistingConfig(configuredDatabases);
56
+
57
+ if (modifyConfiguration) {
58
+ // 2. Select databases
59
+ const selectedDatabaseIds = await SelectionDialogs.selectDatabases(
60
+ availableDatabases,
61
+ configuredDatabases,
62
+ { showSelectAll: true }
63
+ );
64
+
65
+ // 3. Select tables for each database
66
+ const tableSelectionsMap = new Map<string, string[]>();
67
+ for (const databaseId of selectedDatabaseIds) {
68
+ const selectedTableIds = await SelectionDialogs.selectTablesForDatabase(
69
+ databaseId,
70
+ databaseName,
71
+ availableTables,
72
+ configuredTables
73
+ );
74
+ tableSelectionsMap.set(databaseId, selectedTableIds);
75
+ }
76
+
77
+ // 4. Select buckets
78
+ const selectedBucketIds = await SelectionDialogs.selectBucketsForDatabases(
79
+ selectedDatabaseIds,
80
+ availableBuckets,
81
+ configuredBuckets
82
+ );
83
+
84
+ // 5. Create selection summary and confirm
85
+ const selectionSummary = SelectionDialogs.createSyncSelectionSummary(
86
+ databaseSelections,
87
+ bucketSelections
88
+ );
89
+
90
+ const confirmed = await SelectionDialogs.confirmSyncSelection(selectionSummary);
91
+
92
+ if (confirmed) {
93
+ // Proceed with sync operation
94
+ }
95
+ }
96
+ ```
97
+
98
+ ## Configuration Options
99
+
100
+ ### Database Selection Options
101
+ - `showSelectAll`: Show "Select All" option (default: true)
102
+ - `allowNewOnly`: Only show new/unconfigured databases (default: false)
103
+ - `defaultSelected`: Array of database IDs to pre-select
104
+
105
+ ### Table Selection Options
106
+ - `showSelectAll`: Show "Select All" option (default: true)
107
+ - `allowNewOnly`: Only show new/unconfigured tables (default: false)
108
+ - `defaultSelected`: Array of table IDs to pre-select
109
+ - `showDatabaseContext`: Show database name in header (default: true)
110
+
111
+ ### Bucket Selection Options
112
+ - `showSelectAll`: Show "Select All" option (default: true)
113
+ - `allowNewOnly`: Only show new/unconfigured buckets (default: false)
114
+ - `defaultSelected`: Array of bucket IDs to pre-select
115
+ - `groupByDatabase`: Group buckets by database (default: true)
116
+
117
+ ## Interfaces
118
+
119
+ ### `SyncSelectionSummary`
120
+ Contains complete selection information:
121
+ - `databases`: Array of selected databases with their tables
122
+ - `buckets`: Array of selected buckets
123
+ - `totalDatabases/Tables/Buckets`: Count of selected items
124
+ - `newItems/existingItems`: Breakdown of new vs existing configurations
125
+
126
+ ### `DatabaseSelection`
127
+ Represents a selected database:
128
+ - `databaseId/databaseName`: Database identification
129
+ - `tableIds/tableNames`: Selected tables for this database
130
+ - `isNew`: Whether this is a new configuration
131
+
132
+ ### `BucketSelection`
133
+ Represents a selected bucket:
134
+ - `bucketId/bucketName`: Bucket identification
135
+ - `databaseId/databaseName`: Associated database (if applicable)
136
+ - `isNew`: Whether this is a new configuration
137
+
138
+ ## Integration
139
+
140
+ The selection dialogs are designed to integrate seamlessly with the existing CLI infrastructure:
141
+
142
+ - Uses `MessageFormatter` for consistent styling
143
+ - Integrates with existing logging system
144
+ - Follows established error handling patterns
145
+ - Compatible with existing configuration management
146
+ - Uses inquirer.js for interactive prompts
@@ -3,32 +3,95 @@ import chalk from "chalk";
3
3
  import { join } from "node:path";
4
4
  import { MessageFormatter } from "../../shared/messageFormatter.js";
5
5
  import { ConfirmationDialogs } from "../../shared/confirmationDialogs.js";
6
+ import { SelectionDialogs } from "../../shared/selectionDialogs.js";
7
+ import { logger } from "../../shared/logging.js";
6
8
  import { fetchAllDatabases } from "../../databases/methods.js";
7
9
  import { listBuckets } from "../../storage/methods.js";
8
10
  import { getFunction, downloadLatestFunctionDeployment } from "../../functions/methods.js";
9
11
  export const databaseCommands = {
10
12
  async syncDb(cli) {
11
13
  MessageFormatter.progress("Pushing local configuration to Appwrite...", { prefix: "Database" });
12
- const databases = await cli.selectDatabases(cli.getLocalDatabases(), chalk.blue("Select local databases to push:"), true);
13
- if (!databases.length) {
14
- MessageFormatter.warning("No databases selected. Skipping database sync.", { prefix: "Database" });
15
- return;
16
- }
17
14
  try {
18
- // Loop through each database and prompt for collections specific to that database
19
- for (const database of databases) {
20
- MessageFormatter.info(`\n📦 Configuring push for database: ${database.name}`, { prefix: "Database" });
21
- const collections = await cli.selectCollectionsAndTables(database, cli.controller.database, chalk.blue(`Select collections/tables to push to "${database.name}":`), true, // multiSelect
15
+ // Initialize controller
16
+ await cli.controller.init();
17
+ // Get available and configured databases
18
+ const availableDatabases = await fetchAllDatabases(cli.controller.database);
19
+ const configuredDatabases = cli.controller.config?.databases || [];
20
+ // Get local collections for selection
21
+ const localCollections = cli.getLocalCollections();
22
+ // Prompt about existing configuration
23
+ const { syncExisting, modifyConfiguration } = await SelectionDialogs.promptForExistingConfig(configuredDatabases);
24
+ // Select databases
25
+ const selectedDatabaseIds = await SelectionDialogs.selectDatabases(availableDatabases, configuredDatabases, { showSelectAll: true, allowNewOnly: !syncExisting });
26
+ if (selectedDatabaseIds.length === 0) {
27
+ MessageFormatter.warning("No databases selected. Skipping database sync.", { prefix: "Database" });
28
+ return;
29
+ }
30
+ // Select tables/collections for each database using the existing method
31
+ const tableSelectionsMap = new Map();
32
+ const availableTablesMap = new Map();
33
+ for (const databaseId of selectedDatabaseIds) {
34
+ const database = availableDatabases.find(db => db.$id === databaseId);
35
+ // Use the existing selectCollectionsAndTables method
36
+ const selectedCollections = await cli.selectCollectionsAndTables(database, cli.controller.database, chalk.blue(`Select collections/tables to push to "${database.name}":`), true, // multiSelect
22
37
  true // prefer local
23
38
  );
24
- if (collections.length === 0) {
39
+ // Map selected collections to table IDs
40
+ const selectedTableIds = selectedCollections.map((c) => c.$id || c.id);
41
+ // Store selections
42
+ tableSelectionsMap.set(databaseId, selectedTableIds);
43
+ availableTablesMap.set(databaseId, selectedCollections);
44
+ if (selectedCollections.length === 0) {
25
45
  MessageFormatter.warning(`No collections selected for database "${database.name}". Skipping.`, { prefix: "Database" });
26
46
  continue;
27
47
  }
28
- // Push selected collections to this specific database
29
- await cli.controller.syncDb([database], collections);
30
- MessageFormatter.success(`Pushed ${collections.length} collection(s) to database "${database.name}"`, { prefix: "Database" });
31
48
  }
49
+ // Ask if user wants to select buckets
50
+ const { selectBuckets } = await inquirer.prompt([
51
+ {
52
+ type: "confirm",
53
+ name: "selectBuckets",
54
+ message: "Do you want to select storage buckets to sync as well?",
55
+ default: false,
56
+ },
57
+ ]);
58
+ let bucketSelections = [];
59
+ if (selectBuckets) {
60
+ // Get available and configured buckets
61
+ try {
62
+ const availableBucketsResponse = await listBuckets(cli.controller.storage);
63
+ const availableBuckets = availableBucketsResponse.buckets || [];
64
+ const configuredBuckets = cli.controller.config?.buckets || [];
65
+ if (availableBuckets.length === 0) {
66
+ MessageFormatter.warning("No storage buckets available in remote instance.", { prefix: "Database" });
67
+ }
68
+ else {
69
+ // Select buckets using SelectionDialogs
70
+ const selectedBucketIds = await SelectionDialogs.selectBucketsForDatabases(selectedDatabaseIds, availableBuckets, configuredBuckets, { showSelectAll: true, groupByDatabase: true });
71
+ if (selectedBucketIds.length > 0) {
72
+ // Create BucketSelection objects
73
+ bucketSelections = SelectionDialogs.createBucketSelection(selectedBucketIds, availableBuckets, configuredBuckets, availableDatabases);
74
+ MessageFormatter.info(`Selected ${bucketSelections.length} storage bucket(s)`, { prefix: "Database" });
75
+ }
76
+ }
77
+ }
78
+ catch (error) {
79
+ MessageFormatter.warning("Failed to fetch storage buckets. Continuing with databases only.", { prefix: "Database" });
80
+ logger.warn("Storage bucket fetch failed during syncDb", { error: error instanceof Error ? error.message : String(error) });
81
+ }
82
+ }
83
+ // Create DatabaseSelection objects
84
+ const databaseSelections = SelectionDialogs.createDatabaseSelection(selectedDatabaseIds, availableDatabases, tableSelectionsMap, configuredDatabases, availableTablesMap);
85
+ // Show confirmation summary
86
+ const selectionSummary = SelectionDialogs.createSyncSelectionSummary(databaseSelections, bucketSelections);
87
+ const confirmed = await SelectionDialogs.confirmSyncSelection(selectionSummary);
88
+ if (!confirmed) {
89
+ MessageFormatter.info("Sync operation cancelled by user", { prefix: "Database" });
90
+ return;
91
+ }
92
+ // Perform selective sync using the controller
93
+ MessageFormatter.progress("Starting selective sync...", { prefix: "Database" });
94
+ await cli.controller.selectiveSync(databaseSelections, bucketSelections);
32
95
  MessageFormatter.success("\n✅ All database configurations pushed successfully!", { prefix: "Database" });
33
96
  // Then handle functions if requested
34
97
  const { syncFunctions } = await inquirer.prompt([
@@ -73,19 +136,23 @@ export const databaseCommands = {
73
136
  ]);
74
137
  if (syncDatabases) {
75
138
  const remoteDatabases = await fetchAllDatabases(cli.controller.database);
76
- // Use the controller's synchronizeConfigurations method which handles collections properly
77
- MessageFormatter.progress("Pulling collections and generating collection files...", { prefix: "Collections" });
78
- await cli.controller.synchronizeConfigurations(remoteDatabases);
79
- // Also configure buckets for any new databases
139
+ // First, prepare the combined database list for bucket configuration
80
140
  const localDatabases = cli.controller.config?.databases || [];
81
- const updatedConfig = await cli.configureBuckets({
141
+ const allDatabases = [
142
+ ...localDatabases,
143
+ ...remoteDatabases.filter((rd) => !localDatabases.some((ld) => ld.name === rd.name)),
144
+ ];
145
+ // Configure buckets FIRST to get user selections before writing config
146
+ MessageFormatter.progress("Configuring storage buckets...", { prefix: "Buckets" });
147
+ const configWithBuckets = await cli.configureBuckets({
82
148
  ...cli.controller.config,
83
- databases: [
84
- ...localDatabases,
85
- ...remoteDatabases.filter((rd) => !localDatabases.some((ld) => ld.name === rd.name)),
86
- ],
149
+ databases: allDatabases,
87
150
  });
88
- cli.controller.config = updatedConfig;
151
+ // Update controller config with bucket selections
152
+ cli.controller.config = configWithBuckets;
153
+ // Now synchronize configurations with the updated config that includes bucket selections
154
+ MessageFormatter.progress("Pulling collections and generating collection files...", { prefix: "Collections" });
155
+ await cli.controller.synchronizeConfigurations(remoteDatabases, configWithBuckets);
89
156
  }
90
157
  // Then sync functions
91
158
  const { syncFunctions } = await inquirer.prompt([
package/dist/main.js CHANGED
@@ -13,6 +13,8 @@ import chalk from "chalk";
13
13
  import { listSpecifications } from "./functions/methods.js";
14
14
  import { MessageFormatter } from "./shared/messageFormatter.js";
15
15
  import { ConfirmationDialogs } from "./shared/confirmationDialogs.js";
16
+ import { SelectionDialogs } from "./shared/selectionDialogs.js";
17
+ import { logger } from "./shared/logging.js";
16
18
  import path from "path";
17
19
  import fs from "fs";
18
20
  import { createRequire } from "node:module";
@@ -23,6 +25,153 @@ const require = createRequire(import.meta.url);
23
25
  if (!globalThis.require) {
24
26
  globalThis.require = require;
25
27
  }
28
+ /**
29
+ * Enhanced sync function with intelligent configuration detection and selection dialogs
30
+ */
31
+ async function performEnhancedSync(controller, parsedArgv) {
32
+ try {
33
+ MessageFormatter.banner("Enhanced Sync", "Intelligent configuration detection and selection");
34
+ if (!controller.config) {
35
+ MessageFormatter.error("No Appwrite configuration found", undefined, { prefix: "Sync" });
36
+ return null;
37
+ }
38
+ // Get all available databases from remote
39
+ const availableDatabases = await fetchAllDatabases(controller.database);
40
+ if (availableDatabases.length === 0) {
41
+ MessageFormatter.warning("No databases found in remote project", { prefix: "Sync" });
42
+ return null;
43
+ }
44
+ // Get existing configuration
45
+ const configuredDatabases = controller.config.databases || [];
46
+ const configuredBuckets = controller.config.buckets || [];
47
+ // Check if we have existing configuration
48
+ const hasExistingConfig = configuredDatabases.length > 0 || configuredBuckets.length > 0;
49
+ let syncExisting = false;
50
+ let modifyConfiguration = true;
51
+ if (hasExistingConfig) {
52
+ // Prompt about existing configuration
53
+ const response = await SelectionDialogs.promptForExistingConfig([
54
+ ...configuredDatabases,
55
+ ...configuredBuckets
56
+ ]);
57
+ syncExisting = response.syncExisting;
58
+ modifyConfiguration = response.modifyConfiguration;
59
+ if (syncExisting && !modifyConfiguration) {
60
+ // Just sync existing configuration without changes
61
+ MessageFormatter.info("Syncing existing configuration without modifications", { prefix: "Sync" });
62
+ // Convert configured databases to DatabaseSelection format
63
+ const databaseSelections = configuredDatabases.map(db => ({
64
+ databaseId: db.$id,
65
+ databaseName: db.name,
66
+ tableIds: [], // Tables will be populated from collections config
67
+ tableNames: [],
68
+ isNew: false
69
+ }));
70
+ // Convert configured buckets to BucketSelection format
71
+ const bucketSelections = configuredBuckets.map(bucket => ({
72
+ bucketId: bucket.$id,
73
+ bucketName: bucket.name,
74
+ databaseId: undefined,
75
+ databaseName: undefined,
76
+ isNew: false
77
+ }));
78
+ const selectionSummary = SelectionDialogs.createSyncSelectionSummary(databaseSelections, bucketSelections);
79
+ const confirmed = await SelectionDialogs.confirmSyncSelection(selectionSummary);
80
+ if (!confirmed) {
81
+ MessageFormatter.info("Sync operation cancelled by user", { prefix: "Sync" });
82
+ return null;
83
+ }
84
+ // Perform sync with existing configuration
85
+ await controller.selectiveSync(databaseSelections, bucketSelections);
86
+ return selectionSummary;
87
+ }
88
+ }
89
+ if (!modifyConfiguration) {
90
+ MessageFormatter.info("No configuration changes requested", { prefix: "Sync" });
91
+ return null;
92
+ }
93
+ // Allow new items selection based on user choice
94
+ const allowNewOnly = !syncExisting;
95
+ // Select databases
96
+ const selectedDatabaseIds = await SelectionDialogs.selectDatabases(availableDatabases, configuredDatabases, {
97
+ showSelectAll: true,
98
+ allowNewOnly,
99
+ defaultSelected: syncExisting ? configuredDatabases.map(db => db.$id) : []
100
+ });
101
+ if (selectedDatabaseIds.length === 0) {
102
+ MessageFormatter.warning("No databases selected for sync", { prefix: "Sync" });
103
+ return null;
104
+ }
105
+ // For each selected database, get available tables and select them
106
+ const tableSelectionsMap = new Map();
107
+ const availableTablesMap = new Map();
108
+ for (const databaseId of selectedDatabaseIds) {
109
+ const database = availableDatabases.find(db => db.$id === databaseId);
110
+ SelectionDialogs.showProgress(`Fetching tables for database: ${database.name}`);
111
+ // Get available tables from remote
112
+ const availableTables = await fetchAllCollections(databaseId, controller.database);
113
+ availableTablesMap.set(databaseId, availableTables);
114
+ // Get configured tables for this database
115
+ // Note: Collections are stored globally in the config, not per database
116
+ const configuredTables = controller.config.collections || [];
117
+ // Select tables for this database
118
+ const selectedTableIds = await SelectionDialogs.selectTablesForDatabase(databaseId, database.name, availableTables, configuredTables, {
119
+ showSelectAll: true,
120
+ allowNewOnly,
121
+ defaultSelected: syncExisting ? configuredTables.map((t) => t.$id) : []
122
+ });
123
+ tableSelectionsMap.set(databaseId, selectedTableIds);
124
+ if (selectedTableIds.length === 0) {
125
+ MessageFormatter.warning(`No tables selected for database: ${database.name}`, { prefix: "Sync" });
126
+ }
127
+ }
128
+ // Select buckets
129
+ let selectedBucketIds = [];
130
+ // Get available buckets from remote
131
+ if (controller.storage) {
132
+ try {
133
+ // Note: We need to implement fetchAllBuckets or use storage.listBuckets
134
+ // For now, we'll use configured buckets as available
135
+ SelectionDialogs.showProgress("Fetching storage buckets...");
136
+ // Create a mock availableBuckets array - in real implementation,
137
+ // you'd fetch this from the Appwrite API
138
+ const availableBuckets = configuredBuckets; // Placeholder
139
+ selectedBucketIds = await SelectionDialogs.selectBucketsForDatabases(selectedDatabaseIds, availableBuckets, configuredBuckets, {
140
+ showSelectAll: true,
141
+ allowNewOnly: parsedArgv.selectBuckets ? false : allowNewOnly,
142
+ groupByDatabase: true,
143
+ defaultSelected: syncExisting ? configuredBuckets.map(b => b.$id) : []
144
+ });
145
+ }
146
+ catch (error) {
147
+ MessageFormatter.warning("Could not fetch storage buckets", { prefix: "Sync" });
148
+ logger.warn("Failed to fetch buckets during sync", { error });
149
+ }
150
+ }
151
+ // Create selection objects
152
+ const databaseSelections = SelectionDialogs.createDatabaseSelection(selectedDatabaseIds, availableDatabases, tableSelectionsMap, configuredDatabases, availableTablesMap);
153
+ const bucketSelections = SelectionDialogs.createBucketSelection(selectedBucketIds, [], // availableBuckets - would be populated from API
154
+ configuredBuckets, availableDatabases);
155
+ // Show final confirmation
156
+ const selectionSummary = SelectionDialogs.createSyncSelectionSummary(databaseSelections, bucketSelections);
157
+ const confirmed = await SelectionDialogs.confirmSyncSelection(selectionSummary);
158
+ if (!confirmed) {
159
+ MessageFormatter.info("Sync operation cancelled by user", { prefix: "Sync" });
160
+ return null;
161
+ }
162
+ // Perform the selective sync
163
+ await controller.selectiveSync(databaseSelections, bucketSelections);
164
+ MessageFormatter.success("Enhanced sync completed successfully", { prefix: "Sync" });
165
+ return selectionSummary;
166
+ }
167
+ catch (error) {
168
+ SelectionDialogs.showError("Enhanced sync failed", error instanceof Error ? error : new Error(String(error)));
169
+ return null;
170
+ }
171
+ }
172
+ /**
173
+ * Performs selective sync with the given database and bucket selections
174
+ */
26
175
  /**
27
176
  * Checks if the migration from collections to tables should be allowed
28
177
  * Returns an object with:
@@ -143,6 +292,15 @@ const argv = yargs(hideBin(process.argv))
143
292
  .option("sync", {
144
293
  type: "boolean",
145
294
  description: "Pull and synchronize your local config with the remote Appwrite project schema",
295
+ })
296
+ .option("autoSync", {
297
+ alias: ["auto"],
298
+ type: "boolean",
299
+ description: "Skip prompts and sync all databases, tables, and buckets (current behavior)"
300
+ })
301
+ .option("selectBuckets", {
302
+ type: "boolean",
303
+ description: "Force bucket selection dialog even if buckets are already configured"
146
304
  })
147
305
  .option("endpoint", {
148
306
  type: "string",
@@ -711,10 +869,23 @@ async function main() {
711
869
  operationStats.pushedCollections = controller.config?.collections?.length || 0;
712
870
  }
713
871
  else if (parsedArgv.sync) {
714
- // SYNC: Pull from remote
715
- const databases = options.databases || (await fetchAllDatabases(controller.database));
716
- await controller.synchronizeConfigurations(databases);
717
- operationStats.syncedDatabases = databases.length;
872
+ // Enhanced SYNC: Pull from remote with intelligent configuration detection
873
+ if (parsedArgv.autoSync) {
874
+ // Legacy behavior: sync everything without prompts
875
+ MessageFormatter.info("Using auto-sync mode (legacy behavior)", { prefix: "Sync" });
876
+ const databases = options.databases || (await fetchAllDatabases(controller.database));
877
+ await controller.synchronizeConfigurations(databases);
878
+ operationStats.syncedDatabases = databases.length;
879
+ }
880
+ else {
881
+ // Enhanced sync flow with selection dialogs
882
+ const syncResult = await performEnhancedSync(controller, parsedArgv);
883
+ if (syncResult) {
884
+ operationStats.syncedDatabases = syncResult.databases.length;
885
+ operationStats.syncedCollections = syncResult.totalTables;
886
+ operationStats.syncedBuckets = syncResult.buckets.length;
887
+ }
888
+ }
718
889
  }
719
890
  if (options.generateSchemas) {
720
891
  await controller.generateSchemas();
@@ -1,5 +1,7 @@
1
1
  import { Storage, type Models } from "node-appwrite";
2
2
  import { type AppwriteConfig } from "appwrite-utils";
3
+ import type { DatabaseAdapter } from "../adapters/DatabaseAdapter.js";
4
+ import type { DatabaseSelection, BucketSelection } from "../shared/selectionDialogs.js";
3
5
  export declare class AppwriteToX {
4
6
  config: AppwriteConfig;
5
7
  storage: Storage;
@@ -102,7 +104,14 @@ export declare class AppwriteToX {
102
104
  } | undefined;
103
105
  })[]>;
104
106
  appwriteFolderPath: string;
107
+ adapter?: DatabaseAdapter;
108
+ apiMode?: 'legacy' | 'tablesdb';
109
+ databaseApiModes: Map<string, "legacy" | "tablesdb">;
105
110
  constructor(config: AppwriteConfig, appwriteFolderPath: string, storage: Storage);
111
+ /**
112
+ * Initialize adapter for database operations with API mode detection
113
+ */
114
+ private initializeAdapter;
106
115
  private ensureClientInitialized;
107
116
  parsePermissionString: (permissionString: string) => {
108
117
  permission: string;
@@ -116,6 +125,22 @@ export declare class AppwriteToX {
116
125
  target: string;
117
126
  })[];
118
127
  updateCollectionConfigAttributes: (collection: Models.Collection) => void;
119
- appwriteSync(config: AppwriteConfig, databases?: Models.Database[]): Promise<void>;
120
- toSchemas(databases?: Models.Database[]): Promise<void>;
128
+ /**
129
+ * Fetch collections/tables using the appropriate adapter or legacy client
130
+ */
131
+ private fetchCollectionsOrTables;
132
+ /**
133
+ * Get collection/table using the appropriate adapter or legacy client
134
+ */
135
+ private getCollectionOrTable;
136
+ /**
137
+ * Detect API mode for a specific database by testing adapter capabilities
138
+ */
139
+ private detectDatabaseApiMode;
140
+ /**
141
+ * Get API mode context for schema generation
142
+ */
143
+ private getSchemaGeneratorApiContext;
144
+ appwriteSync(config: AppwriteConfig, databases?: Models.Database[], databaseSelections?: DatabaseSelection[], bucketSelections?: BucketSelection[]): Promise<void>;
145
+ toSchemas(databases?: Models.Database[], databaseSelections?: DatabaseSelection[], bucketSelections?: BucketSelection[]): Promise<void>;
121
146
  }