diff --git a/.github/workflows/autoclose.yml b/.github/workflows/autoclose.yml deleted file mode 100644 index 3e2b3cbc..00000000 --- a/.github/workflows/autoclose.yml +++ /dev/null @@ -1,11 +0,0 @@ -name: Auto-close External Pull Requests - -on: - pull_request_target: - types: [opened, reopened] - -jobs: - auto_close: - uses: appwrite/.github/.github/workflows/autoclose.yml@main - secrets: - GH_AUTO_CLOSE_PR_TOKEN: ${{ secrets.GH_AUTO_CLOSE_PR_TOKEN }} diff --git a/.github/workflows/npm-publish.yml b/.github/workflows/npm-publish.yml index e29aa8b4..215bccd1 100644 --- a/.github/workflows/npm-publish.yml +++ b/.github/workflows/npm-publish.yml @@ -1,47 +1,59 @@ name: Publish Package to npmjs + on: release: types: [published] + +permissions: + id-token: write + contents: read + jobs: - build-for-linux-and-windows: + build-and-publish: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 - - uses: actions/setup-node@v2 + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 with: - node-version: '16.x' + node-version: '22' registry-url: 'https://registry.npmjs.org' + + - name: Update npm to latest version for OIDC support + run: npm install -g npm@latest + - name: Setup binfmt with QEMU run: | sudo apt update sudo apt install qemu-system binfmt-support qemu-user-static update-binfmts --display + - name: Setup ldid run: | git clone https://github.com/tpoechtrager/ldid cd ./ldid sudo make sudo make install - - name: Install dependenices and build for Linux and Windows + + - name: Install dependencies and build for Linux and Windows run: | - npm install + npm ci npm run linux-x64 npm run linux-arm64 npm run windows-x64 npm run windows-arm64 npm run mac-x64 npm run mac-arm64 + - name: Publish NPM library run: | if ${{ contains(github.event.release.tag_name, '-rc') }}; then echo "Publishing Release Candidate ${{ github.event.release.tag_name}} to NPM" - npm publish --tag next + npm publish --provenance --access public --tag next else echo "Publishing ${{ github.event.release.tag_name}} to NPM" - npm publish + npm publish --provenance --access public fi - env: - NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN_NO_ORG }} + - uses: fnkr/github-action-ghr@v1 env: GHR_PATH: build/ diff --git a/.gitignore b/.gitignore index 5e37476a..8cd6d728 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ node_modules/ build/ -.DS_Store \ No newline at end of file +.DS_Store +dist/ \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index fbc157e9..e9a30d38 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,12 @@ # Change Log -## 13.0.0-rc.1 +## 13.0.0-rc.2 -* Migrates codebase from JavaScript to TypeScript +- Fixes a lot of typescript errors throughout the codebase + +## 13.0.0-rc.2 + +- Migrates codebase from JavaScript to TypeScript ## 12.0.1 @@ -10,176 +14,176 @@ Fix type generation for `point`, `lineString` and `polygon` columns ## 12.0.0 -* Change `create-deployment-template`'s `version` parameter to `type` and `reference`. eg. usage - `create-deployment-template --type tag --reference 1.0.0` -* Remove `bucket-id` parameter from `create-csv-export` command -* Allow enabling or disabling of image `transformations` in a bucket -* Fix type generation for `point`, `lineString` and `polygon` columns +- Change `create-deployment-template`'s `version` parameter to `type` and `reference`. eg. usage - `create-deployment-template --type tag --reference 1.0.0` +- Remove `bucket-id` parameter from `create-csv-export` command +- Allow enabling or disabling of image `transformations` in a bucket +- Fix type generation for `point`, `lineString` and `polygon` columns ## 11.1.1 -* Fix duplicate `enums` during type generation by prefixing them with table name. For example, `enum MyEnum` will now be generated as `enum MyTableMyEnum` to avoid conflicts. +- Fix duplicate `enums` during type generation by prefixing them with table name. For example, `enum MyEnum` will now be generated as `enum MyTableMyEnum` to avoid conflicts. ## 11.1.0 -* Add `total` parameter to list queries allowing skipping counting rows in a table for improved performance +- Add `total` parameter to list queries allowing skipping counting rows in a table for improved performance ## 11.0.0 -* Rename `create-csv-migration` to `create-csv-import` command to create a CSV import of a collection/table -* Add `create-csv-export` command to create a CSV export of a collection/table -* Add `create-resend-provider` and `update-resend-provider` commands to create and update a Resend Email provider -* Fix syncing of tables deleted locally during `push tables` command -* Fix added push command support for cli spatial types -* Fix attribute changing during push -* Replace pkg with @yao-pkg/pkg in dependencies +- Rename `create-csv-migration` to `create-csv-import` command to create a CSV import of a collection/table +- Add `create-csv-export` command to create a CSV export of a collection/table +- Add `create-resend-provider` and `update-resend-provider` commands to create and update a Resend Email provider +- Fix syncing of tables deleted locally during `push tables` command +- Fix added push command support for cli spatial types +- Fix attribute changing during push +- Replace pkg with @yao-pkg/pkg in dependencies ## 10.2.3 -* Fix `init tables` command not working -* Improve tablesDB resource syncing during `push tables` command +- Fix `init tables` command not working +- Improve tablesDB resource syncing during `push tables` command ## 10.2.2 -* Fix `logout` command showing duplicate sessions -* Fix `logout` command showing a blank email even when logged out -* Add syncing of `tablesDB` resource during `push tables` command +- Fix `logout` command showing duplicate sessions +- Fix `logout` command showing a blank email even when logged out +- Add syncing of `tablesDB` resource during `push tables` command ## 10.2.1 -* Add transaction support for Databases and TablesDB +- Add transaction support for Databases and TablesDB ## 10.1.0 -* Deprecate `createVerification` method in `Account` service -* Add `createEmailVerification` method in `Account` service +- Deprecate `createVerification` method in `Account` service +- Add `createEmailVerification` method in `Account` service ## 10.0.1 -* Fix CLI Dart model generation issues -* Fix row permissions and security sync -* Fix error when pushing columns with relationships -* Fix resource name from attributes to columns for TablesDB indexes +- Fix CLI Dart model generation issues +- Fix row permissions and security sync +- Fix error when pushing columns with relationships +- Fix resource name from attributes to columns for TablesDB indexes ## 10.0.0 -* **Breaking:** Removed Avatars CLI command and all related subcommands; corresponding examples deleted -* **Feat:** Geo defaults now accept coordinate arrays for Databases and Tables DB, with automatic normalization -* **Feat:** Pull command skips deprecated resources by default and shows clearer totals/messages -* **Feat:** Updated CLI descriptions: Databases marked legacy; added tables-db, projects, and project -* Fix TypeScript type generation now quotes invalid property names to produce valid typings -* Update documentation: Removed Avatars CLI examples and updated help text to reflect new geo defaults and terminology +- **Breaking:** Removed Avatars CLI command and all related subcommands; corresponding examples deleted +- **Feat:** Geo defaults now accept coordinate arrays for Databases and Tables DB, with automatic normalization +- **Feat:** Pull command skips deprecated resources by default and shows clearer totals/messages +- **Feat:** Updated CLI descriptions: Databases marked legacy; added tables-db, projects, and project +- Fix TypeScript type generation now quotes invalid property names to produce valid typings +- Update documentation: Removed Avatars CLI examples and updated help text to reflect new geo defaults and terminology ## 8.3.0 -* **Feat:** Add support for `appwrite.config.json` file - * All new projects will be initialized with this configuration file - * Resolves bundler conflicts (e.g., Vite) that incorrectly interpret `.json` files as library imports -* Add `incrementDocumentAttribute` and `decrementDocumentAttribute` support to `Databases` service -* Type generation fixes: - * Fix relationships using the relatedCollection's id instead of name - * Update auto generated comment to show relative path instead of absolute path +- **Feat:** Add support for `appwrite.config.json` file + - All new projects will be initialized with this configuration file + - Resolves bundler conflicts (e.g., Vite) that incorrectly interpret `.json` files as library imports +- Add `incrementDocumentAttribute` and `decrementDocumentAttribute` support to `Databases` service +- Type generation fixes: + - Fix relationships using the relatedCollection's id instead of name + - Update auto generated comment to show relative path instead of absolute path > **Note:** The existing `appwrite.json` file remains fully supported for backward compatibility ## 8.2.2 -* Fix object comparison logic when pushing settings -* Type generation fixes: - * Dart: Fixed import casing to snake_case, removed `extends Document` and hardcoded attributes, removed unnecessary imports - * Java: Fixed indentation to 4 spaces, updated imports to `java.util.Objects`, fixed enum casing in strict mode as per [Oracle official docs](https://docs.oracle.com/javase/tutorial/java/javaOO/enum.html) - * Javascript: Updated optional values formatting from `|null` to `| null` - * Kotlin: Fixed indentation to 4 spaces per [Kotlinlang official docs](https://kotlinlang.org/docs/coding-conventions.html#indentation) - * PHP: Fixed indentation to 4 spaces per [PHP Fig official docs](https://www.php-fig.org/psr/psr-2/) - * Swift: Fixed indentation to 4 spaces, improved `decodeIfPresent` usage for optionals, added missing `public` to `init` method - * Typescript: Fixed indentation to 4 spaces per [Typescript coding guidelines](https://github.com/microsoft/TypeScript/wiki/Coding-guidelines) +- Fix object comparison logic when pushing settings +- Type generation fixes: + - Dart: Fixed import casing to snake_case, removed `extends Document` and hardcoded attributes, removed unnecessary imports + - Java: Fixed indentation to 4 spaces, updated imports to `java.util.Objects`, fixed enum casing in strict mode as per [Oracle official docs](https://docs.oracle.com/javase/tutorial/java/javaOO/enum.html) + - Javascript: Updated optional values formatting from `|null` to `| null` + - Kotlin: Fixed indentation to 4 spaces per [Kotlinlang official docs](https://kotlinlang.org/docs/coding-conventions.html#indentation) + - PHP: Fixed indentation to 4 spaces per [PHP Fig official docs](https://www.php-fig.org/psr/psr-2/) + - Swift: Fixed indentation to 4 spaces, improved `decodeIfPresent` usage for optionals, added missing `public` to `init` method + - Typescript: Fixed indentation to 4 spaces per [Typescript coding guidelines](https://github.com/microsoft/TypeScript/wiki/Coding-guidelines) ## 8.2.1 -* Added `--with-variables` option to the Sites command for adding/updating environment variables -* Fixed Functions environment variables not being pushed with `--with-variables` -* Removed `awaitPools` when wiping old variables +- Added `--with-variables` option to the Sites command for adding/updating environment variables +- Fixed Functions environment variables not being pushed with `--with-variables` +- Removed `awaitPools` when wiping old variables > **Note:** Storing environment variables in the `vars` attribute of `appwrite.json` is now deprecated due to security risks. Variables are now synced directly from the `.env` file in the root directory of the function’s or site’s folder. ## 8.2.0 -* Add `encrypt` attribute support -* Add improved warnings on attribute recreation and deletion -* Fix `null` parsing error when using create attribute command -* Type generation fixes and improvements: - * Add `--strict` / `-s` flag to `appwrite types` command to generate types in strict mode. This automatically converts the casing of attributes to match the language's naming conventions - * Add automatic package import to `dart` language which uses package detection to import the correct package - * Add `Document` class extension to generated types in `dart` and `js` language to support internal attributes like `$id` and `$collectionId` etc. - * Add proper enum support to `js` language - * Fix indentation in `java`, `kotlin` and `swift` to use 2 spaces instead of 4 for consistency across all languages - * Fix doc comments to use correct syntax in various languages (for eg. `///` instead of `/*`) - * Update enums in `dart` to use lowerCamelCase in `strict` mode as per [constant_identifier_names](https://dart.dev/tools/diagnostics/constant_identifier_names?utm_source=dartdev&utm_medium=redir&utm_id=diagcode&utm_content=constant_identifier_names) +- Add `encrypt` attribute support +- Add improved warnings on attribute recreation and deletion +- Fix `null` parsing error when using create attribute command +- Type generation fixes and improvements: + - Add `--strict` / `-s` flag to `appwrite types` command to generate types in strict mode. This automatically converts the casing of attributes to match the language's naming conventions + - Add automatic package import to `dart` language which uses package detection to import the correct package + - Add `Document` class extension to generated types in `dart` and `js` language to support internal attributes like `$id` and `$collectionId` etc. + - Add proper enum support to `js` language + - Fix indentation in `java`, `kotlin` and `swift` to use 2 spaces instead of 4 for consistency across all languages + - Fix doc comments to use correct syntax in various languages (for eg. `///` instead of `/*`) + - Update enums in `dart` to use lowerCamelCase in `strict` mode as per [constant_identifier_names](https://dart.dev/tools/diagnostics/constant_identifier_names?utm_source=dartdev&utm_medium=redir&utm_id=diagcode&utm_content=constant_identifier_names) ## 8.1.1 -* Fix circular dependency issue due to usage of `success` method in `utils.js` file from `parser.js` file -* Type generation fixes: - * Add ability to generate types directly to a specific file by passing a file path to `appwrite types output_path`, instead of just a directory - * Fix non-required attributes to not be null if default value is provided - * Fix `Models` import error - * Improve formatting and add auto-generated comments +- Fix circular dependency issue due to usage of `success` method in `utils.js` file from `parser.js` file +- Type generation fixes: + - Add ability to generate types directly to a specific file by passing a file path to `appwrite types output_path`, instead of just a directory + - Fix non-required attributes to not be null if default value is provided + - Fix `Models` import error + - Improve formatting and add auto-generated comments ## 8.1.0 -* Add multi-region support to `init` command -* Update `init` command to clear previous configuration in `appwrite.json` -* Update localConfig to store multi-region endpoint -* Fix throw error when creating unknown attribute instead of timing out -* Fix equal comparison of large numbers and BigNumber instances using proper equality checks -* Fix duplication of reasons when comparing localConfig with remoteConfig -* Fix `firstOrNull()` to `firstOrNull` in types generation for dart -* Refactor to use `isCloud()` method consistently +- Add multi-region support to `init` command +- Update `init` command to clear previous configuration in `appwrite.json` +- Update localConfig to store multi-region endpoint +- Fix throw error when creating unknown attribute instead of timing out +- Fix equal comparison of large numbers and BigNumber instances using proper equality checks +- Fix duplication of reasons when comparing localConfig with remoteConfig +- Fix `firstOrNull()` to `firstOrNull` in types generation for dart +- Refactor to use `isCloud()` method consistently ## 8.0.2 -* Add Type generation fixes: - * Properly handle enum attributes in dart, java and kotlin - * Fix initialisation of null attributes in dart's fromMap method - * Fix relationships and enums in swift +- Add Type generation fixes: + - Properly handle enum attributes in dart, java and kotlin + - Fix initialisation of null attributes in dart's fromMap method + - Fix relationships and enums in swift ## 8.0.1 -* Add `resourceId` and `resourceType` attributes to `createRedirectRule` -* Add `providerReference` to vcs command for getting repository contents -* Add warning comment to `bulk updateDocuments` method -* Fix type generation for enums in Typescript and PHP language +- Add `resourceId` and `resourceType` attributes to `createRedirectRule` +- Add `providerReference` to vcs command for getting repository contents +- Add warning comment to `bulk updateDocuments` method +- Fix type generation for enums in Typescript and PHP language ## 8.0.0 -* Add `types` command to generate language specific typings for collections. Currently supports - `php`, `swift`, `dart`, `js`, `ts`, `kotlin` and `java` -* Update bulk operation docs to include experiment feature warnings -* Remove assistant service and commands +- Add `types` command to generate language specific typings for collections. Currently supports - `php`, `swift`, `dart`, `js`, `ts`, `kotlin` and `java` +- Update bulk operation docs to include experiment feature warnings +- Remove assistant service and commands ## 7.0.0 -* Add `sites` command -* Add `tokens` command -* Add `devKeys` support to `projects` command -* Add `init site`, `pull site` and `push site` commands -* Add bulk operation methods like `createDocuments`, `deleteDocuments` etc. -* Add new upsert methods: `upsertDocument` and `upsertDocuments` -* Update GET requests to not include content-type header +- Add `sites` command +- Add `tokens` command +- Add `devKeys` support to `projects` command +- Add `init site`, `pull site` and `push site` commands +- Add bulk operation methods like `createDocuments`, `deleteDocuments` etc. +- Add new upsert methods: `upsertDocument` and `upsertDocuments` +- Update GET requests to not include content-type header ## 6.2.3 -* Fix hot swapping error in `python-ml` function +- Fix hot swapping error in `python-ml` function ## 6.2.2 -* Fix GitHub builds by adding `qemu-system` package -* Fix attribute creation timed out +- Fix GitHub builds by adding `qemu-system` package +- Fix attribute creation timed out ## 6.2.1 -* Add `listOrganizations` method to `organizations` service and fix init project command +- Add `listOrganizations` method to `organizations` service and fix init project command ## 6.2.0 -* Add specifications support to CLI -* Update package version -* Fix: Missed specifications param when updating a function \ No newline at end of file +- Add specifications support to CLI +- Update package version +- Fix: Missed specifications param when updating a function diff --git a/LICENSE.md b/LICENSE.md index c1602fcd..c64456ce 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -9,4 +9,4 @@ Redistribution and use in source and binary forms, with or without modification, 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/README.md b/README.md index f1cdf543..608fb2ca 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # Appwrite Command Line SDK ![License](https://img.shields.io/github/license/appwrite/sdk-for-cli.svg?style=flat-square) -![Version](https://img.shields.io/badge/api%20version-1.8.0-blue.svg?style=flat-square) +![Version](https://img.shields.io/badge/api%20version-1.8.1-blue.svg?style=flat-square) [![Build Status](https://img.shields.io/travis/com/appwrite/sdk-generator?style=flat-square)](https://travis-ci.com/appwrite/sdk-generator) [![Twitter Account](https://img.shields.io/twitter/follow/appwrite?color=00acee&label=twitter&style=flat-square)](https://twitter.com/appwrite) [![Discord](https://img.shields.io/discord/564160730845151244?label=discord&style=flat-square)](https://appwrite.io/discord) @@ -17,6 +17,7 @@ Appwrite is an open-source backend as a service server that abstract and simplif The Appwrite CLI is a Node based command line tool to help you interact with the Appwrite API. The CLI is distributed both as an [`npm package`](https://www.npmjs.com/package/appwrite-cli) as well as [pre built binaries](https://github.com/appwrite/sdk-for-cli/releases/latest) for specific operating systems and architectures. ### Install using NPM + --- If you have `npm` installed, it's as easy as running @@ -29,55 +30,64 @@ Once the installation is complete, you can verify the install using ```sh $ appwrite -v -13.0.0-rc.1 +13.0.0-rc.2 ``` ### Install using prebuilt binaries + --- If you do not have `npm` installed, you can always install the prebuilt binaries for your architecture and OS using our convenient installation scripts. ### Linux / MacOS Terminal + ```bash $ wget -q https://appwrite.io/cli/install.sh -O - | /bin/bash ``` ### MacOS via [Homebrew](https://brew.sh) + ```bash -$ brew install appwrite +$ brew install appwrite ``` ### Windows + Via Powershell + ```powershell $ iwr -useb https://appwrite.io/cli/install.ps1 | iex ``` + Via [Scoop](https://scoop.sh) + ```powershell $ scoop install https://raw.githubusercontent.com/appwrite/sdk-for-cli/master/scoop/appwrite.config.json ``` Once the installation completes, you can verify your install using + ``` $ appwrite -v -13.0.0-rc.1 +13.0.0-rc.2 ``` -## Getting Started +## Getting Started -Before you can use the CLI, you need to login to your Appwrite account. +Before you can use the CLI, you need to login to your Appwrite account. ```sh $ appwrite login ? Enter your email test@test.com ? Enter your password ******** -✓ Success +✓ Success ``` -This will also prompt you to enter your Appwrite endpoint ( default: http://localhost/v1 ) -* ### Initialising your project -Once logged in, the CLI needs to be initialised before you can use it with your Appwrite project. You can do this with the `appwrite init project` command. +This will also prompt you to enter your Appwrite endpoint ( default: http://localhost/v1 ) + +- ### Initialising your project + Once logged in, the CLI needs to be initialised before you can use it with your Appwrite project. You can do this with the `appwrite init project` command. ```sh $ appwrite init project @@ -85,18 +95,20 @@ $ appwrite init project The following prompt will guide you through the setup process. The `init` command also creates an `appwrite.json` file representing your Appwrite project. -The `appwrite.json` file does a lot of things. -* Provides context to the CLI -* Keeps track of all your cloud functions -* Keeps track of all your project's collections -* Helps you deploy your Appwrite project to production and more.. +The `appwrite.json` file does a lot of things. + +- Provides context to the CLI +- Keeps track of all your cloud functions +- Keeps track of all your project's collections +- Helps you deploy your Appwrite project to production and more.. You can also fetch all the collections in your current project using + ```sh appwrite init collection ``` -* ### Creating and deploying cloud functions +- ### Creating and deploying cloud functions The CLI makes it extremely easy to create and deploy Appwrite's cloud functions. Initialise your new function using @@ -104,13 +116,13 @@ The CLI makes it extremely easy to create and deploy Appwrite's cloud functions. $ appwrite init function ? What would you like to name your function? My Awesome Function ? What runtime would you like to use? Node.js (node-15.5) -✓ Success +✓ Success ``` This will create a new function `My Awesome Function` in your current Appwrite project and also create a template function for you to get started. ```sh -$ tree My\ Awesome\ Function +$ tree My\ Awesome\ Function My Awesome Function ├── README.md @@ -121,7 +133,7 @@ My Awesome Function 0 directories, 4 files ``` -You can now deploy this function using +You can now deploy this function using ```sh $ appwrite push function @@ -133,50 +145,56 @@ $ appwrite push function Your function has now been deployed on your Appwrite server! As soon as the build process is finished, you can start executing the function. -* ### Deploying Collections +- ### Deploying Collections -Similarly, you can deploy all your collections to your Appwrite server using +Similarly, you can deploy all your collections to your Appwrite server using ```sh appwrite push collections ``` > ### Note +> > By default, requests to domains with self signed SSL certificates (or no certificates) are disabled. If you trust the domain, you can bypass the certificate validation using + ```sh $ appwrite client --selfSigned true ``` -## Usage +## Usage The Appwrite CLI follows the following general syntax. + ```sh $ appwrite [COMMAND] --[OPTIONS] ``` -A few sample commands to get you started +A few sample commands to get you started ```sh $ appwrite users create --userId "unique()" --email hello@appwrite.io --password very_strong_password -$ appwrite users list +$ appwrite users list ``` -To create a document you can use the following command +To create a document you can use the following command + ```sh $ appwrite databases create-document --database-id --collection-id --document-id "unique()" --data '{"name": "Walter O Brein"}' --permissions 'read("any")' 'read("team:abc")' ``` ### Some Gotchas + - `data` must be a valid JSON string where each key and value are enclosed in double quotes `"` like the example above. - Some arguments like the `read` and `write` permissions are expected to be arrays. In the Appwrite CLI, array values are passed in using space as a separator like in the example above. +To get information about the different services available, you can use -To get information about the different services available, you can use ```sh $ appwrite -h ``` -To get information about a particular service and the commands available in a service you can use +To get information about a particular service and the commands available in a service you can use + ```sh $ appwrite users // or $ appwrite users --help // or @@ -188,7 +206,7 @@ To get information about a particular command and the parameters it accepts, you ```sh $ appwrite users list --help -$ appwrite account get --help +$ appwrite account get --help ``` At any point, you can view or reset the CLI configuration using the `client` service. @@ -201,27 +219,28 @@ $ appwrite client --reset ## CI mode -The Appwrite CLI can also work in a CI environment. The initialisation of the CLI works a bit differently in CI. In CI, you set your `endpoint`, `projectId` and `API Key` using +The Appwrite CLI can also work in a CI environment. The initialisation of the CLI works a bit differently in CI. In CI, you set your `endpoint`, `projectId` and `API Key` using ```sh appwrite client --endpoint http://localhost/v1 --projectId --key ``` - ## Contribution This library is auto-generated by Appwrite custom [SDK Generator](https://github.com/appwrite/sdk-generator). To learn more about how you can help us improve this SDK, please check the [contribution guide](https://github.com/appwrite/sdk-generator/blob/master/CONTRIBUTING.md) before sending a pull-request. -To build and test the CLI for development, follow these steps +To build and test the CLI for development, follow these steps 1. Clone the SDK Generator repository and cd into the directory + ```sh $ git clone https://github.com/appwrite/sdk-generator $ cd sdk-generator ``` 2. Ensure Docker is running locally and then install the composer dependencies using -```sh + +```sh $ docker run --rm --interactive --tty --volume "$(pwd)":/app composer install --ignore-platform-reqs --optimize-autoloader --no-plugins --no-scripts --prefer-dist # Generate the SDKs @@ -229,20 +248,24 @@ $ docker run --rm -v $(pwd):/app -w /app php:8.1-cli php example.php ``` 3. Head over to the generated SDK and install the dependencies. + ```sh $ cd examples/cli -$ npm install +$ npm install ``` -4. Install the CLI using +4. Install the CLI using + ```sh $ npm install -g . ``` -5. You can now use the CLI +5. You can now use the CLI + ```sh $ appwrite -v ``` + ## License Please see the [BSD-3-Clause license](https://raw.githubusercontent.com/appwrite/appwrite/master/LICENSE) file for more information. diff --git a/bun.lock b/bun.lock new file mode 100644 index 00000000..9459f426 --- /dev/null +++ b/bun.lock @@ -0,0 +1,401 @@ +{ + "lockfileVersion": 1, + "workspaces": { + "": { + "name": "appwrite-cli", + "dependencies": { + "@appwrite.io/console": "^2.1.0", + "chalk": "4.1.2", + "chokidar": "^3.6.0", + "cli-progress": "^3.12.0", + "cli-table3": "^0.6.2", + "commander": "^9.2.0", + "dotenv": "^16.4.5", + "ejs": "^3.1.9", + "form-data": "^4.0.0", + "ignore": "^7.0.5", + "inquirer": "^8.2.4", + "inquirer-search-list": "^1.2.6", + "json-bigint": "^1.0.0", + "tail": "^2.2.6", + "tar": "^6.1.11", + "undici": "^5.28.2", + }, + "devDependencies": { + "@types/cli-progress": "^3.11.5", + "@types/inquirer": "^8.2.10", + "@types/json-bigint": "^1.0.4", + "@types/node": "^18.19.0", + "@types/tar": "^6.1.11", + "prettier": "^3.7.4", + "tsx": "^4.21.0", + "typescript": "^5.3.3", + }, + }, + }, + "packages": { + "@appwrite.io/console": ["@appwrite.io/console@2.1.0", "", {}, "sha512-5xomd3h1g3JXu0FaGkZDrtgDxmkoMriFRUtTZuxSLlVD2IpACAV2vHggauKS97ebYJHjROlCRNWpvOZ0bggwUA=="], + + "@colors/colors": ["@colors/colors@1.5.0", "", {}, "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ=="], + + "@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.27.2", "", { "os": "aix", "cpu": "ppc64" }, "sha512-GZMB+a0mOMZs4MpDbj8RJp4cw+w1WV5NYD6xzgvzUJ5Ek2jerwfO2eADyI6ExDSUED+1X8aMbegahsJi+8mgpw=="], + + "@esbuild/android-arm": ["@esbuild/android-arm@0.27.2", "", { "os": "android", "cpu": "arm" }, "sha512-DVNI8jlPa7Ujbr1yjU2PfUSRtAUZPG9I1RwW4F4xFB1Imiu2on0ADiI/c3td+KmDtVKNbi+nffGDQMfcIMkwIA=="], + + "@esbuild/android-arm64": ["@esbuild/android-arm64@0.27.2", "", { "os": "android", "cpu": "arm64" }, "sha512-pvz8ZZ7ot/RBphf8fv60ljmaoydPU12VuXHImtAs0XhLLw+EXBi2BLe3OYSBslR4rryHvweW5gmkKFwTiFy6KA=="], + + "@esbuild/android-x64": ["@esbuild/android-x64@0.27.2", "", { "os": "android", "cpu": "x64" }, "sha512-z8Ank4Byh4TJJOh4wpz8g2vDy75zFL0TlZlkUkEwYXuPSgX8yzep596n6mT7905kA9uHZsf/o2OJZubl2l3M7A=="], + + "@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.27.2", "", { "os": "darwin", "cpu": "arm64" }, "sha512-davCD2Zc80nzDVRwXTcQP/28fiJbcOwvdolL0sOiOsbwBa72kegmVU0Wrh1MYrbuCL98Omp5dVhQFWRKR2ZAlg=="], + + "@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.27.2", "", { "os": "darwin", "cpu": "x64" }, "sha512-ZxtijOmlQCBWGwbVmwOF/UCzuGIbUkqB1faQRf5akQmxRJ1ujusWsb3CVfk/9iZKr2L5SMU5wPBi1UWbvL+VQA=="], + + "@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.27.2", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-lS/9CN+rgqQ9czogxlMcBMGd+l8Q3Nj1MFQwBZJyoEKI50XGxwuzznYdwcav6lpOGv5BqaZXqvBSiB/kJ5op+g=="], + + "@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.27.2", "", { "os": "freebsd", "cpu": "x64" }, "sha512-tAfqtNYb4YgPnJlEFu4c212HYjQWSO/w/h/lQaBK7RbwGIkBOuNKQI9tqWzx7Wtp7bTPaGC6MJvWI608P3wXYA=="], + + "@esbuild/linux-arm": ["@esbuild/linux-arm@0.27.2", "", { "os": "linux", "cpu": "arm" }, "sha512-vWfq4GaIMP9AIe4yj1ZUW18RDhx6EPQKjwe7n8BbIecFtCQG4CfHGaHuh7fdfq+y3LIA2vGS/o9ZBGVxIDi9hw=="], + + "@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.27.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-hYxN8pr66NsCCiRFkHUAsxylNOcAQaxSSkHMMjcpx0si13t1LHFphxJZUiGwojB1a/Hd5OiPIqDdXONia6bhTw=="], + + "@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.27.2", "", { "os": "linux", "cpu": "ia32" }, "sha512-MJt5BRRSScPDwG2hLelYhAAKh9imjHK5+NE/tvnRLbIqUWa+0E9N4WNMjmp/kXXPHZGqPLxggwVhz7QP8CTR8w=="], + + "@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.27.2", "", { "os": "linux", "cpu": "none" }, "sha512-lugyF1atnAT463aO6KPshVCJK5NgRnU4yb3FUumyVz+cGvZbontBgzeGFO1nF+dPueHD367a2ZXe1NtUkAjOtg=="], + + "@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.27.2", "", { "os": "linux", "cpu": "none" }, "sha512-nlP2I6ArEBewvJ2gjrrkESEZkB5mIoaTswuqNFRv/WYd+ATtUpe9Y09RnJvgvdag7he0OWgEZWhviS1OTOKixw=="], + + "@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.27.2", "", { "os": "linux", "cpu": "ppc64" }, "sha512-C92gnpey7tUQONqg1n6dKVbx3vphKtTHJaNG2Ok9lGwbZil6DrfyecMsp9CrmXGQJmZ7iiVXvvZH6Ml5hL6XdQ=="], + + "@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.27.2", "", { "os": "linux", "cpu": "none" }, "sha512-B5BOmojNtUyN8AXlK0QJyvjEZkWwy/FKvakkTDCziX95AowLZKR6aCDhG7LeF7uMCXEJqwa8Bejz5LTPYm8AvA=="], + + "@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.27.2", "", { "os": "linux", "cpu": "s390x" }, "sha512-p4bm9+wsPwup5Z8f4EpfN63qNagQ47Ua2znaqGH6bqLlmJ4bx97Y9JdqxgGZ6Y8xVTixUnEkoKSHcpRlDnNr5w=="], + + "@esbuild/linux-x64": ["@esbuild/linux-x64@0.27.2", "", { "os": "linux", "cpu": "x64" }, "sha512-uwp2Tip5aPmH+NRUwTcfLb+W32WXjpFejTIOWZFw/v7/KnpCDKG66u4DLcurQpiYTiYwQ9B7KOeMJvLCu/OvbA=="], + + "@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.27.2", "", { "os": "none", "cpu": "arm64" }, "sha512-Kj6DiBlwXrPsCRDeRvGAUb/LNrBASrfqAIok+xB0LxK8CHqxZ037viF13ugfsIpePH93mX7xfJp97cyDuTZ3cw=="], + + "@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.27.2", "", { "os": "none", "cpu": "x64" }, "sha512-HwGDZ0VLVBY3Y+Nw0JexZy9o/nUAWq9MlV7cahpaXKW6TOzfVno3y3/M8Ga8u8Yr7GldLOov27xiCnqRZf0tCA=="], + + "@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.27.2", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-DNIHH2BPQ5551A7oSHD0CKbwIA/Ox7+78/AWkbS5QoRzaqlev2uFayfSxq68EkonB+IKjiuxBFoV8ESJy8bOHA=="], + + "@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.27.2", "", { "os": "openbsd", "cpu": "x64" }, "sha512-/it7w9Nb7+0KFIzjalNJVR5bOzA9Vay+yIPLVHfIQYG/j+j9VTH84aNB8ExGKPU4AzfaEvN9/V4HV+F+vo8OEg=="], + + "@esbuild/openharmony-arm64": ["@esbuild/openharmony-arm64@0.27.2", "", { "os": "none", "cpu": "arm64" }, "sha512-LRBbCmiU51IXfeXk59csuX/aSaToeG7w48nMwA6049Y4J4+VbWALAuXcs+qcD04rHDuSCSRKdmY63sruDS5qag=="], + + "@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.27.2", "", { "os": "sunos", "cpu": "x64" }, "sha512-kMtx1yqJHTmqaqHPAzKCAkDaKsffmXkPHThSfRwZGyuqyIeBvf08KSsYXl+abf5HDAPMJIPnbBfXvP2ZC2TfHg=="], + + "@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.27.2", "", { "os": "win32", "cpu": "arm64" }, "sha512-Yaf78O/B3Kkh+nKABUF++bvJv5Ijoy9AN1ww904rOXZFLWVc5OLOfL56W+C8F9xn5JQZa3UX6m+IktJnIb1Jjg=="], + + "@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.27.2", "", { "os": "win32", "cpu": "ia32" }, "sha512-Iuws0kxo4yusk7sw70Xa2E2imZU5HoixzxfGCdxwBdhiDgt9vX9VUCBhqcwY7/uh//78A1hMkkROMJq9l27oLQ=="], + + "@esbuild/win32-x64": ["@esbuild/win32-x64@0.27.2", "", { "os": "win32", "cpu": "x64" }, "sha512-sRdU18mcKf7F+YgheI/zGf5alZatMUTKj/jNS6l744f9u3WFu4v7twcUI9vu4mknF4Y9aDlblIie0IM+5xxaqQ=="], + + "@fastify/busboy": ["@fastify/busboy@2.1.1", "", {}, "sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA=="], + + "@inquirer/external-editor": ["@inquirer/external-editor@1.0.3", "", { "dependencies": { "chardet": "^2.1.1", "iconv-lite": "^0.7.0" }, "peerDependencies": { "@types/node": ">=18" }, "optionalPeers": ["@types/node"] }, "sha512-RWbSrDiYmO4LbejWY7ttpxczuwQyZLBUyygsA9Nsv95hpzUWwnNTVQmAq3xuh7vNwCp07UTmE5i11XAEExx4RA=="], + + "@types/cli-progress": ["@types/cli-progress@3.11.6", "", { "dependencies": { "@types/node": "*" } }, "sha512-cE3+jb9WRlu+uOSAugewNpITJDt1VF8dHOopPO4IABFc3SXYL5WE/+PTz/FCdZRRfIujiWW3n3aMbv1eIGVRWA=="], + + "@types/inquirer": ["@types/inquirer@8.2.12", "", { "dependencies": { "@types/through": "*", "rxjs": "^7.2.0" } }, "sha512-YxURZF2ZsSjU5TAe06tW0M3sL4UI9AMPA6dd8I72uOtppzNafcY38xkYgCZ/vsVOAyNdzHmvtTpLWilOrbP0dQ=="], + + "@types/json-bigint": ["@types/json-bigint@1.0.4", "", {}, "sha512-ydHooXLbOmxBbubnA7Eh+RpBzuaIiQjh8WGJYQB50JFGFrdxW7JzVlyEV7fAXw0T2sqJ1ysTneJbiyNLqZRAag=="], + + "@types/node": ["@types/node@18.19.130", "", { "dependencies": { "undici-types": "~5.26.4" } }, "sha512-GRaXQx6jGfL8sKfaIDD6OupbIHBr9jv7Jnaml9tB7l4v068PAOXqfcujMMo5PhbIs6ggR1XODELqahT2R8v0fg=="], + + "@types/tar": ["@types/tar@6.1.13", "", { "dependencies": { "@types/node": "*", "minipass": "^4.0.0" } }, "sha512-IznnlmU5f4WcGTh2ltRu/Ijpmk8wiWXfF0VA4s+HPjHZgvFggk1YaIkbo5krX/zUCzWF8N/l4+W/LNxnvAJ8nw=="], + + "@types/through": ["@types/through@0.0.33", "", { "dependencies": { "@types/node": "*" } }, "sha512-HsJ+z3QuETzP3cswwtzt2vEIiHBk/dCcHGhbmG5X3ecnwFD/lPrMpliGXxSCg03L9AhrdwA4Oz/qfspkDW+xGQ=="], + + "ansi-escapes": ["ansi-escapes@4.3.2", "", { "dependencies": { "type-fest": "^0.21.3" } }, "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ=="], + + "ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], + + "ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="], + + "anymatch": ["anymatch@3.1.3", "", { "dependencies": { "normalize-path": "^3.0.0", "picomatch": "^2.0.4" } }, "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw=="], + + "async": ["async@3.2.6", "", {}, "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA=="], + + "asynckit": ["asynckit@0.4.0", "", {}, "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="], + + "balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], + + "base64-js": ["base64-js@1.5.1", "", {}, "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="], + + "bignumber.js": ["bignumber.js@9.3.1", "", {}, "sha512-Ko0uX15oIUS7wJ3Rb30Fs6SkVbLmPBAKdlm7q9+ak9bbIeFf0MwuBsQV6z7+X768/cHsfg+WlysDWJcmthjsjQ=="], + + "binary-extensions": ["binary-extensions@2.3.0", "", {}, "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw=="], + + "bl": ["bl@4.1.0", "", { "dependencies": { "buffer": "^5.5.0", "inherits": "^2.0.4", "readable-stream": "^3.4.0" } }, "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w=="], + + "brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="], + + "braces": ["braces@3.0.3", "", { "dependencies": { "fill-range": "^7.1.1" } }, "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA=="], + + "buffer": ["buffer@5.7.1", "", { "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.1.13" } }, "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ=="], + + "call-bind-apply-helpers": ["call-bind-apply-helpers@1.0.2", "", { "dependencies": { "es-errors": "^1.3.0", "function-bind": "^1.1.2" } }, "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ=="], + + "chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="], + + "chardet": ["chardet@2.1.1", "", {}, "sha512-PsezH1rqdV9VvyNhxxOW32/d75r01NY7TQCmOqomRo15ZSOKbpTFVsfjghxo6JloQUCGnH4k1LGu0R4yCLlWQQ=="], + + "chokidar": ["chokidar@3.6.0", "", { "dependencies": { "anymatch": "~3.1.2", "braces": "~3.0.2", "glob-parent": "~5.1.2", "is-binary-path": "~2.1.0", "is-glob": "~4.0.1", "normalize-path": "~3.0.0", "readdirp": "~3.6.0" }, "optionalDependencies": { "fsevents": "~2.3.2" } }, "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw=="], + + "chownr": ["chownr@2.0.0", "", {}, "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ=="], + + "cli-cursor": ["cli-cursor@3.1.0", "", { "dependencies": { "restore-cursor": "^3.1.0" } }, "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw=="], + + "cli-progress": ["cli-progress@3.12.0", "", { "dependencies": { "string-width": "^4.2.3" } }, "sha512-tRkV3HJ1ASwm19THiiLIXLO7Im7wlTuKnvkYaTkyoAPefqjNg7W7DHKUlGRxy9vxDvbyCYQkQozvptuMkGCg8A=="], + + "cli-spinners": ["cli-spinners@2.9.2", "", {}, "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg=="], + + "cli-table3": ["cli-table3@0.6.5", "", { "dependencies": { "string-width": "^4.2.0" }, "optionalDependencies": { "@colors/colors": "1.5.0" } }, "sha512-+W/5efTR7y5HRD7gACw9yQjqMVvEMLBHmboM/kPWam+H+Hmyrgjh6YncVKK122YZkXrLudzTuAukUw9FnMf7IQ=="], + + "cli-width": ["cli-width@3.0.0", "", {}, "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw=="], + + "clone": ["clone@1.0.4", "", {}, "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg=="], + + "color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "~1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="], + + "color-name": ["color-name@1.1.4", "", {}, "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="], + + "combined-stream": ["combined-stream@1.0.8", "", { "dependencies": { "delayed-stream": "~1.0.0" } }, "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg=="], + + "commander": ["commander@9.5.0", "", {}, "sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ=="], + + "defaults": ["defaults@1.0.4", "", { "dependencies": { "clone": "^1.0.2" } }, "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A=="], + + "delayed-stream": ["delayed-stream@1.0.0", "", {}, "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ=="], + + "dotenv": ["dotenv@16.6.1", "", {}, "sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow=="], + + "dunder-proto": ["dunder-proto@1.0.1", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.1", "es-errors": "^1.3.0", "gopd": "^1.2.0" } }, "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A=="], + + "ejs": ["ejs@3.1.10", "", { "dependencies": { "jake": "^10.8.5" }, "bin": { "ejs": "bin/cli.js" } }, "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA=="], + + "emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="], + + "es-define-property": ["es-define-property@1.0.1", "", {}, "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g=="], + + "es-errors": ["es-errors@1.3.0", "", {}, "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw=="], + + "es-object-atoms": ["es-object-atoms@1.1.1", "", { "dependencies": { "es-errors": "^1.3.0" } }, "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA=="], + + "es-set-tostringtag": ["es-set-tostringtag@2.1.0", "", { "dependencies": { "es-errors": "^1.3.0", "get-intrinsic": "^1.2.6", "has-tostringtag": "^1.0.2", "hasown": "^2.0.2" } }, "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA=="], + + "esbuild": ["esbuild@0.27.2", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.27.2", "@esbuild/android-arm": "0.27.2", "@esbuild/android-arm64": "0.27.2", "@esbuild/android-x64": "0.27.2", "@esbuild/darwin-arm64": "0.27.2", "@esbuild/darwin-x64": "0.27.2", "@esbuild/freebsd-arm64": "0.27.2", "@esbuild/freebsd-x64": "0.27.2", "@esbuild/linux-arm": "0.27.2", "@esbuild/linux-arm64": "0.27.2", "@esbuild/linux-ia32": "0.27.2", "@esbuild/linux-loong64": "0.27.2", "@esbuild/linux-mips64el": "0.27.2", "@esbuild/linux-ppc64": "0.27.2", "@esbuild/linux-riscv64": "0.27.2", "@esbuild/linux-s390x": "0.27.2", "@esbuild/linux-x64": "0.27.2", "@esbuild/netbsd-arm64": "0.27.2", "@esbuild/netbsd-x64": "0.27.2", "@esbuild/openbsd-arm64": "0.27.2", "@esbuild/openbsd-x64": "0.27.2", "@esbuild/openharmony-arm64": "0.27.2", "@esbuild/sunos-x64": "0.27.2", "@esbuild/win32-arm64": "0.27.2", "@esbuild/win32-ia32": "0.27.2", "@esbuild/win32-x64": "0.27.2" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-HyNQImnsOC7X9PMNaCIeAm4ISCQXs5a5YasTXVliKv4uuBo1dKrG0A+uQS8M5eXjVMnLg3WgXaKvprHlFJQffw=="], + + "escape-string-regexp": ["escape-string-regexp@1.0.5", "", {}, "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg=="], + + "external-editor": ["external-editor@2.2.0", "", { "dependencies": { "chardet": "^0.4.0", "iconv-lite": "^0.4.17", "tmp": "^0.0.33" } }, "sha512-bSn6gvGxKt+b7+6TKEv1ZycHleA7aHhRHyAqJyp5pbUFuYYNIzpZnQDk7AsYckyWdEnTeAnay0aCy2aV6iTk9A=="], + + "figures": ["figures@3.2.0", "", { "dependencies": { "escape-string-regexp": "^1.0.5" } }, "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg=="], + + "filelist": ["filelist@1.0.4", "", { "dependencies": { "minimatch": "^5.0.1" } }, "sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q=="], + + "fill-range": ["fill-range@7.1.1", "", { "dependencies": { "to-regex-range": "^5.0.1" } }, "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg=="], + + "form-data": ["form-data@4.0.5", "", { "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", "es-set-tostringtag": "^2.1.0", "hasown": "^2.0.2", "mime-types": "^2.1.12" } }, "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w=="], + + "fs-minipass": ["fs-minipass@2.1.0", "", { "dependencies": { "minipass": "^3.0.0" } }, "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg=="], + + "fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="], + + "function-bind": ["function-bind@1.1.2", "", {}, "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA=="], + + "fuzzy": ["fuzzy@0.1.3", "", {}, "sha512-/gZffu4ykarLrCiP3Ygsa86UAo1E5vEVlvTrpkKywXSbP9Xhln3oSp9QSV57gEq3JFFpGJ4GZ+5zdEp3FcUh4w=="], + + "get-intrinsic": ["get-intrinsic@1.3.0", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.2", "es-define-property": "^1.0.1", "es-errors": "^1.3.0", "es-object-atoms": "^1.1.1", "function-bind": "^1.1.2", "get-proto": "^1.0.1", "gopd": "^1.2.0", "has-symbols": "^1.1.0", "hasown": "^2.0.2", "math-intrinsics": "^1.1.0" } }, "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ=="], + + "get-proto": ["get-proto@1.0.1", "", { "dependencies": { "dunder-proto": "^1.0.1", "es-object-atoms": "^1.0.0" } }, "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g=="], + + "get-tsconfig": ["get-tsconfig@4.13.0", "", { "dependencies": { "resolve-pkg-maps": "^1.0.0" } }, "sha512-1VKTZJCwBrvbd+Wn3AOgQP/2Av+TfTCOlE4AcRJE72W1ksZXbAx8PPBR9RzgTeSPzlPMHrbANMH3LbltH73wxQ=="], + + "glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="], + + "gopd": ["gopd@1.2.0", "", {}, "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg=="], + + "has-flag": ["has-flag@4.0.0", "", {}, "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="], + + "has-symbols": ["has-symbols@1.1.0", "", {}, "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ=="], + + "has-tostringtag": ["has-tostringtag@1.0.2", "", { "dependencies": { "has-symbols": "^1.0.3" } }, "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw=="], + + "hasown": ["hasown@2.0.2", "", { "dependencies": { "function-bind": "^1.1.2" } }, "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ=="], + + "iconv-lite": ["iconv-lite@0.7.1", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" } }, "sha512-2Tth85cXwGFHfvRgZWszZSvdo+0Xsqmw8k8ZwxScfcBneNUraK+dxRxRm24nszx80Y0TVio8kKLt5sLE7ZCLlw=="], + + "ieee754": ["ieee754@1.2.1", "", {}, "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="], + + "ignore": ["ignore@7.0.5", "", {}, "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg=="], + + "inherits": ["inherits@2.0.4", "", {}, "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="], + + "inquirer": ["inquirer@8.2.7", "", { "dependencies": { "@inquirer/external-editor": "^1.0.0", "ansi-escapes": "^4.2.1", "chalk": "^4.1.1", "cli-cursor": "^3.1.0", "cli-width": "^3.0.0", "figures": "^3.0.0", "lodash": "^4.17.21", "mute-stream": "0.0.8", "ora": "^5.4.1", "run-async": "^2.4.0", "rxjs": "^7.5.5", "string-width": "^4.1.0", "strip-ansi": "^6.0.0", "through": "^2.3.6", "wrap-ansi": "^6.0.1" } }, "sha512-UjOaSel/iddGZJ5xP/Eixh6dY1XghiBw4XK13rCCIJcJfyhhoul/7KhLLUGtebEj6GDYM6Vnx/mVsjx2L/mFIA=="], + + "inquirer-search-list": ["inquirer-search-list@1.2.6", "", { "dependencies": { "chalk": "^2.3.0", "figures": "^2.0.0", "fuzzy": "^0.1.3", "inquirer": "^3.3.0" } }, "sha512-C4pKSW7FOYnkAloH8rB4FiM91H1v08QFZZJh6KRt//bMfdDBIhgdX8wjHvrVH2bu5oIo6wYqGpzSBxkeClPxew=="], + + "is-binary-path": ["is-binary-path@2.1.0", "", { "dependencies": { "binary-extensions": "^2.0.0" } }, "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw=="], + + "is-extglob": ["is-extglob@2.1.1", "", {}, "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ=="], + + "is-fullwidth-code-point": ["is-fullwidth-code-point@3.0.0", "", {}, "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="], + + "is-glob": ["is-glob@4.0.3", "", { "dependencies": { "is-extglob": "^2.1.1" } }, "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg=="], + + "is-interactive": ["is-interactive@1.0.0", "", {}, "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w=="], + + "is-number": ["is-number@7.0.0", "", {}, "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng=="], + + "is-unicode-supported": ["is-unicode-supported@0.1.0", "", {}, "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw=="], + + "jake": ["jake@10.9.4", "", { "dependencies": { "async": "^3.2.6", "filelist": "^1.0.4", "picocolors": "^1.1.1" }, "bin": { "jake": "bin/cli.js" } }, "sha512-wpHYzhxiVQL+IV05BLE2Xn34zW1S223hvjtqk0+gsPrwd/8JNLXJgZZM/iPFsYc1xyphF+6M6EvdE5E9MBGkDA=="], + + "json-bigint": ["json-bigint@1.0.0", "", { "dependencies": { "bignumber.js": "^9.0.0" } }, "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ=="], + + "lodash": ["lodash@4.17.21", "", {}, "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="], + + "log-symbols": ["log-symbols@4.1.0", "", { "dependencies": { "chalk": "^4.1.0", "is-unicode-supported": "^0.1.0" } }, "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg=="], + + "math-intrinsics": ["math-intrinsics@1.1.0", "", {}, "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g=="], + + "mime-db": ["mime-db@1.52.0", "", {}, "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="], + + "mime-types": ["mime-types@2.1.35", "", { "dependencies": { "mime-db": "1.52.0" } }, "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw=="], + + "mimic-fn": ["mimic-fn@2.1.0", "", {}, "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg=="], + + "minimatch": ["minimatch@5.1.6", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g=="], + + "minipass": ["minipass@4.2.8", "", {}, "sha512-fNzuVyifolSLFL4NzpF+wEF4qrgqaaKX0haXPQEdQ7NKAN+WecoKMHV09YcuL/DHxrUsYQOK3MiuDf7Ip2OXfQ=="], + + "minizlib": ["minizlib@2.1.2", "", { "dependencies": { "minipass": "^3.0.0", "yallist": "^4.0.0" } }, "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg=="], + + "mkdirp": ["mkdirp@1.0.4", "", { "bin": { "mkdirp": "bin/cmd.js" } }, "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw=="], + + "mute-stream": ["mute-stream@0.0.8", "", {}, "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA=="], + + "normalize-path": ["normalize-path@3.0.0", "", {}, "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA=="], + + "onetime": ["onetime@5.1.2", "", { "dependencies": { "mimic-fn": "^2.1.0" } }, "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg=="], + + "ora": ["ora@5.4.1", "", { "dependencies": { "bl": "^4.1.0", "chalk": "^4.1.0", "cli-cursor": "^3.1.0", "cli-spinners": "^2.5.0", "is-interactive": "^1.0.0", "is-unicode-supported": "^0.1.0", "log-symbols": "^4.1.0", "strip-ansi": "^6.0.0", "wcwidth": "^1.0.1" } }, "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ=="], + + "os-tmpdir": ["os-tmpdir@1.0.2", "", {}, "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g=="], + + "picocolors": ["picocolors@1.1.1", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="], + + "picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], + + "prettier": ["prettier@3.7.4", "", { "bin": { "prettier": "bin/prettier.cjs" } }, "sha512-v6UNi1+3hSlVvv8fSaoUbggEM5VErKmmpGA7Pl3HF8V6uKY7rvClBOJlH6yNwQtfTueNkGVpOv/mtWL9L4bgRA=="], + + "readable-stream": ["readable-stream@3.6.2", "", { "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", "util-deprecate": "^1.0.1" } }, "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA=="], + + "readdirp": ["readdirp@3.6.0", "", { "dependencies": { "picomatch": "^2.2.1" } }, "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA=="], + + "resolve-pkg-maps": ["resolve-pkg-maps@1.0.0", "", {}, "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw=="], + + "restore-cursor": ["restore-cursor@3.1.0", "", { "dependencies": { "onetime": "^5.1.0", "signal-exit": "^3.0.2" } }, "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA=="], + + "run-async": ["run-async@2.4.1", "", {}, "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ=="], + + "rx-lite": ["rx-lite@4.0.8", "", {}, "sha512-Cun9QucwK6MIrp3mry/Y7hqD1oFqTYLQ4pGxaHTjIdaFDWRGGLikqp6u8LcWJnzpoALg9hap+JGk8sFIUuEGNA=="], + + "rx-lite-aggregates": ["rx-lite-aggregates@4.0.8", "", { "dependencies": { "rx-lite": "*" } }, "sha512-3xPNZGW93oCjiO7PtKxRK6iOVYBWBvtf9QHDfU23Oc+dLIQmAV//UnyXV/yihv81VS/UqoQPk4NegS8EFi55Hg=="], + + "rxjs": ["rxjs@7.8.2", "", { "dependencies": { "tslib": "^2.1.0" } }, "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA=="], + + "safe-buffer": ["safe-buffer@5.2.1", "", {}, "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="], + + "safer-buffer": ["safer-buffer@2.1.2", "", {}, "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="], + + "signal-exit": ["signal-exit@3.0.7", "", {}, "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ=="], + + "string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="], + + "string_decoder": ["string_decoder@1.3.0", "", { "dependencies": { "safe-buffer": "~5.2.0" } }, "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA=="], + + "strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], + + "supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="], + + "tail": ["tail@2.2.6", "", {}, "sha512-IQ6G4wK/t8VBauYiGPLx+d3fA5XjSVagjWV5SIYzvEvglbQjwEcukeYI68JOPpdydjxhZ9sIgzRlSmwSpphHyw=="], + + "tar": ["tar@6.2.1", "", { "dependencies": { "chownr": "^2.0.0", "fs-minipass": "^2.0.0", "minipass": "^5.0.0", "minizlib": "^2.1.1", "mkdirp": "^1.0.3", "yallist": "^4.0.0" } }, "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A=="], + + "through": ["through@2.3.8", "", {}, "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg=="], + + "tmp": ["tmp@0.0.33", "", { "dependencies": { "os-tmpdir": "~1.0.2" } }, "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw=="], + + "to-regex-range": ["to-regex-range@5.0.1", "", { "dependencies": { "is-number": "^7.0.0" } }, "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ=="], + + "tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], + + "tsx": ["tsx@4.21.0", "", { "dependencies": { "esbuild": "~0.27.0", "get-tsconfig": "^4.7.5" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "bin": { "tsx": "dist/cli.mjs" } }, "sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw=="], + + "type-fest": ["type-fest@0.21.3", "", {}, "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w=="], + + "typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="], + + "undici": ["undici@5.29.0", "", { "dependencies": { "@fastify/busboy": "^2.0.0" } }, "sha512-raqeBD6NQK4SkWhQzeYKd1KmIG6dllBOTt55Rmkt4HtI9mwdWtJljnrXjAFUBLTSN67HWrOIZ3EPF4kjUw80Bg=="], + + "undici-types": ["undici-types@5.26.5", "", {}, "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA=="], + + "util-deprecate": ["util-deprecate@1.0.2", "", {}, "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="], + + "wcwidth": ["wcwidth@1.0.1", "", { "dependencies": { "defaults": "^1.0.3" } }, "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg=="], + + "wrap-ansi": ["wrap-ansi@6.2.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA=="], + + "yallist": ["yallist@4.0.0", "", {}, "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="], + + "external-editor/chardet": ["chardet@0.4.2", "", {}, "sha512-j/Toj7f1z98Hh2cYo2BVr85EpIRWqUi7rtRSGxh/cqUjqrnJe9l9UE7IUGd2vQ2p+kSHLkSzObQPZPLUC6TQwg=="], + + "external-editor/iconv-lite": ["iconv-lite@0.4.24", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3" } }, "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA=="], + + "fs-minipass/minipass": ["minipass@3.3.6", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw=="], + + "inquirer-search-list/chalk": ["chalk@2.4.2", "", { "dependencies": { "ansi-styles": "^3.2.1", "escape-string-regexp": "^1.0.5", "supports-color": "^5.3.0" } }, "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ=="], + + "inquirer-search-list/figures": ["figures@2.0.0", "", { "dependencies": { "escape-string-regexp": "^1.0.5" } }, "sha512-Oa2M9atig69ZkfwiApY8F2Yy+tzMbazyvqv21R0NsSC8floSOC09BbT1ITWAdoMGQvJ/aZnR1KMwdx9tvHnTNA=="], + + "inquirer-search-list/inquirer": ["inquirer@3.3.0", "", { "dependencies": { "ansi-escapes": "^3.0.0", "chalk": "^2.0.0", "cli-cursor": "^2.1.0", "cli-width": "^2.0.0", "external-editor": "^2.0.4", "figures": "^2.0.0", "lodash": "^4.3.0", "mute-stream": "0.0.7", "run-async": "^2.2.0", "rx-lite": "^4.0.8", "rx-lite-aggregates": "^4.0.8", "string-width": "^2.1.0", "strip-ansi": "^4.0.0", "through": "^2.3.6" } }, "sha512-h+xtnyk4EwKvFWHrUYsWErEVR+igKtLdchu+o0Z1RL7VU/jVMFbYir2bp6bAj8efFNxWqHX0dIss6fJQ+/+qeQ=="], + + "minizlib/minipass": ["minipass@3.3.6", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw=="], + + "tar/minipass": ["minipass@5.0.0", "", {}, "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ=="], + + "inquirer-search-list/chalk/ansi-styles": ["ansi-styles@3.2.1", "", { "dependencies": { "color-convert": "^1.9.0" } }, "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA=="], + + "inquirer-search-list/chalk/supports-color": ["supports-color@5.5.0", "", { "dependencies": { "has-flag": "^3.0.0" } }, "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow=="], + + "inquirer-search-list/inquirer/ansi-escapes": ["ansi-escapes@3.2.0", "", {}, "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ=="], + + "inquirer-search-list/inquirer/cli-cursor": ["cli-cursor@2.1.0", "", { "dependencies": { "restore-cursor": "^2.0.0" } }, "sha512-8lgKz8LmCRYZZQDpRyT2m5rKJ08TnU4tR9FFFW2rxpxR1FzWi4PQ/NfyODchAatHaUgnSPVcx/R5w6NuTBzFiw=="], + + "inquirer-search-list/inquirer/cli-width": ["cli-width@2.2.1", "", {}, "sha512-GRMWDxpOB6Dgk2E5Uo+3eEBvtOOlimMmpbFiKuLFnQzYDavtLFY3K5ona41jgN/WdRZtG7utuVSVTL4HbZHGkw=="], + + "inquirer-search-list/inquirer/mute-stream": ["mute-stream@0.0.7", "", {}, "sha512-r65nCZhrbXXb6dXOACihYApHw2Q6pV0M3V0PSxd74N0+D8nzAdEAITq2oAjA1jVnKI+tGvEBUpqiMh0+rW6zDQ=="], + + "inquirer-search-list/inquirer/string-width": ["string-width@2.1.1", "", { "dependencies": { "is-fullwidth-code-point": "^2.0.0", "strip-ansi": "^4.0.0" } }, "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw=="], + + "inquirer-search-list/inquirer/strip-ansi": ["strip-ansi@4.0.0", "", { "dependencies": { "ansi-regex": "^3.0.0" } }, "sha512-4XaJ2zQdCzROZDivEVIDPkcQn8LMFSa8kj8Gxb/Lnwzv9A8VctNZ+lfivC/sV3ivW8ElJTERXZoPBRrZKkNKow=="], + + "inquirer-search-list/chalk/ansi-styles/color-convert": ["color-convert@1.9.3", "", { "dependencies": { "color-name": "1.1.3" } }, "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg=="], + + "inquirer-search-list/chalk/supports-color/has-flag": ["has-flag@3.0.0", "", {}, "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw=="], + + "inquirer-search-list/inquirer/cli-cursor/restore-cursor": ["restore-cursor@2.0.0", "", { "dependencies": { "onetime": "^2.0.0", "signal-exit": "^3.0.2" } }, "sha512-6IzJLuGi4+R14vwagDHX+JrXmPVtPpn4mffDJ1UdR7/Edm87fl6yi8mMBIVvFtJaNTUvjughmW4hwLhRG7gC1Q=="], + + "inquirer-search-list/inquirer/string-width/is-fullwidth-code-point": ["is-fullwidth-code-point@2.0.0", "", {}, "sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w=="], + + "inquirer-search-list/inquirer/strip-ansi/ansi-regex": ["ansi-regex@3.0.1", "", {}, "sha512-+O9Jct8wf++lXxxFc4hc8LsjaSq0HFzzL7cVsw8pRDIPdjKD2mT4ytDZlLuSBZ4cLKZFXIrMGO7DbQCtMJJMKw=="], + + "inquirer-search-list/chalk/ansi-styles/color-convert/color-name": ["color-name@1.1.3", "", {}, "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw=="], + + "inquirer-search-list/inquirer/cli-cursor/restore-cursor/onetime": ["onetime@2.0.1", "", { "dependencies": { "mimic-fn": "^1.0.0" } }, "sha512-oyyPpiMaKARvvcgip+JV+7zci5L8D1W9RZIz2l1o08AM3pfspitVWnPt3mzHcBPp12oYMTy0pqrFs/C+m3EwsQ=="], + + "inquirer-search-list/inquirer/cli-cursor/restore-cursor/onetime/mimic-fn": ["mimic-fn@1.2.0", "", {}, "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ=="], + } +} diff --git a/docs/examples/account/create-anonymous-session.md b/docs/examples/account/create-anonymous-session.md deleted file mode 100644 index b6f2432c..00000000 --- a/docs/examples/account/create-anonymous-session.md +++ /dev/null @@ -1 +0,0 @@ -appwrite account create-anonymous-session diff --git a/docs/examples/account/create-email-password-session.md b/docs/examples/account/create-email-password-session.md deleted file mode 100644 index b13874c7..00000000 --- a/docs/examples/account/create-email-password-session.md +++ /dev/null @@ -1,3 +0,0 @@ -appwrite account create-email-password-session \ - --email email@example.com \ - --password password diff --git a/docs/examples/account/create-email-token.md b/docs/examples/account/create-email-token.md deleted file mode 100644 index 1902e8b2..00000000 --- a/docs/examples/account/create-email-token.md +++ /dev/null @@ -1,3 +0,0 @@ -appwrite account create-email-token \ - --user-id \ - --email email@example.com diff --git a/docs/examples/account/create-email-verification.md b/docs/examples/account/create-email-verification.md deleted file mode 100644 index f9f37f2f..00000000 --- a/docs/examples/account/create-email-verification.md +++ /dev/null @@ -1,2 +0,0 @@ -appwrite account create-email-verification \ - --url https://example.com diff --git a/docs/examples/account/create-jwt.md b/docs/examples/account/create-jwt.md deleted file mode 100644 index f2d65695..00000000 --- a/docs/examples/account/create-jwt.md +++ /dev/null @@ -1 +0,0 @@ -appwrite account create-jwt diff --git a/docs/examples/account/create-magic-url-token.md b/docs/examples/account/create-magic-url-token.md deleted file mode 100644 index 4f16a8b2..00000000 --- a/docs/examples/account/create-magic-url-token.md +++ /dev/null @@ -1,3 +0,0 @@ -appwrite account create-magic-url-token \ - --user-id \ - --email email@example.com diff --git a/docs/examples/account/create-mfa-authenticator.md b/docs/examples/account/create-mfa-authenticator.md deleted file mode 100644 index a4542767..00000000 --- a/docs/examples/account/create-mfa-authenticator.md +++ /dev/null @@ -1,2 +0,0 @@ -appwrite account create-mfa-authenticator \ - --type totp diff --git a/docs/examples/account/create-mfa-challenge.md b/docs/examples/account/create-mfa-challenge.md deleted file mode 100644 index 24bab3d6..00000000 --- a/docs/examples/account/create-mfa-challenge.md +++ /dev/null @@ -1,2 +0,0 @@ -appwrite account create-mfa-challenge \ - --factor email diff --git a/docs/examples/account/create-mfa-recovery-codes.md b/docs/examples/account/create-mfa-recovery-codes.md deleted file mode 100644 index 4f165d90..00000000 --- a/docs/examples/account/create-mfa-recovery-codes.md +++ /dev/null @@ -1 +0,0 @@ -appwrite account create-mfa-recovery-codes diff --git a/docs/examples/account/create-o-auth-2-session.md b/docs/examples/account/create-o-auth-2-session.md deleted file mode 100644 index fda2faac..00000000 --- a/docs/examples/account/create-o-auth-2-session.md +++ /dev/null @@ -1,2 +0,0 @@ -appwrite account create-o-auth-2-session \ - --provider amazon diff --git a/docs/examples/account/create-o-auth-2-token.md b/docs/examples/account/create-o-auth-2-token.md deleted file mode 100644 index 7fff73f5..00000000 --- a/docs/examples/account/create-o-auth-2-token.md +++ /dev/null @@ -1,2 +0,0 @@ -appwrite account create-o-auth-2-token \ - --provider amazon diff --git a/docs/examples/account/create-phone-token.md b/docs/examples/account/create-phone-token.md deleted file mode 100644 index 619478c6..00000000 --- a/docs/examples/account/create-phone-token.md +++ /dev/null @@ -1,3 +0,0 @@ -appwrite account create-phone-token \ - --user-id \ - --phone +12065550100 diff --git a/docs/examples/account/create-phone-verification.md b/docs/examples/account/create-phone-verification.md deleted file mode 100644 index b5a95ed9..00000000 --- a/docs/examples/account/create-phone-verification.md +++ /dev/null @@ -1 +0,0 @@ -appwrite account create-phone-verification diff --git a/docs/examples/account/create-push-target.md b/docs/examples/account/create-push-target.md deleted file mode 100644 index 1ba6fe30..00000000 --- a/docs/examples/account/create-push-target.md +++ /dev/null @@ -1,3 +0,0 @@ -appwrite account create-push-target \ - --target-id \ - --identifier diff --git a/docs/examples/account/create-recovery.md b/docs/examples/account/create-recovery.md deleted file mode 100644 index d6977de8..00000000 --- a/docs/examples/account/create-recovery.md +++ /dev/null @@ -1,3 +0,0 @@ -appwrite account create-recovery \ - --email email@example.com \ - --url https://example.com diff --git a/docs/examples/account/create-session.md b/docs/examples/account/create-session.md deleted file mode 100644 index eefeb350..00000000 --- a/docs/examples/account/create-session.md +++ /dev/null @@ -1,3 +0,0 @@ -appwrite account create-session \ - --user-id \ - --secret diff --git a/docs/examples/account/create-verification.md b/docs/examples/account/create-verification.md deleted file mode 100644 index 6e972f2f..00000000 --- a/docs/examples/account/create-verification.md +++ /dev/null @@ -1,2 +0,0 @@ -appwrite account create-verification \ - --url https://example.com diff --git a/docs/examples/account/create.md b/docs/examples/account/create.md deleted file mode 100644 index 56eca76d..00000000 --- a/docs/examples/account/create.md +++ /dev/null @@ -1,4 +0,0 @@ -appwrite account create \ - --user-id \ - --email email@example.com \ - --password '' diff --git a/docs/examples/account/delete-identity.md b/docs/examples/account/delete-identity.md deleted file mode 100644 index 650ab7bf..00000000 --- a/docs/examples/account/delete-identity.md +++ /dev/null @@ -1,2 +0,0 @@ -appwrite account delete-identity \ - --identity-id diff --git a/docs/examples/account/delete-mfa-authenticator.md b/docs/examples/account/delete-mfa-authenticator.md deleted file mode 100644 index e3689b17..00000000 --- a/docs/examples/account/delete-mfa-authenticator.md +++ /dev/null @@ -1,2 +0,0 @@ -appwrite account delete-mfa-authenticator \ - --type totp diff --git a/docs/examples/account/delete-push-target.md b/docs/examples/account/delete-push-target.md deleted file mode 100644 index 04f94f64..00000000 --- a/docs/examples/account/delete-push-target.md +++ /dev/null @@ -1,2 +0,0 @@ -appwrite account delete-push-target \ - --target-id diff --git a/docs/examples/account/delete-session.md b/docs/examples/account/delete-session.md deleted file mode 100644 index 6476fd9a..00000000 --- a/docs/examples/account/delete-session.md +++ /dev/null @@ -1,2 +0,0 @@ -appwrite account delete-session \ - --session-id diff --git a/docs/examples/account/delete-sessions.md b/docs/examples/account/delete-sessions.md deleted file mode 100644 index 73810691..00000000 --- a/docs/examples/account/delete-sessions.md +++ /dev/null @@ -1 +0,0 @@ -appwrite account delete-sessions diff --git a/docs/examples/account/delete.md b/docs/examples/account/delete.md deleted file mode 100644 index dac412f7..00000000 --- a/docs/examples/account/delete.md +++ /dev/null @@ -1 +0,0 @@ -appwrite account delete diff --git a/docs/examples/account/get-mfa-recovery-codes.md b/docs/examples/account/get-mfa-recovery-codes.md deleted file mode 100644 index 01a2f35e..00000000 --- a/docs/examples/account/get-mfa-recovery-codes.md +++ /dev/null @@ -1 +0,0 @@ -appwrite account get-mfa-recovery-codes diff --git a/docs/examples/account/get-prefs.md b/docs/examples/account/get-prefs.md deleted file mode 100644 index 5796c083..00000000 --- a/docs/examples/account/get-prefs.md +++ /dev/null @@ -1 +0,0 @@ -appwrite account get-prefs diff --git a/docs/examples/account/get-session.md b/docs/examples/account/get-session.md deleted file mode 100644 index 9901eb24..00000000 --- a/docs/examples/account/get-session.md +++ /dev/null @@ -1,2 +0,0 @@ -appwrite account get-session \ - --session-id diff --git a/docs/examples/account/get.md b/docs/examples/account/get.md deleted file mode 100644 index c8b46e34..00000000 --- a/docs/examples/account/get.md +++ /dev/null @@ -1 +0,0 @@ -appwrite account get diff --git a/docs/examples/account/list-identities.md b/docs/examples/account/list-identities.md deleted file mode 100644 index 095dcc47..00000000 --- a/docs/examples/account/list-identities.md +++ /dev/null @@ -1 +0,0 @@ -appwrite account list-identities diff --git a/docs/examples/account/list-logs.md b/docs/examples/account/list-logs.md deleted file mode 100644 index 73fb9b62..00000000 --- a/docs/examples/account/list-logs.md +++ /dev/null @@ -1 +0,0 @@ -appwrite account list-logs diff --git a/docs/examples/account/list-mfa-factors.md b/docs/examples/account/list-mfa-factors.md deleted file mode 100644 index 6930f347..00000000 --- a/docs/examples/account/list-mfa-factors.md +++ /dev/null @@ -1 +0,0 @@ -appwrite account list-mfa-factors diff --git a/docs/examples/account/list-sessions.md b/docs/examples/account/list-sessions.md deleted file mode 100644 index 1aca27ba..00000000 --- a/docs/examples/account/list-sessions.md +++ /dev/null @@ -1 +0,0 @@ -appwrite account list-sessions diff --git a/docs/examples/account/update-email-verification.md b/docs/examples/account/update-email-verification.md deleted file mode 100644 index 02ff32aa..00000000 --- a/docs/examples/account/update-email-verification.md +++ /dev/null @@ -1,3 +0,0 @@ -appwrite account update-email-verification \ - --user-id \ - --secret diff --git a/docs/examples/account/update-email.md b/docs/examples/account/update-email.md deleted file mode 100644 index 9753a064..00000000 --- a/docs/examples/account/update-email.md +++ /dev/null @@ -1,3 +0,0 @@ -appwrite account update-email \ - --email email@example.com \ - --password password diff --git a/docs/examples/account/update-magic-url-session.md b/docs/examples/account/update-magic-url-session.md deleted file mode 100644 index 0bf9ed7d..00000000 --- a/docs/examples/account/update-magic-url-session.md +++ /dev/null @@ -1,3 +0,0 @@ -appwrite account update-magic-url-session \ - --user-id \ - --secret diff --git a/docs/examples/account/update-mfa-authenticator.md b/docs/examples/account/update-mfa-authenticator.md deleted file mode 100644 index 838297ba..00000000 --- a/docs/examples/account/update-mfa-authenticator.md +++ /dev/null @@ -1,3 +0,0 @@ -appwrite account update-mfa-authenticator \ - --type totp \ - --otp diff --git a/docs/examples/account/update-mfa-challenge.md b/docs/examples/account/update-mfa-challenge.md deleted file mode 100644 index 4a5c8fbf..00000000 --- a/docs/examples/account/update-mfa-challenge.md +++ /dev/null @@ -1,3 +0,0 @@ -appwrite account update-mfa-challenge \ - --challenge-id \ - --otp diff --git a/docs/examples/account/update-mfa-recovery-codes.md b/docs/examples/account/update-mfa-recovery-codes.md deleted file mode 100644 index 9e9ab074..00000000 --- a/docs/examples/account/update-mfa-recovery-codes.md +++ /dev/null @@ -1 +0,0 @@ -appwrite account update-mfa-recovery-codes diff --git a/docs/examples/account/update-mfa.md b/docs/examples/account/update-mfa.md deleted file mode 100644 index fa122d9b..00000000 --- a/docs/examples/account/update-mfa.md +++ /dev/null @@ -1,2 +0,0 @@ -appwrite account update-mfa \ - --mfa false diff --git a/docs/examples/account/update-name.md b/docs/examples/account/update-name.md deleted file mode 100644 index c858d0e3..00000000 --- a/docs/examples/account/update-name.md +++ /dev/null @@ -1,2 +0,0 @@ -appwrite account update-name \ - --name diff --git a/docs/examples/account/update-password.md b/docs/examples/account/update-password.md deleted file mode 100644 index e4bbdfc4..00000000 --- a/docs/examples/account/update-password.md +++ /dev/null @@ -1,2 +0,0 @@ -appwrite account update-password \ - --password '' diff --git a/docs/examples/account/update-phone-session.md b/docs/examples/account/update-phone-session.md deleted file mode 100644 index 599a9053..00000000 --- a/docs/examples/account/update-phone-session.md +++ /dev/null @@ -1,3 +0,0 @@ -appwrite account update-phone-session \ - --user-id \ - --secret diff --git a/docs/examples/account/update-phone-verification.md b/docs/examples/account/update-phone-verification.md deleted file mode 100644 index 59dde678..00000000 --- a/docs/examples/account/update-phone-verification.md +++ /dev/null @@ -1,3 +0,0 @@ -appwrite account update-phone-verification \ - --user-id \ - --secret diff --git a/docs/examples/account/update-phone.md b/docs/examples/account/update-phone.md deleted file mode 100644 index 5c257c84..00000000 --- a/docs/examples/account/update-phone.md +++ /dev/null @@ -1,3 +0,0 @@ -appwrite account update-phone \ - --phone +12065550100 \ - --password password diff --git a/docs/examples/account/update-prefs.md b/docs/examples/account/update-prefs.md deleted file mode 100644 index 7b00d7bc..00000000 --- a/docs/examples/account/update-prefs.md +++ /dev/null @@ -1,2 +0,0 @@ -appwrite account update-prefs \ - --prefs '{ "key": "value" }' diff --git a/docs/examples/account/update-push-target.md b/docs/examples/account/update-push-target.md deleted file mode 100644 index f71232af..00000000 --- a/docs/examples/account/update-push-target.md +++ /dev/null @@ -1,3 +0,0 @@ -appwrite account update-push-target \ - --target-id \ - --identifier diff --git a/docs/examples/account/update-recovery.md b/docs/examples/account/update-recovery.md deleted file mode 100644 index c2a97bda..00000000 --- a/docs/examples/account/update-recovery.md +++ /dev/null @@ -1,4 +0,0 @@ -appwrite account update-recovery \ - --user-id \ - --secret \ - --password '' diff --git a/docs/examples/account/update-session.md b/docs/examples/account/update-session.md deleted file mode 100644 index 36833c46..00000000 --- a/docs/examples/account/update-session.md +++ /dev/null @@ -1,2 +0,0 @@ -appwrite account update-session \ - --session-id diff --git a/docs/examples/account/update-status.md b/docs/examples/account/update-status.md deleted file mode 100644 index d2717492..00000000 --- a/docs/examples/account/update-status.md +++ /dev/null @@ -1 +0,0 @@ -appwrite account update-status diff --git a/docs/examples/account/update-verification.md b/docs/examples/account/update-verification.md deleted file mode 100644 index d7276c63..00000000 --- a/docs/examples/account/update-verification.md +++ /dev/null @@ -1,3 +0,0 @@ -appwrite account update-verification \ - --user-id \ - --secret diff --git a/docs/examples/console/get-resource.md b/docs/examples/console/get-resource.md deleted file mode 100644 index 5251dd6a..00000000 --- a/docs/examples/console/get-resource.md +++ /dev/null @@ -1,3 +0,0 @@ -appwrite console get-resource \ - --value \ - --type rules diff --git a/docs/examples/console/variables.md b/docs/examples/console/variables.md deleted file mode 100644 index 1c67cf5a..00000000 --- a/docs/examples/console/variables.md +++ /dev/null @@ -1 +0,0 @@ -appwrite console variables diff --git a/docs/examples/databases/create-boolean-attribute.md b/docs/examples/databases/create-boolean-attribute.md deleted file mode 100644 index ce4d65fa..00000000 --- a/docs/examples/databases/create-boolean-attribute.md +++ /dev/null @@ -1,5 +0,0 @@ -appwrite databases create-boolean-attribute \ - --database-id \ - --collection-id \ - --key '' \ - --required false diff --git a/docs/examples/databases/create-collection.md b/docs/examples/databases/create-collection.md deleted file mode 100644 index 89a754ce..00000000 --- a/docs/examples/databases/create-collection.md +++ /dev/null @@ -1,4 +0,0 @@ -appwrite databases create-collection \ - --database-id \ - --collection-id \ - --name diff --git a/docs/examples/databases/create-datetime-attribute.md b/docs/examples/databases/create-datetime-attribute.md deleted file mode 100644 index b445d084..00000000 --- a/docs/examples/databases/create-datetime-attribute.md +++ /dev/null @@ -1,5 +0,0 @@ -appwrite databases create-datetime-attribute \ - --database-id \ - --collection-id \ - --key '' \ - --required false diff --git a/docs/examples/databases/create-document.md b/docs/examples/databases/create-document.md deleted file mode 100644 index a45335ad..00000000 --- a/docs/examples/databases/create-document.md +++ /dev/null @@ -1,5 +0,0 @@ -appwrite databases create-document \ - --database-id \ - --collection-id \ - --document-id \ - --data '{ "key": "value" }' diff --git a/docs/examples/databases/create-documents.md b/docs/examples/databases/create-documents.md deleted file mode 100644 index 3512b684..00000000 --- a/docs/examples/databases/create-documents.md +++ /dev/null @@ -1,4 +0,0 @@ -appwrite databases create-documents \ - --database-id \ - --collection-id \ - --documents one two three diff --git a/docs/examples/databases/create-email-attribute.md b/docs/examples/databases/create-email-attribute.md deleted file mode 100644 index e4e9a0ba..00000000 --- a/docs/examples/databases/create-email-attribute.md +++ /dev/null @@ -1,5 +0,0 @@ -appwrite databases create-email-attribute \ - --database-id \ - --collection-id \ - --key '' \ - --required false diff --git a/docs/examples/databases/create-enum-attribute.md b/docs/examples/databases/create-enum-attribute.md deleted file mode 100644 index 2d4c72be..00000000 --- a/docs/examples/databases/create-enum-attribute.md +++ /dev/null @@ -1,6 +0,0 @@ -appwrite databases create-enum-attribute \ - --database-id \ - --collection-id \ - --key '' \ - --elements one two three \ - --required false diff --git a/docs/examples/databases/create-float-attribute.md b/docs/examples/databases/create-float-attribute.md deleted file mode 100644 index 0b9988b3..00000000 --- a/docs/examples/databases/create-float-attribute.md +++ /dev/null @@ -1,5 +0,0 @@ -appwrite databases create-float-attribute \ - --database-id \ - --collection-id \ - --key '' \ - --required false diff --git a/docs/examples/databases/create-index.md b/docs/examples/databases/create-index.md deleted file mode 100644 index cd8fc1dc..00000000 --- a/docs/examples/databases/create-index.md +++ /dev/null @@ -1,6 +0,0 @@ -appwrite databases create-index \ - --database-id \ - --collection-id \ - --key '' \ - --type key \ - --attributes one two three diff --git a/docs/examples/databases/create-integer-attribute.md b/docs/examples/databases/create-integer-attribute.md deleted file mode 100644 index 4c2207e8..00000000 --- a/docs/examples/databases/create-integer-attribute.md +++ /dev/null @@ -1,5 +0,0 @@ -appwrite databases create-integer-attribute \ - --database-id \ - --collection-id \ - --key '' \ - --required false diff --git a/docs/examples/databases/create-ip-attribute.md b/docs/examples/databases/create-ip-attribute.md deleted file mode 100644 index a1cd44e8..00000000 --- a/docs/examples/databases/create-ip-attribute.md +++ /dev/null @@ -1,5 +0,0 @@ -appwrite databases create-ip-attribute \ - --database-id \ - --collection-id \ - --key '' \ - --required false diff --git a/docs/examples/databases/create-line-attribute.md b/docs/examples/databases/create-line-attribute.md deleted file mode 100644 index f0d81ede..00000000 --- a/docs/examples/databases/create-line-attribute.md +++ /dev/null @@ -1,5 +0,0 @@ -appwrite databases create-line-attribute \ - --database-id \ - --collection-id \ - --key '' \ - --required false diff --git a/docs/examples/databases/create-operations.md b/docs/examples/databases/create-operations.md deleted file mode 100644 index 367b435c..00000000 --- a/docs/examples/databases/create-operations.md +++ /dev/null @@ -1,2 +0,0 @@ -appwrite databases create-operations \ - --transaction-id diff --git a/docs/examples/databases/create-point-attribute.md b/docs/examples/databases/create-point-attribute.md deleted file mode 100644 index 926c7318..00000000 --- a/docs/examples/databases/create-point-attribute.md +++ /dev/null @@ -1,5 +0,0 @@ -appwrite databases create-point-attribute \ - --database-id \ - --collection-id \ - --key '' \ - --required false diff --git a/docs/examples/databases/create-polygon-attribute.md b/docs/examples/databases/create-polygon-attribute.md deleted file mode 100644 index f0a00c74..00000000 --- a/docs/examples/databases/create-polygon-attribute.md +++ /dev/null @@ -1,5 +0,0 @@ -appwrite databases create-polygon-attribute \ - --database-id \ - --collection-id \ - --key '' \ - --required false diff --git a/docs/examples/databases/create-relationship-attribute.md b/docs/examples/databases/create-relationship-attribute.md deleted file mode 100644 index 70031623..00000000 --- a/docs/examples/databases/create-relationship-attribute.md +++ /dev/null @@ -1,5 +0,0 @@ -appwrite databases create-relationship-attribute \ - --database-id \ - --collection-id \ - --related-collection-id \ - --type oneToOne diff --git a/docs/examples/databases/create-string-attribute.md b/docs/examples/databases/create-string-attribute.md deleted file mode 100644 index ed464c59..00000000 --- a/docs/examples/databases/create-string-attribute.md +++ /dev/null @@ -1,6 +0,0 @@ -appwrite databases create-string-attribute \ - --database-id \ - --collection-id \ - --key '' \ - --size 1 \ - --required false diff --git a/docs/examples/databases/create-transaction.md b/docs/examples/databases/create-transaction.md deleted file mode 100644 index ef348e75..00000000 --- a/docs/examples/databases/create-transaction.md +++ /dev/null @@ -1 +0,0 @@ -appwrite databases create-transaction diff --git a/docs/examples/databases/create-url-attribute.md b/docs/examples/databases/create-url-attribute.md deleted file mode 100644 index 6968e8c6..00000000 --- a/docs/examples/databases/create-url-attribute.md +++ /dev/null @@ -1,5 +0,0 @@ -appwrite databases create-url-attribute \ - --database-id \ - --collection-id \ - --key '' \ - --required false diff --git a/docs/examples/databases/create.md b/docs/examples/databases/create.md deleted file mode 100644 index 47b04383..00000000 --- a/docs/examples/databases/create.md +++ /dev/null @@ -1,3 +0,0 @@ -appwrite databases create \ - --database-id \ - --name diff --git a/docs/examples/databases/decrement-document-attribute.md b/docs/examples/databases/decrement-document-attribute.md deleted file mode 100644 index 0b9b8a6b..00000000 --- a/docs/examples/databases/decrement-document-attribute.md +++ /dev/null @@ -1,5 +0,0 @@ -appwrite databases decrement-document-attribute \ - --database-id \ - --collection-id \ - --document-id \ - --attribute '' diff --git a/docs/examples/databases/delete-attribute.md b/docs/examples/databases/delete-attribute.md deleted file mode 100644 index 0d683586..00000000 --- a/docs/examples/databases/delete-attribute.md +++ /dev/null @@ -1,4 +0,0 @@ -appwrite databases delete-attribute \ - --database-id \ - --collection-id \ - --key '' diff --git a/docs/examples/databases/delete-collection.md b/docs/examples/databases/delete-collection.md deleted file mode 100644 index d120865c..00000000 --- a/docs/examples/databases/delete-collection.md +++ /dev/null @@ -1,3 +0,0 @@ -appwrite databases delete-collection \ - --database-id \ - --collection-id diff --git a/docs/examples/databases/delete-document.md b/docs/examples/databases/delete-document.md deleted file mode 100644 index 8e900198..00000000 --- a/docs/examples/databases/delete-document.md +++ /dev/null @@ -1,4 +0,0 @@ -appwrite databases delete-document \ - --database-id \ - --collection-id \ - --document-id diff --git a/docs/examples/databases/delete-documents.md b/docs/examples/databases/delete-documents.md deleted file mode 100644 index b334ed72..00000000 --- a/docs/examples/databases/delete-documents.md +++ /dev/null @@ -1,3 +0,0 @@ -appwrite databases delete-documents \ - --database-id \ - --collection-id diff --git a/docs/examples/databases/delete-index.md b/docs/examples/databases/delete-index.md deleted file mode 100644 index 2de11d36..00000000 --- a/docs/examples/databases/delete-index.md +++ /dev/null @@ -1,4 +0,0 @@ -appwrite databases delete-index \ - --database-id \ - --collection-id \ - --key '' diff --git a/docs/examples/databases/delete-transaction.md b/docs/examples/databases/delete-transaction.md deleted file mode 100644 index 13c02b67..00000000 --- a/docs/examples/databases/delete-transaction.md +++ /dev/null @@ -1,2 +0,0 @@ -appwrite databases delete-transaction \ - --transaction-id diff --git a/docs/examples/databases/delete.md b/docs/examples/databases/delete.md deleted file mode 100644 index 47437779..00000000 --- a/docs/examples/databases/delete.md +++ /dev/null @@ -1,2 +0,0 @@ -appwrite databases delete \ - --database-id diff --git a/docs/examples/databases/get-attribute.md b/docs/examples/databases/get-attribute.md deleted file mode 100644 index 70cee2c6..00000000 --- a/docs/examples/databases/get-attribute.md +++ /dev/null @@ -1,4 +0,0 @@ -appwrite databases get-attribute \ - --database-id \ - --collection-id \ - --key '' diff --git a/docs/examples/databases/get-collection-usage.md b/docs/examples/databases/get-collection-usage.md deleted file mode 100644 index c9881e27..00000000 --- a/docs/examples/databases/get-collection-usage.md +++ /dev/null @@ -1,3 +0,0 @@ -appwrite databases get-collection-usage \ - --database-id \ - --collection-id diff --git a/docs/examples/databases/get-collection.md b/docs/examples/databases/get-collection.md deleted file mode 100644 index 17cbdbef..00000000 --- a/docs/examples/databases/get-collection.md +++ /dev/null @@ -1,3 +0,0 @@ -appwrite databases get-collection \ - --database-id \ - --collection-id diff --git a/docs/examples/databases/get-document.md b/docs/examples/databases/get-document.md deleted file mode 100644 index beb44c14..00000000 --- a/docs/examples/databases/get-document.md +++ /dev/null @@ -1,4 +0,0 @@ -appwrite databases get-document \ - --database-id \ - --collection-id \ - --document-id diff --git a/docs/examples/databases/get-index.md b/docs/examples/databases/get-index.md deleted file mode 100644 index 50b5961a..00000000 --- a/docs/examples/databases/get-index.md +++ /dev/null @@ -1,4 +0,0 @@ -appwrite databases get-index \ - --database-id \ - --collection-id \ - --key '' diff --git a/docs/examples/databases/get-transaction.md b/docs/examples/databases/get-transaction.md deleted file mode 100644 index 7fc80e40..00000000 --- a/docs/examples/databases/get-transaction.md +++ /dev/null @@ -1,2 +0,0 @@ -appwrite databases get-transaction \ - --transaction-id diff --git a/docs/examples/databases/get-usage.md b/docs/examples/databases/get-usage.md deleted file mode 100644 index e3c87481..00000000 --- a/docs/examples/databases/get-usage.md +++ /dev/null @@ -1,2 +0,0 @@ -appwrite databases get-usage \ - --database-id diff --git a/docs/examples/databases/get.md b/docs/examples/databases/get.md deleted file mode 100644 index 83cec7dc..00000000 --- a/docs/examples/databases/get.md +++ /dev/null @@ -1,2 +0,0 @@ -appwrite databases get \ - --database-id diff --git a/docs/examples/databases/increment-document-attribute.md b/docs/examples/databases/increment-document-attribute.md deleted file mode 100644 index d51e44db..00000000 --- a/docs/examples/databases/increment-document-attribute.md +++ /dev/null @@ -1,5 +0,0 @@ -appwrite databases increment-document-attribute \ - --database-id \ - --collection-id \ - --document-id \ - --attribute '' diff --git a/docs/examples/databases/list-attributes.md b/docs/examples/databases/list-attributes.md deleted file mode 100644 index c531111e..00000000 --- a/docs/examples/databases/list-attributes.md +++ /dev/null @@ -1,3 +0,0 @@ -appwrite databases list-attributes \ - --database-id \ - --collection-id diff --git a/docs/examples/databases/list-collection-logs.md b/docs/examples/databases/list-collection-logs.md deleted file mode 100644 index 27f3a9bc..00000000 --- a/docs/examples/databases/list-collection-logs.md +++ /dev/null @@ -1,3 +0,0 @@ -appwrite databases list-collection-logs \ - --database-id \ - --collection-id diff --git a/docs/examples/databases/list-collections.md b/docs/examples/databases/list-collections.md deleted file mode 100644 index 55576eb4..00000000 --- a/docs/examples/databases/list-collections.md +++ /dev/null @@ -1,2 +0,0 @@ -appwrite databases list-collections \ - --database-id diff --git a/docs/examples/databases/list-document-logs.md b/docs/examples/databases/list-document-logs.md deleted file mode 100644 index 9f8fb22e..00000000 --- a/docs/examples/databases/list-document-logs.md +++ /dev/null @@ -1,4 +0,0 @@ -appwrite databases list-document-logs \ - --database-id \ - --collection-id \ - --document-id diff --git a/docs/examples/databases/list-documents.md b/docs/examples/databases/list-documents.md deleted file mode 100644 index 69e921c0..00000000 --- a/docs/examples/databases/list-documents.md +++ /dev/null @@ -1,3 +0,0 @@ -appwrite databases list-documents \ - --database-id \ - --collection-id diff --git a/docs/examples/databases/list-indexes.md b/docs/examples/databases/list-indexes.md deleted file mode 100644 index f12c1e93..00000000 --- a/docs/examples/databases/list-indexes.md +++ /dev/null @@ -1,3 +0,0 @@ -appwrite databases list-indexes \ - --database-id \ - --collection-id diff --git a/docs/examples/databases/list-logs.md b/docs/examples/databases/list-logs.md deleted file mode 100644 index 293df553..00000000 --- a/docs/examples/databases/list-logs.md +++ /dev/null @@ -1,2 +0,0 @@ -appwrite databases list-logs \ - --database-id diff --git a/docs/examples/databases/list-transactions.md b/docs/examples/databases/list-transactions.md deleted file mode 100644 index f0cc259b..00000000 --- a/docs/examples/databases/list-transactions.md +++ /dev/null @@ -1 +0,0 @@ -appwrite databases list-transactions diff --git a/docs/examples/databases/list-usage.md b/docs/examples/databases/list-usage.md deleted file mode 100644 index 6bff75fa..00000000 --- a/docs/examples/databases/list-usage.md +++ /dev/null @@ -1 +0,0 @@ -appwrite databases list-usage diff --git a/docs/examples/databases/list.md b/docs/examples/databases/list.md deleted file mode 100644 index 6681edc9..00000000 --- a/docs/examples/databases/list.md +++ /dev/null @@ -1 +0,0 @@ -appwrite databases list diff --git a/docs/examples/databases/update-boolean-attribute.md b/docs/examples/databases/update-boolean-attribute.md deleted file mode 100644 index 578a5dc5..00000000 --- a/docs/examples/databases/update-boolean-attribute.md +++ /dev/null @@ -1,6 +0,0 @@ -appwrite databases update-boolean-attribute \ - --database-id \ - --collection-id \ - --key '' \ - --required false \ - --default false diff --git a/docs/examples/databases/update-collection.md b/docs/examples/databases/update-collection.md deleted file mode 100644 index 0bad4850..00000000 --- a/docs/examples/databases/update-collection.md +++ /dev/null @@ -1,4 +0,0 @@ -appwrite databases update-collection \ - --database-id \ - --collection-id \ - --name diff --git a/docs/examples/databases/update-datetime-attribute.md b/docs/examples/databases/update-datetime-attribute.md deleted file mode 100644 index 53459e02..00000000 --- a/docs/examples/databases/update-datetime-attribute.md +++ /dev/null @@ -1,6 +0,0 @@ -appwrite databases update-datetime-attribute \ - --database-id \ - --collection-id \ - --key '' \ - --required false \ - --default '' diff --git a/docs/examples/databases/update-document.md b/docs/examples/databases/update-document.md deleted file mode 100644 index 29f14612..00000000 --- a/docs/examples/databases/update-document.md +++ /dev/null @@ -1,4 +0,0 @@ -appwrite databases update-document \ - --database-id \ - --collection-id \ - --document-id diff --git a/docs/examples/databases/update-documents.md b/docs/examples/databases/update-documents.md deleted file mode 100644 index f4f85eb7..00000000 --- a/docs/examples/databases/update-documents.md +++ /dev/null @@ -1,3 +0,0 @@ -appwrite databases update-documents \ - --database-id \ - --collection-id diff --git a/docs/examples/databases/update-email-attribute.md b/docs/examples/databases/update-email-attribute.md deleted file mode 100644 index 20ea2192..00000000 --- a/docs/examples/databases/update-email-attribute.md +++ /dev/null @@ -1,6 +0,0 @@ -appwrite databases update-email-attribute \ - --database-id \ - --collection-id \ - --key '' \ - --required false \ - --default email@example.com diff --git a/docs/examples/databases/update-enum-attribute.md b/docs/examples/databases/update-enum-attribute.md deleted file mode 100644 index dfae8d27..00000000 --- a/docs/examples/databases/update-enum-attribute.md +++ /dev/null @@ -1,7 +0,0 @@ -appwrite databases update-enum-attribute \ - --database-id \ - --collection-id \ - --key '' \ - --elements one two three \ - --required false \ - --default diff --git a/docs/examples/databases/update-float-attribute.md b/docs/examples/databases/update-float-attribute.md deleted file mode 100644 index caeaa96f..00000000 --- a/docs/examples/databases/update-float-attribute.md +++ /dev/null @@ -1,6 +0,0 @@ -appwrite databases update-float-attribute \ - --database-id \ - --collection-id \ - --key '' \ - --required false \ - --default null diff --git a/docs/examples/databases/update-integer-attribute.md b/docs/examples/databases/update-integer-attribute.md deleted file mode 100644 index 2ab6e121..00000000 --- a/docs/examples/databases/update-integer-attribute.md +++ /dev/null @@ -1,6 +0,0 @@ -appwrite databases update-integer-attribute \ - --database-id \ - --collection-id \ - --key '' \ - --required false \ - --default null diff --git a/docs/examples/databases/update-ip-attribute.md b/docs/examples/databases/update-ip-attribute.md deleted file mode 100644 index 44b40105..00000000 --- a/docs/examples/databases/update-ip-attribute.md +++ /dev/null @@ -1,6 +0,0 @@ -appwrite databases update-ip-attribute \ - --database-id \ - --collection-id \ - --key '' \ - --required false \ - --default '' diff --git a/docs/examples/databases/update-line-attribute.md b/docs/examples/databases/update-line-attribute.md deleted file mode 100644 index 37059ece..00000000 --- a/docs/examples/databases/update-line-attribute.md +++ /dev/null @@ -1,5 +0,0 @@ -appwrite databases update-line-attribute \ - --database-id \ - --collection-id \ - --key '' \ - --required false diff --git a/docs/examples/databases/update-point-attribute.md b/docs/examples/databases/update-point-attribute.md deleted file mode 100644 index bcc983a4..00000000 --- a/docs/examples/databases/update-point-attribute.md +++ /dev/null @@ -1,5 +0,0 @@ -appwrite databases update-point-attribute \ - --database-id \ - --collection-id \ - --key '' \ - --required false diff --git a/docs/examples/databases/update-polygon-attribute.md b/docs/examples/databases/update-polygon-attribute.md deleted file mode 100644 index 6e1e1001..00000000 --- a/docs/examples/databases/update-polygon-attribute.md +++ /dev/null @@ -1,5 +0,0 @@ -appwrite databases update-polygon-attribute \ - --database-id \ - --collection-id \ - --key '' \ - --required false diff --git a/docs/examples/databases/update-relationship-attribute.md b/docs/examples/databases/update-relationship-attribute.md deleted file mode 100644 index d3f27d78..00000000 --- a/docs/examples/databases/update-relationship-attribute.md +++ /dev/null @@ -1,4 +0,0 @@ -appwrite databases update-relationship-attribute \ - --database-id \ - --collection-id \ - --key '' diff --git a/docs/examples/databases/update-string-attribute.md b/docs/examples/databases/update-string-attribute.md deleted file mode 100644 index 0e0dd714..00000000 --- a/docs/examples/databases/update-string-attribute.md +++ /dev/null @@ -1,6 +0,0 @@ -appwrite databases update-string-attribute \ - --database-id \ - --collection-id \ - --key '' \ - --required false \ - --default diff --git a/docs/examples/databases/update-transaction.md b/docs/examples/databases/update-transaction.md deleted file mode 100644 index cda11d4e..00000000 --- a/docs/examples/databases/update-transaction.md +++ /dev/null @@ -1,2 +0,0 @@ -appwrite databases update-transaction \ - --transaction-id diff --git a/docs/examples/databases/update-url-attribute.md b/docs/examples/databases/update-url-attribute.md deleted file mode 100644 index 76e6feb1..00000000 --- a/docs/examples/databases/update-url-attribute.md +++ /dev/null @@ -1,6 +0,0 @@ -appwrite databases update-url-attribute \ - --database-id \ - --collection-id \ - --key '' \ - --required false \ - --default https://example.com diff --git a/docs/examples/databases/update.md b/docs/examples/databases/update.md deleted file mode 100644 index e3e1de75..00000000 --- a/docs/examples/databases/update.md +++ /dev/null @@ -1,3 +0,0 @@ -appwrite databases update \ - --database-id \ - --name diff --git a/docs/examples/databases/upsert-document.md b/docs/examples/databases/upsert-document.md deleted file mode 100644 index 8b1e1382..00000000 --- a/docs/examples/databases/upsert-document.md +++ /dev/null @@ -1,4 +0,0 @@ -appwrite databases upsert-document \ - --database-id \ - --collection-id \ - --document-id diff --git a/docs/examples/databases/upsert-documents.md b/docs/examples/databases/upsert-documents.md deleted file mode 100644 index e58c202d..00000000 --- a/docs/examples/databases/upsert-documents.md +++ /dev/null @@ -1,4 +0,0 @@ -appwrite databases upsert-documents \ - --database-id \ - --collection-id \ - --documents one two three diff --git a/docs/examples/functions/create-deployment.md b/docs/examples/functions/create-deployment.md deleted file mode 100644 index 465951c3..00000000 --- a/docs/examples/functions/create-deployment.md +++ /dev/null @@ -1,4 +0,0 @@ -appwrite functions create-deployment \ - --function-id \ - --code 'path/to/file.png' \ - --activate false diff --git a/docs/examples/functions/create-duplicate-deployment.md b/docs/examples/functions/create-duplicate-deployment.md deleted file mode 100644 index 7d5c28bc..00000000 --- a/docs/examples/functions/create-duplicate-deployment.md +++ /dev/null @@ -1,3 +0,0 @@ -appwrite functions create-duplicate-deployment \ - --function-id \ - --deployment-id diff --git a/docs/examples/functions/create-execution.md b/docs/examples/functions/create-execution.md deleted file mode 100644 index fd3b3dd6..00000000 --- a/docs/examples/functions/create-execution.md +++ /dev/null @@ -1,2 +0,0 @@ -appwrite functions create-execution \ - --function-id diff --git a/docs/examples/functions/create-template-deployment.md b/docs/examples/functions/create-template-deployment.md deleted file mode 100644 index 72fa62b3..00000000 --- a/docs/examples/functions/create-template-deployment.md +++ /dev/null @@ -1,7 +0,0 @@ -appwrite functions create-template-deployment \ - --function-id \ - --repository \ - --owner \ - --root-directory \ - --type commit \ - --reference diff --git a/docs/examples/functions/create-variable.md b/docs/examples/functions/create-variable.md deleted file mode 100644 index 50edcaaa..00000000 --- a/docs/examples/functions/create-variable.md +++ /dev/null @@ -1,4 +0,0 @@ -appwrite functions create-variable \ - --function-id \ - --key \ - --value diff --git a/docs/examples/functions/create-vcs-deployment.md b/docs/examples/functions/create-vcs-deployment.md deleted file mode 100644 index 8e846222..00000000 --- a/docs/examples/functions/create-vcs-deployment.md +++ /dev/null @@ -1,4 +0,0 @@ -appwrite functions create-vcs-deployment \ - --function-id \ - --type branch \ - --reference diff --git a/docs/examples/functions/create.md b/docs/examples/functions/create.md deleted file mode 100644 index bdca30d8..00000000 --- a/docs/examples/functions/create.md +++ /dev/null @@ -1,4 +0,0 @@ -appwrite functions create \ - --function-id \ - --name \ - --runtime node-14.5 diff --git a/docs/examples/functions/delete-deployment.md b/docs/examples/functions/delete-deployment.md deleted file mode 100644 index 4f50b927..00000000 --- a/docs/examples/functions/delete-deployment.md +++ /dev/null @@ -1,3 +0,0 @@ -appwrite functions delete-deployment \ - --function-id \ - --deployment-id diff --git a/docs/examples/functions/delete-execution.md b/docs/examples/functions/delete-execution.md deleted file mode 100644 index a11c4cb7..00000000 --- a/docs/examples/functions/delete-execution.md +++ /dev/null @@ -1,3 +0,0 @@ -appwrite functions delete-execution \ - --function-id \ - --execution-id diff --git a/docs/examples/functions/delete-variable.md b/docs/examples/functions/delete-variable.md deleted file mode 100644 index aebe8570..00000000 --- a/docs/examples/functions/delete-variable.md +++ /dev/null @@ -1,3 +0,0 @@ -appwrite functions delete-variable \ - --function-id \ - --variable-id diff --git a/docs/examples/functions/delete.md b/docs/examples/functions/delete.md deleted file mode 100644 index abf27334..00000000 --- a/docs/examples/functions/delete.md +++ /dev/null @@ -1,2 +0,0 @@ -appwrite functions delete \ - --function-id diff --git a/docs/examples/functions/get-deployment-download.md b/docs/examples/functions/get-deployment-download.md deleted file mode 100644 index b9bfcabf..00000000 --- a/docs/examples/functions/get-deployment-download.md +++ /dev/null @@ -1,3 +0,0 @@ -appwrite functions get-deployment-download \ - --function-id \ - --deployment-id diff --git a/docs/examples/functions/get-deployment.md b/docs/examples/functions/get-deployment.md deleted file mode 100644 index 4a658074..00000000 --- a/docs/examples/functions/get-deployment.md +++ /dev/null @@ -1,3 +0,0 @@ -appwrite functions get-deployment \ - --function-id \ - --deployment-id diff --git a/docs/examples/functions/get-execution.md b/docs/examples/functions/get-execution.md deleted file mode 100644 index ac2ad142..00000000 --- a/docs/examples/functions/get-execution.md +++ /dev/null @@ -1,3 +0,0 @@ -appwrite functions get-execution \ - --function-id \ - --execution-id diff --git a/docs/examples/functions/get-template.md b/docs/examples/functions/get-template.md deleted file mode 100644 index 2ab2afbc..00000000 --- a/docs/examples/functions/get-template.md +++ /dev/null @@ -1,2 +0,0 @@ -appwrite functions get-template \ - --template-id diff --git a/docs/examples/functions/get-usage.md b/docs/examples/functions/get-usage.md deleted file mode 100644 index a3f061d1..00000000 --- a/docs/examples/functions/get-usage.md +++ /dev/null @@ -1,2 +0,0 @@ -appwrite functions get-usage \ - --function-id diff --git a/docs/examples/functions/get-variable.md b/docs/examples/functions/get-variable.md deleted file mode 100644 index 06a3a496..00000000 --- a/docs/examples/functions/get-variable.md +++ /dev/null @@ -1,3 +0,0 @@ -appwrite functions get-variable \ - --function-id \ - --variable-id diff --git a/docs/examples/functions/get.md b/docs/examples/functions/get.md deleted file mode 100644 index fafa87ec..00000000 --- a/docs/examples/functions/get.md +++ /dev/null @@ -1,2 +0,0 @@ -appwrite functions get \ - --function-id diff --git a/docs/examples/functions/list-deployments.md b/docs/examples/functions/list-deployments.md deleted file mode 100644 index 5bb2c601..00000000 --- a/docs/examples/functions/list-deployments.md +++ /dev/null @@ -1,2 +0,0 @@ -appwrite functions list-deployments \ - --function-id diff --git a/docs/examples/functions/list-executions.md b/docs/examples/functions/list-executions.md deleted file mode 100644 index a0089477..00000000 --- a/docs/examples/functions/list-executions.md +++ /dev/null @@ -1,2 +0,0 @@ -appwrite functions list-executions \ - --function-id diff --git a/docs/examples/functions/list-runtimes.md b/docs/examples/functions/list-runtimes.md deleted file mode 100644 index a0430d6c..00000000 --- a/docs/examples/functions/list-runtimes.md +++ /dev/null @@ -1 +0,0 @@ -appwrite functions list-runtimes diff --git a/docs/examples/functions/list-specifications.md b/docs/examples/functions/list-specifications.md deleted file mode 100644 index 4fac74ec..00000000 --- a/docs/examples/functions/list-specifications.md +++ /dev/null @@ -1 +0,0 @@ -appwrite functions list-specifications diff --git a/docs/examples/functions/list-templates.md b/docs/examples/functions/list-templates.md deleted file mode 100644 index 22209fe1..00000000 --- a/docs/examples/functions/list-templates.md +++ /dev/null @@ -1 +0,0 @@ -appwrite functions list-templates diff --git a/docs/examples/functions/list-usage.md b/docs/examples/functions/list-usage.md deleted file mode 100644 index de28c5c9..00000000 --- a/docs/examples/functions/list-usage.md +++ /dev/null @@ -1 +0,0 @@ -appwrite functions list-usage diff --git a/docs/examples/functions/list-variables.md b/docs/examples/functions/list-variables.md deleted file mode 100644 index 03e11625..00000000 --- a/docs/examples/functions/list-variables.md +++ /dev/null @@ -1,2 +0,0 @@ -appwrite functions list-variables \ - --function-id diff --git a/docs/examples/functions/list.md b/docs/examples/functions/list.md deleted file mode 100644 index 2d9f0ba7..00000000 --- a/docs/examples/functions/list.md +++ /dev/null @@ -1 +0,0 @@ -appwrite functions list diff --git a/docs/examples/functions/update-deployment-status.md b/docs/examples/functions/update-deployment-status.md deleted file mode 100644 index 6f0bc1e5..00000000 --- a/docs/examples/functions/update-deployment-status.md +++ /dev/null @@ -1,3 +0,0 @@ -appwrite functions update-deployment-status \ - --function-id \ - --deployment-id diff --git a/docs/examples/functions/update-function-deployment.md b/docs/examples/functions/update-function-deployment.md deleted file mode 100644 index d3534b4e..00000000 --- a/docs/examples/functions/update-function-deployment.md +++ /dev/null @@ -1,3 +0,0 @@ -appwrite functions update-function-deployment \ - --function-id \ - --deployment-id diff --git a/docs/examples/functions/update-variable.md b/docs/examples/functions/update-variable.md deleted file mode 100644 index c1d87f29..00000000 --- a/docs/examples/functions/update-variable.md +++ /dev/null @@ -1,4 +0,0 @@ -appwrite functions update-variable \ - --function-id \ - --variable-id \ - --key diff --git a/docs/examples/functions/update.md b/docs/examples/functions/update.md deleted file mode 100644 index c436ef05..00000000 --- a/docs/examples/functions/update.md +++ /dev/null @@ -1,3 +0,0 @@ -appwrite functions update \ - --function-id \ - --name diff --git a/docs/examples/graphql/mutation.md b/docs/examples/graphql/mutation.md deleted file mode 100644 index 678fcc2e..00000000 --- a/docs/examples/graphql/mutation.md +++ /dev/null @@ -1,2 +0,0 @@ -appwrite graphql mutation \ - --query '{ "key": "value" }' diff --git a/docs/examples/graphql/query.md b/docs/examples/graphql/query.md deleted file mode 100644 index 157115a1..00000000 --- a/docs/examples/graphql/query.md +++ /dev/null @@ -1,2 +0,0 @@ -appwrite graphql query \ - --query '{ "key": "value" }' diff --git a/docs/examples/health/get-antivirus.md b/docs/examples/health/get-antivirus.md deleted file mode 100644 index 2ef8b6f3..00000000 --- a/docs/examples/health/get-antivirus.md +++ /dev/null @@ -1 +0,0 @@ -appwrite health get-antivirus diff --git a/docs/examples/health/get-cache.md b/docs/examples/health/get-cache.md deleted file mode 100644 index b1ff1310..00000000 --- a/docs/examples/health/get-cache.md +++ /dev/null @@ -1 +0,0 @@ -appwrite health get-cache diff --git a/docs/examples/health/get-certificate.md b/docs/examples/health/get-certificate.md deleted file mode 100644 index 17652161..00000000 --- a/docs/examples/health/get-certificate.md +++ /dev/null @@ -1 +0,0 @@ -appwrite health get-certificate diff --git a/docs/examples/health/get-db.md b/docs/examples/health/get-db.md deleted file mode 100644 index c5e9cb37..00000000 --- a/docs/examples/health/get-db.md +++ /dev/null @@ -1 +0,0 @@ -appwrite health get-db diff --git a/docs/examples/health/get-failed-jobs.md b/docs/examples/health/get-failed-jobs.md deleted file mode 100644 index 9704875b..00000000 --- a/docs/examples/health/get-failed-jobs.md +++ /dev/null @@ -1,2 +0,0 @@ -appwrite health get-failed-jobs \ - --name v1-database diff --git a/docs/examples/health/get-pub-sub.md b/docs/examples/health/get-pub-sub.md deleted file mode 100644 index 29e93a2b..00000000 --- a/docs/examples/health/get-pub-sub.md +++ /dev/null @@ -1 +0,0 @@ -appwrite health get-pub-sub diff --git a/docs/examples/health/get-queue-builds.md b/docs/examples/health/get-queue-builds.md deleted file mode 100644 index 657b9888..00000000 --- a/docs/examples/health/get-queue-builds.md +++ /dev/null @@ -1 +0,0 @@ -appwrite health get-queue-builds diff --git a/docs/examples/health/get-queue-certificates.md b/docs/examples/health/get-queue-certificates.md deleted file mode 100644 index a7c1c64a..00000000 --- a/docs/examples/health/get-queue-certificates.md +++ /dev/null @@ -1 +0,0 @@ -appwrite health get-queue-certificates diff --git a/docs/examples/health/get-queue-databases.md b/docs/examples/health/get-queue-databases.md deleted file mode 100644 index 17d15bad..00000000 --- a/docs/examples/health/get-queue-databases.md +++ /dev/null @@ -1 +0,0 @@ -appwrite health get-queue-databases diff --git a/docs/examples/health/get-queue-deletes.md b/docs/examples/health/get-queue-deletes.md deleted file mode 100644 index 78ddc322..00000000 --- a/docs/examples/health/get-queue-deletes.md +++ /dev/null @@ -1 +0,0 @@ -appwrite health get-queue-deletes diff --git a/docs/examples/health/get-queue-functions.md b/docs/examples/health/get-queue-functions.md deleted file mode 100644 index 8109a8e8..00000000 --- a/docs/examples/health/get-queue-functions.md +++ /dev/null @@ -1 +0,0 @@ -appwrite health get-queue-functions diff --git a/docs/examples/health/get-queue-logs.md b/docs/examples/health/get-queue-logs.md deleted file mode 100644 index 5ff48cc8..00000000 --- a/docs/examples/health/get-queue-logs.md +++ /dev/null @@ -1 +0,0 @@ -appwrite health get-queue-logs diff --git a/docs/examples/health/get-queue-mails.md b/docs/examples/health/get-queue-mails.md deleted file mode 100644 index e44b1b62..00000000 --- a/docs/examples/health/get-queue-mails.md +++ /dev/null @@ -1 +0,0 @@ -appwrite health get-queue-mails diff --git a/docs/examples/health/get-queue-messaging.md b/docs/examples/health/get-queue-messaging.md deleted file mode 100644 index 5249c735..00000000 --- a/docs/examples/health/get-queue-messaging.md +++ /dev/null @@ -1 +0,0 @@ -appwrite health get-queue-messaging diff --git a/docs/examples/health/get-queue-migrations.md b/docs/examples/health/get-queue-migrations.md deleted file mode 100644 index 11b07a10..00000000 --- a/docs/examples/health/get-queue-migrations.md +++ /dev/null @@ -1 +0,0 @@ -appwrite health get-queue-migrations diff --git a/docs/examples/health/get-queue-stats-resources.md b/docs/examples/health/get-queue-stats-resources.md deleted file mode 100644 index 2e511862..00000000 --- a/docs/examples/health/get-queue-stats-resources.md +++ /dev/null @@ -1 +0,0 @@ -appwrite health get-queue-stats-resources diff --git a/docs/examples/health/get-queue-usage.md b/docs/examples/health/get-queue-usage.md deleted file mode 100644 index 1790e0fb..00000000 --- a/docs/examples/health/get-queue-usage.md +++ /dev/null @@ -1 +0,0 @@ -appwrite health get-queue-usage diff --git a/docs/examples/health/get-queue-webhooks.md b/docs/examples/health/get-queue-webhooks.md deleted file mode 100644 index e1753347..00000000 --- a/docs/examples/health/get-queue-webhooks.md +++ /dev/null @@ -1 +0,0 @@ -appwrite health get-queue-webhooks diff --git a/docs/examples/health/get-storage-local.md b/docs/examples/health/get-storage-local.md deleted file mode 100644 index 512d135f..00000000 --- a/docs/examples/health/get-storage-local.md +++ /dev/null @@ -1 +0,0 @@ -appwrite health get-storage-local diff --git a/docs/examples/health/get-storage.md b/docs/examples/health/get-storage.md deleted file mode 100644 index 170bcfc4..00000000 --- a/docs/examples/health/get-storage.md +++ /dev/null @@ -1 +0,0 @@ -appwrite health get-storage diff --git a/docs/examples/health/get-time.md b/docs/examples/health/get-time.md deleted file mode 100644 index feb3901e..00000000 --- a/docs/examples/health/get-time.md +++ /dev/null @@ -1 +0,0 @@ -appwrite health get-time diff --git a/docs/examples/health/get.md b/docs/examples/health/get.md deleted file mode 100644 index 94c08e5a..00000000 --- a/docs/examples/health/get.md +++ /dev/null @@ -1 +0,0 @@ -appwrite health get diff --git a/docs/examples/locale/get.md b/docs/examples/locale/get.md deleted file mode 100644 index 2002a06c..00000000 --- a/docs/examples/locale/get.md +++ /dev/null @@ -1 +0,0 @@ -appwrite locale get diff --git a/docs/examples/locale/list-codes.md b/docs/examples/locale/list-codes.md deleted file mode 100644 index ac96ac14..00000000 --- a/docs/examples/locale/list-codes.md +++ /dev/null @@ -1 +0,0 @@ -appwrite locale list-codes diff --git a/docs/examples/locale/list-continents.md b/docs/examples/locale/list-continents.md deleted file mode 100644 index 18267872..00000000 --- a/docs/examples/locale/list-continents.md +++ /dev/null @@ -1 +0,0 @@ -appwrite locale list-continents diff --git a/docs/examples/locale/list-countries-eu.md b/docs/examples/locale/list-countries-eu.md deleted file mode 100644 index eba8886a..00000000 --- a/docs/examples/locale/list-countries-eu.md +++ /dev/null @@ -1 +0,0 @@ -appwrite locale list-countries-eu diff --git a/docs/examples/locale/list-countries-phones.md b/docs/examples/locale/list-countries-phones.md deleted file mode 100644 index ea271552..00000000 --- a/docs/examples/locale/list-countries-phones.md +++ /dev/null @@ -1 +0,0 @@ -appwrite locale list-countries-phones diff --git a/docs/examples/locale/list-countries.md b/docs/examples/locale/list-countries.md deleted file mode 100644 index 65244613..00000000 --- a/docs/examples/locale/list-countries.md +++ /dev/null @@ -1 +0,0 @@ -appwrite locale list-countries diff --git a/docs/examples/locale/list-currencies.md b/docs/examples/locale/list-currencies.md deleted file mode 100644 index bbc0f363..00000000 --- a/docs/examples/locale/list-currencies.md +++ /dev/null @@ -1 +0,0 @@ -appwrite locale list-currencies diff --git a/docs/examples/locale/list-languages.md b/docs/examples/locale/list-languages.md deleted file mode 100644 index a0cfe918..00000000 --- a/docs/examples/locale/list-languages.md +++ /dev/null @@ -1 +0,0 @@ -appwrite locale list-languages diff --git a/docs/examples/messaging/create-apns-provider.md b/docs/examples/messaging/create-apns-provider.md deleted file mode 100644 index fd5aaa99..00000000 --- a/docs/examples/messaging/create-apns-provider.md +++ /dev/null @@ -1,3 +0,0 @@ -appwrite messaging create-apns-provider \ - --provider-id \ - --name diff --git a/docs/examples/messaging/create-email.md b/docs/examples/messaging/create-email.md deleted file mode 100644 index e8ffc116..00000000 --- a/docs/examples/messaging/create-email.md +++ /dev/null @@ -1,4 +0,0 @@ -appwrite messaging create-email \ - --message-id \ - --subject \ - --content diff --git a/docs/examples/messaging/create-fcm-provider.md b/docs/examples/messaging/create-fcm-provider.md deleted file mode 100644 index 487bb039..00000000 --- a/docs/examples/messaging/create-fcm-provider.md +++ /dev/null @@ -1,3 +0,0 @@ -appwrite messaging create-fcm-provider \ - --provider-id \ - --name diff --git a/docs/examples/messaging/create-mailgun-provider.md b/docs/examples/messaging/create-mailgun-provider.md deleted file mode 100644 index 2616f007..00000000 --- a/docs/examples/messaging/create-mailgun-provider.md +++ /dev/null @@ -1,3 +0,0 @@ -appwrite messaging create-mailgun-provider \ - --provider-id \ - --name diff --git a/docs/examples/messaging/create-msg-91-provider.md b/docs/examples/messaging/create-msg-91-provider.md deleted file mode 100644 index d4f975d3..00000000 --- a/docs/examples/messaging/create-msg-91-provider.md +++ /dev/null @@ -1,3 +0,0 @@ -appwrite messaging create-msg-91-provider \ - --provider-id \ - --name diff --git a/docs/examples/messaging/create-push.md b/docs/examples/messaging/create-push.md deleted file mode 100644 index d5740b93..00000000 --- a/docs/examples/messaging/create-push.md +++ /dev/null @@ -1,2 +0,0 @@ -appwrite messaging create-push \ - --message-id diff --git a/docs/examples/messaging/create-resend-provider.md b/docs/examples/messaging/create-resend-provider.md deleted file mode 100644 index 9a16a17a..00000000 --- a/docs/examples/messaging/create-resend-provider.md +++ /dev/null @@ -1,3 +0,0 @@ -appwrite messaging create-resend-provider \ - --provider-id \ - --name diff --git a/docs/examples/messaging/create-sendgrid-provider.md b/docs/examples/messaging/create-sendgrid-provider.md deleted file mode 100644 index 2a478fdb..00000000 --- a/docs/examples/messaging/create-sendgrid-provider.md +++ /dev/null @@ -1,3 +0,0 @@ -appwrite messaging create-sendgrid-provider \ - --provider-id \ - --name diff --git a/docs/examples/messaging/create-sms.md b/docs/examples/messaging/create-sms.md deleted file mode 100644 index 3633d065..00000000 --- a/docs/examples/messaging/create-sms.md +++ /dev/null @@ -1,3 +0,0 @@ -appwrite messaging create-sms \ - --message-id \ - --content diff --git a/docs/examples/messaging/create-smtp-provider.md b/docs/examples/messaging/create-smtp-provider.md deleted file mode 100644 index 9a417835..00000000 --- a/docs/examples/messaging/create-smtp-provider.md +++ /dev/null @@ -1,4 +0,0 @@ -appwrite messaging create-smtp-provider \ - --provider-id \ - --name \ - --host diff --git a/docs/examples/messaging/create-subscriber.md b/docs/examples/messaging/create-subscriber.md deleted file mode 100644 index 5fe7682f..00000000 --- a/docs/examples/messaging/create-subscriber.md +++ /dev/null @@ -1,4 +0,0 @@ -appwrite messaging create-subscriber \ - --topic-id \ - --subscriber-id \ - --target-id diff --git a/docs/examples/messaging/create-telesign-provider.md b/docs/examples/messaging/create-telesign-provider.md deleted file mode 100644 index 052028d6..00000000 --- a/docs/examples/messaging/create-telesign-provider.md +++ /dev/null @@ -1,3 +0,0 @@ -appwrite messaging create-telesign-provider \ - --provider-id \ - --name diff --git a/docs/examples/messaging/create-textmagic-provider.md b/docs/examples/messaging/create-textmagic-provider.md deleted file mode 100644 index 6ff37b01..00000000 --- a/docs/examples/messaging/create-textmagic-provider.md +++ /dev/null @@ -1,3 +0,0 @@ -appwrite messaging create-textmagic-provider \ - --provider-id \ - --name diff --git a/docs/examples/messaging/create-topic.md b/docs/examples/messaging/create-topic.md deleted file mode 100644 index 3a28bb16..00000000 --- a/docs/examples/messaging/create-topic.md +++ /dev/null @@ -1,3 +0,0 @@ -appwrite messaging create-topic \ - --topic-id \ - --name diff --git a/docs/examples/messaging/create-twilio-provider.md b/docs/examples/messaging/create-twilio-provider.md deleted file mode 100644 index 2b2f00dc..00000000 --- a/docs/examples/messaging/create-twilio-provider.md +++ /dev/null @@ -1,3 +0,0 @@ -appwrite messaging create-twilio-provider \ - --provider-id \ - --name diff --git a/docs/examples/messaging/create-vonage-provider.md b/docs/examples/messaging/create-vonage-provider.md deleted file mode 100644 index 56fb3e67..00000000 --- a/docs/examples/messaging/create-vonage-provider.md +++ /dev/null @@ -1,3 +0,0 @@ -appwrite messaging create-vonage-provider \ - --provider-id \ - --name diff --git a/docs/examples/messaging/delete-provider.md b/docs/examples/messaging/delete-provider.md deleted file mode 100644 index 75671a99..00000000 --- a/docs/examples/messaging/delete-provider.md +++ /dev/null @@ -1,2 +0,0 @@ -appwrite messaging delete-provider \ - --provider-id diff --git a/docs/examples/messaging/delete-subscriber.md b/docs/examples/messaging/delete-subscriber.md deleted file mode 100644 index d433e3a5..00000000 --- a/docs/examples/messaging/delete-subscriber.md +++ /dev/null @@ -1,3 +0,0 @@ -appwrite messaging delete-subscriber \ - --topic-id \ - --subscriber-id diff --git a/docs/examples/messaging/delete-topic.md b/docs/examples/messaging/delete-topic.md deleted file mode 100644 index 0c2887c0..00000000 --- a/docs/examples/messaging/delete-topic.md +++ /dev/null @@ -1,2 +0,0 @@ -appwrite messaging delete-topic \ - --topic-id diff --git a/docs/examples/messaging/delete.md b/docs/examples/messaging/delete.md deleted file mode 100644 index eb5d2a62..00000000 --- a/docs/examples/messaging/delete.md +++ /dev/null @@ -1,2 +0,0 @@ -appwrite messaging delete \ - --message-id diff --git a/docs/examples/messaging/get-message.md b/docs/examples/messaging/get-message.md deleted file mode 100644 index 2de245ef..00000000 --- a/docs/examples/messaging/get-message.md +++ /dev/null @@ -1,2 +0,0 @@ -appwrite messaging get-message \ - --message-id diff --git a/docs/examples/messaging/get-provider.md b/docs/examples/messaging/get-provider.md deleted file mode 100644 index b115c52c..00000000 --- a/docs/examples/messaging/get-provider.md +++ /dev/null @@ -1,2 +0,0 @@ -appwrite messaging get-provider \ - --provider-id diff --git a/docs/examples/messaging/get-subscriber.md b/docs/examples/messaging/get-subscriber.md deleted file mode 100644 index 88c2ab60..00000000 --- a/docs/examples/messaging/get-subscriber.md +++ /dev/null @@ -1,3 +0,0 @@ -appwrite messaging get-subscriber \ - --topic-id \ - --subscriber-id diff --git a/docs/examples/messaging/get-topic.md b/docs/examples/messaging/get-topic.md deleted file mode 100644 index 7628bedf..00000000 --- a/docs/examples/messaging/get-topic.md +++ /dev/null @@ -1,2 +0,0 @@ -appwrite messaging get-topic \ - --topic-id diff --git a/docs/examples/messaging/list-message-logs.md b/docs/examples/messaging/list-message-logs.md deleted file mode 100644 index 9cc6dc55..00000000 --- a/docs/examples/messaging/list-message-logs.md +++ /dev/null @@ -1,2 +0,0 @@ -appwrite messaging list-message-logs \ - --message-id diff --git a/docs/examples/messaging/list-messages.md b/docs/examples/messaging/list-messages.md deleted file mode 100644 index 1e8a726f..00000000 --- a/docs/examples/messaging/list-messages.md +++ /dev/null @@ -1 +0,0 @@ -appwrite messaging list-messages diff --git a/docs/examples/messaging/list-provider-logs.md b/docs/examples/messaging/list-provider-logs.md deleted file mode 100644 index 95e514ec..00000000 --- a/docs/examples/messaging/list-provider-logs.md +++ /dev/null @@ -1,2 +0,0 @@ -appwrite messaging list-provider-logs \ - --provider-id diff --git a/docs/examples/messaging/list-providers.md b/docs/examples/messaging/list-providers.md deleted file mode 100644 index d075be57..00000000 --- a/docs/examples/messaging/list-providers.md +++ /dev/null @@ -1 +0,0 @@ -appwrite messaging list-providers diff --git a/docs/examples/messaging/list-subscriber-logs.md b/docs/examples/messaging/list-subscriber-logs.md deleted file mode 100644 index 4858c6c7..00000000 --- a/docs/examples/messaging/list-subscriber-logs.md +++ /dev/null @@ -1,2 +0,0 @@ -appwrite messaging list-subscriber-logs \ - --subscriber-id diff --git a/docs/examples/messaging/list-subscribers.md b/docs/examples/messaging/list-subscribers.md deleted file mode 100644 index c122c684..00000000 --- a/docs/examples/messaging/list-subscribers.md +++ /dev/null @@ -1,2 +0,0 @@ -appwrite messaging list-subscribers \ - --topic-id diff --git a/docs/examples/messaging/list-targets.md b/docs/examples/messaging/list-targets.md deleted file mode 100644 index e161e933..00000000 --- a/docs/examples/messaging/list-targets.md +++ /dev/null @@ -1,2 +0,0 @@ -appwrite messaging list-targets \ - --message-id diff --git a/docs/examples/messaging/list-topic-logs.md b/docs/examples/messaging/list-topic-logs.md deleted file mode 100644 index 121f2795..00000000 --- a/docs/examples/messaging/list-topic-logs.md +++ /dev/null @@ -1,2 +0,0 @@ -appwrite messaging list-topic-logs \ - --topic-id diff --git a/docs/examples/messaging/list-topics.md b/docs/examples/messaging/list-topics.md deleted file mode 100644 index 0337b3d1..00000000 --- a/docs/examples/messaging/list-topics.md +++ /dev/null @@ -1 +0,0 @@ -appwrite messaging list-topics diff --git a/docs/examples/messaging/update-apns-provider.md b/docs/examples/messaging/update-apns-provider.md deleted file mode 100644 index 7bd5db26..00000000 --- a/docs/examples/messaging/update-apns-provider.md +++ /dev/null @@ -1,2 +0,0 @@ -appwrite messaging update-apns-provider \ - --provider-id diff --git a/docs/examples/messaging/update-email.md b/docs/examples/messaging/update-email.md deleted file mode 100644 index 7e318ad4..00000000 --- a/docs/examples/messaging/update-email.md +++ /dev/null @@ -1,2 +0,0 @@ -appwrite messaging update-email \ - --message-id diff --git a/docs/examples/messaging/update-fcm-provider.md b/docs/examples/messaging/update-fcm-provider.md deleted file mode 100644 index 4d416806..00000000 --- a/docs/examples/messaging/update-fcm-provider.md +++ /dev/null @@ -1,2 +0,0 @@ -appwrite messaging update-fcm-provider \ - --provider-id diff --git a/docs/examples/messaging/update-mailgun-provider.md b/docs/examples/messaging/update-mailgun-provider.md deleted file mode 100644 index 9d07afea..00000000 --- a/docs/examples/messaging/update-mailgun-provider.md +++ /dev/null @@ -1,2 +0,0 @@ -appwrite messaging update-mailgun-provider \ - --provider-id diff --git a/docs/examples/messaging/update-msg-91-provider.md b/docs/examples/messaging/update-msg-91-provider.md deleted file mode 100644 index e4bc24b4..00000000 --- a/docs/examples/messaging/update-msg-91-provider.md +++ /dev/null @@ -1,2 +0,0 @@ -appwrite messaging update-msg-91-provider \ - --provider-id diff --git a/docs/examples/messaging/update-push.md b/docs/examples/messaging/update-push.md deleted file mode 100644 index c11d4629..00000000 --- a/docs/examples/messaging/update-push.md +++ /dev/null @@ -1,2 +0,0 @@ -appwrite messaging update-push \ - --message-id diff --git a/docs/examples/messaging/update-resend-provider.md b/docs/examples/messaging/update-resend-provider.md deleted file mode 100644 index df22cf07..00000000 --- a/docs/examples/messaging/update-resend-provider.md +++ /dev/null @@ -1,2 +0,0 @@ -appwrite messaging update-resend-provider \ - --provider-id diff --git a/docs/examples/messaging/update-sendgrid-provider.md b/docs/examples/messaging/update-sendgrid-provider.md deleted file mode 100644 index 77e9fcd2..00000000 --- a/docs/examples/messaging/update-sendgrid-provider.md +++ /dev/null @@ -1,2 +0,0 @@ -appwrite messaging update-sendgrid-provider \ - --provider-id diff --git a/docs/examples/messaging/update-sms.md b/docs/examples/messaging/update-sms.md deleted file mode 100644 index 888df629..00000000 --- a/docs/examples/messaging/update-sms.md +++ /dev/null @@ -1,2 +0,0 @@ -appwrite messaging update-sms \ - --message-id diff --git a/docs/examples/messaging/update-smtp-provider.md b/docs/examples/messaging/update-smtp-provider.md deleted file mode 100644 index 23bb8999..00000000 --- a/docs/examples/messaging/update-smtp-provider.md +++ /dev/null @@ -1,2 +0,0 @@ -appwrite messaging update-smtp-provider \ - --provider-id diff --git a/docs/examples/messaging/update-telesign-provider.md b/docs/examples/messaging/update-telesign-provider.md deleted file mode 100644 index 69eee1f5..00000000 --- a/docs/examples/messaging/update-telesign-provider.md +++ /dev/null @@ -1,2 +0,0 @@ -appwrite messaging update-telesign-provider \ - --provider-id diff --git a/docs/examples/messaging/update-textmagic-provider.md b/docs/examples/messaging/update-textmagic-provider.md deleted file mode 100644 index ff23b821..00000000 --- a/docs/examples/messaging/update-textmagic-provider.md +++ /dev/null @@ -1,2 +0,0 @@ -appwrite messaging update-textmagic-provider \ - --provider-id diff --git a/docs/examples/messaging/update-topic.md b/docs/examples/messaging/update-topic.md deleted file mode 100644 index ea7bc458..00000000 --- a/docs/examples/messaging/update-topic.md +++ /dev/null @@ -1,2 +0,0 @@ -appwrite messaging update-topic \ - --topic-id diff --git a/docs/examples/messaging/update-twilio-provider.md b/docs/examples/messaging/update-twilio-provider.md deleted file mode 100644 index 25f2910d..00000000 --- a/docs/examples/messaging/update-twilio-provider.md +++ /dev/null @@ -1,2 +0,0 @@ -appwrite messaging update-twilio-provider \ - --provider-id diff --git a/docs/examples/messaging/update-vonage-provider.md b/docs/examples/messaging/update-vonage-provider.md deleted file mode 100644 index 7b87a942..00000000 --- a/docs/examples/messaging/update-vonage-provider.md +++ /dev/null @@ -1,2 +0,0 @@ -appwrite messaging update-vonage-provider \ - --provider-id diff --git a/docs/examples/migrations/create-appwrite-migration.md b/docs/examples/migrations/create-appwrite-migration.md deleted file mode 100644 index 34fee2f3..00000000 --- a/docs/examples/migrations/create-appwrite-migration.md +++ /dev/null @@ -1,5 +0,0 @@ -appwrite migrations create-appwrite-migration \ - --resources one two three \ - --endpoint https://example.com \ - --project-id \ - --api-key diff --git a/docs/examples/migrations/create-csv-export.md b/docs/examples/migrations/create-csv-export.md deleted file mode 100644 index 61eceabc..00000000 --- a/docs/examples/migrations/create-csv-export.md +++ /dev/null @@ -1,3 +0,0 @@ -appwrite migrations create-csv-export \ - --resource-id \ - --filename diff --git a/docs/examples/migrations/create-csv-import.md b/docs/examples/migrations/create-csv-import.md deleted file mode 100644 index 196112bd..00000000 --- a/docs/examples/migrations/create-csv-import.md +++ /dev/null @@ -1,4 +0,0 @@ -appwrite migrations create-csv-import \ - --bucket-id \ - --file-id \ - --resource-id diff --git a/docs/examples/migrations/create-firebase-migration.md b/docs/examples/migrations/create-firebase-migration.md deleted file mode 100644 index 81337b4c..00000000 --- a/docs/examples/migrations/create-firebase-migration.md +++ /dev/null @@ -1,3 +0,0 @@ -appwrite migrations create-firebase-migration \ - --resources one two three \ - --service-account diff --git a/docs/examples/migrations/create-n-host-migration.md b/docs/examples/migrations/create-n-host-migration.md deleted file mode 100644 index 2bcba6ad..00000000 --- a/docs/examples/migrations/create-n-host-migration.md +++ /dev/null @@ -1,8 +0,0 @@ -appwrite migrations create-n-host-migration \ - --resources one two three \ - --subdomain \ - --region \ - --admin-secret \ - --database \ - --username \ - --password diff --git a/docs/examples/migrations/create-supabase-migration.md b/docs/examples/migrations/create-supabase-migration.md deleted file mode 100644 index a186b172..00000000 --- a/docs/examples/migrations/create-supabase-migration.md +++ /dev/null @@ -1,7 +0,0 @@ -appwrite migrations create-supabase-migration \ - --resources one two three \ - --endpoint https://example.com \ - --api-key \ - --database-host \ - --username \ - --password diff --git a/docs/examples/migrations/delete.md b/docs/examples/migrations/delete.md deleted file mode 100644 index b7ad0f07..00000000 --- a/docs/examples/migrations/delete.md +++ /dev/null @@ -1,2 +0,0 @@ -appwrite migrations delete \ - --migration-id diff --git a/docs/examples/migrations/get-appwrite-report.md b/docs/examples/migrations/get-appwrite-report.md deleted file mode 100644 index 3f54fed2..00000000 --- a/docs/examples/migrations/get-appwrite-report.md +++ /dev/null @@ -1,5 +0,0 @@ -appwrite migrations get-appwrite-report \ - --resources one two three \ - --endpoint https://example.com \ - --project-id \ - --key diff --git a/docs/examples/migrations/get-firebase-report.md b/docs/examples/migrations/get-firebase-report.md deleted file mode 100644 index 33e7e732..00000000 --- a/docs/examples/migrations/get-firebase-report.md +++ /dev/null @@ -1,3 +0,0 @@ -appwrite migrations get-firebase-report \ - --resources one two three \ - --service-account diff --git a/docs/examples/migrations/get-n-host-report.md b/docs/examples/migrations/get-n-host-report.md deleted file mode 100644 index 2d1ed043..00000000 --- a/docs/examples/migrations/get-n-host-report.md +++ /dev/null @@ -1,8 +0,0 @@ -appwrite migrations get-n-host-report \ - --resources one two three \ - --subdomain \ - --region \ - --admin-secret \ - --database \ - --username \ - --password diff --git a/docs/examples/migrations/get-supabase-report.md b/docs/examples/migrations/get-supabase-report.md deleted file mode 100644 index 789c66a5..00000000 --- a/docs/examples/migrations/get-supabase-report.md +++ /dev/null @@ -1,7 +0,0 @@ -appwrite migrations get-supabase-report \ - --resources one two three \ - --endpoint https://example.com \ - --api-key \ - --database-host \ - --username \ - --password diff --git a/docs/examples/migrations/get.md b/docs/examples/migrations/get.md deleted file mode 100644 index 46959a3e..00000000 --- a/docs/examples/migrations/get.md +++ /dev/null @@ -1,2 +0,0 @@ -appwrite migrations get \ - --migration-id diff --git a/docs/examples/migrations/list.md b/docs/examples/migrations/list.md deleted file mode 100644 index 659c9fd4..00000000 --- a/docs/examples/migrations/list.md +++ /dev/null @@ -1 +0,0 @@ -appwrite migrations list diff --git a/docs/examples/migrations/retry.md b/docs/examples/migrations/retry.md deleted file mode 100644 index d656dd99..00000000 --- a/docs/examples/migrations/retry.md +++ /dev/null @@ -1,2 +0,0 @@ -appwrite migrations retry \ - --migration-id diff --git a/docs/examples/project/create-variable.md b/docs/examples/project/create-variable.md deleted file mode 100644 index 113c0baf..00000000 --- a/docs/examples/project/create-variable.md +++ /dev/null @@ -1,3 +0,0 @@ -appwrite project create-variable \ - --key \ - --value diff --git a/docs/examples/project/delete-variable.md b/docs/examples/project/delete-variable.md deleted file mode 100644 index a4213dca..00000000 --- a/docs/examples/project/delete-variable.md +++ /dev/null @@ -1,2 +0,0 @@ -appwrite project delete-variable \ - --variable-id diff --git a/docs/examples/project/get-usage.md b/docs/examples/project/get-usage.md deleted file mode 100644 index 75cc4b99..00000000 --- a/docs/examples/project/get-usage.md +++ /dev/null @@ -1,3 +0,0 @@ -appwrite project get-usage \ - --start-date '' \ - --end-date '' diff --git a/docs/examples/project/get-variable.md b/docs/examples/project/get-variable.md deleted file mode 100644 index 28337585..00000000 --- a/docs/examples/project/get-variable.md +++ /dev/null @@ -1,2 +0,0 @@ -appwrite project get-variable \ - --variable-id diff --git a/docs/examples/project/list-variables.md b/docs/examples/project/list-variables.md deleted file mode 100644 index dc6251c4..00000000 --- a/docs/examples/project/list-variables.md +++ /dev/null @@ -1 +0,0 @@ -appwrite project list-variables diff --git a/docs/examples/project/update-variable.md b/docs/examples/project/update-variable.md deleted file mode 100644 index 5f12a12b..00000000 --- a/docs/examples/project/update-variable.md +++ /dev/null @@ -1,3 +0,0 @@ -appwrite project update-variable \ - --variable-id \ - --key diff --git a/docs/examples/projects/create-dev-key.md b/docs/examples/projects/create-dev-key.md deleted file mode 100644 index b90e0ca8..00000000 --- a/docs/examples/projects/create-dev-key.md +++ /dev/null @@ -1,4 +0,0 @@ -appwrite projects create-dev-key \ - --project-id \ - --name \ - --expire '' diff --git a/docs/examples/projects/create-jwt.md b/docs/examples/projects/create-jwt.md deleted file mode 100644 index df708a53..00000000 --- a/docs/examples/projects/create-jwt.md +++ /dev/null @@ -1,3 +0,0 @@ -appwrite projects create-jwt \ - --project-id \ - --scopes one two three diff --git a/docs/examples/projects/create-key.md b/docs/examples/projects/create-key.md deleted file mode 100644 index 0650ccd1..00000000 --- a/docs/examples/projects/create-key.md +++ /dev/null @@ -1,4 +0,0 @@ -appwrite projects create-key \ - --project-id \ - --name \ - --scopes one two three diff --git a/docs/examples/projects/create-platform.md b/docs/examples/projects/create-platform.md deleted file mode 100644 index 94f52341..00000000 --- a/docs/examples/projects/create-platform.md +++ /dev/null @@ -1,4 +0,0 @@ -appwrite projects create-platform \ - --project-id \ - --type web \ - --name diff --git a/docs/examples/projects/create-smtp-test.md b/docs/examples/projects/create-smtp-test.md deleted file mode 100644 index c83aebfb..00000000 --- a/docs/examples/projects/create-smtp-test.md +++ /dev/null @@ -1,6 +0,0 @@ -appwrite projects create-smtp-test \ - --project-id \ - --emails one two three \ - --sender-name \ - --sender-email email@example.com \ - --host '' diff --git a/docs/examples/projects/create-webhook.md b/docs/examples/projects/create-webhook.md deleted file mode 100644 index 0983d314..00000000 --- a/docs/examples/projects/create-webhook.md +++ /dev/null @@ -1,6 +0,0 @@ -appwrite projects create-webhook \ - --project-id \ - --name \ - --events one two three \ - --url '' \ - --security false diff --git a/docs/examples/projects/create.md b/docs/examples/projects/create.md deleted file mode 100644 index 5bdd1ffd..00000000 --- a/docs/examples/projects/create.md +++ /dev/null @@ -1,4 +0,0 @@ -appwrite projects create \ - --project-id '' \ - --name \ - --team-id diff --git a/docs/examples/projects/delete-dev-key.md b/docs/examples/projects/delete-dev-key.md deleted file mode 100644 index 3e911eab..00000000 --- a/docs/examples/projects/delete-dev-key.md +++ /dev/null @@ -1,3 +0,0 @@ -appwrite projects delete-dev-key \ - --project-id \ - --key-id diff --git a/docs/examples/projects/delete-email-template.md b/docs/examples/projects/delete-email-template.md deleted file mode 100644 index 81cf403c..00000000 --- a/docs/examples/projects/delete-email-template.md +++ /dev/null @@ -1,4 +0,0 @@ -appwrite projects delete-email-template \ - --project-id \ - --type verification \ - --locale af diff --git a/docs/examples/projects/delete-key.md b/docs/examples/projects/delete-key.md deleted file mode 100644 index eccb09b9..00000000 --- a/docs/examples/projects/delete-key.md +++ /dev/null @@ -1,3 +0,0 @@ -appwrite projects delete-key \ - --project-id \ - --key-id diff --git a/docs/examples/projects/delete-platform.md b/docs/examples/projects/delete-platform.md deleted file mode 100644 index 7f68e7d6..00000000 --- a/docs/examples/projects/delete-platform.md +++ /dev/null @@ -1,3 +0,0 @@ -appwrite projects delete-platform \ - --project-id \ - --platform-id diff --git a/docs/examples/projects/delete-sms-template.md b/docs/examples/projects/delete-sms-template.md deleted file mode 100644 index 666de541..00000000 --- a/docs/examples/projects/delete-sms-template.md +++ /dev/null @@ -1,4 +0,0 @@ -appwrite projects delete-sms-template \ - --project-id \ - --type verification \ - --locale af diff --git a/docs/examples/projects/delete-webhook.md b/docs/examples/projects/delete-webhook.md deleted file mode 100644 index 70e68655..00000000 --- a/docs/examples/projects/delete-webhook.md +++ /dev/null @@ -1,3 +0,0 @@ -appwrite projects delete-webhook \ - --project-id \ - --webhook-id diff --git a/docs/examples/projects/delete.md b/docs/examples/projects/delete.md deleted file mode 100644 index 31273855..00000000 --- a/docs/examples/projects/delete.md +++ /dev/null @@ -1,2 +0,0 @@ -appwrite projects delete \ - --project-id diff --git a/docs/examples/projects/get-dev-key.md b/docs/examples/projects/get-dev-key.md deleted file mode 100644 index 57b2c227..00000000 --- a/docs/examples/projects/get-dev-key.md +++ /dev/null @@ -1,3 +0,0 @@ -appwrite projects get-dev-key \ - --project-id \ - --key-id diff --git a/docs/examples/projects/get-email-template.md b/docs/examples/projects/get-email-template.md deleted file mode 100644 index ea6d5422..00000000 --- a/docs/examples/projects/get-email-template.md +++ /dev/null @@ -1,4 +0,0 @@ -appwrite projects get-email-template \ - --project-id \ - --type verification \ - --locale af diff --git a/docs/examples/projects/get-key.md b/docs/examples/projects/get-key.md deleted file mode 100644 index cfd50135..00000000 --- a/docs/examples/projects/get-key.md +++ /dev/null @@ -1,3 +0,0 @@ -appwrite projects get-key \ - --project-id \ - --key-id diff --git a/docs/examples/projects/get-platform.md b/docs/examples/projects/get-platform.md deleted file mode 100644 index 62077309..00000000 --- a/docs/examples/projects/get-platform.md +++ /dev/null @@ -1,3 +0,0 @@ -appwrite projects get-platform \ - --project-id \ - --platform-id diff --git a/docs/examples/projects/get-sms-template.md b/docs/examples/projects/get-sms-template.md deleted file mode 100644 index bbb755b0..00000000 --- a/docs/examples/projects/get-sms-template.md +++ /dev/null @@ -1,4 +0,0 @@ -appwrite projects get-sms-template \ - --project-id \ - --type verification \ - --locale af diff --git a/docs/examples/projects/get-webhook.md b/docs/examples/projects/get-webhook.md deleted file mode 100644 index d725bee7..00000000 --- a/docs/examples/projects/get-webhook.md +++ /dev/null @@ -1,3 +0,0 @@ -appwrite projects get-webhook \ - --project-id \ - --webhook-id diff --git a/docs/examples/projects/get.md b/docs/examples/projects/get.md deleted file mode 100644 index 0665b37e..00000000 --- a/docs/examples/projects/get.md +++ /dev/null @@ -1,2 +0,0 @@ -appwrite projects get \ - --project-id diff --git a/docs/examples/projects/list-dev-keys.md b/docs/examples/projects/list-dev-keys.md deleted file mode 100644 index f6f9a844..00000000 --- a/docs/examples/projects/list-dev-keys.md +++ /dev/null @@ -1,2 +0,0 @@ -appwrite projects list-dev-keys \ - --project-id diff --git a/docs/examples/projects/list-keys.md b/docs/examples/projects/list-keys.md deleted file mode 100644 index aa70a5c5..00000000 --- a/docs/examples/projects/list-keys.md +++ /dev/null @@ -1,2 +0,0 @@ -appwrite projects list-keys \ - --project-id diff --git a/docs/examples/projects/list-platforms.md b/docs/examples/projects/list-platforms.md deleted file mode 100644 index e7fbfb28..00000000 --- a/docs/examples/projects/list-platforms.md +++ /dev/null @@ -1,2 +0,0 @@ -appwrite projects list-platforms \ - --project-id diff --git a/docs/examples/projects/list-webhooks.md b/docs/examples/projects/list-webhooks.md deleted file mode 100644 index ab4012a1..00000000 --- a/docs/examples/projects/list-webhooks.md +++ /dev/null @@ -1,2 +0,0 @@ -appwrite projects list-webhooks \ - --project-id diff --git a/docs/examples/projects/list.md b/docs/examples/projects/list.md deleted file mode 100644 index f84f712f..00000000 --- a/docs/examples/projects/list.md +++ /dev/null @@ -1 +0,0 @@ -appwrite projects list diff --git a/docs/examples/projects/update-api-status-all.md b/docs/examples/projects/update-api-status-all.md deleted file mode 100644 index bbbec450..00000000 --- a/docs/examples/projects/update-api-status-all.md +++ /dev/null @@ -1,3 +0,0 @@ -appwrite projects update-api-status-all \ - --project-id \ - --status false diff --git a/docs/examples/projects/update-api-status.md b/docs/examples/projects/update-api-status.md deleted file mode 100644 index 7e269ba2..00000000 --- a/docs/examples/projects/update-api-status.md +++ /dev/null @@ -1,4 +0,0 @@ -appwrite projects update-api-status \ - --project-id \ - --api rest \ - --status false diff --git a/docs/examples/projects/update-auth-duration.md b/docs/examples/projects/update-auth-duration.md deleted file mode 100644 index 07e458e7..00000000 --- a/docs/examples/projects/update-auth-duration.md +++ /dev/null @@ -1,3 +0,0 @@ -appwrite projects update-auth-duration \ - --project-id \ - --duration 0 diff --git a/docs/examples/projects/update-auth-limit.md b/docs/examples/projects/update-auth-limit.md deleted file mode 100644 index 5e5d2add..00000000 --- a/docs/examples/projects/update-auth-limit.md +++ /dev/null @@ -1,3 +0,0 @@ -appwrite projects update-auth-limit \ - --project-id \ - --limit 0 diff --git a/docs/examples/projects/update-auth-password-dictionary.md b/docs/examples/projects/update-auth-password-dictionary.md deleted file mode 100644 index b4160e34..00000000 --- a/docs/examples/projects/update-auth-password-dictionary.md +++ /dev/null @@ -1,3 +0,0 @@ -appwrite projects update-auth-password-dictionary \ - --project-id \ - --enabled false diff --git a/docs/examples/projects/update-auth-password-history.md b/docs/examples/projects/update-auth-password-history.md deleted file mode 100644 index cffc9179..00000000 --- a/docs/examples/projects/update-auth-password-history.md +++ /dev/null @@ -1,3 +0,0 @@ -appwrite projects update-auth-password-history \ - --project-id \ - --limit 0 diff --git a/docs/examples/projects/update-auth-sessions-limit.md b/docs/examples/projects/update-auth-sessions-limit.md deleted file mode 100644 index fc205c03..00000000 --- a/docs/examples/projects/update-auth-sessions-limit.md +++ /dev/null @@ -1,3 +0,0 @@ -appwrite projects update-auth-sessions-limit \ - --project-id \ - --limit 1 diff --git a/docs/examples/projects/update-auth-status.md b/docs/examples/projects/update-auth-status.md deleted file mode 100644 index 5f38dc92..00000000 --- a/docs/examples/projects/update-auth-status.md +++ /dev/null @@ -1,4 +0,0 @@ -appwrite projects update-auth-status \ - --project-id \ - --method email-password \ - --status false diff --git a/docs/examples/projects/update-dev-key.md b/docs/examples/projects/update-dev-key.md deleted file mode 100644 index 1e54db37..00000000 --- a/docs/examples/projects/update-dev-key.md +++ /dev/null @@ -1,5 +0,0 @@ -appwrite projects update-dev-key \ - --project-id \ - --key-id \ - --name \ - --expire '' diff --git a/docs/examples/projects/update-email-template.md b/docs/examples/projects/update-email-template.md deleted file mode 100644 index f8e4919a..00000000 --- a/docs/examples/projects/update-email-template.md +++ /dev/null @@ -1,6 +0,0 @@ -appwrite projects update-email-template \ - --project-id \ - --type verification \ - --locale af \ - --subject \ - --message diff --git a/docs/examples/projects/update-key.md b/docs/examples/projects/update-key.md deleted file mode 100644 index 8ac173b7..00000000 --- a/docs/examples/projects/update-key.md +++ /dev/null @@ -1,5 +0,0 @@ -appwrite projects update-key \ - --project-id \ - --key-id \ - --name \ - --scopes one two three diff --git a/docs/examples/projects/update-memberships-privacy.md b/docs/examples/projects/update-memberships-privacy.md deleted file mode 100644 index 94582f48..00000000 --- a/docs/examples/projects/update-memberships-privacy.md +++ /dev/null @@ -1,5 +0,0 @@ -appwrite projects update-memberships-privacy \ - --project-id \ - --user-name false \ - --user-email false \ - --mfa false diff --git a/docs/examples/projects/update-mock-numbers.md b/docs/examples/projects/update-mock-numbers.md deleted file mode 100644 index 774887d6..00000000 --- a/docs/examples/projects/update-mock-numbers.md +++ /dev/null @@ -1,3 +0,0 @@ -appwrite projects update-mock-numbers \ - --project-id \ - --numbers one two three diff --git a/docs/examples/projects/update-o-auth-2.md b/docs/examples/projects/update-o-auth-2.md deleted file mode 100644 index 7f8364df..00000000 --- a/docs/examples/projects/update-o-auth-2.md +++ /dev/null @@ -1,3 +0,0 @@ -appwrite projects update-o-auth-2 \ - --project-id \ - --provider amazon diff --git a/docs/examples/projects/update-personal-data-check.md b/docs/examples/projects/update-personal-data-check.md deleted file mode 100644 index 7130decb..00000000 --- a/docs/examples/projects/update-personal-data-check.md +++ /dev/null @@ -1,3 +0,0 @@ -appwrite projects update-personal-data-check \ - --project-id \ - --enabled false diff --git a/docs/examples/projects/update-platform.md b/docs/examples/projects/update-platform.md deleted file mode 100644 index 170e8a6e..00000000 --- a/docs/examples/projects/update-platform.md +++ /dev/null @@ -1,4 +0,0 @@ -appwrite projects update-platform \ - --project-id \ - --platform-id \ - --name diff --git a/docs/examples/projects/update-service-status-all.md b/docs/examples/projects/update-service-status-all.md deleted file mode 100644 index 1d8fab29..00000000 --- a/docs/examples/projects/update-service-status-all.md +++ /dev/null @@ -1,3 +0,0 @@ -appwrite projects update-service-status-all \ - --project-id \ - --status false diff --git a/docs/examples/projects/update-service-status.md b/docs/examples/projects/update-service-status.md deleted file mode 100644 index ce589bcb..00000000 --- a/docs/examples/projects/update-service-status.md +++ /dev/null @@ -1,4 +0,0 @@ -appwrite projects update-service-status \ - --project-id \ - --service account \ - --status false diff --git a/docs/examples/projects/update-session-alerts.md b/docs/examples/projects/update-session-alerts.md deleted file mode 100644 index d25fa960..00000000 --- a/docs/examples/projects/update-session-alerts.md +++ /dev/null @@ -1,3 +0,0 @@ -appwrite projects update-session-alerts \ - --project-id \ - --alerts false diff --git a/docs/examples/projects/update-session-invalidation.md b/docs/examples/projects/update-session-invalidation.md deleted file mode 100644 index 17d635e5..00000000 --- a/docs/examples/projects/update-session-invalidation.md +++ /dev/null @@ -1,3 +0,0 @@ -appwrite projects update-session-invalidation \ - --project-id \ - --enabled false diff --git a/docs/examples/projects/update-sms-template.md b/docs/examples/projects/update-sms-template.md deleted file mode 100644 index 5e10477f..00000000 --- a/docs/examples/projects/update-sms-template.md +++ /dev/null @@ -1,5 +0,0 @@ -appwrite projects update-sms-template \ - --project-id \ - --type verification \ - --locale af \ - --message diff --git a/docs/examples/projects/update-smtp.md b/docs/examples/projects/update-smtp.md deleted file mode 100644 index f62059aa..00000000 --- a/docs/examples/projects/update-smtp.md +++ /dev/null @@ -1,3 +0,0 @@ -appwrite projects update-smtp \ - --project-id \ - --enabled false diff --git a/docs/examples/projects/update-team.md b/docs/examples/projects/update-team.md deleted file mode 100644 index 4cb0a981..00000000 --- a/docs/examples/projects/update-team.md +++ /dev/null @@ -1,3 +0,0 @@ -appwrite projects update-team \ - --project-id \ - --team-id diff --git a/docs/examples/projects/update-webhook-signature.md b/docs/examples/projects/update-webhook-signature.md deleted file mode 100644 index 708ff656..00000000 --- a/docs/examples/projects/update-webhook-signature.md +++ /dev/null @@ -1,3 +0,0 @@ -appwrite projects update-webhook-signature \ - --project-id \ - --webhook-id diff --git a/docs/examples/projects/update-webhook.md b/docs/examples/projects/update-webhook.md deleted file mode 100644 index f505e6e5..00000000 --- a/docs/examples/projects/update-webhook.md +++ /dev/null @@ -1,7 +0,0 @@ -appwrite projects update-webhook \ - --project-id \ - --webhook-id \ - --name \ - --events one two three \ - --url '' \ - --security false diff --git a/docs/examples/projects/update.md b/docs/examples/projects/update.md deleted file mode 100644 index e3c7ecaa..00000000 --- a/docs/examples/projects/update.md +++ /dev/null @@ -1,3 +0,0 @@ -appwrite projects update \ - --project-id \ - --name diff --git a/docs/examples/proxy/create-api-rule.md b/docs/examples/proxy/create-api-rule.md deleted file mode 100644 index 3bd7bb16..00000000 --- a/docs/examples/proxy/create-api-rule.md +++ /dev/null @@ -1,2 +0,0 @@ -appwrite proxy create-api-rule \ - --domain '' diff --git a/docs/examples/proxy/create-function-rule.md b/docs/examples/proxy/create-function-rule.md deleted file mode 100644 index 2312f3af..00000000 --- a/docs/examples/proxy/create-function-rule.md +++ /dev/null @@ -1,3 +0,0 @@ -appwrite proxy create-function-rule \ - --domain '' \ - --function-id diff --git a/docs/examples/proxy/create-redirect-rule.md b/docs/examples/proxy/create-redirect-rule.md deleted file mode 100644 index 763f9bc8..00000000 --- a/docs/examples/proxy/create-redirect-rule.md +++ /dev/null @@ -1,6 +0,0 @@ -appwrite proxy create-redirect-rule \ - --domain '' \ - --url https://example.com \ - --status-code 301 \ - --resource-id \ - --resource-type site diff --git a/docs/examples/proxy/create-site-rule.md b/docs/examples/proxy/create-site-rule.md deleted file mode 100644 index fa7859b3..00000000 --- a/docs/examples/proxy/create-site-rule.md +++ /dev/null @@ -1,3 +0,0 @@ -appwrite proxy create-site-rule \ - --domain '' \ - --site-id diff --git a/docs/examples/proxy/delete-rule.md b/docs/examples/proxy/delete-rule.md deleted file mode 100644 index c676893a..00000000 --- a/docs/examples/proxy/delete-rule.md +++ /dev/null @@ -1,2 +0,0 @@ -appwrite proxy delete-rule \ - --rule-id diff --git a/docs/examples/proxy/get-rule.md b/docs/examples/proxy/get-rule.md deleted file mode 100644 index 22ac1de7..00000000 --- a/docs/examples/proxy/get-rule.md +++ /dev/null @@ -1,2 +0,0 @@ -appwrite proxy get-rule \ - --rule-id diff --git a/docs/examples/proxy/list-rules.md b/docs/examples/proxy/list-rules.md deleted file mode 100644 index ab530846..00000000 --- a/docs/examples/proxy/list-rules.md +++ /dev/null @@ -1 +0,0 @@ -appwrite proxy list-rules diff --git a/docs/examples/proxy/update-rule-verification.md b/docs/examples/proxy/update-rule-verification.md deleted file mode 100644 index b381aa33..00000000 --- a/docs/examples/proxy/update-rule-verification.md +++ /dev/null @@ -1,2 +0,0 @@ -appwrite proxy update-rule-verification \ - --rule-id diff --git a/docs/examples/sites/create-deployment.md b/docs/examples/sites/create-deployment.md deleted file mode 100644 index dda04682..00000000 --- a/docs/examples/sites/create-deployment.md +++ /dev/null @@ -1,4 +0,0 @@ -appwrite sites create-deployment \ - --site-id \ - --code 'path/to/file.png' \ - --activate false diff --git a/docs/examples/sites/create-duplicate-deployment.md b/docs/examples/sites/create-duplicate-deployment.md deleted file mode 100644 index 30cf7d5a..00000000 --- a/docs/examples/sites/create-duplicate-deployment.md +++ /dev/null @@ -1,3 +0,0 @@ -appwrite sites create-duplicate-deployment \ - --site-id \ - --deployment-id diff --git a/docs/examples/sites/create-template-deployment.md b/docs/examples/sites/create-template-deployment.md deleted file mode 100644 index 52425340..00000000 --- a/docs/examples/sites/create-template-deployment.md +++ /dev/null @@ -1,7 +0,0 @@ -appwrite sites create-template-deployment \ - --site-id \ - --repository \ - --owner \ - --root-directory \ - --type branch \ - --reference diff --git a/docs/examples/sites/create-variable.md b/docs/examples/sites/create-variable.md deleted file mode 100644 index af1f4701..00000000 --- a/docs/examples/sites/create-variable.md +++ /dev/null @@ -1,4 +0,0 @@ -appwrite sites create-variable \ - --site-id \ - --key \ - --value diff --git a/docs/examples/sites/create-vcs-deployment.md b/docs/examples/sites/create-vcs-deployment.md deleted file mode 100644 index ab9c444e..00000000 --- a/docs/examples/sites/create-vcs-deployment.md +++ /dev/null @@ -1,4 +0,0 @@ -appwrite sites create-vcs-deployment \ - --site-id \ - --type branch \ - --reference diff --git a/docs/examples/sites/create.md b/docs/examples/sites/create.md deleted file mode 100644 index 6806a106..00000000 --- a/docs/examples/sites/create.md +++ /dev/null @@ -1,5 +0,0 @@ -appwrite sites create \ - --site-id \ - --name \ - --framework analog \ - --build-runtime node-14.5 diff --git a/docs/examples/sites/delete-deployment.md b/docs/examples/sites/delete-deployment.md deleted file mode 100644 index 7f7fe2f8..00000000 --- a/docs/examples/sites/delete-deployment.md +++ /dev/null @@ -1,3 +0,0 @@ -appwrite sites delete-deployment \ - --site-id \ - --deployment-id diff --git a/docs/examples/sites/delete-log.md b/docs/examples/sites/delete-log.md deleted file mode 100644 index 3ea35039..00000000 --- a/docs/examples/sites/delete-log.md +++ /dev/null @@ -1,3 +0,0 @@ -appwrite sites delete-log \ - --site-id \ - --log-id diff --git a/docs/examples/sites/delete-variable.md b/docs/examples/sites/delete-variable.md deleted file mode 100644 index a7a32b93..00000000 --- a/docs/examples/sites/delete-variable.md +++ /dev/null @@ -1,3 +0,0 @@ -appwrite sites delete-variable \ - --site-id \ - --variable-id diff --git a/docs/examples/sites/delete.md b/docs/examples/sites/delete.md deleted file mode 100644 index e03eca67..00000000 --- a/docs/examples/sites/delete.md +++ /dev/null @@ -1,2 +0,0 @@ -appwrite sites delete \ - --site-id diff --git a/docs/examples/sites/get-deployment-download.md b/docs/examples/sites/get-deployment-download.md deleted file mode 100644 index e7af5c31..00000000 --- a/docs/examples/sites/get-deployment-download.md +++ /dev/null @@ -1,3 +0,0 @@ -appwrite sites get-deployment-download \ - --site-id \ - --deployment-id diff --git a/docs/examples/sites/get-deployment.md b/docs/examples/sites/get-deployment.md deleted file mode 100644 index 28fee04d..00000000 --- a/docs/examples/sites/get-deployment.md +++ /dev/null @@ -1,3 +0,0 @@ -appwrite sites get-deployment \ - --site-id \ - --deployment-id diff --git a/docs/examples/sites/get-log.md b/docs/examples/sites/get-log.md deleted file mode 100644 index adba0267..00000000 --- a/docs/examples/sites/get-log.md +++ /dev/null @@ -1,3 +0,0 @@ -appwrite sites get-log \ - --site-id \ - --log-id diff --git a/docs/examples/sites/get-template.md b/docs/examples/sites/get-template.md deleted file mode 100644 index 64bfd67d..00000000 --- a/docs/examples/sites/get-template.md +++ /dev/null @@ -1,2 +0,0 @@ -appwrite sites get-template \ - --template-id diff --git a/docs/examples/sites/get-usage.md b/docs/examples/sites/get-usage.md deleted file mode 100644 index e1f88627..00000000 --- a/docs/examples/sites/get-usage.md +++ /dev/null @@ -1,2 +0,0 @@ -appwrite sites get-usage \ - --site-id diff --git a/docs/examples/sites/get-variable.md b/docs/examples/sites/get-variable.md deleted file mode 100644 index 2e96d632..00000000 --- a/docs/examples/sites/get-variable.md +++ /dev/null @@ -1,3 +0,0 @@ -appwrite sites get-variable \ - --site-id \ - --variable-id diff --git a/docs/examples/sites/get.md b/docs/examples/sites/get.md deleted file mode 100644 index db34c821..00000000 --- a/docs/examples/sites/get.md +++ /dev/null @@ -1,2 +0,0 @@ -appwrite sites get \ - --site-id diff --git a/docs/examples/sites/list-deployments.md b/docs/examples/sites/list-deployments.md deleted file mode 100644 index 0c5de057..00000000 --- a/docs/examples/sites/list-deployments.md +++ /dev/null @@ -1,2 +0,0 @@ -appwrite sites list-deployments \ - --site-id diff --git a/docs/examples/sites/list-frameworks.md b/docs/examples/sites/list-frameworks.md deleted file mode 100644 index 7a213b9a..00000000 --- a/docs/examples/sites/list-frameworks.md +++ /dev/null @@ -1 +0,0 @@ -appwrite sites list-frameworks diff --git a/docs/examples/sites/list-logs.md b/docs/examples/sites/list-logs.md deleted file mode 100644 index 565bcab9..00000000 --- a/docs/examples/sites/list-logs.md +++ /dev/null @@ -1,2 +0,0 @@ -appwrite sites list-logs \ - --site-id diff --git a/docs/examples/sites/list-specifications.md b/docs/examples/sites/list-specifications.md deleted file mode 100644 index e8f1a87e..00000000 --- a/docs/examples/sites/list-specifications.md +++ /dev/null @@ -1 +0,0 @@ -appwrite sites list-specifications diff --git a/docs/examples/sites/list-templates.md b/docs/examples/sites/list-templates.md deleted file mode 100644 index bde094fc..00000000 --- a/docs/examples/sites/list-templates.md +++ /dev/null @@ -1 +0,0 @@ -appwrite sites list-templates diff --git a/docs/examples/sites/list-usage.md b/docs/examples/sites/list-usage.md deleted file mode 100644 index b5b4171d..00000000 --- a/docs/examples/sites/list-usage.md +++ /dev/null @@ -1 +0,0 @@ -appwrite sites list-usage diff --git a/docs/examples/sites/list-variables.md b/docs/examples/sites/list-variables.md deleted file mode 100644 index 419fe76f..00000000 --- a/docs/examples/sites/list-variables.md +++ /dev/null @@ -1,2 +0,0 @@ -appwrite sites list-variables \ - --site-id diff --git a/docs/examples/sites/list.md b/docs/examples/sites/list.md deleted file mode 100644 index 9d3b883c..00000000 --- a/docs/examples/sites/list.md +++ /dev/null @@ -1 +0,0 @@ -appwrite sites list diff --git a/docs/examples/sites/update-deployment-status.md b/docs/examples/sites/update-deployment-status.md deleted file mode 100644 index 9220265d..00000000 --- a/docs/examples/sites/update-deployment-status.md +++ /dev/null @@ -1,3 +0,0 @@ -appwrite sites update-deployment-status \ - --site-id \ - --deployment-id diff --git a/docs/examples/sites/update-site-deployment.md b/docs/examples/sites/update-site-deployment.md deleted file mode 100644 index 9db9e11a..00000000 --- a/docs/examples/sites/update-site-deployment.md +++ /dev/null @@ -1,3 +0,0 @@ -appwrite sites update-site-deployment \ - --site-id \ - --deployment-id diff --git a/docs/examples/sites/update-variable.md b/docs/examples/sites/update-variable.md deleted file mode 100644 index e7df76a5..00000000 --- a/docs/examples/sites/update-variable.md +++ /dev/null @@ -1,4 +0,0 @@ -appwrite sites update-variable \ - --site-id \ - --variable-id \ - --key diff --git a/docs/examples/sites/update.md b/docs/examples/sites/update.md deleted file mode 100644 index 6fab0af5..00000000 --- a/docs/examples/sites/update.md +++ /dev/null @@ -1,4 +0,0 @@ -appwrite sites update \ - --site-id \ - --name \ - --framework analog diff --git a/docs/examples/storage/create-bucket.md b/docs/examples/storage/create-bucket.md deleted file mode 100644 index 2e26dc77..00000000 --- a/docs/examples/storage/create-bucket.md +++ /dev/null @@ -1,3 +0,0 @@ -appwrite storage create-bucket \ - --bucket-id \ - --name diff --git a/docs/examples/storage/create-file.md b/docs/examples/storage/create-file.md deleted file mode 100644 index 82b4d0a1..00000000 --- a/docs/examples/storage/create-file.md +++ /dev/null @@ -1,4 +0,0 @@ -appwrite storage create-file \ - --bucket-id \ - --file-id \ - --file 'path/to/file.png' diff --git a/docs/examples/storage/delete-bucket.md b/docs/examples/storage/delete-bucket.md deleted file mode 100644 index 33e520cc..00000000 --- a/docs/examples/storage/delete-bucket.md +++ /dev/null @@ -1,2 +0,0 @@ -appwrite storage delete-bucket \ - --bucket-id diff --git a/docs/examples/storage/delete-file.md b/docs/examples/storage/delete-file.md deleted file mode 100644 index a3006c2f..00000000 --- a/docs/examples/storage/delete-file.md +++ /dev/null @@ -1,3 +0,0 @@ -appwrite storage delete-file \ - --bucket-id \ - --file-id diff --git a/docs/examples/storage/get-bucket-usage.md b/docs/examples/storage/get-bucket-usage.md deleted file mode 100644 index 794b0ec8..00000000 --- a/docs/examples/storage/get-bucket-usage.md +++ /dev/null @@ -1,2 +0,0 @@ -appwrite storage get-bucket-usage \ - --bucket-id diff --git a/docs/examples/storage/get-bucket.md b/docs/examples/storage/get-bucket.md deleted file mode 100644 index 64042812..00000000 --- a/docs/examples/storage/get-bucket.md +++ /dev/null @@ -1,2 +0,0 @@ -appwrite storage get-bucket \ - --bucket-id diff --git a/docs/examples/storage/get-file-download.md b/docs/examples/storage/get-file-download.md deleted file mode 100644 index 12a74ea0..00000000 --- a/docs/examples/storage/get-file-download.md +++ /dev/null @@ -1,3 +0,0 @@ -appwrite storage get-file-download \ - --bucket-id \ - --file-id diff --git a/docs/examples/storage/get-file-preview.md b/docs/examples/storage/get-file-preview.md deleted file mode 100644 index 82f180ef..00000000 --- a/docs/examples/storage/get-file-preview.md +++ /dev/null @@ -1,3 +0,0 @@ -appwrite storage get-file-preview \ - --bucket-id \ - --file-id diff --git a/docs/examples/storage/get-file-view.md b/docs/examples/storage/get-file-view.md deleted file mode 100644 index 5ce6526f..00000000 --- a/docs/examples/storage/get-file-view.md +++ /dev/null @@ -1,3 +0,0 @@ -appwrite storage get-file-view \ - --bucket-id \ - --file-id diff --git a/docs/examples/storage/get-file.md b/docs/examples/storage/get-file.md deleted file mode 100644 index 8c139e60..00000000 --- a/docs/examples/storage/get-file.md +++ /dev/null @@ -1,3 +0,0 @@ -appwrite storage get-file \ - --bucket-id \ - --file-id diff --git a/docs/examples/storage/get-usage.md b/docs/examples/storage/get-usage.md deleted file mode 100644 index 1d69ffd8..00000000 --- a/docs/examples/storage/get-usage.md +++ /dev/null @@ -1 +0,0 @@ -appwrite storage get-usage diff --git a/docs/examples/storage/list-buckets.md b/docs/examples/storage/list-buckets.md deleted file mode 100644 index 1bffd0eb..00000000 --- a/docs/examples/storage/list-buckets.md +++ /dev/null @@ -1 +0,0 @@ -appwrite storage list-buckets diff --git a/docs/examples/storage/list-files.md b/docs/examples/storage/list-files.md deleted file mode 100644 index 29dc20d3..00000000 --- a/docs/examples/storage/list-files.md +++ /dev/null @@ -1,2 +0,0 @@ -appwrite storage list-files \ - --bucket-id diff --git a/docs/examples/storage/update-bucket.md b/docs/examples/storage/update-bucket.md deleted file mode 100644 index 12282f3b..00000000 --- a/docs/examples/storage/update-bucket.md +++ /dev/null @@ -1,3 +0,0 @@ -appwrite storage update-bucket \ - --bucket-id \ - --name diff --git a/docs/examples/storage/update-file.md b/docs/examples/storage/update-file.md deleted file mode 100644 index 86a3f3d1..00000000 --- a/docs/examples/storage/update-file.md +++ /dev/null @@ -1,3 +0,0 @@ -appwrite storage update-file \ - --bucket-id \ - --file-id diff --git a/docs/examples/tablesdb/create-boolean-column.md b/docs/examples/tablesdb/create-boolean-column.md deleted file mode 100644 index b191215d..00000000 --- a/docs/examples/tablesdb/create-boolean-column.md +++ /dev/null @@ -1,5 +0,0 @@ -appwrite tables-db create-boolean-column \ - --database-id \ - --table-id \ - --key '' \ - --required false diff --git a/docs/examples/tablesdb/create-datetime-column.md b/docs/examples/tablesdb/create-datetime-column.md deleted file mode 100644 index 7ccaf9e4..00000000 --- a/docs/examples/tablesdb/create-datetime-column.md +++ /dev/null @@ -1,5 +0,0 @@ -appwrite tables-db create-datetime-column \ - --database-id \ - --table-id \ - --key '' \ - --required false diff --git a/docs/examples/tablesdb/create-email-column.md b/docs/examples/tablesdb/create-email-column.md deleted file mode 100644 index 54f32b99..00000000 --- a/docs/examples/tablesdb/create-email-column.md +++ /dev/null @@ -1,5 +0,0 @@ -appwrite tables-db create-email-column \ - --database-id \ - --table-id \ - --key '' \ - --required false diff --git a/docs/examples/tablesdb/create-enum-column.md b/docs/examples/tablesdb/create-enum-column.md deleted file mode 100644 index 4f3e9cea..00000000 --- a/docs/examples/tablesdb/create-enum-column.md +++ /dev/null @@ -1,6 +0,0 @@ -appwrite tables-db create-enum-column \ - --database-id \ - --table-id \ - --key '' \ - --elements one two three \ - --required false diff --git a/docs/examples/tablesdb/create-float-column.md b/docs/examples/tablesdb/create-float-column.md deleted file mode 100644 index a365cefc..00000000 --- a/docs/examples/tablesdb/create-float-column.md +++ /dev/null @@ -1,5 +0,0 @@ -appwrite tables-db create-float-column \ - --database-id \ - --table-id \ - --key '' \ - --required false diff --git a/docs/examples/tablesdb/create-index.md b/docs/examples/tablesdb/create-index.md deleted file mode 100644 index 7100907f..00000000 --- a/docs/examples/tablesdb/create-index.md +++ /dev/null @@ -1,6 +0,0 @@ -appwrite tables-db create-index \ - --database-id \ - --table-id \ - --key '' \ - --type key \ - --columns one two three diff --git a/docs/examples/tablesdb/create-integer-column.md b/docs/examples/tablesdb/create-integer-column.md deleted file mode 100644 index 2dc799b2..00000000 --- a/docs/examples/tablesdb/create-integer-column.md +++ /dev/null @@ -1,5 +0,0 @@ -appwrite tables-db create-integer-column \ - --database-id \ - --table-id \ - --key '' \ - --required false diff --git a/docs/examples/tablesdb/create-ip-column.md b/docs/examples/tablesdb/create-ip-column.md deleted file mode 100644 index 2b460133..00000000 --- a/docs/examples/tablesdb/create-ip-column.md +++ /dev/null @@ -1,5 +0,0 @@ -appwrite tables-db create-ip-column \ - --database-id \ - --table-id \ - --key '' \ - --required false diff --git a/docs/examples/tablesdb/create-line-column.md b/docs/examples/tablesdb/create-line-column.md deleted file mode 100644 index cd6db93e..00000000 --- a/docs/examples/tablesdb/create-line-column.md +++ /dev/null @@ -1,5 +0,0 @@ -appwrite tables-db create-line-column \ - --database-id \ - --table-id \ - --key '' \ - --required false diff --git a/docs/examples/tablesdb/create-operations.md b/docs/examples/tablesdb/create-operations.md deleted file mode 100644 index dbea6186..00000000 --- a/docs/examples/tablesdb/create-operations.md +++ /dev/null @@ -1,2 +0,0 @@ -appwrite tables-db create-operations \ - --transaction-id diff --git a/docs/examples/tablesdb/create-point-column.md b/docs/examples/tablesdb/create-point-column.md deleted file mode 100644 index 0e7d2320..00000000 --- a/docs/examples/tablesdb/create-point-column.md +++ /dev/null @@ -1,5 +0,0 @@ -appwrite tables-db create-point-column \ - --database-id \ - --table-id \ - --key '' \ - --required false diff --git a/docs/examples/tablesdb/create-polygon-column.md b/docs/examples/tablesdb/create-polygon-column.md deleted file mode 100644 index 060323b1..00000000 --- a/docs/examples/tablesdb/create-polygon-column.md +++ /dev/null @@ -1,5 +0,0 @@ -appwrite tables-db create-polygon-column \ - --database-id \ - --table-id \ - --key '' \ - --required false diff --git a/docs/examples/tablesdb/create-relationship-column.md b/docs/examples/tablesdb/create-relationship-column.md deleted file mode 100644 index d7d58b6e..00000000 --- a/docs/examples/tablesdb/create-relationship-column.md +++ /dev/null @@ -1,5 +0,0 @@ -appwrite tables-db create-relationship-column \ - --database-id \ - --table-id \ - --related-table-id \ - --type oneToOne diff --git a/docs/examples/tablesdb/create-row.md b/docs/examples/tablesdb/create-row.md deleted file mode 100644 index d15c5ec0..00000000 --- a/docs/examples/tablesdb/create-row.md +++ /dev/null @@ -1,5 +0,0 @@ -appwrite tables-db create-row \ - --database-id \ - --table-id \ - --row-id \ - --data '{ "key": "value" }' diff --git a/docs/examples/tablesdb/create-rows.md b/docs/examples/tablesdb/create-rows.md deleted file mode 100644 index 39eb3496..00000000 --- a/docs/examples/tablesdb/create-rows.md +++ /dev/null @@ -1,4 +0,0 @@ -appwrite tables-db create-rows \ - --database-id \ - --table-id \ - --rows one two three diff --git a/docs/examples/tablesdb/create-string-column.md b/docs/examples/tablesdb/create-string-column.md deleted file mode 100644 index a394ff59..00000000 --- a/docs/examples/tablesdb/create-string-column.md +++ /dev/null @@ -1,6 +0,0 @@ -appwrite tables-db create-string-column \ - --database-id \ - --table-id \ - --key '' \ - --size 1 \ - --required false diff --git a/docs/examples/tablesdb/create-table.md b/docs/examples/tablesdb/create-table.md deleted file mode 100644 index 1c5a22d7..00000000 --- a/docs/examples/tablesdb/create-table.md +++ /dev/null @@ -1,4 +0,0 @@ -appwrite tables-db create-table \ - --database-id \ - --table-id \ - --name diff --git a/docs/examples/tablesdb/create-transaction.md b/docs/examples/tablesdb/create-transaction.md deleted file mode 100644 index c6487fd7..00000000 --- a/docs/examples/tablesdb/create-transaction.md +++ /dev/null @@ -1 +0,0 @@ -appwrite tables-db create-transaction diff --git a/docs/examples/tablesdb/create-url-column.md b/docs/examples/tablesdb/create-url-column.md deleted file mode 100644 index d9b9f2b3..00000000 --- a/docs/examples/tablesdb/create-url-column.md +++ /dev/null @@ -1,5 +0,0 @@ -appwrite tables-db create-url-column \ - --database-id \ - --table-id \ - --key '' \ - --required false diff --git a/docs/examples/tablesdb/create.md b/docs/examples/tablesdb/create.md deleted file mode 100644 index d10c5d66..00000000 --- a/docs/examples/tablesdb/create.md +++ /dev/null @@ -1,3 +0,0 @@ -appwrite tables-db create \ - --database-id \ - --name diff --git a/docs/examples/tablesdb/decrement-row-column.md b/docs/examples/tablesdb/decrement-row-column.md deleted file mode 100644 index 79e0a51d..00000000 --- a/docs/examples/tablesdb/decrement-row-column.md +++ /dev/null @@ -1,5 +0,0 @@ -appwrite tables-db decrement-row-column \ - --database-id \ - --table-id \ - --row-id \ - --column '' diff --git a/docs/examples/tablesdb/delete-column.md b/docs/examples/tablesdb/delete-column.md deleted file mode 100644 index 46892905..00000000 --- a/docs/examples/tablesdb/delete-column.md +++ /dev/null @@ -1,4 +0,0 @@ -appwrite tables-db delete-column \ - --database-id \ - --table-id \ - --key '' diff --git a/docs/examples/tablesdb/delete-index.md b/docs/examples/tablesdb/delete-index.md deleted file mode 100644 index 0729f879..00000000 --- a/docs/examples/tablesdb/delete-index.md +++ /dev/null @@ -1,4 +0,0 @@ -appwrite tables-db delete-index \ - --database-id \ - --table-id \ - --key '' diff --git a/docs/examples/tablesdb/delete-row.md b/docs/examples/tablesdb/delete-row.md deleted file mode 100644 index 03b3562f..00000000 --- a/docs/examples/tablesdb/delete-row.md +++ /dev/null @@ -1,4 +0,0 @@ -appwrite tables-db delete-row \ - --database-id \ - --table-id \ - --row-id diff --git a/docs/examples/tablesdb/delete-rows.md b/docs/examples/tablesdb/delete-rows.md deleted file mode 100644 index 92cd143a..00000000 --- a/docs/examples/tablesdb/delete-rows.md +++ /dev/null @@ -1,3 +0,0 @@ -appwrite tables-db delete-rows \ - --database-id \ - --table-id diff --git a/docs/examples/tablesdb/delete-table.md b/docs/examples/tablesdb/delete-table.md deleted file mode 100644 index 6ec9df45..00000000 --- a/docs/examples/tablesdb/delete-table.md +++ /dev/null @@ -1,3 +0,0 @@ -appwrite tables-db delete-table \ - --database-id \ - --table-id diff --git a/docs/examples/tablesdb/delete-transaction.md b/docs/examples/tablesdb/delete-transaction.md deleted file mode 100644 index 59e40d2f..00000000 --- a/docs/examples/tablesdb/delete-transaction.md +++ /dev/null @@ -1,2 +0,0 @@ -appwrite tables-db delete-transaction \ - --transaction-id diff --git a/docs/examples/tablesdb/delete.md b/docs/examples/tablesdb/delete.md deleted file mode 100644 index 52bf4cdd..00000000 --- a/docs/examples/tablesdb/delete.md +++ /dev/null @@ -1,2 +0,0 @@ -appwrite tables-db delete \ - --database-id diff --git a/docs/examples/tablesdb/get-column.md b/docs/examples/tablesdb/get-column.md deleted file mode 100644 index d209c45b..00000000 --- a/docs/examples/tablesdb/get-column.md +++ /dev/null @@ -1,4 +0,0 @@ -appwrite tables-db get-column \ - --database-id \ - --table-id \ - --key '' diff --git a/docs/examples/tablesdb/get-index.md b/docs/examples/tablesdb/get-index.md deleted file mode 100644 index 2035e78b..00000000 --- a/docs/examples/tablesdb/get-index.md +++ /dev/null @@ -1,4 +0,0 @@ -appwrite tables-db get-index \ - --database-id \ - --table-id \ - --key '' diff --git a/docs/examples/tablesdb/get-row.md b/docs/examples/tablesdb/get-row.md deleted file mode 100644 index c8d06ea0..00000000 --- a/docs/examples/tablesdb/get-row.md +++ /dev/null @@ -1,4 +0,0 @@ -appwrite tables-db get-row \ - --database-id \ - --table-id \ - --row-id diff --git a/docs/examples/tablesdb/get-table-usage.md b/docs/examples/tablesdb/get-table-usage.md deleted file mode 100644 index 0e7782f5..00000000 --- a/docs/examples/tablesdb/get-table-usage.md +++ /dev/null @@ -1,3 +0,0 @@ -appwrite tables-db get-table-usage \ - --database-id \ - --table-id diff --git a/docs/examples/tablesdb/get-table.md b/docs/examples/tablesdb/get-table.md deleted file mode 100644 index 9e5e0381..00000000 --- a/docs/examples/tablesdb/get-table.md +++ /dev/null @@ -1,3 +0,0 @@ -appwrite tables-db get-table \ - --database-id \ - --table-id diff --git a/docs/examples/tablesdb/get-transaction.md b/docs/examples/tablesdb/get-transaction.md deleted file mode 100644 index 29ea9d75..00000000 --- a/docs/examples/tablesdb/get-transaction.md +++ /dev/null @@ -1,2 +0,0 @@ -appwrite tables-db get-transaction \ - --transaction-id diff --git a/docs/examples/tablesdb/get-usage.md b/docs/examples/tablesdb/get-usage.md deleted file mode 100644 index ff421ce3..00000000 --- a/docs/examples/tablesdb/get-usage.md +++ /dev/null @@ -1,2 +0,0 @@ -appwrite tables-db get-usage \ - --database-id diff --git a/docs/examples/tablesdb/get.md b/docs/examples/tablesdb/get.md deleted file mode 100644 index 1b125ecc..00000000 --- a/docs/examples/tablesdb/get.md +++ /dev/null @@ -1,2 +0,0 @@ -appwrite tables-db get \ - --database-id diff --git a/docs/examples/tablesdb/increment-row-column.md b/docs/examples/tablesdb/increment-row-column.md deleted file mode 100644 index a15ab691..00000000 --- a/docs/examples/tablesdb/increment-row-column.md +++ /dev/null @@ -1,5 +0,0 @@ -appwrite tables-db increment-row-column \ - --database-id \ - --table-id \ - --row-id \ - --column '' diff --git a/docs/examples/tablesdb/list-columns.md b/docs/examples/tablesdb/list-columns.md deleted file mode 100644 index 4c233d51..00000000 --- a/docs/examples/tablesdb/list-columns.md +++ /dev/null @@ -1,3 +0,0 @@ -appwrite tables-db list-columns \ - --database-id \ - --table-id diff --git a/docs/examples/tablesdb/list-indexes.md b/docs/examples/tablesdb/list-indexes.md deleted file mode 100644 index 4139175a..00000000 --- a/docs/examples/tablesdb/list-indexes.md +++ /dev/null @@ -1,3 +0,0 @@ -appwrite tables-db list-indexes \ - --database-id \ - --table-id diff --git a/docs/examples/tablesdb/list-row-logs.md b/docs/examples/tablesdb/list-row-logs.md deleted file mode 100644 index dfa2f984..00000000 --- a/docs/examples/tablesdb/list-row-logs.md +++ /dev/null @@ -1,4 +0,0 @@ -appwrite tables-db list-row-logs \ - --database-id \ - --table-id \ - --row-id diff --git a/docs/examples/tablesdb/list-rows.md b/docs/examples/tablesdb/list-rows.md deleted file mode 100644 index 904350ef..00000000 --- a/docs/examples/tablesdb/list-rows.md +++ /dev/null @@ -1,3 +0,0 @@ -appwrite tables-db list-rows \ - --database-id \ - --table-id diff --git a/docs/examples/tablesdb/list-table-logs.md b/docs/examples/tablesdb/list-table-logs.md deleted file mode 100644 index a803bf40..00000000 --- a/docs/examples/tablesdb/list-table-logs.md +++ /dev/null @@ -1,3 +0,0 @@ -appwrite tables-db list-table-logs \ - --database-id \ - --table-id diff --git a/docs/examples/tablesdb/list-tables.md b/docs/examples/tablesdb/list-tables.md deleted file mode 100644 index f7e79308..00000000 --- a/docs/examples/tablesdb/list-tables.md +++ /dev/null @@ -1,2 +0,0 @@ -appwrite tables-db list-tables \ - --database-id diff --git a/docs/examples/tablesdb/list-transactions.md b/docs/examples/tablesdb/list-transactions.md deleted file mode 100644 index 4dfbc2e5..00000000 --- a/docs/examples/tablesdb/list-transactions.md +++ /dev/null @@ -1 +0,0 @@ -appwrite tables-db list-transactions diff --git a/docs/examples/tablesdb/list-usage.md b/docs/examples/tablesdb/list-usage.md deleted file mode 100644 index 9e6b9802..00000000 --- a/docs/examples/tablesdb/list-usage.md +++ /dev/null @@ -1 +0,0 @@ -appwrite tables-db list-usage diff --git a/docs/examples/tablesdb/list.md b/docs/examples/tablesdb/list.md deleted file mode 100644 index 22d7e017..00000000 --- a/docs/examples/tablesdb/list.md +++ /dev/null @@ -1 +0,0 @@ -appwrite tables-db list diff --git a/docs/examples/tablesdb/update-boolean-column.md b/docs/examples/tablesdb/update-boolean-column.md deleted file mode 100644 index 318ddac3..00000000 --- a/docs/examples/tablesdb/update-boolean-column.md +++ /dev/null @@ -1,6 +0,0 @@ -appwrite tables-db update-boolean-column \ - --database-id \ - --table-id \ - --key '' \ - --required false \ - --default false diff --git a/docs/examples/tablesdb/update-datetime-column.md b/docs/examples/tablesdb/update-datetime-column.md deleted file mode 100644 index b40a8253..00000000 --- a/docs/examples/tablesdb/update-datetime-column.md +++ /dev/null @@ -1,6 +0,0 @@ -appwrite tables-db update-datetime-column \ - --database-id \ - --table-id \ - --key '' \ - --required false \ - --default '' diff --git a/docs/examples/tablesdb/update-email-column.md b/docs/examples/tablesdb/update-email-column.md deleted file mode 100644 index cd8104b7..00000000 --- a/docs/examples/tablesdb/update-email-column.md +++ /dev/null @@ -1,6 +0,0 @@ -appwrite tables-db update-email-column \ - --database-id \ - --table-id \ - --key '' \ - --required false \ - --default email@example.com diff --git a/docs/examples/tablesdb/update-enum-column.md b/docs/examples/tablesdb/update-enum-column.md deleted file mode 100644 index 66bc3e28..00000000 --- a/docs/examples/tablesdb/update-enum-column.md +++ /dev/null @@ -1,7 +0,0 @@ -appwrite tables-db update-enum-column \ - --database-id \ - --table-id \ - --key '' \ - --elements one two three \ - --required false \ - --default diff --git a/docs/examples/tablesdb/update-float-column.md b/docs/examples/tablesdb/update-float-column.md deleted file mode 100644 index a3c6e6b2..00000000 --- a/docs/examples/tablesdb/update-float-column.md +++ /dev/null @@ -1,6 +0,0 @@ -appwrite tables-db update-float-column \ - --database-id \ - --table-id \ - --key '' \ - --required false \ - --default null diff --git a/docs/examples/tablesdb/update-integer-column.md b/docs/examples/tablesdb/update-integer-column.md deleted file mode 100644 index f651c5c1..00000000 --- a/docs/examples/tablesdb/update-integer-column.md +++ /dev/null @@ -1,6 +0,0 @@ -appwrite tables-db update-integer-column \ - --database-id \ - --table-id \ - --key '' \ - --required false \ - --default null diff --git a/docs/examples/tablesdb/update-ip-column.md b/docs/examples/tablesdb/update-ip-column.md deleted file mode 100644 index 9a1425c5..00000000 --- a/docs/examples/tablesdb/update-ip-column.md +++ /dev/null @@ -1,6 +0,0 @@ -appwrite tables-db update-ip-column \ - --database-id \ - --table-id \ - --key '' \ - --required false \ - --default '' diff --git a/docs/examples/tablesdb/update-line-column.md b/docs/examples/tablesdb/update-line-column.md deleted file mode 100644 index 203ebd64..00000000 --- a/docs/examples/tablesdb/update-line-column.md +++ /dev/null @@ -1,5 +0,0 @@ -appwrite tables-db update-line-column \ - --database-id \ - --table-id \ - --key '' \ - --required false diff --git a/docs/examples/tablesdb/update-point-column.md b/docs/examples/tablesdb/update-point-column.md deleted file mode 100644 index 676a37ef..00000000 --- a/docs/examples/tablesdb/update-point-column.md +++ /dev/null @@ -1,5 +0,0 @@ -appwrite tables-db update-point-column \ - --database-id \ - --table-id \ - --key '' \ - --required false diff --git a/docs/examples/tablesdb/update-polygon-column.md b/docs/examples/tablesdb/update-polygon-column.md deleted file mode 100644 index 24e1f01f..00000000 --- a/docs/examples/tablesdb/update-polygon-column.md +++ /dev/null @@ -1,5 +0,0 @@ -appwrite tables-db update-polygon-column \ - --database-id \ - --table-id \ - --key '' \ - --required false diff --git a/docs/examples/tablesdb/update-relationship-column.md b/docs/examples/tablesdb/update-relationship-column.md deleted file mode 100644 index fb358a31..00000000 --- a/docs/examples/tablesdb/update-relationship-column.md +++ /dev/null @@ -1,4 +0,0 @@ -appwrite tables-db update-relationship-column \ - --database-id \ - --table-id \ - --key '' diff --git a/docs/examples/tablesdb/update-row.md b/docs/examples/tablesdb/update-row.md deleted file mode 100644 index 31d88664..00000000 --- a/docs/examples/tablesdb/update-row.md +++ /dev/null @@ -1,4 +0,0 @@ -appwrite tables-db update-row \ - --database-id \ - --table-id \ - --row-id diff --git a/docs/examples/tablesdb/update-rows.md b/docs/examples/tablesdb/update-rows.md deleted file mode 100644 index eca741f1..00000000 --- a/docs/examples/tablesdb/update-rows.md +++ /dev/null @@ -1,3 +0,0 @@ -appwrite tables-db update-rows \ - --database-id \ - --table-id diff --git a/docs/examples/tablesdb/update-string-column.md b/docs/examples/tablesdb/update-string-column.md deleted file mode 100644 index fadb277b..00000000 --- a/docs/examples/tablesdb/update-string-column.md +++ /dev/null @@ -1,6 +0,0 @@ -appwrite tables-db update-string-column \ - --database-id \ - --table-id \ - --key '' \ - --required false \ - --default diff --git a/docs/examples/tablesdb/update-table.md b/docs/examples/tablesdb/update-table.md deleted file mode 100644 index 92884dfb..00000000 --- a/docs/examples/tablesdb/update-table.md +++ /dev/null @@ -1,4 +0,0 @@ -appwrite tables-db update-table \ - --database-id \ - --table-id \ - --name diff --git a/docs/examples/tablesdb/update-transaction.md b/docs/examples/tablesdb/update-transaction.md deleted file mode 100644 index 6fa6d951..00000000 --- a/docs/examples/tablesdb/update-transaction.md +++ /dev/null @@ -1,2 +0,0 @@ -appwrite tables-db update-transaction \ - --transaction-id diff --git a/docs/examples/tablesdb/update-url-column.md b/docs/examples/tablesdb/update-url-column.md deleted file mode 100644 index e1bbdbb3..00000000 --- a/docs/examples/tablesdb/update-url-column.md +++ /dev/null @@ -1,6 +0,0 @@ -appwrite tables-db update-url-column \ - --database-id \ - --table-id \ - --key '' \ - --required false \ - --default https://example.com diff --git a/docs/examples/tablesdb/update.md b/docs/examples/tablesdb/update.md deleted file mode 100644 index b8dbec19..00000000 --- a/docs/examples/tablesdb/update.md +++ /dev/null @@ -1,3 +0,0 @@ -appwrite tables-db update \ - --database-id \ - --name diff --git a/docs/examples/tablesdb/upsert-row.md b/docs/examples/tablesdb/upsert-row.md deleted file mode 100644 index 32c9fd62..00000000 --- a/docs/examples/tablesdb/upsert-row.md +++ /dev/null @@ -1,4 +0,0 @@ -appwrite tables-db upsert-row \ - --database-id \ - --table-id \ - --row-id diff --git a/docs/examples/tablesdb/upsert-rows.md b/docs/examples/tablesdb/upsert-rows.md deleted file mode 100644 index 85e0bc0e..00000000 --- a/docs/examples/tablesdb/upsert-rows.md +++ /dev/null @@ -1,4 +0,0 @@ -appwrite tables-db upsert-rows \ - --database-id \ - --table-id \ - --rows one two three diff --git a/docs/examples/teams/create-membership.md b/docs/examples/teams/create-membership.md deleted file mode 100644 index 6e9d50a1..00000000 --- a/docs/examples/teams/create-membership.md +++ /dev/null @@ -1,3 +0,0 @@ -appwrite teams create-membership \ - --team-id \ - --roles one two three diff --git a/docs/examples/teams/create.md b/docs/examples/teams/create.md deleted file mode 100644 index fb8bc3ad..00000000 --- a/docs/examples/teams/create.md +++ /dev/null @@ -1,3 +0,0 @@ -appwrite teams create \ - --team-id \ - --name diff --git a/docs/examples/teams/delete-membership.md b/docs/examples/teams/delete-membership.md deleted file mode 100644 index c9f1596a..00000000 --- a/docs/examples/teams/delete-membership.md +++ /dev/null @@ -1,3 +0,0 @@ -appwrite teams delete-membership \ - --team-id \ - --membership-id diff --git a/docs/examples/teams/delete.md b/docs/examples/teams/delete.md deleted file mode 100644 index 04d5e4ea..00000000 --- a/docs/examples/teams/delete.md +++ /dev/null @@ -1,2 +0,0 @@ -appwrite teams delete \ - --team-id diff --git a/docs/examples/teams/get-membership.md b/docs/examples/teams/get-membership.md deleted file mode 100644 index a832b238..00000000 --- a/docs/examples/teams/get-membership.md +++ /dev/null @@ -1,3 +0,0 @@ -appwrite teams get-membership \ - --team-id \ - --membership-id diff --git a/docs/examples/teams/get-prefs.md b/docs/examples/teams/get-prefs.md deleted file mode 100644 index a2d456a7..00000000 --- a/docs/examples/teams/get-prefs.md +++ /dev/null @@ -1,2 +0,0 @@ -appwrite teams get-prefs \ - --team-id diff --git a/docs/examples/teams/get.md b/docs/examples/teams/get.md deleted file mode 100644 index 94f80a9a..00000000 --- a/docs/examples/teams/get.md +++ /dev/null @@ -1,2 +0,0 @@ -appwrite teams get \ - --team-id diff --git a/docs/examples/teams/list-logs.md b/docs/examples/teams/list-logs.md deleted file mode 100644 index cbdf32ad..00000000 --- a/docs/examples/teams/list-logs.md +++ /dev/null @@ -1,2 +0,0 @@ -appwrite teams list-logs \ - --team-id diff --git a/docs/examples/teams/list-memberships.md b/docs/examples/teams/list-memberships.md deleted file mode 100644 index 6a1cbcae..00000000 --- a/docs/examples/teams/list-memberships.md +++ /dev/null @@ -1,2 +0,0 @@ -appwrite teams list-memberships \ - --team-id diff --git a/docs/examples/teams/list.md b/docs/examples/teams/list.md deleted file mode 100644 index 90ab82f8..00000000 --- a/docs/examples/teams/list.md +++ /dev/null @@ -1 +0,0 @@ -appwrite teams list diff --git a/docs/examples/teams/update-membership-status.md b/docs/examples/teams/update-membership-status.md deleted file mode 100644 index 9c234f52..00000000 --- a/docs/examples/teams/update-membership-status.md +++ /dev/null @@ -1,5 +0,0 @@ -appwrite teams update-membership-status \ - --team-id \ - --membership-id \ - --user-id \ - --secret diff --git a/docs/examples/teams/update-membership.md b/docs/examples/teams/update-membership.md deleted file mode 100644 index f16c776a..00000000 --- a/docs/examples/teams/update-membership.md +++ /dev/null @@ -1,4 +0,0 @@ -appwrite teams update-membership \ - --team-id \ - --membership-id \ - --roles one two three diff --git a/docs/examples/teams/update-name.md b/docs/examples/teams/update-name.md deleted file mode 100644 index cc803fbc..00000000 --- a/docs/examples/teams/update-name.md +++ /dev/null @@ -1,3 +0,0 @@ -appwrite teams update-name \ - --team-id \ - --name diff --git a/docs/examples/teams/update-prefs.md b/docs/examples/teams/update-prefs.md deleted file mode 100644 index a8ce4264..00000000 --- a/docs/examples/teams/update-prefs.md +++ /dev/null @@ -1,3 +0,0 @@ -appwrite teams update-prefs \ - --team-id \ - --prefs '{ "key": "value" }' diff --git a/docs/examples/tokens/create-file-token.md b/docs/examples/tokens/create-file-token.md deleted file mode 100644 index 3890041d..00000000 --- a/docs/examples/tokens/create-file-token.md +++ /dev/null @@ -1,3 +0,0 @@ -appwrite tokens create-file-token \ - --bucket-id \ - --file-id diff --git a/docs/examples/tokens/delete.md b/docs/examples/tokens/delete.md deleted file mode 100644 index 93c99a92..00000000 --- a/docs/examples/tokens/delete.md +++ /dev/null @@ -1,2 +0,0 @@ -appwrite tokens delete \ - --token-id diff --git a/docs/examples/tokens/get.md b/docs/examples/tokens/get.md deleted file mode 100644 index 617c112e..00000000 --- a/docs/examples/tokens/get.md +++ /dev/null @@ -1,2 +0,0 @@ -appwrite tokens get \ - --token-id diff --git a/docs/examples/tokens/list.md b/docs/examples/tokens/list.md deleted file mode 100644 index 95e0df3b..00000000 --- a/docs/examples/tokens/list.md +++ /dev/null @@ -1,3 +0,0 @@ -appwrite tokens list \ - --bucket-id \ - --file-id diff --git a/docs/examples/tokens/update.md b/docs/examples/tokens/update.md deleted file mode 100644 index ab86424a..00000000 --- a/docs/examples/tokens/update.md +++ /dev/null @@ -1,2 +0,0 @@ -appwrite tokens update \ - --token-id diff --git a/docs/examples/users/create-argon-2-user.md b/docs/examples/users/create-argon-2-user.md deleted file mode 100644 index fd2a7e41..00000000 --- a/docs/examples/users/create-argon-2-user.md +++ /dev/null @@ -1,4 +0,0 @@ -appwrite users create-argon-2-user \ - --user-id \ - --email email@example.com \ - --password password diff --git a/docs/examples/users/create-bcrypt-user.md b/docs/examples/users/create-bcrypt-user.md deleted file mode 100644 index e05d9e83..00000000 --- a/docs/examples/users/create-bcrypt-user.md +++ /dev/null @@ -1,4 +0,0 @@ -appwrite users create-bcrypt-user \ - --user-id \ - --email email@example.com \ - --password password diff --git a/docs/examples/users/create-jwt.md b/docs/examples/users/create-jwt.md deleted file mode 100644 index 508c0f64..00000000 --- a/docs/examples/users/create-jwt.md +++ /dev/null @@ -1,2 +0,0 @@ -appwrite users create-jwt \ - --user-id diff --git a/docs/examples/users/create-md-5-user.md b/docs/examples/users/create-md-5-user.md deleted file mode 100644 index f47b9499..00000000 --- a/docs/examples/users/create-md-5-user.md +++ /dev/null @@ -1,4 +0,0 @@ -appwrite users create-md-5-user \ - --user-id \ - --email email@example.com \ - --password password diff --git a/docs/examples/users/create-mfa-recovery-codes.md b/docs/examples/users/create-mfa-recovery-codes.md deleted file mode 100644 index c2128723..00000000 --- a/docs/examples/users/create-mfa-recovery-codes.md +++ /dev/null @@ -1,2 +0,0 @@ -appwrite users create-mfa-recovery-codes \ - --user-id diff --git a/docs/examples/users/create-ph-pass-user.md b/docs/examples/users/create-ph-pass-user.md deleted file mode 100644 index a4047051..00000000 --- a/docs/examples/users/create-ph-pass-user.md +++ /dev/null @@ -1,4 +0,0 @@ -appwrite users create-ph-pass-user \ - --user-id \ - --email email@example.com \ - --password password diff --git a/docs/examples/users/create-scrypt-modified-user.md b/docs/examples/users/create-scrypt-modified-user.md deleted file mode 100644 index df4d651a..00000000 --- a/docs/examples/users/create-scrypt-modified-user.md +++ /dev/null @@ -1,7 +0,0 @@ -appwrite users create-scrypt-modified-user \ - --user-id \ - --email email@example.com \ - --password password \ - --password-salt \ - --password-salt-separator \ - --password-signer-key diff --git a/docs/examples/users/create-scrypt-user.md b/docs/examples/users/create-scrypt-user.md deleted file mode 100644 index 2f911b58..00000000 --- a/docs/examples/users/create-scrypt-user.md +++ /dev/null @@ -1,9 +0,0 @@ -appwrite users create-scrypt-user \ - --user-id \ - --email email@example.com \ - --password password \ - --password-salt \ - --password-cpu null \ - --password-memory null \ - --password-parallel null \ - --password-length null diff --git a/docs/examples/users/create-session.md b/docs/examples/users/create-session.md deleted file mode 100644 index 2644dce0..00000000 --- a/docs/examples/users/create-session.md +++ /dev/null @@ -1,2 +0,0 @@ -appwrite users create-session \ - --user-id diff --git a/docs/examples/users/create-sha-user.md b/docs/examples/users/create-sha-user.md deleted file mode 100644 index 6965698f..00000000 --- a/docs/examples/users/create-sha-user.md +++ /dev/null @@ -1,4 +0,0 @@ -appwrite users create-sha-user \ - --user-id \ - --email email@example.com \ - --password password diff --git a/docs/examples/users/create-target.md b/docs/examples/users/create-target.md deleted file mode 100644 index d0775c9e..00000000 --- a/docs/examples/users/create-target.md +++ /dev/null @@ -1,5 +0,0 @@ -appwrite users create-target \ - --user-id \ - --target-id \ - --provider-type email \ - --identifier diff --git a/docs/examples/users/create-token.md b/docs/examples/users/create-token.md deleted file mode 100644 index 30b7812a..00000000 --- a/docs/examples/users/create-token.md +++ /dev/null @@ -1,2 +0,0 @@ -appwrite users create-token \ - --user-id diff --git a/docs/examples/users/create.md b/docs/examples/users/create.md deleted file mode 100644 index 1103eaf4..00000000 --- a/docs/examples/users/create.md +++ /dev/null @@ -1,2 +0,0 @@ -appwrite users create \ - --user-id diff --git a/docs/examples/users/delete-identity.md b/docs/examples/users/delete-identity.md deleted file mode 100644 index 602a7d0c..00000000 --- a/docs/examples/users/delete-identity.md +++ /dev/null @@ -1,2 +0,0 @@ -appwrite users delete-identity \ - --identity-id diff --git a/docs/examples/users/delete-mfa-authenticator.md b/docs/examples/users/delete-mfa-authenticator.md deleted file mode 100644 index a0fcc704..00000000 --- a/docs/examples/users/delete-mfa-authenticator.md +++ /dev/null @@ -1,3 +0,0 @@ -appwrite users delete-mfa-authenticator \ - --user-id \ - --type totp diff --git a/docs/examples/users/delete-session.md b/docs/examples/users/delete-session.md deleted file mode 100644 index f638b833..00000000 --- a/docs/examples/users/delete-session.md +++ /dev/null @@ -1,3 +0,0 @@ -appwrite users delete-session \ - --user-id \ - --session-id diff --git a/docs/examples/users/delete-sessions.md b/docs/examples/users/delete-sessions.md deleted file mode 100644 index eb038cc5..00000000 --- a/docs/examples/users/delete-sessions.md +++ /dev/null @@ -1,2 +0,0 @@ -appwrite users delete-sessions \ - --user-id diff --git a/docs/examples/users/delete-target.md b/docs/examples/users/delete-target.md deleted file mode 100644 index e6410dd1..00000000 --- a/docs/examples/users/delete-target.md +++ /dev/null @@ -1,3 +0,0 @@ -appwrite users delete-target \ - --user-id \ - --target-id diff --git a/docs/examples/users/delete.md b/docs/examples/users/delete.md deleted file mode 100644 index 00f8f9c9..00000000 --- a/docs/examples/users/delete.md +++ /dev/null @@ -1,2 +0,0 @@ -appwrite users delete \ - --user-id diff --git a/docs/examples/users/get-mfa-recovery-codes.md b/docs/examples/users/get-mfa-recovery-codes.md deleted file mode 100644 index cbb75820..00000000 --- a/docs/examples/users/get-mfa-recovery-codes.md +++ /dev/null @@ -1,2 +0,0 @@ -appwrite users get-mfa-recovery-codes \ - --user-id diff --git a/docs/examples/users/get-prefs.md b/docs/examples/users/get-prefs.md deleted file mode 100644 index 45d01a6f..00000000 --- a/docs/examples/users/get-prefs.md +++ /dev/null @@ -1,2 +0,0 @@ -appwrite users get-prefs \ - --user-id diff --git a/docs/examples/users/get-target.md b/docs/examples/users/get-target.md deleted file mode 100644 index 1be3c0ef..00000000 --- a/docs/examples/users/get-target.md +++ /dev/null @@ -1,3 +0,0 @@ -appwrite users get-target \ - --user-id \ - --target-id diff --git a/docs/examples/users/get-usage.md b/docs/examples/users/get-usage.md deleted file mode 100644 index a4d13e70..00000000 --- a/docs/examples/users/get-usage.md +++ /dev/null @@ -1 +0,0 @@ -appwrite users get-usage diff --git a/docs/examples/users/get.md b/docs/examples/users/get.md deleted file mode 100644 index 341844cf..00000000 --- a/docs/examples/users/get.md +++ /dev/null @@ -1,2 +0,0 @@ -appwrite users get \ - --user-id diff --git a/docs/examples/users/list-identities.md b/docs/examples/users/list-identities.md deleted file mode 100644 index d4fa82f2..00000000 --- a/docs/examples/users/list-identities.md +++ /dev/null @@ -1 +0,0 @@ -appwrite users list-identities diff --git a/docs/examples/users/list-logs.md b/docs/examples/users/list-logs.md deleted file mode 100644 index d2b95bee..00000000 --- a/docs/examples/users/list-logs.md +++ /dev/null @@ -1,2 +0,0 @@ -appwrite users list-logs \ - --user-id diff --git a/docs/examples/users/list-memberships.md b/docs/examples/users/list-memberships.md deleted file mode 100644 index f027e4a2..00000000 --- a/docs/examples/users/list-memberships.md +++ /dev/null @@ -1,2 +0,0 @@ -appwrite users list-memberships \ - --user-id diff --git a/docs/examples/users/list-mfa-factors.md b/docs/examples/users/list-mfa-factors.md deleted file mode 100644 index d2cadf5b..00000000 --- a/docs/examples/users/list-mfa-factors.md +++ /dev/null @@ -1,2 +0,0 @@ -appwrite users list-mfa-factors \ - --user-id diff --git a/docs/examples/users/list-sessions.md b/docs/examples/users/list-sessions.md deleted file mode 100644 index 761447a6..00000000 --- a/docs/examples/users/list-sessions.md +++ /dev/null @@ -1,2 +0,0 @@ -appwrite users list-sessions \ - --user-id diff --git a/docs/examples/users/list-targets.md b/docs/examples/users/list-targets.md deleted file mode 100644 index 26330e80..00000000 --- a/docs/examples/users/list-targets.md +++ /dev/null @@ -1,2 +0,0 @@ -appwrite users list-targets \ - --user-id diff --git a/docs/examples/users/list.md b/docs/examples/users/list.md deleted file mode 100644 index 94057adf..00000000 --- a/docs/examples/users/list.md +++ /dev/null @@ -1 +0,0 @@ -appwrite users list diff --git a/docs/examples/users/update-email-verification.md b/docs/examples/users/update-email-verification.md deleted file mode 100644 index 9f4788aa..00000000 --- a/docs/examples/users/update-email-verification.md +++ /dev/null @@ -1,3 +0,0 @@ -appwrite users update-email-verification \ - --user-id \ - --email-verification false diff --git a/docs/examples/users/update-email.md b/docs/examples/users/update-email.md deleted file mode 100644 index f02b79de..00000000 --- a/docs/examples/users/update-email.md +++ /dev/null @@ -1,3 +0,0 @@ -appwrite users update-email \ - --user-id \ - --email email@example.com diff --git a/docs/examples/users/update-labels.md b/docs/examples/users/update-labels.md deleted file mode 100644 index 5963768f..00000000 --- a/docs/examples/users/update-labels.md +++ /dev/null @@ -1,3 +0,0 @@ -appwrite users update-labels \ - --user-id \ - --labels one two three diff --git a/docs/examples/users/update-mfa-recovery-codes.md b/docs/examples/users/update-mfa-recovery-codes.md deleted file mode 100644 index 4f63119f..00000000 --- a/docs/examples/users/update-mfa-recovery-codes.md +++ /dev/null @@ -1,2 +0,0 @@ -appwrite users update-mfa-recovery-codes \ - --user-id diff --git a/docs/examples/users/update-mfa.md b/docs/examples/users/update-mfa.md deleted file mode 100644 index 1d36d9e1..00000000 --- a/docs/examples/users/update-mfa.md +++ /dev/null @@ -1,3 +0,0 @@ -appwrite users update-mfa \ - --user-id \ - --mfa false diff --git a/docs/examples/users/update-name.md b/docs/examples/users/update-name.md deleted file mode 100644 index 2f0d0788..00000000 --- a/docs/examples/users/update-name.md +++ /dev/null @@ -1,3 +0,0 @@ -appwrite users update-name \ - --user-id \ - --name diff --git a/docs/examples/users/update-password.md b/docs/examples/users/update-password.md deleted file mode 100644 index ec320c23..00000000 --- a/docs/examples/users/update-password.md +++ /dev/null @@ -1,3 +0,0 @@ -appwrite users update-password \ - --user-id \ - --password '' diff --git a/docs/examples/users/update-phone-verification.md b/docs/examples/users/update-phone-verification.md deleted file mode 100644 index 2cf56b2a..00000000 --- a/docs/examples/users/update-phone-verification.md +++ /dev/null @@ -1,3 +0,0 @@ -appwrite users update-phone-verification \ - --user-id \ - --phone-verification false diff --git a/docs/examples/users/update-phone.md b/docs/examples/users/update-phone.md deleted file mode 100644 index d1b7db35..00000000 --- a/docs/examples/users/update-phone.md +++ /dev/null @@ -1,3 +0,0 @@ -appwrite users update-phone \ - --user-id \ - --number +12065550100 diff --git a/docs/examples/users/update-prefs.md b/docs/examples/users/update-prefs.md deleted file mode 100644 index b4e27cda..00000000 --- a/docs/examples/users/update-prefs.md +++ /dev/null @@ -1,3 +0,0 @@ -appwrite users update-prefs \ - --user-id \ - --prefs '{ "key": "value" }' diff --git a/docs/examples/users/update-status.md b/docs/examples/users/update-status.md deleted file mode 100644 index f7c1bb44..00000000 --- a/docs/examples/users/update-status.md +++ /dev/null @@ -1,3 +0,0 @@ -appwrite users update-status \ - --user-id \ - --status false diff --git a/docs/examples/users/update-target.md b/docs/examples/users/update-target.md deleted file mode 100644 index 1fa4b7ab..00000000 --- a/docs/examples/users/update-target.md +++ /dev/null @@ -1,3 +0,0 @@ -appwrite users update-target \ - --user-id \ - --target-id diff --git a/docs/examples/vcs/create-repository-detection.md b/docs/examples/vcs/create-repository-detection.md deleted file mode 100644 index d10eac80..00000000 --- a/docs/examples/vcs/create-repository-detection.md +++ /dev/null @@ -1,4 +0,0 @@ -appwrite vcs create-repository-detection \ - --installation-id \ - --provider-repository-id \ - --type runtime diff --git a/docs/examples/vcs/create-repository.md b/docs/examples/vcs/create-repository.md deleted file mode 100644 index fa9206cf..00000000 --- a/docs/examples/vcs/create-repository.md +++ /dev/null @@ -1,4 +0,0 @@ -appwrite vcs create-repository \ - --installation-id \ - --name \ - --private false diff --git a/docs/examples/vcs/delete-installation.md b/docs/examples/vcs/delete-installation.md deleted file mode 100644 index ae9fd335..00000000 --- a/docs/examples/vcs/delete-installation.md +++ /dev/null @@ -1,2 +0,0 @@ -appwrite vcs delete-installation \ - --installation-id diff --git a/docs/examples/vcs/get-installation.md b/docs/examples/vcs/get-installation.md deleted file mode 100644 index e589d604..00000000 --- a/docs/examples/vcs/get-installation.md +++ /dev/null @@ -1,2 +0,0 @@ -appwrite vcs get-installation \ - --installation-id diff --git a/docs/examples/vcs/get-repository-contents.md b/docs/examples/vcs/get-repository-contents.md deleted file mode 100644 index 786d2201..00000000 --- a/docs/examples/vcs/get-repository-contents.md +++ /dev/null @@ -1,3 +0,0 @@ -appwrite vcs get-repository-contents \ - --installation-id \ - --provider-repository-id diff --git a/docs/examples/vcs/get-repository.md b/docs/examples/vcs/get-repository.md deleted file mode 100644 index 10ab5550..00000000 --- a/docs/examples/vcs/get-repository.md +++ /dev/null @@ -1,3 +0,0 @@ -appwrite vcs get-repository \ - --installation-id \ - --provider-repository-id diff --git a/docs/examples/vcs/list-installations.md b/docs/examples/vcs/list-installations.md deleted file mode 100644 index 92e13bf0..00000000 --- a/docs/examples/vcs/list-installations.md +++ /dev/null @@ -1 +0,0 @@ -appwrite vcs list-installations diff --git a/docs/examples/vcs/list-repositories.md b/docs/examples/vcs/list-repositories.md deleted file mode 100644 index 7a321407..00000000 --- a/docs/examples/vcs/list-repositories.md +++ /dev/null @@ -1,3 +0,0 @@ -appwrite vcs list-repositories \ - --installation-id \ - --type runtime diff --git a/docs/examples/vcs/list-repository-branches.md b/docs/examples/vcs/list-repository-branches.md deleted file mode 100644 index c6036731..00000000 --- a/docs/examples/vcs/list-repository-branches.md +++ /dev/null @@ -1,3 +0,0 @@ -appwrite vcs list-repository-branches \ - --installation-id \ - --provider-repository-id diff --git a/docs/examples/vcs/update-external-deployments.md b/docs/examples/vcs/update-external-deployments.md deleted file mode 100644 index f83891cb..00000000 --- a/docs/examples/vcs/update-external-deployments.md +++ /dev/null @@ -1,4 +0,0 @@ -appwrite vcs update-external-deployments \ - --installation-id \ - --repository-id \ - --provider-pull-request-id diff --git a/index.ts b/index.ts index 54d01fd9..108957b8 100644 --- a/index.ts +++ b/index.ts @@ -5,148 +5,164 @@ const oldWidth = process.stdout.columns; process.stdout.columns = 100; /** ---------------------------------------------- */ -import program = require('commander'); -import chalk = require('chalk'); -const { version } = require('../package.json'); -import { commandDescriptions, cliConfig } from './lib/parser'; -import { client } from './lib/commands/generic'; -import { getLatestVersion, compareVersions } from './lib/utils'; -import inquirer = require('inquirer'); -import { login, logout, whoami, migrate, register } from './lib/commands/generic'; -import { init } from './lib/commands/init'; -import { types } from './lib/commands/types'; -import { pull } from './lib/commands/pull'; -import { run } from './lib/commands/run'; -import { push, deploy } from './lib/commands/push'; -import { update } from './lib/commands/update'; -import { account } from './lib/commands/account'; -import { console } from './lib/commands/console'; -import { databases } from './lib/commands/databases'; -import { functions } from './lib/commands/functions'; -import { graphql } from './lib/commands/graphql'; -import { health } from './lib/commands/health'; -import { locale } from './lib/commands/locale'; -import { messaging } from './lib/commands/messaging'; -import { migrations } from './lib/commands/migrations'; -import { project } from './lib/commands/project'; -import { projects } from './lib/commands/projects'; -import { proxy } from './lib/commands/proxy'; -import { sites } from './lib/commands/sites'; -import { storage } from './lib/commands/storage'; -import { tablesDB } from './lib/commands/tables-db'; -import { teams } from './lib/commands/teams'; -import { tokens } from './lib/commands/tokens'; -import { users } from './lib/commands/users'; -import { vcs } from './lib/commands/vcs'; +import { program } from "commander"; +import chalk from "chalk"; +import packageJson from "./package.json" with { type: "json" }; +const { version } = packageJson; +import { commandDescriptions, cliConfig } from "./lib/parser.js"; +import { client } from "./lib/commands/generic.js"; +import { getLatestVersion, compareVersions } from "./lib/utils.js"; +import inquirer from "inquirer"; +import { + login, + logout, + whoami, + migrate, + register, +} from "./lib/commands/generic.js"; +import { init } from "./lib/commands/init.js"; +import { types } from "./lib/commands/types.js"; +import { pull } from "./lib/commands/pull.js"; +import { run } from "./lib/commands/run.js"; +import { push, deploy } from "./lib/commands/push.js"; +import { update } from "./lib/commands/update.js"; +import { account } from "./lib/commands/services/account.js"; +import { console } from "./lib/commands/services/console.js"; +import { databases } from "./lib/commands/services/databases.js"; +import { functions } from "./lib/commands/services/functions.js"; +import { graphql } from "./lib/commands/services/graphql.js"; +import { health } from "./lib/commands/services/health.js"; +import { locale } from "./lib/commands/services/locale.js"; +import { messaging } from "./lib/commands/services/messaging.js"; +import { migrations } from "./lib/commands/services/migrations.js"; +import { project } from "./lib/commands/services/project.js"; +import { projects } from "./lib/commands/services/projects.js"; +import { proxy } from "./lib/commands/services/proxy.js"; +import { sites } from "./lib/commands/services/sites.js"; +import { storage } from "./lib/commands/services/storage.js"; +import { tablesdb } from "./lib/commands/services/tablesdb.js"; +import { teams } from "./lib/commands/services/teams.js"; +import { tokens } from "./lib/commands/services/tokens.js"; +import { users } from "./lib/commands/services/users.js"; +import { vcs } from "./lib/commands/services/vcs.js"; +import searchList from "inquirer-search-list"; -inquirer.registerPrompt('search-list', require('inquirer-search-list')); +inquirer.registerPrompt("search-list", searchList); /** * Check for updates and show version information */ async function checkVersion(): Promise { - process.stdout.write(chalk.bold(`appwrite version ${version}`) + '\n'); + process.stdout.write(chalk.bold(`appwrite version ${version}`) + "\n"); - try { - const latestVersion = await getLatestVersion(); - const comparison = compareVersions(version, latestVersion); + try { + const latestVersion = await getLatestVersion(); + const comparison = compareVersions(version, latestVersion); - if (comparison > 0) { - // Current version is older than latest - process.stdout.write( - chalk.yellow(`\n⚠️ A newer version is available: ${chalk.bold(latestVersion)}`) + '\n' - ); - process.stdout.write( - chalk.cyan( - `💡 Run '${chalk.bold('appwrite update')}' to update to the latest version.` - ) + '\n' - ); - } else if (comparison === 0) { - process.stdout.write(chalk.green('\n✅ You are running the latest version!') + '\n'); - } else { - // Current version is newer than latest (pre-release/dev) - process.stdout.write(chalk.blue('\n🚀 You are running a pre-release or development version.') + '\n'); - } - } catch (error) { - // Silently fail version check, just show current version - process.stdout.write(chalk.gray('\n(Unable to check for updates)') + '\n'); + if (comparison > 0) { + // Current version is older than latest + process.stdout.write( + chalk.yellow( + `\n⚠️ A newer version is available: ${chalk.bold(latestVersion)}`, + ) + "\n", + ); + process.stdout.write( + chalk.cyan( + `💡 Run '${chalk.bold("appwrite update")}' to update to the latest version.`, + ) + "\n", + ); + } else if (comparison === 0) { + process.stdout.write( + chalk.green("\n✅ You are running the latest version!") + "\n", + ); + } else { + // Current version is newer than latest (pre-release/dev) + process.stdout.write( + chalk.blue( + "\n🚀 You are running a pre-release or development version.", + ) + "\n", + ); } + } catch (error) { + // Silently fail version check, just show current version + process.stdout.write(chalk.gray("\n(Unable to check for updates)") + "\n"); + } } // Intercept version flag before Commander.js processes it -if (process.argv.includes('-v') || process.argv.includes('--version')) { - (async () => { - await checkVersion(); - process.exit(0); - })(); +if (process.argv.includes("-v") || process.argv.includes("--version")) { + (async () => { + await checkVersion(); + process.exit(0); + })(); } else { - program - .description(commandDescriptions['main']) - .configureHelp({ - helpWidth: process.stdout.columns || 80, - sortSubcommands: true, - }) - .helpOption('-h, --help', 'Display help for command') - .version(version, '-v, --version', 'Output the version number') - .option('-V, --verbose', 'Show complete error log') - .option('-j, --json', 'Output in JSON format') - .hook('preAction', migrate) - .option('-f,--force', 'Flag to confirm all warnings') - .option('-a,--all', 'Flag to push all resources') - .option('--id [id...]', 'Flag to pass a list of ids for a given action') - .option('--report', 'Enable reporting in case of CLI errors') - .on('option:json', () => { - cliConfig.json = true; - }) - .on('option:verbose', () => { - cliConfig.verbose = true; - }) - .on('option:report', function () { - cliConfig.report = true; - cliConfig.reportData = { data: this }; - }) - .on('option:force', () => { - cliConfig.force = true; - }) - .on('option:all', () => { - cliConfig.all = true; - }) - .on('option:id', function () { - cliConfig.ids = (this as any).opts().id; - }) - .showSuggestionAfterError() - .addCommand(whoami) - .addCommand(register) - .addCommand(login) - .addCommand(init) - .addCommand(pull) - .addCommand(push) - .addCommand(types) - .addCommand(deploy) - .addCommand(run) - .addCommand(update) - .addCommand(logout) - .addCommand(account) - .addCommand(console) - .addCommand(databases) - .addCommand(functions) - .addCommand(graphql) - .addCommand(health) - .addCommand(locale) - .addCommand(messaging) - .addCommand(migrations) - .addCommand(project) - .addCommand(projects) - .addCommand(proxy) - .addCommand(sites) - .addCommand(storage) - .addCommand(tablesDB) - .addCommand(teams) - .addCommand(tokens) - .addCommand(users) - .addCommand(vcs) - .addCommand(client) - .parse(process.argv); + program + .description(commandDescriptions["main"]) + .configureHelp({ + helpWidth: process.stdout.columns || 80, + sortSubcommands: true, + }) + .helpOption("-h, --help", "Display help for command") + .version(version, "-v, --version", "Output the version number") + .option("-V, --verbose", "Show complete error log") + .option("-j, --json", "Output in JSON format") + .hook("preAction", migrate) + .option("-f,--force", "Flag to confirm all warnings") + .option("-a,--all", "Flag to push all resources") + .option("--id [id...]", "Flag to pass a list of ids for a given action") + .option("--report", "Enable reporting in case of CLI errors") + .on("option:json", () => { + cliConfig.json = true; + }) + .on("option:verbose", () => { + cliConfig.verbose = true; + }) + .on("option:report", function () { + cliConfig.report = true; + cliConfig.reportData = { data: this }; + }) + .on("option:force", () => { + cliConfig.force = true; + }) + .on("option:all", () => { + cliConfig.all = true; + }) + .on("option:id", function () { + cliConfig.ids = (this as any).opts().id; + }) + .showSuggestionAfterError() + .addCommand(whoami) + .addCommand(register) + .addCommand(login) + .addCommand(init) + .addCommand(pull) + .addCommand(push) + .addCommand(types) + .addCommand(deploy) + .addCommand(run) + .addCommand(update) + .addCommand(logout) + .addCommand(account) + .addCommand(console) + .addCommand(databases) + .addCommand(functions) + .addCommand(graphql) + .addCommand(health) + .addCommand(locale) + .addCommand(messaging) + .addCommand(migrations) + .addCommand(project) + .addCommand(projects) + .addCommand(proxy) + .addCommand(sites) + .addCommand(storage) + .addCommand(tablesdb) + .addCommand(teams) + .addCommand(tokens) + .addCommand(users) + .addCommand(vcs) + .addCommand(client) + .parse(process.argv); - process.stdout.columns = oldWidth; + process.stdout.columns = oldWidth; } diff --git a/install.ps1 b/install.ps1 index d21f8f52..86ca00bb 100644 --- a/install.ps1 +++ b/install.ps1 @@ -13,8 +13,8 @@ # You can use "View source" of this page to see the full script. # REPO -$GITHUB_x64_URL = "https://github.com/appwrite/sdk-for-cli/releases/download/13.0.0-rc.1/appwrite-cli-win-x64.exe" -$GITHUB_arm64_URL = "https://github.com/appwrite/sdk-for-cli/releases/download/13.0.0-rc.1/appwrite-cli-win-arm64.exe" +$GITHUB_x64_URL = "https://github.com/appwrite/sdk-for-cli/releases/download/13.0.0-rc.2/appwrite-cli-win-x64.exe" +$GITHUB_arm64_URL = "https://github.com/appwrite/sdk-for-cli/releases/download/13.0.0-rc.2/appwrite-cli-win-arm64.exe" $APPWRITE_BINARY_NAME = "appwrite.exe" diff --git a/install.sh b/install.sh index 8732228a..faa9c248 100644 --- a/install.sh +++ b/install.sh @@ -96,7 +96,7 @@ printSuccess() { downloadBinary() { echo "[2/4] Downloading executable for $OS ($ARCH) ..." - GITHUB_LATEST_VERSION="13.0.0-rc.1" + GITHUB_LATEST_VERSION="13.0.0-rc.2" GITHUB_FILE="appwrite-cli-${OS}-${ARCH}" GITHUB_URL="https://github.com/$GITHUB_REPOSITORY_NAME/releases/download/$GITHUB_LATEST_VERSION/$GITHUB_FILE" diff --git a/lib/client.ts b/lib/client.ts index 9d6833d9..566b6aeb 100644 --- a/lib/client.ts +++ b/lib/client.ts @@ -1,259 +1,292 @@ -import os = require('os'); -import { fetch, FormData, Agent } from 'undici'; -import JSONbig = require('json-bigint'); -import AppwriteException = require('./exception'); -import { globalConfig } from './config'; -import chalk = require('chalk'); -import type { Headers, RequestParams, ResponseType, FileUpload } from './types'; +import os from "os"; +import { fetch, FormData, Agent } from "undici"; +import JSONbig from "json-bigint"; +import { AppwriteException } from "@appwrite.io/console"; +import { globalConfig } from "./config.js"; +import chalk from "chalk"; +import type { + Headers, + RequestParams, + ResponseType, + FileUpload, +} from "./types.js"; const JSONBigInt = JSONbig({ storeAsString: false }); class Client { - private readonly CHUNK_SIZE = 5 * 1024 * 1024; // 5MB - private endpoint: string; - private headers: Headers; - private selfSigned: boolean; + private endpoint: string; + private headers: Headers; + private selfSigned: boolean; - constructor() { - this.endpoint = 'https://cloud.appwrite.io/v1'; - this.selfSigned = false; - this.headers = { - 'content-type': '', - 'x-sdk-name': 'Command Line', - 'x-sdk-platform': 'console', - 'x-sdk-language': 'cli', - 'x-sdk-version': '13.0.0-rc.1', - 'user-agent': `AppwriteCLI/13.0.0-rc.1 (${os.type()} ${os.version()}; ${os.arch()})`, - 'X-Appwrite-Response-Format': '1.8.0', - }; - } - - /** - * Set Cookie - * - * Your cookie - * - * @param {string} cookie - * - * @return self - */ - setCookie(cookie: string): this { - this.addHeader('cookie', cookie); - return this; - } + constructor() { + this.endpoint = "https://cloud.appwrite.io/v1"; + this.selfSigned = false; + this.headers = { + "content-type": "", + "x-sdk-name": "Command Line", + "x-sdk-platform": "console", + "x-sdk-language": "cli", + "x-sdk-version": "13.0.0-rc.2", + "user-agent": `AppwriteCLI/13.0.0-rc.2 (${os.type()} ${os.version()}; ${os.arch()})`, + "X-Appwrite-Response-Format": "1.8.1", + }; + } - /** - * Set Project - * - * Your project ID - * - * @param {string} project - * - * @return self - */ - setProject(project: string): this { - this.addHeader('X-Appwrite-Project', project); - return this; - } + /** + * Set Cookie + * + * Your cookie + * + * @param {string} cookie + * + * @return self + */ + setCookie(cookie: string): this { + this.addHeader("cookie", cookie); + return this; + } - /** - * Set Key - * - * Your secret API key - * - * @param {string} key - * - * @return self - */ - setKey(key: string): this { - this.addHeader('X-Appwrite-Key', key); - return this; - } + /** + * Set Project + * + * Your project ID + * + * @param {string} project + * + * @return self + */ + setProject(project: string): this { + this.addHeader("X-Appwrite-Project", project); + return this; + } - /** - * Set JWT - * - * Your secret JSON Web Token - * - * @param {string} jwt - * - * @return self - */ - setJWT(jwt: string): this { - this.addHeader('X-Appwrite-JWT', jwt); - return this; - } + /** + * Set Key + * + * Your secret API key + * + * @param {string} key + * + * @return self + */ + setKey(key: string): this { + this.addHeader("X-Appwrite-Key", key); + return this; + } - /** - * Set Locale - * - * @param {string} locale - * - * @return self - */ - setLocale(locale: string): this { - this.addHeader('X-Appwrite-Locale', locale); - return this; - } + /** + * Set JWT + * + * Your secret JSON Web Token + * + * @param {string} jwt + * + * @return self + */ + setJWT(jwt: string): this { + this.addHeader("X-Appwrite-JWT", jwt); + return this; + } - /** - * Set Mode - * - * @param {string} mode - * - * @return self - */ - setMode(mode: string): this { - this.addHeader('X-Appwrite-Mode', mode); - return this; - } + /** + * Set Locale + * + * @param {string} locale + * + * @return self + */ + setLocale(locale: string): this { + this.addHeader("X-Appwrite-Locale", locale); + return this; + } - /** - * Set self signed. - * - * @param {bool} status - * - * @return this - */ - setSelfSigned(status: boolean): this { - this.selfSigned = status; - return this; - } + /** + * Set Mode + * + * @param {string} mode + * + * @return self + */ + setMode(mode: string): this { + this.addHeader("X-Appwrite-Mode", mode); + return this; + } - /** - * Set endpoint. - * - * @param {string} endpoint - * - * @return this - */ - setEndpoint(endpoint: string): this { - if (!endpoint.startsWith('http://') && !endpoint.startsWith('https://')) { - throw new AppwriteException('Invalid endpoint URL: ' + endpoint); - } + /** + * Set self signed. + * + * @param {bool} status + * + * @return this + */ + setSelfSigned(status: boolean): this { + this.selfSigned = status; + return this; + } - this.endpoint = endpoint; - return this; + /** + * Set endpoint. + * + * @param {string} endpoint + * + * @return this + */ + setEndpoint(endpoint: string): this { + if (!endpoint.startsWith("http://") && !endpoint.startsWith("https://")) { + throw new AppwriteException("Invalid endpoint URL: " + endpoint); } - /** - * @param {string} key - * @param {string} value - */ - addHeader(key: string, value: string): this { - this.headers[key.toLowerCase()] = value; - return this; - } + this.endpoint = endpoint; + return this; + } - async call( - method: string, - path: string = '', - headers: Headers = {}, - params: RequestParams = {}, - responseType: ResponseType = 'json' - ): Promise { - const mergedHeaders: Headers = { ...this.headers, ...headers }; - const url = new URL(this.endpoint + path); + /** + * @param {string} key + * @param {string} value + */ + addHeader(key: string, value: string): this { + this.headers[key.toLowerCase()] = value; + return this; + } - let body: FormData | string | undefined = undefined; + async call( + method: string, + path: string = "", + headers: Headers = {}, + params: RequestParams = {}, + responseType: ResponseType = "json", + ): Promise { + const mergedHeaders: Headers = { ...this.headers, ...headers }; + const url = new URL(this.endpoint + path); - if (method.toUpperCase() === 'GET') { - url.search = new URLSearchParams(Client.flatten(params) as Record).toString(); - } else if (mergedHeaders['content-type']?.toLowerCase().startsWith('multipart/form-data')) { - delete mergedHeaders['content-type']; - const formData = new FormData(); + let body: FormData | string | undefined = undefined; - const flatParams = Client.flatten(params); + if (method.toUpperCase() === "GET") { + url.search = new URLSearchParams( + Client.flatten(params) as Record, + ).toString(); + } else if ( + mergedHeaders["content-type"] + ?.toLowerCase() + .startsWith("multipart/form-data") + ) { + delete mergedHeaders["content-type"]; + const formData = new FormData(); - for (const [key, value] of Object.entries(flatParams)) { - if (value && typeof value === 'object' && 'type' in value && value.type === 'file') { - const fileUpload = value as FileUpload; - formData.append(key, fileUpload.file as any, fileUpload.filename); - } else { - formData.append(key, value as string); - } - } + const flatParams = Client.flatten(params); - body = formData; + for (const [key, value] of Object.entries(flatParams)) { + if ( + value && + typeof value === "object" && + "type" in value && + value.type === "file" + ) { + const fileUpload = value as FileUpload; + formData.append(key, fileUpload.file as any, fileUpload.filename); } else { - body = JSONBigInt.stringify(params); + formData.append(key, value as string); } + } - let response: Awaited> | undefined = undefined; - try { - response = await fetch(url.toString(), { - method: method.toUpperCase(), - headers: mergedHeaders, - body, - dispatcher: new Agent({ - connect: { - rejectUnauthorized: !this.selfSigned, - }, - }), - }); - } catch (error) { - throw new AppwriteException((error as Error).message); - } + body = formData; + } else { + body = JSONBigInt.stringify(params); + } - if (response.status >= 400) { - const text = await response.text(); - let json: { message?: string; code?: number; type?: string } | undefined = undefined; - try { - json = JSON.parse(text); - } catch (error) { - throw new AppwriteException(text, response.status, '', text); - } + let response: Awaited> | undefined = undefined; + try { + response = await fetch(url.toString(), { + method: method.toUpperCase(), + headers: mergedHeaders, + body, + dispatcher: new Agent({ + connect: { + rejectUnauthorized: !this.selfSigned, + }, + }), + }); + } catch (error) { + throw new AppwriteException((error as Error).message); + } - if (path !== '/account' && json.code === 401 && json.type === 'user_more_factors_required') { - console.log(`${chalk.cyan.bold('ℹ Info')} ${chalk.cyan('Unusable account found, removing...')}`); + if (response.status >= 400) { + const text = await response.text(); + let json: { message?: string; code?: number; type?: string } | undefined = + undefined; + try { + json = JSON.parse(text); + } catch (error) { + throw new AppwriteException(text, response.status, "", text); + } - const current = globalConfig.getCurrentSession(); - globalConfig.setCurrentSession(''); - globalConfig.removeSession(current); - } - throw new AppwriteException(json.message || text, json.code, json.type, text); - } + if ( + path !== "/account" && + json.code === 401 && + json.type === "user_more_factors_required" + ) { + console.log( + `${chalk.cyan.bold("ℹ Info")} ${chalk.cyan("Unusable account found, removing...")}`, + ); - if (responseType === 'arraybuffer') { - const data = await response.arrayBuffer(); - return data as T; - } + const current = globalConfig.getCurrentSession(); + globalConfig.setCurrentSession(""); + globalConfig.removeSession(current); + } + throw new AppwriteException( + json.message || text, + json.code, + json.type, + text, + ); + } - const cookies = response.headers.getSetCookie(); - if (cookies && cookies.length > 0) { - for (const cookie of cookies) { - if (cookie.startsWith('a_session_console=')) { - globalConfig.setCookie(cookie); - } - } - } + if (responseType === "arraybuffer") { + const data = await response.arrayBuffer(); + return data as T; + } - const text = await response.text(); - let json: T | undefined = undefined; - try { - json = JSONBigInt.parse(text); - } catch (error) { - return text as T; + const cookies = response.headers.getSetCookie(); + if (cookies && cookies.length > 0) { + for (const cookie of cookies) { + if (cookie.startsWith("a_session_console=")) { + globalConfig.setCookie(cookie); } - return json as T; + } } - static flatten(data: RequestParams, prefix: string = ''): Record { - let output: Record = {}; + const text = await response.text(); + let json: T | undefined = undefined; + try { + json = JSONBigInt.parse(text); + } catch (error) { + return text as T; + } + return json as T; + } - for (const key in data) { - const value = data[key]; - const finalKey = prefix ? prefix + '[' + key + ']' : key; + static flatten( + data: RequestParams, + prefix: string = "", + ): Record { + let output: Record = {}; - if (Array.isArray(value)) { - output = { ...output, ...Client.flatten(value as unknown as RequestParams, finalKey) }; - } else { - output[finalKey] = value; - } - } + for (const key in data) { + const value = data[key]; + const finalKey = prefix ? prefix + "[" + key + "]" : key; - return output; + if (Array.isArray(value)) { + output = { + ...output, + ...Client.flatten(value as unknown as RequestParams, finalKey), + }; + } else { + output[finalKey] = value; + } } + + return output; + } } -export = Client; +export default Client; diff --git a/lib/commands/account.ts b/lib/commands/account.ts deleted file mode 100644 index 98a88fd3..00000000 --- a/lib/commands/account.ts +++ /dev/null @@ -1,1867 +0,0 @@ -import fs = require('fs'); -import pathLib = require('path'); -import tar = require('tar'); -import ignore = require('ignore'); -import { promisify } from 'util'; -import Client from '../client'; -import { getAllFiles, showConsoleLink } from '../utils'; -import { Command } from 'commander'; -import { sdkForProject, sdkForConsole } from '../sdks'; -import { parse, actionRunner, parseInteger, parseBool, commandDescriptions, success, log, warn } from '../parser'; -import { localConfig, globalConfig } from '../config'; -import { File } from 'undici'; -import { ReadableStream } from 'stream/web'; - -function convertReadStreamToReadableStream(readStream: fs.ReadStream): ReadableStream { - return new ReadableStream({ - start(controller) { - readStream.on("data", (chunk: Buffer) => { - controller.enqueue(chunk); - }); - readStream.on("end", () => { - controller.close(); - }); - readStream.on("error", (err: Error) => { - controller.error(err); - }); - }, - cancel() { - readStream.destroy(); - }, - }); -} - -export const account = new Command("account").description(commandDescriptions['account'] ?? '').configureHelp({ - helpWidth: process.stdout.columns || 80 -}) - -interface AccountGetRequestParams { - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; - console?: boolean; -} - -export const accountGet = async ({parseOutput = true, overrideForCli = false, sdk = undefined, console: showConsole}: AccountGetRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/account'; - let payload = {}; - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - if(showConsole) { - showConsoleLink('account', 'get'); - } else { - parse(response) - } - } - - return response; - -} -interface AccountCreateRequestParams { - userId: string; - email: string; - password: string; - name?: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const accountCreate = async ({userId,email,password,name,parseOutput = true, overrideForCli = false, sdk = undefined}: AccountCreateRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/account'; - let payload = {}; - if (typeof userId !== 'undefined') { - payload['userId'] = userId; - } - if (typeof email !== 'undefined') { - payload['email'] = email; - } - if (typeof password !== 'undefined') { - payload['password'] = password; - } - if (typeof name !== 'undefined') { - payload['name'] = name; - } - - let response = undefined; - - response = await client.call('post', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface AccountDeleteRequestParams { - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const accountDelete = async ({parseOutput = true, overrideForCli = false, sdk = undefined}: AccountDeleteRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/account'; - let payload = {}; - - let response = undefined; - - response = await client.call('delete', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface AccountUpdateEmailRequestParams { - email: string; - password: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const accountUpdateEmail = async ({email,password,parseOutput = true, overrideForCli = false, sdk = undefined}: AccountUpdateEmailRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/account/email'; - let payload = {}; - if (typeof email !== 'undefined') { - payload['email'] = email; - } - if (typeof password !== 'undefined') { - payload['password'] = password; - } - - let response = undefined; - - response = await client.call('patch', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface AccountListIdentitiesRequestParams { - queries?: string[]; - total?: boolean; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const accountListIdentities = async ({queries,total,parseOutput = true, overrideForCli = false, sdk = undefined}: AccountListIdentitiesRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/account/identities'; - let payload = {}; - if (typeof queries !== 'undefined') { - payload['queries'] = queries; - } - if (typeof total !== 'undefined') { - payload['total'] = total; - } - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface AccountDeleteIdentityRequestParams { - identityId: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const accountDeleteIdentity = async ({identityId,parseOutput = true, overrideForCli = false, sdk = undefined}: AccountDeleteIdentityRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/account/identities/{identityId}'.replace('{identityId}', identityId); - let payload = {}; - - let response = undefined; - - response = await client.call('delete', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface AccountCreateJWTRequestParams { - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const accountCreateJWT = async ({parseOutput = true, overrideForCli = false, sdk = undefined}: AccountCreateJWTRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/account/jwts'; - let payload = {}; - - let response = undefined; - - response = await client.call('post', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface AccountListLogsRequestParams { - queries?: string[]; - total?: boolean; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const accountListLogs = async ({queries,total,parseOutput = true, overrideForCli = false, sdk = undefined}: AccountListLogsRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/account/logs'; - let payload = {}; - if (typeof queries !== 'undefined') { - payload['queries'] = queries; - } - if (typeof total !== 'undefined') { - payload['total'] = total; - } - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface AccountUpdateMFARequestParams { - mfa: boolean; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const accountUpdateMFA = async ({mfa,parseOutput = true, overrideForCli = false, sdk = undefined}: AccountUpdateMFARequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/account/mfa'; - let payload = {}; - if (typeof mfa !== 'undefined') { - payload['mfa'] = mfa; - } - - let response = undefined; - - response = await client.call('patch', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface AccountCreateMFAAuthenticatorRequestParams { - type: AuthenticatorType; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const accountCreateMFAAuthenticator = async ({type,parseOutput = true, overrideForCli = false, sdk = undefined}: AccountCreateMFAAuthenticatorRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/account/mfa/authenticators/{type}'.replace('{type}', type); - let payload = {}; - - let response = undefined; - - response = await client.call('post', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface AccountUpdateMFAAuthenticatorRequestParams { - type: AuthenticatorType; - otp: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const accountUpdateMFAAuthenticator = async ({type,otp,parseOutput = true, overrideForCli = false, sdk = undefined}: AccountUpdateMFAAuthenticatorRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/account/mfa/authenticators/{type}'.replace('{type}', type); - let payload = {}; - if (typeof otp !== 'undefined') { - payload['otp'] = otp; - } - - let response = undefined; - - response = await client.call('put', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface AccountDeleteMFAAuthenticatorRequestParams { - type: AuthenticatorType; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const accountDeleteMFAAuthenticator = async ({type,parseOutput = true, overrideForCli = false, sdk = undefined}: AccountDeleteMFAAuthenticatorRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/account/mfa/authenticators/{type}'.replace('{type}', type); - let payload = {}; - - let response = undefined; - - response = await client.call('delete', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface AccountCreateMFAChallengeRequestParams { - factor: AuthenticationFactor; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const accountCreateMFAChallenge = async ({factor,parseOutput = true, overrideForCli = false, sdk = undefined}: AccountCreateMFAChallengeRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/account/mfa/challenges'; - let payload = {}; - if (typeof factor !== 'undefined') { - payload['factor'] = factor; - } - - let response = undefined; - - response = await client.call('post', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface AccountUpdateMFAChallengeRequestParams { - challengeId: string; - otp: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const accountUpdateMFAChallenge = async ({challengeId,otp,parseOutput = true, overrideForCli = false, sdk = undefined}: AccountUpdateMFAChallengeRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/account/mfa/challenges'; - let payload = {}; - if (typeof challengeId !== 'undefined') { - payload['challengeId'] = challengeId; - } - if (typeof otp !== 'undefined') { - payload['otp'] = otp; - } - - let response = undefined; - - response = await client.call('put', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface AccountListMFAFactorsRequestParams { - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const accountListMFAFactors = async ({parseOutput = true, overrideForCli = false, sdk = undefined}: AccountListMFAFactorsRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/account/mfa/factors'; - let payload = {}; - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface AccountGetMFARecoveryCodesRequestParams { - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const accountGetMFARecoveryCodes = async ({parseOutput = true, overrideForCli = false, sdk = undefined}: AccountGetMFARecoveryCodesRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/account/mfa/recovery-codes'; - let payload = {}; - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface AccountCreateMFARecoveryCodesRequestParams { - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const accountCreateMFARecoveryCodes = async ({parseOutput = true, overrideForCli = false, sdk = undefined}: AccountCreateMFARecoveryCodesRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/account/mfa/recovery-codes'; - let payload = {}; - - let response = undefined; - - response = await client.call('post', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface AccountUpdateMFARecoveryCodesRequestParams { - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const accountUpdateMFARecoveryCodes = async ({parseOutput = true, overrideForCli = false, sdk = undefined}: AccountUpdateMFARecoveryCodesRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/account/mfa/recovery-codes'; - let payload = {}; - - let response = undefined; - - response = await client.call('patch', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface AccountUpdateNameRequestParams { - name: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const accountUpdateName = async ({name,parseOutput = true, overrideForCli = false, sdk = undefined}: AccountUpdateNameRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/account/name'; - let payload = {}; - if (typeof name !== 'undefined') { - payload['name'] = name; - } - - let response = undefined; - - response = await client.call('patch', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface AccountUpdatePasswordRequestParams { - password: string; - oldPassword?: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const accountUpdatePassword = async ({password,oldPassword,parseOutput = true, overrideForCli = false, sdk = undefined}: AccountUpdatePasswordRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/account/password'; - let payload = {}; - if (typeof password !== 'undefined') { - payload['password'] = password; - } - if (typeof oldPassword !== 'undefined') { - payload['oldPassword'] = oldPassword; - } - - let response = undefined; - - response = await client.call('patch', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface AccountUpdatePhoneRequestParams { - phone: string; - password: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const accountUpdatePhone = async ({phone,password,parseOutput = true, overrideForCli = false, sdk = undefined}: AccountUpdatePhoneRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/account/phone'; - let payload = {}; - if (typeof phone !== 'undefined') { - payload['phone'] = phone; - } - if (typeof password !== 'undefined') { - payload['password'] = password; - } - - let response = undefined; - - response = await client.call('patch', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface AccountGetPrefsRequestParams { - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const accountGetPrefs = async ({parseOutput = true, overrideForCli = false, sdk = undefined}: AccountGetPrefsRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/account/prefs'; - let payload = {}; - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface AccountUpdatePrefsRequestParams { - prefs: object; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const accountUpdatePrefs = async ({prefs,parseOutput = true, overrideForCli = false, sdk = undefined}: AccountUpdatePrefsRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/account/prefs'; - let payload = {}; - if (typeof prefs !== 'undefined') { - payload['prefs'] = JSON.parse(prefs); - } - - let response = undefined; - - response = await client.call('patch', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface AccountCreateRecoveryRequestParams { - email: string; - url: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const accountCreateRecovery = async ({email,url,parseOutput = true, overrideForCli = false, sdk = undefined}: AccountCreateRecoveryRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/account/recovery'; - let payload = {}; - if (typeof email !== 'undefined') { - payload['email'] = email; - } - if (typeof url !== 'undefined') { - payload['url'] = url; - } - - let response = undefined; - - response = await client.call('post', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface AccountUpdateRecoveryRequestParams { - userId: string; - secret: string; - password: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const accountUpdateRecovery = async ({userId,secret,password,parseOutput = true, overrideForCli = false, sdk = undefined}: AccountUpdateRecoveryRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/account/recovery'; - let payload = {}; - if (typeof userId !== 'undefined') { - payload['userId'] = userId; - } - if (typeof secret !== 'undefined') { - payload['secret'] = secret; - } - if (typeof password !== 'undefined') { - payload['password'] = password; - } - - let response = undefined; - - response = await client.call('put', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface AccountListSessionsRequestParams { - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; - console?: boolean; -} - -export const accountListSessions = async ({parseOutput = true, overrideForCli = false, sdk = undefined, console: showConsole}: AccountListSessionsRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/account/sessions'; - let payload = {}; - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - if(showConsole) { - showConsoleLink('account', 'listSessions'); - } else { - parse(response) - } - } - - return response; - -} -interface AccountDeleteSessionsRequestParams { - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const accountDeleteSessions = async ({parseOutput = true, overrideForCli = false, sdk = undefined}: AccountDeleteSessionsRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/account/sessions'; - let payload = {}; - - let response = undefined; - - response = await client.call('delete', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface AccountCreateAnonymousSessionRequestParams { - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const accountCreateAnonymousSession = async ({parseOutput = true, overrideForCli = false, sdk = undefined}: AccountCreateAnonymousSessionRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/account/sessions/anonymous'; - let payload = {}; - - let response = undefined; - - response = await client.call('post', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface AccountCreateEmailPasswordSessionRequestParams { - email: string; - password: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const accountCreateEmailPasswordSession = async ({email,password,parseOutput = true, overrideForCli = false, sdk = undefined}: AccountCreateEmailPasswordSessionRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/account/sessions/email'; - let payload = {}; - if (typeof email !== 'undefined') { - payload['email'] = email; - } - if (typeof password !== 'undefined') { - payload['password'] = password; - } - - let response = undefined; - - response = await client.call('post', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface AccountUpdateMagicURLSessionRequestParams { - userId: string; - secret: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const accountUpdateMagicURLSession = async ({userId,secret,parseOutput = true, overrideForCli = false, sdk = undefined}: AccountUpdateMagicURLSessionRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/account/sessions/magic-url'; - let payload = {}; - if (typeof userId !== 'undefined') { - payload['userId'] = userId; - } - if (typeof secret !== 'undefined') { - payload['secret'] = secret; - } - - let response = undefined; - - response = await client.call('put', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface AccountCreateOAuth2SessionRequestParams { - provider: OAuthProvider; - success?: string; - failure?: string; - scopes?: string[]; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const accountCreateOAuth2Session = async ({provider,success,failure,scopes,parseOutput = true, overrideForCli = false, sdk = undefined}: AccountCreateOAuth2SessionRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/account/sessions/oauth2/{provider}'.replace('{provider}', provider); - let payload = {}; - if (typeof success !== 'undefined') { - payload['success'] = success; - } - if (typeof failure !== 'undefined') { - payload['failure'] = failure; - } - if (typeof scopes !== 'undefined') { - payload['scopes'] = scopes; - } - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface AccountUpdatePhoneSessionRequestParams { - userId: string; - secret: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const accountUpdatePhoneSession = async ({userId,secret,parseOutput = true, overrideForCli = false, sdk = undefined}: AccountUpdatePhoneSessionRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/account/sessions/phone'; - let payload = {}; - if (typeof userId !== 'undefined') { - payload['userId'] = userId; - } - if (typeof secret !== 'undefined') { - payload['secret'] = secret; - } - - let response = undefined; - - response = await client.call('put', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface AccountCreateSessionRequestParams { - userId: string; - secret: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const accountCreateSession = async ({userId,secret,parseOutput = true, overrideForCli = false, sdk = undefined}: AccountCreateSessionRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/account/sessions/token'; - let payload = {}; - if (typeof userId !== 'undefined') { - payload['userId'] = userId; - } - if (typeof secret !== 'undefined') { - payload['secret'] = secret; - } - - let response = undefined; - - response = await client.call('post', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface AccountGetSessionRequestParams { - sessionId: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const accountGetSession = async ({sessionId,parseOutput = true, overrideForCli = false, sdk = undefined}: AccountGetSessionRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/account/sessions/{sessionId}'.replace('{sessionId}', sessionId); - let payload = {}; - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface AccountUpdateSessionRequestParams { - sessionId: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const accountUpdateSession = async ({sessionId,parseOutput = true, overrideForCli = false, sdk = undefined}: AccountUpdateSessionRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/account/sessions/{sessionId}'.replace('{sessionId}', sessionId); - let payload = {}; - - let response = undefined; - - response = await client.call('patch', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface AccountDeleteSessionRequestParams { - sessionId: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const accountDeleteSession = async ({sessionId,parseOutput = true, overrideForCli = false, sdk = undefined}: AccountDeleteSessionRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/account/sessions/{sessionId}'.replace('{sessionId}', sessionId); - let payload = {}; - - let response = undefined; - - response = await client.call('delete', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface AccountUpdateStatusRequestParams { - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const accountUpdateStatus = async ({parseOutput = true, overrideForCli = false, sdk = undefined}: AccountUpdateStatusRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/account/status'; - let payload = {}; - - let response = undefined; - - response = await client.call('patch', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface AccountCreatePushTargetRequestParams { - targetId: string; - identifier: string; - providerId?: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const accountCreatePushTarget = async ({targetId,identifier,providerId,parseOutput = true, overrideForCli = false, sdk = undefined}: AccountCreatePushTargetRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/account/targets/push'; - let payload = {}; - if (typeof targetId !== 'undefined') { - payload['targetId'] = targetId; - } - if (typeof identifier !== 'undefined') { - payload['identifier'] = identifier; - } - if (typeof providerId !== 'undefined') { - payload['providerId'] = providerId; - } - - let response = undefined; - - response = await client.call('post', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface AccountUpdatePushTargetRequestParams { - targetId: string; - identifier: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const accountUpdatePushTarget = async ({targetId,identifier,parseOutput = true, overrideForCli = false, sdk = undefined}: AccountUpdatePushTargetRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/account/targets/{targetId}/push'.replace('{targetId}', targetId); - let payload = {}; - if (typeof identifier !== 'undefined') { - payload['identifier'] = identifier; - } - - let response = undefined; - - response = await client.call('put', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface AccountDeletePushTargetRequestParams { - targetId: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const accountDeletePushTarget = async ({targetId,parseOutput = true, overrideForCli = false, sdk = undefined}: AccountDeletePushTargetRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/account/targets/{targetId}/push'.replace('{targetId}', targetId); - let payload = {}; - - let response = undefined; - - response = await client.call('delete', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface AccountCreateEmailTokenRequestParams { - userId: string; - email: string; - phrase?: boolean; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const accountCreateEmailToken = async ({userId,email,phrase,parseOutput = true, overrideForCli = false, sdk = undefined}: AccountCreateEmailTokenRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/account/tokens/email'; - let payload = {}; - if (typeof userId !== 'undefined') { - payload['userId'] = userId; - } - if (typeof email !== 'undefined') { - payload['email'] = email; - } - if (typeof phrase !== 'undefined') { - payload['phrase'] = phrase; - } - - let response = undefined; - - response = await client.call('post', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface AccountCreateMagicURLTokenRequestParams { - userId: string; - email: string; - url?: string; - phrase?: boolean; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const accountCreateMagicURLToken = async ({userId,email,url,phrase,parseOutput = true, overrideForCli = false, sdk = undefined}: AccountCreateMagicURLTokenRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/account/tokens/magic-url'; - let payload = {}; - if (typeof userId !== 'undefined') { - payload['userId'] = userId; - } - if (typeof email !== 'undefined') { - payload['email'] = email; - } - if (typeof url !== 'undefined') { - payload['url'] = url; - } - if (typeof phrase !== 'undefined') { - payload['phrase'] = phrase; - } - - let response = undefined; - - response = await client.call('post', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface AccountCreateOAuth2TokenRequestParams { - provider: OAuthProvider; - success?: string; - failure?: string; - scopes?: string[]; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const accountCreateOAuth2Token = async ({provider,success,failure,scopes,parseOutput = true, overrideForCli = false, sdk = undefined}: AccountCreateOAuth2TokenRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/account/tokens/oauth2/{provider}'.replace('{provider}', provider); - let payload = {}; - if (typeof success !== 'undefined') { - payload['success'] = success; - } - if (typeof failure !== 'undefined') { - payload['failure'] = failure; - } - if (typeof scopes !== 'undefined') { - payload['scopes'] = scopes; - } - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface AccountCreatePhoneTokenRequestParams { - userId: string; - phone: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const accountCreatePhoneToken = async ({userId,phone,parseOutput = true, overrideForCli = false, sdk = undefined}: AccountCreatePhoneTokenRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/account/tokens/phone'; - let payload = {}; - if (typeof userId !== 'undefined') { - payload['userId'] = userId; - } - if (typeof phone !== 'undefined') { - payload['phone'] = phone; - } - - let response = undefined; - - response = await client.call('post', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface AccountCreateEmailVerificationRequestParams { - url: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const accountCreateEmailVerification = async ({url,parseOutput = true, overrideForCli = false, sdk = undefined}: AccountCreateEmailVerificationRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/account/verifications/email'; - let payload = {}; - if (typeof url !== 'undefined') { - payload['url'] = url; - } - - let response = undefined; - - response = await client.call('post', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface AccountCreateVerificationRequestParams { - url: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const accountCreateVerification = async ({url,parseOutput = true, overrideForCli = false, sdk = undefined}: AccountCreateVerificationRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/account/verifications/email'; - let payload = {}; - if (typeof url !== 'undefined') { - payload['url'] = url; - } - - let response = undefined; - - response = await client.call('post', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface AccountUpdateEmailVerificationRequestParams { - userId: string; - secret: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const accountUpdateEmailVerification = async ({userId,secret,parseOutput = true, overrideForCli = false, sdk = undefined}: AccountUpdateEmailVerificationRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/account/verifications/email'; - let payload = {}; - if (typeof userId !== 'undefined') { - payload['userId'] = userId; - } - if (typeof secret !== 'undefined') { - payload['secret'] = secret; - } - - let response = undefined; - - response = await client.call('put', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface AccountUpdateVerificationRequestParams { - userId: string; - secret: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const accountUpdateVerification = async ({userId,secret,parseOutput = true, overrideForCli = false, sdk = undefined}: AccountUpdateVerificationRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/account/verifications/email'; - let payload = {}; - if (typeof userId !== 'undefined') { - payload['userId'] = userId; - } - if (typeof secret !== 'undefined') { - payload['secret'] = secret; - } - - let response = undefined; - - response = await client.call('put', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface AccountCreatePhoneVerificationRequestParams { - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const accountCreatePhoneVerification = async ({parseOutput = true, overrideForCli = false, sdk = undefined}: AccountCreatePhoneVerificationRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/account/verifications/phone'; - let payload = {}; - - let response = undefined; - - response = await client.call('post', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface AccountUpdatePhoneVerificationRequestParams { - userId: string; - secret: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const accountUpdatePhoneVerification = async ({userId,secret,parseOutput = true, overrideForCli = false, sdk = undefined}: AccountUpdatePhoneVerificationRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/account/verifications/phone'; - let payload = {}; - if (typeof userId !== 'undefined') { - payload['userId'] = userId; - } - if (typeof secret !== 'undefined') { - payload['secret'] = secret; - } - - let response = undefined; - - response = await client.call('put', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -account - .command(`get`) - .description(`Get the currently logged in user.`) - .option(`--console`, `Get the resource console url`) - .action(actionRunner(accountGet)) - -account - .command(`create`) - .description(`Use this endpoint to allow a new user to register a new account in your project. After the user registration completes successfully, you can use the [/account/verfication](https://appwrite.io/docs/references/cloud/client-web/account#createVerification) route to start verifying the user email address. To allow the new user to login to their new account, you need to create a new [account session](https://appwrite.io/docs/references/cloud/client-web/account#createEmailSession).`) - .requiredOption(`--user-id `, `User ID. Choose a custom ID or generate a random ID with 'ID.unique()'. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.`) - .requiredOption(`--email `, `User email.`) - .requiredOption(`--password `, `New user password. Must be between 8 and 256 chars.`) - .option(`--name `, `User name. Max length: 128 chars.`) - .action(actionRunner(accountCreate)) - -account - .command(`delete`) - .description(`Delete the currently logged in user.`) - .action(actionRunner(accountDelete)) - -account - .command(`update-email`) - .description(`Update currently logged in user account email address. After changing user address, the user confirmation status will get reset. A new confirmation email is not sent automatically however you can use the send confirmation email endpoint again to send the confirmation email. For security measures, user password is required to complete this request. This endpoint can also be used to convert an anonymous account to a normal one, by passing an email address and a new password. `) - .requiredOption(`--email `, `User email.`) - .requiredOption(`--password `, `User password. Must be at least 8 chars.`) - .action(actionRunner(accountUpdateEmail)) - -account - .command(`list-identities`) - .description(`Get the list of identities for the currently logged in user.`) - .option(`--queries [queries...]`, `Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: userId, provider, providerUid, providerEmail, providerAccessTokenExpiry`) - .option(`--total [value]`, `When set to false, the total count returned will be 0 and will not be calculated.`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .action(actionRunner(accountListIdentities)) - -account - .command(`delete-identity`) - .description(`Delete an identity by its unique ID.`) - .requiredOption(`--identity-id `, `Identity ID.`) - .action(actionRunner(accountDeleteIdentity)) - -account - .command(`create-jwt`) - .description(`Use this endpoint to create a JSON Web Token. You can use the resulting JWT to authenticate on behalf of the current user when working with the Appwrite server-side API and SDKs. The JWT secret is valid for 15 minutes from its creation and will be invalid if the user will logout in that time frame.`) - .action(actionRunner(accountCreateJWT)) - -account - .command(`list-logs`) - .description(`Get the list of latest security activity logs for the currently logged in user. Each log returns user IP address, location and date and time of log.`) - .option(`--queries [queries...]`, `Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Only supported methods are limit and offset`) - .option(`--total [value]`, `When set to false, the total count returned will be 0 and will not be calculated.`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .action(actionRunner(accountListLogs)) - -account - .command(`update-mfa`) - .description(`Enable or disable MFA on an account.`) - .requiredOption(`--mfa [value]`, `Enable or disable MFA.`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .action(actionRunner(accountUpdateMFA)) - -account - .command(`create-mfa-authenticator`) - .description(`Add an authenticator app to be used as an MFA factor. Verify the authenticator using the [verify authenticator](/docs/references/cloud/client-web/account#updateMfaAuthenticator) method.`) - .requiredOption(`--type `, `Type of authenticator. Must be 'totp'`) - .action(actionRunner(accountCreateMFAAuthenticator)) - -account - .command(`update-mfa-authenticator`) - .description(`Verify an authenticator app after adding it using the [add authenticator](/docs/references/cloud/client-web/account#createMfaAuthenticator) method.`) - .requiredOption(`--type `, `Type of authenticator.`) - .requiredOption(`--otp `, `Valid verification token.`) - .action(actionRunner(accountUpdateMFAAuthenticator)) - -account - .command(`delete-mfa-authenticator`) - .description(`Delete an authenticator for a user by ID.`) - .requiredOption(`--type `, `Type of authenticator.`) - .action(actionRunner(accountDeleteMFAAuthenticator)) - -account - .command(`create-mfa-challenge`) - .description(`Begin the process of MFA verification after sign-in. Finish the flow with [updateMfaChallenge](/docs/references/cloud/client-web/account#updateMfaChallenge) method.`) - .requiredOption(`--factor `, `Factor used for verification. Must be one of following: 'email', 'phone', 'totp', 'recoveryCode'.`) - .action(actionRunner(accountCreateMFAChallenge)) - -account - .command(`update-mfa-challenge`) - .description(`Complete the MFA challenge by providing the one-time password. Finish the process of MFA verification by providing the one-time password. To begin the flow, use [createMfaChallenge](/docs/references/cloud/client-web/account#createMfaChallenge) method.`) - .requiredOption(`--challenge-id `, `ID of the challenge.`) - .requiredOption(`--otp `, `Valid verification token.`) - .action(actionRunner(accountUpdateMFAChallenge)) - -account - .command(`list-mfa-factors`) - .description(`List the factors available on the account to be used as a MFA challange.`) - .action(actionRunner(accountListMFAFactors)) - -account - .command(`get-mfa-recovery-codes`) - .description(`Get recovery codes that can be used as backup for MFA flow. Before getting codes, they must be generated using [createMfaRecoveryCodes](/docs/references/cloud/client-web/account#createMfaRecoveryCodes) method. An OTP challenge is required to read recovery codes.`) - .action(actionRunner(accountGetMFARecoveryCodes)) - -account - .command(`create-mfa-recovery-codes`) - .description(`Generate recovery codes as backup for MFA flow. It's recommended to generate and show then immediately after user successfully adds their authehticator. Recovery codes can be used as a MFA verification type in [createMfaChallenge](/docs/references/cloud/client-web/account#createMfaChallenge) method.`) - .action(actionRunner(accountCreateMFARecoveryCodes)) - -account - .command(`update-mfa-recovery-codes`) - .description(`Regenerate recovery codes that can be used as backup for MFA flow. Before regenerating codes, they must be first generated using [createMfaRecoveryCodes](/docs/references/cloud/client-web/account#createMfaRecoveryCodes) method. An OTP challenge is required to regenreate recovery codes.`) - .action(actionRunner(accountUpdateMFARecoveryCodes)) - -account - .command(`update-name`) - .description(`Update currently logged in user account name.`) - .requiredOption(`--name `, `User name. Max length: 128 chars.`) - .action(actionRunner(accountUpdateName)) - -account - .command(`update-password`) - .description(`Update currently logged in user password. For validation, user is required to pass in the new password, and the old password. For users created with OAuth, Team Invites and Magic URL, oldPassword is optional.`) - .requiredOption(`--password `, `New user password. Must be at least 8 chars.`) - .option(`--old-password `, `Current user password. Must be at least 8 chars.`) - .action(actionRunner(accountUpdatePassword)) - -account - .command(`update-phone`) - .description(`Update the currently logged in user's phone number. After updating the phone number, the phone verification status will be reset. A confirmation SMS is not sent automatically, however you can use the [POST /account/verification/phone](https://appwrite.io/docs/references/cloud/client-web/account#createPhoneVerification) endpoint to send a confirmation SMS.`) - .requiredOption(`--phone `, `Phone number. Format this number with a leading '+' and a country code, e.g., +16175551212.`) - .requiredOption(`--password `, `User password. Must be at least 8 chars.`) - .action(actionRunner(accountUpdatePhone)) - -account - .command(`get-prefs`) - .description(`Get the preferences as a key-value object for the currently logged in user.`) - .action(actionRunner(accountGetPrefs)) - -account - .command(`update-prefs`) - .description(`Update currently logged in user account preferences. The object you pass is stored as is, and replaces any previous value. The maximum allowed prefs size is 64kB and throws error if exceeded.`) - .requiredOption(`--prefs `, `Prefs key-value JSON object.`) - .action(actionRunner(accountUpdatePrefs)) - -account - .command(`create-recovery`) - .description(`Sends the user an email with a temporary secret key for password reset. When the user clicks the confirmation link he is redirected back to your app password reset URL with the secret key and email address values attached to the URL query string. Use the query string params to submit a request to the [PUT /account/recovery](https://appwrite.io/docs/references/cloud/client-web/account#updateRecovery) endpoint to complete the process. The verification link sent to the user's email address is valid for 1 hour.`) - .requiredOption(`--email `, `User email.`) - .requiredOption(`--url `, `URL to redirect the user back to your app from the recovery email. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.`) - .action(actionRunner(accountCreateRecovery)) - -account - .command(`update-recovery`) - .description(`Use this endpoint to complete the user account password reset. Both the **userId** and **secret** arguments will be passed as query parameters to the redirect URL you have provided when sending your request to the [POST /account/recovery](https://appwrite.io/docs/references/cloud/client-web/account#createRecovery) endpoint. Please note that in order to avoid a [Redirect Attack](https://github.com/OWASP/CheatSheetSeries/blob/master/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.md) the only valid redirect URLs are the ones from domains you have set when adding your platforms in the console interface.`) - .requiredOption(`--user-id `, `User ID.`) - .requiredOption(`--secret `, `Valid reset token.`) - .requiredOption(`--password `, `New user password. Must be between 8 and 256 chars.`) - .action(actionRunner(accountUpdateRecovery)) - -account - .command(`list-sessions`) - .description(`Get the list of active sessions across different devices for the currently logged in user.`) - .option(`--console`, `Get the resource console url`) - .action(actionRunner(accountListSessions)) - -account - .command(`delete-sessions`) - .description(`Delete all sessions from the user account and remove any sessions cookies from the end client.`) - .action(actionRunner(accountDeleteSessions)) - -account - .command(`create-anonymous-session`) - .description(`Use this endpoint to allow a new user to register an anonymous account in your project. This route will also create a new session for the user. To allow the new user to convert an anonymous account to a normal account, you need to update its [email and password](https://appwrite.io/docs/references/cloud/client-web/account#updateEmail) or create an [OAuth2 session](https://appwrite.io/docs/references/cloud/client-web/account#CreateOAuth2Session).`) - .action(actionRunner(accountCreateAnonymousSession)) - -account - .command(`create-email-password-session`) - .description(`Allow the user to login into their account by providing a valid email and password combination. This route will create a new session for the user. A user is limited to 10 active sessions at a time by default. [Learn more about session limits](https://appwrite.io/docs/authentication-security#limits).`) - .requiredOption(`--email `, `User email.`) - .requiredOption(`--password `, `User password. Must be at least 8 chars.`) - .action(actionRunner(accountCreateEmailPasswordSession)) - -account - .command(`update-magic-url-session`) - .description(`[**DEPRECATED** - This command is deprecated. Please use 'account create-session' instead] Use this endpoint to create a session from token. Provide the **userId** and **secret** parameters from the successful response of authentication flows initiated by token creation. For example, magic URL and phone login.`) - .requiredOption(`--user-id `, `User ID. Choose a custom ID or generate a random ID with 'ID.unique()'. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.`) - .requiredOption(`--secret `, `Valid verification token.`) - .action(actionRunner(accountUpdateMagicURLSession)) - -account - .command(`create-o-auth-2-session`) - .description(`Allow the user to login to their account using the OAuth2 provider of their choice. Each OAuth2 provider should be enabled from the Appwrite console first. Use the success and failure arguments to provide a redirect URL's back to your app when login is completed. If there is already an active session, the new session will be attached to the logged-in account. If there are no active sessions, the server will attempt to look for a user with the same email address as the email received from the OAuth2 provider and attach the new session to the existing user. If no matching user is found - the server will create a new user. A user is limited to 10 active sessions at a time by default. [Learn more about session limits](https://appwrite.io/docs/authentication-security#limits). `) - .requiredOption(`--provider `, `OAuth2 Provider. Currently, supported providers are: amazon, apple, auth0, authentik, autodesk, bitbucket, bitly, box, dailymotion, discord, disqus, dropbox, etsy, facebook, figma, github, gitlab, google, linkedin, microsoft, notion, oidc, okta, paypal, paypalSandbox, podio, salesforce, slack, spotify, stripe, tradeshift, tradeshiftBox, twitch, wordpress, yahoo, yammer, yandex, zoho, zoom.`) - .option(`--success `, `URL to redirect back to your app after a successful login attempt. Only URLs from hostnames in your project's platform list are allowed. This requirement helps to prevent an [open redirect](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.`) - .option(`--failure `, `URL to redirect back to your app after a failed login attempt. Only URLs from hostnames in your project's platform list are allowed. This requirement helps to prevent an [open redirect](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.`) - .option(`--scopes [scopes...]`, `A list of custom OAuth2 scopes. Check each provider internal docs for a list of supported scopes. Maximum of 100 scopes are allowed, each 4096 characters long.`) - .action(actionRunner(accountCreateOAuth2Session)) - -account - .command(`update-phone-session`) - .description(`[**DEPRECATED** - This command is deprecated. Please use 'account create-session' instead] Use this endpoint to create a session from token. Provide the **userId** and **secret** parameters from the successful response of authentication flows initiated by token creation. For example, magic URL and phone login.`) - .requiredOption(`--user-id `, `User ID. Choose a custom ID or generate a random ID with 'ID.unique()'. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.`) - .requiredOption(`--secret `, `Valid verification token.`) - .action(actionRunner(accountUpdatePhoneSession)) - -account - .command(`create-session`) - .description(`Use this endpoint to create a session from token. Provide the **userId** and **secret** parameters from the successful response of authentication flows initiated by token creation. For example, magic URL and phone login.`) - .requiredOption(`--user-id `, `User ID. Choose a custom ID or generate a random ID with 'ID.unique()'. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.`) - .requiredOption(`--secret `, `Secret of a token generated by login methods. For example, the 'createMagicURLToken' or 'createPhoneToken' methods.`) - .action(actionRunner(accountCreateSession)) - -account - .command(`get-session`) - .description(`Use this endpoint to get a logged in user's session using a Session ID. Inputting 'current' will return the current session being used.`) - .requiredOption(`--session-id `, `Session ID. Use the string 'current' to get the current device session.`) - .action(actionRunner(accountGetSession)) - -account - .command(`update-session`) - .description(`Use this endpoint to extend a session's length. Extending a session is useful when session expiry is short. If the session was created using an OAuth provider, this endpoint refreshes the access token from the provider.`) - .requiredOption(`--session-id `, `Session ID. Use the string 'current' to update the current device session.`) - .action(actionRunner(accountUpdateSession)) - -account - .command(`delete-session`) - .description(`Logout the user. Use 'current' as the session ID to logout on this device, use a session ID to logout on another device. If you're looking to logout the user on all devices, use [Delete Sessions](https://appwrite.io/docs/references/cloud/client-web/account#deleteSessions) instead.`) - .requiredOption(`--session-id `, `Session ID. Use the string 'current' to delete the current device session.`) - .action(actionRunner(accountDeleteSession)) - -account - .command(`update-status`) - .description(`Block the currently logged in user account. Behind the scene, the user record is not deleted but permanently blocked from any access. To completely delete a user, use the Users API instead.`) - .action(actionRunner(accountUpdateStatus)) - -account - .command(`create-push-target`) - .description(`Use this endpoint to register a device for push notifications. Provide a target ID (custom or generated using ID.unique()), a device identifier (usually a device token), and optionally specify which provider should send notifications to this target. The target is automatically linked to the current session and includes device information like brand and model.`) - .requiredOption(`--target-id `, `Target ID. Choose a custom ID or generate a random ID with 'ID.unique()'. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.`) - .requiredOption(`--identifier `, `The target identifier (token, email, phone etc.)`) - .option(`--provider-id `, `Provider ID. Message will be sent to this target from the specified provider ID. If no provider ID is set the first setup provider will be used.`) - .action(actionRunner(accountCreatePushTarget)) - -account - .command(`update-push-target`) - .description(`Update the currently logged in user's push notification target. You can modify the target's identifier (device token) and provider ID (token, email, phone etc.). The target must exist and belong to the current user. If you change the provider ID, notifications will be sent through the new messaging provider instead.`) - .requiredOption(`--target-id `, `Target ID.`) - .requiredOption(`--identifier `, `The target identifier (token, email, phone etc.)`) - .action(actionRunner(accountUpdatePushTarget)) - -account - .command(`delete-push-target`) - .description(`Delete a push notification target for the currently logged in user. After deletion, the device will no longer receive push notifications. The target must exist and belong to the current user.`) - .requiredOption(`--target-id `, `Target ID.`) - .action(actionRunner(accountDeletePushTarget)) - -account - .command(`create-email-token`) - .description(`Sends the user an email with a secret key for creating a session. If the email address has never been used, a **new account is created** using the provided 'userId'. Otherwise, if the email address is already attached to an account, the **user ID is ignored**. Then, the user will receive an email with the one-time password. Use the returned user ID and secret and submit a request to the [POST /v1/account/sessions/token](https://appwrite.io/docs/references/cloud/client-web/account#createSession) endpoint to complete the login process. The secret sent to the user's email is valid for 15 minutes. A user is limited to 10 active sessions at a time by default. [Learn more about session limits](https://appwrite.io/docs/authentication-security#limits). `) - .requiredOption(`--user-id `, `User ID. Choose a custom ID or generate a random ID with 'ID.unique()'. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars. If the email address has never been used, a new account is created using the provided userId. Otherwise, if the email address is already attached to an account, the user ID is ignored.`) - .requiredOption(`--email `, `User email.`) - .option(`--phrase [value]`, `Toggle for security phrase. If enabled, email will be send with a randomly generated phrase and the phrase will also be included in the response. Confirming phrases match increases the security of your authentication flow.`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .action(actionRunner(accountCreateEmailToken)) - -account - .command(`create-magic-url-token`) - .description(`Sends the user an email with a secret key for creating a session. If the provided user ID has not been registered, a new user will be created. When the user clicks the link in the email, the user is redirected back to the URL you provided with the secret key and userId values attached to the URL query string. Use the query string parameters to submit a request to the [POST /v1/account/sessions/token](https://appwrite.io/docs/references/cloud/client-web/account#createSession) endpoint to complete the login process. The link sent to the user's email address is valid for 1 hour. A user is limited to 10 active sessions at a time by default. [Learn more about session limits](https://appwrite.io/docs/authentication-security#limits). `) - .requiredOption(`--user-id `, `Unique Id. Choose a custom ID or generate a random ID with 'ID.unique()'. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars. If the email address has never been used, a new account is created using the provided userId. Otherwise, if the email address is already attached to an account, the user ID is ignored.`) - .requiredOption(`--email `, `User email.`) - .option(`--url `, `URL to redirect the user back to your app from the magic URL login. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.`) - .option(`--phrase [value]`, `Toggle for security phrase. If enabled, email will be send with a randomly generated phrase and the phrase will also be included in the response. Confirming phrases match increases the security of your authentication flow.`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .action(actionRunner(accountCreateMagicURLToken)) - -account - .command(`create-o-auth-2-token`) - .description(`Allow the user to login to their account using the OAuth2 provider of their choice. Each OAuth2 provider should be enabled from the Appwrite console first. Use the success and failure arguments to provide a redirect URL's back to your app when login is completed. If authentication succeeds, 'userId' and 'secret' of a token will be appended to the success URL as query parameters. These can be used to create a new session using the [Create session](https://appwrite.io/docs/references/cloud/client-web/account#createSession) endpoint. A user is limited to 10 active sessions at a time by default. [Learn more about session limits](https://appwrite.io/docs/authentication-security#limits).`) - .requiredOption(`--provider `, `OAuth2 Provider. Currently, supported providers are: amazon, apple, auth0, authentik, autodesk, bitbucket, bitly, box, dailymotion, discord, disqus, dropbox, etsy, facebook, figma, github, gitlab, google, linkedin, microsoft, notion, oidc, okta, paypal, paypalSandbox, podio, salesforce, slack, spotify, stripe, tradeshift, tradeshiftBox, twitch, wordpress, yahoo, yammer, yandex, zoho, zoom.`) - .option(`--success `, `URL to redirect back to your app after a successful login attempt. Only URLs from hostnames in your project's platform list are allowed. This requirement helps to prevent an [open redirect](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.`) - .option(`--failure `, `URL to redirect back to your app after a failed login attempt. Only URLs from hostnames in your project's platform list are allowed. This requirement helps to prevent an [open redirect](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.`) - .option(`--scopes [scopes...]`, `A list of custom OAuth2 scopes. Check each provider internal docs for a list of supported scopes. Maximum of 100 scopes are allowed, each 4096 characters long.`) - .action(actionRunner(accountCreateOAuth2Token)) - -account - .command(`create-phone-token`) - .description(`Sends the user an SMS with a secret key for creating a session. If the provided user ID has not be registered, a new user will be created. Use the returned user ID and secret and submit a request to the [POST /v1/account/sessions/token](https://appwrite.io/docs/references/cloud/client-web/account#createSession) endpoint to complete the login process. The secret sent to the user's phone is valid for 15 minutes. A user is limited to 10 active sessions at a time by default. [Learn more about session limits](https://appwrite.io/docs/authentication-security#limits).`) - .requiredOption(`--user-id `, `Unique Id. Choose a custom ID or generate a random ID with 'ID.unique()'. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars. If the phone number has never been used, a new account is created using the provided userId. Otherwise, if the phone number is already attached to an account, the user ID is ignored.`) - .requiredOption(`--phone `, `Phone number. Format this number with a leading '+' and a country code, e.g., +16175551212.`) - .action(actionRunner(accountCreatePhoneToken)) - -account - .command(`create-email-verification`) - .description(`Use this endpoint to send a verification message to your user email address to confirm they are the valid owners of that address. Both the **userId** and **secret** arguments will be passed as query parameters to the URL you have provided to be attached to the verification email. The provided URL should redirect the user back to your app and allow you to complete the verification process by verifying both the **userId** and **secret** parameters. Learn more about how to [complete the verification process](https://appwrite.io/docs/references/cloud/client-web/account#updateVerification). The verification link sent to the user's email address is valid for 7 days. Please note that in order to avoid a [Redirect Attack](https://github.com/OWASP/CheatSheetSeries/blob/master/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.md), the only valid redirect URLs are the ones from domains you have set when adding your platforms in the console interface. `) - .requiredOption(`--url `, `URL to redirect the user back to your app from the verification email. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.`) - .action(actionRunner(accountCreateEmailVerification)) - -account - .command(`create-verification`) - .description(`[**DEPRECATED** - This command is deprecated. Please use 'account create-email-verification' instead] Use this endpoint to send a verification message to your user email address to confirm they are the valid owners of that address. Both the **userId** and **secret** arguments will be passed as query parameters to the URL you have provided to be attached to the verification email. The provided URL should redirect the user back to your app and allow you to complete the verification process by verifying both the **userId** and **secret** parameters. Learn more about how to [complete the verification process](https://appwrite.io/docs/references/cloud/client-web/account#updateVerification). The verification link sent to the user's email address is valid for 7 days. Please note that in order to avoid a [Redirect Attack](https://github.com/OWASP/CheatSheetSeries/blob/master/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.md), the only valid redirect URLs are the ones from domains you have set when adding your platforms in the console interface. `) - .requiredOption(`--url `, `URL to redirect the user back to your app from the verification email. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.`) - .action(actionRunner(accountCreateVerification)) - -account - .command(`update-email-verification`) - .description(`Use this endpoint to complete the user email verification process. Use both the **userId** and **secret** parameters that were attached to your app URL to verify the user email ownership. If confirmed this route will return a 200 status code.`) - .requiredOption(`--user-id `, `User ID.`) - .requiredOption(`--secret `, `Valid verification token.`) - .action(actionRunner(accountUpdateEmailVerification)) - -account - .command(`update-verification`) - .description(`[**DEPRECATED** - This command is deprecated. Please use 'account update-email-verification' instead] Use this endpoint to complete the user email verification process. Use both the **userId** and **secret** parameters that were attached to your app URL to verify the user email ownership. If confirmed this route will return a 200 status code.`) - .requiredOption(`--user-id `, `User ID.`) - .requiredOption(`--secret `, `Valid verification token.`) - .action(actionRunner(accountUpdateVerification)) - -account - .command(`create-phone-verification`) - .description(`Use this endpoint to send a verification SMS to the currently logged in user. This endpoint is meant for use after updating a user's phone number using the [accountUpdatePhone](https://appwrite.io/docs/references/cloud/client-web/account#updatePhone) endpoint. Learn more about how to [complete the verification process](https://appwrite.io/docs/references/cloud/client-web/account#updatePhoneVerification). The verification code sent to the user's phone number is valid for 15 minutes.`) - .action(actionRunner(accountCreatePhoneVerification)) - -account - .command(`update-phone-verification`) - .description(`Use this endpoint to complete the user phone verification process. Use the **userId** and **secret** that were sent to your user's phone number to verify the user email ownership. If confirmed this route will return a 200 status code.`) - .requiredOption(`--user-id `, `User ID.`) - .requiredOption(`--secret `, `Valid verification token.`) - .action(actionRunner(accountUpdatePhoneVerification)) - - diff --git a/lib/commands/console.ts b/lib/commands/console.ts deleted file mode 100644 index e9ad93c7..00000000 --- a/lib/commands/console.ts +++ /dev/null @@ -1,112 +0,0 @@ -import fs = require('fs'); -import pathLib = require('path'); -import tar = require('tar'); -import ignore = require('ignore'); -import { promisify } from 'util'; -import Client from '../client'; -import { getAllFiles, showConsoleLink } from '../utils'; -import { Command } from 'commander'; -import { sdkForProject, sdkForConsole } from '../sdks'; -import { parse, actionRunner, parseInteger, parseBool, commandDescriptions, success, log, warn } from '../parser'; -import { localConfig, globalConfig } from '../config'; -import { File } from 'undici'; -import { ReadableStream } from 'stream/web'; - -function convertReadStreamToReadableStream(readStream: fs.ReadStream): ReadableStream { - return new ReadableStream({ - start(controller) { - readStream.on("data", (chunk: Buffer) => { - controller.enqueue(chunk); - }); - readStream.on("end", () => { - controller.close(); - }); - readStream.on("error", (err: Error) => { - controller.error(err); - }); - }, - cancel() { - readStream.destroy(); - }, - }); -} - -export const console = new Command("console").description(commandDescriptions['console'] ?? '').configureHelp({ - helpWidth: process.stdout.columns || 80 -}) - -interface ConsoleGetResourceRequestParams { - value: string; - type: ConsoleResourceType; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; - console?: boolean; -} - -export const consoleGetResource = async ({value,type,parseOutput = true, overrideForCli = false, sdk = undefined, console: showConsole}: ConsoleGetResourceRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/console/resources'; - let payload = {}; - if (typeof value !== 'undefined') { - payload['value'] = value; - } - if (typeof type !== 'undefined') { - payload['type'] = type; - } - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - if(showConsole) { - showConsoleLink('console', 'getResource'); - } else { - parse(response) - } - } - - return response; - -} -interface ConsoleVariablesRequestParams { - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const consoleVariables = async ({parseOutput = true, overrideForCli = false, sdk = undefined}: ConsoleVariablesRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/console/variables'; - let payload = {}; - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -console - .command(`get-resource`) - .description(`Check if a resource ID is available.`) - .requiredOption(`--value `, `Resource value.`) - .requiredOption(`--type `, `Resource type.`) - .option(`--console`, `Get the resource console url`) - .action(actionRunner(consoleGetResource)) - -console - .command(`variables`) - .description(`Get all Environment Variables that are relevant for the console.`) - .action(actionRunner(consoleVariables)) - - diff --git a/lib/commands/databases.ts b/lib/commands/databases.ts deleted file mode 100644 index 83de0290..00000000 --- a/lib/commands/databases.ts +++ /dev/null @@ -1,3272 +0,0 @@ -import fs = require('fs'); -import pathLib = require('path'); -import tar = require('tar'); -import ignore = require('ignore'); -import { promisify } from 'util'; -import Client from '../client'; -import { getAllFiles, showConsoleLink } from '../utils'; -import { Command } from 'commander'; -import { sdkForProject, sdkForConsole } from '../sdks'; -import { parse, actionRunner, parseInteger, parseBool, commandDescriptions, success, log, warn } from '../parser'; -import { localConfig, globalConfig } from '../config'; -import { File } from 'undici'; -import { ReadableStream } from 'stream/web'; - -function convertReadStreamToReadableStream(readStream: fs.ReadStream): ReadableStream { - return new ReadableStream({ - start(controller) { - readStream.on("data", (chunk: Buffer) => { - controller.enqueue(chunk); - }); - readStream.on("end", () => { - controller.close(); - }); - readStream.on("error", (err: Error) => { - controller.error(err); - }); - }, - cancel() { - readStream.destroy(); - }, - }); -} - -export const databases = new Command("databases").description(commandDescriptions['databases'] ?? '').configureHelp({ - helpWidth: process.stdout.columns || 80 -}) - -interface DatabasesListRequestParams { - queries?: string[]; - search?: string; - total?: boolean; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; - console?: boolean; -} - -export const databasesList = async ({queries,search,total,parseOutput = true, overrideForCli = false, sdk = undefined, console: showConsole}: DatabasesListRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/databases'; - let payload = {}; - if (typeof queries !== 'undefined') { - payload['queries'] = queries; - } - if (typeof search !== 'undefined') { - payload['search'] = search; - } - if (typeof total !== 'undefined') { - payload['total'] = total; - } - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - if(showConsole) { - showConsoleLink('databases', 'list'); - } else { - parse(response) - } - } - - return response; - -} -interface DatabasesCreateRequestParams { - databaseId: string; - name: string; - enabled?: boolean; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const databasesCreate = async ({databaseId,name,enabled,parseOutput = true, overrideForCli = false, sdk = undefined}: DatabasesCreateRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/databases'; - let payload = {}; - if (typeof databaseId !== 'undefined') { - payload['databaseId'] = databaseId; - } - if (typeof name !== 'undefined') { - payload['name'] = name; - } - if (typeof enabled !== 'undefined') { - payload['enabled'] = enabled; - } - - let response = undefined; - - response = await client.call('post', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface DatabasesListTransactionsRequestParams { - queries?: string[]; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; - console?: boolean; -} - -export const databasesListTransactions = async ({queries,parseOutput = true, overrideForCli = false, sdk = undefined, console: showConsole}: DatabasesListTransactionsRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/databases/transactions'; - let payload = {}; - if (typeof queries !== 'undefined') { - payload['queries'] = queries; - } - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - if(showConsole) { - showConsoleLink('databases', 'listTransactions'); - } else { - parse(response) - } - } - - return response; - -} -interface DatabasesCreateTransactionRequestParams { - ttl?: number; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const databasesCreateTransaction = async ({ttl,parseOutput = true, overrideForCli = false, sdk = undefined}: DatabasesCreateTransactionRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/databases/transactions'; - let payload = {}; - if (typeof ttl !== 'undefined') { - payload['ttl'] = ttl; - } - - let response = undefined; - - response = await client.call('post', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface DatabasesGetTransactionRequestParams { - transactionId: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; - console?: boolean; -} - -export const databasesGetTransaction = async ({transactionId,parseOutput = true, overrideForCli = false, sdk = undefined, console: showConsole}: DatabasesGetTransactionRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/databases/transactions/{transactionId}'.replace('{transactionId}', transactionId); - let payload = {}; - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - if(showConsole) { - showConsoleLink('databases', 'getTransaction', transactionId); - } else { - parse(response) - } - } - - return response; - -} -interface DatabasesUpdateTransactionRequestParams { - transactionId: string; - commit?: boolean; - rollback?: boolean; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const databasesUpdateTransaction = async ({transactionId,commit,rollback,parseOutput = true, overrideForCli = false, sdk = undefined}: DatabasesUpdateTransactionRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/databases/transactions/{transactionId}'.replace('{transactionId}', transactionId); - let payload = {}; - if (typeof commit !== 'undefined') { - payload['commit'] = commit; - } - if (typeof rollback !== 'undefined') { - payload['rollback'] = rollback; - } - - let response = undefined; - - response = await client.call('patch', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface DatabasesDeleteTransactionRequestParams { - transactionId: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const databasesDeleteTransaction = async ({transactionId,parseOutput = true, overrideForCli = false, sdk = undefined}: DatabasesDeleteTransactionRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/databases/transactions/{transactionId}'.replace('{transactionId}', transactionId); - let payload = {}; - - let response = undefined; - - response = await client.call('delete', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface DatabasesCreateOperationsRequestParams { - transactionId: string; - operations?: object[]; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const databasesCreateOperations = async ({transactionId,operations,parseOutput = true, overrideForCli = false, sdk = undefined}: DatabasesCreateOperationsRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/databases/transactions/{transactionId}/operations'.replace('{transactionId}', transactionId); - let payload = {}; - operations = operations === true ? [] : operations; - if (typeof operations !== 'undefined') { - payload['operations'] = operations; - } - - let response = undefined; - - response = await client.call('post', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface DatabasesListUsageRequestParams { - range?: UsageRange; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; - console?: boolean; -} - -export const databasesListUsage = async ({range,parseOutput = true, overrideForCli = false, sdk = undefined, console: showConsole}: DatabasesListUsageRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/databases/usage'; - let payload = {}; - if (typeof range !== 'undefined') { - payload['range'] = range; - } - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - if(showConsole) { - showConsoleLink('databases', 'listUsage'); - } else { - parse(response) - } - } - - return response; - -} -interface DatabasesGetRequestParams { - databaseId: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; - console?: boolean; -} - -export const databasesGet = async ({databaseId,parseOutput = true, overrideForCli = false, sdk = undefined, console: showConsole}: DatabasesGetRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/databases/{databaseId}'.replace('{databaseId}', databaseId); - let payload = {}; - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - if(showConsole) { - showConsoleLink('databases', 'get', databaseId); - } else { - parse(response) - } - } - - return response; - -} -interface DatabasesUpdateRequestParams { - databaseId: string; - name: string; - enabled?: boolean; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const databasesUpdate = async ({databaseId,name,enabled,parseOutput = true, overrideForCli = false, sdk = undefined}: DatabasesUpdateRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/databases/{databaseId}'.replace('{databaseId}', databaseId); - let payload = {}; - if (typeof name !== 'undefined') { - payload['name'] = name; - } - if (typeof enabled !== 'undefined') { - payload['enabled'] = enabled; - } - - let response = undefined; - - response = await client.call('put', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface DatabasesDeleteRequestParams { - databaseId: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const databasesDelete = async ({databaseId,parseOutput = true, overrideForCli = false, sdk = undefined}: DatabasesDeleteRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/databases/{databaseId}'.replace('{databaseId}', databaseId); - let payload = {}; - - let response = undefined; - - response = await client.call('delete', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface DatabasesListCollectionsRequestParams { - databaseId: string; - queries?: string[]; - search?: string; - total?: boolean; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; - console?: boolean; -} - -export const databasesListCollections = async ({databaseId,queries,search,total,parseOutput = true, overrideForCli = false, sdk = undefined, console: showConsole}: DatabasesListCollectionsRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/databases/{databaseId}/collections'.replace('{databaseId}', databaseId); - let payload = {}; - if (typeof queries !== 'undefined') { - payload['queries'] = queries; - } - if (typeof search !== 'undefined') { - payload['search'] = search; - } - if (typeof total !== 'undefined') { - payload['total'] = total; - } - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - if(showConsole) { - showConsoleLink('databases', 'listCollections', databaseId); - } else { - parse(response) - } - } - - return response; - -} -interface DatabasesCreateCollectionRequestParams { - databaseId: string; - collectionId: string; - name: string; - permissions?: string[]; - documentSecurity?: boolean; - enabled?: boolean; - attributes?: object[]; - indexes?: object[]; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const databasesCreateCollection = async ({databaseId,collectionId,name,permissions,documentSecurity,enabled,attributes,indexes,parseOutput = true, overrideForCli = false, sdk = undefined}: DatabasesCreateCollectionRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/databases/{databaseId}/collections'.replace('{databaseId}', databaseId); - let payload = {}; - if (typeof collectionId !== 'undefined') { - payload['collectionId'] = collectionId; - } - if (typeof name !== 'undefined') { - payload['name'] = name; - } - permissions = permissions === true ? [] : permissions; - if (typeof permissions !== 'undefined') { - payload['permissions'] = permissions; - } - if (typeof documentSecurity !== 'undefined') { - payload['documentSecurity'] = documentSecurity; - } - if (typeof enabled !== 'undefined') { - payload['enabled'] = enabled; - } - attributes = attributes === true ? [] : attributes; - if (typeof attributes !== 'undefined') { - payload['attributes'] = attributes; - } - indexes = indexes === true ? [] : indexes; - if (typeof indexes !== 'undefined') { - payload['indexes'] = indexes; - } - - let response = undefined; - - response = await client.call('post', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface DatabasesGetCollectionRequestParams { - databaseId: string; - collectionId: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; - console?: boolean; -} - -export const databasesGetCollection = async ({databaseId,collectionId,parseOutput = true, overrideForCli = false, sdk = undefined, console: showConsole}: DatabasesGetCollectionRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/databases/{databaseId}/collections/{collectionId}'.replace('{databaseId}', databaseId).replace('{collectionId}', collectionId); - let payload = {}; - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - if(showConsole) { - showConsoleLink('databases', 'getCollection', databaseId, collectionId); - } else { - parse(response) - } - } - - return response; - -} -interface DatabasesUpdateCollectionRequestParams { - databaseId: string; - collectionId: string; - name: string; - permissions?: string[]; - documentSecurity?: boolean; - enabled?: boolean; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const databasesUpdateCollection = async ({databaseId,collectionId,name,permissions,documentSecurity,enabled,parseOutput = true, overrideForCli = false, sdk = undefined}: DatabasesUpdateCollectionRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/databases/{databaseId}/collections/{collectionId}'.replace('{databaseId}', databaseId).replace('{collectionId}', collectionId); - let payload = {}; - if (typeof name !== 'undefined') { - payload['name'] = name; - } - permissions = permissions === true ? [] : permissions; - if (typeof permissions !== 'undefined') { - payload['permissions'] = permissions; - } - if (typeof documentSecurity !== 'undefined') { - payload['documentSecurity'] = documentSecurity; - } - if (typeof enabled !== 'undefined') { - payload['enabled'] = enabled; - } - - let response = undefined; - - response = await client.call('put', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface DatabasesDeleteCollectionRequestParams { - databaseId: string; - collectionId: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const databasesDeleteCollection = async ({databaseId,collectionId,parseOutput = true, overrideForCli = false, sdk = undefined}: DatabasesDeleteCollectionRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/databases/{databaseId}/collections/{collectionId}'.replace('{databaseId}', databaseId).replace('{collectionId}', collectionId); - let payload = {}; - - let response = undefined; - - response = await client.call('delete', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface DatabasesListAttributesRequestParams { - databaseId: string; - collectionId: string; - queries?: string[]; - total?: boolean; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; - console?: boolean; -} - -export const databasesListAttributes = async ({databaseId,collectionId,queries,total,parseOutput = true, overrideForCli = false, sdk = undefined, console: showConsole}: DatabasesListAttributesRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/databases/{databaseId}/collections/{collectionId}/attributes'.replace('{databaseId}', databaseId).replace('{collectionId}', collectionId); - let payload = {}; - if (typeof queries !== 'undefined') { - payload['queries'] = queries; - } - if (typeof total !== 'undefined') { - payload['total'] = total; - } - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - if(showConsole) { - showConsoleLink('databases', 'listAttributes', databaseId, collectionId); - } else { - parse(response) - } - } - - return response; - -} -interface DatabasesCreateBooleanAttributeRequestParams { - databaseId: string; - collectionId: string; - key: string; - required: boolean; - xdefault?: boolean; - array?: boolean; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const databasesCreateBooleanAttribute = async ({databaseId,collectionId,key,required,xdefault,array,parseOutput = true, overrideForCli = false, sdk = undefined}: DatabasesCreateBooleanAttributeRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/databases/{databaseId}/collections/{collectionId}/attributes/boolean'.replace('{databaseId}', databaseId).replace('{collectionId}', collectionId); - let payload = {}; - if (typeof key !== 'undefined') { - payload['key'] = key; - } - if (typeof required !== 'undefined') { - payload['required'] = required; - } - if (typeof xdefault !== 'undefined') { - payload['default'] = xdefault; - } - if (typeof array !== 'undefined') { - payload['array'] = array; - } - - let response = undefined; - - response = await client.call('post', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface DatabasesUpdateBooleanAttributeRequestParams { - databaseId: string; - collectionId: string; - key: string; - required: boolean; - xdefault: boolean; - newKey?: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const databasesUpdateBooleanAttribute = async ({databaseId,collectionId,key,required,xdefault,newKey,parseOutput = true, overrideForCli = false, sdk = undefined}: DatabasesUpdateBooleanAttributeRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/databases/{databaseId}/collections/{collectionId}/attributes/boolean/{key}'.replace('{databaseId}', databaseId).replace('{collectionId}', collectionId).replace('{key}', key); - let payload = {}; - if (typeof required !== 'undefined') { - payload['required'] = required; - } - if (typeof xdefault !== 'undefined') { - payload['default'] = xdefault; - } - if (typeof newKey !== 'undefined') { - payload['newKey'] = newKey; - } - - let response = undefined; - - response = await client.call('patch', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface DatabasesCreateDatetimeAttributeRequestParams { - databaseId: string; - collectionId: string; - key: string; - required: boolean; - xdefault?: string; - array?: boolean; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const databasesCreateDatetimeAttribute = async ({databaseId,collectionId,key,required,xdefault,array,parseOutput = true, overrideForCli = false, sdk = undefined}: DatabasesCreateDatetimeAttributeRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/databases/{databaseId}/collections/{collectionId}/attributes/datetime'.replace('{databaseId}', databaseId).replace('{collectionId}', collectionId); - let payload = {}; - if (typeof key !== 'undefined') { - payload['key'] = key; - } - if (typeof required !== 'undefined') { - payload['required'] = required; - } - if (typeof xdefault !== 'undefined') { - payload['default'] = xdefault; - } - if (typeof array !== 'undefined') { - payload['array'] = array; - } - - let response = undefined; - - response = await client.call('post', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface DatabasesUpdateDatetimeAttributeRequestParams { - databaseId: string; - collectionId: string; - key: string; - required: boolean; - xdefault: string; - newKey?: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const databasesUpdateDatetimeAttribute = async ({databaseId,collectionId,key,required,xdefault,newKey,parseOutput = true, overrideForCli = false, sdk = undefined}: DatabasesUpdateDatetimeAttributeRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/databases/{databaseId}/collections/{collectionId}/attributes/datetime/{key}'.replace('{databaseId}', databaseId).replace('{collectionId}', collectionId).replace('{key}', key); - let payload = {}; - if (typeof required !== 'undefined') { - payload['required'] = required; - } - if (typeof xdefault !== 'undefined') { - payload['default'] = xdefault; - } - if (typeof newKey !== 'undefined') { - payload['newKey'] = newKey; - } - - let response = undefined; - - response = await client.call('patch', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface DatabasesCreateEmailAttributeRequestParams { - databaseId: string; - collectionId: string; - key: string; - required: boolean; - xdefault?: string; - array?: boolean; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const databasesCreateEmailAttribute = async ({databaseId,collectionId,key,required,xdefault,array,parseOutput = true, overrideForCli = false, sdk = undefined}: DatabasesCreateEmailAttributeRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/databases/{databaseId}/collections/{collectionId}/attributes/email'.replace('{databaseId}', databaseId).replace('{collectionId}', collectionId); - let payload = {}; - if (typeof key !== 'undefined') { - payload['key'] = key; - } - if (typeof required !== 'undefined') { - payload['required'] = required; - } - if (typeof xdefault !== 'undefined') { - payload['default'] = xdefault; - } - if (typeof array !== 'undefined') { - payload['array'] = array; - } - - let response = undefined; - - response = await client.call('post', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface DatabasesUpdateEmailAttributeRequestParams { - databaseId: string; - collectionId: string; - key: string; - required: boolean; - xdefault: string; - newKey?: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const databasesUpdateEmailAttribute = async ({databaseId,collectionId,key,required,xdefault,newKey,parseOutput = true, overrideForCli = false, sdk = undefined}: DatabasesUpdateEmailAttributeRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/databases/{databaseId}/collections/{collectionId}/attributes/email/{key}'.replace('{databaseId}', databaseId).replace('{collectionId}', collectionId).replace('{key}', key); - let payload = {}; - if (typeof required !== 'undefined') { - payload['required'] = required; - } - if (typeof xdefault !== 'undefined') { - payload['default'] = xdefault; - } - if (typeof newKey !== 'undefined') { - payload['newKey'] = newKey; - } - - let response = undefined; - - response = await client.call('patch', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface DatabasesCreateEnumAttributeRequestParams { - databaseId: string; - collectionId: string; - key: string; - elements: string[]; - required: boolean; - xdefault?: string; - array?: boolean; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const databasesCreateEnumAttribute = async ({databaseId,collectionId,key,elements,required,xdefault,array,parseOutput = true, overrideForCli = false, sdk = undefined}: DatabasesCreateEnumAttributeRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/databases/{databaseId}/collections/{collectionId}/attributes/enum'.replace('{databaseId}', databaseId).replace('{collectionId}', collectionId); - let payload = {}; - if (typeof key !== 'undefined') { - payload['key'] = key; - } - elements = elements === true ? [] : elements; - if (typeof elements !== 'undefined') { - payload['elements'] = elements; - } - if (typeof required !== 'undefined') { - payload['required'] = required; - } - if (typeof xdefault !== 'undefined') { - payload['default'] = xdefault; - } - if (typeof array !== 'undefined') { - payload['array'] = array; - } - - let response = undefined; - - response = await client.call('post', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface DatabasesUpdateEnumAttributeRequestParams { - databaseId: string; - collectionId: string; - key: string; - elements: string[]; - required: boolean; - xdefault: string; - newKey?: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const databasesUpdateEnumAttribute = async ({databaseId,collectionId,key,elements,required,xdefault,newKey,parseOutput = true, overrideForCli = false, sdk = undefined}: DatabasesUpdateEnumAttributeRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/databases/{databaseId}/collections/{collectionId}/attributes/enum/{key}'.replace('{databaseId}', databaseId).replace('{collectionId}', collectionId).replace('{key}', key); - let payload = {}; - elements = elements === true ? [] : elements; - if (typeof elements !== 'undefined') { - payload['elements'] = elements; - } - if (typeof required !== 'undefined') { - payload['required'] = required; - } - if (typeof xdefault !== 'undefined') { - payload['default'] = xdefault; - } - if (typeof newKey !== 'undefined') { - payload['newKey'] = newKey; - } - - let response = undefined; - - response = await client.call('patch', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface DatabasesCreateFloatAttributeRequestParams { - databaseId: string; - collectionId: string; - key: string; - required: boolean; - min?: number; - max?: number; - xdefault?: number; - array?: boolean; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const databasesCreateFloatAttribute = async ({databaseId,collectionId,key,required,min,max,xdefault,array,parseOutput = true, overrideForCli = false, sdk = undefined}: DatabasesCreateFloatAttributeRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/databases/{databaseId}/collections/{collectionId}/attributes/float'.replace('{databaseId}', databaseId).replace('{collectionId}', collectionId); - let payload = {}; - if (typeof key !== 'undefined') { - payload['key'] = key; - } - if (typeof required !== 'undefined') { - payload['required'] = required; - } - if (typeof min !== 'undefined') { - payload['min'] = min; - } - if (typeof max !== 'undefined') { - payload['max'] = max; - } - if (typeof xdefault !== 'undefined') { - payload['default'] = xdefault; - } - if (typeof array !== 'undefined') { - payload['array'] = array; - } - - let response = undefined; - - response = await client.call('post', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface DatabasesUpdateFloatAttributeRequestParams { - databaseId: string; - collectionId: string; - key: string; - required: boolean; - xdefault: number; - min?: number; - max?: number; - newKey?: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const databasesUpdateFloatAttribute = async ({databaseId,collectionId,key,required,xdefault,min,max,newKey,parseOutput = true, overrideForCli = false, sdk = undefined}: DatabasesUpdateFloatAttributeRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/databases/{databaseId}/collections/{collectionId}/attributes/float/{key}'.replace('{databaseId}', databaseId).replace('{collectionId}', collectionId).replace('{key}', key); - let payload = {}; - if (typeof required !== 'undefined') { - payload['required'] = required; - } - if (typeof min !== 'undefined') { - payload['min'] = min; - } - if (typeof max !== 'undefined') { - payload['max'] = max; - } - if (typeof xdefault !== 'undefined') { - payload['default'] = xdefault; - } - if (typeof newKey !== 'undefined') { - payload['newKey'] = newKey; - } - - let response = undefined; - - response = await client.call('patch', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface DatabasesCreateIntegerAttributeRequestParams { - databaseId: string; - collectionId: string; - key: string; - required: boolean; - min?: number; - max?: number; - xdefault?: number; - array?: boolean; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const databasesCreateIntegerAttribute = async ({databaseId,collectionId,key,required,min,max,xdefault,array,parseOutput = true, overrideForCli = false, sdk = undefined}: DatabasesCreateIntegerAttributeRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/databases/{databaseId}/collections/{collectionId}/attributes/integer'.replace('{databaseId}', databaseId).replace('{collectionId}', collectionId); - let payload = {}; - if (typeof key !== 'undefined') { - payload['key'] = key; - } - if (typeof required !== 'undefined') { - payload['required'] = required; - } - if (typeof min !== 'undefined') { - payload['min'] = min; - } - if (typeof max !== 'undefined') { - payload['max'] = max; - } - if (typeof xdefault !== 'undefined') { - payload['default'] = xdefault; - } - if (typeof array !== 'undefined') { - payload['array'] = array; - } - - let response = undefined; - - response = await client.call('post', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface DatabasesUpdateIntegerAttributeRequestParams { - databaseId: string; - collectionId: string; - key: string; - required: boolean; - xdefault: number; - min?: number; - max?: number; - newKey?: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const databasesUpdateIntegerAttribute = async ({databaseId,collectionId,key,required,xdefault,min,max,newKey,parseOutput = true, overrideForCli = false, sdk = undefined}: DatabasesUpdateIntegerAttributeRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/databases/{databaseId}/collections/{collectionId}/attributes/integer/{key}'.replace('{databaseId}', databaseId).replace('{collectionId}', collectionId).replace('{key}', key); - let payload = {}; - if (typeof required !== 'undefined') { - payload['required'] = required; - } - if (typeof min !== 'undefined') { - payload['min'] = min; - } - if (typeof max !== 'undefined') { - payload['max'] = max; - } - if (typeof xdefault !== 'undefined') { - payload['default'] = xdefault; - } - if (typeof newKey !== 'undefined') { - payload['newKey'] = newKey; - } - - let response = undefined; - - response = await client.call('patch', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface DatabasesCreateIpAttributeRequestParams { - databaseId: string; - collectionId: string; - key: string; - required: boolean; - xdefault?: string; - array?: boolean; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const databasesCreateIpAttribute = async ({databaseId,collectionId,key,required,xdefault,array,parseOutput = true, overrideForCli = false, sdk = undefined}: DatabasesCreateIpAttributeRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/databases/{databaseId}/collections/{collectionId}/attributes/ip'.replace('{databaseId}', databaseId).replace('{collectionId}', collectionId); - let payload = {}; - if (typeof key !== 'undefined') { - payload['key'] = key; - } - if (typeof required !== 'undefined') { - payload['required'] = required; - } - if (typeof xdefault !== 'undefined') { - payload['default'] = xdefault; - } - if (typeof array !== 'undefined') { - payload['array'] = array; - } - - let response = undefined; - - response = await client.call('post', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface DatabasesUpdateIpAttributeRequestParams { - databaseId: string; - collectionId: string; - key: string; - required: boolean; - xdefault: string; - newKey?: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const databasesUpdateIpAttribute = async ({databaseId,collectionId,key,required,xdefault,newKey,parseOutput = true, overrideForCli = false, sdk = undefined}: DatabasesUpdateIpAttributeRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/databases/{databaseId}/collections/{collectionId}/attributes/ip/{key}'.replace('{databaseId}', databaseId).replace('{collectionId}', collectionId).replace('{key}', key); - let payload = {}; - if (typeof required !== 'undefined') { - payload['required'] = required; - } - if (typeof xdefault !== 'undefined') { - payload['default'] = xdefault; - } - if (typeof newKey !== 'undefined') { - payload['newKey'] = newKey; - } - - let response = undefined; - - response = await client.call('patch', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface DatabasesCreateLineAttributeRequestParams { - databaseId: string; - collectionId: string; - key: string; - required: boolean; - xdefault?: any[]; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const databasesCreateLineAttribute = async ({databaseId,collectionId,key,required,xdefault,parseOutput = true, overrideForCli = false, sdk = undefined}: DatabasesCreateLineAttributeRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/databases/{databaseId}/collections/{collectionId}/attributes/line'.replace('{databaseId}', databaseId).replace('{collectionId}', collectionId); - let payload = {}; - if (typeof key !== 'undefined') { - payload['key'] = key; - } - if (typeof required !== 'undefined') { - payload['required'] = required; - } - xdefault = xdefault === true ? [] : xdefault; - if (typeof xdefault !== 'undefined') { - payload['default'] = xdefault; - } - - let response = undefined; - - response = await client.call('post', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface DatabasesUpdateLineAttributeRequestParams { - databaseId: string; - collectionId: string; - key: string; - required: boolean; - xdefault?: any[]; - newKey?: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const databasesUpdateLineAttribute = async ({databaseId,collectionId,key,required,xdefault,newKey,parseOutput = true, overrideForCli = false, sdk = undefined}: DatabasesUpdateLineAttributeRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/databases/{databaseId}/collections/{collectionId}/attributes/line/{key}'.replace('{databaseId}', databaseId).replace('{collectionId}', collectionId).replace('{key}', key); - let payload = {}; - if (typeof required !== 'undefined') { - payload['required'] = required; - } - xdefault = xdefault === true ? [] : xdefault; - if (typeof xdefault !== 'undefined') { - payload['default'] = xdefault; - } - if (typeof newKey !== 'undefined') { - payload['newKey'] = newKey; - } - - let response = undefined; - - response = await client.call('patch', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface DatabasesCreatePointAttributeRequestParams { - databaseId: string; - collectionId: string; - key: string; - required: boolean; - xdefault?: any[]; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const databasesCreatePointAttribute = async ({databaseId,collectionId,key,required,xdefault,parseOutput = true, overrideForCli = false, sdk = undefined}: DatabasesCreatePointAttributeRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/databases/{databaseId}/collections/{collectionId}/attributes/point'.replace('{databaseId}', databaseId).replace('{collectionId}', collectionId); - let payload = {}; - if (typeof key !== 'undefined') { - payload['key'] = key; - } - if (typeof required !== 'undefined') { - payload['required'] = required; - } - xdefault = xdefault === true ? [] : xdefault; - if (typeof xdefault !== 'undefined') { - payload['default'] = xdefault; - } - - let response = undefined; - - response = await client.call('post', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface DatabasesUpdatePointAttributeRequestParams { - databaseId: string; - collectionId: string; - key: string; - required: boolean; - xdefault?: any[]; - newKey?: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const databasesUpdatePointAttribute = async ({databaseId,collectionId,key,required,xdefault,newKey,parseOutput = true, overrideForCli = false, sdk = undefined}: DatabasesUpdatePointAttributeRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/databases/{databaseId}/collections/{collectionId}/attributes/point/{key}'.replace('{databaseId}', databaseId).replace('{collectionId}', collectionId).replace('{key}', key); - let payload = {}; - if (typeof required !== 'undefined') { - payload['required'] = required; - } - xdefault = xdefault === true ? [] : xdefault; - if (typeof xdefault !== 'undefined') { - payload['default'] = xdefault; - } - if (typeof newKey !== 'undefined') { - payload['newKey'] = newKey; - } - - let response = undefined; - - response = await client.call('patch', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface DatabasesCreatePolygonAttributeRequestParams { - databaseId: string; - collectionId: string; - key: string; - required: boolean; - xdefault?: any[]; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const databasesCreatePolygonAttribute = async ({databaseId,collectionId,key,required,xdefault,parseOutput = true, overrideForCli = false, sdk = undefined}: DatabasesCreatePolygonAttributeRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/databases/{databaseId}/collections/{collectionId}/attributes/polygon'.replace('{databaseId}', databaseId).replace('{collectionId}', collectionId); - let payload = {}; - if (typeof key !== 'undefined') { - payload['key'] = key; - } - if (typeof required !== 'undefined') { - payload['required'] = required; - } - xdefault = xdefault === true ? [] : xdefault; - if (typeof xdefault !== 'undefined') { - payload['default'] = xdefault; - } - - let response = undefined; - - response = await client.call('post', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface DatabasesUpdatePolygonAttributeRequestParams { - databaseId: string; - collectionId: string; - key: string; - required: boolean; - xdefault?: any[]; - newKey?: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const databasesUpdatePolygonAttribute = async ({databaseId,collectionId,key,required,xdefault,newKey,parseOutput = true, overrideForCli = false, sdk = undefined}: DatabasesUpdatePolygonAttributeRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/databases/{databaseId}/collections/{collectionId}/attributes/polygon/{key}'.replace('{databaseId}', databaseId).replace('{collectionId}', collectionId).replace('{key}', key); - let payload = {}; - if (typeof required !== 'undefined') { - payload['required'] = required; - } - xdefault = xdefault === true ? [] : xdefault; - if (typeof xdefault !== 'undefined') { - payload['default'] = xdefault; - } - if (typeof newKey !== 'undefined') { - payload['newKey'] = newKey; - } - - let response = undefined; - - response = await client.call('patch', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface DatabasesCreateRelationshipAttributeRequestParams { - databaseId: string; - collectionId: string; - relatedCollectionId: string; - type: RelationshipType; - twoWay?: boolean; - key?: string; - twoWayKey?: string; - onDelete?: RelationMutate; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const databasesCreateRelationshipAttribute = async ({databaseId,collectionId,relatedCollectionId,type,twoWay,key,twoWayKey,onDelete,parseOutput = true, overrideForCli = false, sdk = undefined}: DatabasesCreateRelationshipAttributeRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/databases/{databaseId}/collections/{collectionId}/attributes/relationship'.replace('{databaseId}', databaseId).replace('{collectionId}', collectionId); - let payload = {}; - if (typeof relatedCollectionId !== 'undefined') { - payload['relatedCollectionId'] = relatedCollectionId; - } - if (typeof type !== 'undefined') { - payload['type'] = type; - } - if (typeof twoWay !== 'undefined') { - payload['twoWay'] = twoWay; - } - if (typeof key !== 'undefined') { - payload['key'] = key; - } - if (typeof twoWayKey !== 'undefined') { - payload['twoWayKey'] = twoWayKey; - } - if (typeof onDelete !== 'undefined') { - payload['onDelete'] = onDelete; - } - - let response = undefined; - - response = await client.call('post', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface DatabasesCreateStringAttributeRequestParams { - databaseId: string; - collectionId: string; - key: string; - size: number; - required: boolean; - xdefault?: string; - array?: boolean; - encrypt?: boolean; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const databasesCreateStringAttribute = async ({databaseId,collectionId,key,size,required,xdefault,array,encrypt,parseOutput = true, overrideForCli = false, sdk = undefined}: DatabasesCreateStringAttributeRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/databases/{databaseId}/collections/{collectionId}/attributes/string'.replace('{databaseId}', databaseId).replace('{collectionId}', collectionId); - let payload = {}; - if (typeof key !== 'undefined') { - payload['key'] = key; - } - if (typeof size !== 'undefined') { - payload['size'] = size; - } - if (typeof required !== 'undefined') { - payload['required'] = required; - } - if (typeof xdefault !== 'undefined') { - payload['default'] = xdefault; - } - if (typeof array !== 'undefined') { - payload['array'] = array; - } - if (typeof encrypt !== 'undefined') { - payload['encrypt'] = encrypt; - } - - let response = undefined; - - response = await client.call('post', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface DatabasesUpdateStringAttributeRequestParams { - databaseId: string; - collectionId: string; - key: string; - required: boolean; - xdefault: string; - size?: number; - newKey?: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const databasesUpdateStringAttribute = async ({databaseId,collectionId,key,required,xdefault,size,newKey,parseOutput = true, overrideForCli = false, sdk = undefined}: DatabasesUpdateStringAttributeRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/databases/{databaseId}/collections/{collectionId}/attributes/string/{key}'.replace('{databaseId}', databaseId).replace('{collectionId}', collectionId).replace('{key}', key); - let payload = {}; - if (typeof required !== 'undefined') { - payload['required'] = required; - } - if (typeof xdefault !== 'undefined') { - payload['default'] = xdefault; - } - if (typeof size !== 'undefined') { - payload['size'] = size; - } - if (typeof newKey !== 'undefined') { - payload['newKey'] = newKey; - } - - let response = undefined; - - response = await client.call('patch', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface DatabasesCreateUrlAttributeRequestParams { - databaseId: string; - collectionId: string; - key: string; - required: boolean; - xdefault?: string; - array?: boolean; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const databasesCreateUrlAttribute = async ({databaseId,collectionId,key,required,xdefault,array,parseOutput = true, overrideForCli = false, sdk = undefined}: DatabasesCreateUrlAttributeRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/databases/{databaseId}/collections/{collectionId}/attributes/url'.replace('{databaseId}', databaseId).replace('{collectionId}', collectionId); - let payload = {}; - if (typeof key !== 'undefined') { - payload['key'] = key; - } - if (typeof required !== 'undefined') { - payload['required'] = required; - } - if (typeof xdefault !== 'undefined') { - payload['default'] = xdefault; - } - if (typeof array !== 'undefined') { - payload['array'] = array; - } - - let response = undefined; - - response = await client.call('post', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface DatabasesUpdateUrlAttributeRequestParams { - databaseId: string; - collectionId: string; - key: string; - required: boolean; - xdefault: string; - newKey?: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const databasesUpdateUrlAttribute = async ({databaseId,collectionId,key,required,xdefault,newKey,parseOutput = true, overrideForCli = false, sdk = undefined}: DatabasesUpdateUrlAttributeRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/databases/{databaseId}/collections/{collectionId}/attributes/url/{key}'.replace('{databaseId}', databaseId).replace('{collectionId}', collectionId).replace('{key}', key); - let payload = {}; - if (typeof required !== 'undefined') { - payload['required'] = required; - } - if (typeof xdefault !== 'undefined') { - payload['default'] = xdefault; - } - if (typeof newKey !== 'undefined') { - payload['newKey'] = newKey; - } - - let response = undefined; - - response = await client.call('patch', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface DatabasesGetAttributeRequestParams { - databaseId: string; - collectionId: string; - key: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const databasesGetAttribute = async ({databaseId,collectionId,key,parseOutput = true, overrideForCli = false, sdk = undefined}: DatabasesGetAttributeRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/databases/{databaseId}/collections/{collectionId}/attributes/{key}'.replace('{databaseId}', databaseId).replace('{collectionId}', collectionId).replace('{key}', key); - let payload = {}; - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface DatabasesDeleteAttributeRequestParams { - databaseId: string; - collectionId: string; - key: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const databasesDeleteAttribute = async ({databaseId,collectionId,key,parseOutput = true, overrideForCli = false, sdk = undefined}: DatabasesDeleteAttributeRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/databases/{databaseId}/collections/{collectionId}/attributes/{key}'.replace('{databaseId}', databaseId).replace('{collectionId}', collectionId).replace('{key}', key); - let payload = {}; - - let response = undefined; - - response = await client.call('delete', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface DatabasesUpdateRelationshipAttributeRequestParams { - databaseId: string; - collectionId: string; - key: string; - onDelete?: RelationMutate; - newKey?: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const databasesUpdateRelationshipAttribute = async ({databaseId,collectionId,key,onDelete,newKey,parseOutput = true, overrideForCli = false, sdk = undefined}: DatabasesUpdateRelationshipAttributeRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/databases/{databaseId}/collections/{collectionId}/attributes/{key}/relationship'.replace('{databaseId}', databaseId).replace('{collectionId}', collectionId).replace('{key}', key); - let payload = {}; - if (typeof onDelete !== 'undefined') { - payload['onDelete'] = onDelete; - } - if (typeof newKey !== 'undefined') { - payload['newKey'] = newKey; - } - - let response = undefined; - - response = await client.call('patch', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface DatabasesListDocumentsRequestParams { - databaseId: string; - collectionId: string; - queries?: string[]; - transactionId?: string; - total?: boolean; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; - console?: boolean; -} - -export const databasesListDocuments = async ({databaseId,collectionId,queries,transactionId,total,parseOutput = true, overrideForCli = false, sdk = undefined, console: showConsole}: DatabasesListDocumentsRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/databases/{databaseId}/collections/{collectionId}/documents'.replace('{databaseId}', databaseId).replace('{collectionId}', collectionId); - let payload = {}; - if (typeof queries !== 'undefined') { - payload['queries'] = queries; - } - if (typeof transactionId !== 'undefined') { - payload['transactionId'] = transactionId; - } - if (typeof total !== 'undefined') { - payload['total'] = total; - } - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - if(showConsole) { - showConsoleLink('databases', 'listDocuments', databaseId, collectionId); - } else { - parse(response) - } - } - - return response; - -} -interface DatabasesCreateDocumentRequestParams { - databaseId: string; - collectionId: string; - documentId: string; - data: object; - permissions?: string[]; - transactionId?: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const databasesCreateDocument = async ({databaseId,collectionId,documentId,data,permissions,transactionId,parseOutput = true, overrideForCli = false, sdk = undefined}: DatabasesCreateDocumentRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/databases/{databaseId}/collections/{collectionId}/documents'.replace('{databaseId}', databaseId).replace('{collectionId}', collectionId); - let payload = {}; - if (typeof documentId !== 'undefined') { - payload['documentId'] = documentId; - } - if (typeof data !== 'undefined') { - payload['data'] = JSON.parse(data); - } - permissions = permissions === true ? [] : permissions; - if (typeof permissions !== 'undefined') { - payload['permissions'] = permissions; - } - if (typeof transactionId !== 'undefined') { - payload['transactionId'] = transactionId; - } - - let response = undefined; - - response = await client.call('post', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface DatabasesCreateDocumentsRequestParams { - databaseId: string; - collectionId: string; - documents: object[]; - transactionId?: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const databasesCreateDocuments = async ({databaseId,collectionId,documents,transactionId,parseOutput = true, overrideForCli = false, sdk = undefined}: DatabasesCreateDocumentsRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/databases/{databaseId}/collections/{collectionId}/documents'.replace('{databaseId}', databaseId).replace('{collectionId}', collectionId); - let payload = {}; - documents = documents === true ? [] : documents; - if (typeof documents !== 'undefined') { - payload['documents'] = documents; - } - if (typeof transactionId !== 'undefined') { - payload['transactionId'] = transactionId; - } - - let response = undefined; - - response = await client.call('post', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface DatabasesUpsertDocumentsRequestParams { - databaseId: string; - collectionId: string; - documents: object[]; - transactionId?: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const databasesUpsertDocuments = async ({databaseId,collectionId,documents,transactionId,parseOutput = true, overrideForCli = false, sdk = undefined}: DatabasesUpsertDocumentsRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/databases/{databaseId}/collections/{collectionId}/documents'.replace('{databaseId}', databaseId).replace('{collectionId}', collectionId); - let payload = {}; - documents = documents === true ? [] : documents; - if (typeof documents !== 'undefined') { - payload['documents'] = documents; - } - if (typeof transactionId !== 'undefined') { - payload['transactionId'] = transactionId; - } - - let response = undefined; - - response = await client.call('put', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface DatabasesUpdateDocumentsRequestParams { - databaseId: string; - collectionId: string; - data?: object; - queries?: string[]; - transactionId?: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const databasesUpdateDocuments = async ({databaseId,collectionId,data,queries,transactionId,parseOutput = true, overrideForCli = false, sdk = undefined}: DatabasesUpdateDocumentsRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/databases/{databaseId}/collections/{collectionId}/documents'.replace('{databaseId}', databaseId).replace('{collectionId}', collectionId); - let payload = {}; - if (typeof data !== 'undefined') { - payload['data'] = JSON.parse(data); - } - queries = queries === true ? [] : queries; - if (typeof queries !== 'undefined') { - payload['queries'] = queries; - } - if (typeof transactionId !== 'undefined') { - payload['transactionId'] = transactionId; - } - - let response = undefined; - - response = await client.call('patch', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface DatabasesDeleteDocumentsRequestParams { - databaseId: string; - collectionId: string; - queries?: string[]; - transactionId?: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const databasesDeleteDocuments = async ({databaseId,collectionId,queries,transactionId,parseOutput = true, overrideForCli = false, sdk = undefined}: DatabasesDeleteDocumentsRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/databases/{databaseId}/collections/{collectionId}/documents'.replace('{databaseId}', databaseId).replace('{collectionId}', collectionId); - let payload = {}; - queries = queries === true ? [] : queries; - if (typeof queries !== 'undefined') { - payload['queries'] = queries; - } - if (typeof transactionId !== 'undefined') { - payload['transactionId'] = transactionId; - } - - let response = undefined; - - response = await client.call('delete', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface DatabasesGetDocumentRequestParams { - databaseId: string; - collectionId: string; - documentId: string; - queries?: string[]; - transactionId?: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; - console?: boolean; -} - -export const databasesGetDocument = async ({databaseId,collectionId,documentId,queries,transactionId,parseOutput = true, overrideForCli = false, sdk = undefined, console: showConsole}: DatabasesGetDocumentRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/databases/{databaseId}/collections/{collectionId}/documents/{documentId}'.replace('{databaseId}', databaseId).replace('{collectionId}', collectionId).replace('{documentId}', documentId); - let payload = {}; - if (typeof queries !== 'undefined') { - payload['queries'] = queries; - } - if (typeof transactionId !== 'undefined') { - payload['transactionId'] = transactionId; - } - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - if(showConsole) { - showConsoleLink('databases', 'getDocument', databaseId, collectionId, documentId); - } else { - parse(response) - } - } - - return response; - -} -interface DatabasesUpsertDocumentRequestParams { - databaseId: string; - collectionId: string; - documentId: string; - data?: object; - permissions?: string[]; - transactionId?: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const databasesUpsertDocument = async ({databaseId,collectionId,documentId,data,permissions,transactionId,parseOutput = true, overrideForCli = false, sdk = undefined}: DatabasesUpsertDocumentRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/databases/{databaseId}/collections/{collectionId}/documents/{documentId}'.replace('{databaseId}', databaseId).replace('{collectionId}', collectionId).replace('{documentId}', documentId); - let payload = {}; - if (typeof data !== 'undefined') { - payload['data'] = JSON.parse(data); - } - permissions = permissions === true ? [] : permissions; - if (typeof permissions !== 'undefined') { - payload['permissions'] = permissions; - } - if (typeof transactionId !== 'undefined') { - payload['transactionId'] = transactionId; - } - - let response = undefined; - - response = await client.call('put', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface DatabasesUpdateDocumentRequestParams { - databaseId: string; - collectionId: string; - documentId: string; - data?: object; - permissions?: string[]; - transactionId?: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const databasesUpdateDocument = async ({databaseId,collectionId,documentId,data,permissions,transactionId,parseOutput = true, overrideForCli = false, sdk = undefined}: DatabasesUpdateDocumentRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/databases/{databaseId}/collections/{collectionId}/documents/{documentId}'.replace('{databaseId}', databaseId).replace('{collectionId}', collectionId).replace('{documentId}', documentId); - let payload = {}; - if (typeof data !== 'undefined') { - payload['data'] = JSON.parse(data); - } - permissions = permissions === true ? [] : permissions; - if (typeof permissions !== 'undefined') { - payload['permissions'] = permissions; - } - if (typeof transactionId !== 'undefined') { - payload['transactionId'] = transactionId; - } - - let response = undefined; - - response = await client.call('patch', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface DatabasesDeleteDocumentRequestParams { - databaseId: string; - collectionId: string; - documentId: string; - transactionId?: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const databasesDeleteDocument = async ({databaseId,collectionId,documentId,transactionId,parseOutput = true, overrideForCli = false, sdk = undefined}: DatabasesDeleteDocumentRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/databases/{databaseId}/collections/{collectionId}/documents/{documentId}'.replace('{databaseId}', databaseId).replace('{collectionId}', collectionId).replace('{documentId}', documentId); - let payload = {}; - if (typeof transactionId !== 'undefined') { - payload['transactionId'] = transactionId; - } - - let response = undefined; - - response = await client.call('delete', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface DatabasesListDocumentLogsRequestParams { - databaseId: string; - collectionId: string; - documentId: string; - queries?: string[]; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const databasesListDocumentLogs = async ({databaseId,collectionId,documentId,queries,parseOutput = true, overrideForCli = false, sdk = undefined}: DatabasesListDocumentLogsRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/databases/{databaseId}/collections/{collectionId}/documents/{documentId}/logs'.replace('{databaseId}', databaseId).replace('{collectionId}', collectionId).replace('{documentId}', documentId); - let payload = {}; - if (typeof queries !== 'undefined') { - payload['queries'] = queries; - } - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface DatabasesDecrementDocumentAttributeRequestParams { - databaseId: string; - collectionId: string; - documentId: string; - attribute: string; - value?: number; - min?: number; - transactionId?: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const databasesDecrementDocumentAttribute = async ({databaseId,collectionId,documentId,attribute,value,min,transactionId,parseOutput = true, overrideForCli = false, sdk = undefined}: DatabasesDecrementDocumentAttributeRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/databases/{databaseId}/collections/{collectionId}/documents/{documentId}/{attribute}/decrement'.replace('{databaseId}', databaseId).replace('{collectionId}', collectionId).replace('{documentId}', documentId).replace('{attribute}', attribute); - let payload = {}; - if (typeof value !== 'undefined') { - payload['value'] = value; - } - if (typeof min !== 'undefined') { - payload['min'] = min; - } - if (typeof transactionId !== 'undefined') { - payload['transactionId'] = transactionId; - } - - let response = undefined; - - response = await client.call('patch', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface DatabasesIncrementDocumentAttributeRequestParams { - databaseId: string; - collectionId: string; - documentId: string; - attribute: string; - value?: number; - max?: number; - transactionId?: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const databasesIncrementDocumentAttribute = async ({databaseId,collectionId,documentId,attribute,value,max,transactionId,parseOutput = true, overrideForCli = false, sdk = undefined}: DatabasesIncrementDocumentAttributeRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/databases/{databaseId}/collections/{collectionId}/documents/{documentId}/{attribute}/increment'.replace('{databaseId}', databaseId).replace('{collectionId}', collectionId).replace('{documentId}', documentId).replace('{attribute}', attribute); - let payload = {}; - if (typeof value !== 'undefined') { - payload['value'] = value; - } - if (typeof max !== 'undefined') { - payload['max'] = max; - } - if (typeof transactionId !== 'undefined') { - payload['transactionId'] = transactionId; - } - - let response = undefined; - - response = await client.call('patch', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface DatabasesListIndexesRequestParams { - databaseId: string; - collectionId: string; - queries?: string[]; - total?: boolean; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; - console?: boolean; -} - -export const databasesListIndexes = async ({databaseId,collectionId,queries,total,parseOutput = true, overrideForCli = false, sdk = undefined, console: showConsole}: DatabasesListIndexesRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/databases/{databaseId}/collections/{collectionId}/indexes'.replace('{databaseId}', databaseId).replace('{collectionId}', collectionId); - let payload = {}; - if (typeof queries !== 'undefined') { - payload['queries'] = queries; - } - if (typeof total !== 'undefined') { - payload['total'] = total; - } - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - if(showConsole) { - showConsoleLink('databases', 'listIndexes', databaseId, collectionId); - } else { - parse(response) - } - } - - return response; - -} -interface DatabasesCreateIndexRequestParams { - databaseId: string; - collectionId: string; - key: string; - type: IndexType; - attributes: string[]; - orders?: string[]; - lengths?: number[]; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const databasesCreateIndex = async ({databaseId,collectionId,key,type,attributes,orders,lengths,parseOutput = true, overrideForCli = false, sdk = undefined}: DatabasesCreateIndexRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/databases/{databaseId}/collections/{collectionId}/indexes'.replace('{databaseId}', databaseId).replace('{collectionId}', collectionId); - let payload = {}; - if (typeof key !== 'undefined') { - payload['key'] = key; - } - if (typeof type !== 'undefined') { - payload['type'] = type; - } - attributes = attributes === true ? [] : attributes; - if (typeof attributes !== 'undefined') { - payload['attributes'] = attributes; - } - orders = orders === true ? [] : orders; - if (typeof orders !== 'undefined') { - payload['orders'] = orders; - } - lengths = lengths === true ? [] : lengths; - if (typeof lengths !== 'undefined') { - payload['lengths'] = lengths; - } - - let response = undefined; - - response = await client.call('post', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface DatabasesGetIndexRequestParams { - databaseId: string; - collectionId: string; - key: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const databasesGetIndex = async ({databaseId,collectionId,key,parseOutput = true, overrideForCli = false, sdk = undefined}: DatabasesGetIndexRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/databases/{databaseId}/collections/{collectionId}/indexes/{key}'.replace('{databaseId}', databaseId).replace('{collectionId}', collectionId).replace('{key}', key); - let payload = {}; - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface DatabasesDeleteIndexRequestParams { - databaseId: string; - collectionId: string; - key: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const databasesDeleteIndex = async ({databaseId,collectionId,key,parseOutput = true, overrideForCli = false, sdk = undefined}: DatabasesDeleteIndexRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/databases/{databaseId}/collections/{collectionId}/indexes/{key}'.replace('{databaseId}', databaseId).replace('{collectionId}', collectionId).replace('{key}', key); - let payload = {}; - - let response = undefined; - - response = await client.call('delete', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface DatabasesListCollectionLogsRequestParams { - databaseId: string; - collectionId: string; - queries?: string[]; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const databasesListCollectionLogs = async ({databaseId,collectionId,queries,parseOutput = true, overrideForCli = false, sdk = undefined}: DatabasesListCollectionLogsRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/databases/{databaseId}/collections/{collectionId}/logs'.replace('{databaseId}', databaseId).replace('{collectionId}', collectionId); - let payload = {}; - if (typeof queries !== 'undefined') { - payload['queries'] = queries; - } - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface DatabasesGetCollectionUsageRequestParams { - databaseId: string; - collectionId: string; - range?: UsageRange; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const databasesGetCollectionUsage = async ({databaseId,collectionId,range,parseOutput = true, overrideForCli = false, sdk = undefined}: DatabasesGetCollectionUsageRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/databases/{databaseId}/collections/{collectionId}/usage'.replace('{databaseId}', databaseId).replace('{collectionId}', collectionId); - let payload = {}; - if (typeof range !== 'undefined') { - payload['range'] = range; - } - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface DatabasesListLogsRequestParams { - databaseId: string; - queries?: string[]; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const databasesListLogs = async ({databaseId,queries,parseOutput = true, overrideForCli = false, sdk = undefined}: DatabasesListLogsRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/databases/{databaseId}/logs'.replace('{databaseId}', databaseId); - let payload = {}; - if (typeof queries !== 'undefined') { - payload['queries'] = queries; - } - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface DatabasesGetUsageRequestParams { - databaseId: string; - range?: UsageRange; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const databasesGetUsage = async ({databaseId,range,parseOutput = true, overrideForCli = false, sdk = undefined}: DatabasesGetUsageRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/databases/{databaseId}/usage'.replace('{databaseId}', databaseId); - let payload = {}; - if (typeof range !== 'undefined') { - payload['range'] = range; - } - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -databases - .command(`list`) - .description(`[**DEPRECATED** - This command is deprecated. Please use 'tables-db list' instead] Get a list of all databases from the current Appwrite project. You can use the search parameter to filter your results.`) - .option(`--queries [queries...]`, `Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: name`) - .option(`--search `, `Search term to filter your list results. Max length: 256 chars.`) - .option(`--total [value]`, `When set to false, the total count returned will be 0 and will not be calculated.`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .option(`--console`, `Get the resource console url`) - .action(actionRunner(databasesList)) - -databases - .command(`create`) - .description(`[**DEPRECATED** - This command is deprecated. Please use 'tables-db create' instead] Create a new Database. `) - .requiredOption(`--database-id `, `Unique Id. Choose a custom ID or generate a random ID with 'ID.unique()'. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.`) - .requiredOption(`--name `, `Database name. Max length: 128 chars.`) - .option(`--enabled [value]`, `Is the database enabled? When set to 'disabled', users cannot access the database but Server SDKs with an API key can still read and write to the database. No data is lost when this is toggled.`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .action(actionRunner(databasesCreate)) - -databases - .command(`list-transactions`) - .description(`List transactions across all databases.`) - .option(`--queries [queries...]`, `Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries).`) - .option(`--console`, `Get the resource console url`) - .action(actionRunner(databasesListTransactions)) - -databases - .command(`create-transaction`) - .description(`Create a new transaction.`) - .option(`--ttl `, `Seconds before the transaction expires.`, parseInteger) - .action(actionRunner(databasesCreateTransaction)) - -databases - .command(`get-transaction`) - .description(`Get a transaction by its unique ID.`) - .requiredOption(`--transaction-id `, `Transaction ID.`) - .option(`--console`, `Get the resource console url`) - .action(actionRunner(databasesGetTransaction)) - -databases - .command(`update-transaction`) - .description(`Update a transaction, to either commit or roll back its operations.`) - .requiredOption(`--transaction-id `, `Transaction ID.`) - .option(`--commit [value]`, `Commit transaction?`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .option(`--rollback [value]`, `Rollback transaction?`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .action(actionRunner(databasesUpdateTransaction)) - -databases - .command(`delete-transaction`) - .description(`Delete a transaction by its unique ID.`) - .requiredOption(`--transaction-id `, `Transaction ID.`) - .action(actionRunner(databasesDeleteTransaction)) - -databases - .command(`create-operations`) - .description(`Create multiple operations in a single transaction.`) - .requiredOption(`--transaction-id `, `Transaction ID.`) - .option(`--operations [operations...]`, `Array of staged operations.`) - .action(actionRunner(databasesCreateOperations)) - -databases - .command(`list-usage`) - .description(`[**DEPRECATED** - This command is deprecated. Please use 'tables-db list-usage' instead] List usage metrics and statistics for all databases in the project. You can view the total number of databases, collections, documents, and storage usage. The response includes both current totals and historical data over time. Use the optional range parameter to specify the time window for historical data: 24h (last 24 hours), 30d (last 30 days), or 90d (last 90 days). If not specified, range defaults to 30 days.`) - .option(`--range `, `Date range.`) - .option(`--console`, `Get the resource console url`) - .action(actionRunner(databasesListUsage)) - -databases - .command(`get`) - .description(`[**DEPRECATED** - This command is deprecated. Please use 'tables-db get' instead] Get a database by its unique ID. This endpoint response returns a JSON object with the database metadata.`) - .requiredOption(`--database-id `, `Database ID.`) - .option(`--console`, `Get the resource console url`) - .action(actionRunner(databasesGet)) - -databases - .command(`update`) - .description(`[**DEPRECATED** - This command is deprecated. Please use 'tables-db update' instead] Update a database by its unique ID.`) - .requiredOption(`--database-id `, `Database ID.`) - .requiredOption(`--name `, `Database name. Max length: 128 chars.`) - .option(`--enabled [value]`, `Is database enabled? When set to 'disabled', users cannot access the database but Server SDKs with an API key can still read and write to the database. No data is lost when this is toggled.`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .action(actionRunner(databasesUpdate)) - -databases - .command(`delete`) - .description(`[**DEPRECATED** - This command is deprecated. Please use 'tables-db delete' instead] Delete a database by its unique ID. Only API keys with with databases.write scope can delete a database.`) - .requiredOption(`--database-id `, `Database ID.`) - .action(actionRunner(databasesDelete)) - -databases - .command(`list-collections`) - .description(`[**DEPRECATED** - This command is deprecated. Please use 'tables-db list-tables' instead] Get a list of all collections that belong to the provided databaseId. You can use the search parameter to filter your results.`) - .requiredOption(`--database-id `, `Database ID.`) - .option(`--queries [queries...]`, `Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: name, enabled, documentSecurity`) - .option(`--search `, `Search term to filter your list results. Max length: 256 chars.`) - .option(`--total [value]`, `When set to false, the total count returned will be 0 and will not be calculated.`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .option(`--console`, `Get the resource console url`) - .action(actionRunner(databasesListCollections)) - -databases - .command(`create-collection`) - .description(`[**DEPRECATED** - This command is deprecated. Please use 'tables-db create-table' instead] Create a new Collection. Before using this route, you should create a new database resource using either a [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection) API or directly from your database console.`) - .requiredOption(`--database-id `, `Database ID.`) - .requiredOption(`--collection-id `, `Unique Id. Choose a custom ID or generate a random ID with 'ID.unique()'. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.`) - .requiredOption(`--name `, `Collection name. Max length: 128 chars.`) - .option(`--permissions [permissions...]`, `An array of permissions strings. By default, no user is granted with any permissions. [Learn more about permissions](https://appwrite.io/docs/permissions).`) - .option(`--document-security [value]`, `Enables configuring permissions for individual documents. A user needs one of document or collection level permissions to access a document. [Learn more about permissions](https://appwrite.io/docs/permissions).`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .option(`--enabled [value]`, `Is collection enabled? When set to 'disabled', users cannot access the collection but Server SDKs with and API key can still read and write to the collection. No data is lost when this is toggled.`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .option(`--attributes [attributes...]`, `Array of attribute definitions to create. Each attribute should contain: key (string), type (string: string, integer, float, boolean, datetime), size (integer, required for string type), required (boolean, optional), default (mixed, optional), array (boolean, optional), and type-specific options.`) - .option(`--indexes [indexes...]`, `Array of index definitions to create. Each index should contain: key (string), type (string: key, fulltext, unique, spatial), attributes (array of attribute keys), orders (array of ASC/DESC, optional), and lengths (array of integers, optional).`) - .action(actionRunner(databasesCreateCollection)) - -databases - .command(`get-collection`) - .description(`[**DEPRECATED** - This command is deprecated. Please use 'tables-db get-table' instead] Get a collection by its unique ID. This endpoint response returns a JSON object with the collection metadata.`) - .requiredOption(`--database-id `, `Database ID.`) - .requiredOption(`--collection-id `, `Collection ID.`) - .option(`--console`, `Get the resource console url`) - .action(actionRunner(databasesGetCollection)) - -databases - .command(`update-collection`) - .description(`[**DEPRECATED** - This command is deprecated. Please use 'tables-db update-table' instead] Update a collection by its unique ID.`) - .requiredOption(`--database-id `, `Database ID.`) - .requiredOption(`--collection-id `, `Collection ID.`) - .requiredOption(`--name `, `Collection name. Max length: 128 chars.`) - .option(`--permissions [permissions...]`, `An array of permission strings. By default, the current permissions are inherited. [Learn more about permissions](https://appwrite.io/docs/permissions).`) - .option(`--document-security [value]`, `Enables configuring permissions for individual documents. A user needs one of document or collection level permissions to access a document. [Learn more about permissions](https://appwrite.io/docs/permissions).`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .option(`--enabled [value]`, `Is collection enabled? When set to 'disabled', users cannot access the collection but Server SDKs with and API key can still read and write to the collection. No data is lost when this is toggled.`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .action(actionRunner(databasesUpdateCollection)) - -databases - .command(`delete-collection`) - .description(`[**DEPRECATED** - This command is deprecated. Please use 'tables-db delete-table' instead] Delete a collection by its unique ID. Only users with write permissions have access to delete this resource.`) - .requiredOption(`--database-id `, `Database ID.`) - .requiredOption(`--collection-id `, `Collection ID.`) - .action(actionRunner(databasesDeleteCollection)) - -databases - .command(`list-attributes`) - .description(`[**DEPRECATED** - This command is deprecated. Please use 'tables-db list-columns' instead] List attributes in the collection.`) - .requiredOption(`--database-id `, `Database ID.`) - .requiredOption(`--collection-id `, `Collection ID.`) - .option(`--queries [queries...]`, `Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: key, type, size, required, array, status, error`) - .option(`--total [value]`, `When set to false, the total count returned will be 0 and will not be calculated.`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .option(`--console`, `Get the resource console url`) - .action(actionRunner(databasesListAttributes)) - -databases - .command(`create-boolean-attribute`) - .description(`[**DEPRECATED** - This command is deprecated. Please use 'tables-db create-boolean-column' instead] Create a boolean attribute. `) - .requiredOption(`--database-id `, `Database ID.`) - .requiredOption(`--collection-id `, `Collection ID. You can create a new table using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection).`) - .requiredOption(`--key `, `Attribute Key.`) - .requiredOption(`--required [value]`, `Is attribute required?`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .option(`--xdefault [value]`, `Default value for attribute when not provided. Cannot be set when attribute is required.`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .option(`--array [value]`, `Is attribute an array?`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .action(actionRunner(databasesCreateBooleanAttribute)) - -databases - .command(`update-boolean-attribute`) - .description(`[**DEPRECATED** - This command is deprecated. Please use 'tables-db update-boolean-column' instead] Update a boolean attribute. Changing the 'default' value will not update already existing documents.`) - .requiredOption(`--database-id `, `Database ID.`) - .requiredOption(`--collection-id `, `Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#createCollection).`) - .requiredOption(`--key `, `Attribute Key.`) - .requiredOption(`--required [value]`, `Is attribute required?`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .option(`--xdefault [value]`, `Default value for attribute when not provided. Cannot be set when attribute is required.`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .option(`--new-key `, `New attribute key.`) - .action(actionRunner(databasesUpdateBooleanAttribute)) - -databases - .command(`create-datetime-attribute`) - .description(`[**DEPRECATED** - This command is deprecated. Please use 'tables-db create-datetime-column' instead] Create a date time attribute according to the ISO 8601 standard.`) - .requiredOption(`--database-id `, `Database ID.`) - .requiredOption(`--collection-id `, `Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#createCollection).`) - .requiredOption(`--key `, `Attribute Key.`) - .requiredOption(`--required [value]`, `Is attribute required?`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .option(`--xdefault `, `Default value for the attribute in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format. Cannot be set when attribute is required.`) - .option(`--array [value]`, `Is attribute an array?`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .action(actionRunner(databasesCreateDatetimeAttribute)) - -databases - .command(`update-datetime-attribute`) - .description(`[**DEPRECATED** - This command is deprecated. Please use 'tables-db update-datetime-column' instead] Update a date time attribute. Changing the 'default' value will not update already existing documents.`) - .requiredOption(`--database-id `, `Database ID.`) - .requiredOption(`--collection-id `, `Collection ID.`) - .requiredOption(`--key `, `Attribute Key.`) - .requiredOption(`--required [value]`, `Is attribute required?`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .option(`--xdefault `, `Default value for attribute when not provided. Cannot be set when attribute is required.`) - .option(`--new-key `, `New attribute key.`) - .action(actionRunner(databasesUpdateDatetimeAttribute)) - -databases - .command(`create-email-attribute`) - .description(`[**DEPRECATED** - This command is deprecated. Please use 'tables-db create-email-column' instead] Create an email attribute. `) - .requiredOption(`--database-id `, `Database ID.`) - .requiredOption(`--collection-id `, `Collection ID.`) - .requiredOption(`--key `, `Attribute Key.`) - .requiredOption(`--required [value]`, `Is attribute required?`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .option(`--xdefault `, `Default value for attribute when not provided. Cannot be set when attribute is required.`) - .option(`--array [value]`, `Is attribute an array?`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .action(actionRunner(databasesCreateEmailAttribute)) - -databases - .command(`update-email-attribute`) - .description(`[**DEPRECATED** - This command is deprecated. Please use 'tables-db update-email-column' instead] Update an email attribute. Changing the 'default' value will not update already existing documents. `) - .requiredOption(`--database-id `, `Database ID.`) - .requiredOption(`--collection-id `, `Collection ID.`) - .requiredOption(`--key `, `Attribute Key.`) - .requiredOption(`--required [value]`, `Is attribute required?`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .option(`--xdefault `, `Default value for attribute when not provided. Cannot be set when attribute is required.`) - .option(`--new-key `, `New Attribute Key.`) - .action(actionRunner(databasesUpdateEmailAttribute)) - -databases - .command(`create-enum-attribute`) - .description(`[**DEPRECATED** - This command is deprecated. Please use 'tables-db create-enum-column' instead] Create an enum attribute. The 'elements' param acts as a white-list of accepted values for this attribute. `) - .requiredOption(`--database-id `, `Database ID.`) - .requiredOption(`--collection-id `, `Collection ID.`) - .requiredOption(`--key `, `Attribute Key.`) - .requiredOption(`--elements [elements...]`, `Array of enum values.`) - .requiredOption(`--required [value]`, `Is attribute required?`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .option(`--xdefault `, `Default value for attribute when not provided. Cannot be set when attribute is required.`) - .option(`--array [value]`, `Is attribute an array?`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .action(actionRunner(databasesCreateEnumAttribute)) - -databases - .command(`update-enum-attribute`) - .description(`[**DEPRECATED** - This command is deprecated. Please use 'tables-db update-enum-column' instead] Update an enum attribute. Changing the 'default' value will not update already existing documents. `) - .requiredOption(`--database-id `, `Database ID.`) - .requiredOption(`--collection-id `, `Collection ID.`) - .requiredOption(`--key `, `Attribute Key.`) - .requiredOption(`--elements [elements...]`, `Updated list of enum values.`) - .requiredOption(`--required [value]`, `Is attribute required?`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .option(`--xdefault `, `Default value for attribute when not provided. Cannot be set when attribute is required.`) - .option(`--new-key `, `New Attribute Key.`) - .action(actionRunner(databasesUpdateEnumAttribute)) - -databases - .command(`create-float-attribute`) - .description(`[**DEPRECATED** - This command is deprecated. Please use 'tables-db create-float-column' instead] Create a float attribute. Optionally, minimum and maximum values can be provided. `) - .requiredOption(`--database-id `, `Database ID.`) - .requiredOption(`--collection-id `, `Collection ID.`) - .requiredOption(`--key `, `Attribute Key.`) - .requiredOption(`--required [value]`, `Is attribute required?`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .option(`--min `, `Minimum value.`, parseInteger) - .option(`--max `, `Maximum value.`, parseInteger) - .option(`--xdefault `, `Default value. Cannot be set when required.`, parseInteger) - .option(`--array [value]`, `Is attribute an array?`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .action(actionRunner(databasesCreateFloatAttribute)) - -databases - .command(`update-float-attribute`) - .description(`[**DEPRECATED** - This command is deprecated. Please use 'tables-db update-float-column' instead] Update a float attribute. Changing the 'default' value will not update already existing documents. `) - .requiredOption(`--database-id `, `Database ID.`) - .requiredOption(`--collection-id `, `Collection ID.`) - .requiredOption(`--key `, `Attribute Key.`) - .requiredOption(`--required [value]`, `Is attribute required?`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .option(`--xdefault `, `Default value. Cannot be set when required.`, parseInteger) - .option(`--min `, `Minimum value.`, parseInteger) - .option(`--max `, `Maximum value.`, parseInteger) - .option(`--new-key `, `New Attribute Key.`) - .action(actionRunner(databasesUpdateFloatAttribute)) - -databases - .command(`create-integer-attribute`) - .description(`[**DEPRECATED** - This command is deprecated. Please use 'tables-db create-integer-column' instead] Create an integer attribute. Optionally, minimum and maximum values can be provided. `) - .requiredOption(`--database-id `, `Database ID.`) - .requiredOption(`--collection-id `, `Collection ID.`) - .requiredOption(`--key `, `Attribute Key.`) - .requiredOption(`--required [value]`, `Is attribute required?`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .option(`--min `, `Minimum value`, parseInteger) - .option(`--max `, `Maximum value`, parseInteger) - .option(`--xdefault `, `Default value. Cannot be set when attribute is required.`, parseInteger) - .option(`--array [value]`, `Is attribute an array?`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .action(actionRunner(databasesCreateIntegerAttribute)) - -databases - .command(`update-integer-attribute`) - .description(`[**DEPRECATED** - This command is deprecated. Please use 'tables-db update-integer-column' instead] Update an integer attribute. Changing the 'default' value will not update already existing documents. `) - .requiredOption(`--database-id `, `Database ID.`) - .requiredOption(`--collection-id `, `Collection ID.`) - .requiredOption(`--key `, `Attribute Key.`) - .requiredOption(`--required [value]`, `Is attribute required?`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .option(`--xdefault `, `Default value. Cannot be set when attribute is required.`, parseInteger) - .option(`--min `, `Minimum value`, parseInteger) - .option(`--max `, `Maximum value`, parseInteger) - .option(`--new-key `, `New Attribute Key.`) - .action(actionRunner(databasesUpdateIntegerAttribute)) - -databases - .command(`create-ip-attribute`) - .description(`[**DEPRECATED** - This command is deprecated. Please use 'tables-db create-ip-column' instead] Create IP address attribute. `) - .requiredOption(`--database-id `, `Database ID.`) - .requiredOption(`--collection-id `, `Collection ID.`) - .requiredOption(`--key `, `Attribute Key.`) - .requiredOption(`--required [value]`, `Is attribute required?`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .option(`--xdefault `, `Default value. Cannot be set when attribute is required.`) - .option(`--array [value]`, `Is attribute an array?`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .action(actionRunner(databasesCreateIpAttribute)) - -databases - .command(`update-ip-attribute`) - .description(`[**DEPRECATED** - This command is deprecated. Please use 'tables-db update-ip-column' instead] Update an ip attribute. Changing the 'default' value will not update already existing documents. `) - .requiredOption(`--database-id `, `Database ID.`) - .requiredOption(`--collection-id `, `Collection ID.`) - .requiredOption(`--key `, `Attribute Key.`) - .requiredOption(`--required [value]`, `Is attribute required?`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .option(`--xdefault `, `Default value. Cannot be set when attribute is required.`) - .option(`--new-key `, `New Attribute Key.`) - .action(actionRunner(databasesUpdateIpAttribute)) - -databases - .command(`create-line-attribute`) - .description(`[**DEPRECATED** - This command is deprecated. Please use 'tables-db create-line-column' instead] Create a geometric line attribute.`) - .requiredOption(`--database-id `, `Database ID.`) - .requiredOption(`--collection-id `, `Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection).`) - .requiredOption(`--key `, `Attribute Key.`) - .requiredOption(`--required [value]`, `Is attribute required?`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .option(`--xdefault `, `Default value for attribute when not provided, two-dimensional array of coordinate pairs, [[longitude, latitude], [longitude, latitude], …], listing the vertices of the line in order. Cannot be set when attribute is required.`) - .action(actionRunner(databasesCreateLineAttribute)) - -databases - .command(`update-line-attribute`) - .description(`[**DEPRECATED** - This command is deprecated. Please use 'tables-db update-line-column' instead] Update a line attribute. Changing the 'default' value will not update already existing documents.`) - .requiredOption(`--database-id `, `Database ID.`) - .requiredOption(`--collection-id `, `Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#createCollection).`) - .requiredOption(`--key `, `Attribute Key.`) - .requiredOption(`--required [value]`, `Is attribute required?`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .option(`--xdefault `, `Default value for attribute when not provided, two-dimensional array of coordinate pairs, [[longitude, latitude], [longitude, latitude], …], listing the vertices of the line in order. Cannot be set when attribute is required.`) - .option(`--new-key `, `New attribute key.`) - .action(actionRunner(databasesUpdateLineAttribute)) - -databases - .command(`create-point-attribute`) - .description(`[**DEPRECATED** - This command is deprecated. Please use 'tables-db create-point-column' instead] Create a geometric point attribute.`) - .requiredOption(`--database-id `, `Database ID.`) - .requiredOption(`--collection-id `, `Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection).`) - .requiredOption(`--key `, `Attribute Key.`) - .requiredOption(`--required [value]`, `Is attribute required?`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .option(`--xdefault `, `Default value for attribute when not provided, array of two numbers [longitude, latitude], representing a single coordinate. Cannot be set when attribute is required.`) - .action(actionRunner(databasesCreatePointAttribute)) - -databases - .command(`update-point-attribute`) - .description(`[**DEPRECATED** - This command is deprecated. Please use 'tables-db update-point-column' instead] Update a point attribute. Changing the 'default' value will not update already existing documents.`) - .requiredOption(`--database-id `, `Database ID.`) - .requiredOption(`--collection-id `, `Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#createCollection).`) - .requiredOption(`--key `, `Attribute Key.`) - .requiredOption(`--required [value]`, `Is attribute required?`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .option(`--xdefault `, `Default value for attribute when not provided, array of two numbers [longitude, latitude], representing a single coordinate. Cannot be set when attribute is required.`) - .option(`--new-key `, `New attribute key.`) - .action(actionRunner(databasesUpdatePointAttribute)) - -databases - .command(`create-polygon-attribute`) - .description(`[**DEPRECATED** - This command is deprecated. Please use 'tables-db create-polygon-column' instead] Create a geometric polygon attribute.`) - .requiredOption(`--database-id `, `Database ID.`) - .requiredOption(`--collection-id `, `Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection).`) - .requiredOption(`--key `, `Attribute Key.`) - .requiredOption(`--required [value]`, `Is attribute required?`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .option(`--xdefault `, `Default value for attribute when not provided, three-dimensional array where the outer array holds one or more linear rings, [[[longitude, latitude], …], …], the first ring is the exterior boundary, any additional rings are interior holes, and each ring must start and end with the same coordinate pair. Cannot be set when attribute is required.`) - .action(actionRunner(databasesCreatePolygonAttribute)) - -databases - .command(`update-polygon-attribute`) - .description(`[**DEPRECATED** - This command is deprecated. Please use 'tables-db update-polygon-column' instead] Update a polygon attribute. Changing the 'default' value will not update already existing documents.`) - .requiredOption(`--database-id `, `Database ID.`) - .requiredOption(`--collection-id `, `Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#createCollection).`) - .requiredOption(`--key `, `Attribute Key.`) - .requiredOption(`--required [value]`, `Is attribute required?`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .option(`--xdefault `, `Default value for attribute when not provided, three-dimensional array where the outer array holds one or more linear rings, [[[longitude, latitude], …], …], the first ring is the exterior boundary, any additional rings are interior holes, and each ring must start and end with the same coordinate pair. Cannot be set when attribute is required.`) - .option(`--new-key `, `New attribute key.`) - .action(actionRunner(databasesUpdatePolygonAttribute)) - -databases - .command(`create-relationship-attribute`) - .description(`[**DEPRECATED** - This command is deprecated. Please use 'tables-db create-relationship-column' instead] Create relationship attribute. [Learn more about relationship attributes](https://appwrite.io/docs/databases-relationships#relationship-attributes). `) - .requiredOption(`--database-id `, `Database ID.`) - .requiredOption(`--collection-id `, `Collection ID.`) - .requiredOption(`--related-collection-id `, `Related Collection ID.`) - .requiredOption(`--type `, `Relation type`) - .option(`--two-way [value]`, `Is Two Way?`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .option(`--key `, `Attribute Key.`) - .option(`--two-way-key `, `Two Way Attribute Key.`) - .option(`--on-delete `, `Constraints option`) - .action(actionRunner(databasesCreateRelationshipAttribute)) - -databases - .command(`create-string-attribute`) - .description(`[**DEPRECATED** - This command is deprecated. Please use 'tables-db create-string-column' instead] Create a string attribute. `) - .requiredOption(`--database-id `, `Database ID.`) - .requiredOption(`--collection-id `, `Collection ID. You can create a new table using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection).`) - .requiredOption(`--key `, `Attribute Key.`) - .requiredOption(`--size `, `Attribute size for text attributes, in number of characters.`, parseInteger) - .requiredOption(`--required [value]`, `Is attribute required?`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .option(`--xdefault `, `Default value for attribute when not provided. Cannot be set when attribute is required.`) - .option(`--array [value]`, `Is attribute an array?`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .option(`--encrypt [value]`, `Toggle encryption for the attribute. Encryption enhances security by not storing any plain text values in the database. However, encrypted attributes cannot be queried.`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .action(actionRunner(databasesCreateStringAttribute)) - -databases - .command(`update-string-attribute`) - .description(`[**DEPRECATED** - This command is deprecated. Please use 'tables-db update-string-column' instead] Update a string attribute. Changing the 'default' value will not update already existing documents. `) - .requiredOption(`--database-id `, `Database ID.`) - .requiredOption(`--collection-id `, `Collection ID. You can create a new table using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection).`) - .requiredOption(`--key `, `Attribute Key.`) - .requiredOption(`--required [value]`, `Is attribute required?`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .option(`--xdefault `, `Default value for attribute when not provided. Cannot be set when attribute is required.`) - .option(`--size `, `Maximum size of the string attribute.`, parseInteger) - .option(`--new-key `, `New Attribute Key.`) - .action(actionRunner(databasesUpdateStringAttribute)) - -databases - .command(`create-url-attribute`) - .description(`[**DEPRECATED** - This command is deprecated. Please use 'tables-db create-url-column' instead] Create a URL attribute. `) - .requiredOption(`--database-id `, `Database ID.`) - .requiredOption(`--collection-id `, `Collection ID.`) - .requiredOption(`--key `, `Attribute Key.`) - .requiredOption(`--required [value]`, `Is attribute required?`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .option(`--xdefault `, `Default value for attribute when not provided. Cannot be set when attribute is required.`) - .option(`--array [value]`, `Is attribute an array?`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .action(actionRunner(databasesCreateUrlAttribute)) - -databases - .command(`update-url-attribute`) - .description(`[**DEPRECATED** - This command is deprecated. Please use 'tables-db update-url-column' instead] Update an url attribute. Changing the 'default' value will not update already existing documents. `) - .requiredOption(`--database-id `, `Database ID.`) - .requiredOption(`--collection-id `, `Collection ID.`) - .requiredOption(`--key `, `Attribute Key.`) - .requiredOption(`--required [value]`, `Is attribute required?`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .option(`--xdefault `, `Default value for attribute when not provided. Cannot be set when attribute is required.`) - .option(`--new-key `, `New Attribute Key.`) - .action(actionRunner(databasesUpdateUrlAttribute)) - -databases - .command(`get-attribute`) - .description(`[**DEPRECATED** - This command is deprecated. Please use 'tables-db get-column' instead] Get attribute by ID.`) - .requiredOption(`--database-id `, `Database ID.`) - .requiredOption(`--collection-id `, `Collection ID.`) - .requiredOption(`--key `, `Attribute Key.`) - .action(actionRunner(databasesGetAttribute)) - -databases - .command(`delete-attribute`) - .description(`[**DEPRECATED** - This command is deprecated. Please use 'tables-db delete-column' instead] Deletes an attribute.`) - .requiredOption(`--database-id `, `Database ID.`) - .requiredOption(`--collection-id `, `Collection ID.`) - .requiredOption(`--key `, `Attribute Key.`) - .action(actionRunner(databasesDeleteAttribute)) - -databases - .command(`update-relationship-attribute`) - .description(`[**DEPRECATED** - This command is deprecated. Please use 'tables-db update-relationship-column' instead] Update relationship attribute. [Learn more about relationship attributes](https://appwrite.io/docs/databases-relationships#relationship-attributes). `) - .requiredOption(`--database-id `, `Database ID.`) - .requiredOption(`--collection-id `, `Collection ID.`) - .requiredOption(`--key `, `Attribute Key.`) - .option(`--on-delete `, `Constraints option`) - .option(`--new-key `, `New Attribute Key.`) - .action(actionRunner(databasesUpdateRelationshipAttribute)) - -databases - .command(`list-documents`) - .description(`[**DEPRECATED** - This command is deprecated. Please use 'tables-db list-rows' instead] Get a list of all the user's documents in a given collection. You can use the query params to filter your results.`) - .requiredOption(`--database-id `, `Database ID.`) - .requiredOption(`--collection-id `, `Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection).`) - .option(`--queries [queries...]`, `Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of 100 queries are allowed, each 4096 characters long.`) - .option(`--transaction-id `, `Transaction ID to read uncommitted changes within the transaction.`) - .option(`--total [value]`, `When set to false, the total count returned will be 0 and will not be calculated.`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .option(`--console`, `Get the resource console url`) - .action(actionRunner(databasesListDocuments)) - -databases - .command(`create-document`) - .description(`[**DEPRECATED** - This command is deprecated. Please use 'tables-db create-row' instead] Create a new Document. Before using this route, you should create a new collection resource using either a [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection) API or directly from your database console.`) - .requiredOption(`--database-id `, `Database ID.`) - .requiredOption(`--collection-id `, `Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection). Make sure to define attributes before creating documents.`) - .requiredOption(`--document-id `, `Document ID. Choose a custom ID or generate a random ID with 'ID.unique()'. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.`) - .requiredOption(`--data `, `Document data as JSON object.`) - .option(`--permissions [permissions...]`, `An array of permissions strings. By default, only the current user is granted all permissions. [Learn more about permissions](https://appwrite.io/docs/permissions).`) - .option(`--transaction-id `, `Transaction ID for staging the operation.`) - .action(actionRunner(databasesCreateDocument)) - -databases - .command(`create-documents`) - .description(`[**DEPRECATED** - This command is deprecated. Please use 'tables-db create-rows' instead] Create new Documents. Before using this route, you should create a new collection resource using either a [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection) API or directly from your database console.`) - .requiredOption(`--database-id `, `Database ID.`) - .requiredOption(`--collection-id `, `Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection). Make sure to define attributes before creating documents.`) - .requiredOption(`--documents [documents...]`, `Array of documents data as JSON objects.`) - .option(`--transaction-id `, `Transaction ID for staging the operation.`) - .action(actionRunner(databasesCreateDocuments)) - -databases - .command(`upsert-documents`) - .description(`[**DEPRECATED** - This command is deprecated. Please use 'tables-db upsert-rows' instead] Create or update Documents. Before using this route, you should create a new collection resource using either a [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection) API or directly from your database console. `) - .requiredOption(`--database-id `, `Database ID.`) - .requiredOption(`--collection-id `, `Collection ID.`) - .requiredOption(`--documents [documents...]`, `Array of document data as JSON objects. May contain partial documents.`) - .option(`--transaction-id `, `Transaction ID for staging the operation.`) - .action(actionRunner(databasesUpsertDocuments)) - -databases - .command(`update-documents`) - .description(`[**DEPRECATED** - This command is deprecated. Please use 'tables-db update-rows' instead] Update all documents that match your queries, if no queries are submitted then all documents are updated. You can pass only specific fields to be updated.`) - .requiredOption(`--database-id `, `Database ID.`) - .requiredOption(`--collection-id `, `Collection ID.`) - .option(`--data `, `Document data as JSON object. Include only attribute and value pairs to be updated.`) - .option(`--queries [queries...]`, `Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of 100 queries are allowed, each 4096 characters long.`) - .option(`--transaction-id `, `Transaction ID for staging the operation.`) - .action(actionRunner(databasesUpdateDocuments)) - -databases - .command(`delete-documents`) - .description(`[**DEPRECATED** - This command is deprecated. Please use 'tables-db delete-rows' instead] Bulk delete documents using queries, if no queries are passed then all documents are deleted.`) - .requiredOption(`--database-id `, `Database ID.`) - .requiredOption(`--collection-id `, `Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection).`) - .option(`--queries [queries...]`, `Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of 100 queries are allowed, each 4096 characters long.`) - .option(`--transaction-id `, `Transaction ID for staging the operation.`) - .action(actionRunner(databasesDeleteDocuments)) - -databases - .command(`get-document`) - .description(`[**DEPRECATED** - This command is deprecated. Please use 'tables-db get-row' instead] Get a document by its unique ID. This endpoint response returns a JSON object with the document data.`) - .requiredOption(`--database-id `, `Database ID.`) - .requiredOption(`--collection-id `, `Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection).`) - .requiredOption(`--document-id `, `Document ID.`) - .option(`--queries [queries...]`, `Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of 100 queries are allowed, each 4096 characters long.`) - .option(`--transaction-id `, `Transaction ID to read uncommitted changes within the transaction.`) - .option(`--console`, `Get the resource console url`) - .action(actionRunner(databasesGetDocument)) - -databases - .command(`upsert-document`) - .description(`[**DEPRECATED** - This command is deprecated. Please use 'tables-db upsert-row' instead] Create or update a Document. Before using this route, you should create a new collection resource using either a [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection) API or directly from your database console.`) - .requiredOption(`--database-id `, `Database ID.`) - .requiredOption(`--collection-id `, `Collection ID.`) - .requiredOption(`--document-id `, `Document ID.`) - .option(`--data `, `Document data as JSON object. Include all required attributes of the document to be created or updated.`) - .option(`--permissions [permissions...]`, `An array of permissions strings. By default, the current permissions are inherited. [Learn more about permissions](https://appwrite.io/docs/permissions).`) - .option(`--transaction-id `, `Transaction ID for staging the operation.`) - .action(actionRunner(databasesUpsertDocument)) - -databases - .command(`update-document`) - .description(`[**DEPRECATED** - This command is deprecated. Please use 'tables-db update-row' instead] Update a document by its unique ID. Using the patch method you can pass only specific fields that will get updated.`) - .requiredOption(`--database-id `, `Database ID.`) - .requiredOption(`--collection-id `, `Collection ID.`) - .requiredOption(`--document-id `, `Document ID.`) - .option(`--data `, `Document data as JSON object. Include only attribute and value pairs to be updated.`) - .option(`--permissions [permissions...]`, `An array of permissions strings. By default, the current permissions are inherited. [Learn more about permissions](https://appwrite.io/docs/permissions).`) - .option(`--transaction-id `, `Transaction ID for staging the operation.`) - .action(actionRunner(databasesUpdateDocument)) - -databases - .command(`delete-document`) - .description(`[**DEPRECATED** - This command is deprecated. Please use 'tables-db delete-row' instead] Delete a document by its unique ID.`) - .requiredOption(`--database-id `, `Database ID.`) - .requiredOption(`--collection-id `, `Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection).`) - .requiredOption(`--document-id `, `Document ID.`) - .option(`--transaction-id `, `Transaction ID for staging the operation.`) - .action(actionRunner(databasesDeleteDocument)) - -databases - .command(`list-document-logs`) - .description(`[**DEPRECATED** - This command is deprecated. Please use 'tables-db list-row-logs' instead] Get the document activity logs list by its unique ID.`) - .requiredOption(`--database-id `, `Database ID.`) - .requiredOption(`--collection-id `, `Collection ID.`) - .requiredOption(`--document-id `, `Document ID.`) - .option(`--queries [queries...]`, `Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Only supported methods are limit and offset`) - .action(actionRunner(databasesListDocumentLogs)) - -databases - .command(`decrement-document-attribute`) - .description(`[**DEPRECATED** - This command is deprecated. Please use 'tables-db decrement-row-column' instead] Decrement a specific attribute of a document by a given value.`) - .requiredOption(`--database-id `, `Database ID.`) - .requiredOption(`--collection-id `, `Collection ID.`) - .requiredOption(`--document-id `, `Document ID.`) - .requiredOption(`--attribute `, `Attribute key.`) - .option(`--value `, `Value to increment the attribute by. The value must be a number.`, parseInteger) - .option(`--min `, `Minimum value for the attribute. If the current value is lesser than this value, an exception will be thrown.`, parseInteger) - .option(`--transaction-id `, `Transaction ID for staging the operation.`) - .action(actionRunner(databasesDecrementDocumentAttribute)) - -databases - .command(`increment-document-attribute`) - .description(`[**DEPRECATED** - This command is deprecated. Please use 'tables-db increment-row-column' instead] Increment a specific attribute of a document by a given value.`) - .requiredOption(`--database-id `, `Database ID.`) - .requiredOption(`--collection-id `, `Collection ID.`) - .requiredOption(`--document-id `, `Document ID.`) - .requiredOption(`--attribute `, `Attribute key.`) - .option(`--value `, `Value to increment the attribute by. The value must be a number.`, parseInteger) - .option(`--max `, `Maximum value for the attribute. If the current value is greater than this value, an error will be thrown.`, parseInteger) - .option(`--transaction-id `, `Transaction ID for staging the operation.`) - .action(actionRunner(databasesIncrementDocumentAttribute)) - -databases - .command(`list-indexes`) - .description(`[**DEPRECATED** - This command is deprecated. Please use 'tables-db list-indexes' instead] List indexes in the collection.`) - .requiredOption(`--database-id `, `Database ID.`) - .requiredOption(`--collection-id `, `Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection).`) - .option(`--queries [queries...]`, `Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: key, type, status, attributes, error`) - .option(`--total [value]`, `When set to false, the total count returned will be 0 and will not be calculated.`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .option(`--console`, `Get the resource console url`) - .action(actionRunner(databasesListIndexes)) - -databases - .command(`create-index`) - .description(`[**DEPRECATED** - This command is deprecated. Please use 'tables-db create-index' instead] Creates an index on the attributes listed. Your index should include all the attributes you will query in a single request. Attributes can be 'key', 'fulltext', and 'unique'.`) - .requiredOption(`--database-id `, `Database ID.`) - .requiredOption(`--collection-id `, `Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection).`) - .requiredOption(`--key `, `Index Key.`) - .requiredOption(`--type `, `Index type.`) - .requiredOption(`--attributes [attributes...]`, `Array of attributes to index. Maximum of 100 attributes are allowed, each 32 characters long.`) - .option(`--orders [orders...]`, `Array of index orders. Maximum of 100 orders are allowed.`) - .option(`--lengths [lengths...]`, `Length of index. Maximum of 100`) - .action(actionRunner(databasesCreateIndex)) - -databases - .command(`get-index`) - .description(`[**DEPRECATED** - This command is deprecated. Please use 'tables-db get-index' instead] Get an index by its unique ID.`) - .requiredOption(`--database-id `, `Database ID.`) - .requiredOption(`--collection-id `, `Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection).`) - .requiredOption(`--key `, `Index Key.`) - .action(actionRunner(databasesGetIndex)) - -databases - .command(`delete-index`) - .description(`[**DEPRECATED** - This command is deprecated. Please use 'tables-db delete-index' instead] Delete an index.`) - .requiredOption(`--database-id `, `Database ID.`) - .requiredOption(`--collection-id `, `Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection).`) - .requiredOption(`--key `, `Index Key.`) - .action(actionRunner(databasesDeleteIndex)) - -databases - .command(`list-collection-logs`) - .description(`[**DEPRECATED** - This command is deprecated. Please use 'tables-db list-table-logs' instead] Get the collection activity logs list by its unique ID.`) - .requiredOption(`--database-id `, `Database ID.`) - .requiredOption(`--collection-id `, `Collection ID.`) - .option(`--queries [queries...]`, `Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Only supported methods are limit and offset`) - .action(actionRunner(databasesListCollectionLogs)) - -databases - .command(`get-collection-usage`) - .description(`[**DEPRECATED** - This command is deprecated. Please use 'tables-db get-table-usage' instead] Get usage metrics and statistics for a collection. Returning the total number of documents. The response includes both current totals and historical data over time. Use the optional range parameter to specify the time window for historical data: 24h (last 24 hours), 30d (last 30 days), or 90d (last 90 days). If not specified, range defaults to 30 days.`) - .requiredOption(`--database-id `, `Database ID.`) - .requiredOption(`--collection-id `, `Collection ID.`) - .option(`--range `, `Date range.`) - .action(actionRunner(databasesGetCollectionUsage)) - -databases - .command(`list-logs`) - .description(`[**DEPRECATED** - This command is deprecated. Please use 'tables-db list-database-logs' instead] Get the database activity logs list by its unique ID.`) - .requiredOption(`--database-id `, `Database ID.`) - .option(`--queries [queries...]`, `Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Only supported methods are limit and offset`) - .action(actionRunner(databasesListLogs)) - -databases - .command(`get-usage`) - .description(`[**DEPRECATED** - This command is deprecated. Please use 'tables-db get-usage' instead] Get usage metrics and statistics for a database. You can view the total number of collections, documents, and storage usage. The response includes both current totals and historical data over time. Use the optional range parameter to specify the time window for historical data: 24h (last 24 hours), 30d (last 30 days), or 90d (last 90 days). If not specified, range defaults to 30 days.`) - .requiredOption(`--database-id `, `Database ID.`) - .option(`--range `, `Date range.`) - .action(actionRunner(databasesGetUsage)) - - diff --git a/lib/commands/functions.ts b/lib/commands/functions.ts deleted file mode 100644 index e592c00b..00000000 --- a/lib/commands/functions.ts +++ /dev/null @@ -1,1587 +0,0 @@ -import fs = require('fs'); -import pathLib = require('path'); -import tar = require('tar'); -import ignore = require('ignore'); -import { promisify } from 'util'; -import Client from '../client'; -import { getAllFiles, showConsoleLink } from '../utils'; -import { Command } from 'commander'; -import { sdkForProject, sdkForConsole } from '../sdks'; -import { parse, actionRunner, parseInteger, parseBool, commandDescriptions, success, log, warn } from '../parser'; -import { localConfig, globalConfig } from '../config'; -import { File } from 'undici'; -import { ReadableStream } from 'stream/web'; - -function convertReadStreamToReadableStream(readStream: fs.ReadStream): ReadableStream { - return new ReadableStream({ - start(controller) { - readStream.on("data", (chunk: Buffer) => { - controller.enqueue(chunk); - }); - readStream.on("end", () => { - controller.close(); - }); - readStream.on("error", (err: Error) => { - controller.error(err); - }); - }, - cancel() { - readStream.destroy(); - }, - }); -} - -export const functions = new Command("functions").description(commandDescriptions['functions'] ?? '').configureHelp({ - helpWidth: process.stdout.columns || 80 -}) - -interface FunctionsListRequestParams { - queries?: string[]; - search?: string; - total?: boolean; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; - console?: boolean; -} - -export const functionsList = async ({queries,search,total,parseOutput = true, overrideForCli = false, sdk = undefined, console: showConsole}: FunctionsListRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/functions'; - let payload = {}; - if (typeof queries !== 'undefined') { - payload['queries'] = queries; - } - if (typeof search !== 'undefined') { - payload['search'] = search; - } - if (typeof total !== 'undefined') { - payload['total'] = total; - } - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - if(showConsole) { - showConsoleLink('functions', 'list'); - } else { - parse(response) - } - } - - return response; - -} -interface FunctionsCreateRequestParams { - functionId: string; - name: string; - runtime: Runtime; - execute?: string[]; - events?: string[]; - schedule?: string; - timeout?: number; - enabled?: boolean; - logging?: boolean; - entrypoint?: string; - commands?: string; - scopes?: string[]; - installationId?: string; - providerRepositoryId?: string; - providerBranch?: string; - providerSilentMode?: boolean; - providerRootDirectory?: string; - specification?: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const functionsCreate = async ({functionId,name,runtime,execute,events,schedule,timeout,enabled,logging,entrypoint,commands,scopes,installationId,providerRepositoryId,providerBranch,providerSilentMode,providerRootDirectory,specification,parseOutput = true, overrideForCli = false, sdk = undefined}: FunctionsCreateRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/functions'; - let payload = {}; - if (typeof functionId !== 'undefined') { - payload['functionId'] = functionId; - } - if (typeof name !== 'undefined') { - payload['name'] = name; - } - if (typeof runtime !== 'undefined') { - payload['runtime'] = runtime; - } - execute = execute === true ? [] : execute; - if (typeof execute !== 'undefined') { - payload['execute'] = execute; - } - events = events === true ? [] : events; - if (typeof events !== 'undefined') { - payload['events'] = events; - } - if (typeof schedule !== 'undefined') { - payload['schedule'] = schedule; - } - if (typeof timeout !== 'undefined') { - payload['timeout'] = timeout; - } - if (typeof enabled !== 'undefined') { - payload['enabled'] = enabled; - } - if (typeof logging !== 'undefined') { - payload['logging'] = logging; - } - if (typeof entrypoint !== 'undefined') { - payload['entrypoint'] = entrypoint; - } - if (typeof commands !== 'undefined') { - payload['commands'] = commands; - } - scopes = scopes === true ? [] : scopes; - if (typeof scopes !== 'undefined') { - payload['scopes'] = scopes; - } - if (typeof installationId !== 'undefined') { - payload['installationId'] = installationId; - } - if (typeof providerRepositoryId !== 'undefined') { - payload['providerRepositoryId'] = providerRepositoryId; - } - if (typeof providerBranch !== 'undefined') { - payload['providerBranch'] = providerBranch; - } - if (typeof providerSilentMode !== 'undefined') { - payload['providerSilentMode'] = providerSilentMode; - } - if (typeof providerRootDirectory !== 'undefined') { - payload['providerRootDirectory'] = providerRootDirectory; - } - if (typeof specification !== 'undefined') { - payload['specification'] = specification; - } - - let response = undefined; - - response = await client.call('post', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface FunctionsListRuntimesRequestParams { - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const functionsListRuntimes = async ({parseOutput = true, overrideForCli = false, sdk = undefined}: FunctionsListRuntimesRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/functions/runtimes'; - let payload = {}; - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface FunctionsListSpecificationsRequestParams { - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; - console?: boolean; -} - -export const functionsListSpecifications = async ({parseOutput = true, overrideForCli = false, sdk = undefined, console: showConsole}: FunctionsListSpecificationsRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/functions/specifications'; - let payload = {}; - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - if(showConsole) { - showConsoleLink('functions', 'listSpecifications'); - } else { - parse(response) - } - } - - return response; - -} -interface FunctionsListTemplatesRequestParams { - runtimes?: string[]; - useCases?: string[]; - limit?: number; - offset?: number; - total?: boolean; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; - console?: boolean; -} - -export const functionsListTemplates = async ({runtimes,useCases,limit,offset,total,parseOutput = true, overrideForCli = false, sdk = undefined, console: showConsole}: FunctionsListTemplatesRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/functions/templates'; - let payload = {}; - if (typeof runtimes !== 'undefined') { - payload['runtimes'] = runtimes; - } - if (typeof useCases !== 'undefined') { - payload['useCases'] = useCases; - } - if (typeof limit !== 'undefined') { - payload['limit'] = limit; - } - if (typeof offset !== 'undefined') { - payload['offset'] = offset; - } - if (typeof total !== 'undefined') { - payload['total'] = total; - } - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - if(showConsole) { - showConsoleLink('functions', 'listTemplates'); - } else { - parse(response) - } - } - - return response; - -} -interface FunctionsGetTemplateRequestParams { - templateId: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; - console?: boolean; -} - -export const functionsGetTemplate = async ({templateId,parseOutput = true, overrideForCli = false, sdk = undefined, console: showConsole}: FunctionsGetTemplateRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/functions/templates/{templateId}'.replace('{templateId}', templateId); - let payload = {}; - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - if(showConsole) { - showConsoleLink('functions', 'getTemplate', templateId); - } else { - parse(response) - } - } - - return response; - -} -interface FunctionsListUsageRequestParams { - range?: UsageRange; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; - console?: boolean; -} - -export const functionsListUsage = async ({range,parseOutput = true, overrideForCli = false, sdk = undefined, console: showConsole}: FunctionsListUsageRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/functions/usage'; - let payload = {}; - if (typeof range !== 'undefined') { - payload['range'] = range; - } - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - if(showConsole) { - showConsoleLink('functions', 'listUsage'); - } else { - parse(response) - } - } - - return response; - -} -interface FunctionsGetRequestParams { - functionId: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; - console?: boolean; -} - -export const functionsGet = async ({functionId,parseOutput = true, overrideForCli = false, sdk = undefined, console: showConsole}: FunctionsGetRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/functions/{functionId}'.replace('{functionId}', functionId); - let payload = {}; - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - if(showConsole) { - showConsoleLink('functions', 'get', functionId); - } else { - parse(response) - } - } - - return response; - -} -interface FunctionsUpdateRequestParams { - functionId: string; - name: string; - runtime?: Runtime; - execute?: string[]; - events?: string[]; - schedule?: string; - timeout?: number; - enabled?: boolean; - logging?: boolean; - entrypoint?: string; - commands?: string; - scopes?: string[]; - installationId?: string; - providerRepositoryId?: string; - providerBranch?: string; - providerSilentMode?: boolean; - providerRootDirectory?: string; - specification?: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const functionsUpdate = async ({functionId,name,runtime,execute,events,schedule,timeout,enabled,logging,entrypoint,commands,scopes,installationId,providerRepositoryId,providerBranch,providerSilentMode,providerRootDirectory,specification,parseOutput = true, overrideForCli = false, sdk = undefined}: FunctionsUpdateRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/functions/{functionId}'.replace('{functionId}', functionId); - let payload = {}; - if (typeof name !== 'undefined') { - payload['name'] = name; - } - if (typeof runtime !== 'undefined') { - payload['runtime'] = runtime; - } - execute = execute === true ? [] : execute; - if (typeof execute !== 'undefined') { - payload['execute'] = execute; - } - events = events === true ? [] : events; - if (typeof events !== 'undefined') { - payload['events'] = events; - } - if (typeof schedule !== 'undefined') { - payload['schedule'] = schedule; - } - if (typeof timeout !== 'undefined') { - payload['timeout'] = timeout; - } - if (typeof enabled !== 'undefined') { - payload['enabled'] = enabled; - } - if (typeof logging !== 'undefined') { - payload['logging'] = logging; - } - if (typeof entrypoint !== 'undefined') { - payload['entrypoint'] = entrypoint; - } - if (typeof commands !== 'undefined') { - payload['commands'] = commands; - } - scopes = scopes === true ? [] : scopes; - if (typeof scopes !== 'undefined') { - payload['scopes'] = scopes; - } - if (typeof installationId !== 'undefined') { - payload['installationId'] = installationId; - } - if (typeof providerRepositoryId !== 'undefined') { - payload['providerRepositoryId'] = providerRepositoryId; - } - if (typeof providerBranch !== 'undefined') { - payload['providerBranch'] = providerBranch; - } - if (typeof providerSilentMode !== 'undefined') { - payload['providerSilentMode'] = providerSilentMode; - } - if (typeof providerRootDirectory !== 'undefined') { - payload['providerRootDirectory'] = providerRootDirectory; - } - if (typeof specification !== 'undefined') { - payload['specification'] = specification; - } - - let response = undefined; - - response = await client.call('put', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface FunctionsDeleteRequestParams { - functionId: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const functionsDelete = async ({functionId,parseOutput = true, overrideForCli = false, sdk = undefined}: FunctionsDeleteRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/functions/{functionId}'.replace('{functionId}', functionId); - let payload = {}; - - let response = undefined; - - response = await client.call('delete', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface FunctionsUpdateFunctionDeploymentRequestParams { - functionId: string; - deploymentId: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const functionsUpdateFunctionDeployment = async ({functionId,deploymentId,parseOutput = true, overrideForCli = false, sdk = undefined}: FunctionsUpdateFunctionDeploymentRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/functions/{functionId}/deployment'.replace('{functionId}', functionId); - let payload = {}; - if (typeof deploymentId !== 'undefined') { - payload['deploymentId'] = deploymentId; - } - - let response = undefined; - - response = await client.call('patch', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface FunctionsListDeploymentsRequestParams { - functionId: string; - queries?: string[]; - search?: string; - total?: boolean; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; - console?: boolean; -} - -export const functionsListDeployments = async ({functionId,queries,search,total,parseOutput = true, overrideForCli = false, sdk = undefined, console: showConsole}: FunctionsListDeploymentsRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/functions/{functionId}/deployments'.replace('{functionId}', functionId); - let payload = {}; - if (typeof queries !== 'undefined') { - payload['queries'] = queries; - } - if (typeof search !== 'undefined') { - payload['search'] = search; - } - if (typeof total !== 'undefined') { - payload['total'] = total; - } - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - if(showConsole) { - showConsoleLink('functions', 'listDeployments', functionId); - } else { - parse(response) - } - } - - return response; - -} -interface FunctionsCreateDeploymentRequestParams { - functionId: string; - code: string; - activate: boolean; - entrypoint?: string; - commands?: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; - onProgress?: (progress: number) => void; -} - -export const functionsCreateDeployment = async ({functionId,code,activate,entrypoint,commands,parseOutput = true, overrideForCli = false, sdk = undefined,onProgress = () => {}}: FunctionsCreateDeploymentRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/functions/{functionId}/deployments'.replace('{functionId}', functionId); - let payload = {}; - if (typeof entrypoint !== 'undefined') { - payload['entrypoint'] = entrypoint; - } - if (typeof commands !== 'undefined') { - payload['commands'] = commands; - } - const folderPath = fs.realpathSync(code); - if (!fs.lstatSync(folderPath).isDirectory()) { - throw new Error('The path is not a directory.'); - } - - const ignorer = ignore(); - - const resourceId = functionId; - const resourceConfig = localConfig.getFunction(resourceId); - - ignorer.add('.appwrite'); - - if (resourceConfig.ignore) { - ignorer.add(resourceConfig.ignore); - } else if (fs.existsSync(pathLib.join(code, '.gitignore'))) { - ignorer.add(fs.readFileSync(pathLib.join(code, '.gitignore')).toString()); - } - - const files = getAllFiles(code).map((file) => pathLib.relative(code, file)).filter((file) => !ignorer.ignores(file)); - - const archiveFileName = `functions-${resourceId}-code.tar.gz`; - - await tar - .create({ - gzip: true, - sync: true, - cwd: folderPath, - file: archiveFileName - }, files); - - let archivePath = fs.realpathSync(archiveFileName) - if (typeof archivePath !== 'undefined') { - payload['code'] = archivePath; - code = archivePath; - } - - const filePath = fs.realpathSync(code); - const nodeStream = fs.createReadStream(filePath); - const stream = convertReadStreamToReadableStream(nodeStream); - - if (typeof filePath !== 'undefined') { - code = { type: 'file', stream, filename: pathLib.basename(filePath), size: fs.statSync(filePath).size }; - payload['code'] = code - } - if (typeof activate !== 'undefined') { - payload['activate'] = activate; - } - - const size = code.size; - - const apiHeaders = { - 'content-type': 'multipart/form-data', - }; - - let id = undefined; - let response = undefined; - - let chunksUploaded = 0; - - let currentChunk = 1; - let currentPosition = 0; - let uploadableChunk = new Uint8Array(client.CHUNK_SIZE); - - const uploadChunk = async (lastUpload = false) => { - if(currentChunk <= chunksUploaded) { - return; - } - - const start = ((currentChunk - 1) * client.CHUNK_SIZE); - let end = start + currentPosition - 1; - - if(!lastUpload || currentChunk !== 1) { - apiHeaders['content-range'] = 'bytes ' + start + '-' + end + '/' + size; - } - - let uploadableChunkTrimmed; - - if(currentPosition + 1 >= client.CHUNK_SIZE) { - uploadableChunkTrimmed = uploadableChunk; - } else { - uploadableChunkTrimmed = new Uint8Array(currentPosition); - for(let i = 0; i <= currentPosition; i++) { - uploadableChunkTrimmed[i] = uploadableChunk[i]; - } - } - - if (id) { - apiHeaders['x-appwrite-id'] = id; - } - - payload['code'] = { type: 'file', file: new File([uploadableChunkTrimmed], code.filename), filename: code.filename }; - - response = await client.call('post', apiPath, apiHeaders, payload); - - if (!id) { - id = response['$id']; - } - - if (onProgress !== null) { - onProgress({ - $id: response['$id'], - progress: Math.min((currentChunk) * client.CHUNK_SIZE, size) / size * 100, - sizeUploaded: end+1, - chunksTotal: response['chunksTotal'], - chunksUploaded: response['chunksUploaded'] - }); - } - - uploadableChunk = new Uint8Array(client.CHUNK_SIZE); - currentChunk++; - currentPosition = 0; - } - - for await (const chunk of code.stream) { - for(const b of chunk) { - uploadableChunk[currentPosition] = b; - - currentPosition++; - if(currentPosition >= client.CHUNK_SIZE) { - await uploadChunk(); - currentPosition = 0; - } - } - } - - if (currentPosition > 0) { // Check if there's any remaining data for the last chunk - await uploadChunk(true); - } - - await fs.unlink(filePath,()=>{}); - - if (parseOutput) { - parse(response) - } - - return response; -} -interface FunctionsCreateDuplicateDeploymentRequestParams { - functionId: string; - deploymentId: string; - buildId?: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const functionsCreateDuplicateDeployment = async ({functionId,deploymentId,buildId,parseOutput = true, overrideForCli = false, sdk = undefined}: FunctionsCreateDuplicateDeploymentRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/functions/{functionId}/deployments/duplicate'.replace('{functionId}', functionId); - let payload = {}; - if (typeof deploymentId !== 'undefined') { - payload['deploymentId'] = deploymentId; - } - if (typeof buildId !== 'undefined') { - payload['buildId'] = buildId; - } - - let response = undefined; - - response = await client.call('post', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface FunctionsCreateTemplateDeploymentRequestParams { - functionId: string; - repository: string; - owner: string; - rootDirectory: string; - type: TemplateReferenceType; - reference: string; - activate?: boolean; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const functionsCreateTemplateDeployment = async ({functionId,repository,owner,rootDirectory,type,reference,activate,parseOutput = true, overrideForCli = false, sdk = undefined}: FunctionsCreateTemplateDeploymentRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/functions/{functionId}/deployments/template'.replace('{functionId}', functionId); - let payload = {}; - if (typeof repository !== 'undefined') { - payload['repository'] = repository; - } - if (typeof owner !== 'undefined') { - payload['owner'] = owner; - } - if (typeof rootDirectory !== 'undefined') { - payload['rootDirectory'] = rootDirectory; - } - if (typeof type !== 'undefined') { - payload['type'] = type; - } - if (typeof reference !== 'undefined') { - payload['reference'] = reference; - } - if (typeof activate !== 'undefined') { - payload['activate'] = activate; - } - - let response = undefined; - - response = await client.call('post', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface FunctionsCreateVcsDeploymentRequestParams { - functionId: string; - type: VCSReferenceType; - reference: string; - activate?: boolean; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const functionsCreateVcsDeployment = async ({functionId,type,reference,activate,parseOutput = true, overrideForCli = false, sdk = undefined}: FunctionsCreateVcsDeploymentRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/functions/{functionId}/deployments/vcs'.replace('{functionId}', functionId); - let payload = {}; - if (typeof type !== 'undefined') { - payload['type'] = type; - } - if (typeof reference !== 'undefined') { - payload['reference'] = reference; - } - if (typeof activate !== 'undefined') { - payload['activate'] = activate; - } - - let response = undefined; - - response = await client.call('post', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface FunctionsGetDeploymentRequestParams { - functionId: string; - deploymentId: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; - console?: boolean; -} - -export const functionsGetDeployment = async ({functionId,deploymentId,parseOutput = true, overrideForCli = false, sdk = undefined, console: showConsole}: FunctionsGetDeploymentRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/functions/{functionId}/deployments/{deploymentId}'.replace('{functionId}', functionId).replace('{deploymentId}', deploymentId); - let payload = {}; - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - if(showConsole) { - showConsoleLink('functions', 'getDeployment', functionId, deploymentId); - } else { - parse(response) - } - } - - return response; - -} -interface FunctionsDeleteDeploymentRequestParams { - functionId: string; - deploymentId: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const functionsDeleteDeployment = async ({functionId,deploymentId,parseOutput = true, overrideForCli = false, sdk = undefined}: FunctionsDeleteDeploymentRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/functions/{functionId}/deployments/{deploymentId}'.replace('{functionId}', functionId).replace('{deploymentId}', deploymentId); - let payload = {}; - - let response = undefined; - - response = await client.call('delete', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface FunctionsGetDeploymentDownloadRequestParams { - functionId: string; - deploymentId: string; - type?: DeploymentDownloadType; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; - destination?: string; - console?: boolean; -} - -export const functionsGetDeploymentDownload = async ({functionId,deploymentId,type,parseOutput = true, overrideForCli = false, sdk = undefined, destination, console: showConsole}: FunctionsGetDeploymentDownloadRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/functions/{functionId}/deployments/{deploymentId}/download'.replace('{functionId}', functionId).replace('{deploymentId}', deploymentId); - let payload = {}; - if (typeof type !== 'undefined') { - payload['type'] = type; - } - if (!overrideForCli) { - payload['project'] = localConfig.getProject().projectId - payload['key'] = globalConfig.getKey(); - const queryParams = new URLSearchParams(payload); - apiPath = `${globalConfig.getEndpoint()}${apiPath}?${queryParams.toString()}`; - } - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload, 'arraybuffer'); - - if (overrideForCli) { - response = Buffer.from(response); - } - - fs.writeFileSync(destination, response); - if (parseOutput) { - if(showConsole) { - showConsoleLink('functions', 'getDeploymentDownload', functionId, deploymentId); - } else { - parse(response) - } - } - - return response; - -} -interface FunctionsUpdateDeploymentStatusRequestParams { - functionId: string; - deploymentId: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const functionsUpdateDeploymentStatus = async ({functionId,deploymentId,parseOutput = true, overrideForCli = false, sdk = undefined}: FunctionsUpdateDeploymentStatusRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/functions/{functionId}/deployments/{deploymentId}/status'.replace('{functionId}', functionId).replace('{deploymentId}', deploymentId); - let payload = {}; - - let response = undefined; - - response = await client.call('patch', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface FunctionsListExecutionsRequestParams { - functionId: string; - queries?: string[]; - total?: boolean; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; - console?: boolean; -} - -export const functionsListExecutions = async ({functionId,queries,total,parseOutput = true, overrideForCli = false, sdk = undefined, console: showConsole}: FunctionsListExecutionsRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/functions/{functionId}/executions'.replace('{functionId}', functionId); - let payload = {}; - if (typeof queries !== 'undefined') { - payload['queries'] = queries; - } - if (typeof total !== 'undefined') { - payload['total'] = total; - } - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - if(showConsole) { - showConsoleLink('functions', 'listExecutions', functionId); - } else { - parse(response) - } - } - - return response; - -} -interface FunctionsCreateExecutionRequestParams { - functionId: string; - body?: string; - async?: boolean; - xpath?: string; - method?: ExecutionMethod; - headers?: object; - scheduledAt?: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const functionsCreateExecution = async ({functionId,body,async,xpath,method,headers,scheduledAt,parseOutput = true, overrideForCli = false, sdk = undefined}: FunctionsCreateExecutionRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/functions/{functionId}/executions'.replace('{functionId}', functionId); - let payload = {}; - if (typeof body !== 'undefined') { - payload['body'] = body; - } - if (typeof async !== 'undefined') { - payload['async'] = async; - } - if (typeof xpath !== 'undefined') { - payload['path'] = xpath; - } - if (typeof method !== 'undefined') { - payload['method'] = method; - } - if (typeof headers !== 'undefined') { - payload['headers'] = JSON.parse(headers); - } - if (typeof scheduledAt !== 'undefined') { - payload['scheduledAt'] = scheduledAt; - } - - let response = undefined; - - response = await client.call('post', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface FunctionsGetExecutionRequestParams { - functionId: string; - executionId: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; - console?: boolean; -} - -export const functionsGetExecution = async ({functionId,executionId,parseOutput = true, overrideForCli = false, sdk = undefined, console: showConsole}: FunctionsGetExecutionRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/functions/{functionId}/executions/{executionId}'.replace('{functionId}', functionId).replace('{executionId}', executionId); - let payload = {}; - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - if(showConsole) { - showConsoleLink('functions', 'getExecution', functionId, executionId); - } else { - parse(response) - } - } - - return response; - -} -interface FunctionsDeleteExecutionRequestParams { - functionId: string; - executionId: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const functionsDeleteExecution = async ({functionId,executionId,parseOutput = true, overrideForCli = false, sdk = undefined}: FunctionsDeleteExecutionRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/functions/{functionId}/executions/{executionId}'.replace('{functionId}', functionId).replace('{executionId}', executionId); - let payload = {}; - - let response = undefined; - - response = await client.call('delete', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface FunctionsGetUsageRequestParams { - functionId: string; - range?: UsageRange; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const functionsGetUsage = async ({functionId,range,parseOutput = true, overrideForCli = false, sdk = undefined}: FunctionsGetUsageRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/functions/{functionId}/usage'.replace('{functionId}', functionId); - let payload = {}; - if (typeof range !== 'undefined') { - payload['range'] = range; - } - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface FunctionsListVariablesRequestParams { - functionId: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const functionsListVariables = async ({functionId,parseOutput = true, overrideForCli = false, sdk = undefined}: FunctionsListVariablesRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/functions/{functionId}/variables'.replace('{functionId}', functionId); - let payload = {}; - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface FunctionsCreateVariableRequestParams { - functionId: string; - key: string; - value: string; - secret?: boolean; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const functionsCreateVariable = async ({functionId,key,value,secret,parseOutput = true, overrideForCli = false, sdk = undefined}: FunctionsCreateVariableRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/functions/{functionId}/variables'.replace('{functionId}', functionId); - let payload = {}; - if (typeof key !== 'undefined') { - payload['key'] = key; - } - if (typeof value !== 'undefined') { - payload['value'] = value; - } - if (typeof secret !== 'undefined') { - payload['secret'] = secret; - } - - let response = undefined; - - response = await client.call('post', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface FunctionsGetVariableRequestParams { - functionId: string; - variableId: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const functionsGetVariable = async ({functionId,variableId,parseOutput = true, overrideForCli = false, sdk = undefined}: FunctionsGetVariableRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/functions/{functionId}/variables/{variableId}'.replace('{functionId}', functionId).replace('{variableId}', variableId); - let payload = {}; - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface FunctionsUpdateVariableRequestParams { - functionId: string; - variableId: string; - key: string; - value?: string; - secret?: boolean; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const functionsUpdateVariable = async ({functionId,variableId,key,value,secret,parseOutput = true, overrideForCli = false, sdk = undefined}: FunctionsUpdateVariableRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/functions/{functionId}/variables/{variableId}'.replace('{functionId}', functionId).replace('{variableId}', variableId); - let payload = {}; - if (typeof key !== 'undefined') { - payload['key'] = key; - } - if (typeof value !== 'undefined') { - payload['value'] = value; - } - if (typeof secret !== 'undefined') { - payload['secret'] = secret; - } - - let response = undefined; - - response = await client.call('put', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface FunctionsDeleteVariableRequestParams { - functionId: string; - variableId: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const functionsDeleteVariable = async ({functionId,variableId,parseOutput = true, overrideForCli = false, sdk = undefined}: FunctionsDeleteVariableRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/functions/{functionId}/variables/{variableId}'.replace('{functionId}', functionId).replace('{variableId}', variableId); - let payload = {}; - - let response = undefined; - - response = await client.call('delete', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -functions - .command(`list`) - .description(`Get a list of all the project's functions. You can use the query params to filter your results.`) - .option(`--queries [queries...]`, `Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: name, enabled, runtime, deploymentId, schedule, scheduleNext, schedulePrevious, timeout, entrypoint, commands, installationId`) - .option(`--search `, `Search term to filter your list results. Max length: 256 chars.`) - .option(`--total [value]`, `When set to false, the total count returned will be 0 and will not be calculated.`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .option(`--console`, `Get the resource console url`) - .action(actionRunner(functionsList)) - -functions - .command(`create`) - .description(`Create a new function. You can pass a list of [permissions](https://appwrite.io/docs/permissions) to allow different project users or team with access to execute the function using the client API.`) - .requiredOption(`--function-id `, `Function ID. Choose a custom ID or generate a random ID with 'ID.unique()'. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.`) - .requiredOption(`--name `, `Function name. Max length: 128 chars.`) - .requiredOption(`--runtime `, `Execution runtime.`) - .option(`--execute [execute...]`, `An array of role strings with execution permissions. By default no user is granted with any execute permissions. [learn more about roles](https://appwrite.io/docs/permissions#permission-roles). Maximum of 100 roles are allowed, each 64 characters long.`) - .option(`--events [events...]`, `Events list. Maximum of 100 events are allowed.`) - .option(`--schedule `, `Schedule CRON syntax.`) - .option(`--timeout `, `Function maximum execution time in seconds.`, parseInteger) - .option(`--enabled [value]`, `Is function enabled? When set to 'disabled', users cannot access the function but Server SDKs with and API key can still access the function. No data is lost when this is toggled.`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .option(`--logging [value]`, `When disabled, executions will exclude logs and errors, and will be slightly faster.`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .option(`--entrypoint `, `Entrypoint File. This path is relative to the "providerRootDirectory".`) - .option(`--commands `, `Build Commands.`) - .option(`--scopes [scopes...]`, `List of scopes allowed for API key auto-generated for every execution. Maximum of 100 scopes are allowed.`) - .option(`--installation-id `, `Appwrite Installation ID for VCS (Version Control System) deployment.`) - .option(`--provider-repository-id `, `Repository ID of the repo linked to the function.`) - .option(`--provider-branch `, `Production branch for the repo linked to the function.`) - .option(`--provider-silent-mode [value]`, `Is the VCS (Version Control System) connection in silent mode for the repo linked to the function? In silent mode, comments will not be made on commits and pull requests.`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .option(`--provider-root-directory `, `Path to function code in the linked repo.`) - .option(`--specification `, `Runtime specification for the function and builds.`) - .action(actionRunner(functionsCreate)) - -functions - .command(`list-runtimes`) - .description(`Get a list of all runtimes that are currently active on your instance.`) - .action(actionRunner(functionsListRuntimes)) - -functions - .command(`list-specifications`) - .description(`List allowed function specifications for this instance.`) - .option(`--console`, `Get the resource console url`) - .action(actionRunner(functionsListSpecifications)) - -functions - .command(`list-templates`) - .description(`List available function templates. You can use template details in [createFunction](/docs/references/cloud/server-nodejs/functions#create) method.`) - .option(`--runtimes [runtimes...]`, `List of runtimes allowed for filtering function templates. Maximum of 100 runtimes are allowed.`) - .option(`--use-cases [use-cases...]`, `List of use cases allowed for filtering function templates. Maximum of 100 use cases are allowed.`) - .option(`--limit `, `Limit the number of templates returned in the response. Default limit is 25, and maximum limit is 5000.`, parseInteger) - .option(`--offset `, `Offset the list of returned templates. Maximum offset is 5000.`, parseInteger) - .option(`--total [value]`, `When set to false, the total count returned will be 0 and will not be calculated.`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .option(`--console`, `Get the resource console url`) - .action(actionRunner(functionsListTemplates)) - -functions - .command(`get-template`) - .description(`Get a function template using ID. You can use template details in [createFunction](/docs/references/cloud/server-nodejs/functions#create) method.`) - .requiredOption(`--template-id `, `Template ID.`) - .option(`--console`, `Get the resource console url`) - .action(actionRunner(functionsGetTemplate)) - -functions - .command(`list-usage`) - .description(`Get usage metrics and statistics for all functions in the project. View statistics including total deployments, builds, logs, storage usage, and compute time. The response includes both current totals and historical data for each metric. Use the optional range parameter to specify the time window for historical data: 24h (last 24 hours), 30d (last 30 days), or 90d (last 90 days). If not specified, defaults to 30 days.`) - .option(`--range `, `Date range.`) - .option(`--console`, `Get the resource console url`) - .action(actionRunner(functionsListUsage)) - -functions - .command(`get`) - .description(`Get a function by its unique ID.`) - .requiredOption(`--function-id `, `Function ID.`) - .option(`--console`, `Get the resource console url`) - .action(actionRunner(functionsGet)) - -functions - .command(`update`) - .description(`Update function by its unique ID.`) - .requiredOption(`--function-id `, `Function ID.`) - .requiredOption(`--name `, `Function name. Max length: 128 chars.`) - .option(`--runtime `, `Execution runtime.`) - .option(`--execute [execute...]`, `An array of role strings with execution permissions. By default no user is granted with any execute permissions. [learn more about roles](https://appwrite.io/docs/permissions#permission-roles). Maximum of 100 roles are allowed, each 64 characters long.`) - .option(`--events [events...]`, `Events list. Maximum of 100 events are allowed.`) - .option(`--schedule `, `Schedule CRON syntax.`) - .option(`--timeout `, `Maximum execution time in seconds.`, parseInteger) - .option(`--enabled [value]`, `Is function enabled? When set to 'disabled', users cannot access the function but Server SDKs with and API key can still access the function. No data is lost when this is toggled.`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .option(`--logging [value]`, `When disabled, executions will exclude logs and errors, and will be slightly faster.`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .option(`--entrypoint `, `Entrypoint File. This path is relative to the "providerRootDirectory".`) - .option(`--commands `, `Build Commands.`) - .option(`--scopes [scopes...]`, `List of scopes allowed for API Key auto-generated for every execution. Maximum of 100 scopes are allowed.`) - .option(`--installation-id `, `Appwrite Installation ID for VCS (Version Controle System) deployment.`) - .option(`--provider-repository-id `, `Repository ID of the repo linked to the function`) - .option(`--provider-branch `, `Production branch for the repo linked to the function`) - .option(`--provider-silent-mode [value]`, `Is the VCS (Version Control System) connection in silent mode for the repo linked to the function? In silent mode, comments will not be made on commits and pull requests.`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .option(`--provider-root-directory `, `Path to function code in the linked repo.`) - .option(`--specification `, `Runtime specification for the function and builds.`) - .action(actionRunner(functionsUpdate)) - -functions - .command(`delete`) - .description(`Delete a function by its unique ID.`) - .requiredOption(`--function-id `, `Function ID.`) - .action(actionRunner(functionsDelete)) - -functions - .command(`update-function-deployment`) - .description(`Update the function active deployment. Use this endpoint to switch the code deployment that should be used when visitor opens your function.`) - .requiredOption(`--function-id `, `Function ID.`) - .requiredOption(`--deployment-id `, `Deployment ID.`) - .action(actionRunner(functionsUpdateFunctionDeployment)) - -functions - .command(`list-deployments`) - .description(`Get a list of all the function's code deployments. You can use the query params to filter your results.`) - .requiredOption(`--function-id `, `Function ID.`) - .option(`--queries [queries...]`, `Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: buildSize, sourceSize, totalSize, buildDuration, status, activate, type`) - .option(`--search `, `Search term to filter your list results. Max length: 256 chars.`) - .option(`--total [value]`, `When set to false, the total count returned will be 0 and will not be calculated.`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .option(`--console`, `Get the resource console url`) - .action(actionRunner(functionsListDeployments)) - -functions - .command(`create-deployment`) - .description(`Create a new function code deployment. Use this endpoint to upload a new version of your code function. To execute your newly uploaded code, you'll need to update the function's deployment to use your new deployment UID. This endpoint accepts a tar.gz file compressed with your code. Make sure to include any dependencies your code has within the compressed file. You can learn more about code packaging in the [Appwrite Cloud Functions tutorial](https://appwrite.io/docs/functions). Use the "command" param to set the entrypoint used to execute your code.`) - .requiredOption(`--function-id `, `Function ID.`) - .requiredOption(`--code `, `Gzip file with your code package. When used with the Appwrite CLI, pass the path to your code directory, and the CLI will automatically package your code. Use a path that is within the current directory.`) - .requiredOption(`--activate [value]`, `Automatically activate the deployment when it is finished building.`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .option(`--entrypoint `, `Entrypoint File.`) - .option(`--commands `, `Build Commands.`) - .action(actionRunner(functionsCreateDeployment)) - -functions - .command(`create-duplicate-deployment`) - .description(`Create a new build for an existing function deployment. This endpoint allows you to rebuild a deployment with the updated function configuration, including its entrypoint and build commands if they have been modified. The build process will be queued and executed asynchronously. The original deployment's code will be preserved and used for the new build.`) - .requiredOption(`--function-id `, `Function ID.`) - .requiredOption(`--deployment-id `, `Deployment ID.`) - .option(`--build-id `, `Build unique ID.`) - .action(actionRunner(functionsCreateDuplicateDeployment)) - -functions - .command(`create-template-deployment`) - .description(`Create a deployment based on a template. Use this endpoint with combination of [listTemplates](https://appwrite.io/docs/products/functions/templates) to find the template details.`) - .requiredOption(`--function-id `, `Function ID.`) - .requiredOption(`--repository `, `Repository name of the template.`) - .requiredOption(`--owner `, `The name of the owner of the template.`) - .requiredOption(`--root-directory `, `Path to function code in the template repo.`) - .requiredOption(`--type `, `Type for the reference provided. Can be commit, branch, or tag`) - .requiredOption(`--reference `, `Reference value, can be a commit hash, branch name, or release tag`) - .option(`--activate [value]`, `Automatically activate the deployment when it is finished building.`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .action(actionRunner(functionsCreateTemplateDeployment)) - -functions - .command(`create-vcs-deployment`) - .description(`Create a deployment when a function is connected to VCS. This endpoint lets you create deployment from a branch, commit, or a tag.`) - .requiredOption(`--function-id `, `Function ID.`) - .requiredOption(`--type `, `Type of reference passed. Allowed values are: branch, commit`) - .requiredOption(`--reference `, `VCS reference to create deployment from. Depending on type this can be: branch name, commit hash`) - .option(`--activate [value]`, `Automatically activate the deployment when it is finished building.`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .action(actionRunner(functionsCreateVcsDeployment)) - -functions - .command(`get-deployment`) - .description(`Get a function deployment by its unique ID.`) - .requiredOption(`--function-id `, `Function ID.`) - .requiredOption(`--deployment-id `, `Deployment ID.`) - .option(`--console`, `Get the resource console url`) - .action(actionRunner(functionsGetDeployment)) - -functions - .command(`delete-deployment`) - .description(`Delete a code deployment by its unique ID.`) - .requiredOption(`--function-id `, `Function ID.`) - .requiredOption(`--deployment-id `, `Deployment ID.`) - .action(actionRunner(functionsDeleteDeployment)) - -functions - .command(`get-deployment-download`) - .description(`Get a function deployment content by its unique ID. The endpoint response return with a 'Content-Disposition: attachment' header that tells the browser to start downloading the file to user downloads directory.`) - .requiredOption(`--function-id `, `Function ID.`) - .requiredOption(`--deployment-id `, `Deployment ID.`) - .option(`--type `, `Deployment file to download. Can be: "source", "output".`) - .requiredOption(`--destination `, `output file path.`) - .option(`--console`, `Get the resource console url`) - .action(actionRunner(functionsGetDeploymentDownload)) - -functions - .command(`update-deployment-status`) - .description(`Cancel an ongoing function deployment build. If the build is already in progress, it will be stopped and marked as canceled. If the build hasn't started yet, it will be marked as canceled without executing. You cannot cancel builds that have already completed (status 'ready') or failed. The response includes the final build status and details.`) - .requiredOption(`--function-id `, `Function ID.`) - .requiredOption(`--deployment-id `, `Deployment ID.`) - .action(actionRunner(functionsUpdateDeploymentStatus)) - -functions - .command(`list-executions`) - .description(`Get a list of all the current user function execution logs. You can use the query params to filter your results.`) - .requiredOption(`--function-id `, `Function ID.`) - .option(`--queries [queries...]`, `Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: trigger, status, responseStatusCode, duration, requestMethod, requestPath, deploymentId`) - .option(`--total [value]`, `When set to false, the total count returned will be 0 and will not be calculated.`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .option(`--console`, `Get the resource console url`) - .action(actionRunner(functionsListExecutions)) - -functions - .command(`create-execution`) - .description(`Trigger a function execution. The returned object will return you the current execution status. You can ping the 'Get Execution' endpoint to get updates on the current execution status. Once this endpoint is called, your function execution process will start asynchronously.`) - .requiredOption(`--function-id `, `Function ID.`) - .option(`--body `, `HTTP body of execution. Default value is empty string.`) - .option(`--async [value]`, `Execute code in the background. Default value is false.`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .option(`--xpath `, `HTTP path of execution. Path can include query params. Default value is /`) - .option(`--method `, `HTTP method of execution. Default value is POST.`) - .option(`--headers `, `HTTP headers of execution. Defaults to empty.`) - .option(`--scheduled-at `, `Scheduled execution time in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format. DateTime value must be in future with precision in minutes.`) - .action(actionRunner(functionsCreateExecution)) - -functions - .command(`get-execution`) - .description(`Get a function execution log by its unique ID.`) - .requiredOption(`--function-id `, `Function ID.`) - .requiredOption(`--execution-id `, `Execution ID.`) - .option(`--console`, `Get the resource console url`) - .action(actionRunner(functionsGetExecution)) - -functions - .command(`delete-execution`) - .description(`Delete a function execution by its unique ID.`) - .requiredOption(`--function-id `, `Function ID.`) - .requiredOption(`--execution-id `, `Execution ID.`) - .action(actionRunner(functionsDeleteExecution)) - -functions - .command(`get-usage`) - .description(`Get usage metrics and statistics for a for a specific function. View statistics including total deployments, builds, executions, storage usage, and compute time. The response includes both current totals and historical data for each metric. Use the optional range parameter to specify the time window for historical data: 24h (last 24 hours), 30d (last 30 days), or 90d (last 90 days). If not specified, defaults to 30 days.`) - .requiredOption(`--function-id `, `Function ID.`) - .option(`--range `, `Date range.`) - .action(actionRunner(functionsGetUsage)) - -functions - .command(`list-variables`) - .description(`Get a list of all variables of a specific function.`) - .requiredOption(`--function-id `, `Function unique ID.`) - .action(actionRunner(functionsListVariables)) - -functions - .command(`create-variable`) - .description(`Create a new function environment variable. These variables can be accessed in the function at runtime as environment variables.`) - .requiredOption(`--function-id `, `Function unique ID.`) - .requiredOption(`--key `, `Variable key. Max length: 255 chars.`) - .requiredOption(`--value `, `Variable value. Max length: 8192 chars.`) - .option(`--secret [value]`, `Secret variables can be updated or deleted, but only functions can read them during build and runtime.`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .action(actionRunner(functionsCreateVariable)) - -functions - .command(`get-variable`) - .description(`Get a variable by its unique ID.`) - .requiredOption(`--function-id `, `Function unique ID.`) - .requiredOption(`--variable-id `, `Variable unique ID.`) - .action(actionRunner(functionsGetVariable)) - -functions - .command(`update-variable`) - .description(`Update variable by its unique ID.`) - .requiredOption(`--function-id `, `Function unique ID.`) - .requiredOption(`--variable-id `, `Variable unique ID.`) - .requiredOption(`--key `, `Variable key. Max length: 255 chars.`) - .option(`--value `, `Variable value. Max length: 8192 chars.`) - .option(`--secret [value]`, `Secret variables can be updated or deleted, but only functions can read them during build and runtime.`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .action(actionRunner(functionsUpdateVariable)) - -functions - .command(`delete-variable`) - .description(`Delete a variable by its unique ID.`) - .requiredOption(`--function-id `, `Function unique ID.`) - .requiredOption(`--variable-id `, `Variable unique ID.`) - .action(actionRunner(functionsDeleteVariable)) - - diff --git a/lib/commands/generic.ts b/lib/commands/generic.ts index 5dfc962d..0115c394 100644 --- a/lib/commands/generic.ts +++ b/lib/commands/generic.ts @@ -1,338 +1,440 @@ -import inquirer from 'inquirer'; -import { Command } from 'commander'; -import Client from '../client'; -import { sdkForConsole } from '../sdks'; -import { globalConfig, localConfig } from '../config'; -import { actionRunner, success, parseBool, commandDescriptions, error, parse, hint, log, drawTable, cliConfig } from '../parser'; -import ID from '../id'; -import { questionsLogin, questionsLogout, questionsListFactors, questionsMFAChallenge } from '../questions'; -import { accountUpdateMFAChallenge, accountCreateMFAChallenge, accountGet, accountCreateEmailPasswordSession, accountDeleteSession } from './account'; - -const DEFAULT_ENDPOINT = 'https://cloud.appwrite.io/v1'; +import inquirer from "inquirer"; +import { Command } from "commander"; +import { Client } from "@appwrite.io/console"; +import { sdkForConsole } from "../sdks.js"; +import { globalConfig, localConfig } from "../config.js"; +import { + actionRunner, + success, + parseBool, + commandDescriptions, + error, + parse, + hint, + log, + drawTable, + cliConfig, +} from "../parser.js"; +import ID from "../id.js"; +import { + questionsLogin, + questionsLogout, + questionsListFactors, + questionsMFAChallenge, +} from "../questions.js"; +import { Account, Client as ConsoleClient } from "@appwrite.io/console"; +import ClientLegacy from "../client.js"; + +const DEFAULT_ENDPOINT = "https://cloud.appwrite.io/v1"; interface LoginCommandOptions { - email?: string; - password?: string; - endpoint?: string; - mfa?: string; - code?: string; + email?: string; + password?: string; + endpoint?: string; + mfa?: string; + code?: string; } -export const loginCommand = async ({ email, password, endpoint, mfa, code }: LoginCommandOptions): Promise => { - const oldCurrent = globalConfig.getCurrentSession(); +export const loginCommand = async ({ + email, + password, + endpoint, + mfa, + code, +}: LoginCommandOptions): Promise => { + const oldCurrent = globalConfig.getCurrentSession(); - const configEndpoint = (endpoint ?? globalConfig.getEndpoint()) || DEFAULT_ENDPOINT; + const configEndpoint = + (endpoint ?? globalConfig.getEndpoint()) || DEFAULT_ENDPOINT; - if (globalConfig.getCurrentSession() !== '') { - log('You are currently signed in as ' + globalConfig.getEmail()); + if (globalConfig.getCurrentSession() !== "") { + log("You are currently signed in as " + globalConfig.getEmail()); - if (globalConfig.getSessions().length === 1) { - hint('You can sign in and manage multiple accounts with Appwrite CLI'); - } + if (globalConfig.getSessions().length === 1) { + hint("You can sign in and manage multiple accounts with Appwrite CLI"); } + } - const answers = email && password ? { email, password } : await inquirer.prompt(questionsLogin); - - if (!answers.method) { - answers.method = 'login'; - } + const answers = + email && password + ? { email, password } + : await inquirer.prompt(questionsLogin); - if (answers.method === 'select') { - const accountId = answers.accountId; + if (!answers.method) { + answers.method = "login"; + } - if (!globalConfig.getSessionIds().includes(accountId)) { - throw Error('Session ID not found'); - } + if (answers.method === "select") { + const accountId = answers.accountId; - globalConfig.setCurrentSession(accountId); - success(`Current account is ${accountId}`); + if (!globalConfig.getSessionIds().includes(accountId)) { + throw Error("Session ID not found"); + } - return; + globalConfig.setCurrentSession(accountId); + success(`Current account is ${accountId}`); + + return; + } + + const id = ID.unique(); + + globalConfig.addSession(id, { endpoint: configEndpoint }); + globalConfig.setCurrentSession(id); + globalConfig.setEndpoint(configEndpoint); + globalConfig.setEmail(answers.email); + + // Use legacy client for login to extract cookies from response + const legacyClient = new ClientLegacy(); + legacyClient.setEndpoint(configEndpoint); + legacyClient.setProject("console"); + if (globalConfig.getSelfSigned()) { + legacyClient.setSelfSigned(true); + } + + let client = await sdkForConsole(false); + let accountClient = new Account(client); + + let account; + + try { + await legacyClient.call( + "POST", + "/account/sessions/email", + { + "content-type": "application/json", + }, + { + email: answers.email, + password: answers.password, + }, + ); + + const savedCookie = globalConfig.getCookie(); + + if (savedCookie) { + legacyClient.setCookie(savedCookie); + client.setCookie(savedCookie); } - const id = ID.unique(); - - globalConfig.addSession(id, {}); - globalConfig.setCurrentSession(id); - globalConfig.setEndpoint(configEndpoint); - globalConfig.setEmail(answers.email); - - let client = await sdkForConsole(false); - - let account; - - try { - await accountCreateEmailPasswordSession({ - email: answers.email, - password: answers.password, - parseOutput: false, - sdk: client - }) - - client.setCookie(globalConfig.getCookie()); - - account = await accountGet({ - sdk: client, - parseOutput: false - }); - } catch (err: any) { - if (err.response === 'user_more_factors_required') { - const { factor } = mfa ? { factor: mfa } : await inquirer.prompt(questionsListFactors); - - const challenge = await accountCreateMFAChallenge({ - factor, - parseOutput: false, - sdk: client - }); - - const { otp } = code ? { otp: code } : await inquirer.prompt(questionsMFAChallenge); - - await accountUpdateMFAChallenge({ - challengeId: challenge.$id, - otp, - parseOutput: false, - sdk: client - }); - - account = await accountGet({ - sdk: client, - parseOutput: false - }); - } else { - globalConfig.removeSession(id); - globalConfig.setCurrentSession(oldCurrent); - if (endpoint !== DEFAULT_ENDPOINT && err.response === 'user_invalid_credentials') { - log('Use the --endpoint option for self-hosted instances') - } - throw err; - } + accountClient = new Account(client); + account = await accountClient.get(); + } catch (err: any) { + if ( + err.type === "user_more_factors_required" || + err.response === "user_more_factors_required" + ) { + const { factor } = mfa + ? { factor: mfa } + : await inquirer.prompt(questionsListFactors); + const challenge = await accountClient.createMfaChallenge(factor); + + const { otp } = code + ? { otp: code } + : await inquirer.prompt(questionsMFAChallenge); + await legacyClient.call( + "PUT", + "/account/mfa/challenges", + { + "content-type": "application/json", + }, + { + challengeId: challenge.$id, + otp: otp, + }, + ); + + const savedCookie = globalConfig.getCookie(); + if (savedCookie) { + client.setCookie(savedCookie); + } + + accountClient = new Account(client); + account = await accountClient.get(); + } else { + globalConfig.removeSession(id); + globalConfig.setCurrentSession(oldCurrent); + if ( + endpoint !== DEFAULT_ENDPOINT && + (err.type === "user_invalid_credentials" || + err.response === "user_invalid_credentials") + ) { + log("Use the --endpoint option for self-hosted instances"); + } + throw err; } + } - success("Successfully signed in as " + account.email); - hint("Next you can create or link to your project using 'appwrite init project'"); + success("Successfully signed in as " + account.email); + hint( + "Next you can create or link to your project using 'appwrite init project'", + ); }; export const whoami = new Command("whoami") - .description(commandDescriptions['whoami']) - .action(actionRunner(async () => { - if (globalConfig.getEndpoint() === '' || globalConfig.getCookie() === '') { - error("No user is signed in. To sign in, run 'appwrite login'"); - return; - } - - let client = await sdkForConsole(false); - - let account; + .description(commandDescriptions["whoami"]) + .action( + actionRunner(async () => { + if ( + globalConfig.getEndpoint() === "" || + globalConfig.getCookie() === "" + ) { + error("No user is signed in. To sign in, run 'appwrite login'"); + return; + } - try { - account = await accountGet({ - sdk: client, - parseOutput: false - }); - } catch (_) { - error("No user is signed in. To sign in, run 'appwrite login'"); - return; - } + let client = await sdkForConsole(false); + let accountClient = new Account(client); - const data = [ - { - 'ID': account.$id, - 'Name': account.name, - 'Email': account.email, - 'MFA enabled': account.mfa ? 'Yes' : 'No', - 'Endpoint': globalConfig.getEndpoint() - } - ]; + let account; - if (cliConfig.json) { - console.log(data); - return; - } + try { + account = await accountClient.get(); + } catch (_) { + error("No user is signed in. To sign in, run 'appwrite login'"); + return; + } + + const data = [ + { + ID: account.$id, + Name: account.name, + Email: account.email, + "MFA enabled": account.mfa ? "Yes" : "No", + Endpoint: globalConfig.getEndpoint(), + }, + ]; + + if (cliConfig.json) { + console.log(data); + return; + } - drawTable(data) - })); + drawTable(data); + }), + ); export const register = new Command("register") - .description(commandDescriptions['register']) - .action(actionRunner(async () => { - log('Visit https://cloud.appwrite.io/register to create an account') - })); + .description(commandDescriptions["register"]) + .action( + actionRunner(async () => { + log("Visit https://cloud.appwrite.io/register to create an account"); + }), + ); export const login = new Command("login") - .description(commandDescriptions['login']) - .option(`--email [email]`, `User email`) - .option(`--password [password]`, `User password`) - .option(`--endpoint [endpoint]`, `Appwrite endpoint for self hosted instances`) - .option(`--mfa [factor]`, `Multi-factor authentication login factor: totp, email, phone or recoveryCode`) - .option(`--code [code]`, `Multi-factor code`) - .configureHelp({ - helpWidth: process.stdout.columns || 80 - }) - .action(actionRunner(loginCommand)); + .description(commandDescriptions["login"]) + .option(`--email [email]`, `User email`) + .option(`--password [password]`, `User password`) + .option( + `--endpoint [endpoint]`, + `Appwrite endpoint for self hosted instances`, + ) + .option( + `--mfa [factor]`, + `Multi-factor authentication login factor: totp, email, phone or recoveryCode`, + ) + .option(`--code [code]`, `Multi-factor code`) + .configureHelp({ + helpWidth: process.stdout.columns || 80, + }) + .action(actionRunner(loginCommand)); const deleteSession = async (accountId: string): Promise => { - try { - let client = await sdkForConsole(); - - await accountDeleteSession({ - sessionId: 'current', - parseOutput: false, - sdk: client - }) - } catch (e) { - error('Unable to log out, removing locally saved session information') - } finally { - globalConfig.removeSession(accountId); - } -} + try { + let client = await sdkForConsole(); + let accountClient = new Account(client); + + await accountClient.deleteSession("current"); + } catch (e) { + error("Unable to log out, removing locally saved session information"); + } finally { + globalConfig.removeSession(accountId); + } +}; export const logout = new Command("logout") - .description(commandDescriptions['logout']) - .configureHelp({ - helpWidth: process.stdout.columns || 80 - }) - .action(actionRunner(async () => { - const sessions = globalConfig.getSessions(); - const current = globalConfig.getCurrentSession(); - - if (current === '' || !sessions.length) { - log('No active sessions found.'); - return; - } - if (sessions.length === 1) { - await deleteSession(current); - globalConfig.setCurrentSession(''); - success("Logging out"); + .description(commandDescriptions["logout"]) + .configureHelp({ + helpWidth: process.stdout.columns || 80, + }) + .action( + actionRunner(async () => { + const sessions = globalConfig.getSessions(); + const current = globalConfig.getCurrentSession(); + + if (current === "" || !sessions.length) { + log("No active sessions found."); + return; + } + if (sessions.length === 1) { + await deleteSession(current); + globalConfig.setCurrentSession(""); + success("Logging out"); - return; - } + return; + } - const answers = await inquirer.prompt(questionsLogout); + const answers = await inquirer.prompt(questionsLogout); - if (answers.accounts) { - for (let accountId of answers.accounts) { - globalConfig.setCurrentSession(accountId); - await deleteSession(accountId); - } + if (answers.accounts) { + for (let accountId of answers.accounts) { + globalConfig.setCurrentSession(accountId); + await deleteSession(accountId); } + } - const remainingSessions = globalConfig.getSessions(); + const remainingSessions = globalConfig.getSessions(); - if (remainingSessions.length > 0 && remainingSessions.filter((session: any) => session.id === current).length !== 1) { - const accountId = remainingSessions[0].id; - globalConfig.setCurrentSession(accountId); + if ( + remainingSessions.length > 0 && + remainingSessions.filter((session: any) => session.id === current) + .length !== 1 + ) { + const accountId = remainingSessions[0].id; + globalConfig.setCurrentSession(accountId); - success(`Current account is ${accountId}`); - } else if (remainingSessions.length === 0) { - globalConfig.setCurrentSession(''); - } + success(`Current account is ${accountId}`); + } else if (remainingSessions.length === 0) { + globalConfig.setCurrentSession(""); + } - success("Logging out"); - })); + success("Logging out"); + }), + ); interface ClientCommandOptions { - selfSigned?: boolean; - endpoint?: string; - projectId?: string; - key?: string; - debug?: boolean; - reset?: boolean; + selfSigned?: boolean; + endpoint?: string; + projectId?: string; + key?: string; + debug?: boolean; + reset?: boolean; } export const client = new Command("client") - .description(commandDescriptions['client']) - .configureHelp({ - helpWidth: process.stdout.columns || 80 - }) - .option("-ss, --self-signed ", "Configure the CLI to use a self-signed certificate ( true or false )", parseBool) - .option("-e, --endpoint ", "Set your Appwrite server endpoint") - .option("-p, --project-id ", "Set your Appwrite project ID") - .option("-k, --key ", "Set your Appwrite server's API key") - .option("-d, --debug", "Print CLI debug information") - .option("-r, --reset", "Reset the CLI configuration") - .action(actionRunner(async ({ selfSigned, endpoint, projectId, key, debug, reset }: ClientCommandOptions, command: Command) => { - if (selfSigned == undefined && endpoint == undefined && projectId == undefined && key == undefined && debug == undefined && reset == undefined) { - command.help() + .description(commandDescriptions["client"]) + .configureHelp({ + helpWidth: process.stdout.columns || 80, + }) + .option( + "-ss, --self-signed ", + "Configure the CLI to use a self-signed certificate ( true or false )", + parseBool, + ) + .option("-e, --endpoint ", "Set your Appwrite server endpoint") + .option("-p, --project-id ", "Set your Appwrite project ID") + .option("-k, --key ", "Set your Appwrite server's API key") + .option("-d, --debug", "Print CLI debug information") + .option("-r, --reset", "Reset the CLI configuration") + .action( + actionRunner( + async ( + { + selfSigned, + endpoint, + projectId, + key, + debug, + reset, + }: ClientCommandOptions, + command: Command, + ) => { + if ( + selfSigned == undefined && + endpoint == undefined && + projectId == undefined && + key == undefined && + debug == undefined && + reset == undefined + ) { + command.help(); } if (debug) { - let config = { - endpoint: globalConfig.getEndpoint(), - key: globalConfig.getKey(), - cookie: globalConfig.getCookie(), - selfSigned: globalConfig.getSelfSigned(), - project: localConfig.getProject() - } - parse(config) + let config = { + endpoint: globalConfig.getEndpoint(), + key: globalConfig.getKey(), + cookie: globalConfig.getCookie(), + selfSigned: globalConfig.getSelfSigned(), + project: localConfig.getProject(), + }; + parse(config); } if (endpoint !== undefined) { - try { - const id = ID.unique(); - let url = new URL(endpoint); - if (url.protocol !== "http:" && url.protocol !== "https:") { - throw new Error(); - } - - let clientInstance = new Client().setEndpoint(endpoint); - clientInstance.setProject('console'); - if (selfSigned || globalConfig.getSelfSigned()) { - clientInstance.setSelfSigned(true); - } - let response = await clientInstance.call('GET', '/health/version'); - if (!response.version) { - throw new Error(); - } - globalConfig.setCurrentSession(id); - globalConfig.addSession(id, {}); - globalConfig.setEndpoint(endpoint); - } catch (_) { - throw new Error("Invalid endpoint or your Appwrite server is not running as expected."); + try { + const id = ID.unique(); + let url = new URL(endpoint); + if (url.protocol !== "http:" && url.protocol !== "https:") { + throw new Error(); + } + + let clientInstance = new Client().setEndpoint(endpoint); + clientInstance.setProject("console"); + if (selfSigned || globalConfig.getSelfSigned()) { + clientInstance.setSelfSigned(true); } + let response = (await clientInstance.call( + "GET", + new URL(endpoint + "/health/version"), + )) as { version?: string }; + if (!response.version) { + throw new Error(); + } + globalConfig.setCurrentSession(id); + globalConfig.addSession(id, { endpoint }); + globalConfig.setEndpoint(endpoint); + } catch (_) { + throw new Error( + "Invalid endpoint or your Appwrite server is not running as expected.", + ); + } } if (key !== undefined) { - globalConfig.setKey(key) + globalConfig.setKey(key); } if (projectId !== undefined) { - localConfig.setProject(projectId, ''); + localConfig.setProject(projectId, ""); } if (selfSigned == true || selfSigned == false) { - globalConfig.setSelfSigned(selfSigned); + globalConfig.setSelfSigned(selfSigned); } if (reset !== undefined) { - const sessions = globalConfig.getSessions(); + const sessions = globalConfig.getSessions(); - for (let accountId of sessions.map((session: any) => session.id)) { - globalConfig.setCurrentSession(accountId); - await deleteSession(accountId); - } + for (let accountId of sessions.map((session: any) => session.id)) { + globalConfig.setCurrentSession(accountId); + await deleteSession(accountId); + } } - success("Setting client") - })); + success("Setting client"); + }, + ), + ); export const migrate = async (): Promise => { - if (!globalConfig.has('endpoint') || !globalConfig.has('cookie')) { - return; - } - - const endpoint = globalConfig.get('endpoint'); - const cookie = globalConfig.get('cookie'); - - const id = ID.unique(); - const data = { - endpoint, - cookie, - email: 'legacy' - }; - - globalConfig.addSession(id, data); - globalConfig.setCurrentSession(id); - globalConfig.delete('endpoint'); - globalConfig.delete('cookie'); -} - + if (!globalConfig.has("endpoint") || !globalConfig.has("cookie")) { + return; + } + + const endpoint = globalConfig.get("endpoint") as string; + const cookie = globalConfig.get("cookie") as string; + + const id = ID.unique(); + const data = { + endpoint, + cookie, + email: "legacy", + }; + + globalConfig.addSession(id, data); + globalConfig.setCurrentSession(id); + globalConfig.delete("endpoint"); + globalConfig.delete("cookie"); +}; diff --git a/lib/commands/graphql.ts b/lib/commands/graphql.ts deleted file mode 100644 index 04d0f74b..00000000 --- a/lib/commands/graphql.ts +++ /dev/null @@ -1,110 +0,0 @@ -import fs = require('fs'); -import pathLib = require('path'); -import tar = require('tar'); -import ignore = require('ignore'); -import { promisify } from 'util'; -import Client from '../client'; -import { getAllFiles, showConsoleLink } from '../utils'; -import { Command } from 'commander'; -import { sdkForProject, sdkForConsole } from '../sdks'; -import { parse, actionRunner, parseInteger, parseBool, commandDescriptions, success, log, warn } from '../parser'; -import { localConfig, globalConfig } from '../config'; -import { File } from 'undici'; -import { ReadableStream } from 'stream/web'; - -function convertReadStreamToReadableStream(readStream: fs.ReadStream): ReadableStream { - return new ReadableStream({ - start(controller) { - readStream.on("data", (chunk: Buffer) => { - controller.enqueue(chunk); - }); - readStream.on("end", () => { - controller.close(); - }); - readStream.on("error", (err: Error) => { - controller.error(err); - }); - }, - cancel() { - readStream.destroy(); - }, - }); -} - -export const graphql = new Command("graphql").description(commandDescriptions['graphql'] ?? '').configureHelp({ - helpWidth: process.stdout.columns || 80 -}) - -interface GraphqlQueryRequestParams { - query: object; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const graphqlQuery = async ({query,parseOutput = true, overrideForCli = false, sdk = undefined}: GraphqlQueryRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/graphql'; - let payload = {}; - if (typeof query !== 'undefined') { - payload['query'] = JSON.parse(query); - } - - let response = undefined; - - response = await client.call('post', apiPath, { - 'x-sdk-graphql': 'true', - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface GraphqlMutationRequestParams { - query: object; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const graphqlMutation = async ({query,parseOutput = true, overrideForCli = false, sdk = undefined}: GraphqlMutationRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/graphql/mutation'; - let payload = {}; - if (typeof query !== 'undefined') { - payload['query'] = JSON.parse(query); - } - - let response = undefined; - - response = await client.call('post', apiPath, { - 'x-sdk-graphql': 'true', - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -graphql - .command(`query`) - .description(`Execute a GraphQL mutation.`) - .requiredOption(`--query `, `The query or queries to execute.`) - .action(actionRunner(graphqlQuery)) - -graphql - .command(`mutation`) - .description(`Execute a GraphQL mutation.`) - .requiredOption(`--query `, `The query or queries to execute.`) - .action(actionRunner(graphqlMutation)) - - diff --git a/lib/commands/health.ts b/lib/commands/health.ts deleted file mode 100644 index 7852de79..00000000 --- a/lib/commands/health.ts +++ /dev/null @@ -1,753 +0,0 @@ -import fs = require('fs'); -import pathLib = require('path'); -import tar = require('tar'); -import ignore = require('ignore'); -import { promisify } from 'util'; -import Client from '../client'; -import { getAllFiles, showConsoleLink } from '../utils'; -import { Command } from 'commander'; -import { sdkForProject, sdkForConsole } from '../sdks'; -import { parse, actionRunner, parseInteger, parseBool, commandDescriptions, success, log, warn } from '../parser'; -import { localConfig, globalConfig } from '../config'; -import { File } from 'undici'; -import { ReadableStream } from 'stream/web'; - -function convertReadStreamToReadableStream(readStream: fs.ReadStream): ReadableStream { - return new ReadableStream({ - start(controller) { - readStream.on("data", (chunk: Buffer) => { - controller.enqueue(chunk); - }); - readStream.on("end", () => { - controller.close(); - }); - readStream.on("error", (err: Error) => { - controller.error(err); - }); - }, - cancel() { - readStream.destroy(); - }, - }); -} - -export const health = new Command("health").description(commandDescriptions['health'] ?? '').configureHelp({ - helpWidth: process.stdout.columns || 80 -}) - -interface HealthGetRequestParams { - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const healthGet = async ({parseOutput = true, overrideForCli = false, sdk = undefined}: HealthGetRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/health'; - let payload = {}; - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface HealthGetAntivirusRequestParams { - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const healthGetAntivirus = async ({parseOutput = true, overrideForCli = false, sdk = undefined}: HealthGetAntivirusRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/health/anti-virus'; - let payload = {}; - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface HealthGetCacheRequestParams { - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const healthGetCache = async ({parseOutput = true, overrideForCli = false, sdk = undefined}: HealthGetCacheRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/health/cache'; - let payload = {}; - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface HealthGetCertificateRequestParams { - domain?: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const healthGetCertificate = async ({domain,parseOutput = true, overrideForCli = false, sdk = undefined}: HealthGetCertificateRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/health/certificate'; - let payload = {}; - if (typeof domain !== 'undefined') { - payload['domain'] = domain; - } - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface HealthGetDBRequestParams { - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const healthGetDB = async ({parseOutput = true, overrideForCli = false, sdk = undefined}: HealthGetDBRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/health/db'; - let payload = {}; - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface HealthGetPubSubRequestParams { - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const healthGetPubSub = async ({parseOutput = true, overrideForCli = false, sdk = undefined}: HealthGetPubSubRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/health/pubsub'; - let payload = {}; - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface HealthGetQueueBuildsRequestParams { - threshold?: number; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const healthGetQueueBuilds = async ({threshold,parseOutput = true, overrideForCli = false, sdk = undefined}: HealthGetQueueBuildsRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/health/queue/builds'; - let payload = {}; - if (typeof threshold !== 'undefined') { - payload['threshold'] = threshold; - } - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface HealthGetQueueCertificatesRequestParams { - threshold?: number; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const healthGetQueueCertificates = async ({threshold,parseOutput = true, overrideForCli = false, sdk = undefined}: HealthGetQueueCertificatesRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/health/queue/certificates'; - let payload = {}; - if (typeof threshold !== 'undefined') { - payload['threshold'] = threshold; - } - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface HealthGetQueueDatabasesRequestParams { - name?: string; - threshold?: number; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const healthGetQueueDatabases = async ({name,threshold,parseOutput = true, overrideForCli = false, sdk = undefined}: HealthGetQueueDatabasesRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/health/queue/databases'; - let payload = {}; - if (typeof name !== 'undefined') { - payload['name'] = name; - } - if (typeof threshold !== 'undefined') { - payload['threshold'] = threshold; - } - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface HealthGetQueueDeletesRequestParams { - threshold?: number; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const healthGetQueueDeletes = async ({threshold,parseOutput = true, overrideForCli = false, sdk = undefined}: HealthGetQueueDeletesRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/health/queue/deletes'; - let payload = {}; - if (typeof threshold !== 'undefined') { - payload['threshold'] = threshold; - } - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface HealthGetFailedJobsRequestParams { - name: Name; - threshold?: number; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const healthGetFailedJobs = async ({name,threshold,parseOutput = true, overrideForCli = false, sdk = undefined}: HealthGetFailedJobsRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/health/queue/failed/{name}'.replace('{name}', name); - let payload = {}; - if (typeof threshold !== 'undefined') { - payload['threshold'] = threshold; - } - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface HealthGetQueueFunctionsRequestParams { - threshold?: number; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const healthGetQueueFunctions = async ({threshold,parseOutput = true, overrideForCli = false, sdk = undefined}: HealthGetQueueFunctionsRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/health/queue/functions'; - let payload = {}; - if (typeof threshold !== 'undefined') { - payload['threshold'] = threshold; - } - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface HealthGetQueueLogsRequestParams { - threshold?: number; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const healthGetQueueLogs = async ({threshold,parseOutput = true, overrideForCli = false, sdk = undefined}: HealthGetQueueLogsRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/health/queue/logs'; - let payload = {}; - if (typeof threshold !== 'undefined') { - payload['threshold'] = threshold; - } - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface HealthGetQueueMailsRequestParams { - threshold?: number; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const healthGetQueueMails = async ({threshold,parseOutput = true, overrideForCli = false, sdk = undefined}: HealthGetQueueMailsRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/health/queue/mails'; - let payload = {}; - if (typeof threshold !== 'undefined') { - payload['threshold'] = threshold; - } - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface HealthGetQueueMessagingRequestParams { - threshold?: number; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const healthGetQueueMessaging = async ({threshold,parseOutput = true, overrideForCli = false, sdk = undefined}: HealthGetQueueMessagingRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/health/queue/messaging'; - let payload = {}; - if (typeof threshold !== 'undefined') { - payload['threshold'] = threshold; - } - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface HealthGetQueueMigrationsRequestParams { - threshold?: number; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const healthGetQueueMigrations = async ({threshold,parseOutput = true, overrideForCli = false, sdk = undefined}: HealthGetQueueMigrationsRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/health/queue/migrations'; - let payload = {}; - if (typeof threshold !== 'undefined') { - payload['threshold'] = threshold; - } - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface HealthGetQueueStatsResourcesRequestParams { - threshold?: number; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const healthGetQueueStatsResources = async ({threshold,parseOutput = true, overrideForCli = false, sdk = undefined}: HealthGetQueueStatsResourcesRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/health/queue/stats-resources'; - let payload = {}; - if (typeof threshold !== 'undefined') { - payload['threshold'] = threshold; - } - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface HealthGetQueueUsageRequestParams { - threshold?: number; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const healthGetQueueUsage = async ({threshold,parseOutput = true, overrideForCli = false, sdk = undefined}: HealthGetQueueUsageRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/health/queue/stats-usage'; - let payload = {}; - if (typeof threshold !== 'undefined') { - payload['threshold'] = threshold; - } - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface HealthGetQueueWebhooksRequestParams { - threshold?: number; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const healthGetQueueWebhooks = async ({threshold,parseOutput = true, overrideForCli = false, sdk = undefined}: HealthGetQueueWebhooksRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/health/queue/webhooks'; - let payload = {}; - if (typeof threshold !== 'undefined') { - payload['threshold'] = threshold; - } - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface HealthGetStorageRequestParams { - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const healthGetStorage = async ({parseOutput = true, overrideForCli = false, sdk = undefined}: HealthGetStorageRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/health/storage'; - let payload = {}; - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface HealthGetStorageLocalRequestParams { - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const healthGetStorageLocal = async ({parseOutput = true, overrideForCli = false, sdk = undefined}: HealthGetStorageLocalRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/health/storage/local'; - let payload = {}; - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface HealthGetTimeRequestParams { - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const healthGetTime = async ({parseOutput = true, overrideForCli = false, sdk = undefined}: HealthGetTimeRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/health/time'; - let payload = {}; - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -health - .command(`get`) - .description(`Check the Appwrite HTTP server is up and responsive.`) - .action(actionRunner(healthGet)) - -health - .command(`get-antivirus`) - .description(`Check the Appwrite Antivirus server is up and connection is successful.`) - .action(actionRunner(healthGetAntivirus)) - -health - .command(`get-cache`) - .description(`Check the Appwrite in-memory cache servers are up and connection is successful.`) - .action(actionRunner(healthGetCache)) - -health - .command(`get-certificate`) - .description(`Get the SSL certificate for a domain`) - .option(`--domain `, `string`) - .action(actionRunner(healthGetCertificate)) - -health - .command(`get-db`) - .description(`Check the Appwrite database servers are up and connection is successful.`) - .action(actionRunner(healthGetDB)) - -health - .command(`get-pub-sub`) - .description(`Check the Appwrite pub-sub servers are up and connection is successful.`) - .action(actionRunner(healthGetPubSub)) - -health - .command(`get-queue-builds`) - .description(`Get the number of builds that are waiting to be processed in the Appwrite internal queue server.`) - .option(`--threshold `, `Queue size threshold. When hit (equal or higher), endpoint returns server error. Default value is 5000.`, parseInteger) - .action(actionRunner(healthGetQueueBuilds)) - -health - .command(`get-queue-certificates`) - .description(`Get the number of certificates that are waiting to be issued against [Letsencrypt](https://letsencrypt.org/) in the Appwrite internal queue server.`) - .option(`--threshold `, `Queue size threshold. When hit (equal or higher), endpoint returns server error. Default value is 5000.`, parseInteger) - .action(actionRunner(healthGetQueueCertificates)) - -health - .command(`get-queue-databases`) - .description(`Get the number of database changes that are waiting to be processed in the Appwrite internal queue server.`) - .option(`--name `, `Queue name for which to check the queue size`) - .option(`--threshold `, `Queue size threshold. When hit (equal or higher), endpoint returns server error. Default value is 5000.`, parseInteger) - .action(actionRunner(healthGetQueueDatabases)) - -health - .command(`get-queue-deletes`) - .description(`Get the number of background destructive changes that are waiting to be processed in the Appwrite internal queue server.`) - .option(`--threshold `, `Queue size threshold. When hit (equal or higher), endpoint returns server error. Default value is 5000.`, parseInteger) - .action(actionRunner(healthGetQueueDeletes)) - -health - .command(`get-failed-jobs`) - .description(`Returns the amount of failed jobs in a given queue. `) - .requiredOption(`--name `, `The name of the queue`) - .option(`--threshold `, `Queue size threshold. When hit (equal or higher), endpoint returns server error. Default value is 5000.`, parseInteger) - .action(actionRunner(healthGetFailedJobs)) - -health - .command(`get-queue-functions`) - .description(`Get the number of function executions that are waiting to be processed in the Appwrite internal queue server.`) - .option(`--threshold `, `Queue size threshold. When hit (equal or higher), endpoint returns server error. Default value is 5000.`, parseInteger) - .action(actionRunner(healthGetQueueFunctions)) - -health - .command(`get-queue-logs`) - .description(`Get the number of logs that are waiting to be processed in the Appwrite internal queue server.`) - .option(`--threshold `, `Queue size threshold. When hit (equal or higher), endpoint returns server error. Default value is 5000.`, parseInteger) - .action(actionRunner(healthGetQueueLogs)) - -health - .command(`get-queue-mails`) - .description(`Get the number of mails that are waiting to be processed in the Appwrite internal queue server.`) - .option(`--threshold `, `Queue size threshold. When hit (equal or higher), endpoint returns server error. Default value is 5000.`, parseInteger) - .action(actionRunner(healthGetQueueMails)) - -health - .command(`get-queue-messaging`) - .description(`Get the number of messages that are waiting to be processed in the Appwrite internal queue server.`) - .option(`--threshold `, `Queue size threshold. When hit (equal or higher), endpoint returns server error. Default value is 5000.`, parseInteger) - .action(actionRunner(healthGetQueueMessaging)) - -health - .command(`get-queue-migrations`) - .description(`Get the number of migrations that are waiting to be processed in the Appwrite internal queue server.`) - .option(`--threshold `, `Queue size threshold. When hit (equal or higher), endpoint returns server error. Default value is 5000.`, parseInteger) - .action(actionRunner(healthGetQueueMigrations)) - -health - .command(`get-queue-stats-resources`) - .description(`Get the number of metrics that are waiting to be processed in the Appwrite stats resources queue.`) - .option(`--threshold `, `Queue size threshold. When hit (equal or higher), endpoint returns server error. Default value is 5000.`, parseInteger) - .action(actionRunner(healthGetQueueStatsResources)) - -health - .command(`get-queue-usage`) - .description(`Get the number of metrics that are waiting to be processed in the Appwrite internal queue server.`) - .option(`--threshold `, `Queue size threshold. When hit (equal or higher), endpoint returns server error. Default value is 5000.`, parseInteger) - .action(actionRunner(healthGetQueueUsage)) - -health - .command(`get-queue-webhooks`) - .description(`Get the number of webhooks that are waiting to be processed in the Appwrite internal queue server.`) - .option(`--threshold `, `Queue size threshold. When hit (equal or higher), endpoint returns server error. Default value is 5000.`, parseInteger) - .action(actionRunner(healthGetQueueWebhooks)) - -health - .command(`get-storage`) - .description(`Check the Appwrite storage device is up and connection is successful.`) - .action(actionRunner(healthGetStorage)) - -health - .command(`get-storage-local`) - .description(`Check the Appwrite local storage device is up and connection is successful.`) - .action(actionRunner(healthGetStorageLocal)) - -health - .command(`get-time`) - .description(`Check the Appwrite server time is synced with Google remote NTP server. We use this technology to smoothly handle leap seconds with no disruptive events. The [Network Time Protocol](https://en.wikipedia.org/wiki/Network_Time_Protocol) (NTP) is used by hundreds of millions of computers and devices to synchronize their clocks over the Internet. If your computer sets its own clock, it likely uses NTP.`) - .action(actionRunner(healthGetTime)) - - diff --git a/lib/commands/init.ts b/lib/commands/init.ts index ab03fa2a..6aa1dc0c 100644 --- a/lib/commands/init.ts +++ b/lib/commands/init.ts @@ -1,429 +1,503 @@ -import fs = require('fs'); -import path = require('path'); -import childProcess = require('child_process'); -import { Command } from 'commander'; -import inquirer from 'inquirer'; -import { projectsCreate, projectsGet } from './projects'; -import { storageCreateBucket } from './storage'; -import { messagingCreateTopic } from './messaging'; -import { functionsCreate } from './functions'; -import { databasesCreateCollection } from './databases'; -import { pullResources } from './pull'; -import ID from '../id'; -import { localConfig, globalConfig } from '../config'; +import fs from "fs"; +import path from "path"; +import childProcess from "child_process"; +import { Command } from "commander"; +import inquirer from "inquirer"; +import { getProjectsService, getSitesService } from "../services.js"; +import { pullResources } from "./pull.js"; +import ID from "../id.js"; +import { localConfig, globalConfig } from "../config.js"; import { - questionsCreateFunction, - questionsCreateFunctionSelectTemplate, - questionsCreateSite, - questionsCreateBucket, - questionsCreateMessagingTopic, - questionsCreateCollection, - questionsCreateTable, - questionsInitProject, - questionsInitProjectAutopull, - questionsInitResources, - questionsCreateTeam -} from '../questions'; -import { cliConfig, success, log, hint, error, actionRunner, commandDescriptions } from '../parser'; -import { accountGet } from './account'; -import { sitesListTemplates } from './sites'; -import { sdkForConsole } from '../sdks'; -import { isCloud } from '../utils'; + questionsCreateFunction, + questionsCreateFunctionSelectTemplate, + questionsCreateSite, + questionsCreateBucket, + questionsCreateMessagingTopic, + questionsCreateCollection, + questionsCreateTable, + questionsInitProject, + questionsInitProjectAutopull, + questionsInitResources, + questionsCreateTeam, +} from "../questions.js"; +import { + cliConfig, + success, + log, + hint, + error, + actionRunner, + commandDescriptions, +} from "../parser.js"; +import { sdkForConsole } from "../sdks.js"; +import { isCloud } from "../utils.js"; +import { Account } from "@appwrite.io/console"; const initResources = async (): Promise => { - const actions: Record Promise> = { - function: initFunction, - site: initSite, - table: initTable, - bucket: initBucket, - team: initTeam, - message: initTopic, - collection: initCollection - } - - const answers = await inquirer.prompt(questionsInitResources[0]); - - const action = actions[answers.resource]; - if (action !== undefined) { - await action({ returnOnZero: true }); - } + const actions: Record Promise> = { + function: initFunction, + site: initSite, + table: initTable, + bucket: initBucket, + team: initTeam, + message: initTopic, + collection: initCollection, + }; + + const answers = await inquirer.prompt([questionsInitResources[0]]); + + const action = actions[answers.resource]; + if (action !== undefined) { + await action({ returnOnZero: true }); + } }; interface InitProjectOptions { - organizationId?: string; - projectId?: string; - projectName?: string; + organizationId?: string; + projectId?: string; + projectName?: string; } -const initProject = async ({ organizationId, projectId, projectName }: InitProjectOptions = {}): Promise => { - let response: any = {}; +const initProject = async ({ + organizationId, + projectId, + projectName, +}: InitProjectOptions = {}): Promise => { + let response: any = {}; - try { - if (globalConfig.getEndpoint() === '' || globalConfig.getCookie() === '') { - throw ''; - } - const client = await sdkForConsole(); - - await accountGet({ - parseOutput: false, - sdk: client - }); - } catch (e) { - error("Error Session not found. Please run 'appwrite login' to create a session"); - process.exit(1); + try { + if (globalConfig.getEndpoint() === "" || globalConfig.getCookie() === "") { + throw ""; } - - let answers: any = {}; - - if (!organizationId && !projectId && !projectName) { - answers = await inquirer.prompt(questionsInitProject) - if (answers.override === false) { - process.exit(1) - } - } else { - answers.start = 'existing'; - answers.project = {}; - answers.organization = {}; - - answers.organization = organizationId ?? (await inquirer.prompt(questionsInitProject[2])).organization; - answers.project.name = projectName ?? (await inquirer.prompt(questionsInitProject[3])).project; - answers.project = projectId ?? (await inquirer.prompt(questionsInitProject[4])).id; - - try { - await projectsGet({ projectId, parseOutput: false }); - } catch (e: any) { - if (e.code === 404) { - answers.start = 'new'; - answers.id = answers.project; - answers.project = answers.project.name; - } else { - throw e; - } - } + const client = await sdkForConsole(); + const accountClient = new Account(client); + + await accountClient.get(); + } catch (e) { + error( + "Error Session not found. Please run 'appwrite login' to create a session", + ); + process.exit(1); + } + + let answers: any = {}; + + if (!organizationId && !projectId && !projectName) { + answers = await inquirer.prompt(questionsInitProject); + if (answers.override === false) { + process.exit(1); } + } else { + answers.start = "existing"; + answers.project = {}; + answers.organization = {}; + + answers.organization = + organizationId ?? + (await inquirer.prompt([questionsInitProject[2]])).organization; + answers.project.name = + projectName ?? (await inquirer.prompt([questionsInitProject[3]])).project; + answers.project = + projectId ?? (await inquirer.prompt([questionsInitProject[4]])).id; - localConfig.clear(); // Clear the config to avoid any conflicts - const url = new URL("https://cloud.appwrite.io/v1"); - - if (answers.start === 'new') { - response = await projectsCreate({ - projectId: answers.id, - name: answers.project, - teamId: answers.organization, - parseOutput: false - }) - - localConfig.setProject(response['$id']); - if (answers.region) { - localConfig.setEndpoint(`https://${answers.region}.${url.host}${url.pathname}`); - } - } else { - localConfig.setProject(answers.project["$id"]); - if(isCloud()) { - localConfig.setEndpoint(`https://${answers.project["region"]}.${url.host}${url.pathname}`); - } + try { + const projectsService = await getProjectsService(); + await projectsService.get(projectId); + } catch (e: any) { + if (e.code === 404) { + answers.start = "new"; + answers.id = answers.project; + answers.project = answers.project.name; + } else { + throw e; + } } - - success(`Project successfully ${answers.start === 'existing' ? 'linked' : 'created'}. Details are now stored in appwrite.config.json file.`); - - if(answers.start === 'existing') { - answers = await inquirer.prompt(questionsInitProjectAutopull); - if(answers.autopull) { - cliConfig.all = true; - cliConfig.force = true; - await pullResources({ - skipDeprecated: true - }); - } else { - log("You can run 'appwrite pull all' to synchronize all of your existing resources."); - } + } + + localConfig.clear(); // Clear the config to avoid any conflicts + const url = new URL("https://cloud.appwrite.io/v1"); + + if (answers.start === "new") { + const projectsService = await getProjectsService(); + response = await projectsService.create( + answers.id, + answers.project, + answers.organization, + answers.region, + ); + + localConfig.setProject(response["$id"]); + if (answers.region) { + localConfig.setEndpoint( + `https://${answers.region}.${url.host}${url.pathname}`, + ); } + } else { + localConfig.setProject(answers.project["$id"]); + if (isCloud()) { + localConfig.setEndpoint( + `https://${answers.project["region"]}.${url.host}${url.pathname}`, + ); + } + } + + success( + `Project successfully ${answers.start === "existing" ? "linked" : "created"}. Details are now stored in appwrite.config.json file.`, + ); + + if (answers.start === "existing") { + answers = await inquirer.prompt(questionsInitProjectAutopull); + if (answers.autopull) { + cliConfig.all = true; + cliConfig.force = true; + await pullResources({ + skipDeprecated: true, + }); + } else { + log( + "You can run 'appwrite pull all' to synchronize all of your existing resources.", + ); + } + } - hint("Next you can use 'appwrite init' to create resources in your project, or use 'appwrite pull' and 'appwrite push' to synchronize your project.") -} + hint( + "Next you can use 'appwrite init' to create resources in your project, or use 'appwrite pull' and 'appwrite push' to synchronize your project.", + ); +}; const initBucket = async (): Promise => { - const answers = await inquirer.prompt(questionsCreateBucket) - - localConfig.addBucket({ - $id: answers.id === 'unique()' ? ID.unique() : answers.id, - name: answers.bucket, - fileSecurity: answers.fileSecurity.toLowerCase() === 'yes', - enabled: true, - }); - success("Initialing bucket"); - log("Next you can use 'appwrite push bucket' to deploy the changes."); + const answers = await inquirer.prompt(questionsCreateBucket); + + localConfig.addBucket({ + $id: answers.id === "unique()" ? ID.unique() : answers.id, + name: answers.bucket, + fileSecurity: answers.fileSecurity.toLowerCase() === "yes", + enabled: true, + }); + success("Initialing bucket"); + log("Next you can use 'appwrite push bucket' to deploy the changes."); }; const initTeam = async (): Promise => { - const answers = await inquirer.prompt(questionsCreateTeam) + const answers = await inquirer.prompt(questionsCreateTeam); - localConfig.addTeam({ - $id: answers.id === 'unique()' ? ID.unique() : answers.id, - name: answers.bucket, - }); + localConfig.addTeam({ + $id: answers.id === "unique()" ? ID.unique() : answers.id, + name: answers.bucket, + }); - success("Initialing team"); - log("Next you can use 'appwrite push team' to deploy the changes."); + success("Initialing team"); + log("Next you can use 'appwrite push team' to deploy the changes."); }; const initTable = async (): Promise => { - const answers = await inquirer.prompt(questionsCreateTable) - const newDatabase = (answers.method ?? '').toLowerCase() !== 'existing'; - - if (!newDatabase) { - answers.databaseId = answers.database; - answers.databaseName = localConfig.getTablesDB(answers.database).name; - } - - const databaseId = answers.databaseId === 'unique()' ? ID.unique() : answers.databaseId; - - if (newDatabase || !localConfig.getTablesDB(answers.databaseId)) { - localConfig.addTablesDB({ - $id: databaseId, - name: answers.databaseName, - enabled: true - }); - } - - localConfig.addTable({ - $id: answers.id === 'unique()' ? ID.unique() : answers.id, - $permissions: [], - databaseId: databaseId, - name: answers.table, - enabled: true, - rowSecurity: answers.rowSecurity.toLowerCase() === 'yes', - columns: [], - indexes: [], + const answers = await inquirer.prompt(questionsCreateTable); + const newDatabase = (answers.method ?? "").toLowerCase() !== "existing"; + + if (!newDatabase) { + answers.databaseId = answers.database; + answers.databaseName = localConfig.getTablesDB(answers.database).name; + } + + const databaseId = + answers.databaseId === "unique()" ? ID.unique() : answers.databaseId; + + if (newDatabase || !localConfig.getTablesDB(answers.databaseId)) { + localConfig.addTablesDB({ + $id: databaseId, + name: answers.databaseName, + enabled: true, }); - - success("Initialing table"); - log("Next you can use 'appwrite push table' to deploy the changes."); + } + + localConfig.addTable({ + $id: answers.id === "unique()" ? ID.unique() : answers.id, + $permissions: [], + databaseId: databaseId, + name: answers.table, + enabled: true, + rowSecurity: answers.rowSecurity.toLowerCase() === "yes", + columns: [], + indexes: [], + }); + + success("Initialing table"); + log("Next you can use 'appwrite push table' to deploy the changes."); }; const initCollection = async (): Promise => { - const answers = await inquirer.prompt(questionsCreateCollection) - const newDatabase = (answers.method ?? '').toLowerCase() !== 'existing'; - - if (!newDatabase) { - answers.databaseId = answers.database; - answers.databaseName = localConfig.getDatabase(answers.database).name; - } - - const databaseId = answers.databaseId === 'unique()' ? ID.unique() : answers.databaseId; - - if (newDatabase || !localConfig.getDatabase(answers.databaseId)) { - localConfig.addDatabase({ - $id: databaseId, - name: answers.databaseName, - enabled: true - }); - } - - localConfig.addCollection({ - $id: answers.id === 'unique()' ? ID.unique() : answers.id, - databaseId: databaseId, - name: answers.collection, - documentSecurity: answers.documentSecurity.toLowerCase() === 'yes', - attributes: [], - indexes: [], - enabled: true, + const answers = await inquirer.prompt(questionsCreateCollection); + const newDatabase = (answers.method ?? "").toLowerCase() !== "existing"; + + if (!newDatabase) { + answers.databaseId = answers.database; + answers.databaseName = localConfig.getDatabase(answers.database).name; + } + + const databaseId = + answers.databaseId === "unique()" ? ID.unique() : answers.databaseId; + + if (newDatabase || !localConfig.getDatabase(answers.databaseId)) { + localConfig.addDatabase({ + $id: databaseId, + name: answers.databaseName, + enabled: true, }); - - success("Initialing collection"); - log("Next you can use 'appwrite push collection' to deploy the changes."); + } + + localConfig.addCollection({ + $id: answers.id === "unique()" ? ID.unique() : answers.id, + databaseId: databaseId, + name: answers.collection, + documentSecurity: answers.documentSecurity.toLowerCase() === "yes", + attributes: [], + indexes: [], + enabled: true, + }); + + success("Initialing collection"); + log("Next you can use 'appwrite push collection' to deploy the changes."); }; const initTopic = async (): Promise => { - const answers = await inquirer.prompt(questionsCreateMessagingTopic) - - localConfig.addMessagingTopic({ - $id: answers.id === 'unique()' ? ID.unique() : answers.id, - name: answers.topic, + const answers = await inquirer.prompt(questionsCreateMessagingTopic); - }); + localConfig.addMessagingTopic({ + $id: answers.id === "unique()" ? ID.unique() : answers.id, + name: answers.topic, + }); - success("Initialing topic"); - log("Next you can use 'appwrite push topic' to deploy the changes."); + success("Initialing topic"); + log("Next you can use 'appwrite push topic' to deploy the changes."); }; const initFunction = async (): Promise => { - process.chdir(localConfig.configDirectoryPath) - - // TODO: Add CI/CD support (ID, name, runtime) - const answers = await inquirer.prompt(questionsCreateFunction) - const functionFolder = path.join(process.cwd(), 'functions'); - - if (!fs.existsSync(functionFolder)) { - fs.mkdirSync(functionFolder, { - recursive: true - }); - } - - const functionId = answers.id === 'unique()' ? ID.unique() : answers.id; - const functionName = answers.name; - const functionDir = path.join(functionFolder, functionName); - const templatesDir = path.join(functionFolder, `${functionId}-templates`); - const runtimeDir = path.join(templatesDir, answers.runtime.name); - - if (fs.existsSync(functionDir)) { - throw new Error(`( ${functionName} ) already exists in the current directory. Please choose another name.`); - } - - if (!answers.runtime.entrypoint) { - log(`Entrypoint for this runtime not found. You will be asked to configure entrypoint when you first push the function.`); - } - - if (!answers.runtime.commands) { - log(`Installation command for this runtime not found. You will be asked to configure the install command when you first push the function.`); - } - - fs.mkdirSync(functionDir, { mode: 0o777 }); - fs.mkdirSync(templatesDir, { mode: 0o777 }); - const repo = "https://github.com/appwrite/templates"; - const api = `https://api.github.com/repos/appwrite/templates/contents/${answers.runtime.name}` - let selected: { template: string } = { template: 'starter' }; + process.chdir(localConfig.configDirectoryPath); - const sparse = (selected ? `${answers.runtime.name}/${selected.template}` : answers.runtime.name).toLowerCase(); + // TODO: Add CI/CD support (ID, name, runtime) + const answers = await inquirer.prompt(questionsCreateFunction); + const functionFolder = path.join(process.cwd(), "functions"); - let gitInitCommands = `git clone --single-branch --depth 1 --sparse ${repo} .`; // depth prevents fetching older commits reducing the amount fetched - - let gitPullCommands = `git sparse-checkout add ${sparse}`; - - /* Force use CMD as powershell does not support && */ - if (process.platform === 'win32') { - gitInitCommands = 'cmd /c "' + gitInitCommands + '"'; - gitPullCommands = 'cmd /c "' + gitPullCommands + '"'; + if (!fs.existsSync(functionFolder)) { + fs.mkdirSync(functionFolder, { + recursive: true, + }); + } + + const functionId = answers.id === "unique()" ? ID.unique() : answers.id; + const functionName = answers.name; + const functionDir = path.join(functionFolder, functionName); + const templatesDir = path.join(functionFolder, `${functionId}-templates`); + const runtimeDir = path.join(templatesDir, answers.runtime.name); + + if (fs.existsSync(functionDir)) { + throw new Error( + `( ${functionName} ) already exists in the current directory. Please choose another name.`, + ); + } + + if (!answers.runtime.entrypoint) { + log( + `Entrypoint for this runtime not found. You will be asked to configure entrypoint when you first push the function.`, + ); + } + + if (!answers.runtime.commands) { + log( + `Installation command for this runtime not found. You will be asked to configure the install command when you first push the function.`, + ); + } + + fs.mkdirSync(functionDir, { mode: 0o777 }); + fs.mkdirSync(templatesDir, { mode: 0o777 }); + const repo = "https://github.com/appwrite/templates"; + const api = `https://api.github.com/repos/appwrite/templates/contents/${answers.runtime.name}`; + let selected: { template: string } = { template: "starter" }; + + const sparse = ( + selected + ? `${answers.runtime.name}/${selected.template}` + : answers.runtime.name + ).toLowerCase(); + + let gitInitCommands = `git clone --single-branch --depth 1 --sparse ${repo} .`; // depth prevents fetching older commits reducing the amount fetched + + let gitPullCommands = `git sparse-checkout add ${sparse}`; + + /* Force use CMD as powershell does not support && */ + if (process.platform === "win32") { + gitInitCommands = 'cmd /c "' + gitInitCommands + '"'; + gitPullCommands = 'cmd /c "' + gitPullCommands + '"'; + } + + /* Execute the child process but do not print any std output */ + try { + childProcess.execSync(gitInitCommands, { + stdio: "pipe", + cwd: templatesDir, + }); + childProcess.execSync(gitPullCommands, { + stdio: "pipe", + cwd: templatesDir, + }); + } catch (err: any) { + /* Specialised errors with recommended actions to take */ + if (err.message.includes("error: unknown option")) { + throw new Error( + `${err.message} \n\nSuggestion: Try updating your git to the latest version, then trying to run this command again.`, + ); + } else if ( + err.message.includes( + "is not recognized as an internal or external command,", + ) || + err.message.includes("command not found") + ) { + throw new Error( + `${err.message} \n\nSuggestion: It appears that git is not installed, try installing git then trying to run this command again.`, + ); + } else { + throw err; } - - /* Execute the child process but do not print any std output */ - try { - childProcess.execSync(gitInitCommands, { stdio: 'pipe', cwd: templatesDir }); - childProcess.execSync(gitPullCommands, { stdio: 'pipe', cwd: templatesDir }); - } catch (err: any) { - /* Specialised errors with recommended actions to take */ - if (err.message.includes('error: unknown option')) { - throw new Error(`${err.message} \n\nSuggestion: Try updating your git to the latest version, then trying to run this command again.`) - } else if (err.message.includes('is not recognized as an internal or external command,') || err.message.includes('command not found')) { - throw new Error(`${err.message} \n\nSuggestion: It appears that git is not installed, try installing git then trying to run this command again.`) - } else { - throw err; - } + } + + fs.rmSync(path.join(templatesDir, ".git"), { recursive: true }); + if (!selected) { + const templates: string[] = []; + templates.push( + ...fs + .readdirSync(runtimeDir, { withFileTypes: true }) + .filter((item) => item.isDirectory() && item.name !== "starter") + .map((dirent) => dirent.name), + ); + selected = { template: "starter" }; + + if (templates.length > 1) { + selected = await inquirer.prompt( + questionsCreateFunctionSelectTemplate(templates), + ); } - - fs.rmSync(path.join(templatesDir, ".git"), { recursive: true }); - if (!selected) { - const templates: string[] = []; - templates.push(...fs.readdirSync(runtimeDir, { withFileTypes: true }) - .filter(item => item.isDirectory() && item.name !== 'starter') - .map(dirent => dirent.name)); - selected = { template: 'starter' }; - - if (templates.length > 1) { - selected = await inquirer.prompt(questionsCreateFunctionSelectTemplate(templates)) - } + } + + const copyRecursiveSync = (src: string, dest: string): void => { + let exists = fs.existsSync(src); + let stats = exists && fs.statSync(src); + let isDirectory = exists && stats && stats.isDirectory(); + if (isDirectory) { + if (!fs.existsSync(dest)) { + fs.mkdirSync(dest); + } + + fs.readdirSync(src).forEach(function (childItemName) { + copyRecursiveSync( + path.join(src, childItemName), + path.join(dest, childItemName), + ); + }); + } else { + fs.copyFileSync(src, dest); } - - const copyRecursiveSync = (src: string, dest: string): void => { - let exists = fs.existsSync(src); - let stats = exists && fs.statSync(src); - let isDirectory = exists && stats && stats.isDirectory(); - if (isDirectory) { - if (!fs.existsSync(dest)) { - fs.mkdirSync(dest); - } - - fs.readdirSync(src).forEach(function (childItemName) { - copyRecursiveSync(path.join(src, childItemName), path.join(dest, childItemName)); - }); - } else { - fs.copyFileSync(src, dest); - } - }; - copyRecursiveSync(path.join(runtimeDir, selected.template), functionDir); - - fs.rmSync(templatesDir, { recursive: true, force: true }); - - const readmePath = path.join(process.cwd(), 'functions', functionName, 'README.md'); - const readmeFile = fs.readFileSync(readmePath).toString(); - const newReadmeFile = readmeFile.split('\n'); - newReadmeFile[0] = `# ${answers.name}`; - newReadmeFile.splice(1, 2); - fs.writeFileSync(readmePath, newReadmeFile.join('\n')); - - let data = { - $id: functionId, - name: answers.name, - runtime: answers.runtime.id, - specification: answers.specification, - execute: ["any"], - events: [], - scopes: ["users.read"], - schedule: "", - timeout: 15, - enabled: true, - logging: true, - entrypoint: answers.runtime.entrypoint || '', - commands: answers.runtime.commands || '', - ignore: answers.runtime.ignore || null, - path: `functions/${functionName}`, - }; - - localConfig.addFunction(data); - success("Initialing function"); - log("Next you can use 'appwrite run function' to develop a function locally. To deploy the function, use 'appwrite push function'"); -} + }; + copyRecursiveSync(path.join(runtimeDir, selected.template), functionDir); + + fs.rmSync(templatesDir, { recursive: true, force: true }); + + const readmePath = path.join( + process.cwd(), + "functions", + functionName, + "README.md", + ); + const readmeFile = fs.readFileSync(readmePath).toString(); + const newReadmeFile = readmeFile.split("\n"); + newReadmeFile[0] = `# ${answers.name}`; + newReadmeFile.splice(1, 2); + fs.writeFileSync(readmePath, newReadmeFile.join("\n")); + + let data = { + $id: functionId, + name: answers.name, + runtime: answers.runtime.id, + specification: answers.specification, + execute: ["any"], + events: [], + scopes: ["users.read"], + schedule: "", + timeout: 15, + enabled: true, + logging: true, + entrypoint: answers.runtime.entrypoint || "", + commands: answers.runtime.commands || "", + ignore: answers.runtime.ignore || null, + path: `functions/${functionName}`, + }; + + localConfig.addFunction(data); + success("Initialing function"); + log( + "Next you can use 'appwrite run function' to develop a function locally. To deploy the function, use 'appwrite push function'", + ); +}; const initSite = async (): Promise => { - process.chdir(localConfig.configDirectoryPath) - - const answers = await inquirer.prompt(questionsCreateSite); - const siteFolder = path.join(process.cwd(), 'sites'); - - if (!fs.existsSync(siteFolder)) { - fs.mkdirSync(siteFolder, { - recursive: true - }); - } - - const siteId = answers.id === 'unique()' ? ID.unique() : answers.id; - const siteName = answers.name; - const siteDir = path.join(siteFolder, siteName); - const templatesDir = path.join(siteFolder, `${siteId}-templates`); + process.chdir(localConfig.configDirectoryPath); - if (fs.existsSync(siteDir)) { - throw new Error(`( ${siteName} ) already exists in the current directory. Please choose another name.`); - } + const answers = await inquirer.prompt(questionsCreateSite); + const siteFolder = path.join(process.cwd(), "sites"); - let templateDetails: any; - try { - const response = await sitesListTemplates({ - frameworks: [answers.framework.key], - useCases: ['starter'], - limit: 1, - parseOutput: false - }); - if (response.total == 0) { - throw new Error(`No starter template found for framework ${answers.framework.key}`); - } - templateDetails = response.templates[0]; - } catch (err: any) { - throw new Error(`Failed to fetch template for framework ${answers.framework.key}: ${err.message}`); + if (!fs.existsSync(siteFolder)) { + fs.mkdirSync(siteFolder, { + recursive: true, + }); + } + + const siteId = answers.id === "unique()" ? ID.unique() : answers.id; + const siteName = answers.name; + const siteDir = path.join(siteFolder, siteName); + const templatesDir = path.join(siteFolder, `${siteId}-templates`); + + if (fs.existsSync(siteDir)) { + throw new Error( + `( ${siteName} ) already exists in the current directory. Please choose another name.`, + ); + } + + let templateDetails: any; + try { + const sitesService = await getSitesService(); + const response = await sitesService.listTemplates( + [answers.framework.key], + ["starter"], + 1, + ); + if (response.total == 0) { + throw new Error( + `No starter template found for framework ${answers.framework.key}`, + ); } - - fs.mkdirSync(siteDir, { mode: 0o777 }); - fs.mkdirSync(templatesDir, { mode: 0o777 }); - const repo = `https://github.com/${templateDetails.providerOwner}/${templateDetails.providerRepositoryId}`; - let selected = { template: templateDetails.frameworks[0].providerRootDirectory }; - - let gitCloneCommands = ''; - - const sparse = selected.template.startsWith('./') ? selected.template.substring(2) : selected.template; - - log('Fetching site code ...'); - - if(selected.template === './') { - gitCloneCommands = ` + templateDetails = response.templates[0]; + } catch (err: any) { + throw new Error( + `Failed to fetch template for framework ${answers.framework.key}: ${err.message}`, + ); + } + + fs.mkdirSync(siteDir, { mode: 0o777 }); + fs.mkdirSync(templatesDir, { mode: 0o777 }); + const repo = `https://github.com/${templateDetails.providerOwner}/${templateDetails.providerRepositoryId}`; + let selected = { + template: templateDetails.frameworks[0].providerRootDirectory, + }; + + let gitCloneCommands = ""; + + const sparse = selected.template.startsWith("./") + ? selected.template.substring(2) + : selected.template; + + log("Fetching site code ..."); + + if (selected.template === "./") { + gitCloneCommands = ` mkdir -p . cd . git init @@ -432,8 +506,8 @@ const initSite = async (): Promise => { git fetch --depth=1 origin refs/tags/$(git ls-remote --tags origin "${templateDetails.providerVersion}" | tail -n 1 | awk -F '/' '{print $3}') git checkout FETCH_HEAD `.trim(); - } else { - gitCloneCommands = ` + } else { + gitCloneCommands = ` mkdir -p . cd . git init @@ -446,167 +520,194 @@ const initSite = async (): Promise => { git fetch --depth=1 origin refs/tags/$(git ls-remote --tags origin "${templateDetails.providerVersion}" | tail -n 1 | awk -F '/' '{print $3}') git checkout FETCH_HEAD `.trim(); - } - - /* Force use CMD as powershell does not support && */ - if (process.platform === 'win32') { - gitCloneCommands = 'cmd /c "' + gitCloneCommands + '"'; - } - - /* Execute the child process but do not print any std output */ - try { - childProcess.execSync(gitCloneCommands, { stdio: 'pipe', cwd: templatesDir }); - } catch (err: any) { - /* Specialised errors with recommended actions to take */ - if (err.message.includes('error: unknown option')) { - throw new Error(`${err.message} \n\nSuggestion: Try updating your git to the latest version, then trying to run this command again.`) - } else if (err.message.includes('is not recognized as an internal or external command,') || err.message.includes('command not found')) { - throw new Error(`${err.message} \n\nSuggestion: It appears that git is not installed, try installing git then trying to run this command again.`) - } else { - throw err; - } - } - - fs.rmSync(path.join(templatesDir, ".git"), { recursive: true }); - - const copyRecursiveSync = (src: string, dest: string): void => { - let exists = fs.existsSync(src); - let stats = exists && fs.statSync(src); - let isDirectory = exists && stats && stats.isDirectory(); - if (isDirectory) { - if (!fs.existsSync(dest)) { - fs.mkdirSync(dest); - } - - fs.readdirSync(src).forEach(function (childItemName) { - copyRecursiveSync(path.join(src, childItemName), path.join(dest, childItemName)); - }); - } else { - fs.copyFileSync(src, dest); - } - }; - copyRecursiveSync(selected.template === './' ? templatesDir : path.join(templatesDir, selected.template), siteDir); - - fs.rmSync(templatesDir, { recursive: true, force: true }); - - const readmePath = path.join(process.cwd(), 'sites', siteName, 'README.md'); - const readmeFile = fs.readFileSync(readmePath).toString(); - const newReadmeFile = readmeFile.split('\n'); - newReadmeFile[0] = `# ${answers.key}`; - newReadmeFile.splice(1, 2); - fs.writeFileSync(readmePath, newReadmeFile.join('\n')); - - let vars = (templateDetails.variables ?? []).map((variable: any) => { - let value = variable.value; - const replacements: Record = { - '{apiEndpoint}': globalConfig.getEndpoint(), - '{projectId}': localConfig.getProject().projectId, - '{projectName}': localConfig.getProject().projectName, - }; - - for (const placeholder in replacements) { - if (value?.includes(placeholder)) { - value = value.replace(placeholder, replacements[placeholder]); - } - } - - return { - key: variable.name, - value: value - }; + } + + /* Force use CMD as powershell does not support && */ + if (process.platform === "win32") { + gitCloneCommands = 'cmd /c "' + gitCloneCommands + '"'; + } + + /* Execute the child process but do not print any std output */ + try { + childProcess.execSync(gitCloneCommands, { + stdio: "pipe", + cwd: templatesDir, }); - - let data = { - $id: siteId, - name: answers.name, - framework: answers.framework.key, - adapter: templateDetails.frameworks[0].adapter || '', - buildRuntime: templateDetails.frameworks[0].buildRuntime || '', - installCommand: templateDetails.frameworks[0].installCommand || '', - buildCommand: templateDetails.frameworks[0].buildCommand || '', - outputDirectory: templateDetails.frameworks[0].outputDirectory || '', - fallbackFile: templateDetails.frameworks[0].fallbackFile || '', - specification: answers.specification, - enabled: true, - timeout: 30, - logging: true, - ignore: answers.framework.ignore || null, - path: `sites/${siteName}`, - vars: vars - }; - - if (!data.buildRuntime) { - log(`Build runtime for this framework not found. You will be asked to configure build runtime when you first push the site.`); - } - - if (!data.installCommand) { - log(`Installation command for this framework not found. You will be asked to configure the install command when you first push the site.`); + } catch (err: any) { + /* Specialised errors with recommended actions to take */ + if (err.message.includes("error: unknown option")) { + throw new Error( + `${err.message} \n\nSuggestion: Try updating your git to the latest version, then trying to run this command again.`, + ); + } else if ( + err.message.includes( + "is not recognized as an internal or external command,", + ) || + err.message.includes("command not found") + ) { + throw new Error( + `${err.message} \n\nSuggestion: It appears that git is not installed, try installing git then trying to run this command again.`, + ); + } else { + throw err; } - - if (!data.buildCommand) { - log(`Build command for this framework not found. You will be asked to configure the build command when you first push the site.`); + } + + fs.rmSync(path.join(templatesDir, ".git"), { recursive: true }); + + const copyRecursiveSync = (src: string, dest: string): void => { + let exists = fs.existsSync(src); + let stats = exists && fs.statSync(src); + let isDirectory = exists && stats && stats.isDirectory(); + if (isDirectory) { + if (!fs.existsSync(dest)) { + fs.mkdirSync(dest); + } + + fs.readdirSync(src).forEach(function (childItemName) { + copyRecursiveSync( + path.join(src, childItemName), + path.join(dest, childItemName), + ); + }); + } else { + fs.copyFileSync(src, dest); } + }; + copyRecursiveSync( + selected.template === "./" + ? templatesDir + : path.join(templatesDir, selected.template), + siteDir, + ); + + fs.rmSync(templatesDir, { recursive: true, force: true }); + + const readmePath = path.join(process.cwd(), "sites", siteName, "README.md"); + const readmeFile = fs.readFileSync(readmePath).toString(); + const newReadmeFile = readmeFile.split("\n"); + newReadmeFile[0] = `# ${answers.key}`; + newReadmeFile.splice(1, 2); + fs.writeFileSync(readmePath, newReadmeFile.join("\n")); + + let vars = (templateDetails.variables ?? []).map((variable: any) => { + let value = variable.value; + const replacements: Record = { + "{apiEndpoint}": globalConfig.getEndpoint(), + "{projectId}": localConfig.getProject().projectId, + "{projectName}": localConfig.getProject().projectName, + }; - if (!data.outputDirectory) { - log(`Output directory for this framework not found. You will be asked to configure the output directory when you first push the site.`); + for (const placeholder in replacements) { + if (value?.includes(placeholder)) { + value = value.replace(placeholder, replacements[placeholder]); + } } - localConfig.addSite(data); - success("Initializing site"); - log("Next you can use 'appwrite push site' to deploy the changes."); + return { + key: variable.name, + value: value, + }; + }); + + let data = { + $id: siteId, + name: answers.name, + framework: answers.framework.key, + adapter: templateDetails.frameworks[0].adapter || "", + buildRuntime: templateDetails.frameworks[0].buildRuntime || "", + installCommand: templateDetails.frameworks[0].installCommand || "", + buildCommand: templateDetails.frameworks[0].buildCommand || "", + outputDirectory: templateDetails.frameworks[0].outputDirectory || "", + fallbackFile: templateDetails.frameworks[0].fallbackFile || "", + specification: answers.specification, + enabled: true, + timeout: 30, + logging: true, + ignore: answers.framework.ignore || null, + path: `sites/${siteName}`, + vars: vars, + }; + + if (!data.buildRuntime) { + log( + `Build runtime for this framework not found. You will be asked to configure build runtime when you first push the site.`, + ); + } + + if (!data.installCommand) { + log( + `Installation command for this framework not found. You will be asked to configure the install command when you first push the site.`, + ); + } + + if (!data.buildCommand) { + log( + `Build command for this framework not found. You will be asked to configure the build command when you first push the site.`, + ); + } + + if (!data.outputDirectory) { + log( + `Output directory for this framework not found. You will be asked to configure the output directory when you first push the site.`, + ); + } + + localConfig.addSite(data); + success("Initializing site"); + log("Next you can use 'appwrite push site' to deploy the changes."); }; export const init = new Command("init") - .description(commandDescriptions['init']) - .action(actionRunner(initResources)); + .description(commandDescriptions["init"]) + .action(actionRunner(initResources)); init - .command("project") - .description("Init a new Appwrite project") - .option("--organization-id ", "Appwrite organization ID") - .option("--project-id ", "Appwrite project ID") - .option("--project-name ", "Appwrite project ID") - .action(actionRunner(initProject)); + .command("project") + .description("Init a new Appwrite project") + .option("--organization-id ", "Appwrite organization ID") + .option("--project-id ", "Appwrite project ID") + .option("--project-name ", "Appwrite project ID") + .action(actionRunner(initProject)); init - .command("function") - .alias("functions") - .description("Init a new Appwrite function") - .action(actionRunner(initFunction)); + .command("function") + .alias("functions") + .description("Init a new Appwrite function") + .action(actionRunner(initFunction)); init - .command("site") - .alias("sites") - .description("Init a new Appwrite site") - .action(actionRunner(initSite)); + .command("site") + .alias("sites") + .description("Init a new Appwrite site") + .action(actionRunner(initSite)); init - .command("bucket") - .alias("buckets") - .description("Init a new Appwrite bucket") - .action(actionRunner(initBucket)); + .command("bucket") + .alias("buckets") + .description("Init a new Appwrite bucket") + .action(actionRunner(initBucket)); init - .command("team") - .alias("teams") - .description("Init a new Appwrite team") - .action(actionRunner(initTeam)); + .command("team") + .alias("teams") + .description("Init a new Appwrite team") + .action(actionRunner(initTeam)); init - .command("collection") - .alias("collections") - .description("Init a new Appwrite collection") - .action(actionRunner(initCollection)); + .command("collection") + .alias("collections") + .description("Init a new Appwrite collection") + .action(actionRunner(initCollection)); init - .command("table") - .alias("tables") - .description("Init a new Appwrite table") - .action(actionRunner(initTable)); + .command("table") + .alias("tables") + .description("Init a new Appwrite table") + .action(actionRunner(initTable)); init - .command("topic") - .alias("topics") - .description("Init a new Appwrite topic") - .action(actionRunner(initTopic)); - + .command("topic") + .alias("topics") + .description("Init a new Appwrite topic") + .action(actionRunner(initTopic)); diff --git a/lib/commands/locale.ts b/lib/commands/locale.ts deleted file mode 100644 index e80a44a5..00000000 --- a/lib/commands/locale.ts +++ /dev/null @@ -1,270 +0,0 @@ -import fs = require('fs'); -import pathLib = require('path'); -import tar = require('tar'); -import ignore = require('ignore'); -import { promisify } from 'util'; -import Client from '../client'; -import { getAllFiles, showConsoleLink } from '../utils'; -import { Command } from 'commander'; -import { sdkForProject, sdkForConsole } from '../sdks'; -import { parse, actionRunner, parseInteger, parseBool, commandDescriptions, success, log, warn } from '../parser'; -import { localConfig, globalConfig } from '../config'; -import { File } from 'undici'; -import { ReadableStream } from 'stream/web'; - -function convertReadStreamToReadableStream(readStream: fs.ReadStream): ReadableStream { - return new ReadableStream({ - start(controller) { - readStream.on("data", (chunk: Buffer) => { - controller.enqueue(chunk); - }); - readStream.on("end", () => { - controller.close(); - }); - readStream.on("error", (err: Error) => { - controller.error(err); - }); - }, - cancel() { - readStream.destroy(); - }, - }); -} - -export const locale = new Command("locale").description(commandDescriptions['locale'] ?? '').configureHelp({ - helpWidth: process.stdout.columns || 80 -}) - -interface LocaleGetRequestParams { - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const localeGet = async ({parseOutput = true, overrideForCli = false, sdk = undefined}: LocaleGetRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/locale'; - let payload = {}; - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface LocaleListCodesRequestParams { - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const localeListCodes = async ({parseOutput = true, overrideForCli = false, sdk = undefined}: LocaleListCodesRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/locale/codes'; - let payload = {}; - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface LocaleListContinentsRequestParams { - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const localeListContinents = async ({parseOutput = true, overrideForCli = false, sdk = undefined}: LocaleListContinentsRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/locale/continents'; - let payload = {}; - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface LocaleListCountriesRequestParams { - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const localeListCountries = async ({parseOutput = true, overrideForCli = false, sdk = undefined}: LocaleListCountriesRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/locale/countries'; - let payload = {}; - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface LocaleListCountriesEURequestParams { - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const localeListCountriesEU = async ({parseOutput = true, overrideForCli = false, sdk = undefined}: LocaleListCountriesEURequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/locale/countries/eu'; - let payload = {}; - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface LocaleListCountriesPhonesRequestParams { - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const localeListCountriesPhones = async ({parseOutput = true, overrideForCli = false, sdk = undefined}: LocaleListCountriesPhonesRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/locale/countries/phones'; - let payload = {}; - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface LocaleListCurrenciesRequestParams { - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const localeListCurrencies = async ({parseOutput = true, overrideForCli = false, sdk = undefined}: LocaleListCurrenciesRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/locale/currencies'; - let payload = {}; - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface LocaleListLanguagesRequestParams { - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const localeListLanguages = async ({parseOutput = true, overrideForCli = false, sdk = undefined}: LocaleListLanguagesRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/locale/languages'; - let payload = {}; - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -locale - .command(`get`) - .description(`Get the current user location based on IP. Returns an object with user country code, country name, continent name, continent code, ip address and suggested currency. You can use the locale header to get the data in a supported language. ([IP Geolocation by DB-IP](https://db-ip.com))`) - .action(actionRunner(localeGet)) - -locale - .command(`list-codes`) - .description(`List of all locale codes in [ISO 639-1](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes).`) - .action(actionRunner(localeListCodes)) - -locale - .command(`list-continents`) - .description(`List of all continents. You can use the locale header to get the data in a supported language.`) - .action(actionRunner(localeListContinents)) - -locale - .command(`list-countries`) - .description(`List of all countries. You can use the locale header to get the data in a supported language.`) - .action(actionRunner(localeListCountries)) - -locale - .command(`list-countries-eu`) - .description(`List of all countries that are currently members of the EU. You can use the locale header to get the data in a supported language.`) - .action(actionRunner(localeListCountriesEU)) - -locale - .command(`list-countries-phones`) - .description(`List of all countries phone codes. You can use the locale header to get the data in a supported language.`) - .action(actionRunner(localeListCountriesPhones)) - -locale - .command(`list-currencies`) - .description(`List of all currencies, including currency symbol, name, plural, and decimal digits for all major and minor currencies. You can use the locale header to get the data in a supported language.`) - .action(actionRunner(localeListCurrencies)) - -locale - .command(`list-languages`) - .description(`List of all languages classified by ISO 639-1 including 2-letter code, name in English, and name in the respective language.`) - .action(actionRunner(localeListLanguages)) - - diff --git a/lib/commands/messaging.ts b/lib/commands/messaging.ts deleted file mode 100644 index 92d4c854..00000000 --- a/lib/commands/messaging.ts +++ /dev/null @@ -1,2878 +0,0 @@ -import fs = require('fs'); -import pathLib = require('path'); -import tar = require('tar'); -import ignore = require('ignore'); -import { promisify } from 'util'; -import Client from '../client'; -import { getAllFiles, showConsoleLink } from '../utils'; -import { Command } from 'commander'; -import { sdkForProject, sdkForConsole } from '../sdks'; -import { parse, actionRunner, parseInteger, parseBool, commandDescriptions, success, log, warn } from '../parser'; -import { localConfig, globalConfig } from '../config'; -import { File } from 'undici'; -import { ReadableStream } from 'stream/web'; - -function convertReadStreamToReadableStream(readStream: fs.ReadStream): ReadableStream { - return new ReadableStream({ - start(controller) { - readStream.on("data", (chunk: Buffer) => { - controller.enqueue(chunk); - }); - readStream.on("end", () => { - controller.close(); - }); - readStream.on("error", (err: Error) => { - controller.error(err); - }); - }, - cancel() { - readStream.destroy(); - }, - }); -} - -export const messaging = new Command("messaging").description(commandDescriptions['messaging'] ?? '').configureHelp({ - helpWidth: process.stdout.columns || 80 -}) - -interface MessagingListMessagesRequestParams { - queries?: string[]; - search?: string; - total?: boolean; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; - console?: boolean; -} - -export const messagingListMessages = async ({queries,search,total,parseOutput = true, overrideForCli = false, sdk = undefined, console: showConsole}: MessagingListMessagesRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/messaging/messages'; - let payload = {}; - if (typeof queries !== 'undefined') { - payload['queries'] = queries; - } - if (typeof search !== 'undefined') { - payload['search'] = search; - } - if (typeof total !== 'undefined') { - payload['total'] = total; - } - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - if(showConsole) { - showConsoleLink('messaging', 'listMessages'); - } else { - parse(response) - } - } - - return response; - -} -interface MessagingCreateEmailRequestParams { - messageId: string; - subject: string; - content: string; - topics?: string[]; - users?: string[]; - targets?: string[]; - cc?: string[]; - bcc?: string[]; - attachments?: string[]; - draft?: boolean; - html?: boolean; - scheduledAt?: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const messagingCreateEmail = async ({messageId,subject,content,topics,users,targets,cc,bcc,attachments,draft,html,scheduledAt,parseOutput = true, overrideForCli = false, sdk = undefined}: MessagingCreateEmailRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/messaging/messages/email'; - let payload = {}; - if (typeof messageId !== 'undefined') { - payload['messageId'] = messageId; - } - if (typeof subject !== 'undefined') { - payload['subject'] = subject; - } - if (typeof content !== 'undefined') { - payload['content'] = content; - } - topics = topics === true ? [] : topics; - if (typeof topics !== 'undefined') { - payload['topics'] = topics; - } - users = users === true ? [] : users; - if (typeof users !== 'undefined') { - payload['users'] = users; - } - targets = targets === true ? [] : targets; - if (typeof targets !== 'undefined') { - payload['targets'] = targets; - } - cc = cc === true ? [] : cc; - if (typeof cc !== 'undefined') { - payload['cc'] = cc; - } - bcc = bcc === true ? [] : bcc; - if (typeof bcc !== 'undefined') { - payload['bcc'] = bcc; - } - attachments = attachments === true ? [] : attachments; - if (typeof attachments !== 'undefined') { - payload['attachments'] = attachments; - } - if (typeof draft !== 'undefined') { - payload['draft'] = draft; - } - if (typeof html !== 'undefined') { - payload['html'] = html; - } - if (typeof scheduledAt !== 'undefined') { - payload['scheduledAt'] = scheduledAt; - } - - let response = undefined; - - response = await client.call('post', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface MessagingUpdateEmailRequestParams { - messageId: string; - topics?: string[]; - users?: string[]; - targets?: string[]; - subject?: string; - content?: string; - draft?: boolean; - html?: boolean; - cc?: string[]; - bcc?: string[]; - scheduledAt?: string; - attachments?: string[]; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const messagingUpdateEmail = async ({messageId,topics,users,targets,subject,content,draft,html,cc,bcc,scheduledAt,attachments,parseOutput = true, overrideForCli = false, sdk = undefined}: MessagingUpdateEmailRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/messaging/messages/email/{messageId}'.replace('{messageId}', messageId); - let payload = {}; - topics = topics === true ? [] : topics; - if (typeof topics !== 'undefined') { - payload['topics'] = topics; - } - users = users === true ? [] : users; - if (typeof users !== 'undefined') { - payload['users'] = users; - } - targets = targets === true ? [] : targets; - if (typeof targets !== 'undefined') { - payload['targets'] = targets; - } - if (typeof subject !== 'undefined') { - payload['subject'] = subject; - } - if (typeof content !== 'undefined') { - payload['content'] = content; - } - if (typeof draft !== 'undefined') { - payload['draft'] = draft; - } - if (typeof html !== 'undefined') { - payload['html'] = html; - } - cc = cc === true ? [] : cc; - if (typeof cc !== 'undefined') { - payload['cc'] = cc; - } - bcc = bcc === true ? [] : bcc; - if (typeof bcc !== 'undefined') { - payload['bcc'] = bcc; - } - if (typeof scheduledAt !== 'undefined') { - payload['scheduledAt'] = scheduledAt; - } - attachments = attachments === true ? [] : attachments; - if (typeof attachments !== 'undefined') { - payload['attachments'] = attachments; - } - - let response = undefined; - - response = await client.call('patch', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface MessagingCreatePushRequestParams { - messageId: string; - title?: string; - body?: string; - topics?: string[]; - users?: string[]; - targets?: string[]; - data?: object; - action?: string; - image?: string; - icon?: string; - sound?: string; - color?: string; - tag?: string; - badge?: number; - draft?: boolean; - scheduledAt?: string; - contentAvailable?: boolean; - critical?: boolean; - priority?: MessagePriority; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const messagingCreatePush = async ({messageId,title,body,topics,users,targets,data,action,image,icon,sound,color,tag,badge,draft,scheduledAt,contentAvailable,critical,priority,parseOutput = true, overrideForCli = false, sdk = undefined}: MessagingCreatePushRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/messaging/messages/push'; - let payload = {}; - if (typeof messageId !== 'undefined') { - payload['messageId'] = messageId; - } - if (typeof title !== 'undefined') { - payload['title'] = title; - } - if (typeof body !== 'undefined') { - payload['body'] = body; - } - topics = topics === true ? [] : topics; - if (typeof topics !== 'undefined') { - payload['topics'] = topics; - } - users = users === true ? [] : users; - if (typeof users !== 'undefined') { - payload['users'] = users; - } - targets = targets === true ? [] : targets; - if (typeof targets !== 'undefined') { - payload['targets'] = targets; - } - if (typeof data !== 'undefined') { - payload['data'] = JSON.parse(data); - } - if (typeof action !== 'undefined') { - payload['action'] = action; - } - if (typeof image !== 'undefined') { - payload['image'] = image; - } - if (typeof icon !== 'undefined') { - payload['icon'] = icon; - } - if (typeof sound !== 'undefined') { - payload['sound'] = sound; - } - if (typeof color !== 'undefined') { - payload['color'] = color; - } - if (typeof tag !== 'undefined') { - payload['tag'] = tag; - } - if (typeof badge !== 'undefined') { - payload['badge'] = badge; - } - if (typeof draft !== 'undefined') { - payload['draft'] = draft; - } - if (typeof scheduledAt !== 'undefined') { - payload['scheduledAt'] = scheduledAt; - } - if (typeof contentAvailable !== 'undefined') { - payload['contentAvailable'] = contentAvailable; - } - if (typeof critical !== 'undefined') { - payload['critical'] = critical; - } - if (typeof priority !== 'undefined') { - payload['priority'] = priority; - } - - let response = undefined; - - response = await client.call('post', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface MessagingUpdatePushRequestParams { - messageId: string; - topics?: string[]; - users?: string[]; - targets?: string[]; - title?: string; - body?: string; - data?: object; - action?: string; - image?: string; - icon?: string; - sound?: string; - color?: string; - tag?: string; - badge?: number; - draft?: boolean; - scheduledAt?: string; - contentAvailable?: boolean; - critical?: boolean; - priority?: MessagePriority; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const messagingUpdatePush = async ({messageId,topics,users,targets,title,body,data,action,image,icon,sound,color,tag,badge,draft,scheduledAt,contentAvailable,critical,priority,parseOutput = true, overrideForCli = false, sdk = undefined}: MessagingUpdatePushRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/messaging/messages/push/{messageId}'.replace('{messageId}', messageId); - let payload = {}; - topics = topics === true ? [] : topics; - if (typeof topics !== 'undefined') { - payload['topics'] = topics; - } - users = users === true ? [] : users; - if (typeof users !== 'undefined') { - payload['users'] = users; - } - targets = targets === true ? [] : targets; - if (typeof targets !== 'undefined') { - payload['targets'] = targets; - } - if (typeof title !== 'undefined') { - payload['title'] = title; - } - if (typeof body !== 'undefined') { - payload['body'] = body; - } - if (typeof data !== 'undefined') { - payload['data'] = JSON.parse(data); - } - if (typeof action !== 'undefined') { - payload['action'] = action; - } - if (typeof image !== 'undefined') { - payload['image'] = image; - } - if (typeof icon !== 'undefined') { - payload['icon'] = icon; - } - if (typeof sound !== 'undefined') { - payload['sound'] = sound; - } - if (typeof color !== 'undefined') { - payload['color'] = color; - } - if (typeof tag !== 'undefined') { - payload['tag'] = tag; - } - if (typeof badge !== 'undefined') { - payload['badge'] = badge; - } - if (typeof draft !== 'undefined') { - payload['draft'] = draft; - } - if (typeof scheduledAt !== 'undefined') { - payload['scheduledAt'] = scheduledAt; - } - if (typeof contentAvailable !== 'undefined') { - payload['contentAvailable'] = contentAvailable; - } - if (typeof critical !== 'undefined') { - payload['critical'] = critical; - } - if (typeof priority !== 'undefined') { - payload['priority'] = priority; - } - - let response = undefined; - - response = await client.call('patch', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface MessagingCreateSMSRequestParams { - messageId: string; - content: string; - topics?: string[]; - users?: string[]; - targets?: string[]; - draft?: boolean; - scheduledAt?: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const messagingCreateSMS = async ({messageId,content,topics,users,targets,draft,scheduledAt,parseOutput = true, overrideForCli = false, sdk = undefined}: MessagingCreateSMSRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/messaging/messages/sms'; - let payload = {}; - if (typeof messageId !== 'undefined') { - payload['messageId'] = messageId; - } - if (typeof content !== 'undefined') { - payload['content'] = content; - } - topics = topics === true ? [] : topics; - if (typeof topics !== 'undefined') { - payload['topics'] = topics; - } - users = users === true ? [] : users; - if (typeof users !== 'undefined') { - payload['users'] = users; - } - targets = targets === true ? [] : targets; - if (typeof targets !== 'undefined') { - payload['targets'] = targets; - } - if (typeof draft !== 'undefined') { - payload['draft'] = draft; - } - if (typeof scheduledAt !== 'undefined') { - payload['scheduledAt'] = scheduledAt; - } - - let response = undefined; - - response = await client.call('post', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface MessagingUpdateSMSRequestParams { - messageId: string; - topics?: string[]; - users?: string[]; - targets?: string[]; - content?: string; - draft?: boolean; - scheduledAt?: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const messagingUpdateSMS = async ({messageId,topics,users,targets,content,draft,scheduledAt,parseOutput = true, overrideForCli = false, sdk = undefined}: MessagingUpdateSMSRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/messaging/messages/sms/{messageId}'.replace('{messageId}', messageId); - let payload = {}; - topics = topics === true ? [] : topics; - if (typeof topics !== 'undefined') { - payload['topics'] = topics; - } - users = users === true ? [] : users; - if (typeof users !== 'undefined') { - payload['users'] = users; - } - targets = targets === true ? [] : targets; - if (typeof targets !== 'undefined') { - payload['targets'] = targets; - } - if (typeof content !== 'undefined') { - payload['content'] = content; - } - if (typeof draft !== 'undefined') { - payload['draft'] = draft; - } - if (typeof scheduledAt !== 'undefined') { - payload['scheduledAt'] = scheduledAt; - } - - let response = undefined; - - response = await client.call('patch', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface MessagingGetMessageRequestParams { - messageId: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; - console?: boolean; -} - -export const messagingGetMessage = async ({messageId,parseOutput = true, overrideForCli = false, sdk = undefined, console: showConsole}: MessagingGetMessageRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/messaging/messages/{messageId}'.replace('{messageId}', messageId); - let payload = {}; - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - if(showConsole) { - showConsoleLink('messaging', 'getMessage', messageId); - } else { - parse(response) - } - } - - return response; - -} -interface MessagingDeleteRequestParams { - messageId: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const messagingDelete = async ({messageId,parseOutput = true, overrideForCli = false, sdk = undefined}: MessagingDeleteRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/messaging/messages/{messageId}'.replace('{messageId}', messageId); - let payload = {}; - - let response = undefined; - - response = await client.call('delete', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface MessagingListMessageLogsRequestParams { - messageId: string; - queries?: string[]; - total?: boolean; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; - console?: boolean; -} - -export const messagingListMessageLogs = async ({messageId,queries,total,parseOutput = true, overrideForCli = false, sdk = undefined, console: showConsole}: MessagingListMessageLogsRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/messaging/messages/{messageId}/logs'.replace('{messageId}', messageId); - let payload = {}; - if (typeof queries !== 'undefined') { - payload['queries'] = queries; - } - if (typeof total !== 'undefined') { - payload['total'] = total; - } - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - if(showConsole) { - showConsoleLink('messaging', 'listMessageLogs', messageId); - } else { - parse(response) - } - } - - return response; - -} -interface MessagingListTargetsRequestParams { - messageId: string; - queries?: string[]; - total?: boolean; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const messagingListTargets = async ({messageId,queries,total,parseOutput = true, overrideForCli = false, sdk = undefined}: MessagingListTargetsRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/messaging/messages/{messageId}/targets'.replace('{messageId}', messageId); - let payload = {}; - if (typeof queries !== 'undefined') { - payload['queries'] = queries; - } - if (typeof total !== 'undefined') { - payload['total'] = total; - } - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface MessagingListProvidersRequestParams { - queries?: string[]; - search?: string; - total?: boolean; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; - console?: boolean; -} - -export const messagingListProviders = async ({queries,search,total,parseOutput = true, overrideForCli = false, sdk = undefined, console: showConsole}: MessagingListProvidersRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/messaging/providers'; - let payload = {}; - if (typeof queries !== 'undefined') { - payload['queries'] = queries; - } - if (typeof search !== 'undefined') { - payload['search'] = search; - } - if (typeof total !== 'undefined') { - payload['total'] = total; - } - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - if(showConsole) { - showConsoleLink('messaging', 'listProviders'); - } else { - parse(response) - } - } - - return response; - -} -interface MessagingCreateAPNSProviderRequestParams { - providerId: string; - name: string; - authKey?: string; - authKeyId?: string; - teamId?: string; - bundleId?: string; - sandbox?: boolean; - enabled?: boolean; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const messagingCreateAPNSProvider = async ({providerId,name,authKey,authKeyId,teamId,bundleId,sandbox,enabled,parseOutput = true, overrideForCli = false, sdk = undefined}: MessagingCreateAPNSProviderRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/messaging/providers/apns'; - let payload = {}; - if (typeof providerId !== 'undefined') { - payload['providerId'] = providerId; - } - if (typeof name !== 'undefined') { - payload['name'] = name; - } - if (typeof authKey !== 'undefined') { - payload['authKey'] = authKey; - } - if (typeof authKeyId !== 'undefined') { - payload['authKeyId'] = authKeyId; - } - if (typeof teamId !== 'undefined') { - payload['teamId'] = teamId; - } - if (typeof bundleId !== 'undefined') { - payload['bundleId'] = bundleId; - } - if (typeof sandbox !== 'undefined') { - payload['sandbox'] = sandbox; - } - if (typeof enabled !== 'undefined') { - payload['enabled'] = enabled; - } - - let response = undefined; - - response = await client.call('post', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface MessagingUpdateAPNSProviderRequestParams { - providerId: string; - name?: string; - enabled?: boolean; - authKey?: string; - authKeyId?: string; - teamId?: string; - bundleId?: string; - sandbox?: boolean; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const messagingUpdateAPNSProvider = async ({providerId,name,enabled,authKey,authKeyId,teamId,bundleId,sandbox,parseOutput = true, overrideForCli = false, sdk = undefined}: MessagingUpdateAPNSProviderRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/messaging/providers/apns/{providerId}'.replace('{providerId}', providerId); - let payload = {}; - if (typeof name !== 'undefined') { - payload['name'] = name; - } - if (typeof enabled !== 'undefined') { - payload['enabled'] = enabled; - } - if (typeof authKey !== 'undefined') { - payload['authKey'] = authKey; - } - if (typeof authKeyId !== 'undefined') { - payload['authKeyId'] = authKeyId; - } - if (typeof teamId !== 'undefined') { - payload['teamId'] = teamId; - } - if (typeof bundleId !== 'undefined') { - payload['bundleId'] = bundleId; - } - if (typeof sandbox !== 'undefined') { - payload['sandbox'] = sandbox; - } - - let response = undefined; - - response = await client.call('patch', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface MessagingCreateFCMProviderRequestParams { - providerId: string; - name: string; - serviceAccountJSON?: object; - enabled?: boolean; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const messagingCreateFCMProvider = async ({providerId,name,serviceAccountJSON,enabled,parseOutput = true, overrideForCli = false, sdk = undefined}: MessagingCreateFCMProviderRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/messaging/providers/fcm'; - let payload = {}; - if (typeof providerId !== 'undefined') { - payload['providerId'] = providerId; - } - if (typeof name !== 'undefined') { - payload['name'] = name; - } - if (typeof serviceAccountJSON !== 'undefined') { - payload['serviceAccountJSON'] = JSON.parse(serviceAccountJSON); - } - if (typeof enabled !== 'undefined') { - payload['enabled'] = enabled; - } - - let response = undefined; - - response = await client.call('post', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface MessagingUpdateFCMProviderRequestParams { - providerId: string; - name?: string; - enabled?: boolean; - serviceAccountJSON?: object; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const messagingUpdateFCMProvider = async ({providerId,name,enabled,serviceAccountJSON,parseOutput = true, overrideForCli = false, sdk = undefined}: MessagingUpdateFCMProviderRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/messaging/providers/fcm/{providerId}'.replace('{providerId}', providerId); - let payload = {}; - if (typeof name !== 'undefined') { - payload['name'] = name; - } - if (typeof enabled !== 'undefined') { - payload['enabled'] = enabled; - } - if (typeof serviceAccountJSON !== 'undefined') { - payload['serviceAccountJSON'] = JSON.parse(serviceAccountJSON); - } - - let response = undefined; - - response = await client.call('patch', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface MessagingCreateMailgunProviderRequestParams { - providerId: string; - name: string; - apiKey?: string; - domain?: string; - isEuRegion?: boolean; - fromName?: string; - fromEmail?: string; - replyToName?: string; - replyToEmail?: string; - enabled?: boolean; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const messagingCreateMailgunProvider = async ({providerId,name,apiKey,domain,isEuRegion,fromName,fromEmail,replyToName,replyToEmail,enabled,parseOutput = true, overrideForCli = false, sdk = undefined}: MessagingCreateMailgunProviderRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/messaging/providers/mailgun'; - let payload = {}; - if (typeof providerId !== 'undefined') { - payload['providerId'] = providerId; - } - if (typeof name !== 'undefined') { - payload['name'] = name; - } - if (typeof apiKey !== 'undefined') { - payload['apiKey'] = apiKey; - } - if (typeof domain !== 'undefined') { - payload['domain'] = domain; - } - if (typeof isEuRegion !== 'undefined') { - payload['isEuRegion'] = isEuRegion; - } - if (typeof fromName !== 'undefined') { - payload['fromName'] = fromName; - } - if (typeof fromEmail !== 'undefined') { - payload['fromEmail'] = fromEmail; - } - if (typeof replyToName !== 'undefined') { - payload['replyToName'] = replyToName; - } - if (typeof replyToEmail !== 'undefined') { - payload['replyToEmail'] = replyToEmail; - } - if (typeof enabled !== 'undefined') { - payload['enabled'] = enabled; - } - - let response = undefined; - - response = await client.call('post', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface MessagingUpdateMailgunProviderRequestParams { - providerId: string; - name?: string; - apiKey?: string; - domain?: string; - isEuRegion?: boolean; - enabled?: boolean; - fromName?: string; - fromEmail?: string; - replyToName?: string; - replyToEmail?: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const messagingUpdateMailgunProvider = async ({providerId,name,apiKey,domain,isEuRegion,enabled,fromName,fromEmail,replyToName,replyToEmail,parseOutput = true, overrideForCli = false, sdk = undefined}: MessagingUpdateMailgunProviderRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/messaging/providers/mailgun/{providerId}'.replace('{providerId}', providerId); - let payload = {}; - if (typeof name !== 'undefined') { - payload['name'] = name; - } - if (typeof apiKey !== 'undefined') { - payload['apiKey'] = apiKey; - } - if (typeof domain !== 'undefined') { - payload['domain'] = domain; - } - if (typeof isEuRegion !== 'undefined') { - payload['isEuRegion'] = isEuRegion; - } - if (typeof enabled !== 'undefined') { - payload['enabled'] = enabled; - } - if (typeof fromName !== 'undefined') { - payload['fromName'] = fromName; - } - if (typeof fromEmail !== 'undefined') { - payload['fromEmail'] = fromEmail; - } - if (typeof replyToName !== 'undefined') { - payload['replyToName'] = replyToName; - } - if (typeof replyToEmail !== 'undefined') { - payload['replyToEmail'] = replyToEmail; - } - - let response = undefined; - - response = await client.call('patch', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface MessagingCreateMsg91ProviderRequestParams { - providerId: string; - name: string; - templateId?: string; - senderId?: string; - authKey?: string; - enabled?: boolean; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const messagingCreateMsg91Provider = async ({providerId,name,templateId,senderId,authKey,enabled,parseOutput = true, overrideForCli = false, sdk = undefined}: MessagingCreateMsg91ProviderRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/messaging/providers/msg91'; - let payload = {}; - if (typeof providerId !== 'undefined') { - payload['providerId'] = providerId; - } - if (typeof name !== 'undefined') { - payload['name'] = name; - } - if (typeof templateId !== 'undefined') { - payload['templateId'] = templateId; - } - if (typeof senderId !== 'undefined') { - payload['senderId'] = senderId; - } - if (typeof authKey !== 'undefined') { - payload['authKey'] = authKey; - } - if (typeof enabled !== 'undefined') { - payload['enabled'] = enabled; - } - - let response = undefined; - - response = await client.call('post', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface MessagingUpdateMsg91ProviderRequestParams { - providerId: string; - name?: string; - enabled?: boolean; - templateId?: string; - senderId?: string; - authKey?: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const messagingUpdateMsg91Provider = async ({providerId,name,enabled,templateId,senderId,authKey,parseOutput = true, overrideForCli = false, sdk = undefined}: MessagingUpdateMsg91ProviderRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/messaging/providers/msg91/{providerId}'.replace('{providerId}', providerId); - let payload = {}; - if (typeof name !== 'undefined') { - payload['name'] = name; - } - if (typeof enabled !== 'undefined') { - payload['enabled'] = enabled; - } - if (typeof templateId !== 'undefined') { - payload['templateId'] = templateId; - } - if (typeof senderId !== 'undefined') { - payload['senderId'] = senderId; - } - if (typeof authKey !== 'undefined') { - payload['authKey'] = authKey; - } - - let response = undefined; - - response = await client.call('patch', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface MessagingCreateResendProviderRequestParams { - providerId: string; - name: string; - apiKey?: string; - fromName?: string; - fromEmail?: string; - replyToName?: string; - replyToEmail?: string; - enabled?: boolean; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const messagingCreateResendProvider = async ({providerId,name,apiKey,fromName,fromEmail,replyToName,replyToEmail,enabled,parseOutput = true, overrideForCli = false, sdk = undefined}: MessagingCreateResendProviderRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/messaging/providers/resend'; - let payload = {}; - if (typeof providerId !== 'undefined') { - payload['providerId'] = providerId; - } - if (typeof name !== 'undefined') { - payload['name'] = name; - } - if (typeof apiKey !== 'undefined') { - payload['apiKey'] = apiKey; - } - if (typeof fromName !== 'undefined') { - payload['fromName'] = fromName; - } - if (typeof fromEmail !== 'undefined') { - payload['fromEmail'] = fromEmail; - } - if (typeof replyToName !== 'undefined') { - payload['replyToName'] = replyToName; - } - if (typeof replyToEmail !== 'undefined') { - payload['replyToEmail'] = replyToEmail; - } - if (typeof enabled !== 'undefined') { - payload['enabled'] = enabled; - } - - let response = undefined; - - response = await client.call('post', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface MessagingUpdateResendProviderRequestParams { - providerId: string; - name?: string; - enabled?: boolean; - apiKey?: string; - fromName?: string; - fromEmail?: string; - replyToName?: string; - replyToEmail?: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const messagingUpdateResendProvider = async ({providerId,name,enabled,apiKey,fromName,fromEmail,replyToName,replyToEmail,parseOutput = true, overrideForCli = false, sdk = undefined}: MessagingUpdateResendProviderRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/messaging/providers/resend/{providerId}'.replace('{providerId}', providerId); - let payload = {}; - if (typeof name !== 'undefined') { - payload['name'] = name; - } - if (typeof enabled !== 'undefined') { - payload['enabled'] = enabled; - } - if (typeof apiKey !== 'undefined') { - payload['apiKey'] = apiKey; - } - if (typeof fromName !== 'undefined') { - payload['fromName'] = fromName; - } - if (typeof fromEmail !== 'undefined') { - payload['fromEmail'] = fromEmail; - } - if (typeof replyToName !== 'undefined') { - payload['replyToName'] = replyToName; - } - if (typeof replyToEmail !== 'undefined') { - payload['replyToEmail'] = replyToEmail; - } - - let response = undefined; - - response = await client.call('patch', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface MessagingCreateSendgridProviderRequestParams { - providerId: string; - name: string; - apiKey?: string; - fromName?: string; - fromEmail?: string; - replyToName?: string; - replyToEmail?: string; - enabled?: boolean; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const messagingCreateSendgridProvider = async ({providerId,name,apiKey,fromName,fromEmail,replyToName,replyToEmail,enabled,parseOutput = true, overrideForCli = false, sdk = undefined}: MessagingCreateSendgridProviderRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/messaging/providers/sendgrid'; - let payload = {}; - if (typeof providerId !== 'undefined') { - payload['providerId'] = providerId; - } - if (typeof name !== 'undefined') { - payload['name'] = name; - } - if (typeof apiKey !== 'undefined') { - payload['apiKey'] = apiKey; - } - if (typeof fromName !== 'undefined') { - payload['fromName'] = fromName; - } - if (typeof fromEmail !== 'undefined') { - payload['fromEmail'] = fromEmail; - } - if (typeof replyToName !== 'undefined') { - payload['replyToName'] = replyToName; - } - if (typeof replyToEmail !== 'undefined') { - payload['replyToEmail'] = replyToEmail; - } - if (typeof enabled !== 'undefined') { - payload['enabled'] = enabled; - } - - let response = undefined; - - response = await client.call('post', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface MessagingUpdateSendgridProviderRequestParams { - providerId: string; - name?: string; - enabled?: boolean; - apiKey?: string; - fromName?: string; - fromEmail?: string; - replyToName?: string; - replyToEmail?: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const messagingUpdateSendgridProvider = async ({providerId,name,enabled,apiKey,fromName,fromEmail,replyToName,replyToEmail,parseOutput = true, overrideForCli = false, sdk = undefined}: MessagingUpdateSendgridProviderRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/messaging/providers/sendgrid/{providerId}'.replace('{providerId}', providerId); - let payload = {}; - if (typeof name !== 'undefined') { - payload['name'] = name; - } - if (typeof enabled !== 'undefined') { - payload['enabled'] = enabled; - } - if (typeof apiKey !== 'undefined') { - payload['apiKey'] = apiKey; - } - if (typeof fromName !== 'undefined') { - payload['fromName'] = fromName; - } - if (typeof fromEmail !== 'undefined') { - payload['fromEmail'] = fromEmail; - } - if (typeof replyToName !== 'undefined') { - payload['replyToName'] = replyToName; - } - if (typeof replyToEmail !== 'undefined') { - payload['replyToEmail'] = replyToEmail; - } - - let response = undefined; - - response = await client.call('patch', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface MessagingCreateSMTPProviderRequestParams { - providerId: string; - name: string; - host: string; - port?: number; - username?: string; - password?: string; - encryption?: SmtpEncryption; - autoTLS?: boolean; - mailer?: string; - fromName?: string; - fromEmail?: string; - replyToName?: string; - replyToEmail?: string; - enabled?: boolean; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const messagingCreateSMTPProvider = async ({providerId,name,host,port,username,password,encryption,autoTLS,mailer,fromName,fromEmail,replyToName,replyToEmail,enabled,parseOutput = true, overrideForCli = false, sdk = undefined}: MessagingCreateSMTPProviderRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/messaging/providers/smtp'; - let payload = {}; - if (typeof providerId !== 'undefined') { - payload['providerId'] = providerId; - } - if (typeof name !== 'undefined') { - payload['name'] = name; - } - if (typeof host !== 'undefined') { - payload['host'] = host; - } - if (typeof port !== 'undefined') { - payload['port'] = port; - } - if (typeof username !== 'undefined') { - payload['username'] = username; - } - if (typeof password !== 'undefined') { - payload['password'] = password; - } - if (typeof encryption !== 'undefined') { - payload['encryption'] = encryption; - } - if (typeof autoTLS !== 'undefined') { - payload['autoTLS'] = autoTLS; - } - if (typeof mailer !== 'undefined') { - payload['mailer'] = mailer; - } - if (typeof fromName !== 'undefined') { - payload['fromName'] = fromName; - } - if (typeof fromEmail !== 'undefined') { - payload['fromEmail'] = fromEmail; - } - if (typeof replyToName !== 'undefined') { - payload['replyToName'] = replyToName; - } - if (typeof replyToEmail !== 'undefined') { - payload['replyToEmail'] = replyToEmail; - } - if (typeof enabled !== 'undefined') { - payload['enabled'] = enabled; - } - - let response = undefined; - - response = await client.call('post', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface MessagingUpdateSMTPProviderRequestParams { - providerId: string; - name?: string; - host?: string; - port?: number; - username?: string; - password?: string; - encryption?: SmtpEncryption; - autoTLS?: boolean; - mailer?: string; - fromName?: string; - fromEmail?: string; - replyToName?: string; - replyToEmail?: string; - enabled?: boolean; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const messagingUpdateSMTPProvider = async ({providerId,name,host,port,username,password,encryption,autoTLS,mailer,fromName,fromEmail,replyToName,replyToEmail,enabled,parseOutput = true, overrideForCli = false, sdk = undefined}: MessagingUpdateSMTPProviderRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/messaging/providers/smtp/{providerId}'.replace('{providerId}', providerId); - let payload = {}; - if (typeof name !== 'undefined') { - payload['name'] = name; - } - if (typeof host !== 'undefined') { - payload['host'] = host; - } - if (typeof port !== 'undefined') { - payload['port'] = port; - } - if (typeof username !== 'undefined') { - payload['username'] = username; - } - if (typeof password !== 'undefined') { - payload['password'] = password; - } - if (typeof encryption !== 'undefined') { - payload['encryption'] = encryption; - } - if (typeof autoTLS !== 'undefined') { - payload['autoTLS'] = autoTLS; - } - if (typeof mailer !== 'undefined') { - payload['mailer'] = mailer; - } - if (typeof fromName !== 'undefined') { - payload['fromName'] = fromName; - } - if (typeof fromEmail !== 'undefined') { - payload['fromEmail'] = fromEmail; - } - if (typeof replyToName !== 'undefined') { - payload['replyToName'] = replyToName; - } - if (typeof replyToEmail !== 'undefined') { - payload['replyToEmail'] = replyToEmail; - } - if (typeof enabled !== 'undefined') { - payload['enabled'] = enabled; - } - - let response = undefined; - - response = await client.call('patch', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface MessagingCreateTelesignProviderRequestParams { - providerId: string; - name: string; - from?: string; - customerId?: string; - apiKey?: string; - enabled?: boolean; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const messagingCreateTelesignProvider = async ({providerId,name,from,customerId,apiKey,enabled,parseOutput = true, overrideForCli = false, sdk = undefined}: MessagingCreateTelesignProviderRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/messaging/providers/telesign'; - let payload = {}; - if (typeof providerId !== 'undefined') { - payload['providerId'] = providerId; - } - if (typeof name !== 'undefined') { - payload['name'] = name; - } - if (typeof from !== 'undefined') { - payload['from'] = from; - } - if (typeof customerId !== 'undefined') { - payload['customerId'] = customerId; - } - if (typeof apiKey !== 'undefined') { - payload['apiKey'] = apiKey; - } - if (typeof enabled !== 'undefined') { - payload['enabled'] = enabled; - } - - let response = undefined; - - response = await client.call('post', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface MessagingUpdateTelesignProviderRequestParams { - providerId: string; - name?: string; - enabled?: boolean; - customerId?: string; - apiKey?: string; - from?: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const messagingUpdateTelesignProvider = async ({providerId,name,enabled,customerId,apiKey,from,parseOutput = true, overrideForCli = false, sdk = undefined}: MessagingUpdateTelesignProviderRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/messaging/providers/telesign/{providerId}'.replace('{providerId}', providerId); - let payload = {}; - if (typeof name !== 'undefined') { - payload['name'] = name; - } - if (typeof enabled !== 'undefined') { - payload['enabled'] = enabled; - } - if (typeof customerId !== 'undefined') { - payload['customerId'] = customerId; - } - if (typeof apiKey !== 'undefined') { - payload['apiKey'] = apiKey; - } - if (typeof from !== 'undefined') { - payload['from'] = from; - } - - let response = undefined; - - response = await client.call('patch', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface MessagingCreateTextmagicProviderRequestParams { - providerId: string; - name: string; - from?: string; - username?: string; - apiKey?: string; - enabled?: boolean; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const messagingCreateTextmagicProvider = async ({providerId,name,from,username,apiKey,enabled,parseOutput = true, overrideForCli = false, sdk = undefined}: MessagingCreateTextmagicProviderRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/messaging/providers/textmagic'; - let payload = {}; - if (typeof providerId !== 'undefined') { - payload['providerId'] = providerId; - } - if (typeof name !== 'undefined') { - payload['name'] = name; - } - if (typeof from !== 'undefined') { - payload['from'] = from; - } - if (typeof username !== 'undefined') { - payload['username'] = username; - } - if (typeof apiKey !== 'undefined') { - payload['apiKey'] = apiKey; - } - if (typeof enabled !== 'undefined') { - payload['enabled'] = enabled; - } - - let response = undefined; - - response = await client.call('post', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface MessagingUpdateTextmagicProviderRequestParams { - providerId: string; - name?: string; - enabled?: boolean; - username?: string; - apiKey?: string; - from?: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const messagingUpdateTextmagicProvider = async ({providerId,name,enabled,username,apiKey,from,parseOutput = true, overrideForCli = false, sdk = undefined}: MessagingUpdateTextmagicProviderRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/messaging/providers/textmagic/{providerId}'.replace('{providerId}', providerId); - let payload = {}; - if (typeof name !== 'undefined') { - payload['name'] = name; - } - if (typeof enabled !== 'undefined') { - payload['enabled'] = enabled; - } - if (typeof username !== 'undefined') { - payload['username'] = username; - } - if (typeof apiKey !== 'undefined') { - payload['apiKey'] = apiKey; - } - if (typeof from !== 'undefined') { - payload['from'] = from; - } - - let response = undefined; - - response = await client.call('patch', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface MessagingCreateTwilioProviderRequestParams { - providerId: string; - name: string; - from?: string; - accountSid?: string; - authToken?: string; - enabled?: boolean; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const messagingCreateTwilioProvider = async ({providerId,name,from,accountSid,authToken,enabled,parseOutput = true, overrideForCli = false, sdk = undefined}: MessagingCreateTwilioProviderRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/messaging/providers/twilio'; - let payload = {}; - if (typeof providerId !== 'undefined') { - payload['providerId'] = providerId; - } - if (typeof name !== 'undefined') { - payload['name'] = name; - } - if (typeof from !== 'undefined') { - payload['from'] = from; - } - if (typeof accountSid !== 'undefined') { - payload['accountSid'] = accountSid; - } - if (typeof authToken !== 'undefined') { - payload['authToken'] = authToken; - } - if (typeof enabled !== 'undefined') { - payload['enabled'] = enabled; - } - - let response = undefined; - - response = await client.call('post', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface MessagingUpdateTwilioProviderRequestParams { - providerId: string; - name?: string; - enabled?: boolean; - accountSid?: string; - authToken?: string; - from?: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const messagingUpdateTwilioProvider = async ({providerId,name,enabled,accountSid,authToken,from,parseOutput = true, overrideForCli = false, sdk = undefined}: MessagingUpdateTwilioProviderRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/messaging/providers/twilio/{providerId}'.replace('{providerId}', providerId); - let payload = {}; - if (typeof name !== 'undefined') { - payload['name'] = name; - } - if (typeof enabled !== 'undefined') { - payload['enabled'] = enabled; - } - if (typeof accountSid !== 'undefined') { - payload['accountSid'] = accountSid; - } - if (typeof authToken !== 'undefined') { - payload['authToken'] = authToken; - } - if (typeof from !== 'undefined') { - payload['from'] = from; - } - - let response = undefined; - - response = await client.call('patch', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface MessagingCreateVonageProviderRequestParams { - providerId: string; - name: string; - from?: string; - apiKey?: string; - apiSecret?: string; - enabled?: boolean; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const messagingCreateVonageProvider = async ({providerId,name,from,apiKey,apiSecret,enabled,parseOutput = true, overrideForCli = false, sdk = undefined}: MessagingCreateVonageProviderRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/messaging/providers/vonage'; - let payload = {}; - if (typeof providerId !== 'undefined') { - payload['providerId'] = providerId; - } - if (typeof name !== 'undefined') { - payload['name'] = name; - } - if (typeof from !== 'undefined') { - payload['from'] = from; - } - if (typeof apiKey !== 'undefined') { - payload['apiKey'] = apiKey; - } - if (typeof apiSecret !== 'undefined') { - payload['apiSecret'] = apiSecret; - } - if (typeof enabled !== 'undefined') { - payload['enabled'] = enabled; - } - - let response = undefined; - - response = await client.call('post', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface MessagingUpdateVonageProviderRequestParams { - providerId: string; - name?: string; - enabled?: boolean; - apiKey?: string; - apiSecret?: string; - from?: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const messagingUpdateVonageProvider = async ({providerId,name,enabled,apiKey,apiSecret,from,parseOutput = true, overrideForCli = false, sdk = undefined}: MessagingUpdateVonageProviderRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/messaging/providers/vonage/{providerId}'.replace('{providerId}', providerId); - let payload = {}; - if (typeof name !== 'undefined') { - payload['name'] = name; - } - if (typeof enabled !== 'undefined') { - payload['enabled'] = enabled; - } - if (typeof apiKey !== 'undefined') { - payload['apiKey'] = apiKey; - } - if (typeof apiSecret !== 'undefined') { - payload['apiSecret'] = apiSecret; - } - if (typeof from !== 'undefined') { - payload['from'] = from; - } - - let response = undefined; - - response = await client.call('patch', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface MessagingGetProviderRequestParams { - providerId: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; - console?: boolean; -} - -export const messagingGetProvider = async ({providerId,parseOutput = true, overrideForCli = false, sdk = undefined, console: showConsole}: MessagingGetProviderRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/messaging/providers/{providerId}'.replace('{providerId}', providerId); - let payload = {}; - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - if(showConsole) { - showConsoleLink('messaging', 'getProvider', providerId); - } else { - parse(response) - } - } - - return response; - -} -interface MessagingDeleteProviderRequestParams { - providerId: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const messagingDeleteProvider = async ({providerId,parseOutput = true, overrideForCli = false, sdk = undefined}: MessagingDeleteProviderRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/messaging/providers/{providerId}'.replace('{providerId}', providerId); - let payload = {}; - - let response = undefined; - - response = await client.call('delete', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface MessagingListProviderLogsRequestParams { - providerId: string; - queries?: string[]; - total?: boolean; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const messagingListProviderLogs = async ({providerId,queries,total,parseOutput = true, overrideForCli = false, sdk = undefined}: MessagingListProviderLogsRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/messaging/providers/{providerId}/logs'.replace('{providerId}', providerId); - let payload = {}; - if (typeof queries !== 'undefined') { - payload['queries'] = queries; - } - if (typeof total !== 'undefined') { - payload['total'] = total; - } - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface MessagingListSubscriberLogsRequestParams { - subscriberId: string; - queries?: string[]; - total?: boolean; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const messagingListSubscriberLogs = async ({subscriberId,queries,total,parseOutput = true, overrideForCli = false, sdk = undefined}: MessagingListSubscriberLogsRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/messaging/subscribers/{subscriberId}/logs'.replace('{subscriberId}', subscriberId); - let payload = {}; - if (typeof queries !== 'undefined') { - payload['queries'] = queries; - } - if (typeof total !== 'undefined') { - payload['total'] = total; - } - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface MessagingListTopicsRequestParams { - queries?: string[]; - search?: string; - total?: boolean; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; - console?: boolean; -} - -export const messagingListTopics = async ({queries,search,total,parseOutput = true, overrideForCli = false, sdk = undefined, console: showConsole}: MessagingListTopicsRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/messaging/topics'; - let payload = {}; - if (typeof queries !== 'undefined') { - payload['queries'] = queries; - } - if (typeof search !== 'undefined') { - payload['search'] = search; - } - if (typeof total !== 'undefined') { - payload['total'] = total; - } - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - if(showConsole) { - showConsoleLink('messaging', 'listTopics'); - } else { - parse(response) - } - } - - return response; - -} -interface MessagingCreateTopicRequestParams { - topicId: string; - name: string; - subscribe?: string[]; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const messagingCreateTopic = async ({topicId,name,subscribe,parseOutput = true, overrideForCli = false, sdk = undefined}: MessagingCreateTopicRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/messaging/topics'; - let payload = {}; - if (typeof topicId !== 'undefined') { - payload['topicId'] = topicId; - } - if (typeof name !== 'undefined') { - payload['name'] = name; - } - subscribe = subscribe === true ? [] : subscribe; - if (typeof subscribe !== 'undefined') { - payload['subscribe'] = subscribe; - } - - let response = undefined; - - response = await client.call('post', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface MessagingGetTopicRequestParams { - topicId: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; - console?: boolean; -} - -export const messagingGetTopic = async ({topicId,parseOutput = true, overrideForCli = false, sdk = undefined, console: showConsole}: MessagingGetTopicRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/messaging/topics/{topicId}'.replace('{topicId}', topicId); - let payload = {}; - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - if(showConsole) { - showConsoleLink('messaging', 'getTopic', topicId); - } else { - parse(response) - } - } - - return response; - -} -interface MessagingUpdateTopicRequestParams { - topicId: string; - name?: string; - subscribe?: string[]; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const messagingUpdateTopic = async ({topicId,name,subscribe,parseOutput = true, overrideForCli = false, sdk = undefined}: MessagingUpdateTopicRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/messaging/topics/{topicId}'.replace('{topicId}', topicId); - let payload = {}; - if (typeof name !== 'undefined') { - payload['name'] = name; - } - subscribe = subscribe === true ? [] : subscribe; - if (typeof subscribe !== 'undefined') { - payload['subscribe'] = subscribe; - } - - let response = undefined; - - response = await client.call('patch', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface MessagingDeleteTopicRequestParams { - topicId: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const messagingDeleteTopic = async ({topicId,parseOutput = true, overrideForCli = false, sdk = undefined}: MessagingDeleteTopicRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/messaging/topics/{topicId}'.replace('{topicId}', topicId); - let payload = {}; - - let response = undefined; - - response = await client.call('delete', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface MessagingListTopicLogsRequestParams { - topicId: string; - queries?: string[]; - total?: boolean; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const messagingListTopicLogs = async ({topicId,queries,total,parseOutput = true, overrideForCli = false, sdk = undefined}: MessagingListTopicLogsRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/messaging/topics/{topicId}/logs'.replace('{topicId}', topicId); - let payload = {}; - if (typeof queries !== 'undefined') { - payload['queries'] = queries; - } - if (typeof total !== 'undefined') { - payload['total'] = total; - } - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface MessagingListSubscribersRequestParams { - topicId: string; - queries?: string[]; - search?: string; - total?: boolean; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; - console?: boolean; -} - -export const messagingListSubscribers = async ({topicId,queries,search,total,parseOutput = true, overrideForCli = false, sdk = undefined, console: showConsole}: MessagingListSubscribersRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/messaging/topics/{topicId}/subscribers'.replace('{topicId}', topicId); - let payload = {}; - if (typeof queries !== 'undefined') { - payload['queries'] = queries; - } - if (typeof search !== 'undefined') { - payload['search'] = search; - } - if (typeof total !== 'undefined') { - payload['total'] = total; - } - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - if(showConsole) { - showConsoleLink('messaging', 'listSubscribers', topicId); - } else { - parse(response) - } - } - - return response; - -} -interface MessagingCreateSubscriberRequestParams { - topicId: string; - subscriberId: string; - targetId: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const messagingCreateSubscriber = async ({topicId,subscriberId,targetId,parseOutput = true, overrideForCli = false, sdk = undefined}: MessagingCreateSubscriberRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/messaging/topics/{topicId}/subscribers'.replace('{topicId}', topicId); - let payload = {}; - if (typeof subscriberId !== 'undefined') { - payload['subscriberId'] = subscriberId; - } - if (typeof targetId !== 'undefined') { - payload['targetId'] = targetId; - } - - let response = undefined; - - response = await client.call('post', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface MessagingGetSubscriberRequestParams { - topicId: string; - subscriberId: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const messagingGetSubscriber = async ({topicId,subscriberId,parseOutput = true, overrideForCli = false, sdk = undefined}: MessagingGetSubscriberRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/messaging/topics/{topicId}/subscribers/{subscriberId}'.replace('{topicId}', topicId).replace('{subscriberId}', subscriberId); - let payload = {}; - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface MessagingDeleteSubscriberRequestParams { - topicId: string; - subscriberId: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const messagingDeleteSubscriber = async ({topicId,subscriberId,parseOutput = true, overrideForCli = false, sdk = undefined}: MessagingDeleteSubscriberRequestParams): Promise => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/messaging/topics/{topicId}/subscribers/{subscriberId}'.replace('{topicId}', topicId).replace('{subscriberId}', subscriberId); - let payload = {}; - - let response = undefined; - - response = await client.call('delete', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -messaging - .command(`list-messages`) - .description(`Get a list of all messages from the current Appwrite project.`) - .option(`--queries [queries...]`, `Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: scheduledAt, deliveredAt, deliveredTotal, status, description, providerType`) - .option(`--search `, `Search term to filter your list results. Max length: 256 chars.`) - .option(`--total [value]`, `When set to false, the total count returned will be 0 and will not be calculated.`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .option(`--console`, `Get the resource console url`) - .action(actionRunner(messagingListMessages)) - -messaging - .command(`create-email`) - .description(`Create a new email message.`) - .requiredOption(`--message-id `, `Message ID. Choose a custom ID or generate a random ID with 'ID.unique()'. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.`) - .requiredOption(`--subject `, `Email Subject.`) - .requiredOption(`--content `, `Email Content.`) - .option(`--topics [topics...]`, `List of Topic IDs.`) - .option(`--users [users...]`, `List of User IDs.`) - .option(`--targets [targets...]`, `List of Targets IDs.`) - .option(`--cc [cc...]`, `Array of target IDs to be added as CC.`) - .option(`--bcc [bcc...]`, `Array of target IDs to be added as BCC.`) - .option(`--attachments [attachments...]`, `Array of compound ID strings of bucket IDs and file IDs to be attached to the email. They should be formatted as :.`) - .option(`--draft [value]`, `Is message a draft`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .option(`--html [value]`, `Is content of type HTML`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .option(`--scheduled-at `, `Scheduled delivery time for message in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format. DateTime value must be in future.`) - .action(actionRunner(messagingCreateEmail)) - -messaging - .command(`update-email`) - .description(`Update an email message by its unique ID. This endpoint only works on messages that are in draft status. Messages that are already processing, sent, or failed cannot be updated. `) - .requiredOption(`--message-id `, `Message ID.`) - .option(`--topics [topics...]`, `List of Topic IDs.`) - .option(`--users [users...]`, `List of User IDs.`) - .option(`--targets [targets...]`, `List of Targets IDs.`) - .option(`--subject `, `Email Subject.`) - .option(`--content `, `Email Content.`) - .option(`--draft [value]`, `Is message a draft`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .option(`--html [value]`, `Is content of type HTML`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .option(`--cc [cc...]`, `Array of target IDs to be added as CC.`) - .option(`--bcc [bcc...]`, `Array of target IDs to be added as BCC.`) - .option(`--scheduled-at `, `Scheduled delivery time for message in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format. DateTime value must be in future.`) - .option(`--attachments [attachments...]`, `Array of compound ID strings of bucket IDs and file IDs to be attached to the email. They should be formatted as :.`) - .action(actionRunner(messagingUpdateEmail)) - -messaging - .command(`create-push`) - .description(`Create a new push notification.`) - .requiredOption(`--message-id `, `Message ID. Choose a custom ID or generate a random ID with 'ID.unique()'. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.`) - .option(`--title `, `Title for push notification.`) - .option(`--body <body>`, `Body for push notification.`) - .option(`--topics [topics...]`, `List of Topic IDs.`) - .option(`--users [users...]`, `List of User IDs.`) - .option(`--targets [targets...]`, `List of Targets IDs.`) - .option(`--data <data>`, `Additional key-value pair data for push notification.`) - .option(`--action <action>`, `Action for push notification.`) - .option(`--image <image>`, `Image for push notification. Must be a compound bucket ID to file ID of a jpeg, png, or bmp image in Appwrite Storage. It should be formatted as <BUCKET_ID>:<FILE_ID>.`) - .option(`--icon <icon>`, `Icon for push notification. Available only for Android and Web Platform.`) - .option(`--sound <sound>`, `Sound for push notification. Available only for Android and iOS Platform.`) - .option(`--color <color>`, `Color for push notification. Available only for Android Platform.`) - .option(`--tag <tag>`, `Tag for push notification. Available only for Android Platform.`) - .option(`--badge <badge>`, `Badge for push notification. Available only for iOS Platform.`, parseInteger) - .option(`--draft [value]`, `Is message a draft`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .option(`--scheduled-at <scheduled-at>`, `Scheduled delivery time for message in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format. DateTime value must be in future.`) - .option(`--content-available [value]`, `If set to true, the notification will be delivered in the background. Available only for iOS Platform.`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .option(`--critical [value]`, `If set to true, the notification will be marked as critical. This requires the app to have the critical notification entitlement. Available only for iOS Platform.`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .option(`--priority <priority>`, `Set the notification priority. "normal" will consider device state and may not deliver notifications immediately. "high" will always attempt to immediately deliver the notification.`) - .action(actionRunner(messagingCreatePush)) - -messaging - .command(`update-push`) - .description(`Update a push notification by its unique ID. This endpoint only works on messages that are in draft status. Messages that are already processing, sent, or failed cannot be updated. `) - .requiredOption(`--message-id <message-id>`, `Message ID.`) - .option(`--topics [topics...]`, `List of Topic IDs.`) - .option(`--users [users...]`, `List of User IDs.`) - .option(`--targets [targets...]`, `List of Targets IDs.`) - .option(`--title <title>`, `Title for push notification.`) - .option(`--body <body>`, `Body for push notification.`) - .option(`--data <data>`, `Additional Data for push notification.`) - .option(`--action <action>`, `Action for push notification.`) - .option(`--image <image>`, `Image for push notification. Must be a compound bucket ID to file ID of a jpeg, png, or bmp image in Appwrite Storage. It should be formatted as <BUCKET_ID>:<FILE_ID>.`) - .option(`--icon <icon>`, `Icon for push notification. Available only for Android and Web platforms.`) - .option(`--sound <sound>`, `Sound for push notification. Available only for Android and iOS platforms.`) - .option(`--color <color>`, `Color for push notification. Available only for Android platforms.`) - .option(`--tag <tag>`, `Tag for push notification. Available only for Android platforms.`) - .option(`--badge <badge>`, `Badge for push notification. Available only for iOS platforms.`, parseInteger) - .option(`--draft [value]`, `Is message a draft`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .option(`--scheduled-at <scheduled-at>`, `Scheduled delivery time for message in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format. DateTime value must be in future.`) - .option(`--content-available [value]`, `If set to true, the notification will be delivered in the background. Available only for iOS Platform.`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .option(`--critical [value]`, `If set to true, the notification will be marked as critical. This requires the app to have the critical notification entitlement. Available only for iOS Platform.`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .option(`--priority <priority>`, `Set the notification priority. "normal" will consider device battery state and may send notifications later. "high" will always attempt to immediately deliver the notification.`) - .action(actionRunner(messagingUpdatePush)) - -messaging - .command(`create-sms`) - .description(`Create a new SMS message.`) - .requiredOption(`--message-id <message-id>`, `Message ID. Choose a custom ID or generate a random ID with 'ID.unique()'. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.`) - .requiredOption(`--content <content>`, `SMS Content.`) - .option(`--topics [topics...]`, `List of Topic IDs.`) - .option(`--users [users...]`, `List of User IDs.`) - .option(`--targets [targets...]`, `List of Targets IDs.`) - .option(`--draft [value]`, `Is message a draft`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .option(`--scheduled-at <scheduled-at>`, `Scheduled delivery time for message in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format. DateTime value must be in future.`) - .action(actionRunner(messagingCreateSMS)) - -messaging - .command(`update-sms`) - .description(`Update an SMS message by its unique ID. This endpoint only works on messages that are in draft status. Messages that are already processing, sent, or failed cannot be updated. `) - .requiredOption(`--message-id <message-id>`, `Message ID.`) - .option(`--topics [topics...]`, `List of Topic IDs.`) - .option(`--users [users...]`, `List of User IDs.`) - .option(`--targets [targets...]`, `List of Targets IDs.`) - .option(`--content <content>`, `Email Content.`) - .option(`--draft [value]`, `Is message a draft`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .option(`--scheduled-at <scheduled-at>`, `Scheduled delivery time for message in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format. DateTime value must be in future.`) - .action(actionRunner(messagingUpdateSMS)) - -messaging - .command(`get-message`) - .description(`Get a message by its unique ID. `) - .requiredOption(`--message-id <message-id>`, `Message ID.`) - .option(`--console`, `Get the resource console url`) - .action(actionRunner(messagingGetMessage)) - -messaging - .command(`delete`) - .description(`Delete a message. If the message is not a draft or scheduled, but has been sent, this will not recall the message.`) - .requiredOption(`--message-id <message-id>`, `Message ID.`) - .action(actionRunner(messagingDelete)) - -messaging - .command(`list-message-logs`) - .description(`Get the message activity logs listed by its unique ID.`) - .requiredOption(`--message-id <message-id>`, `Message ID.`) - .option(`--queries [queries...]`, `Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Only supported methods are limit and offset`) - .option(`--total [value]`, `When set to false, the total count returned will be 0 and will not be calculated.`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .option(`--console`, `Get the resource console url`) - .action(actionRunner(messagingListMessageLogs)) - -messaging - .command(`list-targets`) - .description(`Get a list of the targets associated with a message.`) - .requiredOption(`--message-id <message-id>`, `Message ID.`) - .option(`--queries [queries...]`, `Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: userId, providerId, identifier, providerType`) - .option(`--total [value]`, `When set to false, the total count returned will be 0 and will not be calculated.`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .action(actionRunner(messagingListTargets)) - -messaging - .command(`list-providers`) - .description(`Get a list of all providers from the current Appwrite project.`) - .option(`--queries [queries...]`, `Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: name, provider, type, enabled`) - .option(`--search <search>`, `Search term to filter your list results. Max length: 256 chars.`) - .option(`--total [value]`, `When set to false, the total count returned will be 0 and will not be calculated.`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .option(`--console`, `Get the resource console url`) - .action(actionRunner(messagingListProviders)) - -messaging - .command(`create-apns-provider`) - .description(`Create a new Apple Push Notification service provider.`) - .requiredOption(`--provider-id <provider-id>`, `Provider ID. Choose a custom ID or generate a random ID with 'ID.unique()'. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.`) - .requiredOption(`--name <name>`, `Provider name.`) - .option(`--auth-key <auth-key>`, `APNS authentication key.`) - .option(`--auth-key-id <auth-key-id>`, `APNS authentication key ID.`) - .option(`--team-id <team-id>`, `APNS team ID.`) - .option(`--bundle-id <bundle-id>`, `APNS bundle ID.`) - .option(`--sandbox [value]`, `Use APNS sandbox environment.`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .option(`--enabled [value]`, `Set as enabled.`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .action(actionRunner(messagingCreateAPNSProvider)) - -messaging - .command(`update-apns-provider`) - .description(`Update a Apple Push Notification service provider by its unique ID.`) - .requiredOption(`--provider-id <provider-id>`, `Provider ID.`) - .option(`--name <name>`, `Provider name.`) - .option(`--enabled [value]`, `Set as enabled.`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .option(`--auth-key <auth-key>`, `APNS authentication key.`) - .option(`--auth-key-id <auth-key-id>`, `APNS authentication key ID.`) - .option(`--team-id <team-id>`, `APNS team ID.`) - .option(`--bundle-id <bundle-id>`, `APNS bundle ID.`) - .option(`--sandbox [value]`, `Use APNS sandbox environment.`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .action(actionRunner(messagingUpdateAPNSProvider)) - -messaging - .command(`create-fcm-provider`) - .description(`Create a new Firebase Cloud Messaging provider.`) - .requiredOption(`--provider-id <provider-id>`, `Provider ID. Choose a custom ID or generate a random ID with 'ID.unique()'. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.`) - .requiredOption(`--name <name>`, `Provider name.`) - .option(`--service-account-json <service-account-json>`, `FCM service account JSON.`) - .option(`--enabled [value]`, `Set as enabled.`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .action(actionRunner(messagingCreateFCMProvider)) - -messaging - .command(`update-fcm-provider`) - .description(`Update a Firebase Cloud Messaging provider by its unique ID.`) - .requiredOption(`--provider-id <provider-id>`, `Provider ID.`) - .option(`--name <name>`, `Provider name.`) - .option(`--enabled [value]`, `Set as enabled.`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .option(`--service-account-json <service-account-json>`, `FCM service account JSON.`) - .action(actionRunner(messagingUpdateFCMProvider)) - -messaging - .command(`create-mailgun-provider`) - .description(`Create a new Mailgun provider.`) - .requiredOption(`--provider-id <provider-id>`, `Provider ID. Choose a custom ID or generate a random ID with 'ID.unique()'. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.`) - .requiredOption(`--name <name>`, `Provider name.`) - .option(`--api-key <api-key>`, `Mailgun API Key.`) - .option(`--domain <domain>`, `Mailgun Domain.`) - .option(`--is-eu-region [value]`, `Set as EU region.`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .option(`--from-name <from-name>`, `Sender Name.`) - .option(`--from-email <from-email>`, `Sender email address.`) - .option(`--reply-to-name <reply-to-name>`, `Name set in the reply to field for the mail. Default value is sender name. Reply to name must have reply to email as well.`) - .option(`--reply-to-email <reply-to-email>`, `Email set in the reply to field for the mail. Default value is sender email. Reply to email must have reply to name as well.`) - .option(`--enabled [value]`, `Set as enabled.`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .action(actionRunner(messagingCreateMailgunProvider)) - -messaging - .command(`update-mailgun-provider`) - .description(`Update a Mailgun provider by its unique ID.`) - .requiredOption(`--provider-id <provider-id>`, `Provider ID.`) - .option(`--name <name>`, `Provider name.`) - .option(`--api-key <api-key>`, `Mailgun API Key.`) - .option(`--domain <domain>`, `Mailgun Domain.`) - .option(`--is-eu-region [value]`, `Set as EU region.`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .option(`--enabled [value]`, `Set as enabled.`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .option(`--from-name <from-name>`, `Sender Name.`) - .option(`--from-email <from-email>`, `Sender email address.`) - .option(`--reply-to-name <reply-to-name>`, `Name set in the reply to field for the mail. Default value is sender name.`) - .option(`--reply-to-email <reply-to-email>`, `Email set in the reply to field for the mail. Default value is sender email.`) - .action(actionRunner(messagingUpdateMailgunProvider)) - -messaging - .command(`create-msg-91-provider`) - .description(`Create a new MSG91 provider.`) - .requiredOption(`--provider-id <provider-id>`, `Provider ID. Choose a custom ID or generate a random ID with 'ID.unique()'. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.`) - .requiredOption(`--name <name>`, `Provider name.`) - .option(`--template-id <template-id>`, `Msg91 template ID`) - .option(`--sender-id <sender-id>`, `Msg91 sender ID.`) - .option(`--auth-key <auth-key>`, `Msg91 auth key.`) - .option(`--enabled [value]`, `Set as enabled.`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .action(actionRunner(messagingCreateMsg91Provider)) - -messaging - .command(`update-msg-91-provider`) - .description(`Update a MSG91 provider by its unique ID.`) - .requiredOption(`--provider-id <provider-id>`, `Provider ID.`) - .option(`--name <name>`, `Provider name.`) - .option(`--enabled [value]`, `Set as enabled.`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .option(`--template-id <template-id>`, `Msg91 template ID.`) - .option(`--sender-id <sender-id>`, `Msg91 sender ID.`) - .option(`--auth-key <auth-key>`, `Msg91 auth key.`) - .action(actionRunner(messagingUpdateMsg91Provider)) - -messaging - .command(`create-resend-provider`) - .description(`Create a new Resend provider.`) - .requiredOption(`--provider-id <provider-id>`, `Provider ID. Choose a custom ID or generate a random ID with 'ID.unique()'. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.`) - .requiredOption(`--name <name>`, `Provider name.`) - .option(`--api-key <api-key>`, `Resend API key.`) - .option(`--from-name <from-name>`, `Sender Name.`) - .option(`--from-email <from-email>`, `Sender email address.`) - .option(`--reply-to-name <reply-to-name>`, `Name set in the reply to field for the mail. Default value is sender name.`) - .option(`--reply-to-email <reply-to-email>`, `Email set in the reply to field for the mail. Default value is sender email.`) - .option(`--enabled [value]`, `Set as enabled.`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .action(actionRunner(messagingCreateResendProvider)) - -messaging - .command(`update-resend-provider`) - .description(`Update a Resend provider by its unique ID.`) - .requiredOption(`--provider-id <provider-id>`, `Provider ID.`) - .option(`--name <name>`, `Provider name.`) - .option(`--enabled [value]`, `Set as enabled.`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .option(`--api-key <api-key>`, `Resend API key.`) - .option(`--from-name <from-name>`, `Sender Name.`) - .option(`--from-email <from-email>`, `Sender email address.`) - .option(`--reply-to-name <reply-to-name>`, `Name set in the Reply To field for the mail. Default value is Sender Name.`) - .option(`--reply-to-email <reply-to-email>`, `Email set in the Reply To field for the mail. Default value is Sender Email.`) - .action(actionRunner(messagingUpdateResendProvider)) - -messaging - .command(`create-sendgrid-provider`) - .description(`Create a new Sendgrid provider.`) - .requiredOption(`--provider-id <provider-id>`, `Provider ID. Choose a custom ID or generate a random ID with 'ID.unique()'. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.`) - .requiredOption(`--name <name>`, `Provider name.`) - .option(`--api-key <api-key>`, `Sendgrid API key.`) - .option(`--from-name <from-name>`, `Sender Name.`) - .option(`--from-email <from-email>`, `Sender email address.`) - .option(`--reply-to-name <reply-to-name>`, `Name set in the reply to field for the mail. Default value is sender name.`) - .option(`--reply-to-email <reply-to-email>`, `Email set in the reply to field for the mail. Default value is sender email.`) - .option(`--enabled [value]`, `Set as enabled.`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .action(actionRunner(messagingCreateSendgridProvider)) - -messaging - .command(`update-sendgrid-provider`) - .description(`Update a Sendgrid provider by its unique ID.`) - .requiredOption(`--provider-id <provider-id>`, `Provider ID.`) - .option(`--name <name>`, `Provider name.`) - .option(`--enabled [value]`, `Set as enabled.`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .option(`--api-key <api-key>`, `Sendgrid API key.`) - .option(`--from-name <from-name>`, `Sender Name.`) - .option(`--from-email <from-email>`, `Sender email address.`) - .option(`--reply-to-name <reply-to-name>`, `Name set in the Reply To field for the mail. Default value is Sender Name.`) - .option(`--reply-to-email <reply-to-email>`, `Email set in the Reply To field for the mail. Default value is Sender Email.`) - .action(actionRunner(messagingUpdateSendgridProvider)) - -messaging - .command(`create-smtp-provider`) - .description(`Create a new SMTP provider.`) - .requiredOption(`--provider-id <provider-id>`, `Provider ID. Choose a custom ID or generate a random ID with 'ID.unique()'. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.`) - .requiredOption(`--name <name>`, `Provider name.`) - .requiredOption(`--host <host>`, `SMTP hosts. Either a single hostname or multiple semicolon-delimited hostnames. You can also specify a different port for each host such as 'smtp1.example.com:25;smtp2.example.com'. You can also specify encryption type, for example: 'tls://smtp1.example.com:587;ssl://smtp2.example.com:465"'. Hosts will be tried in order.`) - .option(`--port <port>`, `The default SMTP server port.`, parseInteger) - .option(`--username <username>`, `Authentication username.`) - .option(`--password <password>`, `Authentication password.`) - .option(`--encryption <encryption>`, `Encryption type. Can be omitted, 'ssl', or 'tls'`) - .option(`--auto-tls [value]`, `Enable SMTP AutoTLS feature.`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .option(`--mailer <mailer>`, `The value to use for the X-Mailer header.`) - .option(`--from-name <from-name>`, `Sender Name.`) - .option(`--from-email <from-email>`, `Sender email address.`) - .option(`--reply-to-name <reply-to-name>`, `Name set in the reply to field for the mail. Default value is sender name.`) - .option(`--reply-to-email <reply-to-email>`, `Email set in the reply to field for the mail. Default value is sender email.`) - .option(`--enabled [value]`, `Set as enabled.`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .action(actionRunner(messagingCreateSMTPProvider)) - -messaging - .command(`update-smtp-provider`) - .description(`Update a SMTP provider by its unique ID.`) - .requiredOption(`--provider-id <provider-id>`, `Provider ID.`) - .option(`--name <name>`, `Provider name.`) - .option(`--host <host>`, `SMTP hosts. Either a single hostname or multiple semicolon-delimited hostnames. You can also specify a different port for each host such as 'smtp1.example.com:25;smtp2.example.com'. You can also specify encryption type, for example: 'tls://smtp1.example.com:587;ssl://smtp2.example.com:465"'. Hosts will be tried in order.`) - .option(`--port <port>`, `SMTP port.`, parseInteger) - .option(`--username <username>`, `Authentication username.`) - .option(`--password <password>`, `Authentication password.`) - .option(`--encryption <encryption>`, `Encryption type. Can be 'ssl' or 'tls'`) - .option(`--auto-tls [value]`, `Enable SMTP AutoTLS feature.`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .option(`--mailer <mailer>`, `The value to use for the X-Mailer header.`) - .option(`--from-name <from-name>`, `Sender Name.`) - .option(`--from-email <from-email>`, `Sender email address.`) - .option(`--reply-to-name <reply-to-name>`, `Name set in the Reply To field for the mail. Default value is Sender Name.`) - .option(`--reply-to-email <reply-to-email>`, `Email set in the Reply To field for the mail. Default value is Sender Email.`) - .option(`--enabled [value]`, `Set as enabled.`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .action(actionRunner(messagingUpdateSMTPProvider)) - -messaging - .command(`create-telesign-provider`) - .description(`Create a new Telesign provider.`) - .requiredOption(`--provider-id <provider-id>`, `Provider ID. Choose a custom ID or generate a random ID with 'ID.unique()'. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.`) - .requiredOption(`--name <name>`, `Provider name.`) - .option(`--from <from>`, `Sender Phone number. Format this number with a leading '+' and a country code, e.g., +16175551212.`) - .option(`--customer-id <customer-id>`, `Telesign customer ID.`) - .option(`--api-key <api-key>`, `Telesign API key.`) - .option(`--enabled [value]`, `Set as enabled.`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .action(actionRunner(messagingCreateTelesignProvider)) - -messaging - .command(`update-telesign-provider`) - .description(`Update a Telesign provider by its unique ID.`) - .requiredOption(`--provider-id <provider-id>`, `Provider ID.`) - .option(`--name <name>`, `Provider name.`) - .option(`--enabled [value]`, `Set as enabled.`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .option(`--customer-id <customer-id>`, `Telesign customer ID.`) - .option(`--api-key <api-key>`, `Telesign API key.`) - .option(`--from <from>`, `Sender number.`) - .action(actionRunner(messagingUpdateTelesignProvider)) - -messaging - .command(`create-textmagic-provider`) - .description(`Create a new Textmagic provider.`) - .requiredOption(`--provider-id <provider-id>`, `Provider ID. Choose a custom ID or generate a random ID with 'ID.unique()'. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.`) - .requiredOption(`--name <name>`, `Provider name.`) - .option(`--from <from>`, `Sender Phone number. Format this number with a leading '+' and a country code, e.g., +16175551212.`) - .option(`--username <username>`, `Textmagic username.`) - .option(`--api-key <api-key>`, `Textmagic apiKey.`) - .option(`--enabled [value]`, `Set as enabled.`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .action(actionRunner(messagingCreateTextmagicProvider)) - -messaging - .command(`update-textmagic-provider`) - .description(`Update a Textmagic provider by its unique ID.`) - .requiredOption(`--provider-id <provider-id>`, `Provider ID.`) - .option(`--name <name>`, `Provider name.`) - .option(`--enabled [value]`, `Set as enabled.`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .option(`--username <username>`, `Textmagic username.`) - .option(`--api-key <api-key>`, `Textmagic apiKey.`) - .option(`--from <from>`, `Sender number.`) - .action(actionRunner(messagingUpdateTextmagicProvider)) - -messaging - .command(`create-twilio-provider`) - .description(`Create a new Twilio provider.`) - .requiredOption(`--provider-id <provider-id>`, `Provider ID. Choose a custom ID or generate a random ID with 'ID.unique()'. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.`) - .requiredOption(`--name <name>`, `Provider name.`) - .option(`--from <from>`, `Sender Phone number. Format this number with a leading '+' and a country code, e.g., +16175551212.`) - .option(`--account-sid <account-sid>`, `Twilio account secret ID.`) - .option(`--auth-token <auth-token>`, `Twilio authentication token.`) - .option(`--enabled [value]`, `Set as enabled.`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .action(actionRunner(messagingCreateTwilioProvider)) - -messaging - .command(`update-twilio-provider`) - .description(`Update a Twilio provider by its unique ID.`) - .requiredOption(`--provider-id <provider-id>`, `Provider ID.`) - .option(`--name <name>`, `Provider name.`) - .option(`--enabled [value]`, `Set as enabled.`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .option(`--account-sid <account-sid>`, `Twilio account secret ID.`) - .option(`--auth-token <auth-token>`, `Twilio authentication token.`) - .option(`--from <from>`, `Sender number.`) - .action(actionRunner(messagingUpdateTwilioProvider)) - -messaging - .command(`create-vonage-provider`) - .description(`Create a new Vonage provider.`) - .requiredOption(`--provider-id <provider-id>`, `Provider ID. Choose a custom ID or generate a random ID with 'ID.unique()'. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.`) - .requiredOption(`--name <name>`, `Provider name.`) - .option(`--from <from>`, `Sender Phone number. Format this number with a leading '+' and a country code, e.g., +16175551212.`) - .option(`--api-key <api-key>`, `Vonage API key.`) - .option(`--api-secret <api-secret>`, `Vonage API secret.`) - .option(`--enabled [value]`, `Set as enabled.`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .action(actionRunner(messagingCreateVonageProvider)) - -messaging - .command(`update-vonage-provider`) - .description(`Update a Vonage provider by its unique ID.`) - .requiredOption(`--provider-id <provider-id>`, `Provider ID.`) - .option(`--name <name>`, `Provider name.`) - .option(`--enabled [value]`, `Set as enabled.`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .option(`--api-key <api-key>`, `Vonage API key.`) - .option(`--api-secret <api-secret>`, `Vonage API secret.`) - .option(`--from <from>`, `Sender number.`) - .action(actionRunner(messagingUpdateVonageProvider)) - -messaging - .command(`get-provider`) - .description(`Get a provider by its unique ID. `) - .requiredOption(`--provider-id <provider-id>`, `Provider ID.`) - .option(`--console`, `Get the resource console url`) - .action(actionRunner(messagingGetProvider)) - -messaging - .command(`delete-provider`) - .description(`Delete a provider by its unique ID.`) - .requiredOption(`--provider-id <provider-id>`, `Provider ID.`) - .action(actionRunner(messagingDeleteProvider)) - -messaging - .command(`list-provider-logs`) - .description(`Get the provider activity logs listed by its unique ID.`) - .requiredOption(`--provider-id <provider-id>`, `Provider ID.`) - .option(`--queries [queries...]`, `Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Only supported methods are limit and offset`) - .option(`--total [value]`, `When set to false, the total count returned will be 0 and will not be calculated.`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .action(actionRunner(messagingListProviderLogs)) - -messaging - .command(`list-subscriber-logs`) - .description(`Get the subscriber activity logs listed by its unique ID.`) - .requiredOption(`--subscriber-id <subscriber-id>`, `Subscriber ID.`) - .option(`--queries [queries...]`, `Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Only supported methods are limit and offset`) - .option(`--total [value]`, `When set to false, the total count returned will be 0 and will not be calculated.`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .action(actionRunner(messagingListSubscriberLogs)) - -messaging - .command(`list-topics`) - .description(`Get a list of all topics from the current Appwrite project.`) - .option(`--queries [queries...]`, `Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: name, description, emailTotal, smsTotal, pushTotal`) - .option(`--search <search>`, `Search term to filter your list results. Max length: 256 chars.`) - .option(`--total [value]`, `When set to false, the total count returned will be 0 and will not be calculated.`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .option(`--console`, `Get the resource console url`) - .action(actionRunner(messagingListTopics)) - -messaging - .command(`create-topic`) - .description(`Create a new topic.`) - .requiredOption(`--topic-id <topic-id>`, `Topic ID. Choose a custom Topic ID or a new Topic ID.`) - .requiredOption(`--name <name>`, `Topic Name.`) - .option(`--subscribe [subscribe...]`, `An array of role strings with subscribe permission. By default all users are granted with any subscribe permission. [learn more about roles](https://appwrite.io/docs/permissions#permission-roles). Maximum of 100 roles are allowed, each 64 characters long.`) - .action(actionRunner(messagingCreateTopic)) - -messaging - .command(`get-topic`) - .description(`Get a topic by its unique ID. `) - .requiredOption(`--topic-id <topic-id>`, `Topic ID.`) - .option(`--console`, `Get the resource console url`) - .action(actionRunner(messagingGetTopic)) - -messaging - .command(`update-topic`) - .description(`Update a topic by its unique ID. `) - .requiredOption(`--topic-id <topic-id>`, `Topic ID.`) - .option(`--name <name>`, `Topic Name.`) - .option(`--subscribe [subscribe...]`, `An array of role strings with subscribe permission. By default all users are granted with any subscribe permission. [learn more about roles](https://appwrite.io/docs/permissions#permission-roles). Maximum of 100 roles are allowed, each 64 characters long.`) - .action(actionRunner(messagingUpdateTopic)) - -messaging - .command(`delete-topic`) - .description(`Delete a topic by its unique ID.`) - .requiredOption(`--topic-id <topic-id>`, `Topic ID.`) - .action(actionRunner(messagingDeleteTopic)) - -messaging - .command(`list-topic-logs`) - .description(`Get the topic activity logs listed by its unique ID.`) - .requiredOption(`--topic-id <topic-id>`, `Topic ID.`) - .option(`--queries [queries...]`, `Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Only supported methods are limit and offset`) - .option(`--total [value]`, `When set to false, the total count returned will be 0 and will not be calculated.`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .action(actionRunner(messagingListTopicLogs)) - -messaging - .command(`list-subscribers`) - .description(`Get a list of all subscribers from the current Appwrite project.`) - .requiredOption(`--topic-id <topic-id>`, `Topic ID. The topic ID subscribed to.`) - .option(`--queries [queries...]`, `Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: name, provider, type, enabled`) - .option(`--search <search>`, `Search term to filter your list results. Max length: 256 chars.`) - .option(`--total [value]`, `When set to false, the total count returned will be 0 and will not be calculated.`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .option(`--console`, `Get the resource console url`) - .action(actionRunner(messagingListSubscribers)) - -messaging - .command(`create-subscriber`) - .description(`Create a new subscriber.`) - .requiredOption(`--topic-id <topic-id>`, `Topic ID. The topic ID to subscribe to.`) - .requiredOption(`--subscriber-id <subscriber-id>`, `Subscriber ID. Choose a custom Subscriber ID or a new Subscriber ID.`) - .requiredOption(`--target-id <target-id>`, `Target ID. The target ID to link to the specified Topic ID.`) - .action(actionRunner(messagingCreateSubscriber)) - -messaging - .command(`get-subscriber`) - .description(`Get a subscriber by its unique ID. `) - .requiredOption(`--topic-id <topic-id>`, `Topic ID. The topic ID subscribed to.`) - .requiredOption(`--subscriber-id <subscriber-id>`, `Subscriber ID.`) - .action(actionRunner(messagingGetSubscriber)) - -messaging - .command(`delete-subscriber`) - .description(`Delete a subscriber by its unique ID.`) - .requiredOption(`--topic-id <topic-id>`, `Topic ID. The topic ID subscribed to.`) - .requiredOption(`--subscriber-id <subscriber-id>`, `Subscriber ID.`) - .action(actionRunner(messagingDeleteSubscriber)) - - diff --git a/lib/commands/migrations.ts b/lib/commands/migrations.ts deleted file mode 100644 index b2c6a740..00000000 --- a/lib/commands/migrations.ts +++ /dev/null @@ -1,754 +0,0 @@ -import fs = require('fs'); -import pathLib = require('path'); -import tar = require('tar'); -import ignore = require('ignore'); -import { promisify } from 'util'; -import Client from '../client'; -import { getAllFiles, showConsoleLink } from '../utils'; -import { Command } from 'commander'; -import { sdkForProject, sdkForConsole } from '../sdks'; -import { parse, actionRunner, parseInteger, parseBool, commandDescriptions, success, log, warn } from '../parser'; -import { localConfig, globalConfig } from '../config'; -import { File } from 'undici'; -import { ReadableStream } from 'stream/web'; - -function convertReadStreamToReadableStream(readStream: fs.ReadStream): ReadableStream { - return new ReadableStream({ - start(controller) { - readStream.on("data", (chunk: Buffer) => { - controller.enqueue(chunk); - }); - readStream.on("end", () => { - controller.close(); - }); - readStream.on("error", (err: Error) => { - controller.error(err); - }); - }, - cancel() { - readStream.destroy(); - }, - }); -} - -export const migrations = new Command("migrations").description(commandDescriptions['migrations'] ?? '').configureHelp({ - helpWidth: process.stdout.columns || 80 -}) - -interface MigrationsListRequestParams { - queries?: string[]; - search?: string; - total?: boolean; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const migrationsList = async ({queries,search,total,parseOutput = true, overrideForCli = false, sdk = undefined}: MigrationsListRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/migrations'; - let payload = {}; - if (typeof queries !== 'undefined') { - payload['queries'] = queries; - } - if (typeof search !== 'undefined') { - payload['search'] = search; - } - if (typeof total !== 'undefined') { - payload['total'] = total; - } - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface MigrationsCreateAppwriteMigrationRequestParams { - resources: string[]; - endpoint: string; - projectId: string; - apiKey: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const migrationsCreateAppwriteMigration = async ({resources,endpoint,projectId,apiKey,parseOutput = true, overrideForCli = false, sdk = undefined}: MigrationsCreateAppwriteMigrationRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/migrations/appwrite'; - let payload = {}; - resources = resources === true ? [] : resources; - if (typeof resources !== 'undefined') { - payload['resources'] = resources; - } - if (typeof endpoint !== 'undefined') { - payload['endpoint'] = endpoint; - } - if (typeof projectId !== 'undefined') { - payload['projectId'] = projectId; - } - if (typeof apiKey !== 'undefined') { - payload['apiKey'] = apiKey; - } - - let response = undefined; - - response = await client.call('post', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface MigrationsGetAppwriteReportRequestParams { - resources: string[]; - endpoint: string; - projectID: string; - key: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const migrationsGetAppwriteReport = async ({resources,endpoint,projectID,key,parseOutput = true, overrideForCli = false, sdk = undefined}: MigrationsGetAppwriteReportRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/migrations/appwrite/report'; - let payload = {}; - if (typeof resources !== 'undefined') { - payload['resources'] = resources; - } - if (typeof endpoint !== 'undefined') { - payload['endpoint'] = endpoint; - } - if (typeof projectID !== 'undefined') { - payload['projectID'] = projectID; - } - if (typeof key !== 'undefined') { - payload['key'] = key; - } - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface MigrationsCreateCSVExportRequestParams { - resourceId: string; - filename: string; - columns?: string[]; - queries?: string[]; - delimiter?: string; - enclosure?: string; - escape?: string; - header?: boolean; - notify?: boolean; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const migrationsCreateCSVExport = async ({resourceId,filename,columns,queries,delimiter,enclosure,escape,header,notify,parseOutput = true, overrideForCli = false, sdk = undefined}: MigrationsCreateCSVExportRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/migrations/csv/exports'; - let payload = {}; - if (typeof resourceId !== 'undefined') { - payload['resourceId'] = resourceId; - } - if (typeof filename !== 'undefined') { - payload['filename'] = filename; - } - columns = columns === true ? [] : columns; - if (typeof columns !== 'undefined') { - payload['columns'] = columns; - } - queries = queries === true ? [] : queries; - if (typeof queries !== 'undefined') { - payload['queries'] = queries; - } - if (typeof delimiter !== 'undefined') { - payload['delimiter'] = delimiter; - } - if (typeof enclosure !== 'undefined') { - payload['enclosure'] = enclosure; - } - if (typeof escape !== 'undefined') { - payload['escape'] = escape; - } - if (typeof header !== 'undefined') { - payload['header'] = header; - } - if (typeof notify !== 'undefined') { - payload['notify'] = notify; - } - - let response = undefined; - - response = await client.call('post', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface MigrationsCreateCSVImportRequestParams { - bucketId: string; - fileId: string; - resourceId: string; - internalFile?: boolean; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const migrationsCreateCSVImport = async ({bucketId,fileId,resourceId,internalFile,parseOutput = true, overrideForCli = false, sdk = undefined}: MigrationsCreateCSVImportRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/migrations/csv/imports'; - let payload = {}; - if (typeof bucketId !== 'undefined') { - payload['bucketId'] = bucketId; - } - if (typeof fileId !== 'undefined') { - payload['fileId'] = fileId; - } - if (typeof resourceId !== 'undefined') { - payload['resourceId'] = resourceId; - } - if (typeof internalFile !== 'undefined') { - payload['internalFile'] = internalFile; - } - - let response = undefined; - - response = await client.call('post', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface MigrationsCreateFirebaseMigrationRequestParams { - resources: string[]; - serviceAccount: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const migrationsCreateFirebaseMigration = async ({resources,serviceAccount,parseOutput = true, overrideForCli = false, sdk = undefined}: MigrationsCreateFirebaseMigrationRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/migrations/firebase'; - let payload = {}; - resources = resources === true ? [] : resources; - if (typeof resources !== 'undefined') { - payload['resources'] = resources; - } - if (typeof serviceAccount !== 'undefined') { - payload['serviceAccount'] = serviceAccount; - } - - let response = undefined; - - response = await client.call('post', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface MigrationsGetFirebaseReportRequestParams { - resources: string[]; - serviceAccount: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const migrationsGetFirebaseReport = async ({resources,serviceAccount,parseOutput = true, overrideForCli = false, sdk = undefined}: MigrationsGetFirebaseReportRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/migrations/firebase/report'; - let payload = {}; - if (typeof resources !== 'undefined') { - payload['resources'] = resources; - } - if (typeof serviceAccount !== 'undefined') { - payload['serviceAccount'] = serviceAccount; - } - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface MigrationsCreateNHostMigrationRequestParams { - resources: string[]; - subdomain: string; - region: string; - adminSecret: string; - database: string; - username: string; - password: string; - port?: number; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const migrationsCreateNHostMigration = async ({resources,subdomain,region,adminSecret,database,username,password,port,parseOutput = true, overrideForCli = false, sdk = undefined}: MigrationsCreateNHostMigrationRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/migrations/nhost'; - let payload = {}; - resources = resources === true ? [] : resources; - if (typeof resources !== 'undefined') { - payload['resources'] = resources; - } - if (typeof subdomain !== 'undefined') { - payload['subdomain'] = subdomain; - } - if (typeof region !== 'undefined') { - payload['region'] = region; - } - if (typeof adminSecret !== 'undefined') { - payload['adminSecret'] = adminSecret; - } - if (typeof database !== 'undefined') { - payload['database'] = database; - } - if (typeof username !== 'undefined') { - payload['username'] = username; - } - if (typeof password !== 'undefined') { - payload['password'] = password; - } - if (typeof port !== 'undefined') { - payload['port'] = port; - } - - let response = undefined; - - response = await client.call('post', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface MigrationsGetNHostReportRequestParams { - resources: string[]; - subdomain: string; - region: string; - adminSecret: string; - database: string; - username: string; - password: string; - port?: number; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const migrationsGetNHostReport = async ({resources,subdomain,region,adminSecret,database,username,password,port,parseOutput = true, overrideForCli = false, sdk = undefined}: MigrationsGetNHostReportRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/migrations/nhost/report'; - let payload = {}; - if (typeof resources !== 'undefined') { - payload['resources'] = resources; - } - if (typeof subdomain !== 'undefined') { - payload['subdomain'] = subdomain; - } - if (typeof region !== 'undefined') { - payload['region'] = region; - } - if (typeof adminSecret !== 'undefined') { - payload['adminSecret'] = adminSecret; - } - if (typeof database !== 'undefined') { - payload['database'] = database; - } - if (typeof username !== 'undefined') { - payload['username'] = username; - } - if (typeof password !== 'undefined') { - payload['password'] = password; - } - if (typeof port !== 'undefined') { - payload['port'] = port; - } - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface MigrationsCreateSupabaseMigrationRequestParams { - resources: string[]; - endpoint: string; - apiKey: string; - databaseHost: string; - username: string; - password: string; - port?: number; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const migrationsCreateSupabaseMigration = async ({resources,endpoint,apiKey,databaseHost,username,password,port,parseOutput = true, overrideForCli = false, sdk = undefined}: MigrationsCreateSupabaseMigrationRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/migrations/supabase'; - let payload = {}; - resources = resources === true ? [] : resources; - if (typeof resources !== 'undefined') { - payload['resources'] = resources; - } - if (typeof endpoint !== 'undefined') { - payload['endpoint'] = endpoint; - } - if (typeof apiKey !== 'undefined') { - payload['apiKey'] = apiKey; - } - if (typeof databaseHost !== 'undefined') { - payload['databaseHost'] = databaseHost; - } - if (typeof username !== 'undefined') { - payload['username'] = username; - } - if (typeof password !== 'undefined') { - payload['password'] = password; - } - if (typeof port !== 'undefined') { - payload['port'] = port; - } - - let response = undefined; - - response = await client.call('post', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface MigrationsGetSupabaseReportRequestParams { - resources: string[]; - endpoint: string; - apiKey: string; - databaseHost: string; - username: string; - password: string; - port?: number; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const migrationsGetSupabaseReport = async ({resources,endpoint,apiKey,databaseHost,username,password,port,parseOutput = true, overrideForCli = false, sdk = undefined}: MigrationsGetSupabaseReportRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/migrations/supabase/report'; - let payload = {}; - if (typeof resources !== 'undefined') { - payload['resources'] = resources; - } - if (typeof endpoint !== 'undefined') { - payload['endpoint'] = endpoint; - } - if (typeof apiKey !== 'undefined') { - payload['apiKey'] = apiKey; - } - if (typeof databaseHost !== 'undefined') { - payload['databaseHost'] = databaseHost; - } - if (typeof username !== 'undefined') { - payload['username'] = username; - } - if (typeof password !== 'undefined') { - payload['password'] = password; - } - if (typeof port !== 'undefined') { - payload['port'] = port; - } - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface MigrationsGetRequestParams { - migrationId: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const migrationsGet = async ({migrationId,parseOutput = true, overrideForCli = false, sdk = undefined}: MigrationsGetRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/migrations/{migrationId}'.replace('{migrationId}', migrationId); - let payload = {}; - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface MigrationsRetryRequestParams { - migrationId: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const migrationsRetry = async ({migrationId,parseOutput = true, overrideForCli = false, sdk = undefined}: MigrationsRetryRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/migrations/{migrationId}'.replace('{migrationId}', migrationId); - let payload = {}; - - let response = undefined; - - response = await client.call('patch', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface MigrationsDeleteRequestParams { - migrationId: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const migrationsDelete = async ({migrationId,parseOutput = true, overrideForCli = false, sdk = undefined}: MigrationsDeleteRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/migrations/{migrationId}'.replace('{migrationId}', migrationId); - let payload = {}; - - let response = undefined; - - response = await client.call('delete', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -migrations - .command(`list`) - .description(`List all migrations in the current project. This endpoint returns a list of all migrations including their status, progress, and any errors that occurred during the migration process.`) - .option(`--queries [queries...]`, `Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/databases#querying-documents). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: status, stage, source, destination, resources, statusCounters, resourceData, errors`) - .option(`--search <search>`, `Search term to filter your list results. Max length: 256 chars.`) - .option(`--total [value]`, `When set to false, the total count returned will be 0 and will not be calculated.`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .action(actionRunner(migrationsList)) - -migrations - .command(`create-appwrite-migration`) - .description(`Migrate data from another Appwrite project to your current project. This endpoint allows you to migrate resources like databases, collections, documents, users, and files from an existing Appwrite project. `) - .requiredOption(`--resources [resources...]`, `List of resources to migrate`) - .requiredOption(`--endpoint <endpoint>`, `Source Appwrite endpoint`) - .requiredOption(`--project-id <project-id>`, `Source Project ID`) - .requiredOption(`--api-key <api-key>`, `Source API Key`) - .action(actionRunner(migrationsCreateAppwriteMigration)) - -migrations - .command(`get-appwrite-report`) - .description(`Generate a report of the data in an Appwrite project before migrating. This endpoint analyzes the source project and returns information about the resources that can be migrated.`) - .requiredOption(`--resources [resources...]`, `List of resources to migrate`) - .requiredOption(`--endpoint <endpoint>`, `Source's Appwrite Endpoint`) - .requiredOption(`--project-id <project-id>`, `Source's Project ID`) - .requiredOption(`--key <key>`, `Source's API Key`) - .action(actionRunner(migrationsGetAppwriteReport)) - -migrations - .command(`create-csv-export`) - .description(`Export documents to a CSV file from your Appwrite database. This endpoint allows you to export documents to a CSV file stored in a secure internal bucket. You'll receive an email with a download link when the export is complete.`) - .requiredOption(`--resource-id <resource-id>`, `Composite ID in the format {databaseId:collectionId}, identifying a collection within a database to export.`) - .requiredOption(`--filename <filename>`, `The name of the file to be created for the export, excluding the .csv extension.`) - .option(`--columns [columns...]`, `List of attributes to export. If empty, all attributes will be exported. You can use the '*' wildcard to export all attributes from the collection.`) - .option(`--queries [queries...]`, `Array of query strings generated using the Query class provided by the SDK to filter documents to export. [Learn more about queries](https://appwrite.io/docs/databases#querying-documents). Maximum of 100 queries are allowed, each 4096 characters long.`) - .option(`--delimiter <delimiter>`, `The character that separates each column value. Default is comma.`) - .option(`--enclosure <enclosure>`, `The character that encloses each column value. Default is double quotes.`) - .option(`--escape <escape>`, `The escape character for the enclosure character. Default is double quotes.`) - .option(`--header [value]`, `Whether to include the header row with column names. Default is true.`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .option(`--notify [value]`, `Set to true to receive an email when the export is complete. Default is true.`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .action(actionRunner(migrationsCreateCSVExport)) - -migrations - .command(`create-csv-import`) - .description(`Import documents from a CSV file into your Appwrite database. This endpoint allows you to import documents from a CSV file uploaded to Appwrite Storage bucket.`) - .requiredOption(`--bucket-id <bucket-id>`, `Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](https://appwrite.io/docs/server/storage#createBucket).`) - .requiredOption(`--file-id <file-id>`, `File ID.`) - .requiredOption(`--resource-id <resource-id>`, `Composite ID in the format {databaseId:collectionId}, identifying a collection within a database.`) - .option(`--internal-file [value]`, `Is the file stored in an internal bucket?`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .action(actionRunner(migrationsCreateCSVImport)) - -migrations - .command(`create-firebase-migration`) - .description(`Migrate data from a Firebase project to your Appwrite project. This endpoint allows you to migrate resources like authentication and other supported services from a Firebase project. `) - .requiredOption(`--resources [resources...]`, `List of resources to migrate`) - .requiredOption(`--service-account <service-account>`, `JSON of the Firebase service account credentials`) - .action(actionRunner(migrationsCreateFirebaseMigration)) - -migrations - .command(`get-firebase-report`) - .description(`Generate a report of the data in a Firebase project before migrating. This endpoint analyzes the source project and returns information about the resources that can be migrated.`) - .requiredOption(`--resources [resources...]`, `List of resources to migrate`) - .requiredOption(`--service-account <service-account>`, `JSON of the Firebase service account credentials`) - .action(actionRunner(migrationsGetFirebaseReport)) - -migrations - .command(`create-n-host-migration`) - .description(`Migrate data from an NHost project to your Appwrite project. This endpoint allows you to migrate resources like authentication, databases, and other supported services from an NHost project. `) - .requiredOption(`--resources [resources...]`, `List of resources to migrate`) - .requiredOption(`--subdomain <subdomain>`, `Source's Subdomain`) - .requiredOption(`--region <region>`, `Source's Region`) - .requiredOption(`--admin-secret <admin-secret>`, `Source's Admin Secret`) - .requiredOption(`--database <database>`, `Source's Database Name`) - .requiredOption(`--username <username>`, `Source's Database Username`) - .requiredOption(`--password <password>`, `Source's Database Password`) - .option(`--port <port>`, `Source's Database Port`, parseInteger) - .action(actionRunner(migrationsCreateNHostMigration)) - -migrations - .command(`get-n-host-report`) - .description(`Generate a detailed report of the data in an NHost project before migrating. This endpoint analyzes the source project and returns information about the resources that can be migrated. `) - .requiredOption(`--resources [resources...]`, `List of resources to migrate.`) - .requiredOption(`--subdomain <subdomain>`, `Source's Subdomain.`) - .requiredOption(`--region <region>`, `Source's Region.`) - .requiredOption(`--admin-secret <admin-secret>`, `Source's Admin Secret.`) - .requiredOption(`--database <database>`, `Source's Database Name.`) - .requiredOption(`--username <username>`, `Source's Database Username.`) - .requiredOption(`--password <password>`, `Source's Database Password.`) - .option(`--port <port>`, `Source's Database Port.`, parseInteger) - .action(actionRunner(migrationsGetNHostReport)) - -migrations - .command(`create-supabase-migration`) - .description(`Migrate data from a Supabase project to your Appwrite project. This endpoint allows you to migrate resources like authentication, databases, and other supported services from a Supabase project. `) - .requiredOption(`--resources [resources...]`, `List of resources to migrate`) - .requiredOption(`--endpoint <endpoint>`, `Source's Supabase Endpoint`) - .requiredOption(`--api-key <api-key>`, `Source's API Key`) - .requiredOption(`--database-host <database-host>`, `Source's Database Host`) - .requiredOption(`--username <username>`, `Source's Database Username`) - .requiredOption(`--password <password>`, `Source's Database Password`) - .option(`--port <port>`, `Source's Database Port`, parseInteger) - .action(actionRunner(migrationsCreateSupabaseMigration)) - -migrations - .command(`get-supabase-report`) - .description(`Generate a report of the data in a Supabase project before migrating. This endpoint analyzes the source project and returns information about the resources that can be migrated. `) - .requiredOption(`--resources [resources...]`, `List of resources to migrate`) - .requiredOption(`--endpoint <endpoint>`, `Source's Supabase Endpoint.`) - .requiredOption(`--api-key <api-key>`, `Source's API Key.`) - .requiredOption(`--database-host <database-host>`, `Source's Database Host.`) - .requiredOption(`--username <username>`, `Source's Database Username.`) - .requiredOption(`--password <password>`, `Source's Database Password.`) - .option(`--port <port>`, `Source's Database Port.`, parseInteger) - .action(actionRunner(migrationsGetSupabaseReport)) - -migrations - .command(`get`) - .description(`Get a migration by its unique ID. This endpoint returns detailed information about a specific migration including its current status, progress, and any errors that occurred during the migration process. `) - .requiredOption(`--migration-id <migration-id>`, `Migration unique ID.`) - .action(actionRunner(migrationsGet)) - -migrations - .command(`retry`) - .description(`Retry a failed migration. This endpoint allows you to retry a migration that has previously failed.`) - .requiredOption(`--migration-id <migration-id>`, `Migration unique ID.`) - .action(actionRunner(migrationsRetry)) - -migrations - .command(`delete`) - .description(`Delete a migration by its unique ID. This endpoint allows you to remove a migration from your project's migration history. `) - .requiredOption(`--migration-id <migration-id>`, `Migration ID.`) - .action(actionRunner(migrationsDelete)) - - diff --git a/lib/commands/organizations.ts b/lib/commands/organizations.ts deleted file mode 100644 index 977873a4..00000000 --- a/lib/commands/organizations.ts +++ /dev/null @@ -1,46 +0,0 @@ -import { sdkForProject } from '../sdks'; -import { parse } from '../parser'; -import { showConsoleLink } from '../utils'; -import Client from '../client'; - -interface OrganizationsListRequestParams { - queries?: string[]; - search?: string; - parseOutput?: boolean; - sdk?: Client; - console?: boolean; -} - -export const organizationsList = async ({ - queries, - search, - parseOutput = true, - sdk = undefined, - console: showConsole -}: OrganizationsListRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : sdk; - let apiPath = '/organizations'; - let payload: Record<string, any> = {}; - - if (typeof queries !== 'undefined') { - payload['queries'] = queries; - } - if (typeof search !== 'undefined') { - payload['search'] = search; - } - - let response = await client.call('get', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - if(showConsole) { - showConsoleLink('organizations', 'list'); - } else { - parse(response) - } - } - - return response; -} - diff --git a/lib/commands/project.ts b/lib/commands/project.ts deleted file mode 100644 index 9e6f33d7..00000000 --- a/lib/commands/project.ts +++ /dev/null @@ -1,266 +0,0 @@ -import fs = require('fs'); -import pathLib = require('path'); -import tar = require('tar'); -import ignore = require('ignore'); -import { promisify } from 'util'; -import Client from '../client'; -import { getAllFiles, showConsoleLink } from '../utils'; -import { Command } from 'commander'; -import { sdkForProject, sdkForConsole } from '../sdks'; -import { parse, actionRunner, parseInteger, parseBool, commandDescriptions, success, log, warn } from '../parser'; -import { localConfig, globalConfig } from '../config'; -import { File } from 'undici'; -import { ReadableStream } from 'stream/web'; - -function convertReadStreamToReadableStream(readStream: fs.ReadStream): ReadableStream { - return new ReadableStream({ - start(controller) { - readStream.on("data", (chunk: Buffer) => { - controller.enqueue(chunk); - }); - readStream.on("end", () => { - controller.close(); - }); - readStream.on("error", (err: Error) => { - controller.error(err); - }); - }, - cancel() { - readStream.destroy(); - }, - }); -} - -export const project = new Command("project").description(commandDescriptions['project'] ?? '').configureHelp({ - helpWidth: process.stdout.columns || 80 -}) - -interface ProjectGetUsageRequestParams { - startDate: string; - endDate: string; - period?: ProjectUsageRange; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const projectGetUsage = async ({startDate,endDate,period,parseOutput = true, overrideForCli = false, sdk = undefined}: ProjectGetUsageRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/project/usage'; - let payload = {}; - if (typeof startDate !== 'undefined') { - payload['startDate'] = startDate; - } - if (typeof endDate !== 'undefined') { - payload['endDate'] = endDate; - } - if (typeof period !== 'undefined') { - payload['period'] = period; - } - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface ProjectListVariablesRequestParams { - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const projectListVariables = async ({parseOutput = true, overrideForCli = false, sdk = undefined}: ProjectListVariablesRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/project/variables'; - let payload = {}; - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface ProjectCreateVariableRequestParams { - key: string; - value: string; - secret?: boolean; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const projectCreateVariable = async ({key,value,secret,parseOutput = true, overrideForCli = false, sdk = undefined}: ProjectCreateVariableRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/project/variables'; - let payload = {}; - if (typeof key !== 'undefined') { - payload['key'] = key; - } - if (typeof value !== 'undefined') { - payload['value'] = value; - } - if (typeof secret !== 'undefined') { - payload['secret'] = secret; - } - - let response = undefined; - - response = await client.call('post', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface ProjectGetVariableRequestParams { - variableId: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const projectGetVariable = async ({variableId,parseOutput = true, overrideForCli = false, sdk = undefined}: ProjectGetVariableRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/project/variables/{variableId}'.replace('{variableId}', variableId); - let payload = {}; - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface ProjectUpdateVariableRequestParams { - variableId: string; - key: string; - value?: string; - secret?: boolean; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const projectUpdateVariable = async ({variableId,key,value,secret,parseOutput = true, overrideForCli = false, sdk = undefined}: ProjectUpdateVariableRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/project/variables/{variableId}'.replace('{variableId}', variableId); - let payload = {}; - if (typeof key !== 'undefined') { - payload['key'] = key; - } - if (typeof value !== 'undefined') { - payload['value'] = value; - } - if (typeof secret !== 'undefined') { - payload['secret'] = secret; - } - - let response = undefined; - - response = await client.call('put', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface ProjectDeleteVariableRequestParams { - variableId: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const projectDeleteVariable = async ({variableId,parseOutput = true, overrideForCli = false, sdk = undefined}: ProjectDeleteVariableRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/project/variables/{variableId}'.replace('{variableId}', variableId); - let payload = {}; - - let response = undefined; - - response = await client.call('delete', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -project - .command(`get-usage`) - .description(`Get comprehensive usage statistics for your project. View metrics including network requests, bandwidth, storage, function executions, database usage, and user activity. Specify a time range with startDate and endDate, and optionally set the data granularity with period (1h or 1d). The response includes both total counts and detailed breakdowns by resource, along with historical data over the specified period.`) - .requiredOption(`--start-date <start-date>`, `Starting date for the usage`) - .requiredOption(`--end-date <end-date>`, `End date for the usage`) - .option(`--period <period>`, `Period used`) - .action(actionRunner(projectGetUsage)) - -project - .command(`list-variables`) - .description(`Get a list of all project variables. These variables will be accessible in all Appwrite Functions at runtime.`) - .action(actionRunner(projectListVariables)) - -project - .command(`create-variable`) - .description(`Create a new project variable. This variable will be accessible in all Appwrite Functions at runtime.`) - .requiredOption(`--key <key>`, `Variable key. Max length: 255 chars.`) - .requiredOption(`--value <value>`, `Variable value. Max length: 8192 chars.`) - .option(`--secret [value]`, `Secret variables can be updated or deleted, but only projects can read them during build and runtime.`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .action(actionRunner(projectCreateVariable)) - -project - .command(`get-variable`) - .description(`Get a project variable by its unique ID.`) - .requiredOption(`--variable-id <variable-id>`, `Variable unique ID.`) - .action(actionRunner(projectGetVariable)) - -project - .command(`update-variable`) - .description(`Update project variable by its unique ID. This variable will be accessible in all Appwrite Functions at runtime.`) - .requiredOption(`--variable-id <variable-id>`, `Variable unique ID.`) - .requiredOption(`--key <key>`, `Variable key. Max length: 255 chars.`) - .option(`--value <value>`, `Variable value. Max length: 8192 chars.`) - .option(`--secret [value]`, `Secret variables can be updated or deleted, but only projects can read them during build and runtime.`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .action(actionRunner(projectUpdateVariable)) - -project - .command(`delete-variable`) - .description(`Delete a project variable by its unique ID. `) - .requiredOption(`--variable-id <variable-id>`, `Variable unique ID.`) - .action(actionRunner(projectDeleteVariable)) - - diff --git a/lib/commands/projects.ts b/lib/commands/projects.ts deleted file mode 100644 index f8b2c8c5..00000000 --- a/lib/commands/projects.ts +++ /dev/null @@ -1,2370 +0,0 @@ -import fs = require('fs'); -import pathLib = require('path'); -import tar = require('tar'); -import ignore = require('ignore'); -import { promisify } from 'util'; -import Client from '../client'; -import { getAllFiles, showConsoleLink } from '../utils'; -import { Command } from 'commander'; -import { sdkForProject, sdkForConsole } from '../sdks'; -import { parse, actionRunner, parseInteger, parseBool, commandDescriptions, success, log, warn } from '../parser'; -import { localConfig, globalConfig } from '../config'; -import { File } from 'undici'; -import { ReadableStream } from 'stream/web'; - -function convertReadStreamToReadableStream(readStream: fs.ReadStream): ReadableStream { - return new ReadableStream({ - start(controller) { - readStream.on("data", (chunk: Buffer) => { - controller.enqueue(chunk); - }); - readStream.on("end", () => { - controller.close(); - }); - readStream.on("error", (err: Error) => { - controller.error(err); - }); - }, - cancel() { - readStream.destroy(); - }, - }); -} - -export const projects = new Command("projects").description(commandDescriptions['projects'] ?? '').configureHelp({ - helpWidth: process.stdout.columns || 80 -}) - -interface ProjectsListRequestParams { - queries?: string[]; - search?: string; - total?: boolean; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; - console?: boolean; -} - -export const projectsList = async ({queries,search,total,parseOutput = true, overrideForCli = false, sdk = undefined, console: showConsole}: ProjectsListRequestParams): Promise<any> => { - let client = !sdk ? await sdkForConsole() : - sdk; - let apiPath = '/projects'; - let payload = {}; - if (typeof queries !== 'undefined') { - payload['queries'] = queries; - } - if (typeof search !== 'undefined') { - payload['search'] = search; - } - if (typeof total !== 'undefined') { - payload['total'] = total; - } - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - if(showConsole) { - showConsoleLink('projects', 'list'); - } else { - parse(response) - } - } - - return response; - -} -interface ProjectsCreateRequestParams { - projectId: string; - name: string; - teamId: string; - region?: Region; - description?: string; - logo?: string; - url?: string; - legalName?: string; - legalCountry?: string; - legalState?: string; - legalCity?: string; - legalAddress?: string; - legalTaxId?: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const projectsCreate = async ({projectId,name,teamId,region,description,logo,url,legalName,legalCountry,legalState,legalCity,legalAddress,legalTaxId,parseOutput = true, overrideForCli = false, sdk = undefined}: ProjectsCreateRequestParams): Promise<any> => { - let client = !sdk ? await sdkForConsole() : - sdk; - let apiPath = '/projects'; - let payload = {}; - if (typeof projectId !== 'undefined') { - payload['projectId'] = projectId; - } - if (typeof name !== 'undefined') { - payload['name'] = name; - } - if (typeof teamId !== 'undefined') { - payload['teamId'] = teamId; - } - if (typeof region !== 'undefined') { - payload['region'] = region; - } - if (typeof description !== 'undefined') { - payload['description'] = description; - } - if (typeof logo !== 'undefined') { - payload['logo'] = logo; - } - if (typeof url !== 'undefined') { - payload['url'] = url; - } - if (typeof legalName !== 'undefined') { - payload['legalName'] = legalName; - } - if (typeof legalCountry !== 'undefined') { - payload['legalCountry'] = legalCountry; - } - if (typeof legalState !== 'undefined') { - payload['legalState'] = legalState; - } - if (typeof legalCity !== 'undefined') { - payload['legalCity'] = legalCity; - } - if (typeof legalAddress !== 'undefined') { - payload['legalAddress'] = legalAddress; - } - if (typeof legalTaxId !== 'undefined') { - payload['legalTaxId'] = legalTaxId; - } - - let response = undefined; - - response = await client.call('post', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface ProjectsGetRequestParams { - projectId: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; - console?: boolean; -} - -export const projectsGet = async ({projectId,parseOutput = true, overrideForCli = false, sdk = undefined, console: showConsole}: ProjectsGetRequestParams): Promise<any> => { - let client = !sdk ? await sdkForConsole() : - sdk; - let apiPath = '/projects/{projectId}'.replace('{projectId}', projectId); - let payload = {}; - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - if(showConsole) { - showConsoleLink('projects', 'get', projectId); - } else { - parse(response) - } - } - - return response; - -} -interface ProjectsUpdateRequestParams { - projectId: string; - name: string; - description?: string; - logo?: string; - url?: string; - legalName?: string; - legalCountry?: string; - legalState?: string; - legalCity?: string; - legalAddress?: string; - legalTaxId?: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const projectsUpdate = async ({projectId,name,description,logo,url,legalName,legalCountry,legalState,legalCity,legalAddress,legalTaxId,parseOutput = true, overrideForCli = false, sdk = undefined}: ProjectsUpdateRequestParams): Promise<any> => { - let client = !sdk ? await sdkForConsole() : - sdk; - let apiPath = '/projects/{projectId}'.replace('{projectId}', projectId); - let payload = {}; - if (typeof name !== 'undefined') { - payload['name'] = name; - } - if (typeof description !== 'undefined') { - payload['description'] = description; - } - if (typeof logo !== 'undefined') { - payload['logo'] = logo; - } - if (typeof url !== 'undefined') { - payload['url'] = url; - } - if (typeof legalName !== 'undefined') { - payload['legalName'] = legalName; - } - if (typeof legalCountry !== 'undefined') { - payload['legalCountry'] = legalCountry; - } - if (typeof legalState !== 'undefined') { - payload['legalState'] = legalState; - } - if (typeof legalCity !== 'undefined') { - payload['legalCity'] = legalCity; - } - if (typeof legalAddress !== 'undefined') { - payload['legalAddress'] = legalAddress; - } - if (typeof legalTaxId !== 'undefined') { - payload['legalTaxId'] = legalTaxId; - } - - let response = undefined; - - response = await client.call('patch', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface ProjectsDeleteRequestParams { - projectId: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const projectsDelete = async ({projectId,parseOutput = true, overrideForCli = false, sdk = undefined}: ProjectsDeleteRequestParams): Promise<any> => { - let client = !sdk ? await sdkForConsole() : - sdk; - let apiPath = '/projects/{projectId}'.replace('{projectId}', projectId); - let payload = {}; - - let response = undefined; - - response = await client.call('delete', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface ProjectsUpdateAPIStatusRequestParams { - projectId: string; - api: Api; - status: boolean; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const projectsUpdateAPIStatus = async ({projectId,api,status,parseOutput = true, overrideForCli = false, sdk = undefined}: ProjectsUpdateAPIStatusRequestParams): Promise<any> => { - let client = !sdk ? await sdkForConsole() : - sdk; - let apiPath = '/projects/{projectId}/api'.replace('{projectId}', projectId); - let payload = {}; - if (typeof api !== 'undefined') { - payload['api'] = api; - } - if (typeof status !== 'undefined') { - payload['status'] = status; - } - - let response = undefined; - - response = await client.call('patch', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface ProjectsUpdateAPIStatusAllRequestParams { - projectId: string; - status: boolean; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const projectsUpdateAPIStatusAll = async ({projectId,status,parseOutput = true, overrideForCli = false, sdk = undefined}: ProjectsUpdateAPIStatusAllRequestParams): Promise<any> => { - let client = !sdk ? await sdkForConsole() : - sdk; - let apiPath = '/projects/{projectId}/api/all'.replace('{projectId}', projectId); - let payload = {}; - if (typeof status !== 'undefined') { - payload['status'] = status; - } - - let response = undefined; - - response = await client.call('patch', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface ProjectsUpdateAuthDurationRequestParams { - projectId: string; - duration: number; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const projectsUpdateAuthDuration = async ({projectId,duration,parseOutput = true, overrideForCli = false, sdk = undefined}: ProjectsUpdateAuthDurationRequestParams): Promise<any> => { - let client = !sdk ? await sdkForConsole() : - sdk; - let apiPath = '/projects/{projectId}/auth/duration'.replace('{projectId}', projectId); - let payload = {}; - if (typeof duration !== 'undefined') { - payload['duration'] = duration; - } - - let response = undefined; - - response = await client.call('patch', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface ProjectsUpdateAuthLimitRequestParams { - projectId: string; - limit: number; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const projectsUpdateAuthLimit = async ({projectId,limit,parseOutput = true, overrideForCli = false, sdk = undefined}: ProjectsUpdateAuthLimitRequestParams): Promise<any> => { - let client = !sdk ? await sdkForConsole() : - sdk; - let apiPath = '/projects/{projectId}/auth/limit'.replace('{projectId}', projectId); - let payload = {}; - if (typeof limit !== 'undefined') { - payload['limit'] = limit; - } - - let response = undefined; - - response = await client.call('patch', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface ProjectsUpdateAuthSessionsLimitRequestParams { - projectId: string; - limit: number; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const projectsUpdateAuthSessionsLimit = async ({projectId,limit,parseOutput = true, overrideForCli = false, sdk = undefined}: ProjectsUpdateAuthSessionsLimitRequestParams): Promise<any> => { - let client = !sdk ? await sdkForConsole() : - sdk; - let apiPath = '/projects/{projectId}/auth/max-sessions'.replace('{projectId}', projectId); - let payload = {}; - if (typeof limit !== 'undefined') { - payload['limit'] = limit; - } - - let response = undefined; - - response = await client.call('patch', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface ProjectsUpdateMembershipsPrivacyRequestParams { - projectId: string; - userName: boolean; - userEmail: boolean; - mfa: boolean; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const projectsUpdateMembershipsPrivacy = async ({projectId,userName,userEmail,mfa,parseOutput = true, overrideForCli = false, sdk = undefined}: ProjectsUpdateMembershipsPrivacyRequestParams): Promise<any> => { - let client = !sdk ? await sdkForConsole() : - sdk; - let apiPath = '/projects/{projectId}/auth/memberships-privacy'.replace('{projectId}', projectId); - let payload = {}; - if (typeof userName !== 'undefined') { - payload['userName'] = userName; - } - if (typeof userEmail !== 'undefined') { - payload['userEmail'] = userEmail; - } - if (typeof mfa !== 'undefined') { - payload['mfa'] = mfa; - } - - let response = undefined; - - response = await client.call('patch', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface ProjectsUpdateMockNumbersRequestParams { - projectId: string; - numbers: object[]; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const projectsUpdateMockNumbers = async ({projectId,numbers,parseOutput = true, overrideForCli = false, sdk = undefined}: ProjectsUpdateMockNumbersRequestParams): Promise<any> => { - let client = !sdk ? await sdkForConsole() : - sdk; - let apiPath = '/projects/{projectId}/auth/mock-numbers'.replace('{projectId}', projectId); - let payload = {}; - numbers = numbers === true ? [] : numbers; - if (typeof numbers !== 'undefined') { - payload['numbers'] = numbers; - } - - let response = undefined; - - response = await client.call('patch', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface ProjectsUpdateAuthPasswordDictionaryRequestParams { - projectId: string; - enabled: boolean; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const projectsUpdateAuthPasswordDictionary = async ({projectId,enabled,parseOutput = true, overrideForCli = false, sdk = undefined}: ProjectsUpdateAuthPasswordDictionaryRequestParams): Promise<any> => { - let client = !sdk ? await sdkForConsole() : - sdk; - let apiPath = '/projects/{projectId}/auth/password-dictionary'.replace('{projectId}', projectId); - let payload = {}; - if (typeof enabled !== 'undefined') { - payload['enabled'] = enabled; - } - - let response = undefined; - - response = await client.call('patch', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface ProjectsUpdateAuthPasswordHistoryRequestParams { - projectId: string; - limit: number; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const projectsUpdateAuthPasswordHistory = async ({projectId,limit,parseOutput = true, overrideForCli = false, sdk = undefined}: ProjectsUpdateAuthPasswordHistoryRequestParams): Promise<any> => { - let client = !sdk ? await sdkForConsole() : - sdk; - let apiPath = '/projects/{projectId}/auth/password-history'.replace('{projectId}', projectId); - let payload = {}; - if (typeof limit !== 'undefined') { - payload['limit'] = limit; - } - - let response = undefined; - - response = await client.call('patch', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface ProjectsUpdatePersonalDataCheckRequestParams { - projectId: string; - enabled: boolean; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const projectsUpdatePersonalDataCheck = async ({projectId,enabled,parseOutput = true, overrideForCli = false, sdk = undefined}: ProjectsUpdatePersonalDataCheckRequestParams): Promise<any> => { - let client = !sdk ? await sdkForConsole() : - sdk; - let apiPath = '/projects/{projectId}/auth/personal-data'.replace('{projectId}', projectId); - let payload = {}; - if (typeof enabled !== 'undefined') { - payload['enabled'] = enabled; - } - - let response = undefined; - - response = await client.call('patch', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface ProjectsUpdateSessionAlertsRequestParams { - projectId: string; - alerts: boolean; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const projectsUpdateSessionAlerts = async ({projectId,alerts,parseOutput = true, overrideForCli = false, sdk = undefined}: ProjectsUpdateSessionAlertsRequestParams): Promise<any> => { - let client = !sdk ? await sdkForConsole() : - sdk; - let apiPath = '/projects/{projectId}/auth/session-alerts'.replace('{projectId}', projectId); - let payload = {}; - if (typeof alerts !== 'undefined') { - payload['alerts'] = alerts; - } - - let response = undefined; - - response = await client.call('patch', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface ProjectsUpdateSessionInvalidationRequestParams { - projectId: string; - enabled: boolean; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const projectsUpdateSessionInvalidation = async ({projectId,enabled,parseOutput = true, overrideForCli = false, sdk = undefined}: ProjectsUpdateSessionInvalidationRequestParams): Promise<any> => { - let client = !sdk ? await sdkForConsole() : - sdk; - let apiPath = '/projects/{projectId}/auth/session-invalidation'.replace('{projectId}', projectId); - let payload = {}; - if (typeof enabled !== 'undefined') { - payload['enabled'] = enabled; - } - - let response = undefined; - - response = await client.call('patch', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface ProjectsUpdateAuthStatusRequestParams { - projectId: string; - method: AuthMethod; - status: boolean; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const projectsUpdateAuthStatus = async ({projectId,method,status,parseOutput = true, overrideForCli = false, sdk = undefined}: ProjectsUpdateAuthStatusRequestParams): Promise<any> => { - let client = !sdk ? await sdkForConsole() : - sdk; - let apiPath = '/projects/{projectId}/auth/{method}'.replace('{projectId}', projectId).replace('{method}', method); - let payload = {}; - if (typeof status !== 'undefined') { - payload['status'] = status; - } - - let response = undefined; - - response = await client.call('patch', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface ProjectsListDevKeysRequestParams { - projectId: string; - queries?: string[]; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; - console?: boolean; -} - -export const projectsListDevKeys = async ({projectId,queries,parseOutput = true, overrideForCli = false, sdk = undefined, console: showConsole}: ProjectsListDevKeysRequestParams): Promise<any> => { - let client = !sdk ? await sdkForConsole() : - sdk; - let apiPath = '/projects/{projectId}/dev-keys'.replace('{projectId}', projectId); - let payload = {}; - if (typeof queries !== 'undefined') { - payload['queries'] = queries; - } - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - if(showConsole) { - showConsoleLink('projects', 'listDevKeys', projectId); - } else { - parse(response) - } - } - - return response; - -} -interface ProjectsCreateDevKeyRequestParams { - projectId: string; - name: string; - expire: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const projectsCreateDevKey = async ({projectId,name,expire,parseOutput = true, overrideForCli = false, sdk = undefined}: ProjectsCreateDevKeyRequestParams): Promise<any> => { - let client = !sdk ? await sdkForConsole() : - sdk; - let apiPath = '/projects/{projectId}/dev-keys'.replace('{projectId}', projectId); - let payload = {}; - if (typeof name !== 'undefined') { - payload['name'] = name; - } - if (typeof expire !== 'undefined') { - payload['expire'] = expire; - } - - let response = undefined; - - response = await client.call('post', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface ProjectsGetDevKeyRequestParams { - projectId: string; - keyId: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; - console?: boolean; -} - -export const projectsGetDevKey = async ({projectId,keyId,parseOutput = true, overrideForCli = false, sdk = undefined, console: showConsole}: ProjectsGetDevKeyRequestParams): Promise<any> => { - let client = !sdk ? await sdkForConsole() : - sdk; - let apiPath = '/projects/{projectId}/dev-keys/{keyId}'.replace('{projectId}', projectId).replace('{keyId}', keyId); - let payload = {}; - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - if(showConsole) { - showConsoleLink('projects', 'getDevKey', projectId, keyId); - } else { - parse(response) - } - } - - return response; - -} -interface ProjectsUpdateDevKeyRequestParams { - projectId: string; - keyId: string; - name: string; - expire: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const projectsUpdateDevKey = async ({projectId,keyId,name,expire,parseOutput = true, overrideForCli = false, sdk = undefined}: ProjectsUpdateDevKeyRequestParams): Promise<any> => { - let client = !sdk ? await sdkForConsole() : - sdk; - let apiPath = '/projects/{projectId}/dev-keys/{keyId}'.replace('{projectId}', projectId).replace('{keyId}', keyId); - let payload = {}; - if (typeof name !== 'undefined') { - payload['name'] = name; - } - if (typeof expire !== 'undefined') { - payload['expire'] = expire; - } - - let response = undefined; - - response = await client.call('put', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface ProjectsDeleteDevKeyRequestParams { - projectId: string; - keyId: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const projectsDeleteDevKey = async ({projectId,keyId,parseOutput = true, overrideForCli = false, sdk = undefined}: ProjectsDeleteDevKeyRequestParams): Promise<any> => { - let client = !sdk ? await sdkForConsole() : - sdk; - let apiPath = '/projects/{projectId}/dev-keys/{keyId}'.replace('{projectId}', projectId).replace('{keyId}', keyId); - let payload = {}; - - let response = undefined; - - response = await client.call('delete', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface ProjectsCreateJWTRequestParams { - projectId: string; - scopes: string[]; - duration?: number; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const projectsCreateJWT = async ({projectId,scopes,duration,parseOutput = true, overrideForCli = false, sdk = undefined}: ProjectsCreateJWTRequestParams): Promise<any> => { - let client = !sdk ? await sdkForConsole() : - sdk; - let apiPath = '/projects/{projectId}/jwts'.replace('{projectId}', projectId); - let payload = {}; - scopes = scopes === true ? [] : scopes; - if (typeof scopes !== 'undefined') { - payload['scopes'] = scopes; - } - if (typeof duration !== 'undefined') { - payload['duration'] = duration; - } - - let response = undefined; - - response = await client.call('post', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface ProjectsListKeysRequestParams { - projectId: string; - total?: boolean; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; - console?: boolean; -} - -export const projectsListKeys = async ({projectId,total,parseOutput = true, overrideForCli = false, sdk = undefined, console: showConsole}: ProjectsListKeysRequestParams): Promise<any> => { - let client = !sdk ? await sdkForConsole() : - sdk; - let apiPath = '/projects/{projectId}/keys'.replace('{projectId}', projectId); - let payload = {}; - if (typeof total !== 'undefined') { - payload['total'] = total; - } - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - if(showConsole) { - showConsoleLink('projects', 'listKeys', projectId); - } else { - parse(response) - } - } - - return response; - -} -interface ProjectsCreateKeyRequestParams { - projectId: string; - name: string; - scopes: string[]; - expire?: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const projectsCreateKey = async ({projectId,name,scopes,expire,parseOutput = true, overrideForCli = false, sdk = undefined}: ProjectsCreateKeyRequestParams): Promise<any> => { - let client = !sdk ? await sdkForConsole() : - sdk; - let apiPath = '/projects/{projectId}/keys'.replace('{projectId}', projectId); - let payload = {}; - if (typeof name !== 'undefined') { - payload['name'] = name; - } - scopes = scopes === true ? [] : scopes; - if (typeof scopes !== 'undefined') { - payload['scopes'] = scopes; - } - if (typeof expire !== 'undefined') { - payload['expire'] = expire; - } - - let response = undefined; - - response = await client.call('post', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface ProjectsGetKeyRequestParams { - projectId: string; - keyId: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; - console?: boolean; -} - -export const projectsGetKey = async ({projectId,keyId,parseOutput = true, overrideForCli = false, sdk = undefined, console: showConsole}: ProjectsGetKeyRequestParams): Promise<any> => { - let client = !sdk ? await sdkForConsole() : - sdk; - let apiPath = '/projects/{projectId}/keys/{keyId}'.replace('{projectId}', projectId).replace('{keyId}', keyId); - let payload = {}; - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - if(showConsole) { - showConsoleLink('projects', 'getKey', projectId, keyId); - } else { - parse(response) - } - } - - return response; - -} -interface ProjectsUpdateKeyRequestParams { - projectId: string; - keyId: string; - name: string; - scopes: string[]; - expire?: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const projectsUpdateKey = async ({projectId,keyId,name,scopes,expire,parseOutput = true, overrideForCli = false, sdk = undefined}: ProjectsUpdateKeyRequestParams): Promise<any> => { - let client = !sdk ? await sdkForConsole() : - sdk; - let apiPath = '/projects/{projectId}/keys/{keyId}'.replace('{projectId}', projectId).replace('{keyId}', keyId); - let payload = {}; - if (typeof name !== 'undefined') { - payload['name'] = name; - } - scopes = scopes === true ? [] : scopes; - if (typeof scopes !== 'undefined') { - payload['scopes'] = scopes; - } - if (typeof expire !== 'undefined') { - payload['expire'] = expire; - } - - let response = undefined; - - response = await client.call('put', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface ProjectsDeleteKeyRequestParams { - projectId: string; - keyId: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const projectsDeleteKey = async ({projectId,keyId,parseOutput = true, overrideForCli = false, sdk = undefined}: ProjectsDeleteKeyRequestParams): Promise<any> => { - let client = !sdk ? await sdkForConsole() : - sdk; - let apiPath = '/projects/{projectId}/keys/{keyId}'.replace('{projectId}', projectId).replace('{keyId}', keyId); - let payload = {}; - - let response = undefined; - - response = await client.call('delete', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface ProjectsUpdateOAuth2RequestParams { - projectId: string; - provider: OAuthProvider; - appId?: string; - secret?: string; - enabled?: boolean; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const projectsUpdateOAuth2 = async ({projectId,provider,appId,secret,enabled,parseOutput = true, overrideForCli = false, sdk = undefined}: ProjectsUpdateOAuth2RequestParams): Promise<any> => { - let client = !sdk ? await sdkForConsole() : - sdk; - let apiPath = '/projects/{projectId}/oauth2'.replace('{projectId}', projectId); - let payload = {}; - if (typeof provider !== 'undefined') { - payload['provider'] = provider; - } - if (typeof appId !== 'undefined') { - payload['appId'] = appId; - } - if (typeof secret !== 'undefined') { - payload['secret'] = secret; - } - if (typeof enabled !== 'undefined') { - payload['enabled'] = enabled; - } - - let response = undefined; - - response = await client.call('patch', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface ProjectsListPlatformsRequestParams { - projectId: string; - total?: boolean; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; - console?: boolean; -} - -export const projectsListPlatforms = async ({projectId,total,parseOutput = true, overrideForCli = false, sdk = undefined, console: showConsole}: ProjectsListPlatformsRequestParams): Promise<any> => { - let client = !sdk ? await sdkForConsole() : - sdk; - let apiPath = '/projects/{projectId}/platforms'.replace('{projectId}', projectId); - let payload = {}; - if (typeof total !== 'undefined') { - payload['total'] = total; - } - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - if(showConsole) { - showConsoleLink('projects', 'listPlatforms', projectId); - } else { - parse(response) - } - } - - return response; - -} -interface ProjectsCreatePlatformRequestParams { - projectId: string; - type: PlatformType; - name: string; - key?: string; - store?: string; - hostname?: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const projectsCreatePlatform = async ({projectId,type,name,key,store,hostname,parseOutput = true, overrideForCli = false, sdk = undefined}: ProjectsCreatePlatformRequestParams): Promise<any> => { - let client = !sdk ? await sdkForConsole() : - sdk; - let apiPath = '/projects/{projectId}/platforms'.replace('{projectId}', projectId); - let payload = {}; - if (typeof type !== 'undefined') { - payload['type'] = type; - } - if (typeof name !== 'undefined') { - payload['name'] = name; - } - if (typeof key !== 'undefined') { - payload['key'] = key; - } - if (typeof store !== 'undefined') { - payload['store'] = store; - } - if (typeof hostname !== 'undefined') { - payload['hostname'] = hostname; - } - - let response = undefined; - - response = await client.call('post', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface ProjectsGetPlatformRequestParams { - projectId: string; - platformId: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; - console?: boolean; -} - -export const projectsGetPlatform = async ({projectId,platformId,parseOutput = true, overrideForCli = false, sdk = undefined, console: showConsole}: ProjectsGetPlatformRequestParams): Promise<any> => { - let client = !sdk ? await sdkForConsole() : - sdk; - let apiPath = '/projects/{projectId}/platforms/{platformId}'.replace('{projectId}', projectId).replace('{platformId}', platformId); - let payload = {}; - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - if(showConsole) { - showConsoleLink('projects', 'getPlatform', projectId, platformId); - } else { - parse(response) - } - } - - return response; - -} -interface ProjectsUpdatePlatformRequestParams { - projectId: string; - platformId: string; - name: string; - key?: string; - store?: string; - hostname?: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const projectsUpdatePlatform = async ({projectId,platformId,name,key,store,hostname,parseOutput = true, overrideForCli = false, sdk = undefined}: ProjectsUpdatePlatformRequestParams): Promise<any> => { - let client = !sdk ? await sdkForConsole() : - sdk; - let apiPath = '/projects/{projectId}/platforms/{platformId}'.replace('{projectId}', projectId).replace('{platformId}', platformId); - let payload = {}; - if (typeof name !== 'undefined') { - payload['name'] = name; - } - if (typeof key !== 'undefined') { - payload['key'] = key; - } - if (typeof store !== 'undefined') { - payload['store'] = store; - } - if (typeof hostname !== 'undefined') { - payload['hostname'] = hostname; - } - - let response = undefined; - - response = await client.call('put', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface ProjectsDeletePlatformRequestParams { - projectId: string; - platformId: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const projectsDeletePlatform = async ({projectId,platformId,parseOutput = true, overrideForCli = false, sdk = undefined}: ProjectsDeletePlatformRequestParams): Promise<any> => { - let client = !sdk ? await sdkForConsole() : - sdk; - let apiPath = '/projects/{projectId}/platforms/{platformId}'.replace('{projectId}', projectId).replace('{platformId}', platformId); - let payload = {}; - - let response = undefined; - - response = await client.call('delete', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface ProjectsUpdateServiceStatusRequestParams { - projectId: string; - service: ApiService; - status: boolean; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const projectsUpdateServiceStatus = async ({projectId,service,status,parseOutput = true, overrideForCli = false, sdk = undefined}: ProjectsUpdateServiceStatusRequestParams): Promise<any> => { - let client = !sdk ? await sdkForConsole() : - sdk; - let apiPath = '/projects/{projectId}/service'.replace('{projectId}', projectId); - let payload = {}; - if (typeof service !== 'undefined') { - payload['service'] = service; - } - if (typeof status !== 'undefined') { - payload['status'] = status; - } - - let response = undefined; - - response = await client.call('patch', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface ProjectsUpdateServiceStatusAllRequestParams { - projectId: string; - status: boolean; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const projectsUpdateServiceStatusAll = async ({projectId,status,parseOutput = true, overrideForCli = false, sdk = undefined}: ProjectsUpdateServiceStatusAllRequestParams): Promise<any> => { - let client = !sdk ? await sdkForConsole() : - sdk; - let apiPath = '/projects/{projectId}/service/all'.replace('{projectId}', projectId); - let payload = {}; - if (typeof status !== 'undefined') { - payload['status'] = status; - } - - let response = undefined; - - response = await client.call('patch', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface ProjectsUpdateSMTPRequestParams { - projectId: string; - enabled: boolean; - senderName?: string; - senderEmail?: string; - replyTo?: string; - host?: string; - port?: number; - username?: string; - password?: string; - secure?: SMTPSecure; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const projectsUpdateSMTP = async ({projectId,enabled,senderName,senderEmail,replyTo,host,port,username,password,secure,parseOutput = true, overrideForCli = false, sdk = undefined}: ProjectsUpdateSMTPRequestParams): Promise<any> => { - let client = !sdk ? await sdkForConsole() : - sdk; - let apiPath = '/projects/{projectId}/smtp'.replace('{projectId}', projectId); - let payload = {}; - if (typeof enabled !== 'undefined') { - payload['enabled'] = enabled; - } - if (typeof senderName !== 'undefined') { - payload['senderName'] = senderName; - } - if (typeof senderEmail !== 'undefined') { - payload['senderEmail'] = senderEmail; - } - if (typeof replyTo !== 'undefined') { - payload['replyTo'] = replyTo; - } - if (typeof host !== 'undefined') { - payload['host'] = host; - } - if (typeof port !== 'undefined') { - payload['port'] = port; - } - if (typeof username !== 'undefined') { - payload['username'] = username; - } - if (typeof password !== 'undefined') { - payload['password'] = password; - } - if (typeof secure !== 'undefined') { - payload['secure'] = secure; - } - - let response = undefined; - - response = await client.call('patch', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface ProjectsCreateSMTPTestRequestParams { - projectId: string; - emails: string[]; - senderName: string; - senderEmail: string; - host: string; - replyTo?: string; - port?: number; - username?: string; - password?: string; - secure?: SMTPSecure; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const projectsCreateSMTPTest = async ({projectId,emails,senderName,senderEmail,host,replyTo,port,username,password,secure,parseOutput = true, overrideForCli = false, sdk = undefined}: ProjectsCreateSMTPTestRequestParams): Promise<any> => { - let client = !sdk ? await sdkForConsole() : - sdk; - let apiPath = '/projects/{projectId}/smtp/tests'.replace('{projectId}', projectId); - let payload = {}; - emails = emails === true ? [] : emails; - if (typeof emails !== 'undefined') { - payload['emails'] = emails; - } - if (typeof senderName !== 'undefined') { - payload['senderName'] = senderName; - } - if (typeof senderEmail !== 'undefined') { - payload['senderEmail'] = senderEmail; - } - if (typeof replyTo !== 'undefined') { - payload['replyTo'] = replyTo; - } - if (typeof host !== 'undefined') { - payload['host'] = host; - } - if (typeof port !== 'undefined') { - payload['port'] = port; - } - if (typeof username !== 'undefined') { - payload['username'] = username; - } - if (typeof password !== 'undefined') { - payload['password'] = password; - } - if (typeof secure !== 'undefined') { - payload['secure'] = secure; - } - - let response = undefined; - - response = await client.call('post', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface ProjectsUpdateTeamRequestParams { - projectId: string; - teamId: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const projectsUpdateTeam = async ({projectId,teamId,parseOutput = true, overrideForCli = false, sdk = undefined}: ProjectsUpdateTeamRequestParams): Promise<any> => { - let client = !sdk ? await sdkForConsole() : - sdk; - let apiPath = '/projects/{projectId}/team'.replace('{projectId}', projectId); - let payload = {}; - if (typeof teamId !== 'undefined') { - payload['teamId'] = teamId; - } - - let response = undefined; - - response = await client.call('patch', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface ProjectsGetEmailTemplateRequestParams { - projectId: string; - type: EmailTemplateType; - locale: EmailTemplateLocale; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const projectsGetEmailTemplate = async ({projectId,type,locale,parseOutput = true, overrideForCli = false, sdk = undefined}: ProjectsGetEmailTemplateRequestParams): Promise<any> => { - let client = !sdk ? await sdkForConsole() : - sdk; - let apiPath = '/projects/{projectId}/templates/email/{type}/{locale}'.replace('{projectId}', projectId).replace('{type}', type).replace('{locale}', locale); - let payload = {}; - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface ProjectsUpdateEmailTemplateRequestParams { - projectId: string; - type: EmailTemplateType; - locale: EmailTemplateLocale; - subject: string; - message: string; - senderName?: string; - senderEmail?: string; - replyTo?: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const projectsUpdateEmailTemplate = async ({projectId,type,locale,subject,message,senderName,senderEmail,replyTo,parseOutput = true, overrideForCli = false, sdk = undefined}: ProjectsUpdateEmailTemplateRequestParams): Promise<any> => { - let client = !sdk ? await sdkForConsole() : - sdk; - let apiPath = '/projects/{projectId}/templates/email/{type}/{locale}'.replace('{projectId}', projectId).replace('{type}', type).replace('{locale}', locale); - let payload = {}; - if (typeof subject !== 'undefined') { - payload['subject'] = subject; - } - if (typeof message !== 'undefined') { - payload['message'] = message; - } - if (typeof senderName !== 'undefined') { - payload['senderName'] = senderName; - } - if (typeof senderEmail !== 'undefined') { - payload['senderEmail'] = senderEmail; - } - if (typeof replyTo !== 'undefined') { - payload['replyTo'] = replyTo; - } - - let response = undefined; - - response = await client.call('patch', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface ProjectsDeleteEmailTemplateRequestParams { - projectId: string; - type: EmailTemplateType; - locale: EmailTemplateLocale; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const projectsDeleteEmailTemplate = async ({projectId,type,locale,parseOutput = true, overrideForCli = false, sdk = undefined}: ProjectsDeleteEmailTemplateRequestParams): Promise<any> => { - let client = !sdk ? await sdkForConsole() : - sdk; - let apiPath = '/projects/{projectId}/templates/email/{type}/{locale}'.replace('{projectId}', projectId).replace('{type}', type).replace('{locale}', locale); - let payload = {}; - - let response = undefined; - - response = await client.call('delete', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface ProjectsGetSMSTemplateRequestParams { - projectId: string; - type: SmsTemplateType; - locale: SmsTemplateLocale; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const projectsGetSMSTemplate = async ({projectId,type,locale,parseOutput = true, overrideForCli = false, sdk = undefined}: ProjectsGetSMSTemplateRequestParams): Promise<any> => { - let client = !sdk ? await sdkForConsole() : - sdk; - let apiPath = '/projects/{projectId}/templates/sms/{type}/{locale}'.replace('{projectId}', projectId).replace('{type}', type).replace('{locale}', locale); - let payload = {}; - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface ProjectsUpdateSMSTemplateRequestParams { - projectId: string; - type: SmsTemplateType; - locale: SmsTemplateLocale; - message: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const projectsUpdateSMSTemplate = async ({projectId,type,locale,message,parseOutput = true, overrideForCli = false, sdk = undefined}: ProjectsUpdateSMSTemplateRequestParams): Promise<any> => { - let client = !sdk ? await sdkForConsole() : - sdk; - let apiPath = '/projects/{projectId}/templates/sms/{type}/{locale}'.replace('{projectId}', projectId).replace('{type}', type).replace('{locale}', locale); - let payload = {}; - if (typeof message !== 'undefined') { - payload['message'] = message; - } - - let response = undefined; - - response = await client.call('patch', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface ProjectsDeleteSMSTemplateRequestParams { - projectId: string; - type: SmsTemplateType; - locale: SmsTemplateLocale; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const projectsDeleteSMSTemplate = async ({projectId,type,locale,parseOutput = true, overrideForCli = false, sdk = undefined}: ProjectsDeleteSMSTemplateRequestParams): Promise<any> => { - let client = !sdk ? await sdkForConsole() : - sdk; - let apiPath = '/projects/{projectId}/templates/sms/{type}/{locale}'.replace('{projectId}', projectId).replace('{type}', type).replace('{locale}', locale); - let payload = {}; - - let response = undefined; - - response = await client.call('delete', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface ProjectsListWebhooksRequestParams { - projectId: string; - total?: boolean; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; - console?: boolean; -} - -export const projectsListWebhooks = async ({projectId,total,parseOutput = true, overrideForCli = false, sdk = undefined, console: showConsole}: ProjectsListWebhooksRequestParams): Promise<any> => { - let client = !sdk ? await sdkForConsole() : - sdk; - let apiPath = '/projects/{projectId}/webhooks'.replace('{projectId}', projectId); - let payload = {}; - if (typeof total !== 'undefined') { - payload['total'] = total; - } - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - if(showConsole) { - showConsoleLink('projects', 'listWebhooks', projectId); - } else { - parse(response) - } - } - - return response; - -} -interface ProjectsCreateWebhookRequestParams { - projectId: string; - name: string; - events: string[]; - url: string; - security: boolean; - enabled?: boolean; - httpUser?: string; - httpPass?: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const projectsCreateWebhook = async ({projectId,name,events,url,security,enabled,httpUser,httpPass,parseOutput = true, overrideForCli = false, sdk = undefined}: ProjectsCreateWebhookRequestParams): Promise<any> => { - let client = !sdk ? await sdkForConsole() : - sdk; - let apiPath = '/projects/{projectId}/webhooks'.replace('{projectId}', projectId); - let payload = {}; - if (typeof name !== 'undefined') { - payload['name'] = name; - } - if (typeof enabled !== 'undefined') { - payload['enabled'] = enabled; - } - events = events === true ? [] : events; - if (typeof events !== 'undefined') { - payload['events'] = events; - } - if (typeof url !== 'undefined') { - payload['url'] = url; - } - if (typeof security !== 'undefined') { - payload['security'] = security; - } - if (typeof httpUser !== 'undefined') { - payload['httpUser'] = httpUser; - } - if (typeof httpPass !== 'undefined') { - payload['httpPass'] = httpPass; - } - - let response = undefined; - - response = await client.call('post', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface ProjectsGetWebhookRequestParams { - projectId: string; - webhookId: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; - console?: boolean; -} - -export const projectsGetWebhook = async ({projectId,webhookId,parseOutput = true, overrideForCli = false, sdk = undefined, console: showConsole}: ProjectsGetWebhookRequestParams): Promise<any> => { - let client = !sdk ? await sdkForConsole() : - sdk; - let apiPath = '/projects/{projectId}/webhooks/{webhookId}'.replace('{projectId}', projectId).replace('{webhookId}', webhookId); - let payload = {}; - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - if(showConsole) { - showConsoleLink('projects', 'getWebhook', projectId, webhookId); - } else { - parse(response) - } - } - - return response; - -} -interface ProjectsUpdateWebhookRequestParams { - projectId: string; - webhookId: string; - name: string; - events: string[]; - url: string; - security: boolean; - enabled?: boolean; - httpUser?: string; - httpPass?: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const projectsUpdateWebhook = async ({projectId,webhookId,name,events,url,security,enabled,httpUser,httpPass,parseOutput = true, overrideForCli = false, sdk = undefined}: ProjectsUpdateWebhookRequestParams): Promise<any> => { - let client = !sdk ? await sdkForConsole() : - sdk; - let apiPath = '/projects/{projectId}/webhooks/{webhookId}'.replace('{projectId}', projectId).replace('{webhookId}', webhookId); - let payload = {}; - if (typeof name !== 'undefined') { - payload['name'] = name; - } - if (typeof enabled !== 'undefined') { - payload['enabled'] = enabled; - } - events = events === true ? [] : events; - if (typeof events !== 'undefined') { - payload['events'] = events; - } - if (typeof url !== 'undefined') { - payload['url'] = url; - } - if (typeof security !== 'undefined') { - payload['security'] = security; - } - if (typeof httpUser !== 'undefined') { - payload['httpUser'] = httpUser; - } - if (typeof httpPass !== 'undefined') { - payload['httpPass'] = httpPass; - } - - let response = undefined; - - response = await client.call('put', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface ProjectsDeleteWebhookRequestParams { - projectId: string; - webhookId: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const projectsDeleteWebhook = async ({projectId,webhookId,parseOutput = true, overrideForCli = false, sdk = undefined}: ProjectsDeleteWebhookRequestParams): Promise<any> => { - let client = !sdk ? await sdkForConsole() : - sdk; - let apiPath = '/projects/{projectId}/webhooks/{webhookId}'.replace('{projectId}', projectId).replace('{webhookId}', webhookId); - let payload = {}; - - let response = undefined; - - response = await client.call('delete', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface ProjectsUpdateWebhookSignatureRequestParams { - projectId: string; - webhookId: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const projectsUpdateWebhookSignature = async ({projectId,webhookId,parseOutput = true, overrideForCli = false, sdk = undefined}: ProjectsUpdateWebhookSignatureRequestParams): Promise<any> => { - let client = !sdk ? await sdkForConsole() : - sdk; - let apiPath = '/projects/{projectId}/webhooks/{webhookId}/signature'.replace('{projectId}', projectId).replace('{webhookId}', webhookId); - let payload = {}; - - let response = undefined; - - response = await client.call('patch', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -projects - .command(`list`) - .description(`Get a list of all projects. You can use the query params to filter your results. `) - .option(`--queries [queries...]`, `Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: name, teamId`) - .option(`--search <search>`, `Search term to filter your list results. Max length: 256 chars.`) - .option(`--total [value]`, `When set to false, the total count returned will be 0 and will not be calculated.`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .option(`--console`, `Get the resource console url`) - .action(actionRunner(projectsList)) - -projects - .command(`create`) - .description(`Create a new project. You can create a maximum of 100 projects per account. `) - .requiredOption(`--project-id <project-id>`, `Unique Id. Choose a custom ID or generate a random ID with 'ID.unique()'. Valid chars are a-z, and hyphen. Can't start with a special char. Max length is 36 chars.`) - .requiredOption(`--name <name>`, `Project name. Max length: 128 chars.`) - .requiredOption(`--team-id <team-id>`, `Team unique ID.`) - .option(`--region <region>`, `Project Region.`) - .option(`--description <description>`, `Project description. Max length: 256 chars.`) - .option(`--logo <logo>`, `Project logo.`) - .option(`--url <url>`, `Project URL.`) - .option(`--legal-name <legal-name>`, `Project legal Name. Max length: 256 chars.`) - .option(`--legal-country <legal-country>`, `Project legal Country. Max length: 256 chars.`) - .option(`--legal-state <legal-state>`, `Project legal State. Max length: 256 chars.`) - .option(`--legal-city <legal-city>`, `Project legal City. Max length: 256 chars.`) - .option(`--legal-address <legal-address>`, `Project legal Address. Max length: 256 chars.`) - .option(`--legal-tax-id <legal-tax-id>`, `Project legal Tax ID. Max length: 256 chars.`) - .action(actionRunner(projectsCreate)) - -projects - .command(`get`) - .description(`Get a project by its unique ID. This endpoint allows you to retrieve the project's details, including its name, description, team, region, and other metadata. `) - .requiredOption(`--project-id <project-id>`, `Project unique ID.`) - .option(`--console`, `Get the resource console url`) - .action(actionRunner(projectsGet)) - -projects - .command(`update`) - .description(`Update a project by its unique ID.`) - .requiredOption(`--project-id <project-id>`, `Project unique ID.`) - .requiredOption(`--name <name>`, `Project name. Max length: 128 chars.`) - .option(`--description <description>`, `Project description. Max length: 256 chars.`) - .option(`--logo <logo>`, `Project logo.`) - .option(`--url <url>`, `Project URL.`) - .option(`--legal-name <legal-name>`, `Project legal name. Max length: 256 chars.`) - .option(`--legal-country <legal-country>`, `Project legal country. Max length: 256 chars.`) - .option(`--legal-state <legal-state>`, `Project legal state. Max length: 256 chars.`) - .option(`--legal-city <legal-city>`, `Project legal city. Max length: 256 chars.`) - .option(`--legal-address <legal-address>`, `Project legal address. Max length: 256 chars.`) - .option(`--legal-tax-id <legal-tax-id>`, `Project legal tax ID. Max length: 256 chars.`) - .action(actionRunner(projectsUpdate)) - -projects - .command(`delete`) - .description(`Delete a project by its unique ID.`) - .requiredOption(`--project-id <project-id>`, `Project unique ID.`) - .action(actionRunner(projectsDelete)) - -projects - .command(`update-api-status`) - .description(`Update the status of a specific API type. Use this endpoint to enable or disable API types such as REST, GraphQL and Realtime.`) - .requiredOption(`--project-id <project-id>`, `Project unique ID.`) - .requiredOption(`--api <api>`, `API name.`) - .requiredOption(`--status [value]`, `API status.`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .action(actionRunner(projectsUpdateAPIStatus)) - -projects - .command(`update-api-status-all`) - .description(`Update the status of all API types. Use this endpoint to enable or disable API types such as REST, GraphQL and Realtime all at once.`) - .requiredOption(`--project-id <project-id>`, `Project unique ID.`) - .requiredOption(`--status [value]`, `API status.`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .action(actionRunner(projectsUpdateAPIStatusAll)) - -projects - .command(`update-auth-duration`) - .description(`Update how long sessions created within a project should stay active for.`) - .requiredOption(`--project-id <project-id>`, `Project unique ID.`) - .requiredOption(`--duration <duration>`, `Project session length in seconds. Max length: 31536000 seconds.`, parseInteger) - .action(actionRunner(projectsUpdateAuthDuration)) - -projects - .command(`update-auth-limit`) - .description(`Update the maximum number of users allowed in this project. Set to 0 for unlimited users. `) - .requiredOption(`--project-id <project-id>`, `Project unique ID.`) - .requiredOption(`--limit <limit>`, `Set the max number of users allowed in this project. Use 0 for unlimited.`, parseInteger) - .action(actionRunner(projectsUpdateAuthLimit)) - -projects - .command(`update-auth-sessions-limit`) - .description(`Update the maximum number of sessions allowed per user within the project, if the limit is hit the oldest session will be deleted to make room for new sessions.`) - .requiredOption(`--project-id <project-id>`, `Project unique ID.`) - .requiredOption(`--limit <limit>`, `Set the max number of users allowed in this project. Value allowed is between 1-100. Default is 10`, parseInteger) - .action(actionRunner(projectsUpdateAuthSessionsLimit)) - -projects - .command(`update-memberships-privacy`) - .description(`Update project membership privacy settings. Use this endpoint to control what user information is visible to other team members, such as user name, email, and MFA status. `) - .requiredOption(`--project-id <project-id>`, `Project unique ID.`) - .requiredOption(`--user-name [value]`, `Set to true to show userName to members of a team.`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .requiredOption(`--user-email [value]`, `Set to true to show email to members of a team.`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .requiredOption(`--mfa [value]`, `Set to true to show mfa to members of a team.`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .action(actionRunner(projectsUpdateMembershipsPrivacy)) - -projects - .command(`update-mock-numbers`) - .description(`Update the list of mock phone numbers for testing. Use these numbers to bypass SMS verification in development. `) - .requiredOption(`--project-id <project-id>`, `Project unique ID.`) - .requiredOption(`--numbers [numbers...]`, `An array of mock numbers and their corresponding verification codes (OTPs). Each number should be a valid E.164 formatted phone number. Maximum of 10 numbers are allowed.`) - .action(actionRunner(projectsUpdateMockNumbers)) - -projects - .command(`update-auth-password-dictionary`) - .description(`Enable or disable checking user passwords against common passwords dictionary. This helps ensure users don't use common and insecure passwords. `) - .requiredOption(`--project-id <project-id>`, `Project unique ID.`) - .requiredOption(`--enabled [value]`, `Set whether or not to enable checking user's password against most commonly used passwords. Default is false.`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .action(actionRunner(projectsUpdateAuthPasswordDictionary)) - -projects - .command(`update-auth-password-history`) - .description(`Update the authentication password history requirement. Use this endpoint to require new passwords to be different than the last X amount of previously used ones.`) - .requiredOption(`--project-id <project-id>`, `Project unique ID.`) - .requiredOption(`--limit <limit>`, `Set the max number of passwords to store in user history. User can't choose a new password that is already stored in the password history list. Max number of passwords allowed in history is20. Default value is 0`, parseInteger) - .action(actionRunner(projectsUpdateAuthPasswordHistory)) - -projects - .command(`update-personal-data-check`) - .description(`Enable or disable checking user passwords against their personal data. This helps prevent users from using personal information in their passwords. `) - .requiredOption(`--project-id <project-id>`, `Project unique ID.`) - .requiredOption(`--enabled [value]`, `Set whether or not to check a password for similarity with personal data. Default is false.`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .action(actionRunner(projectsUpdatePersonalDataCheck)) - -projects - .command(`update-session-alerts`) - .description(`Enable or disable session email alerts. When enabled, users will receive email notifications when new sessions are created.`) - .requiredOption(`--project-id <project-id>`, `Project unique ID.`) - .requiredOption(`--alerts [value]`, `Set to true to enable session emails.`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .action(actionRunner(projectsUpdateSessionAlerts)) - -projects - .command(`update-session-invalidation`) - .description(`Invalidate all existing sessions. An optional auth security setting for projects, and enabled by default for console project.`) - .requiredOption(`--project-id <project-id>`, `Project unique ID.`) - .requiredOption(`--enabled [value]`, `Update authentication session invalidation status. Use this endpoint to enable or disable session invalidation on password change`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .action(actionRunner(projectsUpdateSessionInvalidation)) - -projects - .command(`update-auth-status`) - .description(`Update the status of a specific authentication method. Use this endpoint to enable or disable different authentication methods such as email, magic urls or sms in your project. `) - .requiredOption(`--project-id <project-id>`, `Project unique ID.`) - .requiredOption(`--method <method>`, `Auth Method. Possible values: email-password,magic-url,email-otp,anonymous,invites,jwt,phone`) - .requiredOption(`--status [value]`, `Set the status of this auth method.`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .action(actionRunner(projectsUpdateAuthStatus)) - -projects - .command(`list-dev-keys`) - .description(`List all the project\'s dev keys. Dev keys are project specific and allow you to bypass rate limits and get better error logging during development.'`) - .requiredOption(`--project-id <project-id>`, `Project unique ID.`) - .option(`--queries [queries...]`, `Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: accessedAt, expire`) - .option(`--console`, `Get the resource console url`) - .action(actionRunner(projectsListDevKeys)) - -projects - .command(`create-dev-key`) - .description(`Create a new project dev key. Dev keys are project specific and allow you to bypass rate limits and get better error logging during development. Strictly meant for development purposes only.`) - .requiredOption(`--project-id <project-id>`, `Project unique ID.`) - .requiredOption(`--name <name>`, `Key name. Max length: 128 chars.`) - .requiredOption(`--expire <expire>`, `Expiration time in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format.`) - .action(actionRunner(projectsCreateDevKey)) - -projects - .command(`get-dev-key`) - .description(`Get a project\'s dev key by its unique ID. Dev keys are project specific and allow you to bypass rate limits and get better error logging during development.`) - .requiredOption(`--project-id <project-id>`, `Project unique ID.`) - .requiredOption(`--key-id <key-id>`, `Key unique ID.`) - .option(`--console`, `Get the resource console url`) - .action(actionRunner(projectsGetDevKey)) - -projects - .command(`update-dev-key`) - .description(`Update a project\'s dev key by its unique ID. Use this endpoint to update a project\'s dev key name or expiration time.'`) - .requiredOption(`--project-id <project-id>`, `Project unique ID.`) - .requiredOption(`--key-id <key-id>`, `Key unique ID.`) - .requiredOption(`--name <name>`, `Key name. Max length: 128 chars.`) - .requiredOption(`--expire <expire>`, `Expiration time in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format.`) - .action(actionRunner(projectsUpdateDevKey)) - -projects - .command(`delete-dev-key`) - .description(`Delete a project\'s dev key by its unique ID. Once deleted, the key will no longer allow bypassing of rate limits and better logging of errors.`) - .requiredOption(`--project-id <project-id>`, `Project unique ID.`) - .requiredOption(`--key-id <key-id>`, `Key unique ID.`) - .action(actionRunner(projectsDeleteDevKey)) - -projects - .command(`create-jwt`) - .description(`Create a new JWT token. This token can be used to authenticate users with custom scopes and expiration time. `) - .requiredOption(`--project-id <project-id>`, `Project unique ID.`) - .requiredOption(`--scopes [scopes...]`, `List of scopes allowed for JWT key. Maximum of 100 scopes are allowed.`) - .option(`--duration <duration>`, `Time in seconds before JWT expires. Default duration is 900 seconds, and maximum is 3600 seconds.`, parseInteger) - .action(actionRunner(projectsCreateJWT)) - -projects - .command(`list-keys`) - .description(`Get a list of all API keys from the current project. `) - .requiredOption(`--project-id <project-id>`, `Project unique ID.`) - .option(`--total [value]`, `When set to false, the total count returned will be 0 and will not be calculated.`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .option(`--console`, `Get the resource console url`) - .action(actionRunner(projectsListKeys)) - -projects - .command(`create-key`) - .description(`Create a new API key. It's recommended to have multiple API keys with strict scopes for separate functions within your project.`) - .requiredOption(`--project-id <project-id>`, `Project unique ID.`) - .requiredOption(`--name <name>`, `Key name. Max length: 128 chars.`) - .option(`--scopes [scopes...]`, `Key scopes list. Maximum of 100 scopes are allowed.`) - .option(`--expire <expire>`, `Expiration time in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format. Use null for unlimited expiration.`) - .action(actionRunner(projectsCreateKey)) - -projects - .command(`get-key`) - .description(`Get a key by its unique ID. This endpoint returns details about a specific API key in your project including it's scopes.`) - .requiredOption(`--project-id <project-id>`, `Project unique ID.`) - .requiredOption(`--key-id <key-id>`, `Key unique ID.`) - .option(`--console`, `Get the resource console url`) - .action(actionRunner(projectsGetKey)) - -projects - .command(`update-key`) - .description(`Update a key by its unique ID. Use this endpoint to update the name, scopes, or expiration time of an API key. `) - .requiredOption(`--project-id <project-id>`, `Project unique ID.`) - .requiredOption(`--key-id <key-id>`, `Key unique ID.`) - .requiredOption(`--name <name>`, `Key name. Max length: 128 chars.`) - .option(`--scopes [scopes...]`, `Key scopes list. Maximum of 100 events are allowed.`) - .option(`--expire <expire>`, `Expiration time in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format. Use null for unlimited expiration.`) - .action(actionRunner(projectsUpdateKey)) - -projects - .command(`delete-key`) - .description(`Delete a key by its unique ID. Once deleted, the key can no longer be used to authenticate API calls. `) - .requiredOption(`--project-id <project-id>`, `Project unique ID.`) - .requiredOption(`--key-id <key-id>`, `Key unique ID.`) - .action(actionRunner(projectsDeleteKey)) - -projects - .command(`update-o-auth-2`) - .description(`Update the OAuth2 provider configurations. Use this endpoint to set up or update the OAuth2 provider credentials or enable/disable providers. `) - .requiredOption(`--project-id <project-id>`, `Project unique ID.`) - .requiredOption(`--provider <provider>`, `Provider Name`) - .option(`--app-id <app-id>`, `Provider app ID. Max length: 256 chars.`) - .option(`--secret <secret>`, `Provider secret key. Max length: 512 chars.`) - .option(`--enabled [value]`, `Provider status. Set to 'false' to disable new session creation.`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .action(actionRunner(projectsUpdateOAuth2)) - -projects - .command(`list-platforms`) - .description(`Get a list of all platforms in the project. This endpoint returns an array of all platforms and their configurations. `) - .requiredOption(`--project-id <project-id>`, `Project unique ID.`) - .option(`--total [value]`, `When set to false, the total count returned will be 0 and will not be calculated.`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .option(`--console`, `Get the resource console url`) - .action(actionRunner(projectsListPlatforms)) - -projects - .command(`create-platform`) - .description(`Create a new platform for your project. Use this endpoint to register a new platform where your users will run your application which will interact with the Appwrite API.`) - .requiredOption(`--project-id <project-id>`, `Project unique ID.`) - .requiredOption(`--type <type>`, `Platform type. Possible values are: web, flutter-web, flutter-ios, flutter-android, flutter-linux, flutter-macos, flutter-windows, apple-ios, apple-macos, apple-watchos, apple-tvos, android, unity, react-native-ios, react-native-android.`) - .requiredOption(`--name <name>`, `Platform name. Max length: 128 chars.`) - .option(`--key <key>`, `Package name for Android or bundle ID for iOS or macOS. Max length: 256 chars.`) - .option(`--store <store>`, `App store or Google Play store ID. Max length: 256 chars.`) - .option(`--hostname <hostname>`, `Platform client hostname. Max length: 256 chars.`) - .action(actionRunner(projectsCreatePlatform)) - -projects - .command(`get-platform`) - .description(`Get a platform by its unique ID. This endpoint returns the platform's details, including its name, type, and key configurations. `) - .requiredOption(`--project-id <project-id>`, `Project unique ID.`) - .requiredOption(`--platform-id <platform-id>`, `Platform unique ID.`) - .option(`--console`, `Get the resource console url`) - .action(actionRunner(projectsGetPlatform)) - -projects - .command(`update-platform`) - .description(`Update a platform by its unique ID. Use this endpoint to update the platform's name, key, platform store ID, or hostname. `) - .requiredOption(`--project-id <project-id>`, `Project unique ID.`) - .requiredOption(`--platform-id <platform-id>`, `Platform unique ID.`) - .requiredOption(`--name <name>`, `Platform name. Max length: 128 chars.`) - .option(`--key <key>`, `Package name for android or bundle ID for iOS. Max length: 256 chars.`) - .option(`--store <store>`, `App store or Google Play store ID. Max length: 256 chars.`) - .option(`--hostname <hostname>`, `Platform client URL. Max length: 256 chars.`) - .action(actionRunner(projectsUpdatePlatform)) - -projects - .command(`delete-platform`) - .description(`Delete a platform by its unique ID. This endpoint removes the platform and all its configurations from the project. `) - .requiredOption(`--project-id <project-id>`, `Project unique ID.`) - .requiredOption(`--platform-id <platform-id>`, `Platform unique ID.`) - .action(actionRunner(projectsDeletePlatform)) - -projects - .command(`update-service-status`) - .description(`Update the status of a specific service. Use this endpoint to enable or disable a service in your project. `) - .requiredOption(`--project-id <project-id>`, `Project unique ID.`) - .requiredOption(`--service <service>`, `Service name.`) - .requiredOption(`--status [value]`, `Service status.`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .action(actionRunner(projectsUpdateServiceStatus)) - -projects - .command(`update-service-status-all`) - .description(`Update the status of all services. Use this endpoint to enable or disable all optional services at once. `) - .requiredOption(`--project-id <project-id>`, `Project unique ID.`) - .requiredOption(`--status [value]`, `Service status.`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .action(actionRunner(projectsUpdateServiceStatusAll)) - -projects - .command(`update-smtp`) - .description(`Update the SMTP configuration for your project. Use this endpoint to configure your project's SMTP provider with your custom settings for sending transactional emails. `) - .requiredOption(`--project-id <project-id>`, `Project unique ID.`) - .requiredOption(`--enabled [value]`, `Enable custom SMTP service`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .option(`--sender-name <sender-name>`, `Name of the email sender`) - .option(`--sender-email <sender-email>`, `Email of the sender`) - .option(`--reply-to <reply-to>`, `Reply to email`) - .option(`--host <host>`, `SMTP server host name`) - .option(`--port <port>`, `SMTP server port`, parseInteger) - .option(`--username <username>`, `SMTP server username`) - .option(`--password <password>`, `SMTP server password`) - .option(`--secure <secure>`, `Does SMTP server use secure connection`) - .action(actionRunner(projectsUpdateSMTP)) - -projects - .command(`create-smtp-test`) - .description(`Send a test email to verify SMTP configuration. `) - .requiredOption(`--project-id <project-id>`, `Project unique ID.`) - .requiredOption(`--emails [emails...]`, `Array of emails to send test email to. Maximum of 10 emails are allowed.`) - .requiredOption(`--sender-name <sender-name>`, `Name of the email sender`) - .requiredOption(`--sender-email <sender-email>`, `Email of the sender`) - .requiredOption(`--host <host>`, `SMTP server host name`) - .option(`--reply-to <reply-to>`, `Reply to email`) - .option(`--port <port>`, `SMTP server port`, parseInteger) - .option(`--username <username>`, `SMTP server username`) - .option(`--password <password>`, `SMTP server password`) - .option(`--secure <secure>`, `Does SMTP server use secure connection`) - .action(actionRunner(projectsCreateSMTPTest)) - -projects - .command(`update-team`) - .description(`Update the team ID of a project allowing for it to be transferred to another team.`) - .requiredOption(`--project-id <project-id>`, `Project unique ID.`) - .requiredOption(`--team-id <team-id>`, `Team ID of the team to transfer project to.`) - .action(actionRunner(projectsUpdateTeam)) - -projects - .command(`get-email-template`) - .description(`Get a custom email template for the specified locale and type. This endpoint returns the template content, subject, and other configuration details. `) - .requiredOption(`--project-id <project-id>`, `Project unique ID.`) - .requiredOption(`--type <type>`, `Template type`) - .requiredOption(`--locale <locale>`, `Template locale`) - .action(actionRunner(projectsGetEmailTemplate)) - -projects - .command(`update-email-template`) - .description(`Update a custom email template for the specified locale and type. Use this endpoint to modify the content of your email templates.`) - .requiredOption(`--project-id <project-id>`, `Project unique ID.`) - .requiredOption(`--type <type>`, `Template type`) - .requiredOption(`--locale <locale>`, `Template locale`) - .requiredOption(`--subject <subject>`, `Email Subject`) - .requiredOption(`--message <message>`, `Template message`) - .option(`--sender-name <sender-name>`, `Name of the email sender`) - .option(`--sender-email <sender-email>`, `Email of the sender`) - .option(`--reply-to <reply-to>`, `Reply to email`) - .action(actionRunner(projectsUpdateEmailTemplate)) - -projects - .command(`delete-email-template`) - .description(`Reset a custom email template to its default value. This endpoint removes any custom content and restores the template to its original state. `) - .requiredOption(`--project-id <project-id>`, `Project unique ID.`) - .requiredOption(`--type <type>`, `Template type`) - .requiredOption(`--locale <locale>`, `Template locale`) - .action(actionRunner(projectsDeleteEmailTemplate)) - -projects - .command(`get-sms-template`) - .description(`Get a custom SMS template for the specified locale and type returning it's contents.`) - .requiredOption(`--project-id <project-id>`, `Project unique ID.`) - .requiredOption(`--type <type>`, `Template type`) - .requiredOption(`--locale <locale>`, `Template locale`) - .action(actionRunner(projectsGetSMSTemplate)) - -projects - .command(`update-sms-template`) - .description(`Update a custom SMS template for the specified locale and type. Use this endpoint to modify the content of your SMS templates. `) - .requiredOption(`--project-id <project-id>`, `Project unique ID.`) - .requiredOption(`--type <type>`, `Template type`) - .requiredOption(`--locale <locale>`, `Template locale`) - .requiredOption(`--message <message>`, `Template message`) - .action(actionRunner(projectsUpdateSMSTemplate)) - -projects - .command(`delete-sms-template`) - .description(`Reset a custom SMS template to its default value. This endpoint removes any custom message and restores the template to its original state. `) - .requiredOption(`--project-id <project-id>`, `Project unique ID.`) - .requiredOption(`--type <type>`, `Template type`) - .requiredOption(`--locale <locale>`, `Template locale`) - .action(actionRunner(projectsDeleteSMSTemplate)) - -projects - .command(`list-webhooks`) - .description(`Get a list of all webhooks belonging to the project. You can use the query params to filter your results. `) - .requiredOption(`--project-id <project-id>`, `Project unique ID.`) - .option(`--total [value]`, `When set to false, the total count returned will be 0 and will not be calculated.`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .option(`--console`, `Get the resource console url`) - .action(actionRunner(projectsListWebhooks)) - -projects - .command(`create-webhook`) - .description(`Create a new webhook. Use this endpoint to configure a URL that will receive events from Appwrite when specific events occur. `) - .requiredOption(`--project-id <project-id>`, `Project unique ID.`) - .requiredOption(`--name <name>`, `Webhook name. Max length: 128 chars.`) - .requiredOption(`--events [events...]`, `Events list. Maximum of 100 events are allowed.`) - .requiredOption(`--url <url>`, `Webhook URL.`) - .requiredOption(`--security [value]`, `Certificate verification, false for disabled or true for enabled.`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .option(`--enabled [value]`, `Enable or disable a webhook.`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .option(`--http-user <http-user>`, `Webhook HTTP user. Max length: 256 chars.`) - .option(`--http-pass <http-pass>`, `Webhook HTTP password. Max length: 256 chars.`) - .action(actionRunner(projectsCreateWebhook)) - -projects - .command(`get-webhook`) - .description(`Get a webhook by its unique ID. This endpoint returns details about a specific webhook configured for a project. `) - .requiredOption(`--project-id <project-id>`, `Project unique ID.`) - .requiredOption(`--webhook-id <webhook-id>`, `Webhook unique ID.`) - .option(`--console`, `Get the resource console url`) - .action(actionRunner(projectsGetWebhook)) - -projects - .command(`update-webhook`) - .description(`Update a webhook by its unique ID. Use this endpoint to update the URL, events, or status of an existing webhook. `) - .requiredOption(`--project-id <project-id>`, `Project unique ID.`) - .requiredOption(`--webhook-id <webhook-id>`, `Webhook unique ID.`) - .requiredOption(`--name <name>`, `Webhook name. Max length: 128 chars.`) - .requiredOption(`--events [events...]`, `Events list. Maximum of 100 events are allowed.`) - .requiredOption(`--url <url>`, `Webhook URL.`) - .requiredOption(`--security [value]`, `Certificate verification, false for disabled or true for enabled.`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .option(`--enabled [value]`, `Enable or disable a webhook.`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .option(`--http-user <http-user>`, `Webhook HTTP user. Max length: 256 chars.`) - .option(`--http-pass <http-pass>`, `Webhook HTTP password. Max length: 256 chars.`) - .action(actionRunner(projectsUpdateWebhook)) - -projects - .command(`delete-webhook`) - .description(`Delete a webhook by its unique ID. Once deleted, the webhook will no longer receive project events. `) - .requiredOption(`--project-id <project-id>`, `Project unique ID.`) - .requiredOption(`--webhook-id <webhook-id>`, `Webhook unique ID.`) - .action(actionRunner(projectsDeleteWebhook)) - -projects - .command(`update-webhook-signature`) - .description(`Update the webhook signature key. This endpoint can be used to regenerate the signature key used to sign and validate payload deliveries for a specific webhook. `) - .requiredOption(`--project-id <project-id>`, `Project unique ID.`) - .requiredOption(`--webhook-id <webhook-id>`, `Webhook unique ID.`) - .action(actionRunner(projectsUpdateWebhookSignature)) - - diff --git a/lib/commands/proxy.ts b/lib/commands/proxy.ts deleted file mode 100644 index fb48eaf0..00000000 --- a/lib/commands/proxy.ts +++ /dev/null @@ -1,357 +0,0 @@ -import fs = require('fs'); -import pathLib = require('path'); -import tar = require('tar'); -import ignore = require('ignore'); -import { promisify } from 'util'; -import Client from '../client'; -import { getAllFiles, showConsoleLink } from '../utils'; -import { Command } from 'commander'; -import { sdkForProject, sdkForConsole } from '../sdks'; -import { parse, actionRunner, parseInteger, parseBool, commandDescriptions, success, log, warn } from '../parser'; -import { localConfig, globalConfig } from '../config'; -import { File } from 'undici'; -import { ReadableStream } from 'stream/web'; - -function convertReadStreamToReadableStream(readStream: fs.ReadStream): ReadableStream { - return new ReadableStream({ - start(controller) { - readStream.on("data", (chunk: Buffer) => { - controller.enqueue(chunk); - }); - readStream.on("end", () => { - controller.close(); - }); - readStream.on("error", (err: Error) => { - controller.error(err); - }); - }, - cancel() { - readStream.destroy(); - }, - }); -} - -export const proxy = new Command("proxy").description(commandDescriptions['proxy'] ?? '').configureHelp({ - helpWidth: process.stdout.columns || 80 -}) - -interface ProxyListRulesRequestParams { - queries?: string[]; - search?: string; - total?: boolean; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const proxyListRules = async ({queries,search,total,parseOutput = true, overrideForCli = false, sdk = undefined}: ProxyListRulesRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/proxy/rules'; - let payload = {}; - if (typeof queries !== 'undefined') { - payload['queries'] = queries; - } - if (typeof search !== 'undefined') { - payload['search'] = search; - } - if (typeof total !== 'undefined') { - payload['total'] = total; - } - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface ProxyCreateAPIRuleRequestParams { - domain: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const proxyCreateAPIRule = async ({domain,parseOutput = true, overrideForCli = false, sdk = undefined}: ProxyCreateAPIRuleRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/proxy/rules/api'; - let payload = {}; - if (typeof domain !== 'undefined') { - payload['domain'] = domain; - } - - let response = undefined; - - response = await client.call('post', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface ProxyCreateFunctionRuleRequestParams { - domain: string; - functionId: string; - branch?: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const proxyCreateFunctionRule = async ({domain,functionId,branch,parseOutput = true, overrideForCli = false, sdk = undefined}: ProxyCreateFunctionRuleRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/proxy/rules/function'; - let payload = {}; - if (typeof domain !== 'undefined') { - payload['domain'] = domain; - } - if (typeof functionId !== 'undefined') { - payload['functionId'] = functionId; - } - if (typeof branch !== 'undefined') { - payload['branch'] = branch; - } - - let response = undefined; - - response = await client.call('post', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface ProxyCreateRedirectRuleRequestParams { - domain: string; - url: string; - statusCode: StatusCode; - resourceId: string; - resourceType: ProxyResourceType; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const proxyCreateRedirectRule = async ({domain,url,statusCode,resourceId,resourceType,parseOutput = true, overrideForCli = false, sdk = undefined}: ProxyCreateRedirectRuleRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/proxy/rules/redirect'; - let payload = {}; - if (typeof domain !== 'undefined') { - payload['domain'] = domain; - } - if (typeof url !== 'undefined') { - payload['url'] = url; - } - if (typeof statusCode !== 'undefined') { - payload['statusCode'] = statusCode; - } - if (typeof resourceId !== 'undefined') { - payload['resourceId'] = resourceId; - } - if (typeof resourceType !== 'undefined') { - payload['resourceType'] = resourceType; - } - - let response = undefined; - - response = await client.call('post', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface ProxyCreateSiteRuleRequestParams { - domain: string; - siteId: string; - branch?: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const proxyCreateSiteRule = async ({domain,siteId,branch,parseOutput = true, overrideForCli = false, sdk = undefined}: ProxyCreateSiteRuleRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/proxy/rules/site'; - let payload = {}; - if (typeof domain !== 'undefined') { - payload['domain'] = domain; - } - if (typeof siteId !== 'undefined') { - payload['siteId'] = siteId; - } - if (typeof branch !== 'undefined') { - payload['branch'] = branch; - } - - let response = undefined; - - response = await client.call('post', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface ProxyGetRuleRequestParams { - ruleId: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const proxyGetRule = async ({ruleId,parseOutput = true, overrideForCli = false, sdk = undefined}: ProxyGetRuleRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/proxy/rules/{ruleId}'.replace('{ruleId}', ruleId); - let payload = {}; - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface ProxyDeleteRuleRequestParams { - ruleId: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const proxyDeleteRule = async ({ruleId,parseOutput = true, overrideForCli = false, sdk = undefined}: ProxyDeleteRuleRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/proxy/rules/{ruleId}'.replace('{ruleId}', ruleId); - let payload = {}; - - let response = undefined; - - response = await client.call('delete', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface ProxyUpdateRuleVerificationRequestParams { - ruleId: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const proxyUpdateRuleVerification = async ({ruleId,parseOutput = true, overrideForCli = false, sdk = undefined}: ProxyUpdateRuleVerificationRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/proxy/rules/{ruleId}/verification'.replace('{ruleId}', ruleId); - let payload = {}; - - let response = undefined; - - response = await client.call('patch', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -proxy - .command(`list-rules`) - .description(`Get a list of all the proxy rules. You can use the query params to filter your results.`) - .option(`--queries [queries...]`, `Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/databases#querying-documents). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: domain, type, trigger, deploymentResourceType, deploymentResourceId, deploymentId, deploymentVcsProviderBranch`) - .option(`--search <search>`, `Search term to filter your list results. Max length: 256 chars.`) - .option(`--total [value]`, `When set to false, the total count returned will be 0 and will not be calculated.`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .action(actionRunner(proxyListRules)) - -proxy - .command(`create-api-rule`) - .description(`Create a new proxy rule for serving Appwrite's API on custom domain.`) - .requiredOption(`--domain <domain>`, `Domain name.`) - .action(actionRunner(proxyCreateAPIRule)) - -proxy - .command(`create-function-rule`) - .description(`Create a new proxy rule for executing Appwrite Function on custom domain.`) - .requiredOption(`--domain <domain>`, `Domain name.`) - .requiredOption(`--function-id <function-id>`, `ID of function to be executed.`) - .option(`--branch <branch>`, `Name of VCS branch to deploy changes automatically`) - .action(actionRunner(proxyCreateFunctionRule)) - -proxy - .command(`create-redirect-rule`) - .description(`Create a new proxy rule for to redirect from custom domain to another domain.`) - .requiredOption(`--domain <domain>`, `Domain name.`) - .requiredOption(`--url <url>`, `Target URL of redirection`) - .requiredOption(`--status-code <status-code>`, `Status code of redirection`) - .requiredOption(`--resource-id <resource-id>`, `ID of parent resource.`) - .requiredOption(`--resource-type <resource-type>`, `Type of parent resource.`) - .action(actionRunner(proxyCreateRedirectRule)) - -proxy - .command(`create-site-rule`) - .description(`Create a new proxy rule for serving Appwrite Site on custom domain.`) - .requiredOption(`--domain <domain>`, `Domain name.`) - .requiredOption(`--site-id <site-id>`, `ID of site to be executed.`) - .option(`--branch <branch>`, `Name of VCS branch to deploy changes automatically`) - .action(actionRunner(proxyCreateSiteRule)) - -proxy - .command(`get-rule`) - .description(`Get a proxy rule by its unique ID.`) - .requiredOption(`--rule-id <rule-id>`, `Rule ID.`) - .action(actionRunner(proxyGetRule)) - -proxy - .command(`delete-rule`) - .description(`Delete a proxy rule by its unique ID.`) - .requiredOption(`--rule-id <rule-id>`, `Rule ID.`) - .action(actionRunner(proxyDeleteRule)) - -proxy - .command(`update-rule-verification`) - .description(`Retry getting verification process of a proxy rule. This endpoint triggers domain verification by checking DNS records (CNAME) against the configured target domain. If verification is successful, a TLS certificate will be automatically provisioned for the domain.`) - .requiredOption(`--rule-id <rule-id>`, `Rule ID.`) - .action(actionRunner(proxyUpdateRuleVerification)) - - diff --git a/lib/commands/pull.ts b/lib/commands/pull.ts index 3c306cc5..ccf60cec 100644 --- a/lib/commands/pull.ts +++ b/lib/commands/pull.ts @@ -1,557 +1,668 @@ -import fs = require('fs'); -import chalk from 'chalk'; -import tar = require('tar'); -import { Command } from 'commander'; -import inquirer from 'inquirer'; -import { messagingListTopics } from './messaging'; -import { teamsList } from './teams'; -import { projectsGet } from './projects'; -import { functionsList, functionsGetDeploymentDownload, functionsListDeployments } from './functions'; -import { sitesList, sitesGetDeploymentDownload, sitesListDeployments } from './sites'; -import { databasesGet, databasesListCollections, databasesList } from './databases'; -import { tablesDBList, tablesDBGet, tablesDBListTables } from './tables-db'; -import { storageListBuckets } from './storage'; -import { localConfig } from '../config'; -import { paginate } from '../paginate'; -import { questionsPullCollection, questionsPullFunctions, questionsPullFunctionsCode, questionsPullSites, questionsPullSitesCode, questionsPullResources } from '../questions'; -import { cliConfig, success, log, warn, actionRunner, commandDescriptions } from '../parser'; +import fs from "fs"; +import chalk from "chalk"; +import tar from "tar"; +import { Command } from "commander"; +import inquirer from "inquirer"; +import { + getMessagingService, + getTeamsService, + getProjectsService, + getFunctionsService, + getSitesService, + getDatabasesService, + getTablesDBService, + getStorageService, +} from "../services.js"; +import { localConfig } from "../config.js"; +import { paginate } from "../paginate.js"; +import { + questionsPullCollection, + questionsPullFunctions, + questionsPullFunctionsCode, + questionsPullSites, + questionsPullSitesCode, + questionsPullResources, +} from "../questions.js"; +import { + cliConfig, + success, + log, + warn, + error, + actionRunner, + commandDescriptions, +} from "../parser.js"; interface PullResourcesOptions { - skipDeprecated?: boolean; + skipDeprecated?: boolean; } interface PullFunctionsOptions { - code?: boolean; - withVariables?: boolean; + code?: boolean; + withVariables?: boolean; } interface PullSitesOptions { - code?: boolean; - withVariables?: boolean; + code?: boolean; + withVariables?: boolean; } export const pullResources = async ({ - skipDeprecated = false + skipDeprecated = false, }: PullResourcesOptions = {}): Promise<void> => { - const actions: Record<string, (options?: any) => Promise<void>> = { - settings: pullSettings, - functions: pullFunctions, - sites: pullSites, - collections: pullCollection, - tables: pullTable, - buckets: pullBucket, - teams: pullTeam, - messages: pullMessagingTopic + const project = localConfig.getProject(); + if (!project.projectId) { + error( + "Project configuration not found. Please run 'appwrite init project' to initialize your project first.", + ); + process.exit(1); + } + + const actions: Record<string, (options?: any) => Promise<void>> = { + settings: pullSettings, + functions: pullFunctions, + sites: pullSites, + collections: pullCollection, + tables: pullTable, + buckets: pullBucket, + teams: pullTeam, + messages: pullMessagingTopic, + }; + + if (skipDeprecated) { + delete actions.collections; + } + + if (cliConfig.all) { + for (let action of Object.values(actions)) { + cliConfig.all = true; + await action({ returnOnZero: true }); } + } else { + const answers = await inquirer.prompt([questionsPullResources[0]]); - if (skipDeprecated) { - delete actions.collections; - } - - if (cliConfig.all) { - for (let action of Object.values(actions)) { - cliConfig.all = true; - await action({ returnOnZero: true }); - } - } else { - const answers = await inquirer.prompt(questionsPullResources[0]); - - const action = actions[answers.resource]; - if (action !== undefined) { - await action({ returnOnZero: true }); - } + const action = actions[answers.resource]; + if (action !== undefined) { + await action({ returnOnZero: true }); } + } }; const pullSettings = async (): Promise<void> => { - log("Pulling project settings ..."); + log("Pulling project settings ..."); - try { - let response = await projectsGet({ - parseOutput: false, - projectId: localConfig.getProject().projectId - }); - - localConfig.setProject(response.$id, response.name, response); - - success(`Successfully pulled ${chalk.bold('all')} project settings.`); - } catch (e) { - throw e; - } -} + try { + const projectsService = await getProjectsService(); + let response = await projectsService.get( + localConfig.getProject().projectId, + ); -const pullFunctions = async ({ code, withVariables }: PullFunctionsOptions = {}): Promise<void> => { - process.chdir(localConfig.configDirectoryPath) + localConfig.setProject(response.$id, response.name, response); - log("Fetching functions ..."); - let total = 0; + success(`Successfully pulled ${chalk.bold("all")} project settings.`); + } catch (e) { + throw e; + } +}; - const fetchResponse = await functionsList({ - queries: [JSON.stringify({ method: 'limit', values: [1] })], - parseOutput: false - }); - if (fetchResponse["functions"].length <= 0) { - log("No functions found."); - success(`Successfully pulled ${chalk.bold(total)} functions.`); - return; +const pullFunctions = async ({ + code, + withVariables, +}: PullFunctionsOptions = {}): Promise<void> => { + process.chdir(localConfig.configDirectoryPath); + + log("Fetching functions ..."); + let total = 0; + + const functionsService = await getFunctionsService(); + const fetchResponse = await functionsService.list([ + JSON.stringify({ method: "limit", values: [1] }), + ]); + if (fetchResponse["functions"].length <= 0) { + log("No functions found."); + success(`Successfully pulled ${chalk.bold(total)} functions.`); + return; + } + + const functions = cliConfig.all + ? ( + await paginate( + async () => (await getFunctionsService()).list(), + {}, + 100, + "functions", + ) + ).functions + : (await inquirer.prompt(questionsPullFunctions)).functions; + + let allowCodePull: boolean | null = cliConfig.force === true ? true : null; + + for (let func of functions) { + total++; + log(`Pulling function ${chalk.bold(func["name"])} ...`); + + const localFunction = localConfig.getFunction(func.$id); + + func["path"] = localFunction["path"]; + if (!localFunction["path"]) { + func["path"] = `functions/${func.name}`; } + const holdingVars = func["vars"]; + // We don't save var in to the config + delete func["vars"]; + localConfig.addFunction(func); - const functions = cliConfig.all - ? (await paginate(functionsList, { parseOutput: false }, 100, 'functions')).functions - : (await inquirer.prompt(questionsPullFunctions)).functions; - - let allowCodePull: boolean | null = cliConfig.force === true ? true : null; - - for (let func of functions) { - total++; - log(`Pulling function ${chalk.bold(func['name'])} ...`); - - const localFunction = localConfig.getFunction(func.$id); - - func['path'] = localFunction['path']; - if (!localFunction['path']) { - func['path'] = `functions/${func.name}`; - } - const holdingVars = func['vars']; - // We don't save var in to the config - delete func['vars']; - localConfig.addFunction(func); - - if (!fs.existsSync(func['path'])) { - fs.mkdirSync(func['path'], { recursive: true }); - } - - if (code === false) { - warn("Source code download skipped."); - continue; - } - - if (allowCodePull === null) { - const codeAnswer = await inquirer.prompt(questionsPullFunctionsCode); - allowCodePull = codeAnswer.override; - } - - if (!allowCodePull) { - continue; - } - - let deploymentId: string | null = null; - - try { - const fetchResponse = await functionsListDeployments({ - functionId: func['$id'], - queries: [ - JSON.stringify({ method: 'limit', values: [1] }), - JSON.stringify({ method: 'orderDesc', values: ['$id'] }) - ], - parseOutput: false - }); - - if (fetchResponse['total'] > 0) { - deploymentId = fetchResponse['deployments'][0]['$id']; - } - - } catch { - } - - if (deploymentId === null) { - log("Source code download skipped because function doesn't have any available deployment"); - continue; - } - - log("Pulling latest deployment code ..."); - - const compressedFileName = `${func['$id']}-${+new Date()}.tar.gz` - await functionsGetDeploymentDownload({ - functionId: func['$id'], - deploymentId, - destination: compressedFileName, - overrideForCli: true, - parseOutput: false - }); - - tar.extract({ - sync: true, - cwd: func['path'], - file: compressedFileName, - strict: false, - }); - - fs.rmSync(compressedFileName); - - if (withVariables) { - const envFileLocation = `${func['path']}/.env` - try { - fs.rmSync(envFileLocation); - } catch { - } - - fs.writeFileSync(envFileLocation, holdingVars.map((r: any) => `${r.key}=${r.value}\n`).join('')) - } + if (!fs.existsSync(func["path"])) { + fs.mkdirSync(func["path"], { recursive: true }); } - success(`Successfully pulled ${chalk.bold(total)} functions.`); -} - -const pullSites = async ({ code, withVariables }: PullSitesOptions = {}): Promise<void> => { - process.chdir(localConfig.configDirectoryPath) - - log("Fetching sites ..."); - let total = 0; + if (code === false) { + warn("Source code download skipped."); + continue; + } - const fetchResponse = await sitesList({ - queries: [JSON.stringify({ method: 'limit', values: [1] })], - parseOutput: false - }); - if (fetchResponse["sites"].length <= 0) { - log("No sites found."); - success(`Successfully pulled ${chalk.bold(total)} sites.`); - return; + if (allowCodePull === null) { + const codeAnswer = await inquirer.prompt(questionsPullFunctionsCode); + allowCodePull = codeAnswer.override; } - const sites = cliConfig.all - ? (await paginate(sitesList, { parseOutput: false }, 100, 'sites')).sites - : (await inquirer.prompt(questionsPullSites)).sites; - - let allowCodePull: boolean | null = cliConfig.force === true ? true : null; - - for (let site of sites) { - total++; - log(`Pulling site ${chalk.bold(site['name'])} ...`); - - const localSite = localConfig.getSite(site.$id); - - site['path'] = localSite['path']; - if (!localSite['path']) { - site['path'] = `sites/${site.name}`; - } - const holdingVars = site['vars']; - // We don't save var in to the config - delete site['vars']; - localConfig.addSite(site); - - if (!fs.existsSync(site['path'])) { - fs.mkdirSync(site['path'], { recursive: true }); - } - - if (code === false) { - warn("Source code download skipped."); - continue; - } - - if (allowCodePull === null) { - const codeAnswer = await inquirer.prompt(questionsPullSitesCode); - allowCodePull = codeAnswer.override; - } - - if (!allowCodePull) { - continue; - } - - let deploymentId: string | null = null; - - try { - const fetchResponse = await sitesListDeployments({ - siteId: site['$id'], - queries: [ - JSON.stringify({ method: 'limit', values: [1] }), - JSON.stringify({ method: 'orderDesc', values: ['$id'] }) - ], - parseOutput: false - }); - - if (fetchResponse['total'] > 0) { - deploymentId = fetchResponse['deployments'][0]['$id']; - } - - } catch { - } - - if (deploymentId === null) { - log("Source code download skipped because site doesn't have any available deployment"); - continue; - } - - log("Pulling latest deployment code ..."); - - const compressedFileName = `${site['$id']}-${+new Date()}.tar.gz` - await sitesGetDeploymentDownload({ - siteId: site['$id'], - deploymentId, - destination: compressedFileName, - overrideForCli: true, - parseOutput: false - }); - - tar.extract({ - sync: true, - cwd: site['path'], - file: compressedFileName, - strict: false, - }); - - fs.rmSync(compressedFileName); - - if (withVariables) { - const envFileLocation = `${site['path']}/.env` - try { - fs.rmSync(envFileLocation); - } catch { - } - - fs.writeFileSync(envFileLocation, holdingVars.map((r: any) => `${r.key}=${r.value}\n`).join('')) - } + if (!allowCodePull) { + continue; } - success(`Successfully pulled ${chalk.bold(total)} sites.`); -} + let deploymentId: string | null = null; -const pullCollection = async (): Promise<void> => { - warn("appwrite pull collection has been deprecated. Please consider using 'appwrite pull tables' instead"); - log("Fetching collections ..."); - let totalDatabases = 0; - let totalCollections = 0; - - const fetchResponse = await databasesList({ - queries: [JSON.stringify({ method: 'limit', values: [1] })], - parseOutput: false - }); - if (fetchResponse["databases"].length <= 0) { - log("No collections found."); - success(`Successfully pulled ${chalk.bold(totalCollections)} collections from ${chalk.bold(totalDatabases)} databases.`); - return; + try { + const fetchResponse = await functionsService.listDeployments({ + functionId: func["$id"], + queries: [ + JSON.stringify({ method: "limit", values: [1] }), + JSON.stringify({ method: "orderDesc", values: ["$id"] }), + ], + }); + + if (fetchResponse["total"] > 0) { + deploymentId = fetchResponse["deployments"][0]["$id"]; + } + } catch {} + + if (deploymentId === null) { + log( + "Source code download skipped because function doesn't have any available deployment", + ); + continue; } - let databases: string[] = cliConfig.ids; + log("Pulling latest deployment code ..."); - if (databases.length === 0) { - if (cliConfig.all) { - databases = (await paginate(databasesList, { parseOutput: false }, 100, 'databases')).databases.map((database: any) => database.$id); - } else { - databases = (await inquirer.prompt(questionsPullCollection)).databases; - } - } + const compressedFileName = `${func["$id"]}-${+new Date()}.tar.gz`; + const downloadUrl = functionsService.getDeploymentDownload({ + functionId: func["$id"], + deploymentId: deploymentId, + }); - for (const databaseId of databases) { - const database = await databasesGet({ - databaseId, - parseOutput: false - }); - - totalDatabases++; - log(`Pulling all collections from ${chalk.bold(database['name'])} database ...`); - - localConfig.addDatabase(database); - - const { collections } = await paginate(databasesListCollections, { - databaseId, - parseOutput: false - }, 100, 'collections'); - - for (const collection of collections) { - totalCollections++; - localConfig.addCollection({ - ...collection, - '$createdAt': undefined, - '$updatedAt': undefined - }); - } - } + const client = (await getFunctionsService()).client; + const downloadBuffer = await client.call( + "get", + new URL(downloadUrl), + {}, + {}, + "arrayBuffer", + ); + + fs.writeFileSync(compressedFileName, Buffer.from(downloadBuffer as any)); + + tar.extract({ + sync: true, + cwd: func["path"], + file: compressedFileName, + strict: false, + }); - success(`Successfully pulled ${chalk.bold(totalCollections)} collections from ${chalk.bold(totalDatabases)} databases.`); -} + fs.rmSync(compressedFileName); -const pullTable = async (): Promise<void> => { - log("Fetching tables ..."); - let totalTablesDBs = 0; - let totalTables = 0; + if (withVariables) { + const envFileLocation = `${func["path"]}/.env`; + try { + fs.rmSync(envFileLocation); + } catch {} - const fetchResponse = await tablesDBList({ - queries: [JSON.stringify({ method: 'limit', values: [1] })], - parseOutput: false - }); - if (fetchResponse["databases"].length <= 0) { - log("No tables found."); - success(`Successfully pulled ${chalk.bold(totalTables)} tables from ${chalk.bold(totalTablesDBs)} tableDBs.`); - return; + fs.writeFileSync( + envFileLocation, + holdingVars.map((r: any) => `${r.key}=${r.value}\n`).join(""), + ); } + } - let databases: string[] = cliConfig.ids; + success(`Successfully pulled ${chalk.bold(total)} functions.`); +}; - if (databases.length === 0) { - if (cliConfig.all) { - databases = (await paginate(tablesDBList, { parseOutput: false }, 100, 'databases')).databases.map((database: any) => database.$id); - } else { - databases = (await inquirer.prompt(questionsPullCollection)).databases; - } +const pullSites = async ({ + code, + withVariables, +}: PullSitesOptions = {}): Promise<void> => { + process.chdir(localConfig.configDirectoryPath); + + log("Fetching sites ..."); + let total = 0; + + const sitesService = await getSitesService(); + const fetchResponse = await sitesService.list([ + JSON.stringify({ method: "limit", values: [1] }), + ]); + if (fetchResponse["sites"].length <= 0) { + log("No sites found."); + success(`Successfully pulled ${chalk.bold(total)} sites.`); + return; + } + + const sites = cliConfig.all + ? ( + await paginate( + async () => (await getSitesService()).list(), + {}, + 100, + "sites", + ) + ).sites + : (await inquirer.prompt(questionsPullSites)).sites; + + let allowCodePull: boolean | null = cliConfig.force === true ? true : null; + + for (let site of sites) { + total++; + log(`Pulling site ${chalk.bold(site["name"])} ...`); + + const localSite = localConfig.getSite(site.$id); + + site["path"] = localSite["path"]; + if (!localSite["path"]) { + site["path"] = `sites/${site.name}`; } + const holdingVars = site["vars"]; + // We don't save var in to the config + delete site["vars"]; + localConfig.addSite(site); - for (const databaseId of databases) { - const database = await tablesDBGet({ - databaseId, - parseOutput: false - }); - - totalTablesDBs++; - log(`Pulling all tables from ${chalk.bold(database['name'])} database ...`); - - localConfig.addTablesDB(database); - - const { tables } = await paginate(tablesDBListTables, { - databaseId, - parseOutput: false - }, 100, 'tables'); - - for (const table of tables) { - totalTables++; - localConfig.addTable({ - ...table, - '$createdAt': undefined, - '$updatedAt': undefined - }); - } + if (!fs.existsSync(site["path"])) { + fs.mkdirSync(site["path"], { recursive: true }); } - success(`Successfully pulled ${chalk.bold(totalTables)} tables from ${chalk.bold(totalTablesDBs)} tableDBs.`); -} + if (code === false) { + warn("Source code download skipped."); + continue; + } -const pullBucket = async (): Promise<void> => { - log("Fetching buckets ..."); - let total = 0; + if (allowCodePull === null) { + const codeAnswer = await inquirer.prompt(questionsPullSitesCode); + allowCodePull = codeAnswer.override; + } - const fetchResponse = await storageListBuckets({ - queries: [JSON.stringify({ method: 'limit', values: [1] })], - parseOutput: false - }); - if (fetchResponse["buckets"].length <= 0) { - log("No buckets found."); - success(`Successfully pulled ${chalk.bold(total)} buckets.`); - return; + if (!allowCodePull) { + continue; } - const { buckets } = await paginate(storageListBuckets, { parseOutput: false }, 100, 'buckets'); + let deploymentId: string | null = null; - for (const bucket of buckets) { - total++; - log(`Pulling bucket ${chalk.bold(bucket['name'])} ...`); - localConfig.addBucket(bucket); + try { + const fetchResponse = await sitesService.listDeployments({ + siteId: site["$id"], + queries: [ + JSON.stringify({ method: "limit", values: [1] }), + JSON.stringify({ method: "orderDesc", values: ["$id"] }), + ], + }); + + if (fetchResponse["total"] > 0) { + deploymentId = fetchResponse["deployments"][0]["$id"]; + } + } catch {} + + if (deploymentId === null) { + log( + "Source code download skipped because site doesn't have any available deployment", + ); + continue; } - success(`Successfully pulled ${chalk.bold(total)} buckets.`); -} + log("Pulling latest deployment code ..."); -const pullTeam = async (): Promise<void> => { - log("Fetching teams ..."); - let total = 0; + const compressedFileName = `${site["$id"]}-${+new Date()}.tar.gz`; + const downloadUrl = sitesService.getDeploymentDownload({ + siteId: site["$id"], + deploymentId: deploymentId, + }); - const fetchResponse = await teamsList({ - queries: [JSON.stringify({ method: 'limit', values: [1] })], - parseOutput: false + const client = (await getSitesService()).client; + const downloadBuffer = await client.call( + "get", + new URL(downloadUrl), + {}, + {}, + "arrayBuffer", + ); + + fs.writeFileSync(compressedFileName, Buffer.from(downloadBuffer as any)); + + tar.extract({ + sync: true, + cwd: site["path"], + file: compressedFileName, + strict: false, }); - if (fetchResponse["teams"].length <= 0) { - log("No teams found."); - success(`Successfully pulled ${chalk.bold(total)} teams.`); - return; - } - const { teams } = await paginate(teamsList, { parseOutput: false }, 100, 'teams'); + fs.rmSync(compressedFileName); - for (const team of teams) { - total++; - log(`Pulling team ${chalk.bold(team['name'])} ...`); - localConfig.addTeam(team); - } + if (withVariables) { + const envFileLocation = `${site["path"]}/.env`; + try { + fs.rmSync(envFileLocation); + } catch {} - success(`Successfully pulled ${chalk.bold(total)} teams.`); -} + fs.writeFileSync( + envFileLocation, + holdingVars.map((r: any) => `${r.key}=${r.value}\n`).join(""), + ); + } + } -const pullMessagingTopic = async (): Promise<void> => { - log("Fetching topics ..."); - let total = 0; + success(`Successfully pulled ${chalk.bold(total)} sites.`); +}; - const fetchResponse = await messagingListTopics({ - queries: [JSON.stringify({ method: 'limit', values: [1] })], - parseOutput: false - }); - if (fetchResponse["topics"].length <= 0) { - log("No topics found."); - success(`Successfully pulled ${chalk.bold(total)} topics.`); - return; +const pullCollection = async (): Promise<void> => { + warn( + "appwrite pull collection has been deprecated. Please consider using 'appwrite pull tables' instead", + ); + log("Fetching collections ..."); + let totalDatabases = 0; + let totalCollections = 0; + + const databasesService = await getDatabasesService(); + const fetchResponse = await databasesService.list([ + JSON.stringify({ method: "limit", values: [1] }), + ]); + if (fetchResponse["databases"].length <= 0) { + log("No collections found."); + success( + `Successfully pulled ${chalk.bold(totalCollections)} collections from ${chalk.bold(totalDatabases)} databases.`, + ); + return; + } + + let databases: string[] = cliConfig.ids; + + if (databases.length === 0) { + if (cliConfig.all) { + databases = ( + await paginate( + async () => (await getDatabasesService()).list(), + {}, + 100, + "databases", + ) + ).databases.map((database: any) => database.$id); + } else { + databases = (await inquirer.prompt(questionsPullCollection)).databases; } + } + + for (const databaseId of databases) { + const database = await databasesService.get(databaseId); + + totalDatabases++; + log( + `Pulling all collections from ${chalk.bold(database["name"])} database ...`, + ); + + localConfig.addDatabase(database); + + const { collections } = await paginate( + async () => (await getDatabasesService()).listCollections(databaseId), + {}, + 100, + "collections", + ); + + for (const collection of collections) { + totalCollections++; + localConfig.addCollection({ + ...collection, + $createdAt: undefined, + $updatedAt: undefined, + }); + } + } - const { topics } = await paginate(messagingListTopics, { parseOutput: false }, 100, 'topics'); + success( + `Successfully pulled ${chalk.bold(totalCollections)} collections from ${chalk.bold(totalDatabases)} databases.`, + ); +}; - for (const topic of topics) { - total++; - log(`Pulling topic ${chalk.bold(topic['name'])} ...`); - localConfig.addMessagingTopic(topic); +const pullTable = async (): Promise<void> => { + log("Fetching tables ..."); + let totalTablesDBs = 0; + let totalTables = 0; + + const tablesDBService = await getTablesDBService(); + const fetchResponse = await tablesDBService.list([ + JSON.stringify({ method: "limit", values: [1] }), + ]); + if (fetchResponse["databases"].length <= 0) { + log("No tables found."); + success( + `Successfully pulled ${chalk.bold(totalTables)} tables from ${chalk.bold(totalTablesDBs)} tableDBs.`, + ); + return; + } + + let databases: string[] = cliConfig.ids; + + if (databases.length === 0) { + if (cliConfig.all) { + databases = ( + await paginate( + async () => (await getTablesDBService()).list(), + {}, + 100, + "databases", + ) + ).databases.map((database: any) => database.$id); + } else { + databases = (await inquirer.prompt(questionsPullCollection)).databases; } + } + + for (const databaseId of databases) { + const database = await tablesDBService.get(databaseId); + + totalTablesDBs++; + log(`Pulling all tables from ${chalk.bold(database["name"])} database ...`); + + localConfig.addTablesDB(database); + + const { tables } = await paginate( + async () => (await getTablesDBService()).listTables(databaseId), + {}, + 100, + "tables", + ); + + for (const table of tables) { + totalTables++; + localConfig.addTable({ + ...table, + $createdAt: undefined, + $updatedAt: undefined, + }); + } + } + + success( + `Successfully pulled ${chalk.bold(totalTables)} tables from ${chalk.bold(totalTablesDBs)} tableDBs.`, + ); +}; + +const pullBucket = async (): Promise<void> => { + log("Fetching buckets ..."); + let total = 0; + + const storageService = await getStorageService(); + const fetchResponse = await storageService.listBuckets([ + JSON.stringify({ method: "limit", values: [1] }), + ]); + if (fetchResponse["buckets"].length <= 0) { + log("No buckets found."); + success(`Successfully pulled ${chalk.bold(total)} buckets.`); + return; + } + + const { buckets } = await paginate( + async () => (await getStorageService()).listBuckets(), + {}, + 100, + "buckets", + ); + + for (const bucket of buckets) { + total++; + log(`Pulling bucket ${chalk.bold(bucket["name"])} ...`); + localConfig.addBucket(bucket); + } + + success(`Successfully pulled ${chalk.bold(total)} buckets.`); +}; + +const pullTeam = async (): Promise<void> => { + log("Fetching teams ..."); + let total = 0; + + const teamsService = await getTeamsService(); + const fetchResponse = await teamsService.list([ + JSON.stringify({ method: "limit", values: [1] }), + ]); + if (fetchResponse["teams"].length <= 0) { + log("No teams found."); + success(`Successfully pulled ${chalk.bold(total)} teams.`); + return; + } + + const { teams } = await paginate( + async () => (await getTeamsService()).list(), + {}, + 100, + "teams", + ); + + for (const team of teams) { + total++; + log(`Pulling team ${chalk.bold(team["name"])} ...`); + localConfig.addTeam(team); + } + + success(`Successfully pulled ${chalk.bold(total)} teams.`); +}; +const pullMessagingTopic = async (): Promise<void> => { + log("Fetching topics ..."); + let total = 0; + + const messagingService = await getMessagingService(); + const fetchResponse = await messagingService.listTopics([ + JSON.stringify({ method: "limit", values: [1] }), + ]); + if (fetchResponse["topics"].length <= 0) { + log("No topics found."); success(`Successfully pulled ${chalk.bold(total)} topics.`); -} + return; + } + + const { topics } = await paginate( + async () => (await getMessagingService()).listTopics(), + {}, + 100, + "topics", + ); + + for (const topic of topics) { + total++; + log(`Pulling topic ${chalk.bold(topic["name"])} ...`); + localConfig.addMessagingTopic(topic); + } + + success(`Successfully pulled ${chalk.bold(total)} topics.`); +}; export const pull = new Command("pull") - .description(commandDescriptions['pull']) - .action(actionRunner(() => pullResources({ skipDeprecated: true }))); + .description(commandDescriptions["pull"]) + .action(actionRunner(() => pullResources({ skipDeprecated: true }))); pull - .command("all") - .description("Pull all resource.") - .action(actionRunner(() => { - cliConfig.all = true; - return pullResources({ - skipDeprecated: true - }); - })); + .command("all") + .description("Pull all resource.") + .action( + actionRunner(() => { + cliConfig.all = true; + return pullResources({ + skipDeprecated: true, + }); + }), + ); pull - .command("settings") - .description("Pull your Appwrite project name, services and auth settings") - .action(actionRunner(pullSettings)); + .command("settings") + .description("Pull your Appwrite project name, services and auth settings") + .action(actionRunner(pullSettings)); pull - .command("function") - .alias("functions") - .description("Pull your Appwrite cloud function") - .option("--no-code", "Don't pull the function's code") - .option("--with-variables", `Pull function variables. ${chalk.red('recommend for testing purposes only')}`) - .action(actionRunner(pullFunctions)) + .command("function") + .alias("functions") + .description("Pull your Appwrite cloud function") + .option("--no-code", "Don't pull the function's code") + .option( + "--with-variables", + `Pull function variables. ${chalk.red("recommend for testing purposes only")}`, + ) + .action(actionRunner(pullFunctions)); pull - .command("site") - .alias("sites") - .description("Pull your Appwrite site") - .option("--no-code", "Don't pull the site's code") - .option("--with-variables", `Pull site variables. ${chalk.red('recommend for testing purposes only')}`) - .action(actionRunner(pullSites)) + .command("site") + .alias("sites") + .description("Pull your Appwrite site") + .option("--no-code", "Don't pull the site's code") + .option( + "--with-variables", + `Pull site variables. ${chalk.red("recommend for testing purposes only")}`, + ) + .action(actionRunner(pullSites)); pull - .command("collection") - .alias("collections") - .description("Pull your Appwrite collections (deprecated, please use 'pull tables' instead)") - .action(actionRunner(pullCollection)) + .command("collection") + .alias("collections") + .description( + "Pull your Appwrite collections (deprecated, please use 'pull tables' instead)", + ) + .action(actionRunner(pullCollection)); pull - .command("table") - .alias("tables") - .description("Pull your Appwrite tables") - .action(actionRunner(pullTable)) + .command("table") + .alias("tables") + .description("Pull your Appwrite tables") + .action(actionRunner(pullTable)); pull - .command("bucket") - .alias("buckets") - .description("Pull your Appwrite buckets") - .action(actionRunner(pullBucket)) + .command("bucket") + .alias("buckets") + .description("Pull your Appwrite buckets") + .action(actionRunner(pullBucket)); pull - .command("team") - .alias("teams") - .description("Pull your Appwrite teams") - .action(actionRunner(pullTeam)) + .command("team") + .alias("teams") + .description("Pull your Appwrite teams") + .action(actionRunner(pullTeam)); pull - .command("topic") - .alias("topics") - .description("Pull your Appwrite messaging topics") - .action(actionRunner(pullMessagingTopic)) - + .command("topic") + .alias("topics") + .description("Pull your Appwrite messaging topics") + .action(actionRunner(pullMessagingTopic)); diff --git a/lib/commands/push.ts b/lib/commands/push.ts index d59f88f4..b1ae3a60 100644 --- a/lib/commands/push.ts +++ b/lib/commands/push.ts @@ -1,1812 +1,2250 @@ -import fs = require('fs'); -import path = require('path'); -import { parse as parseDotenv } from 'dotenv'; -import chalk from 'chalk'; +import fs from "fs"; +import { parse as parseDotenv } from "dotenv"; +import chalk from "chalk"; import inquirer from "inquirer"; -import JSONbig from "json-bigint"; import { Command } from "commander"; -import ID from "../id"; -import { localConfig, globalConfig, KeysAttributes, KeysFunction, KeysSite, whitelistKeys, KeysTopics, KeysStorage, KeysTeams, KeysCollection, KeysTable } from "../config"; -import { Spinner, SPINNER_ARC, SPINNER_DOTS } from '../spinner'; -import { paginate } from '../paginate'; -import { questionsPushBuckets, questionsPushTeams, questionsPushFunctions, questionsPushSites, questionsGetEntrypoint, questionsPushCollections, questionsPushTables, questionPushChanges, questionPushChangesConfirmation, questionsPushMessagingTopics, questionsPushResources } from "../questions"; -import { cliConfig, actionRunner, success, warn, log, hint, error, commandDescriptions, drawTable } from "../parser"; -import { proxyCreateFunctionRule, proxyCreateSiteRule, proxyListRules } from './proxy'; -import { consoleVariables } from './console'; -import { sdkForConsole } from '../sdks'; -import { functionsGet, functionsCreate, functionsUpdate, functionsCreateDeployment, functionsGetDeployment, functionsListVariables, functionsDeleteVariable, functionsCreateVariable } from './functions'; -import { sitesGet, sitesCreate, sitesUpdate, sitesCreateDeployment, sitesGetDeployment, sitesCreateVariable, sitesListVariables, sitesDeleteVariable } from './sites'; +import ID from "../id.js"; import { - databasesGet, - databasesCreate, - databasesUpdate, - databasesCreateBooleanAttribute, - databasesGetCollection, - databasesCreateCollection, - databasesCreateStringAttribute, - databasesCreateIntegerAttribute, - databasesCreateFloatAttribute, - databasesCreateEmailAttribute, - databasesCreateDatetimeAttribute, - databasesCreateIndex, - databasesCreateUrlAttribute, - databasesCreateIpAttribute, - databasesCreateEnumAttribute, - databasesUpdateBooleanAttribute, - databasesUpdateStringAttribute, - databasesUpdateIntegerAttribute, - databasesUpdateFloatAttribute, - databasesUpdateEmailAttribute, - databasesUpdateDatetimeAttribute, - databasesUpdateUrlAttribute, - databasesUpdateIpAttribute, - databasesUpdateEnumAttribute, - databasesUpdateRelationshipAttribute, - databasesCreateRelationshipAttribute, - databasesCreatePointAttribute, - databasesUpdatePointAttribute, - databasesCreateLineAttribute, - databasesUpdateLineAttribute, - databasesCreatePolygonAttribute, - databasesUpdatePolygonAttribute, - databasesDeleteAttribute, - databasesDeleteIndex, - databasesListAttributes, - databasesListIndexes, - databasesUpdateCollection -} from "./databases"; + localConfig, + globalConfig, + KeysAttributes, + KeysFunction, + KeysSite, + whitelistKeys, + KeysTopics, + KeysStorage, + KeysTeams, + KeysCollection, + KeysTable, +} from "../config.js"; +import { Spinner, SPINNER_ARC, SPINNER_DOTS } from "../spinner.js"; +import { paginate } from "../paginate.js"; import { - tablesDBCreate, - tablesDBGet, - tablesDBUpdate, - tablesDBCreateTable, - tablesDBGetTable, - tablesDBUpdateTable, - tablesDBList, - tablesDBDelete, - tablesDBListTables, - tablesDBDeleteTable -} from "./tables-db"; + questionsPushBuckets, + questionsPushTeams, + questionsPushFunctions, + questionsPushSites, + questionsGetEntrypoint, + questionsPushCollections, + questionsPushTables, + questionPushChanges, + questionPushChangesConfirmation, + questionsPushMessagingTopics, + questionsPushResources, +} from "../questions.js"; import { - storageGetBucket, storageUpdateBucket, storageCreateBucket -} from "./storage"; + cliConfig, + actionRunner, + success, + warn, + log, + hint, + error, + commandDescriptions, + drawTable, +} from "../parser.js"; import { - messagingGetTopic, messagingUpdateTopic, messagingCreateTopic -} from "./messaging"; -import { - teamsGet, - teamsUpdateName, - teamsCreate -} from "./teams"; -import { - projectsGet, - projectsUpdate, - projectsUpdateServiceStatus, - projectsUpdateAuthStatus, - projectsUpdateAuthDuration, - projectsUpdateAuthLimit, - projectsUpdateAuthSessionsLimit, - projectsUpdateAuthPasswordDictionary, - projectsUpdateAuthPasswordHistory, - projectsUpdatePersonalDataCheck, - projectsUpdateSessionAlerts, - projectsUpdateMockNumbers, -} from "./projects"; -import { checkDeployConditions } from '../utils'; - -const JSONbigNative = JSONbig({ storeAsString: false }); - -const STEP_SIZE = 100; // Resources + getProxyService, + getConsoleService, + getFunctionsService, + getSitesService, + getDatabasesService, + getTablesDBService, + getStorageService, + getMessagingService, + getTeamsService, + getProjectsService, +} from "../services.js"; +import { ApiService, AuthMethod } from "@appwrite.io/console"; +import { checkDeployConditions } from "../utils.js"; + +const STEP_SIZE = 100; // Resources const POLL_DEBOUNCE = 2000; // Milliseconds -const POLL_MAX_DEBOUNCE = 1800; // Times of POLL_DEBOUNCE (1 hour) const POLL_DEFAULT_VALUE = 30; let pollMaxDebounces = POLL_DEFAULT_VALUE; -const changeableKeys = ['status', 'required', 'xdefault', 'elements', 'min', 'max', 'default', 'error']; - -interface AwaitPools { - wipeAttributes: (databaseId: string, collectionId: string, iteration?: number) => Promise<boolean>; - wipeIndexes: (databaseId: string, collectionId: string, iteration?: number) => Promise<boolean>; - deleteAttributes: (databaseId: string, collectionId: string, attributeKeys: any[], iteration?: number) => Promise<boolean>; - expectAttributes: (databaseId: string, collectionId: string, attributeKeys: string[], iteration?: number) => Promise<boolean>; - deleteIndexes: (databaseId: string, collectionId: string, indexesKeys: any[], iteration?: number) => Promise<boolean>; - expectIndexes: (databaseId: string, collectionId: string, indexKeys: string[], iteration?: number) => Promise<boolean>; +const changeableKeys = [ + "status", + "required", + "xdefault", + "elements", + "min", + "max", + "default", + "error", +]; + +interface ObjectChange { + group: string; + setting: string; + remote: string; + local: string; } -const awaitPools: AwaitPools = { - wipeAttributes: async (databaseId: string, collectionId: string, iteration: number = 1): Promise<boolean> => { - if (iteration > pollMaxDebounces) { - return false; - } - - const { total } = await databasesListAttributes({ - databaseId, - collectionId, - queries: [JSON.stringify({ method: 'limit', values: [1] })], - parseOutput: false - }); +type ComparableValue = boolean | number | string | any[] | undefined; - if (total === 0) { - return true; - } +interface AttributeChange { + key: string; + attribute: any; + reason: string; + action: string; +} - if (pollMaxDebounces === POLL_DEFAULT_VALUE) { - let steps = Math.max(1, Math.ceil(total / STEP_SIZE)); - if (steps > 1 && iteration === 1) { - pollMaxDebounces *= steps; +interface PushResourcesOptions { + skipDeprecated?: boolean; +} - log('Found a large number of attributes, increasing timeout to ' + (pollMaxDebounces * POLL_DEBOUNCE / 1000 / 60) + ' minutes') - } - } +interface PushSiteOptions { + siteId?: string; + async?: boolean; + code?: boolean; + withVariables?: boolean; +} - await new Promise(resolve => setTimeout(resolve, POLL_DEBOUNCE)); +interface PushFunctionOptions { + functionId?: string; + async?: boolean; + code?: boolean; + withVariables?: boolean; +} - return await awaitPools.wipeAttributes( - databaseId, - collectionId, - iteration + 1 - ); - }, - wipeIndexes: async (databaseId: string, collectionId: string, iteration: number = 1): Promise<boolean> => { - if (iteration > pollMaxDebounces) { - return false; - } +interface TablesDBChangesResult { + applied: boolean; + resyncNeeded: boolean; +} - const { total } = await databasesListIndexes({ - databaseId, - collectionId, - queries: [JSON.stringify({ method: 'limit', values: [1] })], - parseOutput: false - }); +interface PushTableOptions { + attempts?: number; +} - if (total === 0) { - return true; - } +interface AwaitPools { + wipeAttributes: ( + databaseId: string, + collectionId: string, + iteration?: number, + ) => Promise<boolean>; + + wipeIndexes: ( + databaseId: string, + collectionId: string, + iteration?: number, + ) => Promise<boolean>; + + deleteAttributes: ( + databaseId: string, + collectionId: string, + attributeKeys: any[], + iteration?: number, + ) => Promise<boolean>; + + expectAttributes: ( + databaseId: string, + collectionId: string, + attributeKeys: string[], + iteration?: number, + ) => Promise<boolean>; + + deleteIndexes: ( + databaseId: string, + collectionId: string, + indexesKeys: any[], + iteration?: number, + ) => Promise<boolean>; + + expectIndexes: ( + databaseId: string, + collectionId: string, + indexKeys: string[], + iteration?: number, + ) => Promise<boolean>; +} - if (pollMaxDebounces === POLL_DEFAULT_VALUE) { - let steps = Math.max(1, Math.ceil(total / STEP_SIZE)); - if (steps > 1 && iteration === 1) { - pollMaxDebounces *= steps; +const awaitPools: AwaitPools = { + wipeAttributes: async ( + databaseId: string, + collectionId: string, + iteration: number = 1, + ): Promise<boolean> => { + if (iteration > pollMaxDebounces) { + return false; + } + + const databasesService = await getDatabasesService(); + const response = await databasesService.listAttributes( + databaseId, + collectionId, + [JSON.stringify({ method: "limit", values: [1] })], + ); + const { total } = response; - log('Found a large number of indexes, increasing timeout to ' + (pollMaxDebounces * POLL_DEBOUNCE / 1000 / 60) + ' minutes') - } - } + if (total === 0) { + return true; + } - await new Promise(resolve => setTimeout(resolve, POLL_DEBOUNCE)); + if (pollMaxDebounces === POLL_DEFAULT_VALUE) { + let steps = Math.max(1, Math.ceil(total / STEP_SIZE)); + if (steps > 1 && iteration === 1) { + pollMaxDebounces *= steps; - return await awaitPools.wipeIndexes( - databaseId, - collectionId, - iteration + 1 + log( + "Found a large number of attributes, increasing timeout to " + + (pollMaxDebounces * POLL_DEBOUNCE) / 1000 / 60 + + " minutes", ); - }, - deleteAttributes: async (databaseId: string, collectionId: string, attributeKeys: any[], iteration: number = 1): Promise<boolean> => { - if (iteration > pollMaxDebounces) { - return false; - } + } + } - if (pollMaxDebounces === POLL_DEFAULT_VALUE) { - let steps = Math.max(1, Math.ceil(attributeKeys.length / STEP_SIZE)); - if (steps > 1 && iteration === 1) { - pollMaxDebounces *= steps; + await new Promise((resolve) => setTimeout(resolve, POLL_DEBOUNCE)); - log('Found a large number of attributes to be deleted. Increasing timeout to ' + (pollMaxDebounces * POLL_DEBOUNCE / 1000 / 60) + ' minutes') - } - } - - const { attributes } = await paginate(databasesListAttributes, { - databaseId, - collectionId, - parseOutput: false - }, 100, 'attributes'); - - const ready = attributeKeys.filter((attribute: any) => attributes.includes(attribute.key)); + return await awaitPools.wipeAttributes( + databaseId, + collectionId, + iteration + 1, + ); + }, + wipeIndexes: async ( + databaseId: string, + collectionId: string, + iteration: number = 1, + ): Promise<boolean> => { + if (iteration > pollMaxDebounces) { + return false; + } + + const databasesService = await getDatabasesService(); + const response = await databasesService.listIndexes( + databaseId, + collectionId, + [JSON.stringify({ method: "limit", values: [1] })], + ); + const { total } = response; - if (ready.length === 0) { - return true; - } + if (total === 0) { + return true; + } - await new Promise(resolve => setTimeout(resolve, POLL_DEBOUNCE)); + if (pollMaxDebounces === POLL_DEFAULT_VALUE) { + let steps = Math.max(1, Math.ceil(total / STEP_SIZE)); + if (steps > 1 && iteration === 1) { + pollMaxDebounces *= steps; - return await awaitPools.expectAttributes( - databaseId, - collectionId, - attributeKeys, - iteration + 1 + log( + "Found a large number of indexes, increasing timeout to " + + (pollMaxDebounces * POLL_DEBOUNCE) / 1000 / 60 + + " minutes", ); - }, - expectAttributes: async (databaseId: string, collectionId: string, attributeKeys: string[], iteration: number = 1): Promise<boolean> => { - if (iteration > pollMaxDebounces) { - return false; - } - - if (pollMaxDebounces === POLL_DEFAULT_VALUE) { - let steps = Math.max(1, Math.ceil(attributeKeys.length / STEP_SIZE)); - if (steps > 1 && iteration === 1) { - pollMaxDebounces *= steps; + } + } - log('Creating a large number of attributes, increasing timeout to ' + (pollMaxDebounces * POLL_DEBOUNCE / 1000 / 60) + ' minutes') - } - } + await new Promise((resolve) => setTimeout(resolve, POLL_DEBOUNCE)); - const { attributes } = await paginate(databasesListAttributes, { - databaseId, - collectionId, - parseOutput: false - }, 100, 'attributes'); + return await awaitPools.wipeIndexes( + databaseId, + collectionId, + iteration + 1, + ); + }, + deleteAttributes: async ( + databaseId: string, + collectionId: string, + attributeKeys: any[], + iteration: number = 1, + ): Promise<boolean> => { + if (iteration > pollMaxDebounces) { + return false; + } + + if (pollMaxDebounces === POLL_DEFAULT_VALUE) { + let steps = Math.max(1, Math.ceil(attributeKeys.length / STEP_SIZE)); + if (steps > 1 && iteration === 1) { + pollMaxDebounces *= steps; + + log( + "Found a large number of attributes to be deleted. Increasing timeout to " + + (pollMaxDebounces * POLL_DEBOUNCE) / 1000 / 60 + + " minutes", + ); + } + } - const ready = attributes - .filter((attribute: any) => { - if (attributeKeys.includes(attribute.key)) { - if (['stuck', 'failed'].includes(attribute.status)) { - throw new Error(`Attribute '${attribute.key}' failed!`); - } + const { attributes } = await paginate( + async (args: any) => { + const databasesService = await getDatabasesService(); + return await databasesService.listAttributes( + args.databaseId, + args.collectionId, + args.queries || [], + ); + }, + { + databaseId, + collectionId, + }, + 100, + "attributes", + ); - return attribute.status === 'available'; - } + const ready = attributeKeys.filter((attribute: any) => + attributes.includes(attribute.key), + ); - return false; - }) - .map((attribute: any) => attribute.key); + if (ready.length === 0) { + return true; + } - if (ready.length === attributeKeys.length) { - return true; - } + await new Promise((resolve) => setTimeout(resolve, POLL_DEBOUNCE)); - await new Promise(resolve => setTimeout(resolve, POLL_DEBOUNCE)); + return await awaitPools.expectAttributes( + databaseId, + collectionId, + attributeKeys, + iteration + 1, + ); + }, + expectAttributes: async ( + databaseId: string, + collectionId: string, + attributeKeys: string[], + iteration: number = 1, + ): Promise<boolean> => { + if (iteration > pollMaxDebounces) { + return false; + } + + if (pollMaxDebounces === POLL_DEFAULT_VALUE) { + let steps = Math.max(1, Math.ceil(attributeKeys.length / STEP_SIZE)); + if (steps > 1 && iteration === 1) { + pollMaxDebounces *= steps; + + log( + "Creating a large number of attributes, increasing timeout to " + + (pollMaxDebounces * POLL_DEBOUNCE) / 1000 / 60 + + " minutes", + ); + } + } - return await awaitPools.expectAttributes( - databaseId, - collectionId, - attributeKeys, - iteration + 1 + const { attributes } = await paginate( + async (args: any) => { + const databasesService = await getDatabasesService(); + return await databasesService.listAttributes( + args.databaseId, + args.collectionId, + args.queries || [], ); - }, - deleteIndexes: async (databaseId: string, collectionId: string, indexesKeys: any[], iteration: number = 1): Promise<boolean> => { - if (iteration > pollMaxDebounces) { - return false; - } + }, + { + databaseId, + collectionId, + }, + 100, + "attributes", + ); - if (pollMaxDebounces === POLL_DEFAULT_VALUE) { - let steps = Math.max(1, Math.ceil(indexesKeys.length / STEP_SIZE)); - if (steps > 1 && iteration === 1) { - pollMaxDebounces *= steps; + const ready = attributes + .filter((attribute: any) => { + if (attributeKeys.includes(attribute.key)) { + if (["stuck", "failed"].includes(attribute.status)) { + throw new Error(`Attribute '${attribute.key}' failed!`); + } - log('Found a large number of indexes to be deleted. Increasing timeout to ' + (pollMaxDebounces * POLL_DEBOUNCE / 1000 / 60) + ' minutes') - } + return attribute.status === "available"; } - const { indexes } = await paginate(databasesListIndexes, { - databaseId, - collectionId, - parseOutput: false - }, 100, 'indexes'); + return false; + }) + .map((attribute: any) => attribute.key); - const ready = indexesKeys.filter((index: any) => indexes.includes(index.key)); + if (ready.length === attributeKeys.length) { + return true; + } - if (ready.length === 0) { - return true; - } + await new Promise((resolve) => setTimeout(resolve, POLL_DEBOUNCE)); - await new Promise(resolve => setTimeout(resolve, POLL_DEBOUNCE)); + return await awaitPools.expectAttributes( + databaseId, + collectionId, + attributeKeys, + iteration + 1, + ); + }, + deleteIndexes: async ( + databaseId: string, + collectionId: string, + indexesKeys: any[], + iteration: number = 1, + ): Promise<boolean> => { + if (iteration > pollMaxDebounces) { + return false; + } + + if (pollMaxDebounces === POLL_DEFAULT_VALUE) { + let steps = Math.max(1, Math.ceil(indexesKeys.length / STEP_SIZE)); + if (steps > 1 && iteration === 1) { + pollMaxDebounces *= steps; + + log( + "Found a large number of indexes to be deleted. Increasing timeout to " + + (pollMaxDebounces * POLL_DEBOUNCE) / 1000 / 60 + + " minutes", + ); + } + } - return await awaitPools.expectIndexes( - databaseId, - collectionId, - indexesKeys, - iteration + 1 + const { indexes } = await paginate( + async (args: any) => { + const databasesService = await getDatabasesService(); + return await databasesService.listIndexes( + args.databaseId, + args.collectionId, + args.queries || [], ); - }, - expectIndexes: async (databaseId: string, collectionId: string, indexKeys: string[], iteration: number = 1): Promise<boolean> => { - if (iteration > pollMaxDebounces) { - return false; - } + }, + { + databaseId, + collectionId, + }, + 100, + "indexes", + ); - if (pollMaxDebounces === POLL_DEFAULT_VALUE) { - let steps = Math.max(1, Math.ceil(indexKeys.length / STEP_SIZE)); - if (steps > 1 && iteration === 1) { - pollMaxDebounces *= steps; + const ready = indexesKeys.filter((index: any) => + indexes.includes(index.key), + ); - log('Creating a large number of indexes, increasing timeout to ' + (pollMaxDebounces * POLL_DEBOUNCE / 1000 / 60) + ' minutes') - } - } + if (ready.length === 0) { + return true; + } - const { indexes } = await paginate(databasesListIndexes, { - databaseId, - collectionId, - parseOutput: false - }, 100, 'indexes'); + await new Promise((resolve) => setTimeout(resolve, POLL_DEBOUNCE)); - const ready = indexes - .filter((index: any) => { - if (indexKeys.includes(index.key)) { - if (['stuck', 'failed'].includes(index.status)) { - throw new Error(`Index '${index.key}' failed!`); - } + return await awaitPools.expectIndexes( + databaseId, + collectionId, + indexesKeys, + iteration + 1, + ); + }, + expectIndexes: async ( + databaseId: string, + collectionId: string, + indexKeys: string[], + iteration: number = 1, + ): Promise<boolean> => { + if (iteration > pollMaxDebounces) { + return false; + } + + if (pollMaxDebounces === POLL_DEFAULT_VALUE) { + let steps = Math.max(1, Math.ceil(indexKeys.length / STEP_SIZE)); + if (steps > 1 && iteration === 1) { + pollMaxDebounces *= steps; + + log( + "Creating a large number of indexes, increasing timeout to " + + (pollMaxDebounces * POLL_DEBOUNCE) / 1000 / 60 + + " minutes", + ); + } + } - return index.status === 'available'; - } + const { indexes } = await paginate( + async (args: any) => { + const databasesService = await getDatabasesService(); + return await databasesService.listIndexes( + args.databaseId, + args.collectionId, + args.queries || [], + ); + }, + { + databaseId, + collectionId, + }, + 100, + "indexes", + ); - return false; - }) - .map((index: any) => index.key); + const ready = indexes + .filter((index: any) => { + if (indexKeys.includes(index.key)) { + if (["stuck", "failed"].includes(index.status)) { + throw new Error(`Index '${index.key}' failed!`); + } - if (ready.length >= indexKeys.length) { - return true; + return index.status === "available"; } - await new Promise(resolve => setTimeout(resolve, POLL_DEBOUNCE)); + return false; + }) + .map((index: any) => index.key); - return await awaitPools.expectIndexes( - databaseId, - collectionId, - indexKeys, - iteration + 1 - ); - }, -} - -const getConfirmation = async (): Promise<boolean> => { - if (cliConfig.force) { - return true; + if (ready.length >= indexKeys.length) { + return true; } - async function fixConfirmation(): Promise<string> { - const answers = await inquirer.prompt(questionPushChangesConfirmation); - if (answers.changes !== 'YES' && answers.changes !== 'NO') { - return await fixConfirmation(); - } - - return answers.changes; - } + await new Promise((resolve) => setTimeout(resolve, POLL_DEBOUNCE)); - let answers = await inquirer.prompt(questionPushChanges); + return await awaitPools.expectIndexes( + databaseId, + collectionId, + indexKeys, + iteration + 1, + ); + }, +}; - if (answers.changes !== 'YES' && answers.changes !== 'NO') { - answers.changes = await fixConfirmation(); - } +const getConfirmation = async (): Promise<boolean> => { + if (cliConfig.force) { + return true; + } - if (answers.changes === 'YES') { - return true; + async function fixConfirmation(): Promise<string> { + const answers = await inquirer.prompt(questionPushChangesConfirmation); + if (answers.changes !== "YES" && answers.changes !== "NO") { + return await fixConfirmation(); } - warn('Skipping push action. Changes were not applied.'); - return false; + return answers.changes; + } -}; -const isEmpty = (value: any): boolean => (value === null || value === undefined || (typeof value === "string" && value.trim().length === 0) || (Array.isArray(value) && value.length === 0)); + let answers = await inquirer.prompt(questionPushChanges); -const approveChanges = async (resource: any[], resourceGetFunction: Function, keys: Set<string>, resourceName: string, resourcePlural: string, skipKeys: string[] = [], secondId: string = '', secondResourceName: string = ''): Promise<boolean> => { - log('Checking for changes ...'); - const changes: any[] = []; + if (answers.changes !== "YES" && answers.changes !== "NO") { + answers.changes = await fixConfirmation(); + } - await Promise.all(resource.map(async (localResource) => { - try { - const options: Record<string, any> = { - [resourceName]: localResource['$id'], - parseOutput: false, - }; + if (answers.changes === "YES") { + return true; + } - if (secondId !== '' && secondResourceName !== '') { - options[secondResourceName] = localResource[secondId] - } + warn("Skipping push action. Changes were not applied."); + return false; +}; +const isEmpty = (value: any): boolean => + value === null || + value === undefined || + (typeof value === "string" && value.trim().length === 0) || + (Array.isArray(value) && value.length === 0); + +const approveChanges = async ( + resource: any[], + resourceGetFunction: Function, + keys: Set<string>, + resourceName: string, + resourcePlural: string, + skipKeys: string[] = [], + secondId: string = "", + secondResourceName: string = "", +): Promise<boolean> => { + log("Checking for changes ..."); + const changes: any[] = []; + + await Promise.all( + resource.map(async (localResource) => { + try { + const options: Record<string, any> = { + [resourceName]: localResource["$id"], + }; + + if (secondId !== "" && secondResourceName !== "") { + options[secondResourceName] = localResource[secondId]; + } + + const remoteResource = await resourceGetFunction(options); + + for (let [key, value] of Object.entries( + whitelistKeys(remoteResource, keys), + )) { + if (skipKeys.includes(key)) { + continue; + } - const remoteResource = await resourceGetFunction(options); - - for (let [key, value] of Object.entries(whitelistKeys(remoteResource, keys))) { - if (skipKeys.includes(key)) { - continue; - } - - if (isEmpty(value) && isEmpty(localResource[key])) { - continue; - } - - if (Array.isArray(value) && Array.isArray(localResource[key])) { - if (JSON.stringify(value) !== JSON.stringify(localResource[key])) { - changes.push({ - id: localResource['$id'], - key, - remote: chalk.red((value as string[]).join('\n')), - local: chalk.green(localResource[key].join('\n')) - }) - } - } else if (value !== localResource[key]) { - changes.push({ - id: localResource['$id'], - key, - remote: chalk.red(value), - local: chalk.green(localResource[key]) - }) - } - } - } catch (e: any) { - if (Number(e.code) !== 404) { - throw e; + if (isEmpty(value) && isEmpty(localResource[key])) { + continue; + } + + if (Array.isArray(value) && Array.isArray(localResource[key])) { + if (JSON.stringify(value) !== JSON.stringify(localResource[key])) { + changes.push({ + id: localResource["$id"], + key, + remote: chalk.red((value as string[]).join("\n")), + local: chalk.green(localResource[key].join("\n")), + }); } + } else if (value !== localResource[key]) { + changes.push({ + id: localResource["$id"], + key, + remote: chalk.red(value), + local: chalk.green(localResource[key]), + }); + } } - })); - - if (changes.length === 0) { - return true; - } + } catch (e: any) { + if (Number(e.code) !== 404) { + throw e; + } + } + }), + ); - drawTable(changes); - if ((await getConfirmation()) === true) { - return true; - } + if (changes.length === 0) { + return true; + } - success(`Successfully pushed 0 ${resourcePlural}.`); - return false; -} + drawTable(changes); + if ((await getConfirmation()) === true) { + return true; + } -const getObjectChanges = (remote: any, local: any, index: string, what: string): any[] => { - const changes: any[] = []; - - if (remote[index] && local[index]) { - for (let [service, status] of Object.entries(remote[index])) { - const localValue = local[index][service]; - let valuesEqual = false; + success(`Successfully pushed 0 ${resourcePlural}.`); + return false; +}; - if (Array.isArray(status) && Array.isArray(localValue)) { - valuesEqual = JSON.stringify(status) === JSON.stringify(localValue); - } else { - valuesEqual = status === localValue; - } - - if (!valuesEqual) { - changes.push({ group: what, setting: service, remote: chalk.red(status), local: chalk.green(localValue) }) - } - } +const getObjectChanges = <T extends Record<string, any>>( + remote: T, + local: T, + index: keyof T, + what: string, +): ObjectChange[] => { + const changes: ObjectChange[] = []; + + const remoteNested = remote[index]; + const localNested = local[index]; + + if ( + remoteNested && + localNested && + typeof remoteNested === "object" && + !Array.isArray(remoteNested) && + typeof localNested === "object" && + !Array.isArray(localNested) + ) { + const remoteObj = remoteNested as Record<string, ComparableValue>; + const localObj = localNested as Record<string, ComparableValue>; + + for (const [service, status] of Object.entries(remoteObj)) { + const localValue = localObj[service]; + let valuesEqual = false; + + if (Array.isArray(status) && Array.isArray(localValue)) { + valuesEqual = JSON.stringify(status) === JSON.stringify(localValue); + } else { + valuesEqual = status === localValue; + } + + if (!valuesEqual) { + changes.push({ + group: what, + setting: service, + remote: chalk.red(String(status ?? "")), + local: chalk.green(String(localValue ?? "")), + }); + } } + } - return changes; -} - -const createAttribute = (databaseId: string, collectionId: string, attribute: any): Promise<any> => { - switch (attribute.type) { - case 'string': - switch (attribute.format) { - case 'email': - return databasesCreateEmailAttribute({ - databaseId, - collectionId, - key: attribute.key, - required: attribute.required, - xdefault: attribute.default, - array: attribute.array, - parseOutput: false - }) - case 'url': - return databasesCreateUrlAttribute({ - databaseId, - collectionId, - key: attribute.key, - required: attribute.required, - xdefault: attribute.default, - array: attribute.array, - parseOutput: false - }) - case 'ip': - return databasesCreateIpAttribute({ - databaseId, - collectionId, - key: attribute.key, - required: attribute.required, - xdefault: attribute.default, - array: attribute.array, - parseOutput: false - }) - case 'enum': - return databasesCreateEnumAttribute({ - databaseId, - collectionId, - key: attribute.key, - elements: attribute.elements, - required: attribute.required, - xdefault: attribute.default, - array: attribute.array, - parseOutput: false - }) - default: - return databasesCreateStringAttribute({ - databaseId, - collectionId, - key: attribute.key, - size: attribute.size, - required: attribute.required, - xdefault: attribute.default, - array: attribute.array, - encrypt: attribute.encrypt, - parseOutput: false - }) + return changes; +}; - } - case 'integer': - return databasesCreateIntegerAttribute({ - databaseId, - collectionId, - key: attribute.key, - required: attribute.required, - min: attribute.min, - max: attribute.max, - xdefault: attribute.default, - array: attribute.array, - parseOutput: false - }) - case 'double': - return databasesCreateFloatAttribute({ - databaseId, - collectionId, - key: attribute.key, - required: attribute.required, - min: attribute.min, - max: attribute.max, - xdefault: attribute.default, - array: attribute.array, - parseOutput: false - }) - case 'boolean': - return databasesCreateBooleanAttribute({ - databaseId, - collectionId, - key: attribute.key, - required: attribute.required, - xdefault: attribute.default, - array: attribute.array, - parseOutput: false - }) - case 'datetime': - return databasesCreateDatetimeAttribute({ - databaseId, - collectionId, - key: attribute.key, - required: attribute.required, - xdefault: attribute.default, - array: attribute.array, - parseOutput: false - }) - case 'relationship': - return databasesCreateRelationshipAttribute({ - databaseId, - collectionId, - relatedCollectionId: attribute.relatedTable ?? attribute.relatedCollection, - type: attribute.relationType, - twoWay: attribute.twoWay, - key: attribute.key, - twoWayKey: attribute.twoWayKey, - onDelete: attribute.onDelete, - parseOutput: false - }) - case 'point': - return databasesCreatePointAttribute({ - databaseId, - collectionId, - key:attribute.key, - required:attribute.required, - xdefault:attribute.default, - parseOutput:false - }) - case 'linestring': - return databasesCreateLineAttribute({ - databaseId, - collectionId, - key:attribute.key, - required:attribute.required, - xdefault:attribute.default, - parseOutput:false - }) - case 'polygon': - return databasesCreatePolygonAttribute({ - databaseId, - collectionId, - key:attribute.key, - required:attribute.required, - xdefault:attribute.default, - parseOutput:false - }) +const createAttribute = async ( + databaseId: string, + collectionId: string, + attribute: any, +): Promise<any> => { + const databasesService = await getDatabasesService(); + switch (attribute.type) { + case "string": + switch (attribute.format) { + case "email": + return databasesService.createEmailAttribute({ + databaseId, + collectionId, + key: attribute.key, + required: attribute.required, + xdefault: attribute.default, + array: attribute.array, + }); + case "url": + return databasesService.createUrlAttribute({ + databaseId, + collectionId, + key: attribute.key, + required: attribute.required, + xdefault: attribute.default, + array: attribute.array, + }); + case "ip": + return databasesService.createIpAttribute({ + databaseId, + collectionId, + key: attribute.key, + required: attribute.required, + xdefault: attribute.default, + array: attribute.array, + }); + case "enum": + return databasesService.createEnumAttribute({ + databaseId, + collectionId, + key: attribute.key, + elements: attribute.elements, + required: attribute.required, + xdefault: attribute.default, + array: attribute.array, + }); default: - throw new Error(`Unsupported attribute type: ${attribute.type}`); - } -} - -const updateAttribute = (databaseId: string, collectionId: string, attribute: any): Promise<any> => { - switch (attribute.type) { - case 'string': - switch (attribute.format) { - case 'email': - return databasesUpdateEmailAttribute({ - databaseId, - collectionId, - key: attribute.key, - required: attribute.required, - xdefault: attribute.default, - array: attribute.array, - parseOutput: false - }) - case 'url': - return databasesUpdateUrlAttribute({ - databaseId, - collectionId, - key: attribute.key, - required: attribute.required, - xdefault: attribute.default, - array: attribute.array, - parseOutput: false - }) - case 'ip': - return databasesUpdateIpAttribute({ - databaseId, - collectionId, - key: attribute.key, - required: attribute.required, - xdefault: attribute.default, - array: attribute.array, - parseOutput: false - }) - case 'enum': - return databasesUpdateEnumAttribute({ - databaseId, - collectionId, - key: attribute.key, - elements: attribute.elements, - required: attribute.required, - xdefault: attribute.default, - array: attribute.array, - parseOutput: false - }) - default: - return databasesUpdateStringAttribute({ - databaseId, - collectionId, - key: attribute.key, - size: attribute.size, - required: attribute.required, - xdefault: attribute.default, - array: attribute.array, - parseOutput: false - }) + return databasesService.createStringAttribute({ + databaseId, + collectionId, + key: attribute.key, + size: attribute.size, + required: attribute.required, + xdefault: attribute.default, + array: attribute.array, + encrypt: attribute.encrypt, + }); + } + case "integer": + return databasesService.createIntegerAttribute({ + databaseId, + collectionId, + key: attribute.key, + required: attribute.required, + min: attribute.min, + max: attribute.max, + xdefault: attribute.default, + array: attribute.array, + }); + case "double": + return databasesService.createFloatAttribute({ + databaseId, + collectionId, + key: attribute.key, + required: attribute.required, + min: attribute.min, + max: attribute.max, + xdefault: attribute.default, + array: attribute.array, + }); + case "boolean": + return databasesService.createBooleanAttribute({ + databaseId, + collectionId, + key: attribute.key, + required: attribute.required, + xdefault: attribute.default, + array: attribute.array, + }); + case "datetime": + return databasesService.createDatetimeAttribute({ + databaseId, + collectionId, + key: attribute.key, + required: attribute.required, + xdefault: attribute.default, + array: attribute.array, + }); + case "relationship": + return databasesService.createRelationshipAttribute({ + databaseId, + collectionId, + relatedCollectionId: + attribute.relatedTable ?? attribute.relatedCollection, + type: attribute.relationType, + twoWay: attribute.twoWay, + key: attribute.key, + twoWayKey: attribute.twoWayKey, + onDelete: attribute.onDelete, + }); + case "point": + return databasesService.createPointAttribute({ + databaseId, + collectionId, + key: attribute.key, + required: attribute.required, + xdefault: attribute.default, + }); + case "linestring": + return databasesService.createLineAttribute({ + databaseId, + collectionId, + key: attribute.key, + required: attribute.required, + xdefault: attribute.default, + }); + case "polygon": + return databasesService.createPolygonAttribute({ + databaseId, + collectionId, + key: attribute.key, + required: attribute.required, + xdefault: attribute.default, + }); + default: + throw new Error(`Unsupported attribute type: ${attribute.type}`); + } +}; - } - case 'integer': - return databasesUpdateIntegerAttribute({ - databaseId, - collectionId, - key: attribute.key, - required: attribute.required, - min: attribute.min, - max: attribute.max, - xdefault: attribute.default, - array: attribute.array, - parseOutput: false - }) - case 'double': - return databasesUpdateFloatAttribute({ - databaseId, - collectionId, - key: attribute.key, - required: attribute.required, - min: attribute.min, - max: attribute.max, - xdefault: attribute.default, - array: attribute.array, - parseOutput: false - }) - case 'boolean': - return databasesUpdateBooleanAttribute({ - databaseId, - collectionId, - key: attribute.key, - required: attribute.required, - xdefault: attribute.default, - array: attribute.array, - parseOutput: false - }) - case 'datetime': - return databasesUpdateDatetimeAttribute({ - databaseId, - collectionId, - key: attribute.key, - required: attribute.required, - xdefault: attribute.default, - array: attribute.array, - parseOutput: false - }) - case 'relationship': - return databasesUpdateRelationshipAttribute({ - databaseId, - collectionId, - relatedCollectionId: attribute.relatedTable ?? attribute.relatedCollection, - type: attribute.relationType, - twoWay: attribute.twoWay, - key: attribute.key, - twoWayKey: attribute.twoWayKey, - onDelete: attribute.onDelete, - parseOutput: false - }) - case 'point': - return databasesUpdatePointAttribute({ - databaseId, - collectionId, - key:attribute.key, - required:attribute.required, - xdefault:attribute.default, - parseOutput:false - }) - case 'linestring': - return databasesUpdateLineAttribute({ - databaseId, - collectionId, - key:attribute.key, - required:attribute.required, - xdefault:attribute.default, - parseOutput:false - }) - case 'polygon': - return databasesUpdatePolygonAttribute({ - databaseId, - collectionId, - key:attribute.key, - required:attribute.required, - xdefault:attribute.default, - parseOutput:false - }) +const updateAttribute = async ( + databaseId: string, + collectionId: string, + attribute: any, +): Promise<any> => { + const databasesService = await getDatabasesService(); + switch (attribute.type) { + case "string": + switch (attribute.format) { + case "email": + return databasesService.updateEmailAttribute({ + databaseId, + collectionId, + key: attribute.key, + required: attribute.required, + xdefault: attribute.default, + }); + case "url": + return databasesService.updateUrlAttribute({ + databaseId, + collectionId, + key: attribute.key, + required: attribute.required, + xdefault: attribute.default, + }); + case "ip": + return databasesService.updateIpAttribute({ + databaseId, + collectionId, + key: attribute.key, + required: attribute.required, + xdefault: attribute.default, + }); + case "enum": + return databasesService.updateEnumAttribute({ + databaseId, + collectionId, + key: attribute.key, + elements: attribute.elements, + required: attribute.required, + xdefault: attribute.default, + }); default: - throw new Error(`Unsupported attribute type: ${attribute.type}`); - } -} -const deleteAttribute = async (collection: any, attribute: any, isIndex: boolean = false): Promise<void> => { - log(`Deleting ${isIndex ? 'index' : 'attribute'} ${attribute.key} of ${collection.name} ( ${collection['$id']} )`); - - if (isIndex) { - await databasesDeleteIndex({ - databaseId: collection['databaseId'], - collectionId: collection['$id'], + return databasesService.updateStringAttribute({ + databaseId, + collectionId, key: attribute.key, - parseOutput: false - }); - return; - } - - await databasesDeleteAttribute({ - databaseId: collection['databaseId'], - collectionId: collection['$id'], + required: attribute.required, + xdefault: attribute.default, + }); + } + case "integer": + return databasesService.updateIntegerAttribute({ + databaseId, + collectionId, key: attribute.key, - parseOutput: false - }); -} + required: attribute.required, + min: attribute.min, + max: attribute.max, + xdefault: attribute.default, + }); + case "double": + return databasesService.updateFloatAttribute({ + databaseId, + collectionId, + key: attribute.key, + required: attribute.required, + min: attribute.min, + max: attribute.max, + xdefault: attribute.default, + }); + case "boolean": + return databasesService.updateBooleanAttribute({ + databaseId, + collectionId, + key: attribute.key, + required: attribute.required, + xdefault: attribute.default, + }); + case "datetime": + return databasesService.updateDatetimeAttribute({ + databaseId, + collectionId, + key: attribute.key, + required: attribute.required, + xdefault: attribute.default, + }); + case "relationship": + return databasesService.updateRelationshipAttribute({ + databaseId, + collectionId, + key: attribute.key, + onDelete: attribute.onDelete, + }); + case "point": + return databasesService.updatePointAttribute({ + databaseId, + collectionId, + key: attribute.key, + required: attribute.required, + xdefault: attribute.default, + }); + case "linestring": + return databasesService.updateLineAttribute({ + databaseId, + collectionId, + key: attribute.key, + required: attribute.required, + xdefault: attribute.default, + }); + case "polygon": + return databasesService.updatePolygonAttribute({ + databaseId, + collectionId, + key: attribute.key, + required: attribute.required, + xdefault: attribute.default, + }); + default: + throw new Error(`Unsupported attribute type: ${attribute.type}`); + } +}; +const deleteAttribute = async ( + collection: any, + attribute: any, + isIndex: boolean = false, +): Promise<void> => { + log( + `Deleting ${isIndex ? "index" : "attribute"} ${attribute.key} of ${collection.name} ( ${collection["$id"]} )`, + ); + + const databasesService = await getDatabasesService(); + if (isIndex) { + await databasesService.deleteIndex( + collection["databaseId"], + collection["$id"], + attribute.key, + ); + return; + } + + await databasesService.deleteAttribute( + collection["databaseId"], + collection["$id"], + attribute.key, + ); +}; const isEqual = (a: any, b: any): boolean => { - if (a === b) return true; - - if (a && b && typeof a === 'object' && typeof b === 'object') { - if (a.constructor && a.constructor.name === 'BigNumber' && - b.constructor && b.constructor.name === 'BigNumber') { - return a.eq(b); - } - - if (typeof a.equals === 'function') { - return a.equals(b); - } - - if (typeof a.eq === 'function') { - return a.eq(b); - } - } - - if (typeof a === 'number' && typeof b === 'number') { - if (isNaN(a) && isNaN(b)) return true; - if (!isFinite(a) && !isFinite(b)) return a === b; - return Math.abs(a - b) < Number.EPSILON; + if (a === b) return true; + + if (a && b && typeof a === "object" && typeof b === "object") { + if ( + a.constructor && + a.constructor.name === "BigNumber" && + b.constructor && + b.constructor.name === "BigNumber" + ) { + return a.eq(b); } - - return false; -}; -const compareAttribute = (remote: any, local: any, reason: string, key: string): string => { - if (isEmpty(remote) && isEmpty(local)) { - return reason; + if (typeof a.equals === "function") { + return a.equals(b); } - if (Array.isArray(remote) && Array.isArray(local)) { - if (JSON.stringify(remote) !== JSON.stringify(local)) { - const bol = reason === '' ? '' : '\n'; - reason += `${bol}${key} changed from ${chalk.red(remote)} to ${chalk.green(local)}`; - } - } else if (!isEqual(remote, local)) { - const bol = reason === '' ? '' : '\n'; - reason += `${bol}${key} changed from ${chalk.red(remote)} to ${chalk.green(local)}`; + if (typeof a.eq === "function") { + return a.eq(b); } + } - return reason -} + if (typeof a === "number" && typeof b === "number") { + if (isNaN(a) && isNaN(b)) return true; + if (!isFinite(a) && !isFinite(b)) return a === b; + return Math.abs(a - b) < Number.EPSILON; + } -interface AttributeChange { - key: string; - attribute: any; - reason: string; - action: string; -} + return false; +}; + +const compareAttribute = ( + remote: any, + local: any, + reason: string, + key: string, +): string => { + if (isEmpty(remote) && isEmpty(local)) { + return reason; + } + + if (Array.isArray(remote) && Array.isArray(local)) { + if (JSON.stringify(remote) !== JSON.stringify(local)) { + const bol = reason === "" ? "" : "\n"; + reason += `${bol}${key} changed from ${chalk.red(remote)} to ${chalk.green(local)}`; + } + } else if (!isEqual(remote, local)) { + const bol = reason === "" ? "" : "\n"; + reason += `${bol}${key} changed from ${chalk.red(remote)} to ${chalk.green(local)}`; + } + + return reason; +}; /** * Check if attribute non-changeable fields has been changed * If so return the differences as an object. */ -const checkAttributeChanges = (remote: any, local: any, collection: any, recreating: boolean = true): AttributeChange | undefined => { - if (local === undefined) { - return undefined; - } - - const keyName = `${chalk.yellow(local.key)} in ${collection.name} (${collection['$id']})`; - const action = chalk.cyan(recreating ? 'recreating' : 'changing'); - let reason = ''; - let attribute = recreating ? remote : local; +const checkAttributeChanges = ( + remote: any, + local: any, + collection: any, + recreating: boolean = true, +): AttributeChange | undefined => { + if (local === undefined) { + return undefined; + } - for (let key of Object.keys(remote)) { - if (!KeysAttributes.has(key)) { - continue; - } + const keyName = `${chalk.yellow(local.key)} in ${collection.name} (${collection["$id"]})`; + const action = chalk.cyan(recreating ? "recreating" : "changing"); + let reason = ""; + let attribute = recreating ? remote : local; - if (changeableKeys.includes(key)) { - if (!recreating) { - reason = compareAttribute(remote[key], local[key], reason, key) - } - continue; - } + for (let key of Object.keys(remote)) { + if (!KeysAttributes.has(key)) { + continue; + } - if (!recreating) { - continue; - } + if (changeableKeys.includes(key)) { + if (!recreating) { + reason = compareAttribute(remote[key], local[key], reason, key); + } + continue; + } - reason = compareAttribute(remote[key], local[key], reason, key) + if (!recreating) { + continue; } - return reason === '' ? undefined : { key: keyName, attribute, reason, action }; -} + reason = compareAttribute(remote[key], local[key], reason, key); + } + + return reason === "" + ? undefined + : { key: keyName, attribute, reason, action }; +}; /** * Check if attributes contain the given attribute */ -const attributesContains = (attribute: any, attributes: any[]): any => attributes.find((attr) => attr.key === attribute.key); - -const generateChangesObject = (attribute: any, collection: any, isAdding: boolean): AttributeChange => { - return { - key: `${chalk.yellow(attribute.key)} in ${collection.name} (${collection['$id']})`, - attribute: attribute, - reason: isAdding ? 'Field isn\'t present on the remote server' : 'Field isn\'t present on the appwrite.config.json file', - action: isAdding ? chalk.green('adding') : chalk.red('deleting') - }; +const attributesContains = (attribute: any, attributes: any[]): any => + attributes.find((attr) => attr.key === attribute.key); + +const generateChangesObject = ( + attribute: any, + collection: any, + isAdding: boolean, +): AttributeChange => { + return { + key: `${chalk.yellow(attribute.key)} in ${collection.name} (${collection["$id"]})`, + attribute: attribute, + reason: isAdding + ? "Field isn't present on the remote server" + : "Field isn't present on the appwrite.config.json file", + action: isAdding ? chalk.green("adding") : chalk.red("deleting"), + }; }; /** * Filter deleted and recreated attributes, * return list of attributes to create */ -const attributesToCreate = async (remoteAttributes: any[], localAttributes: any[], collection: any, isIndex: boolean = false): Promise<any[]> => { - - const deleting = remoteAttributes.filter((attribute) => !attributesContains(attribute, localAttributes)).map((attr) => generateChangesObject(attr, collection, false)); - const adding = localAttributes.filter((attribute) => !attributesContains(attribute, remoteAttributes)).map((attr) => generateChangesObject(attr, collection, true)); - const conflicts = remoteAttributes.map((attribute) => checkAttributeChanges(attribute, attributesContains(attribute, localAttributes), collection)).filter(attribute => attribute !== undefined) as AttributeChange[]; - const changes = remoteAttributes.map((attribute) => checkAttributeChanges(attribute, attributesContains(attribute, localAttributes), collection, false)) - .filter(attribute => attribute !== undefined) - .filter(attribute => conflicts.filter(attr => attribute!.key === attr.key).length !== 1) as AttributeChange[]; - - let changedAttributes: any[] = []; - const changing = [...deleting, ...adding, ...conflicts, ...changes] - if (changing.length === 0) { - return changedAttributes; +const attributesToCreate = async ( + remoteAttributes: any[], + localAttributes: any[], + collection: any, + isIndex: boolean = false, +): Promise<any[]> => { + const deleting = remoteAttributes + .filter((attribute) => !attributesContains(attribute, localAttributes)) + .map((attr) => generateChangesObject(attr, collection, false)); + const adding = localAttributes + .filter((attribute) => !attributesContains(attribute, remoteAttributes)) + .map((attr) => generateChangesObject(attr, collection, true)); + const conflicts = remoteAttributes + .map((attribute) => + checkAttributeChanges( + attribute, + attributesContains(attribute, localAttributes), + collection, + ), + ) + .filter((attribute) => attribute !== undefined) as AttributeChange[]; + const changes = remoteAttributes + .map((attribute) => + checkAttributeChanges( + attribute, + attributesContains(attribute, localAttributes), + collection, + false, + ), + ) + .filter((attribute) => attribute !== undefined) + .filter( + (attribute) => + conflicts.filter((attr) => attribute!.key === attr.key).length !== 1, + ) as AttributeChange[]; + + let changedAttributes: any[] = []; + const changing = [...deleting, ...adding, ...conflicts, ...changes]; + if (changing.length === 0) { + return changedAttributes; + } + + log( + !cliConfig.force + ? "There are pending changes in your collection deployment" + : "List of applied changes", + ); + + drawTable( + changing.map((change) => { + return { Key: change.key, Action: change.action, Reason: change.reason }; + }), + ); + + if (!cliConfig.force) { + if (deleting.length > 0 && !isIndex) { + console.log( + `${chalk.red("------------------------------------------------------")}`, + ); + console.log( + `${chalk.red("| WARNING: Attribute deletion may cause loss of data |")}`, + ); + console.log( + `${chalk.red("------------------------------------------------------")}`, + ); + console.log(); + } + if (conflicts.length > 0 && !isIndex) { + console.log( + `${chalk.red("--------------------------------------------------------")}`, + ); + console.log( + `${chalk.red("| WARNING: Attribute recreation may cause loss of data |")}`, + ); + console.log( + `${chalk.red("--------------------------------------------------------")}`, + ); + console.log(); } - log(!cliConfig.force ? 'There are pending changes in your collection deployment' : 'List of applied changes'); - - drawTable(changing.map((change) => { - return { Key: change.key, Action: change.action, Reason: change.reason, }; - })); - - if (!cliConfig.force) { - if (deleting.length > 0 && !isIndex) { - console.log(`${chalk.red('------------------------------------------------------')}`); - console.log(`${chalk.red('| WARNING: Attribute deletion may cause loss of data |')}`); - console.log(`${chalk.red('------------------------------------------------------')}`); - console.log(); - } - if (conflicts.length > 0 && !isIndex) { - console.log(`${chalk.red('--------------------------------------------------------')}`); - console.log(`${chalk.red('| WARNING: Attribute recreation may cause loss of data |')}`); - console.log(`${chalk.red('--------------------------------------------------------')}`); - console.log(); - } - - if ((await getConfirmation()) !== true) { - return changedAttributes; - } - } - - if (conflicts.length > 0) { - changedAttributes = conflicts.map((change) => change.attribute); - await Promise.all(changedAttributes.map((changed) => deleteAttribute(collection, changed, isIndex))); - remoteAttributes = remoteAttributes.filter((attribute) => !attributesContains(attribute, changedAttributes)) - } - - if (changes.length > 0) { - changedAttributes = changes.map((change) => change.attribute); - await Promise.all(changedAttributes.map((changed) => updateAttribute(collection['databaseId'], collection['$id'], changed))); + if ((await getConfirmation()) !== true) { + return changedAttributes; } + } - const deletingAttributes = deleting.map((change) => change.attribute); - await Promise.all(deletingAttributes.map((attribute) => deleteAttribute(collection, attribute, isIndex))); - const attributeKeys = [...remoteAttributes.map((attribute: any) => attribute.key), ...deletingAttributes.map((attribute: any) => attribute.key)] - - if (attributeKeys.length) { - const deleteAttributesPoolStatus = await awaitPools.deleteAttributes(collection['databaseId'], collection['$id'], attributeKeys); + if (conflicts.length > 0) { + changedAttributes = conflicts.map((change) => change.attribute); + await Promise.all( + changedAttributes.map((changed) => + deleteAttribute(collection, changed, isIndex), + ), + ); + remoteAttributes = remoteAttributes.filter( + (attribute) => !attributesContains(attribute, changedAttributes), + ); + } + + if (changes.length > 0) { + changedAttributes = changes.map((change) => change.attribute); + await Promise.all( + changedAttributes.map((changed) => + updateAttribute(collection["databaseId"], collection["$id"], changed), + ), + ); + } + + const deletingAttributes = deleting.map((change) => change.attribute); + await Promise.all( + deletingAttributes.map((attribute) => + deleteAttribute(collection, attribute, isIndex), + ), + ); + const attributeKeys = [ + ...remoteAttributes.map((attribute: any) => attribute.key), + ...deletingAttributes.map((attribute: any) => attribute.key), + ]; + + if (attributeKeys.length) { + const deleteAttributesPoolStatus = await awaitPools.deleteAttributes( + collection["databaseId"], + collection["$id"], + attributeKeys, + ); - if (!deleteAttributesPoolStatus) { - throw new Error("Attribute deletion timed out."); - } + if (!deleteAttributesPoolStatus) { + throw new Error("Attribute deletion timed out."); } + } - return localAttributes.filter((attribute) => !attributesContains(attribute, remoteAttributes)); -} - -const createIndexes = async (indexes: any[], collection: any): Promise<void> => { - log(`Creating indexes ...`) - - for (let index of indexes) { - await databasesCreateIndex({ - databaseId: collection['databaseId'], - collectionId: collection['$id'], - key: index.key, - type: index.type, - attributes: index.columns ?? index.attributes, - orders: index.orders, - parseOutput: false - }); - } + return localAttributes.filter( + (attribute) => !attributesContains(attribute, remoteAttributes), + ); +}; - const result = await awaitPools.expectIndexes( - collection['databaseId'], - collection['$id'], - indexes.map((index: any) => index.key) +const createIndexes = async ( + indexes: any[], + collection: any, +): Promise<void> => { + log(`Creating indexes ...`); + + const databasesService = await getDatabasesService(); + for (let index of indexes) { + await databasesService.createIndex( + collection["databaseId"], + collection["$id"], + index.key, + index.type, + index.columns ?? index.attributes, + index.orders, ); + } - if (!result) { - throw new Error('Index creation timed out.'); - } - - success(`Created ${indexes.length} indexes`); -} - -const createAttributes = async (attributes: any[], collection: any): Promise<void> => { - for (let attribute of attributes) { - if (attribute.side !== 'child') { - await createAttribute(collection['databaseId'], collection['$id'], attribute); - } - } + const result = await awaitPools.expectIndexes( + collection["databaseId"], + collection["$id"], + indexes.map((index: any) => index.key), + ); - const result = await awaitPools.expectAttributes( - collection['databaseId'], - collection['$id'], - collection.attributes.filter((attribute: any) => attribute.side !== 'child').map((attribute: any) => attribute.key) - ); + if (!result) { + throw new Error("Index creation timed out."); + } - if (!result) { - throw new Error(`Attribute creation timed out.`); - } + success(`Created ${indexes.length} indexes`); +}; - success(`Created ${attributes.length} attributes`); -} +const createAttributes = async ( + attributes: any[], + collection: any, +): Promise<void> => { + for (let attribute of attributes) { + if (attribute.side !== "child") { + await createAttribute( + collection["databaseId"], + collection["$id"], + attribute, + ); + } + } + + const result = await awaitPools.expectAttributes( + collection["databaseId"], + collection["$id"], + collection.attributes + .filter((attribute: any) => attribute.side !== "child") + .map((attribute: any) => attribute.key), + ); + + if (!result) { + throw new Error(`Attribute creation timed out.`); + } + + success(`Created ${attributes.length} attributes`); +}; const createColumns = async (columns: any[], table: any): Promise<void> => { - for (let column of columns) { - if (column.side !== 'child') { - await createAttribute(table['databaseId'], table['$id'], column); - } + for (let column of columns) { + if (column.side !== "child") { + await createAttribute(table["databaseId"], table["$id"], column); } + } - const result = await awaitPools.expectAttributes( - table['databaseId'], - table['$id'], - table.columns.filter((column: any) => column.side !== 'child').map((column: any) => column.key) - ); - - if (!result) { - throw new Error(`Column creation timed out.`); - } + const result = await awaitPools.expectAttributes( + table["databaseId"], + table["$id"], + table.columns + .filter((column: any) => column.side !== "child") + .map((column: any) => column.key), + ); - success(`Created ${columns.length} columns`); -} + if (!result) { + throw new Error(`Column creation timed out.`); + } -const pushResources = async (): Promise<void> => { - const actions: Record<string, (options?: any) => Promise<void>> = { - settings: pushSettings, - functions: pushFunction, - sites: pushSite, - collections: pushCollection, - tables: pushTable, - buckets: pushBucket, - teams: pushTeam, - messages: pushMessagingTopic - } - - if (cliConfig.all) { - for (let action of Object.values(actions)) { - await action({ returnOnZero: true }); - } - } else { - const answers = await inquirer.prompt(questionsPushResources[0]); + success(`Created ${columns.length} columns`); +}; - const action = actions[answers.resource]; - if (action !== undefined) { - await action({ returnOnZero: true }); - } - } +const pushResources = async ({ + skipDeprecated = false, +}: PushResourcesOptions = {}): Promise<void> => { + const actions: Record<string, (options?: any) => Promise<void>> = { + settings: pushSettings, + functions: pushFunction, + sites: pushSite, + collections: pushCollection, + tables: pushTable, + buckets: pushBucket, + teams: pushTeam, + messages: pushMessagingTopic, + }; + + if (skipDeprecated) { + delete actions.collections; + } + + if (cliConfig.all) { + for (let action of Object.values(actions)) { + await action(); + } + } else { + const answers = await inquirer.prompt(questionsPushResources); + + const action = actions[answers.resource]; + if (action !== undefined) { + await action(); + } + } }; const pushSettings = async (): Promise<void> => { - checkDeployConditions(localConfig); + checkDeployConditions(localConfig); - try { - let response = await projectsGet({ - parseOutput: false, - projectId: localConfig.getProject().projectId - }); + try { + const projectsService = await getProjectsService(); + let response = await projectsService.get( + localConfig.getProject().projectId, + ); - const remoteSettings = localConfig.createSettingsObject(response ?? {}); - const localSettings = localConfig.getProject().projectSettings ?? {}; + const remoteSettings = localConfig.createSettingsObject(response ?? {}); + const localSettings = localConfig.getProject().projectSettings ?? {}; - log('Checking for changes ...'); - const changes: any[] = []; + log("Checking for changes ..."); + const changes: any[] = []; - changes.push(...(getObjectChanges(remoteSettings, localSettings, 'services', 'Service'))); - changes.push(...(getObjectChanges(remoteSettings['auth'] ?? {}, localSettings['auth'] ?? {}, 'methods', 'Auth method'))); - changes.push(...(getObjectChanges(remoteSettings['auth'] ?? {}, localSettings['auth'] ?? {}, 'security', 'Auth security'))); + changes.push( + ...getObjectChanges(remoteSettings, localSettings, "services", "Service"), + ); + changes.push( + ...getObjectChanges( + remoteSettings["auth"] ?? {}, + localSettings["auth"] ?? {}, + "methods", + "Auth method", + ), + ); + changes.push( + ...getObjectChanges( + remoteSettings["auth"] ?? {}, + localSettings["auth"] ?? {}, + "security", + "Auth security", + ), + ); - if (changes.length > 0) { - drawTable(changes); - if ((await getConfirmation()) !== true) { - success(`Successfully pushed 0 project settings.`); - return; - } - } - } catch (e) { + if (changes.length > 0) { + drawTable(changes); + if ((await getConfirmation()) !== true) { + success(`Successfully pushed 0 project settings.`); + return; + } } + } catch (e) {} - try { - log("Pushing project settings ..."); - - const projectId = localConfig.getProject().projectId; - const projectName = localConfig.getProject().projectName; - const settings = localConfig.getProject().projectSettings ?? {}; - - if (projectName) { - log("Applying project name ..."); - await projectsUpdate({ - projectId, - name: projectName, - parseOutput: false - }); - } + try { + log("Pushing project settings ..."); - if (settings.services) { - log("Applying service statuses ..."); - for (let [service, status] of Object.entries(settings.services)) { - await projectsUpdateServiceStatus({ - projectId, - service, - status, - parseOutput: false - }); - } - } + const projectsService = await getProjectsService(); + const projectId = localConfig.getProject().projectId; + const projectName = localConfig.getProject().projectName; + const settings = localConfig.getProject().projectSettings ?? {}; - if (settings.auth) { - if (settings.auth.security) { - log("Applying auth security settings ..."); - await projectsUpdateAuthDuration({ projectId, duration: settings.auth.security.duration, parseOutput: false }); - await projectsUpdateAuthLimit({ projectId, limit: settings.auth.security.limit, parseOutput: false }); - await projectsUpdateAuthSessionsLimit({ projectId, limit: settings.auth.security.sessionsLimit, parseOutput: false }); - await projectsUpdateAuthPasswordDictionary({ projectId, enabled: settings.auth.security.passwordDictionary, parseOutput: false }); - await projectsUpdateAuthPasswordHistory({ projectId, limit: settings.auth.security.passwordHistory, parseOutput: false }); - await projectsUpdatePersonalDataCheck({ projectId, enabled: settings.auth.security.personalDataCheck, parseOutput: false }); - await projectsUpdateSessionAlerts({ projectId, alerts: settings.auth.security.sessionAlerts, parseOutput: false }); - await projectsUpdateMockNumbers({ projectId, numbers: settings.auth.security.mockNumbers, parseOutput: false }); - } - - if (settings.auth.methods) { - log("Applying auth methods statuses ..."); - - for (let [method, status] of Object.entries(settings.auth.methods)) { - await projectsUpdateAuthStatus({ - projectId, - method, - status, - parseOutput: false - }); - } - } - } - - success(`Successfully pushed ${chalk.bold('all')} project settings.`); - } catch (e) { - throw e; + if (projectName) { + log("Applying project name ..."); + await projectsService.update(projectId, projectName); } -} -interface PushSiteOptions { - siteId?: string; - async?: boolean; - code?: boolean; - withVariables?: boolean; - returnOnZero?: boolean; -} - -const pushSite = async({ siteId, async: asyncDeploy, code, withVariables }: PushSiteOptions = { returnOnZero: false }): Promise<void> => { - process.chdir(localConfig.configDirectoryPath) + if (settings.services) { + log("Applying service statuses ..."); + for (let [service, status] of Object.entries(settings.services)) { + await projectsService.updateServiceStatus( + projectId, + service as ApiService, + status, + ); + } + } - const siteIds: string[] = []; + if (settings.auth) { + if (settings.auth.security) { + log("Applying auth security settings ..."); + await projectsService.updateAuthDuration( + projectId, + settings.auth.security.duration, + ); + await projectsService.updateAuthLimit( + projectId, + settings.auth.security.limit, + ); + await projectsService.updateAuthSessionsLimit( + projectId, + settings.auth.security.sessionsLimit, + ); + await projectsService.updateAuthPasswordDictionary( + projectId, + settings.auth.security.passwordDictionary, + ); + await projectsService.updateAuthPasswordHistory( + projectId, + settings.auth.security.passwordHistory, + ); + await projectsService.updatePersonalDataCheck( + projectId, + settings.auth.security.personalDataCheck, + ); + await projectsService.updateSessionAlerts( + projectId, + settings.auth.security.sessionAlerts, + ); + await projectsService.updateMockNumbers( + projectId, + settings.auth.security.mockNumbers, + ); + } - if(siteId) { - siteIds.push(siteId); - } else if (cliConfig.all) { - checkDeployConditions(localConfig); - const sites = localConfig.getSites(); - siteIds.push(...sites.map((site: any) => { - return site.$id; - })); - } + if (settings.auth.methods) { + log("Applying auth methods statuses ..."); - if (siteIds.length <= 0) { - const answers = await inquirer.prompt(questionsPushSites[0]); - if (answers.sites) { - siteIds.push(...answers.sites); + for (let [method, status] of Object.entries(settings.auth.methods)) { + await projectsService.updateAuthStatus( + projectId, + method as AuthMethod, + status, + ); } + } } - if (siteIds.length === 0) { - log("No sites found."); - hint("Use 'appwrite pull sites' to synchronize existing one, or use 'appwrite init site' to create a new one."); - return; - } - - let sites = siteIds.map((id: string) => { - const sites = localConfig.getSites(); - const site = sites.find((s: any) => s.$id === id); + success(`Successfully pushed ${chalk.bold("all")} project settings.`); + } catch (e) { + throw e; + } +}; - if (!site) { - throw new Error("Site '" + id + "' not found.") - } +const pushSite = async ({ + siteId, + async: asyncDeploy, + code, + withVariables, +}: PushSiteOptions = {}): Promise<void> => { + process.chdir(localConfig.configDirectoryPath); - return site; - }); + const siteIds: string[] = []; - log('Validating sites ...'); - // Validation is done BEFORE pushing so the deployment process can be run in async with progress update - for (let site of sites) { + if (siteId) { + siteIds.push(siteId); + } else if (cliConfig.all) { + checkDeployConditions(localConfig); + const sites = localConfig.getSites(); + siteIds.push( + ...sites.map((site: any) => { + return site.$id; + }), + ); + } - if (!site.buildCommand) { - log(`Site ${site.name} is missing build command.`); - const answers = await inquirer.prompt(questionsGetEntrypoint) - site.buildCommand = answers.entrypoint; - localConfig.addSite(site); - } + if (siteIds.length <= 0) { + const answers = await inquirer.prompt(questionsPushSites); + if (answers.sites) { + siteIds.push(...answers.sites); } + } - if (!(await approveChanges(sites, sitesGet, KeysSite, 'siteId', 'sites', ['vars']))) { - return; - } + if (siteIds.length === 0) { + log("No sites found."); + hint( + "Use 'appwrite pull sites' to synchronize existing one, or use 'appwrite init site' to create a new one.", + ); + return; + } + + let sites = siteIds.map((id: string) => { + const sites = localConfig.getSites(); + const site = sites.find((s: any) => s.$id === id); + + if (!site) { + throw new Error("Site '" + id + "' not found."); + } + + return site; + }); + + log("Validating sites ..."); + // Validation is done BEFORE pushing so the deployment process can be run in async with progress update + for (let site of sites) { + if (!site.buildCommand) { + log(`Site ${site.name} is missing build command.`); + const answers = await inquirer.prompt(questionsGetEntrypoint); + site.buildCommand = answers.entrypoint; + localConfig.addSite(site); + } + } + + if ( + !(await approveChanges( + sites, + async (args: any) => { + const sitesService = await getSitesService(); + return await sitesService.get({ siteId: args.siteId }); + }, + KeysSite, + "siteId", + "sites", + ["vars"], + )) + ) { + return; + } + + log("Pushing sites ..."); + + Spinner.start(false); + let successfullyPushed = 0; + let successfullyDeployed = 0; + const failedDeployments: any[] = []; + const errors: any[] = []; + + await Promise.all( + sites.map(async (site: any) => { + let response: any = {}; + + const ignore = site.ignore ? "appwrite.config.json" : ".gitignore"; + let siteExists = false; + let deploymentCreated = false; + + const updaterRow = new Spinner({ + status: "", + resource: site.name, + id: site["$id"], + end: `Ignoring using: ${ignore}`, + }); + + updaterRow.update({ status: "Getting" }).startSpinner(SPINNER_DOTS); + + const sitesService = await getSitesService(); + try { + response = await sitesService.get({ siteId: site["$id"] }); + siteExists = true; + if (response.framework !== site.framework) { + updaterRow.fail({ + errorMessage: `Framework mismatch! (local=${site.framework},remote=${response.framework}) Please delete remote site or update your appwrite.config.json`, + }); + return; + } + + updaterRow.update({ status: "Updating" }).replaceSpinner(SPINNER_ARC); + + response = await sitesService.update({ + siteId: site["$id"], + name: site.name, + framework: site.framework, + enabled: site.enabled, + logging: site.logging, + timeout: site.timeout, + installCommand: site.installCommand, + buildCommand: site.buildCommand, + outputDirectory: site.outputDirectory, + buildRuntime: site.buildRuntime, + adapter: site.adapter, + specification: site.specification, + }); + } catch (e: any) { + if (Number(e.code) === 404) { + siteExists = false; + } else { + errors.push(e); + updaterRow.fail({ + errorMessage: e.message ?? "General error occurs please try again", + }); + return; + } + } - log('Pushing sites ...'); + if (!siteExists) { + updaterRow.update({ status: "Creating" }).replaceSpinner(SPINNER_DOTS); - Spinner.start(false); - let successfullyPushed = 0; - let successfullyDeployed = 0; - const failedDeployments: any[] = []; - const errors: any[] = []; + try { + response = await sitesService.create({ + siteId: site.$id, + name: site.name, + framework: site.framework, + enabled: site.enabled, + logging: site.logging, + timeout: site.timeout, + installCommand: site.installCommand, + buildCommand: site.buildCommand, + outputDirectory: site.outputDirectory, + buildRuntime: site.buildRuntime, + adapter: site.adapter, + specification: site.specification, + }); + + let domain = ""; + try { + const consoleService = await getConsoleService(); + const variables = await consoleService.variables(); + domain = ID.unique() + "." + variables["_APP_DOMAIN_SITES"]; + } catch (error) { + console.error("Error fetching console variables."); + throw error; + } + + try { + const proxyService = await getProxyService(); + const rule = await proxyService.createSiteRule(domain, site.$id); + } catch (error) { + console.error("Error creating site rule."); + throw error; + } + + updaterRow.update({ status: "Created" }); + } catch (e: any) { + errors.push(e); + updaterRow.fail({ + errorMessage: e.message ?? "General error occurs please try again", + }); + return; + } + } + + if (withVariables) { + updaterRow + .update({ status: "Creating variables" }) + .replaceSpinner(SPINNER_ARC); + + const sitesService = await getSitesService(); + const { variables } = await paginate( + async (args: any) => { + return await sitesService.listVariables({ siteId: args.siteId }); + }, + { + siteId: site["$id"], + }, + 100, + "variables", + ); - await Promise.all(sites.map(async (site: any) => { - let response: any = {}; + await Promise.all( + variables.map(async (variable: any) => { + const sitesService = await getSitesService(); + await sitesService.deleteVariable({ + siteId: site["$id"], + variableId: variable["$id"], + }); + }), + ); - const ignore = site.ignore ? 'appwrite.config.json' : '.gitignore'; - let siteExists = false; - let deploymentCreated = false; + const envFileLocation = `${site["path"]}/.env`; + let envVariables: Array<{ key: string; value: string }> = []; + try { + if (fs.existsSync(envFileLocation)) { + const envObject = parseDotenv( + fs.readFileSync(envFileLocation, "utf8"), + ); + envVariables = Object.entries(envObject || {}).map( + ([key, value]) => ({ key, value }), + ); + } + } catch (error) { + // Handle parsing errors gracefully + envVariables = []; + } + await Promise.all( + envVariables.map(async (variable) => { + const sitesService = await getSitesService(); + await sitesService.createVariable({ + siteId: site["$id"], + key: variable.key, + value: variable.value, + secret: false, + }); + }), + ); + } - const updaterRow = new Spinner({ status: '', resource: site.name, id: site['$id'], end: `Ignoring using: ${ignore}` }); + if (code === false) { + successfullyPushed++; + successfullyDeployed++; + updaterRow.update({ status: "Pushed" }); + updaterRow.stopSpinner(); + return; + } + + try { + updaterRow.update({ status: "Pushing" }).replaceSpinner(SPINNER_ARC); + const sitesService = await getSitesService(); + response = await sitesService.createDeployment({ + siteId: site["$id"], + installCommand: site.installCommand, + buildCommand: site.buildCommand, + outputDirectory: site.outputDirectory, + code: site.path, + activate: true, + }); - updaterRow.update({ status: 'Getting' }).startSpinner(SPINNER_DOTS); + updaterRow.update({ status: "Pushed" }); + deploymentCreated = true; + successfullyPushed++; + } catch (e: any) { + errors.push(e); - try { - response = await sitesGet({ - siteId: site['$id'], - parseOutput: false, + switch (e.code) { + case "ENOENT": + updaterRow.fail({ + errorMessage: "Not found in the current directory. Skipping...", }); - siteExists = true; - if (response.framework !== site.framework) { - updaterRow.fail({ errorMessage: `Framework mismatch! (local=${site.framework},remote=${response.framework}) Please delete remote site or update your appwrite.config.json` }) - return; - } - - updaterRow.update({ status: 'Updating' }).replaceSpinner(SPINNER_ARC); - - response = await sitesUpdate({ - siteId: site['$id'], - name: site.name, - framework: site.framework, - buildRuntime: site.buildRuntime, - specification: site.specification, - timeout: site.timeout, - enabled: site.enabled, - logging: site.logging, - adapter: site.adapter, - buildCommand: site.buildCommand, - installCommand: site.installCommand, - outputDirectory: site.outputDirectory, - fallbackFile: site.fallbackFile, - vars: JSON.stringify(response.vars), - parseOutput: false + break; + default: + updaterRow.fail({ + errorMessage: + e.message ?? "An unknown error occurred. Please try again.", }); - } catch (e: any) { - - if (Number(e.code) === 404) { - siteExists = false; - } else { - errors.push(e); - updaterRow.fail({ errorMessage: e.message ?? 'General error occurs please try again' }); - return; - } } + } - if (!siteExists) { - updaterRow.update({ status: 'Creating' }).replaceSpinner(SPINNER_DOTS); - - try { - response = await sitesCreate({ - siteId: site.$id, - name: site.name, - framework: site.framework, - specification: site.specification, - buildRuntime: site.buildRuntime, - buildCommand: site.buildCommand, - installCommand: site.installCommand, - outputDirectory: site.outputDirectory, - fallbackFile: site.fallbackFile, - adapter: site.adapter, - timeout: site.timeout, - enabled: site.enabled, - logging: site.logging, - parseOutput: false - }); - - let domain = ''; - try { - const variables = await consoleVariables({ parseOutput: false, sdk: await sdkForConsole() }); - domain = ID.unique() + '.' + variables['_APP_DOMAIN_SITES']; - } catch (error) { - console.error('Error fetching console variables.'); - throw error; - } - - try { - const rule = await proxyCreateSiteRule( - { - domain: domain, - siteId: site.$id - } - ); - } catch (error) { - console.error('Error creating site rule.'); - throw error; - } - - updaterRow.update({ status: 'Created' }); - } catch (e: any) { - errors.push(e) - updaterRow.fail({ errorMessage: e.message ?? 'General error occurs please try again' }); - return; - } - } + if (deploymentCreated && !asyncDeploy) { + try { + const deploymentId = response["$id"]; + updaterRow.update({ + status: "Deploying", + end: "Checking deployment status...", + }); + let pollChecks = 0; + + while (true) { + const sitesService = await getSitesService(); + response = await sitesService.getDeployment({ + siteId: site["$id"], + deploymentId: deploymentId, + }); - if (withVariables) { - updaterRow.update({ status: 'Creating variables' }).replaceSpinner(SPINNER_ARC); - - const { variables } = await paginate(sitesListVariables, { - siteId: site['$id'], - parseOutput: false - }, 100, 'variables'); - - await Promise.all(variables.map(async (variable: any) => { - await sitesDeleteVariable({ - siteId: site['$id'], - variableId: variable['$id'], - parseOutput: false - }); - })); - - const envFileLocation = `${site['path']}/.env`; - let envVariables: Array<{key: string; value: string}> = []; - try { - if (fs.existsSync(envFileLocation)) { - const envObject = parseDotenv(fs.readFileSync(envFileLocation, 'utf8')); - envVariables = Object.entries(envObject || {}).map(([key, value]) => ({ key, value })); - } - } catch (error) { - // Handle parsing errors gracefully - envVariables = []; + const status = response["status"]; + if (status === "ready") { + successfullyDeployed++; + + let url = ""; + const proxyService = await getProxyService(); + const res = await proxyService.listRules([ + JSON.stringify({ method: "limit", values: [1] }), + JSON.stringify({ + method: "equal", + attribute: "deploymentResourceType", + values: ["site"], + }), + JSON.stringify({ + method: "equal", + attribute: "deploymentResourceId", + values: [site["$id"]], + }), + JSON.stringify({ + method: "equal", + attribute: "trigger", + values: ["manual"], + }), + ]); + + if (Number(res.total) === 1) { + url = res.rules[0].domain; + } + + updaterRow.update({ status: "Deployed", end: url }); + + break; + } else if (status === "failed") { + failedDeployments.push({ + name: site["name"], + $id: site["$id"], + deployment: response["$id"], + }); + updaterRow.fail({ errorMessage: `Failed to deploy` }); + + break; + } else { + updaterRow.update({ + status: "Deploying", + end: `Current status: ${status}`, + }); } - await Promise.all(envVariables.map(async (variable) => { - await sitesCreateVariable({ - siteId: site['$id'], - key: variable.key, - value: variable.value, - parseOutput: false, - secret: false - }); - })); - } - - if (code === false) { - successfullyPushed++; - successfullyDeployed++; - updaterRow.update({ status: 'Pushed' }); - updaterRow.stopSpinner(); - return; - } - try { - updaterRow.update({ status: 'Pushing' }).replaceSpinner(SPINNER_ARC); - response = await sitesCreateDeployment({ - siteId: site['$id'], - buildCommand: site.buildCommand, - installCommand: site.installCommand, - outputDirectory: site.outputDirectory, - fallbackFile: site.fallbackFile, - code: site.path, - activate: true, - parseOutput: false - }) - - updaterRow.update({ status: 'Pushed' }); - deploymentCreated = true; - successfullyPushed++; + pollChecks++; + await new Promise((resolve) => + setTimeout(resolve, POLL_DEBOUNCE * 1.5), + ); + } } catch (e: any) { - errors.push(e); - - switch (e.code) { - case 'ENOENT': - updaterRow.fail({ errorMessage: 'Not found in the current directory. Skipping...' }) - break; - default: - updaterRow.fail({ errorMessage: e.message ?? 'An unknown error occurred. Please try again.' }) - } + errors.push(e); + updaterRow.fail({ + errorMessage: + e.message ?? "Unknown error occurred. Please try again", + }); } + } - if (deploymentCreated && !asyncDeploy) { - try { - const deploymentId = response['$id']; - updaterRow.update({ status: 'Deploying', end: 'Checking deployment status...' }) - let pollChecks = 0; - - while (true) { - response = await sitesGetDeployment({ - siteId: site['$id'], - deploymentId: deploymentId, - parseOutput: false - }); - - const status = response['status']; - if (status === 'ready') { - successfullyDeployed++; - - let url = ''; - const res = await proxyListRules({ - parseOutput: false, - queries: [ - JSON.stringify({ method: 'limit', values: [1] }), - JSON.stringify({ method: 'equal', "attribute": "deploymentResourceType", "values": ["site"] }), - JSON.stringify({ method: 'equal', "attribute": "deploymentResourceId", "values": [site['$id']] }), - JSON.stringify({ method: 'equal', "attribute": "trigger", "values": ["manual"] }), - ], - }); - - if (Number(res.total) === 1) { - url = res.rules[0].domain; - } - - updaterRow.update({ status: 'Deployed', end: url }); - - break; - } else if (status === 'failed') { - failedDeployments.push({ name: site['name'], $id: site['$id'], deployment: response['$id'] }); - updaterRow.fail({ errorMessage: `Failed to deploy` }); - - break; - } else { - updaterRow.update({ status: 'Deploying', end: `Current status: ${status}` }) - } - - pollChecks++; - await new Promise(resolve => setTimeout(resolve, POLL_DEBOUNCE * 1.5)); - } - } catch (e: any) { - errors.push(e); - updaterRow.fail({ errorMessage: e.message ?? 'Unknown error occurred. Please try again' }) - } - } - - updaterRow.stopSpinner(); - })); - - Spinner.stop(); + updaterRow.stopSpinner(); + }), + ); - failedDeployments.forEach((failed) => { - const { name, deployment, $id } = failed; - const failUrl = `${globalConfig.getEndpoint().slice(0, -3)}/console/project-${localConfig.getProject().projectId}/sites/site-${$id}/deployments/deployment-${deployment}`; + Spinner.stop(); - error(`Deployment of ${name} has failed. Check at ${failUrl} for more details\n`); - }); + failedDeployments.forEach((failed) => { + const { name, deployment, $id } = failed; + const failUrl = `${globalConfig.getEndpoint().slice(0, -3)}/console/project-${localConfig.getProject().projectId}/sites/site-${$id}/deployments/deployment-${deployment}`; - if (!asyncDeploy) { - if (successfullyPushed === 0) { - error('No sites were pushed.'); - } else if (successfullyDeployed !== successfullyPushed) { - warn(`Successfully pushed ${successfullyDeployed} of ${successfullyPushed} sites`) - } else { - success(`Successfully pushed ${successfullyPushed} sites.`); - } + error( + `Deployment of ${name} has failed. Check at ${failUrl} for more details\n`, + ); + }); + + if (!asyncDeploy) { + if (successfullyPushed === 0) { + error("No sites were pushed."); + } else if (successfullyDeployed !== successfullyPushed) { + warn( + `Successfully pushed ${successfullyDeployed} of ${successfullyPushed} sites`, + ); } else { - success(`Successfully pushed ${successfullyPushed} sites.`); + success(`Successfully pushed ${successfullyPushed} sites.`); } + } else { + success(`Successfully pushed ${successfullyPushed} sites.`); + } - if (cliConfig.verbose) { - errors.forEach(e => { - console.error(e); - }) - } -} - -interface PushFunctionOptions { - functionId?: string; - async?: boolean; - code?: boolean; - withVariables?: boolean; - returnOnZero?: boolean; -} - -const pushFunction = async ({ functionId, async: asyncDeploy, code, withVariables }: PushFunctionOptions = { returnOnZero: false }): Promise<void> => { - process.chdir(localConfig.configDirectoryPath) + if (cliConfig.verbose) { + errors.forEach((e) => { + console.error(e); + }); + } +}; - const functionIds: string[] = []; +const pushFunction = async ({ + functionId, + async: asyncDeploy, + code, + withVariables, +}: PushFunctionOptions = {}): Promise<void> => { + process.chdir(localConfig.configDirectoryPath); - if (functionId) { - functionIds.push(functionId); - } else if (cliConfig.all) { - checkDeployConditions(localConfig); - const functions = localConfig.getFunctions(); - functionIds.push(...functions.map((func: any) => { - return func.$id; - })); - } + const functionIds: string[] = []; - if (functionIds.length <= 0) { - const answers = await inquirer.prompt(questionsPushFunctions[0]); - if (answers.functions) { - functionIds.push(...answers.functions); - } - } + if (functionId) { + functionIds.push(functionId); + } else if (cliConfig.all) { + checkDeployConditions(localConfig); + const functions = localConfig.getFunctions(); + functionIds.push( + ...functions.map((func: any) => { + return func.$id; + }), + ); + } - if (functionIds.length === 0) { - log("No functions found."); - hint("Use 'appwrite pull functions' to synchronize existing one, or use 'appwrite init function' to create a new one."); - return; + if (functionIds.length <= 0) { + const answers = await inquirer.prompt(questionsPushFunctions); + if (answers.functions) { + functionIds.push(...answers.functions); } + } - let functions = functionIds.map((id: string) => { - const functions = localConfig.getFunctions(); - const func = functions.find((f: any) => f.$id === id); - - if (!func) { - throw new Error("Function '" + id + "' not found.") + if (functionIds.length === 0) { + log("No functions found."); + hint( + "Use 'appwrite pull functions' to synchronize existing one, or use 'appwrite init function' to create a new one.", + ); + return; + } + + let functions = functionIds.map((id: string) => { + const functions = localConfig.getFunctions(); + const func = functions.find((f: any) => f.$id === id); + + if (!func) { + throw new Error("Function '" + id + "' not found."); + } + + return func; + }); + + log("Validating functions ..."); + // Validation is done BEFORE pushing so the deployment process can be run in async with progress update + for (let func of functions) { + if (!func.entrypoint) { + log(`Function ${func.name} is missing an entrypoint.`); + const answers = await inquirer.prompt(questionsGetEntrypoint); + func.entrypoint = answers.entrypoint; + localConfig.addFunction(func); + } + } + + if ( + !(await approveChanges( + functions, + async (args: any) => { + const functionsService = await getFunctionsService(); + return await functionsService.get({ functionId: args.functionId }); + }, + KeysFunction, + "functionId", + "functions", + ["vars"], + )) + ) { + return; + } + + log("Pushing functions ..."); + + Spinner.start(false); + let successfullyPushed = 0; + let successfullyDeployed = 0; + const failedDeployments: any[] = []; + const errors: any[] = []; + + await Promise.all( + functions.map(async (func: any) => { + let response: any = {}; + + const ignore = func.ignore ? "appwrite.config.json" : ".gitignore"; + let functionExists = false; + let deploymentCreated = false; + + const updaterRow = new Spinner({ + status: "", + resource: func.name, + id: func["$id"], + end: `Ignoring using: ${ignore}`, + }); + + updaterRow.update({ status: "Getting" }).startSpinner(SPINNER_DOTS); + const functionsService = await getFunctionsService(); + try { + response = await functionsService.get({ functionId: func["$id"] }); + functionExists = true; + if (response.runtime !== func.runtime) { + updaterRow.fail({ + errorMessage: `Runtime mismatch! (local=${func.runtime},remote=${response.runtime}) Please delete remote function or update your appwrite.config.json`, + }); + return; + } + + updaterRow.update({ status: "Updating" }).replaceSpinner(SPINNER_ARC); + + response = await functionsService.update({ + functionId: func["$id"], + name: func.name, + runtime: func.runtime, + execute: func.execute, + events: func.events, + schedule: func.schedule, + timeout: func.timeout, + enabled: func.enabled, + logging: func.logging, + entrypoint: func.entrypoint, + commands: func.commands, + scopes: func.scopes, + specification: func.specification, + }); + } catch (e: any) { + if (Number(e.code) === 404) { + functionExists = false; + } else { + errors.push(e); + updaterRow.fail({ + errorMessage: e.message ?? "General error occurs please try again", + }); + return; } + } - return func; - }); - - log('Validating functions ...'); - // Validation is done BEFORE pushing so the deployment process can be run in async with progress update - for (let func of functions) { - - if (!func.entrypoint) { - log(`Function ${func.name} is missing an entrypoint.`); - const answers = await inquirer.prompt(questionsGetEntrypoint) - func.entrypoint = answers.entrypoint; - localConfig.addFunction(func); - } - } + if (!functionExists) { + updaterRow.update({ status: "Creating" }).replaceSpinner(SPINNER_DOTS); - if (!(await approveChanges(functions, functionsGet, KeysFunction, 'functionId', 'functions', ['vars']))) { - return; - } - - log('Pushing functions ...'); - - Spinner.start(false); - let successfullyPushed = 0; - let successfullyDeployed = 0; - const failedDeployments: any[] = []; - const errors: any[] = []; - - await Promise.all(functions.map(async (func: any) => { - let response: any = {}; - - const ignore = func.ignore ? 'appwrite.config.json' : '.gitignore'; - let functionExists = false; - let deploymentCreated = false; - - const updaterRow = new Spinner({ status: '', resource: func.name, id: func['$id'], end: `Ignoring using: ${ignore}` }); - - updaterRow.update({ status: 'Getting' }).startSpinner(SPINNER_DOTS); try { - response = await functionsGet({ - functionId: func['$id'], - parseOutput: false, + response = await functionsService.create({ + functionId: func.$id, + name: func.name, + runtime: func.runtime, + execute: func.execute, + events: func.events, + schedule: func.schedule, + timeout: func.timeout, + enabled: func.enabled, + logging: func.logging, + entrypoint: func.entrypoint, + commands: func.commands, + scopes: func.scopes, + specification: func.specification, + }); + + let domain = ""; + try { + const consoleService = await getConsoleService(); + const variables = await consoleService.variables(); + domain = ID.unique() + "." + variables["_APP_DOMAIN_FUNCTIONS"]; + } catch (error) { + console.error("Error fetching console variables."); + throw error; + } + + try { + const proxyService = await getProxyService(); + const rule = await proxyService.createFunctionRule( + domain, + func.$id, + ); + } catch (error) { + console.error("Error creating function rule."); + throw error; + } + + updaterRow.update({ status: "Created" }); + } catch (e: any) { + errors.push(e); + updaterRow.fail({ + errorMessage: e.message ?? "General error occurs please try again", + }); + return; + } + } + + if (withVariables) { + updaterRow + .update({ status: "Updating variables" }) + .replaceSpinner(SPINNER_ARC); + + const functionsService = await getFunctionsService(); + const { variables } = await paginate( + async (args: any) => { + return await functionsService.listVariables({ + functionId: args.functionId, }); - functionExists = true; - if (response.runtime !== func.runtime) { - updaterRow.fail({ errorMessage: `Runtime mismatch! (local=${func.runtime},remote=${response.runtime}) Please delete remote function or update your appwrite.config.json` }) - return; - } + }, + { + functionId: func["$id"], + }, + 100, + "variables", + ); - updaterRow.update({ status: 'Updating' }).replaceSpinner(SPINNER_ARC); - - response = await functionsUpdate({ - functionId: func['$id'], - name: func.name, - specification: func.specification, - execute: func.execute, - events: func.events, - schedule: func.schedule, - timeout: func.timeout, - enabled: func.enabled, - logging: func.logging, - entrypoint: func.entrypoint, - commands: func.commands, - scopes: func.scopes, - vars: JSON.stringify(response.vars), - parseOutput: false + await Promise.all( + variables.map(async (variable: any) => { + const functionsService = await getFunctionsService(); + await functionsService.deleteVariable({ + functionId: func["$id"], + variableId: variable["$id"], }); - } catch (e: any) { - - if (Number(e.code) === 404) { - functionExists = false; - } else { - errors.push(e); - updaterRow.fail({ errorMessage: e.message ?? 'General error occurs please try again' }); - return; - } - } + }), + ); - if (!functionExists) { - updaterRow.update({ status: 'Creating' }).replaceSpinner(SPINNER_DOTS); - - try { - response = await functionsCreate({ - functionId: func.$id, - name: func.name, - runtime: func.runtime, - specification: func.specification, - execute: func.execute, - events: func.events, - schedule: func.schedule, - timeout: func.timeout, - enabled: func.enabled, - logging: func.logging, - entrypoint: func.entrypoint, - commands: func.commands, - scopes: func.scopes, - parseOutput: false - }); - - let domain = ''; - try { - const variables = await consoleVariables({ parseOutput: false, sdk: await sdkForConsole() }); - domain = ID.unique() + '.' + variables['_APP_DOMAIN_FUNCTIONS']; - } catch (error) { - console.error('Error fetching console variables.'); - throw error; - } - - try { - const rule = await proxyCreateFunctionRule( - { - domain: domain, - functionId: func.$id - } - ); - } catch (error) { - console.error('Error creating function rule.'); - throw error; - } - - updaterRow.update({ status: 'Created' }); - } catch (e: any) { - errors.push(e) - updaterRow.fail({ errorMessage: e.message ?? 'General error occurs please try again' }); - return; - } - } + const envFileLocation = `${func["path"]}/.env`; + let envVariables: Array<{ key: string; value: string }> = []; + try { + if (fs.existsSync(envFileLocation)) { + const envObject = parseDotenv( + fs.readFileSync(envFileLocation, "utf8"), + ); + envVariables = Object.entries(envObject || {}).map( + ([key, value]) => ({ key, value }), + ); + } + } catch (error) { + // Handle parsing errors gracefully + envVariables = []; + } + await Promise.all( + envVariables.map(async (variable) => { + const functionsService = await getFunctionsService(); + await functionsService.createVariable({ + functionId: func["$id"], + key: variable.key, + value: variable.value, + secret: false, + }); + }), + ); + } - if (withVariables) { - updaterRow.update({ status: 'Updating variables' }).replaceSpinner(SPINNER_ARC); - - const { variables } = await paginate(functionsListVariables, { - functionId: func['$id'], - parseOutput: false - }, 100, 'variables'); - - await Promise.all(variables.map(async (variable: any) => { - await functionsDeleteVariable({ - functionId: func['$id'], - variableId: variable['$id'], - parseOutput: false - }); - })); - - const envFileLocation = `${func['path']}/.env`; - let envVariables: Array<{key: string; value: string}> = []; - try { - if (fs.existsSync(envFileLocation)) { - const envObject = parseDotenv(fs.readFileSync(envFileLocation, 'utf8')); - envVariables = Object.entries(envObject || {}).map(([key, value]) => ({ key, value })); - } - } catch (error) { - // Handle parsing errors gracefully - envVariables = []; - } - await Promise.all(envVariables.map(async (variable) => { - await functionsCreateVariable({ - functionId: func['$id'], - variableId: ID.unique(), - key: variable.key, - value: variable.value, - parseOutput: false, - secret: false - }); - })); - } + if (code === false) { + successfullyPushed++; + successfullyDeployed++; + updaterRow.update({ status: "Pushed" }); + updaterRow.stopSpinner(); + return; + } + + try { + updaterRow.update({ status: "Pushing" }).replaceSpinner(SPINNER_ARC); + const functionsService = await getFunctionsService(); + response = await functionsService.createDeployment({ + functionId: func["$id"], + entrypoint: func.entrypoint, + commands: func.commands, + code: func.path, + activate: true, + }); - if (code === false) { - successfullyPushed++; - successfullyDeployed++; - updaterRow.update({ status: 'Pushed' }); - updaterRow.stopSpinner(); - return; + updaterRow.update({ status: "Pushed" }); + deploymentCreated = true; + successfullyPushed++; + } catch (e: any) { + errors.push(e); + + switch (e.code) { + case "ENOENT": + updaterRow.fail({ + errorMessage: "Not found in the current directory. Skipping...", + }); + break; + default: + updaterRow.fail({ + errorMessage: + e.message ?? "An unknown error occurred. Please try again.", + }); } + } + if (deploymentCreated && !asyncDeploy) { try { - updaterRow.update({ status: 'Pushing' }).replaceSpinner(SPINNER_ARC); - response = await functionsCreateDeployment({ - functionId: func['$id'], - entrypoint: func.entrypoint, - commands: func.commands, - code: func.path, - activate: true, - parseOutput: false - }) - - updaterRow.update({ status: 'Pushed' }); - deploymentCreated = true; - successfullyPushed++; - } catch (e: any) { - errors.push(e); - - switch (e.code) { - case 'ENOENT': - updaterRow.fail({ errorMessage: 'Not found in the current directory. Skipping...' }) - break; - default: - updaterRow.fail({ errorMessage: e.message ?? 'An unknown error occurred. Please try again.' }) - } - } + const deploymentId = response["$id"]; + updaterRow.update({ + status: "Deploying", + end: "Checking deployment status...", + }); + let pollChecks = 0; + + while (true) { + const functionsService = await getFunctionsService(); + response = await functionsService.getDeployment({ + functionId: func["$id"], + deploymentId: deploymentId, + }); - if (deploymentCreated && !asyncDeploy) { - try { - const deploymentId = response['$id']; - updaterRow.update({ status: 'Deploying', end: 'Checking deployment status...' }) - let pollChecks = 0; - - while (true) { - response = await functionsGetDeployment({ - functionId: func['$id'], - deploymentId: deploymentId, - parseOutput: false - }); - - const status = response['status']; - if (status === 'ready') { - successfullyDeployed++; - - let url = ''; - const res = await proxyListRules({ - parseOutput: false, - queries: [ - JSON.stringify({ method: 'limit', values: [1] }), - JSON.stringify({ method: 'equal', "attribute": "deploymentResourceType", "values": ["function"] }), - JSON.stringify({ method: 'equal', "attribute": "deploymentResourceId", "values": [func['$id']] }), - JSON.stringify({ method: 'equal', "attribute": "trigger", "values": ["manual"] }), - ], - }); - - if (Number(res.total) === 1) { - url = res.rules[0].domain; - } - - updaterRow.update({ status: 'Deployed', end: url }); - - break; - } else if (status === 'failed') { - failedDeployments.push({ name: func['name'], $id: func['$id'], deployment: response['$id'] }); - updaterRow.fail({ errorMessage: `Failed to deploy` }); - - break; - } else { - updaterRow.update({ status: 'Deploying', end: `Current status: ${status}` }) - } - - pollChecks++; - await new Promise(resolve => setTimeout(resolve, POLL_DEBOUNCE * 1.5)); - } - } catch (e: any) { - errors.push(e); - updaterRow.fail({ errorMessage: e.message ?? 'Unknown error occurred. Please try again' }) + const status = response["status"]; + if (status === "ready") { + successfullyDeployed++; + + let url = ""; + const proxyService = await getProxyService(); + const res = await proxyService.listRules([ + JSON.stringify({ method: "limit", values: [1] }), + JSON.stringify({ + method: "equal", + attribute: "deploymentResourceType", + values: ["function"], + }), + JSON.stringify({ + method: "equal", + attribute: "deploymentResourceId", + values: [func["$id"]], + }), + JSON.stringify({ + method: "equal", + attribute: "trigger", + values: ["manual"], + }), + ]); + + if (Number(res.total) === 1) { + url = res.rules[0].domain; + } + + updaterRow.update({ status: "Deployed", end: url }); + + break; + } else if (status === "failed") { + failedDeployments.push({ + name: func["name"], + $id: func["$id"], + deployment: response["$id"], + }); + updaterRow.fail({ errorMessage: `Failed to deploy` }); + + break; + } else { + updaterRow.update({ + status: "Deploying", + end: `Current status: ${status}`, + }); } - } - updaterRow.stopSpinner(); - })); + pollChecks++; + await new Promise((resolve) => + setTimeout(resolve, POLL_DEBOUNCE * 1.5), + ); + } + } catch (e: any) { + errors.push(e); + updaterRow.fail({ + errorMessage: + e.message ?? "Unknown error occurred. Please try again", + }); + } + } - Spinner.stop(); + updaterRow.stopSpinner(); + }), + ); - failedDeployments.forEach((failed) => { - const { name, deployment, $id } = failed; - const failUrl = `${globalConfig.getEndpoint().slice(0, -3)}/console/project-${localConfig.getProject().projectId}/functions/function-${$id}/deployment-${deployment}`; + Spinner.stop(); - error(`Deployment of ${name} has failed. Check at ${failUrl} for more details\n`); - }); + failedDeployments.forEach((failed) => { + const { name, deployment, $id } = failed; + const failUrl = `${globalConfig.getEndpoint().slice(0, -3)}/console/project-${localConfig.getProject().projectId}/functions/function-${$id}/deployment-${deployment}`; - if (!asyncDeploy) { - if (successfullyPushed === 0) { - error('No functions were pushed.'); - } else if (successfullyDeployed !== successfullyPushed) { - warn(`Successfully pushed ${successfullyDeployed} of ${successfullyPushed} functions`) - } else { - success(`Successfully pushed ${successfullyPushed} functions.`); - } + error( + `Deployment of ${name} has failed. Check at ${failUrl} for more details\n`, + ); + }); + + if (!asyncDeploy) { + if (successfullyPushed === 0) { + error("No functions were pushed."); + } else if (successfullyDeployed !== successfullyPushed) { + warn( + `Successfully pushed ${successfullyDeployed} of ${successfullyPushed} functions`, + ); } else { - success(`Successfully pushed ${successfullyPushed} functions.`); + success(`Successfully pushed ${successfullyPushed} functions.`); } + } else { + success(`Successfully pushed ${successfullyPushed} functions.`); + } - if (cliConfig.verbose) { - errors.forEach(e => { - console.error(e); - }) - } -} + if (cliConfig.verbose) { + errors.forEach((e) => { + console.error(e); + }); + } +}; -interface TablesDBChangesResult { - applied: boolean; - resyncNeeded: boolean; -} +const checkAndApplyTablesDBChanges = + async (): Promise<TablesDBChangesResult> => { + log("Checking for tablesDB changes ..."); -const checkAndApplyTablesDBChanges = async (): Promise<TablesDBChangesResult> => { - log('Checking for tablesDB changes ...'); - const localTablesDBs = localConfig.getTablesDBs(); - const { databases: remoteTablesDBs } = await paginate(tablesDBList, { parseOutput: false }, 100, 'databases'); - + const { databases: remoteTablesDBs } = await paginate( + async (args: any) => { + const tablesDBService = await getTablesDBService(); + return await tablesDBService.list(args.queries || []); + }, + {}, + 100, + "databases", + ); + if (localTablesDBs.length === 0 && remoteTablesDBs.length === 0) { - return { applied: false, resyncNeeded: false }; + return { applied: false, resyncNeeded: false }; } - + const changes: any[] = []; const toCreate: any[] = []; const toUpdate: any[] = []; @@ -1814,801 +2252,932 @@ const checkAndApplyTablesDBChanges = async (): Promise<TablesDBChangesResult> => // Check for deletions - remote DBs that aren't in local config for (const remoteDB of remoteTablesDBs) { - const localDB = localTablesDBs.find((db: any) => db.$id === remoteDB.$id); - if (!localDB) { - toDelete.push(remoteDB); - changes.push({ - id: remoteDB.$id, - action: chalk.red('deleting'), - key: 'Database', - remote: remoteDB.name, - local: '(deleted locally)' - }); - } + const localDB = localTablesDBs.find((db: any) => db.$id === remoteDB.$id); + if (!localDB) { + toDelete.push(remoteDB); + changes.push({ + id: remoteDB.$id, + action: chalk.red("deleting"), + key: "Database", + remote: remoteDB.name, + local: "(deleted locally)", + }); + } } // Check for additions and updates for (const localDB of localTablesDBs) { - const remoteDB = remoteTablesDBs.find((db: any) => db.$id === localDB.$id); - - if (!remoteDB) { - toCreate.push(localDB); - changes.push({ - id: localDB.$id, - action: chalk.green('creating'), - key: 'Database', - remote: '(does not exist)', - local: localDB.name - }); - } else { - let hasChanges = false; - - if (remoteDB.name !== localDB.name) { - hasChanges = true; - changes.push({ - id: localDB.$id, - action: chalk.yellow('updating'), - key: 'Name', - remote: remoteDB.name, - local: localDB.name - }); - } - - if (remoteDB.enabled !== localDB.enabled) { - hasChanges = true; - changes.push({ - id: localDB.$id, - action: chalk.yellow('updating'), - key: 'Enabled', - remote: remoteDB.enabled, - local: localDB.enabled - }); - } - - if (hasChanges) { - toUpdate.push(localDB); - } + const remoteDB = remoteTablesDBs.find( + (db: any) => db.$id === localDB.$id, + ); + + if (!remoteDB) { + toCreate.push(localDB); + changes.push({ + id: localDB.$id, + action: chalk.green("creating"), + key: "Database", + remote: "(does not exist)", + local: localDB.name, + }); + } else { + let hasChanges = false; + + if (remoteDB.name !== localDB.name) { + hasChanges = true; + changes.push({ + id: localDB.$id, + action: chalk.yellow("updating"), + key: "Name", + remote: remoteDB.name, + local: localDB.name, + }); + } + + if (remoteDB.enabled !== localDB.enabled) { + hasChanges = true; + changes.push({ + id: localDB.$id, + action: chalk.yellow("updating"), + key: "Enabled", + remote: remoteDB.enabled, + local: localDB.enabled, + }); } + + if (hasChanges) { + toUpdate.push(localDB); + } + } } if (changes.length === 0) { - console.log('No changes found in tablesDB resource'); - console.log(); - return { applied: false, resyncNeeded: false }; + return { applied: false, resyncNeeded: false }; } - log('Found changes in tablesDB resource:'); + log("Found changes in tablesDB resource:"); drawTable(changes); if (toDelete.length > 0) { - console.log(`${chalk.red('------------------------------------------------------------------')}`); - console.log(`${chalk.red('| WARNING: Database deletion will also delete all related tables |')}`); - console.log(`${chalk.red('------------------------------------------------------------------')}`); - console.log(); + console.log( + `${chalk.red("------------------------------------------------------------------")}`, + ); + console.log( + `${chalk.red("| WARNING: Database deletion will also delete all related tables |")}`, + ); + console.log( + `${chalk.red("------------------------------------------------------------------")}`, + ); + console.log(); } if ((await getConfirmation()) !== true) { - return { applied: false, resyncNeeded: false }; + return { applied: false, resyncNeeded: false }; } // Apply deletions first let needsResync = false; for (const db of toDelete) { - try { - log(`Deleting database ${db.name} ( ${db.$id} ) ...`); - await tablesDBDelete({ - databaseId: db.$id, - parseOutput: false - }); - success(`Deleted ${db.name} ( ${db.$id} )`); - needsResync = true; - } catch (e: any) { - error(`Failed to delete database ${db.name} ( ${db.$id} ): ${e.message}`); - throw new Error(`Database sync failed during deletion of ${db.$id}. Some changes may have been applied.`); - } + try { + log(`Deleting database ${db.name} ( ${db.$id} ) ...`); + const tablesDBService = await getTablesDBService(); + await tablesDBService.delete(db.$id); + success(`Deleted ${db.name} ( ${db.$id} )`); + needsResync = true; + } catch (e: any) { + error( + `Failed to delete database ${db.name} ( ${db.$id} ): ${e.message}`, + ); + throw new Error( + `Database sync failed during deletion of ${db.$id}. Some changes may have been applied.`, + ); + } } // Apply creations for (const db of toCreate) { - try { - log(`Creating database ${db.name} ( ${db.$id} ) ...`); - await tablesDBCreate({ - databaseId: db.$id, - name: db.name, - enabled: db.enabled, - parseOutput: false - }); - success(`Created ${db.name} ( ${db.$id} )`); - } catch (e: any) { - error(`Failed to create database ${db.name} ( ${db.$id} ): ${e.message}`); - throw new Error(`Database sync failed during creation of ${db.$id}. Some changes may have been applied.`); - } + try { + log(`Creating database ${db.name} ( ${db.$id} ) ...`); + const tablesDBService = await getTablesDBService(); + await tablesDBService.create(db.$id, db.name, db.enabled); + success(`Created ${db.name} ( ${db.$id} )`); + } catch (e: any) { + error( + `Failed to create database ${db.name} ( ${db.$id} ): ${e.message}`, + ); + throw new Error( + `Database sync failed during creation of ${db.$id}. Some changes may have been applied.`, + ); + } } // Apply updates for (const db of toUpdate) { - try { - log(`Updating database ${db.name} ( ${db.$id} ) ...`); - await tablesDBUpdate({ - databaseId: db.$id, - name: db.name, - enabled: db.enabled, - parseOutput: false - }); - success(`Updated ${db.name} ( ${db.$id} )`); - } catch (e: any) { - error(`Failed to update database ${db.name} ( ${db.$id} ): ${e.message}`); - throw new Error(`Database sync failed during update of ${db.$id}. Some changes may have been applied.`); - } + try { + log(`Updating database ${db.name} ( ${db.$id} ) ...`); + const tablesDBService = await getTablesDBService(); + await tablesDBService.update(db.$id, db.name, db.enabled); + success(`Updated ${db.name} ( ${db.$id} )`); + } catch (e: any) { + error( + `Failed to update database ${db.name} ( ${db.$id} ): ${e.message}`, + ); + throw new Error( + `Database sync failed during update of ${db.$id}. Some changes may have been applied.`, + ); + } } - if (toDelete.length === 0){ - console.log(); + if (toDelete.length === 0) { + console.log(); } return { applied: true, resyncNeeded: needsResync }; -}; - -interface PushTableOptions { - returnOnZero?: boolean; - attempts?: number; -} - -const pushTable = async ({ returnOnZero, attempts }: PushTableOptions = { returnOnZero: false }): Promise<void> => { - const tables: any[] = []; - - if (attempts) { - pollMaxDebounces = attempts; - } - - const { applied: tablesDBApplied, resyncNeeded } = await checkAndApplyTablesDBChanges(); - if (resyncNeeded) { - log('Resyncing configuration due to tablesDB deletions ...'); - - const remoteTablesDBs = (await paginate(tablesDBList, { parseOutput: false }, 100, 'databases')).databases; - const localTablesDBs = localConfig.getTablesDBs(); - - const remoteDatabaseIds = new Set(remoteTablesDBs.map((db: any) => db.$id)); - const localTables = localConfig.getTables(); - const validTables = localTables.filter((table: any) => remoteDatabaseIds.has(table.databaseId)); - - localConfig.set('tables', validTables); - - const validTablesDBs = localTablesDBs.filter((db: any) => remoteDatabaseIds.has(db.$id)); - localConfig.set('tablesDB', validTablesDBs); - - success('Configuration resynced successfully.'); - console.log(); - } - - log('Checking for deleted tables ...'); + }; + +const pushTable = async ({ + attempts, +}: PushTableOptions = {}): Promise<void> => { + const tables: any[] = []; + + if (attempts) { + pollMaxDebounces = attempts; + } + + const { applied: tablesDBApplied, resyncNeeded } = + await checkAndApplyTablesDBChanges(); + if (resyncNeeded) { + log("Resyncing configuration due to tablesDB deletions ..."); + + const remoteTablesDBs = ( + await paginate( + async (args: any) => { + const tablesDBService = await getTablesDBService(); + return await tablesDBService.list(args.queries || []); + }, + {}, + 100, + "databases", + ) + ).databases; const localTablesDBs = localConfig.getTablesDBs(); + + const remoteDatabaseIds = new Set(remoteTablesDBs.map((db: any) => db.$id)); const localTables = localConfig.getTables(); - const tablesToDelete: any[] = []; + const validTables = localTables.filter((table: any) => + remoteDatabaseIds.has(table.databaseId), + ); - for (const db of localTablesDBs) { - try { - const { tables: remoteTables } = await paginate(tablesDBListTables, { - databaseId: db.$id, - parseOutput: false - }, 100, 'tables'); - - for (const remoteTable of remoteTables) { - const localTable = localTables.find((t: any) => t.$id === remoteTable.$id && t.databaseId === db.$id); - if (!localTable) { - tablesToDelete.push({ - ...remoteTable, - databaseId: db.$id, - databaseName: db.name - }); - } - } - } catch (e) { - // Skip if database doesn't exist or other errors - } - } + localConfig.set("tables", validTables); - if (tablesToDelete.length > 0) { - log('Found tables that exist remotely but not locally:'); - const deletionChanges = tablesToDelete.map((table: any) => ({ - id: table.$id, - action: chalk.red('deleting'), - key: 'Table', - database: table.databaseName, - remote: table.name, - local: '(deleted locally)' - })); - drawTable(deletionChanges); - - if ((await getConfirmation()) === true) { - for (const table of tablesToDelete) { - try { - log(`Deleting table ${table.name} ( ${table.$id} ) from database ${table.databaseName} ...`); - await tablesDBDeleteTable({ - databaseId: table.databaseId, - tableId: table.$id, - parseOutput: false - }); - success(`Deleted ${table.name} ( ${table.$id} )`); - } catch (e: any) { - error(`Failed to delete table ${table.name} ( ${table.$id} ): ${e.message}`); - } - } - } - } else { - console.log('No tables found to delete'); - } - console.log(); + const validTablesDBs = localTablesDBs.filter((db: any) => + remoteDatabaseIds.has(db.$id), + ); + localConfig.set("tablesDB", validTablesDBs); - if (cliConfig.all) { - checkDeployConditions(localConfig); - tables.push(...localConfig.getTables()); - } else { - const answers = await inquirer.prompt(questionsPushTables) - if (answers.tables) { - const configTables = new Map(); - localConfig.getTables().forEach((c: any) => { - configTables.set(`${c['databaseId']}|${c['$id']}`, c); - }); - answers.tables.forEach((a: any) => { - const table = configTables.get(a); - tables.push(table); - }) - } - } + success("Configuration resynced successfully."); + console.log(); + } - if (tables.length === 0) { - log("No tables found."); - hint("Use 'appwrite pull tables' to synchronize existing one, or use 'appwrite init table' to create a new one."); - return; - } + log("Checking for deleted tables ..."); + const localTablesDBs = localConfig.getTablesDBs(); + const localTables = localConfig.getTables(); + const tablesToDelete: any[] = []; - if (!(await approveChanges(tables, tablesDBGetTable, KeysTable, 'tableId', 'tables', ['columns', 'indexes'], 'databaseId', 'databaseId'))) { - return; - } - let tablesChanged = new Set(); + for (const db of localTablesDBs) { + try { + const { tables: remoteTables } = await paginate( + async (args: any) => { + const tablesDBService = await getTablesDBService(); + return await tablesDBService.listTables( + args.databaseId, + args.queries || [], + ); + }, + { + databaseId: db.$id, + }, + 100, + "tables", + ); + + for (const remoteTable of remoteTables) { + const localTable = localTables.find( + (t: any) => t.$id === remoteTable.$id && t.databaseId === db.$id, + ); + if (!localTable) { + tablesToDelete.push({ + ...remoteTable, + databaseId: db.$id, + databaseName: db.name, + }); + } + } + } catch (e) { + // Skip if database doesn't exist or other errors + } + } + + if (tablesToDelete.length > 0) { + log("Found tables that exist remotely but not locally:"); + const deletionChanges = tablesToDelete.map((table: any) => ({ + id: table.$id, + action: chalk.red("deleting"), + key: "Table", + database: table.databaseName, + remote: table.name, + local: "(deleted locally)", + })); + drawTable(deletionChanges); - // Parallel tables actions - await Promise.all(tables.map(async (table: any) => { + if ((await getConfirmation()) === true) { + for (const table of tablesToDelete) { try { - const remoteTable = await tablesDBGetTable({ - databaseId: table['databaseId'], - tableId: table['$id'], - parseOutput: false, - }); - - const changes: string[] = []; - if (remoteTable.name !== table.name) changes.push('name'); - if (remoteTable.rowSecurity !== table.rowSecurity) changes.push('rowSecurity'); - if (remoteTable.enabled !== table.enabled) changes.push('enabled'); - if (JSON.stringify(remoteTable['$permissions']) !== JSON.stringify(table['$permissions'])) changes.push('permissions'); - - if (changes.length > 0) { - await tablesDBUpdateTable({ - databaseId: table['databaseId'], - tableId: table['$id'], - name: table.name, - parseOutput: false, - rowSecurity: table.rowSecurity, - permissions: table['$permissions'] - }) - - success(`Updated ${table.name} ( ${table['$id']} ) - ${changes.join(', ')}`); - tablesChanged.add(table['$id']); - } - table.remoteVersion = remoteTable; - - table.isExisted = true; + log( + `Deleting table ${table.name} ( ${table.$id} ) from database ${table.databaseName} ...`, + ); + const tablesDBService = await getTablesDBService(); + await tablesDBService.deleteTable(table.databaseId, table.$id); + success(`Deleted ${table.name} ( ${table.$id} )`); } catch (e: any) { - if (Number(e.code) === 404) { - log(`Table ${table.name} does not exist in the project. Creating ... `); - await tablesDBCreateTable({ - databaseId: table['databaseId'], - tableId: table['$id'], - name: table.name, - rowSecurity: table.rowSecurity, - permissions: table['$permissions'], - parseOutput: false - }) - - success(`Created ${table.name} ( ${table['$id']} )`); - tablesChanged.add(table['$id']); - } else { - throw e; - } - } - })) - - // Serialize attribute actions - for (let table of tables) { - let columns = table.columns; - let indexes = table.indexes; - - if (table.isExisted) { - columns = await attributesToCreate(table.remoteVersion.columns, table.columns, table); - indexes = await attributesToCreate(table.remoteVersion.indexes, table.indexes, table, true); - - if ((Array.isArray(columns) && columns.length <= 0) && (Array.isArray(indexes) && indexes.length <= 0)) { - continue; - } + error( + `Failed to delete table ${table.name} ( ${table.$id} ): ${e.message}`, + ); } - - log(`Pushing table ${table.name} ( ${table['databaseId']} - ${table['$id']} ) attributes`) - - try { - await createColumns(columns, table) - } catch (e) { - throw e; - } - - try { - await createIndexes(indexes, table); - } catch (e) { - throw e; - } - tablesChanged.add(table['$id']); - success(`Successfully pushed ${table.name} ( ${table['$id']} )`); + } } + } - success(`Successfully pushed ${tablesChanged.size} tables`); -} - -interface PushCollectionOptions { - returnOnZero?: boolean; - attempts?: number; -} - -const pushCollection = async ({ returnOnZero, attempts }: PushCollectionOptions = { returnOnZero: false }): Promise<void> => { - warn("appwrite push collection has been deprecated. Please consider using 'appwrite push tables' instead"); - const collections: any[] = []; + if (cliConfig.all) { + checkDeployConditions(localConfig); + tables.push(...localConfig.getTables()); + } else { + const answers = await inquirer.prompt(questionsPushTables); + if (answers.tables) { + const configTables = new Map(); + localConfig.getTables().forEach((c: any) => { + configTables.set(`${c["databaseId"]}|${c["$id"]}`, c); + }); + answers.tables.forEach((a: any) => { + const table = configTables.get(a); + tables.push(table); + }); + } + } + + if (tables.length === 0) { + log("No tables found."); + hint( + "Use 'appwrite pull tables' to synchronize existing one, or use 'appwrite init table' to create a new one.", + ); + return; + } + + if ( + !(await approveChanges( + tables, + async (args: any) => { + const tablesDBService = await getTablesDBService(); + return await tablesDBService.getTable(args.databaseId, args.tableId); + }, + KeysTable, + "tableId", + "tables", + ["columns", "indexes"], + "databaseId", + "databaseId", + )) + ) { + return; + } + let tablesChanged = new Set(); + + // Parallel tables actions + await Promise.all( + tables.map(async (table: any) => { + try { + const tablesDBService = await getTablesDBService(); + const remoteTable = await tablesDBService.getTable( + table["databaseId"], + table["$id"], + ); - if (attempts) { - pollMaxDebounces = attempts; - } + const changes: string[] = []; + if (remoteTable.name !== table.name) changes.push("name"); + if (remoteTable.rowSecurity !== table.rowSecurity) + changes.push("rowSecurity"); + if (remoteTable.enabled !== table.enabled) changes.push("enabled"); + if ( + JSON.stringify(remoteTable["$permissions"]) !== + JSON.stringify(table["$permissions"]) + ) + changes.push("permissions"); - if (cliConfig.all) { - checkDeployConditions(localConfig); - collections.push(...localConfig.getCollections()); - } else { - const answers = await inquirer.prompt(questionsPushCollections) - if (answers.collections) { - const configCollections = new Map(); - localConfig.getCollections().forEach((c: any) => { - configCollections.set(`${c['databaseId']}|${c['$id']}`, c); - }); - answers.collections.forEach((a: any) => { - const collection = configCollections.get(a); - collections.push(collection); - }) - } - } + if (changes.length > 0) { + await tablesDBService.updateTable( + table["databaseId"], + table["$id"], + table.name, + table.rowSecurity, + table["$permissions"], + ); + + success( + `Updated ${table.name} ( ${table["$id"]} ) - ${changes.join(", ")}`, + ); + tablesChanged.add(table["$id"]); + } + table.remoteVersion = remoteTable; + + table.isExisted = true; + } catch (e: any) { + if (Number(e.code) === 404) { + log( + `Table ${table.name} does not exist in the project. Creating ... `, + ); + const tablesDBService = await getTablesDBService(); + await tablesDBService.createTable( + table["databaseId"], + table["$id"], + table.name, + table.rowSecurity, + table["$permissions"], + ); + + success(`Created ${table.name} ( ${table["$id"]} )`); + tablesChanged.add(table["$id"]); + } else { + throw e; + } + } + }), + ); + + // Serialize attribute actions + for (let table of tables) { + let columns = table.columns; + let indexes = table.indexes; + + if (table.isExisted) { + columns = await attributesToCreate( + table.remoteVersion.columns, + table.columns, + table, + ); + indexes = await attributesToCreate( + table.remoteVersion.indexes, + table.indexes, + table, + true, + ); + + if ( + Array.isArray(columns) && + columns.length <= 0 && + Array.isArray(indexes) && + indexes.length <= 0 + ) { + continue; + } + } + + log( + `Pushing table ${table.name} ( ${table["databaseId"]} - ${table["$id"]} ) attributes`, + ); - if (collections.length === 0) { - log("No collections found."); - hint("Use 'appwrite pull collections' to synchronize existing one, or use 'appwrite init collection' to create a new one."); - return; + try { + await createColumns(columns, table); + } catch (e) { + throw e; } - const databases = Array.from(new Set(collections.map((collection: any) => collection['databaseId']))); - - // Parallel db actions - await Promise.all(databases.map(async (databaseId: any) => { - const localDatabase = localConfig.getDatabase(databaseId); - - try { - const database = await databasesGet({ - databaseId: databaseId, - parseOutput: false, - }); - - if (database.name !== (localDatabase.name ?? databaseId)) { - await databasesUpdate({ - databaseId: databaseId, - name: localDatabase.name ?? databaseId, - parseOutput: false - }) - - success(`Updated ${localDatabase.name} ( ${databaseId} ) name`); - } - } catch (err) { - log(`Database ${databaseId} not found. Creating it now ...`); - - await databasesCreate({ - databaseId: databaseId, - name: localDatabase.name ?? databaseId, - parseOutput: false, - }); - } - })); - - if (!(await approveChanges(collections, databasesGetCollection, KeysCollection, 'collectionId', 'collections', ['attributes', 'indexes'], 'databaseId', 'databaseId',))) { - return; + try { + await createIndexes(indexes, table); + } catch (e) { + throw e; } - // Parallel collection actions - await Promise.all(collections.map(async (collection: any) => { - try { - const remoteCollection = await databasesGetCollection({ - databaseId: collection['databaseId'], - collectionId: collection['$id'], - parseOutput: false, - }); - - if (remoteCollection.name !== collection.name) { - await databasesUpdateCollection({ - databaseId: collection['databaseId'], - collectionId: collection['$id'], - name: collection.name, - parseOutput: false - }) - - success(`Updated ${collection.name} ( ${collection['$id']} ) name`); - } - collection.remoteVersion = remoteCollection; - - collection.isExisted = true; - } catch (e: any) { - if (Number(e.code) === 404) { - log(`Collection ${collection.name} does not exist in the project. Creating ... `); - await databasesCreateCollection({ - databaseId: collection['databaseId'], - collectionId: collection['$id'], - name: collection.name, - documentSecurity: collection.documentSecurity, - permissions: collection['$permissions'], - parseOutput: false - }) - } else { - throw e; - } - } - })) - let numberOfCollections = 0; - // Serialize attribute actions - for (let collection of collections) { - let attributes = collection.attributes; - let indexes = collection.indexes; - - if (collection.isExisted) { - attributes = await attributesToCreate(collection.remoteVersion.attributes, collection.attributes, collection); - indexes = await attributesToCreate(collection.remoteVersion.indexes, collection.indexes, collection, true); - - if ((Array.isArray(attributes) && attributes.length <= 0) && (Array.isArray(indexes) && indexes.length <= 0)) { - continue; - } - - } + tablesChanged.add(table["$id"]); + success(`Successfully pushed ${table.name} ( ${table["$id"]} )`); + } - log(`Pushing collection ${collection.name} ( ${collection['databaseId']} - ${collection['$id']} ) attributes`) + success(`Successfully pushed ${tablesChanged.size} tables`); +}; - try { - await createAttributes(attributes, collection) - } catch (e) { - throw e; - } +const pushCollection = async ({ attempts }): Promise<void> => { + warn( + "appwrite push collection has been deprecated. Please consider using 'appwrite push tables' instead", + ); + const collections: any[] = []; - try { - await createIndexes(indexes, collection); - } catch (e) { - throw e; - } - numberOfCollections++; - success(`Successfully pushed ${collection.name} ( ${collection['$id']} )`); - } + if (attempts) { + pollMaxDebounces = attempts; + } - success(`Successfully pushed ${numberOfCollections} collections`); -} + if (cliConfig.all) { + checkDeployConditions(localConfig); + collections.push(...localConfig.getCollections()); + } else { + const answers = await inquirer.prompt(questionsPushCollections); + if (answers.collections) { + const configCollections = new Map(); + localConfig.getCollections().forEach((c: any) => { + configCollections.set(`${c["databaseId"]}|${c["$id"]}`, c); + }); + answers.collections.forEach((a: any) => { + const collection = configCollections.get(a); + collections.push(collection); + }); + } + } + + if (collections.length === 0) { + log("No collections found."); + hint( + "Use 'appwrite pull collections' to synchronize existing one, or use 'appwrite init collection' to create a new one.", + ); + return; + } -interface PushBucketOptions { - returnOnZero?: boolean; -} + const databases = Array.from( + new Set(collections.map((collection: any) => collection["databaseId"])), + ); -const pushBucket = async ({ returnOnZero }: PushBucketOptions = { returnOnZero: false }): Promise<void> => { - let response: any = {}; + // Parallel db actions + await Promise.all( + databases.map(async (databaseId: any) => { + const localDatabase = localConfig.getDatabase(databaseId); - let bucketIds: string[] = []; - const configBuckets = localConfig.getBuckets(); + const databasesService = await getDatabasesService(); + try { + const database = await databasesService.get(databaseId); - if (cliConfig.all) { - checkDeployConditions(localConfig); - bucketIds.push(...configBuckets.map((b: any) => b.$id)); - } + if (database.name !== (localDatabase.name ?? databaseId)) { + await databasesService.update( + databaseId, + localDatabase.name ?? databaseId, + ); - if (bucketIds.length === 0) { - const answers = await inquirer.prompt(questionsPushBuckets[0]) - if (answers.buckets) { - bucketIds.push(...answers.buckets); + success(`Updated ${localDatabase.name} ( ${databaseId} ) name`); } - } - - if (bucketIds.length === 0) { - log("No buckets found."); - hint("Use 'appwrite pull buckets' to synchronize existing one, or use 'appwrite init bucket' to create a new one."); - return; - } + } catch (err) { + log(`Database ${databaseId} not found. Creating it now ...`); - let buckets: any[] = []; + await databasesService.create( + databaseId, + localDatabase.name ?? databaseId, + ); + } + }), + ); + + if ( + !(await approveChanges( + collections, + async (args: any) => { + const databasesService = await getDatabasesService(); + return await databasesService.getCollection( + args.databaseId, + args.collectionId, + ); + }, + KeysCollection, + "collectionId", + "collections", + ["attributes", "indexes"], + "databaseId", + "databaseId", + )) + ) { + return; + } + // Parallel collection actions + await Promise.all( + collections.map(async (collection: any) => { + try { + const databasesService = await getDatabasesService(); + const remoteCollection = await databasesService.getCollection( + collection["databaseId"], + collection["$id"], + ); - for (const bucketId of bucketIds) { - const idBuckets = configBuckets.filter((b: any) => b.$id === bucketId); - buckets.push(...idBuckets); - } + if (remoteCollection.name !== collection.name) { + await databasesService.updateCollection( + collection["databaseId"], + collection["$id"], + collection.name, + ); + + success(`Updated ${collection.name} ( ${collection["$id"]} ) name`); + } + collection.remoteVersion = remoteCollection; + + collection.isExisted = true; + } catch (e: any) { + if (Number(e.code) === 404) { + log( + `Collection ${collection.name} does not exist in the project. Creating ... `, + ); + const databasesService = await getDatabasesService(); + await databasesService.createCollection( + collection["databaseId"], + collection["$id"], + collection.name, + collection.documentSecurity, + collection["$permissions"], + ); + } else { + throw e; + } + } + }), + ); + let numberOfCollections = 0; + // Serialize attribute actions + for (let collection of collections) { + let attributes = collection.attributes; + let indexes = collection.indexes; + + if (collection.isExisted) { + attributes = await attributesToCreate( + collection.remoteVersion.attributes, + collection.attributes, + collection, + ); + indexes = await attributesToCreate( + collection.remoteVersion.indexes, + collection.indexes, + collection, + true, + ); + + if ( + Array.isArray(attributes) && + attributes.length <= 0 && + Array.isArray(indexes) && + indexes.length <= 0 + ) { + continue; + } + } + + log( + `Pushing collection ${collection.name} ( ${collection["databaseId"]} - ${collection["$id"]} ) attributes`, + ); - if (!(await approveChanges(buckets, storageGetBucket, KeysStorage, 'bucketId', 'buckets'))) { - return; + try { + await createAttributes(attributes, collection); + } catch (e) { + throw e; } - log('Pushing buckets ...'); - - for (let bucket of buckets) { - log(`Pushing bucket ${chalk.bold(bucket['name'])} ...`); - - try { - response = await storageGetBucket({ - bucketId: bucket['$id'], - parseOutput: false, - }) - - await storageUpdateBucket({ - bucketId: bucket['$id'], - name: bucket.name, - permissions: bucket['$permissions'], - fileSecurity: bucket.fileSecurity, - enabled: bucket.enabled, - maximumFileSize: bucket.maximumFileSize, - allowedFileExtensions: bucket.allowedFileExtensions, - encryption: bucket.encryption, - antivirus: bucket.antivirus, - compression: bucket.compression, - parseOutput: false - }); - } catch (e: any) { - if (Number(e.code) === 404) { - log(`Bucket ${bucket.name} does not exist in the project. Creating ... `); - - response = await storageCreateBucket({ - bucketId: bucket['$id'], - name: bucket.name, - permissions: bucket['$permissions'], - fileSecurity: bucket.fileSecurity, - enabled: bucket.enabled, - maximumFileSize: bucket.maximumFileSize, - allowedFileExtensions: bucket.allowedFileExtensions, - compression: bucket.compression, - encryption: bucket.encryption, - antivirus: bucket.antivirus, - parseOutput: false - }) - } else { - throw e; - } - } + try { + await createIndexes(indexes, collection); + } catch (e) { + throw e; } + numberOfCollections++; + success(`Successfully pushed ${collection.name} ( ${collection["$id"]} )`); + } - success(`Successfully pushed ${buckets.length} buckets.`); -} + success(`Successfully pushed ${numberOfCollections} collections`); +}; -interface PushTeamOptions { - returnOnZero?: boolean; -} +const pushBucket = async (): Promise<void> => { + let response: any = {}; -const pushTeam = async ({ returnOnZero }: PushTeamOptions = { returnOnZero: false }): Promise<void> => { - let response: any = {}; + let bucketIds: string[] = []; + const configBuckets = localConfig.getBuckets(); - let teamIds: string[] = []; - const configTeams = localConfig.getTeams(); + if (cliConfig.all) { + checkDeployConditions(localConfig); + bucketIds.push(...configBuckets.map((b: any) => b.$id)); + } - if (cliConfig.all) { - checkDeployConditions(localConfig); - teamIds.push(...configTeams.map((t: any) => t.$id)); + if (bucketIds.length === 0) { + const answers = await inquirer.prompt(questionsPushBuckets); + if (answers.buckets) { + bucketIds.push(...answers.buckets); } + } - if (teamIds.length === 0) { - const answers = await inquirer.prompt(questionsPushTeams[0]) - if (answers.teams) { - teamIds.push(...answers.teams); - } - } + if (bucketIds.length === 0) { + log("No buckets found."); + hint( + "Use 'appwrite pull buckets' to synchronize existing one, or use 'appwrite init bucket' to create a new one.", + ); + return; + } + + let buckets: any[] = []; + + for (const bucketId of bucketIds) { + const idBuckets = configBuckets.filter((b: any) => b.$id === bucketId); + buckets.push(...idBuckets); + } + + if ( + !(await approveChanges( + buckets, + async (args: any) => { + const storageService = await getStorageService(); + return await storageService.getBucket(args.bucketId); + }, + KeysStorage, + "bucketId", + "buckets", + )) + ) { + return; + } + + log("Pushing buckets ..."); + + for (let bucket of buckets) { + log(`Pushing bucket ${chalk.bold(bucket["name"])} ...`); + + const storageService = await getStorageService(); + try { + response = await storageService.getBucket(bucket["$id"]); + + await storageService.updateBucket( + bucket["$id"], + bucket.name, + bucket["$permissions"], + bucket.fileSecurity, + bucket.enabled, + bucket.maximumFileSize, + bucket.allowedFileExtensions, + bucket.encryption, + bucket.antivirus, + bucket.compression, + ); + } catch (e: any) { + if (Number(e.code) === 404) { + log( + `Bucket ${bucket.name} does not exist in the project. Creating ... `, + ); - if (teamIds.length === 0) { - log("No teams found."); - hint("Use 'appwrite pull teams' to synchronize existing one, or use 'appwrite init team' to create a new one."); - return; + response = await storageService.createBucket( + bucket["$id"], + bucket.name, + bucket["$permissions"], + bucket.fileSecurity, + bucket.enabled, + bucket.maximumFileSize, + bucket.allowedFileExtensions, + bucket.compression, + bucket.encryption, + bucket.antivirus, + ); + } else { + throw e; + } } + } - let teams: any[] = []; - - for (const teamId of teamIds) { - const idTeams = configTeams.filter((t: any) => t.$id === teamId); - teams.push(...idTeams); - } + success(`Successfully pushed ${buckets.length} buckets.`); +}; - if (!(await approveChanges(teams, teamsGet, KeysTeams, 'teamId', 'teams'))) { - return; - } +const pushTeam = async (): Promise<void> => { + let response: any = {}; - log('Pushing teams ...'); + let teamIds: string[] = []; + const configTeams = localConfig.getTeams(); - for (let team of teams) { - log(`Pushing team ${chalk.bold(team['name'])} ...`); + if (cliConfig.all) { + checkDeployConditions(localConfig); + teamIds.push(...configTeams.map((t: any) => t.$id)); + } - try { - response = await teamsGet({ - teamId: team['$id'], - parseOutput: false, - }) - - await teamsUpdateName({ - teamId: team['$id'], - name: team.name, - parseOutput: false - }); - } catch (e: any) { - if (Number(e.code) === 404) { - log(`Team ${team.name} does not exist in the project. Creating ... `); - - response = await teamsCreate({ - teamId: team['$id'], - name: team.name, - parseOutput: false - }) - } else { - throw e; - } - } + if (teamIds.length === 0) { + const answers = await inquirer.prompt(questionsPushTeams); + if (answers.teams) { + teamIds.push(...answers.teams); } + } - success(`Successfully pushed ${teams.length} teams.`); -} - -interface PushMessagingTopicOptions { - returnOnZero?: boolean; -} - -const pushMessagingTopic = async ({ returnOnZero }: PushMessagingTopicOptions = { returnOnZero: false }): Promise<void> => { - let response: any = {}; + if (teamIds.length === 0) { + log("No teams found."); + hint( + "Use 'appwrite pull teams' to synchronize existing one, or use 'appwrite init team' to create a new one.", + ); + return; + } + + let teams: any[] = []; + + for (const teamId of teamIds) { + const idTeams = configTeams.filter((t: any) => t.$id === teamId); + teams.push(...idTeams); + } + + if ( + !(await approveChanges( + teams, + async (args: any) => { + const teamsService = await getTeamsService(); + return await teamsService.get(args.teamId); + }, + KeysTeams, + "teamId", + "teams", + )) + ) { + return; + } + + log("Pushing teams ..."); + + for (let team of teams) { + log(`Pushing team ${chalk.bold(team["name"])} ...`); + + const teamsService = await getTeamsService(); + try { + response = await teamsService.get(team["$id"]); - let topicsIds: string[] = []; - const configTopics = localConfig.getMessagingTopics(); + await teamsService.updateName(team["$id"], team.name); + } catch (e: any) { + if (Number(e.code) === 404) { + log(`Team ${team.name} does not exist in the project. Creating ... `); - if (cliConfig.all) { - checkDeployConditions(localConfig); - topicsIds.push(...configTopics.map((b: any) => b.$id)); + response = await teamsService.create(team["$id"], team.name); + } else { + throw e; + } } + } - if (topicsIds.length === 0) { - const answers = await inquirer.prompt(questionsPushMessagingTopics[0]) - if (answers.topics) { - topicsIds.push(...answers.topics); - } - } + success(`Successfully pushed ${teams.length} teams.`); +}; - if (topicsIds.length === 0) { - log("No topics found."); - hint("Use 'appwrite pull topics' to synchronize existing one, or use 'appwrite init topic' to create a new one."); - return; - } +const pushMessagingTopic = async (): Promise<void> => { + let response: any = {}; - let topics: any[] = []; + let topicsIds: string[] = []; + const configTopics = localConfig.getMessagingTopics(); - for (const topicId of topicsIds) { - const idTopic = configTopics.filter((b: any) => b.$id === topicId); - topics.push(...idTopic); - } + if (cliConfig.all) { + checkDeployConditions(localConfig); + topicsIds.push(...configTopics.map((b: any) => b.$id)); + } - if (!(await approveChanges(topics, messagingGetTopic, KeysTopics, 'topicId', 'topics'))) { - return; + if (topicsIds.length === 0) { + const answers = await inquirer.prompt(questionsPushMessagingTopics); + if (answers.topics) { + topicsIds.push(...answers.topics); } + } - log('Pushing topics ...'); - - for (let topic of topics) { - log(`Pushing topic ${chalk.bold(topic['name'])} ...`); - - try { - response = await messagingGetTopic({ - topicId: topic['$id'], - parseOutput: false - }) - log(`Topic ${topic.name} ( ${topic['$id']} ) already exists.`); - - await messagingUpdateTopic({ - topicId: topic['$id'], - name: topic.name, - subscribe: topic.subscribe, - parseOutput: false - }); - } catch (e: any) { - if (Number(e.code) === 404) { - log(`Topic ${topic.name} does not exist in the project. Creating ... `); - - response = await messagingCreateTopic({ - topicId: topic['$id'], - name: topic.name, - subscribe: topic.subscribe, - parseOutput: false - }) + if (topicsIds.length === 0) { + log("No topics found."); + hint( + "Use 'appwrite pull topics' to synchronize existing one, or use 'appwrite init topic' to create a new one.", + ); + return; + } + + let topics: any[] = []; + + for (const topicId of topicsIds) { + const idTopic = configTopics.filter((b: any) => b.$id === topicId); + topics.push(...idTopic); + } + + if ( + !(await approveChanges( + topics, + async (args: any) => { + const messagingService = await getMessagingService(); + return await messagingService.getTopic(args.topicId); + }, + KeysTopics, + "topicId", + "topics", + )) + ) { + return; + } + + log("Pushing topics ..."); + + for (let topic of topics) { + log(`Pushing topic ${chalk.bold(topic["name"])} ...`); + + const messagingService = await getMessagingService(); + try { + response = await messagingService.getTopic(topic["$id"]); + log(`Topic ${topic.name} ( ${topic["$id"]} ) already exists.`); + + await messagingService.updateTopic( + topic["$id"], + topic.name, + topic.subscribe, + ); + } catch (e: any) { + if (Number(e.code) === 404) { + log(`Topic ${topic.name} does not exist in the project. Creating ... `); + + response = await messagingService.createTopic( + topic["$id"], + topic.name, + topic.subscribe, + ); - success(`Created ${topic.name} ( ${topic['$id']} )`); - } else { - throw e; - } - } + success(`Created ${topic.name} ( ${topic["$id"]} )`); + } else { + throw e; + } } + } - success(`Successfully pushed ${topics.length} topics.`); -} + success(`Successfully pushed ${topics.length} topics.`); +}; export const push = new Command("push") - .description(commandDescriptions['push']) - .action(actionRunner(pushResources)); + .description(commandDescriptions["push"]) + .action(actionRunner(() => pushResources({ skipDeprecated: true }))); push - .command("all") - .description("Push all resource.") - .action(actionRunner(() => { - cliConfig.all = true; - return pushResources(); - })); + .command("all") + .description("Push all resource.") + .action( + actionRunner(() => { + cliConfig.all = true; + return pushResources({ skipDeprecated: true }); + }), + ); push - .command("settings") - .description("Push project name, services and auth settings") - .action(actionRunner(pushSettings)); + .command("settings") + .description("Push project name, services and auth settings") + .action(actionRunner(pushSettings)); push - .command("function") - .alias("functions") - .description("Push functions in the current directory.") - .option(`-f, --function-id <function-id>`, `ID of function to run`) - .option(`-A, --async`, `Don't wait for functions deployments status`) - .option("--no-code", "Don't push the function's code") - .option("--with-variables", `Push function variables.`) - .action(actionRunner(pushFunction)); + .command("function") + .alias("functions") + .description("Push functions in the current directory.") + .option(`-f, --function-id <function-id>`, `ID of function to run`) + .option(`-A, --async`, `Don't wait for functions deployments status`) + .option("--no-code", "Don't push the function's code") + .option("--with-variables", `Push function variables.`) + .action(actionRunner(pushFunction)); push - .command("site") - .alias("sites") - .description("Push sites in the current directory.") - .option(`-f, --site-id <site-id>`, `ID of site to run`) - .option(`-A, --async`, `Don't wait for sites deployments status`) - .option("--no-code", "Don't push the site's code") - .option("--with-variables", `Push site variables.`) - .action(actionRunner(pushSite)); + .command("site") + .alias("sites") + .description("Push sites in the current directory.") + .option(`-f, --site-id <site-id>`, `ID of site to run`) + .option(`-A, --async`, `Don't wait for sites deployments status`) + .option("--no-code", "Don't push the site's code") + .option("--with-variables", `Push site variables.`) + .action(actionRunner(pushSite)); push - .command("collection") - .alias("collections") - .description("Push collections in the current project. (deprecated, please use 'push tables' instead)") - .option(`-a, --attempts <numberOfAttempts>`, `Max number of attempts before timing out. default: 30.`) - .action(actionRunner(pushCollection)); + .command("collection") + .alias("collections") + .description( + "Push collections in the current project. (deprecated, please use 'push tables' instead)", + ) + .option( + `-a, --attempts <numberOfAttempts>`, + `Max number of attempts before timing out. default: 30.`, + ) + .action(actionRunner(pushCollection)); push - .command("table") - .alias("tables") - .description("Push tables in the current project.") - .option(`-a, --attempts <numberOfAttempts>`, `Max number of attempts before timing out. default: 30.`) - .action(actionRunner(pushTable)); + .command("table") + .alias("tables") + .description("Push tables in the current project.") + .option( + `-a, --attempts <numberOfAttempts>`, + `Max number of attempts before timing out. default: 30.`, + ) + .action(actionRunner(pushTable)); push - .command("bucket") - .alias("buckets") - .description("Push buckets in the current project.") - .action(actionRunner(pushBucket)); + .command("bucket") + .alias("buckets") + .description("Push buckets in the current project.") + .action(actionRunner(pushBucket)); push - .command("team") - .alias("teams") - .description("Push teams in the current project.") - .action(actionRunner(pushTeam)); + .command("team") + .alias("teams") + .description("Push teams in the current project.") + .action(actionRunner(pushTeam)); push - .command("topic") - .alias("topics") - .description("Push messaging topics in the current project.") - .action(actionRunner(pushMessagingTopic)); + .command("topic") + .alias("topics") + .description("Push messaging topics in the current project.") + .action(actionRunner(pushMessagingTopic)); export const deploy = new Command("deploy") - .description('Removed. Use appwrite push instead') - .action(actionRunner(async () => { - warn("appwrite deploy has been removed. Please use 'appwrite push' instead"); - })); + .description("Removed. Use appwrite push instead") + .action( + actionRunner(async () => { + warn( + "appwrite deploy has been removed. Please use 'appwrite push' instead", + ); + }), + ); diff --git a/lib/commands/run.ts b/lib/commands/run.ts index 8caf2feb..56de363a 100644 --- a/lib/commands/run.ts +++ b/lib/commands/run.ts @@ -1,336 +1,416 @@ -import { Tail } from 'tail'; -import { parse as parseDotenv } from 'dotenv'; -import chalk from 'chalk'; -import ignore = require('ignore'); -import tar = require('tar'); -import fs = require('fs'); -import chokidar from 'chokidar'; -import inquirer from 'inquirer'; -import path = require('path'); -import { Command } from 'commander'; -import { localConfig, globalConfig } from '../config'; -import { paginate } from '../paginate'; -import { functionsListVariables } from './functions'; -import { questionsRunFunctions } from '../questions'; -import { actionRunner, success, log, warn, error, hint, commandDescriptions, drawTable } from '../parser'; -import { systemHasCommand, isPortTaken, getAllFiles } from '../utils'; -import { runtimeNames, systemTools, JwtManager, Queue } from '../emulation/utils'; -import { dockerStop, dockerCleanup, dockerStart, dockerBuild, dockerPull } from '../emulation/docker'; +import { Tail } from "tail"; +import { parse as parseDotenv } from "dotenv"; +import chalk from "chalk"; +import ignoreModule from "ignore"; +const ignore: typeof ignoreModule = + (ignoreModule as any).default ?? ignoreModule; +import tar from "tar"; +import fs from "fs"; +import chokidar from "chokidar"; +import inquirer from "inquirer"; +import path from "path"; +import { Command } from "commander"; +import { localConfig, globalConfig } from "../config.js"; +import { paginate } from "../paginate.js"; +import { getFunctionsService } from "../services.js"; +import { questionsRunFunctions } from "../questions.js"; +import { + actionRunner, + success, + log, + warn, + error, + hint, + commandDescriptions, + drawTable, +} from "../parser.js"; +import { systemHasCommand, isPortTaken, getAllFiles } from "../utils.js"; +import { + runtimeNames, + systemTools, + JwtManager, + Queue, +} from "../emulation/utils.js"; +import { + dockerStop, + dockerCleanup, + dockerStart, + dockerBuild, + dockerPull, +} from "../emulation/docker.js"; interface RunFunctionOptions { - port?: string | number; - functionId?: string; - withVariables?: boolean; - reload?: boolean; - userId?: string; + port?: string | number; + functionId?: string; + withVariables?: boolean; + reload?: boolean; + userId?: string; } -const runFunction = async ({ port, functionId, withVariables, reload, userId }: RunFunctionOptions = {}): Promise<void> => { - // Selection - if(!functionId) { - const answers = await inquirer.prompt(questionsRunFunctions[0]); - functionId = answers.function; +const runFunction = async ({ + port, + functionId, + withVariables, + reload, + userId, +}: RunFunctionOptions = {}): Promise<void> => { + // Selection + if (!functionId) { + const answers = await inquirer.prompt([questionsRunFunctions[0]]); + functionId = answers.function; + } + + const functions = localConfig.getFunctions(); + const func = functions.find((f: any) => f.$id === functionId); + if (!func) { + throw new Error("Function '" + functionId + "' not found."); + } + + const runtimeName = func.runtime.split("-").slice(0, -1).join("-"); + const tool = systemTools[runtimeName]; + + // Configuration: Port + let portNum: number | null = null; + if (port) { + portNum = +port; + } + + if (isNaN(portNum!)) { + portNum = null; + } + + if (portNum) { + const taken = await isPortTaken(portNum); + + if (taken) { + error(`Port ${portNum} is already in use by another process.`); + return; } - - const functions = localConfig.getFunctions(); - const func = functions.find((f: any) => f.$id === functionId); - if (!func) { - throw new Error("Function '" + functionId + "' not found.") - } - - const runtimeName = func.runtime.split("-").slice(0, -1).join("-"); - const tool = systemTools[runtimeName]; - - // Configuration: Port - let portNum: number | null = null; - if(port) { - portNum = +port; + } + + if (!portNum) { + let portFound = false; + portNum = 3000; + while (portNum < 3100) { + const taken = await isPortTaken(portNum); + if (!taken) { + portFound = true; + break; + } + + portNum++; } - if(isNaN(portNum!)) { - portNum = null; - } - - if(portNum) { - const taken = await isPortTaken(portNum); - - if(taken) { - error(`Port ${portNum} is already in use by another process.`); - return; - } - } - - if(!portNum) { - let portFound = false; - portNum = 3000; - while(portNum < 3100) { - const taken = await isPortTaken(portNum); - if(!taken) { - portFound = true; - break; - } - - portNum++; - } - - if(!portFound) { - error("Could not find an available port. Please select a port with 'appwrite run --port YOUR_PORT' command."); - return; - } + if (!portFound) { + error( + "Could not find an available port. Please select a port with 'appwrite run --port YOUR_PORT' command.", + ); + return; } - - // Configuration: Engine - if(!systemHasCommand('docker')) { - return error("Docker Engine is required for local development. Please install Docker using: https://docs.docker.com/engine/install/"); + } + + // Configuration: Engine + if (!systemHasCommand("docker")) { + return error( + "Docker Engine is required for local development. Please install Docker using: https://docs.docker.com/engine/install/", + ); + } + + // Settings + const settings = { + runtime: func.runtime, + entrypoint: func.entrypoint, + path: func.path, + commands: func.commands, + scopes: func.scopes ?? [], + }; + + drawTable([settings]); + log( + "If you wish to change your local settings, update the appwrite.config.json file and rerun the 'appwrite run' command.", + ); + hint( + "Permissions, events, CRON and timeouts dont apply when running locally.", + ); + + await dockerCleanup(func.$id); + + process.on("SIGINT", async () => { + log("Cleaning up ..."); + await dockerCleanup(func.$id); + success("Local function successfully stopped."); + process.exit(); + }); + + const logsPath = path.join( + localConfig.getDirname(), + func.path, + ".appwrite/logs.txt", + ); + const errorsPath = path.join( + localConfig.getDirname(), + func.path, + ".appwrite/errors.txt", + ); + + if (!fs.existsSync(path.dirname(logsPath))) { + fs.mkdirSync(path.dirname(logsPath), { recursive: true }); + } + + if (!fs.existsSync(logsPath)) { + fs.writeFileSync(logsPath, ""); + } + + if (!fs.existsSync(errorsPath)) { + fs.writeFileSync(errorsPath, ""); + } + + const userVariables: Record<string, string> = {}; + const allVariables: Record<string, string> = {}; + + if (withVariables) { + try { + const { variables: remoteVariables } = await paginate( + async () => (await getFunctionsService()).listVariables(func["$id"]), + {}, + 100, + "variables", + ); + + remoteVariables.forEach((v: any) => { + allVariables[v.key] = v.value; + userVariables[v.key] = v.value; + }); + } catch (err: any) { + warn( + "Remote variables not fetched. Production environment variables will not be available. Reason: " + + err.message, + ); } + } - // Settings - const settings = { - runtime: func.runtime, - entrypoint: func.entrypoint, - path: func.path, - commands: func.commands, - scopes: func.scopes ?? [] - }; - - drawTable([settings]); - log("If you wish to change your local settings, update the appwrite.config.json file and rerun the 'appwrite run' command."); - hint("Permissions, events, CRON and timeouts dont apply when running locally."); + const functionPath = path.join(localConfig.getDirname(), func.path); + const envPath = path.join(functionPath, ".env"); + if (fs.existsSync(envPath)) { + const env = parseDotenv(fs.readFileSync(envPath).toString() ?? ""); - await dockerCleanup(func.$id); - - process.on('SIGINT', async () => { - log('Cleaning up ...'); - await dockerCleanup(func.$id); - success("Local function successfully stopped."); - process.exit(); + Object.keys(env).forEach((key) => { + allVariables[key] = env[key]; + userVariables[key] = env[key]; }); - - const logsPath = path.join(localConfig.getDirname(), func.path, '.appwrite/logs.txt'); - const errorsPath = path.join(localConfig.getDirname(), func.path, '.appwrite/errors.txt'); - - if(!fs.existsSync(path.dirname(logsPath))) { - fs.mkdirSync(path.dirname(logsPath), { recursive: true }); - } - - if (!fs.existsSync(logsPath)) { - fs.writeFileSync(logsPath, ''); + } + + allVariables["APPWRITE_FUNCTION_API_ENDPOINT"] = + globalConfig.getFrom("endpoint"); + allVariables["APPWRITE_FUNCTION_ID"] = func.$id; + allVariables["APPWRITE_FUNCTION_NAME"] = func.name; + allVariables["APPWRITE_FUNCTION_DEPLOYMENT"] = ""; // TODO: Implement when relevant + allVariables["APPWRITE_FUNCTION_PROJECT_ID"] = + localConfig.getProject().projectId; + allVariables["APPWRITE_FUNCTION_RUNTIME_NAME"] = + runtimeNames[runtimeName] ?? ""; + allVariables["APPWRITE_FUNCTION_RUNTIME_VERSION"] = func.runtime; + + try { + await JwtManager.setup(userId, func.scopes ?? []); + } catch (err: any) { + warn( + "Dynamic API key not generated. Header x-appwrite-key will not be set. Reason: " + + err.message, + ); + } + + const headers: Record<string, string> = {}; + headers["x-appwrite-key"] = JwtManager.functionJwt ?? ""; + headers["x-appwrite-trigger"] = "http"; + headers["x-appwrite-event"] = ""; + headers["x-appwrite-user-id"] = userId ?? ""; + headers["x-appwrite-user-jwt"] = JwtManager.userJwt ?? ""; + allVariables["OPEN_RUNTIMES_HEADERS"] = JSON.stringify(headers); + + if (Object.keys(userVariables).length > 0) { + drawTable( + Object.keys(userVariables).map((key) => ({ + key, + value: userVariables[key] + .split("") + .filter((_: string, i: number) => i < 16) + .map(() => "*") + .join(""), + })), + ); + } + + await dockerPull(func); + + new Tail(logsPath).on("line", function (data: string) { + process.stdout.write(chalk.white(`${data}\n`)); + }); + new Tail(errorsPath).on("line", function (data: string) { + process.stdout.write(chalk.white(`${data}\n`)); + }); + + if (reload) { + const ignorer = ignore(); + ignorer.add(".appwrite"); + ignorer.add("code.tar.gz"); + + if (func.ignore) { + ignorer.add(func.ignore); + } else if (fs.existsSync(path.join(functionPath, ".gitignore"))) { + ignorer.add( + fs.readFileSync(path.join(functionPath, ".gitignore")).toString(), + ); } - if (!fs.existsSync(errorsPath)) { - fs.writeFileSync(errorsPath, ''); - } + chokidar + .watch(".", { + cwd: path.join(localConfig.getDirname(), func.path), + ignoreInitial: true, + ignored: (xpath: string) => { + const relativePath = path.relative(functionPath, xpath); + + if (!relativePath) { + return false; + } + return ignorer.ignores(relativePath); + }, + }) + .on("all", async (_event: string, filePath: string) => { + Queue.push(filePath); + }); + } + + Queue.events.on("reload", async ({ files }: { files: string[] }) => { + Queue.lock(); - const userVariables: Record<string, string> = {}; - const allVariables: Record<string, string> = {}; - - if(withVariables) { - try { - const { variables: remoteVariables } = await paginate(functionsListVariables, { - functionId: func['$id'], - parseOutput: false - }, 100, 'variables'); - - remoteVariables.forEach((v: any) => { - allVariables[v.key] = v.value; - userVariables[v.key] = v.value; - }); - } catch(err: any) { - warn("Remote variables not fetched. Production environment variables will not be available. Reason: " + err.message); + try { + await dockerStop(func.$id); + + const dependencyFile = files.find((filePath: string) => + tool.dependencyFiles.includes(filePath), + ); + if (tool.isCompiled || dependencyFile) { + log(`Rebuilding the function due to file changes ...`); + await dockerBuild(func, allVariables); + + if (!Queue.isEmpty()) { + Queue.unlock(); + return; } - } - const functionPath = path.join(localConfig.getDirname(), func.path); - const envPath = path.join(functionPath, '.env'); - if(fs.existsSync(envPath)) { - const env = parseDotenv(fs.readFileSync(envPath).toString() ?? ''); + await dockerStart(func, allVariables, portNum!); + } else { + log( + "Hot-swapping function.. Files with change are " + files.join(", "), + ); + + const hotSwapPath = path.join(functionPath, ".appwrite/hot-swap"); + const buildPath = path.join(functionPath, ".appwrite/build.tar.gz"); + + // Prepare temp folder + if (!fs.existsSync(hotSwapPath)) { + fs.mkdirSync(hotSwapPath, { recursive: true }); + } else { + fs.rmSync(hotSwapPath, { recursive: true, force: true }); + fs.mkdirSync(hotSwapPath, { recursive: true }); + } - Object.keys(env).forEach((key) => { - allVariables[key] = env[key]; - userVariables[key] = env[key]; + await tar.extract({ + keep: true, + sync: true, + cwd: hotSwapPath, + file: buildPath, }); - } - - allVariables['APPWRITE_FUNCTION_API_ENDPOINT'] = globalConfig.getFrom('endpoint'); - allVariables['APPWRITE_FUNCTION_ID'] = func.$id; - allVariables['APPWRITE_FUNCTION_NAME'] = func.name; - allVariables['APPWRITE_FUNCTION_DEPLOYMENT'] = ''; // TODO: Implement when relevant - allVariables['APPWRITE_FUNCTION_PROJECT_ID'] = localConfig.getProject().projectId; - allVariables['APPWRITE_FUNCTION_RUNTIME_NAME'] = runtimeNames[runtimeName] ?? ''; - allVariables['APPWRITE_FUNCTION_RUNTIME_VERSION'] = func.runtime; - - try { - await JwtManager.setup(userId, func.scopes ?? []); - } catch(err: any) { - warn("Dynamic API key not generated. Header x-appwrite-key will not be set. Reason: " + err.message); - } - - const headers: Record<string, string> = {}; - headers['x-appwrite-key'] = JwtManager.functionJwt ?? ''; - headers['x-appwrite-trigger'] = 'http'; - headers['x-appwrite-event'] = ''; - headers['x-appwrite-user-id'] = userId ?? ''; - headers['x-appwrite-user-jwt'] = JwtManager.userJwt ?? ''; - allVariables['OPEN_RUNTIMES_HEADERS'] = JSON.stringify(headers); - - if(Object.keys(userVariables).length > 0) { - drawTable(Object.keys(userVariables).map((key) => ({ - key, - value: userVariables[key].split("").filter((_: string, i: number) => i < 16).map(() => "*").join("") - }))); - } - - await dockerPull(func); - - new Tail(logsPath).on("line", function(data: string) { - process.stdout.write(chalk.white(`${data}\n`)); - }); - new Tail(errorsPath).on("line", function(data: string) { - process.stdout.write(chalk.white(`${data}\n`)); - }); - if(reload) { const ignorer = ignore(); - ignorer.add('.appwrite'); - ignorer.add('code.tar.gz'); - + ignorer.add(".appwrite"); if (func.ignore) { - ignorer.add(func.ignore); - } else if (fs.existsSync(path.join(functionPath, '.gitignore'))) { - ignorer.add(fs.readFileSync(path.join(functionPath, '.gitignore')).toString()); + ignorer.add(func.ignore); + } else if (fs.existsSync(path.join(functionPath, ".gitignore"))) { + ignorer.add( + fs.readFileSync(path.join(functionPath, ".gitignore")).toString(), + ); } - chokidar.watch('.', { - cwd: path.join(localConfig.getDirname(), func.path), - ignoreInitial: true, - ignored: (xpath: string) => { - const relativePath = path.relative(functionPath, xpath); - - if(!relativePath) { - return false; - } - return ignorer.ignores(relativePath); - } - }).on('all', async (_event: string, filePath: string) => { - Queue.push(filePath); - }); - } - - Queue.events.on('reload', async ({ files }: { files: string[] }) => { - Queue.lock(); - - try { - await dockerStop(func.$id); - - const dependencyFile = files.find((filePath: string) => tool.dependencyFiles.includes(filePath)); - if(tool.isCompiled || dependencyFile) { - log(`Rebuilding the function due to file changes ...`); - await dockerBuild(func, allVariables); - - if(!Queue.isEmpty()) { - Queue.unlock(); - return; - } - - await dockerStart(func, allVariables, portNum!); - } else { - log('Hot-swapping function.. Files with change are ' + files.join(', ')); - - const hotSwapPath = path.join(functionPath, '.appwrite/hot-swap'); - const buildPath = path.join(functionPath, '.appwrite/build.tar.gz'); - - // Prepare temp folder - if (!fs.existsSync(hotSwapPath)) { - fs.mkdirSync(hotSwapPath, { recursive: true }); - } else { - fs.rmSync(hotSwapPath, { recursive: true, force: true }); - fs.mkdirSync(hotSwapPath, { recursive: true }); - } - - await tar - .extract({ - keep: true, - gzip: true, - sync: true, - cwd: hotSwapPath, - file: buildPath - }); - - const ignorer = ignore.default(); - ignorer.add('.appwrite'); - if (func.ignore) { - ignorer.add(func.ignore); - } else if (fs.existsSync(path.join(functionPath, '.gitignore'))) { - ignorer.add(fs.readFileSync(path.join(functionPath, '.gitignore')).toString()); - } - - const filesToCopy = getAllFiles(functionPath).map((file: string) => path.relative(functionPath, file)).filter((file: string) => !ignorer.ignores(file)); - for(const f of filesToCopy) { - const filePath = path.join(hotSwapPath, f); - if (fs.existsSync(filePath)) { - fs.rmSync(filePath, { force: true }); - } - - const fileDir = path.dirname(filePath); - if (!fs.existsSync(fileDir)) { - fs.mkdirSync(fileDir, { recursive: true }); - } - - const sourcePath = path.join(functionPath, f); - fs.copyFileSync(sourcePath, filePath); - } - - await tar - .create({ - gzip: true, - sync: true, - cwd: hotSwapPath, - file: buildPath - }, ['.']); - - await dockerStart(func, allVariables, portNum!); - } - } catch(err) { - console.error(err); - } finally { - Queue.unlock(); + const filesToCopy = getAllFiles(functionPath) + .map((file: string) => path.relative(functionPath, file)) + .filter((file: string) => !ignorer.ignores(file)); + for (const f of filesToCopy) { + const filePath = path.join(hotSwapPath, f); + if (fs.existsSync(filePath)) { + fs.rmSync(filePath, { force: true }); + } + + const fileDir = path.dirname(filePath); + if (!fs.existsSync(fileDir)) { + fs.mkdirSync(fileDir, { recursive: true }); + } + + const sourcePath = path.join(functionPath, f); + fs.copyFileSync(sourcePath, filePath); } - }); - - Queue.lock(); - log('Building function using Docker ...'); - await dockerBuild(func, allVariables); - - if(!Queue.isEmpty()) { - Queue.unlock(); - return; + await tar.create( + { + gzip: true, + sync: true, + cwd: hotSwapPath, + file: buildPath, + }, + ["."], + ); + + await dockerStart(func, allVariables, portNum!); + } + } catch (err) { + console.error(err); + } finally { + Queue.unlock(); } + }); + + Queue.lock(); - log('Starting function using Docker ...'); - hint('Function automatically restarts when you edit your code.'); - await dockerStart(func, allVariables, portNum!); + log("Building function using Docker ..."); + await dockerBuild(func, allVariables); + if (!Queue.isEmpty()) { Queue.unlock(); -} + return; + } + + log("Starting function using Docker ..."); + hint("Function automatically restarts when you edit your code."); + await dockerStart(func, allVariables, portNum!); + + Queue.unlock(); +}; export const run = new Command("run") - .description(commandDescriptions['run']) - .configureHelp({ - helpWidth: process.stdout.columns || 80 - }) - .action(actionRunner(async (_options: any, command: Command) => { - command.help(); - })); + .description(commandDescriptions["run"]) + .configureHelp({ + helpWidth: process.stdout.columns || 80, + }) + .action( + actionRunner(async (_options: any, command: Command) => { + command.help(); + }), + ); run - .command("function") - .alias("functions") - .description("Run functions in the current directory.") - .option(`--function-id <function-id>`, `ID of function to run`) - .option(`--port <port>`, `Local port`) - .option(`--user-id <user-id>`, `ID of user to impersonate`) - .option(`--with-variables`, `Run with function variables from function settings`) - .option(`--no-reload`, `Prevent live reloading of server when changes are made to function files`) - .action(actionRunner(runFunction)); - + .command("function") + .alias("functions") + .description("Run functions in the current directory.") + .option(`--function-id <function-id>`, `ID of function to run`) + .option(`--port <port>`, `Local port`) + .option(`--user-id <user-id>`, `ID of user to impersonate`) + .option( + `--with-variables`, + `Run with function variables from function settings`, + ) + .option( + `--no-reload`, + `Prevent live reloading of server when changes are made to function files`, + ) + .action(actionRunner(runFunction)); diff --git a/lib/commands/services/account.ts b/lib/commands/services/account.ts new file mode 100644 index 00000000..e1bfcd03 --- /dev/null +++ b/lib/commands/services/account.ts @@ -0,0 +1,832 @@ +import { Command } from "commander"; +import { sdkForProject } from "../../sdks.js"; +import { + actionRunner, + commandDescriptions, + parseBool, + parseInteger, +} from "../../parser.js"; +import { + Account, + AuthenticatorType, + AuthenticationFactor, + OAuthProvider, +} from "@appwrite.io/console"; + +let accountClient: Account | null = null; + +const getAccountClient = async (): Promise<Account> => { + if (!accountClient) { + const sdkClient = await sdkForProject(); + accountClient = new Account(sdkClient); + } + return accountClient; +}; + +export const account = new Command("account") + .description(commandDescriptions["account"] ?? "") + .configureHelp({ + helpWidth: process.stdout.columns || 80, + }); + +account + .command(`get`) + .description(`Get the currently logged in user.`) + .action(actionRunner(async () => await (await getAccountClient()).get())); + +account + .command(`create`) + .description( + `Use this endpoint to allow a new user to register a new account in your project. After the user registration completes successfully, you can use the [/account/verfication](https://appwrite.io/docs/references/cloud/client-web/account#createVerification) route to start verifying the user email address. To allow the new user to login to their new account, you need to create a new [account session](https://appwrite.io/docs/references/cloud/client-web/account#createEmailSession).`, + ) + .requiredOption( + `--user-id <user-id>`, + `User ID. Choose a custom ID or generate a random ID with \`ID.unique()\`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.`, + ) + .requiredOption(`--email <email>`, `User email.`) + .requiredOption( + `--password <password>`, + `New user password. Must be between 8 and 256 chars.`, + ) + .option(`--name <name>`, `User name. Max length: 128 chars.`) + .action( + actionRunner( + async ({ userId, email, password, name }) => + await (await getAccountClient()).create(userId, email, password, name), + ), + ); + +account + .command(`delete`) + .description(`Delete the currently logged in user.`) + .action(actionRunner(async () => await (await getAccountClient()).delete())); + +account + .command(`update-email`) + .description( + `Update currently logged in user account email address. After changing user address, the user confirmation status will get reset. A new confirmation email is not sent automatically however you can use the send confirmation email endpoint again to send the confirmation email. For security measures, user password is required to complete this request. +This endpoint can also be used to convert an anonymous account to a normal one, by passing an email address and a new password. +`, + ) + .requiredOption(`--email <email>`, `User email.`) + .requiredOption( + `--password <password>`, + `User password. Must be at least 8 chars.`, + ) + .action( + actionRunner( + async ({ email, password }) => + await (await getAccountClient()).updateEmail(email, password), + ), + ); + +account + .command(`list-identities`) + .description(`Get the list of identities for the currently logged in user.`) + .option( + `--queries [queries...]`, + `Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: userId, provider, providerUid, providerEmail, providerAccessTokenExpiry`, + ) + .option( + `--total [value]`, + `When set to false, the total count returned will be 0 and will not be calculated.`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .action( + actionRunner( + async ({ queries, total }) => + await (await getAccountClient()).listIdentities(queries, total), + ), + ); + +account + .command(`delete-identity`) + .description(`Delete an identity by its unique ID.`) + .requiredOption(`--identity-id <identity-id>`, `Identity ID.`) + .action( + actionRunner( + async ({ identityId }) => + await (await getAccountClient()).deleteIdentity(identityId), + ), + ); + +account + .command(`create-jwt`) + .description( + `Use this endpoint to create a JSON Web Token. You can use the resulting JWT to authenticate on behalf of the current user when working with the Appwrite server-side API and SDKs. The JWT secret is valid for 15 minutes from its creation and will be invalid if the user will logout in that time frame.`, + ) + .option( + `--duration <duration>`, + `Time in seconds before JWT expires. Default duration is 900 seconds, and maximum is 3600 seconds.`, + parseInteger, + ) + .action( + actionRunner( + async ({ duration }) => + await (await getAccountClient()).createJWT(duration), + ), + ); + +account + .command(`list-logs`) + .description( + `Get the list of latest security activity logs for the currently logged in user. Each log returns user IP address, location and date and time of log.`, + ) + .option( + `--queries [queries...]`, + `Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Only supported methods are limit and offset`, + ) + .option( + `--total [value]`, + `When set to false, the total count returned will be 0 and will not be calculated.`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .action( + actionRunner( + async ({ queries, total }) => + await (await getAccountClient()).listLogs(queries, total), + ), + ); + +account + .command(`update-mfa`) + .description(`Enable or disable MFA on an account.`) + .requiredOption(`--mfa <mfa>`, `Enable or disable MFA.`, parseBool) + .action( + actionRunner( + async ({ mfa }) => await (await getAccountClient()).updateMFA(mfa), + ), + ); + +account + .command(`create-mfa-authenticator`) + .description( + `[**DEPRECATED** - This command is deprecated. Please use 'account createMfaAuthenticator' instead] Add an authenticator app to be used as an MFA factor. Verify the authenticator using the [verify authenticator](/docs/references/cloud/client-web/account#updateMfaAuthenticator) method.`, + ) + .requiredOption(`--type <type>`, `Type of authenticator. Must be \`totp\``) + .action( + actionRunner( + async ({ xType }) => + await ( + await getAccountClient() + ).createMfaAuthenticator(xType as AuthenticatorType), + ), + ); + +account + .command(`update-mfa-authenticator`) + .description( + `[**DEPRECATED** - This command is deprecated. Please use 'account updateMfaAuthenticator' instead] Verify an authenticator app after adding it using the [add authenticator](/docs/references/cloud/client-web/account#createMfaAuthenticator) method.`, + ) + .requiredOption(`--type <type>`, `Type of authenticator.`) + .requiredOption(`--otp <otp>`, `Valid verification token.`) + .action( + actionRunner( + async ({ xType, otp }) => + await ( + await getAccountClient() + ).updateMfaAuthenticator(xType as AuthenticatorType, otp), + ), + ); + +account + .command(`delete-mfa-authenticator`) + .description( + `[**DEPRECATED** - This command is deprecated. Please use 'account deleteMfaAuthenticator' instead] Delete an authenticator for a user by ID.`, + ) + .requiredOption(`--type <type>`, `Type of authenticator.`) + .action( + actionRunner( + async ({ xType }) => + await ( + await getAccountClient() + ).deleteMfaAuthenticator(xType as AuthenticatorType), + ), + ); + +account + .command(`create-mfa-challenge`) + .description( + `[**DEPRECATED** - This command is deprecated. Please use 'account createMfaChallenge' instead] Begin the process of MFA verification after sign-in. Finish the flow with [updateMfaChallenge](/docs/references/cloud/client-web/account#updateMfaChallenge) method.`, + ) + .requiredOption( + `--factor <factor>`, + `Factor used for verification. Must be one of following: \`email\`, \`phone\`, \`totp\`, \`recoveryCode\`.`, + ) + .action( + actionRunner( + async ({ factor }) => + await ( + await getAccountClient() + ).createMfaChallenge(factor as AuthenticationFactor), + ), + ); + +account + .command(`update-mfa-challenge`) + .description( + `[**DEPRECATED** - This command is deprecated. Please use 'account updateMfaChallenge' instead] Complete the MFA challenge by providing the one-time password. Finish the process of MFA verification by providing the one-time password. To begin the flow, use [createMfaChallenge](/docs/references/cloud/client-web/account#createMfaChallenge) method.`, + ) + .requiredOption(`--challenge-id <challenge-id>`, `ID of the challenge.`) + .requiredOption(`--otp <otp>`, `Valid verification token.`) + .action( + actionRunner( + async ({ challengeId, otp }) => + await (await getAccountClient()).updateMfaChallenge(challengeId, otp), + ), + ); + +account + .command(`list-mfa-factors`) + .description( + `[**DEPRECATED** - This command is deprecated. Please use 'account listMfaFactors' instead] List the factors available on the account to be used as a MFA challange.`, + ) + .action( + actionRunner(async () => await (await getAccountClient()).listMfaFactors()), + ); + +account + .command(`get-mfa-recovery-codes`) + .description( + `[**DEPRECATED** - This command is deprecated. Please use 'account getMfaRecoveryCodes' instead] Get recovery codes that can be used as backup for MFA flow. Before getting codes, they must be generated using [createMfaRecoveryCodes](/docs/references/cloud/client-web/account#createMfaRecoveryCodes) method. An OTP challenge is required to read recovery codes.`, + ) + .action( + actionRunner( + async () => await (await getAccountClient()).getMfaRecoveryCodes(), + ), + ); + +account + .command(`create-mfa-recovery-codes`) + .description( + `[**DEPRECATED** - This command is deprecated. Please use 'account createMfaRecoveryCodes' instead] Generate recovery codes as backup for MFA flow. It's recommended to generate and show then immediately after user successfully adds their authehticator. Recovery codes can be used as a MFA verification type in [createMfaChallenge](/docs/references/cloud/client-web/account#createMfaChallenge) method.`, + ) + .action( + actionRunner( + async () => await (await getAccountClient()).createMfaRecoveryCodes(), + ), + ); + +account + .command(`update-mfa-recovery-codes`) + .description( + `[**DEPRECATED** - This command is deprecated. Please use 'account updateMfaRecoveryCodes' instead] Regenerate recovery codes that can be used as backup for MFA flow. Before regenerating codes, they must be first generated using [createMfaRecoveryCodes](/docs/references/cloud/client-web/account#createMfaRecoveryCodes) method. An OTP challenge is required to regenreate recovery codes.`, + ) + .action( + actionRunner( + async () => await (await getAccountClient()).updateMfaRecoveryCodes(), + ), + ); + +account + .command(`update-name`) + .description(`Update currently logged in user account name.`) + .requiredOption(`--name <name>`, `User name. Max length: 128 chars.`) + .action( + actionRunner( + async ({ name }) => await (await getAccountClient()).updateName(name), + ), + ); + +account + .command(`update-password`) + .description( + `Update currently logged in user password. For validation, user is required to pass in the new password, and the old password. For users created with OAuth, Team Invites and Magic URL, oldPassword is optional.`, + ) + .requiredOption( + `--password <password>`, + `New user password. Must be at least 8 chars.`, + ) + .option( + `--old-password <old-password>`, + `Current user password. Must be at least 8 chars.`, + ) + .action( + actionRunner( + async ({ password, oldPassword }) => + await (await getAccountClient()).updatePassword(password, oldPassword), + ), + ); + +account + .command(`update-phone`) + .description( + `Update the currently logged in user's phone number. After updating the phone number, the phone verification status will be reset. A confirmation SMS is not sent automatically, however you can use the [POST /account/verification/phone](https://appwrite.io/docs/references/cloud/client-web/account#createPhoneVerification) endpoint to send a confirmation SMS.`, + ) + .requiredOption( + `--phone <phone>`, + `Phone number. Format this number with a leading '+' and a country code, e.g., +16175551212.`, + ) + .requiredOption( + `--password <password>`, + `User password. Must be at least 8 chars.`, + ) + .action( + actionRunner( + async ({ phone, password }) => + await (await getAccountClient()).updatePhone(phone, password), + ), + ); + +account + .command(`get-prefs`) + .description( + `Get the preferences as a key-value object for the currently logged in user.`, + ) + .action( + actionRunner(async () => await (await getAccountClient()).getPrefs()), + ); + +account + .command(`update-prefs`) + .description( + `Update currently logged in user account preferences. The object you pass is stored as is, and replaces any previous value. The maximum allowed prefs size is 64kB and throws error if exceeded.`, + ) + .requiredOption(`--prefs <prefs>`, `Prefs key-value JSON object.`) + .action( + actionRunner( + async ({ prefs }) => + await (await getAccountClient()).updatePrefs(JSON.parse(prefs)), + ), + ); + +account + .command(`create-recovery`) + .description( + `Sends the user an email with a temporary secret key for password reset. When the user clicks the confirmation link he is redirected back to your app password reset URL with the secret key and email address values attached to the URL query string. Use the query string params to submit a request to the [PUT /account/recovery](https://appwrite.io/docs/references/cloud/client-web/account#updateRecovery) endpoint to complete the process. The verification link sent to the user's email address is valid for 1 hour.`, + ) + .requiredOption(`--email <email>`, `User email.`) + .requiredOption( + `--url <url>`, + `URL to redirect the user back to your app from the recovery email. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.`, + ) + .action( + actionRunner( + async ({ email, url }) => + await (await getAccountClient()).createRecovery(email, url), + ), + ); + +account + .command(`update-recovery`) + .description( + `Use this endpoint to complete the user account password reset. Both the **userId** and **secret** arguments will be passed as query parameters to the redirect URL you have provided when sending your request to the [POST /account/recovery](https://appwrite.io/docs/references/cloud/client-web/account#createRecovery) endpoint. + +Please note that in order to avoid a [Redirect Attack](https://github.com/OWASP/CheatSheetSeries/blob/master/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.md) the only valid redirect URLs are the ones from domains you have set when adding your platforms in the console interface.`, + ) + .requiredOption(`--user-id <user-id>`, `User ID.`) + .requiredOption(`--secret <secret>`, `Valid reset token.`) + .requiredOption( + `--password <password>`, + `New user password. Must be between 8 and 256 chars.`, + ) + .action( + actionRunner( + async ({ userId, secret, password }) => + await ( + await getAccountClient() + ).updateRecovery(userId, secret, password), + ), + ); + +account + .command(`list-sessions`) + .description( + `Get the list of active sessions across different devices for the currently logged in user.`, + ) + .action( + actionRunner(async () => await (await getAccountClient()).listSessions()), + ); + +account + .command(`delete-sessions`) + .description( + `Delete all sessions from the user account and remove any sessions cookies from the end client.`, + ) + .action( + actionRunner(async () => await (await getAccountClient()).deleteSessions()), + ); + +account + .command(`create-anonymous-session`) + .description( + `Use this endpoint to allow a new user to register an anonymous account in your project. This route will also create a new session for the user. To allow the new user to convert an anonymous account to a normal account, you need to update its [email and password](https://appwrite.io/docs/references/cloud/client-web/account#updateEmail) or create an [OAuth2 session](https://appwrite.io/docs/references/cloud/client-web/account#CreateOAuth2Session).`, + ) + .action( + actionRunner( + async () => await (await getAccountClient()).createAnonymousSession(), + ), + ); + +account + .command(`create-email-password-session`) + .description( + `Allow the user to login into their account by providing a valid email and password combination. This route will create a new session for the user. + +A user is limited to 10 active sessions at a time by default. [Learn more about session limits](https://appwrite.io/docs/authentication-security#limits).`, + ) + .requiredOption(`--email <email>`, `User email.`) + .requiredOption( + `--password <password>`, + `User password. Must be at least 8 chars.`, + ) + .action( + actionRunner( + async ({ email, password }) => + await ( + await getAccountClient() + ).createEmailPasswordSession(email, password), + ), + ); + +account + .command(`update-magic-urlsession`) + .description( + `[**DEPRECATED** - This command is deprecated. Please use 'account updateMagicURLSession' instead] Use this endpoint to create a session from token. Provide the **userId** and **secret** parameters from the successful response of authentication flows initiated by token creation. For example, magic URL and phone login.`, + ) + .requiredOption( + `--user-id <user-id>`, + `User ID. Choose a custom ID or generate a random ID with \`ID.unique()\`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.`, + ) + .requiredOption(`--secret <secret>`, `Valid verification token.`) + .action( + actionRunner( + async ({ userId, secret }) => + await (await getAccountClient()).updateMagicURLSession(userId, secret), + ), + ); + +account + .command(`create-oauth2-session`) + .description( + `Allow the user to login to their account using the OAuth2 provider of their choice. Each OAuth2 provider should be enabled from the Appwrite console first. Use the success and failure arguments to provide a redirect URL's back to your app when login is completed. + +If there is already an active session, the new session will be attached to the logged-in account. If there are no active sessions, the server will attempt to look for a user with the same email address as the email received from the OAuth2 provider and attach the new session to the existing user. If no matching user is found - the server will create a new user. + +A user is limited to 10 active sessions at a time by default. [Learn more about session limits](https://appwrite.io/docs/authentication-security#limits). +`, + ) + .requiredOption( + `--provider <provider>`, + `OAuth2 Provider. Currently, supported providers are: amazon, apple, auth0, authentik, autodesk, bitbucket, bitly, box, dailymotion, discord, disqus, dropbox, etsy, facebook, figma, github, gitlab, google, linkedin, microsoft, notion, oidc, okta, paypal, paypalSandbox, podio, salesforce, slack, spotify, stripe, tradeshift, tradeshiftBox, twitch, wordpress, yahoo, yammer, yandex, zoho, zoom.`, + ) + .option( + `--success <success>`, + `URL to redirect back to your app after a successful login attempt. Only URLs from hostnames in your project's platform list are allowed. This requirement helps to prevent an [open redirect](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.`, + ) + .option( + `--failure <failure>`, + `URL to redirect back to your app after a failed login attempt. Only URLs from hostnames in your project's platform list are allowed. This requirement helps to prevent an [open redirect](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.`, + ) + .option( + `--scopes [scopes...]`, + `A list of custom OAuth2 scopes. Check each provider internal docs for a list of supported scopes. Maximum of 100 scopes are allowed, each 4096 characters long.`, + ) + .action( + actionRunner( + async ({ provider, success, failure, scopes }) => + await ( + await getAccountClient() + ).createOAuth2Session( + provider as OAuthProvider, + success, + failure, + scopes, + ), + ), + ); + +account + .command(`update-phone-session`) + .description( + `[**DEPRECATED** - This command is deprecated. Please use 'account updatePhoneSession' instead] Use this endpoint to create a session from token. Provide the **userId** and **secret** parameters from the successful response of authentication flows initiated by token creation. For example, magic URL and phone login.`, + ) + .requiredOption( + `--user-id <user-id>`, + `User ID. Choose a custom ID or generate a random ID with \`ID.unique()\`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.`, + ) + .requiredOption(`--secret <secret>`, `Valid verification token.`) + .action( + actionRunner( + async ({ userId, secret }) => + await (await getAccountClient()).updatePhoneSession(userId, secret), + ), + ); + +account + .command(`create-session`) + .description( + `Use this endpoint to create a session from token. Provide the **userId** and **secret** parameters from the successful response of authentication flows initiated by token creation. For example, magic URL and phone login.`, + ) + .requiredOption( + `--user-id <user-id>`, + `User ID. Choose a custom ID or generate a random ID with \`ID.unique()\`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.`, + ) + .requiredOption( + `--secret <secret>`, + `Secret of a token generated by login methods. For example, the \`createMagicURLToken\` or \`createPhoneToken\` methods.`, + ) + .action( + actionRunner( + async ({ userId, secret }) => + await (await getAccountClient()).createSession(userId, secret), + ), + ); + +account + .command(`get-session`) + .description( + `Use this endpoint to get a logged in user's session using a Session ID. Inputting 'current' will return the current session being used.`, + ) + .requiredOption( + `--session-id <session-id>`, + `Session ID. Use the string 'current' to get the current device session.`, + ) + .action( + actionRunner( + async ({ sessionId }) => + await (await getAccountClient()).getSession(sessionId), + ), + ); + +account + .command(`update-session`) + .description( + `Use this endpoint to extend a session's length. Extending a session is useful when session expiry is short. If the session was created using an OAuth provider, this endpoint refreshes the access token from the provider.`, + ) + .requiredOption( + `--session-id <session-id>`, + `Session ID. Use the string 'current' to update the current device session.`, + ) + .action( + actionRunner( + async ({ sessionId }) => + await (await getAccountClient()).updateSession(sessionId), + ), + ); + +account + .command(`delete-session`) + .description( + `Logout the user. Use 'current' as the session ID to logout on this device, use a session ID to logout on another device. If you're looking to logout the user on all devices, use [Delete Sessions](https://appwrite.io/docs/references/cloud/client-web/account#deleteSessions) instead.`, + ) + .requiredOption( + `--session-id <session-id>`, + `Session ID. Use the string 'current' to delete the current device session.`, + ) + .action( + actionRunner( + async ({ sessionId }) => + await (await getAccountClient()).deleteSession(sessionId), + ), + ); + +account + .command(`update-status`) + .description( + `Block the currently logged in user account. Behind the scene, the user record is not deleted but permanently blocked from any access. To completely delete a user, use the Users API instead.`, + ) + .action( + actionRunner(async () => await (await getAccountClient()).updateStatus()), + ); + +account + .command(`create-push-target`) + .description( + `Use this endpoint to register a device for push notifications. Provide a target ID (custom or generated using ID.unique()), a device identifier (usually a device token), and optionally specify which provider should send notifications to this target. The target is automatically linked to the current session and includes device information like brand and model.`, + ) + .requiredOption( + `--target-id <target-id>`, + `Target ID. Choose a custom ID or generate a random ID with \`ID.unique()\`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.`, + ) + .requiredOption( + `--identifier <identifier>`, + `The target identifier (token, email, phone etc.)`, + ) + .option( + `--provider-id <provider-id>`, + `Provider ID. Message will be sent to this target from the specified provider ID. If no provider ID is set the first setup provider will be used.`, + ) + .action( + actionRunner( + async ({ targetId, identifier, providerId }) => + await ( + await getAccountClient() + ).createPushTarget(targetId, identifier, providerId), + ), + ); + +account + .command(`update-push-target`) + .description( + `Update the currently logged in user's push notification target. You can modify the target's identifier (device token) and provider ID (token, email, phone etc.). The target must exist and belong to the current user. If you change the provider ID, notifications will be sent through the new messaging provider instead.`, + ) + .requiredOption(`--target-id <target-id>`, `Target ID.`) + .requiredOption( + `--identifier <identifier>`, + `The target identifier (token, email, phone etc.)`, + ) + .action( + actionRunner( + async ({ targetId, identifier }) => + await (await getAccountClient()).updatePushTarget(targetId, identifier), + ), + ); + +account + .command(`delete-push-target`) + .description( + `Delete a push notification target for the currently logged in user. After deletion, the device will no longer receive push notifications. The target must exist and belong to the current user.`, + ) + .requiredOption(`--target-id <target-id>`, `Target ID.`) + .action( + actionRunner( + async ({ targetId }) => + await (await getAccountClient()).deletePushTarget(targetId), + ), + ); + +account + .command(`create-email-token`) + .description( + `Sends the user an email with a secret key for creating a session. If the email address has never been used, a **new account is created** using the provided \`userId\`. Otherwise, if the email address is already attached to an account, the **user ID is ignored**. Then, the user will receive an email with the one-time password. Use the returned user ID and secret and submit a request to the [POST /v1/account/sessions/token](https://appwrite.io/docs/references/cloud/client-web/account#createSession) endpoint to complete the login process. The secret sent to the user's email is valid for 15 minutes. + +A user is limited to 10 active sessions at a time by default. [Learn more about session limits](https://appwrite.io/docs/authentication-security#limits). +`, + ) + .requiredOption( + `--user-id <user-id>`, + `User ID. Choose a custom ID or generate a random ID with \`ID.unique()\`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars. If the email address has never been used, a new account is created using the provided userId. Otherwise, if the email address is already attached to an account, the user ID is ignored.`, + ) + .requiredOption(`--email <email>`, `User email.`) + .option( + `--phrase [value]`, + `Toggle for security phrase. If enabled, email will be send with a randomly generated phrase and the phrase will also be included in the response. Confirming phrases match increases the security of your authentication flow.`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .action( + actionRunner( + async ({ userId, email, phrase }) => + await ( + await getAccountClient() + ).createEmailToken(userId, email, phrase), + ), + ); + +account + .command(`create-magic-urltoken`) + .description( + `Sends the user an email with a secret key for creating a session. If the provided user ID has not been registered, a new user will be created. When the user clicks the link in the email, the user is redirected back to the URL you provided with the secret key and userId values attached to the URL query string. Use the query string parameters to submit a request to the [POST /v1/account/sessions/token](https://appwrite.io/docs/references/cloud/client-web/account#createSession) endpoint to complete the login process. The link sent to the user's email address is valid for 1 hour. + +A user is limited to 10 active sessions at a time by default. [Learn more about session limits](https://appwrite.io/docs/authentication-security#limits). +`, + ) + .requiredOption( + `--user-id <user-id>`, + `Unique Id. Choose a custom ID or generate a random ID with \`ID.unique()\`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars. If the email address has never been used, a new account is created using the provided userId. Otherwise, if the email address is already attached to an account, the user ID is ignored.`, + ) + .requiredOption(`--email <email>`, `User email.`) + .option( + `--url <url>`, + `URL to redirect the user back to your app from the magic URL login. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.`, + ) + .option( + `--phrase [value]`, + `Toggle for security phrase. If enabled, email will be send with a randomly generated phrase and the phrase will also be included in the response. Confirming phrases match increases the security of your authentication flow.`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .action( + actionRunner( + async ({ userId, email, url, phrase }) => + await ( + await getAccountClient() + ).createMagicURLToken(userId, email, url, phrase), + ), + ); + +account + .command(`create-oauth2-token`) + .description( + `Allow the user to login to their account using the OAuth2 provider of their choice. Each OAuth2 provider should be enabled from the Appwrite console first. Use the success and failure arguments to provide a redirect URL's back to your app when login is completed. + +If authentication succeeds, \`userId\` and \`secret\` of a token will be appended to the success URL as query parameters. These can be used to create a new session using the [Create session](https://appwrite.io/docs/references/cloud/client-web/account#createSession) endpoint. + +A user is limited to 10 active sessions at a time by default. [Learn more about session limits](https://appwrite.io/docs/authentication-security#limits).`, + ) + .requiredOption( + `--provider <provider>`, + `OAuth2 Provider. Currently, supported providers are: amazon, apple, auth0, authentik, autodesk, bitbucket, bitly, box, dailymotion, discord, disqus, dropbox, etsy, facebook, figma, github, gitlab, google, linkedin, microsoft, notion, oidc, okta, paypal, paypalSandbox, podio, salesforce, slack, spotify, stripe, tradeshift, tradeshiftBox, twitch, wordpress, yahoo, yammer, yandex, zoho, zoom.`, + ) + .option( + `--success <success>`, + `URL to redirect back to your app after a successful login attempt. Only URLs from hostnames in your project's platform list are allowed. This requirement helps to prevent an [open redirect](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.`, + ) + .option( + `--failure <failure>`, + `URL to redirect back to your app after a failed login attempt. Only URLs from hostnames in your project's platform list are allowed. This requirement helps to prevent an [open redirect](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.`, + ) + .option( + `--scopes [scopes...]`, + `A list of custom OAuth2 scopes. Check each provider internal docs for a list of supported scopes. Maximum of 100 scopes are allowed, each 4096 characters long.`, + ) + .action( + actionRunner( + async ({ provider, success, failure, scopes }) => + await ( + await getAccountClient() + ).createOAuth2Token( + provider as OAuthProvider, + success, + failure, + scopes, + ), + ), + ); + +account + .command(`create-phone-token`) + .description( + `Sends the user an SMS with a secret key for creating a session. If the provided user ID has not be registered, a new user will be created. Use the returned user ID and secret and submit a request to the [POST /v1/account/sessions/token](https://appwrite.io/docs/references/cloud/client-web/account#createSession) endpoint to complete the login process. The secret sent to the user's phone is valid for 15 minutes. + +A user is limited to 10 active sessions at a time by default. [Learn more about session limits](https://appwrite.io/docs/authentication-security#limits).`, + ) + .requiredOption( + `--user-id <user-id>`, + `Unique Id. Choose a custom ID or generate a random ID with \`ID.unique()\`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars. If the phone number has never been used, a new account is created using the provided userId. Otherwise, if the phone number is already attached to an account, the user ID is ignored.`, + ) + .requiredOption( + `--phone <phone>`, + `Phone number. Format this number with a leading '+' and a country code, e.g., +16175551212.`, + ) + .action( + actionRunner( + async ({ userId, phone }) => + await (await getAccountClient()).createPhoneToken(userId, phone), + ), + ); + +account + .command(`create-email-verification`) + .description( + `Use this endpoint to send a verification message to your user email address to confirm they are the valid owners of that address. Both the **userId** and **secret** arguments will be passed as query parameters to the URL you have provided to be attached to the verification email. The provided URL should redirect the user back to your app and allow you to complete the verification process by verifying both the **userId** and **secret** parameters. Learn more about how to [complete the verification process](https://appwrite.io/docs/references/cloud/client-web/account#updateVerification). The verification link sent to the user's email address is valid for 7 days. + +Please note that in order to avoid a [Redirect Attack](https://github.com/OWASP/CheatSheetSeries/blob/master/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.md), the only valid redirect URLs are the ones from domains you have set when adding your platforms in the console interface. +`, + ) + .requiredOption( + `--url <url>`, + `URL to redirect the user back to your app from the verification email. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.`, + ) + .action( + actionRunner( + async ({ url }) => + await (await getAccountClient()).createEmailVerification(url), + ), + ); + +account + .command(`update-email-verification`) + .description( + `Use this endpoint to complete the user email verification process. Use both the **userId** and **secret** parameters that were attached to your app URL to verify the user email ownership. If confirmed this route will return a 200 status code.`, + ) + .requiredOption(`--user-id <user-id>`, `User ID.`) + .requiredOption(`--secret <secret>`, `Valid verification token.`) + .action( + actionRunner( + async ({ userId, secret }) => + await ( + await getAccountClient() + ).updateEmailVerification(userId, secret), + ), + ); + +account + .command(`create-phone-verification`) + .description( + `Use this endpoint to send a verification SMS to the currently logged in user. This endpoint is meant for use after updating a user's phone number using the [accountUpdatePhone](https://appwrite.io/docs/references/cloud/client-web/account#updatePhone) endpoint. Learn more about how to [complete the verification process](https://appwrite.io/docs/references/cloud/client-web/account#updatePhoneVerification). The verification code sent to the user's phone number is valid for 15 minutes.`, + ) + .action( + actionRunner( + async () => await (await getAccountClient()).createPhoneVerification(), + ), + ); + +account + .command(`update-phone-verification`) + .description( + `Use this endpoint to complete the user phone verification process. Use the **userId** and **secret** that were sent to your user's phone number to verify the user email ownership. If confirmed this route will return a 200 status code.`, + ) + .requiredOption(`--user-id <user-id>`, `User ID.`) + .requiredOption(`--secret <secret>`, `Valid verification token.`) + .action( + actionRunner( + async ({ userId, secret }) => + await ( + await getAccountClient() + ).updatePhoneVerification(userId, secret), + ), + ); diff --git a/lib/commands/services/avatars.ts b/lib/commands/services/avatars.ts new file mode 100644 index 00000000..8352d25b --- /dev/null +++ b/lib/commands/services/avatars.ts @@ -0,0 +1,400 @@ +import { Command } from "commander"; +import { sdkForProject } from "../../sdks.js"; +import { + actionRunner, + commandDescriptions, + parseBool, + parseInteger, +} from "../../parser.js"; +import { + Avatars, + Browser, + CreditCard, + Flag, + ImageFormat, +} from "@appwrite.io/console"; + +let avatarsClient: Avatars | null = null; + +const getAvatarsClient = async (): Promise<Avatars> => { + if (!avatarsClient) { + const sdkClient = await sdkForProject(); + avatarsClient = new Avatars(sdkClient); + } + return avatarsClient; +}; + +export const avatars = new Command("avatars") + .description(commandDescriptions["avatars"] ?? "") + .configureHelp({ + helpWidth: process.stdout.columns || 80, + }); + +avatars + .command(`get-browser`) + .description( + `You can use this endpoint to show different browser icons to your users. The code argument receives the browser code as it appears in your user [GET /account/sessions](https://appwrite.io/docs/references/cloud/client-web/account#getSessions) endpoint. Use width, height and quality arguments to change the output settings. + +When one dimension is specified and the other is 0, the image is scaled with preserved aspect ratio. If both dimensions are 0, the API provides an image at source quality. If dimensions are not specified, the default size of image returned is 100x100px.`, + ) + .requiredOption(`--code <code>`, `Browser Code.`) + .option( + `--width <width>`, + `Image width. Pass an integer between 0 to 2000. Defaults to 100.`, + parseInteger, + ) + .option( + `--height <height>`, + `Image height. Pass an integer between 0 to 2000. Defaults to 100.`, + parseInteger, + ) + .option( + `--quality <quality>`, + `Image quality. Pass an integer between 0 to 100. Defaults to keep existing image quality.`, + parseInteger, + ) + .action( + actionRunner( + async ({ code, width, height, quality }) => + await ( + await getAvatarsClient() + ).getBrowser(code as Browser, width, height, quality), + ), + ); + +avatars + .command(`get-credit-card`) + .description( + `The credit card endpoint will return you the icon of the credit card provider you need. Use width, height and quality arguments to change the output settings. + +When one dimension is specified and the other is 0, the image is scaled with preserved aspect ratio. If both dimensions are 0, the API provides an image at source quality. If dimensions are not specified, the default size of image returned is 100x100px. +`, + ) + .requiredOption( + `--code <code>`, + `Credit Card Code. Possible values: amex, argencard, cabal, cencosud, diners, discover, elo, hipercard, jcb, mastercard, naranja, targeta-shopping, unionpay, visa, mir, maestro, rupay.`, + ) + .option( + `--width <width>`, + `Image width. Pass an integer between 0 to 2000. Defaults to 100.`, + parseInteger, + ) + .option( + `--height <height>`, + `Image height. Pass an integer between 0 to 2000. Defaults to 100.`, + parseInteger, + ) + .option( + `--quality <quality>`, + `Image quality. Pass an integer between 0 to 100. Defaults to keep existing image quality.`, + parseInteger, + ) + .action( + actionRunner( + async ({ code, width, height, quality }) => + await ( + await getAvatarsClient() + ).getCreditCard(code as CreditCard, width, height, quality), + ), + ); + +avatars + .command(`get-favicon`) + .description( + `Use this endpoint to fetch the favorite icon (AKA favicon) of any remote website URL. + +This endpoint does not follow HTTP redirects.`, + ) + .requiredOption( + `--url <url>`, + `Website URL which you want to fetch the favicon from.`, + ) + .action( + actionRunner( + async ({ url }) => await (await getAvatarsClient()).getFavicon(url), + ), + ); + +avatars + .command(`get-flag`) + .description( + `You can use this endpoint to show different country flags icons to your users. The code argument receives the 2 letter country code. Use width, height and quality arguments to change the output settings. Country codes follow the [ISO 3166-1](https://en.wikipedia.org/wiki/ISO_3166-1) standard. + +When one dimension is specified and the other is 0, the image is scaled with preserved aspect ratio. If both dimensions are 0, the API provides an image at source quality. If dimensions are not specified, the default size of image returned is 100x100px. +`, + ) + .requiredOption( + `--code <code>`, + `Country Code. ISO Alpha-2 country code format.`, + ) + .option( + `--width <width>`, + `Image width. Pass an integer between 0 to 2000. Defaults to 100.`, + parseInteger, + ) + .option( + `--height <height>`, + `Image height. Pass an integer between 0 to 2000. Defaults to 100.`, + parseInteger, + ) + .option( + `--quality <quality>`, + `Image quality. Pass an integer between 0 to 100. Defaults to keep existing image quality.`, + parseInteger, + ) + .action( + actionRunner( + async ({ code, width, height, quality }) => + await ( + await getAvatarsClient() + ).getFlag(code as Flag, width, height, quality), + ), + ); + +avatars + .command(`get-image`) + .description( + `Use this endpoint to fetch a remote image URL and crop it to any image size you want. This endpoint is very useful if you need to crop and display remote images in your app or in case you want to make sure a 3rd party image is properly served using a TLS protocol. + +When one dimension is specified and the other is 0, the image is scaled with preserved aspect ratio. If both dimensions are 0, the API provides an image at source quality. If dimensions are not specified, the default size of image returned is 400x400px. + +This endpoint does not follow HTTP redirects.`, + ) + .requiredOption(`--url <url>`, `Image URL which you want to crop.`) + .option( + `--width <width>`, + `Resize preview image width, Pass an integer between 0 to 2000. Defaults to 400.`, + parseInteger, + ) + .option( + `--height <height>`, + `Resize preview image height, Pass an integer between 0 to 2000. Defaults to 400.`, + parseInteger, + ) + .action( + actionRunner( + async ({ url, width, height }) => + await (await getAvatarsClient()).getImage(url, width, height), + ), + ); + +avatars + .command(`get-initials`) + .description( + `Use this endpoint to show your user initials avatar icon on your website or app. By default, this route will try to print your logged-in user name or email initials. You can also overwrite the user name if you pass the 'name' parameter. If no name is given and no user is logged, an empty avatar will be returned. + +You can use the color and background params to change the avatar colors. By default, a random theme will be selected. The random theme will persist for the user's initials when reloading the same theme will always return for the same initials. + +When one dimension is specified and the other is 0, the image is scaled with preserved aspect ratio. If both dimensions are 0, the API provides an image at source quality. If dimensions are not specified, the default size of image returned is 100x100px. +`, + ) + .option( + `--name <name>`, + `Full Name. When empty, current user name or email will be used. Max length: 128 chars.`, + ) + .option( + `--width <width>`, + `Image width. Pass an integer between 0 to 2000. Defaults to 100.`, + parseInteger, + ) + .option( + `--height <height>`, + `Image height. Pass an integer between 0 to 2000. Defaults to 100.`, + parseInteger, + ) + .option( + `--background <background>`, + `Changes background color. By default a random color will be picked and stay will persistent to the given name.`, + ) + .action( + actionRunner( + async ({ name, width, height, background }) => + await ( + await getAvatarsClient() + ).getInitials(name, width, height, background), + ), + ); + +avatars + .command(`get-qr`) + .description( + `Converts a given plain text to a QR code image. You can use the query parameters to change the size and style of the resulting image. +`, + ) + .requiredOption( + `--text <text>`, + `Plain text to be converted to QR code image.`, + ) + .option( + `--size <size>`, + `QR code size. Pass an integer between 1 to 1000. Defaults to 400.`, + parseInteger, + ) + .option( + `--margin <margin>`, + `Margin from edge. Pass an integer between 0 to 10. Defaults to 1.`, + parseInteger, + ) + .option( + `--download [value]`, + `Return resulting image with 'Content-Disposition: attachment ' headers for the browser to start downloading it. Pass 0 for no header, or 1 for otherwise. Default value is set to 0.`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .action( + actionRunner( + async ({ text, size, margin, download }) => + await (await getAvatarsClient()).getQR(text, size, margin, download), + ), + ); + +avatars + .command(`get-screenshot`) + .description( + `Use this endpoint to capture a screenshot of any website URL. This endpoint uses a headless browser to render the webpage and capture it as an image. + +You can configure the browser viewport size, theme, user agent, geolocation, permissions, and more. Capture either just the viewport or the full page scroll. + +When width and height are specified, the image is resized accordingly. If both dimensions are 0, the API provides an image at original size. If dimensions are not specified, the default viewport size is 1280x720px.`, + ) + .requiredOption(`--url <url>`, `Website URL which you want to capture.`) + .option( + `--headers <headers>`, + `HTTP headers to send with the browser request. Defaults to empty.`, + ) + .option( + `--viewport-width <viewport-width>`, + `Browser viewport width. Pass an integer between 1 to 1920. Defaults to 1280.`, + parseInteger, + ) + .option( + `--viewport-height <viewport-height>`, + `Browser viewport height. Pass an integer between 1 to 1080. Defaults to 720.`, + parseInteger, + ) + .option( + `--scale <scale>`, + `Browser scale factor. Pass a number between 0.1 to 3. Defaults to 1.`, + parseInteger, + ) + .option( + `--theme <theme>`, + `Browser theme. Pass "light" or "dark". Defaults to "light".`, + ) + .option( + `--user-agent <user-agent>`, + `Custom user agent string. Defaults to browser default.`, + ) + .option( + `--fullpage [value]`, + `Capture full page scroll. Pass 0 for viewport only, or 1 for full page. Defaults to 0.`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .option( + `--locale <locale>`, + `Browser locale (e.g., "en-US", "fr-FR"). Defaults to browser default.`, + ) + .option( + `--timezone <timezone>`, + `IANA timezone identifier (e.g., "America/New_York", "Europe/London"). Defaults to browser default.`, + ) + .option( + `--latitude <latitude>`, + `Geolocation latitude. Pass a number between -90 to 90. Defaults to 0.`, + parseInteger, + ) + .option( + `--longitude <longitude>`, + `Geolocation longitude. Pass a number between -180 to 180. Defaults to 0.`, + parseInteger, + ) + .option( + `--accuracy <accuracy>`, + `Geolocation accuracy in meters. Pass a number between 0 to 100000. Defaults to 0.`, + parseInteger, + ) + .option( + `--touch [value]`, + `Enable touch support. Pass 0 for no touch, or 1 for touch enabled. Defaults to 0.`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .option( + `--permissions [permissions...]`, + `Browser permissions to grant. Pass an array of permission names like ["geolocation", "camera", "microphone"]. Defaults to empty.`, + ) + .option( + `--sleep <sleep>`, + `Wait time in seconds before taking the screenshot. Pass an integer between 0 to 10. Defaults to 0.`, + parseInteger, + ) + .option( + `--width <width>`, + `Output image width. Pass 0 to use original width, or an integer between 1 to 2000. Defaults to 0 (original width).`, + parseInteger, + ) + .option( + `--height <height>`, + `Output image height. Pass 0 to use original height, or an integer between 1 to 2000. Defaults to 0 (original height).`, + parseInteger, + ) + .option( + `--quality <quality>`, + `Screenshot quality. Pass an integer between 0 to 100. Defaults to keep existing image quality.`, + parseInteger, + ) + .option( + `--output <output>`, + `Output format type (jpeg, jpg, png, gif and webp).`, + ) + .action( + actionRunner( + async ({ + url, + headers, + viewportWidth, + viewportHeight, + scale, + theme, + userAgent, + fullpage, + locale, + timezone, + latitude, + longitude, + accuracy, + touch, + permissions, + sleep, + width, + height, + quality, + output, + }) => + await ( + await getAvatarsClient() + ).getScreenshot( + url, + JSON.parse(headers), + viewportWidth, + viewportHeight, + scale, + theme, + userAgent, + fullpage, + locale, + timezone, + latitude, + longitude, + accuracy, + touch, + permissions, + sleep, + width, + height, + quality, + output as ImageFormat, + ), + ), + ); diff --git a/lib/commands/services/console.ts b/lib/commands/services/console.ts new file mode 100644 index 00000000..e4bdf4e2 --- /dev/null +++ b/lib/commands/services/console.ts @@ -0,0 +1,73 @@ +import { Command } from "commander"; +import { sdkForProject } from "../../sdks.js"; +import { + actionRunner, + commandDescriptions, + parseBool, + parseInteger, +} from "../../parser.js"; +import { Console, Assistant, ConsoleResourceType } from "@appwrite.io/console"; + +let consoleClient: Console | null = null; + +const getConsoleClient = async (): Promise<Console> => { + if (!consoleClient) { + const sdkClient = await sdkForProject(); + consoleClient = new Console(sdkClient); + } + return consoleClient; +}; + +let assistantClient: Assistant | null = null; + +const getAssistantClient = async (): Promise<Assistant> => { + if (!assistantClient) { + const sdkClient = await sdkForProject(); + assistantClient = new Assistant(sdkClient); + } + return assistantClient; +}; + +export const console = new Command("console") + .description(commandDescriptions["console"] ?? "") + .configureHelp({ + helpWidth: process.stdout.columns || 80, + }); + +console + .command(`chat`) + .description( + `Send a prompt to the AI assistant and receive a response. This endpoint allows you to interact with Appwrite's AI assistant by sending questions or prompts and receiving helpful responses in real-time through a server-sent events stream. `, + ) + .requiredOption( + `--prompt <prompt>`, + `Prompt. A string containing questions asked to the AI assistant.`, + ) + .action( + actionRunner( + async ({ prompt }) => await (await getAssistantClient()).chat(prompt), + ), + ); + +console + .command(`get-resource`) + .description(`Check if a resource ID is available.`) + .requiredOption(`--value <value>`, `Resource value.`) + .requiredOption(`--type <type>`, `Resource type.`) + .action( + actionRunner( + async ({ value, xType }) => + await ( + await getConsoleClient() + ).getResource(value, xType as ConsoleResourceType), + ), + ); + +console + .command(`variables`) + .description( + `Get all Environment Variables that are relevant for the console.`, + ) + .action( + actionRunner(async () => await (await getConsoleClient()).variables()), + ); diff --git a/lib/commands/services/databases.ts b/lib/commands/services/databases.ts new file mode 100644 index 00000000..b5bf0ee2 --- /dev/null +++ b/lib/commands/services/databases.ts @@ -0,0 +1,2080 @@ +import { Command } from "commander"; +import { sdkForProject } from "../../sdks.js"; +import { + actionRunner, + commandDescriptions, + parseBool, + parseInteger, +} from "../../parser.js"; +import { + Databases, + UsageRange, + RelationshipType, + RelationMutate, + IndexType, +} from "@appwrite.io/console"; + +let databasesClient: Databases | null = null; + +const getDatabasesClient = async (): Promise<Databases> => { + if (!databasesClient) { + const sdkClient = await sdkForProject(); + databasesClient = new Databases(sdkClient); + } + return databasesClient; +}; + +export const databases = new Command("databases") + .description(commandDescriptions["databases"] ?? "") + .configureHelp({ + helpWidth: process.stdout.columns || 80, + }); + +databases + .command(`list`) + .description( + `[**DEPRECATED** - This command is deprecated. Please use 'databases list' instead] Get a list of all databases from the current Appwrite project. You can use the search parameter to filter your results.`, + ) + .option( + `--queries [queries...]`, + `Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: name`, + ) + .option( + `--search <search>`, + `Search term to filter your list results. Max length: 256 chars.`, + ) + .option( + `--total [value]`, + `When set to false, the total count returned will be 0 and will not be calculated.`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .action( + actionRunner( + async ({ queries, search, total }) => + await (await getDatabasesClient()).list(queries, search, total), + ), + ); + +databases + .command(`create`) + .description( + `[**DEPRECATED** - This command is deprecated. Please use 'databases create' instead] Create a new Database. +`, + ) + .requiredOption( + `--database-id <database-id>`, + `Unique Id. Choose a custom ID or generate a random ID with \`ID.unique()\`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.`, + ) + .requiredOption(`--name <name>`, `Database name. Max length: 128 chars.`) + .option( + `--enabled [value]`, + `Is the database enabled? When set to 'disabled', users cannot access the database but Server SDKs with an API key can still read and write to the database. No data is lost when this is toggled.`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .action( + actionRunner( + async ({ databaseId, name, enabled }) => + await (await getDatabasesClient()).create(databaseId, name, enabled), + ), + ); + +databases + .command(`list-transactions`) + .description(`List transactions across all databases.`) + .option( + `--queries [queries...]`, + `Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries).`, + ) + .action( + actionRunner( + async ({ queries }) => + await (await getDatabasesClient()).listTransactions(queries), + ), + ); + +databases + .command(`create-transaction`) + .description(`Create a new transaction.`) + .option( + `--ttl <ttl>`, + `Seconds before the transaction expires.`, + parseInteger, + ) + .action( + actionRunner( + async ({ ttl }) => + await (await getDatabasesClient()).createTransaction(ttl), + ), + ); + +databases + .command(`get-transaction`) + .description(`Get a transaction by its unique ID.`) + .requiredOption(`--transaction-id <transaction-id>`, `Transaction ID.`) + .action( + actionRunner( + async ({ transactionId }) => + await (await getDatabasesClient()).getTransaction(transactionId), + ), + ); + +databases + .command(`update-transaction`) + .description( + `Update a transaction, to either commit or roll back its operations.`, + ) + .requiredOption(`--transaction-id <transaction-id>`, `Transaction ID.`) + .option( + `--commit [value]`, + `Commit transaction?`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .option( + `--rollback [value]`, + `Rollback transaction?`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .action( + actionRunner( + async ({ transactionId, commit, rollback }) => + await ( + await getDatabasesClient() + ).updateTransaction(transactionId, commit, rollback), + ), + ); + +databases + .command(`delete-transaction`) + .description(`Delete a transaction by its unique ID.`) + .requiredOption(`--transaction-id <transaction-id>`, `Transaction ID.`) + .action( + actionRunner( + async ({ transactionId }) => + await (await getDatabasesClient()).deleteTransaction(transactionId), + ), + ); + +databases + .command(`create-operations`) + .description(`Create multiple operations in a single transaction.`) + .requiredOption(`--transaction-id <transaction-id>`, `Transaction ID.`) + .option(`--operations [operations...]`, `Array of staged operations.`) + .action( + actionRunner( + async ({ transactionId, operations }) => + await ( + await getDatabasesClient() + ).createOperations(transactionId, operations), + ), + ); + +databases + .command(`list-usage`) + .description( + `[**DEPRECATED** - This command is deprecated. Please use 'databases listUsage' instead] List usage metrics and statistics for all databases in the project. You can view the total number of databases, collections, documents, and storage usage. The response includes both current totals and historical data over time. Use the optional range parameter to specify the time window for historical data: 24h (last 24 hours), 30d (last 30 days), or 90d (last 90 days). If not specified, range defaults to 30 days.`, + ) + .option(`--range <range>`, `Date range.`) + .action( + actionRunner( + async ({ range }) => + await (await getDatabasesClient()).listUsage(range as UsageRange), + ), + ); + +databases + .command(`get`) + .description( + `[**DEPRECATED** - This command is deprecated. Please use 'databases get' instead] Get a database by its unique ID. This endpoint response returns a JSON object with the database metadata.`, + ) + .requiredOption(`--database-id <database-id>`, `Database ID.`) + .action( + actionRunner( + async ({ databaseId }) => + await (await getDatabasesClient()).get(databaseId), + ), + ); + +databases + .command(`update`) + .description( + `[**DEPRECATED** - This command is deprecated. Please use 'databases update' instead] Update a database by its unique ID.`, + ) + .requiredOption(`--database-id <database-id>`, `Database ID.`) + .requiredOption(`--name <name>`, `Database name. Max length: 128 chars.`) + .option( + `--enabled [value]`, + `Is database enabled? When set to 'disabled', users cannot access the database but Server SDKs with an API key can still read and write to the database. No data is lost when this is toggled.`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .action( + actionRunner( + async ({ databaseId, name, enabled }) => + await (await getDatabasesClient()).update(databaseId, name, enabled), + ), + ); + +databases + .command(`delete`) + .description( + `[**DEPRECATED** - This command is deprecated. Please use 'databases delete' instead] Delete a database by its unique ID. Only API keys with with databases.write scope can delete a database.`, + ) + .requiredOption(`--database-id <database-id>`, `Database ID.`) + .action( + actionRunner( + async ({ databaseId }) => + await (await getDatabasesClient()).delete(databaseId), + ), + ); + +databases + .command(`list-collections`) + .description( + `[**DEPRECATED** - This command is deprecated. Please use 'databases listCollections' instead] Get a list of all collections that belong to the provided databaseId. You can use the search parameter to filter your results.`, + ) + .requiredOption(`--database-id <database-id>`, `Database ID.`) + .option( + `--queries [queries...]`, + `Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: name, enabled, documentSecurity`, + ) + .option( + `--search <search>`, + `Search term to filter your list results. Max length: 256 chars.`, + ) + .option( + `--total [value]`, + `When set to false, the total count returned will be 0 and will not be calculated.`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .action( + actionRunner( + async ({ databaseId, queries, search, total }) => + await ( + await getDatabasesClient() + ).listCollections(databaseId, queries, search, total), + ), + ); + +databases + .command(`create-collection`) + .description( + `[**DEPRECATED** - This command is deprecated. Please use 'databases createCollection' instead] Create a new Collection. Before using this route, you should create a new database resource using either a [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection) API or directly from your database console.`, + ) + .requiredOption(`--database-id <database-id>`, `Database ID.`) + .requiredOption( + `--collection-id <collection-id>`, + `Unique Id. Choose a custom ID or generate a random ID with \`ID.unique()\`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.`, + ) + .requiredOption(`--name <name>`, `Collection name. Max length: 128 chars.`) + .option( + `--permissions [permissions...]`, + `An array of permissions strings. By default, no user is granted with any permissions. [Learn more about permissions](https://appwrite.io/docs/permissions).`, + ) + .option( + `--document-security [value]`, + `Enables configuring permissions for individual documents. A user needs one of document or collection level permissions to access a document. [Learn more about permissions](https://appwrite.io/docs/permissions).`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .option( + `--enabled [value]`, + `Is collection enabled? When set to 'disabled', users cannot access the collection but Server SDKs with and API key can still read and write to the collection. No data is lost when this is toggled.`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .option( + `--attributes [attributes...]`, + `Array of attribute definitions to create. Each attribute should contain: key (string), type (string: string, integer, float, boolean, datetime), size (integer, required for string type), required (boolean, optional), default (mixed, optional), array (boolean, optional), and type-specific options.`, + ) + .option( + `--indexes [indexes...]`, + `Array of index definitions to create. Each index should contain: key (string), type (string: key, fulltext, unique, spatial), attributes (array of attribute keys), orders (array of ASC/DESC, optional), and lengths (array of integers, optional).`, + ) + .action( + actionRunner( + async ({ + databaseId, + collectionId, + name, + permissions, + documentSecurity, + enabled, + attributes, + indexes, + }) => + await ( + await getDatabasesClient() + ).createCollection( + databaseId, + collectionId, + name, + permissions, + documentSecurity, + enabled, + attributes, + indexes, + ), + ), + ); + +databases + .command(`get-collection`) + .description( + `[**DEPRECATED** - This command is deprecated. Please use 'databases getCollection' instead] Get a collection by its unique ID. This endpoint response returns a JSON object with the collection metadata.`, + ) + .requiredOption(`--database-id <database-id>`, `Database ID.`) + .requiredOption(`--collection-id <collection-id>`, `Collection ID.`) + .action( + actionRunner( + async ({ databaseId, collectionId }) => + await ( + await getDatabasesClient() + ).getCollection(databaseId, collectionId), + ), + ); + +databases + .command(`update-collection`) + .description( + `[**DEPRECATED** - This command is deprecated. Please use 'databases updateCollection' instead] Update a collection by its unique ID.`, + ) + .requiredOption(`--database-id <database-id>`, `Database ID.`) + .requiredOption(`--collection-id <collection-id>`, `Collection ID.`) + .requiredOption(`--name <name>`, `Collection name. Max length: 128 chars.`) + .option( + `--permissions [permissions...]`, + `An array of permission strings. By default, the current permissions are inherited. [Learn more about permissions](https://appwrite.io/docs/permissions).`, + ) + .option( + `--document-security [value]`, + `Enables configuring permissions for individual documents. A user needs one of document or collection level permissions to access a document. [Learn more about permissions](https://appwrite.io/docs/permissions).`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .option( + `--enabled [value]`, + `Is collection enabled? When set to 'disabled', users cannot access the collection but Server SDKs with and API key can still read and write to the collection. No data is lost when this is toggled.`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .action( + actionRunner( + async ({ + databaseId, + collectionId, + name, + permissions, + documentSecurity, + enabled, + }) => + await ( + await getDatabasesClient() + ).updateCollection( + databaseId, + collectionId, + name, + permissions, + documentSecurity, + enabled, + ), + ), + ); + +databases + .command(`delete-collection`) + .description( + `[**DEPRECATED** - This command is deprecated. Please use 'databases deleteCollection' instead] Delete a collection by its unique ID. Only users with write permissions have access to delete this resource.`, + ) + .requiredOption(`--database-id <database-id>`, `Database ID.`) + .requiredOption(`--collection-id <collection-id>`, `Collection ID.`) + .action( + actionRunner( + async ({ databaseId, collectionId }) => + await ( + await getDatabasesClient() + ).deleteCollection(databaseId, collectionId), + ), + ); + +databases + .command(`list-attributes`) + .description( + `[**DEPRECATED** - This command is deprecated. Please use 'databases listAttributes' instead] List attributes in the collection.`, + ) + .requiredOption(`--database-id <database-id>`, `Database ID.`) + .requiredOption(`--collection-id <collection-id>`, `Collection ID.`) + .option( + `--queries [queries...]`, + `Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: key, type, size, required, array, status, error`, + ) + .option( + `--total [value]`, + `When set to false, the total count returned will be 0 and will not be calculated.`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .action( + actionRunner( + async ({ databaseId, collectionId, queries, total }) => + await ( + await getDatabasesClient() + ).listAttributes(databaseId, collectionId, queries, total), + ), + ); + +databases + .command(`create-boolean-attribute`) + .description( + `[**DEPRECATED** - This command is deprecated. Please use 'databases createBooleanAttribute' instead] Create a boolean attribute. +`, + ) + .requiredOption(`--database-id <database-id>`, `Database ID.`) + .requiredOption( + `--collection-id <collection-id>`, + `Collection ID. You can create a new table using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection).`, + ) + .requiredOption(`--key <key>`, `Attribute Key.`) + .requiredOption(`--required <required>`, `Is attribute required?`, parseBool) + .option( + `--default [value]`, + `Default value for attribute when not provided. Cannot be set when attribute is required.`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .option( + `--array [value]`, + `Is attribute an array?`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .action( + actionRunner( + async ({ databaseId, collectionId, key, required, xDefault, array }) => + await ( + await getDatabasesClient() + ).createBooleanAttribute( + databaseId, + collectionId, + key, + required, + xDefault, + array, + ), + ), + ); + +databases + .command(`update-boolean-attribute`) + .description( + `[**DEPRECATED** - This command is deprecated. Please use 'databases updateBooleanAttribute' instead] Update a boolean attribute. Changing the \`default\` value will not update already existing documents.`, + ) + .requiredOption(`--database-id <database-id>`, `Database ID.`) + .requiredOption( + `--collection-id <collection-id>`, + `Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#createCollection).`, + ) + .requiredOption(`--key <key>`, `Attribute Key.`) + .requiredOption(`--required <required>`, `Is attribute required?`, parseBool) + .requiredOption( + `--default <default>`, + `Default value for attribute when not provided. Cannot be set when attribute is required.`, + parseBool, + ) + .option(`--new-key <new-key>`, `New attribute key.`) + .action( + actionRunner( + async ({ databaseId, collectionId, key, required, xDefault, newKey }) => + await ( + await getDatabasesClient() + ).updateBooleanAttribute( + databaseId, + collectionId, + key, + required, + xDefault, + newKey, + ), + ), + ); + +databases + .command(`create-datetime-attribute`) + .description( + `[**DEPRECATED** - This command is deprecated. Please use 'databases createDatetimeAttribute' instead] Create a date time attribute according to the ISO 8601 standard.`, + ) + .requiredOption(`--database-id <database-id>`, `Database ID.`) + .requiredOption( + `--collection-id <collection-id>`, + `Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#createCollection).`, + ) + .requiredOption(`--key <key>`, `Attribute Key.`) + .requiredOption(`--required <required>`, `Is attribute required?`, parseBool) + .option( + `--default <default>`, + `Default value for the attribute in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format. Cannot be set when attribute is required.`, + ) + .option( + `--array [value]`, + `Is attribute an array?`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .action( + actionRunner( + async ({ databaseId, collectionId, key, required, xDefault, array }) => + await ( + await getDatabasesClient() + ).createDatetimeAttribute( + databaseId, + collectionId, + key, + required, + xDefault, + array, + ), + ), + ); + +databases + .command(`update-datetime-attribute`) + .description( + `[**DEPRECATED** - This command is deprecated. Please use 'databases updateDatetimeAttribute' instead] Update a date time attribute. Changing the \`default\` value will not update already existing documents.`, + ) + .requiredOption(`--database-id <database-id>`, `Database ID.`) + .requiredOption(`--collection-id <collection-id>`, `Collection ID.`) + .requiredOption(`--key <key>`, `Attribute Key.`) + .requiredOption(`--required <required>`, `Is attribute required?`, parseBool) + .requiredOption( + `--default <default>`, + `Default value for attribute when not provided. Cannot be set when attribute is required.`, + ) + .option(`--new-key <new-key>`, `New attribute key.`) + .action( + actionRunner( + async ({ databaseId, collectionId, key, required, xDefault, newKey }) => + await ( + await getDatabasesClient() + ).updateDatetimeAttribute( + databaseId, + collectionId, + key, + required, + xDefault, + newKey, + ), + ), + ); + +databases + .command(`create-email-attribute`) + .description( + `[**DEPRECATED** - This command is deprecated. Please use 'databases createEmailAttribute' instead] Create an email attribute. +`, + ) + .requiredOption(`--database-id <database-id>`, `Database ID.`) + .requiredOption(`--collection-id <collection-id>`, `Collection ID.`) + .requiredOption(`--key <key>`, `Attribute Key.`) + .requiredOption(`--required <required>`, `Is attribute required?`, parseBool) + .option( + `--default <default>`, + `Default value for attribute when not provided. Cannot be set when attribute is required.`, + ) + .option( + `--array [value]`, + `Is attribute an array?`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .action( + actionRunner( + async ({ databaseId, collectionId, key, required, xDefault, array }) => + await ( + await getDatabasesClient() + ).createEmailAttribute( + databaseId, + collectionId, + key, + required, + xDefault, + array, + ), + ), + ); + +databases + .command(`update-email-attribute`) + .description( + `[**DEPRECATED** - This command is deprecated. Please use 'databases updateEmailAttribute' instead] Update an email attribute. Changing the \`default\` value will not update already existing documents. +`, + ) + .requiredOption(`--database-id <database-id>`, `Database ID.`) + .requiredOption(`--collection-id <collection-id>`, `Collection ID.`) + .requiredOption(`--key <key>`, `Attribute Key.`) + .requiredOption(`--required <required>`, `Is attribute required?`, parseBool) + .requiredOption( + `--default <default>`, + `Default value for attribute when not provided. Cannot be set when attribute is required.`, + ) + .option(`--new-key <new-key>`, `New Attribute Key.`) + .action( + actionRunner( + async ({ databaseId, collectionId, key, required, xDefault, newKey }) => + await ( + await getDatabasesClient() + ).updateEmailAttribute( + databaseId, + collectionId, + key, + required, + xDefault, + newKey, + ), + ), + ); + +databases + .command(`create-enum-attribute`) + .description( + `[**DEPRECATED** - This command is deprecated. Please use 'databases createEnumAttribute' instead] Create an enum attribute. The \`elements\` param acts as a white-list of accepted values for this attribute. +`, + ) + .requiredOption(`--database-id <database-id>`, `Database ID.`) + .requiredOption(`--collection-id <collection-id>`, `Collection ID.`) + .requiredOption(`--key <key>`, `Attribute Key.`) + .requiredOption(`--elements [elements...]`, `Array of enum values.`) + .requiredOption(`--required <required>`, `Is attribute required?`, parseBool) + .option( + `--default <default>`, + `Default value for attribute when not provided. Cannot be set when attribute is required.`, + ) + .option( + `--array [value]`, + `Is attribute an array?`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .action( + actionRunner( + async ({ + databaseId, + collectionId, + key, + elements, + required, + xDefault, + array, + }) => + await ( + await getDatabasesClient() + ).createEnumAttribute( + databaseId, + collectionId, + key, + elements, + required, + xDefault, + array, + ), + ), + ); + +databases + .command(`update-enum-attribute`) + .description( + `[**DEPRECATED** - This command is deprecated. Please use 'databases updateEnumAttribute' instead] Update an enum attribute. Changing the \`default\` value will not update already existing documents. +`, + ) + .requiredOption(`--database-id <database-id>`, `Database ID.`) + .requiredOption(`--collection-id <collection-id>`, `Collection ID.`) + .requiredOption(`--key <key>`, `Attribute Key.`) + .requiredOption(`--elements [elements...]`, `Updated list of enum values.`) + .requiredOption(`--required <required>`, `Is attribute required?`, parseBool) + .requiredOption( + `--default <default>`, + `Default value for attribute when not provided. Cannot be set when attribute is required.`, + ) + .option(`--new-key <new-key>`, `New Attribute Key.`) + .action( + actionRunner( + async ({ + databaseId, + collectionId, + key, + elements, + required, + xDefault, + newKey, + }) => + await ( + await getDatabasesClient() + ).updateEnumAttribute( + databaseId, + collectionId, + key, + elements, + required, + xDefault, + newKey, + ), + ), + ); + +databases + .command(`create-float-attribute`) + .description( + `[**DEPRECATED** - This command is deprecated. Please use 'databases createFloatAttribute' instead] Create a float attribute. Optionally, minimum and maximum values can be provided. +`, + ) + .requiredOption(`--database-id <database-id>`, `Database ID.`) + .requiredOption(`--collection-id <collection-id>`, `Collection ID.`) + .requiredOption(`--key <key>`, `Attribute Key.`) + .requiredOption(`--required <required>`, `Is attribute required?`, parseBool) + .option(`--min <min>`, `Minimum value.`, parseInteger) + .option(`--max <max>`, `Maximum value.`, parseInteger) + .option( + `--default <default>`, + `Default value. Cannot be set when required.`, + parseInteger, + ) + .option( + `--array [value]`, + `Is attribute an array?`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .action( + actionRunner( + async ({ + databaseId, + collectionId, + key, + required, + min, + max, + xDefault, + array, + }) => + await ( + await getDatabasesClient() + ).createFloatAttribute( + databaseId, + collectionId, + key, + required, + min, + max, + xDefault, + array, + ), + ), + ); + +databases + .command(`update-float-attribute`) + .description( + `[**DEPRECATED** - This command is deprecated. Please use 'databases updateFloatAttribute' instead] Update a float attribute. Changing the \`default\` value will not update already existing documents. +`, + ) + .requiredOption(`--database-id <database-id>`, `Database ID.`) + .requiredOption(`--collection-id <collection-id>`, `Collection ID.`) + .requiredOption(`--key <key>`, `Attribute Key.`) + .requiredOption(`--required <required>`, `Is attribute required?`, parseBool) + .option(`--min <min>`, `Minimum value.`, parseInteger) + .option(`--max <max>`, `Maximum value.`, parseInteger) + .requiredOption( + `--default <default>`, + `Default value. Cannot be set when required.`, + parseInteger, + ) + .option(`--new-key <new-key>`, `New Attribute Key.`) + .action( + actionRunner( + async ({ + databaseId, + collectionId, + key, + required, + min, + max, + xDefault, + newKey, + }) => + await ( + await getDatabasesClient() + ).updateFloatAttribute( + databaseId, + collectionId, + key, + required, + min, + max, + xDefault, + newKey, + ), + ), + ); + +databases + .command(`create-integer-attribute`) + .description( + `[**DEPRECATED** - This command is deprecated. Please use 'databases createIntegerAttribute' instead] Create an integer attribute. Optionally, minimum and maximum values can be provided. +`, + ) + .requiredOption(`--database-id <database-id>`, `Database ID.`) + .requiredOption(`--collection-id <collection-id>`, `Collection ID.`) + .requiredOption(`--key <key>`, `Attribute Key.`) + .requiredOption(`--required <required>`, `Is attribute required?`, parseBool) + .option(`--min <min>`, `Minimum value`, parseInteger) + .option(`--max <max>`, `Maximum value`, parseInteger) + .option( + `--default <default>`, + `Default value. Cannot be set when attribute is required.`, + parseInteger, + ) + .option( + `--array [value]`, + `Is attribute an array?`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .action( + actionRunner( + async ({ + databaseId, + collectionId, + key, + required, + min, + max, + xDefault, + array, + }) => + await ( + await getDatabasesClient() + ).createIntegerAttribute( + databaseId, + collectionId, + key, + required, + min, + max, + xDefault, + array, + ), + ), + ); + +databases + .command(`update-integer-attribute`) + .description( + `[**DEPRECATED** - This command is deprecated. Please use 'databases updateIntegerAttribute' instead] Update an integer attribute. Changing the \`default\` value will not update already existing documents. +`, + ) + .requiredOption(`--database-id <database-id>`, `Database ID.`) + .requiredOption(`--collection-id <collection-id>`, `Collection ID.`) + .requiredOption(`--key <key>`, `Attribute Key.`) + .requiredOption(`--required <required>`, `Is attribute required?`, parseBool) + .option(`--min <min>`, `Minimum value`, parseInteger) + .option(`--max <max>`, `Maximum value`, parseInteger) + .requiredOption( + `--default <default>`, + `Default value. Cannot be set when attribute is required.`, + parseInteger, + ) + .option(`--new-key <new-key>`, `New Attribute Key.`) + .action( + actionRunner( + async ({ + databaseId, + collectionId, + key, + required, + min, + max, + xDefault, + newKey, + }) => + await ( + await getDatabasesClient() + ).updateIntegerAttribute( + databaseId, + collectionId, + key, + required, + min, + max, + xDefault, + newKey, + ), + ), + ); + +databases + .command(`create-ip-attribute`) + .description( + `[**DEPRECATED** - This command is deprecated. Please use 'databases createIpAttribute' instead] Create IP address attribute. +`, + ) + .requiredOption(`--database-id <database-id>`, `Database ID.`) + .requiredOption(`--collection-id <collection-id>`, `Collection ID.`) + .requiredOption(`--key <key>`, `Attribute Key.`) + .requiredOption(`--required <required>`, `Is attribute required?`, parseBool) + .option( + `--default <default>`, + `Default value. Cannot be set when attribute is required.`, + ) + .option( + `--array [value]`, + `Is attribute an array?`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .action( + actionRunner( + async ({ databaseId, collectionId, key, required, xDefault, array }) => + await ( + await getDatabasesClient() + ).createIpAttribute( + databaseId, + collectionId, + key, + required, + xDefault, + array, + ), + ), + ); + +databases + .command(`update-ip-attribute`) + .description( + `[**DEPRECATED** - This command is deprecated. Please use 'databases updateIpAttribute' instead] Update an ip attribute. Changing the \`default\` value will not update already existing documents. +`, + ) + .requiredOption(`--database-id <database-id>`, `Database ID.`) + .requiredOption(`--collection-id <collection-id>`, `Collection ID.`) + .requiredOption(`--key <key>`, `Attribute Key.`) + .requiredOption(`--required <required>`, `Is attribute required?`, parseBool) + .requiredOption( + `--default <default>`, + `Default value. Cannot be set when attribute is required.`, + ) + .option(`--new-key <new-key>`, `New Attribute Key.`) + .action( + actionRunner( + async ({ databaseId, collectionId, key, required, xDefault, newKey }) => + await ( + await getDatabasesClient() + ).updateIpAttribute( + databaseId, + collectionId, + key, + required, + xDefault, + newKey, + ), + ), + ); + +databases + .command(`create-line-attribute`) + .description( + `[**DEPRECATED** - This command is deprecated. Please use 'databases createLineAttribute' instead] Create a geometric line attribute.`, + ) + .requiredOption(`--database-id <database-id>`, `Database ID.`) + .requiredOption( + `--collection-id <collection-id>`, + `Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection).`, + ) + .requiredOption(`--key <key>`, `Attribute Key.`) + .requiredOption(`--required <required>`, `Is attribute required?`, parseBool) + .option( + `--default [default...]`, + `Default value for attribute when not provided, two-dimensional array of coordinate pairs, [[longitude, latitude], [longitude, latitude], …], listing the vertices of the line in order. Cannot be set when attribute is required.`, + ) + .action( + actionRunner( + async ({ databaseId, collectionId, key, required, xDefault }) => + await ( + await getDatabasesClient() + ).createLineAttribute( + databaseId, + collectionId, + key, + required, + xDefault, + ), + ), + ); + +databases + .command(`update-line-attribute`) + .description( + `[**DEPRECATED** - This command is deprecated. Please use 'databases updateLineAttribute' instead] Update a line attribute. Changing the \`default\` value will not update already existing documents.`, + ) + .requiredOption(`--database-id <database-id>`, `Database ID.`) + .requiredOption( + `--collection-id <collection-id>`, + `Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#createCollection).`, + ) + .requiredOption(`--key <key>`, `Attribute Key.`) + .requiredOption(`--required <required>`, `Is attribute required?`, parseBool) + .option( + `--default [default...]`, + `Default value for attribute when not provided, two-dimensional array of coordinate pairs, [[longitude, latitude], [longitude, latitude], …], listing the vertices of the line in order. Cannot be set when attribute is required.`, + ) + .option(`--new-key <new-key>`, `New attribute key.`) + .action( + actionRunner( + async ({ databaseId, collectionId, key, required, xDefault, newKey }) => + await ( + await getDatabasesClient() + ).updateLineAttribute( + databaseId, + collectionId, + key, + required, + xDefault, + newKey, + ), + ), + ); + +databases + .command(`create-point-attribute`) + .description( + `[**DEPRECATED** - This command is deprecated. Please use 'databases createPointAttribute' instead] Create a geometric point attribute.`, + ) + .requiredOption(`--database-id <database-id>`, `Database ID.`) + .requiredOption( + `--collection-id <collection-id>`, + `Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection).`, + ) + .requiredOption(`--key <key>`, `Attribute Key.`) + .requiredOption(`--required <required>`, `Is attribute required?`, parseBool) + .option( + `--default [default...]`, + `Default value for attribute when not provided, array of two numbers [longitude, latitude], representing a single coordinate. Cannot be set when attribute is required.`, + ) + .action( + actionRunner( + async ({ databaseId, collectionId, key, required, xDefault }) => + await ( + await getDatabasesClient() + ).createPointAttribute( + databaseId, + collectionId, + key, + required, + xDefault, + ), + ), + ); + +databases + .command(`update-point-attribute`) + .description( + `[**DEPRECATED** - This command is deprecated. Please use 'databases updatePointAttribute' instead] Update a point attribute. Changing the \`default\` value will not update already existing documents.`, + ) + .requiredOption(`--database-id <database-id>`, `Database ID.`) + .requiredOption( + `--collection-id <collection-id>`, + `Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#createCollection).`, + ) + .requiredOption(`--key <key>`, `Attribute Key.`) + .requiredOption(`--required <required>`, `Is attribute required?`, parseBool) + .option( + `--default [default...]`, + `Default value for attribute when not provided, array of two numbers [longitude, latitude], representing a single coordinate. Cannot be set when attribute is required.`, + ) + .option(`--new-key <new-key>`, `New attribute key.`) + .action( + actionRunner( + async ({ databaseId, collectionId, key, required, xDefault, newKey }) => + await ( + await getDatabasesClient() + ).updatePointAttribute( + databaseId, + collectionId, + key, + required, + xDefault, + newKey, + ), + ), + ); + +databases + .command(`create-polygon-attribute`) + .description( + `[**DEPRECATED** - This command is deprecated. Please use 'databases createPolygonAttribute' instead] Create a geometric polygon attribute.`, + ) + .requiredOption(`--database-id <database-id>`, `Database ID.`) + .requiredOption( + `--collection-id <collection-id>`, + `Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection).`, + ) + .requiredOption(`--key <key>`, `Attribute Key.`) + .requiredOption(`--required <required>`, `Is attribute required?`, parseBool) + .option( + `--default [default...]`, + `Default value for attribute when not provided, three-dimensional array where the outer array holds one or more linear rings, [[[longitude, latitude], …], …], the first ring is the exterior boundary, any additional rings are interior holes, and each ring must start and end with the same coordinate pair. Cannot be set when attribute is required.`, + ) + .action( + actionRunner( + async ({ databaseId, collectionId, key, required, xDefault }) => + await ( + await getDatabasesClient() + ).createPolygonAttribute( + databaseId, + collectionId, + key, + required, + xDefault, + ), + ), + ); + +databases + .command(`update-polygon-attribute`) + .description( + `[**DEPRECATED** - This command is deprecated. Please use 'databases updatePolygonAttribute' instead] Update a polygon attribute. Changing the \`default\` value will not update already existing documents.`, + ) + .requiredOption(`--database-id <database-id>`, `Database ID.`) + .requiredOption( + `--collection-id <collection-id>`, + `Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#createCollection).`, + ) + .requiredOption(`--key <key>`, `Attribute Key.`) + .requiredOption(`--required <required>`, `Is attribute required?`, parseBool) + .option( + `--default [default...]`, + `Default value for attribute when not provided, three-dimensional array where the outer array holds one or more linear rings, [[[longitude, latitude], …], …], the first ring is the exterior boundary, any additional rings are interior holes, and each ring must start and end with the same coordinate pair. Cannot be set when attribute is required.`, + ) + .option(`--new-key <new-key>`, `New attribute key.`) + .action( + actionRunner( + async ({ databaseId, collectionId, key, required, xDefault, newKey }) => + await ( + await getDatabasesClient() + ).updatePolygonAttribute( + databaseId, + collectionId, + key, + required, + xDefault, + newKey, + ), + ), + ); + +databases + .command(`create-relationship-attribute`) + .description( + `[**DEPRECATED** - This command is deprecated. Please use 'databases createRelationshipAttribute' instead] Create relationship attribute. [Learn more about relationship attributes](https://appwrite.io/docs/databases-relationships#relationship-attributes). +`, + ) + .requiredOption(`--database-id <database-id>`, `Database ID.`) + .requiredOption(`--collection-id <collection-id>`, `Collection ID.`) + .requiredOption( + `--related-collection-id <related-collection-id>`, + `Related Collection ID.`, + ) + .requiredOption(`--type <type>`, `Relation type`) + .option(`--two-way [value]`, `Is Two Way?`, (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .option(`--key <key>`, `Attribute Key.`) + .option(`--two-way-key <two-way-key>`, `Two Way Attribute Key.`) + .option(`--on-delete <on-delete>`, `Constraints option`) + .action( + actionRunner( + async ({ + databaseId, + collectionId, + relatedCollectionId, + xType, + twoWay, + key, + twoWayKey, + onDelete, + }) => + await ( + await getDatabasesClient() + ).createRelationshipAttribute( + databaseId, + collectionId, + relatedCollectionId, + xType as RelationshipType, + twoWay, + key, + twoWayKey, + onDelete as RelationMutate, + ), + ), + ); + +databases + .command(`create-string-attribute`) + .description( + `[**DEPRECATED** - This command is deprecated. Please use 'databases createStringAttribute' instead] Create a string attribute. +`, + ) + .requiredOption(`--database-id <database-id>`, `Database ID.`) + .requiredOption( + `--collection-id <collection-id>`, + `Collection ID. You can create a new table using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection).`, + ) + .requiredOption(`--key <key>`, `Attribute Key.`) + .requiredOption( + `--size <size>`, + `Attribute size for text attributes, in number of characters.`, + parseInteger, + ) + .requiredOption(`--required <required>`, `Is attribute required?`, parseBool) + .option( + `--default <default>`, + `Default value for attribute when not provided. Cannot be set when attribute is required.`, + ) + .option( + `--array [value]`, + `Is attribute an array?`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .option( + `--encrypt [value]`, + `Toggle encryption for the attribute. Encryption enhances security by not storing any plain text values in the database. However, encrypted attributes cannot be queried.`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .action( + actionRunner( + async ({ + databaseId, + collectionId, + key, + size, + required, + xDefault, + array, + encrypt, + }) => + await ( + await getDatabasesClient() + ).createStringAttribute( + databaseId, + collectionId, + key, + size, + required, + xDefault, + array, + encrypt, + ), + ), + ); + +databases + .command(`update-string-attribute`) + .description( + `[**DEPRECATED** - This command is deprecated. Please use 'databases updateStringAttribute' instead] Update a string attribute. Changing the \`default\` value will not update already existing documents. +`, + ) + .requiredOption(`--database-id <database-id>`, `Database ID.`) + .requiredOption( + `--collection-id <collection-id>`, + `Collection ID. You can create a new table using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection).`, + ) + .requiredOption(`--key <key>`, `Attribute Key.`) + .requiredOption(`--required <required>`, `Is attribute required?`, parseBool) + .requiredOption( + `--default <default>`, + `Default value for attribute when not provided. Cannot be set when attribute is required.`, + ) + .option( + `--size <size>`, + `Maximum size of the string attribute.`, + parseInteger, + ) + .option(`--new-key <new-key>`, `New Attribute Key.`) + .action( + actionRunner( + async ({ + databaseId, + collectionId, + key, + required, + xDefault, + size, + newKey, + }) => + await ( + await getDatabasesClient() + ).updateStringAttribute( + databaseId, + collectionId, + key, + required, + xDefault, + size, + newKey, + ), + ), + ); + +databases + .command(`create-url-attribute`) + .description( + `[**DEPRECATED** - This command is deprecated. Please use 'databases createUrlAttribute' instead] Create a URL attribute. +`, + ) + .requiredOption(`--database-id <database-id>`, `Database ID.`) + .requiredOption(`--collection-id <collection-id>`, `Collection ID.`) + .requiredOption(`--key <key>`, `Attribute Key.`) + .requiredOption(`--required <required>`, `Is attribute required?`, parseBool) + .option( + `--default <default>`, + `Default value for attribute when not provided. Cannot be set when attribute is required.`, + ) + .option( + `--array [value]`, + `Is attribute an array?`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .action( + actionRunner( + async ({ databaseId, collectionId, key, required, xDefault, array }) => + await ( + await getDatabasesClient() + ).createUrlAttribute( + databaseId, + collectionId, + key, + required, + xDefault, + array, + ), + ), + ); + +databases + .command(`update-url-attribute`) + .description( + `[**DEPRECATED** - This command is deprecated. Please use 'databases updateUrlAttribute' instead] Update an url attribute. Changing the \`default\` value will not update already existing documents. +`, + ) + .requiredOption(`--database-id <database-id>`, `Database ID.`) + .requiredOption(`--collection-id <collection-id>`, `Collection ID.`) + .requiredOption(`--key <key>`, `Attribute Key.`) + .requiredOption(`--required <required>`, `Is attribute required?`, parseBool) + .requiredOption( + `--default <default>`, + `Default value for attribute when not provided. Cannot be set when attribute is required.`, + ) + .option(`--new-key <new-key>`, `New Attribute Key.`) + .action( + actionRunner( + async ({ databaseId, collectionId, key, required, xDefault, newKey }) => + await ( + await getDatabasesClient() + ).updateUrlAttribute( + databaseId, + collectionId, + key, + required, + xDefault, + newKey, + ), + ), + ); + +databases + .command(`get-attribute`) + .description( + `[**DEPRECATED** - This command is deprecated. Please use 'databases getAttribute' instead] Get attribute by ID.`, + ) + .requiredOption(`--database-id <database-id>`, `Database ID.`) + .requiredOption(`--collection-id <collection-id>`, `Collection ID.`) + .requiredOption(`--key <key>`, `Attribute Key.`) + .action( + actionRunner( + async ({ databaseId, collectionId, key }) => + await ( + await getDatabasesClient() + ).getAttribute(databaseId, collectionId, key), + ), + ); + +databases + .command(`delete-attribute`) + .description( + `[**DEPRECATED** - This command is deprecated. Please use 'databases deleteAttribute' instead] Deletes an attribute.`, + ) + .requiredOption(`--database-id <database-id>`, `Database ID.`) + .requiredOption(`--collection-id <collection-id>`, `Collection ID.`) + .requiredOption(`--key <key>`, `Attribute Key.`) + .action( + actionRunner( + async ({ databaseId, collectionId, key }) => + await ( + await getDatabasesClient() + ).deleteAttribute(databaseId, collectionId, key), + ), + ); + +databases + .command(`update-relationship-attribute`) + .description( + `[**DEPRECATED** - This command is deprecated. Please use 'databases updateRelationshipAttribute' instead] Update relationship attribute. [Learn more about relationship attributes](https://appwrite.io/docs/databases-relationships#relationship-attributes). +`, + ) + .requiredOption(`--database-id <database-id>`, `Database ID.`) + .requiredOption(`--collection-id <collection-id>`, `Collection ID.`) + .requiredOption(`--key <key>`, `Attribute Key.`) + .option(`--on-delete <on-delete>`, `Constraints option`) + .option(`--new-key <new-key>`, `New Attribute Key.`) + .action( + actionRunner( + async ({ databaseId, collectionId, key, onDelete, newKey }) => + await ( + await getDatabasesClient() + ).updateRelationshipAttribute( + databaseId, + collectionId, + key, + onDelete as RelationMutate, + newKey, + ), + ), + ); + +databases + .command(`list-documents`) + .description( + `[**DEPRECATED** - This command is deprecated. Please use 'databases listDocuments' instead] Get a list of all the user's documents in a given collection. You can use the query params to filter your results.`, + ) + .requiredOption(`--database-id <database-id>`, `Database ID.`) + .requiredOption( + `--collection-id <collection-id>`, + `Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection).`, + ) + .option( + `--queries [queries...]`, + `Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of 100 queries are allowed, each 4096 characters long.`, + ) + .option( + `--transaction-id <transaction-id>`, + `Transaction ID to read uncommitted changes within the transaction.`, + ) + .option( + `--total [value]`, + `When set to false, the total count returned will be 0 and will not be calculated.`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .action( + actionRunner( + async ({ databaseId, collectionId, queries, transactionId, total }) => + await ( + await getDatabasesClient() + ).listDocuments( + databaseId, + collectionId, + queries, + transactionId, + total, + ), + ), + ); + +databases + .command(`create-document`) + .description( + `[**DEPRECATED** - This command is deprecated. Please use 'databases createDocument' instead] Create a new Document. Before using this route, you should create a new collection resource using either a [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection) API or directly from your database console.`, + ) + .requiredOption(`--database-id <database-id>`, `Database ID.`) + .requiredOption( + `--collection-id <collection-id>`, + `Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection). Make sure to define attributes before creating documents.`, + ) + .requiredOption( + `--document-id <document-id>`, + `Document ID. Choose a custom ID or generate a random ID with \`ID.unique()\`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.`, + ) + .requiredOption(`--data <data>`, `Document data as JSON object.`) + .option( + `--permissions [permissions...]`, + `An array of permissions strings. By default, only the current user is granted all permissions. [Learn more about permissions](https://appwrite.io/docs/permissions).`, + ) + .option( + `--transaction-id <transaction-id>`, + `Transaction ID for staging the operation.`, + ) + .action( + actionRunner( + async ({ + databaseId, + collectionId, + documentId, + data, + permissions, + transactionId, + }) => + await ( + await getDatabasesClient() + ).createDocument( + databaseId, + collectionId, + documentId, + JSON.parse(data), + permissions, + transactionId, + ), + ), + ); + +databases + .command(`upsert-documents`) + .description( + `[**DEPRECATED** - This command is deprecated. Please use 'databases upsertDocuments' instead] Create or update Documents. Before using this route, you should create a new collection resource using either a [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection) API or directly from your database console. +`, + ) + .requiredOption(`--database-id <database-id>`, `Database ID.`) + .requiredOption(`--collection-id <collection-id>`, `Collection ID.`) + .requiredOption( + `--documents [documents...]`, + `Array of document data as JSON objects. May contain partial documents.`, + ) + .option( + `--transaction-id <transaction-id>`, + `Transaction ID for staging the operation.`, + ) + .action( + actionRunner( + async ({ databaseId, collectionId, documents, transactionId }) => + await ( + await getDatabasesClient() + ).upsertDocuments(databaseId, collectionId, documents, transactionId), + ), + ); + +databases + .command(`update-documents`) + .description( + `[**DEPRECATED** - This command is deprecated. Please use 'databases updateDocuments' instead] Update all documents that match your queries, if no queries are submitted then all documents are updated. You can pass only specific fields to be updated.`, + ) + .requiredOption(`--database-id <database-id>`, `Database ID.`) + .requiredOption(`--collection-id <collection-id>`, `Collection ID.`) + .option( + `--data <data>`, + `Document data as JSON object. Include only attribute and value pairs to be updated.`, + ) + .option( + `--queries [queries...]`, + `Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of 100 queries are allowed, each 4096 characters long.`, + ) + .option( + `--transaction-id <transaction-id>`, + `Transaction ID for staging the operation.`, + ) + .action( + actionRunner( + async ({ databaseId, collectionId, data, queries, transactionId }) => + await ( + await getDatabasesClient() + ).updateDocuments( + databaseId, + collectionId, + JSON.parse(data), + queries, + transactionId, + ), + ), + ); + +databases + .command(`delete-documents`) + .description( + `[**DEPRECATED** - This command is deprecated. Please use 'databases deleteDocuments' instead] Bulk delete documents using queries, if no queries are passed then all documents are deleted.`, + ) + .requiredOption(`--database-id <database-id>`, `Database ID.`) + .requiredOption( + `--collection-id <collection-id>`, + `Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection).`, + ) + .option( + `--queries [queries...]`, + `Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of 100 queries are allowed, each 4096 characters long.`, + ) + .option( + `--transaction-id <transaction-id>`, + `Transaction ID for staging the operation.`, + ) + .action( + actionRunner( + async ({ databaseId, collectionId, queries, transactionId }) => + await ( + await getDatabasesClient() + ).deleteDocuments(databaseId, collectionId, queries, transactionId), + ), + ); + +databases + .command(`get-document`) + .description( + `[**DEPRECATED** - This command is deprecated. Please use 'databases getDocument' instead] Get a document by its unique ID. This endpoint response returns a JSON object with the document data.`, + ) + .requiredOption(`--database-id <database-id>`, `Database ID.`) + .requiredOption( + `--collection-id <collection-id>`, + `Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection).`, + ) + .requiredOption(`--document-id <document-id>`, `Document ID.`) + .option( + `--queries [queries...]`, + `Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of 100 queries are allowed, each 4096 characters long.`, + ) + .option( + `--transaction-id <transaction-id>`, + `Transaction ID to read uncommitted changes within the transaction.`, + ) + .action( + actionRunner( + async ({ + databaseId, + collectionId, + documentId, + queries, + transactionId, + }) => + await ( + await getDatabasesClient() + ).getDocument( + databaseId, + collectionId, + documentId, + queries, + transactionId, + ), + ), + ); + +databases + .command(`upsert-document`) + .description( + `[**DEPRECATED** - This command is deprecated. Please use 'databases upsertDocument' instead] Create or update a Document. Before using this route, you should create a new collection resource using either a [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection) API or directly from your database console.`, + ) + .requiredOption(`--database-id <database-id>`, `Database ID.`) + .requiredOption(`--collection-id <collection-id>`, `Collection ID.`) + .requiredOption(`--document-id <document-id>`, `Document ID.`) + .option( + `--data <data>`, + `Document data as JSON object. Include all required attributes of the document to be created or updated.`, + ) + .option( + `--permissions [permissions...]`, + `An array of permissions strings. By default, the current permissions are inherited. [Learn more about permissions](https://appwrite.io/docs/permissions).`, + ) + .option( + `--transaction-id <transaction-id>`, + `Transaction ID for staging the operation.`, + ) + .action( + actionRunner( + async ({ + databaseId, + collectionId, + documentId, + data, + permissions, + transactionId, + }) => + await ( + await getDatabasesClient() + ).upsertDocument( + databaseId, + collectionId, + documentId, + JSON.parse(data), + permissions, + transactionId, + ), + ), + ); + +databases + .command(`update-document`) + .description( + `[**DEPRECATED** - This command is deprecated. Please use 'databases updateDocument' instead] Update a document by its unique ID. Using the patch method you can pass only specific fields that will get updated.`, + ) + .requiredOption(`--database-id <database-id>`, `Database ID.`) + .requiredOption(`--collection-id <collection-id>`, `Collection ID.`) + .requiredOption(`--document-id <document-id>`, `Document ID.`) + .option( + `--data <data>`, + `Document data as JSON object. Include only attribute and value pairs to be updated.`, + ) + .option( + `--permissions [permissions...]`, + `An array of permissions strings. By default, the current permissions are inherited. [Learn more about permissions](https://appwrite.io/docs/permissions).`, + ) + .option( + `--transaction-id <transaction-id>`, + `Transaction ID for staging the operation.`, + ) + .action( + actionRunner( + async ({ + databaseId, + collectionId, + documentId, + data, + permissions, + transactionId, + }) => + await ( + await getDatabasesClient() + ).updateDocument( + databaseId, + collectionId, + documentId, + JSON.parse(data), + permissions, + transactionId, + ), + ), + ); + +databases + .command(`delete-document`) + .description( + `[**DEPRECATED** - This command is deprecated. Please use 'databases deleteDocument' instead] Delete a document by its unique ID.`, + ) + .requiredOption(`--database-id <database-id>`, `Database ID.`) + .requiredOption( + `--collection-id <collection-id>`, + `Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection).`, + ) + .requiredOption(`--document-id <document-id>`, `Document ID.`) + .option( + `--transaction-id <transaction-id>`, + `Transaction ID for staging the operation.`, + ) + .action( + actionRunner( + async ({ databaseId, collectionId, documentId, transactionId }) => + await ( + await getDatabasesClient() + ).deleteDocument(databaseId, collectionId, documentId, transactionId), + ), + ); + +databases + .command(`list-document-logs`) + .description( + `[**DEPRECATED** - This command is deprecated. Please use 'databases listDocumentLogs' instead] Get the document activity logs list by its unique ID.`, + ) + .requiredOption(`--database-id <database-id>`, `Database ID.`) + .requiredOption(`--collection-id <collection-id>`, `Collection ID.`) + .requiredOption(`--document-id <document-id>`, `Document ID.`) + .option( + `--queries [queries...]`, + `Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Only supported methods are limit and offset`, + ) + .action( + actionRunner( + async ({ databaseId, collectionId, documentId, queries }) => + await ( + await getDatabasesClient() + ).listDocumentLogs(databaseId, collectionId, documentId, queries), + ), + ); + +databases + .command(`decrement-document-attribute`) + .description( + `[**DEPRECATED** - This command is deprecated. Please use 'databases decrementDocumentAttribute' instead] Decrement a specific attribute of a document by a given value.`, + ) + .requiredOption(`--database-id <database-id>`, `Database ID.`) + .requiredOption(`--collection-id <collection-id>`, `Collection ID.`) + .requiredOption(`--document-id <document-id>`, `Document ID.`) + .requiredOption(`--attribute <attribute>`, `Attribute key.`) + .option( + `--value <value>`, + `Value to increment the attribute by. The value must be a number.`, + parseInteger, + ) + .option( + `--min <min>`, + `Minimum value for the attribute. If the current value is lesser than this value, an exception will be thrown.`, + parseInteger, + ) + .option( + `--transaction-id <transaction-id>`, + `Transaction ID for staging the operation.`, + ) + .action( + actionRunner( + async ({ + databaseId, + collectionId, + documentId, + attribute, + value, + min, + transactionId, + }) => + await ( + await getDatabasesClient() + ).decrementDocumentAttribute( + databaseId, + collectionId, + documentId, + attribute, + value, + min, + transactionId, + ), + ), + ); + +databases + .command(`increment-document-attribute`) + .description( + `[**DEPRECATED** - This command is deprecated. Please use 'databases incrementDocumentAttribute' instead] Increment a specific attribute of a document by a given value.`, + ) + .requiredOption(`--database-id <database-id>`, `Database ID.`) + .requiredOption(`--collection-id <collection-id>`, `Collection ID.`) + .requiredOption(`--document-id <document-id>`, `Document ID.`) + .requiredOption(`--attribute <attribute>`, `Attribute key.`) + .option( + `--value <value>`, + `Value to increment the attribute by. The value must be a number.`, + parseInteger, + ) + .option( + `--max <max>`, + `Maximum value for the attribute. If the current value is greater than this value, an error will be thrown.`, + parseInteger, + ) + .option( + `--transaction-id <transaction-id>`, + `Transaction ID for staging the operation.`, + ) + .action( + actionRunner( + async ({ + databaseId, + collectionId, + documentId, + attribute, + value, + max, + transactionId, + }) => + await ( + await getDatabasesClient() + ).incrementDocumentAttribute( + databaseId, + collectionId, + documentId, + attribute, + value, + max, + transactionId, + ), + ), + ); + +databases + .command(`list-indexes`) + .description( + `[**DEPRECATED** - This command is deprecated. Please use 'databases listIndexes' instead] List indexes in the collection.`, + ) + .requiredOption(`--database-id <database-id>`, `Database ID.`) + .requiredOption( + `--collection-id <collection-id>`, + `Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection).`, + ) + .option( + `--queries [queries...]`, + `Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: key, type, status, attributes, error`, + ) + .option( + `--total [value]`, + `When set to false, the total count returned will be 0 and will not be calculated.`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .action( + actionRunner( + async ({ databaseId, collectionId, queries, total }) => + await ( + await getDatabasesClient() + ).listIndexes(databaseId, collectionId, queries, total), + ), + ); + +databases + .command(`create-index`) + .description( + `[**DEPRECATED** - This command is deprecated. Please use 'databases createIndex' instead] Creates an index on the attributes listed. Your index should include all the attributes you will query in a single request. +Attributes can be \`key\`, \`fulltext\`, and \`unique\`.`, + ) + .requiredOption(`--database-id <database-id>`, `Database ID.`) + .requiredOption( + `--collection-id <collection-id>`, + `Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection).`, + ) + .requiredOption(`--key <key>`, `Index Key.`) + .requiredOption(`--type <type>`, `Index type.`) + .requiredOption( + `--attributes [attributes...]`, + `Array of attributes to index. Maximum of 100 attributes are allowed, each 32 characters long.`, + ) + .option( + `--orders [orders...]`, + `Array of index orders. Maximum of 100 orders are allowed.`, + ) + .option(`--lengths [lengths...]`, `Length of index. Maximum of 100`) + .action( + actionRunner( + async ({ + databaseId, + collectionId, + key, + xType, + attributes, + orders, + lengths, + }) => + await ( + await getDatabasesClient() + ).createIndex( + databaseId, + collectionId, + key, + xType as IndexType, + attributes, + orders, + lengths, + ), + ), + ); + +databases + .command(`get-index`) + .description( + `[**DEPRECATED** - This command is deprecated. Please use 'databases getIndex' instead] Get an index by its unique ID.`, + ) + .requiredOption(`--database-id <database-id>`, `Database ID.`) + .requiredOption( + `--collection-id <collection-id>`, + `Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection).`, + ) + .requiredOption(`--key <key>`, `Index Key.`) + .action( + actionRunner( + async ({ databaseId, collectionId, key }) => + await ( + await getDatabasesClient() + ).getIndex(databaseId, collectionId, key), + ), + ); + +databases + .command(`delete-index`) + .description( + `[**DEPRECATED** - This command is deprecated. Please use 'databases deleteIndex' instead] Delete an index.`, + ) + .requiredOption(`--database-id <database-id>`, `Database ID.`) + .requiredOption( + `--collection-id <collection-id>`, + `Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection).`, + ) + .requiredOption(`--key <key>`, `Index Key.`) + .action( + actionRunner( + async ({ databaseId, collectionId, key }) => + await ( + await getDatabasesClient() + ).deleteIndex(databaseId, collectionId, key), + ), + ); + +databases + .command(`list-collection-logs`) + .description( + `[**DEPRECATED** - This command is deprecated. Please use 'databases listCollectionLogs' instead] Get the collection activity logs list by its unique ID.`, + ) + .requiredOption(`--database-id <database-id>`, `Database ID.`) + .requiredOption(`--collection-id <collection-id>`, `Collection ID.`) + .option( + `--queries [queries...]`, + `Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Only supported methods are limit and offset`, + ) + .action( + actionRunner( + async ({ databaseId, collectionId, queries }) => + await ( + await getDatabasesClient() + ).listCollectionLogs(databaseId, collectionId, queries), + ), + ); + +databases + .command(`get-collection-usage`) + .description( + `[**DEPRECATED** - This command is deprecated. Please use 'databases getCollectionUsage' instead] Get usage metrics and statistics for a collection. Returning the total number of documents. The response includes both current totals and historical data over time. Use the optional range parameter to specify the time window for historical data: 24h (last 24 hours), 30d (last 30 days), or 90d (last 90 days). If not specified, range defaults to 30 days.`, + ) + .requiredOption(`--database-id <database-id>`, `Database ID.`) + .option(`--range <range>`, `Date range.`) + .requiredOption(`--collection-id <collection-id>`, `Collection ID.`) + .action( + actionRunner( + async ({ databaseId, range, collectionId }) => + await ( + await getDatabasesClient() + ).getCollectionUsage(databaseId, range as UsageRange, collectionId), + ), + ); + +databases + .command(`list-logs`) + .description( + `[**DEPRECATED** - This command is deprecated. Please use 'databases listLogs' instead] Get the database activity logs list by its unique ID.`, + ) + .requiredOption(`--database-id <database-id>`, `Database ID.`) + .option( + `--queries [queries...]`, + `Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Only supported methods are limit and offset`, + ) + .action( + actionRunner( + async ({ databaseId, queries }) => + await (await getDatabasesClient()).listLogs(databaseId, queries), + ), + ); + +databases + .command(`get-usage`) + .description( + `[**DEPRECATED** - This command is deprecated. Please use 'databases getUsage' instead] Get usage metrics and statistics for a database. You can view the total number of collections, documents, and storage usage. The response includes both current totals and historical data over time. Use the optional range parameter to specify the time window for historical data: 24h (last 24 hours), 30d (last 30 days), or 90d (last 90 days). If not specified, range defaults to 30 days.`, + ) + .requiredOption(`--database-id <database-id>`, `Database ID.`) + .option(`--range <range>`, `Date range.`) + .action( + actionRunner( + async ({ databaseId, range }) => + await ( + await getDatabasesClient() + ).getUsage(databaseId, range as UsageRange), + ), + ); diff --git a/lib/commands/services/functions.ts b/lib/commands/services/functions.ts new file mode 100644 index 00000000..75e0a4a9 --- /dev/null +++ b/lib/commands/services/functions.ts @@ -0,0 +1,855 @@ +import { Command } from "commander"; +import { sdkForProject } from "../../sdks.js"; +import { + actionRunner, + commandDescriptions, + parseBool, + parseInteger, +} from "../../parser.js"; +import { + Functions, + UsageRange, + TemplateReferenceType, + VCSReferenceType, + DeploymentDownloadType, + ExecutionMethod, +} from "@appwrite.io/console"; + +let functionsClient: Functions | null = null; + +const getFunctionsClient = async (): Promise<Functions> => { + if (!functionsClient) { + const sdkClient = await sdkForProject(); + functionsClient = new Functions(sdkClient); + } + return functionsClient; +}; + +export const functions = new Command("functions") + .description(commandDescriptions["functions"] ?? "") + .configureHelp({ + helpWidth: process.stdout.columns || 80, + }); + +functions + .command(`list`) + .description( + `Get a list of all the project's functions. You can use the query params to filter your results.`, + ) + .option( + `--queries [queries...]`, + `Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: name, enabled, runtime, deploymentId, schedule, scheduleNext, schedulePrevious, timeout, entrypoint, commands, installationId`, + ) + .option( + `--search <search>`, + `Search term to filter your list results. Max length: 256 chars.`, + ) + .option( + `--total [value]`, + `When set to false, the total count returned will be 0 and will not be calculated.`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .action( + actionRunner( + async ({ queries, search, total }) => + await (await getFunctionsClient()).list(queries, search, total), + ), + ); + +functions + .command(`create`) + .description( + `Create a new function. You can pass a list of [permissions](https://appwrite.io/docs/permissions) to allow different project users or team with access to execute the function using the client API.`, + ) + .requiredOption( + `--function-id <function-id>`, + `Function ID. Choose a custom ID or generate a random ID with \`ID.unique()\`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.`, + ) + .requiredOption(`--name <name>`, `Function name. Max length: 128 chars.`) + .requiredOption(`--runtime <runtime>`, `Execution runtime.`) + .option( + `--execute [execute...]`, + `An array of role strings with execution permissions. By default no user is granted with any execute permissions. [learn more about roles](https://appwrite.io/docs/permissions#permission-roles). Maximum of 100 roles are allowed, each 64 characters long.`, + ) + .option( + `--events [events...]`, + `Events list. Maximum of 100 events are allowed.`, + ) + .option(`--schedule <schedule>`, `Schedule CRON syntax.`) + .option( + `--timeout <timeout>`, + `Function maximum execution time in seconds.`, + parseInteger, + ) + .option( + `--enabled [value]`, + `Is function enabled? When set to 'disabled', users cannot access the function but Server SDKs with and API key can still access the function. No data is lost when this is toggled.`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .option( + `--logging [value]`, + `When disabled, executions will exclude logs and errors, and will be slightly faster.`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .option( + `--entrypoint <entrypoint>`, + `Entrypoint File. This path is relative to the "providerRootDirectory".`, + ) + .option(`--commands <commands>`, `Build Commands.`) + .option( + `--scopes [scopes...]`, + `List of scopes allowed for API key auto-generated for every execution. Maximum of 100 scopes are allowed.`, + ) + .option( + `--installation-id <installation-id>`, + `Appwrite Installation ID for VCS (Version Control System) deployment.`, + ) + .option( + `--provider-repository-id <provider-repository-id>`, + `Repository ID of the repo linked to the function.`, + ) + .option( + `--provider-branch <provider-branch>`, + `Production branch for the repo linked to the function.`, + ) + .option( + `--provider-silent-mode [value]`, + `Is the VCS (Version Control System) connection in silent mode for the repo linked to the function? In silent mode, comments will not be made on commits and pull requests.`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .option( + `--provider-root-directory <provider-root-directory>`, + `Path to function code in the linked repo.`, + ) + .option( + `--specification <specification>`, + `Runtime specification for the function and builds.`, + ) + .action( + actionRunner( + async ({ + functionId, + name, + runtime, + execute, + events, + schedule, + timeout, + enabled, + logging, + entrypoint, + commands, + scopes, + installationId, + providerRepositoryId, + providerBranch, + providerSilentMode, + providerRootDirectory, + specification, + }) => + await ( + await getFunctionsClient() + ).create( + functionId, + name, + runtime, + execute, + events, + schedule, + timeout, + enabled, + logging, + entrypoint, + commands, + scopes, + installationId, + providerRepositoryId, + providerBranch, + providerSilentMode, + providerRootDirectory, + specification, + ), + ), + ); + +functions + .command(`list-runtimes`) + .description( + `Get a list of all runtimes that are currently active on your instance.`, + ) + .action( + actionRunner(async () => await (await getFunctionsClient()).listRuntimes()), + ); + +functions + .command(`list-specifications`) + .description(`List allowed function specifications for this instance.`) + .action( + actionRunner( + async () => await (await getFunctionsClient()).listSpecifications(), + ), + ); + +functions + .command(`list-templates`) + .description( + `List available function templates. You can use template details in [createFunction](/docs/references/cloud/server-nodejs/functions#create) method.`, + ) + .option( + `--runtimes [runtimes...]`, + `List of runtimes allowed for filtering function templates. Maximum of 100 runtimes are allowed.`, + ) + .option( + `--use-cases [use-cases...]`, + `List of use cases allowed for filtering function templates. Maximum of 100 use cases are allowed.`, + ) + .option( + `--limit <limit>`, + `Limit the number of templates returned in the response. Default limit is 25, and maximum limit is 5000.`, + parseInteger, + ) + .option( + `--offset <offset>`, + `Offset the list of returned templates. Maximum offset is 5000.`, + parseInteger, + ) + .option( + `--total [value]`, + `When set to false, the total count returned will be 0 and will not be calculated.`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .action( + actionRunner( + async ({ runtimes, useCases, limit, offset, total }) => + await ( + await getFunctionsClient() + ).listTemplates(runtimes, useCases, limit, offset, total), + ), + ); + +functions + .command(`get-template`) + .description( + `Get a function template using ID. You can use template details in [createFunction](/docs/references/cloud/server-nodejs/functions#create) method.`, + ) + .requiredOption(`--template-id <template-id>`, `Template ID.`) + .action( + actionRunner( + async ({ templateId }) => + await (await getFunctionsClient()).getTemplate(templateId), + ), + ); + +functions + .command(`list-usage`) + .description( + `Get usage metrics and statistics for all functions in the project. View statistics including total deployments, builds, logs, storage usage, and compute time. The response includes both current totals and historical data for each metric. Use the optional range parameter to specify the time window for historical data: 24h (last 24 hours), 30d (last 30 days), or 90d (last 90 days). If not specified, defaults to 30 days.`, + ) + .option(`--range <range>`, `Date range.`) + .action( + actionRunner( + async ({ range }) => + await (await getFunctionsClient()).listUsage(range as UsageRange), + ), + ); + +functions + .command(`get`) + .description(`Get a function by its unique ID.`) + .requiredOption(`--function-id <function-id>`, `Function ID.`) + .action( + actionRunner( + async ({ functionId }) => + await (await getFunctionsClient()).get(functionId), + ), + ); + +functions + .command(`update`) + .description(`Update function by its unique ID.`) + .requiredOption(`--function-id <function-id>`, `Function ID.`) + .requiredOption(`--name <name>`, `Function name. Max length: 128 chars.`) + .option(`--runtime <runtime>`, `Execution runtime.`) + .option( + `--execute [execute...]`, + `An array of role strings with execution permissions. By default no user is granted with any execute permissions. [learn more about roles](https://appwrite.io/docs/permissions#permission-roles). Maximum of 100 roles are allowed, each 64 characters long.`, + ) + .option( + `--events [events...]`, + `Events list. Maximum of 100 events are allowed.`, + ) + .option(`--schedule <schedule>`, `Schedule CRON syntax.`) + .option( + `--timeout <timeout>`, + `Maximum execution time in seconds.`, + parseInteger, + ) + .option( + `--enabled [value]`, + `Is function enabled? When set to 'disabled', users cannot access the function but Server SDKs with and API key can still access the function. No data is lost when this is toggled.`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .option( + `--logging [value]`, + `When disabled, executions will exclude logs and errors, and will be slightly faster.`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .option( + `--entrypoint <entrypoint>`, + `Entrypoint File. This path is relative to the "providerRootDirectory".`, + ) + .option(`--commands <commands>`, `Build Commands.`) + .option( + `--scopes [scopes...]`, + `List of scopes allowed for API Key auto-generated for every execution. Maximum of 100 scopes are allowed.`, + ) + .option( + `--installation-id <installation-id>`, + `Appwrite Installation ID for VCS (Version Controle System) deployment.`, + ) + .option( + `--provider-repository-id <provider-repository-id>`, + `Repository ID of the repo linked to the function`, + ) + .option( + `--provider-branch <provider-branch>`, + `Production branch for the repo linked to the function`, + ) + .option( + `--provider-silent-mode [value]`, + `Is the VCS (Version Control System) connection in silent mode for the repo linked to the function? In silent mode, comments will not be made on commits and pull requests.`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .option( + `--provider-root-directory <provider-root-directory>`, + `Path to function code in the linked repo.`, + ) + .option( + `--specification <specification>`, + `Runtime specification for the function and builds.`, + ) + .action( + actionRunner( + async ({ + functionId, + name, + runtime, + execute, + events, + schedule, + timeout, + enabled, + logging, + entrypoint, + commands, + scopes, + installationId, + providerRepositoryId, + providerBranch, + providerSilentMode, + providerRootDirectory, + specification, + }) => + await ( + await getFunctionsClient() + ).update( + functionId, + name, + runtime, + execute, + events, + schedule, + timeout, + enabled, + logging, + entrypoint, + commands, + scopes, + installationId, + providerRepositoryId, + providerBranch, + providerSilentMode, + providerRootDirectory, + specification, + ), + ), + ); + +functions + .command(`delete`) + .description(`Delete a function by its unique ID.`) + .requiredOption(`--function-id <function-id>`, `Function ID.`) + .action( + actionRunner( + async ({ functionId }) => + await (await getFunctionsClient()).delete(functionId), + ), + ); + +functions + .command(`update-function-deployment`) + .description( + `Update the function active deployment. Use this endpoint to switch the code deployment that should be used when visitor opens your function.`, + ) + .requiredOption(`--function-id <function-id>`, `Function ID.`) + .requiredOption(`--deployment-id <deployment-id>`, `Deployment ID.`) + .action( + actionRunner( + async ({ functionId, deploymentId }) => + await ( + await getFunctionsClient() + ).updateFunctionDeployment(functionId, deploymentId), + ), + ); + +functions + .command(`list-deployments`) + .description( + `Get a list of all the function's code deployments. You can use the query params to filter your results.`, + ) + .requiredOption(`--function-id <function-id>`, `Function ID.`) + .option( + `--queries [queries...]`, + `Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: buildSize, sourceSize, totalSize, buildDuration, status, activate, type`, + ) + .option( + `--search <search>`, + `Search term to filter your list results. Max length: 256 chars.`, + ) + .option( + `--total [value]`, + `When set to false, the total count returned will be 0 and will not be calculated.`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .action( + actionRunner( + async ({ functionId, queries, search, total }) => + await ( + await getFunctionsClient() + ).listDeployments(functionId, queries, search, total), + ), + ); + +functions + .command(`create-deployment`) + .description( + `Create a new function code deployment. Use this endpoint to upload a new version of your code function. To execute your newly uploaded code, you'll need to update the function's deployment to use your new deployment UID. + +This endpoint accepts a tar.gz file compressed with your code. Make sure to include any dependencies your code has within the compressed file. You can learn more about code packaging in the [Appwrite Cloud Functions tutorial](https://appwrite.io/docs/functions). + +Use the "command" param to set the entrypoint used to execute your code.`, + ) + .requiredOption(`--function-id <function-id>`, `Function ID.`) + .option(`--entrypoint <entrypoint>`, `Entrypoint File.`) + .option(`--commands <commands>`, `Build Commands.`) + .requiredOption( + `--code <code>`, + `Gzip file with your code package. When used with the Appwrite CLI, pass the path to your code directory, and the CLI will automatically package your code. Use a path that is within the current directory.`, + ) + .requiredOption( + `--activate <activate>`, + `Automatically activate the deployment when it is finished building.`, + parseBool, + ) + .action( + actionRunner( + async ({ functionId, entrypoint, commands, code, activate }) => + await ( + await getFunctionsClient() + ).createDeployment(functionId, entrypoint, commands, code, activate), + ), + ); + +functions + .command(`create-duplicate-deployment`) + .description( + `Create a new build for an existing function deployment. This endpoint allows you to rebuild a deployment with the updated function configuration, including its entrypoint and build commands if they have been modified. The build process will be queued and executed asynchronously. The original deployment's code will be preserved and used for the new build.`, + ) + .requiredOption(`--function-id <function-id>`, `Function ID.`) + .requiredOption(`--deployment-id <deployment-id>`, `Deployment ID.`) + .option(`--build-id <build-id>`, `Build unique ID.`) + .action( + actionRunner( + async ({ functionId, deploymentId, buildId }) => + await ( + await getFunctionsClient() + ).createDuplicateDeployment(functionId, deploymentId, buildId), + ), + ); + +functions + .command(`create-template-deployment`) + .description( + `Create a deployment based on a template. + +Use this endpoint with combination of [listTemplates](https://appwrite.io/docs/products/functions/templates) to find the template details.`, + ) + .requiredOption(`--function-id <function-id>`, `Function ID.`) + .requiredOption( + `--repository <repository>`, + `Repository name of the template.`, + ) + .requiredOption(`--owner <owner>`, `The name of the owner of the template.`) + .requiredOption( + `--root-directory <root-directory>`, + `Path to function code in the template repo.`, + ) + .requiredOption( + `--type <type>`, + `Type for the reference provided. Can be commit, branch, or tag`, + ) + .requiredOption( + `--reference <reference>`, + `Reference value, can be a commit hash, branch name, or release tag`, + ) + .option( + `--activate [value]`, + `Automatically activate the deployment when it is finished building.`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .action( + actionRunner( + async ({ + functionId, + repository, + owner, + rootDirectory, + xType, + reference, + activate, + }) => + await ( + await getFunctionsClient() + ).createTemplateDeployment( + functionId, + repository, + owner, + rootDirectory, + xType as TemplateReferenceType, + reference, + activate, + ), + ), + ); + +functions + .command(`create-vcs-deployment`) + .description( + `Create a deployment when a function is connected to VCS. + +This endpoint lets you create deployment from a branch, commit, or a tag.`, + ) + .requiredOption(`--function-id <function-id>`, `Function ID.`) + .requiredOption( + `--type <type>`, + `Type of reference passed. Allowed values are: branch, commit`, + ) + .requiredOption( + `--reference <reference>`, + `VCS reference to create deployment from. Depending on type this can be: branch name, commit hash`, + ) + .option( + `--activate [value]`, + `Automatically activate the deployment when it is finished building.`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .action( + actionRunner( + async ({ functionId, xType, reference, activate }) => + await ( + await getFunctionsClient() + ).createVcsDeployment( + functionId, + xType as VCSReferenceType, + reference, + activate, + ), + ), + ); + +functions + .command(`get-deployment`) + .description(`Get a function deployment by its unique ID.`) + .requiredOption(`--function-id <function-id>`, `Function ID.`) + .requiredOption(`--deployment-id <deployment-id>`, `Deployment ID.`) + .action( + actionRunner( + async ({ functionId, deploymentId }) => + await ( + await getFunctionsClient() + ).getDeployment(functionId, deploymentId), + ), + ); + +functions + .command(`delete-deployment`) + .description(`Delete a code deployment by its unique ID.`) + .requiredOption(`--function-id <function-id>`, `Function ID.`) + .requiredOption(`--deployment-id <deployment-id>`, `Deployment ID.`) + .action( + actionRunner( + async ({ functionId, deploymentId }) => + await ( + await getFunctionsClient() + ).deleteDeployment(functionId, deploymentId), + ), + ); + +functions + .command(`get-deployment-download`) + .description( + `Get a function deployment content by its unique ID. The endpoint response return with a 'Content-Disposition: attachment' header that tells the browser to start downloading the file to user downloads directory.`, + ) + .requiredOption(`--function-id <function-id>`, `Function ID.`) + .requiredOption(`--deployment-id <deployment-id>`, `Deployment ID.`) + .option( + `--type <type>`, + `Deployment file to download. Can be: "source", "output".`, + ) + .action( + actionRunner( + async ({ functionId, deploymentId, xType }) => + await ( + await getFunctionsClient() + ).getDeploymentDownload( + functionId, + deploymentId, + xType as DeploymentDownloadType, + ), + ), + ); + +functions + .command(`update-deployment-status`) + .description( + `Cancel an ongoing function deployment build. If the build is already in progress, it will be stopped and marked as canceled. If the build hasn't started yet, it will be marked as canceled without executing. You cannot cancel builds that have already completed (status 'ready') or failed. The response includes the final build status and details.`, + ) + .requiredOption(`--function-id <function-id>`, `Function ID.`) + .requiredOption(`--deployment-id <deployment-id>`, `Deployment ID.`) + .action( + actionRunner( + async ({ functionId, deploymentId }) => + await ( + await getFunctionsClient() + ).updateDeploymentStatus(functionId, deploymentId), + ), + ); + +functions + .command(`list-executions`) + .description( + `Get a list of all the current user function execution logs. You can use the query params to filter your results.`, + ) + .requiredOption(`--function-id <function-id>`, `Function ID.`) + .option( + `--queries [queries...]`, + `Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: trigger, status, responseStatusCode, duration, requestMethod, requestPath, deploymentId`, + ) + .option( + `--total [value]`, + `When set to false, the total count returned will be 0 and will not be calculated.`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .action( + actionRunner( + async ({ functionId, queries, total }) => + await ( + await getFunctionsClient() + ).listExecutions(functionId, queries, total), + ), + ); + +functions + .command(`create-execution`) + .description( + `Trigger a function execution. The returned object will return you the current execution status. You can ping the \`Get Execution\` endpoint to get updates on the current execution status. Once this endpoint is called, your function execution process will start asynchronously.`, + ) + .requiredOption(`--function-id <function-id>`, `Function ID.`) + .option( + `--body <body>`, + `HTTP body of execution. Default value is empty string.`, + ) + .option( + `--async [value]`, + `Execute code in the background. Default value is false.`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .option( + `--path <path>`, + `HTTP path of execution. Path can include query params. Default value is /`, + ) + .option( + `--method <method>`, + `HTTP method of execution. Default value is POST.`, + ) + .option( + `--headers <headers>`, + `HTTP headers of execution. Defaults to empty.`, + ) + .option( + `--scheduled-at <scheduled-at>`, + `Scheduled execution time in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format. DateTime value must be in future with precision in minutes.`, + ) + .action( + actionRunner( + async ({ + functionId, + body, + xAsync, + path, + method, + headers, + scheduledAt, + }) => + await ( + await getFunctionsClient() + ).createExecution( + functionId, + body, + xAsync, + path, + method as ExecutionMethod, + JSON.parse(headers), + scheduledAt, + ), + ), + ); + +functions + .command(`get-execution`) + .description(`Get a function execution log by its unique ID.`) + .requiredOption(`--function-id <function-id>`, `Function ID.`) + .requiredOption(`--execution-id <execution-id>`, `Execution ID.`) + .action( + actionRunner( + async ({ functionId, executionId }) => + await ( + await getFunctionsClient() + ).getExecution(functionId, executionId), + ), + ); + +functions + .command(`delete-execution`) + .description(`Delete a function execution by its unique ID.`) + .requiredOption(`--function-id <function-id>`, `Function ID.`) + .requiredOption(`--execution-id <execution-id>`, `Execution ID.`) + .action( + actionRunner( + async ({ functionId, executionId }) => + await ( + await getFunctionsClient() + ).deleteExecution(functionId, executionId), + ), + ); + +functions + .command(`get-usage`) + .description( + `Get usage metrics and statistics for a for a specific function. View statistics including total deployments, builds, executions, storage usage, and compute time. The response includes both current totals and historical data for each metric. Use the optional range parameter to specify the time window for historical data: 24h (last 24 hours), 30d (last 30 days), or 90d (last 90 days). If not specified, defaults to 30 days.`, + ) + .requiredOption(`--function-id <function-id>`, `Function ID.`) + .option(`--range <range>`, `Date range.`) + .action( + actionRunner( + async ({ functionId, range }) => + await ( + await getFunctionsClient() + ).getUsage(functionId, range as UsageRange), + ), + ); + +functions + .command(`list-variables`) + .description(`Get a list of all variables of a specific function.`) + .requiredOption(`--function-id <function-id>`, `Function unique ID.`) + .action( + actionRunner( + async ({ functionId }) => + await (await getFunctionsClient()).listVariables(functionId), + ), + ); + +functions + .command(`create-variable`) + .description( + `Create a new function environment variable. These variables can be accessed in the function at runtime as environment variables.`, + ) + .requiredOption(`--function-id <function-id>`, `Function unique ID.`) + .requiredOption(`--key <key>`, `Variable key. Max length: 255 chars.`) + .requiredOption(`--value <value>`, `Variable value. Max length: 8192 chars.`) + .option( + `--secret [value]`, + `Secret variables can be updated or deleted, but only functions can read them during build and runtime.`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .action( + actionRunner( + async ({ functionId, key, value, secret }) => + await ( + await getFunctionsClient() + ).createVariable(functionId, key, value, secret), + ), + ); + +functions + .command(`get-variable`) + .description(`Get a variable by its unique ID.`) + .requiredOption(`--function-id <function-id>`, `Function unique ID.`) + .requiredOption(`--variable-id <variable-id>`, `Variable unique ID.`) + .action( + actionRunner( + async ({ functionId, variableId }) => + await (await getFunctionsClient()).getVariable(functionId, variableId), + ), + ); + +functions + .command(`update-variable`) + .description(`Update variable by its unique ID.`) + .requiredOption(`--function-id <function-id>`, `Function unique ID.`) + .requiredOption(`--variable-id <variable-id>`, `Variable unique ID.`) + .requiredOption(`--key <key>`, `Variable key. Max length: 255 chars.`) + .option(`--value <value>`, `Variable value. Max length: 8192 chars.`) + .option( + `--secret [value]`, + `Secret variables can be updated or deleted, but only functions can read them during build and runtime.`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .action( + actionRunner( + async ({ functionId, variableId, key, value, secret }) => + await ( + await getFunctionsClient() + ).updateVariable(functionId, variableId, key, value, secret), + ), + ); + +functions + .command(`delete-variable`) + .description(`Delete a variable by its unique ID.`) + .requiredOption(`--function-id <function-id>`, `Function unique ID.`) + .requiredOption(`--variable-id <variable-id>`, `Variable unique ID.`) + .action( + actionRunner( + async ({ functionId, variableId }) => + await ( + await getFunctionsClient() + ).deleteVariable(functionId, variableId), + ), + ); diff --git a/lib/commands/services/graphql.ts b/lib/commands/services/graphql.ts new file mode 100644 index 00000000..37233cdc --- /dev/null +++ b/lib/commands/services/graphql.ts @@ -0,0 +1,47 @@ +import { Command } from "commander"; +import { sdkForProject } from "../../sdks.js"; +import { + actionRunner, + commandDescriptions, + parseBool, + parseInteger, +} from "../../parser.js"; +import { Graphql } from "@appwrite.io/console"; + +let graphqlClient: Graphql | null = null; + +const getGraphqlClient = async (): Promise<Graphql> => { + if (!graphqlClient) { + const sdkClient = await sdkForProject(); + graphqlClient = new Graphql(sdkClient); + } + return graphqlClient; +}; + +export const graphql = new Command("graphql") + .description(commandDescriptions["graphql"] ?? "") + .configureHelp({ + helpWidth: process.stdout.columns || 80, + }); + +graphql + .command(`query`) + .description(`Execute a GraphQL mutation.`) + .requiredOption(`--query <query>`, `The query or queries to execute.`) + .action( + actionRunner( + async ({ query }) => + await (await getGraphqlClient()).query(JSON.parse(query)), + ), + ); + +graphql + .command(`mutation`) + .description(`Execute a GraphQL mutation.`) + .requiredOption(`--query <query>`, `The query or queries to execute.`) + .action( + actionRunner( + async ({ query }) => + await (await getGraphqlClient()).mutation(JSON.parse(query)), + ), + ); diff --git a/lib/commands/services/health.ts b/lib/commands/services/health.ts new file mode 100644 index 00000000..b9eacb44 --- /dev/null +++ b/lib/commands/services/health.ts @@ -0,0 +1,322 @@ +import { Command } from "commander"; +import { sdkForProject } from "../../sdks.js"; +import { + actionRunner, + commandDescriptions, + parseBool, + parseInteger, +} from "../../parser.js"; +import { Health } from "@appwrite.io/console"; + +let healthClient: Health | null = null; + +const getHealthClient = async (): Promise<Health> => { + if (!healthClient) { + const sdkClient = await sdkForProject(); + healthClient = new Health(sdkClient); + } + return healthClient; +}; + +export const health = new Command("health") + .description(commandDescriptions["health"] ?? "") + .configureHelp({ + helpWidth: process.stdout.columns || 80, + }); + +health + .command(`get`) + .description(`Check the Appwrite HTTP server is up and responsive.`) + .action(actionRunner(async () => await (await getHealthClient()).get())); + +health + .command(`get-antivirus`) + .description( + `Check the Appwrite Antivirus server is up and connection is successful.`, + ) + .action( + actionRunner(async () => await (await getHealthClient()).getAntivirus()), + ); + +health + .command(`get-cache`) + .description( + `Check the Appwrite in-memory cache servers are up and connection is successful.`, + ) + .action(actionRunner(async () => await (await getHealthClient()).getCache())); + +health + .command(`get-certificate`) + .description(`Get the SSL certificate for a domain`) + .option(`--domain <domain>`, `string`) + .action( + actionRunner( + async ({ domain }) => + await (await getHealthClient()).getCertificate(domain), + ), + ); + +health + .command(`get-db`) + .description( + `Check the Appwrite database servers are up and connection is successful.`, + ) + .action(actionRunner(async () => await (await getHealthClient()).getDB())); + +health + .command(`get-pub-sub`) + .description( + `Check the Appwrite pub-sub servers are up and connection is successful.`, + ) + .action( + actionRunner(async () => await (await getHealthClient()).getPubSub()), + ); + +health + .command(`get-queue-builds`) + .description( + `Get the number of builds that are waiting to be processed in the Appwrite internal queue server.`, + ) + .option( + `--threshold <threshold>`, + `Queue size threshold. When hit (equal or higher), endpoint returns server error. Default value is 5000.`, + parseInteger, + ) + .action( + actionRunner( + async ({ threshold }) => + await (await getHealthClient()).getQueueBuilds(threshold), + ), + ); + +health + .command(`get-queue-certificates`) + .description( + `Get the number of certificates that are waiting to be issued against [Letsencrypt](https://letsencrypt.org/) in the Appwrite internal queue server.`, + ) + .option( + `--threshold <threshold>`, + `Queue size threshold. When hit (equal or higher), endpoint returns server error. Default value is 5000.`, + parseInteger, + ) + .action( + actionRunner( + async ({ threshold }) => + await (await getHealthClient()).getQueueCertificates(threshold), + ), + ); + +health + .command(`get-queue-databases`) + .description( + `Get the number of database changes that are waiting to be processed in the Appwrite internal queue server.`, + ) + .option(`--name <name>`, `Queue name for which to check the queue size`) + .option( + `--threshold <threshold>`, + `Queue size threshold. When hit (equal or higher), endpoint returns server error. Default value is 5000.`, + parseInteger, + ) + .action( + actionRunner( + async ({ name, threshold }) => + await (await getHealthClient()).getQueueDatabases(name, threshold), + ), + ); + +health + .command(`get-queue-deletes`) + .description( + `Get the number of background destructive changes that are waiting to be processed in the Appwrite internal queue server.`, + ) + .option( + `--threshold <threshold>`, + `Queue size threshold. When hit (equal or higher), endpoint returns server error. Default value is 5000.`, + parseInteger, + ) + .action( + actionRunner( + async ({ threshold }) => + await (await getHealthClient()).getQueueDeletes(threshold), + ), + ); + +health + .command(`get-failed-jobs`) + .description( + `Returns the amount of failed jobs in a given queue. +`, + ) + .requiredOption(`--name <name>`, `The name of the queue`) + .option( + `--threshold <threshold>`, + `Queue size threshold. When hit (equal or higher), endpoint returns server error. Default value is 5000.`, + parseInteger, + ) + .action( + actionRunner( + async ({ name, threshold }) => + await (await getHealthClient()).getFailedJobs(name, threshold), + ), + ); + +health + .command(`get-queue-functions`) + .description( + `Get the number of function executions that are waiting to be processed in the Appwrite internal queue server.`, + ) + .option( + `--threshold <threshold>`, + `Queue size threshold. When hit (equal or higher), endpoint returns server error. Default value is 5000.`, + parseInteger, + ) + .action( + actionRunner( + async ({ threshold }) => + await (await getHealthClient()).getQueueFunctions(threshold), + ), + ); + +health + .command(`get-queue-logs`) + .description( + `Get the number of logs that are waiting to be processed in the Appwrite internal queue server.`, + ) + .option( + `--threshold <threshold>`, + `Queue size threshold. When hit (equal or higher), endpoint returns server error. Default value is 5000.`, + parseInteger, + ) + .action( + actionRunner( + async ({ threshold }) => + await (await getHealthClient()).getQueueLogs(threshold), + ), + ); + +health + .command(`get-queue-mails`) + .description( + `Get the number of mails that are waiting to be processed in the Appwrite internal queue server.`, + ) + .option( + `--threshold <threshold>`, + `Queue size threshold. When hit (equal or higher), endpoint returns server error. Default value is 5000.`, + parseInteger, + ) + .action( + actionRunner( + async ({ threshold }) => + await (await getHealthClient()).getQueueMails(threshold), + ), + ); + +health + .command(`get-queue-messaging`) + .description( + `Get the number of messages that are waiting to be processed in the Appwrite internal queue server.`, + ) + .option( + `--threshold <threshold>`, + `Queue size threshold. When hit (equal or higher), endpoint returns server error. Default value is 5000.`, + parseInteger, + ) + .action( + actionRunner( + async ({ threshold }) => + await (await getHealthClient()).getQueueMessaging(threshold), + ), + ); + +health + .command(`get-queue-migrations`) + .description( + `Get the number of migrations that are waiting to be processed in the Appwrite internal queue server.`, + ) + .option( + `--threshold <threshold>`, + `Queue size threshold. When hit (equal or higher), endpoint returns server error. Default value is 5000.`, + parseInteger, + ) + .action( + actionRunner( + async ({ threshold }) => + await (await getHealthClient()).getQueueMigrations(threshold), + ), + ); + +health + .command(`get-queue-stats-resources`) + .description( + `Get the number of metrics that are waiting to be processed in the Appwrite stats resources queue.`, + ) + .option( + `--threshold <threshold>`, + `Queue size threshold. When hit (equal or higher), endpoint returns server error. Default value is 5000.`, + parseInteger, + ) + .action( + actionRunner( + async ({ threshold }) => + await (await getHealthClient()).getQueueStatsResources(threshold), + ), + ); + +health + .command(`get-queue-usage`) + .description( + `Get the number of metrics that are waiting to be processed in the Appwrite internal queue server.`, + ) + .option( + `--threshold <threshold>`, + `Queue size threshold. When hit (equal or higher), endpoint returns server error. Default value is 5000.`, + parseInteger, + ) + .action( + actionRunner( + async ({ threshold }) => + await (await getHealthClient()).getQueueUsage(threshold), + ), + ); + +health + .command(`get-queue-webhooks`) + .description( + `Get the number of webhooks that are waiting to be processed in the Appwrite internal queue server.`, + ) + .option( + `--threshold <threshold>`, + `Queue size threshold. When hit (equal or higher), endpoint returns server error. Default value is 5000.`, + parseInteger, + ) + .action( + actionRunner( + async ({ threshold }) => + await (await getHealthClient()).getQueueWebhooks(threshold), + ), + ); + +health + .command(`get-storage`) + .description( + `Check the Appwrite storage device is up and connection is successful.`, + ) + .action( + actionRunner(async () => await (await getHealthClient()).getStorage()), + ); + +health + .command(`get-storage-local`) + .description( + `Check the Appwrite local storage device is up and connection is successful.`, + ) + .action( + actionRunner(async () => await (await getHealthClient()).getStorageLocal()), + ); + +health + .command(`get-time`) + .description( + `Check the Appwrite server time is synced with Google remote NTP server. We use this technology to smoothly handle leap seconds with no disruptive events. The [Network Time Protocol](https://en.wikipedia.org/wiki/Network_Time_Protocol) (NTP) is used by hundreds of millions of computers and devices to synchronize their clocks over the Internet. If your computer sets its own clock, it likely uses NTP.`, + ) + .action(actionRunner(async () => await (await getHealthClient()).getTime())); diff --git a/lib/commands/services/locale.ts b/lib/commands/services/locale.ts new file mode 100644 index 00000000..dbae4c50 --- /dev/null +++ b/lib/commands/services/locale.ts @@ -0,0 +1,99 @@ +import { Command } from "commander"; +import { sdkForProject } from "../../sdks.js"; +import { + actionRunner, + commandDescriptions, + parseBool, + parseInteger, +} from "../../parser.js"; +import { Locale } from "@appwrite.io/console"; + +let localeClient: Locale | null = null; + +const getLocaleClient = async (): Promise<Locale> => { + if (!localeClient) { + const sdkClient = await sdkForProject(); + localeClient = new Locale(sdkClient); + } + return localeClient; +}; + +export const locale = new Command("locale") + .description(commandDescriptions["locale"] ?? "") + .configureHelp({ + helpWidth: process.stdout.columns || 80, + }); + +locale + .command(`get`) + .description( + `Get the current user location based on IP. Returns an object with user country code, country name, continent name, continent code, ip address and suggested currency. You can use the locale header to get the data in a supported language. + +([IP Geolocation by DB-IP](https://db-ip.com))`, + ) + .action(actionRunner(async () => await (await getLocaleClient()).get())); + +locale + .command(`list-codes`) + .description( + `List of all locale codes in [ISO 639-1](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes).`, + ) + .action( + actionRunner(async () => await (await getLocaleClient()).listCodes()), + ); + +locale + .command(`list-continents`) + .description( + `List of all continents. You can use the locale header to get the data in a supported language.`, + ) + .action( + actionRunner(async () => await (await getLocaleClient()).listContinents()), + ); + +locale + .command(`list-countries`) + .description( + `List of all countries. You can use the locale header to get the data in a supported language.`, + ) + .action( + actionRunner(async () => await (await getLocaleClient()).listCountries()), + ); + +locale + .command(`list-countries-eu`) + .description( + `List of all countries that are currently members of the EU. You can use the locale header to get the data in a supported language.`, + ) + .action( + actionRunner(async () => await (await getLocaleClient()).listCountriesEU()), + ); + +locale + .command(`list-countries-phones`) + .description( + `List of all countries phone codes. You can use the locale header to get the data in a supported language.`, + ) + .action( + actionRunner( + async () => await (await getLocaleClient()).listCountriesPhones(), + ), + ); + +locale + .command(`list-currencies`) + .description( + `List of all currencies, including currency symbol, name, plural, and decimal digits for all major and minor currencies. You can use the locale header to get the data in a supported language.`, + ) + .action( + actionRunner(async () => await (await getLocaleClient()).listCurrencies()), + ); + +locale + .command(`list-languages`) + .description( + `List of all languages classified by ISO 639-1 including 2-letter code, name in English, and name in the respective language.`, + ) + .action( + actionRunner(async () => await (await getLocaleClient()).listLanguages()), + ); diff --git a/lib/commands/services/messaging.ts b/lib/commands/services/messaging.ts new file mode 100644 index 00000000..bc463cc5 --- /dev/null +++ b/lib/commands/services/messaging.ts @@ -0,0 +1,1871 @@ +import { Command } from "commander"; +import { sdkForProject } from "../../sdks.js"; +import { + actionRunner, + commandDescriptions, + parseBool, + parseInteger, +} from "../../parser.js"; +import { + Messaging, + MessagePriority, + SmtpEncryption, +} from "@appwrite.io/console"; + +let messagingClient: Messaging | null = null; + +const getMessagingClient = async (): Promise<Messaging> => { + if (!messagingClient) { + const sdkClient = await sdkForProject(); + messagingClient = new Messaging(sdkClient); + } + return messagingClient; +}; + +export const messaging = new Command("messaging") + .description(commandDescriptions["messaging"] ?? "") + .configureHelp({ + helpWidth: process.stdout.columns || 80, + }); + +messaging + .command(`list-messages`) + .description(`Get a list of all messages from the current Appwrite project.`) + .option( + `--queries [queries...]`, + `Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: scheduledAt, deliveredAt, deliveredTotal, status, description, providerType`, + ) + .option( + `--search <search>`, + `Search term to filter your list results. Max length: 256 chars.`, + ) + .option( + `--total [value]`, + `When set to false, the total count returned will be 0 and will not be calculated.`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .action( + actionRunner( + async ({ queries, search, total }) => + await (await getMessagingClient()).listMessages(queries, search, total), + ), + ); + +messaging + .command(`create-email`) + .description(`Create a new email message.`) + .requiredOption( + `--message-id <message-id>`, + `Message ID. Choose a custom ID or generate a random ID with \`ID.unique()\`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.`, + ) + .requiredOption(`--subject <subject>`, `Email Subject.`) + .requiredOption(`--content <content>`, `Email Content.`) + .option(`--topics [topics...]`, `List of Topic IDs.`) + .option(`--users [users...]`, `List of User IDs.`) + .option(`--targets [targets...]`, `List of Targets IDs.`) + .option(`--cc [cc...]`, `Array of target IDs to be added as CC.`) + .option(`--bcc [bcc...]`, `Array of target IDs to be added as BCC.`) + .option( + `--attachments [attachments...]`, + `Array of compound ID strings of bucket IDs and file IDs to be attached to the email. They should be formatted as <BUCKET_ID>:<FILE_ID>.`, + ) + .option( + `--draft [value]`, + `Is message a draft`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .option( + `--html [value]`, + `Is content of type HTML`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .option( + `--scheduled-at <scheduled-at>`, + `Scheduled delivery time for message in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format. DateTime value must be in future.`, + ) + .action( + actionRunner( + async ({ + messageId, + subject, + content, + topics, + users, + targets, + cc, + bcc, + attachments, + draft, + html, + scheduledAt, + }) => + await ( + await getMessagingClient() + ).createEmail( + messageId, + subject, + content, + topics, + users, + targets, + cc, + bcc, + attachments, + draft, + html, + scheduledAt, + ), + ), + ); + +messaging + .command(`update-email`) + .description( + `Update an email message by its unique ID. This endpoint only works on messages that are in draft status. Messages that are already processing, sent, or failed cannot be updated. +`, + ) + .requiredOption(`--message-id <message-id>`, `Message ID.`) + .option(`--topics [topics...]`, `List of Topic IDs.`) + .option(`--users [users...]`, `List of User IDs.`) + .option(`--targets [targets...]`, `List of Targets IDs.`) + .option(`--subject <subject>`, `Email Subject.`) + .option(`--content <content>`, `Email Content.`) + .option( + `--draft [value]`, + `Is message a draft`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .option( + `--html [value]`, + `Is content of type HTML`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .option(`--cc [cc...]`, `Array of target IDs to be added as CC.`) + .option(`--bcc [bcc...]`, `Array of target IDs to be added as BCC.`) + .option( + `--scheduled-at <scheduled-at>`, + `Scheduled delivery time for message in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format. DateTime value must be in future.`, + ) + .option( + `--attachments [attachments...]`, + `Array of compound ID strings of bucket IDs and file IDs to be attached to the email. They should be formatted as <BUCKET_ID>:<FILE_ID>.`, + ) + .action( + actionRunner( + async ({ + messageId, + topics, + users, + targets, + subject, + content, + draft, + html, + cc, + bcc, + scheduledAt, + attachments, + }) => + await ( + await getMessagingClient() + ).updateEmail( + messageId, + topics, + users, + targets, + subject, + content, + draft, + html, + cc, + bcc, + scheduledAt, + attachments, + ), + ), + ); + +messaging + .command(`create-push`) + .description(`Create a new push notification.`) + .requiredOption( + `--message-id <message-id>`, + `Message ID. Choose a custom ID or generate a random ID with \`ID.unique()\`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.`, + ) + .option(`--title <title>`, `Title for push notification.`) + .option(`--body <body>`, `Body for push notification.`) + .option(`--topics [topics...]`, `List of Topic IDs.`) + .option(`--users [users...]`, `List of User IDs.`) + .option(`--targets [targets...]`, `List of Targets IDs.`) + .option( + `--data <data>`, + `Additional key-value pair data for push notification.`, + ) + .option(`--action <action>`, `Action for push notification.`) + .option( + `--image <image>`, + `Image for push notification. Must be a compound bucket ID to file ID of a jpeg, png, or bmp image in Appwrite Storage. It should be formatted as <BUCKET_ID>:<FILE_ID>.`, + ) + .option( + `--icon <icon>`, + `Icon for push notification. Available only for Android and Web Platform.`, + ) + .option( + `--sound <sound>`, + `Sound for push notification. Available only for Android and iOS Platform.`, + ) + .option( + `--color <color>`, + `Color for push notification. Available only for Android Platform.`, + ) + .option( + `--tag <tag>`, + `Tag for push notification. Available only for Android Platform.`, + ) + .option( + `--badge <badge>`, + `Badge for push notification. Available only for iOS Platform.`, + parseInteger, + ) + .option( + `--draft [value]`, + `Is message a draft`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .option( + `--scheduled-at <scheduled-at>`, + `Scheduled delivery time for message in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format. DateTime value must be in future.`, + ) + .option( + `--content-available [value]`, + `If set to true, the notification will be delivered in the background. Available only for iOS Platform.`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .option( + `--critical [value]`, + `If set to true, the notification will be marked as critical. This requires the app to have the critical notification entitlement. Available only for iOS Platform.`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .option( + `--priority <priority>`, + `Set the notification priority. "normal" will consider device state and may not deliver notifications immediately. "high" will always attempt to immediately deliver the notification.`, + ) + .action( + actionRunner( + async ({ + messageId, + title, + body, + topics, + users, + targets, + data, + action, + image, + icon, + sound, + color, + tag, + badge, + draft, + scheduledAt, + contentAvailable, + critical, + priority, + }) => + await ( + await getMessagingClient() + ).createPush( + messageId, + title, + body, + topics, + users, + targets, + JSON.parse(data), + action, + image, + icon, + sound, + color, + tag, + badge, + draft, + scheduledAt, + contentAvailable, + critical, + priority as MessagePriority, + ), + ), + ); + +messaging + .command(`update-push`) + .description( + `Update a push notification by its unique ID. This endpoint only works on messages that are in draft status. Messages that are already processing, sent, or failed cannot be updated. +`, + ) + .requiredOption(`--message-id <message-id>`, `Message ID.`) + .option(`--topics [topics...]`, `List of Topic IDs.`) + .option(`--users [users...]`, `List of User IDs.`) + .option(`--targets [targets...]`, `List of Targets IDs.`) + .option(`--title <title>`, `Title for push notification.`) + .option(`--body <body>`, `Body for push notification.`) + .option(`--data <data>`, `Additional Data for push notification.`) + .option(`--action <action>`, `Action for push notification.`) + .option( + `--image <image>`, + `Image for push notification. Must be a compound bucket ID to file ID of a jpeg, png, or bmp image in Appwrite Storage. It should be formatted as <BUCKET_ID>:<FILE_ID>.`, + ) + .option( + `--icon <icon>`, + `Icon for push notification. Available only for Android and Web platforms.`, + ) + .option( + `--sound <sound>`, + `Sound for push notification. Available only for Android and iOS platforms.`, + ) + .option( + `--color <color>`, + `Color for push notification. Available only for Android platforms.`, + ) + .option( + `--tag <tag>`, + `Tag for push notification. Available only for Android platforms.`, + ) + .option( + `--badge <badge>`, + `Badge for push notification. Available only for iOS platforms.`, + parseInteger, + ) + .option( + `--draft [value]`, + `Is message a draft`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .option( + `--scheduled-at <scheduled-at>`, + `Scheduled delivery time for message in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format. DateTime value must be in future.`, + ) + .option( + `--content-available [value]`, + `If set to true, the notification will be delivered in the background. Available only for iOS Platform.`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .option( + `--critical [value]`, + `If set to true, the notification will be marked as critical. This requires the app to have the critical notification entitlement. Available only for iOS Platform.`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .option( + `--priority <priority>`, + `Set the notification priority. "normal" will consider device battery state and may send notifications later. "high" will always attempt to immediately deliver the notification.`, + ) + .action( + actionRunner( + async ({ + messageId, + topics, + users, + targets, + title, + body, + data, + action, + image, + icon, + sound, + color, + tag, + badge, + draft, + scheduledAt, + contentAvailable, + critical, + priority, + }) => + await ( + await getMessagingClient() + ).updatePush( + messageId, + topics, + users, + targets, + title, + body, + JSON.parse(data), + action, + image, + icon, + sound, + color, + tag, + badge, + draft, + scheduledAt, + contentAvailable, + critical, + priority as MessagePriority, + ), + ), + ); + +messaging + .command(`create-sms`) + .description( + `[**DEPRECATED** - This command is deprecated. Please use 'messaging createSms' instead] Create a new SMS message.`, + ) + .requiredOption( + `--message-id <message-id>`, + `Message ID. Choose a custom ID or generate a random ID with \`ID.unique()\`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.`, + ) + .requiredOption(`--content <content>`, `SMS Content.`) + .option(`--topics [topics...]`, `List of Topic IDs.`) + .option(`--users [users...]`, `List of User IDs.`) + .option(`--targets [targets...]`, `List of Targets IDs.`) + .option( + `--draft [value]`, + `Is message a draft`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .option( + `--scheduled-at <scheduled-at>`, + `Scheduled delivery time for message in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format. DateTime value must be in future.`, + ) + .action( + actionRunner( + async ({ + messageId, + content, + topics, + users, + targets, + draft, + scheduledAt, + }) => + await ( + await getMessagingClient() + ).createSms( + messageId, + content, + topics, + users, + targets, + draft, + scheduledAt, + ), + ), + ); + +messaging + .command(`update-sms`) + .description( + `[**DEPRECATED** - This command is deprecated. Please use 'messaging updateSms' instead] Update an SMS message by its unique ID. This endpoint only works on messages that are in draft status. Messages that are already processing, sent, or failed cannot be updated. +`, + ) + .requiredOption(`--message-id <message-id>`, `Message ID.`) + .option(`--topics [topics...]`, `List of Topic IDs.`) + .option(`--users [users...]`, `List of User IDs.`) + .option(`--targets [targets...]`, `List of Targets IDs.`) + .option(`--content <content>`, `Email Content.`) + .option( + `--draft [value]`, + `Is message a draft`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .option( + `--scheduled-at <scheduled-at>`, + `Scheduled delivery time for message in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format. DateTime value must be in future.`, + ) + .action( + actionRunner( + async ({ + messageId, + topics, + users, + targets, + content, + draft, + scheduledAt, + }) => + await ( + await getMessagingClient() + ).updateSms( + messageId, + topics, + users, + targets, + content, + draft, + scheduledAt, + ), + ), + ); + +messaging + .command(`get-message`) + .description( + `Get a message by its unique ID. +`, + ) + .requiredOption(`--message-id <message-id>`, `Message ID.`) + .action( + actionRunner( + async ({ messageId }) => + await (await getMessagingClient()).getMessage(messageId), + ), + ); + +messaging + .command(`delete`) + .description( + `Delete a message. If the message is not a draft or scheduled, but has been sent, this will not recall the message.`, + ) + .requiredOption(`--message-id <message-id>`, `Message ID.`) + .action( + actionRunner( + async ({ messageId }) => + await (await getMessagingClient()).delete(messageId), + ), + ); + +messaging + .command(`list-message-logs`) + .description(`Get the message activity logs listed by its unique ID.`) + .requiredOption(`--message-id <message-id>`, `Message ID.`) + .option( + `--queries [queries...]`, + `Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Only supported methods are limit and offset`, + ) + .option( + `--total [value]`, + `When set to false, the total count returned will be 0 and will not be calculated.`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .action( + actionRunner( + async ({ messageId, queries, total }) => + await ( + await getMessagingClient() + ).listMessageLogs(messageId, queries, total), + ), + ); + +messaging + .command(`list-targets`) + .description(`Get a list of the targets associated with a message.`) + .requiredOption(`--message-id <message-id>`, `Message ID.`) + .option( + `--queries [queries...]`, + `Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: userId, providerId, identifier, providerType`, + ) + .option( + `--total [value]`, + `When set to false, the total count returned will be 0 and will not be calculated.`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .action( + actionRunner( + async ({ messageId, queries, total }) => + await ( + await getMessagingClient() + ).listTargets(messageId, queries, total), + ), + ); + +messaging + .command(`list-providers`) + .description(`Get a list of all providers from the current Appwrite project.`) + .option( + `--queries [queries...]`, + `Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: name, provider, type, enabled`, + ) + .option( + `--search <search>`, + `Search term to filter your list results. Max length: 256 chars.`, + ) + .option( + `--total [value]`, + `When set to false, the total count returned will be 0 and will not be calculated.`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .action( + actionRunner( + async ({ queries, search, total }) => + await ( + await getMessagingClient() + ).listProviders(queries, search, total), + ), + ); + +messaging + .command(`create-apns-provider`) + .description( + `[**DEPRECATED** - This command is deprecated. Please use 'messaging createApnsProvider' instead] Create a new Apple Push Notification service provider.`, + ) + .requiredOption( + `--provider-id <provider-id>`, + `Provider ID. Choose a custom ID or generate a random ID with \`ID.unique()\`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.`, + ) + .requiredOption(`--name <name>`, `Provider name.`) + .option(`--auth-key <auth-key>`, `APNS authentication key.`) + .option(`--auth-key-id <auth-key-id>`, `APNS authentication key ID.`) + .option(`--team-id <team-id>`, `APNS team ID.`) + .option(`--bundle-id <bundle-id>`, `APNS bundle ID.`) + .option( + `--sandbox [value]`, + `Use APNS sandbox environment.`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .option( + `--enabled [value]`, + `Set as enabled.`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .action( + actionRunner( + async ({ + providerId, + name, + authKey, + authKeyId, + teamId, + bundleId, + sandbox, + enabled, + }) => + await ( + await getMessagingClient() + ).createApnsProvider( + providerId, + name, + authKey, + authKeyId, + teamId, + bundleId, + sandbox, + enabled, + ), + ), + ); + +messaging + .command(`update-apns-provider`) + .description( + `[**DEPRECATED** - This command is deprecated. Please use 'messaging updateApnsProvider' instead] Update a Apple Push Notification service provider by its unique ID.`, + ) + .requiredOption(`--provider-id <provider-id>`, `Provider ID.`) + .option(`--name <name>`, `Provider name.`) + .option( + `--enabled [value]`, + `Set as enabled.`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .option(`--auth-key <auth-key>`, `APNS authentication key.`) + .option(`--auth-key-id <auth-key-id>`, `APNS authentication key ID.`) + .option(`--team-id <team-id>`, `APNS team ID.`) + .option(`--bundle-id <bundle-id>`, `APNS bundle ID.`) + .option( + `--sandbox [value]`, + `Use APNS sandbox environment.`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .action( + actionRunner( + async ({ + providerId, + name, + enabled, + authKey, + authKeyId, + teamId, + bundleId, + sandbox, + }) => + await ( + await getMessagingClient() + ).updateApnsProvider( + providerId, + name, + enabled, + authKey, + authKeyId, + teamId, + bundleId, + sandbox, + ), + ), + ); + +messaging + .command(`create-fcm-provider`) + .description( + `[**DEPRECATED** - This command is deprecated. Please use 'messaging createFcmProvider' instead] Create a new Firebase Cloud Messaging provider.`, + ) + .requiredOption( + `--provider-id <provider-id>`, + `Provider ID. Choose a custom ID or generate a random ID with \`ID.unique()\`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.`, + ) + .requiredOption(`--name <name>`, `Provider name.`) + .option( + `--service-account-json <service-account-json>`, + `FCM service account JSON.`, + ) + .option( + `--enabled [value]`, + `Set as enabled.`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .action( + actionRunner( + async ({ providerId, name, serviceAccountJSON, enabled }) => + await ( + await getMessagingClient() + ).createFcmProvider( + providerId, + name, + JSON.parse(serviceAccountJSON), + enabled, + ), + ), + ); + +messaging + .command(`update-fcm-provider`) + .description( + `[**DEPRECATED** - This command is deprecated. Please use 'messaging updateFcmProvider' instead] Update a Firebase Cloud Messaging provider by its unique ID.`, + ) + .requiredOption(`--provider-id <provider-id>`, `Provider ID.`) + .option(`--name <name>`, `Provider name.`) + .option( + `--enabled [value]`, + `Set as enabled.`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .option( + `--service-account-json <service-account-json>`, + `FCM service account JSON.`, + ) + .action( + actionRunner( + async ({ providerId, name, enabled, serviceAccountJSON }) => + await ( + await getMessagingClient() + ).updateFcmProvider( + providerId, + name, + enabled, + JSON.parse(serviceAccountJSON), + ), + ), + ); + +messaging + .command(`create-mailgun-provider`) + .description(`Create a new Mailgun provider.`) + .requiredOption( + `--provider-id <provider-id>`, + `Provider ID. Choose a custom ID or generate a random ID with \`ID.unique()\`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.`, + ) + .requiredOption(`--name <name>`, `Provider name.`) + .option(`--api-key <api-key>`, `Mailgun API Key.`) + .option(`--domain <domain>`, `Mailgun Domain.`) + .option( + `--is-eu-region [value]`, + `Set as EU region.`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .option(`--from-name <from-name>`, `Sender Name.`) + .option(`--from-email <from-email>`, `Sender email address.`) + .option( + `--reply-to-name <reply-to-name>`, + `Name set in the reply to field for the mail. Default value is sender name. Reply to name must have reply to email as well.`, + ) + .option( + `--reply-to-email <reply-to-email>`, + `Email set in the reply to field for the mail. Default value is sender email. Reply to email must have reply to name as well.`, + ) + .option( + `--enabled [value]`, + `Set as enabled.`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .action( + actionRunner( + async ({ + providerId, + name, + apiKey, + domain, + isEuRegion, + fromName, + fromEmail, + replyToName, + replyToEmail, + enabled, + }) => + await ( + await getMessagingClient() + ).createMailgunProvider( + providerId, + name, + apiKey, + domain, + isEuRegion, + fromName, + fromEmail, + replyToName, + replyToEmail, + enabled, + ), + ), + ); + +messaging + .command(`update-mailgun-provider`) + .description(`Update a Mailgun provider by its unique ID.`) + .requiredOption(`--provider-id <provider-id>`, `Provider ID.`) + .option(`--name <name>`, `Provider name.`) + .option(`--api-key <api-key>`, `Mailgun API Key.`) + .option(`--domain <domain>`, `Mailgun Domain.`) + .option( + `--is-eu-region [value]`, + `Set as EU region.`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .option( + `--enabled [value]`, + `Set as enabled.`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .option(`--from-name <from-name>`, `Sender Name.`) + .option(`--from-email <from-email>`, `Sender email address.`) + .option( + `--reply-to-name <reply-to-name>`, + `Name set in the reply to field for the mail. Default value is sender name.`, + ) + .option( + `--reply-to-email <reply-to-email>`, + `Email set in the reply to field for the mail. Default value is sender email.`, + ) + .action( + actionRunner( + async ({ + providerId, + name, + apiKey, + domain, + isEuRegion, + enabled, + fromName, + fromEmail, + replyToName, + replyToEmail, + }) => + await ( + await getMessagingClient() + ).updateMailgunProvider( + providerId, + name, + apiKey, + domain, + isEuRegion, + enabled, + fromName, + fromEmail, + replyToName, + replyToEmail, + ), + ), + ); + +messaging + .command(`create-msg91-provider`) + .description(`Create a new MSG91 provider.`) + .requiredOption( + `--provider-id <provider-id>`, + `Provider ID. Choose a custom ID or generate a random ID with \`ID.unique()\`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.`, + ) + .requiredOption(`--name <name>`, `Provider name.`) + .option(`--template-id <template-id>`, `Msg91 template ID`) + .option(`--sender-id <sender-id>`, `Msg91 sender ID.`) + .option(`--auth-key <auth-key>`, `Msg91 auth key.`) + .option( + `--enabled [value]`, + `Set as enabled.`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .action( + actionRunner( + async ({ providerId, name, templateId, senderId, authKey, enabled }) => + await ( + await getMessagingClient() + ).createMsg91Provider( + providerId, + name, + templateId, + senderId, + authKey, + enabled, + ), + ), + ); + +messaging + .command(`update-msg91-provider`) + .description(`Update a MSG91 provider by its unique ID.`) + .requiredOption(`--provider-id <provider-id>`, `Provider ID.`) + .option(`--name <name>`, `Provider name.`) + .option( + `--enabled [value]`, + `Set as enabled.`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .option(`--template-id <template-id>`, `Msg91 template ID.`) + .option(`--sender-id <sender-id>`, `Msg91 sender ID.`) + .option(`--auth-key <auth-key>`, `Msg91 auth key.`) + .action( + actionRunner( + async ({ providerId, name, enabled, templateId, senderId, authKey }) => + await ( + await getMessagingClient() + ).updateMsg91Provider( + providerId, + name, + enabled, + templateId, + senderId, + authKey, + ), + ), + ); + +messaging + .command(`create-resend-provider`) + .description(`Create a new Resend provider.`) + .requiredOption( + `--provider-id <provider-id>`, + `Provider ID. Choose a custom ID or generate a random ID with \`ID.unique()\`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.`, + ) + .requiredOption(`--name <name>`, `Provider name.`) + .option(`--api-key <api-key>`, `Resend API key.`) + .option(`--from-name <from-name>`, `Sender Name.`) + .option(`--from-email <from-email>`, `Sender email address.`) + .option( + `--reply-to-name <reply-to-name>`, + `Name set in the reply to field for the mail. Default value is sender name.`, + ) + .option( + `--reply-to-email <reply-to-email>`, + `Email set in the reply to field for the mail. Default value is sender email.`, + ) + .option( + `--enabled [value]`, + `Set as enabled.`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .action( + actionRunner( + async ({ + providerId, + name, + apiKey, + fromName, + fromEmail, + replyToName, + replyToEmail, + enabled, + }) => + await ( + await getMessagingClient() + ).createResendProvider( + providerId, + name, + apiKey, + fromName, + fromEmail, + replyToName, + replyToEmail, + enabled, + ), + ), + ); + +messaging + .command(`update-resend-provider`) + .description(`Update a Resend provider by its unique ID.`) + .requiredOption(`--provider-id <provider-id>`, `Provider ID.`) + .option(`--name <name>`, `Provider name.`) + .option( + `--enabled [value]`, + `Set as enabled.`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .option(`--api-key <api-key>`, `Resend API key.`) + .option(`--from-name <from-name>`, `Sender Name.`) + .option(`--from-email <from-email>`, `Sender email address.`) + .option( + `--reply-to-name <reply-to-name>`, + `Name set in the Reply To field for the mail. Default value is Sender Name.`, + ) + .option( + `--reply-to-email <reply-to-email>`, + `Email set in the Reply To field for the mail. Default value is Sender Email.`, + ) + .action( + actionRunner( + async ({ + providerId, + name, + enabled, + apiKey, + fromName, + fromEmail, + replyToName, + replyToEmail, + }) => + await ( + await getMessagingClient() + ).updateResendProvider( + providerId, + name, + enabled, + apiKey, + fromName, + fromEmail, + replyToName, + replyToEmail, + ), + ), + ); + +messaging + .command(`create-sendgrid-provider`) + .description(`Create a new Sendgrid provider.`) + .requiredOption( + `--provider-id <provider-id>`, + `Provider ID. Choose a custom ID or generate a random ID with \`ID.unique()\`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.`, + ) + .requiredOption(`--name <name>`, `Provider name.`) + .option(`--api-key <api-key>`, `Sendgrid API key.`) + .option(`--from-name <from-name>`, `Sender Name.`) + .option(`--from-email <from-email>`, `Sender email address.`) + .option( + `--reply-to-name <reply-to-name>`, + `Name set in the reply to field for the mail. Default value is sender name.`, + ) + .option( + `--reply-to-email <reply-to-email>`, + `Email set in the reply to field for the mail. Default value is sender email.`, + ) + .option( + `--enabled [value]`, + `Set as enabled.`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .action( + actionRunner( + async ({ + providerId, + name, + apiKey, + fromName, + fromEmail, + replyToName, + replyToEmail, + enabled, + }) => + await ( + await getMessagingClient() + ).createSendgridProvider( + providerId, + name, + apiKey, + fromName, + fromEmail, + replyToName, + replyToEmail, + enabled, + ), + ), + ); + +messaging + .command(`update-sendgrid-provider`) + .description(`Update a Sendgrid provider by its unique ID.`) + .requiredOption(`--provider-id <provider-id>`, `Provider ID.`) + .option(`--name <name>`, `Provider name.`) + .option( + `--enabled [value]`, + `Set as enabled.`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .option(`--api-key <api-key>`, `Sendgrid API key.`) + .option(`--from-name <from-name>`, `Sender Name.`) + .option(`--from-email <from-email>`, `Sender email address.`) + .option( + `--reply-to-name <reply-to-name>`, + `Name set in the Reply To field for the mail. Default value is Sender Name.`, + ) + .option( + `--reply-to-email <reply-to-email>`, + `Email set in the Reply To field for the mail. Default value is Sender Email.`, + ) + .action( + actionRunner( + async ({ + providerId, + name, + enabled, + apiKey, + fromName, + fromEmail, + replyToName, + replyToEmail, + }) => + await ( + await getMessagingClient() + ).updateSendgridProvider( + providerId, + name, + enabled, + apiKey, + fromName, + fromEmail, + replyToName, + replyToEmail, + ), + ), + ); + +messaging + .command(`create-smtp-provider`) + .description( + `[**DEPRECATED** - This command is deprecated. Please use 'messaging createSmtpProvider' instead] Create a new SMTP provider.`, + ) + .requiredOption( + `--provider-id <provider-id>`, + `Provider ID. Choose a custom ID or generate a random ID with \`ID.unique()\`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.`, + ) + .requiredOption(`--name <name>`, `Provider name.`) + .requiredOption( + `--host <host>`, + `SMTP hosts. Either a single hostname or multiple semicolon-delimited hostnames. You can also specify a different port for each host such as \`smtp1.example.com:25;smtp2.example.com\`. You can also specify encryption type, for example: \`tls://smtp1.example.com:587;ssl://smtp2.example.com:465"\`. Hosts will be tried in order.`, + ) + .option(`--port <port>`, `The default SMTP server port.`, parseInteger) + .option(`--username <username>`, `Authentication username.`) + .option(`--password <password>`, `Authentication password.`) + .option( + `--encryption <encryption>`, + `Encryption type. Can be omitted, 'ssl', or 'tls'`, + ) + .option( + `--auto-tls [value]`, + `Enable SMTP AutoTLS feature.`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .option(`--mailer <mailer>`, `The value to use for the X-Mailer header.`) + .option(`--from-name <from-name>`, `Sender Name.`) + .option(`--from-email <from-email>`, `Sender email address.`) + .option( + `--reply-to-name <reply-to-name>`, + `Name set in the reply to field for the mail. Default value is sender name.`, + ) + .option( + `--reply-to-email <reply-to-email>`, + `Email set in the reply to field for the mail. Default value is sender email.`, + ) + .option( + `--enabled [value]`, + `Set as enabled.`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .action( + actionRunner( + async ({ + providerId, + name, + host, + port, + username, + password, + encryption, + autoTLS, + mailer, + fromName, + fromEmail, + replyToName, + replyToEmail, + enabled, + }) => + await ( + await getMessagingClient() + ).createSmtpProvider( + providerId, + name, + host, + port, + username, + password, + encryption as SmtpEncryption, + autoTLS, + mailer, + fromName, + fromEmail, + replyToName, + replyToEmail, + enabled, + ), + ), + ); + +messaging + .command(`update-smtp-provider`) + .description( + `[**DEPRECATED** - This command is deprecated. Please use 'messaging updateSmtpProvider' instead] Update a SMTP provider by its unique ID.`, + ) + .requiredOption(`--provider-id <provider-id>`, `Provider ID.`) + .option(`--name <name>`, `Provider name.`) + .option( + `--host <host>`, + `SMTP hosts. Either a single hostname or multiple semicolon-delimited hostnames. You can also specify a different port for each host such as \`smtp1.example.com:25;smtp2.example.com\`. You can also specify encryption type, for example: \`tls://smtp1.example.com:587;ssl://smtp2.example.com:465"\`. Hosts will be tried in order.`, + ) + .option(`--port <port>`, `SMTP port.`, parseInteger) + .option(`--username <username>`, `Authentication username.`) + .option(`--password <password>`, `Authentication password.`) + .option(`--encryption <encryption>`, `Encryption type. Can be 'ssl' or 'tls'`) + .option( + `--auto-tls [value]`, + `Enable SMTP AutoTLS feature.`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .option(`--mailer <mailer>`, `The value to use for the X-Mailer header.`) + .option(`--from-name <from-name>`, `Sender Name.`) + .option(`--from-email <from-email>`, `Sender email address.`) + .option( + `--reply-to-name <reply-to-name>`, + `Name set in the Reply To field for the mail. Default value is Sender Name.`, + ) + .option( + `--reply-to-email <reply-to-email>`, + `Email set in the Reply To field for the mail. Default value is Sender Email.`, + ) + .option( + `--enabled [value]`, + `Set as enabled.`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .action( + actionRunner( + async ({ + providerId, + name, + host, + port, + username, + password, + encryption, + autoTLS, + mailer, + fromName, + fromEmail, + replyToName, + replyToEmail, + enabled, + }) => + await ( + await getMessagingClient() + ).updateSmtpProvider( + providerId, + name, + host, + port, + username, + password, + encryption as SmtpEncryption, + autoTLS, + mailer, + fromName, + fromEmail, + replyToName, + replyToEmail, + enabled, + ), + ), + ); + +messaging + .command(`create-telesign-provider`) + .description(`Create a new Telesign provider.`) + .requiredOption( + `--provider-id <provider-id>`, + `Provider ID. Choose a custom ID or generate a random ID with \`ID.unique()\`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.`, + ) + .requiredOption(`--name <name>`, `Provider name.`) + .option( + `--from <from>`, + `Sender Phone number. Format this number with a leading '+' and a country code, e.g., +16175551212.`, + ) + .option(`--customer-id <customer-id>`, `Telesign customer ID.`) + .option(`--api-key <api-key>`, `Telesign API key.`) + .option( + `--enabled [value]`, + `Set as enabled.`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .action( + actionRunner( + async ({ providerId, name, from, customerId, apiKey, enabled }) => + await ( + await getMessagingClient() + ).createTelesignProvider( + providerId, + name, + from, + customerId, + apiKey, + enabled, + ), + ), + ); + +messaging + .command(`update-telesign-provider`) + .description(`Update a Telesign provider by its unique ID.`) + .requiredOption(`--provider-id <provider-id>`, `Provider ID.`) + .option(`--name <name>`, `Provider name.`) + .option( + `--enabled [value]`, + `Set as enabled.`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .option(`--customer-id <customer-id>`, `Telesign customer ID.`) + .option(`--api-key <api-key>`, `Telesign API key.`) + .option(`--from <from>`, `Sender number.`) + .action( + actionRunner( + async ({ providerId, name, enabled, customerId, apiKey, from }) => + await ( + await getMessagingClient() + ).updateTelesignProvider( + providerId, + name, + enabled, + customerId, + apiKey, + from, + ), + ), + ); + +messaging + .command(`create-textmagic-provider`) + .description(`Create a new Textmagic provider.`) + .requiredOption( + `--provider-id <provider-id>`, + `Provider ID. Choose a custom ID or generate a random ID with \`ID.unique()\`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.`, + ) + .requiredOption(`--name <name>`, `Provider name.`) + .option( + `--from <from>`, + `Sender Phone number. Format this number with a leading '+' and a country code, e.g., +16175551212.`, + ) + .option(`--username <username>`, `Textmagic username.`) + .option(`--api-key <api-key>`, `Textmagic apiKey.`) + .option( + `--enabled [value]`, + `Set as enabled.`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .action( + actionRunner( + async ({ providerId, name, from, username, apiKey, enabled }) => + await ( + await getMessagingClient() + ).createTextmagicProvider( + providerId, + name, + from, + username, + apiKey, + enabled, + ), + ), + ); + +messaging + .command(`update-textmagic-provider`) + .description(`Update a Textmagic provider by its unique ID.`) + .requiredOption(`--provider-id <provider-id>`, `Provider ID.`) + .option(`--name <name>`, `Provider name.`) + .option( + `--enabled [value]`, + `Set as enabled.`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .option(`--username <username>`, `Textmagic username.`) + .option(`--api-key <api-key>`, `Textmagic apiKey.`) + .option(`--from <from>`, `Sender number.`) + .action( + actionRunner( + async ({ providerId, name, enabled, username, apiKey, from }) => + await ( + await getMessagingClient() + ).updateTextmagicProvider( + providerId, + name, + enabled, + username, + apiKey, + from, + ), + ), + ); + +messaging + .command(`create-twilio-provider`) + .description(`Create a new Twilio provider.`) + .requiredOption( + `--provider-id <provider-id>`, + `Provider ID. Choose a custom ID or generate a random ID with \`ID.unique()\`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.`, + ) + .requiredOption(`--name <name>`, `Provider name.`) + .option( + `--from <from>`, + `Sender Phone number. Format this number with a leading '+' and a country code, e.g., +16175551212.`, + ) + .option(`--account-sid <account-sid>`, `Twilio account secret ID.`) + .option(`--auth-token <auth-token>`, `Twilio authentication token.`) + .option( + `--enabled [value]`, + `Set as enabled.`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .action( + actionRunner( + async ({ providerId, name, from, accountSid, authToken, enabled }) => + await ( + await getMessagingClient() + ).createTwilioProvider( + providerId, + name, + from, + accountSid, + authToken, + enabled, + ), + ), + ); + +messaging + .command(`update-twilio-provider`) + .description(`Update a Twilio provider by its unique ID.`) + .requiredOption(`--provider-id <provider-id>`, `Provider ID.`) + .option(`--name <name>`, `Provider name.`) + .option( + `--enabled [value]`, + `Set as enabled.`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .option(`--account-sid <account-sid>`, `Twilio account secret ID.`) + .option(`--auth-token <auth-token>`, `Twilio authentication token.`) + .option(`--from <from>`, `Sender number.`) + .action( + actionRunner( + async ({ providerId, name, enabled, accountSid, authToken, from }) => + await ( + await getMessagingClient() + ).updateTwilioProvider( + providerId, + name, + enabled, + accountSid, + authToken, + from, + ), + ), + ); + +messaging + .command(`create-vonage-provider`) + .description(`Create a new Vonage provider.`) + .requiredOption( + `--provider-id <provider-id>`, + `Provider ID. Choose a custom ID or generate a random ID with \`ID.unique()\`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.`, + ) + .requiredOption(`--name <name>`, `Provider name.`) + .option( + `--from <from>`, + `Sender Phone number. Format this number with a leading '+' and a country code, e.g., +16175551212.`, + ) + .option(`--api-key <api-key>`, `Vonage API key.`) + .option(`--api-secret <api-secret>`, `Vonage API secret.`) + .option( + `--enabled [value]`, + `Set as enabled.`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .action( + actionRunner( + async ({ providerId, name, from, apiKey, apiSecret, enabled }) => + await ( + await getMessagingClient() + ).createVonageProvider( + providerId, + name, + from, + apiKey, + apiSecret, + enabled, + ), + ), + ); + +messaging + .command(`update-vonage-provider`) + .description(`Update a Vonage provider by its unique ID.`) + .requiredOption(`--provider-id <provider-id>`, `Provider ID.`) + .option(`--name <name>`, `Provider name.`) + .option( + `--enabled [value]`, + `Set as enabled.`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .option(`--api-key <api-key>`, `Vonage API key.`) + .option(`--api-secret <api-secret>`, `Vonage API secret.`) + .option(`--from <from>`, `Sender number.`) + .action( + actionRunner( + async ({ providerId, name, enabled, apiKey, apiSecret, from }) => + await ( + await getMessagingClient() + ).updateVonageProvider( + providerId, + name, + enabled, + apiKey, + apiSecret, + from, + ), + ), + ); + +messaging + .command(`get-provider`) + .description( + `Get a provider by its unique ID. +`, + ) + .requiredOption(`--provider-id <provider-id>`, `Provider ID.`) + .action( + actionRunner( + async ({ providerId }) => + await (await getMessagingClient()).getProvider(providerId), + ), + ); + +messaging + .command(`delete-provider`) + .description(`Delete a provider by its unique ID.`) + .requiredOption(`--provider-id <provider-id>`, `Provider ID.`) + .action( + actionRunner( + async ({ providerId }) => + await (await getMessagingClient()).deleteProvider(providerId), + ), + ); + +messaging + .command(`list-provider-logs`) + .description(`Get the provider activity logs listed by its unique ID.`) + .requiredOption(`--provider-id <provider-id>`, `Provider ID.`) + .option( + `--queries [queries...]`, + `Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Only supported methods are limit and offset`, + ) + .option( + `--total [value]`, + `When set to false, the total count returned will be 0 and will not be calculated.`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .action( + actionRunner( + async ({ providerId, queries, total }) => + await ( + await getMessagingClient() + ).listProviderLogs(providerId, queries, total), + ), + ); + +messaging + .command(`list-subscriber-logs`) + .description(`Get the subscriber activity logs listed by its unique ID.`) + .requiredOption(`--subscriber-id <subscriber-id>`, `Subscriber ID.`) + .option( + `--queries [queries...]`, + `Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Only supported methods are limit and offset`, + ) + .option( + `--total [value]`, + `When set to false, the total count returned will be 0 and will not be calculated.`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .action( + actionRunner( + async ({ subscriberId, queries, total }) => + await ( + await getMessagingClient() + ).listSubscriberLogs(subscriberId, queries, total), + ), + ); + +messaging + .command(`list-topics`) + .description(`Get a list of all topics from the current Appwrite project.`) + .option( + `--queries [queries...]`, + `Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: name, description, emailTotal, smsTotal, pushTotal`, + ) + .option( + `--search <search>`, + `Search term to filter your list results. Max length: 256 chars.`, + ) + .option( + `--total [value]`, + `When set to false, the total count returned will be 0 and will not be calculated.`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .action( + actionRunner( + async ({ queries, search, total }) => + await (await getMessagingClient()).listTopics(queries, search, total), + ), + ); + +messaging + .command(`create-topic`) + .description(`Create a new topic.`) + .requiredOption( + `--topic-id <topic-id>`, + `Topic ID. Choose a custom Topic ID or a new Topic ID.`, + ) + .requiredOption(`--name <name>`, `Topic Name.`) + .option( + `--subscribe [subscribe...]`, + `An array of role strings with subscribe permission. By default all users are granted with any subscribe permission. [learn more about roles](https://appwrite.io/docs/permissions#permission-roles). Maximum of 100 roles are allowed, each 64 characters long.`, + ) + .action( + actionRunner( + async ({ topicId, name, subscribe }) => + await ( + await getMessagingClient() + ).createTopic(topicId, name, subscribe), + ), + ); + +messaging + .command(`get-topic`) + .description( + `Get a topic by its unique ID. +`, + ) + .requiredOption(`--topic-id <topic-id>`, `Topic ID.`) + .action( + actionRunner( + async ({ topicId }) => + await (await getMessagingClient()).getTopic(topicId), + ), + ); + +messaging + .command(`update-topic`) + .description( + `Update a topic by its unique ID. +`, + ) + .requiredOption(`--topic-id <topic-id>`, `Topic ID.`) + .option(`--name <name>`, `Topic Name.`) + .option( + `--subscribe [subscribe...]`, + `An array of role strings with subscribe permission. By default all users are granted with any subscribe permission. [learn more about roles](https://appwrite.io/docs/permissions#permission-roles). Maximum of 100 roles are allowed, each 64 characters long.`, + ) + .action( + actionRunner( + async ({ topicId, name, subscribe }) => + await ( + await getMessagingClient() + ).updateTopic(topicId, name, subscribe), + ), + ); + +messaging + .command(`delete-topic`) + .description(`Delete a topic by its unique ID.`) + .requiredOption(`--topic-id <topic-id>`, `Topic ID.`) + .action( + actionRunner( + async ({ topicId }) => + await (await getMessagingClient()).deleteTopic(topicId), + ), + ); + +messaging + .command(`list-topic-logs`) + .description(`Get the topic activity logs listed by its unique ID.`) + .requiredOption(`--topic-id <topic-id>`, `Topic ID.`) + .option( + `--queries [queries...]`, + `Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Only supported methods are limit and offset`, + ) + .option( + `--total [value]`, + `When set to false, the total count returned will be 0 and will not be calculated.`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .action( + actionRunner( + async ({ topicId, queries, total }) => + await ( + await getMessagingClient() + ).listTopicLogs(topicId, queries, total), + ), + ); + +messaging + .command(`list-subscribers`) + .description( + `Get a list of all subscribers from the current Appwrite project.`, + ) + .requiredOption( + `--topic-id <topic-id>`, + `Topic ID. The topic ID subscribed to.`, + ) + .option( + `--queries [queries...]`, + `Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: name, provider, type, enabled`, + ) + .option( + `--search <search>`, + `Search term to filter your list results. Max length: 256 chars.`, + ) + .option( + `--total [value]`, + `When set to false, the total count returned will be 0 and will not be calculated.`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .action( + actionRunner( + async ({ topicId, queries, search, total }) => + await ( + await getMessagingClient() + ).listSubscribers(topicId, queries, search, total), + ), + ); + +messaging + .command(`create-subscriber`) + .description(`Create a new subscriber.`) + .requiredOption( + `--topic-id <topic-id>`, + `Topic ID. The topic ID to subscribe to.`, + ) + .requiredOption( + `--subscriber-id <subscriber-id>`, + `Subscriber ID. Choose a custom Subscriber ID or a new Subscriber ID.`, + ) + .requiredOption( + `--target-id <target-id>`, + `Target ID. The target ID to link to the specified Topic ID.`, + ) + .action( + actionRunner( + async ({ topicId, subscriberId, targetId }) => + await ( + await getMessagingClient() + ).createSubscriber(topicId, subscriberId, targetId), + ), + ); + +messaging + .command(`get-subscriber`) + .description( + `Get a subscriber by its unique ID. +`, + ) + .requiredOption( + `--topic-id <topic-id>`, + `Topic ID. The topic ID subscribed to.`, + ) + .requiredOption(`--subscriber-id <subscriber-id>`, `Subscriber ID.`) + .action( + actionRunner( + async ({ topicId, subscriberId }) => + await (await getMessagingClient()).getSubscriber(topicId, subscriberId), + ), + ); + +messaging + .command(`delete-subscriber`) + .description(`Delete a subscriber by its unique ID.`) + .requiredOption( + `--topic-id <topic-id>`, + `Topic ID. The topic ID subscribed to.`, + ) + .requiredOption(`--subscriber-id <subscriber-id>`, `Subscriber ID.`) + .action( + actionRunner( + async ({ topicId, subscriberId }) => + await ( + await getMessagingClient() + ).deleteSubscriber(topicId, subscriberId), + ), + ); diff --git a/lib/commands/services/migrations.ts b/lib/commands/services/migrations.ts new file mode 100644 index 00000000..1c71eee7 --- /dev/null +++ b/lib/commands/services/migrations.ts @@ -0,0 +1,421 @@ +import { Command } from "commander"; +import { sdkForProject } from "../../sdks.js"; +import { + actionRunner, + commandDescriptions, + parseBool, + parseInteger, +} from "../../parser.js"; +import { Migrations } from "@appwrite.io/console"; + +let migrationsClient: Migrations | null = null; + +const getMigrationsClient = async (): Promise<Migrations> => { + if (!migrationsClient) { + const sdkClient = await sdkForProject(); + migrationsClient = new Migrations(sdkClient); + } + return migrationsClient; +}; + +export const migrations = new Command("migrations") + .description(commandDescriptions["migrations"] ?? "") + .configureHelp({ + helpWidth: process.stdout.columns || 80, + }); + +migrations + .command(`list`) + .description( + `List all migrations in the current project. This endpoint returns a list of all migrations including their status, progress, and any errors that occurred during the migration process.`, + ) + .option( + `--queries [queries...]`, + `Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/databases#querying-documents). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: status, stage, source, destination, resources, statusCounters, resourceData, errors`, + ) + .option( + `--search <search>`, + `Search term to filter your list results. Max length: 256 chars.`, + ) + .option( + `--total [value]`, + `When set to false, the total count returned will be 0 and will not be calculated.`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .action( + actionRunner( + async ({ queries, search, total }) => + await (await getMigrationsClient()).list(queries, search, total), + ), + ); + +migrations + .command(`create-appwrite-migration`) + .description( + `Migrate data from another Appwrite project to your current project. This endpoint allows you to migrate resources like databases, collections, documents, users, and files from an existing Appwrite project. `, + ) + .requiredOption(`--resources [resources...]`, `List of resources to migrate`) + .requiredOption(`--endpoint <endpoint>`, `Source Appwrite endpoint`) + .requiredOption(`--project-id <project-id>`, `Source Project ID`) + .requiredOption(`--api-key <api-key>`, `Source API Key`) + .action( + actionRunner( + async ({ resources, endpoint, projectId, apiKey }) => + await ( + await getMigrationsClient() + ).createAppwriteMigration(resources, endpoint, projectId, apiKey), + ), + ); + +migrations + .command(`get-appwrite-report`) + .description( + `Generate a report of the data in an Appwrite project before migrating. This endpoint analyzes the source project and returns information about the resources that can be migrated.`, + ) + .requiredOption(`--resources [resources...]`, `List of resources to migrate`) + .requiredOption(`--endpoint <endpoint>`, `Source's Appwrite Endpoint`) + .requiredOption(`--project-id <project-id>`, `Source's Project ID`) + .requiredOption(`--key <key>`, `Source's API Key`) + .action( + actionRunner( + async ({ resources, endpoint, projectID, key }) => + await ( + await getMigrationsClient() + ).getAppwriteReport(resources, endpoint, projectID, key), + ), + ); + +migrations + .command(`create-csvexport`) + .description( + `Export documents to a CSV file from your Appwrite database. This endpoint allows you to export documents to a CSV file stored in a secure internal bucket. You'll receive an email with a download link when the export is complete.`, + ) + .requiredOption( + `--resource-id <resource-id>`, + `Composite ID in the format {databaseId:collectionId}, identifying a collection within a database to export.`, + ) + .requiredOption( + `--filename <filename>`, + `The name of the file to be created for the export, excluding the .csv extension.`, + ) + .option( + `--columns [columns...]`, + `List of attributes to export. If empty, all attributes will be exported. You can use the \`*\` wildcard to export all attributes from the collection.`, + ) + .option( + `--queries [queries...]`, + `Array of query strings generated using the Query class provided by the SDK to filter documents to export. [Learn more about queries](https://appwrite.io/docs/databases#querying-documents). Maximum of 100 queries are allowed, each 4096 characters long.`, + ) + .option( + `--delimiter <delimiter>`, + `The character that separates each column value. Default is comma.`, + ) + .option( + `--enclosure <enclosure>`, + `The character that encloses each column value. Default is double quotes.`, + ) + .option( + `--escape <escape>`, + `The escape character for the enclosure character. Default is double quotes.`, + ) + .option( + `--header [value]`, + `Whether to include the header row with column names. Default is true.`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .option( + `--notify [value]`, + `Set to true to receive an email when the export is complete. Default is true.`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .action( + actionRunner( + async ({ + resourceId, + filename, + columns, + queries, + delimiter, + enclosure, + escape, + header, + notify, + }) => + await ( + await getMigrationsClient() + ).createCSVExport( + resourceId, + filename, + columns, + queries, + delimiter, + enclosure, + escape, + header, + notify, + ), + ), + ); + +migrations + .command(`create-csvimport`) + .description( + `Import documents from a CSV file into your Appwrite database. This endpoint allows you to import documents from a CSV file uploaded to Appwrite Storage bucket.`, + ) + .requiredOption( + `--bucket-id <bucket-id>`, + `Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](https://appwrite.io/docs/server/storage#createBucket).`, + ) + .requiredOption(`--file-id <file-id>`, `File ID.`) + .requiredOption( + `--resource-id <resource-id>`, + `Composite ID in the format {databaseId:collectionId}, identifying a collection within a database.`, + ) + .option( + `--internal-file [value]`, + `Is the file stored in an internal bucket?`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .action( + actionRunner( + async ({ bucketId, fileId, resourceId, internalFile }) => + await ( + await getMigrationsClient() + ).createCSVImport(bucketId, fileId, resourceId, internalFile), + ), + ); + +migrations + .command(`create-firebase-migration`) + .description( + `Migrate data from a Firebase project to your Appwrite project. This endpoint allows you to migrate resources like authentication and other supported services from a Firebase project. `, + ) + .requiredOption(`--resources [resources...]`, `List of resources to migrate`) + .requiredOption( + `--service-account <service-account>`, + `JSON of the Firebase service account credentials`, + ) + .action( + actionRunner( + async ({ resources, serviceAccount }) => + await ( + await getMigrationsClient() + ).createFirebaseMigration(resources, serviceAccount), + ), + ); + +migrations + .command(`get-firebase-report`) + .description( + `Generate a report of the data in a Firebase project before migrating. This endpoint analyzes the source project and returns information about the resources that can be migrated.`, + ) + .requiredOption(`--resources [resources...]`, `List of resources to migrate`) + .requiredOption( + `--service-account <service-account>`, + `JSON of the Firebase service account credentials`, + ) + .action( + actionRunner( + async ({ resources, serviceAccount }) => + await ( + await getMigrationsClient() + ).getFirebaseReport(resources, serviceAccount), + ), + ); + +migrations + .command(`create-nhost-migration`) + .description( + `Migrate data from an NHost project to your Appwrite project. This endpoint allows you to migrate resources like authentication, databases, and other supported services from an NHost project. `, + ) + .requiredOption(`--resources [resources...]`, `List of resources to migrate`) + .requiredOption(`--subdomain <subdomain>`, `Source's Subdomain`) + .requiredOption(`--region <region>`, `Source's Region`) + .requiredOption(`--admin-secret <admin-secret>`, `Source's Admin Secret`) + .requiredOption(`--database <database>`, `Source's Database Name`) + .requiredOption(`--username <username>`, `Source's Database Username`) + .requiredOption(`--password <password>`, `Source's Database Password`) + .option(`--port <port>`, `Source's Database Port`, parseInteger) + .action( + actionRunner( + async ({ + resources, + subdomain, + region, + adminSecret, + database, + username, + password, + port, + }) => + await ( + await getMigrationsClient() + ).createNHostMigration( + resources, + subdomain, + region, + adminSecret, + database, + username, + password, + port, + ), + ), + ); + +migrations + .command(`get-nhost-report`) + .description( + `Generate a detailed report of the data in an NHost project before migrating. This endpoint analyzes the source project and returns information about the resources that can be migrated. `, + ) + .requiredOption(`--resources [resources...]`, `List of resources to migrate.`) + .requiredOption(`--subdomain <subdomain>`, `Source's Subdomain.`) + .requiredOption(`--region <region>`, `Source's Region.`) + .requiredOption(`--admin-secret <admin-secret>`, `Source's Admin Secret.`) + .requiredOption(`--database <database>`, `Source's Database Name.`) + .requiredOption(`--username <username>`, `Source's Database Username.`) + .requiredOption(`--password <password>`, `Source's Database Password.`) + .option(`--port <port>`, `Source's Database Port.`, parseInteger) + .action( + actionRunner( + async ({ + resources, + subdomain, + region, + adminSecret, + database, + username, + password, + port, + }) => + await ( + await getMigrationsClient() + ).getNHostReport( + resources, + subdomain, + region, + adminSecret, + database, + username, + password, + port, + ), + ), + ); + +migrations + .command(`create-supabase-migration`) + .description( + `Migrate data from a Supabase project to your Appwrite project. This endpoint allows you to migrate resources like authentication, databases, and other supported services from a Supabase project. `, + ) + .requiredOption(`--resources [resources...]`, `List of resources to migrate`) + .requiredOption(`--endpoint <endpoint>`, `Source's Supabase Endpoint`) + .requiredOption(`--api-key <api-key>`, `Source's API Key`) + .requiredOption(`--database-host <database-host>`, `Source's Database Host`) + .requiredOption(`--username <username>`, `Source's Database Username`) + .requiredOption(`--password <password>`, `Source's Database Password`) + .option(`--port <port>`, `Source's Database Port`, parseInteger) + .action( + actionRunner( + async ({ + resources, + endpoint, + apiKey, + databaseHost, + username, + password, + port, + }) => + await ( + await getMigrationsClient() + ).createSupabaseMigration( + resources, + endpoint, + apiKey, + databaseHost, + username, + password, + port, + ), + ), + ); + +migrations + .command(`get-supabase-report`) + .description( + `Generate a report of the data in a Supabase project before migrating. This endpoint analyzes the source project and returns information about the resources that can be migrated. `, + ) + .requiredOption(`--resources [resources...]`, `List of resources to migrate`) + .requiredOption(`--endpoint <endpoint>`, `Source's Supabase Endpoint.`) + .requiredOption(`--api-key <api-key>`, `Source's API Key.`) + .requiredOption(`--database-host <database-host>`, `Source's Database Host.`) + .requiredOption(`--username <username>`, `Source's Database Username.`) + .requiredOption(`--password <password>`, `Source's Database Password.`) + .option(`--port <port>`, `Source's Database Port.`, parseInteger) + .action( + actionRunner( + async ({ + resources, + endpoint, + apiKey, + databaseHost, + username, + password, + port, + }) => + await ( + await getMigrationsClient() + ).getSupabaseReport( + resources, + endpoint, + apiKey, + databaseHost, + username, + password, + port, + ), + ), + ); + +migrations + .command(`get`) + .description( + `Get a migration by its unique ID. This endpoint returns detailed information about a specific migration including its current status, progress, and any errors that occurred during the migration process. `, + ) + .requiredOption(`--migration-id <migration-id>`, `Migration unique ID.`) + .action( + actionRunner( + async ({ migrationId }) => + await (await getMigrationsClient()).get(migrationId), + ), + ); + +migrations + .command(`retry`) + .description( + `Retry a failed migration. This endpoint allows you to retry a migration that has previously failed.`, + ) + .requiredOption(`--migration-id <migration-id>`, `Migration unique ID.`) + .action( + actionRunner( + async ({ migrationId }) => + await (await getMigrationsClient()).retry(migrationId), + ), + ); + +migrations + .command(`delete`) + .description( + `Delete a migration by its unique ID. This endpoint allows you to remove a migration from your project's migration history. `, + ) + .requiredOption(`--migration-id <migration-id>`, `Migration ID.`) + .action( + actionRunner( + async ({ migrationId }) => + await (await getMigrationsClient()).delete(migrationId), + ), + ); diff --git a/lib/commands/services/project.ts b/lib/commands/services/project.ts new file mode 100644 index 00000000..12a3233a --- /dev/null +++ b/lib/commands/services/project.ts @@ -0,0 +1,116 @@ +import { Command } from "commander"; +import { sdkForProject } from "../../sdks.js"; +import { + actionRunner, + commandDescriptions, + parseBool, + parseInteger, +} from "../../parser.js"; +import { Project, ProjectUsageRange } from "@appwrite.io/console"; + +let projectClient: Project | null = null; + +const getProjectClient = async (): Promise<Project> => { + if (!projectClient) { + const sdkClient = await sdkForProject(); + projectClient = new Project(sdkClient); + } + return projectClient; +}; + +export const project = new Command("project") + .description(commandDescriptions["project"] ?? "") + .configureHelp({ + helpWidth: process.stdout.columns || 80, + }); + +project + .command(`get-usage`) + .description( + `Get comprehensive usage statistics for your project. View metrics including network requests, bandwidth, storage, function executions, database usage, and user activity. Specify a time range with startDate and endDate, and optionally set the data granularity with period (1h or 1d). The response includes both total counts and detailed breakdowns by resource, along with historical data over the specified period.`, + ) + .requiredOption(`--start-date <start-date>`, `Starting date for the usage`) + .requiredOption(`--end-date <end-date>`, `End date for the usage`) + .option(`--period <period>`, `Period used`) + .action( + actionRunner( + async ({ startDate, endDate, period }) => + await ( + await getProjectClient() + ).getUsage(startDate, endDate, period as ProjectUsageRange), + ), + ); + +project + .command(`list-variables`) + .description( + `Get a list of all project variables. These variables will be accessible in all Appwrite Functions at runtime.`, + ) + .action( + actionRunner(async () => await (await getProjectClient()).listVariables()), + ); + +project + .command(`create-variable`) + .description( + `Create a new project variable. This variable will be accessible in all Appwrite Functions at runtime.`, + ) + .requiredOption(`--key <key>`, `Variable key. Max length: 255 chars.`) + .requiredOption(`--value <value>`, `Variable value. Max length: 8192 chars.`) + .option( + `--secret [value]`, + `Secret variables can be updated or deleted, but only projects can read them during build and runtime.`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .action( + actionRunner( + async ({ key, value, secret }) => + await (await getProjectClient()).createVariable(key, value, secret), + ), + ); + +project + .command(`get-variable`) + .description(`Get a project variable by its unique ID.`) + .requiredOption(`--variable-id <variable-id>`, `Variable unique ID.`) + .action( + actionRunner( + async ({ variableId }) => + await (await getProjectClient()).getVariable(variableId), + ), + ); + +project + .command(`update-variable`) + .description( + `Update project variable by its unique ID. This variable will be accessible in all Appwrite Functions at runtime.`, + ) + .requiredOption(`--variable-id <variable-id>`, `Variable unique ID.`) + .requiredOption(`--key <key>`, `Variable key. Max length: 255 chars.`) + .option(`--value <value>`, `Variable value. Max length: 8192 chars.`) + .option( + `--secret [value]`, + `Secret variables can be updated or deleted, but only projects can read them during build and runtime.`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .action( + actionRunner( + async ({ variableId, key, value, secret }) => + await ( + await getProjectClient() + ).updateVariable(variableId, key, value, secret), + ), + ); + +project + .command(`delete-variable`) + .description(`Delete a project variable by its unique ID. `) + .requiredOption(`--variable-id <variable-id>`, `Variable unique ID.`) + .action( + actionRunner( + async ({ variableId }) => + await (await getProjectClient()).deleteVariable(variableId), + ), + ); diff --git a/lib/commands/services/projects.ts b/lib/commands/services/projects.ts new file mode 100644 index 00000000..297cf4b2 --- /dev/null +++ b/lib/commands/services/projects.ts @@ -0,0 +1,1317 @@ +import { Command } from "commander"; +import { sdkForProject } from "../../sdks.js"; +import { + actionRunner, + commandDescriptions, + parseBool, + parseInteger, +} from "../../parser.js"; +import { + Projects, + AuthMethod, + OAuthProvider, + PlatformType, + ApiService, + SMTPSecure, + EmailTemplateType, + EmailTemplateLocale, + SmsTemplateType, + SmsTemplateLocale, +} from "@appwrite.io/console"; + +let projectsClient: Projects | null = null; + +const getProjectsClient = async (): Promise<Projects> => { + if (!projectsClient) { + const sdkClient = await sdkForProject(); + projectsClient = new Projects(sdkClient); + } + return projectsClient; +}; + +export const projects = new Command("projects") + .description(commandDescriptions["projects"] ?? "") + .configureHelp({ + helpWidth: process.stdout.columns || 80, + }); + +projects + .command(`list`) + .description( + `Get a list of all projects. You can use the query params to filter your results. `, + ) + .option( + `--queries [queries...]`, + `Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: name, teamId`, + ) + .option( + `--search <search>`, + `Search term to filter your list results. Max length: 256 chars.`, + ) + .option( + `--total [value]`, + `When set to false, the total count returned will be 0 and will not be calculated.`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .action( + actionRunner( + async ({ queries, search, total }) => + await (await getProjectsClient()).list(queries, search, total), + ), + ); + +projects + .command(`create`) + .description( + `Create a new project. You can create a maximum of 100 projects per account. `, + ) + .requiredOption( + `--project-id <project-id>`, + `Unique Id. Choose a custom ID or generate a random ID with \`ID.unique()\`. Valid chars are a-z, and hyphen. Can't start with a special char. Max length is 36 chars.`, + ) + .requiredOption(`--name <name>`, `Project name. Max length: 128 chars.`) + .requiredOption(`--team-id <team-id>`, `Team unique ID.`) + .option(`--region <region>`, `Project Region.`) + .option( + `--description <description>`, + `Project description. Max length: 256 chars.`, + ) + .option(`--logo <logo>`, `Project logo.`) + .option(`--url <url>`, `Project URL.`) + .option( + `--legal-name <legal-name>`, + `Project legal Name. Max length: 256 chars.`, + ) + .option( + `--legal-country <legal-country>`, + `Project legal Country. Max length: 256 chars.`, + ) + .option( + `--legal-state <legal-state>`, + `Project legal State. Max length: 256 chars.`, + ) + .option( + `--legal-city <legal-city>`, + `Project legal City. Max length: 256 chars.`, + ) + .option( + `--legal-address <legal-address>`, + `Project legal Address. Max length: 256 chars.`, + ) + .option( + `--legal-tax-id <legal-tax-id>`, + `Project legal Tax ID. Max length: 256 chars.`, + ) + .action( + actionRunner( + async ({ + projectId, + name, + teamId, + region, + description, + logo, + url, + legalName, + legalCountry, + legalState, + legalCity, + legalAddress, + legalTaxId, + }) => + await ( + await getProjectsClient() + ).create( + projectId, + name, + teamId, + region, + description, + logo, + url, + legalName, + legalCountry, + legalState, + legalCity, + legalAddress, + legalTaxId, + ), + ), + ); + +projects + .command(`get`) + .description( + `Get a project by its unique ID. This endpoint allows you to retrieve the project's details, including its name, description, team, region, and other metadata. `, + ) + .requiredOption(`--project-id <project-id>`, `Project unique ID.`) + .action( + actionRunner( + async ({ projectId }) => await (await getProjectsClient()).get(projectId), + ), + ); + +projects + .command(`update`) + .description(`Update a project by its unique ID.`) + .requiredOption(`--project-id <project-id>`, `Project unique ID.`) + .requiredOption(`--name <name>`, `Project name. Max length: 128 chars.`) + .option( + `--description <description>`, + `Project description. Max length: 256 chars.`, + ) + .option(`--logo <logo>`, `Project logo.`) + .option(`--url <url>`, `Project URL.`) + .option( + `--legal-name <legal-name>`, + `Project legal name. Max length: 256 chars.`, + ) + .option( + `--legal-country <legal-country>`, + `Project legal country. Max length: 256 chars.`, + ) + .option( + `--legal-state <legal-state>`, + `Project legal state. Max length: 256 chars.`, + ) + .option( + `--legal-city <legal-city>`, + `Project legal city. Max length: 256 chars.`, + ) + .option( + `--legal-address <legal-address>`, + `Project legal address. Max length: 256 chars.`, + ) + .option( + `--legal-tax-id <legal-tax-id>`, + `Project legal tax ID. Max length: 256 chars.`, + ) + .action( + actionRunner( + async ({ + projectId, + name, + description, + logo, + url, + legalName, + legalCountry, + legalState, + legalCity, + legalAddress, + legalTaxId, + }) => + await ( + await getProjectsClient() + ).update( + projectId, + name, + description, + logo, + url, + legalName, + legalCountry, + legalState, + legalCity, + legalAddress, + legalTaxId, + ), + ), + ); + +projects + .command(`delete`) + .description(`Delete a project by its unique ID.`) + .requiredOption(`--project-id <project-id>`, `Project unique ID.`) + .action( + actionRunner( + async ({ projectId }) => + await (await getProjectsClient()).delete(projectId), + ), + ); + +projects + .command(`update-api-status`) + .description( + `[**DEPRECATED** - This command is deprecated. Please use 'projects updateApiStatus' instead] Update the status of a specific API type. Use this endpoint to enable or disable API types such as REST, GraphQL and Realtime.`, + ) + .requiredOption(`--project-id <project-id>`, `Project unique ID.`) + .requiredOption(`--api <api>`, `API name.`) + .requiredOption(`--status <status>`, `API status.`, parseBool) + .action( + actionRunner( + async ({ projectId, api, status }) => + await ( + await getProjectsClient() + ).updateApiStatus(projectId, api, status), + ), + ); + +projects + .command(`update-api-status-all`) + .description( + `[**DEPRECATED** - This command is deprecated. Please use 'projects updateApiStatusAll' instead] Update the status of all API types. Use this endpoint to enable or disable API types such as REST, GraphQL and Realtime all at once.`, + ) + .requiredOption(`--project-id <project-id>`, `Project unique ID.`) + .requiredOption(`--status <status>`, `API status.`, parseBool) + .action( + actionRunner( + async ({ projectId, status }) => + await (await getProjectsClient()).updateApiStatusAll(projectId, status), + ), + ); + +projects + .command(`update-auth-duration`) + .description( + `Update how long sessions created within a project should stay active for.`, + ) + .requiredOption(`--project-id <project-id>`, `Project unique ID.`) + .requiredOption( + `--duration <duration>`, + `Project session length in seconds. Max length: 31536000 seconds.`, + parseInteger, + ) + .action( + actionRunner( + async ({ projectId, duration }) => + await ( + await getProjectsClient() + ).updateAuthDuration(projectId, duration), + ), + ); + +projects + .command(`update-auth-limit`) + .description( + `Update the maximum number of users allowed in this project. Set to 0 for unlimited users. `, + ) + .requiredOption(`--project-id <project-id>`, `Project unique ID.`) + .requiredOption( + `--limit <limit>`, + `Set the max number of users allowed in this project. Use 0 for unlimited.`, + parseInteger, + ) + .action( + actionRunner( + async ({ projectId, limit }) => + await (await getProjectsClient()).updateAuthLimit(projectId, limit), + ), + ); + +projects + .command(`update-auth-sessions-limit`) + .description( + `Update the maximum number of sessions allowed per user within the project, if the limit is hit the oldest session will be deleted to make room for new sessions.`, + ) + .requiredOption(`--project-id <project-id>`, `Project unique ID.`) + .requiredOption( + `--limit <limit>`, + `Set the max number of users allowed in this project. Value allowed is between 1-100. Default is 10`, + parseInteger, + ) + .action( + actionRunner( + async ({ projectId, limit }) => + await ( + await getProjectsClient() + ).updateAuthSessionsLimit(projectId, limit), + ), + ); + +projects + .command(`update-memberships-privacy`) + .description( + `Update project membership privacy settings. Use this endpoint to control what user information is visible to other team members, such as user name, email, and MFA status. `, + ) + .requiredOption(`--project-id <project-id>`, `Project unique ID.`) + .requiredOption( + `--user-name <user-name>`, + `Set to true to show userName to members of a team.`, + parseBool, + ) + .requiredOption( + `--user-email <user-email>`, + `Set to true to show email to members of a team.`, + parseBool, + ) + .requiredOption( + `--mfa <mfa>`, + `Set to true to show mfa to members of a team.`, + parseBool, + ) + .action( + actionRunner( + async ({ projectId, userName, userEmail, mfa }) => + await ( + await getProjectsClient() + ).updateMembershipsPrivacy(projectId, userName, userEmail, mfa), + ), + ); + +projects + .command(`update-mock-numbers`) + .description( + `Update the list of mock phone numbers for testing. Use these numbers to bypass SMS verification in development. `, + ) + .requiredOption(`--project-id <project-id>`, `Project unique ID.`) + .requiredOption( + `--numbers [numbers...]`, + `An array of mock numbers and their corresponding verification codes (OTPs). Each number should be a valid E.164 formatted phone number. Maximum of 10 numbers are allowed.`, + ) + .action( + actionRunner( + async ({ projectId, numbers }) => + await (await getProjectsClient()).updateMockNumbers(projectId, numbers), + ), + ); + +projects + .command(`update-auth-password-dictionary`) + .description( + `Enable or disable checking user passwords against common passwords dictionary. This helps ensure users don't use common and insecure passwords. `, + ) + .requiredOption(`--project-id <project-id>`, `Project unique ID.`) + .requiredOption( + `--enabled <enabled>`, + `Set whether or not to enable checking user's password against most commonly used passwords. Default is false.`, + parseBool, + ) + .action( + actionRunner( + async ({ projectId, enabled }) => + await ( + await getProjectsClient() + ).updateAuthPasswordDictionary(projectId, enabled), + ), + ); + +projects + .command(`update-auth-password-history`) + .description( + `Update the authentication password history requirement. Use this endpoint to require new passwords to be different than the last X amount of previously used ones.`, + ) + .requiredOption(`--project-id <project-id>`, `Project unique ID.`) + .requiredOption( + `--limit <limit>`, + `Set the max number of passwords to store in user history. User can't choose a new password that is already stored in the password history list. Max number of passwords allowed in history is20. Default value is 0`, + parseInteger, + ) + .action( + actionRunner( + async ({ projectId, limit }) => + await ( + await getProjectsClient() + ).updateAuthPasswordHistory(projectId, limit), + ), + ); + +projects + .command(`update-personal-data-check`) + .description( + `Enable or disable checking user passwords against their personal data. This helps prevent users from using personal information in their passwords. `, + ) + .requiredOption(`--project-id <project-id>`, `Project unique ID.`) + .requiredOption( + `--enabled <enabled>`, + `Set whether or not to check a password for similarity with personal data. Default is false.`, + parseBool, + ) + .action( + actionRunner( + async ({ projectId, enabled }) => + await ( + await getProjectsClient() + ).updatePersonalDataCheck(projectId, enabled), + ), + ); + +projects + .command(`update-session-alerts`) + .description( + `Enable or disable session email alerts. When enabled, users will receive email notifications when new sessions are created.`, + ) + .requiredOption(`--project-id <project-id>`, `Project unique ID.`) + .requiredOption( + `--alerts <alerts>`, + `Set to true to enable session emails.`, + parseBool, + ) + .action( + actionRunner( + async ({ projectId, alerts }) => + await ( + await getProjectsClient() + ).updateSessionAlerts(projectId, alerts), + ), + ); + +projects + .command(`update-session-invalidation`) + .description( + `Invalidate all existing sessions. An optional auth security setting for projects, and enabled by default for console project.`, + ) + .requiredOption(`--project-id <project-id>`, `Project unique ID.`) + .requiredOption( + `--enabled <enabled>`, + `Update authentication session invalidation status. Use this endpoint to enable or disable session invalidation on password change`, + parseBool, + ) + .action( + actionRunner( + async ({ projectId, enabled }) => + await ( + await getProjectsClient() + ).updateSessionInvalidation(projectId, enabled), + ), + ); + +projects + .command(`update-auth-status`) + .description( + `Update the status of a specific authentication method. Use this endpoint to enable or disable different authentication methods such as email, magic urls or sms in your project. `, + ) + .requiredOption(`--project-id <project-id>`, `Project unique ID.`) + .requiredOption( + `--method <method>`, + `Auth Method. Possible values: email-password,magic-url,email-otp,anonymous,invites,jwt,phone`, + ) + .requiredOption( + `--status <status>`, + `Set the status of this auth method.`, + parseBool, + ) + .action( + actionRunner( + async ({ projectId, method, status }) => + await ( + await getProjectsClient() + ).updateAuthStatus(projectId, method as AuthMethod, status), + ), + ); + +projects + .command(`list-dev-keys`) + .description( + `List all the project\'s dev keys. Dev keys are project specific and allow you to bypass rate limits and get better error logging during development.'`, + ) + .requiredOption(`--project-id <project-id>`, `Project unique ID.`) + .option( + `--queries [queries...]`, + `Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: accessedAt, expire`, + ) + .action( + actionRunner( + async ({ projectId, queries }) => + await (await getProjectsClient()).listDevKeys(projectId, queries), + ), + ); + +projects + .command(`create-dev-key`) + .description( + `Create a new project dev key. Dev keys are project specific and allow you to bypass rate limits and get better error logging during development. Strictly meant for development purposes only.`, + ) + .requiredOption(`--project-id <project-id>`, `Project unique ID.`) + .requiredOption(`--name <name>`, `Key name. Max length: 128 chars.`) + .requiredOption( + `--expire <expire>`, + `Expiration time in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format.`, + ) + .action( + actionRunner( + async ({ projectId, name, expire }) => + await (await getProjectsClient()).createDevKey(projectId, name, expire), + ), + ); + +projects + .command(`get-dev-key`) + .description( + `Get a project\'s dev key by its unique ID. Dev keys are project specific and allow you to bypass rate limits and get better error logging during development.`, + ) + .requiredOption(`--project-id <project-id>`, `Project unique ID.`) + .requiredOption(`--key-id <key-id>`, `Key unique ID.`) + .action( + actionRunner( + async ({ projectId, keyId }) => + await (await getProjectsClient()).getDevKey(projectId, keyId), + ), + ); + +projects + .command(`update-dev-key`) + .description( + `Update a project\'s dev key by its unique ID. Use this endpoint to update a project\'s dev key name or expiration time.'`, + ) + .requiredOption(`--project-id <project-id>`, `Project unique ID.`) + .requiredOption(`--key-id <key-id>`, `Key unique ID.`) + .requiredOption(`--name <name>`, `Key name. Max length: 128 chars.`) + .requiredOption( + `--expire <expire>`, + `Expiration time in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format.`, + ) + .action( + actionRunner( + async ({ projectId, keyId, name, expire }) => + await ( + await getProjectsClient() + ).updateDevKey(projectId, keyId, name, expire), + ), + ); + +projects + .command(`delete-dev-key`) + .description( + `Delete a project\'s dev key by its unique ID. Once deleted, the key will no longer allow bypassing of rate limits and better logging of errors.`, + ) + .requiredOption(`--project-id <project-id>`, `Project unique ID.`) + .requiredOption(`--key-id <key-id>`, `Key unique ID.`) + .action( + actionRunner( + async ({ projectId, keyId }) => + await (await getProjectsClient()).deleteDevKey(projectId, keyId), + ), + ); + +projects + .command(`create-jwt`) + .description( + `Create a new JWT token. This token can be used to authenticate users with custom scopes and expiration time. `, + ) + .requiredOption(`--project-id <project-id>`, `Project unique ID.`) + .requiredOption( + `--scopes [scopes...]`, + `List of scopes allowed for JWT key. Maximum of 100 scopes are allowed.`, + ) + .option( + `--duration <duration>`, + `Time in seconds before JWT expires. Default duration is 900 seconds, and maximum is 3600 seconds.`, + parseInteger, + ) + .action( + actionRunner( + async ({ projectId, scopes, duration }) => + await ( + await getProjectsClient() + ).createJWT(projectId, scopes, duration), + ), + ); + +projects + .command(`list-keys`) + .description(`Get a list of all API keys from the current project. `) + .requiredOption(`--project-id <project-id>`, `Project unique ID.`) + .option( + `--total [value]`, + `When set to false, the total count returned will be 0 and will not be calculated.`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .action( + actionRunner( + async ({ projectId, total }) => + await (await getProjectsClient()).listKeys(projectId, total), + ), + ); + +projects + .command(`create-key`) + .description( + `Create a new API key. It's recommended to have multiple API keys with strict scopes for separate functions within your project.`, + ) + .requiredOption(`--project-id <project-id>`, `Project unique ID.`) + .requiredOption(`--name <name>`, `Key name. Max length: 128 chars.`) + .requiredOption( + `--scopes [scopes...]`, + `Key scopes list. Maximum of 100 scopes are allowed.`, + ) + .option( + `--expire <expire>`, + `Expiration time in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format. Use null for unlimited expiration.`, + ) + .action( + actionRunner( + async ({ projectId, name, scopes, expire }) => + await ( + await getProjectsClient() + ).createKey(projectId, name, scopes, expire), + ), + ); + +projects + .command(`get-key`) + .description( + `Get a key by its unique ID. This endpoint returns details about a specific API key in your project including it's scopes.`, + ) + .requiredOption(`--project-id <project-id>`, `Project unique ID.`) + .requiredOption(`--key-id <key-id>`, `Key unique ID.`) + .action( + actionRunner( + async ({ projectId, keyId }) => + await (await getProjectsClient()).getKey(projectId, keyId), + ), + ); + +projects + .command(`update-key`) + .description( + `Update a key by its unique ID. Use this endpoint to update the name, scopes, or expiration time of an API key. `, + ) + .requiredOption(`--project-id <project-id>`, `Project unique ID.`) + .requiredOption(`--key-id <key-id>`, `Key unique ID.`) + .requiredOption(`--name <name>`, `Key name. Max length: 128 chars.`) + .requiredOption( + `--scopes [scopes...]`, + `Key scopes list. Maximum of 100 events are allowed.`, + ) + .option( + `--expire <expire>`, + `Expiration time in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format. Use null for unlimited expiration.`, + ) + .action( + actionRunner( + async ({ projectId, keyId, name, scopes, expire }) => + await ( + await getProjectsClient() + ).updateKey(projectId, keyId, name, scopes, expire), + ), + ); + +projects + .command(`delete-key`) + .description( + `Delete a key by its unique ID. Once deleted, the key can no longer be used to authenticate API calls. `, + ) + .requiredOption(`--project-id <project-id>`, `Project unique ID.`) + .requiredOption(`--key-id <key-id>`, `Key unique ID.`) + .action( + actionRunner( + async ({ projectId, keyId }) => + await (await getProjectsClient()).deleteKey(projectId, keyId), + ), + ); + +projects + .command(`update-oauth2`) + .description( + `Update the OAuth2 provider configurations. Use this endpoint to set up or update the OAuth2 provider credentials or enable/disable providers. `, + ) + .requiredOption(`--project-id <project-id>`, `Project unique ID.`) + .requiredOption(`--provider <provider>`, `Provider Name`) + .option(`--app-id <app-id>`, `Provider app ID. Max length: 256 chars.`) + .option(`--secret <secret>`, `Provider secret key. Max length: 512 chars.`) + .option( + `--enabled [value]`, + `Provider status. Set to 'false' to disable new session creation.`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .action( + actionRunner( + async ({ projectId, provider, appId, secret, enabled }) => + await ( + await getProjectsClient() + ).updateOAuth2( + projectId, + provider as OAuthProvider, + appId, + secret, + enabled, + ), + ), + ); + +projects + .command(`list-platforms`) + .description( + `Get a list of all platforms in the project. This endpoint returns an array of all platforms and their configurations. `, + ) + .requiredOption(`--project-id <project-id>`, `Project unique ID.`) + .option( + `--total [value]`, + `When set to false, the total count returned will be 0 and will not be calculated.`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .action( + actionRunner( + async ({ projectId, total }) => + await (await getProjectsClient()).listPlatforms(projectId, total), + ), + ); + +projects + .command(`create-platform`) + .description( + `Create a new platform for your project. Use this endpoint to register a new platform where your users will run your application which will interact with the Appwrite API.`, + ) + .requiredOption(`--project-id <project-id>`, `Project unique ID.`) + .requiredOption( + `--type <type>`, + `Platform type. Possible values are: web, flutter-web, flutter-ios, flutter-android, flutter-linux, flutter-macos, flutter-windows, apple-ios, apple-macos, apple-watchos, apple-tvos, android, unity, react-native-ios, react-native-android.`, + ) + .requiredOption(`--name <name>`, `Platform name. Max length: 128 chars.`) + .option( + `--key <key>`, + `Package name for Android or bundle ID for iOS or macOS. Max length: 256 chars.`, + ) + .option( + `--store <store>`, + `App store or Google Play store ID. Max length: 256 chars.`, + ) + .option( + `--hostname <hostname>`, + `Platform client hostname. Max length: 256 chars.`, + ) + .action( + actionRunner( + async ({ projectId, xType, name, key, store, hostname }) => + await ( + await getProjectsClient() + ).createPlatform( + projectId, + xType as PlatformType, + name, + key, + store, + hostname, + ), + ), + ); + +projects + .command(`get-platform`) + .description( + `Get a platform by its unique ID. This endpoint returns the platform's details, including its name, type, and key configurations. `, + ) + .requiredOption(`--project-id <project-id>`, `Project unique ID.`) + .requiredOption(`--platform-id <platform-id>`, `Platform unique ID.`) + .action( + actionRunner( + async ({ projectId, platformId }) => + await (await getProjectsClient()).getPlatform(projectId, platformId), + ), + ); + +projects + .command(`update-platform`) + .description( + `Update a platform by its unique ID. Use this endpoint to update the platform's name, key, platform store ID, or hostname. `, + ) + .requiredOption(`--project-id <project-id>`, `Project unique ID.`) + .requiredOption(`--platform-id <platform-id>`, `Platform unique ID.`) + .requiredOption(`--name <name>`, `Platform name. Max length: 128 chars.`) + .option( + `--key <key>`, + `Package name for android or bundle ID for iOS. Max length: 256 chars.`, + ) + .option( + `--store <store>`, + `App store or Google Play store ID. Max length: 256 chars.`, + ) + .option( + `--hostname <hostname>`, + `Platform client URL. Max length: 256 chars.`, + ) + .action( + actionRunner( + async ({ projectId, platformId, name, key, store, hostname }) => + await ( + await getProjectsClient() + ).updatePlatform(projectId, platformId, name, key, store, hostname), + ), + ); + +projects + .command(`delete-platform`) + .description( + `Delete a platform by its unique ID. This endpoint removes the platform and all its configurations from the project. `, + ) + .requiredOption(`--project-id <project-id>`, `Project unique ID.`) + .requiredOption(`--platform-id <platform-id>`, `Platform unique ID.`) + .action( + actionRunner( + async ({ projectId, platformId }) => + await (await getProjectsClient()).deletePlatform(projectId, platformId), + ), + ); + +projects + .command(`update-service-status`) + .description( + `Update the status of a specific service. Use this endpoint to enable or disable a service in your project. `, + ) + .requiredOption(`--project-id <project-id>`, `Project unique ID.`) + .requiredOption(`--service <service>`, `Service name.`) + .requiredOption(`--status <status>`, `Service status.`, parseBool) + .action( + actionRunner( + async ({ projectId, service, status }) => + await ( + await getProjectsClient() + ).updateServiceStatus(projectId, service as ApiService, status), + ), + ); + +projects + .command(`update-service-status-all`) + .description( + `Update the status of all services. Use this endpoint to enable or disable all optional services at once. `, + ) + .requiredOption(`--project-id <project-id>`, `Project unique ID.`) + .requiredOption(`--status <status>`, `Service status.`, parseBool) + .action( + actionRunner( + async ({ projectId, status }) => + await ( + await getProjectsClient() + ).updateServiceStatusAll(projectId, status), + ), + ); + +projects + .command(`update-smtp`) + .description( + `[**DEPRECATED** - This command is deprecated. Please use 'projects updateSmtp' instead] Update the SMTP configuration for your project. Use this endpoint to configure your project's SMTP provider with your custom settings for sending transactional emails. `, + ) + .requiredOption(`--project-id <project-id>`, `Project unique ID.`) + .requiredOption( + `--enabled <enabled>`, + `Enable custom SMTP service`, + parseBool, + ) + .option(`--sender-name <sender-name>`, `Name of the email sender`) + .option(`--sender-email <sender-email>`, `Email of the sender`) + .option(`--reply-to <reply-to>`, `Reply to email`) + .option(`--host <host>`, `SMTP server host name`) + .option(`--port <port>`, `SMTP server port`, parseInteger) + .option(`--username <username>`, `SMTP server username`) + .option(`--password <password>`, `SMTP server password`) + .option(`--secure <secure>`, `Does SMTP server use secure connection`) + .action( + actionRunner( + async ({ + projectId, + enabled, + senderName, + senderEmail, + replyTo, + host, + port, + username, + password, + secure, + }) => + await ( + await getProjectsClient() + ).updateSmtp( + projectId, + enabled, + senderName, + senderEmail, + replyTo, + host, + port, + username, + password, + secure as SMTPSecure, + ), + ), + ); + +projects + .command(`create-smtp-test`) + .description( + `[**DEPRECATED** - This command is deprecated. Please use 'projects createSmtpTest' instead] Send a test email to verify SMTP configuration. `, + ) + .requiredOption(`--project-id <project-id>`, `Project unique ID.`) + .requiredOption( + `--emails [emails...]`, + `Array of emails to send test email to. Maximum of 10 emails are allowed.`, + ) + .requiredOption(`--sender-name <sender-name>`, `Name of the email sender`) + .requiredOption(`--sender-email <sender-email>`, `Email of the sender`) + .option(`--reply-to <reply-to>`, `Reply to email`) + .requiredOption(`--host <host>`, `SMTP server host name`) + .option(`--port <port>`, `SMTP server port`, parseInteger) + .option(`--username <username>`, `SMTP server username`) + .option(`--password <password>`, `SMTP server password`) + .option(`--secure <secure>`, `Does SMTP server use secure connection`) + .action( + actionRunner( + async ({ + projectId, + emails, + senderName, + senderEmail, + replyTo, + host, + port, + username, + password, + secure, + }) => + await ( + await getProjectsClient() + ).createSmtpTest( + projectId, + emails, + senderName, + senderEmail, + replyTo, + host, + port, + username, + password, + secure as SMTPSecure, + ), + ), + ); + +projects + .command(`update-team`) + .description( + `Update the team ID of a project allowing for it to be transferred to another team.`, + ) + .requiredOption(`--project-id <project-id>`, `Project unique ID.`) + .requiredOption( + `--team-id <team-id>`, + `Team ID of the team to transfer project to.`, + ) + .action( + actionRunner( + async ({ projectId, teamId }) => + await (await getProjectsClient()).updateTeam(projectId, teamId), + ), + ); + +projects + .command(`get-email-template`) + .description( + `Get a custom email template for the specified locale and type. This endpoint returns the template content, subject, and other configuration details. `, + ) + .requiredOption(`--project-id <project-id>`, `Project unique ID.`) + .requiredOption(`--type <type>`, `Template type`) + .requiredOption(`--locale <locale>`, `Template locale`) + .action( + actionRunner( + async ({ projectId, xType, locale }) => + await ( + await getProjectsClient() + ).getEmailTemplate( + projectId, + xType as EmailTemplateType, + locale as EmailTemplateLocale, + ), + ), + ); + +projects + .command(`update-email-template`) + .description( + `Update a custom email template for the specified locale and type. Use this endpoint to modify the content of your email templates.`, + ) + .requiredOption(`--project-id <project-id>`, `Project unique ID.`) + .requiredOption(`--type <type>`, `Template type`) + .requiredOption(`--locale <locale>`, `Template locale`) + .requiredOption(`--subject <subject>`, `Email Subject`) + .requiredOption(`--message <message>`, `Template message`) + .option(`--sender-name <sender-name>`, `Name of the email sender`) + .option(`--sender-email <sender-email>`, `Email of the sender`) + .option(`--reply-to <reply-to>`, `Reply to email`) + .action( + actionRunner( + async ({ + projectId, + xType, + locale, + subject, + message, + senderName, + senderEmail, + replyTo, + }) => + await ( + await getProjectsClient() + ).updateEmailTemplate( + projectId, + xType as EmailTemplateType, + locale as EmailTemplateLocale, + subject, + message, + senderName, + senderEmail, + replyTo, + ), + ), + ); + +projects + .command(`delete-email-template`) + .description( + `Reset a custom email template to its default value. This endpoint removes any custom content and restores the template to its original state. `, + ) + .requiredOption(`--project-id <project-id>`, `Project unique ID.`) + .requiredOption(`--type <type>`, `Template type`) + .requiredOption(`--locale <locale>`, `Template locale`) + .action( + actionRunner( + async ({ projectId, xType, locale }) => + await ( + await getProjectsClient() + ).deleteEmailTemplate( + projectId, + xType as EmailTemplateType, + locale as EmailTemplateLocale, + ), + ), + ); + +projects + .command(`get-sms-template`) + .description( + `[**DEPRECATED** - This command is deprecated. Please use 'projects getSmsTemplate' instead] Get a custom SMS template for the specified locale and type returning it's contents.`, + ) + .requiredOption(`--project-id <project-id>`, `Project unique ID.`) + .requiredOption(`--type <type>`, `Template type`) + .requiredOption(`--locale <locale>`, `Template locale`) + .action( + actionRunner( + async ({ projectId, xType, locale }) => + await ( + await getProjectsClient() + ).getSmsTemplate( + projectId, + xType as SmsTemplateType, + locale as SmsTemplateLocale, + ), + ), + ); + +projects + .command(`update-sms-template`) + .description( + `[**DEPRECATED** - This command is deprecated. Please use 'projects updateSmsTemplate' instead] Update a custom SMS template for the specified locale and type. Use this endpoint to modify the content of your SMS templates. `, + ) + .requiredOption(`--project-id <project-id>`, `Project unique ID.`) + .requiredOption(`--type <type>`, `Template type`) + .requiredOption(`--locale <locale>`, `Template locale`) + .requiredOption(`--message <message>`, `Template message`) + .action( + actionRunner( + async ({ projectId, xType, locale, message }) => + await ( + await getProjectsClient() + ).updateSmsTemplate( + projectId, + xType as SmsTemplateType, + locale as SmsTemplateLocale, + message, + ), + ), + ); + +projects + .command(`delete-sms-template`) + .description( + `[**DEPRECATED** - This command is deprecated. Please use 'projects deleteSmsTemplate' instead] Reset a custom SMS template to its default value. This endpoint removes any custom message and restores the template to its original state. `, + ) + .requiredOption(`--project-id <project-id>`, `Project unique ID.`) + .requiredOption(`--type <type>`, `Template type`) + .requiredOption(`--locale <locale>`, `Template locale`) + .action( + actionRunner( + async ({ projectId, xType, locale }) => + await ( + await getProjectsClient() + ).deleteSmsTemplate( + projectId, + xType as SmsTemplateType, + locale as SmsTemplateLocale, + ), + ), + ); + +projects + .command(`list-webhooks`) + .description( + `Get a list of all webhooks belonging to the project. You can use the query params to filter your results. `, + ) + .requiredOption(`--project-id <project-id>`, `Project unique ID.`) + .option( + `--total [value]`, + `When set to false, the total count returned will be 0 and will not be calculated.`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .action( + actionRunner( + async ({ projectId, total }) => + await (await getProjectsClient()).listWebhooks(projectId, total), + ), + ); + +projects + .command(`create-webhook`) + .description( + `Create a new webhook. Use this endpoint to configure a URL that will receive events from Appwrite when specific events occur. `, + ) + .requiredOption(`--project-id <project-id>`, `Project unique ID.`) + .requiredOption(`--name <name>`, `Webhook name. Max length: 128 chars.`) + .option( + `--enabled [value]`, + `Enable or disable a webhook.`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .requiredOption( + `--events [events...]`, + `Events list. Maximum of 100 events are allowed.`, + ) + .requiredOption(`--url <url>`, `Webhook URL.`) + .requiredOption( + `--security <security>`, + `Certificate verification, false for disabled or true for enabled.`, + parseBool, + ) + .option( + `--http-user <http-user>`, + `Webhook HTTP user. Max length: 256 chars.`, + ) + .option( + `--http-pass <http-pass>`, + `Webhook HTTP password. Max length: 256 chars.`, + ) + .action( + actionRunner( + async ({ + projectId, + name, + enabled, + events, + url, + security, + httpUser, + httpPass, + }) => + await ( + await getProjectsClient() + ).createWebhook( + projectId, + name, + enabled, + events, + url, + security, + httpUser, + httpPass, + ), + ), + ); + +projects + .command(`get-webhook`) + .description( + `Get a webhook by its unique ID. This endpoint returns details about a specific webhook configured for a project. `, + ) + .requiredOption(`--project-id <project-id>`, `Project unique ID.`) + .requiredOption(`--webhook-id <webhook-id>`, `Webhook unique ID.`) + .action( + actionRunner( + async ({ projectId, webhookId }) => + await (await getProjectsClient()).getWebhook(projectId, webhookId), + ), + ); + +projects + .command(`update-webhook`) + .description( + `Update a webhook by its unique ID. Use this endpoint to update the URL, events, or status of an existing webhook. `, + ) + .requiredOption(`--project-id <project-id>`, `Project unique ID.`) + .requiredOption(`--webhook-id <webhook-id>`, `Webhook unique ID.`) + .requiredOption(`--name <name>`, `Webhook name. Max length: 128 chars.`) + .option( + `--enabled [value]`, + `Enable or disable a webhook.`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .requiredOption( + `--events [events...]`, + `Events list. Maximum of 100 events are allowed.`, + ) + .requiredOption(`--url <url>`, `Webhook URL.`) + .requiredOption( + `--security <security>`, + `Certificate verification, false for disabled or true for enabled.`, + parseBool, + ) + .option( + `--http-user <http-user>`, + `Webhook HTTP user. Max length: 256 chars.`, + ) + .option( + `--http-pass <http-pass>`, + `Webhook HTTP password. Max length: 256 chars.`, + ) + .action( + actionRunner( + async ({ + projectId, + webhookId, + name, + enabled, + events, + url, + security, + httpUser, + httpPass, + }) => + await ( + await getProjectsClient() + ).updateWebhook( + projectId, + webhookId, + name, + enabled, + events, + url, + security, + httpUser, + httpPass, + ), + ), + ); + +projects + .command(`delete-webhook`) + .description( + `Delete a webhook by its unique ID. Once deleted, the webhook will no longer receive project events. `, + ) + .requiredOption(`--project-id <project-id>`, `Project unique ID.`) + .requiredOption(`--webhook-id <webhook-id>`, `Webhook unique ID.`) + .action( + actionRunner( + async ({ projectId, webhookId }) => + await (await getProjectsClient()).deleteWebhook(projectId, webhookId), + ), + ); + +projects + .command(`update-webhook-signature`) + .description( + `Update the webhook signature key. This endpoint can be used to regenerate the signature key used to sign and validate payload deliveries for a specific webhook. `, + ) + .requiredOption(`--project-id <project-id>`, `Project unique ID.`) + .requiredOption(`--webhook-id <webhook-id>`, `Webhook unique ID.`) + .action( + actionRunner( + async ({ projectId, webhookId }) => + await ( + await getProjectsClient() + ).updateWebhookSignature(projectId, webhookId), + ), + ); diff --git a/lib/commands/services/proxy.ts b/lib/commands/services/proxy.ts new file mode 100644 index 00000000..37fa420e --- /dev/null +++ b/lib/commands/services/proxy.ts @@ -0,0 +1,163 @@ +import { Command } from "commander"; +import { sdkForProject } from "../../sdks.js"; +import { + actionRunner, + commandDescriptions, + parseBool, + parseInteger, +} from "../../parser.js"; +import { Proxy, ProxyResourceType } from "@appwrite.io/console"; + +let proxyClient: Proxy | null = null; + +const getProxyClient = async (): Promise<Proxy> => { + if (!proxyClient) { + const sdkClient = await sdkForProject(); + proxyClient = new Proxy(sdkClient); + } + return proxyClient; +}; + +export const proxy = new Command("proxy") + .description(commandDescriptions["proxy"] ?? "") + .configureHelp({ + helpWidth: process.stdout.columns || 80, + }); + +proxy + .command(`list-rules`) + .description( + `Get a list of all the proxy rules. You can use the query params to filter your results.`, + ) + .option( + `--queries [queries...]`, + `Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/databases#querying-documents). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: domain, type, trigger, deploymentResourceType, deploymentResourceId, deploymentId, deploymentVcsProviderBranch`, + ) + .option( + `--search <search>`, + `Search term to filter your list results. Max length: 256 chars.`, + ) + .option( + `--total [value]`, + `When set to false, the total count returned will be 0 and will not be calculated.`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .action( + actionRunner( + async ({ queries, search, total }) => + await (await getProxyClient()).listRules(queries, search, total), + ), + ); + +proxy + .command(`create-apirule`) + .description( + `Create a new proxy rule for serving Appwrite's API on custom domain.`, + ) + .requiredOption(`--domain <domain>`, `Domain name.`) + .action( + actionRunner( + async ({ domain }) => + await (await getProxyClient()).createAPIRule(domain), + ), + ); + +proxy + .command(`create-function-rule`) + .description( + `Create a new proxy rule for executing Appwrite Function on custom domain.`, + ) + .requiredOption(`--domain <domain>`, `Domain name.`) + .requiredOption( + `--function-id <function-id>`, + `ID of function to be executed.`, + ) + .option( + `--branch <branch>`, + `Name of VCS branch to deploy changes automatically`, + ) + .action( + actionRunner( + async ({ domain, functionId, branch }) => + await ( + await getProxyClient() + ).createFunctionRule(domain, functionId, branch), + ), + ); + +proxy + .command(`create-redirect-rule`) + .description( + `Create a new proxy rule for to redirect from custom domain to another domain.`, + ) + .requiredOption(`--domain <domain>`, `Domain name.`) + .requiredOption(`--url <url>`, `Target URL of redirection`) + .requiredOption(`--status-code <status-code>`, `Status code of redirection`) + .requiredOption(`--resource-id <resource-id>`, `ID of parent resource.`) + .requiredOption(`--resource-type <resource-type>`, `Type of parent resource.`) + .action( + actionRunner( + async ({ domain, url, statusCode, resourceId, resourceType }) => + await ( + await getProxyClient() + ).createRedirectRule( + domain, + url, + statusCode, + resourceId, + resourceType as ProxyResourceType, + ), + ), + ); + +proxy + .command(`create-site-rule`) + .description( + `Create a new proxy rule for serving Appwrite Site on custom domain.`, + ) + .requiredOption(`--domain <domain>`, `Domain name.`) + .requiredOption(`--site-id <site-id>`, `ID of site to be executed.`) + .option( + `--branch <branch>`, + `Name of VCS branch to deploy changes automatically`, + ) + .action( + actionRunner( + async ({ domain, siteId, branch }) => + await (await getProxyClient()).createSiteRule(domain, siteId, branch), + ), + ); + +proxy + .command(`get-rule`) + .description(`Get a proxy rule by its unique ID.`) + .requiredOption(`--rule-id <rule-id>`, `Rule ID.`) + .action( + actionRunner( + async ({ ruleId }) => await (await getProxyClient()).getRule(ruleId), + ), + ); + +proxy + .command(`delete-rule`) + .description(`Delete a proxy rule by its unique ID.`) + .requiredOption(`--rule-id <rule-id>`, `Rule ID.`) + .action( + actionRunner( + async ({ ruleId }) => await (await getProxyClient()).deleteRule(ruleId), + ), + ); + +proxy + .command(`update-rule-verification`) + .description( + `Retry getting verification process of a proxy rule. This endpoint triggers domain verification by checking DNS records (CNAME) against the configured target domain. If verification is successful, a TLS certificate will be automatically provisioned for the domain.`, + ) + .requiredOption(`--rule-id <rule-id>`, `Rule ID.`) + .action( + actionRunner( + async ({ ruleId }) => + await (await getProxyClient()).updateRuleVerification(ruleId), + ), + ); diff --git a/lib/commands/services/sites.ts b/lib/commands/services/sites.ts new file mode 100644 index 00000000..fe28267b --- /dev/null +++ b/lib/commands/services/sites.ts @@ -0,0 +1,777 @@ +import { Command } from "commander"; +import { sdkForProject } from "../../sdks.js"; +import { + actionRunner, + commandDescriptions, + parseBool, + parseInteger, +} from "../../parser.js"; +import { + Sites, + UsageRange, + TemplateReferenceType, + VCSReferenceType, + DeploymentDownloadType, +} from "@appwrite.io/console"; + +let sitesClient: Sites | null = null; + +const getSitesClient = async (): Promise<Sites> => { + if (!sitesClient) { + const sdkClient = await sdkForProject(); + sitesClient = new Sites(sdkClient); + } + return sitesClient; +}; + +export const sites = new Command("sites") + .description(commandDescriptions["sites"] ?? "") + .configureHelp({ + helpWidth: process.stdout.columns || 80, + }); + +sites + .command(`list`) + .description( + `Get a list of all the project's sites. You can use the query params to filter your results.`, + ) + .option( + `--queries [queries...]`, + `Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: name, enabled, framework, deploymentId, buildCommand, installCommand, outputDirectory, installationId`, + ) + .option( + `--search <search>`, + `Search term to filter your list results. Max length: 256 chars.`, + ) + .option( + `--total [value]`, + `When set to false, the total count returned will be 0 and will not be calculated.`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .action( + actionRunner( + async ({ queries, search, total }) => + await (await getSitesClient()).list(queries, search, total), + ), + ); + +sites + .command(`create`) + .description(`Create a new site.`) + .requiredOption( + `--site-id <site-id>`, + `Site ID. Choose a custom ID or generate a random ID with \`ID.unique()\`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.`, + ) + .requiredOption(`--name <name>`, `Site name. Max length: 128 chars.`) + .requiredOption(`--framework <framework>`, `Sites framework.`) + .option( + `--enabled [value]`, + `Is site enabled? When set to 'disabled', users cannot access the site but Server SDKs with and API key can still access the site. No data is lost when this is toggled.`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .option( + `--logging [value]`, + `When disabled, request logs will exclude logs and errors, and site responses will be slightly faster.`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .option( + `--timeout <timeout>`, + `Maximum request time in seconds.`, + parseInteger, + ) + .option(`--install-command <install-command>`, `Install Command.`) + .option(`--build-command <build-command>`, `Build Command.`) + .option(`--output-directory <output-directory>`, `Output Directory for site.`) + .requiredOption( + `--build-runtime <build-runtime>`, + `Runtime to use during build step.`, + ) + .option( + `--adapter <adapter>`, + `Framework adapter defining rendering strategy. Allowed values are: static, ssr`, + ) + .option( + `--installation-id <installation-id>`, + `Appwrite Installation ID for VCS (Version Control System) deployment.`, + ) + .option( + `--fallback-file <fallback-file>`, + `Fallback file for single page application sites.`, + ) + .option( + `--provider-repository-id <provider-repository-id>`, + `Repository ID of the repo linked to the site.`, + ) + .option( + `--provider-branch <provider-branch>`, + `Production branch for the repo linked to the site.`, + ) + .option( + `--provider-silent-mode [value]`, + `Is the VCS (Version Control System) connection in silent mode for the repo linked to the site? In silent mode, comments will not be made on commits and pull requests.`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .option( + `--provider-root-directory <provider-root-directory>`, + `Path to site code in the linked repo.`, + ) + .option( + `--specification <specification>`, + `Framework specification for the site and builds.`, + ) + .action( + actionRunner( + async ({ + siteId, + name, + framework, + enabled, + logging, + timeout, + installCommand, + buildCommand, + outputDirectory, + buildRuntime, + adapter, + installationId, + fallbackFile, + providerRepositoryId, + providerBranch, + providerSilentMode, + providerRootDirectory, + specification, + }) => + await ( + await getSitesClient() + ).create( + siteId, + name, + framework, + enabled, + logging, + timeout, + installCommand, + buildCommand, + outputDirectory, + buildRuntime, + adapter, + installationId, + fallbackFile, + providerRepositoryId, + providerBranch, + providerSilentMode, + providerRootDirectory, + specification, + ), + ), + ); + +sites + .command(`list-frameworks`) + .description( + `Get a list of all frameworks that are currently available on the server instance.`, + ) + .action( + actionRunner(async () => await (await getSitesClient()).listFrameworks()), + ); + +sites + .command(`list-specifications`) + .description(`List allowed site specifications for this instance.`) + .action( + actionRunner( + async () => await (await getSitesClient()).listSpecifications(), + ), + ); + +sites + .command(`list-templates`) + .description( + `List available site templates. You can use template details in [createSite](/docs/references/cloud/server-nodejs/sites#create) method.`, + ) + .option( + `--frameworks [frameworks...]`, + `List of frameworks allowed for filtering site templates. Maximum of 100 frameworks are allowed.`, + ) + .option( + `--use-cases [use-cases...]`, + `List of use cases allowed for filtering site templates. Maximum of 100 use cases are allowed.`, + ) + .option( + `--limit <limit>`, + `Limit the number of templates returned in the response. Default limit is 25, and maximum limit is 5000.`, + parseInteger, + ) + .option( + `--offset <offset>`, + `Offset the list of returned templates. Maximum offset is 5000.`, + parseInteger, + ) + .action( + actionRunner( + async ({ frameworks, useCases, limit, offset }) => + await ( + await getSitesClient() + ).listTemplates(frameworks, useCases, limit, offset), + ), + ); + +sites + .command(`get-template`) + .description( + `Get a site template using ID. You can use template details in [createSite](/docs/references/cloud/server-nodejs/sites#create) method.`, + ) + .requiredOption(`--template-id <template-id>`, `Template ID.`) + .action( + actionRunner( + async ({ templateId }) => + await (await getSitesClient()).getTemplate(templateId), + ), + ); + +sites + .command(`list-usage`) + .description( + `Get usage metrics and statistics for all sites in the project. View statistics including total deployments, builds, logs, storage usage, and compute time. The response includes both current totals and historical data for each metric. Use the optional range parameter to specify the time window for historical data: 24h (last 24 hours), 30d (last 30 days), or 90d (last 90 days). If not specified, defaults to 30 days.`, + ) + .option(`--range <range>`, `Date range.`) + .action( + actionRunner( + async ({ range }) => + await (await getSitesClient()).listUsage(range as UsageRange), + ), + ); + +sites + .command(`get`) + .description(`Get a site by its unique ID.`) + .requiredOption(`--site-id <site-id>`, `Site ID.`) + .action( + actionRunner( + async ({ siteId }) => await (await getSitesClient()).get(siteId), + ), + ); + +sites + .command(`update`) + .description(`Update site by its unique ID.`) + .requiredOption(`--site-id <site-id>`, `Site ID.`) + .requiredOption(`--name <name>`, `Site name. Max length: 128 chars.`) + .requiredOption(`--framework <framework>`, `Sites framework.`) + .option( + `--enabled [value]`, + `Is site enabled? When set to 'disabled', users cannot access the site but Server SDKs with and API key can still access the site. No data is lost when this is toggled.`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .option( + `--logging [value]`, + `When disabled, request logs will exclude logs and errors, and site responses will be slightly faster.`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .option( + `--timeout <timeout>`, + `Maximum request time in seconds.`, + parseInteger, + ) + .option(`--install-command <install-command>`, `Install Command.`) + .option(`--build-command <build-command>`, `Build Command.`) + .option(`--output-directory <output-directory>`, `Output Directory for site.`) + .option( + `--build-runtime <build-runtime>`, + `Runtime to use during build step.`, + ) + .option( + `--adapter <adapter>`, + `Framework adapter defining rendering strategy. Allowed values are: static, ssr`, + ) + .option( + `--fallback-file <fallback-file>`, + `Fallback file for single page application sites.`, + ) + .option( + `--installation-id <installation-id>`, + `Appwrite Installation ID for VCS (Version Control System) deployment.`, + ) + .option( + `--provider-repository-id <provider-repository-id>`, + `Repository ID of the repo linked to the site.`, + ) + .option( + `--provider-branch <provider-branch>`, + `Production branch for the repo linked to the site.`, + ) + .option( + `--provider-silent-mode [value]`, + `Is the VCS (Version Control System) connection in silent mode for the repo linked to the site? In silent mode, comments will not be made on commits and pull requests.`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .option( + `--provider-root-directory <provider-root-directory>`, + `Path to site code in the linked repo.`, + ) + .option( + `--specification <specification>`, + `Framework specification for the site and builds.`, + ) + .action( + actionRunner( + async ({ + siteId, + name, + framework, + enabled, + logging, + timeout, + installCommand, + buildCommand, + outputDirectory, + buildRuntime, + adapter, + fallbackFile, + installationId, + providerRepositoryId, + providerBranch, + providerSilentMode, + providerRootDirectory, + specification, + }) => + await ( + await getSitesClient() + ).update( + siteId, + name, + framework, + enabled, + logging, + timeout, + installCommand, + buildCommand, + outputDirectory, + buildRuntime, + adapter, + fallbackFile, + installationId, + providerRepositoryId, + providerBranch, + providerSilentMode, + providerRootDirectory, + specification, + ), + ), + ); + +sites + .command(`delete`) + .description(`Delete a site by its unique ID.`) + .requiredOption(`--site-id <site-id>`, `Site ID.`) + .action( + actionRunner( + async ({ siteId }) => await (await getSitesClient()).delete(siteId), + ), + ); + +sites + .command(`update-site-deployment`) + .description( + `Update the site active deployment. Use this endpoint to switch the code deployment that should be used when visitor opens your site.`, + ) + .requiredOption(`--site-id <site-id>`, `Site ID.`) + .requiredOption(`--deployment-id <deployment-id>`, `Deployment ID.`) + .action( + actionRunner( + async ({ siteId, deploymentId }) => + await ( + await getSitesClient() + ).updateSiteDeployment(siteId, deploymentId), + ), + ); + +sites + .command(`list-deployments`) + .description( + `Get a list of all the site's code deployments. You can use the query params to filter your results.`, + ) + .requiredOption(`--site-id <site-id>`, `Site ID.`) + .option( + `--queries [queries...]`, + `Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: buildSize, sourceSize, totalSize, buildDuration, status, activate, type`, + ) + .option( + `--search <search>`, + `Search term to filter your list results. Max length: 256 chars.`, + ) + .option( + `--total [value]`, + `When set to false, the total count returned will be 0 and will not be calculated.`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .action( + actionRunner( + async ({ siteId, queries, search, total }) => + await ( + await getSitesClient() + ).listDeployments(siteId, queries, search, total), + ), + ); + +sites + .command(`create-deployment`) + .description( + `Create a new site code deployment. Use this endpoint to upload a new version of your site code. To activate your newly uploaded code, you'll need to update the site's deployment to use your new deployment ID.`, + ) + .requiredOption(`--site-id <site-id>`, `Site ID.`) + .option(`--install-command <install-command>`, `Install Commands.`) + .option(`--build-command <build-command>`, `Build Commands.`) + .option(`--output-directory <output-directory>`, `Output Directory.`) + .requiredOption( + `--code <code>`, + `Gzip file with your code package. When used with the Appwrite CLI, pass the path to your code directory, and the CLI will automatically package your code. Use a path that is within the current directory.`, + ) + .requiredOption( + `--activate <activate>`, + `Automatically activate the deployment when it is finished building.`, + parseBool, + ) + .action( + actionRunner( + async ({ + siteId, + installCommand, + buildCommand, + outputDirectory, + code, + activate, + }) => + await ( + await getSitesClient() + ).createDeployment( + siteId, + installCommand, + buildCommand, + outputDirectory, + code, + activate, + ), + ), + ); + +sites + .command(`create-duplicate-deployment`) + .description( + `Create a new build for an existing site deployment. This endpoint allows you to rebuild a deployment with the updated site configuration, including its commands and output directory if they have been modified. The build process will be queued and executed asynchronously. The original deployment's code will be preserved and used for the new build.`, + ) + .requiredOption(`--site-id <site-id>`, `Site ID.`) + .requiredOption(`--deployment-id <deployment-id>`, `Deployment ID.`) + .action( + actionRunner( + async ({ siteId, deploymentId }) => + await ( + await getSitesClient() + ).createDuplicateDeployment(siteId, deploymentId), + ), + ); + +sites + .command(`create-template-deployment`) + .description( + `Create a deployment based on a template. + +Use this endpoint with combination of [listTemplates](https://appwrite.io/docs/products/sites/templates) to find the template details.`, + ) + .requiredOption(`--site-id <site-id>`, `Site ID.`) + .requiredOption( + `--repository <repository>`, + `Repository name of the template.`, + ) + .requiredOption(`--owner <owner>`, `The name of the owner of the template.`) + .requiredOption( + `--root-directory <root-directory>`, + `Path to site code in the template repo.`, + ) + .requiredOption( + `--type <type>`, + `Type for the reference provided. Can be commit, branch, or tag`, + ) + .requiredOption( + `--reference <reference>`, + `Reference value, can be a commit hash, branch name, or release tag`, + ) + .option( + `--activate [value]`, + `Automatically activate the deployment when it is finished building.`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .action( + actionRunner( + async ({ + siteId, + repository, + owner, + rootDirectory, + xType, + reference, + activate, + }) => + await ( + await getSitesClient() + ).createTemplateDeployment( + siteId, + repository, + owner, + rootDirectory, + xType as TemplateReferenceType, + reference, + activate, + ), + ), + ); + +sites + .command(`create-vcs-deployment`) + .description( + `Create a deployment when a site is connected to VCS. + +This endpoint lets you create deployment from a branch, commit, or a tag.`, + ) + .requiredOption(`--site-id <site-id>`, `Site ID.`) + .requiredOption( + `--type <type>`, + `Type of reference passed. Allowed values are: branch, commit`, + ) + .requiredOption( + `--reference <reference>`, + `VCS reference to create deployment from. Depending on type this can be: branch name, commit hash`, + ) + .option( + `--activate [value]`, + `Automatically activate the deployment when it is finished building.`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .action( + actionRunner( + async ({ siteId, xType, reference, activate }) => + await ( + await getSitesClient() + ).createVcsDeployment( + siteId, + xType as VCSReferenceType, + reference, + activate, + ), + ), + ); + +sites + .command(`get-deployment`) + .description(`Get a site deployment by its unique ID.`) + .requiredOption(`--site-id <site-id>`, `Site ID.`) + .requiredOption(`--deployment-id <deployment-id>`, `Deployment ID.`) + .action( + actionRunner( + async ({ siteId, deploymentId }) => + await (await getSitesClient()).getDeployment(siteId, deploymentId), + ), + ); + +sites + .command(`delete-deployment`) + .description(`Delete a site deployment by its unique ID.`) + .requiredOption(`--site-id <site-id>`, `Site ID.`) + .requiredOption(`--deployment-id <deployment-id>`, `Deployment ID.`) + .action( + actionRunner( + async ({ siteId, deploymentId }) => + await (await getSitesClient()).deleteDeployment(siteId, deploymentId), + ), + ); + +sites + .command(`get-deployment-download`) + .description( + `Get a site deployment content by its unique ID. The endpoint response return with a 'Content-Disposition: attachment' header that tells the browser to start downloading the file to user downloads directory.`, + ) + .requiredOption(`--site-id <site-id>`, `Site ID.`) + .requiredOption(`--deployment-id <deployment-id>`, `Deployment ID.`) + .option( + `--type <type>`, + `Deployment file to download. Can be: "source", "output".`, + ) + .action( + actionRunner( + async ({ siteId, deploymentId, xType }) => + await ( + await getSitesClient() + ).getDeploymentDownload( + siteId, + deploymentId, + xType as DeploymentDownloadType, + ), + ), + ); + +sites + .command(`update-deployment-status`) + .description( + `Cancel an ongoing site deployment build. If the build is already in progress, it will be stopped and marked as canceled. If the build hasn't started yet, it will be marked as canceled without executing. You cannot cancel builds that have already completed (status 'ready') or failed. The response includes the final build status and details.`, + ) + .requiredOption(`--site-id <site-id>`, `Site ID.`) + .requiredOption(`--deployment-id <deployment-id>`, `Deployment ID.`) + .action( + actionRunner( + async ({ siteId, deploymentId }) => + await ( + await getSitesClient() + ).updateDeploymentStatus(siteId, deploymentId), + ), + ); + +sites + .command(`list-logs`) + .description( + `Get a list of all site logs. You can use the query params to filter your results.`, + ) + .requiredOption(`--site-id <site-id>`, `Site ID.`) + .option( + `--queries [queries...]`, + `Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: trigger, status, responseStatusCode, duration, requestMethod, requestPath, deploymentId`, + ) + .option( + `--total [value]`, + `When set to false, the total count returned will be 0 and will not be calculated.`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .action( + actionRunner( + async ({ siteId, queries, total }) => + await (await getSitesClient()).listLogs(siteId, queries, total), + ), + ); + +sites + .command(`get-log`) + .description(`Get a site request log by its unique ID.`) + .requiredOption(`--site-id <site-id>`, `Site ID.`) + .requiredOption(`--log-id <log-id>`, `Log ID.`) + .action( + actionRunner( + async ({ siteId, logId }) => + await (await getSitesClient()).getLog(siteId, logId), + ), + ); + +sites + .command(`delete-log`) + .description(`Delete a site log by its unique ID.`) + .requiredOption(`--site-id <site-id>`, `Site ID.`) + .requiredOption(`--log-id <log-id>`, `Log ID.`) + .action( + actionRunner( + async ({ siteId, logId }) => + await (await getSitesClient()).deleteLog(siteId, logId), + ), + ); + +sites + .command(`get-usage`) + .description( + `Get usage metrics and statistics for a for a specific site. View statistics including total deployments, builds, executions, storage usage, and compute time. The response includes both current totals and historical data for each metric. Use the optional range parameter to specify the time window for historical data: 24h (last 24 hours), 30d (last 30 days), or 90d (last 90 days). If not specified, defaults to 30 days.`, + ) + .requiredOption(`--site-id <site-id>`, `Site ID.`) + .option(`--range <range>`, `Date range.`) + .action( + actionRunner( + async ({ siteId, range }) => + await (await getSitesClient()).getUsage(siteId, range as UsageRange), + ), + ); + +sites + .command(`list-variables`) + .description(`Get a list of all variables of a specific site.`) + .requiredOption(`--site-id <site-id>`, `Site unique ID.`) + .action( + actionRunner( + async ({ siteId }) => + await (await getSitesClient()).listVariables(siteId), + ), + ); + +sites + .command(`create-variable`) + .description( + `Create a new site variable. These variables can be accessed during build and runtime (server-side rendering) as environment variables.`, + ) + .requiredOption(`--site-id <site-id>`, `Site unique ID.`) + .requiredOption(`--key <key>`, `Variable key. Max length: 255 chars.`) + .requiredOption(`--value <value>`, `Variable value. Max length: 8192 chars.`) + .option( + `--secret [value]`, + `Secret variables can be updated or deleted, but only sites can read them during build and runtime.`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .action( + actionRunner( + async ({ siteId, key, value, secret }) => + await ( + await getSitesClient() + ).createVariable(siteId, key, value, secret), + ), + ); + +sites + .command(`get-variable`) + .description(`Get a variable by its unique ID.`) + .requiredOption(`--site-id <site-id>`, `Site unique ID.`) + .requiredOption(`--variable-id <variable-id>`, `Variable unique ID.`) + .action( + actionRunner( + async ({ siteId, variableId }) => + await (await getSitesClient()).getVariable(siteId, variableId), + ), + ); + +sites + .command(`update-variable`) + .description(`Update variable by its unique ID.`) + .requiredOption(`--site-id <site-id>`, `Site unique ID.`) + .requiredOption(`--variable-id <variable-id>`, `Variable unique ID.`) + .requiredOption(`--key <key>`, `Variable key. Max length: 255 chars.`) + .option(`--value <value>`, `Variable value. Max length: 8192 chars.`) + .option( + `--secret [value]`, + `Secret variables can be updated or deleted, but only sites can read them during build and runtime.`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .action( + actionRunner( + async ({ siteId, variableId, key, value, secret }) => + await ( + await getSitesClient() + ).updateVariable(siteId, variableId, key, value, secret), + ), + ); + +sites + .command(`delete-variable`) + .description(`Delete a variable by its unique ID.`) + .requiredOption(`--site-id <site-id>`, `Site unique ID.`) + .requiredOption(`--variable-id <variable-id>`, `Variable unique ID.`) + .action( + actionRunner( + async ({ siteId, variableId }) => + await (await getSitesClient()).deleteVariable(siteId, variableId), + ), + ); diff --git a/lib/commands/services/storage.ts b/lib/commands/services/storage.ts new file mode 100644 index 00000000..9e4c40cf --- /dev/null +++ b/lib/commands/services/storage.ts @@ -0,0 +1,547 @@ +import { Command } from "commander"; +import { sdkForProject } from "../../sdks.js"; +import { + actionRunner, + commandDescriptions, + parseBool, + parseInteger, +} from "../../parser.js"; +import { + Storage, + ImageGravity, + ImageFormat, + UsageRange, +} from "@appwrite.io/console"; + +let storageClient: Storage | null = null; + +const getStorageClient = async (): Promise<Storage> => { + if (!storageClient) { + const sdkClient = await sdkForProject(); + storageClient = new Storage(sdkClient); + } + return storageClient; +}; + +export const storage = new Command("storage") + .description(commandDescriptions["storage"] ?? "") + .configureHelp({ + helpWidth: process.stdout.columns || 80, + }); + +storage + .command(`list-buckets`) + .description( + `Get a list of all the storage buckets. You can use the query params to filter your results.`, + ) + .option( + `--queries [queries...]`, + `Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: enabled, name, fileSecurity, maximumFileSize, encryption, antivirus, transformations`, + ) + .option( + `--search <search>`, + `Search term to filter your list results. Max length: 256 chars.`, + ) + .option( + `--total [value]`, + `When set to false, the total count returned will be 0 and will not be calculated.`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .action( + actionRunner( + async ({ queries, search, total }) => + await (await getStorageClient()).listBuckets(queries, search, total), + ), + ); + +storage + .command(`create-bucket`) + .description(`Create a new storage bucket.`) + .requiredOption( + `--bucket-id <bucket-id>`, + `Unique Id. Choose a custom ID or generate a random ID with \`ID.unique()\`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.`, + ) + .requiredOption(`--name <name>`, `Bucket name`) + .option( + `--permissions [permissions...]`, + `An array of permission strings. By default, no user is granted with any permissions. [Learn more about permissions](https://appwrite.io/docs/permissions).`, + ) + .option( + `--file-security [value]`, + `Enables configuring permissions for individual file. A user needs one of file or bucket level permissions to access a file. [Learn more about permissions](https://appwrite.io/docs/permissions).`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .option( + `--enabled [value]`, + `Is bucket enabled? When set to 'disabled', users cannot access the files in this bucket but Server SDKs with and API key can still access the bucket. No files are lost when this is toggled.`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .option( + `--maximum-file-size <maximum-file-size>`, + `Maximum file size allowed in bytes. Maximum allowed value is 30MB.`, + parseInteger, + ) + .option( + `--allowed-file-extensions [allowed-file-extensions...]`, + `Allowed file extensions. Maximum of 100 extensions are allowed, each 64 characters long.`, + ) + .option( + `--compression <compression>`, + `Compression algorithm choosen for compression. Can be one of none, [gzip](https://en.wikipedia.org/wiki/Gzip), or [zstd](https://en.wikipedia.org/wiki/Zstd), For file size above 20MB compression is skipped even if it's enabled`, + ) + .option( + `--encryption [value]`, + `Is encryption enabled? For file size above 20MB encryption is skipped even if it's enabled`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .option( + `--antivirus [value]`, + `Is virus scanning enabled? For file size above 20MB AntiVirus scanning is skipped even if it's enabled`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .option( + `--transformations [value]`, + `Are image transformations enabled?`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .action( + actionRunner( + async ({ + bucketId, + name, + permissions, + fileSecurity, + enabled, + maximumFileSize, + allowedFileExtensions, + compression, + encryption, + antivirus, + transformations, + }) => + await ( + await getStorageClient() + ).createBucket( + bucketId, + name, + permissions, + fileSecurity, + enabled, + maximumFileSize, + allowedFileExtensions, + compression, + encryption, + antivirus, + transformations, + ), + ), + ); + +storage + .command(`get-bucket`) + .description( + `Get a storage bucket by its unique ID. This endpoint response returns a JSON object with the storage bucket metadata.`, + ) + .requiredOption(`--bucket-id <bucket-id>`, `Bucket unique ID.`) + .action( + actionRunner( + async ({ bucketId }) => + await (await getStorageClient()).getBucket(bucketId), + ), + ); + +storage + .command(`update-bucket`) + .description(`Update a storage bucket by its unique ID.`) + .requiredOption(`--bucket-id <bucket-id>`, `Bucket unique ID.`) + .requiredOption(`--name <name>`, `Bucket name`) + .option( + `--permissions [permissions...]`, + `An array of permission strings. By default, the current permissions are inherited. [Learn more about permissions](https://appwrite.io/docs/permissions).`, + ) + .option( + `--file-security [value]`, + `Enables configuring permissions for individual file. A user needs one of file or bucket level permissions to access a file. [Learn more about permissions](https://appwrite.io/docs/permissions).`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .option( + `--enabled [value]`, + `Is bucket enabled? When set to 'disabled', users cannot access the files in this bucket but Server SDKs with and API key can still access the bucket. No files are lost when this is toggled.`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .option( + `--maximum-file-size <maximum-file-size>`, + `Maximum file size allowed in bytes. Maximum allowed value is 30MB.`, + parseInteger, + ) + .option( + `--allowed-file-extensions [allowed-file-extensions...]`, + `Allowed file extensions. Maximum of 100 extensions are allowed, each 64 characters long.`, + ) + .option( + `--compression <compression>`, + `Compression algorithm choosen for compression. Can be one of none, [gzip](https://en.wikipedia.org/wiki/Gzip), or [zstd](https://en.wikipedia.org/wiki/Zstd), For file size above 20MB compression is skipped even if it's enabled`, + ) + .option( + `--encryption [value]`, + `Is encryption enabled? For file size above 20MB encryption is skipped even if it's enabled`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .option( + `--antivirus [value]`, + `Is virus scanning enabled? For file size above 20MB AntiVirus scanning is skipped even if it's enabled`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .option( + `--transformations [value]`, + `Are image transformations enabled?`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .action( + actionRunner( + async ({ + bucketId, + name, + permissions, + fileSecurity, + enabled, + maximumFileSize, + allowedFileExtensions, + compression, + encryption, + antivirus, + transformations, + }) => + await ( + await getStorageClient() + ).updateBucket( + bucketId, + name, + permissions, + fileSecurity, + enabled, + maximumFileSize, + allowedFileExtensions, + compression, + encryption, + antivirus, + transformations, + ), + ), + ); + +storage + .command(`delete-bucket`) + .description(`Delete a storage bucket by its unique ID.`) + .requiredOption(`--bucket-id <bucket-id>`, `Bucket unique ID.`) + .action( + actionRunner( + async ({ bucketId }) => + await (await getStorageClient()).deleteBucket(bucketId), + ), + ); + +storage + .command(`list-files`) + .description( + `Get a list of all the user files. You can use the query params to filter your results.`, + ) + .requiredOption( + `--bucket-id <bucket-id>`, + `Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](https://appwrite.io/docs/server/storage#createBucket).`, + ) + .option( + `--queries [queries...]`, + `Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: name, signature, mimeType, sizeOriginal, chunksTotal, chunksUploaded`, + ) + .option( + `--search <search>`, + `Search term to filter your list results. Max length: 256 chars.`, + ) + .option( + `--total [value]`, + `When set to false, the total count returned will be 0 and will not be calculated.`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .action( + actionRunner( + async ({ bucketId, queries, search, total }) => + await ( + await getStorageClient() + ).listFiles(bucketId, queries, search, total), + ), + ); + +storage + .command(`create-file`) + .description( + `Create a new file. Before using this route, you should create a new bucket resource using either a [server integration](https://appwrite.io/docs/server/storage#storageCreateBucket) API or directly from your Appwrite console. + +Larger files should be uploaded using multiple requests with the [content-range](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Range) header to send a partial request with a maximum supported chunk of \`5MB\`. The \`content-range\` header values should always be in bytes. + +When the first request is sent, the server will return the **File** object, and the subsequent part request must include the file's **id** in \`x-appwrite-id\` header to allow the server to know that the partial upload is for the existing file and not for a new one. + +If you're creating a new file using one of the Appwrite SDKs, all the chunking logic will be managed by the SDK internally. +`, + ) + .requiredOption( + `--bucket-id <bucket-id>`, + `Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](https://appwrite.io/docs/server/storage#createBucket).`, + ) + .requiredOption( + `--file-id <file-id>`, + `File ID. Choose a custom ID or generate a random ID with \`ID.unique()\`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.`, + ) + .requiredOption( + `--file <file>`, + `Binary file. Appwrite SDKs provide helpers to handle file input. [Learn about file input](https://appwrite.io/docs/products/storage/upload-download#input-file).`, + ) + .option( + `--permissions [permissions...]`, + `An array of permission strings. By default, only the current user is granted all permissions. [Learn more about permissions](https://appwrite.io/docs/permissions).`, + ) + .action( + actionRunner( + async ({ bucketId, fileId, file, permissions }) => + await ( + await getStorageClient() + ).createFile(bucketId, fileId, file, permissions), + ), + ); + +storage + .command(`get-file`) + .description( + `Get a file by its unique ID. This endpoint response returns a JSON object with the file metadata.`, + ) + .requiredOption( + `--bucket-id <bucket-id>`, + `Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](https://appwrite.io/docs/server/storage#createBucket).`, + ) + .requiredOption(`--file-id <file-id>`, `File ID.`) + .action( + actionRunner( + async ({ bucketId, fileId }) => + await (await getStorageClient()).getFile(bucketId, fileId), + ), + ); + +storage + .command(`update-file`) + .description( + `Update a file by its unique ID. Only users with write permissions have access to update this resource.`, + ) + .requiredOption(`--bucket-id <bucket-id>`, `Bucket unique ID.`) + .requiredOption(`--file-id <file-id>`, `File ID.`) + .option(`--name <name>`, `File name.`) + .option( + `--permissions [permissions...]`, + `An array of permission strings. By default, the current permissions are inherited. [Learn more about permissions](https://appwrite.io/docs/permissions).`, + ) + .action( + actionRunner( + async ({ bucketId, fileId, name, permissions }) => + await ( + await getStorageClient() + ).updateFile(bucketId, fileId, name, permissions), + ), + ); + +storage + .command(`delete-file`) + .description( + `Delete a file by its unique ID. Only users with write permissions have access to delete this resource.`, + ) + .requiredOption( + `--bucket-id <bucket-id>`, + `Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](https://appwrite.io/docs/server/storage#createBucket).`, + ) + .requiredOption(`--file-id <file-id>`, `File ID.`) + .action( + actionRunner( + async ({ bucketId, fileId }) => + await (await getStorageClient()).deleteFile(bucketId, fileId), + ), + ); + +storage + .command(`get-file-download`) + .description( + `Get a file content by its unique ID. The endpoint response return with a 'Content-Disposition: attachment' header that tells the browser to start downloading the file to user downloads directory.`, + ) + .requiredOption( + `--bucket-id <bucket-id>`, + `Storage bucket ID. You can create a new storage bucket using the Storage service [server integration](https://appwrite.io/docs/server/storage#createBucket).`, + ) + .requiredOption(`--file-id <file-id>`, `File ID.`) + .option(`--token <token>`, `File token for accessing this file.`) + .action( + actionRunner( + async ({ bucketId, fileId, token }) => + await ( + await getStorageClient() + ).getFileDownload(bucketId, fileId, token), + ), + ); + +storage + .command(`get-file-preview`) + .description( + `Get a file preview image. Currently, this method supports preview for image files (jpg, png, and gif), other supported formats, like pdf, docs, slides, and spreadsheets, will return the file icon image. You can also pass query string arguments for cutting and resizing your preview image. Preview is supported only for image files smaller than 10MB.`, + ) + .requiredOption( + `--bucket-id <bucket-id>`, + `Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](https://appwrite.io/docs/server/storage#createBucket).`, + ) + .requiredOption(`--file-id <file-id>`, `File ID`) + .option( + `--width <width>`, + `Resize preview image width, Pass an integer between 0 to 4000.`, + parseInteger, + ) + .option( + `--height <height>`, + `Resize preview image height, Pass an integer between 0 to 4000.`, + parseInteger, + ) + .option( + `--gravity <gravity>`, + `Image crop gravity. Can be one of center,top-left,top,top-right,left,right,bottom-left,bottom,bottom-right`, + ) + .option( + `--quality <quality>`, + `Preview image quality. Pass an integer between 0 to 100. Defaults to keep existing image quality.`, + parseInteger, + ) + .option( + `--border-width <border-width>`, + `Preview image border in pixels. Pass an integer between 0 to 100. Defaults to 0.`, + parseInteger, + ) + .option( + `--border-color <border-color>`, + `Preview image border color. Use a valid HEX color, no # is needed for prefix.`, + ) + .option( + `--border-radius <border-radius>`, + `Preview image border radius in pixels. Pass an integer between 0 to 4000.`, + parseInteger, + ) + .option( + `--opacity <opacity>`, + `Preview image opacity. Only works with images having an alpha channel (like png). Pass a number between 0 to 1.`, + parseInteger, + ) + .option( + `--rotation <rotation>`, + `Preview image rotation in degrees. Pass an integer between -360 and 360.`, + parseInteger, + ) + .option( + `--background <background>`, + `Preview image background color. Only works with transparent images (png). Use a valid HEX color, no # is needed for prefix.`, + ) + .option( + `--output <output>`, + `Output format type (jpeg, jpg, png, gif and webp).`, + ) + .option(`--token <token>`, `File token for accessing this file.`) + .action( + actionRunner( + async ({ + bucketId, + fileId, + width, + height, + gravity, + quality, + borderWidth, + borderColor, + borderRadius, + opacity, + rotation, + background, + output, + token, + }) => + await ( + await getStorageClient() + ).getFilePreview( + bucketId, + fileId, + width, + height, + gravity as ImageGravity, + quality, + borderWidth, + borderColor, + borderRadius, + opacity, + rotation, + background, + output as ImageFormat, + token, + ), + ), + ); + +storage + .command(`get-file-view`) + .description( + `Get a file content by its unique ID. This endpoint is similar to the download method but returns with no 'Content-Disposition: attachment' header.`, + ) + .requiredOption( + `--bucket-id <bucket-id>`, + `Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](https://appwrite.io/docs/server/storage#createBucket).`, + ) + .requiredOption(`--file-id <file-id>`, `File ID.`) + .option(`--token <token>`, `File token for accessing this file.`) + .action( + actionRunner( + async ({ bucketId, fileId, token }) => + await (await getStorageClient()).getFileView(bucketId, fileId, token), + ), + ); + +storage + .command(`get-usage`) + .description( + `Get usage metrics and statistics for all buckets in the project. You can view the total number of buckets, files, storage usage. The response includes both current totals and historical data over time. Use the optional range parameter to specify the time window for historical data: 24h (last 24 hours), 30d (last 30 days), or 90d (last 90 days). If not specified, range defaults to 30 days. +`, + ) + .option(`--range <range>`, `Date range.`) + .action( + actionRunner( + async ({ range }) => + await (await getStorageClient()).getUsage(range as UsageRange), + ), + ); + +storage + .command(`get-bucket-usage`) + .description( + `Get usage metrics and statistics a specific bucket in the project. You can view the total number of files, storage usage. The response includes both current totals and historical data over time. Use the optional range parameter to specify the time window for historical data: 24h (last 24 hours), 30d (last 30 days), or 90d (last 90 days). If not specified, range defaults to 30 days. +`, + ) + .requiredOption(`--bucket-id <bucket-id>`, `Bucket ID.`) + .option(`--range <range>`, `Date range.`) + .action( + actionRunner( + async ({ bucketId, range }) => + await ( + await getStorageClient() + ).getBucketUsage(bucketId, range as UsageRange), + ), + ); diff --git a/lib/commands/services/tablesdb.ts b/lib/commands/services/tablesdb.ts new file mode 100644 index 00000000..a190e50f --- /dev/null +++ b/lib/commands/services/tablesdb.ts @@ -0,0 +1,1928 @@ +import { Command } from "commander"; +import { sdkForProject } from "../../sdks.js"; +import { + actionRunner, + commandDescriptions, + parseBool, + parseInteger, +} from "../../parser.js"; +import { + TablesDB, + UsageRange, + RelationshipType, + RelationMutate, + IndexType, +} from "@appwrite.io/console"; + +let tablesdbClient: TablesDB | null = null; + +const getTablesDBClient = async (): Promise<TablesDB> => { + if (!tablesdbClient) { + const sdkClient = await sdkForProject(); + tablesdbClient = new TablesDB(sdkClient); + } + return tablesdbClient; +}; + +export const tablesdb = new Command("tablesdb") + .description(commandDescriptions["tablesdb"] ?? "") + .configureHelp({ + helpWidth: process.stdout.columns || 80, + }); + +tablesdb + .command(`list`) + .description( + `Get a list of all databases from the current Appwrite project. You can use the search parameter to filter your results.`, + ) + .option( + `--queries [queries...]`, + `Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following columns: name`, + ) + .option( + `--search <search>`, + `Search term to filter your list results. Max length: 256 chars.`, + ) + .option( + `--total [value]`, + `When set to false, the total count returned will be 0 and will not be calculated.`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .action( + actionRunner( + async ({ queries, search, total }) => + await (await getTablesDBClient()).list(queries, search, total), + ), + ); + +tablesdb + .command(`create`) + .description( + `Create a new Database. +`, + ) + .requiredOption( + `--database-id <database-id>`, + `Unique Id. Choose a custom ID or generate a random ID with \`ID.unique()\`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.`, + ) + .requiredOption(`--name <name>`, `Database name. Max length: 128 chars.`) + .option( + `--enabled [value]`, + `Is the database enabled? When set to 'disabled', users cannot access the database but Server SDKs with an API key can still read and write to the database. No data is lost when this is toggled.`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .action( + actionRunner( + async ({ databaseId, name, enabled }) => + await (await getTablesDBClient()).create(databaseId, name, enabled), + ), + ); + +tablesdb + .command(`list-transactions`) + .description(`List transactions across all databases.`) + .option( + `--queries [queries...]`, + `Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries).`, + ) + .action( + actionRunner( + async ({ queries }) => + await (await getTablesDBClient()).listTransactions(queries), + ), + ); + +tablesdb + .command(`create-transaction`) + .description(`Create a new transaction.`) + .option( + `--ttl <ttl>`, + `Seconds before the transaction expires.`, + parseInteger, + ) + .action( + actionRunner( + async ({ ttl }) => + await (await getTablesDBClient()).createTransaction(ttl), + ), + ); + +tablesdb + .command(`get-transaction`) + .description(`Get a transaction by its unique ID.`) + .requiredOption(`--transaction-id <transaction-id>`, `Transaction ID.`) + .action( + actionRunner( + async ({ transactionId }) => + await (await getTablesDBClient()).getTransaction(transactionId), + ), + ); + +tablesdb + .command(`update-transaction`) + .description( + `Update a transaction, to either commit or roll back its operations.`, + ) + .requiredOption(`--transaction-id <transaction-id>`, `Transaction ID.`) + .option( + `--commit [value]`, + `Commit transaction?`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .option( + `--rollback [value]`, + `Rollback transaction?`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .action( + actionRunner( + async ({ transactionId, commit, rollback }) => + await ( + await getTablesDBClient() + ).updateTransaction(transactionId, commit, rollback), + ), + ); + +tablesdb + .command(`delete-transaction`) + .description(`Delete a transaction by its unique ID.`) + .requiredOption(`--transaction-id <transaction-id>`, `Transaction ID.`) + .action( + actionRunner( + async ({ transactionId }) => + await (await getTablesDBClient()).deleteTransaction(transactionId), + ), + ); + +tablesdb + .command(`create-operations`) + .description(`Create multiple operations in a single transaction.`) + .requiredOption(`--transaction-id <transaction-id>`, `Transaction ID.`) + .option(`--operations [operations...]`, `Array of staged operations.`) + .action( + actionRunner( + async ({ transactionId, operations }) => + await ( + await getTablesDBClient() + ).createOperations(transactionId, operations), + ), + ); + +tablesdb + .command(`list-usage`) + .description( + `List usage metrics and statistics for all databases in the project. You can view the total number of databases, tables, rows, and storage usage. The response includes both current totals and historical data over time. Use the optional range parameter to specify the time window for historical data: 24h (last 24 hours), 30d (last 30 days), or 90d (last 90 days). If not specified, range defaults to 30 days.`, + ) + .option(`--range <range>`, `Date range.`) + .action( + actionRunner( + async ({ range }) => + await (await getTablesDBClient()).listUsage(range as UsageRange), + ), + ); + +tablesdb + .command(`get`) + .description( + `Get a database by its unique ID. This endpoint response returns a JSON object with the database metadata.`, + ) + .requiredOption(`--database-id <database-id>`, `Database ID.`) + .action( + actionRunner( + async ({ databaseId }) => + await (await getTablesDBClient()).get(databaseId), + ), + ); + +tablesdb + .command(`update`) + .description(`Update a database by its unique ID.`) + .requiredOption(`--database-id <database-id>`, `Database ID.`) + .requiredOption(`--name <name>`, `Database name. Max length: 128 chars.`) + .option( + `--enabled [value]`, + `Is database enabled? When set to 'disabled', users cannot access the database but Server SDKs with an API key can still read and write to the database. No data is lost when this is toggled.`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .action( + actionRunner( + async ({ databaseId, name, enabled }) => + await (await getTablesDBClient()).update(databaseId, name, enabled), + ), + ); + +tablesdb + .command(`delete`) + .description( + `Delete a database by its unique ID. Only API keys with with databases.write scope can delete a database.`, + ) + .requiredOption(`--database-id <database-id>`, `Database ID.`) + .action( + actionRunner( + async ({ databaseId }) => + await (await getTablesDBClient()).delete(databaseId), + ), + ); + +tablesdb + .command(`list-tables`) + .description( + `Get a list of all tables that belong to the provided databaseId. You can use the search parameter to filter your results.`, + ) + .requiredOption(`--database-id <database-id>`, `Database ID.`) + .option( + `--queries [queries...]`, + `Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following columns: name, enabled, rowSecurity`, + ) + .option( + `--search <search>`, + `Search term to filter your list results. Max length: 256 chars.`, + ) + .option( + `--total [value]`, + `When set to false, the total count returned will be 0 and will not be calculated.`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .action( + actionRunner( + async ({ databaseId, queries, search, total }) => + await ( + await getTablesDBClient() + ).listTables(databaseId, queries, search, total), + ), + ); + +tablesdb + .command(`create-table`) + .description( + `Create a new Table. Before using this route, you should create a new database resource using either a [server integration](https://appwrite.io/docs/references/cloud/server-dart/tablesDB#createTable) API or directly from your database console.`, + ) + .requiredOption(`--database-id <database-id>`, `Database ID.`) + .requiredOption( + `--table-id <table-id>`, + `Unique Id. Choose a custom ID or generate a random ID with \`ID.unique()\`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.`, + ) + .requiredOption(`--name <name>`, `Table name. Max length: 128 chars.`) + .option( + `--permissions [permissions...]`, + `An array of permissions strings. By default, no user is granted with any permissions. [Learn more about permissions](https://appwrite.io/docs/permissions).`, + ) + .option( + `--row-security [value]`, + `Enables configuring permissions for individual rows. A user needs one of row or table level permissions to access a row. [Learn more about permissions](https://appwrite.io/docs/permissions).`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .option( + `--enabled [value]`, + `Is table enabled? When set to 'disabled', users cannot access the table but Server SDKs with and API key can still read and write to the table. No data is lost when this is toggled.`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .option( + `--columns [columns...]`, + `Array of column definitions to create. Each column should contain: key (string), type (string: string, integer, float, boolean, datetime, relationship), size (integer, required for string type), required (boolean, optional), default (mixed, optional), array (boolean, optional), and type-specific options.`, + ) + .option( + `--indexes [indexes...]`, + `Array of index definitions to create. Each index should contain: key (string), type (string: key, fulltext, unique, spatial), attributes (array of column keys), orders (array of ASC/DESC, optional), and lengths (array of integers, optional).`, + ) + .action( + actionRunner( + async ({ + databaseId, + tableId, + name, + permissions, + rowSecurity, + enabled, + columns, + indexes, + }) => + await ( + await getTablesDBClient() + ).createTable( + databaseId, + tableId, + name, + permissions, + rowSecurity, + enabled, + columns, + indexes, + ), + ), + ); + +tablesdb + .command(`get-table`) + .description( + `Get a table by its unique ID. This endpoint response returns a JSON object with the table metadata.`, + ) + .requiredOption(`--database-id <database-id>`, `Database ID.`) + .requiredOption(`--table-id <table-id>`, `Table ID.`) + .action( + actionRunner( + async ({ databaseId, tableId }) => + await (await getTablesDBClient()).getTable(databaseId, tableId), + ), + ); + +tablesdb + .command(`update-table`) + .description(`Update a table by its unique ID.`) + .requiredOption(`--database-id <database-id>`, `Database ID.`) + .requiredOption(`--table-id <table-id>`, `Table ID.`) + .requiredOption(`--name <name>`, `Table name. Max length: 128 chars.`) + .option( + `--permissions [permissions...]`, + `An array of permission strings. By default, the current permissions are inherited. [Learn more about permissions](https://appwrite.io/docs/permissions).`, + ) + .option( + `--row-security [value]`, + `Enables configuring permissions for individual rows. A user needs one of row or table-level permissions to access a row. [Learn more about permissions](https://appwrite.io/docs/permissions).`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .option( + `--enabled [value]`, + `Is table enabled? When set to 'disabled', users cannot access the table but Server SDKs with and API key can still read and write to the table. No data is lost when this is toggled.`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .action( + actionRunner( + async ({ + databaseId, + tableId, + name, + permissions, + rowSecurity, + enabled, + }) => + await ( + await getTablesDBClient() + ).updateTable( + databaseId, + tableId, + name, + permissions, + rowSecurity, + enabled, + ), + ), + ); + +tablesdb + .command(`delete-table`) + .description( + `Delete a table by its unique ID. Only users with write permissions have access to delete this resource.`, + ) + .requiredOption(`--database-id <database-id>`, `Database ID.`) + .requiredOption(`--table-id <table-id>`, `Table ID.`) + .action( + actionRunner( + async ({ databaseId, tableId }) => + await (await getTablesDBClient()).deleteTable(databaseId, tableId), + ), + ); + +tablesdb + .command(`list-columns`) + .description(`List columns in the table.`) + .requiredOption(`--database-id <database-id>`, `Database ID.`) + .requiredOption(`--table-id <table-id>`, `Table ID.`) + .option( + `--queries [queries...]`, + `Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following columns: key, type, size, required, array, status, error`, + ) + .option( + `--total [value]`, + `When set to false, the total count returned will be 0 and will not be calculated.`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .action( + actionRunner( + async ({ databaseId, tableId, queries, total }) => + await ( + await getTablesDBClient() + ).listColumns(databaseId, tableId, queries, total), + ), + ); + +tablesdb + .command(`create-boolean-column`) + .description( + `Create a boolean column. +`, + ) + .requiredOption(`--database-id <database-id>`, `Database ID.`) + .requiredOption( + `--table-id <table-id>`, + `Table ID. You can create a new table using the Database service [server integration](https://appwrite.io/docs/references/cloud/server-dart/tablesDB#createTable).`, + ) + .requiredOption(`--key <key>`, `Column Key.`) + .requiredOption(`--required <required>`, `Is column required?`, parseBool) + .option( + `--default [value]`, + `Default value for column when not provided. Cannot be set when column is required.`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .option( + `--array [value]`, + `Is column an array?`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .action( + actionRunner( + async ({ databaseId, tableId, key, required, xDefault, array }) => + await ( + await getTablesDBClient() + ).createBooleanColumn( + databaseId, + tableId, + key, + required, + xDefault, + array, + ), + ), + ); + +tablesdb + .command(`update-boolean-column`) + .description( + `Update a boolean column. Changing the \`default\` value will not update already existing rows.`, + ) + .requiredOption(`--database-id <database-id>`, `Database ID.`) + .requiredOption( + `--table-id <table-id>`, + `Table ID. You can create a new table using the Database service [server integration](https://appwrite.io/docs/references/cloud/server-dart/tablesDB#createTable).`, + ) + .requiredOption(`--key <key>`, `Column Key.`) + .requiredOption(`--required <required>`, `Is column required?`, parseBool) + .requiredOption( + `--default <default>`, + `Default value for column when not provided. Cannot be set when column is required.`, + parseBool, + ) + .option(`--new-key <new-key>`, `New Column Key.`) + .action( + actionRunner( + async ({ databaseId, tableId, key, required, xDefault, newKey }) => + await ( + await getTablesDBClient() + ).updateBooleanColumn( + databaseId, + tableId, + key, + required, + xDefault, + newKey, + ), + ), + ); + +tablesdb + .command(`create-datetime-column`) + .description(`Create a date time column according to the ISO 8601 standard.`) + .requiredOption(`--database-id <database-id>`, `Database ID.`) + .requiredOption(`--table-id <table-id>`, `Table ID.`) + .requiredOption(`--key <key>`, `Column Key.`) + .requiredOption(`--required <required>`, `Is column required?`, parseBool) + .option( + `--default <default>`, + `Default value for the column in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format. Cannot be set when column is required.`, + ) + .option( + `--array [value]`, + `Is column an array?`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .action( + actionRunner( + async ({ databaseId, tableId, key, required, xDefault, array }) => + await ( + await getTablesDBClient() + ).createDatetimeColumn( + databaseId, + tableId, + key, + required, + xDefault, + array, + ), + ), + ); + +tablesdb + .command(`update-datetime-column`) + .description( + `Update a date time column. Changing the \`default\` value will not update already existing rows.`, + ) + .requiredOption(`--database-id <database-id>`, `Database ID.`) + .requiredOption(`--table-id <table-id>`, `Table ID.`) + .requiredOption(`--key <key>`, `Column Key.`) + .requiredOption(`--required <required>`, `Is column required?`, parseBool) + .requiredOption( + `--default <default>`, + `Default value for column when not provided. Cannot be set when column is required.`, + ) + .option(`--new-key <new-key>`, `New Column Key.`) + .action( + actionRunner( + async ({ databaseId, tableId, key, required, xDefault, newKey }) => + await ( + await getTablesDBClient() + ).updateDatetimeColumn( + databaseId, + tableId, + key, + required, + xDefault, + newKey, + ), + ), + ); + +tablesdb + .command(`create-email-column`) + .description( + `Create an email column. +`, + ) + .requiredOption(`--database-id <database-id>`, `Database ID.`) + .requiredOption(`--table-id <table-id>`, `Table ID.`) + .requiredOption(`--key <key>`, `Column Key.`) + .requiredOption(`--required <required>`, `Is column required?`, parseBool) + .option( + `--default <default>`, + `Default value for column when not provided. Cannot be set when column is required.`, + ) + .option( + `--array [value]`, + `Is column an array?`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .action( + actionRunner( + async ({ databaseId, tableId, key, required, xDefault, array }) => + await ( + await getTablesDBClient() + ).createEmailColumn( + databaseId, + tableId, + key, + required, + xDefault, + array, + ), + ), + ); + +tablesdb + .command(`update-email-column`) + .description( + `Update an email column. Changing the \`default\` value will not update already existing rows. +`, + ) + .requiredOption(`--database-id <database-id>`, `Database ID.`) + .requiredOption(`--table-id <table-id>`, `Table ID.`) + .requiredOption(`--key <key>`, `Column Key.`) + .requiredOption(`--required <required>`, `Is column required?`, parseBool) + .requiredOption( + `--default <default>`, + `Default value for column when not provided. Cannot be set when column is required.`, + ) + .option(`--new-key <new-key>`, `New Column Key.`) + .action( + actionRunner( + async ({ databaseId, tableId, key, required, xDefault, newKey }) => + await ( + await getTablesDBClient() + ).updateEmailColumn( + databaseId, + tableId, + key, + required, + xDefault, + newKey, + ), + ), + ); + +tablesdb + .command(`create-enum-column`) + .description( + `Create an enumeration column. The \`elements\` param acts as a white-list of accepted values for this column.`, + ) + .requiredOption(`--database-id <database-id>`, `Database ID.`) + .requiredOption(`--table-id <table-id>`, `Table ID.`) + .requiredOption(`--key <key>`, `Column Key.`) + .requiredOption(`--elements [elements...]`, `Array of enum values.`) + .requiredOption(`--required <required>`, `Is column required?`, parseBool) + .option( + `--default <default>`, + `Default value for column when not provided. Cannot be set when column is required.`, + ) + .option( + `--array [value]`, + `Is column an array?`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .action( + actionRunner( + async ({ + databaseId, + tableId, + key, + elements, + required, + xDefault, + array, + }) => + await ( + await getTablesDBClient() + ).createEnumColumn( + databaseId, + tableId, + key, + elements, + required, + xDefault, + array, + ), + ), + ); + +tablesdb + .command(`update-enum-column`) + .description( + `Update an enum column. Changing the \`default\` value will not update already existing rows. +`, + ) + .requiredOption(`--database-id <database-id>`, `Database ID.`) + .requiredOption(`--table-id <table-id>`, `Table ID.`) + .requiredOption(`--key <key>`, `Column Key.`) + .requiredOption(`--elements [elements...]`, `Updated list of enum values.`) + .requiredOption(`--required <required>`, `Is column required?`, parseBool) + .requiredOption( + `--default <default>`, + `Default value for column when not provided. Cannot be set when column is required.`, + ) + .option(`--new-key <new-key>`, `New Column Key.`) + .action( + actionRunner( + async ({ + databaseId, + tableId, + key, + elements, + required, + xDefault, + newKey, + }) => + await ( + await getTablesDBClient() + ).updateEnumColumn( + databaseId, + tableId, + key, + elements, + required, + xDefault, + newKey, + ), + ), + ); + +tablesdb + .command(`create-float-column`) + .description( + `Create a float column. Optionally, minimum and maximum values can be provided. +`, + ) + .requiredOption(`--database-id <database-id>`, `Database ID.`) + .requiredOption(`--table-id <table-id>`, `Table ID.`) + .requiredOption(`--key <key>`, `Column Key.`) + .requiredOption(`--required <required>`, `Is column required?`, parseBool) + .option(`--min <min>`, `Minimum value`, parseInteger) + .option(`--max <max>`, `Maximum value`, parseInteger) + .option( + `--default <default>`, + `Default value. Cannot be set when required.`, + parseInteger, + ) + .option( + `--array [value]`, + `Is column an array?`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .action( + actionRunner( + async ({ + databaseId, + tableId, + key, + required, + min, + max, + xDefault, + array, + }) => + await ( + await getTablesDBClient() + ).createFloatColumn( + databaseId, + tableId, + key, + required, + min, + max, + xDefault, + array, + ), + ), + ); + +tablesdb + .command(`update-float-column`) + .description( + `Update a float column. Changing the \`default\` value will not update already existing rows. +`, + ) + .requiredOption(`--database-id <database-id>`, `Database ID.`) + .requiredOption(`--table-id <table-id>`, `Table ID.`) + .requiredOption(`--key <key>`, `Column Key.`) + .requiredOption(`--required <required>`, `Is column required?`, parseBool) + .option(`--min <min>`, `Minimum value`, parseInteger) + .option(`--max <max>`, `Maximum value`, parseInteger) + .requiredOption( + `--default <default>`, + `Default value. Cannot be set when required.`, + parseInteger, + ) + .option(`--new-key <new-key>`, `New Column Key.`) + .action( + actionRunner( + async ({ + databaseId, + tableId, + key, + required, + min, + max, + xDefault, + newKey, + }) => + await ( + await getTablesDBClient() + ).updateFloatColumn( + databaseId, + tableId, + key, + required, + min, + max, + xDefault, + newKey, + ), + ), + ); + +tablesdb + .command(`create-integer-column`) + .description( + `Create an integer column. Optionally, minimum and maximum values can be provided. +`, + ) + .requiredOption(`--database-id <database-id>`, `Database ID.`) + .requiredOption(`--table-id <table-id>`, `Table ID.`) + .requiredOption(`--key <key>`, `Column Key.`) + .requiredOption(`--required <required>`, `Is column required?`, parseBool) + .option(`--min <min>`, `Minimum value`, parseInteger) + .option(`--max <max>`, `Maximum value`, parseInteger) + .option( + `--default <default>`, + `Default value. Cannot be set when column is required.`, + parseInteger, + ) + .option( + `--array [value]`, + `Is column an array?`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .action( + actionRunner( + async ({ + databaseId, + tableId, + key, + required, + min, + max, + xDefault, + array, + }) => + await ( + await getTablesDBClient() + ).createIntegerColumn( + databaseId, + tableId, + key, + required, + min, + max, + xDefault, + array, + ), + ), + ); + +tablesdb + .command(`update-integer-column`) + .description( + `Update an integer column. Changing the \`default\` value will not update already existing rows. +`, + ) + .requiredOption(`--database-id <database-id>`, `Database ID.`) + .requiredOption(`--table-id <table-id>`, `Table ID.`) + .requiredOption(`--key <key>`, `Column Key.`) + .requiredOption(`--required <required>`, `Is column required?`, parseBool) + .option(`--min <min>`, `Minimum value`, parseInteger) + .option(`--max <max>`, `Maximum value`, parseInteger) + .requiredOption( + `--default <default>`, + `Default value. Cannot be set when column is required.`, + parseInteger, + ) + .option(`--new-key <new-key>`, `New Column Key.`) + .action( + actionRunner( + async ({ + databaseId, + tableId, + key, + required, + min, + max, + xDefault, + newKey, + }) => + await ( + await getTablesDBClient() + ).updateIntegerColumn( + databaseId, + tableId, + key, + required, + min, + max, + xDefault, + newKey, + ), + ), + ); + +tablesdb + .command(`create-ip-column`) + .description( + `Create IP address column. +`, + ) + .requiredOption(`--database-id <database-id>`, `Database ID.`) + .requiredOption(`--table-id <table-id>`, `Table ID.`) + .requiredOption(`--key <key>`, `Column Key.`) + .requiredOption(`--required <required>`, `Is column required?`, parseBool) + .option( + `--default <default>`, + `Default value. Cannot be set when column is required.`, + ) + .option( + `--array [value]`, + `Is column an array?`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .action( + actionRunner( + async ({ databaseId, tableId, key, required, xDefault, array }) => + await ( + await getTablesDBClient() + ).createIpColumn(databaseId, tableId, key, required, xDefault, array), + ), + ); + +tablesdb + .command(`update-ip-column`) + .description( + `Update an ip column. Changing the \`default\` value will not update already existing rows. +`, + ) + .requiredOption(`--database-id <database-id>`, `Database ID.`) + .requiredOption(`--table-id <table-id>`, `Table ID.`) + .requiredOption(`--key <key>`, `Column Key.`) + .requiredOption(`--required <required>`, `Is column required?`, parseBool) + .requiredOption( + `--default <default>`, + `Default value. Cannot be set when column is required.`, + ) + .option(`--new-key <new-key>`, `New Column Key.`) + .action( + actionRunner( + async ({ databaseId, tableId, key, required, xDefault, newKey }) => + await ( + await getTablesDBClient() + ).updateIpColumn(databaseId, tableId, key, required, xDefault, newKey), + ), + ); + +tablesdb + .command(`create-line-column`) + .description(`Create a geometric line column.`) + .requiredOption(`--database-id <database-id>`, `Database ID.`) + .requiredOption( + `--table-id <table-id>`, + `Table ID. You can create a new table using the TablesDB service [server integration](https://appwrite.io/docs/references/cloud/server-dart/tablesDB#createTable).`, + ) + .requiredOption(`--key <key>`, `Column Key.`) + .requiredOption(`--required <required>`, `Is column required?`, parseBool) + .option( + `--default [default...]`, + `Default value for column when not provided, two-dimensional array of coordinate pairs, [[longitude, latitude], [longitude, latitude], …], listing the vertices of the line in order. Cannot be set when column is required.`, + ) + .action( + actionRunner( + async ({ databaseId, tableId, key, required, xDefault }) => + await ( + await getTablesDBClient() + ).createLineColumn(databaseId, tableId, key, required, xDefault), + ), + ); + +tablesdb + .command(`update-line-column`) + .description( + `Update a line column. Changing the \`default\` value will not update already existing rows.`, + ) + .requiredOption(`--database-id <database-id>`, `Database ID.`) + .requiredOption( + `--table-id <table-id>`, + `Table ID. You can create a new table using the TablesDB service [server integration](https://appwrite.io/docs/references/cloud/server-dart/tablesDB#createTable).`, + ) + .requiredOption(`--key <key>`, `Column Key.`) + .requiredOption(`--required <required>`, `Is column required?`, parseBool) + .option( + `--default [default...]`, + `Default value for column when not provided, two-dimensional array of coordinate pairs, [[longitude, latitude], [longitude, latitude], …], listing the vertices of the line in order. Cannot be set when column is required.`, + ) + .option(`--new-key <new-key>`, `New Column Key.`) + .action( + actionRunner( + async ({ databaseId, tableId, key, required, xDefault, newKey }) => + await ( + await getTablesDBClient() + ).updateLineColumn( + databaseId, + tableId, + key, + required, + xDefault, + newKey, + ), + ), + ); + +tablesdb + .command(`create-point-column`) + .description(`Create a geometric point column.`) + .requiredOption(`--database-id <database-id>`, `Database ID.`) + .requiredOption( + `--table-id <table-id>`, + `Table ID. You can create a new table using the TablesDB service [server integration](https://appwrite.io/docs/references/cloud/server-dart/tablesDB#createTable).`, + ) + .requiredOption(`--key <key>`, `Column Key.`) + .requiredOption(`--required <required>`, `Is column required?`, parseBool) + .option( + `--default [default...]`, + `Default value for column when not provided, array of two numbers [longitude, latitude], representing a single coordinate. Cannot be set when column is required.`, + ) + .action( + actionRunner( + async ({ databaseId, tableId, key, required, xDefault }) => + await ( + await getTablesDBClient() + ).createPointColumn(databaseId, tableId, key, required, xDefault), + ), + ); + +tablesdb + .command(`update-point-column`) + .description( + `Update a point column. Changing the \`default\` value will not update already existing rows.`, + ) + .requiredOption(`--database-id <database-id>`, `Database ID.`) + .requiredOption( + `--table-id <table-id>`, + `Table ID. You can create a new table using the TablesDB service [server integration](https://appwrite.io/docs/references/cloud/server-dart/tablesDB#createTable).`, + ) + .requiredOption(`--key <key>`, `Column Key.`) + .requiredOption(`--required <required>`, `Is column required?`, parseBool) + .option( + `--default [default...]`, + `Default value for column when not provided, array of two numbers [longitude, latitude], representing a single coordinate. Cannot be set when column is required.`, + ) + .option(`--new-key <new-key>`, `New Column Key.`) + .action( + actionRunner( + async ({ databaseId, tableId, key, required, xDefault, newKey }) => + await ( + await getTablesDBClient() + ).updatePointColumn( + databaseId, + tableId, + key, + required, + xDefault, + newKey, + ), + ), + ); + +tablesdb + .command(`create-polygon-column`) + .description(`Create a geometric polygon column.`) + .requiredOption(`--database-id <database-id>`, `Database ID.`) + .requiredOption( + `--table-id <table-id>`, + `Table ID. You can create a new table using the TablesDB service [server integration](https://appwrite.io/docs/references/cloud/server-dart/tablesDB#createTable).`, + ) + .requiredOption(`--key <key>`, `Column Key.`) + .requiredOption(`--required <required>`, `Is column required?`, parseBool) + .option( + `--default [default...]`, + `Default value for column when not provided, three-dimensional array where the outer array holds one or more linear rings, [[[longitude, latitude], …], …], the first ring is the exterior boundary, any additional rings are interior holes, and each ring must start and end with the same coordinate pair. Cannot be set when column is required.`, + ) + .action( + actionRunner( + async ({ databaseId, tableId, key, required, xDefault }) => + await ( + await getTablesDBClient() + ).createPolygonColumn(databaseId, tableId, key, required, xDefault), + ), + ); + +tablesdb + .command(`update-polygon-column`) + .description( + `Update a polygon column. Changing the \`default\` value will not update already existing rows.`, + ) + .requiredOption(`--database-id <database-id>`, `Database ID.`) + .requiredOption( + `--table-id <table-id>`, + `Table ID. You can create a new table using the TablesDB service [server integration](https://appwrite.io/docs/references/cloud/server-dart/tablesDB#createTable).`, + ) + .requiredOption(`--key <key>`, `Column Key.`) + .requiredOption(`--required <required>`, `Is column required?`, parseBool) + .option( + `--default [default...]`, + `Default value for column when not provided, three-dimensional array where the outer array holds one or more linear rings, [[[longitude, latitude], …], …], the first ring is the exterior boundary, any additional rings are interior holes, and each ring must start and end with the same coordinate pair. Cannot be set when column is required.`, + ) + .option(`--new-key <new-key>`, `New Column Key.`) + .action( + actionRunner( + async ({ databaseId, tableId, key, required, xDefault, newKey }) => + await ( + await getTablesDBClient() + ).updatePolygonColumn( + databaseId, + tableId, + key, + required, + xDefault, + newKey, + ), + ), + ); + +tablesdb + .command(`create-relationship-column`) + .description( + `Create relationship column. [Learn more about relationship columns](https://appwrite.io/docs/databases-relationships#relationship-columns). +`, + ) + .requiredOption(`--database-id <database-id>`, `Database ID.`) + .requiredOption(`--table-id <table-id>`, `Table ID.`) + .requiredOption(`--related-table-id <related-table-id>`, `Related Table ID.`) + .requiredOption(`--type <type>`, `Relation type`) + .option(`--two-way [value]`, `Is Two Way?`, (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .option(`--key <key>`, `Column Key.`) + .option(`--two-way-key <two-way-key>`, `Two Way Column Key.`) + .option(`--on-delete <on-delete>`, `Constraints option`) + .action( + actionRunner( + async ({ + databaseId, + tableId, + relatedTableId, + xType, + twoWay, + key, + twoWayKey, + onDelete, + }) => + await ( + await getTablesDBClient() + ).createRelationshipColumn( + databaseId, + tableId, + relatedTableId, + xType as RelationshipType, + twoWay, + key, + twoWayKey, + onDelete as RelationMutate, + ), + ), + ); + +tablesdb + .command(`create-string-column`) + .description( + `Create a string column. +`, + ) + .requiredOption(`--database-id <database-id>`, `Database ID.`) + .requiredOption( + `--table-id <table-id>`, + `Table ID. You can create a new table using the Database service [server integration](https://appwrite.io/docs/references/cloud/server-dart/tablesDB#createTable).`, + ) + .requiredOption(`--key <key>`, `Column Key.`) + .requiredOption( + `--size <size>`, + `Column size for text columns, in number of characters.`, + parseInteger, + ) + .requiredOption(`--required <required>`, `Is column required?`, parseBool) + .option( + `--default <default>`, + `Default value for column when not provided. Cannot be set when column is required.`, + ) + .option( + `--array [value]`, + `Is column an array?`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .option( + `--encrypt [value]`, + `Toggle encryption for the column. Encryption enhances security by not storing any plain text values in the database. However, encrypted columns cannot be queried.`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .action( + actionRunner( + async ({ + databaseId, + tableId, + key, + size, + required, + xDefault, + array, + encrypt, + }) => + await ( + await getTablesDBClient() + ).createStringColumn( + databaseId, + tableId, + key, + size, + required, + xDefault, + array, + encrypt, + ), + ), + ); + +tablesdb + .command(`update-string-column`) + .description( + `Update a string column. Changing the \`default\` value will not update already existing rows. +`, + ) + .requiredOption(`--database-id <database-id>`, `Database ID.`) + .requiredOption( + `--table-id <table-id>`, + `Table ID. You can create a new table using the Database service [server integration](https://appwrite.io/docs/references/cloud/server-dart/tablesDB#createTable).`, + ) + .requiredOption(`--key <key>`, `Column Key.`) + .requiredOption(`--required <required>`, `Is column required?`, parseBool) + .requiredOption( + `--default <default>`, + `Default value for column when not provided. Cannot be set when column is required.`, + ) + .option(`--size <size>`, `Maximum size of the string column.`, parseInteger) + .option(`--new-key <new-key>`, `New Column Key.`) + .action( + actionRunner( + async ({ databaseId, tableId, key, required, xDefault, size, newKey }) => + await ( + await getTablesDBClient() + ).updateStringColumn( + databaseId, + tableId, + key, + required, + xDefault, + size, + newKey, + ), + ), + ); + +tablesdb + .command(`create-url-column`) + .description( + `Create a URL column. +`, + ) + .requiredOption(`--database-id <database-id>`, `Database ID.`) + .requiredOption(`--table-id <table-id>`, `Table ID.`) + .requiredOption(`--key <key>`, `Column Key.`) + .requiredOption(`--required <required>`, `Is column required?`, parseBool) + .option( + `--default <default>`, + `Default value for column when not provided. Cannot be set when column is required.`, + ) + .option( + `--array [value]`, + `Is column an array?`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .action( + actionRunner( + async ({ databaseId, tableId, key, required, xDefault, array }) => + await ( + await getTablesDBClient() + ).createUrlColumn(databaseId, tableId, key, required, xDefault, array), + ), + ); + +tablesdb + .command(`update-url-column`) + .description( + `Update an url column. Changing the \`default\` value will not update already existing rows. +`, + ) + .requiredOption(`--database-id <database-id>`, `Database ID.`) + .requiredOption(`--table-id <table-id>`, `Table ID.`) + .requiredOption(`--key <key>`, `Column Key.`) + .requiredOption(`--required <required>`, `Is column required?`, parseBool) + .requiredOption( + `--default <default>`, + `Default value for column when not provided. Cannot be set when column is required.`, + ) + .option(`--new-key <new-key>`, `New Column Key.`) + .action( + actionRunner( + async ({ databaseId, tableId, key, required, xDefault, newKey }) => + await ( + await getTablesDBClient() + ).updateUrlColumn(databaseId, tableId, key, required, xDefault, newKey), + ), + ); + +tablesdb + .command(`get-column`) + .description(`Get column by ID.`) + .requiredOption(`--database-id <database-id>`, `Database ID.`) + .requiredOption(`--table-id <table-id>`, `Table ID.`) + .requiredOption(`--key <key>`, `Column Key.`) + .action( + actionRunner( + async ({ databaseId, tableId, key }) => + await (await getTablesDBClient()).getColumn(databaseId, tableId, key), + ), + ); + +tablesdb + .command(`delete-column`) + .description(`Deletes a column.`) + .requiredOption(`--database-id <database-id>`, `Database ID.`) + .requiredOption(`--table-id <table-id>`, `Table ID.`) + .requiredOption(`--key <key>`, `Column Key.`) + .action( + actionRunner( + async ({ databaseId, tableId, key }) => + await ( + await getTablesDBClient() + ).deleteColumn(databaseId, tableId, key), + ), + ); + +tablesdb + .command(`update-relationship-column`) + .description( + `Update relationship column. [Learn more about relationship columns](https://appwrite.io/docs/databases-relationships#relationship-columns). +`, + ) + .requiredOption(`--database-id <database-id>`, `Database ID.`) + .requiredOption(`--table-id <table-id>`, `Table ID.`) + .requiredOption(`--key <key>`, `Column Key.`) + .option(`--on-delete <on-delete>`, `Constraints option`) + .option(`--new-key <new-key>`, `New Column Key.`) + .action( + actionRunner( + async ({ databaseId, tableId, key, onDelete, newKey }) => + await ( + await getTablesDBClient() + ).updateRelationshipColumn( + databaseId, + tableId, + key, + onDelete as RelationMutate, + newKey, + ), + ), + ); + +tablesdb + .command(`list-indexes`) + .description(`List indexes on the table.`) + .requiredOption(`--database-id <database-id>`, `Database ID.`) + .requiredOption( + `--table-id <table-id>`, + `Table ID. You can create a new table using the Database service [server integration](https://appwrite.io/docs/references/cloud/server-dart/tablesDB#createTable).`, + ) + .option( + `--queries [queries...]`, + `Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following columns: key, type, status, attributes, error`, + ) + .option( + `--total [value]`, + `When set to false, the total count returned will be 0 and will not be calculated.`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .action( + actionRunner( + async ({ databaseId, tableId, queries, total }) => + await ( + await getTablesDBClient() + ).listIndexes(databaseId, tableId, queries, total), + ), + ); + +tablesdb + .command(`create-index`) + .description( + `Creates an index on the columns listed. Your index should include all the columns you will query in a single request. +Type can be \`key\`, \`fulltext\`, or \`unique\`.`, + ) + .requiredOption(`--database-id <database-id>`, `Database ID.`) + .requiredOption( + `--table-id <table-id>`, + `Table ID. You can create a new table using the Database service [server integration](https://appwrite.io/docs/references/cloud/server-dart/tablesDB#createTable).`, + ) + .requiredOption(`--key <key>`, `Index Key.`) + .requiredOption(`--type <type>`, `Index type.`) + .requiredOption( + `--columns [columns...]`, + `Array of columns to index. Maximum of 100 columns are allowed, each 32 characters long.`, + ) + .option( + `--orders [orders...]`, + `Array of index orders. Maximum of 100 orders are allowed.`, + ) + .option(`--lengths [lengths...]`, `Length of index. Maximum of 100`) + .action( + actionRunner( + async ({ databaseId, tableId, key, xType, columns, orders, lengths }) => + await ( + await getTablesDBClient() + ).createIndex( + databaseId, + tableId, + key, + xType as IndexType, + columns, + orders, + lengths, + ), + ), + ); + +tablesdb + .command(`get-index`) + .description(`Get index by ID.`) + .requiredOption(`--database-id <database-id>`, `Database ID.`) + .requiredOption( + `--table-id <table-id>`, + `Table ID. You can create a new table using the Database service [server integration](https://appwrite.io/docs/references/cloud/server-dart/tablesDB#createTable).`, + ) + .requiredOption(`--key <key>`, `Index Key.`) + .action( + actionRunner( + async ({ databaseId, tableId, key }) => + await (await getTablesDBClient()).getIndex(databaseId, tableId, key), + ), + ); + +tablesdb + .command(`delete-index`) + .description(`Delete an index.`) + .requiredOption(`--database-id <database-id>`, `Database ID.`) + .requiredOption( + `--table-id <table-id>`, + `Table ID. You can create a new table using the TablesDB service [server integration](https://appwrite.io/docs/references/cloud/server-dart/tablesDB#createTable).`, + ) + .requiredOption(`--key <key>`, `Index Key.`) + .action( + actionRunner( + async ({ databaseId, tableId, key }) => + await (await getTablesDBClient()).deleteIndex(databaseId, tableId, key), + ), + ); + +tablesdb + .command(`list-table-logs`) + .description(`Get the table activity logs list by its unique ID.`) + .requiredOption(`--database-id <database-id>`, `Database ID.`) + .requiredOption(`--table-id <table-id>`, `Table ID.`) + .option( + `--queries [queries...]`, + `Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Only supported methods are limit and offset`, + ) + .action( + actionRunner( + async ({ databaseId, tableId, queries }) => + await ( + await getTablesDBClient() + ).listTableLogs(databaseId, tableId, queries), + ), + ); + +tablesdb + .command(`list-rows`) + .description( + `Get a list of all the user's rows in a given table. You can use the query params to filter your results.`, + ) + .requiredOption(`--database-id <database-id>`, `Database ID.`) + .requiredOption( + `--table-id <table-id>`, + `Table ID. You can create a new table using the TablesDB service [server integration](https://appwrite.io/docs/products/databases/tables#create-table).`, + ) + .option( + `--queries [queries...]`, + `Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of 100 queries are allowed, each 4096 characters long.`, + ) + .option( + `--transaction-id <transaction-id>`, + `Transaction ID to read uncommitted changes within the transaction.`, + ) + .option( + `--total [value]`, + `When set to false, the total count returned will be 0 and will not be calculated.`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .action( + actionRunner( + async ({ databaseId, tableId, queries, transactionId, total }) => + await ( + await getTablesDBClient() + ).listRows(databaseId, tableId, queries, transactionId, total), + ), + ); + +tablesdb + .command(`create-row`) + .description( + `Create a new Row. Before using this route, you should create a new table resource using either a [server integration](https://appwrite.io/docs/references/cloud/server-dart/tablesDB#createTable) API or directly from your database console.`, + ) + .requiredOption(`--database-id <database-id>`, `Database ID.`) + .requiredOption( + `--table-id <table-id>`, + `Table ID. You can create a new table using the Database service [server integration](https://appwrite.io/docs/references/cloud/server-dart/tablesDB#createTable). Make sure to define columns before creating rows.`, + ) + .requiredOption( + `--row-id <row-id>`, + `Row ID. Choose a custom ID or generate a random ID with \`ID.unique()\`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.`, + ) + .requiredOption(`--data <data>`, `Row data as JSON object.`) + .option( + `--permissions [permissions...]`, + `An array of permissions strings. By default, only the current user is granted all permissions. [Learn more about permissions](https://appwrite.io/docs/permissions).`, + ) + .option( + `--transaction-id <transaction-id>`, + `Transaction ID for staging the operation.`, + ) + .action( + actionRunner( + async ({ + databaseId, + tableId, + rowId, + data, + permissions, + transactionId, + }) => + await ( + await getTablesDBClient() + ).createRow( + databaseId, + tableId, + rowId, + JSON.parse(data), + permissions, + transactionId, + ), + ), + ); + +tablesdb + .command(`upsert-rows`) + .description( + `Create or update Rows. Before using this route, you should create a new table resource using either a [server integration](https://appwrite.io/docs/references/cloud/server-dart/tablesDB#createTable) API or directly from your database console. +`, + ) + .requiredOption(`--database-id <database-id>`, `Database ID.`) + .requiredOption(`--table-id <table-id>`, `Table ID.`) + .requiredOption( + `--rows [rows...]`, + `Array of row data as JSON objects. May contain partial rows.`, + ) + .option( + `--transaction-id <transaction-id>`, + `Transaction ID for staging the operation.`, + ) + .action( + actionRunner( + async ({ databaseId, tableId, rows, transactionId }) => + await ( + await getTablesDBClient() + ).upsertRows(databaseId, tableId, rows, transactionId), + ), + ); + +tablesdb + .command(`update-rows`) + .description( + `Update all rows that match your queries, if no queries are submitted then all rows are updated. You can pass only specific fields to be updated.`, + ) + .requiredOption(`--database-id <database-id>`, `Database ID.`) + .requiredOption(`--table-id <table-id>`, `Table ID.`) + .option( + `--data <data>`, + `Row data as JSON object. Include only column and value pairs to be updated.`, + ) + .option( + `--queries [queries...]`, + `Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of 100 queries are allowed, each 4096 characters long.`, + ) + .option( + `--transaction-id <transaction-id>`, + `Transaction ID for staging the operation.`, + ) + .action( + actionRunner( + async ({ databaseId, tableId, data, queries, transactionId }) => + await ( + await getTablesDBClient() + ).updateRows( + databaseId, + tableId, + JSON.parse(data), + queries, + transactionId, + ), + ), + ); + +tablesdb + .command(`delete-rows`) + .description( + `Bulk delete rows using queries, if no queries are passed then all rows are deleted.`, + ) + .requiredOption(`--database-id <database-id>`, `Database ID.`) + .requiredOption( + `--table-id <table-id>`, + `Table ID. You can create a new table using the Database service [server integration](https://appwrite.io/docs/references/cloud/server-dart/tablesDB#createTable).`, + ) + .option( + `--queries [queries...]`, + `Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of 100 queries are allowed, each 4096 characters long.`, + ) + .option( + `--transaction-id <transaction-id>`, + `Transaction ID for staging the operation.`, + ) + .action( + actionRunner( + async ({ databaseId, tableId, queries, transactionId }) => + await ( + await getTablesDBClient() + ).deleteRows(databaseId, tableId, queries, transactionId), + ), + ); + +tablesdb + .command(`get-row`) + .description( + `Get a row by its unique ID. This endpoint response returns a JSON object with the row data.`, + ) + .requiredOption(`--database-id <database-id>`, `Database ID.`) + .requiredOption( + `--table-id <table-id>`, + `Table ID. You can create a new table using the Database service [server integration](https://appwrite.io/docs/references/cloud/server-dart/tablesDB#createTable).`, + ) + .requiredOption(`--row-id <row-id>`, `Row ID.`) + .option( + `--queries [queries...]`, + `Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of 100 queries are allowed, each 4096 characters long.`, + ) + .option( + `--transaction-id <transaction-id>`, + `Transaction ID to read uncommitted changes within the transaction.`, + ) + .action( + actionRunner( + async ({ databaseId, tableId, rowId, queries, transactionId }) => + await ( + await getTablesDBClient() + ).getRow(databaseId, tableId, rowId, queries, transactionId), + ), + ); + +tablesdb + .command(`upsert-row`) + .description( + `Create or update a Row. Before using this route, you should create a new table resource using either a [server integration](https://appwrite.io/docs/references/cloud/server-dart/tablesDB#createTable) API or directly from your database console.`, + ) + .requiredOption(`--database-id <database-id>`, `Database ID.`) + .requiredOption(`--table-id <table-id>`, `Table ID.`) + .requiredOption(`--row-id <row-id>`, `Row ID.`) + .option( + `--data <data>`, + `Row data as JSON object. Include all required columns of the row to be created or updated.`, + ) + .option( + `--permissions [permissions...]`, + `An array of permissions strings. By default, the current permissions are inherited. [Learn more about permissions](https://appwrite.io/docs/permissions).`, + ) + .option( + `--transaction-id <transaction-id>`, + `Transaction ID for staging the operation.`, + ) + .action( + actionRunner( + async ({ + databaseId, + tableId, + rowId, + data, + permissions, + transactionId, + }) => + await ( + await getTablesDBClient() + ).upsertRow( + databaseId, + tableId, + rowId, + JSON.parse(data), + permissions, + transactionId, + ), + ), + ); + +tablesdb + .command(`update-row`) + .description( + `Update a row by its unique ID. Using the patch method you can pass only specific fields that will get updated.`, + ) + .requiredOption(`--database-id <database-id>`, `Database ID.`) + .requiredOption(`--table-id <table-id>`, `Table ID.`) + .requiredOption(`--row-id <row-id>`, `Row ID.`) + .option( + `--data <data>`, + `Row data as JSON object. Include only columns and value pairs to be updated.`, + ) + .option( + `--permissions [permissions...]`, + `An array of permissions strings. By default, the current permissions are inherited. [Learn more about permissions](https://appwrite.io/docs/permissions).`, + ) + .option( + `--transaction-id <transaction-id>`, + `Transaction ID for staging the operation.`, + ) + .action( + actionRunner( + async ({ + databaseId, + tableId, + rowId, + data, + permissions, + transactionId, + }) => + await ( + await getTablesDBClient() + ).updateRow( + databaseId, + tableId, + rowId, + JSON.parse(data), + permissions, + transactionId, + ), + ), + ); + +tablesdb + .command(`delete-row`) + .description(`Delete a row by its unique ID.`) + .requiredOption(`--database-id <database-id>`, `Database ID.`) + .requiredOption( + `--table-id <table-id>`, + `Table ID. You can create a new table using the Database service [server integration](https://appwrite.io/docs/references/cloud/server-dart/tablesDB#createTable).`, + ) + .requiredOption(`--row-id <row-id>`, `Row ID.`) + .option( + `--transaction-id <transaction-id>`, + `Transaction ID for staging the operation.`, + ) + .action( + actionRunner( + async ({ databaseId, tableId, rowId, transactionId }) => + await ( + await getTablesDBClient() + ).deleteRow(databaseId, tableId, rowId, transactionId), + ), + ); + +tablesdb + .command(`list-row-logs`) + .description(`Get the row activity logs list by its unique ID.`) + .requiredOption(`--database-id <database-id>`, `Database ID.`) + .requiredOption(`--table-id <table-id>`, `Table ID.`) + .requiredOption(`--row-id <row-id>`, `Row ID.`) + .option( + `--queries [queries...]`, + `Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Only supported methods are limit and offset`, + ) + .action( + actionRunner( + async ({ databaseId, tableId, rowId, queries }) => + await ( + await getTablesDBClient() + ).listRowLogs(databaseId, tableId, rowId, queries), + ), + ); + +tablesdb + .command(`decrement-row-column`) + .description(`Decrement a specific column of a row by a given value.`) + .requiredOption(`--database-id <database-id>`, `Database ID.`) + .requiredOption(`--table-id <table-id>`, `Table ID.`) + .requiredOption(`--row-id <row-id>`, `Row ID.`) + .requiredOption(`--column <column>`, `Column key.`) + .option( + `--value <value>`, + `Value to increment the column by. The value must be a number.`, + parseInteger, + ) + .option( + `--min <min>`, + `Minimum value for the column. If the current value is lesser than this value, an exception will be thrown.`, + parseInteger, + ) + .option( + `--transaction-id <transaction-id>`, + `Transaction ID for staging the operation.`, + ) + .action( + actionRunner( + async ({ + databaseId, + tableId, + rowId, + column, + value, + min, + transactionId, + }) => + await ( + await getTablesDBClient() + ).decrementRowColumn( + databaseId, + tableId, + rowId, + column, + value, + min, + transactionId, + ), + ), + ); + +tablesdb + .command(`increment-row-column`) + .description(`Increment a specific column of a row by a given value.`) + .requiredOption(`--database-id <database-id>`, `Database ID.`) + .requiredOption(`--table-id <table-id>`, `Table ID.`) + .requiredOption(`--row-id <row-id>`, `Row ID.`) + .requiredOption(`--column <column>`, `Column key.`) + .option( + `--value <value>`, + `Value to increment the column by. The value must be a number.`, + parseInteger, + ) + .option( + `--max <max>`, + `Maximum value for the column. If the current value is greater than this value, an error will be thrown.`, + parseInteger, + ) + .option( + `--transaction-id <transaction-id>`, + `Transaction ID for staging the operation.`, + ) + .action( + actionRunner( + async ({ + databaseId, + tableId, + rowId, + column, + value, + max, + transactionId, + }) => + await ( + await getTablesDBClient() + ).incrementRowColumn( + databaseId, + tableId, + rowId, + column, + value, + max, + transactionId, + ), + ), + ); + +tablesdb + .command(`get-table-usage`) + .description( + `Get usage metrics and statistics for a table. Returning the total number of rows. The response includes both current totals and historical data over time. Use the optional range parameter to specify the time window for historical data: 24h (last 24 hours), 30d (last 30 days), or 90d (last 90 days). If not specified, range defaults to 30 days.`, + ) + .requiredOption(`--database-id <database-id>`, `Database ID.`) + .option(`--range <range>`, `Date range.`) + .requiredOption(`--table-id <table-id>`, `Table ID.`) + .action( + actionRunner( + async ({ databaseId, range, tableId }) => + await ( + await getTablesDBClient() + ).getTableUsage(databaseId, range as UsageRange, tableId), + ), + ); + +tablesdb + .command(`get-usage`) + .description( + `Get usage metrics and statistics for a database. You can view the total number of tables, rows, and storage usage. The response includes both current totals and historical data over time. Use the optional range parameter to specify the time window for historical data: 24h (last 24 hours), 30d (last 30 days), or 90d (last 90 days). If not specified, range defaults to 30 days.`, + ) + .requiredOption(`--database-id <database-id>`, `Database ID.`) + .option(`--range <range>`, `Date range.`) + .action( + actionRunner( + async ({ databaseId, range }) => + await ( + await getTablesDBClient() + ).getUsage(databaseId, range as UsageRange), + ), + ); diff --git a/lib/commands/services/teams.ts b/lib/commands/services/teams.ts new file mode 100644 index 00000000..aca176d1 --- /dev/null +++ b/lib/commands/services/teams.ts @@ -0,0 +1,294 @@ +import { Command } from "commander"; +import { sdkForProject } from "../../sdks.js"; +import { + actionRunner, + commandDescriptions, + parseBool, + parseInteger, +} from "../../parser.js"; +import { Teams } from "@appwrite.io/console"; + +let teamsClient: Teams | null = null; + +const getTeamsClient = async (): Promise<Teams> => { + if (!teamsClient) { + const sdkClient = await sdkForProject(); + teamsClient = new Teams(sdkClient); + } + return teamsClient; +}; + +export const teams = new Command("teams") + .description(commandDescriptions["teams"] ?? "") + .configureHelp({ + helpWidth: process.stdout.columns || 80, + }); + +teams + .command(`list`) + .description( + `Get a list of all the teams in which the current user is a member. You can use the parameters to filter your results.`, + ) + .option( + `--queries [queries...]`, + `Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: name, total, billingPlan`, + ) + .option( + `--search <search>`, + `Search term to filter your list results. Max length: 256 chars.`, + ) + .option( + `--total [value]`, + `When set to false, the total count returned will be 0 and will not be calculated.`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .action( + actionRunner( + async ({ queries, search, total }) => + await (await getTeamsClient()).list(queries, search, total), + ), + ); + +teams + .command(`create`) + .description( + `Create a new team. The user who creates the team will automatically be assigned as the owner of the team. Only the users with the owner role can invite new members, add new owners and delete or update the team.`, + ) + .requiredOption( + `--team-id <team-id>`, + `Team ID. Choose a custom ID or generate a random ID with \`ID.unique()\`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.`, + ) + .requiredOption(`--name <name>`, `Team name. Max length: 128 chars.`) + .option( + `--roles [roles...]`, + `Array of strings. Use this param to set the roles in the team for the user who created it. The default role is **owner**. A role can be any string. Learn more about [roles and permissions](https://appwrite.io/docs/permissions). Maximum of 100 roles are allowed, each 32 characters long.`, + ) + .action( + actionRunner( + async ({ teamId, name, roles }) => + await (await getTeamsClient()).create(teamId, name, roles), + ), + ); + +teams + .command(`get`) + .description( + `Get a team by its ID. All team members have read access for this resource.`, + ) + .requiredOption(`--team-id <team-id>`, `Team ID.`) + .action( + actionRunner( + async ({ teamId }) => await (await getTeamsClient()).get(teamId), + ), + ); + +teams + .command(`update-name`) + .description(`Update the team's name by its unique ID.`) + .requiredOption(`--team-id <team-id>`, `Team ID.`) + .requiredOption(`--name <name>`, `New team name. Max length: 128 chars.`) + .action( + actionRunner( + async ({ teamId, name }) => + await (await getTeamsClient()).updateName(teamId, name), + ), + ); + +teams + .command(`delete`) + .description( + `Delete a team using its ID. Only team members with the owner role can delete the team.`, + ) + .requiredOption(`--team-id <team-id>`, `Team ID.`) + .action( + actionRunner( + async ({ teamId }) => await (await getTeamsClient()).delete(teamId), + ), + ); + +teams + .command(`list-logs`) + .description(`Get the team activity logs list by its unique ID.`) + .requiredOption(`--team-id <team-id>`, `Team ID.`) + .option( + `--queries [queries...]`, + `Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Only supported methods are limit and offset`, + ) + .option( + `--total [value]`, + `When set to false, the total count returned will be 0 and will not be calculated.`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .action( + actionRunner( + async ({ teamId, queries, total }) => + await (await getTeamsClient()).listLogs(teamId, queries, total), + ), + ); + +teams + .command(`list-memberships`) + .description( + `Use this endpoint to list a team's members using the team's ID. All team members have read access to this endpoint. Hide sensitive attributes from the response by toggling membership privacy in the Console.`, + ) + .requiredOption(`--team-id <team-id>`, `Team ID.`) + .option( + `--queries [queries...]`, + `Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: userId, teamId, invited, joined, confirm, roles`, + ) + .option( + `--search <search>`, + `Search term to filter your list results. Max length: 256 chars.`, + ) + .option( + `--total [value]`, + `When set to false, the total count returned will be 0 and will not be calculated.`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .action( + actionRunner( + async ({ teamId, queries, search, total }) => + await ( + await getTeamsClient() + ).listMemberships(teamId, queries, search, total), + ), + ); + +teams + .command(`create-membership`) + .description( + `Invite a new member to join your team. Provide an ID for existing users, or invite unregistered users using an email or phone number. If initiated from a Client SDK, Appwrite will send an email or sms with a link to join the team to the invited user, and an account will be created for them if one doesn't exist. If initiated from a Server SDK, the new member will be added automatically to the team. + +You only need to provide one of a user ID, email, or phone number. Appwrite will prioritize accepting the user ID > email > phone number if you provide more than one of these parameters. + +Use the \`url\` parameter to redirect the user from the invitation email to your app. After the user is redirected, use the [Update Team Membership Status](https://appwrite.io/docs/references/cloud/client-web/teams#updateMembershipStatus) endpoint to allow the user to accept the invitation to the team. + +Please note that to avoid a [Redirect Attack](https://github.com/OWASP/CheatSheetSeries/blob/master/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.md) Appwrite will accept the only redirect URLs under the domains you have added as a platform on the Appwrite Console. +`, + ) + .requiredOption(`--team-id <team-id>`, `Team ID.`) + .option(`--email <email>`, `Email of the new team member.`) + .option(`--user-id <user-id>`, `ID of the user to be added to a team.`) + .option( + `--phone <phone>`, + `Phone number. Format this number with a leading '+' and a country code, e.g., +16175551212.`, + ) + .requiredOption( + `--roles [roles...]`, + `Array of strings. Use this param to set the user roles in the team. A role can be any string. Learn more about [roles and permissions](https://appwrite.io/docs/permissions). Maximum of 100 roles are allowed, each 32 characters long.`, + ) + .option( + `--url <url>`, + `URL to redirect the user back to your app from the invitation email. This parameter is not required when an API key is supplied. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.`, + ) + .option( + `--name <name>`, + `Name of the new team member. Max length: 128 chars.`, + ) + .action( + actionRunner( + async ({ teamId, email, userId, phone, roles, url, name }) => + await ( + await getTeamsClient() + ).createMembership(teamId, email, userId, phone, roles, url, name), + ), + ); + +teams + .command(`get-membership`) + .description( + `Get a team member by the membership unique id. All team members have read access for this resource. Hide sensitive attributes from the response by toggling membership privacy in the Console.`, + ) + .requiredOption(`--team-id <team-id>`, `Team ID.`) + .requiredOption(`--membership-id <membership-id>`, `Membership ID.`) + .action( + actionRunner( + async ({ teamId, membershipId }) => + await (await getTeamsClient()).getMembership(teamId, membershipId), + ), + ); + +teams + .command(`update-membership`) + .description( + `Modify the roles of a team member. Only team members with the owner role have access to this endpoint. Learn more about [roles and permissions](https://appwrite.io/docs/permissions). +`, + ) + .requiredOption(`--team-id <team-id>`, `Team ID.`) + .requiredOption(`--membership-id <membership-id>`, `Membership ID.`) + .requiredOption( + `--roles [roles...]`, + `An array of strings. Use this param to set the user's roles in the team. A role can be any string. Learn more about [roles and permissions](https://appwrite.io/docs/permissions). Maximum of 100 roles are allowed, each 32 characters long.`, + ) + .action( + actionRunner( + async ({ teamId, membershipId, roles }) => + await ( + await getTeamsClient() + ).updateMembership(teamId, membershipId, roles), + ), + ); + +teams + .command(`delete-membership`) + .description( + `This endpoint allows a user to leave a team or for a team owner to delete the membership of any other team member. You can also use this endpoint to delete a user membership even if it is not accepted.`, + ) + .requiredOption(`--team-id <team-id>`, `Team ID.`) + .requiredOption(`--membership-id <membership-id>`, `Membership ID.`) + .action( + actionRunner( + async ({ teamId, membershipId }) => + await (await getTeamsClient()).deleteMembership(teamId, membershipId), + ), + ); + +teams + .command(`update-membership-status`) + .description( + `Use this endpoint to allow a user to accept an invitation to join a team after being redirected back to your app from the invitation email received by the user. + +If the request is successful, a session for the user is automatically created. +`, + ) + .requiredOption(`--team-id <team-id>`, `Team ID.`) + .requiredOption(`--membership-id <membership-id>`, `Membership ID.`) + .requiredOption(`--user-id <user-id>`, `User ID.`) + .requiredOption(`--secret <secret>`, `Secret key.`) + .action( + actionRunner( + async ({ teamId, membershipId, userId, secret }) => + await ( + await getTeamsClient() + ).updateMembershipStatus(teamId, membershipId, userId, secret), + ), + ); + +teams + .command(`get-prefs`) + .description( + `Get the team's shared preferences by its unique ID. If a preference doesn't need to be shared by all team members, prefer storing them in [user preferences](https://appwrite.io/docs/references/cloud/client-web/account#getPrefs).`, + ) + .requiredOption(`--team-id <team-id>`, `Team ID.`) + .action( + actionRunner( + async ({ teamId }) => await (await getTeamsClient()).getPrefs(teamId), + ), + ); + +teams + .command(`update-prefs`) + .description( + `Update the team's preferences by its unique ID. The object you pass is stored as is and replaces any previous value. The maximum allowed prefs size is 64kB and throws an error if exceeded.`, + ) + .requiredOption(`--team-id <team-id>`, `Team ID.`) + .requiredOption(`--prefs <prefs>`, `Prefs key-value JSON object.`) + .action( + actionRunner( + async ({ teamId, prefs }) => + await (await getTeamsClient()).updatePrefs(teamId, JSON.parse(prefs)), + ), + ); diff --git a/lib/commands/services/tokens.ts b/lib/commands/services/tokens.ts new file mode 100644 index 00000000..f9354456 --- /dev/null +++ b/lib/commands/services/tokens.ts @@ -0,0 +1,106 @@ +import { Command } from "commander"; +import { sdkForProject } from "../../sdks.js"; +import { + actionRunner, + commandDescriptions, + parseBool, + parseInteger, +} from "../../parser.js"; +import { Tokens } from "@appwrite.io/console"; + +let tokensClient: Tokens | null = null; + +const getTokensClient = async (): Promise<Tokens> => { + if (!tokensClient) { + const sdkClient = await sdkForProject(); + tokensClient = new Tokens(sdkClient); + } + return tokensClient; +}; + +export const tokens = new Command("tokens") + .description(commandDescriptions["tokens"] ?? "") + .configureHelp({ + helpWidth: process.stdout.columns || 80, + }); + +tokens + .command(`list`) + .description( + `List all the tokens created for a specific file or bucket. You can use the query params to filter your results.`, + ) + .requiredOption( + `--bucket-id <bucket-id>`, + `Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](https://appwrite.io/docs/server/storage#createBucket).`, + ) + .requiredOption(`--file-id <file-id>`, `File unique ID.`) + .option( + `--queries [queries...]`, + `Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: expire`, + ) + .option( + `--total [value]`, + `When set to false, the total count returned will be 0 and will not be calculated.`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .action( + actionRunner( + async ({ bucketId, fileId, queries, total }) => + await (await getTokensClient()).list(bucketId, fileId, queries, total), + ), + ); + +tokens + .command(`create-file-token`) + .description( + `Create a new token. A token is linked to a file. Token can be passed as a request URL search parameter.`, + ) + .requiredOption( + `--bucket-id <bucket-id>`, + `Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](https://appwrite.io/docs/server/storage#createBucket).`, + ) + .requiredOption(`--file-id <file-id>`, `File unique ID.`) + .option(`--expire <expire>`, `Token expiry date`) + .action( + actionRunner( + async ({ bucketId, fileId, expire }) => + await ( + await getTokensClient() + ).createFileToken(bucketId, fileId, expire), + ), + ); + +tokens + .command(`get`) + .description(`Get a token by its unique ID.`) + .requiredOption(`--token-id <token-id>`, `Token ID.`) + .action( + actionRunner( + async ({ tokenId }) => await (await getTokensClient()).get(tokenId), + ), + ); + +tokens + .command(`update`) + .description( + `Update a token by its unique ID. Use this endpoint to update a token's expiry date.`, + ) + .requiredOption(`--token-id <token-id>`, `Token unique ID.`) + .option(`--expire <expire>`, `File token expiry date`) + .action( + actionRunner( + async ({ tokenId, expire }) => + await (await getTokensClient()).update(tokenId, expire), + ), + ); + +tokens + .command(`delete`) + .description(`Delete a token by its unique ID.`) + .requiredOption(`--token-id <token-id>`, `Token ID.`) + .action( + actionRunner( + async ({ tokenId }) => await (await getTokensClient()).delete(tokenId), + ), + ); diff --git a/lib/commands/services/users.ts b/lib/commands/services/users.ts new file mode 100644 index 00000000..eb177dbf --- /dev/null +++ b/lib/commands/services/users.ts @@ -0,0 +1,886 @@ +import { Command } from "commander"; +import { sdkForProject } from "../../sdks.js"; +import { + actionRunner, + commandDescriptions, + parseBool, + parseInteger, +} from "../../parser.js"; +import { + Users, + PasswordHash, + UsageRange, + AuthenticatorType, + MessagingProviderType, +} from "@appwrite.io/console"; + +let usersClient: Users | null = null; + +const getUsersClient = async (): Promise<Users> => { + if (!usersClient) { + const sdkClient = await sdkForProject(); + usersClient = new Users(sdkClient); + } + return usersClient; +}; + +export const users = new Command("users") + .description(commandDescriptions["users"] ?? "") + .configureHelp({ + helpWidth: process.stdout.columns || 80, + }); + +users + .command(`list`) + .description( + `Get a list of all the project's users. You can use the query params to filter your results.`, + ) + .option( + `--queries [queries...]`, + `Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: name, email, phone, status, passwordUpdate, registration, emailVerification, phoneVerification, labels`, + ) + .option( + `--search <search>`, + `Search term to filter your list results. Max length: 256 chars.`, + ) + .option( + `--total [value]`, + `When set to false, the total count returned will be 0 and will not be calculated.`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .action( + actionRunner( + async ({ queries, search, total }) => + await (await getUsersClient()).list(queries, search, total), + ), + ); + +users + .command(`create`) + .description(`Create a new user.`) + .requiredOption( + `--user-id <user-id>`, + `User ID. Choose a custom ID or generate a random ID with \`ID.unique()\`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.`, + ) + .option(`--email <email>`, `User email.`) + .option( + `--phone <phone>`, + `Phone number. Format this number with a leading '+' and a country code, e.g., +16175551212.`, + ) + .option( + `--password <password>`, + `Plain text user password. Must be at least 8 chars.`, + ) + .option(`--name <name>`, `User name. Max length: 128 chars.`) + .action( + actionRunner( + async ({ userId, email, phone, password, name }) => + await ( + await getUsersClient() + ).create(userId, email, phone, password, name), + ), + ); + +users + .command(`create-argon2-user`) + .description( + `Create a new user. Password provided must be hashed with the [Argon2](https://en.wikipedia.org/wiki/Argon2) algorithm. Use the [POST /users](https://appwrite.io/docs/server/users#usersCreate) endpoint to create users with a plain text password.`, + ) + .requiredOption( + `--user-id <user-id>`, + `User ID. Choose a custom ID or generate a random ID with \`ID.unique()\`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.`, + ) + .requiredOption(`--email <email>`, `User email.`) + .requiredOption(`--password <password>`, `User password hashed using Argon2.`) + .option(`--name <name>`, `User name. Max length: 128 chars.`) + .action( + actionRunner( + async ({ userId, email, password, name }) => + await ( + await getUsersClient() + ).createArgon2User(userId, email, password, name), + ), + ); + +users + .command(`create-bcrypt-user`) + .description( + `Create a new user. Password provided must be hashed with the [Bcrypt](https://en.wikipedia.org/wiki/Bcrypt) algorithm. Use the [POST /users](https://appwrite.io/docs/server/users#usersCreate) endpoint to create users with a plain text password.`, + ) + .requiredOption( + `--user-id <user-id>`, + `User ID. Choose a custom ID or generate a random ID with \`ID.unique()\`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.`, + ) + .requiredOption(`--email <email>`, `User email.`) + .requiredOption(`--password <password>`, `User password hashed using Bcrypt.`) + .option(`--name <name>`, `User name. Max length: 128 chars.`) + .action( + actionRunner( + async ({ userId, email, password, name }) => + await ( + await getUsersClient() + ).createBcryptUser(userId, email, password, name), + ), + ); + +users + .command(`list-identities`) + .description(`Get identities for all users.`) + .option( + `--queries [queries...]`, + `Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: userId, provider, providerUid, providerEmail, providerAccessTokenExpiry`, + ) + .option( + `--search <search>`, + `Search term to filter your list results. Max length: 256 chars.`, + ) + .option( + `--total [value]`, + `When set to false, the total count returned will be 0 and will not be calculated.`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .action( + actionRunner( + async ({ queries, search, total }) => + await (await getUsersClient()).listIdentities(queries, search, total), + ), + ); + +users + .command(`delete-identity`) + .description(`Delete an identity by its unique ID.`) + .requiredOption(`--identity-id <identity-id>`, `Identity ID.`) + .action( + actionRunner( + async ({ identityId }) => + await (await getUsersClient()).deleteIdentity(identityId), + ), + ); + +users + .command(`create-md5-user`) + .description( + `Create a new user. Password provided must be hashed with the [MD5](https://en.wikipedia.org/wiki/MD5) algorithm. Use the [POST /users](https://appwrite.io/docs/server/users#usersCreate) endpoint to create users with a plain text password.`, + ) + .requiredOption( + `--user-id <user-id>`, + `User ID. Choose a custom ID or generate a random ID with \`ID.unique()\`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.`, + ) + .requiredOption(`--email <email>`, `User email.`) + .requiredOption(`--password <password>`, `User password hashed using MD5.`) + .option(`--name <name>`, `User name. Max length: 128 chars.`) + .action( + actionRunner( + async ({ userId, email, password, name }) => + await ( + await getUsersClient() + ).createMD5User(userId, email, password, name), + ), + ); + +users + .command(`create-phpass-user`) + .description( + `Create a new user. Password provided must be hashed with the [PHPass](https://www.openwall.com/phpass/) algorithm. Use the [POST /users](https://appwrite.io/docs/server/users#usersCreate) endpoint to create users with a plain text password.`, + ) + .requiredOption( + `--user-id <user-id>`, + `User ID. Choose a custom ID or pass the string \`ID.unique()\`to auto generate it. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.`, + ) + .requiredOption(`--email <email>`, `User email.`) + .requiredOption(`--password <password>`, `User password hashed using PHPass.`) + .option(`--name <name>`, `User name. Max length: 128 chars.`) + .action( + actionRunner( + async ({ userId, email, password, name }) => + await ( + await getUsersClient() + ).createPHPassUser(userId, email, password, name), + ), + ); + +users + .command(`create-scrypt-user`) + .description( + `Create a new user. Password provided must be hashed with the [Scrypt](https://github.com/Tarsnap/scrypt) algorithm. Use the [POST /users](https://appwrite.io/docs/server/users#usersCreate) endpoint to create users with a plain text password.`, + ) + .requiredOption( + `--user-id <user-id>`, + `User ID. Choose a custom ID or generate a random ID with \`ID.unique()\`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.`, + ) + .requiredOption(`--email <email>`, `User email.`) + .requiredOption(`--password <password>`, `User password hashed using Scrypt.`) + .requiredOption( + `--password-salt <password-salt>`, + `Optional salt used to hash password.`, + ) + .requiredOption( + `--password-cpu <password-cpu>`, + `Optional CPU cost used to hash password.`, + parseInteger, + ) + .requiredOption( + `--password-memory <password-memory>`, + `Optional memory cost used to hash password.`, + parseInteger, + ) + .requiredOption( + `--password-parallel <password-parallel>`, + `Optional parallelization cost used to hash password.`, + parseInteger, + ) + .requiredOption( + `--password-length <password-length>`, + `Optional hash length used to hash password.`, + parseInteger, + ) + .option(`--name <name>`, `User name. Max length: 128 chars.`) + .action( + actionRunner( + async ({ + userId, + email, + password, + passwordSalt, + passwordCpu, + passwordMemory, + passwordParallel, + passwordLength, + name, + }) => + await ( + await getUsersClient() + ).createScryptUser( + userId, + email, + password, + passwordSalt, + passwordCpu, + passwordMemory, + passwordParallel, + passwordLength, + name, + ), + ), + ); + +users + .command(`create-scrypt-modified-user`) + .description( + `Create a new user. Password provided must be hashed with the [Scrypt Modified](https://gist.github.com/Meldiron/eecf84a0225eccb5a378d45bb27462cc) algorithm. Use the [POST /users](https://appwrite.io/docs/server/users#usersCreate) endpoint to create users with a plain text password.`, + ) + .requiredOption( + `--user-id <user-id>`, + `User ID. Choose a custom ID or generate a random ID with \`ID.unique()\`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.`, + ) + .requiredOption(`--email <email>`, `User email.`) + .requiredOption( + `--password <password>`, + `User password hashed using Scrypt Modified.`, + ) + .requiredOption( + `--password-salt <password-salt>`, + `Salt used to hash password.`, + ) + .requiredOption( + `--password-salt-separator <password-salt-separator>`, + `Salt separator used to hash password.`, + ) + .requiredOption( + `--password-signer-key <password-signer-key>`, + `Signer key used to hash password.`, + ) + .option(`--name <name>`, `User name. Max length: 128 chars.`) + .action( + actionRunner( + async ({ + userId, + email, + password, + passwordSalt, + passwordSaltSeparator, + passwordSignerKey, + name, + }) => + await ( + await getUsersClient() + ).createScryptModifiedUser( + userId, + email, + password, + passwordSalt, + passwordSaltSeparator, + passwordSignerKey, + name, + ), + ), + ); + +users + .command(`create-shauser`) + .description( + `Create a new user. Password provided must be hashed with the [SHA](https://en.wikipedia.org/wiki/Secure_Hash_Algorithm) algorithm. Use the [POST /users](https://appwrite.io/docs/server/users#usersCreate) endpoint to create users with a plain text password.`, + ) + .requiredOption( + `--user-id <user-id>`, + `User ID. Choose a custom ID or generate a random ID with \`ID.unique()\`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.`, + ) + .requiredOption(`--email <email>`, `User email.`) + .requiredOption(`--password <password>`, `User password hashed using SHA.`) + .option( + `--password-version <password-version>`, + `Optional SHA version used to hash password. Allowed values are: 'sha1', 'sha224', 'sha256', 'sha384', 'sha512/224', 'sha512/256', 'sha512', 'sha3-224', 'sha3-256', 'sha3-384', 'sha3-512'`, + ) + .option(`--name <name>`, `User name. Max length: 128 chars.`) + .action( + actionRunner( + async ({ userId, email, password, passwordVersion, name }) => + await ( + await getUsersClient() + ).createSHAUser( + userId, + email, + password, + passwordVersion as PasswordHash, + name, + ), + ), + ); + +users + .command(`get-usage`) + .description( + `Get usage metrics and statistics for all users in the project. You can view the total number of users and sessions. The response includes both current totals and historical data over time. Use the optional range parameter to specify the time window for historical data: 24h (last 24 hours), 30d (last 30 days), or 90d (last 90 days). If not specified, range defaults to 30 days. +`, + ) + .option(`--range <range>`, `Date range.`) + .action( + actionRunner( + async ({ range }) => + await (await getUsersClient()).getUsage(range as UsageRange), + ), + ); + +users + .command(`get`) + .description(`Get a user by its unique ID.`) + .requiredOption(`--user-id <user-id>`, `User ID.`) + .action( + actionRunner( + async ({ userId }) => await (await getUsersClient()).get(userId), + ), + ); + +users + .command(`delete`) + .description( + `Delete a user by its unique ID, thereby releasing it's ID. Since ID is released and can be reused, all user-related resources like documents or storage files should be deleted before user deletion. If you want to keep ID reserved, use the [updateStatus](https://appwrite.io/docs/server/users#usersUpdateStatus) endpoint instead.`, + ) + .requiredOption(`--user-id <user-id>`, `User ID.`) + .action( + actionRunner( + async ({ userId }) => await (await getUsersClient()).delete(userId), + ), + ); + +users + .command(`update-email`) + .description(`Update the user email by its unique ID.`) + .requiredOption(`--user-id <user-id>`, `User ID.`) + .requiredOption(`--email <email>`, `User email.`) + .action( + actionRunner( + async ({ userId, email }) => + await (await getUsersClient()).updateEmail(userId, email), + ), + ); + +users + .command(`create-jwt`) + .description( + `Use this endpoint to create a JSON Web Token for user by its unique ID. You can use the resulting JWT to authenticate on behalf of the user. The JWT secret will become invalid if the session it uses gets deleted.`, + ) + .requiredOption(`--user-id <user-id>`, `User ID.`) + .option( + `--session-id <session-id>`, + `Session ID. Use the string 'recent' to use the most recent session. Defaults to the most recent session.`, + ) + .option( + `--duration <duration>`, + `Time in seconds before JWT expires. Default duration is 900 seconds, and maximum is 3600 seconds.`, + parseInteger, + ) + .action( + actionRunner( + async ({ userId, sessionId, duration }) => + await (await getUsersClient()).createJWT(userId, sessionId, duration), + ), + ); + +users + .command(`update-labels`) + .description( + `Update the user labels by its unique ID. + +Labels can be used to grant access to resources. While teams are a way for user's to share access to a resource, labels can be defined by the developer to grant access without an invitation. See the [Permissions docs](https://appwrite.io/docs/permissions) for more info.`, + ) + .requiredOption(`--user-id <user-id>`, `User ID.`) + .requiredOption( + `--labels [labels...]`, + `Array of user labels. Replaces the previous labels. Maximum of 1000 labels are allowed, each up to 36 alphanumeric characters long.`, + ) + .action( + actionRunner( + async ({ userId, labels }) => + await (await getUsersClient()).updateLabels(userId, labels), + ), + ); + +users + .command(`list-logs`) + .description(`Get the user activity logs list by its unique ID.`) + .requiredOption(`--user-id <user-id>`, `User ID.`) + .option( + `--queries [queries...]`, + `Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Only supported methods are limit and offset`, + ) + .option( + `--total [value]`, + `When set to false, the total count returned will be 0 and will not be calculated.`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .action( + actionRunner( + async ({ userId, queries, total }) => + await (await getUsersClient()).listLogs(userId, queries, total), + ), + ); + +users + .command(`list-memberships`) + .description(`Get the user membership list by its unique ID.`) + .requiredOption(`--user-id <user-id>`, `User ID.`) + .option( + `--queries [queries...]`, + `Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: userId, teamId, invited, joined, confirm, roles`, + ) + .option( + `--search <search>`, + `Search term to filter your list results. Max length: 256 chars.`, + ) + .option( + `--total [value]`, + `When set to false, the total count returned will be 0 and will not be calculated.`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .action( + actionRunner( + async ({ userId, queries, search, total }) => + await ( + await getUsersClient() + ).listMemberships(userId, queries, search, total), + ), + ); + +users + .command(`update-mfa`) + .description( + `[**DEPRECATED** - This command is deprecated. Please use 'users updateMfa' instead] Enable or disable MFA on a user account.`, + ) + .requiredOption(`--user-id <user-id>`, `User ID.`) + .requiredOption(`--mfa <mfa>`, `Enable or disable MFA.`, parseBool) + .action( + actionRunner( + async ({ userId, mfa }) => + await (await getUsersClient()).updateMfa(userId, mfa), + ), + ); + +users + .command(`delete-mfa-authenticator`) + .description( + `[**DEPRECATED** - This command is deprecated. Please use 'users deleteMfaAuthenticator' instead] Delete an authenticator app.`, + ) + .requiredOption(`--user-id <user-id>`, `User ID.`) + .requiredOption(`--type <type>`, `Type of authenticator.`) + .action( + actionRunner( + async ({ userId, xType }) => + await ( + await getUsersClient() + ).deleteMfaAuthenticator(userId, xType as AuthenticatorType), + ), + ); + +users + .command(`list-mfa-factors`) + .description( + `[**DEPRECATED** - This command is deprecated. Please use 'users listMfaFactors' instead] List the factors available on the account to be used as a MFA challange.`, + ) + .requiredOption(`--user-id <user-id>`, `User ID.`) + .action( + actionRunner( + async ({ userId }) => + await (await getUsersClient()).listMfaFactors(userId), + ), + ); + +users + .command(`get-mfa-recovery-codes`) + .description( + `[**DEPRECATED** - This command is deprecated. Please use 'users getMfaRecoveryCodes' instead] Get recovery codes that can be used as backup for MFA flow by User ID. Before getting codes, they must be generated using [createMfaRecoveryCodes](/docs/references/cloud/client-web/account#createMfaRecoveryCodes) method.`, + ) + .requiredOption(`--user-id <user-id>`, `User ID.`) + .action( + actionRunner( + async ({ userId }) => + await (await getUsersClient()).getMfaRecoveryCodes(userId), + ), + ); + +users + .command(`update-mfa-recovery-codes`) + .description( + `[**DEPRECATED** - This command is deprecated. Please use 'users updateMfaRecoveryCodes' instead] Regenerate recovery codes that can be used as backup for MFA flow by User ID. Before regenerating codes, they must be first generated using [createMfaRecoveryCodes](/docs/references/cloud/client-web/account#createMfaRecoveryCodes) method.`, + ) + .requiredOption(`--user-id <user-id>`, `User ID.`) + .action( + actionRunner( + async ({ userId }) => + await (await getUsersClient()).updateMfaRecoveryCodes(userId), + ), + ); + +users + .command(`create-mfa-recovery-codes`) + .description( + `[**DEPRECATED** - This command is deprecated. Please use 'users createMfaRecoveryCodes' instead] Generate recovery codes used as backup for MFA flow for User ID. Recovery codes can be used as a MFA verification type in [createMfaChallenge](/docs/references/cloud/client-web/account#createMfaChallenge) method by client SDK.`, + ) + .requiredOption(`--user-id <user-id>`, `User ID.`) + .action( + actionRunner( + async ({ userId }) => + await (await getUsersClient()).createMfaRecoveryCodes(userId), + ), + ); + +users + .command(`update-name`) + .description(`Update the user name by its unique ID.`) + .requiredOption(`--user-id <user-id>`, `User ID.`) + .requiredOption(`--name <name>`, `User name. Max length: 128 chars.`) + .action( + actionRunner( + async ({ userId, name }) => + await (await getUsersClient()).updateName(userId, name), + ), + ); + +users + .command(`update-password`) + .description(`Update the user password by its unique ID.`) + .requiredOption(`--user-id <user-id>`, `User ID.`) + .requiredOption( + `--password <password>`, + `New user password. Must be at least 8 chars.`, + ) + .action( + actionRunner( + async ({ userId, password }) => + await (await getUsersClient()).updatePassword(userId, password), + ), + ); + +users + .command(`update-phone`) + .description(`Update the user phone by its unique ID.`) + .requiredOption(`--user-id <user-id>`, `User ID.`) + .requiredOption(`--number <number>`, `User phone number.`) + .action( + actionRunner( + async ({ userId, number }) => + await (await getUsersClient()).updatePhone(userId, number), + ), + ); + +users + .command(`get-prefs`) + .description(`Get the user preferences by its unique ID.`) + .requiredOption(`--user-id <user-id>`, `User ID.`) + .action( + actionRunner( + async ({ userId }) => await (await getUsersClient()).getPrefs(userId), + ), + ); + +users + .command(`update-prefs`) + .description( + `Update the user preferences by its unique ID. The object you pass is stored as is, and replaces any previous value. The maximum allowed prefs size is 64kB and throws error if exceeded.`, + ) + .requiredOption(`--user-id <user-id>`, `User ID.`) + .requiredOption(`--prefs <prefs>`, `Prefs key-value JSON object.`) + .action( + actionRunner( + async ({ userId, prefs }) => + await (await getUsersClient()).updatePrefs(userId, JSON.parse(prefs)), + ), + ); + +users + .command(`list-sessions`) + .description(`Get the user sessions list by its unique ID.`) + .requiredOption(`--user-id <user-id>`, `User ID.`) + .option( + `--total [value]`, + `When set to false, the total count returned will be 0 and will not be calculated.`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .action( + actionRunner( + async ({ userId, total }) => + await (await getUsersClient()).listSessions(userId, total), + ), + ); + +users + .command(`create-session`) + .description( + `Creates a session for a user. Returns an immediately usable session object. + +If you want to generate a token for a custom authentication flow, use the [POST /users/{userId}/tokens](https://appwrite.io/docs/server/users#createToken) endpoint.`, + ) + .requiredOption( + `--user-id <user-id>`, + `User ID. Choose a custom ID or generate a random ID with \`ID.unique()\`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.`, + ) + .action( + actionRunner( + async ({ userId }) => + await (await getUsersClient()).createSession(userId), + ), + ); + +users + .command(`delete-sessions`) + .description(`Delete all user's sessions by using the user's unique ID.`) + .requiredOption(`--user-id <user-id>`, `User ID.`) + .action( + actionRunner( + async ({ userId }) => + await (await getUsersClient()).deleteSessions(userId), + ), + ); + +users + .command(`delete-session`) + .description(`Delete a user sessions by its unique ID.`) + .requiredOption(`--user-id <user-id>`, `User ID.`) + .requiredOption(`--session-id <session-id>`, `Session ID.`) + .action( + actionRunner( + async ({ userId, sessionId }) => + await (await getUsersClient()).deleteSession(userId, sessionId), + ), + ); + +users + .command(`update-status`) + .description( + `Update the user status by its unique ID. Use this endpoint as an alternative to deleting a user if you want to keep user's ID reserved.`, + ) + .requiredOption(`--user-id <user-id>`, `User ID.`) + .requiredOption( + `--status <status>`, + `User Status. To activate the user pass \`true\` and to block the user pass \`false\`.`, + parseBool, + ) + .action( + actionRunner( + async ({ userId, status }) => + await (await getUsersClient()).updateStatus(userId, status), + ), + ); + +users + .command(`list-targets`) + .description(`List the messaging targets that are associated with a user.`) + .requiredOption(`--user-id <user-id>`, `User ID.`) + .option( + `--queries [queries...]`, + `Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: userId, providerId, identifier, providerType`, + ) + .option( + `--total [value]`, + `When set to false, the total count returned will be 0 and will not be calculated.`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .action( + actionRunner( + async ({ userId, queries, total }) => + await (await getUsersClient()).listTargets(userId, queries, total), + ), + ); + +users + .command(`create-target`) + .description(`Create a messaging target.`) + .requiredOption(`--user-id <user-id>`, `User ID.`) + .requiredOption( + `--target-id <target-id>`, + `Target ID. Choose a custom ID or generate a random ID with \`ID.unique()\`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.`, + ) + .requiredOption( + `--provider-type <provider-type>`, + `The target provider type. Can be one of the following: \`email\`, \`sms\` or \`push\`.`, + ) + .requiredOption( + `--identifier <identifier>`, + `The target identifier (token, email, phone etc.)`, + ) + .option( + `--provider-id <provider-id>`, + `Provider ID. Message will be sent to this target from the specified provider ID. If no provider ID is set the first setup provider will be used.`, + ) + .option( + `--name <name>`, + `Target name. Max length: 128 chars. For example: My Awesome App Galaxy S23.`, + ) + .action( + actionRunner( + async ({ + userId, + targetId, + providerType, + identifier, + providerId, + name, + }) => + await ( + await getUsersClient() + ).createTarget( + userId, + targetId, + providerType as MessagingProviderType, + identifier, + providerId, + name, + ), + ), + ); + +users + .command(`get-target`) + .description(`Get a user's push notification target by ID.`) + .requiredOption(`--user-id <user-id>`, `User ID.`) + .requiredOption(`--target-id <target-id>`, `Target ID.`) + .action( + actionRunner( + async ({ userId, targetId }) => + await (await getUsersClient()).getTarget(userId, targetId), + ), + ); + +users + .command(`update-target`) + .description(`Update a messaging target.`) + .requiredOption(`--user-id <user-id>`, `User ID.`) + .requiredOption(`--target-id <target-id>`, `Target ID.`) + .option( + `--identifier <identifier>`, + `The target identifier (token, email, phone etc.)`, + ) + .option( + `--provider-id <provider-id>`, + `Provider ID. Message will be sent to this target from the specified provider ID. If no provider ID is set the first setup provider will be used.`, + ) + .option( + `--name <name>`, + `Target name. Max length: 128 chars. For example: My Awesome App Galaxy S23.`, + ) + .action( + actionRunner( + async ({ userId, targetId, identifier, providerId, name }) => + await ( + await getUsersClient() + ).updateTarget(userId, targetId, identifier, providerId, name), + ), + ); + +users + .command(`delete-target`) + .description(`Delete a messaging target.`) + .requiredOption(`--user-id <user-id>`, `User ID.`) + .requiredOption(`--target-id <target-id>`, `Target ID.`) + .action( + actionRunner( + async ({ userId, targetId }) => + await (await getUsersClient()).deleteTarget(userId, targetId), + ), + ); + +users + .command(`create-token`) + .description( + `Returns a token with a secret key for creating a session. Use the user ID and secret and submit a request to the [PUT /account/sessions/token](https://appwrite.io/docs/references/cloud/client-web/account#createSession) endpoint to complete the login process. +`, + ) + .requiredOption(`--user-id <user-id>`, `User ID.`) + .option( + `--length <length>`, + `Token length in characters. The default length is 6 characters`, + parseInteger, + ) + .option( + `--expire <expire>`, + `Token expiration period in seconds. The default expiration is 15 minutes.`, + parseInteger, + ) + .action( + actionRunner( + async ({ userId, length, expire }) => + await (await getUsersClient()).createToken(userId, length, expire), + ), + ); + +users + .command(`update-email-verification`) + .description(`Update the user email verification status by its unique ID.`) + .requiredOption(`--user-id <user-id>`, `User ID.`) + .requiredOption( + `--email-verification <email-verification>`, + `User email verification status.`, + parseBool, + ) + .action( + actionRunner( + async ({ userId, emailVerification }) => + await ( + await getUsersClient() + ).updateEmailVerification(userId, emailVerification), + ), + ); + +users + .command(`update-phone-verification`) + .description(`Update the user phone verification status by its unique ID.`) + .requiredOption(`--user-id <user-id>`, `User ID.`) + .requiredOption( + `--phone-verification <phone-verification>`, + `User phone verification status.`, + parseBool, + ) + .action( + actionRunner( + async ({ userId, phoneVerification }) => + await ( + await getUsersClient() + ).updatePhoneVerification(userId, phoneVerification), + ), + ); diff --git a/lib/commands/services/vcs.ts b/lib/commands/services/vcs.ts new file mode 100644 index 00000000..14711580 --- /dev/null +++ b/lib/commands/services/vcs.ts @@ -0,0 +1,268 @@ +import { Command } from "commander"; +import { sdkForProject } from "../../sdks.js"; +import { + actionRunner, + commandDescriptions, + parseBool, + parseInteger, +} from "../../parser.js"; +import { Vcs, VCSDetectionType } from "@appwrite.io/console"; + +let vcsClient: Vcs | null = null; + +const getVcsClient = async (): Promise<Vcs> => { + if (!vcsClient) { + const sdkClient = await sdkForProject(); + vcsClient = new Vcs(sdkClient); + } + return vcsClient; +}; + +export const vcs = new Command("vcs") + .description(commandDescriptions["vcs"] ?? "") + .configureHelp({ + helpWidth: process.stdout.columns || 80, + }); + +vcs + .command(`create-repository-detection`) + .description( + `Analyze a GitHub repository to automatically detect the programming language and runtime environment. This endpoint scans the repository's files and language statistics to determine the appropriate runtime settings for your function. The GitHub installation must be properly configured and the repository must be accessible through your installation for this endpoint to work.`, + ) + .requiredOption(`--installation-id <installation-id>`, `Installation Id`) + .requiredOption( + `--provider-repository-id <provider-repository-id>`, + `Repository Id`, + ) + .requiredOption( + `--type <type>`, + `Detector type. Must be one of the following: runtime, framework`, + ) + .option( + `--provider-root-directory <provider-root-directory>`, + `Path to Root Directory`, + ) + .action( + actionRunner( + async ({ + installationId, + providerRepositoryId, + xType, + providerRootDirectory, + }) => + await ( + await getVcsClient() + ).createRepositoryDetection( + installationId, + providerRepositoryId, + xType as VCSDetectionType, + providerRootDirectory, + ), + ), + ); + +vcs + .command(`list-repositories`) + .description( + `Get a list of GitHub repositories available through your installation. This endpoint returns repositories with their basic information, detected runtime environments, and latest push dates. You can optionally filter repositories using a search term. Each repository's runtime is automatically detected based on its contents and language statistics. The GitHub installation must be properly configured for this endpoint to work.`, + ) + .requiredOption(`--installation-id <installation-id>`, `Installation Id`) + .requiredOption( + `--type <type>`, + `Detector type. Must be one of the following: runtime, framework`, + ) + .option( + `--search <search>`, + `Search term to filter your list results. Max length: 256 chars.`, + ) + .option( + `--queries [queries...]`, + `Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Only supported methods are limit and offset`, + ) + .action( + actionRunner( + async ({ installationId, xType, search, queries }) => + await ( + await getVcsClient() + ).listRepositories( + installationId, + xType as VCSDetectionType, + search, + queries, + ), + ), + ); + +vcs + .command(`create-repository`) + .description( + `Create a new GitHub repository through your installation. This endpoint allows you to create either a public or private repository by specifying a name and visibility setting. The repository will be created under your GitHub user account or organization, depending on your installation type. The GitHub installation must be properly configured and have the necessary permissions for repository creation.`, + ) + .requiredOption(`--installation-id <installation-id>`, `Installation Id`) + .requiredOption(`--name <name>`, `Repository name (slug)`) + .requiredOption( + `--private <private>`, + `Mark repository public or private`, + parseBool, + ) + .action( + actionRunner( + async ({ installationId, name, xPrivate }) => + await ( + await getVcsClient() + ).createRepository(installationId, name, xPrivate), + ), + ); + +vcs + .command(`get-repository`) + .description( + `Get detailed information about a specific GitHub repository from your installation. This endpoint returns repository details including its ID, name, visibility status, organization, and latest push date. The GitHub installation must be properly configured and have access to the requested repository for this endpoint to work.`, + ) + .requiredOption(`--installation-id <installation-id>`, `Installation Id`) + .requiredOption( + `--provider-repository-id <provider-repository-id>`, + `Repository Id`, + ) + .action( + actionRunner( + async ({ installationId, providerRepositoryId }) => + await ( + await getVcsClient() + ).getRepository(installationId, providerRepositoryId), + ), + ); + +vcs + .command(`list-repository-branches`) + .description( + `Get a list of all branches from a GitHub repository in your installation. This endpoint returns the names of all branches in the repository and their total count. The GitHub installation must be properly configured and have access to the requested repository for this endpoint to work. +`, + ) + .requiredOption(`--installation-id <installation-id>`, `Installation Id`) + .requiredOption( + `--provider-repository-id <provider-repository-id>`, + `Repository Id`, + ) + .action( + actionRunner( + async ({ installationId, providerRepositoryId }) => + await ( + await getVcsClient() + ).listRepositoryBranches(installationId, providerRepositoryId), + ), + ); + +vcs + .command(`get-repository-contents`) + .description( + `Get a list of files and directories from a GitHub repository connected to your project. This endpoint returns the contents of a specified repository path, including file names, sizes, and whether each item is a file or directory. The GitHub installation must be properly configured and the repository must be accessible through your installation for this endpoint to work.`, + ) + .requiredOption(`--installation-id <installation-id>`, `Installation Id`) + .requiredOption( + `--provider-repository-id <provider-repository-id>`, + `Repository Id`, + ) + .option( + `--provider-root-directory <provider-root-directory>`, + `Path to get contents of nested directory`, + ) + .option( + `--provider-reference <provider-reference>`, + `Git reference (branch, tag, commit) to get contents from`, + ) + .action( + actionRunner( + async ({ + installationId, + providerRepositoryId, + providerRootDirectory, + providerReference, + }) => + await ( + await getVcsClient() + ).getRepositoryContents( + installationId, + providerRepositoryId, + providerRootDirectory, + providerReference, + ), + ), + ); + +vcs + .command(`update-external-deployments`) + .description( + `Authorize and create deployments for a GitHub pull request in your project. This endpoint allows external contributions by creating deployments from pull requests, enabling preview environments for code review. The pull request must be open and not previously authorized. The GitHub installation must be properly configured and have access to both the repository and pull request for this endpoint to work.`, + ) + .requiredOption(`--installation-id <installation-id>`, `Installation Id`) + .requiredOption(`--repository-id <repository-id>`, `VCS Repository Id`) + .requiredOption( + `--provider-pull-request-id <provider-pull-request-id>`, + `GitHub Pull Request Id`, + ) + .action( + actionRunner( + async ({ installationId, repositoryId, providerPullRequestId }) => + await ( + await getVcsClient() + ).updateExternalDeployments( + installationId, + repositoryId, + providerPullRequestId, + ), + ), + ); + +vcs + .command(`list-installations`) + .description( + `List all VCS installations configured for the current project. This endpoint returns a list of installations including their provider, organization, and other configuration details. +`, + ) + .option( + `--queries [queries...]`, + `Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: provider, organization`, + ) + .option( + `--search <search>`, + `Search term to filter your list results. Max length: 256 chars.`, + ) + .option( + `--total [value]`, + `When set to false, the total count returned will be 0 and will not be calculated.`, + (value: string | undefined) => + value === undefined ? true : parseBool(value), + ) + .action( + actionRunner( + async ({ queries, search, total }) => + await (await getVcsClient()).listInstallations(queries, search, total), + ), + ); + +vcs + .command(`get-installation`) + .description( + `Get a VCS installation by its unique ID. This endpoint returns the installation's details including its provider, organization, and configuration. `, + ) + .requiredOption(`--installation-id <installation-id>`, `Installation Id`) + .action( + actionRunner( + async ({ installationId }) => + await (await getVcsClient()).getInstallation(installationId), + ), + ); + +vcs + .command(`delete-installation`) + .description( + `Delete a VCS installation by its unique ID. This endpoint removes the installation and all its associated repositories from the project.`, + ) + .requiredOption(`--installation-id <installation-id>`, `Installation Id`) + .action( + actionRunner( + async ({ installationId }) => + await (await getVcsClient()).deleteInstallation(installationId), + ), + ); diff --git a/lib/commands/sites.ts b/lib/commands/sites.ts deleted file mode 100644 index f213f386..00000000 --- a/lib/commands/sites.ts +++ /dev/null @@ -1,1514 +0,0 @@ -import fs = require('fs'); -import pathLib = require('path'); -import tar = require('tar'); -import ignore = require('ignore'); -import { promisify } from 'util'; -import Client from '../client'; -import { getAllFiles, showConsoleLink } from '../utils'; -import { Command } from 'commander'; -import { sdkForProject, sdkForConsole } from '../sdks'; -import { parse, actionRunner, parseInteger, parseBool, commandDescriptions, success, log, warn } from '../parser'; -import { localConfig, globalConfig } from '../config'; -import { File } from 'undici'; -import { ReadableStream } from 'stream/web'; - -function convertReadStreamToReadableStream(readStream: fs.ReadStream): ReadableStream { - return new ReadableStream({ - start(controller) { - readStream.on("data", (chunk: Buffer) => { - controller.enqueue(chunk); - }); - readStream.on("end", () => { - controller.close(); - }); - readStream.on("error", (err: Error) => { - controller.error(err); - }); - }, - cancel() { - readStream.destroy(); - }, - }); -} - -export const sites = new Command("sites").description(commandDescriptions['sites'] ?? '').configureHelp({ - helpWidth: process.stdout.columns || 80 -}) - -interface SitesListRequestParams { - queries?: string[]; - search?: string; - total?: boolean; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; - console?: boolean; -} - -export const sitesList = async ({queries,search,total,parseOutput = true, overrideForCli = false, sdk = undefined, console: showConsole}: SitesListRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/sites'; - let payload = {}; - if (typeof queries !== 'undefined') { - payload['queries'] = queries; - } - if (typeof search !== 'undefined') { - payload['search'] = search; - } - if (typeof total !== 'undefined') { - payload['total'] = total; - } - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - if(showConsole) { - showConsoleLink('sites', 'list'); - } else { - parse(response) - } - } - - return response; - -} -interface SitesCreateRequestParams { - siteId: string; - name: string; - framework: Framework; - buildRuntime: BuildRuntime; - enabled?: boolean; - logging?: boolean; - timeout?: number; - installCommand?: string; - buildCommand?: string; - outputDirectory?: string; - adapter?: Adapter; - installationId?: string; - fallbackFile?: string; - providerRepositoryId?: string; - providerBranch?: string; - providerSilentMode?: boolean; - providerRootDirectory?: string; - specification?: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const sitesCreate = async ({siteId,name,framework,buildRuntime,enabled,logging,timeout,installCommand,buildCommand,outputDirectory,adapter,installationId,fallbackFile,providerRepositoryId,providerBranch,providerSilentMode,providerRootDirectory,specification,parseOutput = true, overrideForCli = false, sdk = undefined}: SitesCreateRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/sites'; - let payload = {}; - if (typeof siteId !== 'undefined') { - payload['siteId'] = siteId; - } - if (typeof name !== 'undefined') { - payload['name'] = name; - } - if (typeof framework !== 'undefined') { - payload['framework'] = framework; - } - if (typeof enabled !== 'undefined') { - payload['enabled'] = enabled; - } - if (typeof logging !== 'undefined') { - payload['logging'] = logging; - } - if (typeof timeout !== 'undefined') { - payload['timeout'] = timeout; - } - if (typeof installCommand !== 'undefined') { - payload['installCommand'] = installCommand; - } - if (typeof buildCommand !== 'undefined') { - payload['buildCommand'] = buildCommand; - } - if (typeof outputDirectory !== 'undefined') { - payload['outputDirectory'] = outputDirectory; - } - if (typeof buildRuntime !== 'undefined') { - payload['buildRuntime'] = buildRuntime; - } - if (typeof adapter !== 'undefined') { - payload['adapter'] = adapter; - } - if (typeof installationId !== 'undefined') { - payload['installationId'] = installationId; - } - if (typeof fallbackFile !== 'undefined') { - payload['fallbackFile'] = fallbackFile; - } - if (typeof providerRepositoryId !== 'undefined') { - payload['providerRepositoryId'] = providerRepositoryId; - } - if (typeof providerBranch !== 'undefined') { - payload['providerBranch'] = providerBranch; - } - if (typeof providerSilentMode !== 'undefined') { - payload['providerSilentMode'] = providerSilentMode; - } - if (typeof providerRootDirectory !== 'undefined') { - payload['providerRootDirectory'] = providerRootDirectory; - } - if (typeof specification !== 'undefined') { - payload['specification'] = specification; - } - - let response = undefined; - - response = await client.call('post', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface SitesListFrameworksRequestParams { - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; - console?: boolean; -} - -export const sitesListFrameworks = async ({parseOutput = true, overrideForCli = false, sdk = undefined, console: showConsole}: SitesListFrameworksRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/sites/frameworks'; - let payload = {}; - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - if(showConsole) { - showConsoleLink('sites', 'listFrameworks'); - } else { - parse(response) - } - } - - return response; - -} -interface SitesListSpecificationsRequestParams { - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; - console?: boolean; -} - -export const sitesListSpecifications = async ({parseOutput = true, overrideForCli = false, sdk = undefined, console: showConsole}: SitesListSpecificationsRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/sites/specifications'; - let payload = {}; - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - if(showConsole) { - showConsoleLink('sites', 'listSpecifications'); - } else { - parse(response) - } - } - - return response; - -} -interface SitesListTemplatesRequestParams { - frameworks?: string[]; - useCases?: string[]; - limit?: number; - offset?: number; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; - console?: boolean; -} - -export const sitesListTemplates = async ({frameworks,useCases,limit,offset,parseOutput = true, overrideForCli = false, sdk = undefined, console: showConsole}: SitesListTemplatesRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/sites/templates'; - let payload = {}; - if (typeof frameworks !== 'undefined') { - payload['frameworks'] = frameworks; - } - if (typeof useCases !== 'undefined') { - payload['useCases'] = useCases; - } - if (typeof limit !== 'undefined') { - payload['limit'] = limit; - } - if (typeof offset !== 'undefined') { - payload['offset'] = offset; - } - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - if(showConsole) { - showConsoleLink('sites', 'listTemplates'); - } else { - parse(response) - } - } - - return response; - -} -interface SitesGetTemplateRequestParams { - templateId: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; - console?: boolean; -} - -export const sitesGetTemplate = async ({templateId,parseOutput = true, overrideForCli = false, sdk = undefined, console: showConsole}: SitesGetTemplateRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/sites/templates/{templateId}'.replace('{templateId}', templateId); - let payload = {}; - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - if(showConsole) { - showConsoleLink('sites', 'getTemplate', templateId); - } else { - parse(response) - } - } - - return response; - -} -interface SitesListUsageRequestParams { - range?: UsageRange; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; - console?: boolean; -} - -export const sitesListUsage = async ({range,parseOutput = true, overrideForCli = false, sdk = undefined, console: showConsole}: SitesListUsageRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/sites/usage'; - let payload = {}; - if (typeof range !== 'undefined') { - payload['range'] = range; - } - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - if(showConsole) { - showConsoleLink('sites', 'listUsage'); - } else { - parse(response) - } - } - - return response; - -} -interface SitesGetRequestParams { - siteId: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; - console?: boolean; -} - -export const sitesGet = async ({siteId,parseOutput = true, overrideForCli = false, sdk = undefined, console: showConsole}: SitesGetRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/sites/{siteId}'.replace('{siteId}', siteId); - let payload = {}; - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - if(showConsole) { - showConsoleLink('sites', 'get', siteId); - } else { - parse(response) - } - } - - return response; - -} -interface SitesUpdateRequestParams { - siteId: string; - name: string; - framework: Framework; - enabled?: boolean; - logging?: boolean; - timeout?: number; - installCommand?: string; - buildCommand?: string; - outputDirectory?: string; - buildRuntime?: BuildRuntime; - adapter?: Adapter; - fallbackFile?: string; - installationId?: string; - providerRepositoryId?: string; - providerBranch?: string; - providerSilentMode?: boolean; - providerRootDirectory?: string; - specification?: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const sitesUpdate = async ({siteId,name,framework,enabled,logging,timeout,installCommand,buildCommand,outputDirectory,buildRuntime,adapter,fallbackFile,installationId,providerRepositoryId,providerBranch,providerSilentMode,providerRootDirectory,specification,parseOutput = true, overrideForCli = false, sdk = undefined}: SitesUpdateRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/sites/{siteId}'.replace('{siteId}', siteId); - let payload = {}; - if (typeof name !== 'undefined') { - payload['name'] = name; - } - if (typeof framework !== 'undefined') { - payload['framework'] = framework; - } - if (typeof enabled !== 'undefined') { - payload['enabled'] = enabled; - } - if (typeof logging !== 'undefined') { - payload['logging'] = logging; - } - if (typeof timeout !== 'undefined') { - payload['timeout'] = timeout; - } - if (typeof installCommand !== 'undefined') { - payload['installCommand'] = installCommand; - } - if (typeof buildCommand !== 'undefined') { - payload['buildCommand'] = buildCommand; - } - if (typeof outputDirectory !== 'undefined') { - payload['outputDirectory'] = outputDirectory; - } - if (typeof buildRuntime !== 'undefined') { - payload['buildRuntime'] = buildRuntime; - } - if (typeof adapter !== 'undefined') { - payload['adapter'] = adapter; - } - if (typeof fallbackFile !== 'undefined') { - payload['fallbackFile'] = fallbackFile; - } - if (typeof installationId !== 'undefined') { - payload['installationId'] = installationId; - } - if (typeof providerRepositoryId !== 'undefined') { - payload['providerRepositoryId'] = providerRepositoryId; - } - if (typeof providerBranch !== 'undefined') { - payload['providerBranch'] = providerBranch; - } - if (typeof providerSilentMode !== 'undefined') { - payload['providerSilentMode'] = providerSilentMode; - } - if (typeof providerRootDirectory !== 'undefined') { - payload['providerRootDirectory'] = providerRootDirectory; - } - if (typeof specification !== 'undefined') { - payload['specification'] = specification; - } - - let response = undefined; - - response = await client.call('put', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface SitesDeleteRequestParams { - siteId: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const sitesDelete = async ({siteId,parseOutput = true, overrideForCli = false, sdk = undefined}: SitesDeleteRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/sites/{siteId}'.replace('{siteId}', siteId); - let payload = {}; - - let response = undefined; - - response = await client.call('delete', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface SitesUpdateSiteDeploymentRequestParams { - siteId: string; - deploymentId: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const sitesUpdateSiteDeployment = async ({siteId,deploymentId,parseOutput = true, overrideForCli = false, sdk = undefined}: SitesUpdateSiteDeploymentRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/sites/{siteId}/deployment'.replace('{siteId}', siteId); - let payload = {}; - if (typeof deploymentId !== 'undefined') { - payload['deploymentId'] = deploymentId; - } - - let response = undefined; - - response = await client.call('patch', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface SitesListDeploymentsRequestParams { - siteId: string; - queries?: string[]; - search?: string; - total?: boolean; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; - console?: boolean; -} - -export const sitesListDeployments = async ({siteId,queries,search,total,parseOutput = true, overrideForCli = false, sdk = undefined, console: showConsole}: SitesListDeploymentsRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/sites/{siteId}/deployments'.replace('{siteId}', siteId); - let payload = {}; - if (typeof queries !== 'undefined') { - payload['queries'] = queries; - } - if (typeof search !== 'undefined') { - payload['search'] = search; - } - if (typeof total !== 'undefined') { - payload['total'] = total; - } - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - if(showConsole) { - showConsoleLink('sites', 'listDeployments', siteId); - } else { - parse(response) - } - } - - return response; - -} -interface SitesCreateDeploymentRequestParams { - siteId: string; - code: string; - activate: boolean; - installCommand?: string; - buildCommand?: string; - outputDirectory?: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; - onProgress?: (progress: number) => void; -} - -export const sitesCreateDeployment = async ({siteId,code,activate,installCommand,buildCommand,outputDirectory,parseOutput = true, overrideForCli = false, sdk = undefined,onProgress = () => {}}: SitesCreateDeploymentRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/sites/{siteId}/deployments'.replace('{siteId}', siteId); - let payload = {}; - if (typeof installCommand !== 'undefined') { - payload['installCommand'] = installCommand; - } - if (typeof buildCommand !== 'undefined') { - payload['buildCommand'] = buildCommand; - } - if (typeof outputDirectory !== 'undefined') { - payload['outputDirectory'] = outputDirectory; - } - const folderPath = fs.realpathSync(code); - if (!fs.lstatSync(folderPath).isDirectory()) { - throw new Error('The path is not a directory.'); - } - - const ignorer = ignore(); - - const resourceId = siteId; - const resourceConfig = localConfig.getSite(resourceId); - - ignorer.add('.appwrite'); - - if (resourceConfig.ignore) { - ignorer.add(resourceConfig.ignore); - } else if (fs.existsSync(pathLib.join(code, '.gitignore'))) { - ignorer.add(fs.readFileSync(pathLib.join(code, '.gitignore')).toString()); - } - - const files = getAllFiles(code).map((file) => pathLib.relative(code, file)).filter((file) => !ignorer.ignores(file)); - - const archiveFileName = `sites-${resourceId}-code.tar.gz`; - - await tar - .create({ - gzip: true, - sync: true, - cwd: folderPath, - file: archiveFileName - }, files); - - let archivePath = fs.realpathSync(archiveFileName) - if (typeof archivePath !== 'undefined') { - payload['code'] = archivePath; - code = archivePath; - } - - const filePath = fs.realpathSync(code); - const nodeStream = fs.createReadStream(filePath); - const stream = convertReadStreamToReadableStream(nodeStream); - - if (typeof filePath !== 'undefined') { - code = { type: 'file', stream, filename: pathLib.basename(filePath), size: fs.statSync(filePath).size }; - payload['code'] = code - } - if (typeof activate !== 'undefined') { - payload['activate'] = activate; - } - - const size = code.size; - - const apiHeaders = { - 'content-type': 'multipart/form-data', - }; - - let id = undefined; - let response = undefined; - - let chunksUploaded = 0; - - let currentChunk = 1; - let currentPosition = 0; - let uploadableChunk = new Uint8Array(client.CHUNK_SIZE); - - const uploadChunk = async (lastUpload = false) => { - if(currentChunk <= chunksUploaded) { - return; - } - - const start = ((currentChunk - 1) * client.CHUNK_SIZE); - let end = start + currentPosition - 1; - - if(!lastUpload || currentChunk !== 1) { - apiHeaders['content-range'] = 'bytes ' + start + '-' + end + '/' + size; - } - - let uploadableChunkTrimmed; - - if(currentPosition + 1 >= client.CHUNK_SIZE) { - uploadableChunkTrimmed = uploadableChunk; - } else { - uploadableChunkTrimmed = new Uint8Array(currentPosition); - for(let i = 0; i <= currentPosition; i++) { - uploadableChunkTrimmed[i] = uploadableChunk[i]; - } - } - - if (id) { - apiHeaders['x-appwrite-id'] = id; - } - - payload['code'] = { type: 'file', file: new File([uploadableChunkTrimmed], code.filename), filename: code.filename }; - - response = await client.call('post', apiPath, apiHeaders, payload); - - if (!id) { - id = response['$id']; - } - - if (onProgress !== null) { - onProgress({ - $id: response['$id'], - progress: Math.min((currentChunk) * client.CHUNK_SIZE, size) / size * 100, - sizeUploaded: end+1, - chunksTotal: response['chunksTotal'], - chunksUploaded: response['chunksUploaded'] - }); - } - - uploadableChunk = new Uint8Array(client.CHUNK_SIZE); - currentChunk++; - currentPosition = 0; - } - - for await (const chunk of code.stream) { - for(const b of chunk) { - uploadableChunk[currentPosition] = b; - - currentPosition++; - if(currentPosition >= client.CHUNK_SIZE) { - await uploadChunk(); - currentPosition = 0; - } - } - } - - if (currentPosition > 0) { // Check if there's any remaining data for the last chunk - await uploadChunk(true); - } - - await fs.unlink(filePath,()=>{}); - - if (parseOutput) { - parse(response) - } - - return response; -} -interface SitesCreateDuplicateDeploymentRequestParams { - siteId: string; - deploymentId: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const sitesCreateDuplicateDeployment = async ({siteId,deploymentId,parseOutput = true, overrideForCli = false, sdk = undefined}: SitesCreateDuplicateDeploymentRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/sites/{siteId}/deployments/duplicate'.replace('{siteId}', siteId); - let payload = {}; - if (typeof deploymentId !== 'undefined') { - payload['deploymentId'] = deploymentId; - } - - let response = undefined; - - response = await client.call('post', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface SitesCreateTemplateDeploymentRequestParams { - siteId: string; - repository: string; - owner: string; - rootDirectory: string; - type: TemplateReferenceType; - reference: string; - activate?: boolean; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const sitesCreateTemplateDeployment = async ({siteId,repository,owner,rootDirectory,type,reference,activate,parseOutput = true, overrideForCli = false, sdk = undefined}: SitesCreateTemplateDeploymentRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/sites/{siteId}/deployments/template'.replace('{siteId}', siteId); - let payload = {}; - if (typeof repository !== 'undefined') { - payload['repository'] = repository; - } - if (typeof owner !== 'undefined') { - payload['owner'] = owner; - } - if (typeof rootDirectory !== 'undefined') { - payload['rootDirectory'] = rootDirectory; - } - if (typeof type !== 'undefined') { - payload['type'] = type; - } - if (typeof reference !== 'undefined') { - payload['reference'] = reference; - } - if (typeof activate !== 'undefined') { - payload['activate'] = activate; - } - - let response = undefined; - - response = await client.call('post', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface SitesCreateVcsDeploymentRequestParams { - siteId: string; - type: VCSReferenceType; - reference: string; - activate?: boolean; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const sitesCreateVcsDeployment = async ({siteId,type,reference,activate,parseOutput = true, overrideForCli = false, sdk = undefined}: SitesCreateVcsDeploymentRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/sites/{siteId}/deployments/vcs'.replace('{siteId}', siteId); - let payload = {}; - if (typeof type !== 'undefined') { - payload['type'] = type; - } - if (typeof reference !== 'undefined') { - payload['reference'] = reference; - } - if (typeof activate !== 'undefined') { - payload['activate'] = activate; - } - - let response = undefined; - - response = await client.call('post', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface SitesGetDeploymentRequestParams { - siteId: string; - deploymentId: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; - console?: boolean; -} - -export const sitesGetDeployment = async ({siteId,deploymentId,parseOutput = true, overrideForCli = false, sdk = undefined, console: showConsole}: SitesGetDeploymentRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/sites/{siteId}/deployments/{deploymentId}'.replace('{siteId}', siteId).replace('{deploymentId}', deploymentId); - let payload = {}; - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - if(showConsole) { - showConsoleLink('sites', 'getDeployment', siteId, deploymentId); - } else { - parse(response) - } - } - - return response; - -} -interface SitesDeleteDeploymentRequestParams { - siteId: string; - deploymentId: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const sitesDeleteDeployment = async ({siteId,deploymentId,parseOutput = true, overrideForCli = false, sdk = undefined}: SitesDeleteDeploymentRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/sites/{siteId}/deployments/{deploymentId}'.replace('{siteId}', siteId).replace('{deploymentId}', deploymentId); - let payload = {}; - - let response = undefined; - - response = await client.call('delete', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface SitesGetDeploymentDownloadRequestParams { - siteId: string; - deploymentId: string; - type?: DeploymentDownloadType; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; - destination?: string; - console?: boolean; -} - -export const sitesGetDeploymentDownload = async ({siteId,deploymentId,type,parseOutput = true, overrideForCli = false, sdk = undefined, destination, console: showConsole}: SitesGetDeploymentDownloadRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/sites/{siteId}/deployments/{deploymentId}/download'.replace('{siteId}', siteId).replace('{deploymentId}', deploymentId); - let payload = {}; - if (typeof type !== 'undefined') { - payload['type'] = type; - } - if (!overrideForCli) { - payload['project'] = localConfig.getProject().projectId - payload['key'] = globalConfig.getKey(); - const queryParams = new URLSearchParams(payload); - apiPath = `${globalConfig.getEndpoint()}${apiPath}?${queryParams.toString()}`; - } - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload, 'arraybuffer'); - - if (overrideForCli) { - response = Buffer.from(response); - } - - fs.writeFileSync(destination, response); - if (parseOutput) { - if(showConsole) { - showConsoleLink('sites', 'getDeploymentDownload', siteId, deploymentId); - } else { - parse(response) - } - } - - return response; - -} -interface SitesUpdateDeploymentStatusRequestParams { - siteId: string; - deploymentId: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const sitesUpdateDeploymentStatus = async ({siteId,deploymentId,parseOutput = true, overrideForCli = false, sdk = undefined}: SitesUpdateDeploymentStatusRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/sites/{siteId}/deployments/{deploymentId}/status'.replace('{siteId}', siteId).replace('{deploymentId}', deploymentId); - let payload = {}; - - let response = undefined; - - response = await client.call('patch', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface SitesListLogsRequestParams { - siteId: string; - queries?: string[]; - total?: boolean; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const sitesListLogs = async ({siteId,queries,total,parseOutput = true, overrideForCli = false, sdk = undefined}: SitesListLogsRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/sites/{siteId}/logs'.replace('{siteId}', siteId); - let payload = {}; - if (typeof queries !== 'undefined') { - payload['queries'] = queries; - } - if (typeof total !== 'undefined') { - payload['total'] = total; - } - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface SitesGetLogRequestParams { - siteId: string; - logId: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; - console?: boolean; -} - -export const sitesGetLog = async ({siteId,logId,parseOutput = true, overrideForCli = false, sdk = undefined, console: showConsole}: SitesGetLogRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/sites/{siteId}/logs/{logId}'.replace('{siteId}', siteId).replace('{logId}', logId); - let payload = {}; - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - if(showConsole) { - showConsoleLink('sites', 'getLog', siteId, logId); - } else { - parse(response) - } - } - - return response; - -} -interface SitesDeleteLogRequestParams { - siteId: string; - logId: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const sitesDeleteLog = async ({siteId,logId,parseOutput = true, overrideForCli = false, sdk = undefined}: SitesDeleteLogRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/sites/{siteId}/logs/{logId}'.replace('{siteId}', siteId).replace('{logId}', logId); - let payload = {}; - - let response = undefined; - - response = await client.call('delete', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface SitesGetUsageRequestParams { - siteId: string; - range?: UsageRange; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const sitesGetUsage = async ({siteId,range,parseOutput = true, overrideForCli = false, sdk = undefined}: SitesGetUsageRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/sites/{siteId}/usage'.replace('{siteId}', siteId); - let payload = {}; - if (typeof range !== 'undefined') { - payload['range'] = range; - } - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface SitesListVariablesRequestParams { - siteId: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const sitesListVariables = async ({siteId,parseOutput = true, overrideForCli = false, sdk = undefined}: SitesListVariablesRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/sites/{siteId}/variables'.replace('{siteId}', siteId); - let payload = {}; - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface SitesCreateVariableRequestParams { - siteId: string; - key: string; - value: string; - secret?: boolean; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const sitesCreateVariable = async ({siteId,key,value,secret,parseOutput = true, overrideForCli = false, sdk = undefined}: SitesCreateVariableRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/sites/{siteId}/variables'.replace('{siteId}', siteId); - let payload = {}; - if (typeof key !== 'undefined') { - payload['key'] = key; - } - if (typeof value !== 'undefined') { - payload['value'] = value; - } - if (typeof secret !== 'undefined') { - payload['secret'] = secret; - } - - let response = undefined; - - response = await client.call('post', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface SitesGetVariableRequestParams { - siteId: string; - variableId: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const sitesGetVariable = async ({siteId,variableId,parseOutput = true, overrideForCli = false, sdk = undefined}: SitesGetVariableRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/sites/{siteId}/variables/{variableId}'.replace('{siteId}', siteId).replace('{variableId}', variableId); - let payload = {}; - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface SitesUpdateVariableRequestParams { - siteId: string; - variableId: string; - key: string; - value?: string; - secret?: boolean; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const sitesUpdateVariable = async ({siteId,variableId,key,value,secret,parseOutput = true, overrideForCli = false, sdk = undefined}: SitesUpdateVariableRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/sites/{siteId}/variables/{variableId}'.replace('{siteId}', siteId).replace('{variableId}', variableId); - let payload = {}; - if (typeof key !== 'undefined') { - payload['key'] = key; - } - if (typeof value !== 'undefined') { - payload['value'] = value; - } - if (typeof secret !== 'undefined') { - payload['secret'] = secret; - } - - let response = undefined; - - response = await client.call('put', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface SitesDeleteVariableRequestParams { - siteId: string; - variableId: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const sitesDeleteVariable = async ({siteId,variableId,parseOutput = true, overrideForCli = false, sdk = undefined}: SitesDeleteVariableRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/sites/{siteId}/variables/{variableId}'.replace('{siteId}', siteId).replace('{variableId}', variableId); - let payload = {}; - - let response = undefined; - - response = await client.call('delete', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -sites - .command(`list`) - .description(`Get a list of all the project's sites. You can use the query params to filter your results.`) - .option(`--queries [queries...]`, `Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: name, enabled, framework, deploymentId, buildCommand, installCommand, outputDirectory, installationId`) - .option(`--search <search>`, `Search term to filter your list results. Max length: 256 chars.`) - .option(`--total [value]`, `When set to false, the total count returned will be 0 and will not be calculated.`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .option(`--console`, `Get the resource console url`) - .action(actionRunner(sitesList)) - -sites - .command(`create`) - .description(`Create a new site.`) - .requiredOption(`--site-id <site-id>`, `Site ID. Choose a custom ID or generate a random ID with 'ID.unique()'. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.`) - .requiredOption(`--name <name>`, `Site name. Max length: 128 chars.`) - .requiredOption(`--framework <framework>`, `Sites framework.`) - .requiredOption(`--build-runtime <build-runtime>`, `Runtime to use during build step.`) - .option(`--enabled [value]`, `Is site enabled? When set to 'disabled', users cannot access the site but Server SDKs with and API key can still access the site. No data is lost when this is toggled.`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .option(`--logging [value]`, `When disabled, request logs will exclude logs and errors, and site responses will be slightly faster.`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .option(`--timeout <timeout>`, `Maximum request time in seconds.`, parseInteger) - .option(`--install-command <install-command>`, `Install Command.`) - .option(`--build-command <build-command>`, `Build Command.`) - .option(`--output-directory <output-directory>`, `Output Directory for site.`) - .option(`--adapter <adapter>`, `Framework adapter defining rendering strategy. Allowed values are: static, ssr`) - .option(`--installation-id <installation-id>`, `Appwrite Installation ID for VCS (Version Control System) deployment.`) - .option(`--fallback-file <fallback-file>`, `Fallback file for single page application sites.`) - .option(`--provider-repository-id <provider-repository-id>`, `Repository ID of the repo linked to the site.`) - .option(`--provider-branch <provider-branch>`, `Production branch for the repo linked to the site.`) - .option(`--provider-silent-mode [value]`, `Is the VCS (Version Control System) connection in silent mode for the repo linked to the site? In silent mode, comments will not be made on commits and pull requests.`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .option(`--provider-root-directory <provider-root-directory>`, `Path to site code in the linked repo.`) - .option(`--specification <specification>`, `Framework specification for the site and builds.`) - .action(actionRunner(sitesCreate)) - -sites - .command(`list-frameworks`) - .description(`Get a list of all frameworks that are currently available on the server instance.`) - .option(`--console`, `Get the resource console url`) - .action(actionRunner(sitesListFrameworks)) - -sites - .command(`list-specifications`) - .description(`List allowed site specifications for this instance.`) - .option(`--console`, `Get the resource console url`) - .action(actionRunner(sitesListSpecifications)) - -sites - .command(`list-templates`) - .description(`List available site templates. You can use template details in [createSite](/docs/references/cloud/server-nodejs/sites#create) method.`) - .option(`--frameworks [frameworks...]`, `List of frameworks allowed for filtering site templates. Maximum of 100 frameworks are allowed.`) - .option(`--use-cases [use-cases...]`, `List of use cases allowed for filtering site templates. Maximum of 100 use cases are allowed.`) - .option(`--limit <limit>`, `Limit the number of templates returned in the response. Default limit is 25, and maximum limit is 5000.`, parseInteger) - .option(`--offset <offset>`, `Offset the list of returned templates. Maximum offset is 5000.`, parseInteger) - .option(`--console`, `Get the resource console url`) - .action(actionRunner(sitesListTemplates)) - -sites - .command(`get-template`) - .description(`Get a site template using ID. You can use template details in [createSite](/docs/references/cloud/server-nodejs/sites#create) method.`) - .requiredOption(`--template-id <template-id>`, `Template ID.`) - .option(`--console`, `Get the resource console url`) - .action(actionRunner(sitesGetTemplate)) - -sites - .command(`list-usage`) - .description(`Get usage metrics and statistics for all sites in the project. View statistics including total deployments, builds, logs, storage usage, and compute time. The response includes both current totals and historical data for each metric. Use the optional range parameter to specify the time window for historical data: 24h (last 24 hours), 30d (last 30 days), or 90d (last 90 days). If not specified, defaults to 30 days.`) - .option(`--range <range>`, `Date range.`) - .option(`--console`, `Get the resource console url`) - .action(actionRunner(sitesListUsage)) - -sites - .command(`get`) - .description(`Get a site by its unique ID.`) - .requiredOption(`--site-id <site-id>`, `Site ID.`) - .option(`--console`, `Get the resource console url`) - .action(actionRunner(sitesGet)) - -sites - .command(`update`) - .description(`Update site by its unique ID.`) - .requiredOption(`--site-id <site-id>`, `Site ID.`) - .requiredOption(`--name <name>`, `Site name. Max length: 128 chars.`) - .requiredOption(`--framework <framework>`, `Sites framework.`) - .option(`--enabled [value]`, `Is site enabled? When set to 'disabled', users cannot access the site but Server SDKs with and API key can still access the site. No data is lost when this is toggled.`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .option(`--logging [value]`, `When disabled, request logs will exclude logs and errors, and site responses will be slightly faster.`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .option(`--timeout <timeout>`, `Maximum request time in seconds.`, parseInteger) - .option(`--install-command <install-command>`, `Install Command.`) - .option(`--build-command <build-command>`, `Build Command.`) - .option(`--output-directory <output-directory>`, `Output Directory for site.`) - .option(`--build-runtime <build-runtime>`, `Runtime to use during build step.`) - .option(`--adapter <adapter>`, `Framework adapter defining rendering strategy. Allowed values are: static, ssr`) - .option(`--fallback-file <fallback-file>`, `Fallback file for single page application sites.`) - .option(`--installation-id <installation-id>`, `Appwrite Installation ID for VCS (Version Control System) deployment.`) - .option(`--provider-repository-id <provider-repository-id>`, `Repository ID of the repo linked to the site.`) - .option(`--provider-branch <provider-branch>`, `Production branch for the repo linked to the site.`) - .option(`--provider-silent-mode [value]`, `Is the VCS (Version Control System) connection in silent mode for the repo linked to the site? In silent mode, comments will not be made on commits and pull requests.`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .option(`--provider-root-directory <provider-root-directory>`, `Path to site code in the linked repo.`) - .option(`--specification <specification>`, `Framework specification for the site and builds.`) - .action(actionRunner(sitesUpdate)) - -sites - .command(`delete`) - .description(`Delete a site by its unique ID.`) - .requiredOption(`--site-id <site-id>`, `Site ID.`) - .action(actionRunner(sitesDelete)) - -sites - .command(`update-site-deployment`) - .description(`Update the site active deployment. Use this endpoint to switch the code deployment that should be used when visitor opens your site.`) - .requiredOption(`--site-id <site-id>`, `Site ID.`) - .requiredOption(`--deployment-id <deployment-id>`, `Deployment ID.`) - .action(actionRunner(sitesUpdateSiteDeployment)) - -sites - .command(`list-deployments`) - .description(`Get a list of all the site's code deployments. You can use the query params to filter your results.`) - .requiredOption(`--site-id <site-id>`, `Site ID.`) - .option(`--queries [queries...]`, `Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: buildSize, sourceSize, totalSize, buildDuration, status, activate, type`) - .option(`--search <search>`, `Search term to filter your list results. Max length: 256 chars.`) - .option(`--total [value]`, `When set to false, the total count returned will be 0 and will not be calculated.`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .option(`--console`, `Get the resource console url`) - .action(actionRunner(sitesListDeployments)) - -sites - .command(`create-deployment`) - .description(`Create a new site code deployment. Use this endpoint to upload a new version of your site code. To activate your newly uploaded code, you'll need to update the site's deployment to use your new deployment ID.`) - .requiredOption(`--site-id <site-id>`, `Site ID.`) - .requiredOption(`--code <code>`, `Gzip file with your code package. When used with the Appwrite CLI, pass the path to your code directory, and the CLI will automatically package your code. Use a path that is within the current directory.`) - .requiredOption(`--activate [value]`, `Automatically activate the deployment when it is finished building.`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .option(`--install-command <install-command>`, `Install Commands.`) - .option(`--build-command <build-command>`, `Build Commands.`) - .option(`--output-directory <output-directory>`, `Output Directory.`) - .action(actionRunner(sitesCreateDeployment)) - -sites - .command(`create-duplicate-deployment`) - .description(`Create a new build for an existing site deployment. This endpoint allows you to rebuild a deployment with the updated site configuration, including its commands and output directory if they have been modified. The build process will be queued and executed asynchronously. The original deployment's code will be preserved and used for the new build.`) - .requiredOption(`--site-id <site-id>`, `Site ID.`) - .requiredOption(`--deployment-id <deployment-id>`, `Deployment ID.`) - .action(actionRunner(sitesCreateDuplicateDeployment)) - -sites - .command(`create-template-deployment`) - .description(`Create a deployment based on a template. Use this endpoint with combination of [listTemplates](https://appwrite.io/docs/products/sites/templates) to find the template details.`) - .requiredOption(`--site-id <site-id>`, `Site ID.`) - .requiredOption(`--repository <repository>`, `Repository name of the template.`) - .requiredOption(`--owner <owner>`, `The name of the owner of the template.`) - .requiredOption(`--root-directory <root-directory>`, `Path to site code in the template repo.`) - .requiredOption(`--type <type>`, `Type for the reference provided. Can be commit, branch, or tag`) - .requiredOption(`--reference <reference>`, `Reference value, can be a commit hash, branch name, or release tag`) - .option(`--activate [value]`, `Automatically activate the deployment when it is finished building.`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .action(actionRunner(sitesCreateTemplateDeployment)) - -sites - .command(`create-vcs-deployment`) - .description(`Create a deployment when a site is connected to VCS. This endpoint lets you create deployment from a branch, commit, or a tag.`) - .requiredOption(`--site-id <site-id>`, `Site ID.`) - .requiredOption(`--type <type>`, `Type of reference passed. Allowed values are: branch, commit`) - .requiredOption(`--reference <reference>`, `VCS reference to create deployment from. Depending on type this can be: branch name, commit hash`) - .option(`--activate [value]`, `Automatically activate the deployment when it is finished building.`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .action(actionRunner(sitesCreateVcsDeployment)) - -sites - .command(`get-deployment`) - .description(`Get a site deployment by its unique ID.`) - .requiredOption(`--site-id <site-id>`, `Site ID.`) - .requiredOption(`--deployment-id <deployment-id>`, `Deployment ID.`) - .option(`--console`, `Get the resource console url`) - .action(actionRunner(sitesGetDeployment)) - -sites - .command(`delete-deployment`) - .description(`Delete a site deployment by its unique ID.`) - .requiredOption(`--site-id <site-id>`, `Site ID.`) - .requiredOption(`--deployment-id <deployment-id>`, `Deployment ID.`) - .action(actionRunner(sitesDeleteDeployment)) - -sites - .command(`get-deployment-download`) - .description(`Get a site deployment content by its unique ID. The endpoint response return with a 'Content-Disposition: attachment' header that tells the browser to start downloading the file to user downloads directory.`) - .requiredOption(`--site-id <site-id>`, `Site ID.`) - .requiredOption(`--deployment-id <deployment-id>`, `Deployment ID.`) - .option(`--type <type>`, `Deployment file to download. Can be: "source", "output".`) - .requiredOption(`--destination <path>`, `output file path.`) - .option(`--console`, `Get the resource console url`) - .action(actionRunner(sitesGetDeploymentDownload)) - -sites - .command(`update-deployment-status`) - .description(`Cancel an ongoing site deployment build. If the build is already in progress, it will be stopped and marked as canceled. If the build hasn't started yet, it will be marked as canceled without executing. You cannot cancel builds that have already completed (status 'ready') or failed. The response includes the final build status and details.`) - .requiredOption(`--site-id <site-id>`, `Site ID.`) - .requiredOption(`--deployment-id <deployment-id>`, `Deployment ID.`) - .action(actionRunner(sitesUpdateDeploymentStatus)) - -sites - .command(`list-logs`) - .description(`Get a list of all site logs. You can use the query params to filter your results.`) - .requiredOption(`--site-id <site-id>`, `Site ID.`) - .option(`--queries [queries...]`, `Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: trigger, status, responseStatusCode, duration, requestMethod, requestPath, deploymentId`) - .option(`--total [value]`, `When set to false, the total count returned will be 0 and will not be calculated.`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .action(actionRunner(sitesListLogs)) - -sites - .command(`get-log`) - .description(`Get a site request log by its unique ID.`) - .requiredOption(`--site-id <site-id>`, `Site ID.`) - .requiredOption(`--log-id <log-id>`, `Log ID.`) - .option(`--console`, `Get the resource console url`) - .action(actionRunner(sitesGetLog)) - -sites - .command(`delete-log`) - .description(`Delete a site log by its unique ID.`) - .requiredOption(`--site-id <site-id>`, `Site ID.`) - .requiredOption(`--log-id <log-id>`, `Log ID.`) - .action(actionRunner(sitesDeleteLog)) - -sites - .command(`get-usage`) - .description(`Get usage metrics and statistics for a for a specific site. View statistics including total deployments, builds, executions, storage usage, and compute time. The response includes both current totals and historical data for each metric. Use the optional range parameter to specify the time window for historical data: 24h (last 24 hours), 30d (last 30 days), or 90d (last 90 days). If not specified, defaults to 30 days.`) - .requiredOption(`--site-id <site-id>`, `Site ID.`) - .option(`--range <range>`, `Date range.`) - .action(actionRunner(sitesGetUsage)) - -sites - .command(`list-variables`) - .description(`Get a list of all variables of a specific site.`) - .requiredOption(`--site-id <site-id>`, `Site unique ID.`) - .action(actionRunner(sitesListVariables)) - -sites - .command(`create-variable`) - .description(`Create a new site variable. These variables can be accessed during build and runtime (server-side rendering) as environment variables.`) - .requiredOption(`--site-id <site-id>`, `Site unique ID.`) - .requiredOption(`--key <key>`, `Variable key. Max length: 255 chars.`) - .requiredOption(`--value <value>`, `Variable value. Max length: 8192 chars.`) - .option(`--secret [value]`, `Secret variables can be updated or deleted, but only sites can read them during build and runtime.`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .action(actionRunner(sitesCreateVariable)) - -sites - .command(`get-variable`) - .description(`Get a variable by its unique ID.`) - .requiredOption(`--site-id <site-id>`, `Site unique ID.`) - .requiredOption(`--variable-id <variable-id>`, `Variable unique ID.`) - .action(actionRunner(sitesGetVariable)) - -sites - .command(`update-variable`) - .description(`Update variable by its unique ID.`) - .requiredOption(`--site-id <site-id>`, `Site unique ID.`) - .requiredOption(`--variable-id <variable-id>`, `Variable unique ID.`) - .requiredOption(`--key <key>`, `Variable key. Max length: 255 chars.`) - .option(`--value <value>`, `Variable value. Max length: 8192 chars.`) - .option(`--secret [value]`, `Secret variables can be updated or deleted, but only sites can read them during build and runtime.`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .action(actionRunner(sitesUpdateVariable)) - -sites - .command(`delete-variable`) - .description(`Delete a variable by its unique ID.`) - .requiredOption(`--site-id <site-id>`, `Site unique ID.`) - .requiredOption(`--variable-id <variable-id>`, `Variable unique ID.`) - .action(actionRunner(sitesDeleteVariable)) - - diff --git a/lib/commands/storage.ts b/lib/commands/storage.ts deleted file mode 100644 index a39f4919..00000000 --- a/lib/commands/storage.ts +++ /dev/null @@ -1,919 +0,0 @@ -import fs = require('fs'); -import pathLib = require('path'); -import tar = require('tar'); -import ignore = require('ignore'); -import { promisify } from 'util'; -import Client from '../client'; -import { getAllFiles, showConsoleLink } from '../utils'; -import { Command } from 'commander'; -import { sdkForProject, sdkForConsole } from '../sdks'; -import { parse, actionRunner, parseInteger, parseBool, commandDescriptions, success, log, warn } from '../parser'; -import { localConfig, globalConfig } from '../config'; -import { File } from 'undici'; -import { ReadableStream } from 'stream/web'; - -function convertReadStreamToReadableStream(readStream: fs.ReadStream): ReadableStream { - return new ReadableStream({ - start(controller) { - readStream.on("data", (chunk: Buffer) => { - controller.enqueue(chunk); - }); - readStream.on("end", () => { - controller.close(); - }); - readStream.on("error", (err: Error) => { - controller.error(err); - }); - }, - cancel() { - readStream.destroy(); - }, - }); -} - -export const storage = new Command("storage").description(commandDescriptions['storage'] ?? '').configureHelp({ - helpWidth: process.stdout.columns || 80 -}) - -interface StorageListBucketsRequestParams { - queries?: string[]; - search?: string; - total?: boolean; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; - console?: boolean; -} - -export const storageListBuckets = async ({queries,search,total,parseOutput = true, overrideForCli = false, sdk = undefined, console: showConsole}: StorageListBucketsRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/storage/buckets'; - let payload = {}; - if (typeof queries !== 'undefined') { - payload['queries'] = queries; - } - if (typeof search !== 'undefined') { - payload['search'] = search; - } - if (typeof total !== 'undefined') { - payload['total'] = total; - } - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - if(showConsole) { - showConsoleLink('storage', 'listBuckets'); - } else { - parse(response) - } - } - - return response; - -} -interface StorageCreateBucketRequestParams { - bucketId: string; - name: string; - permissions?: string[]; - fileSecurity?: boolean; - enabled?: boolean; - maximumFileSize?: number; - allowedFileExtensions?: string[]; - compression?: Compression; - encryption?: boolean; - antivirus?: boolean; - transformations?: boolean; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const storageCreateBucket = async ({bucketId,name,permissions,fileSecurity,enabled,maximumFileSize,allowedFileExtensions,compression,encryption,antivirus,transformations,parseOutput = true, overrideForCli = false, sdk = undefined}: StorageCreateBucketRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/storage/buckets'; - let payload = {}; - if (typeof bucketId !== 'undefined') { - payload['bucketId'] = bucketId; - } - if (typeof name !== 'undefined') { - payload['name'] = name; - } - permissions = permissions === true ? [] : permissions; - if (typeof permissions !== 'undefined') { - payload['permissions'] = permissions; - } - if (typeof fileSecurity !== 'undefined') { - payload['fileSecurity'] = fileSecurity; - } - if (typeof enabled !== 'undefined') { - payload['enabled'] = enabled; - } - if (typeof maximumFileSize !== 'undefined') { - payload['maximumFileSize'] = maximumFileSize; - } - allowedFileExtensions = allowedFileExtensions === true ? [] : allowedFileExtensions; - if (typeof allowedFileExtensions !== 'undefined') { - payload['allowedFileExtensions'] = allowedFileExtensions; - } - if (typeof compression !== 'undefined') { - payload['compression'] = compression; - } - if (typeof encryption !== 'undefined') { - payload['encryption'] = encryption; - } - if (typeof antivirus !== 'undefined') { - payload['antivirus'] = antivirus; - } - if (typeof transformations !== 'undefined') { - payload['transformations'] = transformations; - } - - let response = undefined; - - response = await client.call('post', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface StorageGetBucketRequestParams { - bucketId: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; - console?: boolean; -} - -export const storageGetBucket = async ({bucketId,parseOutput = true, overrideForCli = false, sdk = undefined, console: showConsole}: StorageGetBucketRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/storage/buckets/{bucketId}'.replace('{bucketId}', bucketId); - let payload = {}; - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - if(showConsole) { - showConsoleLink('storage', 'getBucket', bucketId); - } else { - parse(response) - } - } - - return response; - -} -interface StorageUpdateBucketRequestParams { - bucketId: string; - name: string; - permissions?: string[]; - fileSecurity?: boolean; - enabled?: boolean; - maximumFileSize?: number; - allowedFileExtensions?: string[]; - compression?: Compression; - encryption?: boolean; - antivirus?: boolean; - transformations?: boolean; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const storageUpdateBucket = async ({bucketId,name,permissions,fileSecurity,enabled,maximumFileSize,allowedFileExtensions,compression,encryption,antivirus,transformations,parseOutput = true, overrideForCli = false, sdk = undefined}: StorageUpdateBucketRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/storage/buckets/{bucketId}'.replace('{bucketId}', bucketId); - let payload = {}; - if (typeof name !== 'undefined') { - payload['name'] = name; - } - permissions = permissions === true ? [] : permissions; - if (typeof permissions !== 'undefined') { - payload['permissions'] = permissions; - } - if (typeof fileSecurity !== 'undefined') { - payload['fileSecurity'] = fileSecurity; - } - if (typeof enabled !== 'undefined') { - payload['enabled'] = enabled; - } - if (typeof maximumFileSize !== 'undefined') { - payload['maximumFileSize'] = maximumFileSize; - } - allowedFileExtensions = allowedFileExtensions === true ? [] : allowedFileExtensions; - if (typeof allowedFileExtensions !== 'undefined') { - payload['allowedFileExtensions'] = allowedFileExtensions; - } - if (typeof compression !== 'undefined') { - payload['compression'] = compression; - } - if (typeof encryption !== 'undefined') { - payload['encryption'] = encryption; - } - if (typeof antivirus !== 'undefined') { - payload['antivirus'] = antivirus; - } - if (typeof transformations !== 'undefined') { - payload['transformations'] = transformations; - } - - let response = undefined; - - response = await client.call('put', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface StorageDeleteBucketRequestParams { - bucketId: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const storageDeleteBucket = async ({bucketId,parseOutput = true, overrideForCli = false, sdk = undefined}: StorageDeleteBucketRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/storage/buckets/{bucketId}'.replace('{bucketId}', bucketId); - let payload = {}; - - let response = undefined; - - response = await client.call('delete', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface StorageListFilesRequestParams { - bucketId: string; - queries?: string[]; - search?: string; - total?: boolean; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; - console?: boolean; -} - -export const storageListFiles = async ({bucketId,queries,search,total,parseOutput = true, overrideForCli = false, sdk = undefined, console: showConsole}: StorageListFilesRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/storage/buckets/{bucketId}/files'.replace('{bucketId}', bucketId); - let payload = {}; - if (typeof queries !== 'undefined') { - payload['queries'] = queries; - } - if (typeof search !== 'undefined') { - payload['search'] = search; - } - if (typeof total !== 'undefined') { - payload['total'] = total; - } - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - if(showConsole) { - showConsoleLink('storage', 'listFiles', bucketId); - } else { - parse(response) - } - } - - return response; - -} -interface StorageCreateFileRequestParams { - bucketId: string; - fileId: string; - file: string; - permissions?: string[]; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; - onProgress?: (progress: number) => void; -} - -export const storageCreateFile = async ({bucketId,fileId,file,permissions,parseOutput = true, overrideForCli = false, sdk = undefined,onProgress = () => {}}: StorageCreateFileRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/storage/buckets/{bucketId}/files'.replace('{bucketId}', bucketId); - let payload = {}; - if (typeof fileId !== 'undefined') { - payload['fileId'] = fileId; - } - const filePath = fs.realpathSync(file); - const nodeStream = fs.createReadStream(filePath); - const stream = convertReadStreamToReadableStream(nodeStream); - - if (typeof filePath !== 'undefined') { - file = { type: 'file', stream, filename: pathLib.basename(filePath), size: fs.statSync(filePath).size }; - payload['file'] = file - } - permissions = permissions === true ? [] : permissions; - if (typeof permissions !== 'undefined') { - payload['permissions'] = permissions; - } - - const size = file.size; - - const apiHeaders = { - 'content-type': 'multipart/form-data', - }; - - let id = undefined; - let response = undefined; - - let chunksUploaded = 0; - - if(fileId != 'unique()') { - try { - response = await client.call('get', apiPath + '/' + fileId, apiHeaders); - chunksUploaded = response.chunksUploaded; - } catch(e) { - } - } - - let currentChunk = 1; - let currentPosition = 0; - let uploadableChunk = new Uint8Array(client.CHUNK_SIZE); - - const uploadChunk = async (lastUpload = false) => { - if(currentChunk <= chunksUploaded) { - return; - } - - const start = ((currentChunk - 1) * client.CHUNK_SIZE); - let end = start + currentPosition - 1; - - if(!lastUpload || currentChunk !== 1) { - apiHeaders['content-range'] = 'bytes ' + start + '-' + end + '/' + size; - } - - let uploadableChunkTrimmed; - - if(currentPosition + 1 >= client.CHUNK_SIZE) { - uploadableChunkTrimmed = uploadableChunk; - } else { - uploadableChunkTrimmed = new Uint8Array(currentPosition); - for(let i = 0; i <= currentPosition; i++) { - uploadableChunkTrimmed[i] = uploadableChunk[i]; - } - } - - if (id) { - apiHeaders['x-appwrite-id'] = id; - } - - payload['file'] = { type: 'file', file: new File([uploadableChunkTrimmed], file.filename), filename: file.filename }; - - response = await client.call('post', apiPath, apiHeaders, payload); - - if (!id) { - id = response['$id']; - } - - if (onProgress !== null) { - onProgress({ - $id: response['$id'], - progress: Math.min((currentChunk) * client.CHUNK_SIZE, size) / size * 100, - sizeUploaded: end+1, - chunksTotal: response['chunksTotal'], - chunksUploaded: response['chunksUploaded'] - }); - } - - uploadableChunk = new Uint8Array(client.CHUNK_SIZE); - currentChunk++; - currentPosition = 0; - } - - for await (const chunk of file.stream) { - for(const b of chunk) { - uploadableChunk[currentPosition] = b; - - currentPosition++; - if(currentPosition >= client.CHUNK_SIZE) { - await uploadChunk(); - currentPosition = 0; - } - } - } - - if (currentPosition > 0) { // Check if there's any remaining data for the last chunk - await uploadChunk(true); - } - - - if (parseOutput) { - parse(response) - } - - return response; -} -interface StorageGetFileRequestParams { - bucketId: string; - fileId: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; - console?: boolean; -} - -export const storageGetFile = async ({bucketId,fileId,parseOutput = true, overrideForCli = false, sdk = undefined, console: showConsole}: StorageGetFileRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/storage/buckets/{bucketId}/files/{fileId}'.replace('{bucketId}', bucketId).replace('{fileId}', fileId); - let payload = {}; - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - if(showConsole) { - showConsoleLink('storage', 'getFile', bucketId, fileId); - } else { - parse(response) - } - } - - return response; - -} -interface StorageUpdateFileRequestParams { - bucketId: string; - fileId: string; - name?: string; - permissions?: string[]; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const storageUpdateFile = async ({bucketId,fileId,name,permissions,parseOutput = true, overrideForCli = false, sdk = undefined}: StorageUpdateFileRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/storage/buckets/{bucketId}/files/{fileId}'.replace('{bucketId}', bucketId).replace('{fileId}', fileId); - let payload = {}; - if (typeof name !== 'undefined') { - payload['name'] = name; - } - permissions = permissions === true ? [] : permissions; - if (typeof permissions !== 'undefined') { - payload['permissions'] = permissions; - } - - let response = undefined; - - response = await client.call('put', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface StorageDeleteFileRequestParams { - bucketId: string; - fileId: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const storageDeleteFile = async ({bucketId,fileId,parseOutput = true, overrideForCli = false, sdk = undefined}: StorageDeleteFileRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/storage/buckets/{bucketId}/files/{fileId}'.replace('{bucketId}', bucketId).replace('{fileId}', fileId); - let payload = {}; - - let response = undefined; - - response = await client.call('delete', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface StorageGetFileDownloadRequestParams { - bucketId: string; - fileId: string; - token?: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; - destination?: string; -} - -export const storageGetFileDownload = async ({bucketId,fileId,token,parseOutput = true, overrideForCli = false, sdk = undefined, destination}: StorageGetFileDownloadRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/storage/buckets/{bucketId}/files/{fileId}/download'.replace('{bucketId}', bucketId).replace('{fileId}', fileId); - let payload = {}; - if (typeof token !== 'undefined') { - payload['token'] = token; - } - if (!overrideForCli) { - payload['project'] = localConfig.getProject().projectId - payload['key'] = globalConfig.getKey(); - const queryParams = new URLSearchParams(payload); - apiPath = `${globalConfig.getEndpoint()}${apiPath}?${queryParams.toString()}`; - } - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload, 'arraybuffer'); - - if (overrideForCli) { - response = Buffer.from(response); - } - - fs.writeFileSync(destination, response); - if (parseOutput) { - parse(response) - } - - return response; - -} -interface StorageGetFilePreviewRequestParams { - bucketId: string; - fileId: string; - width?: number; - height?: number; - gravity?: ImageGravity; - quality?: number; - borderWidth?: number; - borderColor?: string; - borderRadius?: number; - opacity?: number; - rotation?: number; - background?: string; - output?: ImageFormat; - token?: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; - destination?: string; -} - -export const storageGetFilePreview = async ({bucketId,fileId,width,height,gravity,quality,borderWidth,borderColor,borderRadius,opacity,rotation,background,output,token,parseOutput = true, overrideForCli = false, sdk = undefined, destination}: StorageGetFilePreviewRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/storage/buckets/{bucketId}/files/{fileId}/preview'.replace('{bucketId}', bucketId).replace('{fileId}', fileId); - let payload = {}; - if (typeof width !== 'undefined') { - payload['width'] = width; - } - if (typeof height !== 'undefined') { - payload['height'] = height; - } - if (typeof gravity !== 'undefined') { - payload['gravity'] = gravity; - } - if (typeof quality !== 'undefined') { - payload['quality'] = quality; - } - if (typeof borderWidth !== 'undefined') { - payload['borderWidth'] = borderWidth; - } - if (typeof borderColor !== 'undefined') { - payload['borderColor'] = borderColor; - } - if (typeof borderRadius !== 'undefined') { - payload['borderRadius'] = borderRadius; - } - if (typeof opacity !== 'undefined') { - payload['opacity'] = opacity; - } - if (typeof rotation !== 'undefined') { - payload['rotation'] = rotation; - } - if (typeof background !== 'undefined') { - payload['background'] = background; - } - if (typeof output !== 'undefined') { - payload['output'] = output; - } - if (typeof token !== 'undefined') { - payload['token'] = token; - } - if (!overrideForCli) { - payload['project'] = localConfig.getProject().projectId - payload['key'] = globalConfig.getKey(); - const queryParams = new URLSearchParams(payload); - apiPath = `${globalConfig.getEndpoint()}${apiPath}?${queryParams.toString()}`; - } - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload, 'arraybuffer'); - - if (overrideForCli) { - response = Buffer.from(response); - } - - fs.writeFileSync(destination, response); - if (parseOutput) { - parse(response) - } - - return response; - -} -interface StorageGetFileViewRequestParams { - bucketId: string; - fileId: string; - token?: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; - destination?: string; -} - -export const storageGetFileView = async ({bucketId,fileId,token,parseOutput = true, overrideForCli = false, sdk = undefined, destination}: StorageGetFileViewRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/storage/buckets/{bucketId}/files/{fileId}/view'.replace('{bucketId}', bucketId).replace('{fileId}', fileId); - let payload = {}; - if (typeof token !== 'undefined') { - payload['token'] = token; - } - if (!overrideForCli) { - payload['project'] = localConfig.getProject().projectId - payload['key'] = globalConfig.getKey(); - const queryParams = new URLSearchParams(payload); - apiPath = `${globalConfig.getEndpoint()}${apiPath}?${queryParams.toString()}`; - } - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload, 'arraybuffer'); - - if (overrideForCli) { - response = Buffer.from(response); - } - - fs.writeFileSync(destination, response); - if (parseOutput) { - parse(response) - } - - return response; - -} -interface StorageGetUsageRequestParams { - range?: UsageRange; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const storageGetUsage = async ({range,parseOutput = true, overrideForCli = false, sdk = undefined}: StorageGetUsageRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/storage/usage'; - let payload = {}; - if (typeof range !== 'undefined') { - payload['range'] = range; - } - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface StorageGetBucketUsageRequestParams { - bucketId: string; - range?: UsageRange; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; - console?: boolean; -} - -export const storageGetBucketUsage = async ({bucketId,range,parseOutput = true, overrideForCli = false, sdk = undefined, console: showConsole}: StorageGetBucketUsageRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/storage/{bucketId}/usage'.replace('{bucketId}', bucketId); - let payload = {}; - if (typeof range !== 'undefined') { - payload['range'] = range; - } - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - if(showConsole) { - showConsoleLink('storage', 'getBucketUsage', bucketId); - } else { - parse(response) - } - } - - return response; - -} -storage - .command(`list-buckets`) - .description(`Get a list of all the storage buckets. You can use the query params to filter your results.`) - .option(`--queries [queries...]`, `Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: enabled, name, fileSecurity, maximumFileSize, encryption, antivirus, transformations`) - .option(`--search <search>`, `Search term to filter your list results. Max length: 256 chars.`) - .option(`--total [value]`, `When set to false, the total count returned will be 0 and will not be calculated.`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .option(`--console`, `Get the resource console url`) - .action(actionRunner(storageListBuckets)) - -storage - .command(`create-bucket`) - .description(`Create a new storage bucket.`) - .requiredOption(`--bucket-id <bucket-id>`, `Unique Id. Choose a custom ID or generate a random ID with 'ID.unique()'. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.`) - .requiredOption(`--name <name>`, `Bucket name`) - .option(`--permissions [permissions...]`, `An array of permission strings. By default, no user is granted with any permissions. [Learn more about permissions](https://appwrite.io/docs/permissions).`) - .option(`--file-security [value]`, `Enables configuring permissions for individual file. A user needs one of file or bucket level permissions to access a file. [Learn more about permissions](https://appwrite.io/docs/permissions).`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .option(`--enabled [value]`, `Is bucket enabled? When set to 'disabled', users cannot access the files in this bucket but Server SDKs with and API key can still access the bucket. No files are lost when this is toggled.`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .option(`--maximum-file-size <maximum-file-size>`, `Maximum file size allowed in bytes. Maximum allowed value is 30MB.`, parseInteger) - .option(`--allowed-file-extensions [allowed-file-extensions...]`, `Allowed file extensions. Maximum of 100 extensions are allowed, each 64 characters long.`) - .option(`--compression <compression>`, `Compression algorithm choosen for compression. Can be one of none, [gzip](https://en.wikipedia.org/wiki/Gzip), or [zstd](https://en.wikipedia.org/wiki/Zstd), For file size above 20MB compression is skipped even if it's enabled`) - .option(`--encryption [value]`, `Is encryption enabled? For file size above 20MB encryption is skipped even if it's enabled`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .option(`--antivirus [value]`, `Is virus scanning enabled? For file size above 20MB AntiVirus scanning is skipped even if it's enabled`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .option(`--transformations [value]`, `Are image transformations enabled?`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .action(actionRunner(storageCreateBucket)) - -storage - .command(`get-bucket`) - .description(`Get a storage bucket by its unique ID. This endpoint response returns a JSON object with the storage bucket metadata.`) - .requiredOption(`--bucket-id <bucket-id>`, `Bucket unique ID.`) - .option(`--console`, `Get the resource console url`) - .action(actionRunner(storageGetBucket)) - -storage - .command(`update-bucket`) - .description(`Update a storage bucket by its unique ID.`) - .requiredOption(`--bucket-id <bucket-id>`, `Bucket unique ID.`) - .requiredOption(`--name <name>`, `Bucket name`) - .option(`--permissions [permissions...]`, `An array of permission strings. By default, the current permissions are inherited. [Learn more about permissions](https://appwrite.io/docs/permissions).`) - .option(`--file-security [value]`, `Enables configuring permissions for individual file. A user needs one of file or bucket level permissions to access a file. [Learn more about permissions](https://appwrite.io/docs/permissions).`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .option(`--enabled [value]`, `Is bucket enabled? When set to 'disabled', users cannot access the files in this bucket but Server SDKs with and API key can still access the bucket. No files are lost when this is toggled.`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .option(`--maximum-file-size <maximum-file-size>`, `Maximum file size allowed in bytes. Maximum allowed value is 30MB.`, parseInteger) - .option(`--allowed-file-extensions [allowed-file-extensions...]`, `Allowed file extensions. Maximum of 100 extensions are allowed, each 64 characters long.`) - .option(`--compression <compression>`, `Compression algorithm choosen for compression. Can be one of none, [gzip](https://en.wikipedia.org/wiki/Gzip), or [zstd](https://en.wikipedia.org/wiki/Zstd), For file size above 20MB compression is skipped even if it's enabled`) - .option(`--encryption [value]`, `Is encryption enabled? For file size above 20MB encryption is skipped even if it's enabled`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .option(`--antivirus [value]`, `Is virus scanning enabled? For file size above 20MB AntiVirus scanning is skipped even if it's enabled`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .option(`--transformations [value]`, `Are image transformations enabled?`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .action(actionRunner(storageUpdateBucket)) - -storage - .command(`delete-bucket`) - .description(`Delete a storage bucket by its unique ID.`) - .requiredOption(`--bucket-id <bucket-id>`, `Bucket unique ID.`) - .action(actionRunner(storageDeleteBucket)) - -storage - .command(`list-files`) - .description(`Get a list of all the user files. You can use the query params to filter your results.`) - .requiredOption(`--bucket-id <bucket-id>`, `Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](https://appwrite.io/docs/server/storage#createBucket).`) - .option(`--queries [queries...]`, `Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: name, signature, mimeType, sizeOriginal, chunksTotal, chunksUploaded`) - .option(`--search <search>`, `Search term to filter your list results. Max length: 256 chars.`) - .option(`--total [value]`, `When set to false, the total count returned will be 0 and will not be calculated.`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .option(`--console`, `Get the resource console url`) - .action(actionRunner(storageListFiles)) - -storage - .command(`create-file`) - .description(`Create a new file. Before using this route, you should create a new bucket resource using either a [server integration](https://appwrite.io/docs/server/storage#storageCreateBucket) API or directly from your Appwrite console. Larger files should be uploaded using multiple requests with the [content-range](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Range) header to send a partial request with a maximum supported chunk of '5MB'. The 'content-range' header values should always be in bytes. When the first request is sent, the server will return the **File** object, and the subsequent part request must include the file's **id** in 'x-appwrite-id' header to allow the server to know that the partial upload is for the existing file and not for a new one. If you're creating a new file using one of the Appwrite SDKs, all the chunking logic will be managed by the SDK internally. `) - .requiredOption(`--bucket-id <bucket-id>`, `Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](https://appwrite.io/docs/server/storage#createBucket).`) - .requiredOption(`--file-id <file-id>`, `File ID. Choose a custom ID or generate a random ID with 'ID.unique()'. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.`) - .requiredOption(`--file <file>`, `Binary file. Appwrite SDKs provide helpers to handle file input. [Learn about file input](https://appwrite.io/docs/products/storage/upload-download#input-file).`) - .option(`--permissions [permissions...]`, `An array of permission strings. By default, only the current user is granted all permissions. [Learn more about permissions](https://appwrite.io/docs/permissions).`) - .action(actionRunner(storageCreateFile)) - -storage - .command(`get-file`) - .description(`Get a file by its unique ID. This endpoint response returns a JSON object with the file metadata.`) - .requiredOption(`--bucket-id <bucket-id>`, `Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](https://appwrite.io/docs/server/storage#createBucket).`) - .requiredOption(`--file-id <file-id>`, `File ID.`) - .option(`--console`, `Get the resource console url`) - .action(actionRunner(storageGetFile)) - -storage - .command(`update-file`) - .description(`Update a file by its unique ID. Only users with write permissions have access to update this resource.`) - .requiredOption(`--bucket-id <bucket-id>`, `Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](https://appwrite.io/docs/server/storage#createBucket).`) - .requiredOption(`--file-id <file-id>`, `File unique ID.`) - .option(`--name <name>`, `Name of the file`) - .option(`--permissions [permissions...]`, `An array of permission string. By default, the current permissions are inherited. [Learn more about permissions](https://appwrite.io/docs/permissions).`) - .action(actionRunner(storageUpdateFile)) - -storage - .command(`delete-file`) - .description(`Delete a file by its unique ID. Only users with write permissions have access to delete this resource.`) - .requiredOption(`--bucket-id <bucket-id>`, `Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](https://appwrite.io/docs/server/storage#createBucket).`) - .requiredOption(`--file-id <file-id>`, `File ID.`) - .action(actionRunner(storageDeleteFile)) - -storage - .command(`get-file-download`) - .description(`Get a file content by its unique ID. The endpoint response return with a 'Content-Disposition: attachment' header that tells the browser to start downloading the file to user downloads directory.`) - .requiredOption(`--bucket-id <bucket-id>`, `Storage bucket ID. You can create a new storage bucket using the Storage service [server integration](https://appwrite.io/docs/server/storage#createBucket).`) - .requiredOption(`--file-id <file-id>`, `File ID.`) - .option(`--token <token>`, `File token for accessing this file.`) - .requiredOption(`--destination <path>`, `output file path.`) - .action(actionRunner(storageGetFileDownload)) - -storage - .command(`get-file-preview`) - .description(`Get a file preview image. Currently, this method supports preview for image files (jpg, png, and gif), other supported formats, like pdf, docs, slides, and spreadsheets, will return the file icon image. You can also pass query string arguments for cutting and resizing your preview image. Preview is supported only for image files smaller than 10MB.`) - .requiredOption(`--bucket-id <bucket-id>`, `Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](https://appwrite.io/docs/server/storage#createBucket).`) - .requiredOption(`--file-id <file-id>`, `File ID`) - .option(`--width <width>`, `Resize preview image width, Pass an integer between 0 to 4000.`, parseInteger) - .option(`--height <height>`, `Resize preview image height, Pass an integer between 0 to 4000.`, parseInteger) - .option(`--gravity <gravity>`, `Image crop gravity. Can be one of center,top-left,top,top-right,left,right,bottom-left,bottom,bottom-right`) - .option(`--quality <quality>`, `Preview image quality. Pass an integer between 0 to 100. Defaults to keep existing image quality.`, parseInteger) - .option(`--border-width <border-width>`, `Preview image border in pixels. Pass an integer between 0 to 100. Defaults to 0.`, parseInteger) - .option(`--border-color <border-color>`, `Preview image border color. Use a valid HEX color, no # is needed for prefix.`) - .option(`--border-radius <border-radius>`, `Preview image border radius in pixels. Pass an integer between 0 to 4000.`, parseInteger) - .option(`--opacity <opacity>`, `Preview image opacity. Only works with images having an alpha channel (like png). Pass a number between 0 to 1.`, parseInteger) - .option(`--rotation <rotation>`, `Preview image rotation in degrees. Pass an integer between -360 and 360.`, parseInteger) - .option(`--background <background>`, `Preview image background color. Only works with transparent images (png). Use a valid HEX color, no # is needed for prefix.`) - .option(`--output <output>`, `Output format type (jpeg, jpg, png, gif and webp).`) - .option(`--token <token>`, `File token for accessing this file.`) - .requiredOption(`--destination <path>`, `output file path.`) - .action(actionRunner(storageGetFilePreview)) - -storage - .command(`get-file-view`) - .description(`Get a file content by its unique ID. This endpoint is similar to the download method but returns with no 'Content-Disposition: attachment' header.`) - .requiredOption(`--bucket-id <bucket-id>`, `Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](https://appwrite.io/docs/server/storage#createBucket).`) - .requiredOption(`--file-id <file-id>`, `File ID.`) - .option(`--token <token>`, `File token for accessing this file.`) - .requiredOption(`--destination <path>`, `output file path.`) - .action(actionRunner(storageGetFileView)) - -storage - .command(`get-usage`) - .description(`Get usage metrics and statistics for all buckets in the project. You can view the total number of buckets, files, storage usage. The response includes both current totals and historical data over time. Use the optional range parameter to specify the time window for historical data: 24h (last 24 hours), 30d (last 30 days), or 90d (last 90 days). If not specified, range defaults to 30 days. `) - .option(`--range <range>`, `Date range.`) - .action(actionRunner(storageGetUsage)) - -storage - .command(`get-bucket-usage`) - .description(`Get usage metrics and statistics a specific bucket in the project. You can view the total number of files, storage usage. The response includes both current totals and historical data over time. Use the optional range parameter to specify the time window for historical data: 24h (last 24 hours), 30d (last 30 days), or 90d (last 90 days). If not specified, range defaults to 30 days. `) - .requiredOption(`--bucket-id <bucket-id>`, `Bucket ID.`) - .option(`--range <range>`, `Date range.`) - .option(`--console`, `Get the resource console url`) - .action(actionRunner(storageGetBucketUsage)) - - diff --git a/lib/commands/tables-db.ts b/lib/commands/tables-db.ts deleted file mode 100644 index 28a314f1..00000000 --- a/lib/commands/tables-db.ts +++ /dev/null @@ -1,3260 +0,0 @@ -import fs = require('fs'); -import pathLib = require('path'); -import tar = require('tar'); -import ignore = require('ignore'); -import { promisify } from 'util'; -import Client from '../client'; -import { getAllFiles, showConsoleLink } from '../utils'; -import { Command } from 'commander'; -import { sdkForProject, sdkForConsole } from '../sdks'; -import { parse, actionRunner, parseInteger, parseBool, commandDescriptions, success, log, warn } from '../parser'; -import { localConfig, globalConfig } from '../config'; -import { File } from 'undici'; -import { ReadableStream } from 'stream/web'; - -function convertReadStreamToReadableStream(readStream: fs.ReadStream): ReadableStream { - return new ReadableStream({ - start(controller) { - readStream.on("data", (chunk: Buffer) => { - controller.enqueue(chunk); - }); - readStream.on("end", () => { - controller.close(); - }); - readStream.on("error", (err: Error) => { - controller.error(err); - }); - }, - cancel() { - readStream.destroy(); - }, - }); -} - -export const tablesDB = new Command("tables-db").description(commandDescriptions['tables-db'] ?? '').configureHelp({ - helpWidth: process.stdout.columns || 80 -}) - -interface TablesDBListRequestParams { - queries?: string[]; - search?: string; - total?: boolean; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; - console?: boolean; -} - -export const tablesDBList = async ({queries,search,total,parseOutput = true, overrideForCli = false, sdk = undefined, console: showConsole}: TablesDBListRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/tablesdb'; - let payload = {}; - if (typeof queries !== 'undefined') { - payload['queries'] = queries; - } - if (typeof search !== 'undefined') { - payload['search'] = search; - } - if (typeof total !== 'undefined') { - payload['total'] = total; - } - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - if(showConsole) { - showConsoleLink('tablesDB', 'list'); - } else { - parse(response) - } - } - - return response; - -} -interface TablesDBCreateRequestParams { - databaseId: string; - name: string; - enabled?: boolean; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const tablesDBCreate = async ({databaseId,name,enabled,parseOutput = true, overrideForCli = false, sdk = undefined}: TablesDBCreateRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/tablesdb'; - let payload = {}; - if (typeof databaseId !== 'undefined') { - payload['databaseId'] = databaseId; - } - if (typeof name !== 'undefined') { - payload['name'] = name; - } - if (typeof enabled !== 'undefined') { - payload['enabled'] = enabled; - } - - let response = undefined; - - response = await client.call('post', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface TablesDBListTransactionsRequestParams { - queries?: string[]; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; - console?: boolean; -} - -export const tablesDBListTransactions = async ({queries,parseOutput = true, overrideForCli = false, sdk = undefined, console: showConsole}: TablesDBListTransactionsRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/tablesdb/transactions'; - let payload = {}; - if (typeof queries !== 'undefined') { - payload['queries'] = queries; - } - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - if(showConsole) { - showConsoleLink('tablesDB', 'listTransactions'); - } else { - parse(response) - } - } - - return response; - -} -interface TablesDBCreateTransactionRequestParams { - ttl?: number; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const tablesDBCreateTransaction = async ({ttl,parseOutput = true, overrideForCli = false, sdk = undefined}: TablesDBCreateTransactionRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/tablesdb/transactions'; - let payload = {}; - if (typeof ttl !== 'undefined') { - payload['ttl'] = ttl; - } - - let response = undefined; - - response = await client.call('post', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface TablesDBGetTransactionRequestParams { - transactionId: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; - console?: boolean; -} - -export const tablesDBGetTransaction = async ({transactionId,parseOutput = true, overrideForCli = false, sdk = undefined, console: showConsole}: TablesDBGetTransactionRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/tablesdb/transactions/{transactionId}'.replace('{transactionId}', transactionId); - let payload = {}; - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - if(showConsole) { - showConsoleLink('tablesDB', 'getTransaction', transactionId); - } else { - parse(response) - } - } - - return response; - -} -interface TablesDBUpdateTransactionRequestParams { - transactionId: string; - commit?: boolean; - rollback?: boolean; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const tablesDBUpdateTransaction = async ({transactionId,commit,rollback,parseOutput = true, overrideForCli = false, sdk = undefined}: TablesDBUpdateTransactionRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/tablesdb/transactions/{transactionId}'.replace('{transactionId}', transactionId); - let payload = {}; - if (typeof commit !== 'undefined') { - payload['commit'] = commit; - } - if (typeof rollback !== 'undefined') { - payload['rollback'] = rollback; - } - - let response = undefined; - - response = await client.call('patch', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface TablesDBDeleteTransactionRequestParams { - transactionId: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const tablesDBDeleteTransaction = async ({transactionId,parseOutput = true, overrideForCli = false, sdk = undefined}: TablesDBDeleteTransactionRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/tablesdb/transactions/{transactionId}'.replace('{transactionId}', transactionId); - let payload = {}; - - let response = undefined; - - response = await client.call('delete', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface TablesDBCreateOperationsRequestParams { - transactionId: string; - operations?: object[]; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const tablesDBCreateOperations = async ({transactionId,operations,parseOutput = true, overrideForCli = false, sdk = undefined}: TablesDBCreateOperationsRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/tablesdb/transactions/{transactionId}/operations'.replace('{transactionId}', transactionId); - let payload = {}; - operations = operations === true ? [] : operations; - if (typeof operations !== 'undefined') { - payload['operations'] = operations; - } - - let response = undefined; - - response = await client.call('post', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface TablesDBListUsageRequestParams { - range?: UsageRange; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; - console?: boolean; -} - -export const tablesDBListUsage = async ({range,parseOutput = true, overrideForCli = false, sdk = undefined, console: showConsole}: TablesDBListUsageRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/tablesdb/usage'; - let payload = {}; - if (typeof range !== 'undefined') { - payload['range'] = range; - } - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - if(showConsole) { - showConsoleLink('tablesDB', 'listUsage'); - } else { - parse(response) - } - } - - return response; - -} -interface TablesDBGetRequestParams { - databaseId: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; - console?: boolean; -} - -export const tablesDBGet = async ({databaseId,parseOutput = true, overrideForCli = false, sdk = undefined, console: showConsole}: TablesDBGetRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/tablesdb/{databaseId}'.replace('{databaseId}', databaseId); - let payload = {}; - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - if(showConsole) { - showConsoleLink('tablesDB', 'get', databaseId); - } else { - parse(response) - } - } - - return response; - -} -interface TablesDBUpdateRequestParams { - databaseId: string; - name: string; - enabled?: boolean; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const tablesDBUpdate = async ({databaseId,name,enabled,parseOutput = true, overrideForCli = false, sdk = undefined}: TablesDBUpdateRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/tablesdb/{databaseId}'.replace('{databaseId}', databaseId); - let payload = {}; - if (typeof name !== 'undefined') { - payload['name'] = name; - } - if (typeof enabled !== 'undefined') { - payload['enabled'] = enabled; - } - - let response = undefined; - - response = await client.call('put', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface TablesDBDeleteRequestParams { - databaseId: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const tablesDBDelete = async ({databaseId,parseOutput = true, overrideForCli = false, sdk = undefined}: TablesDBDeleteRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/tablesdb/{databaseId}'.replace('{databaseId}', databaseId); - let payload = {}; - - let response = undefined; - - response = await client.call('delete', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface TablesDBListTablesRequestParams { - databaseId: string; - queries?: string[]; - search?: string; - total?: boolean; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; - console?: boolean; -} - -export const tablesDBListTables = async ({databaseId,queries,search,total,parseOutput = true, overrideForCli = false, sdk = undefined, console: showConsole}: TablesDBListTablesRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/tablesdb/{databaseId}/tables'.replace('{databaseId}', databaseId); - let payload = {}; - if (typeof queries !== 'undefined') { - payload['queries'] = queries; - } - if (typeof search !== 'undefined') { - payload['search'] = search; - } - if (typeof total !== 'undefined') { - payload['total'] = total; - } - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - if(showConsole) { - showConsoleLink('tablesDB', 'listTables', databaseId); - } else { - parse(response) - } - } - - return response; - -} -interface TablesDBCreateTableRequestParams { - databaseId: string; - tableId: string; - name: string; - permissions?: string[]; - rowSecurity?: boolean; - enabled?: boolean; - columns?: object[]; - indexes?: object[]; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const tablesDBCreateTable = async ({databaseId,tableId,name,permissions,rowSecurity,enabled,columns,indexes,parseOutput = true, overrideForCli = false, sdk = undefined}: TablesDBCreateTableRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/tablesdb/{databaseId}/tables'.replace('{databaseId}', databaseId); - let payload = {}; - if (typeof tableId !== 'undefined') { - payload['tableId'] = tableId; - } - if (typeof name !== 'undefined') { - payload['name'] = name; - } - permissions = permissions === true ? [] : permissions; - if (typeof permissions !== 'undefined') { - payload['permissions'] = permissions; - } - if (typeof rowSecurity !== 'undefined') { - payload['rowSecurity'] = rowSecurity; - } - if (typeof enabled !== 'undefined') { - payload['enabled'] = enabled; - } - columns = columns === true ? [] : columns; - if (typeof columns !== 'undefined') { - payload['columns'] = columns; - } - indexes = indexes === true ? [] : indexes; - if (typeof indexes !== 'undefined') { - payload['indexes'] = indexes; - } - - let response = undefined; - - response = await client.call('post', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface TablesDBGetTableRequestParams { - databaseId: string; - tableId: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; - console?: boolean; -} - -export const tablesDBGetTable = async ({databaseId,tableId,parseOutput = true, overrideForCli = false, sdk = undefined, console: showConsole}: TablesDBGetTableRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/tablesdb/{databaseId}/tables/{tableId}'.replace('{databaseId}', databaseId).replace('{tableId}', tableId); - let payload = {}; - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - if(showConsole) { - showConsoleLink('tablesDB', 'getTable', databaseId, tableId); - } else { - parse(response) - } - } - - return response; - -} -interface TablesDBUpdateTableRequestParams { - databaseId: string; - tableId: string; - name: string; - permissions?: string[]; - rowSecurity?: boolean; - enabled?: boolean; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const tablesDBUpdateTable = async ({databaseId,tableId,name,permissions,rowSecurity,enabled,parseOutput = true, overrideForCli = false, sdk = undefined}: TablesDBUpdateTableRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/tablesdb/{databaseId}/tables/{tableId}'.replace('{databaseId}', databaseId).replace('{tableId}', tableId); - let payload = {}; - if (typeof name !== 'undefined') { - payload['name'] = name; - } - permissions = permissions === true ? [] : permissions; - if (typeof permissions !== 'undefined') { - payload['permissions'] = permissions; - } - if (typeof rowSecurity !== 'undefined') { - payload['rowSecurity'] = rowSecurity; - } - if (typeof enabled !== 'undefined') { - payload['enabled'] = enabled; - } - - let response = undefined; - - response = await client.call('put', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface TablesDBDeleteTableRequestParams { - databaseId: string; - tableId: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const tablesDBDeleteTable = async ({databaseId,tableId,parseOutput = true, overrideForCli = false, sdk = undefined}: TablesDBDeleteTableRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/tablesdb/{databaseId}/tables/{tableId}'.replace('{databaseId}', databaseId).replace('{tableId}', tableId); - let payload = {}; - - let response = undefined; - - response = await client.call('delete', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface TablesDBListColumnsRequestParams { - databaseId: string; - tableId: string; - queries?: string[]; - total?: boolean; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; - console?: boolean; -} - -export const tablesDBListColumns = async ({databaseId,tableId,queries,total,parseOutput = true, overrideForCli = false, sdk = undefined, console: showConsole}: TablesDBListColumnsRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/tablesdb/{databaseId}/tables/{tableId}/columns'.replace('{databaseId}', databaseId).replace('{tableId}', tableId); - let payload = {}; - if (typeof queries !== 'undefined') { - payload['queries'] = queries; - } - if (typeof total !== 'undefined') { - payload['total'] = total; - } - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - if(showConsole) { - showConsoleLink('tablesDB', 'listColumns', databaseId, tableId); - } else { - parse(response) - } - } - - return response; - -} -interface TablesDBCreateBooleanColumnRequestParams { - databaseId: string; - tableId: string; - key: string; - required: boolean; - xdefault?: boolean; - array?: boolean; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const tablesDBCreateBooleanColumn = async ({databaseId,tableId,key,required,xdefault,array,parseOutput = true, overrideForCli = false, sdk = undefined}: TablesDBCreateBooleanColumnRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/tablesdb/{databaseId}/tables/{tableId}/columns/boolean'.replace('{databaseId}', databaseId).replace('{tableId}', tableId); - let payload = {}; - if (typeof key !== 'undefined') { - payload['key'] = key; - } - if (typeof required !== 'undefined') { - payload['required'] = required; - } - if (typeof xdefault !== 'undefined') { - payload['default'] = xdefault; - } - if (typeof array !== 'undefined') { - payload['array'] = array; - } - - let response = undefined; - - response = await client.call('post', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface TablesDBUpdateBooleanColumnRequestParams { - databaseId: string; - tableId: string; - key: string; - required: boolean; - xdefault: boolean; - newKey?: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const tablesDBUpdateBooleanColumn = async ({databaseId,tableId,key,required,xdefault,newKey,parseOutput = true, overrideForCli = false, sdk = undefined}: TablesDBUpdateBooleanColumnRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/tablesdb/{databaseId}/tables/{tableId}/columns/boolean/{key}'.replace('{databaseId}', databaseId).replace('{tableId}', tableId).replace('{key}', key); - let payload = {}; - if (typeof required !== 'undefined') { - payload['required'] = required; - } - if (typeof xdefault !== 'undefined') { - payload['default'] = xdefault; - } - if (typeof newKey !== 'undefined') { - payload['newKey'] = newKey; - } - - let response = undefined; - - response = await client.call('patch', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface TablesDBCreateDatetimeColumnRequestParams { - databaseId: string; - tableId: string; - key: string; - required: boolean; - xdefault?: string; - array?: boolean; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const tablesDBCreateDatetimeColumn = async ({databaseId,tableId,key,required,xdefault,array,parseOutput = true, overrideForCli = false, sdk = undefined}: TablesDBCreateDatetimeColumnRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/tablesdb/{databaseId}/tables/{tableId}/columns/datetime'.replace('{databaseId}', databaseId).replace('{tableId}', tableId); - let payload = {}; - if (typeof key !== 'undefined') { - payload['key'] = key; - } - if (typeof required !== 'undefined') { - payload['required'] = required; - } - if (typeof xdefault !== 'undefined') { - payload['default'] = xdefault; - } - if (typeof array !== 'undefined') { - payload['array'] = array; - } - - let response = undefined; - - response = await client.call('post', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface TablesDBUpdateDatetimeColumnRequestParams { - databaseId: string; - tableId: string; - key: string; - required: boolean; - xdefault: string; - newKey?: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const tablesDBUpdateDatetimeColumn = async ({databaseId,tableId,key,required,xdefault,newKey,parseOutput = true, overrideForCli = false, sdk = undefined}: TablesDBUpdateDatetimeColumnRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/tablesdb/{databaseId}/tables/{tableId}/columns/datetime/{key}'.replace('{databaseId}', databaseId).replace('{tableId}', tableId).replace('{key}', key); - let payload = {}; - if (typeof required !== 'undefined') { - payload['required'] = required; - } - if (typeof xdefault !== 'undefined') { - payload['default'] = xdefault; - } - if (typeof newKey !== 'undefined') { - payload['newKey'] = newKey; - } - - let response = undefined; - - response = await client.call('patch', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface TablesDBCreateEmailColumnRequestParams { - databaseId: string; - tableId: string; - key: string; - required: boolean; - xdefault?: string; - array?: boolean; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const tablesDBCreateEmailColumn = async ({databaseId,tableId,key,required,xdefault,array,parseOutput = true, overrideForCli = false, sdk = undefined}: TablesDBCreateEmailColumnRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/tablesdb/{databaseId}/tables/{tableId}/columns/email'.replace('{databaseId}', databaseId).replace('{tableId}', tableId); - let payload = {}; - if (typeof key !== 'undefined') { - payload['key'] = key; - } - if (typeof required !== 'undefined') { - payload['required'] = required; - } - if (typeof xdefault !== 'undefined') { - payload['default'] = xdefault; - } - if (typeof array !== 'undefined') { - payload['array'] = array; - } - - let response = undefined; - - response = await client.call('post', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface TablesDBUpdateEmailColumnRequestParams { - databaseId: string; - tableId: string; - key: string; - required: boolean; - xdefault: string; - newKey?: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const tablesDBUpdateEmailColumn = async ({databaseId,tableId,key,required,xdefault,newKey,parseOutput = true, overrideForCli = false, sdk = undefined}: TablesDBUpdateEmailColumnRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/tablesdb/{databaseId}/tables/{tableId}/columns/email/{key}'.replace('{databaseId}', databaseId).replace('{tableId}', tableId).replace('{key}', key); - let payload = {}; - if (typeof required !== 'undefined') { - payload['required'] = required; - } - if (typeof xdefault !== 'undefined') { - payload['default'] = xdefault; - } - if (typeof newKey !== 'undefined') { - payload['newKey'] = newKey; - } - - let response = undefined; - - response = await client.call('patch', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface TablesDBCreateEnumColumnRequestParams { - databaseId: string; - tableId: string; - key: string; - elements: string[]; - required: boolean; - xdefault?: string; - array?: boolean; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const tablesDBCreateEnumColumn = async ({databaseId,tableId,key,elements,required,xdefault,array,parseOutput = true, overrideForCli = false, sdk = undefined}: TablesDBCreateEnumColumnRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/tablesdb/{databaseId}/tables/{tableId}/columns/enum'.replace('{databaseId}', databaseId).replace('{tableId}', tableId); - let payload = {}; - if (typeof key !== 'undefined') { - payload['key'] = key; - } - elements = elements === true ? [] : elements; - if (typeof elements !== 'undefined') { - payload['elements'] = elements; - } - if (typeof required !== 'undefined') { - payload['required'] = required; - } - if (typeof xdefault !== 'undefined') { - payload['default'] = xdefault; - } - if (typeof array !== 'undefined') { - payload['array'] = array; - } - - let response = undefined; - - response = await client.call('post', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface TablesDBUpdateEnumColumnRequestParams { - databaseId: string; - tableId: string; - key: string; - elements: string[]; - required: boolean; - xdefault: string; - newKey?: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const tablesDBUpdateEnumColumn = async ({databaseId,tableId,key,elements,required,xdefault,newKey,parseOutput = true, overrideForCli = false, sdk = undefined}: TablesDBUpdateEnumColumnRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/tablesdb/{databaseId}/tables/{tableId}/columns/enum/{key}'.replace('{databaseId}', databaseId).replace('{tableId}', tableId).replace('{key}', key); - let payload = {}; - elements = elements === true ? [] : elements; - if (typeof elements !== 'undefined') { - payload['elements'] = elements; - } - if (typeof required !== 'undefined') { - payload['required'] = required; - } - if (typeof xdefault !== 'undefined') { - payload['default'] = xdefault; - } - if (typeof newKey !== 'undefined') { - payload['newKey'] = newKey; - } - - let response = undefined; - - response = await client.call('patch', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface TablesDBCreateFloatColumnRequestParams { - databaseId: string; - tableId: string; - key: string; - required: boolean; - min?: number; - max?: number; - xdefault?: number; - array?: boolean; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const tablesDBCreateFloatColumn = async ({databaseId,tableId,key,required,min,max,xdefault,array,parseOutput = true, overrideForCli = false, sdk = undefined}: TablesDBCreateFloatColumnRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/tablesdb/{databaseId}/tables/{tableId}/columns/float'.replace('{databaseId}', databaseId).replace('{tableId}', tableId); - let payload = {}; - if (typeof key !== 'undefined') { - payload['key'] = key; - } - if (typeof required !== 'undefined') { - payload['required'] = required; - } - if (typeof min !== 'undefined') { - payload['min'] = min; - } - if (typeof max !== 'undefined') { - payload['max'] = max; - } - if (typeof xdefault !== 'undefined') { - payload['default'] = xdefault; - } - if (typeof array !== 'undefined') { - payload['array'] = array; - } - - let response = undefined; - - response = await client.call('post', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface TablesDBUpdateFloatColumnRequestParams { - databaseId: string; - tableId: string; - key: string; - required: boolean; - xdefault: number; - min?: number; - max?: number; - newKey?: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const tablesDBUpdateFloatColumn = async ({databaseId,tableId,key,required,xdefault,min,max,newKey,parseOutput = true, overrideForCli = false, sdk = undefined}: TablesDBUpdateFloatColumnRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/tablesdb/{databaseId}/tables/{tableId}/columns/float/{key}'.replace('{databaseId}', databaseId).replace('{tableId}', tableId).replace('{key}', key); - let payload = {}; - if (typeof required !== 'undefined') { - payload['required'] = required; - } - if (typeof min !== 'undefined') { - payload['min'] = min; - } - if (typeof max !== 'undefined') { - payload['max'] = max; - } - if (typeof xdefault !== 'undefined') { - payload['default'] = xdefault; - } - if (typeof newKey !== 'undefined') { - payload['newKey'] = newKey; - } - - let response = undefined; - - response = await client.call('patch', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface TablesDBCreateIntegerColumnRequestParams { - databaseId: string; - tableId: string; - key: string; - required: boolean; - min?: number; - max?: number; - xdefault?: number; - array?: boolean; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const tablesDBCreateIntegerColumn = async ({databaseId,tableId,key,required,min,max,xdefault,array,parseOutput = true, overrideForCli = false, sdk = undefined}: TablesDBCreateIntegerColumnRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/tablesdb/{databaseId}/tables/{tableId}/columns/integer'.replace('{databaseId}', databaseId).replace('{tableId}', tableId); - let payload = {}; - if (typeof key !== 'undefined') { - payload['key'] = key; - } - if (typeof required !== 'undefined') { - payload['required'] = required; - } - if (typeof min !== 'undefined') { - payload['min'] = min; - } - if (typeof max !== 'undefined') { - payload['max'] = max; - } - if (typeof xdefault !== 'undefined') { - payload['default'] = xdefault; - } - if (typeof array !== 'undefined') { - payload['array'] = array; - } - - let response = undefined; - - response = await client.call('post', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface TablesDBUpdateIntegerColumnRequestParams { - databaseId: string; - tableId: string; - key: string; - required: boolean; - xdefault: number; - min?: number; - max?: number; - newKey?: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const tablesDBUpdateIntegerColumn = async ({databaseId,tableId,key,required,xdefault,min,max,newKey,parseOutput = true, overrideForCli = false, sdk = undefined}: TablesDBUpdateIntegerColumnRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/tablesdb/{databaseId}/tables/{tableId}/columns/integer/{key}'.replace('{databaseId}', databaseId).replace('{tableId}', tableId).replace('{key}', key); - let payload = {}; - if (typeof required !== 'undefined') { - payload['required'] = required; - } - if (typeof min !== 'undefined') { - payload['min'] = min; - } - if (typeof max !== 'undefined') { - payload['max'] = max; - } - if (typeof xdefault !== 'undefined') { - payload['default'] = xdefault; - } - if (typeof newKey !== 'undefined') { - payload['newKey'] = newKey; - } - - let response = undefined; - - response = await client.call('patch', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface TablesDBCreateIpColumnRequestParams { - databaseId: string; - tableId: string; - key: string; - required: boolean; - xdefault?: string; - array?: boolean; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const tablesDBCreateIpColumn = async ({databaseId,tableId,key,required,xdefault,array,parseOutput = true, overrideForCli = false, sdk = undefined}: TablesDBCreateIpColumnRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/tablesdb/{databaseId}/tables/{tableId}/columns/ip'.replace('{databaseId}', databaseId).replace('{tableId}', tableId); - let payload = {}; - if (typeof key !== 'undefined') { - payload['key'] = key; - } - if (typeof required !== 'undefined') { - payload['required'] = required; - } - if (typeof xdefault !== 'undefined') { - payload['default'] = xdefault; - } - if (typeof array !== 'undefined') { - payload['array'] = array; - } - - let response = undefined; - - response = await client.call('post', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface TablesDBUpdateIpColumnRequestParams { - databaseId: string; - tableId: string; - key: string; - required: boolean; - xdefault: string; - newKey?: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const tablesDBUpdateIpColumn = async ({databaseId,tableId,key,required,xdefault,newKey,parseOutput = true, overrideForCli = false, sdk = undefined}: TablesDBUpdateIpColumnRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/tablesdb/{databaseId}/tables/{tableId}/columns/ip/{key}'.replace('{databaseId}', databaseId).replace('{tableId}', tableId).replace('{key}', key); - let payload = {}; - if (typeof required !== 'undefined') { - payload['required'] = required; - } - if (typeof xdefault !== 'undefined') { - payload['default'] = xdefault; - } - if (typeof newKey !== 'undefined') { - payload['newKey'] = newKey; - } - - let response = undefined; - - response = await client.call('patch', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface TablesDBCreateLineColumnRequestParams { - databaseId: string; - tableId: string; - key: string; - required: boolean; - xdefault?: any[]; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const tablesDBCreateLineColumn = async ({databaseId,tableId,key,required,xdefault,parseOutput = true, overrideForCli = false, sdk = undefined}: TablesDBCreateLineColumnRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/tablesdb/{databaseId}/tables/{tableId}/columns/line'.replace('{databaseId}', databaseId).replace('{tableId}', tableId); - let payload = {}; - if (typeof key !== 'undefined') { - payload['key'] = key; - } - if (typeof required !== 'undefined') { - payload['required'] = required; - } - xdefault = xdefault === true ? [] : xdefault; - if (typeof xdefault !== 'undefined') { - payload['default'] = xdefault; - } - - let response = undefined; - - response = await client.call('post', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface TablesDBUpdateLineColumnRequestParams { - databaseId: string; - tableId: string; - key: string; - required: boolean; - xdefault?: any[]; - newKey?: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const tablesDBUpdateLineColumn = async ({databaseId,tableId,key,required,xdefault,newKey,parseOutput = true, overrideForCli = false, sdk = undefined}: TablesDBUpdateLineColumnRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/tablesdb/{databaseId}/tables/{tableId}/columns/line/{key}'.replace('{databaseId}', databaseId).replace('{tableId}', tableId).replace('{key}', key); - let payload = {}; - if (typeof required !== 'undefined') { - payload['required'] = required; - } - xdefault = xdefault === true ? [] : xdefault; - if (typeof xdefault !== 'undefined') { - payload['default'] = xdefault; - } - if (typeof newKey !== 'undefined') { - payload['newKey'] = newKey; - } - - let response = undefined; - - response = await client.call('patch', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface TablesDBCreatePointColumnRequestParams { - databaseId: string; - tableId: string; - key: string; - required: boolean; - xdefault?: any[]; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const tablesDBCreatePointColumn = async ({databaseId,tableId,key,required,xdefault,parseOutput = true, overrideForCli = false, sdk = undefined}: TablesDBCreatePointColumnRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/tablesdb/{databaseId}/tables/{tableId}/columns/point'.replace('{databaseId}', databaseId).replace('{tableId}', tableId); - let payload = {}; - if (typeof key !== 'undefined') { - payload['key'] = key; - } - if (typeof required !== 'undefined') { - payload['required'] = required; - } - xdefault = xdefault === true ? [] : xdefault; - if (typeof xdefault !== 'undefined') { - payload['default'] = xdefault; - } - - let response = undefined; - - response = await client.call('post', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface TablesDBUpdatePointColumnRequestParams { - databaseId: string; - tableId: string; - key: string; - required: boolean; - xdefault?: any[]; - newKey?: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const tablesDBUpdatePointColumn = async ({databaseId,tableId,key,required,xdefault,newKey,parseOutput = true, overrideForCli = false, sdk = undefined}: TablesDBUpdatePointColumnRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/tablesdb/{databaseId}/tables/{tableId}/columns/point/{key}'.replace('{databaseId}', databaseId).replace('{tableId}', tableId).replace('{key}', key); - let payload = {}; - if (typeof required !== 'undefined') { - payload['required'] = required; - } - xdefault = xdefault === true ? [] : xdefault; - if (typeof xdefault !== 'undefined') { - payload['default'] = xdefault; - } - if (typeof newKey !== 'undefined') { - payload['newKey'] = newKey; - } - - let response = undefined; - - response = await client.call('patch', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface TablesDBCreatePolygonColumnRequestParams { - databaseId: string; - tableId: string; - key: string; - required: boolean; - xdefault?: any[]; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const tablesDBCreatePolygonColumn = async ({databaseId,tableId,key,required,xdefault,parseOutput = true, overrideForCli = false, sdk = undefined}: TablesDBCreatePolygonColumnRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/tablesdb/{databaseId}/tables/{tableId}/columns/polygon'.replace('{databaseId}', databaseId).replace('{tableId}', tableId); - let payload = {}; - if (typeof key !== 'undefined') { - payload['key'] = key; - } - if (typeof required !== 'undefined') { - payload['required'] = required; - } - xdefault = xdefault === true ? [] : xdefault; - if (typeof xdefault !== 'undefined') { - payload['default'] = xdefault; - } - - let response = undefined; - - response = await client.call('post', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface TablesDBUpdatePolygonColumnRequestParams { - databaseId: string; - tableId: string; - key: string; - required: boolean; - xdefault?: any[]; - newKey?: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const tablesDBUpdatePolygonColumn = async ({databaseId,tableId,key,required,xdefault,newKey,parseOutput = true, overrideForCli = false, sdk = undefined}: TablesDBUpdatePolygonColumnRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/tablesdb/{databaseId}/tables/{tableId}/columns/polygon/{key}'.replace('{databaseId}', databaseId).replace('{tableId}', tableId).replace('{key}', key); - let payload = {}; - if (typeof required !== 'undefined') { - payload['required'] = required; - } - xdefault = xdefault === true ? [] : xdefault; - if (typeof xdefault !== 'undefined') { - payload['default'] = xdefault; - } - if (typeof newKey !== 'undefined') { - payload['newKey'] = newKey; - } - - let response = undefined; - - response = await client.call('patch', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface TablesDBCreateRelationshipColumnRequestParams { - databaseId: string; - tableId: string; - relatedTableId: string; - type: RelationshipType; - twoWay?: boolean; - key?: string; - twoWayKey?: string; - onDelete?: RelationMutate; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const tablesDBCreateRelationshipColumn = async ({databaseId,tableId,relatedTableId,type,twoWay,key,twoWayKey,onDelete,parseOutput = true, overrideForCli = false, sdk = undefined}: TablesDBCreateRelationshipColumnRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/tablesdb/{databaseId}/tables/{tableId}/columns/relationship'.replace('{databaseId}', databaseId).replace('{tableId}', tableId); - let payload = {}; - if (typeof relatedTableId !== 'undefined') { - payload['relatedTableId'] = relatedTableId; - } - if (typeof type !== 'undefined') { - payload['type'] = type; - } - if (typeof twoWay !== 'undefined') { - payload['twoWay'] = twoWay; - } - if (typeof key !== 'undefined') { - payload['key'] = key; - } - if (typeof twoWayKey !== 'undefined') { - payload['twoWayKey'] = twoWayKey; - } - if (typeof onDelete !== 'undefined') { - payload['onDelete'] = onDelete; - } - - let response = undefined; - - response = await client.call('post', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface TablesDBCreateStringColumnRequestParams { - databaseId: string; - tableId: string; - key: string; - size: number; - required: boolean; - xdefault?: string; - array?: boolean; - encrypt?: boolean; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const tablesDBCreateStringColumn = async ({databaseId,tableId,key,size,required,xdefault,array,encrypt,parseOutput = true, overrideForCli = false, sdk = undefined}: TablesDBCreateStringColumnRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/tablesdb/{databaseId}/tables/{tableId}/columns/string'.replace('{databaseId}', databaseId).replace('{tableId}', tableId); - let payload = {}; - if (typeof key !== 'undefined') { - payload['key'] = key; - } - if (typeof size !== 'undefined') { - payload['size'] = size; - } - if (typeof required !== 'undefined') { - payload['required'] = required; - } - if (typeof xdefault !== 'undefined') { - payload['default'] = xdefault; - } - if (typeof array !== 'undefined') { - payload['array'] = array; - } - if (typeof encrypt !== 'undefined') { - payload['encrypt'] = encrypt; - } - - let response = undefined; - - response = await client.call('post', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface TablesDBUpdateStringColumnRequestParams { - databaseId: string; - tableId: string; - key: string; - required: boolean; - xdefault: string; - size?: number; - newKey?: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const tablesDBUpdateStringColumn = async ({databaseId,tableId,key,required,xdefault,size,newKey,parseOutput = true, overrideForCli = false, sdk = undefined}: TablesDBUpdateStringColumnRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/tablesdb/{databaseId}/tables/{tableId}/columns/string/{key}'.replace('{databaseId}', databaseId).replace('{tableId}', tableId).replace('{key}', key); - let payload = {}; - if (typeof required !== 'undefined') { - payload['required'] = required; - } - if (typeof xdefault !== 'undefined') { - payload['default'] = xdefault; - } - if (typeof size !== 'undefined') { - payload['size'] = size; - } - if (typeof newKey !== 'undefined') { - payload['newKey'] = newKey; - } - - let response = undefined; - - response = await client.call('patch', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface TablesDBCreateUrlColumnRequestParams { - databaseId: string; - tableId: string; - key: string; - required: boolean; - xdefault?: string; - array?: boolean; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const tablesDBCreateUrlColumn = async ({databaseId,tableId,key,required,xdefault,array,parseOutput = true, overrideForCli = false, sdk = undefined}: TablesDBCreateUrlColumnRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/tablesdb/{databaseId}/tables/{tableId}/columns/url'.replace('{databaseId}', databaseId).replace('{tableId}', tableId); - let payload = {}; - if (typeof key !== 'undefined') { - payload['key'] = key; - } - if (typeof required !== 'undefined') { - payload['required'] = required; - } - if (typeof xdefault !== 'undefined') { - payload['default'] = xdefault; - } - if (typeof array !== 'undefined') { - payload['array'] = array; - } - - let response = undefined; - - response = await client.call('post', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface TablesDBUpdateUrlColumnRequestParams { - databaseId: string; - tableId: string; - key: string; - required: boolean; - xdefault: string; - newKey?: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const tablesDBUpdateUrlColumn = async ({databaseId,tableId,key,required,xdefault,newKey,parseOutput = true, overrideForCli = false, sdk = undefined}: TablesDBUpdateUrlColumnRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/tablesdb/{databaseId}/tables/{tableId}/columns/url/{key}'.replace('{databaseId}', databaseId).replace('{tableId}', tableId).replace('{key}', key); - let payload = {}; - if (typeof required !== 'undefined') { - payload['required'] = required; - } - if (typeof xdefault !== 'undefined') { - payload['default'] = xdefault; - } - if (typeof newKey !== 'undefined') { - payload['newKey'] = newKey; - } - - let response = undefined; - - response = await client.call('patch', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface TablesDBGetColumnRequestParams { - databaseId: string; - tableId: string; - key: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; - console?: boolean; -} - -export const tablesDBGetColumn = async ({databaseId,tableId,key,parseOutput = true, overrideForCli = false, sdk = undefined, console: showConsole}: TablesDBGetColumnRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/tablesdb/{databaseId}/tables/{tableId}/columns/{key}'.replace('{databaseId}', databaseId).replace('{tableId}', tableId).replace('{key}', key); - let payload = {}; - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - if(showConsole) { - showConsoleLink('tablesDB', 'getColumn', databaseId, tableId); - } else { - parse(response) - } - } - - return response; - -} -interface TablesDBDeleteColumnRequestParams { - databaseId: string; - tableId: string; - key: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const tablesDBDeleteColumn = async ({databaseId,tableId,key,parseOutput = true, overrideForCli = false, sdk = undefined}: TablesDBDeleteColumnRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/tablesdb/{databaseId}/tables/{tableId}/columns/{key}'.replace('{databaseId}', databaseId).replace('{tableId}', tableId).replace('{key}', key); - let payload = {}; - - let response = undefined; - - response = await client.call('delete', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface TablesDBUpdateRelationshipColumnRequestParams { - databaseId: string; - tableId: string; - key: string; - onDelete?: RelationMutate; - newKey?: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const tablesDBUpdateRelationshipColumn = async ({databaseId,tableId,key,onDelete,newKey,parseOutput = true, overrideForCli = false, sdk = undefined}: TablesDBUpdateRelationshipColumnRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/tablesdb/{databaseId}/tables/{tableId}/columns/{key}/relationship'.replace('{databaseId}', databaseId).replace('{tableId}', tableId).replace('{key}', key); - let payload = {}; - if (typeof onDelete !== 'undefined') { - payload['onDelete'] = onDelete; - } - if (typeof newKey !== 'undefined') { - payload['newKey'] = newKey; - } - - let response = undefined; - - response = await client.call('patch', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface TablesDBListIndexesRequestParams { - databaseId: string; - tableId: string; - queries?: string[]; - total?: boolean; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; - console?: boolean; -} - -export const tablesDBListIndexes = async ({databaseId,tableId,queries,total,parseOutput = true, overrideForCli = false, sdk = undefined, console: showConsole}: TablesDBListIndexesRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/tablesdb/{databaseId}/tables/{tableId}/indexes'.replace('{databaseId}', databaseId).replace('{tableId}', tableId); - let payload = {}; - if (typeof queries !== 'undefined') { - payload['queries'] = queries; - } - if (typeof total !== 'undefined') { - payload['total'] = total; - } - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - if(showConsole) { - showConsoleLink('tablesDB', 'listIndexes', databaseId, tableId); - } else { - parse(response) - } - } - - return response; - -} -interface TablesDBCreateIndexRequestParams { - databaseId: string; - tableId: string; - key: string; - type: IndexType; - columns: string[]; - orders?: string[]; - lengths?: number[]; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const tablesDBCreateIndex = async ({databaseId,tableId,key,type,columns,orders,lengths,parseOutput = true, overrideForCli = false, sdk = undefined}: TablesDBCreateIndexRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/tablesdb/{databaseId}/tables/{tableId}/indexes'.replace('{databaseId}', databaseId).replace('{tableId}', tableId); - let payload = {}; - if (typeof key !== 'undefined') { - payload['key'] = key; - } - if (typeof type !== 'undefined') { - payload['type'] = type; - } - columns = columns === true ? [] : columns; - if (typeof columns !== 'undefined') { - payload['columns'] = columns; - } - orders = orders === true ? [] : orders; - if (typeof orders !== 'undefined') { - payload['orders'] = orders; - } - lengths = lengths === true ? [] : lengths; - if (typeof lengths !== 'undefined') { - payload['lengths'] = lengths; - } - - let response = undefined; - - response = await client.call('post', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface TablesDBGetIndexRequestParams { - databaseId: string; - tableId: string; - key: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const tablesDBGetIndex = async ({databaseId,tableId,key,parseOutput = true, overrideForCli = false, sdk = undefined}: TablesDBGetIndexRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/tablesdb/{databaseId}/tables/{tableId}/indexes/{key}'.replace('{databaseId}', databaseId).replace('{tableId}', tableId).replace('{key}', key); - let payload = {}; - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface TablesDBDeleteIndexRequestParams { - databaseId: string; - tableId: string; - key: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const tablesDBDeleteIndex = async ({databaseId,tableId,key,parseOutput = true, overrideForCli = false, sdk = undefined}: TablesDBDeleteIndexRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/tablesdb/{databaseId}/tables/{tableId}/indexes/{key}'.replace('{databaseId}', databaseId).replace('{tableId}', tableId).replace('{key}', key); - let payload = {}; - - let response = undefined; - - response = await client.call('delete', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface TablesDBListTableLogsRequestParams { - databaseId: string; - tableId: string; - queries?: string[]; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; - console?: boolean; -} - -export const tablesDBListTableLogs = async ({databaseId,tableId,queries,parseOutput = true, overrideForCli = false, sdk = undefined, console: showConsole}: TablesDBListTableLogsRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/tablesdb/{databaseId}/tables/{tableId}/logs'.replace('{databaseId}', databaseId).replace('{tableId}', tableId); - let payload = {}; - if (typeof queries !== 'undefined') { - payload['queries'] = queries; - } - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - if(showConsole) { - showConsoleLink('tablesDB', 'listTableLogs', databaseId, tableId); - } else { - parse(response) - } - } - - return response; - -} -interface TablesDBListRowsRequestParams { - databaseId: string; - tableId: string; - queries?: string[]; - transactionId?: string; - total?: boolean; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; - console?: boolean; -} - -export const tablesDBListRows = async ({databaseId,tableId,queries,transactionId,total,parseOutput = true, overrideForCli = false, sdk = undefined, console: showConsole}: TablesDBListRowsRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/tablesdb/{databaseId}/tables/{tableId}/rows'.replace('{databaseId}', databaseId).replace('{tableId}', tableId); - let payload = {}; - if (typeof queries !== 'undefined') { - payload['queries'] = queries; - } - if (typeof transactionId !== 'undefined') { - payload['transactionId'] = transactionId; - } - if (typeof total !== 'undefined') { - payload['total'] = total; - } - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - if(showConsole) { - showConsoleLink('tablesDB', 'listRows', databaseId, tableId); - } else { - parse(response) - } - } - - return response; - -} -interface TablesDBCreateRowRequestParams { - databaseId: string; - tableId: string; - rowId: string; - data: object; - permissions?: string[]; - transactionId?: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const tablesDBCreateRow = async ({databaseId,tableId,rowId,data,permissions,transactionId,parseOutput = true, overrideForCli = false, sdk = undefined}: TablesDBCreateRowRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/tablesdb/{databaseId}/tables/{tableId}/rows'.replace('{databaseId}', databaseId).replace('{tableId}', tableId); - let payload = {}; - if (typeof rowId !== 'undefined') { - payload['rowId'] = rowId; - } - if (typeof data !== 'undefined') { - payload['data'] = JSON.parse(data); - } - permissions = permissions === true ? [] : permissions; - if (typeof permissions !== 'undefined') { - payload['permissions'] = permissions; - } - if (typeof transactionId !== 'undefined') { - payload['transactionId'] = transactionId; - } - - let response = undefined; - - response = await client.call('post', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface TablesDBCreateRowsRequestParams { - databaseId: string; - tableId: string; - rows: object[]; - transactionId?: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const tablesDBCreateRows = async ({databaseId,tableId,rows,transactionId,parseOutput = true, overrideForCli = false, sdk = undefined}: TablesDBCreateRowsRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/tablesdb/{databaseId}/tables/{tableId}/rows'.replace('{databaseId}', databaseId).replace('{tableId}', tableId); - let payload = {}; - rows = rows === true ? [] : rows; - if (typeof rows !== 'undefined') { - payload['rows'] = rows; - } - if (typeof transactionId !== 'undefined') { - payload['transactionId'] = transactionId; - } - - let response = undefined; - - response = await client.call('post', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface TablesDBUpsertRowsRequestParams { - databaseId: string; - tableId: string; - rows: object[]; - transactionId?: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const tablesDBUpsertRows = async ({databaseId,tableId,rows,transactionId,parseOutput = true, overrideForCli = false, sdk = undefined}: TablesDBUpsertRowsRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/tablesdb/{databaseId}/tables/{tableId}/rows'.replace('{databaseId}', databaseId).replace('{tableId}', tableId); - let payload = {}; - rows = rows === true ? [] : rows; - if (typeof rows !== 'undefined') { - payload['rows'] = rows; - } - if (typeof transactionId !== 'undefined') { - payload['transactionId'] = transactionId; - } - - let response = undefined; - - response = await client.call('put', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface TablesDBUpdateRowsRequestParams { - databaseId: string; - tableId: string; - data?: object; - queries?: string[]; - transactionId?: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const tablesDBUpdateRows = async ({databaseId,tableId,data,queries,transactionId,parseOutput = true, overrideForCli = false, sdk = undefined}: TablesDBUpdateRowsRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/tablesdb/{databaseId}/tables/{tableId}/rows'.replace('{databaseId}', databaseId).replace('{tableId}', tableId); - let payload = {}; - if (typeof data !== 'undefined') { - payload['data'] = JSON.parse(data); - } - queries = queries === true ? [] : queries; - if (typeof queries !== 'undefined') { - payload['queries'] = queries; - } - if (typeof transactionId !== 'undefined') { - payload['transactionId'] = transactionId; - } - - let response = undefined; - - response = await client.call('patch', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface TablesDBDeleteRowsRequestParams { - databaseId: string; - tableId: string; - queries?: string[]; - transactionId?: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const tablesDBDeleteRows = async ({databaseId,tableId,queries,transactionId,parseOutput = true, overrideForCli = false, sdk = undefined}: TablesDBDeleteRowsRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/tablesdb/{databaseId}/tables/{tableId}/rows'.replace('{databaseId}', databaseId).replace('{tableId}', tableId); - let payload = {}; - queries = queries === true ? [] : queries; - if (typeof queries !== 'undefined') { - payload['queries'] = queries; - } - if (typeof transactionId !== 'undefined') { - payload['transactionId'] = transactionId; - } - - let response = undefined; - - response = await client.call('delete', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface TablesDBGetRowRequestParams { - databaseId: string; - tableId: string; - rowId: string; - queries?: string[]; - transactionId?: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; - console?: boolean; -} - -export const tablesDBGetRow = async ({databaseId,tableId,rowId,queries,transactionId,parseOutput = true, overrideForCli = false, sdk = undefined, console: showConsole}: TablesDBGetRowRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/tablesdb/{databaseId}/tables/{tableId}/rows/{rowId}'.replace('{databaseId}', databaseId).replace('{tableId}', tableId).replace('{rowId}', rowId); - let payload = {}; - if (typeof queries !== 'undefined') { - payload['queries'] = queries; - } - if (typeof transactionId !== 'undefined') { - payload['transactionId'] = transactionId; - } - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - if(showConsole) { - showConsoleLink('tablesDB', 'getRow', databaseId, tableId, rowId); - } else { - parse(response) - } - } - - return response; - -} -interface TablesDBUpsertRowRequestParams { - databaseId: string; - tableId: string; - rowId: string; - data?: object; - permissions?: string[]; - transactionId?: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const tablesDBUpsertRow = async ({databaseId,tableId,rowId,data,permissions,transactionId,parseOutput = true, overrideForCli = false, sdk = undefined}: TablesDBUpsertRowRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/tablesdb/{databaseId}/tables/{tableId}/rows/{rowId}'.replace('{databaseId}', databaseId).replace('{tableId}', tableId).replace('{rowId}', rowId); - let payload = {}; - if (typeof data !== 'undefined') { - payload['data'] = JSON.parse(data); - } - permissions = permissions === true ? [] : permissions; - if (typeof permissions !== 'undefined') { - payload['permissions'] = permissions; - } - if (typeof transactionId !== 'undefined') { - payload['transactionId'] = transactionId; - } - - let response = undefined; - - response = await client.call('put', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface TablesDBUpdateRowRequestParams { - databaseId: string; - tableId: string; - rowId: string; - data?: object; - permissions?: string[]; - transactionId?: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const tablesDBUpdateRow = async ({databaseId,tableId,rowId,data,permissions,transactionId,parseOutput = true, overrideForCli = false, sdk = undefined}: TablesDBUpdateRowRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/tablesdb/{databaseId}/tables/{tableId}/rows/{rowId}'.replace('{databaseId}', databaseId).replace('{tableId}', tableId).replace('{rowId}', rowId); - let payload = {}; - if (typeof data !== 'undefined') { - payload['data'] = JSON.parse(data); - } - permissions = permissions === true ? [] : permissions; - if (typeof permissions !== 'undefined') { - payload['permissions'] = permissions; - } - if (typeof transactionId !== 'undefined') { - payload['transactionId'] = transactionId; - } - - let response = undefined; - - response = await client.call('patch', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface TablesDBDeleteRowRequestParams { - databaseId: string; - tableId: string; - rowId: string; - transactionId?: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const tablesDBDeleteRow = async ({databaseId,tableId,rowId,transactionId,parseOutput = true, overrideForCli = false, sdk = undefined}: TablesDBDeleteRowRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/tablesdb/{databaseId}/tables/{tableId}/rows/{rowId}'.replace('{databaseId}', databaseId).replace('{tableId}', tableId).replace('{rowId}', rowId); - let payload = {}; - if (typeof transactionId !== 'undefined') { - payload['transactionId'] = transactionId; - } - - let response = undefined; - - response = await client.call('delete', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface TablesDBListRowLogsRequestParams { - databaseId: string; - tableId: string; - rowId: string; - queries?: string[]; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; - console?: boolean; -} - -export const tablesDBListRowLogs = async ({databaseId,tableId,rowId,queries,parseOutput = true, overrideForCli = false, sdk = undefined, console: showConsole}: TablesDBListRowLogsRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/tablesdb/{databaseId}/tables/{tableId}/rows/{rowId}/logs'.replace('{databaseId}', databaseId).replace('{tableId}', tableId).replace('{rowId}', rowId); - let payload = {}; - if (typeof queries !== 'undefined') { - payload['queries'] = queries; - } - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - if(showConsole) { - showConsoleLink('tablesDB', 'listRowLogs', databaseId, tableId, rowId); - } else { - parse(response) - } - } - - return response; - -} -interface TablesDBDecrementRowColumnRequestParams { - databaseId: string; - tableId: string; - rowId: string; - column: string; - value?: number; - min?: number; - transactionId?: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const tablesDBDecrementRowColumn = async ({databaseId,tableId,rowId,column,value,min,transactionId,parseOutput = true, overrideForCli = false, sdk = undefined}: TablesDBDecrementRowColumnRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/tablesdb/{databaseId}/tables/{tableId}/rows/{rowId}/{column}/decrement'.replace('{databaseId}', databaseId).replace('{tableId}', tableId).replace('{rowId}', rowId).replace('{column}', column); - let payload = {}; - if (typeof value !== 'undefined') { - payload['value'] = value; - } - if (typeof min !== 'undefined') { - payload['min'] = min; - } - if (typeof transactionId !== 'undefined') { - payload['transactionId'] = transactionId; - } - - let response = undefined; - - response = await client.call('patch', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface TablesDBIncrementRowColumnRequestParams { - databaseId: string; - tableId: string; - rowId: string; - column: string; - value?: number; - max?: number; - transactionId?: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const tablesDBIncrementRowColumn = async ({databaseId,tableId,rowId,column,value,max,transactionId,parseOutput = true, overrideForCli = false, sdk = undefined}: TablesDBIncrementRowColumnRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/tablesdb/{databaseId}/tables/{tableId}/rows/{rowId}/{column}/increment'.replace('{databaseId}', databaseId).replace('{tableId}', tableId).replace('{rowId}', rowId).replace('{column}', column); - let payload = {}; - if (typeof value !== 'undefined') { - payload['value'] = value; - } - if (typeof max !== 'undefined') { - payload['max'] = max; - } - if (typeof transactionId !== 'undefined') { - payload['transactionId'] = transactionId; - } - - let response = undefined; - - response = await client.call('patch', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface TablesDBGetTableUsageRequestParams { - databaseId: string; - tableId: string; - range?: UsageRange; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; - console?: boolean; -} - -export const tablesDBGetTableUsage = async ({databaseId,tableId,range,parseOutput = true, overrideForCli = false, sdk = undefined, console: showConsole}: TablesDBGetTableUsageRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/tablesdb/{databaseId}/tables/{tableId}/usage'.replace('{databaseId}', databaseId).replace('{tableId}', tableId); - let payload = {}; - if (typeof range !== 'undefined') { - payload['range'] = range; - } - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - if(showConsole) { - showConsoleLink('tablesDB', 'getTableUsage', databaseId, tableId); - } else { - parse(response) - } - } - - return response; - -} -interface TablesDBGetUsageRequestParams { - databaseId: string; - range?: UsageRange; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const tablesDBGetUsage = async ({databaseId,range,parseOutput = true, overrideForCli = false, sdk = undefined}: TablesDBGetUsageRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/tablesdb/{databaseId}/usage'.replace('{databaseId}', databaseId); - let payload = {}; - if (typeof range !== 'undefined') { - payload['range'] = range; - } - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -tablesDB - .command(`list`) - .description(`Get a list of all databases from the current Appwrite project. You can use the search parameter to filter your results.`) - .option(`--queries [queries...]`, `Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following columns: name`) - .option(`--search <search>`, `Search term to filter your list results. Max length: 256 chars.`) - .option(`--total [value]`, `When set to false, the total count returned will be 0 and will not be calculated.`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .option(`--console`, `Get the resource console url`) - .action(actionRunner(tablesDBList)) - -tablesDB - .command(`create`) - .description(`Create a new Database. `) - .requiredOption(`--database-id <database-id>`, `Unique Id. Choose a custom ID or generate a random ID with 'ID.unique()'. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.`) - .requiredOption(`--name <name>`, `Database name. Max length: 128 chars.`) - .option(`--enabled [value]`, `Is the database enabled? When set to 'disabled', users cannot access the database but Server SDKs with an API key can still read and write to the database. No data is lost when this is toggled.`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .action(actionRunner(tablesDBCreate)) - -tablesDB - .command(`list-transactions`) - .description(`List transactions across all databases.`) - .option(`--queries [queries...]`, `Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries).`) - .option(`--console`, `Get the resource console url`) - .action(actionRunner(tablesDBListTransactions)) - -tablesDB - .command(`create-transaction`) - .description(`Create a new transaction.`) - .option(`--ttl <ttl>`, `Seconds before the transaction expires.`, parseInteger) - .action(actionRunner(tablesDBCreateTransaction)) - -tablesDB - .command(`get-transaction`) - .description(`Get a transaction by its unique ID.`) - .requiredOption(`--transaction-id <transaction-id>`, `Transaction ID.`) - .option(`--console`, `Get the resource console url`) - .action(actionRunner(tablesDBGetTransaction)) - -tablesDB - .command(`update-transaction`) - .description(`Update a transaction, to either commit or roll back its operations.`) - .requiredOption(`--transaction-id <transaction-id>`, `Transaction ID.`) - .option(`--commit [value]`, `Commit transaction?`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .option(`--rollback [value]`, `Rollback transaction?`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .action(actionRunner(tablesDBUpdateTransaction)) - -tablesDB - .command(`delete-transaction`) - .description(`Delete a transaction by its unique ID.`) - .requiredOption(`--transaction-id <transaction-id>`, `Transaction ID.`) - .action(actionRunner(tablesDBDeleteTransaction)) - -tablesDB - .command(`create-operations`) - .description(`Create multiple operations in a single transaction.`) - .requiredOption(`--transaction-id <transaction-id>`, `Transaction ID.`) - .option(`--operations [operations...]`, `Array of staged operations.`) - .action(actionRunner(tablesDBCreateOperations)) - -tablesDB - .command(`list-usage`) - .description(`List usage metrics and statistics for all databases in the project. You can view the total number of databases, tables, rows, and storage usage. The response includes both current totals and historical data over time. Use the optional range parameter to specify the time window for historical data: 24h (last 24 hours), 30d (last 30 days), or 90d (last 90 days). If not specified, range defaults to 30 days.`) - .option(`--range <range>`, `Date range.`) - .option(`--console`, `Get the resource console url`) - .action(actionRunner(tablesDBListUsage)) - -tablesDB - .command(`get`) - .description(`Get a database by its unique ID. This endpoint response returns a JSON object with the database metadata.`) - .requiredOption(`--database-id <database-id>`, `Database ID.`) - .option(`--console`, `Get the resource console url`) - .action(actionRunner(tablesDBGet)) - -tablesDB - .command(`update`) - .description(`Update a database by its unique ID.`) - .requiredOption(`--database-id <database-id>`, `Database ID.`) - .requiredOption(`--name <name>`, `Database name. Max length: 128 chars.`) - .option(`--enabled [value]`, `Is database enabled? When set to 'disabled', users cannot access the database but Server SDKs with an API key can still read and write to the database. No data is lost when this is toggled.`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .action(actionRunner(tablesDBUpdate)) - -tablesDB - .command(`delete`) - .description(`Delete a database by its unique ID. Only API keys with with databases.write scope can delete a database.`) - .requiredOption(`--database-id <database-id>`, `Database ID.`) - .action(actionRunner(tablesDBDelete)) - -tablesDB - .command(`list-tables`) - .description(`Get a list of all tables that belong to the provided databaseId. You can use the search parameter to filter your results.`) - .requiredOption(`--database-id <database-id>`, `Database ID.`) - .option(`--queries [queries...]`, `Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following columns: name, enabled, rowSecurity`) - .option(`--search <search>`, `Search term to filter your list results. Max length: 256 chars.`) - .option(`--total [value]`, `When set to false, the total count returned will be 0 and will not be calculated.`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .option(`--console`, `Get the resource console url`) - .action(actionRunner(tablesDBListTables)) - -tablesDB - .command(`create-table`) - .description(`Create a new Table. Before using this route, you should create a new database resource using either a [server integration](https://appwrite.io/docs/references/cloud/server-dart/tablesDB#createTable) API or directly from your database console.`) - .requiredOption(`--database-id <database-id>`, `Database ID.`) - .requiredOption(`--table-id <table-id>`, `Unique Id. Choose a custom ID or generate a random ID with 'ID.unique()'. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.`) - .requiredOption(`--name <name>`, `Table name. Max length: 128 chars.`) - .option(`--permissions [permissions...]`, `An array of permissions strings. By default, no user is granted with any permissions. [Learn more about permissions](https://appwrite.io/docs/permissions).`) - .option(`--row-security [value]`, `Enables configuring permissions for individual rows. A user needs one of row or table level permissions to access a row. [Learn more about permissions](https://appwrite.io/docs/permissions).`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .option(`--enabled [value]`, `Is table enabled? When set to 'disabled', users cannot access the table but Server SDKs with and API key can still read and write to the table. No data is lost when this is toggled.`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .option(`--columns [columns...]`, `Array of column definitions to create. Each column should contain: key (string), type (string: string, integer, float, boolean, datetime, relationship), size (integer, required for string type), required (boolean, optional), default (mixed, optional), array (boolean, optional), and type-specific options.`) - .option(`--indexes [indexes...]`, `Array of index definitions to create. Each index should contain: key (string), type (string: key, fulltext, unique, spatial), attributes (array of column keys), orders (array of ASC/DESC, optional), and lengths (array of integers, optional).`) - .action(actionRunner(tablesDBCreateTable)) - -tablesDB - .command(`get-table`) - .description(`Get a table by its unique ID. This endpoint response returns a JSON object with the table metadata.`) - .requiredOption(`--database-id <database-id>`, `Database ID.`) - .requiredOption(`--table-id <table-id>`, `Table ID.`) - .option(`--console`, `Get the resource console url`) - .action(actionRunner(tablesDBGetTable)) - -tablesDB - .command(`update-table`) - .description(`Update a table by its unique ID.`) - .requiredOption(`--database-id <database-id>`, `Database ID.`) - .requiredOption(`--table-id <table-id>`, `Table ID.`) - .requiredOption(`--name <name>`, `Table name. Max length: 128 chars.`) - .option(`--permissions [permissions...]`, `An array of permission strings. By default, the current permissions are inherited. [Learn more about permissions](https://appwrite.io/docs/permissions).`) - .option(`--row-security [value]`, `Enables configuring permissions for individual rows. A user needs one of row or table-level permissions to access a row. [Learn more about permissions](https://appwrite.io/docs/permissions).`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .option(`--enabled [value]`, `Is table enabled? When set to 'disabled', users cannot access the table but Server SDKs with and API key can still read and write to the table. No data is lost when this is toggled.`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .action(actionRunner(tablesDBUpdateTable)) - -tablesDB - .command(`delete-table`) - .description(`Delete a table by its unique ID. Only users with write permissions have access to delete this resource.`) - .requiredOption(`--database-id <database-id>`, `Database ID.`) - .requiredOption(`--table-id <table-id>`, `Table ID.`) - .action(actionRunner(tablesDBDeleteTable)) - -tablesDB - .command(`list-columns`) - .description(`List columns in the table.`) - .requiredOption(`--database-id <database-id>`, `Database ID.`) - .requiredOption(`--table-id <table-id>`, `Table ID.`) - .option(`--queries [queries...]`, `Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following columns: key, type, size, required, array, status, error`) - .option(`--total [value]`, `When set to false, the total count returned will be 0 and will not be calculated.`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .option(`--console`, `Get the resource console url`) - .action(actionRunner(tablesDBListColumns)) - -tablesDB - .command(`create-boolean-column`) - .description(`Create a boolean column. `) - .requiredOption(`--database-id <database-id>`, `Database ID.`) - .requiredOption(`--table-id <table-id>`, `Table ID. You can create a new table using the Database service [server integration](https://appwrite.io/docs/references/cloud/server-dart/tablesDB#createTable).`) - .requiredOption(`--key <key>`, `Column Key.`) - .requiredOption(`--required [value]`, `Is column required?`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .option(`--xdefault [value]`, `Default value for column when not provided. Cannot be set when column is required.`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .option(`--array [value]`, `Is column an array?`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .action(actionRunner(tablesDBCreateBooleanColumn)) - -tablesDB - .command(`update-boolean-column`) - .description(`Update a boolean column. Changing the 'default' value will not update already existing rows.`) - .requiredOption(`--database-id <database-id>`, `Database ID.`) - .requiredOption(`--table-id <table-id>`, `Table ID. You can create a new table using the Database service [server integration](https://appwrite.io/docs/references/cloud/server-dart/tablesDB#createTable).`) - .requiredOption(`--key <key>`, `Column Key.`) - .requiredOption(`--required [value]`, `Is column required?`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .option(`--xdefault [value]`, `Default value for column when not provided. Cannot be set when column is required.`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .option(`--new-key <new-key>`, `New Column Key.`) - .action(actionRunner(tablesDBUpdateBooleanColumn)) - -tablesDB - .command(`create-datetime-column`) - .description(`Create a date time column according to the ISO 8601 standard.`) - .requiredOption(`--database-id <database-id>`, `Database ID.`) - .requiredOption(`--table-id <table-id>`, `Table ID.`) - .requiredOption(`--key <key>`, `Column Key.`) - .requiredOption(`--required [value]`, `Is column required?`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .option(`--xdefault <xdefault>`, `Default value for the column in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format. Cannot be set when column is required.`) - .option(`--array [value]`, `Is column an array?`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .action(actionRunner(tablesDBCreateDatetimeColumn)) - -tablesDB - .command(`update-datetime-column`) - .description(`Update a date time column. Changing the 'default' value will not update already existing rows.`) - .requiredOption(`--database-id <database-id>`, `Database ID.`) - .requiredOption(`--table-id <table-id>`, `Table ID.`) - .requiredOption(`--key <key>`, `Column Key.`) - .requiredOption(`--required [value]`, `Is column required?`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .option(`--xdefault <xdefault>`, `Default value for column when not provided. Cannot be set when column is required.`) - .option(`--new-key <new-key>`, `New Column Key.`) - .action(actionRunner(tablesDBUpdateDatetimeColumn)) - -tablesDB - .command(`create-email-column`) - .description(`Create an email column. `) - .requiredOption(`--database-id <database-id>`, `Database ID.`) - .requiredOption(`--table-id <table-id>`, `Table ID.`) - .requiredOption(`--key <key>`, `Column Key.`) - .requiredOption(`--required [value]`, `Is column required?`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .option(`--xdefault <xdefault>`, `Default value for column when not provided. Cannot be set when column is required.`) - .option(`--array [value]`, `Is column an array?`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .action(actionRunner(tablesDBCreateEmailColumn)) - -tablesDB - .command(`update-email-column`) - .description(`Update an email column. Changing the 'default' value will not update already existing rows. `) - .requiredOption(`--database-id <database-id>`, `Database ID.`) - .requiredOption(`--table-id <table-id>`, `Table ID.`) - .requiredOption(`--key <key>`, `Column Key.`) - .requiredOption(`--required [value]`, `Is column required?`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .option(`--xdefault <xdefault>`, `Default value for column when not provided. Cannot be set when column is required.`) - .option(`--new-key <new-key>`, `New Column Key.`) - .action(actionRunner(tablesDBUpdateEmailColumn)) - -tablesDB - .command(`create-enum-column`) - .description(`Create an enumeration column. The 'elements' param acts as a white-list of accepted values for this column.`) - .requiredOption(`--database-id <database-id>`, `Database ID.`) - .requiredOption(`--table-id <table-id>`, `Table ID.`) - .requiredOption(`--key <key>`, `Column Key.`) - .requiredOption(`--elements [elements...]`, `Array of enum values.`) - .requiredOption(`--required [value]`, `Is column required?`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .option(`--xdefault <xdefault>`, `Default value for column when not provided. Cannot be set when column is required.`) - .option(`--array [value]`, `Is column an array?`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .action(actionRunner(tablesDBCreateEnumColumn)) - -tablesDB - .command(`update-enum-column`) - .description(`Update an enum column. Changing the 'default' value will not update already existing rows. `) - .requiredOption(`--database-id <database-id>`, `Database ID.`) - .requiredOption(`--table-id <table-id>`, `Table ID.`) - .requiredOption(`--key <key>`, `Column Key.`) - .requiredOption(`--elements [elements...]`, `Updated list of enum values.`) - .requiredOption(`--required [value]`, `Is column required?`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .option(`--xdefault <xdefault>`, `Default value for column when not provided. Cannot be set when column is required.`) - .option(`--new-key <new-key>`, `New Column Key.`) - .action(actionRunner(tablesDBUpdateEnumColumn)) - -tablesDB - .command(`create-float-column`) - .description(`Create a float column. Optionally, minimum and maximum values can be provided. `) - .requiredOption(`--database-id <database-id>`, `Database ID.`) - .requiredOption(`--table-id <table-id>`, `Table ID.`) - .requiredOption(`--key <key>`, `Column Key.`) - .requiredOption(`--required [value]`, `Is column required?`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .option(`--min <min>`, `Minimum value`, parseInteger) - .option(`--max <max>`, `Maximum value`, parseInteger) - .option(`--xdefault <xdefault>`, `Default value. Cannot be set when required.`, parseInteger) - .option(`--array [value]`, `Is column an array?`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .action(actionRunner(tablesDBCreateFloatColumn)) - -tablesDB - .command(`update-float-column`) - .description(`Update a float column. Changing the 'default' value will not update already existing rows. `) - .requiredOption(`--database-id <database-id>`, `Database ID.`) - .requiredOption(`--table-id <table-id>`, `Table ID.`) - .requiredOption(`--key <key>`, `Column Key.`) - .requiredOption(`--required [value]`, `Is column required?`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .option(`--xdefault <xdefault>`, `Default value. Cannot be set when required.`, parseInteger) - .option(`--min <min>`, `Minimum value`, parseInteger) - .option(`--max <max>`, `Maximum value`, parseInteger) - .option(`--new-key <new-key>`, `New Column Key.`) - .action(actionRunner(tablesDBUpdateFloatColumn)) - -tablesDB - .command(`create-integer-column`) - .description(`Create an integer column. Optionally, minimum and maximum values can be provided. `) - .requiredOption(`--database-id <database-id>`, `Database ID.`) - .requiredOption(`--table-id <table-id>`, `Table ID.`) - .requiredOption(`--key <key>`, `Column Key.`) - .requiredOption(`--required [value]`, `Is column required?`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .option(`--min <min>`, `Minimum value`, parseInteger) - .option(`--max <max>`, `Maximum value`, parseInteger) - .option(`--xdefault <xdefault>`, `Default value. Cannot be set when column is required.`, parseInteger) - .option(`--array [value]`, `Is column an array?`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .action(actionRunner(tablesDBCreateIntegerColumn)) - -tablesDB - .command(`update-integer-column`) - .description(`Update an integer column. Changing the 'default' value will not update already existing rows. `) - .requiredOption(`--database-id <database-id>`, `Database ID.`) - .requiredOption(`--table-id <table-id>`, `Table ID.`) - .requiredOption(`--key <key>`, `Column Key.`) - .requiredOption(`--required [value]`, `Is column required?`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .option(`--xdefault <xdefault>`, `Default value. Cannot be set when column is required.`, parseInteger) - .option(`--min <min>`, `Minimum value`, parseInteger) - .option(`--max <max>`, `Maximum value`, parseInteger) - .option(`--new-key <new-key>`, `New Column Key.`) - .action(actionRunner(tablesDBUpdateIntegerColumn)) - -tablesDB - .command(`create-ip-column`) - .description(`Create IP address column. `) - .requiredOption(`--database-id <database-id>`, `Database ID.`) - .requiredOption(`--table-id <table-id>`, `Table ID.`) - .requiredOption(`--key <key>`, `Column Key.`) - .requiredOption(`--required [value]`, `Is column required?`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .option(`--xdefault <xdefault>`, `Default value. Cannot be set when column is required.`) - .option(`--array [value]`, `Is column an array?`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .action(actionRunner(tablesDBCreateIpColumn)) - -tablesDB - .command(`update-ip-column`) - .description(`Update an ip column. Changing the 'default' value will not update already existing rows. `) - .requiredOption(`--database-id <database-id>`, `Database ID.`) - .requiredOption(`--table-id <table-id>`, `Table ID.`) - .requiredOption(`--key <key>`, `Column Key.`) - .requiredOption(`--required [value]`, `Is column required?`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .option(`--xdefault <xdefault>`, `Default value. Cannot be set when column is required.`) - .option(`--new-key <new-key>`, `New Column Key.`) - .action(actionRunner(tablesDBUpdateIpColumn)) - -tablesDB - .command(`create-line-column`) - .description(`Create a geometric line column.`) - .requiredOption(`--database-id <database-id>`, `Database ID.`) - .requiredOption(`--table-id <table-id>`, `Table ID. You can create a new table using the TablesDB service [server integration](https://appwrite.io/docs/references/cloud/server-dart/tablesDB#createTable).`) - .requiredOption(`--key <key>`, `Column Key.`) - .requiredOption(`--required [value]`, `Is column required?`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .option(`--xdefault <xdefault>`, `Default value for column when not provided, two-dimensional array of coordinate pairs, [[longitude, latitude], [longitude, latitude], …], listing the vertices of the line in order. Cannot be set when column is required.`) - .action(actionRunner(tablesDBCreateLineColumn)) - -tablesDB - .command(`update-line-column`) - .description(`Update a line column. Changing the 'default' value will not update already existing rows.`) - .requiredOption(`--database-id <database-id>`, `Database ID.`) - .requiredOption(`--table-id <table-id>`, `Table ID. You can create a new table using the TablesDB service [server integration](https://appwrite.io/docs/references/cloud/server-dart/tablesDB#createTable).`) - .requiredOption(`--key <key>`, `Column Key.`) - .requiredOption(`--required [value]`, `Is column required?`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .option(`--xdefault <xdefault>`, `Default value for column when not provided, two-dimensional array of coordinate pairs, [[longitude, latitude], [longitude, latitude], …], listing the vertices of the line in order. Cannot be set when column is required.`) - .option(`--new-key <new-key>`, `New Column Key.`) - .action(actionRunner(tablesDBUpdateLineColumn)) - -tablesDB - .command(`create-point-column`) - .description(`Create a geometric point column.`) - .requiredOption(`--database-id <database-id>`, `Database ID.`) - .requiredOption(`--table-id <table-id>`, `Table ID. You can create a new table using the TablesDB service [server integration](https://appwrite.io/docs/references/cloud/server-dart/tablesDB#createTable).`) - .requiredOption(`--key <key>`, `Column Key.`) - .requiredOption(`--required [value]`, `Is column required?`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .option(`--xdefault <xdefault>`, `Default value for column when not provided, array of two numbers [longitude, latitude], representing a single coordinate. Cannot be set when column is required.`) - .action(actionRunner(tablesDBCreatePointColumn)) - -tablesDB - .command(`update-point-column`) - .description(`Update a point column. Changing the 'default' value will not update already existing rows.`) - .requiredOption(`--database-id <database-id>`, `Database ID.`) - .requiredOption(`--table-id <table-id>`, `Table ID. You can create a new table using the TablesDB service [server integration](https://appwrite.io/docs/references/cloud/server-dart/tablesDB#createTable).`) - .requiredOption(`--key <key>`, `Column Key.`) - .requiredOption(`--required [value]`, `Is column required?`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .option(`--xdefault <xdefault>`, `Default value for column when not provided, array of two numbers [longitude, latitude], representing a single coordinate. Cannot be set when column is required.`) - .option(`--new-key <new-key>`, `New Column Key.`) - .action(actionRunner(tablesDBUpdatePointColumn)) - -tablesDB - .command(`create-polygon-column`) - .description(`Create a geometric polygon column.`) - .requiredOption(`--database-id <database-id>`, `Database ID.`) - .requiredOption(`--table-id <table-id>`, `Table ID. You can create a new table using the TablesDB service [server integration](https://appwrite.io/docs/references/cloud/server-dart/tablesDB#createTable).`) - .requiredOption(`--key <key>`, `Column Key.`) - .requiredOption(`--required [value]`, `Is column required?`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .option(`--xdefault <xdefault>`, `Default value for column when not provided, three-dimensional array where the outer array holds one or more linear rings, [[[longitude, latitude], …], …], the first ring is the exterior boundary, any additional rings are interior holes, and each ring must start and end with the same coordinate pair. Cannot be set when column is required.`) - .action(actionRunner(tablesDBCreatePolygonColumn)) - -tablesDB - .command(`update-polygon-column`) - .description(`Update a polygon column. Changing the 'default' value will not update already existing rows.`) - .requiredOption(`--database-id <database-id>`, `Database ID.`) - .requiredOption(`--table-id <table-id>`, `Table ID. You can create a new table using the TablesDB service [server integration](https://appwrite.io/docs/references/cloud/server-dart/tablesDB#createTable).`) - .requiredOption(`--key <key>`, `Column Key.`) - .requiredOption(`--required [value]`, `Is column required?`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .option(`--xdefault <xdefault>`, `Default value for column when not provided, three-dimensional array where the outer array holds one or more linear rings, [[[longitude, latitude], …], …], the first ring is the exterior boundary, any additional rings are interior holes, and each ring must start and end with the same coordinate pair. Cannot be set when column is required.`) - .option(`--new-key <new-key>`, `New Column Key.`) - .action(actionRunner(tablesDBUpdatePolygonColumn)) - -tablesDB - .command(`create-relationship-column`) - .description(`Create relationship column. [Learn more about relationship columns](https://appwrite.io/docs/databases-relationships#relationship-columns). `) - .requiredOption(`--database-id <database-id>`, `Database ID.`) - .requiredOption(`--table-id <table-id>`, `Table ID.`) - .requiredOption(`--related-table-id <related-table-id>`, `Related Table ID.`) - .requiredOption(`--type <type>`, `Relation type`) - .option(`--two-way [value]`, `Is Two Way?`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .option(`--key <key>`, `Column Key.`) - .option(`--two-way-key <two-way-key>`, `Two Way Column Key.`) - .option(`--on-delete <on-delete>`, `Constraints option`) - .action(actionRunner(tablesDBCreateRelationshipColumn)) - -tablesDB - .command(`create-string-column`) - .description(`Create a string column. `) - .requiredOption(`--database-id <database-id>`, `Database ID.`) - .requiredOption(`--table-id <table-id>`, `Table ID. You can create a new table using the Database service [server integration](https://appwrite.io/docs/references/cloud/server-dart/tablesDB#createTable).`) - .requiredOption(`--key <key>`, `Column Key.`) - .requiredOption(`--size <size>`, `Column size for text columns, in number of characters.`, parseInteger) - .requiredOption(`--required [value]`, `Is column required?`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .option(`--xdefault <xdefault>`, `Default value for column when not provided. Cannot be set when column is required.`) - .option(`--array [value]`, `Is column an array?`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .option(`--encrypt [value]`, `Toggle encryption for the column. Encryption enhances security by not storing any plain text values in the database. However, encrypted columns cannot be queried.`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .action(actionRunner(tablesDBCreateStringColumn)) - -tablesDB - .command(`update-string-column`) - .description(`Update a string column. Changing the 'default' value will not update already existing rows. `) - .requiredOption(`--database-id <database-id>`, `Database ID.`) - .requiredOption(`--table-id <table-id>`, `Table ID. You can create a new table using the Database service [server integration](https://appwrite.io/docs/references/cloud/server-dart/tablesDB#createTable).`) - .requiredOption(`--key <key>`, `Column Key.`) - .requiredOption(`--required [value]`, `Is column required?`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .option(`--xdefault <xdefault>`, `Default value for column when not provided. Cannot be set when column is required.`) - .option(`--size <size>`, `Maximum size of the string column.`, parseInteger) - .option(`--new-key <new-key>`, `New Column Key.`) - .action(actionRunner(tablesDBUpdateStringColumn)) - -tablesDB - .command(`create-url-column`) - .description(`Create a URL column. `) - .requiredOption(`--database-id <database-id>`, `Database ID.`) - .requiredOption(`--table-id <table-id>`, `Table ID.`) - .requiredOption(`--key <key>`, `Column Key.`) - .requiredOption(`--required [value]`, `Is column required?`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .option(`--xdefault <xdefault>`, `Default value for column when not provided. Cannot be set when column is required.`) - .option(`--array [value]`, `Is column an array?`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .action(actionRunner(tablesDBCreateUrlColumn)) - -tablesDB - .command(`update-url-column`) - .description(`Update an url column. Changing the 'default' value will not update already existing rows. `) - .requiredOption(`--database-id <database-id>`, `Database ID.`) - .requiredOption(`--table-id <table-id>`, `Table ID.`) - .requiredOption(`--key <key>`, `Column Key.`) - .requiredOption(`--required [value]`, `Is column required?`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .option(`--xdefault <xdefault>`, `Default value for column when not provided. Cannot be set when column is required.`) - .option(`--new-key <new-key>`, `New Column Key.`) - .action(actionRunner(tablesDBUpdateUrlColumn)) - -tablesDB - .command(`get-column`) - .description(`Get column by ID.`) - .requiredOption(`--database-id <database-id>`, `Database ID.`) - .requiredOption(`--table-id <table-id>`, `Table ID.`) - .requiredOption(`--key <key>`, `Column Key.`) - .option(`--console`, `Get the resource console url`) - .action(actionRunner(tablesDBGetColumn)) - -tablesDB - .command(`delete-column`) - .description(`Deletes a column.`) - .requiredOption(`--database-id <database-id>`, `Database ID.`) - .requiredOption(`--table-id <table-id>`, `Table ID.`) - .requiredOption(`--key <key>`, `Column Key.`) - .action(actionRunner(tablesDBDeleteColumn)) - -tablesDB - .command(`update-relationship-column`) - .description(`Update relationship column. [Learn more about relationship columns](https://appwrite.io/docs/databases-relationships#relationship-columns). `) - .requiredOption(`--database-id <database-id>`, `Database ID.`) - .requiredOption(`--table-id <table-id>`, `Table ID.`) - .requiredOption(`--key <key>`, `Column Key.`) - .option(`--on-delete <on-delete>`, `Constraints option`) - .option(`--new-key <new-key>`, `New Column Key.`) - .action(actionRunner(tablesDBUpdateRelationshipColumn)) - -tablesDB - .command(`list-indexes`) - .description(`List indexes on the table.`) - .requiredOption(`--database-id <database-id>`, `Database ID.`) - .requiredOption(`--table-id <table-id>`, `Table ID. You can create a new table using the Database service [server integration](https://appwrite.io/docs/references/cloud/server-dart/tablesDB#createTable).`) - .option(`--queries [queries...]`, `Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following columns: key, type, status, attributes, error`) - .option(`--total [value]`, `When set to false, the total count returned will be 0 and will not be calculated.`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .option(`--console`, `Get the resource console url`) - .action(actionRunner(tablesDBListIndexes)) - -tablesDB - .command(`create-index`) - .description(`Creates an index on the columns listed. Your index should include all the columns you will query in a single request. Type can be 'key', 'fulltext', or 'unique'.`) - .requiredOption(`--database-id <database-id>`, `Database ID.`) - .requiredOption(`--table-id <table-id>`, `Table ID. You can create a new table using the Database service [server integration](https://appwrite.io/docs/references/cloud/server-dart/tablesDB#createTable).`) - .requiredOption(`--key <key>`, `Index Key.`) - .requiredOption(`--type <type>`, `Index type.`) - .requiredOption(`--columns [columns...]`, `Array of columns to index. Maximum of 100 columns are allowed, each 32 characters long.`) - .option(`--orders [orders...]`, `Array of index orders. Maximum of 100 orders are allowed.`) - .option(`--lengths [lengths...]`, `Length of index. Maximum of 100`) - .action(actionRunner(tablesDBCreateIndex)) - -tablesDB - .command(`get-index`) - .description(`Get index by ID.`) - .requiredOption(`--database-id <database-id>`, `Database ID.`) - .requiredOption(`--table-id <table-id>`, `Table ID. You can create a new table using the Database service [server integration](https://appwrite.io/docs/references/cloud/server-dart/tablesDB#createTable).`) - .requiredOption(`--key <key>`, `Index Key.`) - .action(actionRunner(tablesDBGetIndex)) - -tablesDB - .command(`delete-index`) - .description(`Delete an index.`) - .requiredOption(`--database-id <database-id>`, `Database ID.`) - .requiredOption(`--table-id <table-id>`, `Table ID. You can create a new table using the TablesDB service [server integration](https://appwrite.io/docs/references/cloud/server-dart/tablesDB#createTable).`) - .requiredOption(`--key <key>`, `Index Key.`) - .action(actionRunner(tablesDBDeleteIndex)) - -tablesDB - .command(`list-table-logs`) - .description(`Get the table activity logs list by its unique ID.`) - .requiredOption(`--database-id <database-id>`, `Database ID.`) - .requiredOption(`--table-id <table-id>`, `Table ID.`) - .option(`--queries [queries...]`, `Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Only supported methods are limit and offset`) - .option(`--console`, `Get the resource console url`) - .action(actionRunner(tablesDBListTableLogs)) - -tablesDB - .command(`list-rows`) - .description(`Get a list of all the user's rows in a given table. You can use the query params to filter your results.`) - .requiredOption(`--database-id <database-id>`, `Database ID.`) - .requiredOption(`--table-id <table-id>`, `Table ID. You can create a new table using the TablesDB service [server integration](https://appwrite.io/docs/products/databases/tables#create-table).`) - .option(`--queries [queries...]`, `Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of 100 queries are allowed, each 4096 characters long.`) - .option(`--transaction-id <transaction-id>`, `Transaction ID to read uncommitted changes within the transaction.`) - .option(`--total [value]`, `When set to false, the total count returned will be 0 and will not be calculated.`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .option(`--console`, `Get the resource console url`) - .action(actionRunner(tablesDBListRows)) - -tablesDB - .command(`create-row`) - .description(`Create a new Row. Before using this route, you should create a new table resource using either a [server integration](https://appwrite.io/docs/references/cloud/server-dart/tablesDB#createTable) API or directly from your database console.`) - .requiredOption(`--database-id <database-id>`, `Database ID.`) - .requiredOption(`--table-id <table-id>`, `Table ID. You can create a new table using the Database service [server integration](https://appwrite.io/docs/references/cloud/server-dart/tablesDB#createTable). Make sure to define columns before creating rows.`) - .requiredOption(`--row-id <row-id>`, `Row ID. Choose a custom ID or generate a random ID with 'ID.unique()'. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.`) - .requiredOption(`--data <data>`, `Row data as JSON object.`) - .option(`--permissions [permissions...]`, `An array of permissions strings. By default, only the current user is granted all permissions. [Learn more about permissions](https://appwrite.io/docs/permissions).`) - .option(`--transaction-id <transaction-id>`, `Transaction ID for staging the operation.`) - .action(actionRunner(tablesDBCreateRow)) - -tablesDB - .command(`create-rows`) - .description(`Create new Rows. Before using this route, you should create a new table resource using either a [server integration](https://appwrite.io/docs/references/cloud/server-dart/tablesDB#createTable) API or directly from your database console.`) - .requiredOption(`--database-id <database-id>`, `Database ID.`) - .requiredOption(`--table-id <table-id>`, `Table ID. You can create a new table using the Database service [server integration](https://appwrite.io/docs/references/cloud/server-dart/tablesDB#createTable). Make sure to define columns before creating rows.`) - .requiredOption(`--rows [rows...]`, `Array of rows data as JSON objects.`) - .option(`--transaction-id <transaction-id>`, `Transaction ID for staging the operation.`) - .action(actionRunner(tablesDBCreateRows)) - -tablesDB - .command(`upsert-rows`) - .description(`Create or update Rows. Before using this route, you should create a new table resource using either a [server integration](https://appwrite.io/docs/references/cloud/server-dart/tablesDB#createTable) API or directly from your database console. `) - .requiredOption(`--database-id <database-id>`, `Database ID.`) - .requiredOption(`--table-id <table-id>`, `Table ID.`) - .requiredOption(`--rows [rows...]`, `Array of row data as JSON objects. May contain partial rows.`) - .option(`--transaction-id <transaction-id>`, `Transaction ID for staging the operation.`) - .action(actionRunner(tablesDBUpsertRows)) - -tablesDB - .command(`update-rows`) - .description(`Update all rows that match your queries, if no queries are submitted then all rows are updated. You can pass only specific fields to be updated.`) - .requiredOption(`--database-id <database-id>`, `Database ID.`) - .requiredOption(`--table-id <table-id>`, `Table ID.`) - .option(`--data <data>`, `Row data as JSON object. Include only column and value pairs to be updated.`) - .option(`--queries [queries...]`, `Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of 100 queries are allowed, each 4096 characters long.`) - .option(`--transaction-id <transaction-id>`, `Transaction ID for staging the operation.`) - .action(actionRunner(tablesDBUpdateRows)) - -tablesDB - .command(`delete-rows`) - .description(`Bulk delete rows using queries, if no queries are passed then all rows are deleted.`) - .requiredOption(`--database-id <database-id>`, `Database ID.`) - .requiredOption(`--table-id <table-id>`, `Table ID. You can create a new table using the Database service [server integration](https://appwrite.io/docs/references/cloud/server-dart/tablesDB#createTable).`) - .option(`--queries [queries...]`, `Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of 100 queries are allowed, each 4096 characters long.`) - .option(`--transaction-id <transaction-id>`, `Transaction ID for staging the operation.`) - .action(actionRunner(tablesDBDeleteRows)) - -tablesDB - .command(`get-row`) - .description(`Get a row by its unique ID. This endpoint response returns a JSON object with the row data.`) - .requiredOption(`--database-id <database-id>`, `Database ID.`) - .requiredOption(`--table-id <table-id>`, `Table ID. You can create a new table using the Database service [server integration](https://appwrite.io/docs/references/cloud/server-dart/tablesDB#createTable).`) - .requiredOption(`--row-id <row-id>`, `Row ID.`) - .option(`--queries [queries...]`, `Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of 100 queries are allowed, each 4096 characters long.`) - .option(`--transaction-id <transaction-id>`, `Transaction ID to read uncommitted changes within the transaction.`) - .option(`--console`, `Get the resource console url`) - .action(actionRunner(tablesDBGetRow)) - -tablesDB - .command(`upsert-row`) - .description(`Create or update a Row. Before using this route, you should create a new table resource using either a [server integration](https://appwrite.io/docs/references/cloud/server-dart/tablesDB#createTable) API or directly from your database console.`) - .requiredOption(`--database-id <database-id>`, `Database ID.`) - .requiredOption(`--table-id <table-id>`, `Table ID.`) - .requiredOption(`--row-id <row-id>`, `Row ID.`) - .option(`--data <data>`, `Row data as JSON object. Include all required columns of the row to be created or updated.`) - .option(`--permissions [permissions...]`, `An array of permissions strings. By default, the current permissions are inherited. [Learn more about permissions](https://appwrite.io/docs/permissions).`) - .option(`--transaction-id <transaction-id>`, `Transaction ID for staging the operation.`) - .action(actionRunner(tablesDBUpsertRow)) - -tablesDB - .command(`update-row`) - .description(`Update a row by its unique ID. Using the patch method you can pass only specific fields that will get updated.`) - .requiredOption(`--database-id <database-id>`, `Database ID.`) - .requiredOption(`--table-id <table-id>`, `Table ID.`) - .requiredOption(`--row-id <row-id>`, `Row ID.`) - .option(`--data <data>`, `Row data as JSON object. Include only columns and value pairs to be updated.`) - .option(`--permissions [permissions...]`, `An array of permissions strings. By default, the current permissions are inherited. [Learn more about permissions](https://appwrite.io/docs/permissions).`) - .option(`--transaction-id <transaction-id>`, `Transaction ID for staging the operation.`) - .action(actionRunner(tablesDBUpdateRow)) - -tablesDB - .command(`delete-row`) - .description(`Delete a row by its unique ID.`) - .requiredOption(`--database-id <database-id>`, `Database ID.`) - .requiredOption(`--table-id <table-id>`, `Table ID. You can create a new table using the Database service [server integration](https://appwrite.io/docs/references/cloud/server-dart/tablesDB#createTable).`) - .requiredOption(`--row-id <row-id>`, `Row ID.`) - .option(`--transaction-id <transaction-id>`, `Transaction ID for staging the operation.`) - .action(actionRunner(tablesDBDeleteRow)) - -tablesDB - .command(`list-row-logs`) - .description(`Get the row activity logs list by its unique ID.`) - .requiredOption(`--database-id <database-id>`, `Database ID.`) - .requiredOption(`--table-id <table-id>`, `Table ID.`) - .requiredOption(`--row-id <row-id>`, `Row ID.`) - .option(`--queries [queries...]`, `Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Only supported methods are limit and offset`) - .option(`--console`, `Get the resource console url`) - .action(actionRunner(tablesDBListRowLogs)) - -tablesDB - .command(`decrement-row-column`) - .description(`Decrement a specific column of a row by a given value.`) - .requiredOption(`--database-id <database-id>`, `Database ID.`) - .requiredOption(`--table-id <table-id>`, `Table ID.`) - .requiredOption(`--row-id <row-id>`, `Row ID.`) - .requiredOption(`--column <column>`, `Column key.`) - .option(`--value <value>`, `Value to increment the column by. The value must be a number.`, parseInteger) - .option(`--min <min>`, `Minimum value for the column. If the current value is lesser than this value, an exception will be thrown.`, parseInteger) - .option(`--transaction-id <transaction-id>`, `Transaction ID for staging the operation.`) - .action(actionRunner(tablesDBDecrementRowColumn)) - -tablesDB - .command(`increment-row-column`) - .description(`Increment a specific column of a row by a given value.`) - .requiredOption(`--database-id <database-id>`, `Database ID.`) - .requiredOption(`--table-id <table-id>`, `Table ID.`) - .requiredOption(`--row-id <row-id>`, `Row ID.`) - .requiredOption(`--column <column>`, `Column key.`) - .option(`--value <value>`, `Value to increment the column by. The value must be a number.`, parseInteger) - .option(`--max <max>`, `Maximum value for the column. If the current value is greater than this value, an error will be thrown.`, parseInteger) - .option(`--transaction-id <transaction-id>`, `Transaction ID for staging the operation.`) - .action(actionRunner(tablesDBIncrementRowColumn)) - -tablesDB - .command(`get-table-usage`) - .description(`Get usage metrics and statistics for a table. Returning the total number of rows. The response includes both current totals and historical data over time. Use the optional range parameter to specify the time window for historical data: 24h (last 24 hours), 30d (last 30 days), or 90d (last 90 days). If not specified, range defaults to 30 days.`) - .requiredOption(`--database-id <database-id>`, `Database ID.`) - .requiredOption(`--table-id <table-id>`, `Table ID.`) - .option(`--range <range>`, `Date range.`) - .option(`--console`, `Get the resource console url`) - .action(actionRunner(tablesDBGetTableUsage)) - -tablesDB - .command(`get-usage`) - .description(`Get usage metrics and statistics for a database. You can view the total number of tables, rows, and storage usage. The response includes both current totals and historical data over time. Use the optional range parameter to specify the time window for historical data: 24h (last 24 hours), 30d (last 30 days), or 90d (last 90 days). If not specified, range defaults to 30 days.`) - .requiredOption(`--database-id <database-id>`, `Database ID.`) - .option(`--range <range>`, `Date range.`) - .action(actionRunner(tablesDBGetUsage)) - - diff --git a/lib/commands/teams.ts b/lib/commands/teams.ts deleted file mode 100644 index 0f10a3ae..00000000 --- a/lib/commands/teams.ts +++ /dev/null @@ -1,609 +0,0 @@ -import fs = require('fs'); -import pathLib = require('path'); -import tar = require('tar'); -import ignore = require('ignore'); -import { promisify } from 'util'; -import Client from '../client'; -import { getAllFiles, showConsoleLink } from '../utils'; -import { Command } from 'commander'; -import { sdkForProject, sdkForConsole } from '../sdks'; -import { parse, actionRunner, parseInteger, parseBool, commandDescriptions, success, log, warn } from '../parser'; -import { localConfig, globalConfig } from '../config'; -import { File } from 'undici'; -import { ReadableStream } from 'stream/web'; - -function convertReadStreamToReadableStream(readStream: fs.ReadStream): ReadableStream { - return new ReadableStream({ - start(controller) { - readStream.on("data", (chunk: Buffer) => { - controller.enqueue(chunk); - }); - readStream.on("end", () => { - controller.close(); - }); - readStream.on("error", (err: Error) => { - controller.error(err); - }); - }, - cancel() { - readStream.destroy(); - }, - }); -} - -export const teams = new Command("teams").description(commandDescriptions['teams'] ?? '').configureHelp({ - helpWidth: process.stdout.columns || 80 -}) - -interface TeamsListRequestParams { - queries?: string[]; - search?: string; - total?: boolean; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; - console?: boolean; -} - -export const teamsList = async ({queries,search,total,parseOutput = true, overrideForCli = false, sdk = undefined, console: showConsole}: TeamsListRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/teams'; - let payload = {}; - if (typeof queries !== 'undefined') { - payload['queries'] = queries; - } - if (typeof search !== 'undefined') { - payload['search'] = search; - } - if (typeof total !== 'undefined') { - payload['total'] = total; - } - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - if(showConsole) { - showConsoleLink('teams', 'list'); - } else { - parse(response) - } - } - - return response; - -} -interface TeamsCreateRequestParams { - teamId: string; - name: string; - roles?: string[]; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const teamsCreate = async ({teamId,name,roles,parseOutput = true, overrideForCli = false, sdk = undefined}: TeamsCreateRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/teams'; - let payload = {}; - if (typeof teamId !== 'undefined') { - payload['teamId'] = teamId; - } - if (typeof name !== 'undefined') { - payload['name'] = name; - } - roles = roles === true ? [] : roles; - if (typeof roles !== 'undefined') { - payload['roles'] = roles; - } - - let response = undefined; - - response = await client.call('post', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface TeamsGetRequestParams { - teamId: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; - console?: boolean; -} - -export const teamsGet = async ({teamId,parseOutput = true, overrideForCli = false, sdk = undefined, console: showConsole}: TeamsGetRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/teams/{teamId}'.replace('{teamId}', teamId); - let payload = {}; - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - if(showConsole) { - showConsoleLink('teams', 'get', teamId); - } else { - parse(response) - } - } - - return response; - -} -interface TeamsUpdateNameRequestParams { - teamId: string; - name: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const teamsUpdateName = async ({teamId,name,parseOutput = true, overrideForCli = false, sdk = undefined}: TeamsUpdateNameRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/teams/{teamId}'.replace('{teamId}', teamId); - let payload = {}; - if (typeof name !== 'undefined') { - payload['name'] = name; - } - - let response = undefined; - - response = await client.call('put', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface TeamsDeleteRequestParams { - teamId: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const teamsDelete = async ({teamId,parseOutput = true, overrideForCli = false, sdk = undefined}: TeamsDeleteRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/teams/{teamId}'.replace('{teamId}', teamId); - let payload = {}; - - let response = undefined; - - response = await client.call('delete', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface TeamsListLogsRequestParams { - teamId: string; - queries?: string[]; - total?: boolean; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const teamsListLogs = async ({teamId,queries,total,parseOutput = true, overrideForCli = false, sdk = undefined}: TeamsListLogsRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/teams/{teamId}/logs'.replace('{teamId}', teamId); - let payload = {}; - if (typeof queries !== 'undefined') { - payload['queries'] = queries; - } - if (typeof total !== 'undefined') { - payload['total'] = total; - } - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface TeamsListMembershipsRequestParams { - teamId: string; - queries?: string[]; - search?: string; - total?: boolean; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const teamsListMemberships = async ({teamId,queries,search,total,parseOutput = true, overrideForCli = false, sdk = undefined}: TeamsListMembershipsRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/teams/{teamId}/memberships'.replace('{teamId}', teamId); - let payload = {}; - if (typeof queries !== 'undefined') { - payload['queries'] = queries; - } - if (typeof search !== 'undefined') { - payload['search'] = search; - } - if (typeof total !== 'undefined') { - payload['total'] = total; - } - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface TeamsCreateMembershipRequestParams { - teamId: string; - roles: string[]; - email?: string; - userId?: string; - phone?: string; - url?: string; - name?: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const teamsCreateMembership = async ({teamId,roles,email,userId,phone,url,name,parseOutput = true, overrideForCli = false, sdk = undefined}: TeamsCreateMembershipRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/teams/{teamId}/memberships'.replace('{teamId}', teamId); - let payload = {}; - if (typeof email !== 'undefined') { - payload['email'] = email; - } - if (typeof userId !== 'undefined') { - payload['userId'] = userId; - } - if (typeof phone !== 'undefined') { - payload['phone'] = phone; - } - roles = roles === true ? [] : roles; - if (typeof roles !== 'undefined') { - payload['roles'] = roles; - } - if (typeof url !== 'undefined') { - payload['url'] = url; - } - if (typeof name !== 'undefined') { - payload['name'] = name; - } - - let response = undefined; - - response = await client.call('post', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface TeamsGetMembershipRequestParams { - teamId: string; - membershipId: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const teamsGetMembership = async ({teamId,membershipId,parseOutput = true, overrideForCli = false, sdk = undefined}: TeamsGetMembershipRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/teams/{teamId}/memberships/{membershipId}'.replace('{teamId}', teamId).replace('{membershipId}', membershipId); - let payload = {}; - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface TeamsUpdateMembershipRequestParams { - teamId: string; - membershipId: string; - roles: string[]; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const teamsUpdateMembership = async ({teamId,membershipId,roles,parseOutput = true, overrideForCli = false, sdk = undefined}: TeamsUpdateMembershipRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/teams/{teamId}/memberships/{membershipId}'.replace('{teamId}', teamId).replace('{membershipId}', membershipId); - let payload = {}; - roles = roles === true ? [] : roles; - if (typeof roles !== 'undefined') { - payload['roles'] = roles; - } - - let response = undefined; - - response = await client.call('patch', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface TeamsDeleteMembershipRequestParams { - teamId: string; - membershipId: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const teamsDeleteMembership = async ({teamId,membershipId,parseOutput = true, overrideForCli = false, sdk = undefined}: TeamsDeleteMembershipRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/teams/{teamId}/memberships/{membershipId}'.replace('{teamId}', teamId).replace('{membershipId}', membershipId); - let payload = {}; - - let response = undefined; - - response = await client.call('delete', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface TeamsUpdateMembershipStatusRequestParams { - teamId: string; - membershipId: string; - userId: string; - secret: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const teamsUpdateMembershipStatus = async ({teamId,membershipId,userId,secret,parseOutput = true, overrideForCli = false, sdk = undefined}: TeamsUpdateMembershipStatusRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/teams/{teamId}/memberships/{membershipId}/status'.replace('{teamId}', teamId).replace('{membershipId}', membershipId); - let payload = {}; - if (typeof userId !== 'undefined') { - payload['userId'] = userId; - } - if (typeof secret !== 'undefined') { - payload['secret'] = secret; - } - - let response = undefined; - - response = await client.call('patch', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface TeamsGetPrefsRequestParams { - teamId: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const teamsGetPrefs = async ({teamId,parseOutput = true, overrideForCli = false, sdk = undefined}: TeamsGetPrefsRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/teams/{teamId}/prefs'.replace('{teamId}', teamId); - let payload = {}; - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface TeamsUpdatePrefsRequestParams { - teamId: string; - prefs: object; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const teamsUpdatePrefs = async ({teamId,prefs,parseOutput = true, overrideForCli = false, sdk = undefined}: TeamsUpdatePrefsRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/teams/{teamId}/prefs'.replace('{teamId}', teamId); - let payload = {}; - if (typeof prefs !== 'undefined') { - payload['prefs'] = JSON.parse(prefs); - } - - let response = undefined; - - response = await client.call('put', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -teams - .command(`list`) - .description(`Get a list of all the teams in which the current user is a member. You can use the parameters to filter your results.`) - .option(`--queries [queries...]`, `Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: name, total, billingPlan`) - .option(`--search <search>`, `Search term to filter your list results. Max length: 256 chars.`) - .option(`--total [value]`, `When set to false, the total count returned will be 0 and will not be calculated.`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .option(`--console`, `Get the resource console url`) - .action(actionRunner(teamsList)) - -teams - .command(`create`) - .description(`Create a new team. The user who creates the team will automatically be assigned as the owner of the team. Only the users with the owner role can invite new members, add new owners and delete or update the team.`) - .requiredOption(`--team-id <team-id>`, `Team ID. Choose a custom ID or generate a random ID with 'ID.unique()'. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.`) - .requiredOption(`--name <name>`, `Team name. Max length: 128 chars.`) - .option(`--roles [roles...]`, `Array of strings. Use this param to set the roles in the team for the user who created it. The default role is **owner**. A role can be any string. Learn more about [roles and permissions](https://appwrite.io/docs/permissions). Maximum of 100 roles are allowed, each 32 characters long.`) - .action(actionRunner(teamsCreate)) - -teams - .command(`get`) - .description(`Get a team by its ID. All team members have read access for this resource.`) - .requiredOption(`--team-id <team-id>`, `Team ID.`) - .option(`--console`, `Get the resource console url`) - .action(actionRunner(teamsGet)) - -teams - .command(`update-name`) - .description(`Update the team's name by its unique ID.`) - .requiredOption(`--team-id <team-id>`, `Team ID.`) - .requiredOption(`--name <name>`, `New team name. Max length: 128 chars.`) - .action(actionRunner(teamsUpdateName)) - -teams - .command(`delete`) - .description(`Delete a team using its ID. Only team members with the owner role can delete the team.`) - .requiredOption(`--team-id <team-id>`, `Team ID.`) - .action(actionRunner(teamsDelete)) - -teams - .command(`list-logs`) - .description(`Get the team activity logs list by its unique ID.`) - .requiredOption(`--team-id <team-id>`, `Team ID.`) - .option(`--queries [queries...]`, `Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Only supported methods are limit and offset`) - .option(`--total [value]`, `When set to false, the total count returned will be 0 and will not be calculated.`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .action(actionRunner(teamsListLogs)) - -teams - .command(`list-memberships`) - .description(`Use this endpoint to list a team's members using the team's ID. All team members have read access to this endpoint. Hide sensitive attributes from the response by toggling membership privacy in the Console.`) - .requiredOption(`--team-id <team-id>`, `Team ID.`) - .option(`--queries [queries...]`, `Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: userId, teamId, invited, joined, confirm, roles`) - .option(`--search <search>`, `Search term to filter your list results. Max length: 256 chars.`) - .option(`--total [value]`, `When set to false, the total count returned will be 0 and will not be calculated.`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .action(actionRunner(teamsListMemberships)) - -teams - .command(`create-membership`) - .description(`Invite a new member to join your team. Provide an ID for existing users, or invite unregistered users using an email or phone number. If initiated from a Client SDK, Appwrite will send an email or sms with a link to join the team to the invited user, and an account will be created for them if one doesn't exist. If initiated from a Server SDK, the new member will be added automatically to the team. You only need to provide one of a user ID, email, or phone number. Appwrite will prioritize accepting the user ID > email > phone number if you provide more than one of these parameters. Use the 'url' parameter to redirect the user from the invitation email to your app. After the user is redirected, use the [Update Team Membership Status](https://appwrite.io/docs/references/cloud/client-web/teams#updateMembershipStatus) endpoint to allow the user to accept the invitation to the team. Please note that to avoid a [Redirect Attack](https://github.com/OWASP/CheatSheetSeries/blob/master/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.md) Appwrite will accept the only redirect URLs under the domains you have added as a platform on the Appwrite Console. `) - .requiredOption(`--team-id <team-id>`, `Team ID.`) - .requiredOption(`--roles [roles...]`, `Array of strings. Use this param to set the user roles in the team. A role can be any string. Learn more about [roles and permissions](https://appwrite.io/docs/permissions). Maximum of 100 roles are allowed, each 32 characters long.`) - .option(`--email <email>`, `Email of the new team member.`) - .option(`--user-id <user-id>`, `ID of the user to be added to a team.`) - .option(`--phone <phone>`, `Phone number. Format this number with a leading '+' and a country code, e.g., +16175551212.`) - .option(`--url <url>`, `URL to redirect the user back to your app from the invitation email. This parameter is not required when an API key is supplied. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.`) - .option(`--name <name>`, `Name of the new team member. Max length: 128 chars.`) - .action(actionRunner(teamsCreateMembership)) - -teams - .command(`get-membership`) - .description(`Get a team member by the membership unique id. All team members have read access for this resource. Hide sensitive attributes from the response by toggling membership privacy in the Console.`) - .requiredOption(`--team-id <team-id>`, `Team ID.`) - .requiredOption(`--membership-id <membership-id>`, `Membership ID.`) - .action(actionRunner(teamsGetMembership)) - -teams - .command(`update-membership`) - .description(`Modify the roles of a team member. Only team members with the owner role have access to this endpoint. Learn more about [roles and permissions](https://appwrite.io/docs/permissions). `) - .requiredOption(`--team-id <team-id>`, `Team ID.`) - .requiredOption(`--membership-id <membership-id>`, `Membership ID.`) - .requiredOption(`--roles [roles...]`, `An array of strings. Use this param to set the user's roles in the team. A role can be any string. Learn more about [roles and permissions](https://appwrite.io/docs/permissions). Maximum of 100 roles are allowed, each 32 characters long.`) - .action(actionRunner(teamsUpdateMembership)) - -teams - .command(`delete-membership`) - .description(`This endpoint allows a user to leave a team or for a team owner to delete the membership of any other team member. You can also use this endpoint to delete a user membership even if it is not accepted.`) - .requiredOption(`--team-id <team-id>`, `Team ID.`) - .requiredOption(`--membership-id <membership-id>`, `Membership ID.`) - .action(actionRunner(teamsDeleteMembership)) - -teams - .command(`update-membership-status`) - .description(`Use this endpoint to allow a user to accept an invitation to join a team after being redirected back to your app from the invitation email received by the user. If the request is successful, a session for the user is automatically created. `) - .requiredOption(`--team-id <team-id>`, `Team ID.`) - .requiredOption(`--membership-id <membership-id>`, `Membership ID.`) - .requiredOption(`--user-id <user-id>`, `User ID.`) - .requiredOption(`--secret <secret>`, `Secret key.`) - .action(actionRunner(teamsUpdateMembershipStatus)) - -teams - .command(`get-prefs`) - .description(`Get the team's shared preferences by its unique ID. If a preference doesn't need to be shared by all team members, prefer storing them in [user preferences](https://appwrite.io/docs/references/cloud/client-web/account#getPrefs).`) - .requiredOption(`--team-id <team-id>`, `Team ID.`) - .action(actionRunner(teamsGetPrefs)) - -teams - .command(`update-prefs`) - .description(`Update the team's preferences by its unique ID. The object you pass is stored as is and replaces any previous value. The maximum allowed prefs size is 64kB and throws an error if exceeded.`) - .requiredOption(`--team-id <team-id>`, `Team ID.`) - .requiredOption(`--prefs <prefs>`, `Prefs key-value JSON object.`) - .action(actionRunner(teamsUpdatePrefs)) - - diff --git a/lib/commands/tokens.ts b/lib/commands/tokens.ts deleted file mode 100644 index 4292ce13..00000000 --- a/lib/commands/tokens.ts +++ /dev/null @@ -1,232 +0,0 @@ -import fs = require('fs'); -import pathLib = require('path'); -import tar = require('tar'); -import ignore = require('ignore'); -import { promisify } from 'util'; -import Client from '../client'; -import { getAllFiles, showConsoleLink } from '../utils'; -import { Command } from 'commander'; -import { sdkForProject, sdkForConsole } from '../sdks'; -import { parse, actionRunner, parseInteger, parseBool, commandDescriptions, success, log, warn } from '../parser'; -import { localConfig, globalConfig } from '../config'; -import { File } from 'undici'; -import { ReadableStream } from 'stream/web'; - -function convertReadStreamToReadableStream(readStream: fs.ReadStream): ReadableStream { - return new ReadableStream({ - start(controller) { - readStream.on("data", (chunk: Buffer) => { - controller.enqueue(chunk); - }); - readStream.on("end", () => { - controller.close(); - }); - readStream.on("error", (err: Error) => { - controller.error(err); - }); - }, - cancel() { - readStream.destroy(); - }, - }); -} - -export const tokens = new Command("tokens").description(commandDescriptions['tokens'] ?? '').configureHelp({ - helpWidth: process.stdout.columns || 80 -}) - -interface TokensListRequestParams { - bucketId: string; - fileId: string; - queries?: string[]; - total?: boolean; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; - console?: boolean; -} - -export const tokensList = async ({bucketId,fileId,queries,total,parseOutput = true, overrideForCli = false, sdk = undefined, console: showConsole}: TokensListRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/tokens/buckets/{bucketId}/files/{fileId}'.replace('{bucketId}', bucketId).replace('{fileId}', fileId); - let payload = {}; - if (typeof queries !== 'undefined') { - payload['queries'] = queries; - } - if (typeof total !== 'undefined') { - payload['total'] = total; - } - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - if(showConsole) { - showConsoleLink('tokens', 'list', bucketId, fileId); - } else { - parse(response) - } - } - - return response; - -} -interface TokensCreateFileTokenRequestParams { - bucketId: string; - fileId: string; - expire?: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const tokensCreateFileToken = async ({bucketId,fileId,expire,parseOutput = true, overrideForCli = false, sdk = undefined}: TokensCreateFileTokenRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/tokens/buckets/{bucketId}/files/{fileId}'.replace('{bucketId}', bucketId).replace('{fileId}', fileId); - let payload = {}; - if (typeof expire !== 'undefined') { - payload['expire'] = expire; - } - - let response = undefined; - - response = await client.call('post', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface TokensGetRequestParams { - tokenId: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; - console?: boolean; -} - -export const tokensGet = async ({tokenId,parseOutput = true, overrideForCli = false, sdk = undefined, console: showConsole}: TokensGetRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/tokens/{tokenId}'.replace('{tokenId}', tokenId); - let payload = {}; - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - if(showConsole) { - showConsoleLink('tokens', 'get', tokenId); - } else { - parse(response) - } - } - - return response; - -} -interface TokensUpdateRequestParams { - tokenId: string; - expire?: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const tokensUpdate = async ({tokenId,expire,parseOutput = true, overrideForCli = false, sdk = undefined}: TokensUpdateRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/tokens/{tokenId}'.replace('{tokenId}', tokenId); - let payload = {}; - if (typeof expire !== 'undefined') { - payload['expire'] = expire; - } - - let response = undefined; - - response = await client.call('patch', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface TokensDeleteRequestParams { - tokenId: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const tokensDelete = async ({tokenId,parseOutput = true, overrideForCli = false, sdk = undefined}: TokensDeleteRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/tokens/{tokenId}'.replace('{tokenId}', tokenId); - let payload = {}; - - let response = undefined; - - response = await client.call('delete', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -tokens - .command(`list`) - .description(`List all the tokens created for a specific file or bucket. You can use the query params to filter your results.`) - .requiredOption(`--bucket-id <bucket-id>`, `Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](https://appwrite.io/docs/server/storage#createBucket).`) - .requiredOption(`--file-id <file-id>`, `File unique ID.`) - .option(`--queries [queries...]`, `Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: expire`) - .option(`--total [value]`, `When set to false, the total count returned will be 0 and will not be calculated.`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .option(`--console`, `Get the resource console url`) - .action(actionRunner(tokensList)) - -tokens - .command(`create-file-token`) - .description(`Create a new token. A token is linked to a file. Token can be passed as a request URL search parameter.`) - .requiredOption(`--bucket-id <bucket-id>`, `Storage bucket unique ID. You can create a new storage bucket using the Storage service [server integration](https://appwrite.io/docs/server/storage#createBucket).`) - .requiredOption(`--file-id <file-id>`, `File unique ID.`) - .option(`--expire <expire>`, `Token expiry date`) - .action(actionRunner(tokensCreateFileToken)) - -tokens - .command(`get`) - .description(`Get a token by its unique ID.`) - .requiredOption(`--token-id <token-id>`, `Token ID.`) - .option(`--console`, `Get the resource console url`) - .action(actionRunner(tokensGet)) - -tokens - .command(`update`) - .description(`Update a token by its unique ID. Use this endpoint to update a token's expiry date.`) - .requiredOption(`--token-id <token-id>`, `Token unique ID.`) - .option(`--expire <expire>`, `File token expiry date`) - .action(actionRunner(tokensUpdate)) - -tokens - .command(`delete`) - .description(`Delete a token by its unique ID.`) - .requiredOption(`--token-id <token-id>`, `Token ID.`) - .action(actionRunner(tokensDelete)) - - diff --git a/lib/commands/types.ts b/lib/commands/types.ts index f03ce624..04eb26fc 100644 --- a/lib/commands/types.ts +++ b/lib/commands/types.ts @@ -1,20 +1,32 @@ -import ejs = require('ejs'); -import fs = require('fs'); -import path = require('path'); -import { LanguageMeta, detectLanguage, Collection } from '../type-generation/languages/language'; -import { Command, Option, Argument } from 'commander'; -import { localConfig } from '../config'; -import { success, log, warn, actionRunner } from '../parser'; -import { PHP } from '../type-generation/languages/php'; -import { TypeScript } from '../type-generation/languages/typescript'; -import { Kotlin } from '../type-generation/languages/kotlin'; -import { Swift } from '../type-generation/languages/swift'; -import { Java } from '../type-generation/languages/java'; -import { Dart } from '../type-generation/languages/dart'; -import { JavaScript } from '../type-generation/languages/javascript'; -import { CSharp } from '../type-generation/languages/csharp'; - -type SupportedLanguage = 'ts' | 'js' | 'php' | 'kotlin' | 'swift' | 'java' | 'dart' | 'cs'; +import ejs from "ejs"; +import fs from "fs"; +import path from "path"; +import { + LanguageMeta, + detectLanguage, + Collection, +} from "../type-generation/languages/language.js"; +import { Command, Option, Argument } from "commander"; +import { localConfig } from "../config.js"; +import { success, log, warn, actionRunner } from "../parser.js"; +import { PHP } from "../type-generation/languages/php.js"; +import { TypeScript } from "../type-generation/languages/typescript.js"; +import { Kotlin } from "../type-generation/languages/kotlin.js"; +import { Swift } from "../type-generation/languages/swift.js"; +import { Java } from "../type-generation/languages/java.js"; +import { Dart } from "../type-generation/languages/dart.js"; +import { JavaScript } from "../type-generation/languages/javascript.js"; +import { CSharp } from "../type-generation/languages/csharp.js"; + +type SupportedLanguage = + | "ts" + | "js" + | "php" + | "kotlin" + | "swift" + | "java" + | "dart" + | "cs"; function createLanguageMeta(language: SupportedLanguage): LanguageMeta { switch (language) { @@ -44,145 +56,161 @@ const templateHelpers = { toCamelCase: LanguageMeta.toCamelCase, toSnakeCase: LanguageMeta.toSnakeCase, toKebabCase: LanguageMeta.toKebabCase, - toUpperSnakeCase: LanguageMeta.toUpperSnakeCase + toUpperSnakeCase: LanguageMeta.toUpperSnakeCase, }; const typesOutputArgument = new Argument( "<output-directory>", - "The directory to write the types to" + "The directory to write the types to", ); const typesLanguageOption = new Option( "-l, --language <language>", - "The language of the types" + "The language of the types", ) .choices(["auto", "ts", "js", "php", "kotlin", "swift", "java", "dart", "cs"]) .default("auto"); const typesStrictOption = new Option( "-s, --strict", - "Enable strict mode to automatically convert field names to follow language conventions" -) - .default(false); + "Enable strict mode to automatically convert field names to follow language conventions", +).default(false); interface TypesOptions { language: string; strict: boolean; } -const typesCommand = actionRunner(async (rawOutputDirectory: string, {language, strict}: TypesOptions) => { - if (language === "auto") { - language = detectLanguage(); - log(`Detected language: ${language}`); - } - - if (strict) { - warn(`Strict mode enabled: Field names will be converted to follow ${language} conventions`); - } - - const meta = createLanguageMeta(language as SupportedLanguage); - - const rawOutputPath = rawOutputDirectory; - const outputExt = path.extname(rawOutputPath); - const isFileOutput = !!outputExt; - let outputDirectory = rawOutputPath; - let singleFileDestination: string | null = null; - - if (isFileOutput) { - if (meta.isSingleFile()) { - // Use the file path directly for single file languages - outputDirectory = path.dirname(rawOutputPath); - singleFileDestination = rawOutputPath; - } else { - throw new Error(`Invalid output path: ${rawOutputPath}. Output path must be a directory for languages that generate multiple files.`); +const typesCommand = actionRunner( + async (rawOutputDirectory: string, { language, strict }: TypesOptions) => { + if (language === "auto") { + language = detectLanguage(); + log(`Detected language: ${language}`); } - } - if (!fs.existsSync(outputDirectory)) { - log(`Directory: ${outputDirectory} does not exist, creating...`); - fs.mkdirSync(outputDirectory, { recursive: true }); - } + if (strict) { + warn( + `Strict mode enabled: Field names will be converted to follow ${language} conventions`, + ); + } - // Try tables first, fallback to collections - let tables = localConfig.getTables(); - let collections: any[] = []; - let dataSource = 'tables'; - - if (tables.length === 0) { - collections = localConfig.getCollections(); - dataSource = 'collections'; - - if (collections.length === 0) { - const configFileName = path.basename(localConfig.path); - throw new Error(`No tables or collections found in configuration. Make sure ${configFileName} exists and contains tables or collections.`); + const meta = createLanguageMeta(language as SupportedLanguage); + + const rawOutputPath = rawOutputDirectory; + const outputExt = path.extname(rawOutputPath); + const isFileOutput = !!outputExt; + let outputDirectory = rawOutputPath; + let singleFileDestination: string | null = null; + + if (isFileOutput) { + if (meta.isSingleFile()) { + // Use the file path directly for single file languages + outputDirectory = path.dirname(rawOutputPath); + singleFileDestination = rawOutputPath; + } else { + throw new Error( + `Invalid output path: ${rawOutputPath}. Output path must be a directory for languages that generate multiple files.`, + ); + } } - } - // Use tables if available, otherwise use collections - let dataItems: any[] = tables.length > 0 ? tables : collections; - const itemType = tables.length > 0 ? 'tables' : 'collections'; - - // Normalize tables data: rename 'columns' to 'attributes' for template compatibility - if (tables.length > 0) { - dataItems = dataItems.map(table => { - const { columns, ...rest } = table; - return { - ...rest, - attributes: (columns || []).map((column: any) => { - if (column.relatedTable) { - const { relatedTable, ...columnRest } = column; - return { - ...columnRest, - relatedCollection: relatedTable - }; - } - return column; - }) - }; - }); - } + if (!fs.existsSync(outputDirectory)) { + log(`Directory: ${outputDirectory} does not exist, creating...`); + fs.mkdirSync(outputDirectory, { recursive: true }); + } - log(`Found ${dataItems.length} ${itemType}: ${dataItems.map((c: any) => c.name).join(", ")}`); + // Try tables first, fallback to collections + let tables = localConfig.getTables(); + let collections: any[] = []; + let dataSource = "tables"; + + if (tables.length === 0) { + collections = localConfig.getCollections(); + dataSource = "collections"; + + if (collections.length === 0) { + const configFileName = path.basename(localConfig.path); + throw new Error( + `No tables or collections found in configuration. Make sure ${configFileName} exists and contains tables or collections.`, + ); + } + } - // Use columns if available, otherwise use attributes - const resourceType = tables.length > 0 ? 'columns' : 'attributes'; + // Use tables if available, otherwise use collections + let dataItems: any[] = tables.length > 0 ? tables : collections; + const itemType = tables.length > 0 ? "tables" : "collections"; + + // Normalize tables data: rename 'columns' to 'attributes' for template compatibility + if (tables.length > 0) { + dataItems = dataItems.map((table) => { + const { columns, ...rest } = table; + return { + ...rest, + attributes: (columns || []).map((column: any) => { + if (column.relatedTable) { + const { relatedTable, ...columnRest } = column; + return { + ...columnRest, + relatedCollection: relatedTable, + }; + } + return column; + }), + }; + }); + } - const totalAttributes = dataItems.reduce((count: number, item: any) => count + (item.attributes || []).length, 0); - log(`Found ${totalAttributes} ${resourceType} across all ${itemType}`); + log( + `Found ${dataItems.length} ${itemType}: ${dataItems.map((c: any) => c.name).join(", ")}`, + ); - const templater = ejs.compile(meta.getTemplate()); + // Use columns if available, otherwise use attributes + const resourceType = tables.length > 0 ? "columns" : "attributes"; - if (meta.isSingleFile()) { - const content = templater({ - collections: dataItems, - strict, - ...templateHelpers, - getType: meta.getType.bind(meta), - }); + const totalAttributes = dataItems.reduce( + (count: number, item: any) => count + (item.attributes || []).length, + 0, + ); + log(`Found ${totalAttributes} ${resourceType} across all ${itemType}`); - const destination = singleFileDestination || path.join(outputDirectory, meta.getFileName()); + const templater = ejs.compile(meta.getTemplate()); - fs.writeFileSync(destination, content); - log(`Added types to ${destination}`); - } else { - for (const item of dataItems) { + if (meta.isSingleFile()) { const content = templater({ collections: dataItems, - collection: item, strict, ...templateHelpers, getType: meta.getType.bind(meta), }); - - const destination = path.join(outputDirectory, meta.getFileName(item as Collection)); - + + const destination = + singleFileDestination || path.join(outputDirectory, meta.getFileName()); + fs.writeFileSync(destination, content); - log(`Added types for ${item.name} to ${destination}`); + log(`Added types to ${destination}`); + } else { + for (const item of dataItems) { + const content = templater({ + collections: dataItems, + collection: item, + strict, + ...templateHelpers, + getType: meta.getType.bind(meta), + }); + + const destination = path.join( + outputDirectory, + meta.getFileName(item as Collection), + ); + + fs.writeFileSync(destination, content); + log(`Added types for ${item.name} to ${destination}`); + } } - } - - success(`Generated types for all the listed ${itemType}`); -}); + + success(`Generated types for all the listed ${itemType}`); + }, +); export const types = new Command("types") .description("Generate types for your Appwrite project") @@ -190,4 +218,3 @@ export const types = new Command("types") .addOption(typesLanguageOption) .addOption(typesStrictOption) .action(actionRunner(typesCommand)); - diff --git a/lib/commands/update.ts b/lib/commands/update.ts index f0b7b5b6..f4445b90 100644 --- a/lib/commands/update.ts +++ b/lib/commands/update.ts @@ -1,216 +1,255 @@ -import fs = require('fs'); -import path = require('path'); -import { spawn } from 'child_process'; -import { Command } from 'commander'; -import chalk from 'chalk'; -import inquirer from 'inquirer'; -import { success, log, warn, error, hint, actionRunner, commandDescriptions } from '../parser'; -import { getLatestVersion, compareVersions } from '../utils'; -const { version } = require('../../../package.json'); +import fs from "fs"; +import path from "path"; +import { spawn } from "child_process"; +import { Command } from "commander"; +import chalk from "chalk"; +import inquirer from "inquirer"; +import { + success, + log, + warn, + error, + hint, + actionRunner, + commandDescriptions, +} from "../parser.js"; +import { getLatestVersion, compareVersions } from "../utils.js"; +import packageJson from "../../package.json" with { type: "json" }; +const { version } = packageJson; /** * Check if the CLI was installed via npm */ const isInstalledViaNpm = (): boolean => { - try { - const scriptPath = process.argv[1]; - - if (scriptPath.includes('node_modules') && scriptPath.includes('appwrite-cli')) { - return true; - } - - if (scriptPath.includes('/usr/local/lib/node_modules/') || - scriptPath.includes('/opt/homebrew/lib/node_modules/') || - scriptPath.includes('/.npm-global/') || - scriptPath.includes('/node_modules/.bin/')) { - return true; - } - - return false; - } catch (e) { - return false; + try { + const scriptPath = process.argv[1]; + + if ( + scriptPath.includes("node_modules") && + scriptPath.includes("appwrite-cli") + ) { + return true; + } + + if ( + scriptPath.includes("/usr/local/lib/node_modules/") || + scriptPath.includes("/opt/homebrew/lib/node_modules/") || + scriptPath.includes("/.npm-global/") || + scriptPath.includes("/node_modules/.bin/") + ) { + return true; } + + return false; + } catch (e) { + return false; + } }; /** * Check if the CLI was installed via Homebrew */ const isInstalledViaHomebrew = (): boolean => { - try { - const scriptPath = process.argv[1]; - return scriptPath.includes('/opt/homebrew/') || scriptPath.includes('/usr/local/Cellar/'); - } catch (e) { - return false; - } + try { + const scriptPath = process.argv[1]; + return ( + scriptPath.includes("/opt/homebrew/") || + scriptPath.includes("/usr/local/Cellar/") + ); + } catch (e) { + return false; + } }; /** * Execute command and return promise */ -const execCommand = (command: string, args: string[] = [], options: any = {}): Promise<void> => { - return new Promise((resolve, reject) => { - const child = spawn(command, args, { - stdio: 'inherit', - shell: true, - ...options - }); - - child.on('close', (code) => { - if (code === 0) { - resolve(); - } else { - reject(new Error(`Command failed with exit code ${code}`)); - } - }); - - child.on('error', (err) => { - reject(err); - }); +const execCommand = ( + command: string, + args: string[] = [], + options: any = {}, +): Promise<void> => { + return new Promise((resolve, reject) => { + const child = spawn(command, args, { + stdio: "inherit", + shell: true, + ...options, + }); + + child.on("close", (code) => { + if (code === 0) { + resolve(); + } else { + reject(new Error(`Command failed with exit code ${code}`)); + } }); + + child.on("error", (err) => { + reject(err); + }); + }); }; /** * Update via npm */ const updateViaNpm = async (): Promise<void> => { - try { - await execCommand('npm', ['install', '-g', 'appwrite-cli@latest']); - console.log(""); - success("Updated to latest version via npm!"); - hint("Run 'appwrite --version' to verify the new version."); - } catch (e: any) { - if (e.message.includes('EEXIST') || e.message.includes('file already exists')) { - console.log(""); - success("Latest version is already installed via npm!"); - hint("The CLI is up to date. Run 'appwrite --version' to verify."); - } else { - console.log(""); - error(`Failed to update via npm: ${e.message}`); - hint("Try running: npm install -g appwrite-cli@latest --force"); - } + try { + await execCommand("npm", ["install", "-g", "appwrite-cli@latest"]); + console.log(""); + success("Updated to latest version via npm!"); + hint("Run 'appwrite --version' to verify the new version."); + } catch (e: any) { + if ( + e.message.includes("EEXIST") || + e.message.includes("file already exists") + ) { + console.log(""); + success("Latest version is already installed via npm!"); + hint("The CLI is up to date. Run 'appwrite --version' to verify."); + } else { + console.log(""); + error(`Failed to update via npm: ${e.message}`); + hint("Try running: npm install -g appwrite-cli@latest --force"); } + } }; /** * Update via Homebrew */ const updateViaHomebrew = async (): Promise<void> => { - try { - await execCommand('brew', ['upgrade', 'appwrite']); - console.log(""); - success("Updated to latest version via Homebrew!"); - hint("Run 'appwrite --version' to verify the new version."); - } catch (e: any) { - if (e.message.includes('already installed') || e.message.includes('up-to-date')) { - console.log(""); - success("Latest version is already installed via Homebrew!"); - hint("The CLI is up to date. Run 'appwrite --version' to verify."); - } else { - console.log(""); - error(`Failed to update via Homebrew: ${e.message}`); - hint("Try running: brew upgrade appwrite"); - } + try { + await execCommand("brew", ["upgrade", "appwrite"]); + console.log(""); + success("Updated to latest version via Homebrew!"); + hint("Run 'appwrite --version' to verify the new version."); + } catch (e: any) { + if ( + e.message.includes("already installed") || + e.message.includes("up-to-date") + ) { + console.log(""); + success("Latest version is already installed via Homebrew!"); + hint("The CLI is up to date. Run 'appwrite --version' to verify."); + } else { + console.log(""); + error(`Failed to update via Homebrew: ${e.message}`); + hint("Try running: brew upgrade appwrite"); } + } }; /** * Show manual update instructions */ const showManualInstructions = (latestVersion: string): void => { - log("Manual update options:"); - console.log(""); - - log(`${chalk.bold("Option 1: NPM")}`); - console.log(` npm install -g appwrite-cli@latest`); - console.log(""); - - log(`${chalk.bold("Option 2: Homebrew")}`); - console.log(` brew upgrade appwrite`); - console.log(""); - - log(`${chalk.bold("Option 3: Download Binary")}`); - console.log(` Visit: https://github.com/appwrite-cli/releases/tag/${latestVersion}`); + log("Manual update options:"); + console.log(""); + + log(`${chalk.bold("Option 1: NPM")}`); + console.log(` npm install -g appwrite-cli@latest`); + console.log(""); + + log(`${chalk.bold("Option 2: Homebrew")}`); + console.log(` brew upgrade appwrite`); + console.log(""); + + log(`${chalk.bold("Option 3: Download Binary")}`); + console.log( + ` Visit: https://github.com/appwrite-cli/releases/tag/${latestVersion}`, + ); }; /** * Show interactive menu for choosing update method */ const chooseUpdateMethod = async (latestVersion: string): Promise<void> => { - const choices = [ - { name: 'NPM', value: 'npm' }, - { name: 'Homebrew', value: 'homebrew' }, - { name: 'Show manual instructions', value: 'manual' } - ]; - - const { method } = await inquirer.prompt([ - { - type: 'list', - name: 'method', - message: 'Could not detect installation method. How would you like to update?', - choices: choices - } - ]); - - switch (method) { - case 'npm': - await updateViaNpm(); - break; - case 'homebrew': - await updateViaHomebrew(); - break; - case 'manual': - showManualInstructions(latestVersion); - break; - } + const choices = [ + { name: "NPM", value: "npm" }, + { name: "Homebrew", value: "homebrew" }, + { name: "Show manual instructions", value: "manual" }, + ]; + + const { method } = await inquirer.prompt([ + { + type: "list", + name: "method", + message: + "Could not detect installation method. How would you like to update?", + choices: choices, + }, + ]); + + switch (method) { + case "npm": + await updateViaNpm(); + break; + case "homebrew": + await updateViaHomebrew(); + break; + case "manual": + showManualInstructions(latestVersion); + break; + } }; interface UpdateOptions { - manual?: boolean; + manual?: boolean; } /** * Main update function */ const updateCli = async ({ manual }: UpdateOptions = {}): Promise<void> => { - try { - const latestVersion = await getLatestVersion(); - - const comparison = compareVersions(version, latestVersion); - - if (comparison === 0) { - success(`You're already running the latest version (${chalk.bold(version)})!`); - return; - } else if (comparison < 0) { - warn(`You're running a newer version (${chalk.bold(version)}) than the latest released version (${chalk.bold(latestVersion)}).`); - hint("This might be a pre-release or development version."); - return; - } - - log(`Updating from ${chalk.blue(version)} to ${chalk.green(latestVersion)}...`); - console.log(""); - - if (manual) { - showManualInstructions(latestVersion); - return; - } - - if (isInstalledViaNpm()) { - await updateViaNpm(); - } else if (isInstalledViaHomebrew()) { - await updateViaHomebrew(); - } else { - await chooseUpdateMethod(latestVersion); - } - - } catch (e: any) { - console.log(""); - error(`Failed to check for updates: ${e.message}`); - hint("You can manually check for updates at: https://github.com/appwrite-cli/releases"); + try { + const latestVersion = await getLatestVersion(); + + const comparison = compareVersions(version, latestVersion); + + if (comparison === 0) { + success( + `You're already running the latest version (${chalk.bold(version)})!`, + ); + return; + } else if (comparison < 0) { + warn( + `You're running a newer version (${chalk.bold(version)}) than the latest released version (${chalk.bold(latestVersion)}).`, + ); + hint("This might be a pre-release or development version."); + return; } + + log( + `Updating from ${chalk.blue(version)} to ${chalk.green(latestVersion)}...`, + ); + console.log(""); + + if (manual) { + showManualInstructions(latestVersion); + return; + } + + if (isInstalledViaNpm()) { + await updateViaNpm(); + } else if (isInstalledViaHomebrew()) { + await updateViaHomebrew(); + } else { + await chooseUpdateMethod(latestVersion); + } + } catch (e: any) { + console.log(""); + error(`Failed to check for updates: ${e.message}`); + hint( + "You can manually check for updates at: https://github.com/appwrite-cli/releases", + ); + } }; export const update = new Command("update") - .description("Update the Appwrite CLI to the latest version") - .option("--manual", "Show manual update instructions instead of auto-updating") - .action(actionRunner(updateCli)); - + .description("Update the Appwrite CLI to the latest version") + .option( + "--manual", + "Show manual update instructions instead of auto-updating", + ) + .action(actionRunner(updateCli)); diff --git a/lib/commands/users.ts b/lib/commands/users.ts deleted file mode 100644 index 6d9d21ea..00000000 --- a/lib/commands/users.ts +++ /dev/null @@ -1,1804 +0,0 @@ -import fs = require('fs'); -import pathLib = require('path'); -import tar = require('tar'); -import ignore = require('ignore'); -import { promisify } from 'util'; -import Client from '../client'; -import { getAllFiles, showConsoleLink } from '../utils'; -import { Command } from 'commander'; -import { sdkForProject, sdkForConsole } from '../sdks'; -import { parse, actionRunner, parseInteger, parseBool, commandDescriptions, success, log, warn } from '../parser'; -import { localConfig, globalConfig } from '../config'; -import { File } from 'undici'; -import { ReadableStream } from 'stream/web'; - -function convertReadStreamToReadableStream(readStream: fs.ReadStream): ReadableStream { - return new ReadableStream({ - start(controller) { - readStream.on("data", (chunk: Buffer) => { - controller.enqueue(chunk); - }); - readStream.on("end", () => { - controller.close(); - }); - readStream.on("error", (err: Error) => { - controller.error(err); - }); - }, - cancel() { - readStream.destroy(); - }, - }); -} - -export const users = new Command("users").description(commandDescriptions['users'] ?? '').configureHelp({ - helpWidth: process.stdout.columns || 80 -}) - -interface UsersListRequestParams { - queries?: string[]; - search?: string; - total?: boolean; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; - console?: boolean; -} - -export const usersList = async ({queries,search,total,parseOutput = true, overrideForCli = false, sdk = undefined, console: showConsole}: UsersListRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/users'; - let payload = {}; - if (typeof queries !== 'undefined') { - payload['queries'] = queries; - } - if (typeof search !== 'undefined') { - payload['search'] = search; - } - if (typeof total !== 'undefined') { - payload['total'] = total; - } - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - if(showConsole) { - showConsoleLink('users', 'list'); - } else { - parse(response) - } - } - - return response; - -} -interface UsersCreateRequestParams { - userId: string; - email?: string; - phone?: string; - password?: string; - name?: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const usersCreate = async ({userId,email,phone,password,name,parseOutput = true, overrideForCli = false, sdk = undefined}: UsersCreateRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/users'; - let payload = {}; - if (typeof userId !== 'undefined') { - payload['userId'] = userId; - } - if (typeof email !== 'undefined') { - payload['email'] = email; - } - if (typeof phone !== 'undefined') { - payload['phone'] = phone; - } - if (typeof password !== 'undefined') { - payload['password'] = password; - } - if (typeof name !== 'undefined') { - payload['name'] = name; - } - - let response = undefined; - - response = await client.call('post', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface UsersCreateArgon2UserRequestParams { - userId: string; - email: string; - password: string; - name?: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const usersCreateArgon2User = async ({userId,email,password,name,parseOutput = true, overrideForCli = false, sdk = undefined}: UsersCreateArgon2UserRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/users/argon2'; - let payload = {}; - if (typeof userId !== 'undefined') { - payload['userId'] = userId; - } - if (typeof email !== 'undefined') { - payload['email'] = email; - } - if (typeof password !== 'undefined') { - payload['password'] = password; - } - if (typeof name !== 'undefined') { - payload['name'] = name; - } - - let response = undefined; - - response = await client.call('post', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface UsersCreateBcryptUserRequestParams { - userId: string; - email: string; - password: string; - name?: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const usersCreateBcryptUser = async ({userId,email,password,name,parseOutput = true, overrideForCli = false, sdk = undefined}: UsersCreateBcryptUserRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/users/bcrypt'; - let payload = {}; - if (typeof userId !== 'undefined') { - payload['userId'] = userId; - } - if (typeof email !== 'undefined') { - payload['email'] = email; - } - if (typeof password !== 'undefined') { - payload['password'] = password; - } - if (typeof name !== 'undefined') { - payload['name'] = name; - } - - let response = undefined; - - response = await client.call('post', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface UsersListIdentitiesRequestParams { - queries?: string[]; - search?: string; - total?: boolean; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const usersListIdentities = async ({queries,search,total,parseOutput = true, overrideForCli = false, sdk = undefined}: UsersListIdentitiesRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/users/identities'; - let payload = {}; - if (typeof queries !== 'undefined') { - payload['queries'] = queries; - } - if (typeof search !== 'undefined') { - payload['search'] = search; - } - if (typeof total !== 'undefined') { - payload['total'] = total; - } - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface UsersDeleteIdentityRequestParams { - identityId: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const usersDeleteIdentity = async ({identityId,parseOutput = true, overrideForCli = false, sdk = undefined}: UsersDeleteIdentityRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/users/identities/{identityId}'.replace('{identityId}', identityId); - let payload = {}; - - let response = undefined; - - response = await client.call('delete', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface UsersCreateMD5UserRequestParams { - userId: string; - email: string; - password: string; - name?: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const usersCreateMD5User = async ({userId,email,password,name,parseOutput = true, overrideForCli = false, sdk = undefined}: UsersCreateMD5UserRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/users/md5'; - let payload = {}; - if (typeof userId !== 'undefined') { - payload['userId'] = userId; - } - if (typeof email !== 'undefined') { - payload['email'] = email; - } - if (typeof password !== 'undefined') { - payload['password'] = password; - } - if (typeof name !== 'undefined') { - payload['name'] = name; - } - - let response = undefined; - - response = await client.call('post', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface UsersCreatePHPassUserRequestParams { - userId: string; - email: string; - password: string; - name?: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const usersCreatePHPassUser = async ({userId,email,password,name,parseOutput = true, overrideForCli = false, sdk = undefined}: UsersCreatePHPassUserRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/users/phpass'; - let payload = {}; - if (typeof userId !== 'undefined') { - payload['userId'] = userId; - } - if (typeof email !== 'undefined') { - payload['email'] = email; - } - if (typeof password !== 'undefined') { - payload['password'] = password; - } - if (typeof name !== 'undefined') { - payload['name'] = name; - } - - let response = undefined; - - response = await client.call('post', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface UsersCreateScryptUserRequestParams { - userId: string; - email: string; - password: string; - passwordSalt: string; - passwordCpu: number; - passwordMemory: number; - passwordParallel: number; - passwordLength: number; - name?: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const usersCreateScryptUser = async ({userId,email,password,passwordSalt,passwordCpu,passwordMemory,passwordParallel,passwordLength,name,parseOutput = true, overrideForCli = false, sdk = undefined}: UsersCreateScryptUserRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/users/scrypt'; - let payload = {}; - if (typeof userId !== 'undefined') { - payload['userId'] = userId; - } - if (typeof email !== 'undefined') { - payload['email'] = email; - } - if (typeof password !== 'undefined') { - payload['password'] = password; - } - if (typeof passwordSalt !== 'undefined') { - payload['passwordSalt'] = passwordSalt; - } - if (typeof passwordCpu !== 'undefined') { - payload['passwordCpu'] = passwordCpu; - } - if (typeof passwordMemory !== 'undefined') { - payload['passwordMemory'] = passwordMemory; - } - if (typeof passwordParallel !== 'undefined') { - payload['passwordParallel'] = passwordParallel; - } - if (typeof passwordLength !== 'undefined') { - payload['passwordLength'] = passwordLength; - } - if (typeof name !== 'undefined') { - payload['name'] = name; - } - - let response = undefined; - - response = await client.call('post', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface UsersCreateScryptModifiedUserRequestParams { - userId: string; - email: string; - password: string; - passwordSalt: string; - passwordSaltSeparator: string; - passwordSignerKey: string; - name?: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const usersCreateScryptModifiedUser = async ({userId,email,password,passwordSalt,passwordSaltSeparator,passwordSignerKey,name,parseOutput = true, overrideForCli = false, sdk = undefined}: UsersCreateScryptModifiedUserRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/users/scrypt-modified'; - let payload = {}; - if (typeof userId !== 'undefined') { - payload['userId'] = userId; - } - if (typeof email !== 'undefined') { - payload['email'] = email; - } - if (typeof password !== 'undefined') { - payload['password'] = password; - } - if (typeof passwordSalt !== 'undefined') { - payload['passwordSalt'] = passwordSalt; - } - if (typeof passwordSaltSeparator !== 'undefined') { - payload['passwordSaltSeparator'] = passwordSaltSeparator; - } - if (typeof passwordSignerKey !== 'undefined') { - payload['passwordSignerKey'] = passwordSignerKey; - } - if (typeof name !== 'undefined') { - payload['name'] = name; - } - - let response = undefined; - - response = await client.call('post', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface UsersCreateSHAUserRequestParams { - userId: string; - email: string; - password: string; - passwordVersion?: PasswordHash; - name?: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const usersCreateSHAUser = async ({userId,email,password,passwordVersion,name,parseOutput = true, overrideForCli = false, sdk = undefined}: UsersCreateSHAUserRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/users/sha'; - let payload = {}; - if (typeof userId !== 'undefined') { - payload['userId'] = userId; - } - if (typeof email !== 'undefined') { - payload['email'] = email; - } - if (typeof password !== 'undefined') { - payload['password'] = password; - } - if (typeof passwordVersion !== 'undefined') { - payload['passwordVersion'] = passwordVersion; - } - if (typeof name !== 'undefined') { - payload['name'] = name; - } - - let response = undefined; - - response = await client.call('post', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface UsersGetUsageRequestParams { - range?: UsageRange; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const usersGetUsage = async ({range,parseOutput = true, overrideForCli = false, sdk = undefined}: UsersGetUsageRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/users/usage'; - let payload = {}; - if (typeof range !== 'undefined') { - payload['range'] = range; - } - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface UsersGetRequestParams { - userId: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; - console?: boolean; -} - -export const usersGet = async ({userId,parseOutput = true, overrideForCli = false, sdk = undefined, console: showConsole}: UsersGetRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/users/{userId}'.replace('{userId}', userId); - let payload = {}; - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - if(showConsole) { - showConsoleLink('users', 'get', userId); - } else { - parse(response) - } - } - - return response; - -} -interface UsersDeleteRequestParams { - userId: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const usersDelete = async ({userId,parseOutput = true, overrideForCli = false, sdk = undefined}: UsersDeleteRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/users/{userId}'.replace('{userId}', userId); - let payload = {}; - - let response = undefined; - - response = await client.call('delete', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface UsersUpdateEmailRequestParams { - userId: string; - email: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const usersUpdateEmail = async ({userId,email,parseOutput = true, overrideForCli = false, sdk = undefined}: UsersUpdateEmailRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/users/{userId}/email'.replace('{userId}', userId); - let payload = {}; - if (typeof email !== 'undefined') { - payload['email'] = email; - } - - let response = undefined; - - response = await client.call('patch', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface UsersCreateJWTRequestParams { - userId: string; - sessionId?: string; - duration?: number; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const usersCreateJWT = async ({userId,sessionId,duration,parseOutput = true, overrideForCli = false, sdk = undefined}: UsersCreateJWTRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/users/{userId}/jwts'.replace('{userId}', userId); - let payload = {}; - if (typeof sessionId !== 'undefined') { - payload['sessionId'] = sessionId; - } - if (typeof duration !== 'undefined') { - payload['duration'] = duration; - } - - let response = undefined; - - response = await client.call('post', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface UsersUpdateLabelsRequestParams { - userId: string; - labels: string[]; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const usersUpdateLabels = async ({userId,labels,parseOutput = true, overrideForCli = false, sdk = undefined}: UsersUpdateLabelsRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/users/{userId}/labels'.replace('{userId}', userId); - let payload = {}; - labels = labels === true ? [] : labels; - if (typeof labels !== 'undefined') { - payload['labels'] = labels; - } - - let response = undefined; - - response = await client.call('put', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface UsersListLogsRequestParams { - userId: string; - queries?: string[]; - total?: boolean; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const usersListLogs = async ({userId,queries,total,parseOutput = true, overrideForCli = false, sdk = undefined}: UsersListLogsRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/users/{userId}/logs'.replace('{userId}', userId); - let payload = {}; - if (typeof queries !== 'undefined') { - payload['queries'] = queries; - } - if (typeof total !== 'undefined') { - payload['total'] = total; - } - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface UsersListMembershipsRequestParams { - userId: string; - queries?: string[]; - search?: string; - total?: boolean; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const usersListMemberships = async ({userId,queries,search,total,parseOutput = true, overrideForCli = false, sdk = undefined}: UsersListMembershipsRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/users/{userId}/memberships'.replace('{userId}', userId); - let payload = {}; - if (typeof queries !== 'undefined') { - payload['queries'] = queries; - } - if (typeof search !== 'undefined') { - payload['search'] = search; - } - if (typeof total !== 'undefined') { - payload['total'] = total; - } - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface UsersUpdateMFARequestParams { - userId: string; - mfa: boolean; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const usersUpdateMFA = async ({userId,mfa,parseOutput = true, overrideForCli = false, sdk = undefined}: UsersUpdateMFARequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/users/{userId}/mfa'.replace('{userId}', userId); - let payload = {}; - if (typeof mfa !== 'undefined') { - payload['mfa'] = mfa; - } - - let response = undefined; - - response = await client.call('patch', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface UsersDeleteMFAAuthenticatorRequestParams { - userId: string; - type: AuthenticatorType; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const usersDeleteMFAAuthenticator = async ({userId,type,parseOutput = true, overrideForCli = false, sdk = undefined}: UsersDeleteMFAAuthenticatorRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/users/{userId}/mfa/authenticators/{type}'.replace('{userId}', userId).replace('{type}', type); - let payload = {}; - - let response = undefined; - - response = await client.call('delete', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface UsersListMFAFactorsRequestParams { - userId: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const usersListMFAFactors = async ({userId,parseOutput = true, overrideForCli = false, sdk = undefined}: UsersListMFAFactorsRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/users/{userId}/mfa/factors'.replace('{userId}', userId); - let payload = {}; - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface UsersGetMFARecoveryCodesRequestParams { - userId: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const usersGetMFARecoveryCodes = async ({userId,parseOutput = true, overrideForCli = false, sdk = undefined}: UsersGetMFARecoveryCodesRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/users/{userId}/mfa/recovery-codes'.replace('{userId}', userId); - let payload = {}; - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface UsersUpdateMFARecoveryCodesRequestParams { - userId: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const usersUpdateMFARecoveryCodes = async ({userId,parseOutput = true, overrideForCli = false, sdk = undefined}: UsersUpdateMFARecoveryCodesRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/users/{userId}/mfa/recovery-codes'.replace('{userId}', userId); - let payload = {}; - - let response = undefined; - - response = await client.call('put', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface UsersCreateMFARecoveryCodesRequestParams { - userId: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const usersCreateMFARecoveryCodes = async ({userId,parseOutput = true, overrideForCli = false, sdk = undefined}: UsersCreateMFARecoveryCodesRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/users/{userId}/mfa/recovery-codes'.replace('{userId}', userId); - let payload = {}; - - let response = undefined; - - response = await client.call('patch', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface UsersUpdateNameRequestParams { - userId: string; - name: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const usersUpdateName = async ({userId,name,parseOutput = true, overrideForCli = false, sdk = undefined}: UsersUpdateNameRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/users/{userId}/name'.replace('{userId}', userId); - let payload = {}; - if (typeof name !== 'undefined') { - payload['name'] = name; - } - - let response = undefined; - - response = await client.call('patch', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface UsersUpdatePasswordRequestParams { - userId: string; - password: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const usersUpdatePassword = async ({userId,password,parseOutput = true, overrideForCli = false, sdk = undefined}: UsersUpdatePasswordRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/users/{userId}/password'.replace('{userId}', userId); - let payload = {}; - if (typeof password !== 'undefined') { - payload['password'] = password; - } - - let response = undefined; - - response = await client.call('patch', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface UsersUpdatePhoneRequestParams { - userId: string; - number: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const usersUpdatePhone = async ({userId,number,parseOutput = true, overrideForCli = false, sdk = undefined}: UsersUpdatePhoneRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/users/{userId}/phone'.replace('{userId}', userId); - let payload = {}; - if (typeof number !== 'undefined') { - payload['number'] = number; - } - - let response = undefined; - - response = await client.call('patch', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface UsersGetPrefsRequestParams { - userId: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const usersGetPrefs = async ({userId,parseOutput = true, overrideForCli = false, sdk = undefined}: UsersGetPrefsRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/users/{userId}/prefs'.replace('{userId}', userId); - let payload = {}; - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface UsersUpdatePrefsRequestParams { - userId: string; - prefs: object; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const usersUpdatePrefs = async ({userId,prefs,parseOutput = true, overrideForCli = false, sdk = undefined}: UsersUpdatePrefsRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/users/{userId}/prefs'.replace('{userId}', userId); - let payload = {}; - if (typeof prefs !== 'undefined') { - payload['prefs'] = JSON.parse(prefs); - } - - let response = undefined; - - response = await client.call('patch', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface UsersListSessionsRequestParams { - userId: string; - total?: boolean; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; - console?: boolean; -} - -export const usersListSessions = async ({userId,total,parseOutput = true, overrideForCli = false, sdk = undefined, console: showConsole}: UsersListSessionsRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/users/{userId}/sessions'.replace('{userId}', userId); - let payload = {}; - if (typeof total !== 'undefined') { - payload['total'] = total; - } - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - if(showConsole) { - showConsoleLink('users', 'listSessions', userId); - } else { - parse(response) - } - } - - return response; - -} -interface UsersCreateSessionRequestParams { - userId: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const usersCreateSession = async ({userId,parseOutput = true, overrideForCli = false, sdk = undefined}: UsersCreateSessionRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/users/{userId}/sessions'.replace('{userId}', userId); - let payload = {}; - - let response = undefined; - - response = await client.call('post', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface UsersDeleteSessionsRequestParams { - userId: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const usersDeleteSessions = async ({userId,parseOutput = true, overrideForCli = false, sdk = undefined}: UsersDeleteSessionsRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/users/{userId}/sessions'.replace('{userId}', userId); - let payload = {}; - - let response = undefined; - - response = await client.call('delete', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface UsersDeleteSessionRequestParams { - userId: string; - sessionId: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const usersDeleteSession = async ({userId,sessionId,parseOutput = true, overrideForCli = false, sdk = undefined}: UsersDeleteSessionRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/users/{userId}/sessions/{sessionId}'.replace('{userId}', userId).replace('{sessionId}', sessionId); - let payload = {}; - - let response = undefined; - - response = await client.call('delete', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface UsersUpdateStatusRequestParams { - userId: string; - status: boolean; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const usersUpdateStatus = async ({userId,status,parseOutput = true, overrideForCli = false, sdk = undefined}: UsersUpdateStatusRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/users/{userId}/status'.replace('{userId}', userId); - let payload = {}; - if (typeof status !== 'undefined') { - payload['status'] = status; - } - - let response = undefined; - - response = await client.call('patch', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface UsersListTargetsRequestParams { - userId: string; - queries?: string[]; - total?: boolean; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const usersListTargets = async ({userId,queries,total,parseOutput = true, overrideForCli = false, sdk = undefined}: UsersListTargetsRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/users/{userId}/targets'.replace('{userId}', userId); - let payload = {}; - if (typeof queries !== 'undefined') { - payload['queries'] = queries; - } - if (typeof total !== 'undefined') { - payload['total'] = total; - } - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface UsersCreateTargetRequestParams { - userId: string; - targetId: string; - providerType: MessagingProviderType; - identifier: string; - providerId?: string; - name?: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const usersCreateTarget = async ({userId,targetId,providerType,identifier,providerId,name,parseOutput = true, overrideForCli = false, sdk = undefined}: UsersCreateTargetRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/users/{userId}/targets'.replace('{userId}', userId); - let payload = {}; - if (typeof targetId !== 'undefined') { - payload['targetId'] = targetId; - } - if (typeof providerType !== 'undefined') { - payload['providerType'] = providerType; - } - if (typeof identifier !== 'undefined') { - payload['identifier'] = identifier; - } - if (typeof providerId !== 'undefined') { - payload['providerId'] = providerId; - } - if (typeof name !== 'undefined') { - payload['name'] = name; - } - - let response = undefined; - - response = await client.call('post', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface UsersGetTargetRequestParams { - userId: string; - targetId: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const usersGetTarget = async ({userId,targetId,parseOutput = true, overrideForCli = false, sdk = undefined}: UsersGetTargetRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/users/{userId}/targets/{targetId}'.replace('{userId}', userId).replace('{targetId}', targetId); - let payload = {}; - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface UsersUpdateTargetRequestParams { - userId: string; - targetId: string; - identifier?: string; - providerId?: string; - name?: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const usersUpdateTarget = async ({userId,targetId,identifier,providerId,name,parseOutput = true, overrideForCli = false, sdk = undefined}: UsersUpdateTargetRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/users/{userId}/targets/{targetId}'.replace('{userId}', userId).replace('{targetId}', targetId); - let payload = {}; - if (typeof identifier !== 'undefined') { - payload['identifier'] = identifier; - } - if (typeof providerId !== 'undefined') { - payload['providerId'] = providerId; - } - if (typeof name !== 'undefined') { - payload['name'] = name; - } - - let response = undefined; - - response = await client.call('patch', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface UsersDeleteTargetRequestParams { - userId: string; - targetId: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const usersDeleteTarget = async ({userId,targetId,parseOutput = true, overrideForCli = false, sdk = undefined}: UsersDeleteTargetRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/users/{userId}/targets/{targetId}'.replace('{userId}', userId).replace('{targetId}', targetId); - let payload = {}; - - let response = undefined; - - response = await client.call('delete', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface UsersCreateTokenRequestParams { - userId: string; - length?: number; - expire?: number; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const usersCreateToken = async ({userId,length,expire,parseOutput = true, overrideForCli = false, sdk = undefined}: UsersCreateTokenRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/users/{userId}/tokens'.replace('{userId}', userId); - let payload = {}; - if (typeof length !== 'undefined') { - payload['length'] = length; - } - if (typeof expire !== 'undefined') { - payload['expire'] = expire; - } - - let response = undefined; - - response = await client.call('post', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface UsersUpdateEmailVerificationRequestParams { - userId: string; - emailVerification: boolean; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const usersUpdateEmailVerification = async ({userId,emailVerification,parseOutput = true, overrideForCli = false, sdk = undefined}: UsersUpdateEmailVerificationRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/users/{userId}/verification'.replace('{userId}', userId); - let payload = {}; - if (typeof emailVerification !== 'undefined') { - payload['emailVerification'] = emailVerification; - } - - let response = undefined; - - response = await client.call('patch', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface UsersUpdatePhoneVerificationRequestParams { - userId: string; - phoneVerification: boolean; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const usersUpdatePhoneVerification = async ({userId,phoneVerification,parseOutput = true, overrideForCli = false, sdk = undefined}: UsersUpdatePhoneVerificationRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/users/{userId}/verification/phone'.replace('{userId}', userId); - let payload = {}; - if (typeof phoneVerification !== 'undefined') { - payload['phoneVerification'] = phoneVerification; - } - - let response = undefined; - - response = await client.call('patch', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -users - .command(`list`) - .description(`Get a list of all the project's users. You can use the query params to filter your results.`) - .option(`--queries [queries...]`, `Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: name, email, phone, status, passwordUpdate, registration, emailVerification, phoneVerification, labels`) - .option(`--search <search>`, `Search term to filter your list results. Max length: 256 chars.`) - .option(`--total [value]`, `When set to false, the total count returned will be 0 and will not be calculated.`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .option(`--console`, `Get the resource console url`) - .action(actionRunner(usersList)) - -users - .command(`create`) - .description(`Create a new user.`) - .requiredOption(`--user-id <user-id>`, `User ID. Choose a custom ID or generate a random ID with 'ID.unique()'. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.`) - .option(`--email <email>`, `User email.`) - .option(`--phone <phone>`, `Phone number. Format this number with a leading '+' and a country code, e.g., +16175551212.`) - .option(`--password <password>`, `Plain text user password. Must be at least 8 chars.`) - .option(`--name <name>`, `User name. Max length: 128 chars.`) - .action(actionRunner(usersCreate)) - -users - .command(`create-argon-2-user`) - .description(`Create a new user. Password provided must be hashed with the [Argon2](https://en.wikipedia.org/wiki/Argon2) algorithm. Use the [POST /users](https://appwrite.io/docs/server/users#usersCreate) endpoint to create users with a plain text password.`) - .requiredOption(`--user-id <user-id>`, `User ID. Choose a custom ID or generate a random ID with 'ID.unique()'. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.`) - .requiredOption(`--email <email>`, `User email.`) - .requiredOption(`--password <password>`, `User password hashed using Argon2.`) - .option(`--name <name>`, `User name. Max length: 128 chars.`) - .action(actionRunner(usersCreateArgon2User)) - -users - .command(`create-bcrypt-user`) - .description(`Create a new user. Password provided must be hashed with the [Bcrypt](https://en.wikipedia.org/wiki/Bcrypt) algorithm. Use the [POST /users](https://appwrite.io/docs/server/users#usersCreate) endpoint to create users with a plain text password.`) - .requiredOption(`--user-id <user-id>`, `User ID. Choose a custom ID or generate a random ID with 'ID.unique()'. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.`) - .requiredOption(`--email <email>`, `User email.`) - .requiredOption(`--password <password>`, `User password hashed using Bcrypt.`) - .option(`--name <name>`, `User name. Max length: 128 chars.`) - .action(actionRunner(usersCreateBcryptUser)) - -users - .command(`list-identities`) - .description(`Get identities for all users.`) - .option(`--queries [queries...]`, `Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: userId, provider, providerUid, providerEmail, providerAccessTokenExpiry`) - .option(`--search <search>`, `Search term to filter your list results. Max length: 256 chars.`) - .option(`--total [value]`, `When set to false, the total count returned will be 0 and will not be calculated.`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .action(actionRunner(usersListIdentities)) - -users - .command(`delete-identity`) - .description(`Delete an identity by its unique ID.`) - .requiredOption(`--identity-id <identity-id>`, `Identity ID.`) - .action(actionRunner(usersDeleteIdentity)) - -users - .command(`create-md-5-user`) - .description(`Create a new user. Password provided must be hashed with the [MD5](https://en.wikipedia.org/wiki/MD5) algorithm. Use the [POST /users](https://appwrite.io/docs/server/users#usersCreate) endpoint to create users with a plain text password.`) - .requiredOption(`--user-id <user-id>`, `User ID. Choose a custom ID or generate a random ID with 'ID.unique()'. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.`) - .requiredOption(`--email <email>`, `User email.`) - .requiredOption(`--password <password>`, `User password hashed using MD5.`) - .option(`--name <name>`, `User name. Max length: 128 chars.`) - .action(actionRunner(usersCreateMD5User)) - -users - .command(`create-ph-pass-user`) - .description(`Create a new user. Password provided must be hashed with the [PHPass](https://www.openwall.com/phpass/) algorithm. Use the [POST /users](https://appwrite.io/docs/server/users#usersCreate) endpoint to create users with a plain text password.`) - .requiredOption(`--user-id <user-id>`, `User ID. Choose a custom ID or pass the string 'ID.unique()'to auto generate it. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.`) - .requiredOption(`--email <email>`, `User email.`) - .requiredOption(`--password <password>`, `User password hashed using PHPass.`) - .option(`--name <name>`, `User name. Max length: 128 chars.`) - .action(actionRunner(usersCreatePHPassUser)) - -users - .command(`create-scrypt-user`) - .description(`Create a new user. Password provided must be hashed with the [Scrypt](https://github.com/Tarsnap/scrypt) algorithm. Use the [POST /users](https://appwrite.io/docs/server/users#usersCreate) endpoint to create users with a plain text password.`) - .requiredOption(`--user-id <user-id>`, `User ID. Choose a custom ID or generate a random ID with 'ID.unique()'. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.`) - .requiredOption(`--email <email>`, `User email.`) - .requiredOption(`--password <password>`, `User password hashed using Scrypt.`) - .requiredOption(`--password-salt <password-salt>`, `Optional salt used to hash password.`) - .requiredOption(`--password-cpu <password-cpu>`, `Optional CPU cost used to hash password.`, parseInteger) - .requiredOption(`--password-memory <password-memory>`, `Optional memory cost used to hash password.`, parseInteger) - .requiredOption(`--password-parallel <password-parallel>`, `Optional parallelization cost used to hash password.`, parseInteger) - .requiredOption(`--password-length <password-length>`, `Optional hash length used to hash password.`, parseInteger) - .option(`--name <name>`, `User name. Max length: 128 chars.`) - .action(actionRunner(usersCreateScryptUser)) - -users - .command(`create-scrypt-modified-user`) - .description(`Create a new user. Password provided must be hashed with the [Scrypt Modified](https://gist.github.com/Meldiron/eecf84a0225eccb5a378d45bb27462cc) algorithm. Use the [POST /users](https://appwrite.io/docs/server/users#usersCreate) endpoint to create users with a plain text password.`) - .requiredOption(`--user-id <user-id>`, `User ID. Choose a custom ID or generate a random ID with 'ID.unique()'. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.`) - .requiredOption(`--email <email>`, `User email.`) - .requiredOption(`--password <password>`, `User password hashed using Scrypt Modified.`) - .requiredOption(`--password-salt <password-salt>`, `Salt used to hash password.`) - .requiredOption(`--password-salt-separator <password-salt-separator>`, `Salt separator used to hash password.`) - .requiredOption(`--password-signer-key <password-signer-key>`, `Signer key used to hash password.`) - .option(`--name <name>`, `User name. Max length: 128 chars.`) - .action(actionRunner(usersCreateScryptModifiedUser)) - -users - .command(`create-sha-user`) - .description(`Create a new user. Password provided must be hashed with the [SHA](https://en.wikipedia.org/wiki/Secure_Hash_Algorithm) algorithm. Use the [POST /users](https://appwrite.io/docs/server/users#usersCreate) endpoint to create users with a plain text password.`) - .requiredOption(`--user-id <user-id>`, `User ID. Choose a custom ID or generate a random ID with 'ID.unique()'. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.`) - .requiredOption(`--email <email>`, `User email.`) - .requiredOption(`--password <password>`, `User password hashed using SHA.`) - .option(`--password-version <password-version>`, `Optional SHA version used to hash password. Allowed values are: 'sha1', 'sha224', 'sha256', 'sha384', 'sha512/224', 'sha512/256', 'sha512', 'sha3-224', 'sha3-256', 'sha3-384', 'sha3-512'`) - .option(`--name <name>`, `User name. Max length: 128 chars.`) - .action(actionRunner(usersCreateSHAUser)) - -users - .command(`get-usage`) - .description(`Get usage metrics and statistics for all users in the project. You can view the total number of users and sessions. The response includes both current totals and historical data over time. Use the optional range parameter to specify the time window for historical data: 24h (last 24 hours), 30d (last 30 days), or 90d (last 90 days). If not specified, range defaults to 30 days. `) - .option(`--range <range>`, `Date range.`) - .action(actionRunner(usersGetUsage)) - -users - .command(`get`) - .description(`Get a user by its unique ID.`) - .requiredOption(`--user-id <user-id>`, `User ID.`) - .option(`--console`, `Get the resource console url`) - .action(actionRunner(usersGet)) - -users - .command(`delete`) - .description(`Delete a user by its unique ID, thereby releasing it's ID. Since ID is released and can be reused, all user-related resources like documents or storage files should be deleted before user deletion. If you want to keep ID reserved, use the [updateStatus](https://appwrite.io/docs/server/users#usersUpdateStatus) endpoint instead.`) - .requiredOption(`--user-id <user-id>`, `User ID.`) - .action(actionRunner(usersDelete)) - -users - .command(`update-email`) - .description(`Update the user email by its unique ID.`) - .requiredOption(`--user-id <user-id>`, `User ID.`) - .requiredOption(`--email <email>`, `User email.`) - .action(actionRunner(usersUpdateEmail)) - -users - .command(`create-jwt`) - .description(`Use this endpoint to create a JSON Web Token for user by its unique ID. You can use the resulting JWT to authenticate on behalf of the user. The JWT secret will become invalid if the session it uses gets deleted.`) - .requiredOption(`--user-id <user-id>`, `User ID.`) - .option(`--session-id <session-id>`, `Session ID. Use the string 'recent' to use the most recent session. Defaults to the most recent session.`) - .option(`--duration <duration>`, `Time in seconds before JWT expires. Default duration is 900 seconds, and maximum is 3600 seconds.`, parseInteger) - .action(actionRunner(usersCreateJWT)) - -users - .command(`update-labels`) - .description(`Update the user labels by its unique ID. Labels can be used to grant access to resources. While teams are a way for user's to share access to a resource, labels can be defined by the developer to grant access without an invitation. See the [Permissions docs](https://appwrite.io/docs/permissions) for more info.`) - .requiredOption(`--user-id <user-id>`, `User ID.`) - .requiredOption(`--labels [labels...]`, `Array of user labels. Replaces the previous labels. Maximum of 1000 labels are allowed, each up to 36 alphanumeric characters long.`) - .action(actionRunner(usersUpdateLabels)) - -users - .command(`list-logs`) - .description(`Get the user activity logs list by its unique ID.`) - .requiredOption(`--user-id <user-id>`, `User ID.`) - .option(`--queries [queries...]`, `Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Only supported methods are limit and offset`) - .option(`--total [value]`, `When set to false, the total count returned will be 0 and will not be calculated.`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .action(actionRunner(usersListLogs)) - -users - .command(`list-memberships`) - .description(`Get the user membership list by its unique ID.`) - .requiredOption(`--user-id <user-id>`, `User ID.`) - .option(`--queries [queries...]`, `Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: userId, teamId, invited, joined, confirm, roles`) - .option(`--search <search>`, `Search term to filter your list results. Max length: 256 chars.`) - .option(`--total [value]`, `When set to false, the total count returned will be 0 and will not be calculated.`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .action(actionRunner(usersListMemberships)) - -users - .command(`update-mfa`) - .description(`Enable or disable MFA on a user account.`) - .requiredOption(`--user-id <user-id>`, `User ID.`) - .requiredOption(`--mfa [value]`, `Enable or disable MFA.`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .action(actionRunner(usersUpdateMFA)) - -users - .command(`delete-mfa-authenticator`) - .description(`Delete an authenticator app.`) - .requiredOption(`--user-id <user-id>`, `User ID.`) - .requiredOption(`--type <type>`, `Type of authenticator.`) - .action(actionRunner(usersDeleteMFAAuthenticator)) - -users - .command(`list-mfa-factors`) - .description(`List the factors available on the account to be used as a MFA challange.`) - .requiredOption(`--user-id <user-id>`, `User ID.`) - .action(actionRunner(usersListMFAFactors)) - -users - .command(`get-mfa-recovery-codes`) - .description(`Get recovery codes that can be used as backup for MFA flow by User ID. Before getting codes, they must be generated using [createMfaRecoveryCodes](/docs/references/cloud/client-web/account#createMfaRecoveryCodes) method.`) - .requiredOption(`--user-id <user-id>`, `User ID.`) - .action(actionRunner(usersGetMFARecoveryCodes)) - -users - .command(`update-mfa-recovery-codes`) - .description(`Regenerate recovery codes that can be used as backup for MFA flow by User ID. Before regenerating codes, they must be first generated using [createMfaRecoveryCodes](/docs/references/cloud/client-web/account#createMfaRecoveryCodes) method.`) - .requiredOption(`--user-id <user-id>`, `User ID.`) - .action(actionRunner(usersUpdateMFARecoveryCodes)) - -users - .command(`create-mfa-recovery-codes`) - .description(`Generate recovery codes used as backup for MFA flow for User ID. Recovery codes can be used as a MFA verification type in [createMfaChallenge](/docs/references/cloud/client-web/account#createMfaChallenge) method by client SDK.`) - .requiredOption(`--user-id <user-id>`, `User ID.`) - .action(actionRunner(usersCreateMFARecoveryCodes)) - -users - .command(`update-name`) - .description(`Update the user name by its unique ID.`) - .requiredOption(`--user-id <user-id>`, `User ID.`) - .requiredOption(`--name <name>`, `User name. Max length: 128 chars.`) - .action(actionRunner(usersUpdateName)) - -users - .command(`update-password`) - .description(`Update the user password by its unique ID.`) - .requiredOption(`--user-id <user-id>`, `User ID.`) - .requiredOption(`--password <password>`, `New user password. Must be at least 8 chars.`) - .action(actionRunner(usersUpdatePassword)) - -users - .command(`update-phone`) - .description(`Update the user phone by its unique ID.`) - .requiredOption(`--user-id <user-id>`, `User ID.`) - .requiredOption(`--number <number>`, `User phone number.`) - .action(actionRunner(usersUpdatePhone)) - -users - .command(`get-prefs`) - .description(`Get the user preferences by its unique ID.`) - .requiredOption(`--user-id <user-id>`, `User ID.`) - .action(actionRunner(usersGetPrefs)) - -users - .command(`update-prefs`) - .description(`Update the user preferences by its unique ID. The object you pass is stored as is, and replaces any previous value. The maximum allowed prefs size is 64kB and throws error if exceeded.`) - .requiredOption(`--user-id <user-id>`, `User ID.`) - .requiredOption(`--prefs <prefs>`, `Prefs key-value JSON object.`) - .action(actionRunner(usersUpdatePrefs)) - -users - .command(`list-sessions`) - .description(`Get the user sessions list by its unique ID.`) - .requiredOption(`--user-id <user-id>`, `User ID.`) - .option(`--total [value]`, `When set to false, the total count returned will be 0 and will not be calculated.`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .option(`--console`, `Get the resource console url`) - .action(actionRunner(usersListSessions)) - -users - .command(`create-session`) - .description(`Creates a session for a user. Returns an immediately usable session object. If you want to generate a token for a custom authentication flow, use the [POST /users/{userId}/tokens](https://appwrite.io/docs/server/users#createToken) endpoint.`) - .requiredOption(`--user-id <user-id>`, `User ID. Choose a custom ID or generate a random ID with 'ID.unique()'. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.`) - .action(actionRunner(usersCreateSession)) - -users - .command(`delete-sessions`) - .description(`Delete all user's sessions by using the user's unique ID.`) - .requiredOption(`--user-id <user-id>`, `User ID.`) - .action(actionRunner(usersDeleteSessions)) - -users - .command(`delete-session`) - .description(`Delete a user sessions by its unique ID.`) - .requiredOption(`--user-id <user-id>`, `User ID.`) - .requiredOption(`--session-id <session-id>`, `Session ID.`) - .action(actionRunner(usersDeleteSession)) - -users - .command(`update-status`) - .description(`Update the user status by its unique ID. Use this endpoint as an alternative to deleting a user if you want to keep user's ID reserved.`) - .requiredOption(`--user-id <user-id>`, `User ID.`) - .requiredOption(`--status [value]`, `User Status. To activate the user pass 'true' and to block the user pass 'false'.`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .action(actionRunner(usersUpdateStatus)) - -users - .command(`list-targets`) - .description(`List the messaging targets that are associated with a user.`) - .requiredOption(`--user-id <user-id>`, `User ID.`) - .option(`--queries [queries...]`, `Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: userId, providerId, identifier, providerType`) - .option(`--total [value]`, `When set to false, the total count returned will be 0 and will not be calculated.`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .action(actionRunner(usersListTargets)) - -users - .command(`create-target`) - .description(`Create a messaging target.`) - .requiredOption(`--user-id <user-id>`, `User ID.`) - .requiredOption(`--target-id <target-id>`, `Target ID. Choose a custom ID or generate a random ID with 'ID.unique()'. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars.`) - .requiredOption(`--provider-type <provider-type>`, `The target provider type. Can be one of the following: 'email', 'sms' or 'push'.`) - .requiredOption(`--identifier <identifier>`, `The target identifier (token, email, phone etc.)`) - .option(`--provider-id <provider-id>`, `Provider ID. Message will be sent to this target from the specified provider ID. If no provider ID is set the first setup provider will be used.`) - .option(`--name <name>`, `Target name. Max length: 128 chars. For example: My Awesome App Galaxy S23.`) - .action(actionRunner(usersCreateTarget)) - -users - .command(`get-target`) - .description(`Get a user's push notification target by ID.`) - .requiredOption(`--user-id <user-id>`, `User ID.`) - .requiredOption(`--target-id <target-id>`, `Target ID.`) - .action(actionRunner(usersGetTarget)) - -users - .command(`update-target`) - .description(`Update a messaging target.`) - .requiredOption(`--user-id <user-id>`, `User ID.`) - .requiredOption(`--target-id <target-id>`, `Target ID.`) - .option(`--identifier <identifier>`, `The target identifier (token, email, phone etc.)`) - .option(`--provider-id <provider-id>`, `Provider ID. Message will be sent to this target from the specified provider ID. If no provider ID is set the first setup provider will be used.`) - .option(`--name <name>`, `Target name. Max length: 128 chars. For example: My Awesome App Galaxy S23.`) - .action(actionRunner(usersUpdateTarget)) - -users - .command(`delete-target`) - .description(`Delete a messaging target.`) - .requiredOption(`--user-id <user-id>`, `User ID.`) - .requiredOption(`--target-id <target-id>`, `Target ID.`) - .action(actionRunner(usersDeleteTarget)) - -users - .command(`create-token`) - .description(`Returns a token with a secret key for creating a session. Use the user ID and secret and submit a request to the [PUT /account/sessions/token](https://appwrite.io/docs/references/cloud/client-web/account#createSession) endpoint to complete the login process. `) - .requiredOption(`--user-id <user-id>`, `User ID.`) - .option(`--length <length>`, `Token length in characters. The default length is 6 characters`, parseInteger) - .option(`--expire <expire>`, `Token expiration period in seconds. The default expiration is 15 minutes.`, parseInteger) - .action(actionRunner(usersCreateToken)) - -users - .command(`update-email-verification`) - .description(`Update the user email verification status by its unique ID.`) - .requiredOption(`--user-id <user-id>`, `User ID.`) - .requiredOption(`--email-verification [value]`, `User email verification status.`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .action(actionRunner(usersUpdateEmailVerification)) - -users - .command(`update-phone-verification`) - .description(`Update the user phone verification status by its unique ID.`) - .requiredOption(`--user-id <user-id>`, `User ID.`) - .requiredOption(`--phone-verification [value]`, `User phone verification status.`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .action(actionRunner(usersUpdatePhoneVerification)) - - diff --git a/lib/commands/vcs.ts b/lib/commands/vcs.ts deleted file mode 100644 index 7b5de57d..00000000 --- a/lib/commands/vcs.ts +++ /dev/null @@ -1,428 +0,0 @@ -import fs = require('fs'); -import pathLib = require('path'); -import tar = require('tar'); -import ignore = require('ignore'); -import { promisify } from 'util'; -import Client from '../client'; -import { getAllFiles, showConsoleLink } from '../utils'; -import { Command } from 'commander'; -import { sdkForProject, sdkForConsole } from '../sdks'; -import { parse, actionRunner, parseInteger, parseBool, commandDescriptions, success, log, warn } from '../parser'; -import { localConfig, globalConfig } from '../config'; -import { File } from 'undici'; -import { ReadableStream } from 'stream/web'; - -function convertReadStreamToReadableStream(readStream: fs.ReadStream): ReadableStream { - return new ReadableStream({ - start(controller) { - readStream.on("data", (chunk: Buffer) => { - controller.enqueue(chunk); - }); - readStream.on("end", () => { - controller.close(); - }); - readStream.on("error", (err: Error) => { - controller.error(err); - }); - }, - cancel() { - readStream.destroy(); - }, - }); -} - -export const vcs = new Command("vcs").description(commandDescriptions['vcs'] ?? '').configureHelp({ - helpWidth: process.stdout.columns || 80 -}) - -interface VcsCreateRepositoryDetectionRequestParams { - installationId: string; - providerRepositoryId: string; - type: VCSDetectionType; - providerRootDirectory?: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const vcsCreateRepositoryDetection = async ({installationId,providerRepositoryId,type,providerRootDirectory,parseOutput = true, overrideForCli = false, sdk = undefined}: VcsCreateRepositoryDetectionRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/vcs/github/installations/{installationId}/detections'.replace('{installationId}', installationId); - let payload = {}; - if (typeof providerRepositoryId !== 'undefined') { - payload['providerRepositoryId'] = providerRepositoryId; - } - if (typeof type !== 'undefined') { - payload['type'] = type; - } - if (typeof providerRootDirectory !== 'undefined') { - payload['providerRootDirectory'] = providerRootDirectory; - } - - let response = undefined; - - response = await client.call('post', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface VcsListRepositoriesRequestParams { - installationId: string; - type: VCSDetectionType; - search?: string; - queries?: string[]; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const vcsListRepositories = async ({installationId,type,search,queries,parseOutput = true, overrideForCli = false, sdk = undefined}: VcsListRepositoriesRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/vcs/github/installations/{installationId}/providerRepositories'.replace('{installationId}', installationId); - let payload = {}; - if (typeof type !== 'undefined') { - payload['type'] = type; - } - if (typeof search !== 'undefined') { - payload['search'] = search; - } - if (typeof queries !== 'undefined') { - payload['queries'] = queries; - } - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface VcsCreateRepositoryRequestParams { - installationId: string; - name: string; - xprivate: boolean; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const vcsCreateRepository = async ({installationId,name,xprivate,parseOutput = true, overrideForCli = false, sdk = undefined}: VcsCreateRepositoryRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/vcs/github/installations/{installationId}/providerRepositories'.replace('{installationId}', installationId); - let payload = {}; - if (typeof name !== 'undefined') { - payload['name'] = name; - } - if (typeof xprivate !== 'undefined') { - payload['private'] = xprivate; - } - - let response = undefined; - - response = await client.call('post', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface VcsGetRepositoryRequestParams { - installationId: string; - providerRepositoryId: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const vcsGetRepository = async ({installationId,providerRepositoryId,parseOutput = true, overrideForCli = false, sdk = undefined}: VcsGetRepositoryRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/vcs/github/installations/{installationId}/providerRepositories/{providerRepositoryId}'.replace('{installationId}', installationId).replace('{providerRepositoryId}', providerRepositoryId); - let payload = {}; - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface VcsListRepositoryBranchesRequestParams { - installationId: string; - providerRepositoryId: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const vcsListRepositoryBranches = async ({installationId,providerRepositoryId,parseOutput = true, overrideForCli = false, sdk = undefined}: VcsListRepositoryBranchesRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/vcs/github/installations/{installationId}/providerRepositories/{providerRepositoryId}/branches'.replace('{installationId}', installationId).replace('{providerRepositoryId}', providerRepositoryId); - let payload = {}; - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface VcsGetRepositoryContentsRequestParams { - installationId: string; - providerRepositoryId: string; - providerRootDirectory?: string; - providerReference?: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const vcsGetRepositoryContents = async ({installationId,providerRepositoryId,providerRootDirectory,providerReference,parseOutput = true, overrideForCli = false, sdk = undefined}: VcsGetRepositoryContentsRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/vcs/github/installations/{installationId}/providerRepositories/{providerRepositoryId}/contents'.replace('{installationId}', installationId).replace('{providerRepositoryId}', providerRepositoryId); - let payload = {}; - if (typeof providerRootDirectory !== 'undefined') { - payload['providerRootDirectory'] = providerRootDirectory; - } - if (typeof providerReference !== 'undefined') { - payload['providerReference'] = providerReference; - } - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface VcsUpdateExternalDeploymentsRequestParams { - installationId: string; - repositoryId: string; - providerPullRequestId: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const vcsUpdateExternalDeployments = async ({installationId,repositoryId,providerPullRequestId,parseOutput = true, overrideForCli = false, sdk = undefined}: VcsUpdateExternalDeploymentsRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/vcs/github/installations/{installationId}/repositories/{repositoryId}'.replace('{installationId}', installationId).replace('{repositoryId}', repositoryId); - let payload = {}; - if (typeof providerPullRequestId !== 'undefined') { - payload['providerPullRequestId'] = providerPullRequestId; - } - - let response = undefined; - - response = await client.call('patch', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface VcsListInstallationsRequestParams { - queries?: string[]; - search?: string; - total?: boolean; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const vcsListInstallations = async ({queries,search,total,parseOutput = true, overrideForCli = false, sdk = undefined}: VcsListInstallationsRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/vcs/installations'; - let payload = {}; - if (typeof queries !== 'undefined') { - payload['queries'] = queries; - } - if (typeof search !== 'undefined') { - payload['search'] = search; - } - if (typeof total !== 'undefined') { - payload['total'] = total; - } - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface VcsGetInstallationRequestParams { - installationId: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const vcsGetInstallation = async ({installationId,parseOutput = true, overrideForCli = false, sdk = undefined}: VcsGetInstallationRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/vcs/installations/{installationId}'.replace('{installationId}', installationId); - let payload = {}; - - let response = undefined; - - response = await client.call('get', apiPath, { - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -interface VcsDeleteInstallationRequestParams { - installationId: string; - overrideForCli?: boolean; - parseOutput?: boolean; - sdk?: Client; -} - -export const vcsDeleteInstallation = async ({installationId,parseOutput = true, overrideForCli = false, sdk = undefined}: VcsDeleteInstallationRequestParams): Promise<any> => { - let client = !sdk ? await sdkForProject() : - sdk; - let apiPath = '/vcs/installations/{installationId}'.replace('{installationId}', installationId); - let payload = {}; - - let response = undefined; - - response = await client.call('delete', apiPath, { - 'content-type': 'application/json', - }, payload); - - if (parseOutput) { - parse(response) - } - - return response; - -} -vcs - .command(`create-repository-detection`) - .description(`Analyze a GitHub repository to automatically detect the programming language and runtime environment. This endpoint scans the repository's files and language statistics to determine the appropriate runtime settings for your function. The GitHub installation must be properly configured and the repository must be accessible through your installation for this endpoint to work.`) - .requiredOption(`--installation-id <installation-id>`, `Installation Id`) - .requiredOption(`--provider-repository-id <provider-repository-id>`, `Repository Id`) - .requiredOption(`--type <type>`, `Detector type. Must be one of the following: runtime, framework`) - .option(`--provider-root-directory <provider-root-directory>`, `Path to Root Directory`) - .action(actionRunner(vcsCreateRepositoryDetection)) - -vcs - .command(`list-repositories`) - .description(`Get a list of GitHub repositories available through your installation. This endpoint returns repositories with their basic information, detected runtime environments, and latest push dates. You can optionally filter repositories using a search term. Each repository's runtime is automatically detected based on its contents and language statistics. The GitHub installation must be properly configured for this endpoint to work.`) - .requiredOption(`--installation-id <installation-id>`, `Installation Id`) - .requiredOption(`--type <type>`, `Detector type. Must be one of the following: runtime, framework`) - .option(`--search <search>`, `Search term to filter your list results. Max length: 256 chars.`) - .option(`--queries [queries...]`, `Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Only supported methods are limit and offset`) - .action(actionRunner(vcsListRepositories)) - -vcs - .command(`create-repository`) - .description(`Create a new GitHub repository through your installation. This endpoint allows you to create either a public or private repository by specifying a name and visibility setting. The repository will be created under your GitHub user account or organization, depending on your installation type. The GitHub installation must be properly configured and have the necessary permissions for repository creation.`) - .requiredOption(`--installation-id <installation-id>`, `Installation Id`) - .requiredOption(`--name <name>`, `Repository name (slug)`) - .requiredOption(`--xprivate [value]`, `Mark repository public or private`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .action(actionRunner(vcsCreateRepository)) - -vcs - .command(`get-repository`) - .description(`Get detailed information about a specific GitHub repository from your installation. This endpoint returns repository details including its ID, name, visibility status, organization, and latest push date. The GitHub installation must be properly configured and have access to the requested repository for this endpoint to work.`) - .requiredOption(`--installation-id <installation-id>`, `Installation Id`) - .requiredOption(`--provider-repository-id <provider-repository-id>`, `Repository Id`) - .action(actionRunner(vcsGetRepository)) - -vcs - .command(`list-repository-branches`) - .description(`Get a list of all branches from a GitHub repository in your installation. This endpoint returns the names of all branches in the repository and their total count. The GitHub installation must be properly configured and have access to the requested repository for this endpoint to work. `) - .requiredOption(`--installation-id <installation-id>`, `Installation Id`) - .requiredOption(`--provider-repository-id <provider-repository-id>`, `Repository Id`) - .action(actionRunner(vcsListRepositoryBranches)) - -vcs - .command(`get-repository-contents`) - .description(`Get a list of files and directories from a GitHub repository connected to your project. This endpoint returns the contents of a specified repository path, including file names, sizes, and whether each item is a file or directory. The GitHub installation must be properly configured and the repository must be accessible through your installation for this endpoint to work.`) - .requiredOption(`--installation-id <installation-id>`, `Installation Id`) - .requiredOption(`--provider-repository-id <provider-repository-id>`, `Repository Id`) - .option(`--provider-root-directory <provider-root-directory>`, `Path to get contents of nested directory`) - .option(`--provider-reference <provider-reference>`, `Git reference (branch, tag, commit) to get contents from`) - .action(actionRunner(vcsGetRepositoryContents)) - -vcs - .command(`update-external-deployments`) - .description(`Authorize and create deployments for a GitHub pull request in your project. This endpoint allows external contributions by creating deployments from pull requests, enabling preview environments for code review. The pull request must be open and not previously authorized. The GitHub installation must be properly configured and have access to both the repository and pull request for this endpoint to work.`) - .requiredOption(`--installation-id <installation-id>`, `Installation Id`) - .requiredOption(`--repository-id <repository-id>`, `VCS Repository Id`) - .requiredOption(`--provider-pull-request-id <provider-pull-request-id>`, `GitHub Pull Request Id`) - .action(actionRunner(vcsUpdateExternalDeployments)) - -vcs - .command(`list-installations`) - .description(`List all VCS installations configured for the current project. This endpoint returns a list of installations including their provider, organization, and other configuration details. `) - .option(`--queries [queries...]`, `Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: provider, organization`) - .option(`--search <search>`, `Search term to filter your list results. Max length: 256 chars.`) - .option(`--total [value]`, `When set to false, the total count returned will be 0 and will not be calculated.`, (value: string | undefined) => value === undefined ? true : parseBool(value)) - .action(actionRunner(vcsListInstallations)) - -vcs - .command(`get-installation`) - .description(`Get a VCS installation by its unique ID. This endpoint returns the installation's details including its provider, organization, and configuration. `) - .requiredOption(`--installation-id <installation-id>`, `Installation Id`) - .action(actionRunner(vcsGetInstallation)) - -vcs - .command(`delete-installation`) - .description(`Delete a VCS installation by its unique ID. This endpoint removes the installation and all its associated repositories from the project.`) - .requiredOption(`--installation-id <installation-id>`, `Installation Id`) - .action(actionRunner(vcsDeleteInstallation)) - - diff --git a/lib/config.ts b/lib/config.ts index c076c557..b2bf54b7 100644 --- a/lib/config.ts +++ b/lib/config.ts @@ -1,854 +1,969 @@ -import os = require('os'); -import fs = require('fs'); -import _path = require('path'); -import process = require('process'); -import JSONbig = require('json-bigint'); -import type { ConfigData, SessionData, GlobalConfigData, ProjectConfigData } from './types'; +import os from "os"; +import fs from "fs"; +import _path from "path"; +import process from "process"; +import JSONbig from "json-bigint"; +import type { + BucketConfig, + CollectionConfig, + ConfigData, + Entity, + FunctionConfig, + GlobalConfigData, + ProjectConfigData, + ProjectSettings, + RawProjectSettings, + SessionData, + SiteConfig, + TableConfig, + TeamConfig, + TopicConfig, +} from "./types.js"; const JSONBigInt = JSONbig({ storeAsString: false }); -const KeysVars = new Set(['key', 'value']); -const KeysSite = new Set(['path', '$id', 'name', 'enabled', 'logging', 'timeout', 'framework', 'buildRuntime', 'adapter', 'installCommand', 'buildCommand', 'outputDirectory', 'fallbackFile', 'specification', 'vars']); -const KeysFunction = new Set(['path', '$id', 'execute', 'name', 'enabled', 'logging', 'runtime', 'specification', 'scopes', 'events', 'schedule', 'timeout', 'entrypoint', 'commands', 'vars']); -const KeysDatabase = new Set(['$id', 'name', 'enabled']); -const KeysCollection = new Set(['$id', '$permissions', 'databaseId', 'name', 'enabled', 'documentSecurity', 'attributes', 'indexes']); -const KeysTable = new Set(['$id', '$permissions', 'databaseId', 'name', 'enabled', 'rowSecurity', 'columns', 'indexes']); -const KeysStorage = new Set(['$id', '$permissions', 'fileSecurity', 'name', 'enabled', 'maximumFileSize', 'allowedFileExtensions', 'compression', 'encryption', 'antivirus']); -const KeysTopics = new Set(['$id', 'name', 'subscribe']); -const KeysTeams = new Set(['$id', 'name']); +const KeysVars = new Set(["key", "value"]); +const KeysSite = new Set([ + "path", + "$id", + "name", + "enabled", + "logging", + "timeout", + "framework", + "buildRuntime", + "adapter", + "installCommand", + "buildCommand", + "outputDirectory", + "fallbackFile", + "specification", + "vars", +]); +const KeysFunction = new Set([ + "path", + "$id", + "execute", + "name", + "enabled", + "logging", + "runtime", + "specification", + "scopes", + "events", + "schedule", + "timeout", + "entrypoint", + "commands", + "vars", +]); +const KeysDatabase = new Set(["$id", "name", "enabled"]); +const KeysCollection = new Set([ + "$id", + "$permissions", + "databaseId", + "name", + "enabled", + "documentSecurity", + "attributes", + "indexes", +]); +const KeysTable = new Set([ + "$id", + "$permissions", + "databaseId", + "name", + "enabled", + "rowSecurity", + "columns", + "indexes", +]); +const KeysStorage = new Set([ + "$id", + "$permissions", + "fileSecurity", + "name", + "enabled", + "maximumFileSize", + "allowedFileExtensions", + "compression", + "encryption", + "antivirus", +]); +const KeysTopics = new Set(["$id", "name", "subscribe"]); +const KeysTeams = new Set(["$id", "name"]); const KeysAttributes = new Set([ - 'key', - 'type', - 'required', - 'array', - 'size', - 'default', - // integer and float - 'min', - 'max', - // email, enum, URL, IP, and datetime - 'format', - // enum - 'elements', - // relationship - 'relatedCollection', - 'relationType', - 'twoWay', - 'twoWayKey', - 'onDelete', - 'side', - // Indexes - 'attributes', - 'orders', - // Strings - 'encrypt', + "key", + "type", + "required", + "array", + "size", + "default", + // integer and float + "min", + "max", + // email, enum, URL, IP, and datetime + "format", + // enum + "elements", + // relationship + "relatedCollection", + "relationType", + "twoWay", + "twoWayKey", + "onDelete", + "side", + // Indexes + "attributes", + "orders", + // Strings + "encrypt", ]); const KeysColumns = new Set([ - 'key', - 'type', - 'required', - 'array', - 'size', - 'default', - // integer and float - 'min', - 'max', - // email, enum, URL, IP, and datetime - 'format', - // enum - 'elements', - // relationship - 'relatedTable', - 'relationType', - 'twoWay', - 'twoWayKey', - 'onDelete', - 'side', - // Indexes - 'columns', - 'orders', - // Strings - 'encrypt', + "key", + "type", + "required", + "array", + "size", + "default", + // integer and float + "min", + "max", + // email, enum, URL, IP, and datetime + "format", + // enum + "elements", + // relationship + "relatedTable", + "relationType", + "twoWay", + "twoWayKey", + "onDelete", + "side", + // Indexes + "columns", + "orders", + // Strings + "encrypt", +]); +const KeyIndexes = new Set(["key", "type", "status", "attributes", "orders"]); +const KeyIndexesColumns = new Set([ + "key", + "type", + "status", + "columns", + "orders", ]); -const KeyIndexes = new Set(['key', 'type', 'status', 'attributes', 'orders']); -const KeyIndexesColumns = new Set(['key', 'type', 'status', 'columns', 'orders']); function whitelistKeys<T = any>( - value: T, - keys: Set<string>, - nestedKeys: Record<string, Set<string>> = {} + value: T, + keys: Set<string>, + nestedKeys: Record<string, Set<string>> = {}, ): T { - if (Array.isArray(value)) { - const newValue: any[] = []; + if (Array.isArray(value)) { + const newValue: any[] = []; - for (const item of value) { - newValue.push(whitelistKeys(item, keys, nestedKeys)); - } - - return newValue as T; + for (const item of value) { + newValue.push(whitelistKeys(item, keys, nestedKeys)); } - const newValue: Record<string, any> = {}; - Object.keys(value as any).forEach((key) => { - if (keys.has(key)) { - if (nestedKeys[key]) { - newValue[key] = whitelistKeys((value as any)[key], nestedKeys[key]); - } else { - newValue[key] = (value as any)[key]; - } - } - }); return newValue as T; + } + + const newValue: Record<string, any> = {}; + Object.keys(value as any).forEach((key) => { + if (keys.has(key)) { + if (nestedKeys[key]) { + newValue[key] = whitelistKeys((value as any)[key], nestedKeys[key]); + } else { + newValue[key] = (value as any)[key]; + } + } + }); + return newValue as T; } class Config<T extends ConfigData = ConfigData> { - protected path: string; - protected data: T; + readonly path: string; + protected data: T; + + constructor(path: string) { + this.path = path; + this.data = {} as T; + this.read(); + } + + read(): void { + try { + const file = fs.readFileSync(this.path).toString(); + this.data = JSONBigInt.parse(file); + } catch (e) { + this.data = {} as T; + } + } + + write(): void { + const dir = _path.dirname(this.path); + if (!fs.existsSync(dir)) { + fs.mkdirSync(dir, { recursive: true }); + } + fs.writeFileSync(this.path, JSONBigInt.stringify(this.data, null, 4), { + mode: 0o600, + }); + } + + get<K extends keyof T>(key: K): T[K]; + get(key: string): any { + return this.data[key as keyof T]; + } + + set<K extends keyof T>(key: K, value: T[K]): void; + set(key: string, value: any): void { + (this.data as any)[key] = value; + this.write(); + } + + delete(key: string): void { + delete (this.data as any)[key]; + this.write(); + } + + clear(): void { + this.data = {} as T; + this.write(); + } + + has(key: string): boolean { + return this.data[key as keyof T] !== undefined; + } + + keys(): string[] { + return Object.keys(this.data); + } + + values(): unknown[] { + return Object.values(this.data); + } + + toString(): string { + return JSONBigInt.stringify(this.data, null, 4); + } + + protected _getDBEntities(entityType: string): Entity[] { + if (!this.has(entityType)) { + return []; + } + return this.get(entityType) as Entity[]; + } + + protected _getDBEntity( + entityType: string, + $id: string, + ): Entity | Record<string, never> { + if (!this.has(entityType)) { + return {}; + } + + const entities = this.get(entityType) as Entity[]; + for (let i = 0; i < entities.length; i++) { + if (entities[i]["$id"] == $id) { + return entities[i]; + } + } + + return {}; + } + + protected _addDBEntity( + entityType: string, + props: Entity, + keysSet: Set<string>, + nestedKeys: Record<string, Set<string>> = {}, + ): void { + props = whitelistKeys(props, keysSet, nestedKeys); + + if (!this.has(entityType)) { + (this.set as (key: string, value: Entity[]) => void)(entityType, []); + } + + const entities = this.get(entityType) as Entity[]; + for (let i = 0; i < entities.length; i++) { + if (entities[i]["$id"] == props["$id"]) { + entities[i] = props; + (this.set as (key: string, value: Entity[]) => void)( + entityType, + entities, + ); + return; + } + } + entities.push(props); + (this.set as (key: string, value: Entity[]) => void)(entityType, entities); + } +} - constructor(path: string) { - this.path = path; - this.data = {} as T; - this.read(); - } +class Local extends Config<ProjectConfigData> { + static CONFIG_FILE_PATH = "appwrite.config.json"; + static CONFIG_FILE_PATH_LEGACY = "appwrite.json"; + configDirectoryPath = ""; - read(): void { - try { - const file = fs.readFileSync(this.path).toString(); - this.data = JSONBigInt.parse(file); - } catch (e) { - this.data = {} as T; - } - } + constructor( + path: string = Local.CONFIG_FILE_PATH, + legacyPath: string = Local.CONFIG_FILE_PATH_LEGACY, + ) { + let absolutePath = + Local.findConfigFile(path) || Local.findConfigFile(legacyPath); - write(): void { - const dir = _path.dirname(this.path); - if (!fs.existsSync(dir)) { - fs.mkdirSync(dir, { recursive: true }); - } - fs.writeFileSync(this.path, JSONBigInt.stringify(this.data, null, 4), { mode: 0o600 }); + if (!absolutePath) { + absolutePath = `${process.cwd()}/${path}`; } - get<K extends keyof T>(key: K): T[K]; - get(key: string): any { - return this.data[key as keyof T]; - } + super(absolutePath); + this.configDirectoryPath = _path.dirname(absolutePath); + } - set<K extends keyof T>(key: K, value: T[K]): void; - set(key: string, value: any): void { - (this.data as any)[key] = value; - this.write(); - } + static findConfigFile(filename: string): string | null { + let currentPath = process.cwd(); - delete(key: string): void { - delete (this.data as any)[key]; - this.write(); - } + while (true) { + const filePath = `${currentPath}/${filename}`; - clear(): void { - this.data = {} as T; - this.write(); - } + if (fs.existsSync(filePath)) { + return filePath; + } - has(key: string): boolean { - return this.data[key as keyof T] !== undefined; + const parentDirectory = _path.dirname(currentPath); + if (parentDirectory === currentPath) { + break; + } + currentPath = parentDirectory; } - keys(): string[] { - return Object.keys(this.data); - } + return null; + } - values(): unknown[] { - return Object.values(this.data); - } + getDirname(): string { + return _path.dirname(this.path); + } - toString(): string { - return JSONBigInt.stringify(this.data, null, 4); - } + getEndpoint(): string { + return (this.get("endpoint" as keyof ProjectConfigData) as string) || ""; + } - protected _getDBEntities(entityType: string): any[] { - if (!this.has(entityType)) { - return []; - } - return this.get(entityType); - } + setEndpoint(endpoint: string): void { + this.set("endpoint" as any, endpoint); + } - protected _getDBEntity(entityType: string, $id: string): any { - if (!this.has(entityType)) { - return {}; - } - - const entities = this.get(entityType); - for (let i = 0; i < entities.length; i++) { - if (entities[i]['$id'] == $id) { - return entities[i]; - } - } - - return {}; + getSites(): SiteConfig[] { + if (!this.has("sites")) { + return []; } + return this.get("sites") ?? []; + } - protected _addDBEntity( - entityType: string, - props: any, - keysSet: Set<string>, - nestedKeys: Record<string, Set<string>> = {} - ): void { - props = whitelistKeys(props, keysSet, nestedKeys); - - if (!this.has(entityType)) { - this.set(entityType, []); - } - - const entities = this.get(entityType); - for (let i = 0; i < entities.length; i++) { - if (entities[i]['$id'] == props['$id']) { - entities[i] = props; - this.set(entityType, entities); - return; - } - } - entities.push(props); - this.set(entityType, entities); + getSite($id: string): SiteConfig | Record<string, never> { + if (!this.has("sites")) { + return {}; } -} -class Local extends Config<ProjectConfigData> { - static CONFIG_FILE_PATH = 'appwrite.config.json'; - static CONFIG_FILE_PATH_LEGACY = 'appwrite.json'; - configDirectoryPath = ''; - - constructor(path: string = Local.CONFIG_FILE_PATH, legacyPath: string = Local.CONFIG_FILE_PATH_LEGACY) { - let absolutePath = Local.findConfigFile(path) || Local.findConfigFile(legacyPath); - - if (!absolutePath) { - absolutePath = `${process.cwd()}/${path}`; - } - - super(absolutePath); - this.configDirectoryPath = _path.dirname(absolutePath); + const sites = this.get("sites") ?? []; + for (let i = 0; i < sites.length; i++) { + if (sites[i]["$id"] == $id) { + return sites[i]; + } } - static findConfigFile(filename: string): string | null { - let currentPath = process.cwd(); - - while (true) { - const filePath = `${currentPath}/${filename}`; + return {}; + } - if (fs.existsSync(filePath)) { - return filePath; - } - - const parentDirectory = _path.dirname(currentPath); - if (parentDirectory === currentPath) { - break; - } - currentPath = parentDirectory; - } + addSite(props: SiteConfig): void { + props = whitelistKeys(props, KeysSite, { + vars: KeysVars, + }); - return null; + if (!this.has("sites")) { + this.set("sites", []); } - getDirname(): string { - return _path.dirname(this.path); + const sites = this.get("sites") ?? []; + for (let i = 0; i < sites.length; i++) { + if (sites[i]["$id"] == props["$id"]) { + sites[i] = { + ...sites[i], + ...props, + }; + this.set("sites", sites); + return; + } } - getEndpoint(): string { - return this.get('endpoint' as any) || ''; - } + sites.push(props); + this.set("sites", sites); + } - setEndpoint(endpoint: string): void { - this.set('endpoint' as any, endpoint); + getFunctions(): FunctionConfig[] { + if (!this.has("functions")) { + return []; } + return this.get("functions") ?? []; + } - getSites(): any[] { - if (!this.has('sites')) { - return []; - } - return this.get('sites' as any); + getFunction($id: string): FunctionConfig | Record<string, never> { + if (!this.has("functions")) { + return {}; } - getSite($id: string): any { - if (!this.has('sites')) { - return {}; - } - - const sites = this.get('sites' as any); - for (let i = 0; i < sites.length; i++) { - if (sites[i]['$id'] == $id) { - return sites[i]; - } - } - - return {}; + const functions = this.get("functions") ?? []; + for (let i = 0; i < functions.length; i++) { + if (functions[i]["$id"] == $id) { + return functions[i]; + } } - addSite(props: any): void { - props = whitelistKeys(props, KeysSite, { - vars: KeysVars, - }); - - if (!this.has('sites')) { - this.set('sites' as any, []); - } + return {}; + } - const sites = this.get('sites' as any); - for (let i = 0; i < sites.length; i++) { - if (sites[i]['$id'] == props['$id']) { - sites[i] = { - ...sites[i], - ...props, - }; - this.set('sites' as any, sites); - return; - } - } + addFunction(props: FunctionConfig): void { + props = whitelistKeys(props, KeysFunction, { + vars: KeysVars, + }); - sites.push(props); - this.set('sites' as any, sites); + if (!this.has("functions")) { + this.set("functions", []); } - getFunctions(): any[] { - if (!this.has('functions')) { - return []; - } - return this.get('functions' as any); + const functions = this.get("functions") ?? []; + for (let i = 0; i < functions.length; i++) { + if (functions[i]["$id"] == props["$id"]) { + functions[i] = { + ...functions[i], + ...props, + }; + this.set("functions", functions); + return; + } } - getFunction($id: string): any { - if (!this.has('functions')) { - return {}; - } + functions.push(props); + this.set("functions", functions); + } - const functions = this.get('functions' as any); - for (let i = 0; i < functions.length; i++) { - if (functions[i]['$id'] == $id) { - return functions[i]; - } - } - - return {}; + getCollections(): CollectionConfig[] { + if (!this.has("collections")) { + return []; } + return this.get("collections") ?? []; + } - addFunction(props: any): void { - props = whitelistKeys(props, KeysFunction, { - vars: KeysVars, - }); - - if (!this.has('functions')) { - this.set('functions' as any, []); - } - - const functions = this.get('functions' as any); - for (let i = 0; i < functions.length; i++) { - if (functions[i]['$id'] == props['$id']) { - functions[i] = { - ...functions[i], - ...props, - }; - this.set('functions' as any, functions); - return; - } - } - - functions.push(props); - this.set('functions' as any, functions); + getCollection($id: string): CollectionConfig | Record<string, never> { + if (!this.has("collections")) { + return {}; } - getCollections(): any[] { - if (!this.has('collections')) { - return []; - } - return this.get('collections' as any); + const collections = this.get("collections") ?? []; + for (let i = 0; i < collections.length; i++) { + if (collections[i]["$id"] == $id) { + return collections[i]; + } } - getCollection($id: string): any { - if (!this.has('collections')) { - return {}; - } + return {}; + } - const collections = this.get('collections' as any); - for (let i = 0; i < collections.length; i++) { - if (collections[i]['$id'] == $id) { - return collections[i]; - } - } + addCollection(props: CollectionConfig): void { + props = whitelistKeys(props, KeysCollection, { + attributes: KeysAttributes, + indexes: KeyIndexes, + }); - return {}; + if (!this.has("collections")) { + this.set("collections", []); } - addCollection(props: any): void { - props = whitelistKeys(props, KeysCollection, { - attributes: KeysAttributes, - indexes: KeyIndexes, - }); - - if (!this.has('collections')) { - this.set('collections' as any, []); - } - - const collections = this.get('collections' as any); - for (let i = 0; i < collections.length; i++) { - if (collections[i]['$id'] == props['$id'] && collections[i]['databaseId'] == props['databaseId']) { - collections[i] = props; - this.set('collections' as any, collections); - return; - } - } - collections.push(props); - this.set('collections' as any, collections); + const collections = this.get("collections") ?? []; + for (let i = 0; i < collections.length; i++) { + if ( + collections[i]["$id"] == props["$id"] && + collections[i]["databaseId"] == props["databaseId"] + ) { + collections[i] = props; + this.set("collections", collections); + return; + } } + collections.push(props); + this.set("collections", collections); + } - getTables(): any[] { - if (!this.has('tables')) { - return []; - } - return this.get('tables' as any); + getTables(): TableConfig[] { + if (!this.has("tables")) { + return []; } + return this.get("tables") ?? []; + } - getTable($id: string): any { - if (!this.has('tables')) { - return {}; - } - - const tables = this.get('tables' as any); - for (let i = 0; i < tables.length; i++) { - if (tables[i]['$id'] == $id) { - return tables[i]; - } - } + getTable($id: string): TableConfig | Record<string, never> { + if (!this.has("tables")) { + return {}; + } - return {}; + const tables = this.get("tables") ?? []; + for (let i = 0; i < tables.length; i++) { + if (tables[i]["$id"] == $id) { + return tables[i]; + } } - addTable(props: any): void { - props = whitelistKeys(props, KeysTable, { - columns: KeysColumns, - indexes: KeyIndexesColumns, - }); + return {}; + } - if (!this.has('tables')) { - this.set('tables' as any, []); - } + addTable(props: TableConfig): void { + props = whitelistKeys(props, KeysTable, { + columns: KeysColumns, + indexes: KeyIndexesColumns, + }); - const tables = this.get('tables' as any); - for (let i = 0; i < tables.length; i++) { - if (tables[i]['$id'] == props['$id'] && tables[i]['databaseId'] == props['databaseId']) { - tables[i] = props; - this.set('tables' as any, tables); - return; - } - } - tables.push(props); - this.set('tables' as any, tables); + if (!this.has("tables")) { + this.set("tables", []); } - getBuckets(): any[] { - if (!this.has('buckets')) { - return []; - } - return this.get('buckets' as any); + const tables = this.get("tables") ?? []; + for (let i = 0; i < tables.length; i++) { + if ( + tables[i]["$id"] == props["$id"] && + tables[i]["databaseId"] == props["databaseId"] + ) { + tables[i] = props; + this.set("tables", tables); + return; + } } + tables.push(props); + this.set("tables", tables); + } - getBucket($id: string): any { - if (!this.has('buckets')) { - return {}; - } - - const buckets = this.get('buckets' as any); - for (let i = 0; i < buckets.length; i++) { - if (buckets[i]['$id'] == $id) { - return buckets[i]; - } - } - - return {}; + getBuckets(): BucketConfig[] { + if (!this.has("buckets")) { + return []; } + return this.get("buckets") ?? []; + } - addBucket(props: any): void { - props = whitelistKeys(props, KeysStorage); - - if (!this.has('buckets')) { - this.set('buckets' as any, []); - } - - const buckets = this.get('buckets' as any); - for (let i = 0; i < buckets.length; i++) { - if (buckets[i]['$id'] == props['$id']) { - buckets[i] = props; - this.set('buckets' as any, buckets); - return; - } - } - buckets.push(props); - this.set('buckets' as any, buckets); + getBucket($id: string): BucketConfig | Record<string, never> { + if (!this.has("buckets")) { + return {}; } - getMessagingTopics(): any[] { - if (!this.has('topics')) { - return []; - } - return this.get('topics' as any); + const buckets = this.get("buckets") ?? []; + for (let i = 0; i < buckets.length; i++) { + if (buckets[i]["$id"] == $id) { + return buckets[i]; + } } - getMessagingTopic($id: string): any { - if (!this.has('topics')) { - return {}; - } + return {}; + } - const topic = this.get('topics' as any); - for (let i = 0; i < topic.length; i++) { - if (topic[i]['$id'] == $id) { - return topic[i]; - } - } + addBucket(props: BucketConfig): void { + props = whitelistKeys(props, KeysStorage); - return {}; + if (!this.has("buckets")) { + this.set("buckets", []); } - addMessagingTopic(props: any): void { - props = whitelistKeys(props, KeysTopics); - - if (!this.has('topics')) { - this.set('topics' as any, []); - } - - const topics = this.get('topics' as any); - for (let i = 0; i < topics.length; i++) { - if (topics[i]['$id'] === props['$id']) { - topics[i] = props; - this.set('topics' as any, topics); - return; - } - } - topics.push(props); - this.set('topics' as any, topics); + const buckets = this.get("buckets") ?? []; + for (let i = 0; i < buckets.length; i++) { + if (buckets[i]["$id"] == props["$id"]) { + buckets[i] = props; + this.set("buckets", buckets); + return; + } } + buckets.push(props); + this.set("buckets", buckets); + } - getTablesDBs(): any[] { - return this._getDBEntities('tablesDB'); + getMessagingTopics(): TopicConfig[] { + if (!this.has("topics")) { + return []; } + return this.get("topics") ?? []; + } - getTablesDB($id: string): any { - return this._getDBEntity('tablesDB', $id); + getMessagingTopic($id: string): TopicConfig | Record<string, never> { + if (!this.has("topics")) { + return {}; } - addTablesDB(props: any): void { - this._addDBEntity('tablesDB', props, KeysDatabase); + const topics = this.get("topics") ?? []; + for (let i = 0; i < topics.length; i++) { + if (topics[i]["$id"] == $id) { + return topics[i]; + } } - getDatabases(): any[] { - return this._getDBEntities('databases'); - } + return {}; + } - getDatabase($id: string): any { - return this._getDBEntity('databases', $id); - } + addMessagingTopic(props: TopicConfig): void { + props = whitelistKeys(props, KeysTopics); - addDatabase(props: any): void { - this._addDBEntity('databases', props, KeysDatabase); + if (!this.has("topics")) { + this.set("topics", []); } - getTeams(): any[] { - if (!this.has('teams')) { - return []; - } - return this.get('teams' as any); + const topics = this.get("topics") ?? []; + for (let i = 0; i < topics.length; i++) { + if (topics[i]["$id"] === props["$id"]) { + topics[i] = props; + this.set("topics", topics); + return; + } } + topics.push(props); + this.set("topics", topics); + } - getTeam($id: string): any { - if (!this.has('teams')) { - return {}; - } + getTablesDBs(): any[] { + return this._getDBEntities("tablesDB"); + } - const teams = this.get('teams' as any); - for (let i = 0; i < teams.length; i++) { - if (teams[i]['$id'] == $id) { - return teams[i]; - } - } + getTablesDB($id: string): any { + return this._getDBEntity("tablesDB", $id); + } - return {}; - } - - addTeam(props: any): void { - props = whitelistKeys(props, KeysTeams); - if (!this.has('teams')) { - this.set('teams' as any, []); - } + addTablesDB(props: any): void { + this._addDBEntity("tablesDB", props, KeysDatabase); + } - const teams = this.get('teams' as any); - for (let i = 0; i < teams.length; i++) { - if (teams[i]['$id'] == props['$id']) { - teams[i] = props; - this.set('teams' as any, teams); - return; - } - } - teams.push(props); - this.set('teams' as any, teams); - } + getDatabases(): any[] { + return this._getDBEntities("databases"); + } - getProject(): { projectId?: string; projectName?: string; projectSettings?: any } { - if (!this.has('projectId')) { - return {}; - } - - return { - projectId: this.get('projectId' as any), - projectName: this.get('projectName' as any), - projectSettings: this.get('settings' as any), - }; - } + getDatabase($id: string): any { + return this._getDBEntity("databases", $id); + } - setProject(projectId: string, projectName: string = '', projectSettings: any = undefined): void { - this.set('projectId' as any, projectId); - - if (projectName !== '') { - this.set('projectName' as any, projectName); - } - - if (projectSettings === undefined) { - return; - } - - this.set('settings' as any, this.createSettingsObject(projectSettings)); - } - - createSettingsObject(projectSettings: any): any { - return { - services: { - account: projectSettings.serviceStatusForAccount, - avatars: projectSettings.serviceStatusForAvatars, - databases: projectSettings.serviceStatusForDatabases, - locale: projectSettings.serviceStatusForLocale, - health: projectSettings.serviceStatusForHealth, - storage: projectSettings.serviceStatusForStorage, - teams: projectSettings.serviceStatusForTeams, - users: projectSettings.serviceStatusForUsers, - sites: projectSettings.serviceStatusForSites, - functions: projectSettings.serviceStatusForFunctions, - graphql: projectSettings.serviceStatusForGraphql, - messaging: projectSettings.serviceStatusForMessaging, - }, - auth: { - methods: { - jwt: projectSettings.authJWT, - phone: projectSettings.authPhone, - invites: projectSettings.authInvites, - anonymous: projectSettings.authAnonymous, - 'email-otp': projectSettings.authEmailOtp, - 'magic-url': projectSettings.authUsersAuthMagicURL, - 'email-password': projectSettings.authEmailPassword, - }, - security: { - duration: projectSettings.authDuration, - limit: projectSettings.authLimit, - sessionsLimit: projectSettings.authSessionsLimit, - passwordHistory: projectSettings.authPasswordHistory, - passwordDictionary: projectSettings.authPasswordDictionary, - personalDataCheck: projectSettings.authPersonalDataCheck, - sessionAlerts: projectSettings.authSessionAlerts, - mockNumbers: projectSettings.authMockNumbers, - }, - }, - }; - } + addDatabase(props: any): void { + this._addDBEntity("databases", props, KeysDatabase); + } + + getTeams(): TeamConfig[] { + if (!this.has("teams")) { + return []; + } + return this.get("teams") ?? []; + } + + getTeam($id: string): TeamConfig | Record<string, never> { + if (!this.has("teams")) { + return {}; + } + + const teams = this.get("teams") ?? []; + for (let i = 0; i < teams.length; i++) { + if (teams[i]["$id"] == $id) { + return teams[i]; + } + } + + return {}; + } + + addTeam(props: TeamConfig): void { + props = whitelistKeys(props, KeysTeams); + if (!this.has("teams")) { + this.set("teams", []); + } + + const teams = this.get("teams") ?? []; + for (let i = 0; i < teams.length; i++) { + if (teams[i]["$id"] == props["$id"]) { + teams[i] = props; + this.set("teams", teams); + return; + } + } + teams.push(props); + this.set("teams", teams); + } + + getProject(): { + projectId?: string; + projectName?: string; + projectSettings?: ProjectSettings; + } { + if (!this.has("projectId")) { + return {}; + } + + return { + projectId: this.get("projectId"), + projectName: this.get("projectName"), + projectSettings: this.get("settings"), + }; + } + + setProject( + projectId: string, + projectName: string = "", + projectSettings?: RawProjectSettings, + ): void { + this.set("projectId", projectId); + + if (projectName !== "") { + this.set("projectName", projectName); + } + + if (projectSettings === undefined) { + return; + } + + this.set("settings", this.createSettingsObject(projectSettings)); + } + + createSettingsObject(projectSettings: RawProjectSettings): ProjectSettings { + return { + services: { + account: projectSettings.serviceStatusForAccount, + avatars: projectSettings.serviceStatusForAvatars, + databases: projectSettings.serviceStatusForDatabases, + locale: projectSettings.serviceStatusForLocale, + health: projectSettings.serviceStatusForHealth, + storage: projectSettings.serviceStatusForStorage, + teams: projectSettings.serviceStatusForTeams, + users: projectSettings.serviceStatusForUsers, + sites: projectSettings.serviceStatusForSites, + functions: projectSettings.serviceStatusForFunctions, + graphql: projectSettings.serviceStatusForGraphql, + messaging: projectSettings.serviceStatusForMessaging, + }, + auth: { + methods: { + jwt: projectSettings.authJWT, + phone: projectSettings.authPhone, + invites: projectSettings.authInvites, + anonymous: projectSettings.authAnonymous, + "email-otp": projectSettings.authEmailOtp, + "magic-url": projectSettings.authUsersAuthMagicURL, + "email-password": projectSettings.authEmailPassword, + }, + security: { + duration: projectSettings.authDuration, + limit: projectSettings.authLimit, + sessionsLimit: projectSettings.authSessionsLimit, + passwordHistory: projectSettings.authPasswordHistory, + passwordDictionary: projectSettings.authPasswordDictionary, + personalDataCheck: projectSettings.authPersonalDataCheck, + sessionAlerts: projectSettings.authSessionAlerts, + mockNumbers: projectSettings.authMockNumbers, + }, + }, + }; + } } class Global extends Config<GlobalConfigData> { - static CONFIG_FILE_PATH = '.appwrite/prefs.json'; - - static PREFERENCE_CURRENT = 'current'; - static PREFERENCE_ENDPOINT = 'endpoint'; - static PREFERENCE_EMAIL = 'email'; - static PREFERENCE_SELF_SIGNED = 'selfSigned'; - static PREFERENCE_COOKIE = 'cookie'; - static PREFERENCE_PROJECT = 'project'; - static PREFERENCE_KEY = 'key'; - static PREFERENCE_LOCALE = 'locale'; - static PREFERENCE_MODE = 'mode'; - - static IGNORE_ATTRIBUTES = [ - Global.PREFERENCE_CURRENT, - Global.PREFERENCE_SELF_SIGNED, - Global.PREFERENCE_ENDPOINT, - Global.PREFERENCE_COOKIE, - Global.PREFERENCE_PROJECT, - Global.PREFERENCE_KEY, - Global.PREFERENCE_LOCALE, - Global.PREFERENCE_MODE, - ]; - - static MODE_ADMIN = 'admin'; - static MODE_DEFAULT = 'default'; - - static PROJECT_CONSOLE = 'console'; - - constructor(path: string = Global.CONFIG_FILE_PATH) { - const homeDir = os.homedir(); - super(`${homeDir}/${path}`); - } - - getCurrentSession(): string { - if (!this.has(Global.PREFERENCE_CURRENT)) { - return ''; - } - return this.get(Global.PREFERENCE_CURRENT as any); - } - - setCurrentSession(session: string): void { - if (session !== undefined) { - this.set(Global.PREFERENCE_CURRENT as any, session); - } - } - - getSessionIds(): string[] { - return Object.keys(this.data).filter((key) => !Global.IGNORE_ATTRIBUTES.includes(key)); - } - - getSessions(): Array<{ id: string; endpoint: string; email: string }> { - const sessions = Object.keys(this.data).filter((key) => !Global.IGNORE_ATTRIBUTES.includes(key)); - const current = this.getCurrentSession(); - - const sessionMap = new Map<string, { id: string; endpoint: string; email: string }>(); - - sessions.forEach((sessionId) => { - const sessionData = (this.data as any)[sessionId]; - const email = sessionData[Global.PREFERENCE_EMAIL]; - const endpoint = sessionData[Global.PREFERENCE_ENDPOINT]; - const key = `${email}|${endpoint}`; - - if (sessionId === current || !sessionMap.has(key)) { - sessionMap.set(key, { - id: sessionId, - endpoint: sessionData[Global.PREFERENCE_ENDPOINT], - email: sessionData[Global.PREFERENCE_EMAIL], - }); - } + static CONFIG_FILE_PATH = ".appwrite/prefs.json"; + + static PREFERENCE_CURRENT = "current" as const; + static PREFERENCE_ENDPOINT = "endpoint" as const; + static PREFERENCE_EMAIL = "email" as const; + static PREFERENCE_SELF_SIGNED = "selfSigned" as const; + static PREFERENCE_COOKIE = "cookie" as const; + static PREFERENCE_PROJECT = "project" as const; + static PREFERENCE_KEY = "key" as const; + static PREFERENCE_LOCALE = "locale" as const; + static PREFERENCE_MODE = "mode" as const; + + static IGNORE_ATTRIBUTES: readonly string[] = [ + Global.PREFERENCE_CURRENT, + Global.PREFERENCE_SELF_SIGNED, + Global.PREFERENCE_ENDPOINT, + Global.PREFERENCE_COOKIE, + Global.PREFERENCE_PROJECT, + Global.PREFERENCE_KEY, + Global.PREFERENCE_LOCALE, + Global.PREFERENCE_MODE, + ]; + + static MODE_ADMIN = "admin"; + static MODE_DEFAULT = "default"; + + static PROJECT_CONSOLE = "console"; + + constructor(path: string = Global.CONFIG_FILE_PATH) { + const homeDir = os.homedir(); + super(`${homeDir}/${path}`); + } + + getCurrentSession(): string { + if (!this.has(Global.PREFERENCE_CURRENT)) { + return ""; + } + return this.get(Global.PREFERENCE_CURRENT); + } + + setCurrentSession(session: string): void { + if (session !== undefined) { + this.set(Global.PREFERENCE_CURRENT, session); + } + } + + getSessionIds(): string[] { + return Object.keys(this.data).filter( + (key) => !Global.IGNORE_ATTRIBUTES.includes(key), + ); + } + + getSessions(): Array<{ id: string; endpoint: string; email: string }> { + const sessions = Object.keys(this.data).filter( + (key) => !Global.IGNORE_ATTRIBUTES.includes(key), + ); + const current = this.getCurrentSession(); + + const sessionMap = new Map< + string, + { id: string; endpoint: string; email: string } + >(); + + sessions.forEach((sessionId) => { + const sessionData = (this.data as any)[sessionId]; + const email = sessionData[Global.PREFERENCE_EMAIL]; + const endpoint = sessionData[Global.PREFERENCE_ENDPOINT]; + const key = `${email}|${endpoint}`; + + if (sessionId === current || !sessionMap.has(key)) { + sessionMap.set(key, { + id: sessionId, + endpoint: sessionData[Global.PREFERENCE_ENDPOINT], + email: sessionData[Global.PREFERENCE_EMAIL], }); + } + }); - return Array.from(sessionMap.values()); - } - - addSession(session: string, data: SessionData): void { - this.set(session as any, data as any); - } + return Array.from(sessionMap.values()); + } - removeSession(session: string): void { - this.delete(session); - } + addSession(session: string, data: SessionData): void { + this.set(session as any, data as any); + } - getEmail(): string { - if (!this.hasFrom(Global.PREFERENCE_EMAIL)) { - return ''; - } + removeSession(session: string): void { + this.delete(session); + } - return this.getFrom(Global.PREFERENCE_EMAIL); + getEmail(): string { + if (!this.hasFrom(Global.PREFERENCE_EMAIL)) { + return ""; } - setEmail(email: string): void { - this.setTo(Global.PREFERENCE_EMAIL, email); - } + return this.getFrom(Global.PREFERENCE_EMAIL); + } - getEndpoint(): string { - if (!this.hasFrom(Global.PREFERENCE_ENDPOINT)) { - return ''; - } + setEmail(email: string): void { + this.setTo(Global.PREFERENCE_EMAIL, email); + } - return this.getFrom(Global.PREFERENCE_ENDPOINT); + getEndpoint(): string { + if (!this.hasFrom(Global.PREFERENCE_ENDPOINT)) { + return ""; } - setEndpoint(endpoint: string): void { - this.setTo(Global.PREFERENCE_ENDPOINT, endpoint); - } + return this.getFrom(Global.PREFERENCE_ENDPOINT); + } - getSelfSigned(): boolean { - if (!this.hasFrom(Global.PREFERENCE_SELF_SIGNED)) { - return false; - } - return this.getFrom(Global.PREFERENCE_SELF_SIGNED); - } + setEndpoint(endpoint: string): void { + this.setTo(Global.PREFERENCE_ENDPOINT, endpoint); + } - setSelfSigned(selfSigned: boolean): void { - this.setTo(Global.PREFERENCE_SELF_SIGNED, selfSigned); + getSelfSigned(): boolean { + if (!this.hasFrom(Global.PREFERENCE_SELF_SIGNED)) { + return false; } + return this.getFrom(Global.PREFERENCE_SELF_SIGNED); + } - getCookie(): string { - if (!this.hasFrom(Global.PREFERENCE_COOKIE)) { - return ''; - } - return this.getFrom(Global.PREFERENCE_COOKIE); - } + setSelfSigned(selfSigned: boolean): void { + this.setTo(Global.PREFERENCE_SELF_SIGNED, selfSigned); + } - setCookie(cookie: string): void { - this.setTo(Global.PREFERENCE_COOKIE, cookie); + getCookie(): string { + if (!this.hasFrom(Global.PREFERENCE_COOKIE)) { + return ""; } + return this.getFrom(Global.PREFERENCE_COOKIE); + } - getProject(): string { - if (!this.hasFrom(Global.PREFERENCE_PROJECT)) { - return ''; - } - return this.getFrom(Global.PREFERENCE_PROJECT); - } + setCookie(cookie: string): void { + this.setTo(Global.PREFERENCE_COOKIE, cookie); + } - setProject(project: string): void { - this.setTo(Global.PREFERENCE_PROJECT, project); + getProject(): string { + if (!this.hasFrom(Global.PREFERENCE_PROJECT)) { + return ""; } + return this.getFrom(Global.PREFERENCE_PROJECT); + } - getKey(): string { - if (!this.hasFrom(Global.PREFERENCE_KEY)) { - return ''; - } - return this.getFrom(Global.PREFERENCE_KEY); - } + setProject(project: string): void { + this.setTo(Global.PREFERENCE_PROJECT, project); + } - setKey(key: string): void { - this.setTo(Global.PREFERENCE_KEY, key); + getKey(): string { + if (!this.hasFrom(Global.PREFERENCE_KEY)) { + return ""; } + return this.getFrom(Global.PREFERENCE_KEY); + } + + setKey(key: string): void { + this.setTo(Global.PREFERENCE_KEY, key); + } - hasFrom(key: string): boolean { - const current = this.getCurrentSession(); + hasFrom(key: string): boolean { + const current = this.getCurrentSession(); - if (current) { - const config = this.get(current as any) ?? {}; + if (current) { + const config = this.get(current as any) ?? {}; - return (config as any)[key] !== undefined; - } - return false; + return (config as any)[key] !== undefined; } + return false; + } - getFrom(key: string): any { - const current = this.getCurrentSession(); + getFrom(key: string): any { + const current = this.getCurrentSession(); - if (current) { - const config = this.get(current as any) ?? {}; + if (current) { + const config = this.get(current as any) ?? {}; - return (config as any)[key]; - } + return (config as any)[key]; } + } - setTo(key: string, value: any): void { - const current = this.getCurrentSession(); + setTo(key: string, value: any): void { + const current = this.getCurrentSession(); - if (current) { - const config = this.get(current as any); + if (current) { + const config = this.get(current as any); - (config as any)[key] = value; - this.write(); - } + (config as any)[key] = value; + this.write(); } + } } export const localConfig = new Local(); export const globalConfig = new Global(); export { - KeysAttributes, - KeysSite, - KeysFunction, - KeysTopics, - KeysStorage, - KeysTeams, - KeysCollection, - KeysTable, - whitelistKeys, + KeysAttributes, + KeysSite, + KeysFunction, + KeysTopics, + KeysStorage, + KeysTeams, + KeysCollection, + KeysTable, + whitelistKeys, }; diff --git a/lib/emulation/docker.ts b/lib/emulation/docker.ts index 8acd672b..cb6cf296 100644 --- a/lib/emulation/docker.ts +++ b/lib/emulation/docker.ts @@ -1,265 +1,312 @@ -import ignore = require('ignore'); -import net = require('net'); -import chalk from 'chalk'; -import childProcess = require('child_process'); -import { localConfig } from '../config'; -import path = require('path'); -import fs = require('fs'); -import { log, error, success } from '../parser'; -import { openRuntimesVersion, systemTools, Queue } from './utils'; -import { getAllFiles } from '../utils'; - -interface FunctionConfig { - $id: string; - runtime: string; - path: string; - entrypoint: string; - commands: string; - ignore?: string; -} +import ignoreModule from "ignore"; +const ignore: typeof ignoreModule = + (ignoreModule as any).default ?? ignoreModule; +import net from "net"; +import chalk from "chalk"; +import childProcess from "child_process"; +import { localConfig } from "../config.js"; +import path from "path"; +import fs from "fs"; +import { log, error, success } from "../parser.js"; +import { openRuntimesVersion, systemTools, Queue } from "./utils.js"; +import { getAllFiles } from "../utils.js"; +import type { FunctionConfig } from "../types.js"; export async function dockerStop(id: string): Promise<void> { - const stopProcess = childProcess.spawn('docker', ['rm', '--force', id], { - stdio: 'pipe', - env: { - ...process.env, - DOCKER_CLI_HINTS: 'false' - } - }); - - await new Promise<void>((res) => { stopProcess.on('close', res) }); + const stopProcess = childProcess.spawn("docker", ["rm", "--force", id], { + stdio: "pipe", + env: { + ...process.env, + DOCKER_CLI_HINTS: "false", + }, + }); + + await new Promise<void>((res) => { + stopProcess.on("close", res); + }); } export async function dockerPull(func: FunctionConfig): Promise<void> { - const runtimeChunks = func.runtime.split("-"); - const runtimeVersion = runtimeChunks.pop(); - const runtimeName = runtimeChunks.join("-"); - const imageName = `openruntimes/${runtimeName}:${openRuntimesVersion}-${runtimeVersion}`; - - log('Verifying Docker image ...'); - - const pullProcess = childProcess.spawn('docker', ['pull', imageName], { - stdio: 'pipe', - env: { - ...process.env, - DOCKER_CLI_HINTS: 'false' - } - }); - - await new Promise<void>((res) => { pullProcess.on('close', res) }); + const runtimeChunks = func.runtime.split("-"); + const runtimeVersion = runtimeChunks.pop(); + const runtimeName = runtimeChunks.join("-"); + const imageName = `openruntimes/${runtimeName}:${openRuntimesVersion}-${runtimeVersion}`; + + log("Verifying Docker image ..."); + + const pullProcess = childProcess.spawn("docker", ["pull", imageName], { + stdio: "pipe", + env: { + ...process.env, + DOCKER_CLI_HINTS: "false", + }, + }); + + await new Promise<void>((res) => { + pullProcess.on("close", res); + }); } -export async function dockerBuild(func: FunctionConfig, variables: Record<string, string>): Promise<void> { - const runtimeChunks = func.runtime.split("-"); - const runtimeVersion = runtimeChunks.pop(); - const runtimeName = runtimeChunks.join("-"); - const imageName = `openruntimes/${runtimeName}:${openRuntimesVersion}-${runtimeVersion}`; - - const functionDir = path.join(localConfig.getDirname(), func.path); - - const id = func.$id; - - const ignorer = ignore.default(); - ignorer.add('.appwrite'); - if (func.ignore) { - ignorer.add(func.ignore); - } else if (fs.existsSync(path.join(functionDir, '.gitignore'))) { - ignorer.add(fs.readFileSync(path.join(functionDir, '.gitignore')).toString()); - } - - const files = getAllFiles(functionDir).map((file) => path.relative(functionDir, file)).filter((file) => !ignorer.ignores(file)); - const tmpBuildPath = path.join(functionDir, '.appwrite/tmp-build'); - if (!fs.existsSync(tmpBuildPath)) { - fs.mkdirSync(tmpBuildPath, { recursive: true }); +export async function dockerBuild( + func: FunctionConfig, + variables: Record<string, string>, +): Promise<void> { + const runtimeChunks = func.runtime.split("-"); + const runtimeVersion = runtimeChunks.pop(); + const runtimeName = runtimeChunks.join("-"); + const imageName = `openruntimes/${runtimeName}:${openRuntimesVersion}-${runtimeVersion}`; + + const functionDir = path.join(localConfig.getDirname(), func.path); + + const id = func.$id; + + const ignorer = ignore(); + ignorer.add(".appwrite"); + if (func.ignore) { + ignorer.add(func.ignore); + } else if (fs.existsSync(path.join(functionDir, ".gitignore"))) { + ignorer.add( + fs.readFileSync(path.join(functionDir, ".gitignore")).toString(), + ); + } + + const files = getAllFiles(functionDir) + .map((file) => path.relative(functionDir, file)) + .filter((file) => !ignorer.ignores(file)); + const tmpBuildPath = path.join(functionDir, ".appwrite/tmp-build"); + if (!fs.existsSync(tmpBuildPath)) { + fs.mkdirSync(tmpBuildPath, { recursive: true }); + } + + for (const f of files) { + const filePath = path.join(tmpBuildPath, f); + const fileDir = path.dirname(filePath); + if (!fs.existsSync(fileDir)) { + fs.mkdirSync(fileDir, { recursive: true }); } - for(const f of files) { - const filePath = path.join(tmpBuildPath, f); - const fileDir = path.dirname(filePath); - if (!fs.existsSync(fileDir)) { - fs.mkdirSync(fileDir, { recursive: true }); - } - - const sourcePath = path.join(functionDir, f); - fs.copyFileSync(sourcePath, filePath); - } - - const params: string[] = [ 'run' ]; - params.push('--name', id); - params.push('-v', `${tmpBuildPath}/:/mnt/code:rw`); - params.push('-e', 'OPEN_RUNTIMES_ENV=development'); - params.push('-e', 'OPEN_RUNTIMES_SECRET='); - params.push('-e', `OPEN_RUNTIMES_ENTRYPOINT=${func.entrypoint}`); - - for(const k of Object.keys(variables)) { - params.push('-e', `${k}=${variables[k]}`); - } - - params.push(imageName, 'sh', '-c', `helpers/build.sh "${func.commands}"`); - - const buildProcess = childProcess.spawn('docker', params, { - stdio: 'pipe', - cwd: functionDir, - env: { - ...process.env, - DOCKER_CLI_HINTS: 'false' - } - }); - - buildProcess.stdout.on('data', (data) => { - process.stdout.write(chalk.blackBright(`${data}\n`)); - }); - - buildProcess.stderr.on('data', (data) => { - process.stderr.write(chalk.blackBright(`${data}\n`)); - }); - - const killInterval = setInterval(() => { - if(!Queue.isEmpty()) { - log('Cancelling build ...'); - buildProcess.stdout.destroy(); - buildProcess.stdin.destroy(); - buildProcess.stderr.destroy(); - buildProcess.kill("SIGKILL"); - clearInterval(killInterval); - } - }, 100); - - await new Promise<void>((res) => { buildProcess.on('close', res) }); - - clearInterval(killInterval); - if(!Queue.isEmpty()) { - return; - } - - const copyPath = path.join(localConfig.getDirname(), func.path, '.appwrite', 'build.tar.gz'); - const copyDir = path.dirname(copyPath); - if (!fs.existsSync(copyDir)) { - fs.mkdirSync(copyDir, { recursive: true }); - } - - const copyProcess = childProcess.spawn('docker', ['cp', `${id}:/mnt/code/code.tar.gz`, copyPath], { - stdio: 'pipe', - cwd: functionDir, - env: { - ...process.env, - DOCKER_CLI_HINTS: 'false' - } - }); - - await new Promise<void>((res) => { copyProcess.on('close', res) }); - - await dockerStop(id); - - const tempPath = path.join(localConfig.getDirname(), func.path, 'code.tar.gz'); - if (fs.existsSync(tempPath)) { - fs.rmSync(tempPath, { force: true }); + const sourcePath = path.join(functionDir, f); + fs.copyFileSync(sourcePath, filePath); + } + + const params: string[] = ["run"]; + params.push("--name", id); + params.push("-v", `${tmpBuildPath}/:/mnt/code:rw`); + params.push("-e", "OPEN_RUNTIMES_ENV=development"); + params.push("-e", "OPEN_RUNTIMES_SECRET="); + params.push("-e", `OPEN_RUNTIMES_ENTRYPOINT=${func.entrypoint}`); + + for (const k of Object.keys(variables)) { + params.push("-e", `${k}=${variables[k]}`); + } + + params.push(imageName, "sh", "-c", `helpers/build.sh "${func.commands}"`); + + const buildProcess = childProcess.spawn("docker", params, { + stdio: "pipe", + cwd: functionDir, + env: { + ...process.env, + DOCKER_CLI_HINTS: "false", + }, + }); + + buildProcess.stdout.on("data", (data) => { + process.stdout.write(chalk.blackBright(`${data}\n`)); + }); + + buildProcess.stderr.on("data", (data) => { + process.stderr.write(chalk.blackBright(`${data}\n`)); + }); + + const killInterval = setInterval(() => { + if (!Queue.isEmpty()) { + log("Cancelling build ..."); + buildProcess.stdout.destroy(); + buildProcess.stdin.destroy(); + buildProcess.stderr.destroy(); + buildProcess.kill("SIGKILL"); + clearInterval(killInterval); } - - fs.rmSync(tmpBuildPath, { recursive: true, force: true }); + }, 100); + + await new Promise<void>((res) => { + buildProcess.on("close", res); + }); + + clearInterval(killInterval); + if (!Queue.isEmpty()) { + return; + } + + const copyPath = path.join( + localConfig.getDirname(), + func.path, + ".appwrite", + "build.tar.gz", + ); + const copyDir = path.dirname(copyPath); + if (!fs.existsSync(copyDir)) { + fs.mkdirSync(copyDir, { recursive: true }); + } + + const copyProcess = childProcess.spawn( + "docker", + ["cp", `${id}:/mnt/code/code.tar.gz`, copyPath], + { + stdio: "pipe", + cwd: functionDir, + env: { + ...process.env, + DOCKER_CLI_HINTS: "false", + }, + }, + ); + + await new Promise<void>((res) => { + copyProcess.on("close", res); + }); + + await dockerStop(id); + + const tempPath = path.join( + localConfig.getDirname(), + func.path, + "code.tar.gz", + ); + if (fs.existsSync(tempPath)) { + fs.rmSync(tempPath, { force: true }); + } + + fs.rmSync(tmpBuildPath, { recursive: true, force: true }); } -export async function dockerStart(func: FunctionConfig, variables: Record<string, string>, port: number): Promise<void> { - // Pack function files - const functionDir = path.join(localConfig.getDirname(), func.path); - - const runtimeChunks = func.runtime.split("-"); - const runtimeVersion = runtimeChunks.pop(); - const runtimeName = runtimeChunks.join("-"); - const imageName = `openruntimes/${runtimeName}:${openRuntimesVersion}-${runtimeVersion}`; - - const tool = systemTools[runtimeName]; - - const id = func.$id; +export async function dockerStart( + func: FunctionConfig, + variables: Record<string, string>, + port: number, +): Promise<void> { + // Pack function files + const functionDir = path.join(localConfig.getDirname(), func.path); + + const runtimeChunks = func.runtime.split("-"); + const runtimeVersion = runtimeChunks.pop(); + const runtimeName = runtimeChunks.join("-"); + const imageName = `openruntimes/${runtimeName}:${openRuntimesVersion}-${runtimeVersion}`; + + const tool = systemTools[runtimeName]; + + const id = func.$id; + + const params: string[] = ["run"]; + params.push("--rm"); + params.push("--name", id); + params.push("-p", `${port}:3000`); + params.push("-e", "OPEN_RUNTIMES_ENV=development"); + params.push("-e", "OPEN_RUNTIMES_SECRET="); + + for (const k of Object.keys(variables)) { + params.push("-e", `${k}=${variables[k]}`); + } + + params.push( + "-v", + `${functionDir}/.appwrite/logs.txt:/mnt/logs/dev_logs.log:rw`, + ); + params.push( + "-v", + `${functionDir}/.appwrite/errors.txt:/mnt/logs/dev_errors.log:rw`, + ); + params.push( + "-v", + `${functionDir}/.appwrite/build.tar.gz:/mnt/code/code.tar.gz:ro`, + ); + params.push(imageName, "sh", "-c", `helpers/start.sh "${tool.startCommand}"`); + + const startProcess = childProcess.spawn("docker", params, { + stdio: "pipe", + cwd: functionDir, + env: { + ...process.env, + DOCKER_CLI_HINTS: "false", + }, + }); + + startProcess.stdout.on("data", (data) => { + process.stdout.write(chalk.blackBright(data)); + }); + + startProcess.stderr.on("data", (data) => { + process.stdout.write(chalk.blackBright(data)); + }); + + try { + await waitUntilPortOpen(port); + } catch (err: any) { + error( + "Failed to start function with error: " + + (err.message ? err.message : err.toString()), + ); + return; + } + + success(`Visit http://localhost:${port}/ to execute your function.`); +} - const params: string[] = [ 'run' ]; - params.push('--rm'); - params.push('--name', id); - params.push('-p', `${port}:3000`); - params.push('-e', 'OPEN_RUNTIMES_ENV=development'); - params.push('-e', 'OPEN_RUNTIMES_SECRET='); +export async function dockerCleanup(functionId: string): Promise<void> { + await dockerStop(functionId); + + const func = localConfig.getFunction(functionId); + const appwritePath = path.join( + localConfig.getDirname(), + func.path, + ".appwrite", + ); + if (fs.existsSync(appwritePath)) { + fs.rmSync(appwritePath, { recursive: true, force: true }); + } + + const tempPath = path.join( + localConfig.getDirname(), + func.path, + "code.tar.gz", + ); + if (fs.existsSync(tempPath)) { + fs.rmSync(tempPath, { force: true }); + } +} - for(const k of Object.keys(variables)) { - params.push('-e', `${k}=${variables[k]}`); - } +function waitUntilPortOpen(port: number, iteration: number = 0): Promise<void> { + return new Promise((resolve, reject) => { + const client = new net.Socket(); - params.push('-v', `${functionDir}/.appwrite/logs.txt:/mnt/logs/dev_logs.log:rw`); - params.push('-v', `${functionDir}/.appwrite/errors.txt:/mnt/logs/dev_errors.log:rw`); - params.push('-v', `${functionDir}/.appwrite/build.tar.gz:/mnt/code/code.tar.gz:ro`); - params.push(imageName, 'sh', '-c', `helpers/start.sh "${tool.startCommand}"`); - - const startProcess = childProcess.spawn('docker', params, { - stdio: 'pipe', - cwd: functionDir, - env: { - ...process.env, - DOCKER_CLI_HINTS: 'false' - } - }); + client.once("connect", () => { + client.removeAllListeners("connect"); + client.removeAllListeners("error"); + client.end(); + client.destroy(); + client.unref(); - startProcess.stdout.on('data', (data) => { - process.stdout.write(chalk.blackBright(data)); + resolve(); }); - startProcess.stderr.on('data', (data) => { - process.stdout.write(chalk.blackBright(data)); + client.once("error", async (err) => { + client.removeAllListeners("connect"); + client.removeAllListeners("error"); + client.end(); + client.destroy(); + client.unref(); + + if (iteration > 100) { + reject(err); + } else { + await new Promise<void>((res) => setTimeout(res, 100)); + waitUntilPortOpen(port, iteration + 1) + .then(resolve) + .catch(reject); + } }); - try { - await waitUntilPortOpen(port); - } catch(err: any) { - error("Failed to start function with error: " + (err.message ? err.message : err.toString())); - return; - } - - success(`Visit http://localhost:${port}/ to execute your function.`); + client.connect({ port, host: "127.0.0.1" }, function () {}); + }); } - -export async function dockerCleanup(functionId: string): Promise<void> { - await dockerStop(functionId); - - const func = localConfig.getFunction(functionId); - const appwritePath = path.join(localConfig.getDirname(), func.path, '.appwrite'); - if (fs.existsSync(appwritePath)) { - fs.rmSync(appwritePath, { recursive: true, force: true }); - } - - const tempPath = path.join(localConfig.getDirname(), func.path, 'code.tar.gz'); - if (fs.existsSync(tempPath)) { - fs.rmSync(tempPath, { force: true }); - } -} - -function waitUntilPortOpen(port: number, iteration: number = 0): Promise<void> { - return new Promise((resolve, reject) => { - const client = new net.Socket(); - - client.once('connect', () => { - client.removeAllListeners('connect'); - client.removeAllListeners('error'); - client.end(); - client.destroy(); - client.unref(); - - resolve(); - }); - - client.once('error', async (err) => { - client.removeAllListeners('connect'); - client.removeAllListeners('error'); - client.end(); - client.destroy(); - client.unref(); - - if(iteration > 100) { - reject(err); - } else { - await new Promise<void>((res) => setTimeout(res, 100)); - waitUntilPortOpen(port, iteration + 1).then(resolve).catch(reject); - } - }); - - client.connect({port, host: '127.0.0.1'}, function() {}); - }); -} - diff --git a/lib/emulation/utils.ts b/lib/emulation/utils.ts index 787b4dfc..17d16e3b 100644 --- a/lib/emulation/utils.ts +++ b/lib/emulation/utils.ts @@ -1,193 +1,207 @@ -import { EventEmitter } from 'node:events'; -import { projectsCreateJWT } from '../commands/projects'; -import { localConfig } from '../config'; -import { usersGet, usersCreateJWT } from '../commands/users'; -import { log } from '../parser'; +import { EventEmitter } from "node:events"; +import { localConfig } from "../config.js"; +import { log } from "../parser.js"; +import { sdkForConsole } from "../sdks.js"; +import { Projects, Users } from "@appwrite.io/console"; -export const openRuntimesVersion = 'v4'; +export const openRuntimesVersion = "v4"; export const runtimeNames: Record<string, string> = { - node: 'Node.js', - php: 'PHP', - ruby: 'Ruby', - python: 'Python', - 'python-ml': 'Python (ML)', - deno: 'Deno', - dart: 'Dart', - dotnet: '.NET', - java: 'Java', - swift: 'Swift', - kotlin: 'Kotlin', - bun: 'Bun', - go: 'Go', + node: "Node.js", + php: "PHP", + ruby: "Ruby", + python: "Python", + "python-ml": "Python (ML)", + deno: "Deno", + dart: "Dart", + dotnet: ".NET", + java: "Java", + swift: "Swift", + kotlin: "Kotlin", + bun: "Bun", + go: "Go", }; interface SystemTool { - isCompiled: boolean; - startCommand: string; - dependencyFiles: string[]; + isCompiled: boolean; + startCommand: string; + dependencyFiles: string[]; } export const systemTools: Record<string, SystemTool> = { - node: { - isCompiled: false, - startCommand: 'sh helpers/server.sh', - dependencyFiles: ['package.json', 'package-lock.json'], - }, - php: { - isCompiled: false, - startCommand: 'sh helpers/server.sh', - dependencyFiles: ['composer.json', 'composer.lock'], - }, - ruby: { - isCompiled: false, - startCommand: 'sh helpers/server.sh', - dependencyFiles: ['Gemfile', 'Gemfile.lock'], - }, - python: { - isCompiled: false, - startCommand: 'sh helpers/server.sh', - dependencyFiles: ['requirements.txt', 'requirements.lock'], - }, - 'python-ml': { - isCompiled: false, - startCommand: 'sh helpers/server.sh', - dependencyFiles: ['requirements.txt', 'requirements.lock'], - }, - deno: { - isCompiled: false, - startCommand: 'sh helpers/server.sh', - dependencyFiles: [], - }, - dart: { - isCompiled: true, - startCommand: 'sh helpers/server.sh', - dependencyFiles: [], - }, - dotnet: { - isCompiled: true, - startCommand: 'sh helpers/server.sh', - dependencyFiles: [], - }, - java: { - isCompiled: true, - startCommand: 'sh helpers/server.sh', - dependencyFiles: [], - }, - swift: { - isCompiled: true, - startCommand: 'sh helpers/server.sh', - dependencyFiles: [], - }, - kotlin: { - isCompiled: true, - startCommand: 'sh helpers/server.sh', - dependencyFiles: [], - }, - bun: { - isCompiled: false, - startCommand: 'sh helpers/server.sh', - dependencyFiles: ['package.json', 'package-lock.json', 'bun.lockb'], - }, - go: { - isCompiled: true, - startCommand: 'sh helpers/server.sh', - dependencyFiles: [], - }, + node: { + isCompiled: false, + startCommand: "sh helpers/server.sh", + dependencyFiles: ["package.json", "package-lock.json"], + }, + php: { + isCompiled: false, + startCommand: "sh helpers/server.sh", + dependencyFiles: ["composer.json", "composer.lock"], + }, + ruby: { + isCompiled: false, + startCommand: "sh helpers/server.sh", + dependencyFiles: ["Gemfile", "Gemfile.lock"], + }, + python: { + isCompiled: false, + startCommand: "sh helpers/server.sh", + dependencyFiles: ["requirements.txt", "requirements.lock"], + }, + "python-ml": { + isCompiled: false, + startCommand: "sh helpers/server.sh", + dependencyFiles: ["requirements.txt", "requirements.lock"], + }, + deno: { + isCompiled: false, + startCommand: "sh helpers/server.sh", + dependencyFiles: [], + }, + dart: { + isCompiled: true, + startCommand: "sh helpers/server.sh", + dependencyFiles: [], + }, + dotnet: { + isCompiled: true, + startCommand: "sh helpers/server.sh", + dependencyFiles: [], + }, + java: { + isCompiled: true, + startCommand: "sh helpers/server.sh", + dependencyFiles: [], + }, + swift: { + isCompiled: true, + startCommand: "sh helpers/server.sh", + dependencyFiles: [], + }, + kotlin: { + isCompiled: true, + startCommand: "sh helpers/server.sh", + dependencyFiles: [], + }, + bun: { + isCompiled: false, + startCommand: "sh helpers/server.sh", + dependencyFiles: ["package.json", "package-lock.json", "bun.lockb"], + }, + go: { + isCompiled: true, + startCommand: "sh helpers/server.sh", + dependencyFiles: [], + }, }; export const JwtManager = { - userJwt: null as string | null, - functionJwt: null as string | null, - - timerWarn: null as NodeJS.Timeout | null, - timerError: null as NodeJS.Timeout | null, - - async setup(userId: string | null = null, projectScopes: string[] = []): Promise<void> { - if (this.timerWarn) { - clearTimeout(this.timerWarn); - } - - if (this.timerError) { - clearTimeout(this.timerError); - } - - this.timerWarn = setTimeout(() => { - log('Warning: Authorized JWT will expire in 5 minutes. Please stop and re-run the command to refresh tokens for 1 hour.'); - }, 1000 * 60 * 55); // 55 mins - - this.timerError = setTimeout(() => { - log('Warning: Authorized JWT just expired. Please stop and re-run the command to obtain new tokens with 1 hour validity.'); - log('Some Appwrite API communication is not authorized now.'); - }, 1000 * 60 * 60); // 60 mins - - if (userId) { - await usersGet({ - userId, - parseOutput: false, - }); - const userResponse: any = await usersCreateJWT({ - userId, - duration: 60 * 60, - parseOutput: false, - }); - this.userJwt = userResponse.jwt; - } - - const functionResponse: any = await projectsCreateJWT({ - projectId: localConfig.getProject().projectId!, - scopes: projectScopes, - duration: 60 * 60, - parseOutput: false, - }); - this.functionJwt = functionResponse.jwt; - }, + userJwt: null as string | null, + functionJwt: null as string | null, + + timerWarn: null as NodeJS.Timeout | null, + timerError: null as NodeJS.Timeout | null, + + async setup( + userId: string | null = null, + projectScopes: string[] = [], + ): Promise<void> { + const consoleClient = await sdkForConsole(); + const usersClient = new Users(consoleClient); + const projectsClient = new Projects(consoleClient); + + if (this.timerWarn) { + clearTimeout(this.timerWarn); + } + + if (this.timerError) { + clearTimeout(this.timerError); + } + + this.timerWarn = setTimeout( + () => { + log( + "Warning: Authorized JWT will expire in 5 minutes. Please stop and re-run the command to refresh tokens for 1 hour.", + ); + }, + 1000 * 60 * 55, + ); // 55 mins + + this.timerError = setTimeout( + () => { + log( + "Warning: Authorized JWT just expired. Please stop and re-run the command to obtain new tokens with 1 hour validity.", + ); + log("Some Appwrite API communication is not authorized now."); + }, + 1000 * 60 * 60, + ); // 60 mins + + if (userId) { + await usersClient.get({ + userId, + }); + const userResponse: any = await usersClient.createJWT({ + userId, + duration: 60 * 60, + }); + this.userJwt = userResponse.jwt; + } + + const functionResponse: any = await projectsClient.createJWT({ + projectId: localConfig.getProject().projectId!, + scopes: projectScopes, + duration: 60 * 60, + }); + this.functionJwt = functionResponse.jwt; + }, }; interface QueueReloadEvent { - files: string[]; + files: string[]; } export const Queue = { - files: [] as string[], - locked: false, - events: new EventEmitter(), - debounce: null as NodeJS.Timeout | null, - - push(file: string): void { - if (!this.files.includes(file)) { - this.files.push(file); - } - - if (!this.locked) { - this._trigger(); - } - }, - - lock(): void { - this.files = []; - this.locked = true; - }, - - isEmpty(): boolean { - return this.files.length === 0; - }, - - unlock(): void { - this.locked = false; - if (this.files.length > 0) { - this._trigger(); - } - }, - - _trigger(): void { - if (this.debounce) { - return; - } - - this.debounce = setTimeout(() => { - this.events.emit('reload', { files: this.files } as QueueReloadEvent); - this.debounce = null; - }, 300); - }, + files: [] as string[], + locked: false, + events: new EventEmitter(), + debounce: null as NodeJS.Timeout | null, + + push(file: string): void { + if (!this.files.includes(file)) { + this.files.push(file); + } + + if (!this.locked) { + this._trigger(); + } + }, + + lock(): void { + this.files = []; + this.locked = true; + }, + + isEmpty(): boolean { + return this.files.length === 0; + }, + + unlock(): void { + this.locked = false; + if (this.files.length > 0) { + this._trigger(); + } + }, + + _trigger(): void { + if (this.debounce) { + return; + } + + this.debounce = setTimeout(() => { + this.events.emit("reload", { files: this.files } as QueueReloadEvent); + this.debounce = null; + }, 300); + }, }; diff --git a/lib/exception.ts b/lib/exception.ts deleted file mode 100644 index 6bdd66d8..00000000 --- a/lib/exception.ts +++ /dev/null @@ -1,20 +0,0 @@ -class AppwriteException extends Error { - public code?: number; - public type?: string; - public response?: string; - - constructor(message: string, code?: number, type?: string, response?: string) { - super(message); - this.name = 'AppwriteException'; - this.code = code; - this.type = type; - this.response = response; - - // Maintains proper stack trace for where our error was thrown (only available on V8) - if (Error.captureStackTrace) { - Error.captureStackTrace(this, AppwriteException); - } - } -} - -export = AppwriteException; diff --git a/lib/id.ts b/lib/id.ts index abcaea4b..a05a66de 100644 --- a/lib/id.ts +++ b/lib/id.ts @@ -1,30 +1,30 @@ class ID { - // Generate an hex ID based on timestamp - // Recreated from https://www.php.net/manual/en/function.uniqid.php - static #hexTimestamp(): string { - const now = new Date(); - const sec = Math.floor(now.getTime() / 1000); - const msec = now.getMilliseconds(); + // Generate an hex ID based on timestamp + // Recreated from https://www.php.net/manual/en/function.uniqid.php + static #hexTimestamp(): string { + const now = new Date(); + const sec = Math.floor(now.getTime() / 1000); + const msec = now.getMilliseconds(); - // Convert to hexadecimal - const hexTimestamp = sec.toString(16) + msec.toString(16).padStart(5, '0'); - return hexTimestamp; - } + // Convert to hexadecimal + const hexTimestamp = sec.toString(16) + msec.toString(16).padStart(5, "0"); + return hexTimestamp; + } - static custom(id: string): string { - return id; - } + static custom(id: string): string { + return id; + } - static unique(padding: number = 7): string { - // Generate a unique ID with padding to have a longer ID - const baseId = ID.#hexTimestamp(); - let randomPadding = ''; - for (let i = 0; i < padding; i++) { - const randomHexDigit = Math.floor(Math.random() * 16).toString(16); - randomPadding += randomHexDigit; - } - return baseId + randomPadding; + static unique(padding: number = 7): string { + // Generate a unique ID with padding to have a longer ID + const baseId = ID.#hexTimestamp(); + let randomPadding = ""; + for (let i = 0; i < padding; i++) { + const randomHexDigit = Math.floor(Math.random() * 16).toString(16); + randomPadding += randomHexDigit; } + return baseId + randomPadding; + } } -export = ID; +export default ID; diff --git a/lib/paginate.ts b/lib/paginate.ts index 38665663..5a04f5d0 100644 --- a/lib/paginate.ts +++ b/lib/paginate.ts @@ -1,63 +1,77 @@ interface PaginateArgs { - [key: string]: any; + [key: string]: any; } -interface PaginateResponse<T = any> { - [key: string]: T; - total: number; -} +// Overload for when wrapper is empty string - returns array +export function paginate<T = any>( + action: (args: PaginateArgs) => Promise<any>, + args: PaginateArgs, + limit: number, + wrapper: "", + queries?: string[], +): Promise<T[]>; + +// Overload for when wrapper is specified - returns object with that key +export function paginate<T = any, K extends string = string>( + action: (args: PaginateArgs) => Promise<any>, + args: PaginateArgs, + limit: number, + wrapper: K, + queries?: string[], +): Promise<Record<K, T[]> & { total: number }>; + +// Implementation +export async function paginate<T = any>( + action: (args: PaginateArgs) => Promise<any>, + args: PaginateArgs = {}, + limit: number = 100, + wrapper: string = "", + queries: string[] = [], +): Promise<T[] | (Record<string, T[]> & { total: number })> { + let pageNumber = 0; + let results: T[] = []; + let total = 0; + + while (true) { + const offset = pageNumber * limit; + + // Merge the limit and offset into the args + const response = await action({ + ...args, + queries: [ + ...queries, + JSON.stringify({ method: "limit", values: [limit] }), + JSON.stringify({ method: "offset", values: [offset] }), + ], + }); -export const paginate = async <T = any>( - action: (args: PaginateArgs) => Promise<any>, - args: PaginateArgs = {}, - limit: number = 100, - wrapper: string = '', - queries: string[] = [] -): Promise<T[] | PaginateResponse<T[]>> => { - let pageNumber = 0; - let results: T[] = []; - let total = 0; - - while (true) { - const offset = pageNumber * limit; - - // Merge the limit and offset into the args - const response = await action({ - ...args, - queries: [ - ...queries, - JSON.stringify({ method: 'limit', values: [limit] }), - JSON.stringify({ method: 'offset', values: [offset] }), - ], - }); - - if (wrapper === '') { - if (response.length === 0) { - break; - } - results = results.concat(response); - } else { - if (response[wrapper].length === 0) { - break; - } - results = results.concat(response[wrapper]); - } - - total = response.total; - - if (results.length >= total) { - break; - } - - pageNumber++; + if (wrapper === "") { + if (response.length === 0) { + break; + } + results = results.concat(response); + } else { + if (response[wrapper].length === 0) { + break; + } + results = results.concat(response[wrapper]); } - if (wrapper === '') { - return results; + total = response.total; + + if (results.length >= total) { + break; } - return { - [wrapper]: results, - total, - } as PaginateResponse<T[]>; -}; + pageNumber++; + } + + if (wrapper === "") { + return results; + } + + return { + [wrapper]: results, + total, + } as Record<string, T[]> & { total: number }; +} diff --git a/lib/parser.ts b/lib/parser.ts index f9fecb7b..2e4717b0 100644 --- a/lib/parser.ts +++ b/lib/parser.ts @@ -1,238 +1,264 @@ -import chalk = require('chalk'); -import commander = require('commander'); -import Table = require('cli-table3'); -const { description } = require('../../package.json'); -import { globalConfig } from './config'; -import os = require('os'); -import Client = require('./client'); -import { isCloud } from './utils'; -import type { CliConfig } from './types'; +import chalk from "chalk"; +import { InvalidArgumentError } from "commander"; +import Table from "cli-table3"; +import packageJson from "../package.json" with { type: "json" }; +const { description } = packageJson; +import { globalConfig } from "./config.js"; +import os from "os"; +import { Client } from "@appwrite.io/console"; +import { isCloud } from "./utils.js"; +import type { CliConfig } from "./types.js"; const cliConfig: CliConfig = { - verbose: false, - json: false, - force: false, - all: false, - ids: [], - report: false, - reportData: {}, + verbose: false, + json: false, + force: false, + all: false, + ids: [], + report: false, + reportData: {}, }; export const parse = (data: Record<string, any>): void => { - if (cliConfig.json) { - drawJSON(data); - return; - } + if (cliConfig.json) { + drawJSON(data); + return; + } - for (const key in data) { - if (data[key] === null) { - console.log(`${chalk.yellow.bold(key)} : null`); - } else if (Array.isArray(data[key])) { - console.log(`${chalk.yellow.bold.underline(key)}`); - if (typeof data[key][0] === 'object') { - drawTable(data[key]); - } else { - drawJSON(data[key]); - } - } else if (typeof data[key] === 'object') { - if (data[key]?.constructor?.name === 'BigNumber') { - console.log(`${chalk.yellow.bold(key)} : ${data[key]}`); - } else { - console.log(`${chalk.yellow.bold.underline(key)}`); - drawTable([data[key]]); - } - } else { - console.log(`${chalk.yellow.bold(key)} : ${data[key]}`); - } + for (const key in data) { + if (data[key] === null) { + console.log(`${chalk.yellow.bold(key)} : null`); + } else if (Array.isArray(data[key])) { + console.log(`${chalk.yellow.bold.underline(key)}`); + if (typeof data[key][0] === "object") { + drawTable(data[key]); + } else { + drawJSON(data[key]); + } + } else if (typeof data[key] === "object") { + if (data[key]?.constructor?.name === "BigNumber") { + console.log(`${chalk.yellow.bold(key)} : ${data[key]}`); + } else { + console.log(`${chalk.yellow.bold.underline(key)}`); + drawTable([data[key]]); + } + } else { + console.log(`${chalk.yellow.bold(key)} : ${data[key]}`); } + } }; export const drawTable = (data: Array<Record<string, any>>): void => { - if (data.length == 0) { - console.log('[]'); - return; - } + if (data.length == 0) { + console.log("[]"); + return; + } + + // Create an object with all the keys in it + const obj = data.reduce((res, item) => ({ ...res, ...item }), {}); + // Get those keys as an array + const keys = Object.keys(obj); + // Create an object with all keys set to the default value '' + const def = keys.reduce((result: Record<string, string>, key) => { + result[key] = "-"; + return result; + }, {}); + // Use object destructuring to replace all default values with the ones we have + data = data.map((item) => ({ ...def, ...item })); - // Create an object with all the keys in it - const obj = data.reduce((res, item) => ({ ...res, ...item }), {}); - // Get those keys as an array - const keys = Object.keys(obj); - // Create an object with all keys set to the default value '' - const def = keys.reduce((result: Record<string, string>, key) => { - result[key] = '-'; - return result; - }, {}); - // Use object destructuring to replace all default values with the ones we have - data = data.map((item) => ({ ...def, ...item })); - - const columns = Object.keys(data[0]); - - const table = new Table({ - head: columns.map((c) => chalk.cyan.italic.bold(c)), - chars: { - top: ' ', - 'top-mid': ' ', - 'top-left': ' ', - 'top-right': ' ', - bottom: ' ', - 'bottom-mid': ' ', - 'bottom-left': ' ', - 'bottom-right': ' ', - left: ' ', - 'left-mid': ' ', - mid: chalk.cyan('─'), - 'mid-mid': chalk.cyan('┼'), - right: ' ', - 'right-mid': ' ', - middle: chalk.cyan('│'), - }, - }); - - data.forEach((row) => { - const rowValues: any[] = []; - for (const key in row) { - if (row[key] === null) { - rowValues.push('-'); - } else if (Array.isArray(row[key])) { - rowValues.push(JSON.stringify(row[key])); - } else if (typeof row[key] === 'object') { - rowValues.push(JSON.stringify(row[key])); - } else { - rowValues.push(row[key]); - } - } - table.push(rowValues); - }); - console.log(table.toString()); + const columns = Object.keys(data[0]); + + const table = new Table({ + head: columns.map((c) => chalk.cyan.italic.bold(c)), + chars: { + top: " ", + "top-mid": " ", + "top-left": " ", + "top-right": " ", + bottom: " ", + "bottom-mid": " ", + "bottom-left": " ", + "bottom-right": " ", + left: " ", + "left-mid": " ", + mid: chalk.cyan("─"), + "mid-mid": chalk.cyan("┼"), + right: " ", + "right-mid": " ", + middle: chalk.cyan("│"), + }, + }); + + data.forEach((row) => { + const rowValues: any[] = []; + for (const key in row) { + if (row[key] === null) { + rowValues.push("-"); + } else if (Array.isArray(row[key])) { + rowValues.push(JSON.stringify(row[key])); + } else if (typeof row[key] === "object") { + rowValues.push(JSON.stringify(row[key])); + } else { + rowValues.push(row[key]); + } + } + table.push(rowValues); + }); + console.log(table.toString()); }; export const drawJSON = (data: any): void => { - console.log(JSON.stringify(data, null, 2)); + console.log(JSON.stringify(data, null, 2)); }; export const parseError = (err: Error): void => { - if (cliConfig.report) { - (async () => { - let appwriteVersion = 'unknown'; - const endpoint = globalConfig.getEndpoint(); - - try { - const client = new Client().setEndpoint(endpoint); - const res = await client.call<{ version: string }>('get', '/health/version'); - appwriteVersion = res.version; - } catch { - // Silently fail - } - - const version = '13.0.0-rc.1'; - const stepsToReproduce = `Running \`appwrite ${(cliConfig.reportData as any).data.args.join(' ')}\``; - const yourEnvironment = `CLI version: ${version}\nOperation System: ${os.type()}\nAppwrite version: ${appwriteVersion}\nIs Cloud: ${isCloud()}`; - - const stack = '```\n' + (err.stack || err.message) + '\n```'; - - const githubIssueUrl = new URL('https://github.com/appwrite/appwrite/issues/new'); - githubIssueUrl.searchParams.append('labels', 'bug'); - githubIssueUrl.searchParams.append('template', 'bug.yaml'); - githubIssueUrl.searchParams.append('title', `🐛 Bug Report: ${err.message}`); - githubIssueUrl.searchParams.append('actual-behavior', `CLI Error:\n${stack}`); - githubIssueUrl.searchParams.append('steps-to-reproduce', stepsToReproduce); - githubIssueUrl.searchParams.append('environment', yourEnvironment); - - log( - `To report this error you can:\n - Create a support ticket in our Discord server https://appwrite.io/discord \n - Create an issue in our Github\n ${githubIssueUrl.href}\n` - ); - - error('\n Stack Trace: \n'); - console.error(err); - process.exit(1); - })(); + if (cliConfig.report) { + (async () => { + let appwriteVersion = "unknown"; + const endpoint = globalConfig.getEndpoint(); + + try { + const client = new Client().setEndpoint(endpoint); + const res = (await client.call( + "get", + new URL("/health/version", endpoint), + )) as { version: string }; + appwriteVersion = res.version; + } catch { + // Silently fail + } + + const version = "13.0.0-rc.2"; + const stepsToReproduce = `Running \`appwrite ${(cliConfig.reportData as any).data.args.join(" ")}\``; + const yourEnvironment = `CLI version: ${version}\nOperation System: ${os.type()}\nAppwrite version: ${appwriteVersion}\nIs Cloud: ${isCloud()}`; + + const stack = "```\n" + (err.stack || err.message) + "\n```"; + + const githubIssueUrl = new URL( + "https://github.com/appwrite/appwrite/issues/new", + ); + githubIssueUrl.searchParams.append("labels", "bug"); + githubIssueUrl.searchParams.append("template", "bug.yaml"); + githubIssueUrl.searchParams.append( + "title", + `🐛 Bug Report: ${err.message}`, + ); + githubIssueUrl.searchParams.append( + "actual-behavior", + `CLI Error:\n${stack}`, + ); + githubIssueUrl.searchParams.append( + "steps-to-reproduce", + stepsToReproduce, + ); + githubIssueUrl.searchParams.append("environment", yourEnvironment); + + log( + `To report this error you can:\n - Create a support ticket in our Discord server https://appwrite.io/discord \n - Create an issue in our Github\n ${githubIssueUrl.href}\n`, + ); + + error("\n Stack Trace: \n"); + console.error(err); + process.exit(1); + })(); + } else { + if (cliConfig.verbose) { + console.error(err); } else { - if (cliConfig.verbose) { - console.error(err); - } else { - log('For detailed error pass the --verbose or --report flag'); - error(err.message); - } - process.exit(1); + log("For detailed error pass the --verbose or --report flag"); + error(err.message); } + process.exit(1); + } }; -export const actionRunner = <T extends (...args: any[]) => Promise<any>>(fn: T): ((...args: Parameters<T>) => Promise<void>) => { - return (...args: Parameters<T>) => { - if (cliConfig.all && Array.isArray(cliConfig.ids) && cliConfig.ids.length !== 0) { - error(`The '--all' and '--id' flags cannot be used together.`); - process.exit(1); - } - return fn(...args).catch(parseError); - }; +export const actionRunner = <T extends (...args: any[]) => Promise<any>>( + fn: T, +): ((...args: Parameters<T>) => Promise<void>) => { + return (...args: Parameters<T>) => { + if ( + cliConfig.all && + Array.isArray(cliConfig.ids) && + cliConfig.ids.length !== 0 + ) { + error(`The '--all' and '--id' flags cannot be used together.`); + process.exit(1); + } + return fn(...args).catch(parseError); + }; }; export const parseInteger = (value: string): number => { - const parsedValue = parseInt(value, 10); - if (isNaN(parsedValue)) { - throw new commander.InvalidArgumentError('Not a number.'); - } - return parsedValue; + const parsedValue = parseInt(value, 10); + if (isNaN(parsedValue)) { + throw new InvalidArgumentError("Not a number."); + } + return parsedValue; }; export const parseBool = (value: string): boolean => { - if (value === 'true') return true; - if (value === 'false') return false; - throw new commander.InvalidArgumentError('Not a boolean.'); + if (value === "true") return true; + if (value === "false") return false; + throw new InvalidArgumentError("Not a boolean."); }; export const log = (message?: string): void => { - console.log(`${chalk.cyan.bold('ℹ Info:')} ${chalk.cyan(message ?? '')}`); + console.log(`${chalk.cyan.bold("ℹ Info:")} ${chalk.cyan(message ?? "")}`); }; export const warn = (message?: string): void => { - console.log(`${chalk.yellow.bold('ℹ Warning:')} ${chalk.yellow(message ?? '')}`); + console.log( + `${chalk.yellow.bold("ℹ Warning:")} ${chalk.yellow(message ?? "")}`, + ); }; export const hint = (message?: string): void => { - console.log(`${chalk.cyan.bold('♥ Hint:')} ${chalk.cyan(message ?? '')}`); + console.log(`${chalk.cyan.bold("♥ Hint:")} ${chalk.cyan(message ?? "")}`); }; export const success = (message?: string): void => { - console.log(`${chalk.green.bold('✓ Success:')} ${chalk.green(message ?? '')}`); + console.log( + `${chalk.green.bold("✓ Success:")} ${chalk.green(message ?? "")}`, + ); }; export const error = (message?: string): void => { - console.error(`${chalk.red.bold('✗ Error:')} ${chalk.red(message ?? '')}`); + console.error(`${chalk.red.bold("✗ Error:")} ${chalk.red(message ?? "")}`); }; -export const logo = "\n _ _ _ ___ __ _____\n \/_\\ _ __ _ ____ ___ __(_) |_ ___ \/ __\\ \/ \/ \\_ \\\n \/\/_\\\\| '_ \\| '_ \\ \\ \/\\ \/ \/ '__| | __\/ _ \\ \/ \/ \/ \/ \/ \/\\\/\n \/ _ \\ |_) | |_) \\ V V \/| | | | || __\/ \/ \/___\/ \/___\/\\\/ \/_\n \\_\/ \\_\/ .__\/| .__\/ \\_\/\\_\/ |_| |_|\\__\\___| \\____\/\\____\/\\____\/\n |_| |_|\n\n"; +export const logo = + "\n _ _ _ ___ __ _____\n \/_\\ _ __ _ ____ ___ __(_) |_ ___ \/ __\\ \/ \/ \\_ \\\n \/\/_\\\\| '_ \\| '_ \\ \\ \/\\ \/ \/ '__| | __\/ _ \\ \/ \/ \/ \/ \/ \/\\\/\n \/ _ \\ |_) | |_) \\ V V \/| | | | || __\/ \/ \/___\/ \/___\/\\\/ \/_\n \\_\/ \\_\/ .__\/| .__\/ \\_\/\\_\/ |_| |_|\\__\\___| \\____\/\\____\/\\____\/\n |_| |_|\n\n"; export const commandDescriptions: Record<string, string> = { - account: `The account command allows you to authenticate and manage a user account.`, - graphql: `The graphql command allows you to query and mutate any resource type on your Appwrite server.`, - avatars: `The avatars command aims to help you complete everyday tasks related to your app image, icons, and avatars.`, - databases: `(Legacy) The databases command allows you to create structured collections of documents and query and filter lists of documents.`, - 'tables-db': `The tables-db command allows you to create structured tables of columns and query and filter lists of rows.`, - init: `The init command provides a convenient wrapper for creating and initializing projects, functions, collections, buckets, teams, and messaging-topics in Appwrite.`, - push: `The push command provides a convenient wrapper for pushing your functions, collections, buckets, teams, and messaging-topics.`, - run: `The run command allows you to run the project locally to allow easy development and quick debugging.`, - functions: `The functions command allows you to view, create, and manage your Cloud Functions.`, - health: `The health command allows you to both validate and monitor your Appwrite server's health.`, - pull: `The pull command helps you pull your Appwrite project, functions, collections, buckets, teams, and messaging-topics`, - locale: `The locale command allows you to customize your app based on your users' location.`, - sites: `The sites command allows you to view, create and manage your Appwrite Sites.`, - storage: `The storage command allows you to manage your project files.`, - teams: `The teams command allows you to group users of your project to enable them to share read and write access to your project resources.`, - update: `The update command allows you to update the Appwrite CLI to the latest version.`, - users: `The users command allows you to manage your project users.`, - projects: `The projects command allows you to manage your projects, add platforms, manage API keys, Dev Keys etc.`, - project: `The project command allows you to manage project related resources like usage, variables, etc.`, - client: `The client command allows you to configure your CLI`, - login: `The login command allows you to authenticate and manage a user account.`, - logout: `The logout command allows you to log out of your Appwrite account.`, - whoami: `The whomai command gives information about the currently logged-in user.`, - register: `Outputs the link to create an Appwrite account.`, - console: `The console command gives you access to the APIs used by the Appwrite Console.`, - messaging: `The messaging command allows you to manage topics and targets and send messages.`, - migrations: `The migrations command allows you to migrate data between services.`, - vcs: `The vcs command allows you to interact with VCS providers and manage your code repositories.`, - main: chalk.redBright(`${logo}${description}`), + account: `The account command allows you to authenticate and manage a user account.`, + graphql: `The graphql command allows you to query and mutate any resource type on your Appwrite server.`, + avatars: `The avatars command aims to help you complete everyday tasks related to your app image, icons, and avatars.`, + databases: `(Legacy) The databases command allows you to create structured collections of documents and query and filter lists of documents.`, + "tables-db": `The tables-db command allows you to create structured tables of columns and query and filter lists of rows.`, + init: `The init command provides a convenient wrapper for creating and initializing projects, functions, collections, buckets, teams, and messaging-topics in Appwrite.`, + push: `The push command provides a convenient wrapper for pushing your functions, collections, buckets, teams, and messaging-topics.`, + run: `The run command allows you to run the project locally to allow easy development and quick debugging.`, + functions: `The functions command allows you to view, create, and manage your Cloud Functions.`, + health: `The health command allows you to both validate and monitor your Appwrite server's health.`, + pull: `The pull command helps you pull your Appwrite project, functions, collections, buckets, teams, and messaging-topics`, + locale: `The locale command allows you to customize your app based on your users' location.`, + sites: `The sites command allows you to view, create and manage your Appwrite Sites.`, + storage: `The storage command allows you to manage your project files.`, + teams: `The teams command allows you to group users of your project to enable them to share read and write access to your project resources.`, + update: `The update command allows you to update the Appwrite CLI to the latest version.`, + users: `The users command allows you to manage your project users.`, + projects: `The projects command allows you to manage your projects, add platforms, manage API keys, Dev Keys etc.`, + project: `The project command allows you to manage project related resources like usage, variables, etc.`, + client: `The client command allows you to configure your CLI`, + login: `The login command allows you to authenticate and manage a user account.`, + logout: `The logout command allows you to log out of your Appwrite account.`, + whoami: `The whomai command gives information about the currently logged-in user.`, + register: `Outputs the link to create an Appwrite account.`, + console: `The console command gives you access to the APIs used by the Appwrite Console.`, + messaging: `The messaging command allows you to manage topics and targets and send messages.`, + migrations: `The migrations command allows you to migrate data between services.`, + vcs: `The vcs command allows you to interact with VCS providers and manage your code repositories.`, + main: chalk.redBright(`${logo}${description}`), }; export { cliConfig }; diff --git a/lib/questions.ts b/lib/questions.ts index f314ba45..2cac8247 100644 --- a/lib/questions.ts +++ b/lib/questions.ts @@ -1,1090 +1,1167 @@ -import chalk from 'chalk'; -import Client from './client'; -import { localConfig, globalConfig } from './config'; -import { projectsList } from './commands/projects'; -import { organizationsList } from './commands/organizations'; -import { teamsList } from './commands/teams'; -import { functionsListRuntimes, functionsListSpecifications, functionsList } from './commands/functions'; -import { accountListMFAFactors } from './commands/account'; -import { sdkForConsole } from './sdks'; -import { validateRequired } from './validations'; -import { paginate } from './paginate'; -import { isPortTaken, checkDeployConditions, isCloud } from './utils'; -import { databasesList } from './commands/databases'; -import JSONbig from 'json-bigint'; -import { sitesListFrameworks, sitesListSpecifications, sitesList } from './commands/sites'; - -const JSONbigConfig = JSONbig({ storeAsString: false }); +import chalk from "chalk"; +import { localConfig, globalConfig } from "./config.js"; +import { sdkForConsole } from "./sdks.js"; +import { validateRequired } from "./validations.js"; +import { paginate } from "./paginate.js"; +import { checkDeployConditions, isCloud } from "./utils.js"; +import { Account, Client } from "@appwrite.io/console"; +import { + getOrganizationsService, + getTeamsService, + getProjectsService, + getFunctionsService, + getSitesService, + getDatabasesService, +} from "./services.js"; interface Answers { - override?: boolean; - method?: string; - start?: string; - organization?: string; - [key: string]: any; + override?: boolean; + method?: string; + start?: string; + organization?: string; + [key: string]: any; } interface Choice { - name: string; - value: any; - disabled?: boolean | string; - current?: boolean; + name: string; + value: any; + disabled?: boolean | string; + current?: boolean; } interface Question { - type: string; - name: string; - message: string; - default?: any; - when?: ((answers: Answers) => boolean | Promise<boolean>) | boolean; - choices?: (() => Promise<Choice[]> | Choice[]) | Choice[]; - validate?: (value: any) => boolean | string | Promise<boolean | string>; - mask?: string; + type: string; + name: string; + message: string; + default?: any; + when?: ((answers: Answers) => boolean | Promise<boolean>) | boolean; + choices?: + | ((answers: Answers) => Promise<Choice[]> | Choice[]) + | (() => Promise<Choice[]> | Choice[]) + | Choice[] + | string[]; + validate?: (value: any) => boolean | string | Promise<boolean | string>; + mask?: string; } -const whenOverride = (answers: Answers): boolean => answers.override === undefined ? true : answers.override; +const whenOverride = (answers: Answers): boolean => + answers.override === undefined ? true : answers.override; const getIgnores = (runtime: string): string[] => { - const languge = runtime.split("-").slice(0, -1).join("-"); - - switch (languge) { - case 'cpp': - return ['build', 'CMakeFiles', 'CMakeCaches.txt']; - case 'dart': - return ['.packages', '.dart_tool']; - case 'deno': - return []; - case 'dotnet': - return ['bin', 'obj', '.nuget']; - case 'java': - case 'kotlin': - return ['build']; - case 'node': - case 'bun': - return ['node_modules', '.npm']; - case 'php': - return ['vendor']; - case 'python': - case 'python-ml': - return ['__pypackages__']; - case 'ruby': - return ['vendor']; - case 'rust': - return ['target', 'debug', '*.rs.bk', '*.pdb']; - case 'swift': - return ['.build', '.swiftpm']; - } - - return []; + const languge = runtime.split("-").slice(0, -1).join("-"); + + switch (languge) { + case "cpp": + return ["build", "CMakeFiles", "CMakeCaches.txt"]; + case "dart": + return [".packages", ".dart_tool"]; + case "deno": + return []; + case "dotnet": + return ["bin", "obj", ".nuget"]; + case "java": + case "kotlin": + return ["build"]; + case "node": + case "bun": + return ["node_modules", ".npm"]; + case "php": + return ["vendor"]; + case "python": + case "python-ml": + return ["__pypackages__"]; + case "ruby": + return ["vendor"]; + case "rust": + return ["target", "debug", "*.rs.bk", "*.pdb"]; + case "swift": + return [".build", ".swiftpm"]; + } + + return []; }; const getEntrypoint = (runtime: string): string | undefined => { - const languge = runtime.split("-").slice(0, -1).join("-"); - - switch (languge) { - case 'dart': - return 'lib/main.dart'; - case 'deno': - return 'src/main.ts'; - case 'node': - return 'src/main.js'; - case 'bun': - return 'src/main.ts'; - case 'php': - return 'src/index.php'; - case 'python': - case 'python-ml': - return 'src/main.py'; - case 'ruby': - return 'lib/main.rb'; - case 'rust': - return 'main.rs'; - case 'swift': - return 'Sources/index.swift'; - case 'cpp': - return 'src/main.cc'; - case 'dotnet': - return 'src/Index.cs'; - case 'java': - return 'src/Main.java'; - case 'kotlin': - return 'src/Main.kt'; - case 'go': - return 'main.go'; - } - - return undefined; + const languge = runtime.split("-").slice(0, -1).join("-"); + + switch (languge) { + case "dart": + return "lib/main.dart"; + case "deno": + return "src/main.ts"; + case "node": + return "src/main.js"; + case "bun": + return "src/main.ts"; + case "php": + return "src/index.php"; + case "python": + case "python-ml": + return "src/main.py"; + case "ruby": + return "lib/main.rb"; + case "rust": + return "main.rs"; + case "swift": + return "Sources/index.swift"; + case "cpp": + return "src/main.cc"; + case "dotnet": + return "src/Index.cs"; + case "java": + return "src/Main.java"; + case "kotlin": + return "src/Main.kt"; + case "go": + return "main.go"; + } + + return undefined; }; const getInstallCommand = (runtime: string): string | undefined => { - const languge = runtime.split("-").slice(0, -1).join("-"); - - switch (languge) { - case 'dart': - return 'dart pub get'; - case 'deno': - return "deno cache src/main.ts"; - case 'node': - return 'npm install'; - case 'bun': - return 'bun install'; - case 'php': - return 'composer install'; - case 'python': - case 'python-ml': - return 'pip install -r requirements.txt'; - case 'ruby': - return 'bundle install'; - case 'rust': - return 'cargo install'; - case 'dotnet': - return 'dotnet restore'; - case 'swift': - case 'java': - case 'kotlin': - case 'cpp': - return ''; - } - - return undefined; + const languge = runtime.split("-").slice(0, -1).join("-"); + + switch (languge) { + case "dart": + return "dart pub get"; + case "deno": + return "deno cache src/main.ts"; + case "node": + return "npm install"; + case "bun": + return "bun install"; + case "php": + return "composer install"; + case "python": + case "python-ml": + return "pip install -r requirements.txt"; + case "ruby": + return "bundle install"; + case "rust": + return "cargo install"; + case "dotnet": + return "dotnet restore"; + case "swift": + case "java": + case "kotlin": + case "cpp": + return ""; + } + + return undefined; }; export const questionsInitProject: Question[] = [ - { - type: "confirm", - name: "override", - message: - `An Appwrite project ( ${localConfig.getProject()['projectId']} ) is already associated with the current directory. Would you like to override`, - when() { - return Object.keys(localConfig.getProject()).length !== 0; - } + { + type: "confirm", + name: "override", + message: `An Appwrite project ( ${localConfig.getProject()["projectId"]} ) is already associated with the current directory. Would you like to override`, + when() { + return Object.keys(localConfig.getProject()).length !== 0; }, - { - type: "list", - name: "start", - when: whenOverride, - message: "How would you like to start?", - choices: [ - { - name: "Create new project", - value: "new" - }, - { - name: "Link directory to an existing project", - value: "existing" - } - ] + }, + { + type: "list", + name: "start", + when: whenOverride, + message: "How would you like to start?", + choices: [ + { + name: "Create new project", + value: "new", + }, + { + name: "Link directory to an existing project", + value: "existing", + }, + ], + }, + { + type: "search-list", + name: "organization", + message: "Choose your organization", + choices: async () => { + let client = await sdkForConsole(true); + const { teams } = isCloud() + ? await paginate( + async (opts: { sdk?: Client } = {}) => + (await getOrganizationsService(opts.sdk)).list(), + { sdk: client }, + 100, + "teams", + ) + : await paginate( + async (opts: { sdk?: Client } = {}) => + (await getTeamsService(opts.sdk)).list(), + { parseOutput: false, sdk: client }, + 100, + "teams", + ); + + let choices = teams.map((team: any, idx: number) => { + return { + name: `${team.name} (${team["$id"]})`, + value: team["$id"], + }; + }); + + if (choices.length == 0) { + throw new Error( + `No organizations found. Please create a new organization at ${globalConfig.getEndpoint().replace("/v1", "/console/onboarding")}`, + ); + } + + return choices; }, - { - type: "search-list", - name: "organization", - message: "Choose your organization", - choices: async () => { - let client = await sdkForConsole(true); - const { teams } = isCloud() - ? await paginate(organizationsList, { parseOutput: false, sdk: client }, 100, 'teams') - : await paginate(teamsList, { parseOutput: false, sdk: client }, 100, 'teams'); - - let choices = teams.map((team: any, idx: number) => { - return { - name: `${team.name} (${team['$id']})`, - value: team['$id'] - } - }) - - if (choices.length == 0) { - throw new Error(`No organizations found. Please create a new organization at ${globalConfig.getEndpoint().replace('/v1', '/console/onboarding')}`) - } - - return choices; - }, - when: whenOverride + when: whenOverride, + }, + { + type: "input", + name: "project", + message: "What would you like to name your project?", + default: "My Awesome Project", + when: (answer: Answers) => answer.start !== "existing", + }, + { + type: "input", + name: "id", + message: "What ID would you like to have for your project?", + default: "unique()", + when: (answer: Answers) => answer.start !== "existing", + }, + { + type: "search-list", + name: "project", + message: "Choose your Appwrite project.", + choices: async (answers: Answers) => { + const queries = [ + JSON.stringify({ + method: "equal", + attribute: "teamId", + values: [answers.organization], + }), + JSON.stringify({ method: "orderDesc", attribute: "$id" }), + ]; + + const { projects } = await paginate( + async () => (await getProjectsService()).list(queries), + { parseOutput: false }, + 100, + "projects", + queries, + ); + + let choices = projects.map((project: any) => { + return { + name: `${project.name} (${project["$id"]})`, + value: { + $id: project["$id"], + region: project.region || "", + }, + }; + }); + + if (choices.length === 0) { + throw new Error("No projects found. Please create a new project."); + } + + return choices; }, - { - type: "input", - name: "project", - message: "What would you like to name your project?", - default: "My Awesome Project", - when: (answer: Answers) => answer.start !== 'existing' - }, - { - type: "input", - name: "id", - message: "What ID would you like to have for your project?", - default: "unique()", - when: (answer: Answers) => answer.start !== 'existing' + when: (answer: Answers) => answer.start === "existing", + }, + { + type: "list", + name: "region", + message: "Select your Appwrite Cloud region", + choices: async () => { + let client = await sdkForConsole(true); + const endpoint = + globalConfig.getEndpoint() || "https://cloud.appwrite.io/v1"; + let response = (await client.call( + "GET", + new URL(endpoint + "/console/regions"), + )) as { regions: any[] }; + let regions = response.regions || []; + if (!regions.length) { + throw new Error( + "No regions found. Please check your network or Appwrite Cloud availability.", + ); + } + return regions + .filter((region: any) => !region.disabled) + .map((region: any) => ({ + name: `${region.name} (${region.$id})`, + value: region.$id, + })); }, - { - type: "search-list", - name: "project", - message: "Choose your Appwrite project.", - choices: async (answers: Answers) => { - const queries = [ - JSON.stringify({ method: 'equal', attribute: 'teamId', values: [answers.organization] }), - JSON.stringify({ method: 'orderDesc', attribute: '$id' }) - ] - - const { projects } = await paginate(projectsList, { parseOutput: false }, 100, 'projects', queries); - - let choices = projects.map((project: any) => { - return { - name: `${project.name} (${project['$id']})`, - value: { - "$id": project['$id'], - "region": project.region || '' - } - } - }) - - if (choices.length === 0) { - throw new Error("No projects found. Please create a new project.") - } - - return choices; - }, - when: (answer: Answers) => answer.start === 'existing' + when: (answer: Answers) => { + if (answer.start === "existing") return false; + return isCloud(); }, - { - type: "list", - name: "region", - message: "Select your Appwrite Cloud region", - choices: async () => { - let client = await sdkForConsole(true); - let response = await client.call("GET", "/console/regions"); - let regions = response.regions || []; - if (!regions.length) { - throw new Error("No regions found. Please check your network or Appwrite Cloud availability."); - } - return regions.filter((region: any) => !region.disabled).map((region: any) => ({ - name: `${region.name} (${region.$id})`, - value: region.$id - })); - }, - when: (answer: Answers) => { - if (answer.start === 'existing') return false; - return isCloud(); - } - } + }, ]; export const questionsInitProjectAutopull: Question[] = [ - { - type: "confirm", - name: "autopull", - message: - `Would you like to pull all resources from project you just linked?` - }, + { + type: "confirm", + name: "autopull", + message: `Would you like to pull all resources from project you just linked?`, + }, ]; export const questionsPullResources: Question[] = [ - { - type: "list", - name: "resource", - message: "Which resources would you like to pull?", - choices: [ - { name: `Settings ${chalk.blackBright(`(Project)`)}`, value: 'settings' }, - { name: `Functions ${chalk.blackBright(`(Deployment)`)}`, value: 'functions' }, - { name: `Tables ${chalk.blackBright(`(TablesDB)`)}`, value: 'tables' }, - { name: `Buckets ${chalk.blackBright(`(Storage)`)}`, value: 'buckets' }, - { name: `Teams ${chalk.blackBright(`(Auth)`)}`, value: 'teams' }, - { name: `Topics ${chalk.blackBright(`(Messaging)`)}`, value: 'messages' }, - { name: `Collections ${chalk.blackBright(`(Legacy Databases)`)}`, value: 'collections' } - ] - } + { + type: "list", + name: "resource", + message: "Which resources would you like to pull?", + choices: [ + { name: `Settings ${chalk.blackBright(`(Project)`)}`, value: "settings" }, + { + name: `Functions ${chalk.blackBright(`(Deployment)`)}`, + value: "functions", + }, + { name: `Tables ${chalk.blackBright(`(TablesDB)`)}`, value: "tables" }, + { name: `Buckets ${chalk.blackBright(`(Storage)`)}`, value: "buckets" }, + { name: `Teams ${chalk.blackBright(`(Auth)`)}`, value: "teams" }, + { name: `Topics ${chalk.blackBright(`(Messaging)`)}`, value: "messages" }, + { + name: `Collections ${chalk.blackBright(`(Legacy Databases)`)}`, + value: "collections", + }, + ], + }, ]; export const questionsPullFunctions: Question[] = [ - { - type: "checkbox", - name: "functions", - message: "Which functions would you like to pull?", - validate: (value: any) => validateRequired('function', value), - choices: async () => { - const { functions } = await paginate(functionsList, { parseOutput: false }, 100, 'functions'); - - if (functions.length === 0) { - throw "We couldn't find any functions in your Appwrite project"; - } - return functions.map((func: any) => { - return { - name: `${func.name} (${func.$id})`, - value: { ...func } - } - }); - } - } + { + type: "checkbox", + name: "functions", + message: "Which functions would you like to pull?", + validate: (value: any) => validateRequired("function", value), + choices: async () => { + const { functions } = await paginate( + async () => (await getFunctionsService()).list(), + { parseOutput: false }, + 100, + "functions", + ); + + if (functions.length === 0) { + throw "We couldn't find any functions in your Appwrite project"; + } + return functions.map((func: any) => { + return { + name: `${func.name} (${func.$id})`, + value: { ...func }, + }; + }); + }, + }, ]; export const questionsPullFunctionsCode: Question[] = [ - { - type: "confirm", - name: "override", - message: "Do you want to pull source code of the latest deployment?" - }, + { + type: "confirm", + name: "override", + message: "Do you want to pull source code of the latest deployment?", + }, ]; export const questionsPullSites: Question[] = [ - { - type: "checkbox", - name: "sites", - message: "Which sites would you like to pull?", - validate: (value: any) => validateRequired('site', value), - choices: async () => { - const { sites } = await paginate(sitesList, { parseOutput: false }, 100, 'sites'); - - if (sites.length === 0) { - throw "We couldn't find any sites in your Appwrite project"; - } - return sites.map((site: any) => { - return { - name: `${site.name} (${site.$id})`, - value: { ...site } - } - }); - } - } + { + type: "checkbox", + name: "sites", + message: "Which sites would you like to pull?", + validate: (value: any) => validateRequired("site", value), + choices: async () => { + const { sites } = await paginate( + async () => (await getSitesService()).list(), + { parseOutput: false }, + 100, + "sites", + ); + + if (sites.length === 0) { + throw "We couldn't find any sites in your Appwrite project"; + } + return sites.map((site: any) => { + return { + name: `${site.name} (${site.$id})`, + value: { ...site }, + }; + }); + }, + }, ]; export const questionsPullSitesCode: Question[] = [ - { - type: "confirm", - name: "override", - message: "Do you want to pull source code of the latest deployment?" - }, + { + type: "confirm", + name: "override", + message: "Do you want to pull source code of the latest deployment?", + }, ]; export const questionsCreateFunction: Question[] = [ - { - type: "input", - name: "name", - message: "What would you like to name your function?", - default: "My Awesome Function" + { + type: "input", + name: "name", + message: "What would you like to name your function?", + default: "My Awesome Function", + }, + { + type: "input", + name: "id", + message: "What ID would you like to have for your function?", + default: "unique()", + }, + { + type: "list", + name: "runtime", + message: "What runtime would you like to use?", + choices: async () => { + let response = await (await getFunctionsService()).listRuntimes(); + let runtimes = response["runtimes"]; + let choices = runtimes.map((runtime: any, idx: number) => { + return { + name: `${runtime.name} (${runtime["$id"]})`, + value: { + id: runtime["$id"], + name: runtime["$id"].split("-")[0], + entrypoint: getEntrypoint(runtime["$id"]), + ignore: getIgnores(runtime["$id"]), + commands: getInstallCommand(runtime["$id"]), + }, + }; + }); + return choices; }, - { - type: "input", - name: "id", - message: "What ID would you like to have for your function?", - default: "unique()" + }, + { + type: "list", + name: "specification", + message: "What specification would you like to use?", + choices: async () => { + let response = await (await getFunctionsService()).listSpecifications(); + let specifications = response["specifications"]; + let choices = specifications.map((spec: any, idx: number) => { + return { + name: `${spec.cpus} CPU, ${spec.memory}MB RAM`, + value: spec.slug, + disabled: spec.enabled === false ? "Upgrade to use" : false, + }; + }); + return choices; }, - { - type: "list", - name: "runtime", - message: "What runtime would you like to use?", - choices: async () => { - let response = await functionsListRuntimes({ - parseOutput: false - }) - let runtimes = response["runtimes"] - let choices = runtimes.map((runtime: any, idx: number) => { - return { - name: `${runtime.name} (${runtime['$id']})`, - value: { - id: runtime['$id'], - name: runtime['$id'].split('-')[0], - entrypoint: getEntrypoint(runtime['$id']), - ignore: getIgnores(runtime['$id']), - commands: getInstallCommand(runtime['$id']) - }, - } - }) - return choices; - }, - }, - { - type: "list", - name: "specification", - message: "What specification would you like to use?", - choices: async () => { - let response = await functionsListSpecifications({ - parseOutput: false - }) - let specifications = response["specifications"] - let choices = specifications.map((spec: any, idx: number) => { - return { - name: `${spec.cpus} CPU, ${spec.memory}MB RAM`, - value: spec.slug, - disabled: spec.enabled === false ? 'Upgrade to use' : false - } - }) - return choices; - }, - } + }, ]; -export const questionsCreateFunctionSelectTemplate = (templates: string[]): Question[] => { - return [ - { - type: "search-list", - name: "template", - message: "What template would you like to use?", - choices: templates.map((template) => { - const name = `${template[0].toUpperCase()}${template.split('').slice(1).join('')}`.replace(/[-_]/g, ' '); - - return { value: template, name } - }) - } - ]; +export const questionsCreateFunctionSelectTemplate = ( + templates: string[], +): Question[] => { + return [ + { + type: "search-list", + name: "template", + message: "What template would you like to use?", + choices: templates.map((template) => { + const name = + `${template[0].toUpperCase()}${template.split("").slice(1).join("")}`.replace( + /[-_]/g, + " ", + ); + + return { value: template, name }; + }), + }, + ]; }; export const questionsCreateBucket: Question[] = [ - { - type: "input", - name: "bucket", - message: "What would you like to name your bucket?", - default: "My Awesome Bucket" - }, - { - type: "input", - name: "id", - message: "What ID would you like to have for your bucket?", - default: "unique()" - }, - { - type: "list", - name: "fileSecurity", - message: "Enable File-Security configuring permissions for individual file", - choices: ["No", "Yes"] - } + { + type: "input", + name: "bucket", + message: "What would you like to name your bucket?", + default: "My Awesome Bucket", + }, + { + type: "input", + name: "id", + message: "What ID would you like to have for your bucket?", + default: "unique()", + }, + { + type: "list", + name: "fileSecurity", + message: "Enable File-Security configuring permissions for individual file", + choices: ["No", "Yes"], + }, ]; export const questionsCreateTeam: Question[] = [ - { - type: "input", - name: "bucket", - message: "What would you like to name your team?", - default: "My Awesome Team" - }, - { - type: "input", - name: "id", - message: "What ID would you like to have for your team?", - default: "unique()" - } + { + type: "input", + name: "bucket", + message: "What would you like to name your team?", + default: "My Awesome Team", + }, + { + type: "input", + name: "id", + message: "What ID would you like to have for your team?", + default: "unique()", + }, ]; export const questionsCreateCollection: Question[] = [ - { - type: "list", - name: "method", - message: "What database would you like to use for your collection", - choices: ["New", "Existing"], - when: async () => { - return localConfig.getDatabases().length !== 0; - } + { + type: "list", + name: "method", + message: "What database would you like to use for your collection", + choices: ["New", "Existing"], + when: async () => { + return localConfig.getDatabases().length !== 0; }, - { - type: "search-list", - name: "database", - message: "Choose the collection database", - choices: async () => { - const databases = localConfig.getDatabases(); - - let choices = databases.map((database: any, idx: number) => { - return { - name: `${database.name} (${database.$id})`, - value: database.$id - } - }) - - if (choices.length === 0) { - throw new Error("No databases found. Please create one in project console.") - } - - return choices; - }, - when: (answers: Answers) => (answers.method ?? '').toLowerCase() === 'existing' - }, - { - type: "input", - name: "databaseName", - message: "What would you like to name your database?", - default: "My Awesome Database", - when: (answers: Answers) => (answers.method ?? '').toLowerCase() !== 'existing' - }, - { - type: "input", - name: "databaseId", - message: "What ID would you like to have for your database?", - default: "unique()", - when: (answers: Answers) => (answers.method ?? '').toLowerCase() !== 'existing' - }, - { - type: "input", - name: "collection", - message: "What would you like to name your collection?", - default: "My Awesome Collection" + }, + { + type: "search-list", + name: "database", + message: "Choose the collection database", + choices: async () => { + const databases = localConfig.getDatabases(); + + let choices = databases.map((database: any, idx: number) => { + return { + name: `${database.name} (${database.$id})`, + value: database.$id, + }; + }); + + if (choices.length === 0) { + throw new Error( + "No databases found. Please create one in project console.", + ); + } + + return choices; }, - { - type: "input", - name: "id", - message: "What ID would you like to have for your collection?", - default: "unique()" - }, - { - type: "list", - name: "documentSecurity", - message: "Enable document security for configuring permissions for individual documents", - choices: ["No", "Yes"] - } + when: (answers: Answers) => + (answers.method ?? "").toLowerCase() === "existing", + }, + { + type: "input", + name: "databaseName", + message: "What would you like to name your database?", + default: "My Awesome Database", + when: (answers: Answers) => + (answers.method ?? "").toLowerCase() !== "existing", + }, + { + type: "input", + name: "databaseId", + message: "What ID would you like to have for your database?", + default: "unique()", + when: (answers: Answers) => + (answers.method ?? "").toLowerCase() !== "existing", + }, + { + type: "input", + name: "collection", + message: "What would you like to name your collection?", + default: "My Awesome Collection", + }, + { + type: "input", + name: "id", + message: "What ID would you like to have for your collection?", + default: "unique()", + }, + { + type: "list", + name: "documentSecurity", + message: + "Enable document security for configuring permissions for individual documents", + choices: ["No", "Yes"], + }, ]; export const questionsCreateTable: Question[] = [ - { - type: "list", - name: "method", - message: "What database would you like to use for your table?", - choices: ["New", "Existing"], - when: async () => { - return localConfig.getTablesDBs().length !== 0; - } + { + type: "list", + name: "method", + message: "What database would you like to use for your table?", + choices: ["New", "Existing"], + when: async () => { + return localConfig.getTablesDBs().length !== 0; }, - { - type: "search-list", - name: "database", - message: "Choose the table database", - choices: async () => { - const databases = localConfig.getTablesDBs(); - - let choices = databases.map((database: any, idx: number) => { - return { - name: `${database.name} (${database.$id})`, - value: database.$id - } - }) - - if (choices.length === 0) { - throw new Error("No databases found. Please create one in project console.") - } - - return choices; - }, - when: (answers: Answers) => (answers.method ?? '').toLowerCase() === 'existing' - }, - { - type: "input", - name: "databaseName", - message: "What would you like to name your database?", - default: "My Awesome Database", - when: (answers: Answers) => (answers.method ?? '').toLowerCase() !== 'existing' + }, + { + type: "search-list", + name: "database", + message: "Choose the table database", + choices: async () => { + const databases = localConfig.getTablesDBs(); + + let choices = databases.map((database: any, idx: number) => { + return { + name: `${database.name} (${database.$id})`, + value: database.$id, + }; + }); + + if (choices.length === 0) { + throw new Error( + "No databases found. Please create one in project console.", + ); + } + + return choices; }, - { - type: "input", - name: "databaseId", - message: "What ID would you like to have for your database?", - default: "unique()", - when: (answers: Answers) => (answers.method ?? '').toLowerCase() !== 'existing' - }, - { - type: "input", - name: "table", - message: "What would you like to name your table?", - default: "My Awesome Table" - }, - { - type: "input", - name: "id", - message: "What ID would you like to have for your table?", - default: "unique()" - }, - { - type: "list", - name: "rowSecurity", - message: "Enable row security for configuring permissions for individual rows", - choices: ["No", "Yes"] - } + when: (answers: Answers) => + (answers.method ?? "").toLowerCase() === "existing", + }, + { + type: "input", + name: "databaseName", + message: "What would you like to name your database?", + default: "My Awesome Database", + when: (answers: Answers) => + (answers.method ?? "").toLowerCase() !== "existing", + }, + { + type: "input", + name: "databaseId", + message: "What ID would you like to have for your database?", + default: "unique()", + when: (answers: Answers) => + (answers.method ?? "").toLowerCase() !== "existing", + }, + { + type: "input", + name: "table", + message: "What would you like to name your table?", + default: "My Awesome Table", + }, + { + type: "input", + name: "id", + message: "What ID would you like to have for your table?", + default: "unique()", + }, + { + type: "list", + name: "rowSecurity", + message: + "Enable row security for configuring permissions for individual rows", + choices: ["No", "Yes"], + }, ]; export const questionsCreateMessagingTopic: Question[] = [ - { - type: "input", - name: "topic", - message: "What would you like to name your messaging topic?", - default: "My Awesome Topic" - }, - { - type: "input", - name: "id", - message: "What ID would you like to have for your messaging topic?", - default: "unique()" - } + { + type: "input", + name: "topic", + message: "What would you like to name your messaging topic?", + default: "My Awesome Topic", + }, + { + type: "input", + name: "id", + message: "What ID would you like to have for your messaging topic?", + default: "unique()", + }, ]; export const questionsPullCollection: Question[] = [ - { - type: "checkbox", - name: "databases", - message: "From which database would you like to pull collections?", - validate: (value: any) => validateRequired('collection', value), - choices: async () => { - let response = await databasesList({ - parseOutput: false - }) - let databases = response["databases"] - - if (databases.length <= 0) { - throw new Error("No databases found. Please create one in project console.") - } - let choices = databases.map((database: any, idx: number) => { - return { - name: `${database.name} (${database.$id})`, - value: database.$id - } - }) - return choices; - } - } + { + type: "checkbox", + name: "databases", + message: "From which database would you like to pull collections?", + validate: (value: any) => validateRequired("collection", value), + choices: async () => { + let response = await (await getDatabasesService()).list(); + let databases = response["databases"]; + + if (databases.length <= 0) { + throw new Error( + "No databases found. Please create one in project console.", + ); + } + let choices = databases.map((database: any, idx: number) => { + return { + name: `${database.name} (${database.$id})`, + value: database.$id, + }; + }); + return choices; + }, + }, ]; export const questionsLogin: Question[] = [ - { - type: "list", - name: "method", - message: "What you like to do?", - choices: [ - { name: 'Login to an account', value: 'login' }, - { name: 'Switch to an account', value: 'select' } - ], - when: () => globalConfig.getSessions().length >= 2 - }, - { - type: "input", - name: "email", - message: "Enter your email", - validate(value: string) { - if (!value) { - return "Please enter your email"; - } - return true; - }, - when: (answers: Answers) => answers.method !== 'select' + { + type: "list", + name: "method", + message: "What you like to do?", + choices: [ + { name: "Login to an account", value: "login" }, + { name: "Switch to an account", value: "select" }, + ], + when: () => globalConfig.getSessions().length >= 2, + }, + { + type: "input", + name: "email", + message: "Enter your email", + validate(value: string) { + if (!value) { + return "Please enter your email"; + } + return true; }, - { - type: "password", - name: "password", - message: "Enter your password", - mask: "*", - validate(value: string) { - if (!value) { - return "Please enter your password"; - } - return true; - }, - when: (answers: Answers) => answers.method !== 'select' + when: (answers: Answers) => answers.method !== "select", + }, + { + type: "password", + name: "password", + message: "Enter your password", + mask: "*", + validate(value: string) { + if (!value) { + return "Please enter your password"; + } + return true; }, - { - type: "search-list", - name: "accountId", - message: "Select an account to use", - choices() { - const sessions = globalConfig.getSessions(); - const current = globalConfig.getCurrentSession(); - - const data: Choice[] = []; - - const longestEmail = sessions.reduce((prev: any, current: any) => (prev && (prev.email ?? '').length > (current.email ?? '').length) ? prev : current).email.length; - - sessions.forEach((session: any) => { - if (session.email) { - data.push({ - current: current === session.id, - value: session.id, - name: `${session.email.padEnd(longestEmail)} ${current === session.id ? chalk.green.bold('current') : ' '.repeat(6)} ${session.endpoint}`, - }); - } - }) - - return data.sort((a, b) => Number(b.current) - Number(a.current)) - }, - when: (answers: Answers) => answers.method === 'select' + when: (answers: Answers) => answers.method !== "select", + }, + { + type: "search-list", + name: "accountId", + message: "Select an account to use", + choices() { + const sessions = globalConfig.getSessions(); + const current = globalConfig.getCurrentSession(); + + const data: Choice[] = []; + + const longestEmail = sessions.reduce((prev: any, current: any) => + prev && (prev.email ?? "").length > (current.email ?? "").length + ? prev + : current, + ).email.length; + + sessions.forEach((session: any) => { + if (session.email) { + data.push({ + current: current === session.id, + value: session.id, + name: `${session.email.padEnd(longestEmail)} ${current === session.id ? chalk.green.bold("current") : " ".repeat(6)} ${session.endpoint}`, + }); + } + }); + + return data.sort((a, b) => Number(b.current) - Number(a.current)); }, + when: (answers: Answers) => answers.method === "select", + }, ]; export const questionGetEndpoint: Question[] = [ - { - type: "input", - name: "endpoint", - message: "Enter the endpoint of your Appwrite server", - default: "http://localhost/v1", - async validate(value: string) { - if (!value) { - return "Please enter a valid endpoint."; - } - let client = new Client().setEndpoint(value); - try { - let response = await client.call('get', '/health/version'); - if (response.version) { - return true; - } else { - throw new Error(); - } - } catch (error) { - return "Invalid endpoint or your Appwrite server is not running as expected."; - } + { + type: "input", + name: "endpoint", + message: "Enter the endpoint of your Appwrite server", + default: "http://localhost/v1", + async validate(value: string) { + if (!value) { + return "Please enter a valid endpoint."; + } + let client = new Client().setEndpoint(value); + try { + let response = (await client.call( + "get", + new URL(value + "/health/version"), + )) as { version?: string }; + if (response.version) { + return true; + } else { + throw new Error(); } - } + } catch (error) { + return "Invalid endpoint or your Appwrite server is not running as expected."; + } + }, + }, ]; export const questionsLogout: Question[] = [ - { - type: "checkbox", - name: "accounts", - message: "Select accounts to logout from", - validate: (value: any) => validateRequired('account', value), - choices() { - const sessions = globalConfig.getSessions(); - const current = globalConfig.getCurrentSession(); - - const data: Choice[] = []; - - const longestEmail = sessions.reduce((prev: any, current: any) => (prev && (prev.email ?? '').length > (current.email ?? '').length) ? prev : current).email.length; - - sessions.forEach((session: any) => { - if (session.email) { - data.push({ - current: current === session.id, - value: session.id, - name: `${session.email.padEnd(longestEmail)} ${current === session.id ? chalk.green.bold('current') : ' '.repeat(6)} ${session.endpoint}`, - }); - } - }) - - return data.sort((a, b) => Number(b.current) - Number(a.current)) + { + type: "checkbox", + name: "accounts", + message: "Select accounts to logout from", + validate: (value: any) => validateRequired("account", value), + choices() { + const sessions = globalConfig.getSessions(); + const current = globalConfig.getCurrentSession(); + + const data: Choice[] = []; + + const longestEmail = sessions.reduce((prev: any, current: any) => + prev && (prev.email ?? "").length > (current.email ?? "").length + ? prev + : current, + ).email.length; + + sessions.forEach((session: any) => { + if (session.email) { + data.push({ + current: current === session.id, + value: session.id, + name: `${session.email.padEnd(longestEmail)} ${current === session.id ? chalk.green.bold("current") : " ".repeat(6)} ${session.endpoint}`, + }); } - } + }); + + return data.sort((a, b) => Number(b.current) - Number(a.current)); + }, + }, ]; export const questionsPushResources: Question[] = [ - { - type: "list", - name: "resource", - message: "Which resources would you like to push?", - choices: [ - { name: `Settings ${chalk.blackBright(`(Project)`)}`, value: 'settings' }, - { name: `Functions ${chalk.blackBright(`(Deployment)`)}`, value: 'functions' }, - { name: `Tables ${chalk.blackBright(`(TablesDB)`)}`, value: 'tables' }, - { name: `Buckets ${chalk.blackBright(`(Storage)`)}`, value: 'buckets' }, - { name: `Teams ${chalk.blackBright(`(Auth)`)}`, value: 'teams' }, - { name: `Topics ${chalk.blackBright(`(Messaging)`)}`, value: 'messages' }, - { name: `Collections ${chalk.blackBright(`(Legacy Databases)`)}`, value: 'collections' } - ] - } + { + type: "list", + name: "resource", + message: "Which resources would you like to push?", + choices: [ + { name: `Settings ${chalk.blackBright(`(Project)`)}`, value: "settings" }, + { + name: `Functions ${chalk.blackBright(`(Deployment)`)}`, + value: "functions", + }, + { name: `Tables ${chalk.blackBright(`(TablesDB)`)}`, value: "tables" }, + { name: `Buckets ${chalk.blackBright(`(Storage)`)}`, value: "buckets" }, + { name: `Teams ${chalk.blackBright(`(Auth)`)}`, value: "teams" }, + { name: `Topics ${chalk.blackBright(`(Messaging)`)}`, value: "messages" }, + { + name: `Collections ${chalk.blackBright(`(Legacy Databases)`)}`, + value: "collections", + }, + ], + }, ]; export const questionsInitResources: Question[] = [ - { - type: "list", - name: "resource", - message: "Which resource would you create?", - choices: [ - { name: 'Function', value: 'function' }, - { name: 'Site', value: 'site' }, - { name: 'Table', value: 'table' }, - { name: 'Bucket', value: 'bucket' }, - { name: 'Team', value: 'team' }, - { name: 'Topic', value: 'message' }, - { name: 'Collection', value: 'collection' } - ] - } + { + type: "list", + name: "resource", + message: "Which resource would you create?", + choices: [ + { name: "Function", value: "function" }, + { name: "Site", value: "site" }, + { name: "Table", value: "table" }, + { name: "Bucket", value: "bucket" }, + { name: "Team", value: "team" }, + { name: "Topic", value: "message" }, + { name: "Collection", value: "collection" }, + ], + }, ]; export const questionsPushSites: Question[] = [ - { - type: "checkbox", - name: "sites", - message: "Which sites would you like to push?", - validate: (value: any) => validateRequired('site', value), - when: () => localConfig.getSites().length > 0, - choices: () => { - let sites = localConfig.getSites(); - checkDeployConditions(localConfig) - let choices = sites.map((site: any, idx: number) => { - return { - name: `${site.name} (${site.$id})`, - value: site.$id - } - }) - return choices; - } + { + type: "checkbox", + name: "sites", + message: "Which sites would you like to push?", + validate: (value: any) => validateRequired("site", value), + when: () => localConfig.getSites().length > 0, + choices: () => { + let sites = localConfig.getSites(); + checkDeployConditions(localConfig); + let choices = sites.map((site: any, idx: number) => { + return { + name: `${site.name} (${site.$id})`, + value: site.$id, + }; + }); + return choices; }, + }, ]; export const questionsPushFunctions: Question[] = [ - { - type: "checkbox", - name: "functions", - message: "Which functions would you like to push?", - validate: (value: any) => validateRequired('function', value), - when: () => localConfig.getFunctions().length > 0, - choices: () => { - let functions = localConfig.getFunctions(); - checkDeployConditions(localConfig) - let choices = functions.map((func: any, idx: number) => { - return { - name: `${func.name} (${func.$id})`, - value: func.$id - } - }) - return choices; - } + { + type: "checkbox", + name: "functions", + message: "Which functions would you like to push?", + validate: (value: any) => validateRequired("function", value), + when: () => localConfig.getFunctions().length > 0, + choices: () => { + let functions = localConfig.getFunctions(); + checkDeployConditions(localConfig); + let choices = functions.map((func: any, idx: number) => { + return { + name: `${func.name} (${func.$id})`, + value: func.$id, + }; + }); + return choices; }, + }, ]; export const questionsPushCollections: Question[] = [ - { - type: "checkbox", - name: "collections", - message: "Which collections would you like to push?", - validate: (value: any) => validateRequired('collection', value), - when: () => localConfig.getCollections().length > 0, - choices: () => { - let collections = localConfig.getCollections(); - checkDeployConditions(localConfig) - - return collections.map((collection: any) => { - return { - name: `${collection.name} (${collection['databaseId']} - ${collection['$id']})`, - value: `${collection['databaseId']}|${collection['$id']}` - } - }); - } - } + { + type: "checkbox", + name: "collections", + message: "Which collections would you like to push?", + validate: (value: any) => validateRequired("collection", value), + when: () => localConfig.getCollections().length > 0, + choices: () => { + let collections = localConfig.getCollections(); + checkDeployConditions(localConfig); + + return collections.map((collection: any) => { + return { + name: `${collection.name} (${collection["databaseId"]} - ${collection["$id"]})`, + value: `${collection["databaseId"]}|${collection["$id"]}`, + }; + }); + }, + }, ]; export const questionsPushTables: Question[] = [ - { - type: "checkbox", - name: "tables", - message: "Which tables would you like to push?", - validate: (value: any) => validateRequired('table', value), - when: () => localConfig.getTables().length > 0, - choices: () => { - let tables = localConfig.getTables(); - checkDeployConditions(localConfig) - - return tables.map((table: any) => { - return { - name: `${table.name} (${table['databaseId']} - ${table['$id']})`, - value: `${table['databaseId']}|${table['$id']}` - } - }); - } - } + { + type: "checkbox", + name: "tables", + message: "Which tables would you like to push?", + validate: (value: any) => validateRequired("table", value), + when: () => localConfig.getTables().length > 0, + choices: () => { + let tables = localConfig.getTables(); + checkDeployConditions(localConfig); + + return tables.map((table: any) => { + return { + name: `${table.name} (${table["databaseId"]} - ${table["$id"]})`, + value: `${table["databaseId"]}|${table["$id"]}`, + }; + }); + }, + }, ]; export const questionPushChanges: Question[] = [ - { - type: "input", - name: "changes", - message: `Are you sure you want to apply these changes? (YES/NO)` - } + { + type: "input", + name: "changes", + message: `Are you sure you want to apply these changes? (YES/NO)`, + }, ]; export const questionPushChangesConfirmation: Question[] = [ - { - type: "input", - name: "changes", - message: `Please type 'YES' or 'NO':` - } + { + type: "input", + name: "changes", + message: `Please type 'YES' or 'NO':`, + }, ]; export const questionsPushBuckets: Question[] = [ - { - type: "checkbox", - name: "buckets", - message: "Which buckets would you like to push?", - validate: (value: any) => validateRequired('bucket', value), - when: () => localConfig.getBuckets().length > 0, - choices: () => { - let buckets = localConfig.getBuckets(); - checkDeployConditions(localConfig) - - return buckets.map((bucket: any) => { - return { - name: `${bucket.name} (${bucket['$id']})`, - value: bucket.$id - } - }); - } - } + { + type: "checkbox", + name: "buckets", + message: "Which buckets would you like to push?", + validate: (value: any) => validateRequired("bucket", value), + when: () => localConfig.getBuckets().length > 0, + choices: () => { + let buckets = localConfig.getBuckets(); + checkDeployConditions(localConfig); + + return buckets.map((bucket: any) => { + return { + name: `${bucket.name} (${bucket["$id"]})`, + value: bucket.$id, + }; + }); + }, + }, ]; export const questionsPushMessagingTopics: Question[] = [ - { - type: "checkbox", - name: "topics", - message: "Which messaging topic would you like to push?", - validate: (value: any) => validateRequired('topics', value), - when: () => localConfig.getMessagingTopics().length > 0, - choices: () => { - let topics = localConfig.getMessagingTopics(); - - return topics.map((topic: any) => { - return { - name: `${topic.name} (${topic['$id']})`, - value: topic.$id - } - }); - } - } + { + type: "checkbox", + name: "topics", + message: "Which messaging topic would you like to push?", + validate: (value: any) => validateRequired("topics", value), + when: () => localConfig.getMessagingTopics().length > 0, + choices: () => { + let topics = localConfig.getMessagingTopics(); + + return topics.map((topic: any) => { + return { + name: `${topic.name} (${topic["$id"]})`, + value: topic.$id, + }; + }); + }, + }, ]; export const questionsGetEntrypoint: Question[] = [ - { - type: "input", - name: "entrypoint", - message: "Enter the entrypoint", - default: null, - validate(value: string) { - if (!value) { - return "Please enter your entrypoint"; - } - return true; - } + { + type: "input", + name: "entrypoint", + message: "Enter the entrypoint", + default: null, + validate(value: string) { + if (!value) { + return "Please enter your entrypoint"; + } + return true; }, + }, ]; export const questionsPushTeams: Question[] = [ - { - type: "checkbox", - name: "teams", - message: "Which teams would you like to push?", - validate: (value: any) => validateRequired('team', value), - when: () => localConfig.getTeams().length > 0, - choices: () => { - let teams = localConfig.getTeams(); - checkDeployConditions(localConfig); - - return teams.map((team: any) => { - return { - name: `${team.name} (${team['$id']})`, - value: team.$id - } - }); - } + { + type: "checkbox", + name: "teams", + message: "Which teams would you like to push?", + validate: (value: any) => validateRequired("team", value), + when: () => localConfig.getTeams().length > 0, + choices: () => { + let teams = localConfig.getTeams(); + checkDeployConditions(localConfig); + + return teams.map((team: any) => { + return { + name: `${team.name} (${team["$id"]})`, + value: team.$id, + }; + }); }, + }, ]; export const questionsListFactors: Question[] = [ - { - type: "list", - name: "factor", - message: "Your account is protected by multi-factor authentication. Please choose one for verification.", - choices: async () => { - let client = await sdkForConsole(false); - const factors = await accountListMFAFactors({ - sdk: client, - parseOutput: false - }); - - const choices = [ - { - name: `Authenticator app (Get a code from a third-party authenticator app)`, - value: 'totp' - }, - { - name: `Email (Get a security code at your Appwrite email address)`, - value: 'email' - }, - { - name: `SMS (Get a security code on your Appwrite phone number)`, - value: 'phone' - }, - { - name: `Recovery code (Use one of your recovery codes for verification)`, - value: 'recoveryCode' - } - ].filter((ch) => factors[ch.value] === true); - - return choices; - } - } + { + type: "list", + name: "factor", + message: + "Your account is protected by multi-factor authentication. Please choose one for verification.", + choices: async () => { + let client = await sdkForConsole(false); + const accountClient = new Account(client); + const factors = await accountClient.listMfaFactors(); + + const choices = [ + { + name: `Authenticator app (Get a code from a third-party authenticator app)`, + value: "totp", + }, + { + name: `Email (Get a security code at your Appwrite email address)`, + value: "email", + }, + { + name: `SMS (Get a security code on your Appwrite phone number)`, + value: "phone", + }, + { + name: `Recovery code (Use one of your recovery codes for verification)`, + value: "recoveryCode", + }, + ].filter((ch) => factors[ch.value] === true); + + return choices; + }, + }, ]; export const questionsMFAChallenge: Question[] = [ - { - type: "input", - name: "otp", - message: "Enter OTP", - validate(value: string) { - if (!value) { - return "Please enter OTP"; - } - return true; - }, - } + { + type: "input", + name: "otp", + message: "Enter OTP", + validate(value: string) { + if (!value) { + return "Please enter OTP"; + } + return true; + }, + }, ]; export const questionsRunFunctions: Question[] = [ - { - type: "list", - name: "function", - message: "Which function would you like to develop locally?", - validate: (value: any) => validateRequired('function', value), - choices: () => { - let functions = localConfig.getFunctions(); - if (functions.length === 0) { - throw new Error("No functions found. Use 'appwrite pull functions' to synchronize existing one, or use 'appwrite init function' to create a new one."); - } - let choices = functions.map((func: any, idx: number) => { - return { - name: `${func.name} (${func.$id})`, - value: func.$id - } - }) - return choices; - } - } + { + type: "list", + name: "function", + message: "Which function would you like to develop locally?", + validate: (value: any) => validateRequired("function", value), + choices: () => { + let functions = localConfig.getFunctions(); + if (functions.length === 0) { + throw new Error( + "No functions found. Use 'appwrite pull functions' to synchronize existing one, or use 'appwrite init function' to create a new one.", + ); + } + let choices = functions.map((func: any, idx: number) => { + return { + name: `${func.name} (${func.$id})`, + value: func.$id, + }; + }); + return choices; + }, + }, ]; export const questionsCreateSite: Question[] = [ - { - type: "input", - name: "name", - message: "What would you like to name your site?", - default: "My Awesome Site" - }, - { - type: "input", - name: "id", - message: "What ID would you like to have for your site?", - default: "unique()" + { + type: "input", + name: "name", + message: "What would you like to name your site?", + default: "My Awesome Site", + }, + { + type: "input", + name: "id", + message: "What ID would you like to have for your site?", + default: "unique()", + }, + { + type: "list", + name: "framework", + message: "What framework would you like to use?", + choices: async () => { + let response = await (await getSitesService()).listFrameworks(); + let frameworks = response["frameworks"]; + let choices = frameworks.map((framework: any) => { + return { + name: `${framework.name} (${framework.key})`, + value: framework, + }; + }); + return choices; }, - { - type: "list", - name: "framework", - message: "What framework would you like to use?", - choices: async () => { - let response = await sitesListFrameworks({ - parseOutput: false - }); - let frameworks = response["frameworks"]; - let choices = frameworks.map((framework: any) => { - return { - name: `${framework.name} (${framework.key})`, - value: framework, - } - }); - return choices; - }, + }, + { + type: "list", + name: "specification", + message: "What specification would you like to use?", + choices: async () => { + let response = await (await getSitesService()).listSpecifications(); + let specifications = response["specifications"]; + let choices = specifications.map((spec: any) => { + return { + name: `${spec.cpus} CPU, ${spec.memory}MB RAM`, + value: spec.slug, + disabled: spec.enabled === false ? "Upgrade to use" : false, + }; + }); + return choices; }, - { - type: "list", - name: "specification", - message: "What specification would you like to use?", - choices: async () => { - let response = await sitesListSpecifications({ - parseOutput: false - }); - let specifications = response["specifications"]; - let choices = specifications.map((spec: any) => { - return { - name: `${spec.cpus} CPU, ${spec.memory}MB RAM`, - value: spec.slug, - disabled: spec.enabled === false ? 'Upgrade to use' : false - } - }); - return choices; - }, - } + }, ]; - diff --git a/lib/sdks.ts b/lib/sdks.ts index 62e5de04..acc60223 100644 --- a/lib/sdks.ts +++ b/lib/sdks.ts @@ -1,55 +1,84 @@ -import Client = require('./client'); -import { globalConfig, localConfig } from './config'; - -export const sdkForConsole = async (requiresAuth: boolean = true): Promise<Client> => { - const client = new Client(); - const endpoint = globalConfig.getEndpoint(); - const cookie = globalConfig.getCookie(); - const selfSigned = globalConfig.getSelfSigned(); - - if (requiresAuth && cookie === '') { - throw new Error('Session not found. Please run `appwrite login` to create a session'); - } - - client - .setEndpoint(endpoint) - .setCookie(cookie) - .setProject('console') - .setSelfSigned(selfSigned) - .setLocale('en-US'); - - return client; +import { globalConfig, localConfig } from "./config.js"; +import { Client } from "@appwrite.io/console"; +import os from "os"; + +export const sdkForConsole = async ( + requiresAuth: boolean = true, +): Promise<Client> => { + const client = new Client(); + const endpoint = globalConfig.getEndpoint() || "https://cloud.appwrite.io/v1"; + const cookie = globalConfig.getCookie(); + const selfSigned = globalConfig.getSelfSigned(); + + if (requiresAuth && cookie === "") { + throw new Error( + "Session not found. Please run `appwrite login` to create a session", + ); + } + + client.headers = { + "x-sdk-name": "Command Line", + "x-sdk-platform": "console", + "x-sdk-language": "cli", + "x-sdk-version": "13.0.0-rc.2", + "user-agent": `AppwriteCLI/13.0.0-rc.2 (${os.type()} ${os.version()}; ${os.arch()})`, + }; + + client + .setEndpoint(endpoint) + .setProject("console") + .setCookie(cookie) + .setSelfSigned(selfSigned) + .setLocale("en-US"); + + return client; }; export const sdkForProject = async (): Promise<Client> => { - const client = new Client(); - const endpoint = localConfig.getEndpoint() || globalConfig.getEndpoint(); - const project = localConfig.getProject().projectId ? localConfig.getProject().projectId : globalConfig.getProject(); - const key = globalConfig.getKey(); - const cookie = globalConfig.getCookie(); - const selfSigned = globalConfig.getSelfSigned(); - - if (!project) { - throw new Error('Project is not set. Please run `appwrite init project` to initialize the current directory with an Appwrite project.'); - } - - client - .setEndpoint(endpoint) - .setProject(project) - .setSelfSigned(selfSigned) - .setLocale('en-US'); - - if (cookie) { - return client - .setCookie(cookie) - .setMode('admin'); - } - - if (key) { - return client - .setKey(key) - .setMode('default'); - } - - throw new Error('Session not found. Please run `appwrite login` to create a session.'); + const client = new Client(); + + const endpoint = + localConfig.getEndpoint() || + globalConfig.getEndpoint() || + "https://cloud.appwrite.io/v1"; + + const project = localConfig.getProject().projectId + ? localConfig.getProject().projectId + : globalConfig.getProject(); + + const key = globalConfig.getKey(); + const cookie = globalConfig.getCookie(); + const selfSigned = globalConfig.getSelfSigned(); + + if (!project) { + throw new Error( + "Project is not set. Please run `appwrite init project` to initialize the current directory with an Appwrite project.", + ); + } + + client.headers = { + "x-sdk-name": "Command Line", + "x-sdk-platform": "console", + "x-sdk-language": "cli", + "x-sdk-version": "13.0.0-rc.2", + "user-agent": `AppwriteCLI/13.0.0-rc.2 (${os.type()} ${os.version()}; ${os.arch()})`, + }; + + client + .setEndpoint(endpoint) + .setProject(project) + .setSelfSigned(selfSigned) + .setLocale("en-US"); + + if (cookie) { + return client.setCookie(cookie).setMode("admin"); + } + + if (key) { + return client.setKey(key).setMode("default"); + } + + throw new Error( + "Session not found. Please run `appwrite login` to create a session.", + ); }; diff --git a/lib/services.ts b/lib/services.ts new file mode 100644 index 00000000..dc02df77 --- /dev/null +++ b/lib/services.ts @@ -0,0 +1,72 @@ +import { sdkForConsole, sdkForProject } from "./sdks.js"; +import { + Client, + Console, + Databases, + Functions, + Messaging, + Organizations, + Projects, + Proxy, + Sites, + Storage, + TablesDB, + Teams, +} from "@appwrite.io/console"; + +export const getConsoleService = async (sdk?: Client): Promise<Console> => { + const client = !sdk ? await sdkForProject() : sdk; + return new Console(client); +}; + +export const getDatabasesService = async (sdk?: Client): Promise<Databases> => { + const client = !sdk ? await sdkForProject() : sdk; + return new Databases(client); +}; + +export const getFunctionsService = async (sdk?: Client): Promise<Functions> => { + const client = !sdk ? await sdkForProject() : sdk; + return new Functions(client); +}; + +export const getMessagingService = async (sdk?: Client): Promise<Messaging> => { + const client = !sdk ? await sdkForProject() : sdk; + return new Messaging(client); +}; + +export const getOrganizationsService = async ( + sdk?: Client, +): Promise<Organizations> => { + const client = !sdk ? await sdkForProject() : sdk; + return new Organizations(client); +}; + +export const getProjectsService = async (sdk?: Client): Promise<Projects> => { + const client = !sdk ? await sdkForConsole() : sdk; + return new Projects(client); +}; + +export const getProxyService = async (sdk?: Client): Promise<Proxy> => { + const client = !sdk ? await sdkForProject() : sdk; + return new Proxy(client); +}; + +export const getSitesService = async (sdk?: Client): Promise<Sites> => { + const client = !sdk ? await sdkForProject() : sdk; + return new Sites(client); +}; + +export const getStorageService = async (sdk?: Client): Promise<Storage> => { + const client = !sdk ? await sdkForProject() : sdk; + return new Storage(client); +}; + +export const getTablesDBService = async (sdk?: Client): Promise<TablesDB> => { + const client = !sdk ? await sdkForProject() : sdk; + return new TablesDB(client); +}; + +export const getTeamsService = async (sdk?: Client): Promise<Teams> => { + const client = !sdk ? await sdkForProject() : sdk; + return new Teams(client); +}; diff --git a/lib/spinner.ts b/lib/spinner.ts index b99036e8..709f4a62 100644 --- a/lib/spinner.ts +++ b/lib/spinner.ts @@ -1,118 +1,131 @@ -import progress = require('cli-progress'); -import chalk = require('chalk'); +import progress from "cli-progress"; +import chalk from "chalk"; -const SPINNER_ARC = 'arc'; -const SPINNER_DOTS = 'dots'; +const SPINNER_ARC = "arc"; +const SPINNER_DOTS = "dots"; interface SpinnerConfig { - interval: number; - frames: string[]; + interval: number; + frames: string[]; } interface SpinnerPayload { - status: string; - resource: string; - id: string; - prefix?: string; - end?: string; - errorMessage?: string; + status: string; + resource: string; + id: string; + prefix?: string; + end?: string; + errorMessage?: string; } const spinners: Record<string, SpinnerConfig> = { - [SPINNER_ARC]: { - interval: 100, - frames: ['◜', '◠', '◝', '◞', '◡', '◟'], - }, - [SPINNER_DOTS]: { - interval: 80, - frames: ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'], - }, + [SPINNER_ARC]: { + interval: 100, + frames: ["◜", "◠", "◝", "◞", "◡", "◟"], + }, + [SPINNER_DOTS]: { + interval: 80, + frames: ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"], + }, }; class Spinner { - static updatesBar: progress.MultiBar; - private bar: progress.SingleBar; - private spinnerInterval?: NodeJS.Timeout; - - static start(clearOnComplete: boolean = true, hideCursor: boolean = true): void { - Spinner.updatesBar = new progress.MultiBar({ - format: this.formatter, - hideCursor, - clearOnComplete, - stopOnComplete: true, - linewrap: true, - noTTYOutput: true, - }); + static updatesBar: progress.MultiBar; + private bar: progress.SingleBar; + private spinnerInterval?: NodeJS.Timeout; + + static start( + clearOnComplete: boolean = true, + hideCursor: boolean = true, + ): void { + Spinner.updatesBar = new progress.MultiBar({ + format: this.formatter, + hideCursor, + clearOnComplete, + stopOnComplete: true, + linewrap: true, + noTTYOutput: true, + }); + } + + static stop(): void { + Spinner.updatesBar.stop(); + } + + static formatter(options: any, params: any, payload: SpinnerPayload): string { + const status = payload.status.padEnd(12); + const middle = `${payload.resource} (${payload.id})`.padEnd(40); + + let prefix = chalk.cyan(payload.prefix ?? "⧗"); + let start = chalk.cyan(status); + let end = chalk.yellow(payload.end ?? ""); + + if (status.toLowerCase().trim() === "pushed") { + start = chalk.greenBright.bold(status); + prefix = chalk.greenBright.bold("✓"); + end = ""; + } else if (status.toLowerCase().trim() === "deploying") { + start = chalk.cyanBright.bold(status); + } else if (status.toLowerCase().trim() === "deployed") { + start = chalk.green.bold(status); + prefix = chalk.green.bold("✓"); + } else if (status.toLowerCase().trim() === "error") { + start = chalk.red.bold(status); + prefix = chalk.red.bold("✗"); + end = chalk.red(payload.errorMessage ?? ""); } - static stop(): void { - Spinner.updatesBar.stop(); + return Spinner.line(prefix, start, middle, end); + } + + static line( + prefix: string, + start: string, + middle: string, + end: string, + separator: string = "•", + ): string { + return `${prefix} ${start} ${separator} ${middle} ${!end ? "" : separator} ${end}`; + } + + constructor( + payload: SpinnerPayload, + total: number = 100, + startValue: number = 0, + ) { + this.bar = Spinner.updatesBar.create(total, startValue, payload); + } + + update(payload: Partial<SpinnerPayload>): this { + this.bar.update(payload); + return this; + } + + fail(payload: Partial<SpinnerPayload>): void { + this.stopSpinner(); + this.update({ status: "Error", ...payload }); + } + + startSpinner(name: string): void { + let spinnerFrame = 1; + const spinner = spinners[name] ?? spinners["dots"]; + + this.spinnerInterval = setInterval(() => { + if (spinnerFrame === spinner.frames.length) spinnerFrame = 1; + this.bar.update({ prefix: spinner.frames[spinnerFrame++] }); + }, spinner.interval); + } + + stopSpinner(): void { + if (this.spinnerInterval) { + clearInterval(this.spinnerInterval); } + } - static formatter(options: any, params: any, payload: SpinnerPayload): string { - const status = payload.status.padEnd(12); - const middle = `${payload.resource} (${payload.id})`.padEnd(40); - - let prefix = chalk.cyan(payload.prefix ?? '⧗'); - let start = chalk.cyan(status); - let end = chalk.yellow(payload.end ?? ''); - - if (status.toLowerCase().trim() === 'pushed') { - start = chalk.greenBright.bold(status); - prefix = chalk.greenBright.bold('✓'); - end = ''; - } else if (status.toLowerCase().trim() === 'deploying') { - start = chalk.cyanBright.bold(status); - } else if (status.toLowerCase().trim() === 'deployed') { - start = chalk.green.bold(status); - prefix = chalk.green.bold('✓'); - } else if (status.toLowerCase().trim() === 'error') { - start = chalk.red.bold(status); - prefix = chalk.red.bold('✗'); - end = chalk.red(payload.errorMessage ?? ''); - } - - return Spinner.line(prefix, start, middle, end); - } - - static line(prefix: string, start: string, middle: string, end: string, separator: string = '•'): string { - return `${prefix} ${start} ${separator} ${middle} ${!end ? '' : separator} ${end}`; - } - - constructor(payload: SpinnerPayload, total: number = 100, startValue: number = 0) { - this.bar = Spinner.updatesBar.create(total, startValue, payload); - } - - update(payload: Partial<SpinnerPayload>): this { - this.bar.update(payload); - return this; - } - - fail(payload: Partial<SpinnerPayload>): void { - this.stopSpinner(); - this.update({ status: 'Error', ...payload }); - } - - startSpinner(name: string): void { - let spinnerFrame = 1; - const spinner = spinners[name] ?? spinners['dots']; - - this.spinnerInterval = setInterval(() => { - if (spinnerFrame === spinner.frames.length) spinnerFrame = 1; - this.bar.update({ prefix: spinner.frames[spinnerFrame++] }); - }, spinner.interval); - } - - stopSpinner(): void { - if (this.spinnerInterval) { - clearInterval(this.spinnerInterval); - } - } - - replaceSpinner(name: string): void { - this.stopSpinner(); - this.startSpinner(name); - } + replaceSpinner(name: string): void { + this.stopSpinner(); + this.startSpinner(name); + } } export { Spinner, SPINNER_ARC, SPINNER_DOTS }; diff --git a/lib/type-generation/attribute.ts b/lib/type-generation/attribute.ts index 62f1f06d..70e5f5c9 100644 --- a/lib/type-generation/attribute.ts +++ b/lib/type-generation/attribute.ts @@ -1,17 +1,18 @@ export const AttributeType = { - STRING: 'string', - INTEGER: 'integer', - FLOAT: 'double', - BOOLEAN: 'boolean', - DATETIME: 'datetime', - EMAIL: 'email', - IP: 'ip', - URL: 'url', - ENUM: 'enum', - RELATIONSHIP: 'relationship', - POINT: 'point', - LINESTRING: 'linestring', - POLYGON: 'polygon', + STRING: "string", + INTEGER: "integer", + FLOAT: "double", + BOOLEAN: "boolean", + DATETIME: "datetime", + EMAIL: "email", + IP: "ip", + URL: "url", + ENUM: "enum", + RELATIONSHIP: "relationship", + POINT: "point", + LINESTRING: "linestring", + POLYGON: "polygon", } as const; -export type AttributeTypeValue = typeof AttributeType[keyof typeof AttributeType]; +export type AttributeTypeValue = + (typeof AttributeType)[keyof typeof AttributeType]; diff --git a/lib/type-generation/languages/csharp.ts b/lib/type-generation/languages/csharp.ts index 8533ca41..ac5459ea 100644 --- a/lib/type-generation/languages/csharp.ts +++ b/lib/type-generation/languages/csharp.ts @@ -1,65 +1,77 @@ -import { AttributeType } from '../attribute'; -import { LanguageMeta, Attribute, Collection } from './language'; +import { AttributeType } from "../attribute.js"; +import { LanguageMeta, Attribute, Collection } from "./language.js"; export class CSharp extends LanguageMeta { - getType(attribute: Attribute, collections?: Collection[], collectionName?: string): string { - let type = ''; - switch (attribute.type) { - case AttributeType.STRING: - case AttributeType.EMAIL: - case AttributeType.DATETIME: - type = 'string'; - if (attribute.format === AttributeType.ENUM) { - type = LanguageMeta.toPascalCase(collectionName!) + LanguageMeta.toPascalCase(attribute.key); - } - break; - case AttributeType.INTEGER: - type = 'long'; - break; - case AttributeType.FLOAT: - type = 'double'; - break; - case AttributeType.BOOLEAN: - type = 'bool'; - break; - case AttributeType.RELATIONSHIP: - const relatedCollection = collections?.find((c) => c.$id === attribute.relatedCollection); - if (!relatedCollection) { - throw new Error(`Related collection with ID '${attribute.relatedCollection}' not found.`); - } - type = LanguageMeta.toPascalCase(relatedCollection.name); - if ( - (attribute.relationType === 'oneToMany' && attribute.side === 'parent') || - (attribute.relationType === 'manyToOne' && attribute.side === 'child') || - attribute.relationType === 'manyToMany' - ) { - type = `List<${type}>`; - } - break; - case AttributeType.POINT: - type = 'List<double>'; - break; - case AttributeType.LINESTRING: - type = 'List<List<double>>'; - break; - case AttributeType.POLYGON: - type = 'List<List<List<double>>>'; - break; - default: - throw new Error(`Unknown attribute type: ${attribute.type}`); + getType( + attribute: Attribute, + collections?: Collection[], + collectionName?: string, + ): string { + let type = ""; + switch (attribute.type) { + case AttributeType.STRING: + case AttributeType.EMAIL: + case AttributeType.DATETIME: + type = "string"; + if (attribute.format === AttributeType.ENUM) { + type = + LanguageMeta.toPascalCase(collectionName!) + + LanguageMeta.toPascalCase(attribute.key); } - if (attribute.array) { - type = `List<${type}>`; + break; + case AttributeType.INTEGER: + type = "long"; + break; + case AttributeType.FLOAT: + type = "double"; + break; + case AttributeType.BOOLEAN: + type = "bool"; + break; + case AttributeType.RELATIONSHIP: + const relatedCollection = collections?.find( + (c) => c.$id === attribute.relatedCollection, + ); + if (!relatedCollection) { + throw new Error( + `Related collection with ID '${attribute.relatedCollection}' not found.`, + ); } - if (!attribute.required) { - type += '?'; + type = LanguageMeta.toPascalCase(relatedCollection.name); + if ( + (attribute.relationType === "oneToMany" && + attribute.side === "parent") || + (attribute.relationType === "manyToOne" && + attribute.side === "child") || + attribute.relationType === "manyToMany" + ) { + type = `List<${type}>`; } - return type; + break; + case AttributeType.POINT: + type = "List<double>"; + break; + case AttributeType.LINESTRING: + type = "List<List<double>>"; + break; + case AttributeType.POLYGON: + type = "List<List<List<double>>>"; + break; + default: + throw new Error(`Unknown attribute type: ${attribute.type}`); + } + if (attribute.array) { + type = `List<${type}>`; } + if (!attribute.required) { + type += "?"; + } + return type; + } - getTemplate(): string { - return `/// This file is auto-generated by the Appwrite CLI. -/// You can regenerate it by running \`appwrite ${process.argv.slice(2).join(' ')}\`. + getTemplate(): string { + return `/// This file is auto-generated by the Appwrite CLI. +/// You can regenerate it by running \`appwrite ${process.argv.slice(2).join(" ")}\`. #nullable enable using System; @@ -172,10 +184,9 @@ public class <%= toPascalCase(collection.name) %> } } `; - } + } - getFileName(collection: Collection): string { - return LanguageMeta.toPascalCase(collection.name) + '.cs'; - } + getFileName(collection: Collection): string { + return LanguageMeta.toPascalCase(collection.name) + ".cs"; + } } - diff --git a/lib/type-generation/languages/dart.ts b/lib/type-generation/languages/dart.ts index 07dacded..0995b911 100644 --- a/lib/type-generation/languages/dart.ts +++ b/lib/type-generation/languages/dart.ts @@ -1,102 +1,116 @@ -import fs = require('fs'); -import path = require('path'); -import { AttributeType } from '../attribute'; -import { LanguageMeta, Attribute, Collection } from './language'; +import fs from "fs"; +import path from "path"; +import { AttributeType } from "../attribute.js"; +import { LanguageMeta, Attribute, Collection } from "./language.js"; export class Dart extends LanguageMeta { - getPackageName(): string { - const pubspecPath = path.join(process.cwd(), 'pubspec.yaml'); - if (fs.existsSync(pubspecPath)) { - const pubspecContent = fs.readFileSync(pubspecPath, 'utf8'); - const lines = pubspecContent.split('\n'); - - const dependenciesIndex = lines.findIndex((line) => line.trim() === 'dependencies:'); - - if (dependenciesIndex !== -1) { - const indent = lines[dependenciesIndex].search(/\S|$/); - const dependencies: string[] = []; - for (let i = dependenciesIndex + 1; i < lines.length; i++) { - const line = lines[i]; - if (line.trim() === '') continue; - - const lineIndent = line.search(/\S|$/); - if (lineIndent <= indent && line.trim() !== '') { - break; - } - - dependencies.push(line.trim()); - } - - if (dependencies.some((dep) => dep.startsWith('dart_appwrite:'))) { - return 'dart_appwrite'; - } - if (dependencies.some((dep) => dep.startsWith('appwrite:'))) { - return 'appwrite'; - } - } + getPackageName(): string { + const pubspecPath = path.join(process.cwd(), "pubspec.yaml"); + if (fs.existsSync(pubspecPath)) { + const pubspecContent = fs.readFileSync(pubspecPath, "utf8"); + const lines = pubspecContent.split("\n"); + + const dependenciesIndex = lines.findIndex( + (line) => line.trim() === "dependencies:", + ); + + if (dependenciesIndex !== -1) { + const indent = lines[dependenciesIndex].search(/\S|$/); + const dependencies: string[] = []; + for (let i = dependenciesIndex + 1; i < lines.length; i++) { + const line = lines[i]; + if (line.trim() === "") continue; + + const lineIndent = line.search(/\S|$/); + if (lineIndent <= indent && line.trim() !== "") { + break; + } + + dependencies.push(line.trim()); } - return 'appwrite'; + if (dependencies.some((dep) => dep.startsWith("dart_appwrite:"))) { + return "dart_appwrite"; + } + if (dependencies.some((dep) => dep.startsWith("appwrite:"))) { + return "appwrite"; + } + } } - getType(attribute: Attribute, collections?: Collection[], collectionName?: string): string { - let type = ''; - switch (attribute.type) { - case AttributeType.STRING: - case AttributeType.EMAIL: - case AttributeType.DATETIME: - type = 'String'; - if (attribute.format === AttributeType.ENUM) { - type = LanguageMeta.toPascalCase(collectionName!) + LanguageMeta.toPascalCase(attribute.key); - } - break; - case AttributeType.INTEGER: - type = 'int'; - break; - case AttributeType.FLOAT: - type = 'double'; - break; - case AttributeType.BOOLEAN: - type = 'bool'; - break; - case AttributeType.RELATIONSHIP: - const relatedCollection = collections?.find((c) => c.$id === attribute.relatedCollection); - if (!relatedCollection) { - throw new Error(`Related collection with ID '${attribute.relatedCollection}' not found.`); - } - type = LanguageMeta.toPascalCase(relatedCollection.name); - if ( - (attribute.relationType === 'oneToMany' && attribute.side === 'parent') || - (attribute.relationType === 'manyToOne' && attribute.side === 'child') || - attribute.relationType === 'manyToMany' - ) { - type = `List<${type}>`; - } - break; - case AttributeType.POINT: - type = 'List<double>'; - break; - case AttributeType.LINESTRING: - type = 'List<List<double>>'; - break; - case AttributeType.POLYGON: - type = 'List<List<List<double>>>'; - break; - default: - throw new Error(`Unknown attribute type: ${attribute.type}`); + return "appwrite"; + } + + getType( + attribute: Attribute, + collections?: Collection[], + collectionName?: string, + ): string { + let type = ""; + switch (attribute.type) { + case AttributeType.STRING: + case AttributeType.EMAIL: + case AttributeType.DATETIME: + type = "String"; + if (attribute.format === AttributeType.ENUM) { + type = + LanguageMeta.toPascalCase(collectionName!) + + LanguageMeta.toPascalCase(attribute.key); } - if (attribute.array) { - type = `List<${type}>`; + break; + case AttributeType.INTEGER: + type = "int"; + break; + case AttributeType.FLOAT: + type = "double"; + break; + case AttributeType.BOOLEAN: + type = "bool"; + break; + case AttributeType.RELATIONSHIP: + const relatedCollection = collections?.find( + (c) => c.$id === attribute.relatedCollection, + ); + if (!relatedCollection) { + throw new Error( + `Related collection with ID '${attribute.relatedCollection}' not found.`, + ); } - if (!attribute.required) { - type += '?'; + type = LanguageMeta.toPascalCase(relatedCollection.name); + if ( + (attribute.relationType === "oneToMany" && + attribute.side === "parent") || + (attribute.relationType === "manyToOne" && + attribute.side === "child") || + attribute.relationType === "manyToMany" + ) { + type = `List<${type}>`; } - return type; + break; + case AttributeType.POINT: + type = "List<double>"; + break; + case AttributeType.LINESTRING: + type = "List<List<double>>"; + break; + case AttributeType.POLYGON: + type = "List<List<List<double>>>"; + break; + default: + throw new Error(`Unknown attribute type: ${attribute.type}`); } + if (attribute.array) { + type = `List<${type}>`; + } + if (!attribute.required) { + type += "?"; + } + return type; + } - getTemplate(): string { - return `// This file is auto-generated by the Appwrite CLI. -// You can regenerate it by running \`appwrite ${process.argv.slice(2).join(' ')}\`. + getTemplate(): string { + return `// This file is auto-generated by the Appwrite CLI. +// You can regenerate it by running \`appwrite ${process.argv.slice(2).join(" ")}\`. <% const __relatedImportsSeen = new Set(); const sortedAttributes = collection.attributes.slice().sort((a, b) => { if (a.required === b.required) return 0; @@ -195,10 +209,9 @@ map['<%= attribute.key %>'] != null ? <%- toPascalCase(collections.find(c => c.$ } } `; - } + } - getFileName(collection: Collection): string { - return LanguageMeta.toSnakeCase(collection.name) + '.dart'; - } + getFileName(collection: Collection): string { + return LanguageMeta.toSnakeCase(collection.name) + ".dart"; + } } - diff --git a/lib/type-generation/languages/java.ts b/lib/type-generation/languages/java.ts index d2aa6a22..bc0e1e59 100644 --- a/lib/type-generation/languages/java.ts +++ b/lib/type-generation/languages/java.ts @@ -1,65 +1,77 @@ -import { AttributeType } from '../attribute'; -import { LanguageMeta, Attribute, Collection } from './language'; +import { AttributeType } from "../attribute.js"; +import { LanguageMeta, Attribute, Collection } from "./language.js"; export class Java extends LanguageMeta { - getType(attribute: Attribute, collections?: Collection[], collectionName?: string): string { - let type = ''; - switch (attribute.type) { - case AttributeType.STRING: - case AttributeType.EMAIL: - case AttributeType.DATETIME: - type = 'String'; - if (attribute.format === AttributeType.ENUM) { - type = LanguageMeta.toPascalCase(collectionName!) + LanguageMeta.toPascalCase(attribute.key); - } - break; - case AttributeType.INTEGER: - type = 'Integer'; - break; - case AttributeType.FLOAT: - type = 'Double'; - break; - case AttributeType.BOOLEAN: - type = 'Boolean'; - break; - case AttributeType.RELATIONSHIP: - const relatedCollection = collections?.find((c) => c.$id === attribute.relatedCollection); - if (!relatedCollection) { - throw new Error(`Related collection with ID '${attribute.relatedCollection}' not found.`); - } - type = LanguageMeta.toPascalCase(relatedCollection.name); - if ( - (attribute.relationType === 'oneToMany' && attribute.side === 'parent') || - (attribute.relationType === 'manyToOne' && attribute.side === 'child') || - attribute.relationType === 'manyToMany' - ) { - type = 'List<' + type + '>'; - } - break; - case AttributeType.POINT: - type = 'List<Double>'; - break; - case AttributeType.LINESTRING: - type = 'List<List<Double>>'; - break; - case AttributeType.POLYGON: - type = 'List<List<List<Double>>>'; - break; - default: - throw new Error(`Unknown attribute type: ${attribute.type}`); + getType( + attribute: Attribute, + collections?: Collection[], + collectionName?: string, + ): string { + let type = ""; + switch (attribute.type) { + case AttributeType.STRING: + case AttributeType.EMAIL: + case AttributeType.DATETIME: + type = "String"; + if (attribute.format === AttributeType.ENUM) { + type = + LanguageMeta.toPascalCase(collectionName!) + + LanguageMeta.toPascalCase(attribute.key); } - if (attribute.array) { - type = 'List<' + type + '>'; + break; + case AttributeType.INTEGER: + type = "Integer"; + break; + case AttributeType.FLOAT: + type = "Double"; + break; + case AttributeType.BOOLEAN: + type = "Boolean"; + break; + case AttributeType.RELATIONSHIP: + const relatedCollection = collections?.find( + (c) => c.$id === attribute.relatedCollection, + ); + if (!relatedCollection) { + throw new Error( + `Related collection with ID '${attribute.relatedCollection}' not found.`, + ); } - return type; + type = LanguageMeta.toPascalCase(relatedCollection.name); + if ( + (attribute.relationType === "oneToMany" && + attribute.side === "parent") || + (attribute.relationType === "manyToOne" && + attribute.side === "child") || + attribute.relationType === "manyToMany" + ) { + type = "List<" + type + ">"; + } + break; + case AttributeType.POINT: + type = "List<Double>"; + break; + case AttributeType.LINESTRING: + type = "List<List<Double>>"; + break; + case AttributeType.POLYGON: + type = "List<List<List<Double>>>"; + break; + default: + throw new Error(`Unknown attribute type: ${attribute.type}`); + } + if (attribute.array) { + type = "List<" + type + ">"; } + return type; + } - getTemplate(): string { - return `package io.appwrite.models; + getTemplate(): string { + return `package io.appwrite.models; /** * This file is auto-generated by the Appwrite CLI. - * You can regenerate it by running \`appwrite ${process.argv.slice(2).join(' ')}\`. + * You can regenerate it by running \`appwrite ${process.argv.slice(2).join(" ")}\`. */ import java.util.Objects; @@ -132,10 +144,9 @@ public class <%- toPascalCase(collection.name) %> { } } `; - } + } - getFileName(collection: Collection): string { - return LanguageMeta.toPascalCase(collection.name) + '.java'; - } + getFileName(collection: Collection): string { + return LanguageMeta.toPascalCase(collection.name) + ".java"; + } } - diff --git a/lib/type-generation/languages/javascript.ts b/lib/type-generation/languages/javascript.ts index 4da31622..7b64bbff 100644 --- a/lib/type-generation/languages/javascript.ts +++ b/lib/type-generation/languages/javascript.ts @@ -1,87 +1,98 @@ -import fs = require('fs'); -import path = require('path'); -import { AttributeType } from '../attribute'; -import { LanguageMeta, Attribute, Collection } from './language'; +import fs from "fs"; +import path from "path"; +import { AttributeType } from "../attribute.js"; +import { LanguageMeta, Attribute, Collection } from "./language.js"; export class JavaScript extends LanguageMeta { - getType(attribute: Attribute, collections?: Collection[]): string { - let type = ''; - switch (attribute.type) { - case AttributeType.STRING: - case AttributeType.EMAIL: - case AttributeType.DATETIME: - case AttributeType.IP: - case AttributeType.URL: - type = 'string'; - if (attribute.format === AttributeType.ENUM) { - type = LanguageMeta.toPascalCase(attribute.key); - } - break; - case AttributeType.INTEGER: - type = 'number'; - break; - case AttributeType.FLOAT: - type = 'number'; - break; - case AttributeType.BOOLEAN: - type = 'boolean'; - break; - case AttributeType.RELATIONSHIP: - const relatedCollection = collections?.find((c) => c.$id === attribute.relatedCollection); - if (!relatedCollection) { - throw new Error(`Related collection with ID '${attribute.relatedCollection}' not found.`); - } - type = LanguageMeta.toPascalCase(relatedCollection.name); - if ( - (attribute.relationType === 'oneToMany' && attribute.side === 'parent') || - (attribute.relationType === 'manyToOne' && attribute.side === 'child') || - attribute.relationType === 'manyToMany' - ) { - type = `${type}[]`; - } - break; - case AttributeType.POINT: - type = 'number[]'; - break; - case AttributeType.LINESTRING: - type = 'number[][]'; - break; - case AttributeType.POLYGON: - type = 'number[][][]'; - break; - default: - throw new Error(`Unknown attribute type: ${attribute.type}`); + getType(attribute: Attribute, collections?: Collection[]): string { + let type = ""; + switch (attribute.type) { + case AttributeType.STRING: + case AttributeType.EMAIL: + case AttributeType.DATETIME: + case AttributeType.IP: + case AttributeType.URL: + type = "string"; + if (attribute.format === AttributeType.ENUM) { + type = LanguageMeta.toPascalCase(attribute.key); } - if (attribute.array) { - type += '[]'; + break; + case AttributeType.INTEGER: + type = "number"; + break; + case AttributeType.FLOAT: + type = "number"; + break; + case AttributeType.BOOLEAN: + type = "boolean"; + break; + case AttributeType.RELATIONSHIP: + const relatedCollection = collections?.find( + (c) => c.$id === attribute.relatedCollection, + ); + if (!relatedCollection) { + throw new Error( + `Related collection with ID '${attribute.relatedCollection}' not found.`, + ); } - if (!attribute.required && attribute.default === null) { - type += ' | null'; + type = LanguageMeta.toPascalCase(relatedCollection.name); + if ( + (attribute.relationType === "oneToMany" && + attribute.side === "parent") || + (attribute.relationType === "manyToOne" && + attribute.side === "child") || + attribute.relationType === "manyToMany" + ) { + type = `${type}[]`; } - return type; + break; + case AttributeType.POINT: + type = "number[]"; + break; + case AttributeType.LINESTRING: + type = "number[][]"; + break; + case AttributeType.POLYGON: + type = "number[][][]"; + break; + default: + throw new Error(`Unknown attribute type: ${attribute.type}`); } - - isSingleFile(): boolean { - return true; + if (attribute.array) { + type += "[]"; + } + if (!attribute.required && attribute.default === null) { + type += " | null"; } + return type; + } - private _getAppwriteDependency(): string { - if (fs.existsSync(path.resolve(process.cwd(), 'package.json'))) { - const packageJsonRaw = fs.readFileSync(path.resolve(process.cwd(), 'package.json')); - const packageJson = JSON.parse(packageJsonRaw.toString('utf-8')); - return packageJson.dependencies && packageJson.dependencies['node-appwrite'] ? 'node-appwrite' : 'appwrite'; - } + isSingleFile(): boolean { + return true; + } - return 'appwrite'; + private _getAppwriteDependency(): string { + if (fs.existsSync(path.resolve(process.cwd(), "package.json"))) { + const packageJsonRaw = fs.readFileSync( + path.resolve(process.cwd(), "package.json"), + ); + const packageJson = JSON.parse(packageJsonRaw.toString("utf-8")); + return packageJson.dependencies && + packageJson.dependencies["node-appwrite"] + ? "node-appwrite" + : "appwrite"; } - getTemplate(): string { - return `/** + return "appwrite"; + } + + getTemplate(): string { + return `/** * @typedef {import('${this._getAppwriteDependency()}').Models.Row} Row */ // This file is auto-generated by the Appwrite CLI. -// You can regenerate it by running \`appwrite ${process.argv.slice(2).join(' ')}\`. +// You can regenerate it by running \`appwrite ${process.argv.slice(2).join(" ")}\`. <% for (const collection of collections) { -%> <% for (const attribute of collection.attributes) { -%> @@ -103,9 +114,9 @@ export class JavaScript extends LanguageMeta { <% if (index < collections.length - 1) { %> <% } -%> <% } %>`; - } + } - getFileName(_: Collection | undefined): string { - return 'appwrite-types.js'; - } + getFileName(_: Collection | undefined): string { + return "appwrite-types.js"; + } } diff --git a/lib/type-generation/languages/kotlin.ts b/lib/type-generation/languages/kotlin.ts index a2dbf173..bc398e20 100644 --- a/lib/type-generation/languages/kotlin.ts +++ b/lib/type-generation/languages/kotlin.ts @@ -1,64 +1,76 @@ -import { AttributeType } from '../attribute'; -import { LanguageMeta, Attribute, Collection } from './language'; +import { AttributeType } from "../attribute.js"; +import { LanguageMeta, Attribute, Collection } from "./language.js"; export class Kotlin extends LanguageMeta { - getType(attribute: Attribute, collections?: Collection[], collectionName?: string): string { - let type = ''; - switch (attribute.type) { - case AttributeType.STRING: - case AttributeType.EMAIL: - case AttributeType.DATETIME: - type = 'String'; - if (attribute.format === AttributeType.ENUM) { - type = LanguageMeta.toPascalCase(collectionName!) + LanguageMeta.toPascalCase(attribute.key); - } - break; - case AttributeType.INTEGER: - type = 'Int'; - break; - case AttributeType.FLOAT: - type = 'Float'; - break; - case AttributeType.BOOLEAN: - type = 'Boolean'; - break; - case AttributeType.RELATIONSHIP: - const relatedCollection = collections?.find((c) => c.$id === attribute.relatedCollection); - if (!relatedCollection) { - throw new Error(`Related collection with ID '${attribute.relatedCollection}' not found.`); - } - type = LanguageMeta.toPascalCase(relatedCollection.name); - if ( - (attribute.relationType === 'oneToMany' && attribute.side === 'parent') || - (attribute.relationType === 'manyToOne' && attribute.side === 'child') || - attribute.relationType === 'manyToMany' - ) { - type = `List<${type}>`; - } - break; - case AttributeType.POINT: - type = 'List<Double>'; - break; - case AttributeType.LINESTRING: - type = 'List<List<Double>>'; - break; - case AttributeType.POLYGON: - type = 'List<List<List<Double>>>'; - break; - default: - throw new Error(`Unknown attribute type: ${attribute.type}`); + getType( + attribute: Attribute, + collections?: Collection[], + collectionName?: string, + ): string { + let type = ""; + switch (attribute.type) { + case AttributeType.STRING: + case AttributeType.EMAIL: + case AttributeType.DATETIME: + type = "String"; + if (attribute.format === AttributeType.ENUM) { + type = + LanguageMeta.toPascalCase(collectionName!) + + LanguageMeta.toPascalCase(attribute.key); } - if (attribute.array) { - type = 'List<' + type + '>'; + break; + case AttributeType.INTEGER: + type = "Int"; + break; + case AttributeType.FLOAT: + type = "Float"; + break; + case AttributeType.BOOLEAN: + type = "Boolean"; + break; + case AttributeType.RELATIONSHIP: + const relatedCollection = collections?.find( + (c) => c.$id === attribute.relatedCollection, + ); + if (!relatedCollection) { + throw new Error( + `Related collection with ID '${attribute.relatedCollection}' not found.`, + ); } - if (!attribute.required && attribute.default === null) { - type += '?'; + type = LanguageMeta.toPascalCase(relatedCollection.name); + if ( + (attribute.relationType === "oneToMany" && + attribute.side === "parent") || + (attribute.relationType === "manyToOne" && + attribute.side === "child") || + attribute.relationType === "manyToMany" + ) { + type = `List<${type}>`; } - return type; + break; + case AttributeType.POINT: + type = "List<Double>"; + break; + case AttributeType.LINESTRING: + type = "List<List<Double>>"; + break; + case AttributeType.POLYGON: + type = "List<List<List<Double>>>"; + break; + default: + throw new Error(`Unknown attribute type: ${attribute.type}`); } + if (attribute.array) { + type = "List<" + type + ">"; + } + if (!attribute.required && attribute.default === null) { + type += "?"; + } + return type; + } - getTemplate(): string { - return `package io.appwrite.models + getTemplate(): string { + return `package io.appwrite.models <% for (const attribute of collection.attributes) { -%> <% if (attribute.type === 'relationship') { -%> @@ -68,7 +80,7 @@ import <%- toPascalCase(collections.find(c => c.$id === attribute.relatedCollect <% } -%> /** * This file is auto-generated by the Appwrite CLI. - * You can regenerate it by running \`appwrite ${process.argv.slice(2).join(' ')}\`. + * You can regenerate it by running \`appwrite ${process.argv.slice(2).join(" ")}\`. */ <% for (const attribute of collection.attributes) { -%> @@ -87,10 +99,9 @@ data class <%- toPascalCase(collection.name) %>( <% } -%> ) `; - } + } - getFileName(collection: Collection): string { - return LanguageMeta.toPascalCase(collection.name) + '.kt'; - } + getFileName(collection: Collection): string { + return LanguageMeta.toPascalCase(collection.name) + ".kt"; + } } - diff --git a/lib/type-generation/languages/language.ts b/lib/type-generation/languages/language.ts index 4b6a84e6..62224d85 100644 --- a/lib/type-generation/languages/language.ts +++ b/lib/type-generation/languages/language.ts @@ -1,119 +1,127 @@ -import fs = require('fs'); -import path = require('path'); +import fs from "fs"; +import path from "path"; export interface Attribute { - key: string; - type: string; - required?: boolean; - array?: boolean; - default?: any; - format?: string; - elements?: string[]; - relatedCollection?: string; - relationType?: string; - side?: string; + key: string; + type: string; + required?: boolean; + array?: boolean; + default?: any; + format?: string; + elements?: string[]; + relatedCollection?: string; + relationType?: string; + side?: string; } export interface Collection { - $id: string; - name: string; - attributes: Attribute[]; + $id: string; + name: string; + attributes: Attribute[]; } export abstract class LanguageMeta { - constructor() { - if (new.target === LanguageMeta) { - throw new TypeError("Abstract classes can't be instantiated."); - } + constructor() { + if (new.target === LanguageMeta) { + throw new TypeError("Abstract classes can't be instantiated."); } + } - static toKebabCase(string: string): string { - return string - .replace(/[^a-zA-Z0-9\s-_]/g, '') // Remove invalid characters - .replace(/([a-z])([A-Z])/g, '$1-$2') // Add hyphen between camelCase - .replace(/([A-Z])([A-Z][a-z])/g, '$1-$2') // Add hyphen between PascalCase - .replace(/[_\s]+/g, '-') // Replace spaces and underscores with hyphens - .replace(/^-+|-+$/g, '') // Remove leading and trailing hyphens - .replace(/--+/g, '-') // Replace multiple hyphens with a single hyphen - .toLowerCase(); - } + static toKebabCase(string: string): string { + return string + .replace(/[^a-zA-Z0-9\s-_]/g, "") // Remove invalid characters + .replace(/([a-z])([A-Z])/g, "$1-$2") // Add hyphen between camelCase + .replace(/([A-Z])([A-Z][a-z])/g, "$1-$2") // Add hyphen between PascalCase + .replace(/[_\s]+/g, "-") // Replace spaces and underscores with hyphens + .replace(/^-+|-+$/g, "") // Remove leading and trailing hyphens + .replace(/--+/g, "-") // Replace multiple hyphens with a single hyphen + .toLowerCase(); + } - static toSnakeCase(string: string): string { - return this.toKebabCase(string).replace(/-/g, '_'); - } + static toSnakeCase(string: string): string { + return this.toKebabCase(string).replace(/-/g, "_"); + } - static toUpperSnakeCase(string: string): string { - return this.toSnakeCase(string).toUpperCase(); - } + static toUpperSnakeCase(string: string): string { + return this.toSnakeCase(string).toUpperCase(); + } - static toCamelCase(string: string): string { - return this.toKebabCase(string).replace(/-([a-z0-9])/g, (g) => g[1].toUpperCase()); - } + static toCamelCase(string: string): string { + return this.toKebabCase(string).replace(/-([a-z0-9])/g, (g) => + g[1].toUpperCase(), + ); + } - static toPascalCase(string: string): string { - return this.toCamelCase(string).replace(/^./, (g) => g.toUpperCase()); - } + static toPascalCase(string: string): string { + return this.toCamelCase(string).replace(/^./, (g) => g.toUpperCase()); + } - /** - * Get the type literal of the given attribute. - */ - abstract getType(attribute: Attribute, collections?: Collection[], collectionName?: string): string; + /** + * Get the type literal of the given attribute. + */ + abstract getType( + attribute: Attribute, + collections?: Collection[], + collectionName?: string, + ): string; - /** - * Returns true if the language uses a single file for all types. - */ - isSingleFile(): boolean { - return false; - } + /** + * Returns true if the language uses a single file for all types. + */ + isSingleFile(): boolean { + return false; + } - /** - * Get the EJS template used to generate the types for this language. - */ - abstract getTemplate(): string; + /** + * Get the EJS template used to generate the types for this language. + */ + abstract getTemplate(): string; - /** - * Get the file extension used by files of this language. - */ - abstract getFileName(collection?: Collection): string; + /** + * Get the file extension used by files of this language. + */ + abstract getFileName(collection?: Collection): string; } const existsFiles = (...files: string[]): boolean => - files.some((file) => fs.existsSync(path.join(process.cwd(), file))); + files.some((file) => fs.existsSync(path.join(process.cwd(), file))); export function detectLanguage(): string { - if (existsFiles('tsconfig.json', 'deno.json')) { - return 'ts'; - } - if (existsFiles('package.json')) { - return 'js'; - } - if (existsFiles('composer.json')) { - return 'php'; - } - if (existsFiles('requirements.txt', 'Pipfile', 'pyproject.toml')) { - return 'python'; - } - if (existsFiles('Gemfile', 'Rakefile')) { - return 'ruby'; - } - if (existsFiles('build.gradle.kts')) { - return 'kotlin'; - } - if (existsFiles('build.gradle', 'pom.xml')) { - return 'java'; - } - try { - if (fs.readdirSync(process.cwd()).some((file) => file.endsWith('.csproj'))) { - return 'dotnet'; - } - } catch { - // Directory not readable, skip .csproj detection - } - if (existsFiles('Package.swift')) { - return 'swift'; - } - if (existsFiles('pubspec.yaml')) { - return 'dart'; - } - throw new Error('Could not detect language, please specify with -l'); + if (existsFiles("tsconfig.json", "deno.json")) { + return "ts"; + } + if (existsFiles("package.json")) { + return "js"; + } + if (existsFiles("composer.json")) { + return "php"; + } + if (existsFiles("requirements.txt", "Pipfile", "pyproject.toml")) { + return "python"; + } + if (existsFiles("Gemfile", "Rakefile")) { + return "ruby"; + } + if (existsFiles("build.gradle.kts")) { + return "kotlin"; + } + if (existsFiles("build.gradle", "pom.xml")) { + return "java"; + } + try { + if ( + fs.readdirSync(process.cwd()).some((file) => file.endsWith(".csproj")) + ) { + return "dotnet"; + } + } catch { + // Directory not readable, skip .csproj detection + } + if (existsFiles("Package.swift")) { + return "swift"; + } + if (existsFiles("pubspec.yaml")) { + return "dart"; + } + throw new Error("Could not detect language, please specify with -l"); } diff --git a/lib/type-generation/languages/php.ts b/lib/type-generation/languages/php.ts index 942f0225..7814d747 100644 --- a/lib/type-generation/languages/php.ts +++ b/lib/type-generation/languages/php.ts @@ -1,64 +1,76 @@ -import { AttributeType } from '../attribute'; -import { LanguageMeta, Attribute, Collection } from './language'; +import { AttributeType } from "../attribute.js"; +import { LanguageMeta, Attribute, Collection } from "./language.js"; export class PHP extends LanguageMeta { - getType(attribute: Attribute, collections?: Collection[], collectionName?: string): string { - if (attribute.array) { - return 'array'; + getType( + attribute: Attribute, + collections?: Collection[], + collectionName?: string, + ): string { + if (attribute.array) { + return "array"; + } + let type = ""; + switch (attribute.type) { + case AttributeType.STRING: + case AttributeType.EMAIL: + case AttributeType.DATETIME: + type = "string"; + if (attribute.format === AttributeType.ENUM) { + type = + LanguageMeta.toPascalCase(collectionName!) + + LanguageMeta.toPascalCase(attribute.key); } - let type = ''; - switch (attribute.type) { - case AttributeType.STRING: - case AttributeType.EMAIL: - case AttributeType.DATETIME: - type = 'string'; - if (attribute.format === AttributeType.ENUM) { - type = LanguageMeta.toPascalCase(collectionName!) + LanguageMeta.toPascalCase(attribute.key); - } - break; - case AttributeType.INTEGER: - type = 'int'; - break; - case AttributeType.FLOAT: - type = 'float'; - break; - case AttributeType.BOOLEAN: - type = 'bool'; - break; - case AttributeType.RELATIONSHIP: - const relatedCollection = collections?.find((c) => c.$id === attribute.relatedCollection); - if (!relatedCollection) { - throw new Error(`Related collection with ID '${attribute.relatedCollection}' not found.`); - } - type = LanguageMeta.toPascalCase(relatedCollection.name); - if ( - (attribute.relationType === 'oneToMany' && attribute.side === 'parent') || - (attribute.relationType === 'manyToOne' && attribute.side === 'child') || - attribute.relationType === 'manyToMany' - ) { - type = 'array'; - } - break; - case AttributeType.POINT: - case AttributeType.LINESTRING: - case AttributeType.POLYGON: - type = 'array'; - break; - default: - throw new Error(`Unknown attribute type: ${attribute.type}`); + break; + case AttributeType.INTEGER: + type = "int"; + break; + case AttributeType.FLOAT: + type = "float"; + break; + case AttributeType.BOOLEAN: + type = "bool"; + break; + case AttributeType.RELATIONSHIP: + const relatedCollection = collections?.find( + (c) => c.$id === attribute.relatedCollection, + ); + if (!relatedCollection) { + throw new Error( + `Related collection with ID '${attribute.relatedCollection}' not found.`, + ); } - if (!attribute.required && attribute.default === null) { - type += '|null'; + type = LanguageMeta.toPascalCase(relatedCollection.name); + if ( + (attribute.relationType === "oneToMany" && + attribute.side === "parent") || + (attribute.relationType === "manyToOne" && + attribute.side === "child") || + attribute.relationType === "manyToMany" + ) { + type = "array"; } - return type; + break; + case AttributeType.POINT: + case AttributeType.LINESTRING: + case AttributeType.POLYGON: + type = "array"; + break; + default: + throw new Error(`Unknown attribute type: ${attribute.type}`); + } + if (!attribute.required && attribute.default === null) { + type += "|null"; } + return type; + } - getTemplate(): string { - return `<?php + getTemplate(): string { + return `<?php namespace Appwrite\\Models; // This file is auto-generated by the Appwrite CLI. -// You can regenerate it by running \`appwrite ${process.argv.slice(2).join(' ')}\`. +// You can regenerate it by running \`appwrite ${process.argv.slice(2).join(" ")}\`. <% for (const attribute of collection.attributes) { -%> <% if (attribute.type === 'relationship' && !(attribute.relationType === 'manyToMany') && !(attribute.relationType === 'oneToMany' && attribute.side === 'parent')) { -%> @@ -108,10 +120,9 @@ class <%- toPascalCase(collection.name) %> { <% } -%> } `; - } + } - getFileName(collection: Collection): string { - return LanguageMeta.toPascalCase(collection.name) + '.php'; - } + getFileName(collection: Collection): string { + return LanguageMeta.toPascalCase(collection.name) + ".php"; + } } - diff --git a/lib/type-generation/languages/swift.ts b/lib/type-generation/languages/swift.ts index 4910dc4f..7f293ec8 100644 --- a/lib/type-generation/languages/swift.ts +++ b/lib/type-generation/languages/swift.ts @@ -1,67 +1,79 @@ -import { AttributeType } from '../attribute'; -import { LanguageMeta, Attribute, Collection } from './language'; +import { AttributeType } from "../attribute.js"; +import { LanguageMeta, Attribute, Collection } from "./language.js"; export class Swift extends LanguageMeta { - getType(attribute: Attribute, collections?: Collection[], collectionName?: string): string { - let type = ''; - switch (attribute.type) { - case AttributeType.STRING: - case AttributeType.EMAIL: - case AttributeType.DATETIME: - type = 'String'; - if (attribute.format === AttributeType.ENUM) { - type = LanguageMeta.toPascalCase(collectionName!) + LanguageMeta.toPascalCase(attribute.key); - } - break; - case AttributeType.INTEGER: - type = 'Int'; - break; - case AttributeType.FLOAT: - type = 'Double'; - break; - case AttributeType.BOOLEAN: - type = 'Bool'; - break; - case AttributeType.RELATIONSHIP: - const relatedCollection = collections?.find((c) => c.$id === attribute.relatedCollection); - if (!relatedCollection) { - throw new Error(`Related collection with ID '${attribute.relatedCollection}' not found.`); - } - type = LanguageMeta.toPascalCase(relatedCollection.name); - if ( - (attribute.relationType === 'oneToMany' && attribute.side === 'parent') || - (attribute.relationType === 'manyToOne' && attribute.side === 'child') || - attribute.relationType === 'manyToMany' - ) { - type = `[${type}]`; - } - break; - case AttributeType.POINT: - type = '[Double]'; - break; - case AttributeType.LINESTRING: - type = '[[Double]]'; - break; - case AttributeType.POLYGON: - type = '[[[Double]]]'; - break; - default: - throw new Error(`Unknown attribute type: ${attribute.type}`); + getType( + attribute: Attribute, + collections?: Collection[], + collectionName?: string, + ): string { + let type = ""; + switch (attribute.type) { + case AttributeType.STRING: + case AttributeType.EMAIL: + case AttributeType.DATETIME: + type = "String"; + if (attribute.format === AttributeType.ENUM) { + type = + LanguageMeta.toPascalCase(collectionName!) + + LanguageMeta.toPascalCase(attribute.key); } - if (attribute.array) { - type = '[' + type + ']'; + break; + case AttributeType.INTEGER: + type = "Int"; + break; + case AttributeType.FLOAT: + type = "Double"; + break; + case AttributeType.BOOLEAN: + type = "Bool"; + break; + case AttributeType.RELATIONSHIP: + const relatedCollection = collections?.find( + (c) => c.$id === attribute.relatedCollection, + ); + if (!relatedCollection) { + throw new Error( + `Related collection with ID '${attribute.relatedCollection}' not found.`, + ); } - if (!attribute.required && attribute.default === null) { - type += '?'; + type = LanguageMeta.toPascalCase(relatedCollection.name); + if ( + (attribute.relationType === "oneToMany" && + attribute.side === "parent") || + (attribute.relationType === "manyToOne" && + attribute.side === "child") || + attribute.relationType === "manyToMany" + ) { + type = `[${type}]`; } - return type; + break; + case AttributeType.POINT: + type = "[Double]"; + break; + case AttributeType.LINESTRING: + type = "[[Double]]"; + break; + case AttributeType.POLYGON: + type = "[[[Double]]]"; + break; + default: + throw new Error(`Unknown attribute type: ${attribute.type}`); } + if (attribute.array) { + type = "[" + type + "]"; + } + if (!attribute.required && attribute.default === null) { + type += "?"; + } + return type; + } - getTemplate(): string { - return `import Foundation + getTemplate(): string { + return `import Foundation /// This file is auto-generated by the Appwrite CLI. -/// You can regenerate it by running \`appwrite ${process.argv.slice(2).join(' ')}\`. +/// You can regenerate it by running \`appwrite ${process.argv.slice(2).join(" ")}\`. <% for (const attribute of collection.attributes) { -%> <% if (attribute.format === 'enum') { -%> @@ -171,10 +183,9 @@ public class <%- toPascalCase(collection.name) %>: Codable { ) } }`; - } + } - getFileName(collection: Collection): string { - return LanguageMeta.toPascalCase(collection.name) + '.swift'; - } + getFileName(collection: Collection): string { + return LanguageMeta.toPascalCase(collection.name) + ".swift"; + } } - diff --git a/lib/type-generation/languages/typescript.ts b/lib/type-generation/languages/typescript.ts index b28f2c0d..154a3d25 100644 --- a/lib/type-generation/languages/typescript.ts +++ b/lib/type-generation/languages/typescript.ts @@ -1,89 +1,106 @@ -import fs = require('fs'); -import path = require('path'); -import { AttributeType } from '../attribute'; -import { LanguageMeta, Attribute, Collection } from './language'; +import fs from "fs"; +import path from "path"; +import { AttributeType } from "../attribute.js"; +import { LanguageMeta, Attribute, Collection } from "./language.js"; export class TypeScript extends LanguageMeta { - getType(attribute: Attribute, collections?: Collection[], collectionName?: string): string { - let type = ''; - switch (attribute.type) { - case AttributeType.STRING: - case AttributeType.EMAIL: - case AttributeType.DATETIME: - case AttributeType.IP: - case AttributeType.URL: - type = 'string'; - if (attribute.format === AttributeType.ENUM) { - type = LanguageMeta.toPascalCase(collectionName!) + LanguageMeta.toPascalCase(attribute.key); - } - break; - case AttributeType.INTEGER: - type = 'number'; - break; - case AttributeType.FLOAT: - type = 'number'; - break; - case AttributeType.BOOLEAN: - type = 'boolean'; - break; - case AttributeType.RELATIONSHIP: - const relatedCollection = collections?.find((c) => c.$id === attribute.relatedCollection); - if (!relatedCollection) { - throw new Error(`Related collection with ID '${attribute.relatedCollection}' not found.`); - } - type = LanguageMeta.toPascalCase(relatedCollection.name); - if ( - (attribute.relationType === 'oneToMany' && attribute.side === 'parent') || - (attribute.relationType === 'manyToOne' && attribute.side === 'child') || - attribute.relationType === 'manyToMany' - ) { - type = `${type}[]`; - } - break; - case AttributeType.POINT: - type = 'Array<number>'; - break; - case AttributeType.LINESTRING: - type = 'Array<Array<number>>'; - break; - case AttributeType.POLYGON: - type = 'Array<Array<Array<number>>>'; - break; - default: - throw new Error(`Unknown attribute type: ${attribute.type}`); + getType( + attribute: Attribute, + collections?: Collection[], + collectionName?: string, + ): string { + let type = ""; + switch (attribute.type) { + case AttributeType.STRING: + case AttributeType.EMAIL: + case AttributeType.DATETIME: + case AttributeType.IP: + case AttributeType.URL: + type = "string"; + if (attribute.format === AttributeType.ENUM) { + type = + LanguageMeta.toPascalCase(collectionName!) + + LanguageMeta.toPascalCase(attribute.key); } - if (attribute.array) { - type += '[]'; + break; + case AttributeType.INTEGER: + type = "number"; + break; + case AttributeType.FLOAT: + type = "number"; + break; + case AttributeType.BOOLEAN: + type = "boolean"; + break; + case AttributeType.RELATIONSHIP: + const relatedCollection = collections?.find( + (c) => c.$id === attribute.relatedCollection, + ); + if (!relatedCollection) { + throw new Error( + `Related collection with ID '${attribute.relatedCollection}' not found.`, + ); } - if (!attribute.required && attribute.default === null) { - type += ' | null'; + type = LanguageMeta.toPascalCase(relatedCollection.name); + if ( + (attribute.relationType === "oneToMany" && + attribute.side === "parent") || + (attribute.relationType === "manyToOne" && + attribute.side === "child") || + attribute.relationType === "manyToMany" + ) { + type = `${type}[]`; } - return type; + break; + case AttributeType.POINT: + type = "Array<number>"; + break; + case AttributeType.LINESTRING: + type = "Array<Array<number>>"; + break; + case AttributeType.POLYGON: + type = "Array<Array<Array<number>>>"; + break; + default: + throw new Error(`Unknown attribute type: ${attribute.type}`); } - - isSingleFile(): boolean { - return true; + if (attribute.array) { + type += "[]"; + } + if (!attribute.required && attribute.default === null) { + type += " | null"; } + return type; + } - private _getAppwriteDependency(): string { - if (fs.existsSync(path.resolve(process.cwd(), 'package.json'))) { - const packageJsonRaw = fs.readFileSync(path.resolve(process.cwd(), 'package.json')); - const packageJson = JSON.parse(packageJsonRaw.toString('utf-8')); - return packageJson.dependencies && packageJson.dependencies['node-appwrite'] ? 'node-appwrite' : 'appwrite'; - } + isSingleFile(): boolean { + return true; + } - if (fs.existsSync(path.resolve(process.cwd(), 'deno.json'))) { - return 'https://deno.land/x/appwrite/mod.ts'; - } + private _getAppwriteDependency(): string { + if (fs.existsSync(path.resolve(process.cwd(), "package.json"))) { + const packageJsonRaw = fs.readFileSync( + path.resolve(process.cwd(), "package.json"), + ); + const packageJson = JSON.parse(packageJsonRaw.toString("utf-8")); + return packageJson.dependencies && + packageJson.dependencies["node-appwrite"] + ? "node-appwrite" + : "appwrite"; + } - return 'appwrite'; + if (fs.existsSync(path.resolve(process.cwd(), "deno.json"))) { + return "https://deno.land/x/appwrite/mod.ts"; } - getTemplate(): string { - return `import type { Models } from '${this._getAppwriteDependency()}'; + return "appwrite"; + } + + getTemplate(): string { + return `import type { Models } from '${this._getAppwriteDependency()}'; // This file is auto-generated by the Appwrite CLI. -// You can regenerate it by running \`appwrite ${process.argv.slice(2).join(' ')}\`. +// You can regenerate it by running \`appwrite ${process.argv.slice(2).join(" ")}\`. <% for (const collection of collections) { -%> <% for (const attribute of collection.attributes) { -%> @@ -108,9 +125,9 @@ export type <%- toPascalCase(collection.name) %> = Models.Row & { }<% if (index < collections.length - 1) { %> <% } %> <% } -%>`; - } + } - getFileName(_: Collection | undefined): string { - return 'appwrite.d.ts'; - } + getFileName(_: Collection | undefined): string { + return "appwrite.d.ts"; + } } diff --git a/lib/types.ts b/lib/types.ts index dee317a9..4ef751a5 100644 --- a/lib/types.ts +++ b/lib/types.ts @@ -1,150 +1,304 @@ -export interface CliConfig { - verbose: boolean; - json: boolean; - force: boolean; - all: boolean; - ids: string[]; - report: boolean; - reportData: Record<string, unknown>; -} +import type { File } from "undici"; +import type { ReadableStream } from "node:stream/web"; +import type { Models } from "@appwrite.io/console"; + +export type ResponseType = "json" | "arraybuffer"; export interface Headers { - [key: string]: string; + [key: string]: string; } export interface RequestParams { - [key: string]: unknown; + [key: string]: unknown; } export interface FileUpload { - type: 'file'; - file: Buffer | ReadableStream; - filename: string; + type: "file"; + file: File; + filename: string; +} + +export interface FileInput { + type: "file"; + stream: ReadableStream; + filename: string; + size: number; } -export type ResponseType = 'json' | 'arraybuffer'; +export interface UploadProgress { + $id: string; + progress: number; + sizeUploaded: number; + chunksTotal: number; + chunksUploaded: number; +} export interface ConfigData { - [key: string]: unknown; + [key: string]: unknown; +} + +export interface Entity { + $id: string; + [key: string]: unknown; +} + +export interface ParsedData { + [key: string]: unknown; +} + +export interface CommandDescription { + [key: string]: string; +} + +export interface CliConfig { + verbose: boolean; + json: boolean; + force: boolean; + all: boolean; + ids: string[]; + report: boolean; + reportData: Record<string, unknown>; } export interface SessionData { - endpoint: string; - email?: string; - phone?: string; - cookie?: string; + endpoint: string; + email?: string; + phone?: string; + cookie?: string; } -export interface GlobalConfigData { - sessions: { - [key: string]: SessionData; - }; - current: string; - cookie?: string; +export interface GlobalConfigData extends ConfigData { + sessions: { + [key: string]: SessionData; + }; + current: string; + cookie?: string; } -export interface ProjectConfigData { - projectId?: string; - projectName?: string; - functions?: FunctionConfig[]; - collections?: CollectionConfig[]; - databases?: DatabaseConfig[]; - buckets?: BucketConfig[]; - teams?: TeamConfig[]; - topics?: TopicConfig[]; +export interface ProjectSettings { + services?: { + account?: boolean; + avatars?: boolean; + databases?: boolean; + locale?: boolean; + health?: boolean; + storage?: boolean; + teams?: boolean; + users?: boolean; + sites?: boolean; + functions?: boolean; + graphql?: boolean; + messaging?: boolean; + }; + auth?: { + methods?: { + jwt?: boolean; + phone?: boolean; + invites?: boolean; + anonymous?: boolean; + "email-otp"?: boolean; + "magic-url"?: boolean; + "email-password"?: boolean; + }; + security?: { + duration?: number; + limit?: number; + sessionsLimit?: number; + passwordHistory?: number; + passwordDictionary?: boolean; + personalDataCheck?: boolean; + sessionAlerts?: boolean; + mockNumbers?: Models.MockNumber[]; + }; + }; } -export interface FunctionConfig { - $id: string; - name: string; - runtime: string; - path: string; - entrypoint: string; - execute?: string[]; - enabled?: boolean; - logging?: boolean; - events?: string[]; - schedule?: string; - timeout?: number; - vars?: Record<string, string>; - commands?: string; - scopes?: string[]; - specification?: string; +export interface RawProjectSettings { + serviceStatusForAccount?: boolean; + serviceStatusForAvatars?: boolean; + serviceStatusForDatabases?: boolean; + serviceStatusForLocale?: boolean; + serviceStatusForHealth?: boolean; + serviceStatusForStorage?: boolean; + serviceStatusForTeams?: boolean; + serviceStatusForUsers?: boolean; + serviceStatusForSites?: boolean; + serviceStatusForFunctions?: boolean; + serviceStatusForGraphql?: boolean; + serviceStatusForMessaging?: boolean; + authJWT?: boolean; + authPhone?: boolean; + authInvites?: boolean; + authAnonymous?: boolean; + authEmailOtp?: boolean; + authUsersAuthMagicURL?: boolean; + authEmailPassword?: boolean; + authDuration?: number; + authLimit?: number; + authSessionsLimit?: number; + authPasswordHistory?: number; + authPasswordDictionary?: boolean; + authPersonalDataCheck?: boolean; + authSessionAlerts?: boolean; + authMockNumbers?: Models.MockNumber[]; } -export interface CollectionConfig { - $id: string; - $permissions?: string[]; - databaseId: string; - name: string; - enabled?: boolean; - documentSecurity?: boolean; - attributes?: AttributeConfig[]; - indexes?: IndexConfig[]; +export interface DatabaseConfig { + $id: string; + name: string; + enabled?: boolean; } export interface AttributeConfig { - key: string; - type: string; - required?: boolean; - array?: boolean; - size?: number; - default?: unknown; - min?: number; - max?: number; - format?: string; - elements?: string[]; - relatedCollection?: string; - relationType?: string; - twoWay?: boolean; - twoWayKey?: string; - onDelete?: string; - side?: string; - encrypt?: boolean; + key: string; + type: string; + required?: boolean; + array?: boolean; + size?: number; + default?: unknown; + min?: number; + max?: number; + format?: string; + elements?: string[]; + relatedCollection?: string; + relationType?: string; + twoWay?: boolean; + twoWayKey?: string; + onDelete?: string; + side?: string; + encrypt?: boolean; } export interface IndexConfig { - key: string; - type: string; - status?: string; - attributes?: string[]; - orders?: string[]; + key: string; + type: string; + status?: string; + attributes?: string[]; + orders?: string[]; } -export interface DatabaseConfig { - $id: string; - name: string; - enabled?: boolean; +export interface CollectionConfig { + $id: string; + $permissions?: string[]; + databaseId: string; + name: string; + enabled?: boolean; + documentSecurity?: boolean; + attributes?: AttributeConfig[]; + indexes?: IndexConfig[]; +} + +export interface ColumnConfig { + key: string; + type: string; + required?: boolean; + array?: boolean; + size?: number; + default?: unknown; + min?: number; + max?: number; + format?: string; + elements?: string[]; + relatedTable?: string; + relationType?: string; + twoWay?: boolean; + twoWayKey?: string; + onDelete?: string; + side?: string; + encrypt?: boolean; +} + +export interface TableIndexConfig { + key: string; + type: string; + status?: string; + columns?: string[]; + orders?: string[]; +} + +export interface TableConfig { + $id: string; + $permissions?: string[]; + databaseId: string; + name: string; + enabled?: boolean; + rowSecurity?: boolean; + columns?: ColumnConfig[]; + indexes?: TableIndexConfig[]; } export interface BucketConfig { - $id: string; - $permissions?: string[]; - name: string; - enabled?: boolean; - fileSecurity?: boolean; - maximumFileSize?: number; - allowedFileExtensions?: string[]; - compression?: string; - encryption?: boolean; - antivirus?: boolean; + $id: string; + $permissions?: string[]; + name: string; + enabled?: boolean; + fileSecurity?: boolean; + maximumFileSize?: number; + allowedFileExtensions?: string[]; + compression?: string; + encryption?: boolean; + antivirus?: boolean; } -export interface TeamConfig { - $id: string; - name: string; +export interface FunctionConfig { + $id: string; + name: string; + runtime: string; + path: string; + entrypoint: string; + execute?: string[]; + enabled?: boolean; + logging?: boolean; + events?: string[]; + schedule?: string; + timeout?: number; + vars?: Record<string, string>; + commands?: string; + scopes?: string[]; + specification?: string; + ignore?: string; } -export interface TopicConfig { - $id: string; - name: string; - subscribe?: string[]; +export interface SiteConfig { + $id: string; + name: string; + path: string; + enabled?: boolean; + logging?: boolean; + timeout?: number; + framework: string; + buildRuntime?: string; + adapter?: string; + installCommand?: string; + buildCommand?: string; + outputDirectory?: string; + fallbackFile?: string; + specification?: string; + vars?: Record<string, string>; + ignore?: string; } -export interface CommandDescription { - [key: string]: string; +export interface TeamConfig { + $id: string; + name: string; } -export interface ParsedData { - [key: string]: unknown; +export interface TopicConfig { + $id: string; + name: string; + subscribe?: string[]; +} + +export interface ProjectConfigData extends ConfigData { + projectId?: string; + projectName?: string; + settings?: ProjectSettings; + functions?: FunctionConfig[]; + collections?: CollectionConfig[]; + databases?: DatabaseConfig[]; + buckets?: BucketConfig[]; + teams?: TeamConfig[]; + topics?: TopicConfig[]; + sites?: SiteConfig[]; + tables?: TableConfig[]; } diff --git a/lib/utils.ts b/lib/utils.ts index 92180a74..734c30ef 100644 --- a/lib/utils.ts +++ b/lib/utils.ts @@ -1,322 +1,352 @@ -import fs = require('fs'); -import path = require('path'); -import net = require('net'); -import childProcess = require('child_process'); -import chalk = require('chalk'); -import { fetch } from 'undici'; -import { localConfig, globalConfig } from './config'; +import fs from "fs"; +import path from "path"; +import net from "net"; +import childProcess from "child_process"; +import chalk from "chalk"; +import { fetch } from "undici"; +import { localConfig, globalConfig } from "./config.js"; /** * Get the latest version from npm registry */ export async function getLatestVersion(): Promise<string> { - try { - const response = await fetch('https://registry.npmjs.org/appwrite-cli/latest'); - if (!response.ok) { - throw new Error(`HTTP ${response.status}`); - } - const data = await response.json() as { version: string }; - return data.version; - } catch (e) { - throw new Error(`Failed to fetch latest version: ${(e as Error).message}`); - } + try { + const response = await fetch( + "https://registry.npmjs.org/appwrite-cli/latest", + ); + if (!response.ok) { + throw new Error(`HTTP ${response.status}`); + } + const data = (await response.json()) as { version: string }; + return data.version; + } catch (e) { + throw new Error(`Failed to fetch latest version: ${(e as Error).message}`); + } } /** * Compare versions using semantic versioning */ export function compareVersions(current: string, latest: string): number { - const currentParts = current.split('.').map(Number); - const latestParts = latest.split('.').map(Number); + const currentParts = current.split(".").map(Number); + const latestParts = latest.split(".").map(Number); - for (let i = 0; i < Math.max(currentParts.length, latestParts.length); i++) { - const currentPart = currentParts[i] || 0; - const latestPart = latestParts[i] || 0; + for (let i = 0; i < Math.max(currentParts.length, latestParts.length); i++) { + const currentPart = currentParts[i] || 0; + const latestPart = latestParts[i] || 0; - if (latestPart > currentPart) return 1; // Latest is newer - if (latestPart < currentPart) return -1; // Current is newer - } + if (latestPart > currentPart) return 1; // Latest is newer + if (latestPart < currentPart) return -1; // Current is newer + } - return 0; // Same version + return 0; // Same version } export function getAllFiles(folder: string): string[] { - const files: string[] = []; - for (const pathDir of fs.readdirSync(folder)) { - const pathAbsolute = path.join(folder, pathDir); - let stats: fs.Stats; - try { - stats = fs.statSync(pathAbsolute); - } catch (error) { - continue; - } - if (stats.isDirectory()) { - files.push(...getAllFiles(pathAbsolute)); - } else { - files.push(pathAbsolute); - } + const files: string[] = []; + for (const pathDir of fs.readdirSync(folder)) { + const pathAbsolute = path.join(folder, pathDir); + let stats: fs.Stats; + try { + stats = fs.statSync(pathAbsolute); + } catch (error) { + continue; + } + if (stats.isDirectory()) { + files.push(...getAllFiles(pathAbsolute)); + } else { + files.push(pathAbsolute); } - return files; + } + return files; } export async function isPortTaken(port: number): Promise<boolean> { - const taken = await new Promise<boolean>((res, rej) => { - const tester = net - .createServer() - .once('error', function (err: NodeJS.ErrnoException) { - if (err.code != 'EADDRINUSE') return rej(err); - res(true); - }) - .once('listening', function () { - tester - .once('close', function () { - res(false); - }) - .close(); - }) - .listen(port); - }); - - return taken; + const taken = await new Promise<boolean>((res, rej) => { + const tester = net + .createServer() + .once("error", function (err: NodeJS.ErrnoException) { + if (err.code != "EADDRINUSE") return rej(err); + res(true); + }) + .once("listening", function () { + tester + .once("close", function () { + res(false); + }) + .close(); + }) + .listen(port); + }); + + return taken; } export function systemHasCommand(command: string): boolean { - const isUsingWindows = process.platform == 'win32'; - - try { - if (isUsingWindows) { - childProcess.execSync('where ' + command, { stdio: 'pipe' }); - } else { - childProcess.execSync(`[[ $(${command} --version) ]] || { exit 1; } && echo "OK"`, { - stdio: 'pipe', - shell: '/bin/bash', - }); - } - } catch (error) { - console.log(error); - return false; - } - - return true; + const isUsingWindows = process.platform == "win32"; + + try { + if (isUsingWindows) { + childProcess.execSync("where " + command, { stdio: "pipe" }); + } else { + childProcess.execSync( + `[[ $(${command} --version) ]] || { exit 1; } && echo "OK"`, + { + stdio: "pipe", + shell: "/bin/bash", + }, + ); + } + } catch (error) { + console.log(error); + return false; + } + + return true; } export const checkDeployConditions = (localConfig: any): void => { - if (Object.keys(localConfig.data).length === 0) { - throw new Error( - "No appwrite.config.json file found in the current directory. Please run this command again in the folder containing your appwrite.config.json file, or run 'appwrite init project' to link current directory to an Appwrite project." - ); - } + if (Object.keys(localConfig.data).length === 0) { + throw new Error( + "No appwrite.config.json file found in the current directory. Please run this command again in the folder containing your appwrite.config.json file, or run 'appwrite init project' to link current directory to an Appwrite project.", + ); + } }; -export function showConsoleLink(serviceName: string, action: string, ...ids: string[]): void { - const projectId = localConfig.getProject().projectId; - - const url = new URL(globalConfig.getEndpoint().replace('/v1', '/console')); - url.pathname += `/project-${projectId}`; - action = action.toLowerCase(); - - switch (serviceName) { - case 'account': - url.pathname = url.pathname.replace(`/project-${projectId}`, ''); - url.pathname += getAccountPath(action); - break; - case 'databases': - url.pathname += getDatabasePath(action, ids); - break; - case 'functions': - url.pathname += getFunctionsPath(action, ids); - break; - case 'messaging': - url.pathname += getMessagingPath(action, ids); - break; - case 'projects': - url.pathname = url.pathname.replace(`/project-${projectId}`, ''); - url.pathname += getProjectsPath(action, ids); - break; - case 'storage': - url.pathname += getBucketsPath(action, ids); - break; - case 'teams': - url.pathname += getTeamsPath(action, ids); - break; - case 'organizations': - url.pathname += getOrganizationsPath(action, ids); - break; - case 'users': - url.pathname += getUsersPath(action, ids); - break; - default: - return; - } - - console.log(`${chalk.green.bold('✓ Success:')} ${chalk.green(url.toString())}`); +export function showConsoleLink( + serviceName: string, + action: string, + ...ids: string[] +): void { + const projectId = localConfig.getProject().projectId; + + const url = new URL(globalConfig.getEndpoint().replace("/v1", "/console")); + url.pathname += `/project-${projectId}`; + action = action.toLowerCase(); + + switch (serviceName) { + case "account": + url.pathname = url.pathname.replace(`/project-${projectId}`, ""); + url.pathname += getAccountPath(action); + break; + case "databases": + url.pathname += getDatabasePath(action, ids); + break; + case "functions": + url.pathname += getFunctionsPath(action, ids); + break; + case "messaging": + url.pathname += getMessagingPath(action, ids); + break; + case "projects": + url.pathname = url.pathname.replace(`/project-${projectId}`, ""); + url.pathname += getProjectsPath(action, ids); + break; + case "storage": + url.pathname += getBucketsPath(action, ids); + break; + case "teams": + url.pathname += getTeamsPath(action, ids); + break; + case "organizations": + url.pathname += getOrganizationsPath(action, ids); + break; + case "users": + url.pathname += getUsersPath(action, ids); + break; + default: + return; + } + + console.log( + `${chalk.green.bold("✓ Success:")} ${chalk.green(url.toString())}`, + ); } function getAccountPath(action: string): string { - let path = '/account'; + let path = "/account"; - if (action === 'listsessions') { - path += '/sessions'; - } + if (action === "listsessions") { + path += "/sessions"; + } - return path; + return path; } function getDatabasePath(action: string, ids: string[]): string { - let path = '/databases'; - - if (['get', 'listcollections', 'getcollection', 'listattributes', 'listdocuments', 'getdocument', 'listindexes', 'getdatabaseusage'].includes(action)) { - path += `/database-${ids[0]}`; - } - - if (action === 'getdatabaseusage') { - path += `/usage`; - } - - if (['getcollection', 'listattributes', 'listdocuments', 'getdocument', 'listindexes'].includes(action)) { - path += `/collection-${ids[1]}`; - } - - if (action === 'listattributes') { - path += '/attributes'; - } - if (action === 'listindexes') { - path += '/indexes'; - } - if (action === 'getdocument') { - path += `/document-${ids[2]}`; - } - - return path; + let path = "/databases"; + + if ( + [ + "get", + "listcollections", + "getcollection", + "listattributes", + "listdocuments", + "getdocument", + "listindexes", + "getdatabaseusage", + ].includes(action) + ) { + path += `/database-${ids[0]}`; + } + + if (action === "getdatabaseusage") { + path += `/usage`; + } + + if ( + [ + "getcollection", + "listattributes", + "listdocuments", + "getdocument", + "listindexes", + ].includes(action) + ) { + path += `/collection-${ids[1]}`; + } + + if (action === "listattributes") { + path += "/attributes"; + } + if (action === "listindexes") { + path += "/indexes"; + } + if (action === "getdocument") { + path += `/document-${ids[2]}`; + } + + return path; } function getFunctionsPath(action: string, ids: string[]): string { - let path = '/functions'; + let path = "/functions"; - if (action !== 'list') { - path += `/function-${ids[0]}`; - } + if (action !== "list") { + path += `/function-${ids[0]}`; + } - if (action === 'getdeployment') { - path += `/deployment-${ids[1]}`; - } + if (action === "getdeployment") { + path += `/deployment-${ids[1]}`; + } - if (action === 'getexecution' || action === 'listexecution') { - path += `/executions`; - } - if (action === 'getfunctionusage') { - path += `/usage`; - } + if (action === "getexecution" || action === "listexecution") { + path += `/executions`; + } + if (action === "getfunctionusage") { + path += `/usage`; + } - return path; + return path; } function getMessagingPath(action: string, ids: string[]): string { - let path = '/messaging'; + let path = "/messaging"; - if (['getmessage', 'listmessagelogs'].includes(action)) { - path += `/message-${ids[0]}`; - } + if (["getmessage", "listmessagelogs"].includes(action)) { + path += `/message-${ids[0]}`; + } - if (['listproviders', 'getprovider'].includes(action)) { - path += `/providers`; - } + if (["listproviders", "getprovider"].includes(action)) { + path += `/providers`; + } - if (action === 'getprovider') { - path += `/provider-${ids[0]}`; - } + if (action === "getprovider") { + path += `/provider-${ids[0]}`; + } - if (['listtopics', 'gettopic'].includes(action)) { - path += `/topics`; - } + if (["listtopics", "gettopic"].includes(action)) { + path += `/topics`; + } - if (action === 'gettopic') { - path += `/topic-${ids[0]}`; - } + if (action === "gettopic") { + path += `/topic-${ids[0]}`; + } - return path; + return path; } function getProjectsPath(action: string, ids: string[]): string { - let path = ''; + let path = ""; - if (action !== 'list') { - path += `/project-${ids[0]}`; - } + if (action !== "list") { + path += `/project-${ids[0]}`; + } - if (['listkeys', 'getkey'].includes(action)) { - path += '/overview/keys'; - } + if (["listkeys", "getkey"].includes(action)) { + path += "/overview/keys"; + } - if (['listplatforms', 'getplatform'].includes(action)) { - path += '/overview/platforms'; - } + if (["listplatforms", "getplatform"].includes(action)) { + path += "/overview/platforms"; + } - if (['listwebhooks', 'getwebhook'].includes(action)) { - path += '/settings/webhooks'; - } + if (["listwebhooks", "getwebhook"].includes(action)) { + path += "/settings/webhooks"; + } - if (['getplatform', 'getkey', 'getwebhook'].includes(action)) { - path += `/${ids[1]}`; - } + if (["getplatform", "getkey", "getwebhook"].includes(action)) { + path += `/${ids[1]}`; + } - return path; + return path; } function getBucketsPath(action: string, ids: string[]): string { - let path = '/storage'; + let path = "/storage"; - if (action !== 'listbuckets') { - path += `/bucket-${ids[0]}`; - } + if (action !== "listbuckets") { + path += `/bucket-${ids[0]}`; + } - if (action === 'getbucketusage') { - path += `/usage`; - } + if (action === "getbucketusage") { + path += `/usage`; + } - if (action === 'getfile') { - path += `/file-${ids[1]}`; - } + if (action === "getfile") { + path += `/file-${ids[1]}`; + } - return path; + return path; } function getTeamsPath(action: string, ids: string[]): string { - let path = '/auth/teams'; + let path = "/auth/teams"; - if (action !== 'list') { - path += `/team-${ids[0]}`; - } + if (action !== "list") { + path += `/team-${ids[0]}`; + } - return path; + return path; } function getOrganizationsPath(action: string, ids: string[]): string { - let path = `/organization-${ids[0]}`; + let path = `/organization-${ids[0]}`; - if (action === 'list') { - path = '/account/organizations'; - } + if (action === "list") { + path = "/account/organizations"; + } - return path; + return path; } function getUsersPath(action: string, ids: string[]): string { - let path = '/auth'; + let path = "/auth"; - if (action !== 'list') { - path += `/user-${ids[0]}`; - } + if (action !== "list") { + path += `/user-${ids[0]}`; + } - if (action === 'listsessions') { - path += 'sessions'; - } + if (action === "listsessions") { + path += "sessions"; + } - return path; + return path; } export function isCloud(): boolean { - const endpoint = globalConfig.getEndpoint() || 'https://cloud.appwrite.io/v1'; - const hostname = new URL(endpoint).hostname; - return hostname.endsWith('appwrite.io'); + const endpoint = globalConfig.getEndpoint() || "https://cloud.appwrite.io/v1"; + const hostname = new URL(endpoint).hostname; + return hostname.endsWith("appwrite.io"); } diff --git a/lib/validations.ts b/lib/validations.ts index 9720c9af..668af454 100644 --- a/lib/validations.ts +++ b/lib/validations.ts @@ -1,17 +1,20 @@ -export const validateRequired = (resource: string, value: any): string | true => { - if (Array.isArray(value)) { - if (value.length <= 0) { - return `Please select at least one ${resource}`; - } - } else { - if ( - value === undefined || - value === null || - (typeof value === 'string' && value.trim() === '') - ) { - return `${resource} is required`; - } +export const validateRequired = ( + resource: string, + value: any, +): string | true => { + if (Array.isArray(value)) { + if (value.length <= 0) { + return `Please select at least one ${resource}`; } + } else { + if ( + value === undefined || + value === null || + (typeof value === "string" && value.trim() === "") + ) { + return `${resource} is required`; + } + } - return true; + return true; }; diff --git a/package.json b/package.json index e790f278..0db4c143 100644 --- a/package.json +++ b/package.json @@ -1,8 +1,9 @@ { "name": "appwrite-cli", + "type": "module", "homepage": "https://appwrite.io/support", "description": "Appwrite is an open-source self-hosted backend server that abstract and simplify complex and repetitive development tasks behind a very simple REST API", - "version": "13.0.0-rc.1", + "version": "13.0.0-rc.2", "license": "BSD-3-Clause", "main": "dist/index.js", "types": "dist/index.d.ts", @@ -14,40 +15,44 @@ "url": "https://github.com/appwrite/sdk-for-cli" }, "scripts": { - "build": "tsc || true", + "build": "tsc", + "format": "prettier --write \"**/*.{js,ts,json,md}\"", + "generate": "tsx scripts/generate-commands.ts", "prepublishOnly": "npm run build", "test": "echo \"Error: no test specified\" && exit 1", - "linux-x64": "npm run build && pkg -t node18-linux-x64 -o build/appwrite-cli-linux-x64 package.json", - "linux-arm64": "npm run build && pkg -t node18-linux-arm64 -o build/appwrite-cli-linux-arm64 package.json", - "mac-x64": "npm run build && pkg -t node18-macos-x64 -o build/appwrite-cli-darwin-x64 package.json", - "mac-arm64": "npm run build && pkg -t node18-macos-arm64 -o build/appwrite-cli-darwin-arm64 package.json", - "windows-x64": "npm run build && pkg -t node18-win-x64 -o build/appwrite-cli-win-x64.exe package.json", - "windows-arm64": "npm run build && pkg -t node18-win-arm64 -o build/appwrite-cli-win-arm64.exe package.json" + "linux-x64": "bun run build && bun build ./dist/index.js --compile --sourcemap=inline --target=bun-linux-x64 --outfile build/appwrite-cli-linux-x64", + "linux-arm64": "bun run build && bun build ./dist/index.js --compile --sourcemap=inline --target=bun-linux-arm64 --outfile build/appwrite-cli-linux-arm64", + "mac-x64": "bun run build && bun build ./dist/index.js --compile --sourcemap=inline --target=bun-darwin-x64 --outfile build/appwrite-cli-darwin-x64", + "mac-arm64": "bun run build && bun build ./dist/index.js --compile --sourcemap=inline --target=bun-darwin-arm64 --outfile build/appwrite-cli-darwin-arm64", + "windows-x64": "bun run build && bun build ./dist/index.js --compile --sourcemap=inline --target=bun-windows-x64 --outfile build/appwrite-cli-win-x64.exe", + "windows-arm64": "bun run build && bun build ./dist/index.js --compile --sourcemap=inline --target=bun-windows-arm64 --outfile build/appwrite-cli-win-arm64.exe" }, "dependencies": { - "undici": "^5.28.2", - "ejs": "^3.1.9", + "@appwrite.io/console": "^2.1.0", "chalk": "4.1.2", + "chokidar": "^3.6.0", "cli-progress": "^3.12.0", "cli-table3": "^0.6.2", "commander": "^9.2.0", + "dotenv": "^16.4.5", + "ejs": "^3.1.9", "form-data": "^4.0.0", - "json-bigint": "^1.0.0", + "ignore": "^7.0.5", "inquirer": "^8.2.4", "inquirer-search-list": "^1.2.6", - "tar": "^6.1.11", - "ignore": "^5.2.0", - "chokidar": "^3.6.0", + "json-bigint": "^1.0.0", "tail": "^2.2.6", - "dotenv": "^16.4.5" + "tar": "^6.1.11", + "undici": "^5.28.2" }, "devDependencies": { - "@yao-pkg/pkg": "^6.9.0", - "@types/node": "^18.19.0", - "@types/inquirer": "^8.2.10", "@types/cli-progress": "^3.11.5", - "@types/tar": "^6.1.11", + "@types/inquirer": "^8.2.10", "@types/json-bigint": "^1.0.4", + "@types/node": "^18.19.0", + "@types/tar": "^6.1.11", + "prettier": "^3.7.4", + "tsx": "^4.21.0", "typescript": "^5.3.3" }, "pkg": { diff --git a/scoop/appwrite.config.json b/scoop/appwrite.config.json index 257a560d..f5ae51f8 100644 --- a/scoop/appwrite.config.json +++ b/scoop/appwrite.config.json @@ -1,30 +1,20 @@ { - "$schema": "https://raw.githubusercontent.com/ScoopInstaller/Scoop/master/schema.json", - "version": "13.0.0-rc.1", - "description": "The Appwrite CLI is a command-line application that allows you to interact with Appwrite and perform server-side tasks using your terminal.", - "homepage": "https://github.com/appwrite/sdk-for-cli", - "license": "BSD-3-Clause", - "architecture": { - "64bit": { - "url": "https://github.com/appwrite/sdk-for-cli/releases/download/13.0.0-rc.1/appwrite-cli-win-x64.exe", - "bin": [ - [ - "appwrite-cli-win-x64.exe", - "appwrite" - ] - ] - }, - "arm64": { - "url": "https://github.com/appwrite/sdk-for-cli/releases/download/13.0.0-rc.1/appwrite-cli-win-arm64.exe", - "bin": [ - [ - "appwrite-cli-win-arm64.exe", - "appwrite" - ] - ] - } - }, - "checkver": { - "github": "https://github.com/appwrite/sdk-for-cli" - } -} \ No newline at end of file + "$schema": "https://raw.githubusercontent.com/ScoopInstaller/Scoop/master/schema.json", + "version": "13.0.0-rc.2", + "description": "The Appwrite CLI is a command-line application that allows you to interact with Appwrite and perform server-side tasks using your terminal.", + "homepage": "https://github.com/appwrite/sdk-for-cli", + "license": "BSD-3-Clause", + "architecture": { + "64bit": { + "url": "https://github.com/appwrite/sdk-for-cli/releases/download/13.0.0-rc.2/appwrite-cli-win-x64.exe", + "bin": [["appwrite-cli-win-x64.exe", "appwrite"]] + }, + "arm64": { + "url": "https://github.com/appwrite/sdk-for-cli/releases/download/13.0.0-rc.2/appwrite-cli-win-arm64.exe", + "bin": [["appwrite-cli-win-arm64.exe", "appwrite"]] + } + }, + "checkver": { + "github": "https://github.com/appwrite/sdk-for-cli" + } +} diff --git a/scripts/generate-commands.ts b/scripts/generate-commands.ts new file mode 100644 index 00000000..2b6207b5 --- /dev/null +++ b/scripts/generate-commands.ts @@ -0,0 +1,539 @@ +import * as fs from "fs"; +import * as path from "path"; +import * as https from "https"; + +interface SpecParameter { + name: string; + description: string; + required: boolean; + type: string; + in: string; + collectionFormat?: string; + items?: { type: string }; + default?: any; + schema?: any; + "x-example"?: string; + "x-enum-name"?: string; + "x-enum-keys"?: string[]; + format?: string; + enum?: string[]; +} + +interface SpecEndpoint { + summary: string; + operationId: string; + description: string; + deprecated: boolean; + parameters?: SpecParameter[]; + "x-appwrite": { + method: string; + group: string; + methods?: Array<{ + name: string; + parameters: string[]; + required: string[]; + }>; + }; +} + +interface SpecPaths { + [path: string]: { + [method: string]: SpecEndpoint; + }; +} + +interface OpenAPISpec { + paths: SpecPaths; +} + +// Utility functions +function capitalizeFirst(str: string): string { + return str.charAt(0).toUpperCase() + str.slice(1); +} + +function camelToKebab(str: string): string { + return str.replace(/([a-z0-9])([A-Z])/g, "$1-$2").toLowerCase(); +} + +function getParamName(name: string): string { + return camelToKebab(name); +} + +function getParamVarName(name: string): string { + // Convert kebab-case or snake_case to camelCase + let varName = name.replace(/[-_]([a-z])/g, (_, letter) => + letter.toUpperCase(), + ); + + // Handle reserved keywords + const reservedKeywords = [ + "default", + "const", + "let", + "var", + "function", + "class", + "interface", + "type", + "enum", + "export", + "import", + "return", + "if", + "else", + "for", + "while", + "do", + "switch", + "case", + "break", + "continue", + "throw", + "try", + "catch", + "finally", + "new", + "this", + "super", + "extends", + "implements", + "static", + "private", + "public", + "protected", + "readonly", + "async", + "await", + ]; + + if (reservedKeywords.includes(varName)) { + return `x${capitalizeFirst(varName)}`; + } + + return varName; +} + +// Unused but kept for future extension +// function getTypeScriptType(param: SpecParameter): string { +// if (param.type === "array") { +// return "string[]"; +// } +// if (param.type === "boolean") { +// return "boolean"; +// } +// if (param.type === "integer" || param.type === "number") { +// return "number"; +// } +// if (param.type === "object") { +// return "string"; // JSON string +// } +// return "string"; +// } + +function needsParser(param: SpecParameter): string | null { + if (param.type === "boolean") { + return "parseBool"; + } + if (param.type === "integer" || param.type === "number") { + return "parseInteger"; + } + if (param.type === "object") { + return "JSON.parse"; + } + return null; +} + +function getEnumTypesFromParams(params: SpecParameter[]): Set<string> { + const enumTypes = new Set<string>(); + + for (const param of params) { + // Use x-enum-name from the spec to determine enum type + if (param["x-enum-name"]) { + enumTypes.add(param["x-enum-name"]); + } + } + + return enumTypes; +} + +function generateCommand( + commandName: string, + endpoint: SpecEndpoint, + serviceName: string, + clientGetterName: string = `get${capitalizeFirst(serviceName)}Client`, +): string { + const methodName = endpoint["x-appwrite"].method; + const deprecated = endpoint.deprecated; + const deprecationNote = deprecated + ? `[**DEPRECATED** - This command is deprecated. Please use '${serviceName} ${methodName}' instead] ` + : ""; + + let code = `\n${serviceName}\n`; + code += ` .command(\`${commandName}\`)\n`; + code += ` .description(\n`; + code += ` \`${deprecationNote}${endpoint.description.replace(/`/g, "\\`")}\`,\n`; + code += ` )\n`; + + // Get all parameters (both query and body) + const allParams: SpecParameter[] = []; + + if (endpoint.parameters) { + for (const param of endpoint.parameters) { + if (param.in === "body" && param.schema?.properties) { + // Extract body parameters + const required = param.schema.required || []; + for (const [propName, propDef] of Object.entries<any>( + param.schema.properties, + )) { + allParams.push({ + name: propName, + description: propDef.description || "", + required: required.includes(propName), + type: propDef.type || "string", + in: "body", + default: propDef.default, + "x-enum-name": propDef["x-enum-name"], + "x-enum-keys": propDef["x-enum-keys"], + }); + } + } else { + // Query or path parameters + allParams.push(param); + } + } + } + + // Filter parameters based on method definition if x-appwrite.methods exists + let filteredParams = allParams; + const xAppwriteMethods = endpoint["x-appwrite"].methods; + if (xAppwriteMethods && Array.isArray(xAppwriteMethods)) { + const methodDef = xAppwriteMethods.find((m) => m.name === methodName); + if (methodDef) { + const allowedParams = new Set(methodDef.parameters); + const requiredParams = new Set(methodDef.required || []); + + filteredParams = allParams.filter((param) => + allowedParams.has(param.name), + ); + + // Update required status based on method definition + filteredParams = filteredParams.map((param) => ({ + ...param, + required: requiredParams.has(param.name), + })); + } + } + + // Generate options + for (const param of filteredParams) { + const paramName = getParamName(param.name); + const isArray = + param.type === "array" || param.collectionFormat === "multi"; + const isBool = param.type === "boolean"; + + let paramFlag: string; + if (isArray) { + paramFlag = `[${paramName}...]`; + } else if (isBool && !param.required) { + paramFlag = `[value]`; + } else { + paramFlag = `<${paramName}>`; + } + + const optionMethod = param.required ? "requiredOption" : "option"; + + code += ` .${optionMethod}(\n`; + code += ` \`--${paramName} ${paramFlag}\`,\n`; + code += ` \`${param.description.replace(/`/g, "\\`")}\`,\n`; + + // Add parser if needed + const parser = needsParser(param); + if (parser === "parseBool" && !param.required) { + // Special handling for optional boolean flags + code += ` (value: string | undefined) =>\n`; + code += ` value === undefined ? true : parseBool(value),\n`; + } else if (parser && parser !== "JSON.parse") { + code += ` ${parser},\n`; + } + + code += ` )\n`; + } + + // Generate action + const paramVars = filteredParams.map((p) => getParamVarName(p.name)); + const paramVarsStr = + paramVars.length > 0 ? `{ ${paramVars.join(", ")} }` : ""; + + code += ` .action(\n`; + code += ` actionRunner(\n`; + + if (paramVars.length === 0) { + code += ` async () => await (await ${clientGetterName}()).${methodName}(),\n`; + } else { + code += ` async (${paramVarsStr}) =>\n`; + + // Build arguments list + const args: string[] = []; + for (const param of filteredParams) { + const varName = getParamVarName(param.name); + if (needsParser(param) === "JSON.parse") { + args.push(`JSON.parse(${varName})`); + } else if (param["x-enum-name"]) { + args.push(`${varName} as ${param["x-enum-name"]}`); + } else { + args.push(varName); + } + } + + const argsStr = args.join(", "); + + if (args.length <= 3) { + code += ` await (\n`; + code += ` await ${clientGetterName}()\n`; + code += ` ).${methodName}(${argsStr}),\n`; + } else { + code += ` await (\n`; + code += ` await ${clientGetterName}()\n`; + code += ` ).${methodName}(\n`; + for (let i = 0; i < args.length; i++) { + code += ` ${args[i]}${i < args.length - 1 ? "," : ""}\n`; + } + code += ` ),\n`; + } + } + + code += ` ),\n`; + code += ` );\n`; + + return code; +} + +function generateCommandFile( + serviceName: string, + endpoints: { [key: string]: SpecEndpoint }, + serviceClassName: string, + methodToServiceClassMap?: { [methodName: string]: string }, +): string { + // Map method names to their actual service class names + const actualServiceClassMap: { [methodName: string]: string } = + methodToServiceClassMap || {}; + + // Collect all enum types needed + const enumTypes = new Set<string>(); + const serviceClassesNeeded = new Set<string>([serviceClassName]); + + for (const endpoint of Object.values(endpoints)) { + const methodName = endpoint["x-appwrite"].method; + const actualServiceClass = + actualServiceClassMap[methodName] || serviceClassName; + serviceClassesNeeded.add(actualServiceClass); + + const params: SpecParameter[] = []; + + if (endpoint.parameters) { + for (const param of endpoint.parameters) { + if (param.in === "body" && param.schema?.properties) { + const required = param.schema.required || []; + for (const [propName, propDef] of Object.entries<any>( + param.schema.properties, + )) { + params.push({ + name: propName, + description: propDef.description || "", + required: required.includes(propName), + type: propDef.type || "string", + in: "body", + "x-enum-name": propDef["x-enum-name"], + "x-enum-keys": propDef["x-enum-keys"], + }); + } + } else { + params.push(param); + } + } + } + + getEnumTypesFromParams(params).forEach((type) => enumTypes.add(type)); + } + + // Generate imports + let code = `import { Command } from "commander";\n`; + code += `import { sdkForProject } from "../../sdks.js";\n`; + code += `import { actionRunner, commandDescriptions, parseBool, parseInteger } from "../../parser.js";\n`; + + const imports: string[] = []; + serviceClassesNeeded.forEach((className) => imports.push(className)); + enumTypes.forEach((type) => imports.push(type)); + + code += `import {\n`; + for (const imp of imports) { + code += ` ${imp},\n`; + } + code += `} from "@appwrite.io/console";\n\n`; + + // Generate client singletons for all needed service classes + const clientGetters: { [className: string]: string } = {}; + + for (const className of serviceClassesNeeded) { + const clientVarName = + className === serviceClassName + ? `${serviceName}Client` + : `${className.charAt(0).toLowerCase() + className.slice(1)}Client`; + const getterName = `get${className}Client`; + clientGetters[className] = getterName; + + code += `let ${clientVarName}: ${className} | null = null;\n\n`; + code += `const ${getterName} = async (): Promise<${className}> => {\n`; + code += ` if (!${clientVarName}) {\n`; + code += ` const sdkClient = await sdkForProject();\n`; + code += ` ${clientVarName} = new ${className}(sdkClient);\n`; + code += ` }\n`; + code += ` return ${clientVarName};\n`; + code += `};\n\n`; + } + + // Generate main command + code += `export const ${serviceName} = new Command("${serviceName}")\n`; + code += ` .description(commandDescriptions["${serviceName}"] ?? "")\n`; + code += ` .configureHelp({\n`; + code += ` helpWidth: process.stdout.columns || 80,\n`; + code += ` });\n`; + + // Generate all commands + for (const [path, endpoint] of Object.entries(endpoints)) { + const commandName = camelToKebab(endpoint["x-appwrite"].method); + const methodName = endpoint["x-appwrite"].method; + const actualServiceClass = + actualServiceClassMap[methodName] || serviceClassName; + const clientGetterName = clientGetters[actualServiceClass]; + code += generateCommand( + commandName, + endpoint, + serviceName, + clientGetterName, + ); + } + + return code; +} + +async function downloadSpec(url: string): Promise<string> { + return new Promise((resolve, reject) => { + https + .get(url, (res) => { + let data = ""; + res.on("data", (chunk) => { + data += chunk; + }); + res.on("end", () => { + resolve(data); + }); + }) + .on("error", (err) => { + reject(err); + }); + }); +} + +async function main() { + const branch = "1.8.x"; + const version = "1.8.x"; + const platform = "console"; + + const specUrl = `https://raw.githubusercontent.com/appwrite/appwrite/${branch}/app/config/specs/swagger2-${version}-${platform}.json`; + + console.log("Downloading spec from:", specUrl); + const specContent = await downloadSpec(specUrl); + const spec: OpenAPISpec = JSON.parse(specContent); + + console.log("Parsing spec..."); + + // Group endpoints by service based on path prefix + const services: { [key: string]: { [key: string]: SpecEndpoint } } = {}; + const serviceClassNames: { [key: string]: string } = { + account: "Account", + users: "Users", + teams: "Teams", + databases: "Databases", + storage: "Storage", + functions: "Functions", + messaging: "Messaging", + locale: "Locale", + health: "Health", + projects: "Projects", + proxy: "Proxy", + vcs: "Vcs", + migrations: "Migrations", + console: "Console", + graphql: "Graphql", + organizations: "Organizations", + sites: "Sites", + tokens: "Tokens", + tablesdb: "TablesDB", + avatars: "Avatars", + }; + + for (const [pathStr, methods] of Object.entries(spec.paths)) { + // Determine service name from path prefix + const pathParts = pathStr.split("/").filter((p) => p); + const serviceName = pathParts[0]; + + for (const [method, endpoint] of Object.entries(methods)) { + if (endpoint && endpoint["x-appwrite"]) { + if (!services[serviceName]) { + services[serviceName] = {}; + } + + const key = `${method}:${pathStr}`; + services[serviceName][key] = endpoint as SpecEndpoint; + } + } + } + + // Generate command files + const outputDir = path.join(process.cwd(), "lib", "commands", "services"); + + // Create services directory if it doesn't exist + if (!fs.existsSync(outputDir)) { + fs.mkdirSync(outputDir, { recursive: true }); + } + + console.log("Generating command files..."); + + // Map methods to their actual service classes (for methods that belong to different services) + const methodToServiceClassMaps: { + [serviceName: string]: { [methodName: string]: string }; + } = { + console: { + chat: "Assistant", + }, + }; + + for (const [serviceName, endpoints] of Object.entries(services)) { + const serviceClassName = + serviceClassNames[serviceName] || capitalizeFirst(serviceName); + const methodToServiceClassMap = methodToServiceClassMaps[serviceName]; + const content = generateCommandFile( + serviceName, + endpoints, + serviceClassName, + methodToServiceClassMap, + ); + + const outputPath = path.join(outputDir, `${serviceName}.ts`); + fs.writeFileSync(outputPath, content); + + console.log(`Generated: ${outputPath}`); + } + + console.log( + "\nDone! Generated", + Object.keys(services).length, + "command files.", + ); +} + +main().catch((err) => { + console.error("Error:", err); + process.exit(1); +}); diff --git a/tsconfig.json b/tsconfig.json index ce8e4dac..8a6f9bf8 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,8 +1,9 @@ { "compilerOptions": { - "target": "ES2020", - "module": "commonjs", - "lib": ["ES2020"], + "target": "ES2022", + "module": "NodeNext", + "moduleResolution": "NodeNext", + "lib": ["ES2022"], "outDir": "./dist", "rootDir": "./", "strict": false, @@ -13,18 +14,11 @@ "declaration": true, "declarationMap": true, "sourceMap": true, - "moduleResolution": "node", "allowSyntheticDefaultImports": true, "types": ["node"], "noEmitOnError": false, "noImplicitAny": false }, - "include": [ - "**/*.ts" - ], - "exclude": [ - "node_modules", - "dist", - "build" - ] + "include": ["**/*.ts"], + "exclude": ["node_modules", "dist", "build"] }