diff --git a/CHANGELOG.md b/CHANGELOG.md index c41d9c8..7588c06 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Change Log +## 22.1.2 + +* Added: OAuth2 login now requests the `account.admin` scope +* Fixed: `logout` now reports the underlying server error when a session can't be revoked +* Fixed: `logout` and `client --reset` no longer report success when the server session revocation fails + ## 22.1.1 * Added: Support for logging into staging Cloud environments (`stage.cloud.appwrite.io`) diff --git a/README.md b/README.md index 98998bd..944c2f0 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 -22.1.1 +22.1.2 ``` ### 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 -22.1.1 +22.1.2 ``` ## Getting Started diff --git a/install.ps1 b/install.ps1 index f4e750f..264c8ee 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/22.1.1/appwrite-cli-win-x64.exe" -$GITHUB_arm64_URL = "https://github.com/appwrite/sdk-for-cli/releases/download/22.1.1/appwrite-cli-win-arm64.exe" +$GITHUB_x64_URL = "https://github.com/appwrite/sdk-for-cli/releases/download/22.1.2/appwrite-cli-win-x64.exe" +$GITHUB_arm64_URL = "https://github.com/appwrite/sdk-for-cli/releases/download/22.1.2/appwrite-cli-win-arm64.exe" $APPWRITE_BINARY_NAME = "appwrite.exe" diff --git a/install.sh b/install.sh index 53e4170..02842c1 100644 --- a/install.sh +++ b/install.sh @@ -120,7 +120,7 @@ verifyMacOSCodeSignature() { downloadBinary() { echo "[2/5] Downloading executable for $OS ($ARCH) ..." - GITHUB_LATEST_VERSION="22.1.1" + GITHUB_LATEST_VERSION="22.1.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/auth/session.ts b/lib/auth/session.ts index ca8bf48..0e749c7 100644 --- a/lib/auth/session.ts +++ b/lib/auth/session.ts @@ -82,10 +82,10 @@ export const removeCurrentSession = (): void => { */ export const deleteServerSession = async ( sessionId: string, -): Promise => { +): Promise<{ deleted: boolean; error?: string }> => { const session = getSession(sessionId); if (!session?.endpoint) { - return false; + return { deleted: false }; } try { @@ -95,7 +95,7 @@ export const deleteServerSession = async ( session.refreshToken, session.clientId || OAUTH2_CLIENT_ID, ); - return true; + return { deleted: true }; } if (session.cookie) { @@ -110,12 +110,15 @@ export const deleteServerSession = async ( await legacyClient.call("DELETE", "/account/sessions/current", { "content-type": "application/json", }); - return true; + return { deleted: true }; } - return false; - } catch (_e) { - return false; + return { deleted: false }; + } catch (e) { + return { + deleted: false, + error: e instanceof Error ? e.message : String(e), + }; } }; @@ -126,9 +129,10 @@ export const deleteServerSession = async ( */ export const logoutSessions = async ( sessionIds: string[], -): Promise<{ failed: number; failedIds: string[] }> => { +): Promise<{ failed: number; failedIds: string[]; errors: string[] }> => { let failed = 0; const failedIds: string[] = []; + const errors: string[] = []; for (const sessionId of sessionIds) { if (isLocalOnlySession(sessionId)) { @@ -137,16 +141,19 @@ export const logoutSessions = async ( } globalConfig.setCurrentSession(sessionId); - const serverDeleted = await deleteServerSession(sessionId); - if (serverDeleted) { + const result = await deleteServerSession(sessionId); + if (result.deleted) { globalConfig.removeSession(sessionId); } else { failed++; failedIds.push(sessionId); + if (result.error) { + errors.push(result.error); + } } } - return { failed, failedIds }; + return { failed, failedIds, errors }; }; export const removeLegacySessionsExcept = async ( @@ -160,8 +167,8 @@ export const removeLegacySessionsExcept = async ( continue; } - const serverDeleted = await deleteServerSession(sessionId); - if (serverDeleted) { + const result = await deleteServerSession(sessionId); + if (result.deleted) { globalConfig.removeSession(sessionId); removed++; } else { diff --git a/lib/commands/generic.ts b/lib/commands/generic.ts index 9e88e20..ba2b61d 100644 --- a/lib/commands/generic.ts +++ b/lib/commands/generic.ts @@ -10,7 +10,6 @@ import { commandDescriptions, error, parse, - hint, log, drawTable, cliConfig, @@ -27,6 +26,17 @@ import { export { loginCommand }; +const logMessages = { + noActiveSessions: "No active sessions found.", + logoutFailure: (errors: string[] = []): string => { + const uniqueErrors = [...new Set(errors)]; + const details = uniqueErrors.length ? `: ${uniqueErrors.join("; ")}` : ""; + return `Could not log out because the server session could not be revoked${details}. Kept local session data.`; + }, + logoutSuccess: "Logged out successfully", + clientConfigUpdated: "Client configuration updated", +} as const; + export const whoami = new Command("whoami") .description(commandDescriptions["whoami"]) .action( @@ -101,38 +111,37 @@ export const logout = new Command("logout") const originalCurrent = current; if (current === "" || !sessions.length) { - log("No active sessions found."); + log(logMessages.noActiveSessions); return; } if (sessions.length === 1) { - const { failed, failedIds } = await logoutSessions( + const { failed, failedIds, errors } = await logoutSessions( planSessionLogout([current]), ); if (failed > 0) { restoreCurrentSessionFallback(originalCurrent, failedIds); - hint( - "Could not reach server for all sessions; kept local session data", - ); + error(logMessages.logoutFailure(errors)); + return; } else { globalConfig.setCurrentSession(""); } - success("Logged out successfully"); + success(logMessages.logoutSuccess); return; } const answers = await inquirer.prompt(questionsLogout); + let logoutFailed = false; if (answers.accounts?.length) { - const { failed } = await logoutSessions( + const { failed, errors } = await logoutSessions( planSessionLogout(answers.accounts as string[]), ); if (failed > 0) { - hint( - "Could not reach server for all sessions; kept local session data", - ); + logoutFailed = true; + error(logMessages.logoutFailure(errors)); } } @@ -149,16 +158,20 @@ export const logout = new Command("logout") remainingSessions[0]; globalConfig.setCurrentSession(nextSession.id); - success( - nextSession.email - ? `Switched to ${nextSession.email}` - : `Switched to session at ${nextSession.endpoint}`, - ); + if (!logoutFailed) { + success( + nextSession.email + ? `Switched to ${nextSession.email}` + : `Switched to session at ${nextSession.endpoint}`, + ); + } } else if (remainingSessions.length === 0) { globalConfig.setCurrentSession(""); } - success("Logged out successfully"); + if (!logoutFailed) { + success(logMessages.logoutSuccess); + } }), ); @@ -288,22 +301,21 @@ export const client = new Command("client") if (reset !== undefined) { const originalCurrent = globalConfig.getCurrentSession(); - const { failed, failedIds } = await logoutSessions( + const { failed, failedIds, errors } = await logoutSessions( globalConfig.getSessionIds(), ); if (failed > 0) { restoreCurrentSessionFallback(originalCurrent, failedIds); - hint( - "Could not reach server for all sessions; kept local session data", - ); + error(logMessages.logoutFailure(errors)); + return; } else { globalConfig.setCurrentSession(""); } } if (!debug) { - success("Setting client"); + success(logMessages.clientConfigUpdated); } }, ), diff --git a/lib/constants.ts b/lib/constants.ts index 3438bea..01fadb5 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 = '22.1.1'; +export const SDK_VERSION = '22.1.2'; export const SDK_NAME = 'Command Line'; export const SDK_PLATFORM = 'console'; export const SDK_LANGUAGE = 'cli'; @@ -29,7 +29,7 @@ export const DEFAULT_ENDPOINT = 'https://cloud.appwrite.io/v1'; // OAuth2 export const OAUTH2_CLIENT_ID = "appwrite-cli"; -export const OAUTH2_SCOPES = "openid email profile"; +export const OAUTH2_SCOPES = "openid email profile account.admin"; // Config resources export const CONFIG_RESOURCE_KEYS = [ diff --git a/package-lock.json b/package-lock.json index f40024c..c3bc2be 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "appwrite-cli", - "version": "22.1.1", + "version": "22.1.2", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "appwrite-cli", - "version": "22.1.1", + "version": "22.1.2", "license": "BSD-3-Clause", "dependencies": { "@appwrite.io/console": "^15.0.0", diff --git a/package.json b/package.json index 471dce0..93178d9 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": "22.1.1", + "version": "22.1.2", "license": "BSD-3-Clause", "main": "dist/index.cjs", "module": "dist/index.js", diff --git a/scoop/appwrite.config.json b/scoop/appwrite.config.json index 014c855..7defa62 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": "22.1.1", + "version": "22.1.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/22.1.1/appwrite-cli-win-x64.exe", + "url": "https://github.com/appwrite/sdk-for-cli/releases/download/22.1.2/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/22.1.1/appwrite-cli-win-arm64.exe", + "url": "https://github.com/appwrite/sdk-for-cli/releases/download/22.1.2/appwrite-cli-win-arm64.exe", "bin": [ [ "appwrite-cli-win-arm64.exe",