From 4959927e16366910c99866b169a3661fb8935b47 Mon Sep 17 00:00:00 2001 From: Chirag Aggarwal Date: Tue, 28 Jul 2026 22:31:45 +0530 Subject: [PATCH] chore: update Command Line SDK to 24.0.0 --- .github/workflows/publish.yml | 26 ++++---------------------- CHANGELOG.md | 6 ++++++ README.md | 4 ++-- bun.lock | 4 ++-- install.ps1 | 4 ++-- install.sh | 2 +- lib/auth/login.ts | 12 ++++++++---- lib/commands/generic.ts | 8 ++++---- lib/commands/services/backups.ts | 6 +++--- lib/commands/services/storage.ts | 5 +++-- lib/commands/services/tablesdb.ts | 7 ++++--- lib/constants.ts | 2 +- lib/flags.ts | 2 -- lib/sdks.ts | 4 +--- package-lock.json | 12 ++++++------ package.json | 4 ++-- scoop/appwrite.config.json | 6 +++--- 17 files changed, 52 insertions(+), 62 deletions(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 5a58958..09a4deb 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -226,15 +226,12 @@ jobs: echo "formula_path=${FORMULA_PATH}" } >> "$GITHUB_OUTPUT" - - name: Open pull request on Homebrew tap + - name: Commit Homebrew formula update working-directory: homebrew-tap env: RELEASE_TAG: ${{ github.event.release.tag_name }} EXECUTABLE_NAME: ${{ steps.tap.outputs.executable }} FORMULA_PATH: ${{ steps.tap.outputs.formula_path }} - SOURCE_REPO: ${{ github.repository }} - SERVER_URL: ${{ github.server_url }} - GH_TOKEN: ${{ steps.bot-token.outputs.token }} run: | set -euo pipefail @@ -243,27 +240,12 @@ jobs: exit 0 fi - BASE_BRANCH="$(gh repo view --json defaultBranchRef --jq '.defaultBranchRef.name')" - BRANCH="release/${EXECUTABLE_NAME}-${RELEASE_TAG}" - git config user.name "appwrite-bot[bot]" git config user.email "217594562+appwrite-bot[bot]@users.noreply.github.com" - git checkout -B "$BRANCH" git add "$FORMULA_PATH" git commit -m "${EXECUTABLE_NAME} ${RELEASE_TAG}" - git push -f -u origin "$BRANCH" - - PR_TITLE="${EXECUTABLE_NAME} ${RELEASE_TAG}" - PR_BODY=$(printf 'Automated formula update for the `%s` CLI release [`%s`](%s/%s/releases/tag/%s).\n\nOpened automatically by the `%s` publish workflow after release binaries were uploaded.' "$EXECUTABLE_NAME" "$RELEASE_TAG" "$SERVER_URL" "$SOURCE_REPO" "$RELEASE_TAG" "${SOURCE_REPO#*/}") - EXISTING_PR="$(gh pr list --head "$BRANCH" --state open --json number --jq '.[0].number' || true)" - if [ -n "$EXISTING_PR" ]; then - gh pr edit "$EXISTING_PR" --title "$PR_TITLE" --body "$PR_BODY" - else - gh pr create \ - --title "$PR_TITLE" \ - --body "$PR_BODY" \ - --base "$BASE_BRANCH" \ - --head "$BRANCH" - fi + BRANCH="$(git rev-parse --abbrev-ref HEAD)" + git pull --rebase origin "$BRANCH" + git push origin "HEAD:${BRANCH}" diff --git a/CHANGELOG.md b/CHANGELOG.md index c303cce..29236f1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Change Log +## 24.0.0 + +* Added: `login` against Cloud now signs in through your browser +* Updated: `--email`, `--password`, `--mfa`, and `--code` now apply to self-hosted instances only +* Updated: Existing Cloud sessions keep working in read-only mode until you run `login` again + ## 23.2.0 * Added: `apps` installation commands: `list-installations`, `get-installation`, `delete-installation`, `create-installation-token` diff --git a/README.md b/README.md index 91c82b1..a92f8bc 100644 --- a/README.md +++ b/README.md @@ -29,7 +29,7 @@ Once the installation is complete, you can verify the install using ```sh $ appwrite -v -23.2.0 +24.0.0 ``` ### Install using prebuilt binaries @@ -83,7 +83,7 @@ $ scoop install https://raw.githubusercontent.com/appwrite/sdk-for-cli/master/sc Once the installation completes, you can verify your install using ``` $ appwrite -v -23.2.0 +24.0.0 ``` ## Getting Started diff --git a/bun.lock b/bun.lock index 7910561..7cba9a4 100644 --- a/bun.lock +++ b/bun.lock @@ -5,7 +5,7 @@ "": { "name": "appwrite-cli", "dependencies": { - "@appwrite.io/console": "15.6.0", + "@appwrite.io/console": "15.7.0", "@napi-rs/keyring": "^1.3.0", "chalk": "4.1.2", "chokidar": "^3.6.0", @@ -54,7 +54,7 @@ "tmp": "^0.2.6", }, "packages": { - "@appwrite.io/console": ["@appwrite.io/console@15.6.0", "", { "dependencies": { "json-bigint": "1.0.0" } }, "sha512-dSlNP01auhPeppdXEGg3mtg5nRTxqKX7H9aHsbxE/nOlJAzAGEcz9Lt/gwmY/NwzMcXrugU1+uLcXUA4Cu4XTQ=="], + "@appwrite.io/console": ["@appwrite.io/console@15.7.0", "", { "dependencies": { "json-bigint": "1.0.0" } }, "sha512-43FVjVbqdedkoiMrAKCFpEnAhBb7YruW9fHqUJ/uvzMT2yg8g8cx+s5b0gkmiC276URALa5BzkYUBoTLw/Dnsw=="], "@babel/runtime": ["@babel/runtime@7.29.7", "", {}, "sha512-Nq8OhGWiZIZGV6hLHoyAKLLcJihP/xFeBMGJoUrxTX2psI8dCifzLhZISFb+VWS3wFMRDmCGw5R+dOySCqPLhw=="], diff --git a/install.ps1 b/install.ps1 index 4698278..cc94c18 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/23.2.0/appwrite-cli-win-x64.exe" -$GITHUB_arm64_URL = "https://github.com/appwrite/sdk-for-cli/releases/download/23.2.0/appwrite-cli-win-arm64.exe" +$GITHUB_x64_URL = "https://github.com/appwrite/sdk-for-cli/releases/download/24.0.0/appwrite-cli-win-x64.exe" +$GITHUB_arm64_URL = "https://github.com/appwrite/sdk-for-cli/releases/download/24.0.0/appwrite-cli-win-arm64.exe" $APPWRITE_BINARY_NAME = "appwrite.exe" diff --git a/install.sh b/install.sh index aeecfc6..aec0f10 100644 --- a/install.sh +++ b/install.sh @@ -120,7 +120,7 @@ verifyMacOSCodeSignature() { downloadBinary() { echo "[2/5] Downloading executable for $OS ($ARCH) ..." - GITHUB_LATEST_VERSION="23.2.0" + GITHUB_LATEST_VERSION="24.0.0" 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/auth/login.ts b/lib/auth/login.ts index ead58a4..de562ab 100644 --- a/lib/auth/login.ts +++ b/lib/auth/login.ts @@ -13,7 +13,6 @@ import { isRegionalCloudEndpoint, openBrowser, } from "../utils.js"; -import { isFlagEnabled } from "../flags.js"; import ID from "../id.js"; import { questionsListFactors, @@ -476,8 +475,13 @@ export const loginCommand = async ({ const configEndpoint = normalizeCloudConsoleEndpoint( (endpoint ?? globalConfig.getEndpoint()) || DEFAULT_ENDPOINT, ); - const shouldUseCloudLogin = - isFlagEnabled("oauthLogin") && isCloudLoginEndpoint(configEndpoint); + const shouldUseCloudLogin = isCloudLoginEndpoint(configEndpoint); + + if (shouldUseCloudLogin && (email || password || mfa || code)) { + throw new Error( + `Cloud sign-in happens in your browser. Run '${EXECUTABLE_NAME} login' without --email, --password, --mfa or --code — those options are for self-hosted instances.`, + ); + } let oldCurrent = globalConfig.getCurrentSession(); @@ -493,7 +497,7 @@ export const loginCommand = async ({ if (account) { if ( - isFlagEnabled("oauthLogin") && + shouldUseCloudLogin && !globalConfig.getAccessToken() && globalConfig.getCookie() ) { diff --git a/lib/commands/generic.ts b/lib/commands/generic.ts index 2d4c2d1..cb9e601 100644 --- a/lib/commands/generic.ts +++ b/lib/commands/generic.ts @@ -81,13 +81,13 @@ export const register = new Command("register") export const login = new Command("login") .description(commandDescriptions["login"]) - .option(`--email [email]`, `Email`) - .option(`--password [password]`, `Password`) + .option(`--email [email]`, `Email, for self hosted instances`) + .option(`--password [password]`, `Password, for self hosted instances`) .option( `--mfa [factor]`, - `Factor used for MFA. Must be one of: email, phone, totp, recoveryCode`, + `Factor used for MFA on self hosted instances. Must be one of: email, phone, totp, recoveryCode`, ) - .option(`--code [code]`, `Code used for MFA`) + .option(`--code [code]`, `Code used for MFA on self hosted instances`) .option( `--endpoint [endpoint]`, `Appwrite endpoint for self hosted instances`, diff --git a/lib/commands/services/backups.ts b/lib/commands/services/backups.ts index f3b5280..32707d2 100644 --- a/lib/commands/services/backups.ts +++ b/lib/commands/services/backups.ts @@ -181,17 +181,17 @@ const backupsCreateRestorationCommand = backups .command(`create-restoration`) .description(`Create and trigger a new restoration for a backup on a project. -For a backup of one database, the restoration resolves its destination before it is queued. Pass \`newResourceId\` to restore into that database ID, including the archived database ID to overwrite it. When \`newResourceId\` is omitted, a new database ID is generated and returned in \`options\`. +For a backup of one database, the restoration resolves its destination before it is queued. When \`newResourceId\` is omitted, the archived database is restored in place and its own ID is returned in \`options\`. Pass a different \`newResourceId\` to restore alongside it as a new database instead. The restoration migration records the archived database in \`resourceId\` and \`resourceType\`, and the resolved database in \`destinationResourceId\` and \`destinationResourceType\`. Database types are stored canonically as \`database\`, \`documentsdb\`, or \`vectorsdb\`. Project-wide restorations leave these fields empty because they do not have a single source or destination database. To list every migration related to one database, use its canonical type in a nested \`OR(AND(...), AND(...), AND(...))\` across the root, parent, and destination relation pairs: \`(resourceType, resourceId)\`, \`(parentResourceType, parentResourceId)\`, and \`(destinationResourceType, destinationResourceId)\`. Legacy and TablesDB databases use \`database\`; the operational \`resourceType\` of a table migration is not rewritten to \`tablesdb\`. -When restoring a DocumentsDB or VectorsDB database to a new resource from a dedicated source, the restore provisions a fresh dedicated backing database at the source database's own specification. +When restoring a DocumentsDB or VectorsDB database from a dedicated source, the restore provisions a fresh dedicated backing database at the source database's own specification and lands the data there. An in-place restore swaps the database onto that backing only once the restore has succeeded, and retires the backing it displaced only once that swap is confirmed, so the source keeps serving its own data until the restored data is in place and any failure leaves it untouched. A serverless source has no dedicated backing to clone and restores onto the archived database instead. `) .requiredOption(`--archive-id `, `Backup archive ID to restore`) .requiredOption(`--services [services...]`, `Array of services to restore`) - .option(`--new-resource-id `, `Destination resource ID. Omit to generate a new ID, or pass the archived resource ID to overwrite 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.`) + .option(`--new-resource-id `, `Destination resource ID. Omit to restore the archived resource in place, or pass a different ID to restore alongside it as a new resource. 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(`--new-resource-name `, `Database name. Max length: 128 chars.`) .action( actionRunner( diff --git a/lib/commands/services/storage.ts b/lib/commands/services/storage.ts index e168b4e..bba6616 100644 --- a/lib/commands/services/storage.ts +++ b/lib/commands/services/storage.ts @@ -221,10 +221,11 @@ If you're creating a new file using one of the Appwrite SDKs, all the chunking l .requiredOption(`--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 `, `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).`) + .option(`--folder `, `Virtual folder to place the file in, for example "photos/2026". Nest folders with \`/\`. Defaults to the bucket root.`) .action( actionRunner( - async ({ bucketId, fileId, file, permissions }) => - parse(await (await getStorageClient()).createFile(bucketId, fileId, file !== undefined ? await resolveFileParam(file) : undefined, permissions)), + async ({ bucketId, fileId, file, permissions, folder }) => + parse(await (await getStorageClient()).createFile(bucketId, fileId, file !== undefined ? await resolveFileParam(file) : undefined, permissions, folder)), ), ); diff --git a/lib/commands/services/tablesdb.ts b/lib/commands/services/tablesdb.ts index 0d1f427..883213f 100644 --- a/lib/commands/services/tablesdb.ts +++ b/lib/commands/services/tablesdb.ts @@ -210,11 +210,12 @@ const tablesDBUpdateCommand = tablesDB (value: string | undefined) => value === undefined ? true : parseBool(value), ) + .option(`--specification `, `Database specification. Resizing between dedicated specifications changes cpu, memory, storage and the connection ceiling via a rolling cutover with zero downtime. Moving a \`serverless\` database onto a dedicated specification is a data migration, not a resize.`) .option(`--replicas `, `Number of high availability replicas (0-5) for the dedicated database backing this database. Only valid when the database is backed by a dedicated specification. High availability is enabled when greater than 0.`, parseInteger) .action( actionRunner( - async ({ databaseId, name, enabled, replicas }) => - parse(await (await getTablesDBClient()).update(databaseId, name, enabled, replicas)), + async ({ databaseId, name, enabled, specification, replicas }) => + parse(await (await getTablesDBClient()).update(databaseId, name, enabled, specification, replicas)), ), ); @@ -233,7 +234,7 @@ const tablesDBDeleteCommand = tablesDB const tablesDBCreateFailoverCommand = tablesDB .command(`create-failover`) - .description(`Trigger a manual failover for a dedicated database with high availability enabled. Promotes a replica to primary. The failover runs asynchronously; poll the database document for status updates.`) + .description(`Trigger a manual failover for a dedicated database with high availability enabled. Promotes a replica to primary. The failover runs asynchronously; poll the database document for status updates. A database left mid-operation by a failover that did not finish also accepts this call as a repair, provided \`targetReplicaId\` names the member to promote.`) .requiredOption(`--database-id `, `Database ID.`) .option(`--target-replica-id `, `Target replica ID to promote. If not specified, the healthiest replica is selected.`) .action( diff --git a/lib/constants.ts b/lib/constants.ts index f9029f1..76dbc76 100644 --- a/lib/constants.ts +++ b/lib/constants.ts @@ -1,7 +1,7 @@ // SDK export const SDK_TITLE = 'Appwrite'; export const SDK_TITLE_LOWER = 'appwrite'; -export const SDK_VERSION = '23.2.0'; +export const SDK_VERSION = '24.0.0'; export const SDK_NAME = 'Command Line'; export const SDK_PLATFORM = 'console'; export const SDK_LANGUAGE = 'cli'; diff --git a/lib/flags.ts b/lib/flags.ts index 44217f2..d295a9a 100644 --- a/lib/flags.ts +++ b/lib/flags.ts @@ -6,8 +6,6 @@ * and read it anywhere with isFlagEnabled(""). */ const FLAG_ENV_VARS = { - // Browser-based OAuth2 device login for Cloud (otherwise email/password). - oauthLogin: "APPWRITE_CLI_OAUTH_LOGIN", // Treat localhost/loopback endpoints as Cloud for OAuth login testing. devCloudLogin: "APPWRITE_CLI_DEV_CLOUD_LOGIN", } as const; diff --git a/lib/sdks.ts b/lib/sdks.ts index c61c64c..d70c803 100644 --- a/lib/sdks.ts +++ b/lib/sdks.ts @@ -14,7 +14,6 @@ import { } from "./constants.js"; import { warn } from "./parser.js"; import { isCloudHostname } from "./utils.js"; -import { isFlagEnabled } from "./flags.js"; import { getStoredRefreshToken, setStoredRefreshToken, @@ -87,8 +86,7 @@ export const getValidAccessToken = async ( let legacySessionWarningShown = false; const warnLegacySession = (): void => { - // Only nudge toward OAuth login when the feature is enabled. - if (legacySessionWarningShown || !isFlagEnabled("oauthLogin")) { + if (legacySessionWarningShown) { return; } diff --git a/package-lock.json b/package-lock.json index 8e4163f..b8c0934 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,15 +1,15 @@ { "name": "appwrite-cli", - "version": "23.2.0", + "version": "24.0.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "appwrite-cli", - "version": "23.2.0", + "version": "24.0.0", "license": "BSD-3-Clause", "dependencies": { - "@appwrite.io/console": "15.6.0", + "@appwrite.io/console": "15.7.0", "@napi-rs/keyring": "^1.3.0", "chalk": "4.1.2", "chokidar": "^3.6.0", @@ -60,9 +60,9 @@ } }, "node_modules/@appwrite.io/console": { - "version": "15.6.0", - "resolved": "https://registry.npmjs.org/@appwrite.io/console/-/console-15.6.0.tgz", - "integrity": "sha512-dSlNP01auhPeppdXEGg3mtg5nRTxqKX7H9aHsbxE/nOlJAzAGEcz9Lt/gwmY/NwzMcXrugU1+uLcXUA4Cu4XTQ==", + "version": "15.7.0", + "resolved": "https://registry.npmjs.org/@appwrite.io/console/-/console-15.7.0.tgz", + "integrity": "sha512-43FVjVbqdedkoiMrAKCFpEnAhBb7YruW9fHqUJ/uvzMT2yg8g8cx+s5b0gkmiC276URALa5BzkYUBoTLw/Dnsw==", "license": "BSD-3-Clause", "dependencies": { "json-bigint": "1.0.0" diff --git a/package.json b/package.json index f910e10..4ff852c 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "type": "module", "homepage": "https://appwrite.io/support", "description": "Appwrite is an open-source self-hosted backend server that abstracts and simplifies complex and repetitive development tasks behind a very simple REST API", - "version": "23.2.0", + "version": "24.0.0", "license": "BSD-3-Clause", "main": "dist/index.cjs", "module": "dist/index.js", @@ -51,7 +51,7 @@ "windows-arm64": "bun build cli.ts --compile --minify --target=bun-windows-arm64 --outfile build/appwrite-cli-win-arm64.exe" }, "dependencies": { - "@appwrite.io/console": "15.6.0", + "@appwrite.io/console": "15.7.0", "@napi-rs/keyring": "^1.3.0", "chalk": "4.1.2", "chokidar": "^3.6.0", diff --git a/scoop/appwrite.config.json b/scoop/appwrite.config.json index 41ca51c..f955d79 100644 --- a/scoop/appwrite.config.json +++ b/scoop/appwrite.config.json @@ -1,12 +1,12 @@ { "$schema": "https://raw.githubusercontent.com/ScoopInstaller/Scoop/master/schema.json", - "version": "23.2.0", + "version": "24.0.0", "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/23.2.0/appwrite-cli-win-x64.exe", + "url": "https://github.com/appwrite/sdk-for-cli/releases/download/24.0.0/appwrite-cli-win-x64.exe", "bin": [ [ "appwrite-cli-win-x64.exe", @@ -15,7 +15,7 @@ ] }, "arm64": { - "url": "https://github.com/appwrite/sdk-for-cli/releases/download/23.2.0/appwrite-cli-win-arm64.exe", + "url": "https://github.com/appwrite/sdk-for-cli/releases/download/24.0.0/appwrite-cli-win-arm64.exe", "bin": [ [ "appwrite-cli-win-arm64.exe",