appwrite-utils-cli 1.5.2 → 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.
- package/CHANGELOG.md +199 -0
- package/README.md +251 -29
- package/dist/adapters/AdapterFactory.d.ts +10 -3
- package/dist/adapters/AdapterFactory.js +213 -17
- package/dist/adapters/TablesDBAdapter.js +60 -17
- package/dist/backups/operations/bucketBackup.d.ts +19 -0
- package/dist/backups/operations/bucketBackup.js +197 -0
- package/dist/backups/operations/collectionBackup.d.ts +30 -0
- package/dist/backups/operations/collectionBackup.js +201 -0
- package/dist/backups/operations/comprehensiveBackup.d.ts +25 -0
- package/dist/backups/operations/comprehensiveBackup.js +238 -0
- package/dist/backups/schemas/bucketManifest.d.ts +93 -0
- package/dist/backups/schemas/bucketManifest.js +33 -0
- package/dist/backups/schemas/comprehensiveManifest.d.ts +108 -0
- package/dist/backups/schemas/comprehensiveManifest.js +32 -0
- package/dist/backups/tracking/centralizedTracking.d.ts +34 -0
- package/dist/backups/tracking/centralizedTracking.js +274 -0
- package/dist/cli/commands/configCommands.d.ts +8 -0
- package/dist/cli/commands/configCommands.js +160 -0
- package/dist/cli/commands/databaseCommands.d.ts +13 -0
- package/dist/cli/commands/databaseCommands.js +478 -0
- package/dist/cli/commands/functionCommands.d.ts +7 -0
- package/dist/cli/commands/functionCommands.js +289 -0
- package/dist/cli/commands/schemaCommands.d.ts +7 -0
- package/dist/cli/commands/schemaCommands.js +134 -0
- package/dist/cli/commands/transferCommands.d.ts +5 -0
- package/dist/cli/commands/transferCommands.js +384 -0
- package/dist/collections/attributes.d.ts +5 -4
- package/dist/collections/attributes.js +539 -246
- package/dist/collections/indexes.js +39 -37
- package/dist/collections/methods.d.ts +2 -16
- package/dist/collections/methods.js +90 -538
- package/dist/collections/transferOperations.d.ts +7 -0
- package/dist/collections/transferOperations.js +331 -0
- package/dist/collections/wipeOperations.d.ts +16 -0
- package/dist/collections/wipeOperations.js +328 -0
- package/dist/config/configMigration.d.ts +87 -0
- package/dist/config/configMigration.js +390 -0
- package/dist/config/configValidation.d.ts +66 -0
- package/dist/config/configValidation.js +358 -0
- package/dist/config/yamlConfig.d.ts +455 -1
- package/dist/config/yamlConfig.js +145 -52
- package/dist/databases/methods.js +3 -2
- package/dist/databases/setup.d.ts +1 -2
- package/dist/databases/setup.js +9 -87
- package/dist/examples/yamlTerminologyExample.d.ts +42 -0
- package/dist/examples/yamlTerminologyExample.js +269 -0
- package/dist/functions/deployments.js +11 -10
- package/dist/functions/methods.d.ts +1 -1
- package/dist/functions/methods.js +5 -4
- package/dist/init.js +9 -9
- package/dist/interactiveCLI.d.ts +8 -17
- package/dist/interactiveCLI.js +181 -1172
- package/dist/main.js +364 -21
- package/dist/migrations/afterImportActions.js +22 -30
- package/dist/migrations/appwriteToX.js +71 -25
- package/dist/migrations/dataLoader.js +35 -26
- package/dist/migrations/importController.js +29 -30
- package/dist/migrations/relationships.js +13 -12
- package/dist/migrations/services/ImportOrchestrator.js +16 -19
- package/dist/migrations/transfer.js +46 -46
- package/dist/migrations/yaml/YamlImportConfigLoader.d.ts +3 -1
- package/dist/migrations/yaml/YamlImportConfigLoader.js +6 -3
- package/dist/migrations/yaml/YamlImportIntegration.d.ts +9 -3
- package/dist/migrations/yaml/YamlImportIntegration.js +22 -11
- package/dist/migrations/yaml/generateImportSchemas.d.ts +14 -1
- package/dist/migrations/yaml/generateImportSchemas.js +736 -7
- package/dist/schemas/authUser.d.ts +1 -1
- package/dist/setupController.js +3 -2
- package/dist/shared/backupMetadataSchema.d.ts +94 -0
- package/dist/shared/backupMetadataSchema.js +38 -0
- package/dist/shared/backupTracking.d.ts +18 -0
- package/dist/shared/backupTracking.js +176 -0
- package/dist/shared/confirmationDialogs.js +15 -15
- package/dist/shared/errorUtils.d.ts +54 -0
- package/dist/shared/errorUtils.js +95 -0
- package/dist/shared/functionManager.js +20 -19
- package/dist/shared/indexManager.js +12 -11
- package/dist/shared/jsonSchemaGenerator.js +10 -26
- package/dist/shared/logging.d.ts +51 -0
- package/dist/shared/logging.js +70 -0
- package/dist/shared/messageFormatter.d.ts +2 -0
- package/dist/shared/messageFormatter.js +10 -0
- package/dist/shared/migrationHelpers.d.ts +6 -16
- package/dist/shared/migrationHelpers.js +24 -21
- package/dist/shared/operationLogger.d.ts +8 -1
- package/dist/shared/operationLogger.js +11 -24
- package/dist/shared/operationQueue.d.ts +28 -1
- package/dist/shared/operationQueue.js +268 -66
- package/dist/shared/operationsTable.d.ts +26 -0
- package/dist/shared/operationsTable.js +286 -0
- package/dist/shared/operationsTableSchema.d.ts +48 -0
- package/dist/shared/operationsTableSchema.js +35 -0
- package/dist/shared/relationshipExtractor.d.ts +56 -0
- package/dist/shared/relationshipExtractor.js +138 -0
- package/dist/shared/schemaGenerator.d.ts +19 -1
- package/dist/shared/schemaGenerator.js +56 -75
- package/dist/storage/backupCompression.d.ts +20 -0
- package/dist/storage/backupCompression.js +67 -0
- package/dist/storage/methods.d.ts +16 -2
- package/dist/storage/methods.js +98 -14
- package/dist/users/methods.js +9 -8
- package/dist/utils/configDiscovery.d.ts +78 -0
- package/dist/utils/configDiscovery.js +430 -0
- package/dist/utils/directoryUtils.d.ts +22 -0
- package/dist/utils/directoryUtils.js +59 -0
- package/dist/utils/getClientFromConfig.d.ts +17 -8
- package/dist/utils/getClientFromConfig.js +162 -17
- package/dist/utils/helperFunctions.d.ts +16 -2
- package/dist/utils/helperFunctions.js +19 -5
- package/dist/utils/loadConfigs.d.ts +34 -9
- package/dist/utils/loadConfigs.js +236 -316
- package/dist/utils/pathResolvers.d.ts +53 -0
- package/dist/utils/pathResolvers.js +72 -0
- package/dist/utils/projectConfig.d.ts +119 -0
- package/dist/utils/projectConfig.js +171 -0
- package/dist/utils/retryFailedPromises.js +4 -2
- package/dist/utils/sessionAuth.d.ts +48 -0
- package/dist/utils/sessionAuth.js +164 -0
- package/dist/utils/sessionPreservationExample.d.ts +1666 -0
- package/dist/utils/sessionPreservationExample.js +101 -0
- package/dist/utils/setupFiles.js +301 -41
- package/dist/utils/typeGuards.d.ts +35 -0
- package/dist/utils/typeGuards.js +57 -0
- package/dist/utils/versionDetection.js +145 -9
- package/dist/utils/yamlConverter.d.ts +53 -3
- package/dist/utils/yamlConverter.js +232 -13
- package/dist/utils/yamlLoader.d.ts +70 -0
- package/dist/utils/yamlLoader.js +263 -0
- package/dist/utilsController.d.ts +36 -3
- package/dist/utilsController.js +186 -56
- package/package.json +12 -2
- package/src/adapters/AdapterFactory.ts +263 -35
- package/src/adapters/TablesDBAdapter.ts +225 -36
- package/src/backups/operations/bucketBackup.ts +277 -0
- package/src/backups/operations/collectionBackup.ts +310 -0
- package/src/backups/operations/comprehensiveBackup.ts +342 -0
- package/src/backups/schemas/bucketManifest.ts +78 -0
- package/src/backups/schemas/comprehensiveManifest.ts +76 -0
- package/src/backups/tracking/centralizedTracking.ts +352 -0
- package/src/cli/commands/configCommands.ts +194 -0
- package/src/cli/commands/databaseCommands.ts +635 -0
- package/src/cli/commands/functionCommands.ts +379 -0
- package/src/cli/commands/schemaCommands.ts +163 -0
- package/src/cli/commands/transferCommands.ts +457 -0
- package/src/collections/attributes.ts +900 -621
- package/src/collections/attributes.ts.backup +1555 -0
- package/src/collections/indexes.ts +116 -114
- package/src/collections/methods.ts +295 -968
- package/src/collections/transferOperations.ts +516 -0
- package/src/collections/wipeOperations.ts +501 -0
- package/src/config/README.md +274 -0
- package/src/config/configMigration.ts +575 -0
- package/src/config/configValidation.ts +445 -0
- package/src/config/yamlConfig.ts +168 -55
- package/src/databases/methods.ts +3 -2
- package/src/databases/setup.ts +11 -138
- package/src/examples/yamlTerminologyExample.ts +341 -0
- package/src/functions/deployments.ts +14 -12
- package/src/functions/methods.ts +11 -11
- package/src/functions/templates/hono-typescript/README.md +286 -0
- package/src/functions/templates/hono-typescript/package.json +26 -0
- package/src/functions/templates/hono-typescript/src/adapters/request.ts +74 -0
- package/src/functions/templates/hono-typescript/src/adapters/response.ts +106 -0
- package/src/functions/templates/hono-typescript/src/app.ts +180 -0
- package/src/functions/templates/hono-typescript/src/context.ts +103 -0
- package/src/functions/templates/hono-typescript/src/index.ts +54 -0
- package/src/functions/templates/hono-typescript/src/middleware/appwrite.ts +119 -0
- package/src/functions/templates/hono-typescript/tsconfig.json +20 -0
- package/src/functions/templates/typescript-node/package.json +2 -1
- package/src/functions/templates/typescript-node/src/context.ts +103 -0
- package/src/functions/templates/typescript-node/src/index.ts +18 -12
- package/src/functions/templates/uv/pyproject.toml +1 -0
- package/src/functions/templates/uv/src/context.py +125 -0
- package/src/functions/templates/uv/src/index.py +35 -5
- package/src/init.ts +9 -11
- package/src/interactiveCLI.ts +278 -1596
- package/src/main.ts +418 -24
- package/src/migrations/afterImportActions.ts +71 -44
- package/src/migrations/appwriteToX.ts +100 -34
- package/src/migrations/dataLoader.ts +48 -34
- package/src/migrations/importController.ts +44 -39
- package/src/migrations/relationships.ts +28 -18
- package/src/migrations/services/ImportOrchestrator.ts +24 -27
- package/src/migrations/transfer.ts +159 -121
- package/src/migrations/yaml/YamlImportConfigLoader.ts +11 -4
- package/src/migrations/yaml/YamlImportIntegration.ts +47 -20
- package/src/migrations/yaml/generateImportSchemas.ts +751 -12
- package/src/setupController.ts +3 -2
- package/src/shared/backupMetadataSchema.ts +93 -0
- package/src/shared/backupTracking.ts +211 -0
- package/src/shared/confirmationDialogs.ts +19 -19
- package/src/shared/errorUtils.ts +110 -0
- package/src/shared/functionManager.ts +21 -20
- package/src/shared/indexManager.ts +12 -11
- package/src/shared/jsonSchemaGenerator.ts +38 -52
- package/src/shared/logging.ts +75 -0
- package/src/shared/messageFormatter.ts +14 -1
- package/src/shared/migrationHelpers.ts +45 -38
- package/src/shared/operationLogger.ts +11 -36
- package/src/shared/operationQueue.ts +322 -93
- package/src/shared/operationsTable.ts +338 -0
- package/src/shared/operationsTableSchema.ts +60 -0
- package/src/shared/relationshipExtractor.ts +214 -0
- package/src/shared/schemaGenerator.ts +179 -219
- package/src/storage/backupCompression.ts +88 -0
- package/src/storage/methods.ts +131 -34
- package/src/users/methods.ts +11 -9
- package/src/utils/configDiscovery.ts +502 -0
- package/src/utils/directoryUtils.ts +61 -0
- package/src/utils/getClientFromConfig.ts +205 -22
- package/src/utils/helperFunctions.ts +23 -5
- package/src/utils/loadConfigs.ts +313 -345
- package/src/utils/pathResolvers.ts +81 -0
- package/src/utils/projectConfig.ts +299 -0
- package/src/utils/retryFailedPromises.ts +4 -2
- package/src/utils/sessionAuth.ts +230 -0
- package/src/utils/setupFiles.ts +322 -54
- package/src/utils/typeGuards.ts +65 -0
- package/src/utils/versionDetection.ts +218 -64
- package/src/utils/yamlConverter.ts +296 -13
- package/src/utils/yamlLoader.ts +364 -0
- package/src/utilsController.ts +314 -110
- package/tests/README.md +497 -0
- package/tests/adapters/AdapterFactory.test.ts +277 -0
- package/tests/integration/syncOperations.test.ts +463 -0
- package/tests/jest.config.js +25 -0
- package/tests/migration/configMigration.test.ts +546 -0
- package/tests/setup.ts +62 -0
- package/tests/testUtils.ts +340 -0
- package/tests/utils/loadConfigs.test.ts +350 -0
- package/tests/validation/configValidation.test.ts +412 -0
- package/src/utils/schemaStrings.ts +0 -517
@@ -9,6 +9,8 @@
|
|
9
9
|
* 2. Secondary: Health endpoint version check
|
10
10
|
* 3. Fallback: Default to legacy mode for safety
|
11
11
|
*/
|
12
|
+
import { logger } from '../shared/logging.js';
|
13
|
+
import { MessageFormatter } from '../shared/messageFormatter.js';
|
12
14
|
/**
|
13
15
|
* Detects Appwrite API version and TablesDB support
|
14
16
|
*
|
@@ -18,40 +20,117 @@
|
|
18
20
|
* @returns Promise resolving to version detection result
|
19
21
|
*/
|
20
22
|
export async function detectAppwriteVersion(endpoint, project, apiKey) {
|
23
|
+
const startTime = Date.now();
|
21
24
|
// Clean endpoint URL
|
22
25
|
const cleanEndpoint = endpoint.replace(/\/$/, '');
|
26
|
+
logger.info('Starting Appwrite version detection', {
|
27
|
+
endpoint: cleanEndpoint,
|
28
|
+
project,
|
29
|
+
operation: 'detectAppwriteVersion'
|
30
|
+
});
|
31
|
+
// STEP 1: Check server version FIRST
|
32
|
+
const serverVersion = await fetchServerVersion(cleanEndpoint);
|
33
|
+
if (serverVersion && !isVersionAtLeast(serverVersion, '1.8.0')) {
|
34
|
+
// Server < 1.8.0 doesn't support TablesDB
|
35
|
+
logger.info('Server version below 1.8.0 - using legacy adapter', {
|
36
|
+
serverVersion,
|
37
|
+
operation: 'detectAppwriteVersion'
|
38
|
+
});
|
39
|
+
return {
|
40
|
+
apiMode: 'legacy',
|
41
|
+
detectionMethod: 'health_check',
|
42
|
+
serverVersion,
|
43
|
+
confidence: 'high'
|
44
|
+
};
|
45
|
+
}
|
46
|
+
// STEP 2: Only proceed with endpoint probe if version >= 1.8.0 or version unknown
|
23
47
|
// Try primary detection method: TablesDB endpoint probe
|
24
48
|
try {
|
49
|
+
logger.debug('Attempting TablesDB endpoint probe', {
|
50
|
+
endpoint: cleanEndpoint,
|
51
|
+
serverVersion: serverVersion || 'unknown',
|
52
|
+
operation: 'detectAppwriteVersion'
|
53
|
+
});
|
54
|
+
const probeStartTime = Date.now();
|
25
55
|
const tablesDbResult = await probeTablesDbEndpoint(cleanEndpoint, project, apiKey);
|
56
|
+
const probeDuration = Date.now() - probeStartTime;
|
26
57
|
if (tablesDbResult.apiMode === 'tablesdb') {
|
58
|
+
logger.info('TablesDB detected via endpoint probe', {
|
59
|
+
endpoint: cleanEndpoint,
|
60
|
+
detectionMethod: tablesDbResult.detectionMethod,
|
61
|
+
confidence: tablesDbResult.confidence,
|
62
|
+
probeDuration,
|
63
|
+
totalDuration: Date.now() - startTime,
|
64
|
+
operation: 'detectAppwriteVersion'
|
65
|
+
});
|
27
66
|
return tablesDbResult;
|
28
67
|
}
|
29
68
|
}
|
30
69
|
catch (error) {
|
31
|
-
|
70
|
+
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
71
|
+
MessageFormatter.warning(`TablesDB endpoint probe failed: ${errorMessage}`, { prefix: "Version Detection" });
|
72
|
+
logger.warn('TablesDB endpoint probe failed', {
|
73
|
+
endpoint: cleanEndpoint,
|
74
|
+
error: errorMessage,
|
75
|
+
operation: 'detectAppwriteVersion'
|
76
|
+
});
|
32
77
|
}
|
33
78
|
// Try secondary detection method: SDK feature detection
|
34
79
|
try {
|
80
|
+
logger.debug('Attempting SDK capability probe', {
|
81
|
+
endpoint: cleanEndpoint,
|
82
|
+
operation: 'detectAppwriteVersion'
|
83
|
+
});
|
84
|
+
const sdkProbeStartTime = Date.now();
|
35
85
|
const sdkResult = await probeSdkCapabilities();
|
86
|
+
const sdkProbeDuration = Date.now() - sdkProbeStartTime;
|
36
87
|
if (sdkResult.apiMode === 'tablesdb') {
|
88
|
+
logger.info('TablesDB detected via SDK capability probe', {
|
89
|
+
endpoint: cleanEndpoint,
|
90
|
+
detectionMethod: sdkResult.detectionMethod,
|
91
|
+
confidence: sdkResult.confidence,
|
92
|
+
sdkProbeDuration,
|
93
|
+
totalDuration: Date.now() - startTime,
|
94
|
+
operation: 'detectAppwriteVersion'
|
95
|
+
});
|
37
96
|
return sdkResult;
|
38
97
|
}
|
39
98
|
}
|
40
99
|
catch (error) {
|
41
|
-
|
100
|
+
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
101
|
+
MessageFormatter.warning(`SDK capability probe failed: ${errorMessage}`, { prefix: "Version Detection" });
|
102
|
+
logger.warn('SDK capability probe failed', {
|
103
|
+
endpoint: cleanEndpoint,
|
104
|
+
error: errorMessage,
|
105
|
+
operation: 'detectAppwriteVersion'
|
106
|
+
});
|
42
107
|
}
|
43
108
|
// Fallback to legacy mode
|
44
|
-
|
109
|
+
const fallbackResult = {
|
45
110
|
apiMode: 'legacy',
|
46
111
|
detectionMethod: 'fallback',
|
47
112
|
confidence: 'low'
|
48
113
|
};
|
114
|
+
logger.info('Falling back to legacy mode', {
|
115
|
+
endpoint: cleanEndpoint,
|
116
|
+
totalDuration: Date.now() - startTime,
|
117
|
+
result: fallbackResult,
|
118
|
+
operation: 'detectAppwriteVersion'
|
119
|
+
});
|
120
|
+
return fallbackResult;
|
49
121
|
}
|
50
122
|
/**
|
51
123
|
* Test TablesDB endpoint availability - most reliable detection method
|
52
124
|
*/
|
53
125
|
async function probeTablesDbEndpoint(endpoint, project, apiKey) {
|
54
|
-
const
|
126
|
+
const startTime = Date.now();
|
127
|
+
const url = `${endpoint}/tablesdb/`;
|
128
|
+
logger.debug('Probing TablesDB endpoint', {
|
129
|
+
url,
|
130
|
+
project,
|
131
|
+
operation: 'probeTablesDbEndpoint'
|
132
|
+
});
|
133
|
+
const response = await fetch(url, {
|
55
134
|
method: 'GET',
|
56
135
|
headers: {
|
57
136
|
'Content-Type': 'application/json',
|
@@ -61,17 +140,41 @@ async function probeTablesDbEndpoint(endpoint, project, apiKey) {
|
|
61
140
|
// Short timeout for faster detection
|
62
141
|
signal: AbortSignal.timeout(5000)
|
63
142
|
});
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
143
|
+
const duration = Date.now() - startTime;
|
144
|
+
logger.debug('TablesDB endpoint response received', {
|
145
|
+
url,
|
146
|
+
status: response.status,
|
147
|
+
statusText: response.statusText,
|
148
|
+
duration,
|
149
|
+
operation: 'probeTablesDbEndpoint'
|
150
|
+
});
|
151
|
+
if (response.ok) {
|
152
|
+
// ONLY 200 OK means TablesDB available
|
153
|
+
// 404 means endpoint doesn't exist (server < 1.8.0)
|
154
|
+
const result = {
|
68
155
|
apiMode: 'tablesdb',
|
69
156
|
detectionMethod: 'endpoint_probe',
|
70
157
|
confidence: 'high'
|
71
158
|
};
|
159
|
+
logger.info('TablesDB endpoint probe successful', {
|
160
|
+
url,
|
161
|
+
status: response.status,
|
162
|
+
result,
|
163
|
+
duration,
|
164
|
+
operation: 'probeTablesDbEndpoint'
|
165
|
+
});
|
166
|
+
return result;
|
72
167
|
}
|
73
168
|
// 501 Not Implemented or other errors = no TablesDB support
|
74
|
-
|
169
|
+
const error = new Error(`TablesDB endpoint returned ${response.status}: ${response.statusText}`);
|
170
|
+
logger.debug('TablesDB endpoint probe failed', {
|
171
|
+
url,
|
172
|
+
status: response.status,
|
173
|
+
statusText: response.statusText,
|
174
|
+
duration,
|
175
|
+
operation: 'probeTablesDbEndpoint'
|
176
|
+
});
|
177
|
+
throw error;
|
75
178
|
}
|
76
179
|
/**
|
77
180
|
* SDK capability detection as secondary method
|
@@ -158,17 +261,50 @@ const detectionCache = new VersionDetectionCache();
|
|
158
261
|
* @returns Promise resolving to version detection result
|
159
262
|
*/
|
160
263
|
export async function detectAppwriteVersionCached(endpoint, project, apiKey, forceRefresh = false) {
|
264
|
+
const startTime = Date.now();
|
265
|
+
logger.debug('Version detection with cache requested', {
|
266
|
+
endpoint,
|
267
|
+
project,
|
268
|
+
forceRefresh,
|
269
|
+
operation: 'detectAppwriteVersionCached'
|
270
|
+
});
|
161
271
|
// Check cache first (unless force refresh)
|
162
272
|
if (!forceRefresh) {
|
163
273
|
const cached = detectionCache.get(endpoint, project);
|
164
274
|
if (cached) {
|
275
|
+
logger.info('Using cached version detection result', {
|
276
|
+
endpoint,
|
277
|
+
project,
|
278
|
+
cachedResult: cached,
|
279
|
+
operation: 'detectAppwriteVersionCached'
|
280
|
+
});
|
165
281
|
return cached;
|
166
282
|
}
|
283
|
+
logger.debug('No cached result found, performing fresh detection', {
|
284
|
+
endpoint,
|
285
|
+
project,
|
286
|
+
operation: 'detectAppwriteVersionCached'
|
287
|
+
});
|
288
|
+
}
|
289
|
+
else {
|
290
|
+
logger.debug('Force refresh requested, bypassing cache', {
|
291
|
+
endpoint,
|
292
|
+
project,
|
293
|
+
operation: 'detectAppwriteVersionCached'
|
294
|
+
});
|
167
295
|
}
|
168
296
|
// Perform fresh detection
|
169
297
|
const result = await detectAppwriteVersion(endpoint, project, apiKey);
|
298
|
+
const totalDuration = Date.now() - startTime;
|
170
299
|
// Cache the result
|
171
300
|
detectionCache.set(endpoint, project, result);
|
301
|
+
logger.info('Version detection completed and cached', {
|
302
|
+
endpoint,
|
303
|
+
project,
|
304
|
+
result,
|
305
|
+
totalDuration,
|
306
|
+
operation: 'detectAppwriteVersionCached'
|
307
|
+
});
|
172
308
|
return result;
|
173
309
|
}
|
174
310
|
/**
|
@@ -25,23 +25,73 @@ export interface YamlCollectionData {
|
|
25
25
|
onDelete?: string;
|
26
26
|
side?: string;
|
27
27
|
}>;
|
28
|
+
columns?: Array<{
|
29
|
+
key: string;
|
30
|
+
type: string;
|
31
|
+
size?: number;
|
32
|
+
required?: boolean;
|
33
|
+
array?: boolean;
|
34
|
+
default?: any;
|
35
|
+
min?: number;
|
36
|
+
max?: number;
|
37
|
+
elements?: string[];
|
38
|
+
relatedTable?: string;
|
39
|
+
relationType?: string;
|
40
|
+
twoWay?: boolean;
|
41
|
+
twoWayKey?: string;
|
42
|
+
onDelete?: string;
|
43
|
+
side?: string;
|
44
|
+
}>;
|
28
45
|
indexes?: Array<{
|
29
46
|
key: string;
|
30
47
|
type: string;
|
31
48
|
attributes: string[];
|
49
|
+
columns?: string[];
|
32
50
|
orders?: string[];
|
33
51
|
}>;
|
34
52
|
importDefs?: any[];
|
35
53
|
}
|
54
|
+
/**
|
55
|
+
* Configuration for terminology selection
|
56
|
+
*/
|
57
|
+
export interface YamlTerminologyConfig {
|
58
|
+
useTableTerminology: boolean;
|
59
|
+
entityType: 'collection' | 'table';
|
60
|
+
schemaPath?: string;
|
61
|
+
}
|
36
62
|
/**
|
37
63
|
* Converts a Collection object to YAML format with proper schema reference
|
64
|
+
* Supports both collection and table terminology based on configuration
|
38
65
|
*/
|
39
|
-
export declare function collectionToYaml(collection: Collection | CollectionCreate,
|
66
|
+
export declare function collectionToYaml(collection: Collection | CollectionCreate, config?: YamlTerminologyConfig): string;
|
40
67
|
/**
|
41
68
|
* Sanitizes a collection name for use as a filename
|
42
69
|
*/
|
43
70
|
export declare function sanitizeFilename(name: string): string;
|
44
71
|
/**
|
45
|
-
* Generates the filename for a collection YAML file
|
72
|
+
* Generates the filename for a collection/table YAML file
|
73
|
+
*/
|
74
|
+
export declare function getCollectionYamlFilename(collection: Collection | CollectionCreate, useTableTerminology?: boolean): string;
|
75
|
+
/**
|
76
|
+
* Converts column terminology back to attribute terminology for loading
|
77
|
+
*/
|
78
|
+
export declare function normalizeYamlData(yamlData: YamlCollectionData): YamlCollectionData;
|
79
|
+
/**
|
80
|
+
* Determines if YAML data uses table terminology
|
81
|
+
*/
|
82
|
+
export declare function usesTableTerminology(yamlData: YamlCollectionData): boolean;
|
83
|
+
/**
|
84
|
+
* Converts between attribute and column terminology
|
85
|
+
*/
|
86
|
+
export declare function convertTerminology(yamlData: YamlCollectionData, toTableTerminology: boolean): YamlCollectionData;
|
87
|
+
/**
|
88
|
+
* Generates a template YAML file for collections or tables
|
89
|
+
*/
|
90
|
+
export declare function generateYamlTemplate(entityName: string, config: YamlTerminologyConfig): string;
|
91
|
+
/**
|
92
|
+
* Generates example YAML files for both collection and table formats
|
46
93
|
*/
|
47
|
-
export declare function
|
94
|
+
export declare function generateExampleYamls(entityName: string): {
|
95
|
+
collection: string;
|
96
|
+
table: string;
|
97
|
+
};
|
@@ -1,8 +1,14 @@
|
|
1
1
|
import yaml from "js-yaml";
|
2
2
|
/**
|
3
3
|
* Converts a Collection object to YAML format with proper schema reference
|
4
|
+
* Supports both collection and table terminology based on configuration
|
4
5
|
*/
|
5
|
-
export function collectionToYaml(collection,
|
6
|
+
export function collectionToYaml(collection, config = {
|
7
|
+
useTableTerminology: false,
|
8
|
+
entityType: 'collection',
|
9
|
+
schemaPath: "../.yaml_schemas/collection.schema.json"
|
10
|
+
}) {
|
11
|
+
const schemaPath = config.schemaPath || (config.useTableTerminology ? "../.yaml_schemas/table.schema.json" : "../.yaml_schemas/collection.schema.json");
|
6
12
|
// Convert Collection to YamlCollectionData format
|
7
13
|
const yamlData = {
|
8
14
|
name: collection.name,
|
@@ -17,9 +23,9 @@ export function collectionToYaml(collection, schemaPath = "../.yaml_schemas/coll
|
|
17
23
|
target: p.target
|
18
24
|
}));
|
19
25
|
}
|
20
|
-
// Convert attributes
|
26
|
+
// Convert attributes/columns based on terminology
|
21
27
|
if (collection.attributes && collection.attributes.length > 0) {
|
22
|
-
|
28
|
+
const attributeArray = collection.attributes.map(attr => {
|
23
29
|
const yamlAttr = {
|
24
30
|
key: attr.key,
|
25
31
|
type: attr.type,
|
@@ -53,15 +59,31 @@ export function collectionToYaml(collection, schemaPath = "../.yaml_schemas/coll
|
|
53
59
|
yamlAttr.side = attr.side;
|
54
60
|
return yamlAttr;
|
55
61
|
});
|
62
|
+
// Use appropriate terminology
|
63
|
+
if (config.useTableTerminology) {
|
64
|
+
yamlData.columns = attributeArray;
|
65
|
+
}
|
66
|
+
else {
|
67
|
+
yamlData.attributes = attributeArray;
|
68
|
+
}
|
56
69
|
}
|
57
|
-
// Convert indexes
|
70
|
+
// Convert indexes with appropriate field references
|
58
71
|
if (collection.indexes && collection.indexes.length > 0) {
|
59
|
-
yamlData.indexes = collection.indexes.map(idx =>
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
72
|
+
yamlData.indexes = collection.indexes.map(idx => {
|
73
|
+
const indexData = {
|
74
|
+
key: idx.key,
|
75
|
+
type: idx.type,
|
76
|
+
...(idx.orders && idx.orders.length > 0 ? { orders: idx.orders } : {})
|
77
|
+
};
|
78
|
+
// Use appropriate field terminology for index references
|
79
|
+
if (config.useTableTerminology) {
|
80
|
+
indexData.columns = idx.attributes;
|
81
|
+
}
|
82
|
+
else {
|
83
|
+
indexData.attributes = idx.attributes;
|
84
|
+
}
|
85
|
+
return indexData;
|
86
|
+
});
|
65
87
|
}
|
66
88
|
// Add import definitions if they exist
|
67
89
|
if (collection.importDefs && collection.importDefs.length > 0) {
|
@@ -78,8 +100,10 @@ export function collectionToYaml(collection, schemaPath = "../.yaml_schemas/coll
|
|
78
100
|
quotingType: '"',
|
79
101
|
forceQuotes: false,
|
80
102
|
});
|
103
|
+
// Determine the appropriate schema comment based on configuration
|
104
|
+
const entityType = config.useTableTerminology ? 'Table' : 'Collection';
|
81
105
|
return `# yaml-language-server: $schema=${schemaPath}
|
82
|
-
#
|
106
|
+
# ${entityType} Definition: ${collection.name}
|
83
107
|
${yamlContent}`;
|
84
108
|
}
|
85
109
|
/**
|
@@ -89,8 +113,203 @@ export function sanitizeFilename(name) {
|
|
89
113
|
return name.replace(/[^a-zA-Z0-9_-]/g, '_');
|
90
114
|
}
|
91
115
|
/**
|
92
|
-
* Generates the filename for a collection YAML file
|
116
|
+
* Generates the filename for a collection/table YAML file
|
93
117
|
*/
|
94
|
-
export function getCollectionYamlFilename(collection) {
|
118
|
+
export function getCollectionYamlFilename(collection, useTableTerminology = false) {
|
95
119
|
return `${sanitizeFilename(collection.name)}.yaml`;
|
96
120
|
}
|
121
|
+
/**
|
122
|
+
* Converts column terminology back to attribute terminology for loading
|
123
|
+
*/
|
124
|
+
export function normalizeYamlData(yamlData) {
|
125
|
+
const normalized = { ...yamlData };
|
126
|
+
// Convert columns to attributes if present
|
127
|
+
if (yamlData.columns && !yamlData.attributes) {
|
128
|
+
normalized.attributes = yamlData.columns.map(col => ({
|
129
|
+
...col,
|
130
|
+
// Convert table-specific fields back to collection terminology
|
131
|
+
relatedCollection: col.relatedTable || col.relatedCollection,
|
132
|
+
}));
|
133
|
+
delete normalized.columns;
|
134
|
+
}
|
135
|
+
// Normalize index field references
|
136
|
+
if (normalized.indexes) {
|
137
|
+
normalized.indexes = normalized.indexes.map(idx => ({
|
138
|
+
...idx,
|
139
|
+
attributes: idx.columns || idx.attributes,
|
140
|
+
// Remove columns field after normalization
|
141
|
+
columns: undefined
|
142
|
+
}));
|
143
|
+
}
|
144
|
+
return normalized;
|
145
|
+
}
|
146
|
+
/**
|
147
|
+
* Determines if YAML data uses table terminology
|
148
|
+
*/
|
149
|
+
export function usesTableTerminology(yamlData) {
|
150
|
+
return !!(yamlData.columns && yamlData.columns.length > 0) ||
|
151
|
+
!!(yamlData.indexes?.some(idx => !!idx.columns));
|
152
|
+
}
|
153
|
+
/**
|
154
|
+
* Converts between attribute and column terminology
|
155
|
+
*/
|
156
|
+
export function convertTerminology(yamlData, toTableTerminology) {
|
157
|
+
if (toTableTerminology) {
|
158
|
+
// Convert attributes to columns
|
159
|
+
const converted = { ...yamlData };
|
160
|
+
if (yamlData.attributes) {
|
161
|
+
converted.columns = yamlData.attributes.map(attr => ({
|
162
|
+
...attr,
|
163
|
+
relatedTable: attr.relatedCollection,
|
164
|
+
relatedCollection: undefined
|
165
|
+
}));
|
166
|
+
delete converted.attributes;
|
167
|
+
}
|
168
|
+
// Convert index references
|
169
|
+
if (converted.indexes) {
|
170
|
+
converted.indexes = converted.indexes.map(idx => ({
|
171
|
+
...idx,
|
172
|
+
columns: idx.attributes,
|
173
|
+
attributes: idx.attributes // Keep both for compatibility
|
174
|
+
}));
|
175
|
+
}
|
176
|
+
return converted;
|
177
|
+
}
|
178
|
+
else {
|
179
|
+
// Convert columns to attributes (normalize)
|
180
|
+
return normalizeYamlData(yamlData);
|
181
|
+
}
|
182
|
+
}
|
183
|
+
/**
|
184
|
+
* Generates a template YAML file for collections or tables
|
185
|
+
*/
|
186
|
+
export function generateYamlTemplate(entityName, config) {
|
187
|
+
const entityType = config.useTableTerminology ? 'table' : 'collection';
|
188
|
+
const fieldsKey = config.useTableTerminology ? 'columns' : 'attributes';
|
189
|
+
const relationKey = config.useTableTerminology ? 'relatedTable' : 'relatedCollection';
|
190
|
+
const indexFieldsKey = config.useTableTerminology ? 'columns' : 'attributes';
|
191
|
+
// Build template dynamically to handle computed property names
|
192
|
+
const fieldsArray = [
|
193
|
+
{
|
194
|
+
key: "id",
|
195
|
+
type: "string",
|
196
|
+
required: true,
|
197
|
+
size: 36
|
198
|
+
},
|
199
|
+
{
|
200
|
+
key: "name",
|
201
|
+
type: "string",
|
202
|
+
required: true,
|
203
|
+
size: 255
|
204
|
+
},
|
205
|
+
{
|
206
|
+
key: "description",
|
207
|
+
type: "string",
|
208
|
+
required: false,
|
209
|
+
size: 1000
|
210
|
+
},
|
211
|
+
{
|
212
|
+
key: "isActive",
|
213
|
+
type: "boolean",
|
214
|
+
required: true,
|
215
|
+
default: true
|
216
|
+
},
|
217
|
+
{
|
218
|
+
key: "createdAt",
|
219
|
+
type: "datetime",
|
220
|
+
required: true
|
221
|
+
},
|
222
|
+
{
|
223
|
+
key: "tags",
|
224
|
+
type: "string",
|
225
|
+
array: true,
|
226
|
+
required: false
|
227
|
+
},
|
228
|
+
{
|
229
|
+
key: "categoryId",
|
230
|
+
type: "relationship",
|
231
|
+
relationType: "manyToOne",
|
232
|
+
[relationKey]: "Categories",
|
233
|
+
required: false,
|
234
|
+
onDelete: "setNull"
|
235
|
+
}
|
236
|
+
];
|
237
|
+
const indexesArray = [
|
238
|
+
{
|
239
|
+
key: "name_index",
|
240
|
+
type: "key",
|
241
|
+
[indexFieldsKey]: ["name"]
|
242
|
+
},
|
243
|
+
{
|
244
|
+
key: "active_created_index",
|
245
|
+
type: "key",
|
246
|
+
[indexFieldsKey]: ["isActive", "createdAt"],
|
247
|
+
orders: ["asc", "desc"]
|
248
|
+
},
|
249
|
+
{
|
250
|
+
key: "name_fulltext",
|
251
|
+
type: "fulltext",
|
252
|
+
[indexFieldsKey]: ["name", "description"]
|
253
|
+
}
|
254
|
+
];
|
255
|
+
const template = {
|
256
|
+
name: entityName,
|
257
|
+
id: entityName.toLowerCase().replace(/\s+/g, '_'),
|
258
|
+
documentSecurity: false,
|
259
|
+
enabled: true,
|
260
|
+
permissions: [
|
261
|
+
{
|
262
|
+
permission: "read",
|
263
|
+
target: "users"
|
264
|
+
},
|
265
|
+
{
|
266
|
+
permission: "create",
|
267
|
+
target: "users"
|
268
|
+
},
|
269
|
+
{
|
270
|
+
permission: "update",
|
271
|
+
target: "users"
|
272
|
+
},
|
273
|
+
{
|
274
|
+
permission: "delete",
|
275
|
+
target: "users"
|
276
|
+
}
|
277
|
+
],
|
278
|
+
importDefs: []
|
279
|
+
};
|
280
|
+
// Assign fields with correct property name
|
281
|
+
template[fieldsKey] = fieldsArray;
|
282
|
+
template.indexes = indexesArray;
|
283
|
+
// Generate YAML content
|
284
|
+
const yamlContent = yaml.dump(template, {
|
285
|
+
indent: 2,
|
286
|
+
lineWidth: 120,
|
287
|
+
sortKeys: false,
|
288
|
+
quotingType: '"',
|
289
|
+
forceQuotes: false,
|
290
|
+
});
|
291
|
+
// Add schema reference and documentation
|
292
|
+
const schemaPath = config.schemaPath ||
|
293
|
+
(config.useTableTerminology ? "../.yaml_schemas/table.schema.json" : "../.yaml_schemas/collection.schema.json");
|
294
|
+
const documentation = config.useTableTerminology
|
295
|
+
? `# Table Definition: ${entityName}\n# This file defines a table for the new TablesDB API\n#\n# Key differences from Collections:\n# - Uses 'columns' instead of 'attributes'\n# - Uses 'relatedTable' instead of 'relatedCollection'\n# - Indexes reference 'columns' instead of 'attributes'\n#\n`
|
296
|
+
: `# Collection Definition: ${entityName}\n# This file defines a collection for the legacy Databases API\n#\n# Note: For new projects, consider using TablesDB API with table definitions\n#\n`;
|
297
|
+
return `# yaml-language-server: $schema=${schemaPath}\n${documentation}${yamlContent}`;
|
298
|
+
}
|
299
|
+
/**
|
300
|
+
* Generates example YAML files for both collection and table formats
|
301
|
+
*/
|
302
|
+
export function generateExampleYamls(entityName) {
|
303
|
+
const collectionYaml = generateYamlTemplate(entityName, {
|
304
|
+
useTableTerminology: false,
|
305
|
+
entityType: 'collection'
|
306
|
+
});
|
307
|
+
const tableYaml = generateYamlTemplate(entityName, {
|
308
|
+
useTableTerminology: true,
|
309
|
+
entityType: 'table'
|
310
|
+
});
|
311
|
+
return {
|
312
|
+
collection: collectionYaml,
|
313
|
+
table: tableYaml
|
314
|
+
};
|
315
|
+
}
|
@@ -0,0 +1,70 @@
|
|
1
|
+
import { type YamlCollectionData, type YamlTerminologyConfig } from "./yamlConverter.js";
|
2
|
+
import type { CollectionCreate } from "appwrite-utils";
|
3
|
+
/**
|
4
|
+
* Enhanced YAML loader with dual terminology support
|
5
|
+
*/
|
6
|
+
export declare class YamlLoader {
|
7
|
+
private baseDirectory;
|
8
|
+
constructor(baseDirectory: string);
|
9
|
+
/**
|
10
|
+
* Loads a YAML file with automatic terminology detection and normalization
|
11
|
+
*/
|
12
|
+
loadCollectionYaml(filePath: string): Promise<{
|
13
|
+
data: YamlCollectionData;
|
14
|
+
originalTerminology: 'collection' | 'table';
|
15
|
+
normalized: YamlCollectionData;
|
16
|
+
}>;
|
17
|
+
/**
|
18
|
+
* Loads multiple YAML files from a directory with terminology support
|
19
|
+
*/
|
20
|
+
loadDirectoryYamls(directoryPath: string, targetTerminology?: 'collection' | 'table'): Promise<{
|
21
|
+
collections: Array<{
|
22
|
+
filePath: string;
|
23
|
+
data: YamlCollectionData;
|
24
|
+
originalTerminology: 'collection' | 'table';
|
25
|
+
converted?: YamlCollectionData;
|
26
|
+
}>;
|
27
|
+
summary: {
|
28
|
+
total: number;
|
29
|
+
collectionFormat: number;
|
30
|
+
tableFormat: number;
|
31
|
+
converted: number;
|
32
|
+
};
|
33
|
+
}>;
|
34
|
+
/**
|
35
|
+
* Converts YAML data to CollectionCreate format for internal use
|
36
|
+
*/
|
37
|
+
yamlToCollectionCreate(yamlData: YamlCollectionData): CollectionCreate;
|
38
|
+
/**
|
39
|
+
* Saves YAML data with specified terminology
|
40
|
+
*/
|
41
|
+
saveCollectionYaml(filePath: string, data: YamlCollectionData, config: YamlTerminologyConfig): Promise<void>;
|
42
|
+
/**
|
43
|
+
* Migrates YAML files from one terminology to another
|
44
|
+
*/
|
45
|
+
migrateTerminology(sourceDirectory: string, targetDirectory: string, toTableTerminology: boolean): Promise<{
|
46
|
+
migrated: number;
|
47
|
+
skipped: number;
|
48
|
+
errors: string[];
|
49
|
+
}>;
|
50
|
+
/**
|
51
|
+
* Validates YAML files for terminology consistency
|
52
|
+
*/
|
53
|
+
validateTerminologyConsistency(directoryPath: string): Promise<{
|
54
|
+
isConsistent: boolean;
|
55
|
+
issues: Array<{
|
56
|
+
file: string;
|
57
|
+
issue: string;
|
58
|
+
severity: 'warning' | 'error';
|
59
|
+
}>;
|
60
|
+
summary: {
|
61
|
+
collectionFiles: number;
|
62
|
+
tableFiles: number;
|
63
|
+
mixedFiles: number;
|
64
|
+
};
|
65
|
+
}>;
|
66
|
+
}
|
67
|
+
/**
|
68
|
+
* Creates a YAML loader instance for the given base directory
|
69
|
+
*/
|
70
|
+
export declare function createYamlLoader(baseDirectory: string): YamlLoader;
|