@njdamstra/appwrite-utils-cli 1.8.9 → 1.10.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.
- package/CHANGELOG.md +16 -0
- package/CONFIG_TODO.md +1189 -0
- package/SELECTION_DIALOGS.md +146 -0
- package/SERVICE_IMPLEMENTATION_REPORT.md +462 -0
- package/dist/adapters/index.d.ts +7 -8
- package/dist/adapters/index.js +7 -9
- package/dist/backups/operations/bucketBackup.js +2 -2
- package/dist/backups/operations/collectionBackup.d.ts +1 -1
- package/dist/backups/operations/collectionBackup.js +3 -3
- package/dist/backups/operations/comprehensiveBackup.d.ts +1 -1
- package/dist/backups/operations/comprehensiveBackup.js +2 -2
- package/dist/backups/tracking/centralizedTracking.d.ts +1 -1
- package/dist/backups/tracking/centralizedTracking.js +2 -2
- package/dist/cli/commands/configCommands.js +51 -7
- package/dist/cli/commands/databaseCommands.d.ts +1 -0
- package/dist/cli/commands/databaseCommands.js +119 -9
- package/dist/cli/commands/functionCommands.js +3 -3
- package/dist/cli/commands/importFileCommands.d.ts +7 -0
- package/dist/cli/commands/importFileCommands.js +674 -0
- package/dist/cli/commands/schemaCommands.js +3 -3
- package/dist/cli/commands/storageCommands.js +2 -3
- package/dist/cli/commands/transferCommands.js +3 -5
- package/dist/collections/attributes.d.ts +1 -1
- package/dist/collections/attributes.js +2 -35
- package/dist/collections/indexes.js +1 -3
- package/dist/collections/methods.d.ts +1 -1
- package/dist/collections/methods.js +111 -192
- package/dist/collections/tableOperations.d.ts +1 -0
- package/dist/collections/tableOperations.js +55 -23
- package/dist/collections/transferOperations.d.ts +1 -1
- package/dist/collections/transferOperations.js +3 -4
- package/dist/collections/wipeOperations.d.ts +4 -3
- package/dist/collections/wipeOperations.js +112 -39
- package/dist/databases/methods.js +2 -2
- package/dist/databases/setup.js +2 -2
- package/dist/examples/yamlTerminologyExample.js +2 -2
- package/dist/functions/deployments.d.ts +1 -1
- package/dist/functions/deployments.js +5 -5
- package/dist/functions/fnConfigDiscovery.js +2 -2
- package/dist/functions/methods.js +16 -4
- package/dist/init.js +1 -1
- package/dist/interactiveCLI.d.ts +6 -1
- package/dist/interactiveCLI.js +63 -9
- package/dist/main.js +130 -177
- package/dist/migrations/afterImportActions.js +2 -3
- package/dist/migrations/appwriteToX.d.ts +1 -1
- package/dist/migrations/appwriteToX.js +9 -7
- package/dist/migrations/comprehensiveTransfer.js +3 -5
- package/dist/migrations/dataLoader.js +2 -5
- package/dist/migrations/importController.js +3 -4
- package/dist/migrations/importDataActions.js +3 -3
- package/dist/migrations/relationships.js +1 -2
- package/dist/migrations/services/DataTransformationService.js +2 -2
- package/dist/migrations/services/FileHandlerService.js +1 -1
- package/dist/migrations/services/ImportOrchestrator.js +4 -4
- package/dist/migrations/services/RateLimitManager.js +1 -1
- package/dist/migrations/services/RelationshipResolver.js +1 -1
- package/dist/migrations/services/UserMappingService.js +1 -1
- package/dist/migrations/services/ValidationService.js +1 -1
- package/dist/migrations/transfer.d.ts +8 -4
- package/dist/migrations/transfer.js +106 -55
- package/dist/migrations/yaml/YamlImportConfigLoader.js +1 -1
- package/dist/migrations/yaml/YamlImportIntegration.js +2 -2
- package/dist/migrations/yaml/generateImportSchemas.js +1 -1
- package/dist/setupCommands.d.ts +1 -1
- package/dist/setupCommands.js +5 -6
- package/dist/setupController.js +1 -1
- package/dist/shared/backupTracking.d.ts +1 -1
- package/dist/shared/backupTracking.js +2 -2
- package/dist/shared/confirmationDialogs.js +1 -1
- package/dist/shared/migrationHelpers.d.ts +1 -1
- package/dist/shared/migrationHelpers.js +3 -3
- package/dist/shared/operationQueue.d.ts +1 -1
- package/dist/shared/operationQueue.js +2 -3
- package/dist/shared/operationsTable.d.ts +1 -1
- package/dist/shared/operationsTable.js +2 -2
- package/dist/shared/progressManager.js +1 -1
- package/dist/shared/selectionDialogs.js +9 -8
- package/dist/storage/methods.js +4 -4
- package/dist/storage/schemas.d.ts +2 -2
- package/dist/tables/indexManager.d.ts +65 -0
- package/dist/tables/indexManager.js +294 -0
- package/dist/types.d.ts +2 -2
- package/dist/types.js +1 -1
- package/dist/users/methods.js +2 -3
- package/dist/utils/configMigration.js +1 -1
- package/dist/utils/index.d.ts +1 -1
- package/dist/utils/index.js +1 -1
- package/dist/utils/loadConfigs.d.ts +2 -2
- package/dist/utils/loadConfigs.js +6 -7
- package/dist/utils/setupFiles.js +5 -7
- package/dist/utilsController.d.ts +15 -8
- package/dist/utilsController.js +57 -28
- package/package.json +7 -3
- package/src/adapters/index.ts +8 -34
- package/src/backups/operations/bucketBackup.ts +2 -2
- package/src/backups/operations/collectionBackup.ts +4 -4
- package/src/backups/operations/comprehensiveBackup.ts +3 -3
- package/src/backups/tracking/centralizedTracking.ts +3 -3
- package/src/cli/commands/configCommands.ts +72 -8
- package/src/cli/commands/databaseCommands.ts +161 -9
- package/src/cli/commands/functionCommands.ts +4 -3
- package/src/cli/commands/importFileCommands.ts +815 -0
- package/src/cli/commands/schemaCommands.ts +3 -3
- package/src/cli/commands/storageCommands.ts +2 -3
- package/src/cli/commands/transferCommands.ts +3 -6
- package/src/collections/attributes.ts +3 -39
- package/src/collections/indexes.ts +2 -4
- package/src/collections/methods.ts +115 -150
- package/src/collections/tableOperations.ts +57 -21
- package/src/collections/transferOperations.ts +4 -5
- package/src/collections/wipeOperations.ts +154 -51
- package/src/databases/methods.ts +2 -2
- package/src/databases/setup.ts +2 -2
- package/src/examples/yamlTerminologyExample.ts +2 -2
- package/src/functions/deployments.ts +6 -5
- package/src/functions/fnConfigDiscovery.ts +2 -2
- package/src/functions/methods.ts +17 -4
- package/src/init.ts +1 -1
- package/src/interactiveCLI.ts +75 -10
- package/src/main.ts +143 -287
- package/src/migrations/afterImportActions.ts +2 -3
- package/src/migrations/appwriteToX.ts +12 -8
- package/src/migrations/comprehensiveTransfer.ts +6 -6
- package/src/migrations/dataLoader.ts +2 -5
- package/src/migrations/importController.ts +3 -4
- package/src/migrations/importDataActions.ts +3 -3
- package/src/migrations/relationships.ts +1 -2
- package/src/migrations/services/DataTransformationService.ts +2 -2
- package/src/migrations/services/FileHandlerService.ts +1 -1
- package/src/migrations/services/ImportOrchestrator.ts +4 -4
- package/src/migrations/services/RateLimitManager.ts +1 -1
- package/src/migrations/services/RelationshipResolver.ts +1 -1
- package/src/migrations/services/UserMappingService.ts +1 -1
- package/src/migrations/services/ValidationService.ts +1 -1
- package/src/migrations/transfer.ts +126 -83
- package/src/migrations/yaml/YamlImportConfigLoader.ts +1 -1
- package/src/migrations/yaml/YamlImportIntegration.ts +2 -2
- package/src/migrations/yaml/generateImportSchemas.ts +1 -1
- package/src/setupCommands.ts +5 -6
- package/src/setupController.ts +1 -1
- package/src/shared/backupTracking.ts +3 -3
- package/src/shared/confirmationDialogs.ts +1 -1
- package/src/shared/migrationHelpers.ts +4 -4
- package/src/shared/operationQueue.ts +3 -4
- package/src/shared/operationsTable.ts +3 -3
- package/src/shared/progressManager.ts +1 -1
- package/src/shared/selectionDialogs.ts +9 -8
- package/src/storage/methods.ts +4 -4
- package/src/tables/indexManager.ts +409 -0
- package/src/types.ts +2 -2
- package/src/users/methods.ts +2 -3
- package/src/utils/configMigration.ts +1 -1
- package/src/utils/index.ts +1 -1
- package/src/utils/loadConfigs.ts +15 -7
- package/src/utils/setupFiles.ts +5 -7
- package/src/utilsController.ts +86 -32
- package/dist/adapters/AdapterFactory.d.ts +0 -94
- package/dist/adapters/AdapterFactory.js +0 -405
- package/dist/adapters/DatabaseAdapter.d.ts +0 -233
- package/dist/adapters/DatabaseAdapter.js +0 -50
- package/dist/adapters/LegacyAdapter.d.ts +0 -50
- package/dist/adapters/LegacyAdapter.js +0 -612
- package/dist/adapters/TablesDBAdapter.d.ts +0 -45
- package/dist/adapters/TablesDBAdapter.js +0 -571
- package/dist/config/ConfigManager.d.ts +0 -445
- package/dist/config/ConfigManager.js +0 -625
- package/dist/config/configMigration.d.ts +0 -87
- package/dist/config/configMigration.js +0 -390
- package/dist/config/configValidation.d.ts +0 -66
- package/dist/config/configValidation.js +0 -358
- package/dist/config/index.d.ts +0 -8
- package/dist/config/index.js +0 -7
- package/dist/config/services/ConfigDiscoveryService.d.ts +0 -126
- package/dist/config/services/ConfigDiscoveryService.js +0 -374
- package/dist/config/services/ConfigLoaderService.d.ts +0 -129
- package/dist/config/services/ConfigLoaderService.js +0 -540
- package/dist/config/services/ConfigMergeService.d.ts +0 -208
- package/dist/config/services/ConfigMergeService.js +0 -308
- package/dist/config/services/ConfigValidationService.d.ts +0 -214
- package/dist/config/services/ConfigValidationService.js +0 -310
- package/dist/config/services/SessionAuthService.d.ts +0 -225
- package/dist/config/services/SessionAuthService.js +0 -456
- package/dist/config/services/__tests__/ConfigMergeService.test.d.ts +0 -1
- package/dist/config/services/__tests__/ConfigMergeService.test.js +0 -271
- package/dist/config/services/index.d.ts +0 -13
- package/dist/config/services/index.js +0 -10
- package/dist/config/yamlConfig.d.ts +0 -722
- package/dist/config/yamlConfig.js +0 -702
- package/dist/functions/pathResolution.d.ts +0 -37
- package/dist/functions/pathResolution.js +0 -185
- package/dist/shared/attributeMapper.d.ts +0 -20
- package/dist/shared/attributeMapper.js +0 -203
- package/dist/shared/errorUtils.d.ts +0 -54
- package/dist/shared/errorUtils.js +0 -95
- package/dist/shared/functionManager.d.ts +0 -48
- package/dist/shared/functionManager.js +0 -336
- package/dist/shared/indexManager.d.ts +0 -24
- package/dist/shared/indexManager.js +0 -151
- package/dist/shared/jsonSchemaGenerator.d.ts +0 -50
- package/dist/shared/jsonSchemaGenerator.js +0 -290
- package/dist/shared/logging.d.ts +0 -61
- package/dist/shared/logging.js +0 -116
- package/dist/shared/messageFormatter.d.ts +0 -39
- package/dist/shared/messageFormatter.js +0 -162
- package/dist/shared/pydanticModelGenerator.d.ts +0 -17
- package/dist/shared/pydanticModelGenerator.js +0 -615
- package/dist/shared/schemaGenerator.d.ts +0 -40
- package/dist/shared/schemaGenerator.js +0 -556
- package/dist/utils/ClientFactory.d.ts +0 -87
- package/dist/utils/ClientFactory.js +0 -212
- package/dist/utils/configDiscovery.d.ts +0 -78
- package/dist/utils/configDiscovery.js +0 -472
- package/dist/utils/constantsGenerator.d.ts +0 -31
- package/dist/utils/constantsGenerator.js +0 -321
- package/dist/utils/dataConverters.d.ts +0 -46
- package/dist/utils/dataConverters.js +0 -139
- package/dist/utils/directoryUtils.d.ts +0 -22
- package/dist/utils/directoryUtils.js +0 -59
- package/dist/utils/getClientFromConfig.d.ts +0 -39
- package/dist/utils/getClientFromConfig.js +0 -199
- package/dist/utils/helperFunctions.d.ts +0 -63
- package/dist/utils/helperFunctions.js +0 -156
- package/dist/utils/pathResolvers.d.ts +0 -53
- package/dist/utils/pathResolvers.js +0 -72
- package/dist/utils/projectConfig.d.ts +0 -119
- package/dist/utils/projectConfig.js +0 -171
- package/dist/utils/retryFailedPromises.d.ts +0 -2
- package/dist/utils/retryFailedPromises.js +0 -23
- package/dist/utils/sessionAuth.d.ts +0 -48
- package/dist/utils/sessionAuth.js +0 -164
- package/dist/utils/typeGuards.d.ts +0 -35
- package/dist/utils/typeGuards.js +0 -57
- package/dist/utils/validationRules.d.ts +0 -43
- package/dist/utils/validationRules.js +0 -42
- package/dist/utils/versionDetection.d.ts +0 -58
- package/dist/utils/versionDetection.js +0 -251
- package/dist/utils/yamlConverter.d.ts +0 -100
- package/dist/utils/yamlConverter.js +0 -428
- package/dist/utils/yamlLoader.d.ts +0 -70
- package/dist/utils/yamlLoader.js +0 -267
- package/src/adapters/AdapterFactory.ts +0 -510
- package/src/adapters/DatabaseAdapter.ts +0 -306
- package/src/adapters/LegacyAdapter.ts +0 -841
- package/src/adapters/TablesDBAdapter.ts +0 -773
- package/src/config/ConfigManager.ts +0 -808
- package/src/config/README.md +0 -274
- package/src/config/configMigration.ts +0 -575
- package/src/config/configValidation.ts +0 -445
- package/src/config/index.ts +0 -10
- package/src/config/services/ConfigDiscoveryService.ts +0 -463
- package/src/config/services/ConfigLoaderService.ts +0 -740
- package/src/config/services/ConfigMergeService.ts +0 -388
- package/src/config/services/ConfigValidationService.ts +0 -394
- package/src/config/services/SessionAuthService.ts +0 -565
- package/src/config/services/__tests__/ConfigMergeService.test.ts +0 -351
- package/src/config/services/index.ts +0 -29
- package/src/config/yamlConfig.ts +0 -761
- package/src/functions/pathResolution.ts +0 -227
- package/src/shared/attributeMapper.ts +0 -229
- package/src/shared/errorUtils.ts +0 -110
- package/src/shared/functionManager.ts +0 -525
- package/src/shared/indexManager.ts +0 -254
- package/src/shared/jsonSchemaGenerator.ts +0 -383
- package/src/shared/logging.ts +0 -149
- package/src/shared/messageFormatter.ts +0 -208
- package/src/shared/pydanticModelGenerator.ts +0 -618
- package/src/shared/schemaGenerator.ts +0 -644
- package/src/utils/ClientFactory.ts +0 -240
- package/src/utils/configDiscovery.ts +0 -557
- package/src/utils/constantsGenerator.ts +0 -369
- package/src/utils/dataConverters.ts +0 -159
- package/src/utils/directoryUtils.ts +0 -61
- package/src/utils/getClientFromConfig.ts +0 -257
- package/src/utils/helperFunctions.ts +0 -228
- package/src/utils/pathResolvers.ts +0 -81
- package/src/utils/projectConfig.ts +0 -299
- package/src/utils/retryFailedPromises.ts +0 -29
- package/src/utils/sessionAuth.ts +0 -230
- package/src/utils/typeGuards.ts +0 -65
- package/src/utils/validationRules.ts +0 -88
- package/src/utils/versionDetection.ts +0 -292
- package/src/utils/yamlConverter.ts +0 -542
- package/src/utils/yamlLoader.ts +0 -371
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { mapToCreateAttributeParams, mapToUpdateAttributeParams } from "
|
|
1
|
+
import { mapToCreateAttributeParams, mapToUpdateAttributeParams } from "@njdamstra/appwrite-utils-helpers";
|
|
2
2
|
import { Decimal } from "decimal.js";
|
|
3
3
|
const EXTREME_BOUND = new Decimal('1e12');
|
|
4
4
|
// Property configuration for different column types
|
|
@@ -90,11 +90,13 @@ export function normalizeAttributeToComparable(attr) {
|
|
|
90
90
|
return base;
|
|
91
91
|
}
|
|
92
92
|
export function normalizeColumnToComparable(col) {
|
|
93
|
-
// Detect enum surfaced as string+elements from server and normalize to enum for comparison
|
|
93
|
+
// Detect enum surfaced as string+elements or string+format:enum from server and normalize to enum for comparison
|
|
94
94
|
let t = String((col?.type ?? col?.columnType ?? '')).toLowerCase();
|
|
95
95
|
const hasElements = Array.isArray(col?.elements) && col.elements.length > 0;
|
|
96
|
-
|
|
96
|
+
const hasEnumFormat = (col?.format === 'enum');
|
|
97
|
+
if (t === 'string' && (hasElements || hasEnumFormat)) {
|
|
97
98
|
t = 'enum';
|
|
99
|
+
}
|
|
98
100
|
const base = {
|
|
99
101
|
key: col?.key,
|
|
100
102
|
type: t,
|
|
@@ -185,18 +187,27 @@ export function isIndexEqualToIndex(a, b) {
|
|
|
185
187
|
if (String(a.type).toLowerCase() !== String(b.type).toLowerCase())
|
|
186
188
|
return false;
|
|
187
189
|
// Compare attributes as sets (order-insensitive)
|
|
188
|
-
|
|
189
|
-
const
|
|
190
|
+
// Support TablesDB which returns 'columns' instead of 'attributes'
|
|
191
|
+
const attrsAraw = Array.isArray(a.attributes)
|
|
192
|
+
? a.attributes
|
|
193
|
+
: (Array.isArray(a.columns) ? a.columns : []);
|
|
194
|
+
const attrsA = [...attrsAraw].sort();
|
|
195
|
+
const attrsB = Array.isArray(b.attributes)
|
|
196
|
+
? [...b.attributes].sort()
|
|
197
|
+
: (Array.isArray(b.columns) ? [...b.columns].sort() : []);
|
|
190
198
|
if (attrsA.length !== attrsB.length)
|
|
191
199
|
return false;
|
|
192
200
|
for (let i = 0; i < attrsA.length; i++)
|
|
193
201
|
if (attrsA[i] !== attrsB[i])
|
|
194
202
|
return false;
|
|
195
|
-
// Orders are only considered if
|
|
196
|
-
|
|
197
|
-
const
|
|
198
|
-
if (
|
|
199
|
-
|
|
203
|
+
// Orders are only considered if CONFIG (b) has orders defined
|
|
204
|
+
// This prevents false positives when Appwrite returns orders but user didn't specify them
|
|
205
|
+
const hasConfigOrders = Array.isArray(b.orders) && b.orders.length > 0;
|
|
206
|
+
if (hasConfigOrders) {
|
|
207
|
+
// Some APIs may expose 'directions' instead of 'orders'
|
|
208
|
+
const ordersA = Array.isArray(a.orders)
|
|
209
|
+
? [...a.orders].sort()
|
|
210
|
+
: (Array.isArray(a.directions) ? [...a.directions].sort() : []);
|
|
200
211
|
const ordersB = [...b.orders].sort();
|
|
201
212
|
if (ordersA.length !== ordersB.length)
|
|
202
213
|
return false;
|
|
@@ -204,7 +215,6 @@ export function isIndexEqualToIndex(a, b) {
|
|
|
204
215
|
if (ordersA[i] !== ordersB[i])
|
|
205
216
|
return false;
|
|
206
217
|
}
|
|
207
|
-
// If only one side has orders, treat as equal (orders unspecified by user)
|
|
208
218
|
return true;
|
|
209
219
|
}
|
|
210
220
|
/**
|
|
@@ -213,6 +223,7 @@ export function isIndexEqualToIndex(a, b) {
|
|
|
213
223
|
function compareColumnProperties(oldColumn, newAttribute, columnType) {
|
|
214
224
|
const changes = [];
|
|
215
225
|
const t = String(columnType || newAttribute.type || '').toLowerCase();
|
|
226
|
+
const key = newAttribute?.key || 'unknown';
|
|
216
227
|
const mutableProps = MUTABLE_PROPERTIES[t] || [];
|
|
217
228
|
const immutableProps = IMMUTABLE_PROPERTIES[t] || [];
|
|
218
229
|
const getNewVal = (prop) => {
|
|
@@ -233,8 +244,9 @@ function compareColumnProperties(oldColumn, newAttribute, columnType) {
|
|
|
233
244
|
let newValue = getNewVal(prop);
|
|
234
245
|
// Special-case: enum elements empty/missing should not trigger updates
|
|
235
246
|
if (t === 'enum' && prop === 'elements') {
|
|
236
|
-
if (!Array.isArray(newValue) || newValue.length === 0)
|
|
247
|
+
if (!Array.isArray(newValue) || newValue.length === 0) {
|
|
237
248
|
newValue = oldValue;
|
|
249
|
+
}
|
|
238
250
|
}
|
|
239
251
|
if (Array.isArray(oldValue) && Array.isArray(newValue)) {
|
|
240
252
|
if (oldValue.length !== newValue.length || oldValue.some((v, i) => v !== newValue[i])) {
|
|
@@ -260,7 +272,8 @@ function compareColumnProperties(oldColumn, newAttribute, columnType) {
|
|
|
260
272
|
// Type change requires recreate (normalize string+elements to enum on old side)
|
|
261
273
|
const oldTypeRaw = String(oldColumn?.type || oldColumn?.columnType || '').toLowerCase();
|
|
262
274
|
const oldHasElements = Array.isArray(oldColumn?.elements) && oldColumn.elements.length > 0;
|
|
263
|
-
const
|
|
275
|
+
const oldHasEnumFormat = (oldColumn?.format === 'enum');
|
|
276
|
+
const oldType = oldTypeRaw === 'string' && (oldHasElements || oldHasEnumFormat) ? 'enum' : oldTypeRaw;
|
|
264
277
|
if (oldType && t && oldType !== t && TYPE_CHANGE_REQUIRES_RECREATE.includes(oldType)) {
|
|
265
278
|
changes.push({ property: 'type', oldValue: oldType, newValue: t, requiresRecreate: true });
|
|
266
279
|
}
|
|
@@ -299,29 +312,48 @@ function analyzeColumnChanges(oldColumn, newAttribute) {
|
|
|
299
312
|
/**
|
|
300
313
|
* Enhanced version of columns diff with detailed change analysis
|
|
301
314
|
* Order: desired first, then existing (matches internal usage here)
|
|
315
|
+
* Handles case-insensitive key matches as renames (recreates)
|
|
302
316
|
*/
|
|
303
317
|
export function diffColumnsDetailed(desiredAttributes, existingColumns) {
|
|
318
|
+
// Exact key lookup (case-sensitive)
|
|
304
319
|
const byKey = new Map((existingColumns || []).map((col) => [col?.key, col]));
|
|
320
|
+
// Case-insensitive key lookup for detecting renames
|
|
321
|
+
const byKeyLower = new Map((existingColumns || []).map((col) => [col?.key?.toLowerCase(), col]));
|
|
305
322
|
const toCreate = [];
|
|
306
323
|
const toUpdate = [];
|
|
307
324
|
const toRecreate = [];
|
|
308
325
|
const unchanged = [];
|
|
326
|
+
const handledExistingKeys = new Set(); // Track which existing columns we've handled
|
|
309
327
|
for (const attr of desiredAttributes || []) {
|
|
310
328
|
const key = attr?.key;
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
329
|
+
if (!key)
|
|
330
|
+
continue;
|
|
331
|
+
// First try exact match
|
|
332
|
+
const exactMatch = byKey.get(key);
|
|
333
|
+
if (exactMatch) {
|
|
334
|
+
handledExistingKeys.add(key);
|
|
335
|
+
const analysis = analyzeColumnChanges(exactMatch, attr);
|
|
336
|
+
if (!analysis.hasChanges)
|
|
337
|
+
unchanged.push(analysis.columnKey);
|
|
338
|
+
else if (analysis.requiresRecreate)
|
|
339
|
+
toRecreate.push({ oldAttribute: exactMatch, newAttribute: attr });
|
|
340
|
+
else
|
|
341
|
+
toUpdate.push({ attribute: attr, changes: analysis.changes });
|
|
314
342
|
continue;
|
|
315
343
|
}
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
344
|
+
// Check for case-insensitive match (rename scenario like oAuthAccounts -> oauthAccounts)
|
|
345
|
+
const caseInsensitiveMatch = byKeyLower.get(key.toLowerCase());
|
|
346
|
+
if (caseInsensitiveMatch && caseInsensitiveMatch.key !== key) {
|
|
347
|
+
// This is a rename - treat as recreate (delete old, create new)
|
|
348
|
+
handledExistingKeys.add(caseInsensitiveMatch.key);
|
|
349
|
+
toRecreate.push({ oldAttribute: caseInsensitiveMatch, newAttribute: attr });
|
|
350
|
+
continue;
|
|
351
|
+
}
|
|
352
|
+
// No match - it's a new attribute
|
|
353
|
+
toCreate.push(attr);
|
|
323
354
|
}
|
|
324
355
|
// Note: we keep toDelete empty for now (conservative behavior)
|
|
356
|
+
// Deletions are handled separately in methods.ts
|
|
325
357
|
return { toCreate, toUpdate, toRecreate, toDelete: [], unchanged };
|
|
326
358
|
}
|
|
327
359
|
/**
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Databases } from "node-appwrite";
|
|
2
|
-
import type { DatabaseAdapter } from "
|
|
2
|
+
import type { DatabaseAdapter } from "@njdamstra/appwrite-utils-helpers";
|
|
3
3
|
/**
|
|
4
4
|
* Transfers all documents from one collection to another in a different database
|
|
5
5
|
* within the same Appwrite Project
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import { Client, Databases, ID, Query, } from "node-appwrite";
|
|
2
|
-
import { tryAwaitWithRetry, delay, calculateExponentialBackoff } from "
|
|
3
|
-
import { MessageFormatter } from "../shared/messageFormatter.js";
|
|
2
|
+
import { tryAwaitWithRetry, delay, calculateExponentialBackoff, MessageFormatter } from "@njdamstra/appwrite-utils-helpers";
|
|
4
3
|
import { chunk } from "es-toolkit";
|
|
5
|
-
import { isLegacyDatabases } from "
|
|
6
|
-
import { getAdapter } from "
|
|
4
|
+
import { isLegacyDatabases } from "@njdamstra/appwrite-utils-helpers";
|
|
5
|
+
import { getAdapter } from "@njdamstra/appwrite-utils-helpers";
|
|
7
6
|
/**
|
|
8
7
|
* Transfers all documents from one collection to another in a different database
|
|
9
8
|
* within the same Appwrite Project
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Databases } from "node-appwrite";
|
|
2
|
-
import type { DatabaseAdapter } from "
|
|
2
|
+
import type { DatabaseAdapter } from "@njdamstra/appwrite-utils-helpers";
|
|
3
3
|
export declare const wipeDatabase: (database: Databases, databaseId: string) => Promise<{
|
|
4
4
|
collectionId: string;
|
|
5
5
|
collectionName: string;
|
|
@@ -10,7 +10,8 @@ export declare const wipeAllTables: (adapter: DatabaseAdapter, databaseId: strin
|
|
|
10
10
|
tableName: string;
|
|
11
11
|
}[]>;
|
|
12
12
|
/**
|
|
13
|
-
* Optimized deletion of all rows from a table
|
|
14
|
-
* Uses
|
|
13
|
+
* Optimized deletion of all rows from a table.
|
|
14
|
+
* Uses bulk deletion when possible, but falls back to individual row deletion
|
|
15
|
+
* for tables with relationship columns (bulk delete not supported for those).
|
|
15
16
|
*/
|
|
16
17
|
export declare const wipeTableRows: (adapter: DatabaseAdapter, databaseId: string, tableId: string) => Promise<void>;
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import { Databases, Query, } from "node-appwrite";
|
|
2
|
-
import { tryAwaitWithRetry } from "
|
|
3
|
-
import { MessageFormatter } from "
|
|
2
|
+
import { tryAwaitWithRetry } from "@njdamstra/appwrite-utils-helpers";
|
|
3
|
+
import { MessageFormatter, isRetryableError, isCriticalError } from "@njdamstra/appwrite-utils-helpers";
|
|
4
4
|
import { ProgressManager } from "../shared/progressManager.js";
|
|
5
|
-
import {
|
|
6
|
-
import { delay } from "../utils/helperFunctions.js";
|
|
5
|
+
import { delay } from "@njdamstra/appwrite-utils-helpers";
|
|
7
6
|
import { chunk } from "es-toolkit";
|
|
8
7
|
import pLimit from "p-limit";
|
|
9
8
|
import { fetchAllCollections } from "./methods.js";
|
|
@@ -167,52 +166,126 @@ export const wipeAllTables = async (adapter, databaseId) => {
|
|
|
167
166
|
return deleted;
|
|
168
167
|
};
|
|
169
168
|
/**
|
|
170
|
-
* Optimized deletion of all rows from a table
|
|
171
|
-
* Uses
|
|
169
|
+
* Optimized deletion of all rows from a table.
|
|
170
|
+
* Uses bulk deletion when possible, but falls back to individual row deletion
|
|
171
|
+
* for tables with relationship columns (bulk delete not supported for those).
|
|
172
172
|
*/
|
|
173
173
|
export const wipeTableRows = async (adapter, databaseId, tableId) => {
|
|
174
174
|
try {
|
|
175
|
-
// Check if bulk
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
const DELETE_BATCH_SIZE = 250; // How many rows to delete per batch
|
|
175
|
+
// Check if the table has relationship columns — bulk delete is not supported for those
|
|
176
|
+
const tableInfo = await adapter.getTable({ databaseId, tableId });
|
|
177
|
+
const columns = tableInfo.data?.columns || [];
|
|
178
|
+
const hasRelationships = columns.some((col) => col.type === "relationship");
|
|
179
|
+
const DELETE_BATCH_SIZE = 250;
|
|
181
180
|
let totalDeleted = 0;
|
|
182
181
|
let hasMoreRows = true;
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
const
|
|
196
|
-
|
|
182
|
+
const progress = ProgressManager.create(`delete-${tableId}`, 1, { title: "Deleting table rows" });
|
|
183
|
+
if (hasRelationships) {
|
|
184
|
+
// ── Relationship table: fetch rows then delete individually ──
|
|
185
|
+
MessageFormatter.info("Table has relationship columns — using individual row deletion (bulk delete not supported)", { prefix: "Wipe" });
|
|
186
|
+
const FETCH_BATCH_SIZE = 1000;
|
|
187
|
+
const MAX_CONCURRENT_DELETES = 25;
|
|
188
|
+
const limit = pLimit(MAX_CONCURRENT_DELETES);
|
|
189
|
+
// Pipeline: prefetch the first batch, then overlap fetch+delete
|
|
190
|
+
let pendingRows = [];
|
|
191
|
+
let totalDiscovered = 0;
|
|
192
|
+
// Fetch helper — always fetches from the top since we're deleting everything
|
|
193
|
+
const fetchBatch = async () => {
|
|
194
|
+
const queries = [Query.limit(FETCH_BATCH_SIZE)];
|
|
195
|
+
const response = await tryAwaitWithRetry(async () => adapter.listRows({ databaseId, tableId, queries }));
|
|
196
|
+
return response.rows || response.data || [];
|
|
197
|
+
};
|
|
198
|
+
// Kick off the first fetch
|
|
199
|
+
let nextFetchPromise = fetchBatch();
|
|
200
|
+
while (hasMoreRows) {
|
|
201
|
+
// Await the prefetched batch
|
|
202
|
+
const rows = nextFetchPromise ? await nextFetchPromise : [];
|
|
203
|
+
nextFetchPromise = null;
|
|
204
|
+
if (rows.length === 0) {
|
|
197
205
|
hasMoreRows = false;
|
|
198
206
|
break;
|
|
199
207
|
}
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
208
|
+
totalDiscovered += rows.length;
|
|
209
|
+
const isLastBatch = rows.length < FETCH_BATCH_SIZE;
|
|
210
|
+
if (!isLastBatch) {
|
|
211
|
+
progress.setTotal(totalDiscovered + 1000);
|
|
212
|
+
}
|
|
213
|
+
else {
|
|
214
|
+
progress.setTotal(totalDiscovered);
|
|
215
|
+
}
|
|
216
|
+
MessageFormatter.progress(`Fetched ${rows.length} rows (${totalDiscovered} discovered, ${totalDeleted} deleted so far)`, { prefix: "Wipe" });
|
|
217
|
+
// Start deleting this batch — and prefetch the next one concurrently
|
|
218
|
+
// (only prefetch if we expect more rows)
|
|
219
|
+
if (!isLastBatch) {
|
|
220
|
+
// Wait a moment before prefetching so the first few deletes free up API capacity
|
|
221
|
+
nextFetchPromise = delay(200).then(() => fetchBatch());
|
|
222
|
+
}
|
|
223
|
+
// Delete each row with concurrency limit
|
|
224
|
+
const deletePromises = rows.map((row) => limit(async () => {
|
|
225
|
+
try {
|
|
226
|
+
await tryAwaitWithRetry(async () => adapter.deleteRow({ databaseId, tableId, id: row.$id }));
|
|
227
|
+
totalDeleted++;
|
|
228
|
+
progress.update(totalDeleted);
|
|
229
|
+
}
|
|
230
|
+
catch (error) {
|
|
231
|
+
const errorMessage = error.message || String(error);
|
|
232
|
+
if (errorMessage.includes("could not be found")) {
|
|
233
|
+
totalDeleted++;
|
|
234
|
+
progress.update(totalDeleted);
|
|
235
|
+
}
|
|
236
|
+
else if (isCriticalError(errorMessage)) {
|
|
237
|
+
MessageFormatter.error(`Critical error deleting row ${row.$id}: ${errorMessage}`, error, { prefix: "Wipe" });
|
|
238
|
+
throw error;
|
|
239
|
+
}
|
|
240
|
+
else {
|
|
241
|
+
MessageFormatter.error(`Failed to delete row ${row.$id}: ${errorMessage}`, error, { prefix: "Wipe" });
|
|
242
|
+
totalDeleted++;
|
|
243
|
+
progress.update(totalDeleted);
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
}));
|
|
247
|
+
await Promise.all(deletePromises);
|
|
248
|
+
if (isLastBatch) {
|
|
249
|
+
hasMoreRows = false;
|
|
250
|
+
}
|
|
205
251
|
await delay(10);
|
|
206
252
|
}
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
253
|
+
}
|
|
254
|
+
else {
|
|
255
|
+
// ── No relationships: use fast bulk deletion ──
|
|
256
|
+
if (!adapter.bulkDeleteRows) {
|
|
257
|
+
MessageFormatter.error("Bulk deletion not available for this adapter - wipe operation not supported", new Error("bulkDeleteRows not available"), { prefix: "Wipe" });
|
|
258
|
+
throw new Error("Bulk deletion required for wipe operations");
|
|
259
|
+
}
|
|
260
|
+
MessageFormatter.info("Starting optimized table row deletion...", { prefix: "Wipe" });
|
|
261
|
+
while (hasMoreRows) {
|
|
262
|
+
try {
|
|
263
|
+
const result = await tryAwaitWithRetry(async () => adapter.bulkDeleteRows({
|
|
264
|
+
databaseId,
|
|
265
|
+
tableId,
|
|
266
|
+
rowIds: [],
|
|
267
|
+
batchSize: DELETE_BATCH_SIZE
|
|
268
|
+
}));
|
|
269
|
+
const deletedCount = result.total || 0;
|
|
270
|
+
if (deletedCount === 0) {
|
|
271
|
+
hasMoreRows = false;
|
|
272
|
+
break;
|
|
273
|
+
}
|
|
274
|
+
totalDeleted += deletedCount;
|
|
275
|
+
progress.setTotal(totalDeleted + 100);
|
|
276
|
+
progress.update(totalDeleted);
|
|
277
|
+
MessageFormatter.progress(`Deleted ${deletedCount} rows (${totalDeleted} total so far)`, { prefix: "Wipe" });
|
|
278
|
+
await delay(10);
|
|
212
279
|
}
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
280
|
+
catch (error) {
|
|
281
|
+
const errorMessage = error.message || String(error);
|
|
282
|
+
if (isCriticalError(errorMessage)) {
|
|
283
|
+
MessageFormatter.error(`Critical error during bulk deletion: ${errorMessage}`, error, { prefix: "Wipe" });
|
|
284
|
+
throw error;
|
|
285
|
+
}
|
|
286
|
+
else {
|
|
287
|
+
MessageFormatter.error(`Error during deletion batch: ${errorMessage}`, error, { prefix: "Wipe" });
|
|
288
|
+
}
|
|
216
289
|
}
|
|
217
290
|
}
|
|
218
291
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Databases, Query } from "node-appwrite";
|
|
2
|
-
import { delay, tryAwaitWithRetry } from "
|
|
2
|
+
import { delay, tryAwaitWithRetry } from "@njdamstra/appwrite-utils-helpers";
|
|
3
3
|
import { fetchAllCollections } from "../collections/methods.js";
|
|
4
|
-
import { MessageFormatter } from "
|
|
4
|
+
import { MessageFormatter } from "@njdamstra/appwrite-utils-helpers";
|
|
5
5
|
export const fetchAllDatabases = async (database) => {
|
|
6
6
|
const databases = await tryAwaitWithRetry(async () => await database.list([Query.limit(25)]));
|
|
7
7
|
const allDatabases = databases.databases;
|
package/dist/databases/setup.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { Databases, Query } from "node-appwrite";
|
|
2
|
-
import { tryAwaitWithRetry } from "
|
|
2
|
+
import { tryAwaitWithRetry } from "@njdamstra/appwrite-utils-helpers";
|
|
3
3
|
import {} from "@njdamstra/appwrite-utils";
|
|
4
4
|
import { ulid } from "ulidx";
|
|
5
|
-
import { MessageFormatter } from "
|
|
5
|
+
import { MessageFormatter } from "@njdamstra/appwrite-utils-helpers";
|
|
6
6
|
export const ensureDatabasesExist = async (config, databasesToEnsure) => {
|
|
7
7
|
if (!config.appwriteClient) {
|
|
8
8
|
throw new Error("Appwrite client is not initialized in the config");
|
|
@@ -7,8 +7,8 @@
|
|
|
7
7
|
* 3. Validate terminology consistency
|
|
8
8
|
* 4. Migrate between formats
|
|
9
9
|
*/
|
|
10
|
-
import { collectionToYaml, generateYamlTemplate, generateExampleYamls, convertTerminology, normalizeYamlData, usesTableTerminology } from "
|
|
11
|
-
import { createYamlLoader } from "
|
|
10
|
+
import { collectionToYaml, generateYamlTemplate, generateExampleYamls, convertTerminology, normalizeYamlData, usesTableTerminology } from "@njdamstra/appwrite-utils-helpers";
|
|
11
|
+
import { createYamlLoader } from "@njdamstra/appwrite-utils-helpers";
|
|
12
12
|
import { YamlImportIntegration } from "../migrations/yaml/YamlImportIntegration.js";
|
|
13
13
|
import { createImportSchemas } from "../migrations/yaml/generateImportSchemas.js";
|
|
14
14
|
import { CollectionCreateSchema } from "@njdamstra/appwrite-utils";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import { Client, type Models } from "node-appwrite";
|
|
2
2
|
import { type AppwriteFunction } from "@njdamstra/appwrite-utils";
|
|
3
3
|
export declare const deployFunction: (client: Client, functionId: string, codePath: string, activate?: boolean, entrypoint?: string, commands?: string, ignored?: string[]) => Promise<Models.Deployment>;
|
|
4
|
-
export declare const deployLocalFunction: (client: Client, functionName: string, functionConfig: AppwriteFunction, functionPath?: string) => Promise<Models.Deployment>;
|
|
4
|
+
export declare const deployLocalFunction: (client: Client, functionName: string, functionConfig: AppwriteFunction, functionPath?: string, configDirPath?: string) => Promise<Models.Deployment>;
|
|
@@ -10,8 +10,8 @@ import cliProgress from "cli-progress";
|
|
|
10
10
|
import { execSync } from "child_process";
|
|
11
11
|
import { createFunction, getFunction, updateFunction, updateFunctionSpecifications, } from "./methods.js";
|
|
12
12
|
import ignore from "ignore";
|
|
13
|
-
import { MessageFormatter } from "
|
|
14
|
-
import { resolveFunctionDirectory, validateFunctionDirectory } from '
|
|
13
|
+
import { MessageFormatter } from "@njdamstra/appwrite-utils-helpers";
|
|
14
|
+
import { resolveFunctionDirectory, validateFunctionDirectory } from '@njdamstra/appwrite-utils-helpers';
|
|
15
15
|
export const deployFunction = async (client, functionId, codePath, activate = true, entrypoint = "index.js", commands = "npm install", ignored = [
|
|
16
16
|
"node_modules",
|
|
17
17
|
".git",
|
|
@@ -98,7 +98,7 @@ export const deployFunction = async (client, functionId, codePath, activate = tr
|
|
|
98
98
|
throw error;
|
|
99
99
|
}
|
|
100
100
|
};
|
|
101
|
-
export const deployLocalFunction = async (client, functionName, functionConfig, functionPath) => {
|
|
101
|
+
export const deployLocalFunction = async (client, functionName, functionConfig, functionPath, configDirPath) => {
|
|
102
102
|
let functionExists = true;
|
|
103
103
|
let functionThatExists;
|
|
104
104
|
try {
|
|
@@ -107,8 +107,8 @@ export const deployLocalFunction = async (client, functionName, functionConfig,
|
|
|
107
107
|
catch (error) {
|
|
108
108
|
functionExists = false;
|
|
109
109
|
}
|
|
110
|
-
const
|
|
111
|
-
const resolvedPath = resolveFunctionDirectory(functionName,
|
|
110
|
+
const resolvedConfigDir = configDirPath ?? process.cwd();
|
|
111
|
+
const resolvedPath = resolveFunctionDirectory(functionName, resolvedConfigDir, functionConfig.dirPath, functionPath);
|
|
112
112
|
if (!validateFunctionDirectory(resolvedPath)) {
|
|
113
113
|
throw new Error(`Function directory is invalid or missing required files: ${resolvedPath}`);
|
|
114
114
|
}
|
|
@@ -3,8 +3,8 @@ import path from 'node:path';
|
|
|
3
3
|
import yaml from 'js-yaml';
|
|
4
4
|
import { homedir } from 'node:os';
|
|
5
5
|
import { AppwriteFunctionSchema } from '@njdamstra/appwrite-utils';
|
|
6
|
-
import { shouldIgnoreDirectory } from '
|
|
7
|
-
import { MessageFormatter } from '
|
|
6
|
+
import { shouldIgnoreDirectory } from '@njdamstra/appwrite-utils-helpers';
|
|
7
|
+
import { MessageFormatter } from '@njdamstra/appwrite-utils-helpers';
|
|
8
8
|
function findGitRoot(startDir) {
|
|
9
9
|
let dir = path.resolve(startDir);
|
|
10
10
|
while (dir !== path.parse(dir).root) {
|
|
@@ -2,14 +2,15 @@ import { AppwriteException, Client, Functions, Query, Runtime, } from "node-appw
|
|
|
2
2
|
import { join, dirname } from "node:path";
|
|
3
3
|
import { fileURLToPath } from "node:url";
|
|
4
4
|
import fs from "node:fs";
|
|
5
|
-
import {} from "@njdamstra/appwrite-utils";
|
|
5
|
+
import { EventTypeSchema, } from "@njdamstra/appwrite-utils";
|
|
6
6
|
import chalk from "chalk";
|
|
7
7
|
import { extract as extractTar } from "tar";
|
|
8
|
-
import { MessageFormatter } from "
|
|
9
|
-
import { expandTildePath, normalizeFunctionName } from
|
|
8
|
+
import { MessageFormatter } from "@njdamstra/appwrite-utils-helpers";
|
|
9
|
+
import { expandTildePath, normalizeFunctionName } from '@njdamstra/appwrite-utils-helpers';
|
|
10
10
|
/**
|
|
11
11
|
* Validates and filters events array for Appwrite functions
|
|
12
12
|
* - Filters out empty/invalid strings
|
|
13
|
+
* - Validates against EventTypeSchema
|
|
13
14
|
* - Limits to 100 items maximum (Appwrite limit)
|
|
14
15
|
* - Returns empty array if input is invalid
|
|
15
16
|
*/
|
|
@@ -17,7 +18,18 @@ const validateEvents = (events) => {
|
|
|
17
18
|
if (!events || !Array.isArray(events))
|
|
18
19
|
return [];
|
|
19
20
|
return events
|
|
20
|
-
.filter(event =>
|
|
21
|
+
.filter(event => {
|
|
22
|
+
if (!event || typeof event !== 'string' || event.trim().length === 0) {
|
|
23
|
+
return false;
|
|
24
|
+
}
|
|
25
|
+
// Validate against EventTypeSchema
|
|
26
|
+
const result = EventTypeSchema.safeParse(event);
|
|
27
|
+
if (!result.success) {
|
|
28
|
+
MessageFormatter.warning(`Invalid event type "${event}" will be filtered out`, { prefix: "Functions" });
|
|
29
|
+
return false;
|
|
30
|
+
}
|
|
31
|
+
return true;
|
|
32
|
+
})
|
|
21
33
|
.slice(0, 100);
|
|
22
34
|
};
|
|
23
35
|
export const listFunctions = async (client, queries, search) => {
|
package/dist/init.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import inquirer from "inquirer";
|
|
3
3
|
import { createEmptyCollection, setupDirsFiles } from "./utils/setupFiles.js";
|
|
4
|
-
import { MessageFormatter } from "
|
|
4
|
+
import { MessageFormatter } from "@njdamstra/appwrite-utils-helpers";
|
|
5
5
|
MessageFormatter.banner("Appwrite Utils CLI Tool", "For more information, visit https://github.com/njdamstra/AppwriteUtils");
|
|
6
6
|
async function main() {
|
|
7
7
|
const answers = await inquirer.prompt([
|
package/dist/interactiveCLI.d.ts
CHANGED
|
@@ -1,9 +1,14 @@
|
|
|
1
|
+
export interface InteractiveCLIOptions {
|
|
2
|
+
useSession?: boolean;
|
|
3
|
+
sessionCookie?: string;
|
|
4
|
+
}
|
|
1
5
|
export declare class InteractiveCLI {
|
|
2
6
|
private currentDir;
|
|
3
7
|
private controller;
|
|
4
8
|
private isUsingTypeScriptConfig;
|
|
5
9
|
private lastSelectedCollectionIds;
|
|
6
|
-
|
|
10
|
+
private options;
|
|
11
|
+
constructor(currentDir: string, options?: InteractiveCLIOptions);
|
|
7
12
|
run(): Promise<void>;
|
|
8
13
|
private initControllerIfNeeded;
|
|
9
14
|
private manageBuckets;
|