@njdamstra/appwrite-utils-cli 1.8.9
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 +19 -0
- package/README.md +1133 -0
- package/dist/adapters/AdapterFactory.d.ts +94 -0
- package/dist/adapters/AdapterFactory.js +405 -0
- package/dist/adapters/DatabaseAdapter.d.ts +233 -0
- package/dist/adapters/DatabaseAdapter.js +50 -0
- package/dist/adapters/LegacyAdapter.d.ts +50 -0
- package/dist/adapters/LegacyAdapter.js +612 -0
- package/dist/adapters/TablesDBAdapter.d.ts +45 -0
- package/dist/adapters/TablesDBAdapter.js +571 -0
- package/dist/adapters/index.d.ts +11 -0
- package/dist/adapters/index.js +12 -0
- 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 +166 -0
- package/dist/cli/commands/databaseCommands.d.ts +13 -0
- package/dist/cli/commands/databaseCommands.js +554 -0
- package/dist/cli/commands/functionCommands.d.ts +7 -0
- package/dist/cli/commands/functionCommands.js +330 -0
- package/dist/cli/commands/schemaCommands.d.ts +7 -0
- package/dist/cli/commands/schemaCommands.js +169 -0
- package/dist/cli/commands/storageCommands.d.ts +5 -0
- package/dist/cli/commands/storageCommands.js +143 -0
- package/dist/cli/commands/transferCommands.d.ts +5 -0
- package/dist/cli/commands/transferCommands.js +384 -0
- package/dist/collections/attributes.d.ts +13 -0
- package/dist/collections/attributes.js +1364 -0
- package/dist/collections/indexes.d.ts +12 -0
- package/dist/collections/indexes.js +217 -0
- package/dist/collections/methods.d.ts +19 -0
- package/dist/collections/methods.js +682 -0
- package/dist/collections/tableOperations.d.ts +86 -0
- package/dist/collections/tableOperations.js +434 -0
- package/dist/collections/transferOperations.d.ts +8 -0
- package/dist/collections/transferOperations.js +412 -0
- package/dist/collections/wipeOperations.d.ts +16 -0
- package/dist/collections/wipeOperations.js +233 -0
- package/dist/config/ConfigManager.d.ts +445 -0
- package/dist/config/ConfigManager.js +625 -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/index.d.ts +8 -0
- package/dist/config/index.js +7 -0
- package/dist/config/services/ConfigDiscoveryService.d.ts +126 -0
- package/dist/config/services/ConfigDiscoveryService.js +374 -0
- package/dist/config/services/ConfigLoaderService.d.ts +129 -0
- package/dist/config/services/ConfigLoaderService.js +540 -0
- package/dist/config/services/ConfigMergeService.d.ts +208 -0
- package/dist/config/services/ConfigMergeService.js +308 -0
- package/dist/config/services/ConfigValidationService.d.ts +214 -0
- package/dist/config/services/ConfigValidationService.js +310 -0
- package/dist/config/services/SessionAuthService.d.ts +225 -0
- package/dist/config/services/SessionAuthService.js +456 -0
- package/dist/config/services/__tests__/ConfigMergeService.test.d.ts +1 -0
- package/dist/config/services/__tests__/ConfigMergeService.test.js +271 -0
- package/dist/config/services/index.d.ts +13 -0
- package/dist/config/services/index.js +10 -0
- package/dist/config/yamlConfig.d.ts +722 -0
- package/dist/config/yamlConfig.js +702 -0
- package/dist/databases/methods.d.ts +6 -0
- package/dist/databases/methods.js +35 -0
- package/dist/databases/setup.d.ts +5 -0
- package/dist/databases/setup.js +45 -0
- package/dist/examples/yamlTerminologyExample.d.ts +42 -0
- package/dist/examples/yamlTerminologyExample.js +272 -0
- package/dist/functions/deployments.d.ts +4 -0
- package/dist/functions/deployments.js +146 -0
- package/dist/functions/fnConfigDiscovery.d.ts +3 -0
- package/dist/functions/fnConfigDiscovery.js +108 -0
- package/dist/functions/methods.d.ts +16 -0
- package/dist/functions/methods.js +162 -0
- package/dist/functions/pathResolution.d.ts +37 -0
- package/dist/functions/pathResolution.js +185 -0
- package/dist/functions/templates/count-docs-in-collection/README.md +54 -0
- package/dist/functions/templates/count-docs-in-collection/src/main.ts +159 -0
- package/dist/functions/templates/count-docs-in-collection/src/request.ts +9 -0
- package/dist/functions/templates/hono-typescript/README.md +286 -0
- package/dist/functions/templates/hono-typescript/src/adapters/request.ts +74 -0
- package/dist/functions/templates/hono-typescript/src/adapters/response.ts +106 -0
- package/dist/functions/templates/hono-typescript/src/app.ts +180 -0
- package/dist/functions/templates/hono-typescript/src/context.ts +103 -0
- package/dist/functions/templates/hono-typescript/src/index.ts +54 -0
- package/dist/functions/templates/hono-typescript/src/middleware/appwrite.ts +119 -0
- package/dist/functions/templates/typescript-node/README.md +32 -0
- package/dist/functions/templates/typescript-node/src/context.ts +103 -0
- package/dist/functions/templates/typescript-node/src/index.ts +29 -0
- package/dist/functions/templates/uv/README.md +31 -0
- package/dist/functions/templates/uv/pyproject.toml +30 -0
- package/dist/functions/templates/uv/src/__init__.py +0 -0
- package/dist/functions/templates/uv/src/context.py +125 -0
- package/dist/functions/templates/uv/src/index.py +46 -0
- package/dist/init.d.ts +2 -0
- package/dist/init.js +57 -0
- package/dist/interactiveCLI.d.ts +31 -0
- package/dist/interactiveCLI.js +898 -0
- package/dist/main.d.ts +2 -0
- package/dist/main.js +1172 -0
- package/dist/migrations/afterImportActions.d.ts +17 -0
- package/dist/migrations/afterImportActions.js +306 -0
- package/dist/migrations/appwriteToX.d.ts +211 -0
- package/dist/migrations/appwriteToX.js +491 -0
- package/dist/migrations/comprehensiveTransfer.d.ts +147 -0
- package/dist/migrations/comprehensiveTransfer.js +1317 -0
- package/dist/migrations/dataLoader.d.ts +753 -0
- package/dist/migrations/dataLoader.js +1250 -0
- package/dist/migrations/importController.d.ts +23 -0
- package/dist/migrations/importController.js +268 -0
- package/dist/migrations/importDataActions.d.ts +50 -0
- package/dist/migrations/importDataActions.js +230 -0
- package/dist/migrations/relationships.d.ts +29 -0
- package/dist/migrations/relationships.js +204 -0
- package/dist/migrations/services/DataTransformationService.d.ts +55 -0
- package/dist/migrations/services/DataTransformationService.js +158 -0
- package/dist/migrations/services/FileHandlerService.d.ts +75 -0
- package/dist/migrations/services/FileHandlerService.js +236 -0
- package/dist/migrations/services/ImportOrchestrator.d.ts +97 -0
- package/dist/migrations/services/ImportOrchestrator.js +485 -0
- package/dist/migrations/services/RateLimitManager.d.ts +138 -0
- package/dist/migrations/services/RateLimitManager.js +279 -0
- package/dist/migrations/services/RelationshipResolver.d.ts +120 -0
- package/dist/migrations/services/RelationshipResolver.js +332 -0
- package/dist/migrations/services/UserMappingService.d.ts +109 -0
- package/dist/migrations/services/UserMappingService.js +277 -0
- package/dist/migrations/services/ValidationService.d.ts +74 -0
- package/dist/migrations/services/ValidationService.js +260 -0
- package/dist/migrations/transfer.d.ts +26 -0
- package/dist/migrations/transfer.js +608 -0
- package/dist/migrations/yaml/YamlImportConfigLoader.d.ts +131 -0
- package/dist/migrations/yaml/YamlImportConfigLoader.js +383 -0
- package/dist/migrations/yaml/YamlImportIntegration.d.ts +93 -0
- package/dist/migrations/yaml/YamlImportIntegration.js +341 -0
- package/dist/migrations/yaml/generateImportSchemas.d.ts +30 -0
- package/dist/migrations/yaml/generateImportSchemas.js +1327 -0
- package/dist/schemas/authUser.d.ts +24 -0
- package/dist/schemas/authUser.js +17 -0
- package/dist/setup.d.ts +2 -0
- package/dist/setup.js +5 -0
- package/dist/setupCommands.d.ts +58 -0
- package/dist/setupCommands.js +490 -0
- package/dist/setupController.d.ts +9 -0
- package/dist/setupController.js +34 -0
- package/dist/shared/attributeMapper.d.ts +20 -0
- package/dist/shared/attributeMapper.js +203 -0
- 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.d.ts +75 -0
- package/dist/shared/confirmationDialogs.js +236 -0
- package/dist/shared/errorUtils.d.ts +54 -0
- package/dist/shared/errorUtils.js +95 -0
- package/dist/shared/functionManager.d.ts +48 -0
- package/dist/shared/functionManager.js +336 -0
- package/dist/shared/indexManager.d.ts +24 -0
- package/dist/shared/indexManager.js +151 -0
- package/dist/shared/jsonSchemaGenerator.d.ts +50 -0
- package/dist/shared/jsonSchemaGenerator.js +290 -0
- package/dist/shared/logging.d.ts +61 -0
- package/dist/shared/logging.js +116 -0
- package/dist/shared/messageFormatter.d.ts +39 -0
- package/dist/shared/messageFormatter.js +162 -0
- package/dist/shared/migrationHelpers.d.ts +61 -0
- package/dist/shared/migrationHelpers.js +145 -0
- package/dist/shared/operationLogger.d.ts +10 -0
- package/dist/shared/operationLogger.js +12 -0
- package/dist/shared/operationQueue.d.ts +40 -0
- package/dist/shared/operationQueue.js +311 -0
- 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/progressManager.d.ts +62 -0
- package/dist/shared/progressManager.js +215 -0
- package/dist/shared/pydanticModelGenerator.d.ts +17 -0
- package/dist/shared/pydanticModelGenerator.js +615 -0
- package/dist/shared/relationshipExtractor.d.ts +56 -0
- package/dist/shared/relationshipExtractor.js +138 -0
- package/dist/shared/schemaGenerator.d.ts +40 -0
- package/dist/shared/schemaGenerator.js +556 -0
- package/dist/shared/selectionDialogs.d.ts +214 -0
- package/dist/shared/selectionDialogs.js +544 -0
- package/dist/storage/backupCompression.d.ts +20 -0
- package/dist/storage/backupCompression.js +67 -0
- package/dist/storage/methods.d.ts +32 -0
- package/dist/storage/methods.js +472 -0
- package/dist/storage/schemas.d.ts +842 -0
- package/dist/storage/schemas.js +175 -0
- package/dist/types.d.ts +4 -0
- package/dist/types.js +3 -0
- package/dist/users/methods.d.ts +16 -0
- package/dist/users/methods.js +277 -0
- package/dist/utils/ClientFactory.d.ts +87 -0
- package/dist/utils/ClientFactory.js +212 -0
- package/dist/utils/configDiscovery.d.ts +78 -0
- package/dist/utils/configDiscovery.js +472 -0
- package/dist/utils/configMigration.d.ts +1 -0
- package/dist/utils/configMigration.js +261 -0
- package/dist/utils/constantsGenerator.d.ts +31 -0
- package/dist/utils/constantsGenerator.js +321 -0
- package/dist/utils/dataConverters.d.ts +46 -0
- package/dist/utils/dataConverters.js +139 -0
- package/dist/utils/directoryUtils.d.ts +22 -0
- package/dist/utils/directoryUtils.js +59 -0
- package/dist/utils/getClientFromConfig.d.ts +39 -0
- package/dist/utils/getClientFromConfig.js +199 -0
- package/dist/utils/helperFunctions.d.ts +63 -0
- package/dist/utils/helperFunctions.js +156 -0
- package/dist/utils/index.d.ts +2 -0
- package/dist/utils/index.js +2 -0
- package/dist/utils/loadConfigs.d.ts +50 -0
- package/dist/utils/loadConfigs.js +358 -0
- 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.d.ts +2 -0
- package/dist/utils/retryFailedPromises.js +23 -0
- package/dist/utils/sessionAuth.d.ts +48 -0
- package/dist/utils/sessionAuth.js +164 -0
- package/dist/utils/setupFiles.d.ts +4 -0
- package/dist/utils/setupFiles.js +1192 -0
- package/dist/utils/typeGuards.d.ts +35 -0
- package/dist/utils/typeGuards.js +57 -0
- package/dist/utils/validationRules.d.ts +43 -0
- package/dist/utils/validationRules.js +42 -0
- package/dist/utils/versionDetection.d.ts +58 -0
- package/dist/utils/versionDetection.js +251 -0
- package/dist/utils/yamlConverter.d.ts +100 -0
- package/dist/utils/yamlConverter.js +428 -0
- package/dist/utils/yamlLoader.d.ts +70 -0
- package/dist/utils/yamlLoader.js +267 -0
- package/dist/utilsController.d.ts +106 -0
- package/dist/utilsController.js +863 -0
- package/package.json +75 -0
- package/scripts/copy-templates.ts +23 -0
- package/src/adapters/AdapterFactory.ts +510 -0
- package/src/adapters/DatabaseAdapter.ts +306 -0
- package/src/adapters/LegacyAdapter.ts +841 -0
- package/src/adapters/TablesDBAdapter.ts +773 -0
- package/src/adapters/index.ts +37 -0
- 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 +201 -0
- package/src/cli/commands/databaseCommands.ts +749 -0
- package/src/cli/commands/functionCommands.ts +418 -0
- package/src/cli/commands/schemaCommands.ts +200 -0
- package/src/cli/commands/storageCommands.ts +152 -0
- package/src/cli/commands/transferCommands.ts +457 -0
- package/src/collections/attributes.ts +2054 -0
- package/src/collections/attributes.ts.backup +1555 -0
- package/src/collections/indexes.ts +352 -0
- package/src/collections/methods.ts +745 -0
- package/src/collections/tableOperations.ts +506 -0
- package/src/collections/transferOperations.ts +590 -0
- package/src/collections/wipeOperations.ts +346 -0
- package/src/config/ConfigManager.ts +808 -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/index.ts +10 -0
- package/src/config/services/ConfigDiscoveryService.ts +463 -0
- package/src/config/services/ConfigLoaderService.ts +740 -0
- package/src/config/services/ConfigMergeService.ts +388 -0
- package/src/config/services/ConfigValidationService.ts +394 -0
- package/src/config/services/SessionAuthService.ts +565 -0
- package/src/config/services/__tests__/ConfigMergeService.test.ts +351 -0
- package/src/config/services/index.ts +29 -0
- package/src/config/yamlConfig.ts +761 -0
- package/src/databases/methods.ts +49 -0
- package/src/databases/setup.ts +77 -0
- package/src/examples/yamlTerminologyExample.ts +346 -0
- package/src/functions/deployments.ts +220 -0
- package/src/functions/fnConfigDiscovery.ts +103 -0
- package/src/functions/methods.ts +271 -0
- package/src/functions/pathResolution.ts +227 -0
- package/src/functions/templates/count-docs-in-collection/README.md +54 -0
- package/src/functions/templates/count-docs-in-collection/src/main.ts +159 -0
- package/src/functions/templates/count-docs-in-collection/src/request.ts +9 -0
- package/src/functions/templates/hono-typescript/README.md +286 -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/typescript-node/README.md +32 -0
- package/src/functions/templates/typescript-node/src/context.ts +103 -0
- package/src/functions/templates/typescript-node/src/index.ts +29 -0
- package/src/functions/templates/uv/README.md +31 -0
- package/src/functions/templates/uv/pyproject.toml +30 -0
- package/src/functions/templates/uv/src/__init__.py +0 -0
- package/src/functions/templates/uv/src/context.py +125 -0
- package/src/functions/templates/uv/src/index.py +46 -0
- package/src/init.ts +62 -0
- package/src/interactiveCLI.ts +1136 -0
- package/src/main.ts +1661 -0
- package/src/migrations/afterImportActions.ts +580 -0
- package/src/migrations/appwriteToX.ts +664 -0
- package/src/migrations/comprehensiveTransfer.ts +2285 -0
- package/src/migrations/dataLoader.ts +1702 -0
- package/src/migrations/importController.ts +428 -0
- package/src/migrations/importDataActions.ts +315 -0
- package/src/migrations/relationships.ts +334 -0
- package/src/migrations/services/DataTransformationService.ts +196 -0
- package/src/migrations/services/FileHandlerService.ts +311 -0
- package/src/migrations/services/ImportOrchestrator.ts +666 -0
- package/src/migrations/services/RateLimitManager.ts +363 -0
- package/src/migrations/services/RelationshipResolver.ts +461 -0
- package/src/migrations/services/UserMappingService.ts +345 -0
- package/src/migrations/services/ValidationService.ts +349 -0
- package/src/migrations/transfer.ts +1068 -0
- package/src/migrations/yaml/YamlImportConfigLoader.ts +439 -0
- package/src/migrations/yaml/YamlImportIntegration.ts +446 -0
- package/src/migrations/yaml/generateImportSchemas.ts +1354 -0
- package/src/schemas/authUser.ts +23 -0
- package/src/setup.ts +8 -0
- package/src/setupCommands.ts +603 -0
- package/src/setupController.ts +43 -0
- package/src/shared/attributeMapper.ts +229 -0
- package/src/shared/backupMetadataSchema.ts +93 -0
- package/src/shared/backupTracking.ts +211 -0
- package/src/shared/confirmationDialogs.ts +327 -0
- package/src/shared/errorUtils.ts +110 -0
- package/src/shared/functionManager.ts +525 -0
- package/src/shared/indexManager.ts +254 -0
- package/src/shared/jsonSchemaGenerator.ts +383 -0
- package/src/shared/logging.ts +149 -0
- package/src/shared/messageFormatter.ts +208 -0
- package/src/shared/migrationHelpers.ts +232 -0
- package/src/shared/operationLogger.ts +20 -0
- package/src/shared/operationQueue.ts +377 -0
- package/src/shared/operationsTable.ts +338 -0
- package/src/shared/operationsTableSchema.ts +60 -0
- package/src/shared/progressManager.ts +278 -0
- package/src/shared/pydanticModelGenerator.ts +618 -0
- package/src/shared/relationshipExtractor.ts +214 -0
- package/src/shared/schemaGenerator.ts +644 -0
- package/src/shared/selectionDialogs.ts +749 -0
- package/src/storage/backupCompression.ts +88 -0
- package/src/storage/methods.ts +698 -0
- package/src/storage/schemas.ts +205 -0
- package/src/types/node-appwrite-tablesdb.d.ts +44 -0
- package/src/types.ts +9 -0
- package/src/users/methods.ts +359 -0
- package/src/utils/ClientFactory.ts +240 -0
- package/src/utils/configDiscovery.ts +557 -0
- package/src/utils/configMigration.ts +348 -0
- package/src/utils/constantsGenerator.ts +369 -0
- package/src/utils/dataConverters.ts +159 -0
- package/src/utils/directoryUtils.ts +61 -0
- package/src/utils/getClientFromConfig.ts +257 -0
- package/src/utils/helperFunctions.ts +228 -0
- package/src/utils/index.ts +2 -0
- package/src/utils/loadConfigs.ts +449 -0
- package/src/utils/pathResolvers.ts +81 -0
- package/src/utils/projectConfig.ts +299 -0
- package/src/utils/retryFailedPromises.ts +29 -0
- package/src/utils/sessionAuth.ts +230 -0
- package/src/utils/setupFiles.ts +1238 -0
- package/src/utils/typeGuards.ts +65 -0
- package/src/utils/validationRules.ts +88 -0
- package/src/utils/versionDetection.ts +292 -0
- package/src/utils/yamlConverter.ts +542 -0
- package/src/utils/yamlLoader.ts +371 -0
- package/src/utilsController.ts +1203 -0
- 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/tsconfig.json +44 -0
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { Databases, type Models } from "node-appwrite";
|
|
2
|
+
export declare const fetchAllDatabases: (database: Databases) => Promise<Models.Database[]>;
|
|
3
|
+
export declare const wipeDatabase: (database: Databases, databaseId: string) => Promise<{
|
|
4
|
+
collectionId: string;
|
|
5
|
+
collectionName: string;
|
|
6
|
+
}[]>;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { Databases, Query } from "node-appwrite";
|
|
2
|
+
import { delay, tryAwaitWithRetry } from "../utils/helperFunctions.js";
|
|
3
|
+
import { fetchAllCollections } from "../collections/methods.js";
|
|
4
|
+
import { MessageFormatter } from "../shared/messageFormatter.js";
|
|
5
|
+
export const fetchAllDatabases = async (database) => {
|
|
6
|
+
const databases = await tryAwaitWithRetry(async () => await database.list([Query.limit(25)]));
|
|
7
|
+
const allDatabases = databases.databases;
|
|
8
|
+
if (allDatabases.length === 0)
|
|
9
|
+
return [];
|
|
10
|
+
let lastDatabaseId = allDatabases[allDatabases.length - 1].$id;
|
|
11
|
+
while (databases.databases.length === 25) {
|
|
12
|
+
const moreDatabases = await database.list([
|
|
13
|
+
Query.limit(25),
|
|
14
|
+
Query.cursorAfter(lastDatabaseId),
|
|
15
|
+
]);
|
|
16
|
+
allDatabases.push(...moreDatabases.databases);
|
|
17
|
+
if (moreDatabases.databases.length < 25)
|
|
18
|
+
break;
|
|
19
|
+
lastDatabaseId =
|
|
20
|
+
moreDatabases.databases[moreDatabases.databases.length - 1].$id;
|
|
21
|
+
}
|
|
22
|
+
return allDatabases;
|
|
23
|
+
};
|
|
24
|
+
export const wipeDatabase = async (database, databaseId) => {
|
|
25
|
+
MessageFormatter.info(`Wiping database: ${databaseId}`, { prefix: "Database" });
|
|
26
|
+
const existingCollections = await fetchAllCollections(databaseId, database);
|
|
27
|
+
let collectionsDeleted = [];
|
|
28
|
+
for (const { $id: collectionId, name } of existingCollections) {
|
|
29
|
+
MessageFormatter.info(`Deleting collection: ${collectionId}`, { prefix: "Database" });
|
|
30
|
+
collectionsDeleted.push({ collectionId, collectionName: name });
|
|
31
|
+
await tryAwaitWithRetry(async () => await database.deleteCollection(databaseId, collectionId));
|
|
32
|
+
await delay(100);
|
|
33
|
+
}
|
|
34
|
+
return collectionsDeleted;
|
|
35
|
+
};
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { Databases, type Models } from "node-appwrite";
|
|
2
|
+
import { type AppwriteConfig } from "@njdamstra/appwrite-utils";
|
|
3
|
+
export declare const ensureDatabasesExist: (config: AppwriteConfig, databasesToEnsure?: Models.Database[]) => Promise<void>;
|
|
4
|
+
export declare const wipeOtherDatabases: (database: Databases, databasesToKeep: Models.Database[]) => Promise<void>;
|
|
5
|
+
export declare const ensureCollectionsExist: (config: AppwriteConfig, database: Models.Database, collectionsToEnsure?: Models.Collection[]) => Promise<void>;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { Databases, Query } from "node-appwrite";
|
|
2
|
+
import { tryAwaitWithRetry } from "../utils/index.js";
|
|
3
|
+
import {} from "@njdamstra/appwrite-utils";
|
|
4
|
+
import { ulid } from "ulidx";
|
|
5
|
+
import { MessageFormatter } from "../shared/messageFormatter.js";
|
|
6
|
+
export const ensureDatabasesExist = async (config, databasesToEnsure) => {
|
|
7
|
+
if (!config.appwriteClient) {
|
|
8
|
+
throw new Error("Appwrite client is not initialized in the config");
|
|
9
|
+
}
|
|
10
|
+
const database = new Databases(config.appwriteClient);
|
|
11
|
+
const databasesToCreate = databasesToEnsure || config.databases || [];
|
|
12
|
+
if (!databasesToCreate.length) {
|
|
13
|
+
MessageFormatter.info("No databases to create");
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
const existingDatabases = await tryAwaitWithRetry(async () => await database.list([Query.limit(500)]));
|
|
17
|
+
for (const db of databasesToCreate) {
|
|
18
|
+
if (!existingDatabases.databases.some((d) => d.name === db.name)) {
|
|
19
|
+
await tryAwaitWithRetry(async () => await database.create(db.$id || ulid(), db.name, true));
|
|
20
|
+
MessageFormatter.success(`${db.name} database created`);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
export const wipeOtherDatabases = async (database, databasesToKeep) => {
|
|
25
|
+
MessageFormatter.info(`Databases to keep: ${databasesToKeep.map(db => db.name).join(", ")}`);
|
|
26
|
+
const allDatabases = await tryAwaitWithRetry(async () => await database.list([Query.limit(500)]));
|
|
27
|
+
for (const db of allDatabases.databases) {
|
|
28
|
+
if (!databasesToKeep.some((d) => d.name === db.name)) {
|
|
29
|
+
await tryAwaitWithRetry(async () => await database.delete(db.$id));
|
|
30
|
+
MessageFormatter.success(`Deleted database: ${db.name}`);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
export const ensureCollectionsExist = async (config, database, collectionsToEnsure) => {
|
|
35
|
+
const databaseClient = new Databases(config.appwriteClient);
|
|
36
|
+
const collectionsToCreate = collectionsToEnsure ||
|
|
37
|
+
(config.collections ? config.collections : []);
|
|
38
|
+
const existingCollections = await tryAwaitWithRetry(async () => await databaseClient.listCollections(database.$id, [Query.limit(500)]));
|
|
39
|
+
for (const collection of collectionsToCreate) {
|
|
40
|
+
if (!existingCollections.collections.some((c) => c.name === collection.name)) {
|
|
41
|
+
await tryAwaitWithRetry(async () => await databaseClient.createCollection(database.$id, ulid(), collection.name, undefined, true, true));
|
|
42
|
+
MessageFormatter.success(`${collection.name} collection created in ${database.name}`);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
};
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Example demonstrating YAML import/export with dual terminology support
|
|
3
|
+
*
|
|
4
|
+
* This example shows how to:
|
|
5
|
+
* 1. Generate YAML files for both collections and tables
|
|
6
|
+
* 2. Load and convert between terminologies
|
|
7
|
+
* 3. Validate terminology consistency
|
|
8
|
+
* 4. Migrate between formats
|
|
9
|
+
*/
|
|
10
|
+
import { type CollectionCreate } from "@njdamstra/appwrite-utils";
|
|
11
|
+
/**
|
|
12
|
+
* Example 1: Generate YAML templates for both collection and table formats
|
|
13
|
+
*/
|
|
14
|
+
export declare function generateTemplateExamples(outputDir: string): Promise<void>;
|
|
15
|
+
/**
|
|
16
|
+
* Example 2: Convert existing collection definition to different formats
|
|
17
|
+
*/
|
|
18
|
+
export declare function convertCollectionFormats(collection: CollectionCreate): void;
|
|
19
|
+
/**
|
|
20
|
+
* Example 3: Load and process YAML files with mixed terminologies
|
|
21
|
+
*/
|
|
22
|
+
export declare function processYamlFiles(baseDir: string): Promise<void>;
|
|
23
|
+
/**
|
|
24
|
+
* Example 4: Migrate between terminologies
|
|
25
|
+
*/
|
|
26
|
+
export declare function migrateTerminology(baseDir: string): Promise<void>;
|
|
27
|
+
/**
|
|
28
|
+
* Example 5: Validate terminology consistency
|
|
29
|
+
*/
|
|
30
|
+
export declare function validateTerminology(baseDir: string): Promise<void>;
|
|
31
|
+
/**
|
|
32
|
+
* Example 6: Import configuration with terminology support
|
|
33
|
+
*/
|
|
34
|
+
export declare function importConfigurationExample(appwriteFolderPath: string): Promise<void>;
|
|
35
|
+
/**
|
|
36
|
+
* Example 7: Manual terminology conversion
|
|
37
|
+
*/
|
|
38
|
+
export declare function manualTerminologyConversion(): void;
|
|
39
|
+
/**
|
|
40
|
+
* Main example runner
|
|
41
|
+
*/
|
|
42
|
+
export declare function runYamlTerminologyExamples(outputDir: string): Promise<void>;
|
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Example demonstrating YAML import/export with dual terminology support
|
|
3
|
+
*
|
|
4
|
+
* This example shows how to:
|
|
5
|
+
* 1. Generate YAML files for both collections and tables
|
|
6
|
+
* 2. Load and convert between terminologies
|
|
7
|
+
* 3. Validate terminology consistency
|
|
8
|
+
* 4. Migrate between formats
|
|
9
|
+
*/
|
|
10
|
+
import { collectionToYaml, generateYamlTemplate, generateExampleYamls, convertTerminology, normalizeYamlData, usesTableTerminology } from "../utils/yamlConverter.js";
|
|
11
|
+
import { createYamlLoader } from "../utils/yamlLoader.js";
|
|
12
|
+
import { YamlImportIntegration } from "../migrations/yaml/YamlImportIntegration.js";
|
|
13
|
+
import { createImportSchemas } from "../migrations/yaml/generateImportSchemas.js";
|
|
14
|
+
import { CollectionCreateSchema } from "@njdamstra/appwrite-utils";
|
|
15
|
+
import fs from "fs";
|
|
16
|
+
import path from "path";
|
|
17
|
+
/**
|
|
18
|
+
* Example 1: Generate YAML templates for both collection and table formats
|
|
19
|
+
*/
|
|
20
|
+
export async function generateTemplateExamples(outputDir) {
|
|
21
|
+
console.log("🚀 Generating YAML template examples...");
|
|
22
|
+
// Ensure output directories exist
|
|
23
|
+
const collectionsDir = path.join(outputDir, "collections");
|
|
24
|
+
const tablesDir = path.join(outputDir, "tables");
|
|
25
|
+
[collectionsDir, tablesDir].forEach(dir => {
|
|
26
|
+
if (!fs.existsSync(dir)) {
|
|
27
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
// Generate schemas first
|
|
31
|
+
await createImportSchemas(outputDir);
|
|
32
|
+
// Generate examples for both formats
|
|
33
|
+
const examples = generateExampleYamls("Product");
|
|
34
|
+
// Save collection format
|
|
35
|
+
const collectionPath = path.join(collectionsDir, "Product.yaml");
|
|
36
|
+
fs.writeFileSync(collectionPath, examples.collection);
|
|
37
|
+
console.log(`✅ Generated collection YAML: ${collectionPath}`);
|
|
38
|
+
// Save table format
|
|
39
|
+
const tablePath = path.join(tablesDir, "Product.yaml");
|
|
40
|
+
fs.writeFileSync(tablePath, examples.table);
|
|
41
|
+
console.log(`✅ Generated table YAML: ${tablePath}`);
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Example 2: Convert existing collection definition to different formats
|
|
45
|
+
*/
|
|
46
|
+
export function convertCollectionFormats(collection) {
|
|
47
|
+
console.log("🔄 Converting collection to different YAML formats...");
|
|
48
|
+
// Generate collection format YAML
|
|
49
|
+
const collectionConfig = {
|
|
50
|
+
useTableTerminology: false,
|
|
51
|
+
entityType: 'collection',
|
|
52
|
+
schemaPath: "../.yaml_schemas/collection.schema.json"
|
|
53
|
+
};
|
|
54
|
+
const collectionYaml = collectionToYaml(collection, collectionConfig);
|
|
55
|
+
console.log("📄 Collection Format YAML:");
|
|
56
|
+
console.log(collectionYaml);
|
|
57
|
+
console.log("");
|
|
58
|
+
// Generate table format YAML
|
|
59
|
+
const tableConfig = {
|
|
60
|
+
useTableTerminology: true,
|
|
61
|
+
entityType: 'table',
|
|
62
|
+
schemaPath: "../.yaml_schemas/table.schema.json"
|
|
63
|
+
};
|
|
64
|
+
const tableYaml = collectionToYaml(collection, tableConfig);
|
|
65
|
+
console.log("📄 Table Format YAML:");
|
|
66
|
+
console.log(tableYaml);
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Example 3: Load and process YAML files with mixed terminologies
|
|
70
|
+
*/
|
|
71
|
+
export async function processYamlFiles(baseDir) {
|
|
72
|
+
console.log("📂 Processing YAML files with terminology support...");
|
|
73
|
+
const yamlLoader = createYamlLoader(baseDir);
|
|
74
|
+
// Load all YAML files from collections directory
|
|
75
|
+
const collectionsResult = await yamlLoader.loadDirectoryYamls("collections");
|
|
76
|
+
console.log(`📊 Collections Summary:`, collectionsResult.summary);
|
|
77
|
+
// Load all YAML files from tables directory
|
|
78
|
+
const tablesResult = await yamlLoader.loadDirectoryYamls("tables");
|
|
79
|
+
console.log(`📊 Tables Summary:`, tablesResult.summary);
|
|
80
|
+
// Process each file and show terminology detection
|
|
81
|
+
console.log("\\n🔍 File Analysis:");
|
|
82
|
+
[...collectionsResult.collections, ...tablesResult.collections].forEach(file => {
|
|
83
|
+
const terminology = file.originalTerminology;
|
|
84
|
+
const hasColumns = usesTableTerminology(file.data);
|
|
85
|
+
console.log(` ${file.filePath}: ${terminology} format (uses table terminology: ${hasColumns})`);
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Example 4: Migrate between terminologies
|
|
90
|
+
*/
|
|
91
|
+
export async function migrateTerminology(baseDir) {
|
|
92
|
+
console.log("🔄 Migrating between terminologies...");
|
|
93
|
+
const yamlLoader = createYamlLoader(baseDir);
|
|
94
|
+
// Migrate collections to table format
|
|
95
|
+
console.log("\\n📤 Migrating collections to table format...");
|
|
96
|
+
const collectionToTableResult = await yamlLoader.migrateTerminology("collections", "migrated/tables", true // to table terminology
|
|
97
|
+
);
|
|
98
|
+
console.log(`✅ Migration complete: ${collectionToTableResult.migrated} migrated, ${collectionToTableResult.skipped} skipped`);
|
|
99
|
+
if (collectionToTableResult.errors.length > 0) {
|
|
100
|
+
console.log(`❌ Errors:`, collectionToTableResult.errors);
|
|
101
|
+
}
|
|
102
|
+
// Migrate tables to collection format
|
|
103
|
+
console.log("\\n📤 Migrating tables to collection format...");
|
|
104
|
+
const tableToCollectionResult = await yamlLoader.migrateTerminology("tables", "migrated/collections", false // to collection terminology
|
|
105
|
+
);
|
|
106
|
+
console.log(`✅ Migration complete: ${tableToCollectionResult.migrated} migrated, ${tableToCollectionResult.skipped} skipped`);
|
|
107
|
+
if (tableToCollectionResult.errors.length > 0) {
|
|
108
|
+
console.log(`❌ Errors:`, tableToCollectionResult.errors);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Example 5: Validate terminology consistency
|
|
113
|
+
*/
|
|
114
|
+
export async function validateTerminology(baseDir) {
|
|
115
|
+
console.log("🔍 Validating terminology consistency...");
|
|
116
|
+
const yamlLoader = createYamlLoader(baseDir);
|
|
117
|
+
// Validate collections directory
|
|
118
|
+
const collectionsValidation = await yamlLoader.validateTerminologyConsistency("collections");
|
|
119
|
+
console.log("\\n📂 Collections Directory:");
|
|
120
|
+
console.log(` Consistent: ${collectionsValidation.isConsistent}`);
|
|
121
|
+
console.log(` Summary:`, collectionsValidation.summary);
|
|
122
|
+
if (collectionsValidation.issues.length > 0) {
|
|
123
|
+
console.log(` Issues:`);
|
|
124
|
+
collectionsValidation.issues.forEach(issue => {
|
|
125
|
+
console.log(` ${issue.severity.toUpperCase()}: ${issue.file} - ${issue.issue}`);
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
// Validate tables directory
|
|
129
|
+
const tablesValidation = await yamlLoader.validateTerminologyConsistency("tables");
|
|
130
|
+
console.log("\\n📂 Tables Directory:");
|
|
131
|
+
console.log(` Consistent: ${tablesValidation.isConsistent}`);
|
|
132
|
+
console.log(` Summary:`, tablesValidation.summary);
|
|
133
|
+
if (tablesValidation.issues.length > 0) {
|
|
134
|
+
console.log(` Issues:`);
|
|
135
|
+
tablesValidation.issues.forEach(issue => {
|
|
136
|
+
console.log(` ${issue.severity.toUpperCase()}: ${issue.file} - ${issue.issue}`);
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Example 6: Import configuration with terminology support
|
|
142
|
+
*/
|
|
143
|
+
export async function importConfigurationExample(appwriteFolderPath) {
|
|
144
|
+
console.log("📥 Import configuration with terminology support...");
|
|
145
|
+
const yamlImportIntegration = new YamlImportIntegration(appwriteFolderPath);
|
|
146
|
+
// Initialize YAML import system
|
|
147
|
+
await yamlImportIntegration.initialize();
|
|
148
|
+
// Create example import configurations for both formats
|
|
149
|
+
console.log("\\n📝 Creating import configuration templates...");
|
|
150
|
+
// Collection format import config
|
|
151
|
+
await yamlImportIntegration.createFromTemplate("Users", "users.json", false, // collection terminology
|
|
152
|
+
"users-collection-import.yaml");
|
|
153
|
+
// Table format import config
|
|
154
|
+
await yamlImportIntegration.createFromTemplate("Users", "users.json", true, // table terminology
|
|
155
|
+
"users-table-import.yaml");
|
|
156
|
+
// Get statistics
|
|
157
|
+
const stats = await yamlImportIntegration.getStatistics();
|
|
158
|
+
console.log("\\n📊 Import Configuration Statistics:");
|
|
159
|
+
console.log(` Total configurations: ${stats.totalConfigurations}`);
|
|
160
|
+
console.log(` Collections with configs: ${stats.collectionsWithConfigs}`);
|
|
161
|
+
console.log(` Total attribute mappings: ${stats.totalAttributeMappings}`);
|
|
162
|
+
console.log(` Total relationship mappings: ${stats.totalRelationshipMappings}`);
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Example 7: Manual terminology conversion
|
|
166
|
+
*/
|
|
167
|
+
export function manualTerminologyConversion() {
|
|
168
|
+
console.log("🔧 Manual terminology conversion example...");
|
|
169
|
+
// Sample YAML data with collection terminology
|
|
170
|
+
const collectionData = {
|
|
171
|
+
name: "Product",
|
|
172
|
+
id: "product",
|
|
173
|
+
attributes: [
|
|
174
|
+
{
|
|
175
|
+
key: "name",
|
|
176
|
+
type: "string",
|
|
177
|
+
required: true,
|
|
178
|
+
relatedCollection: "Categories"
|
|
179
|
+
}
|
|
180
|
+
],
|
|
181
|
+
indexes: [
|
|
182
|
+
{
|
|
183
|
+
key: "name_index",
|
|
184
|
+
type: "key",
|
|
185
|
+
attributes: ["name"]
|
|
186
|
+
}
|
|
187
|
+
]
|
|
188
|
+
};
|
|
189
|
+
console.log("\\n📝 Original (Collection format):");
|
|
190
|
+
console.log(JSON.stringify(collectionData, null, 2));
|
|
191
|
+
// Convert to table terminology
|
|
192
|
+
const tableData = convertTerminology(collectionData, true);
|
|
193
|
+
console.log("\\n🔄 Converted to Table format:");
|
|
194
|
+
console.log(JSON.stringify(tableData, null, 2));
|
|
195
|
+
// Convert back to collection terminology
|
|
196
|
+
const normalizedData = normalizeYamlData(tableData);
|
|
197
|
+
console.log("\\n↩️ Normalized back to Collection format:");
|
|
198
|
+
console.log(JSON.stringify(normalizedData, null, 2));
|
|
199
|
+
// Terminology detection
|
|
200
|
+
console.log("\\n🔍 Terminology Detection:");
|
|
201
|
+
console.log(` Original uses table terminology: ${usesTableTerminology(collectionData)}`);
|
|
202
|
+
console.log(` Converted uses table terminology: ${usesTableTerminology(tableData)}`);
|
|
203
|
+
console.log(` Normalized uses table terminology: ${usesTableTerminology(normalizedData)}`);
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* Main example runner
|
|
207
|
+
*/
|
|
208
|
+
export async function runYamlTerminologyExamples(outputDir) {
|
|
209
|
+
console.log("🎯 Running YAML Terminology Examples\\n");
|
|
210
|
+
try {
|
|
211
|
+
// Example collection for demonstrations
|
|
212
|
+
const exampleCollectionInput = {
|
|
213
|
+
name: "Product",
|
|
214
|
+
$id: "product",
|
|
215
|
+
enabled: true,
|
|
216
|
+
documentSecurity: false,
|
|
217
|
+
$permissions: [],
|
|
218
|
+
attributes: [
|
|
219
|
+
{
|
|
220
|
+
key: "name",
|
|
221
|
+
type: "string",
|
|
222
|
+
required: true,
|
|
223
|
+
size: 255
|
|
224
|
+
},
|
|
225
|
+
{
|
|
226
|
+
key: "price",
|
|
227
|
+
type: "double",
|
|
228
|
+
required: true,
|
|
229
|
+
min: 0
|
|
230
|
+
},
|
|
231
|
+
{
|
|
232
|
+
key: "categoryId",
|
|
233
|
+
type: "relationship",
|
|
234
|
+
relationType: "manyToOne",
|
|
235
|
+
relatedCollection: "Categories",
|
|
236
|
+
twoWay: false,
|
|
237
|
+
onDelete: "setNull",
|
|
238
|
+
required: false
|
|
239
|
+
}
|
|
240
|
+
],
|
|
241
|
+
indexes: [
|
|
242
|
+
{
|
|
243
|
+
key: "name_index",
|
|
244
|
+
type: "key",
|
|
245
|
+
attributes: ["name"]
|
|
246
|
+
}
|
|
247
|
+
],
|
|
248
|
+
importDefs: []
|
|
249
|
+
};
|
|
250
|
+
const exampleCollection = CollectionCreateSchema.parse(exampleCollectionInput);
|
|
251
|
+
// Run examples
|
|
252
|
+
await generateTemplateExamples(outputDir);
|
|
253
|
+
console.log("\\n" + "=".repeat(60) + "\\n");
|
|
254
|
+
convertCollectionFormats(exampleCollection);
|
|
255
|
+
console.log("\\n" + "=".repeat(60) + "\\n");
|
|
256
|
+
await processYamlFiles(outputDir);
|
|
257
|
+
console.log("\\n" + "=".repeat(60) + "\\n");
|
|
258
|
+
await migrateTerminology(outputDir);
|
|
259
|
+
console.log("\\n" + "=".repeat(60) + "\\n");
|
|
260
|
+
await validateTerminology(outputDir);
|
|
261
|
+
console.log("\\n" + "=".repeat(60) + "\\n");
|
|
262
|
+
await importConfigurationExample(outputDir);
|
|
263
|
+
console.log("\\n" + "=".repeat(60) + "\\n");
|
|
264
|
+
manualTerminologyConversion();
|
|
265
|
+
console.log("\\n🎉 All examples completed successfully!");
|
|
266
|
+
}
|
|
267
|
+
catch (error) {
|
|
268
|
+
console.error("❌ Error running examples:", error);
|
|
269
|
+
throw error;
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
// Note: Functions are already exported above with their declarations
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { Client, type Models } from "node-appwrite";
|
|
2
|
+
import { type AppwriteFunction } from "@njdamstra/appwrite-utils";
|
|
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>;
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import { Client, Functions, Runtime } from "node-appwrite";
|
|
2
|
+
import { InputFile } from "node-appwrite/file";
|
|
3
|
+
import { create as createTarball } from "tar";
|
|
4
|
+
import { join, relative } from "node:path";
|
|
5
|
+
import fs from "node:fs";
|
|
6
|
+
import { platform } from "node:os";
|
|
7
|
+
import {} from "@njdamstra/appwrite-utils";
|
|
8
|
+
import chalk from "chalk";
|
|
9
|
+
import cliProgress from "cli-progress";
|
|
10
|
+
import { execSync } from "child_process";
|
|
11
|
+
import { createFunction, getFunction, updateFunction, updateFunctionSpecifications, } from "./methods.js";
|
|
12
|
+
import ignore from "ignore";
|
|
13
|
+
import { MessageFormatter } from "../shared/messageFormatter.js";
|
|
14
|
+
import { resolveFunctionDirectory, validateFunctionDirectory } from './pathResolution.js';
|
|
15
|
+
export const deployFunction = async (client, functionId, codePath, activate = true, entrypoint = "index.js", commands = "npm install", ignored = [
|
|
16
|
+
"node_modules",
|
|
17
|
+
".git",
|
|
18
|
+
".vscode",
|
|
19
|
+
".DS_Store",
|
|
20
|
+
"__pycache__",
|
|
21
|
+
".venv",
|
|
22
|
+
]) => {
|
|
23
|
+
const functions = new Functions(client);
|
|
24
|
+
MessageFormatter.processing("Preparing function deployment...", { prefix: "Deployment" });
|
|
25
|
+
// Convert ignored patterns to lowercase for case-insensitive comparison
|
|
26
|
+
const ignoredLower = ignored.map((pattern) => pattern.toLowerCase());
|
|
27
|
+
const tarPath = join(process.cwd(), `function-${functionId}.tar.gz`);
|
|
28
|
+
// Verify codePath exists and is a directory
|
|
29
|
+
if (!fs.existsSync(codePath)) {
|
|
30
|
+
throw new Error(`Function directory not found at ${codePath}`);
|
|
31
|
+
}
|
|
32
|
+
const stats = await fs.promises.stat(codePath);
|
|
33
|
+
if (!stats.isDirectory()) {
|
|
34
|
+
throw new Error(`${codePath} is not a directory`);
|
|
35
|
+
}
|
|
36
|
+
MessageFormatter.processing(`Creating tarball from ${codePath}`, { prefix: "Deployment" });
|
|
37
|
+
const progressBar = new cliProgress.SingleBar({
|
|
38
|
+
format: "Uploading |" +
|
|
39
|
+
chalk.cyan("{bar}") +
|
|
40
|
+
"| {percentage}% | {value}/{total} Chunks",
|
|
41
|
+
barCompleteChar: "█",
|
|
42
|
+
barIncompleteChar: "░",
|
|
43
|
+
hideCursor: true,
|
|
44
|
+
});
|
|
45
|
+
await createTarball({
|
|
46
|
+
gzip: true,
|
|
47
|
+
file: tarPath,
|
|
48
|
+
cwd: codePath,
|
|
49
|
+
filter: (path, stat) => {
|
|
50
|
+
const relativePath = relative(codePath, join(codePath, path)).toLowerCase();
|
|
51
|
+
// Skip if path matches any ignored pattern
|
|
52
|
+
if (ignoredLower.some((pattern) => relativePath.startsWith(pattern) ||
|
|
53
|
+
relativePath.includes(`/${pattern}`) ||
|
|
54
|
+
relativePath.includes(`\\${pattern}`))) {
|
|
55
|
+
MessageFormatter.debug(`Ignoring ${path}`, undefined, { prefix: "Deployment" });
|
|
56
|
+
return false;
|
|
57
|
+
}
|
|
58
|
+
return true;
|
|
59
|
+
},
|
|
60
|
+
}, ["."] // This now only includes contents of codePath since we set cwd to codePath
|
|
61
|
+
);
|
|
62
|
+
const fileBuffer = await fs.promises.readFile(tarPath);
|
|
63
|
+
const fileObject = InputFile.fromBuffer(new Uint8Array(fileBuffer), `function-${functionId}.tar.gz`);
|
|
64
|
+
try {
|
|
65
|
+
MessageFormatter.processing("Creating deployment...", { prefix: "Deployment" });
|
|
66
|
+
// Start with 1 as default total since we don't know the chunk size yet
|
|
67
|
+
progressBar.start(1, 0);
|
|
68
|
+
const functionResponse = await functions.createDeployment(functionId, fileObject, activate, entrypoint, commands, (progress) => {
|
|
69
|
+
const chunks = progress.chunksUploaded;
|
|
70
|
+
const total = progress.chunksTotal;
|
|
71
|
+
if (chunks !== undefined && total !== undefined) {
|
|
72
|
+
// First chunk, initialize the bar with correct total
|
|
73
|
+
if (chunks === 0) {
|
|
74
|
+
progressBar.start(total || 100, 0);
|
|
75
|
+
}
|
|
76
|
+
else {
|
|
77
|
+
progressBar.update(chunks);
|
|
78
|
+
// Check if upload is complete
|
|
79
|
+
if (chunks === total) {
|
|
80
|
+
progressBar.update(total);
|
|
81
|
+
progressBar.stop();
|
|
82
|
+
MessageFormatter.success("Upload complete!", { prefix: "Deployment" });
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
// Ensure progress bar completes even if callback never fired
|
|
88
|
+
if (progressBar.getProgress() === 0) {
|
|
89
|
+
progressBar.update(1);
|
|
90
|
+
progressBar.stop();
|
|
91
|
+
}
|
|
92
|
+
await fs.promises.unlink(tarPath);
|
|
93
|
+
return functionResponse;
|
|
94
|
+
}
|
|
95
|
+
catch (error) {
|
|
96
|
+
progressBar.stop();
|
|
97
|
+
MessageFormatter.error("Deployment failed", error instanceof Error ? error : undefined, { prefix: "Deployment" });
|
|
98
|
+
throw error;
|
|
99
|
+
}
|
|
100
|
+
};
|
|
101
|
+
export const deployLocalFunction = async (client, functionName, functionConfig, functionPath) => {
|
|
102
|
+
let functionExists = true;
|
|
103
|
+
let functionThatExists;
|
|
104
|
+
try {
|
|
105
|
+
functionThatExists = await getFunction(client, functionConfig.$id);
|
|
106
|
+
}
|
|
107
|
+
catch (error) {
|
|
108
|
+
functionExists = false;
|
|
109
|
+
}
|
|
110
|
+
const configDirPath = process.cwd(); // TODO: This should be passed from caller
|
|
111
|
+
const resolvedPath = resolveFunctionDirectory(functionName, configDirPath, functionConfig.dirPath, functionPath);
|
|
112
|
+
if (!validateFunctionDirectory(resolvedPath)) {
|
|
113
|
+
throw new Error(`Function directory is invalid or missing required files: ${resolvedPath}`);
|
|
114
|
+
}
|
|
115
|
+
if (functionConfig.predeployCommands?.length) {
|
|
116
|
+
MessageFormatter.processing("Executing predeploy commands...", { prefix: "Deployment" });
|
|
117
|
+
const isWindows = platform() === "win32";
|
|
118
|
+
for (const command of functionConfig.predeployCommands) {
|
|
119
|
+
try {
|
|
120
|
+
MessageFormatter.debug(`Executing: ${command}`, undefined, { prefix: "Deployment" });
|
|
121
|
+
execSync(command, {
|
|
122
|
+
cwd: resolvedPath,
|
|
123
|
+
stdio: "inherit",
|
|
124
|
+
shell: isWindows ? "cmd.exe" : "/bin/sh",
|
|
125
|
+
windowsHide: true,
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
catch (error) {
|
|
129
|
+
MessageFormatter.error(`Failed to execute predeploy command: ${command}`, error instanceof Error ? error : undefined, { prefix: "Deployment" });
|
|
130
|
+
throw new Error(``);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
// Only create function if it doesn't exist
|
|
135
|
+
if (!functionExists) {
|
|
136
|
+
await createFunction(client, functionConfig);
|
|
137
|
+
}
|
|
138
|
+
else {
|
|
139
|
+
MessageFormatter.processing("Updating function...", { prefix: "Deployment" });
|
|
140
|
+
await updateFunction(client, functionConfig);
|
|
141
|
+
}
|
|
142
|
+
const deployPath = functionConfig.deployDir
|
|
143
|
+
? join(resolvedPath, functionConfig.deployDir)
|
|
144
|
+
: resolvedPath;
|
|
145
|
+
return deployFunction(client, functionConfig.$id, deployPath, true, functionConfig.entrypoint, functionConfig.commands, functionConfig.ignore);
|
|
146
|
+
};
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { type AppwriteFunction } from '@njdamstra/appwrite-utils';
|
|
2
|
+
export declare function discoverFnConfigs(startDir: string): AppwriteFunction[];
|
|
3
|
+
export declare function mergeDiscoveredFunctions(central?: AppwriteFunction[], discovered?: AppwriteFunction[]): AppwriteFunction[];
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import yaml from 'js-yaml';
|
|
4
|
+
import { homedir } from 'node:os';
|
|
5
|
+
import { AppwriteFunctionSchema } from '@njdamstra/appwrite-utils';
|
|
6
|
+
import { shouldIgnoreDirectory } from '../utils/directoryUtils.js';
|
|
7
|
+
import { MessageFormatter } from '../shared/messageFormatter.js';
|
|
8
|
+
function findGitRoot(startDir) {
|
|
9
|
+
let dir = path.resolve(startDir);
|
|
10
|
+
while (dir !== path.parse(dir).root) {
|
|
11
|
+
if (fs.existsSync(path.join(dir, '.git')))
|
|
12
|
+
return dir;
|
|
13
|
+
const parent = path.dirname(dir);
|
|
14
|
+
if (parent === dir)
|
|
15
|
+
break;
|
|
16
|
+
dir = parent;
|
|
17
|
+
}
|
|
18
|
+
return path.resolve(startDir);
|
|
19
|
+
}
|
|
20
|
+
function expandTilde(p) {
|
|
21
|
+
if (!p)
|
|
22
|
+
return p;
|
|
23
|
+
if (p === '~' || p.startsWith('~/'))
|
|
24
|
+
return p.replace(/^~(?=$|\/|\\)/, homedir());
|
|
25
|
+
return p;
|
|
26
|
+
}
|
|
27
|
+
export function discoverFnConfigs(startDir) {
|
|
28
|
+
const root = findGitRoot(startDir);
|
|
29
|
+
const results = [];
|
|
30
|
+
const visit = (dir, depth = 0) => {
|
|
31
|
+
if (depth > 5)
|
|
32
|
+
return; // cap depth
|
|
33
|
+
const base = path.basename(dir);
|
|
34
|
+
if (shouldIgnoreDirectory(base))
|
|
35
|
+
return;
|
|
36
|
+
let entries = [];
|
|
37
|
+
try {
|
|
38
|
+
entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
39
|
+
}
|
|
40
|
+
catch {
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
// Check for .fnconfig.yaml / .fnconfig.yml
|
|
44
|
+
for (const fname of ['.fnconfig.yaml', '.fnconfig.yml']) {
|
|
45
|
+
const cfgPath = path.join(dir, fname);
|
|
46
|
+
if (fs.existsSync(cfgPath)) {
|
|
47
|
+
try {
|
|
48
|
+
const raw = fs.readFileSync(cfgPath, 'utf8');
|
|
49
|
+
const data = yaml.load(raw);
|
|
50
|
+
const parsed = AppwriteFunctionSchema.parse({
|
|
51
|
+
$id: data.id || data.$id,
|
|
52
|
+
name: data.name,
|
|
53
|
+
runtime: data.runtime,
|
|
54
|
+
execute: data.execute || [],
|
|
55
|
+
events: data.events || [],
|
|
56
|
+
schedule: data.schedule,
|
|
57
|
+
timeout: data.timeout,
|
|
58
|
+
enabled: data.enabled,
|
|
59
|
+
logging: data.logging,
|
|
60
|
+
entrypoint: data.entrypoint,
|
|
61
|
+
commands: data.commands,
|
|
62
|
+
scopes: data.scopes,
|
|
63
|
+
installationId: data.installationId,
|
|
64
|
+
providerRepositoryId: data.providerRepositoryId,
|
|
65
|
+
providerBranch: data.providerBranch,
|
|
66
|
+
providerSilentMode: data.providerSilentMode,
|
|
67
|
+
providerRootDirectory: data.providerRootDirectory,
|
|
68
|
+
templateRepository: data.templateRepository,
|
|
69
|
+
templateOwner: data.templateOwner,
|
|
70
|
+
templateRootDirectory: data.templateRootDirectory,
|
|
71
|
+
templateVersion: data.templateVersion,
|
|
72
|
+
specification: data.specification,
|
|
73
|
+
dirPath: data.dirPath,
|
|
74
|
+
predeployCommands: data.predeployCommands,
|
|
75
|
+
deployDir: data.deployDir,
|
|
76
|
+
ignore: data.ignore,
|
|
77
|
+
});
|
|
78
|
+
// Resolve dirPath relative to the config file directory
|
|
79
|
+
let dirPath = parsed.dirPath || '.';
|
|
80
|
+
dirPath = expandTilde(dirPath);
|
|
81
|
+
if (!path.isAbsolute(dirPath))
|
|
82
|
+
dirPath = path.resolve(path.dirname(cfgPath), dirPath);
|
|
83
|
+
const merged = { ...parsed, dirPath };
|
|
84
|
+
results.push(merged);
|
|
85
|
+
}
|
|
86
|
+
catch (e) {
|
|
87
|
+
MessageFormatter.warning(`Failed to parse ${cfgPath}: ${e instanceof Error ? e.message : String(e)}`, { prefix: 'Functions' });
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
for (const entry of entries) {
|
|
92
|
+
if (entry.isDirectory())
|
|
93
|
+
visit(path.join(dir, entry.name), depth + 1);
|
|
94
|
+
}
|
|
95
|
+
};
|
|
96
|
+
visit(root, 0);
|
|
97
|
+
return results;
|
|
98
|
+
}
|
|
99
|
+
export function mergeDiscoveredFunctions(central = [], discovered = []) {
|
|
100
|
+
const map = new Map();
|
|
101
|
+
for (const f of central)
|
|
102
|
+
if (f?.$id)
|
|
103
|
+
map.set(f.$id, f);
|
|
104
|
+
for (const f of discovered)
|
|
105
|
+
if (f?.$id)
|
|
106
|
+
map.set(f.$id, f); // discovered overrides
|
|
107
|
+
return Array.from(map.values());
|
|
108
|
+
}
|