From a523c8a2e3a6cfe7ec2e724dba65660fe3996e7d Mon Sep 17 00:00:00 2001 From: root Date: Tue, 21 Oct 2025 05:49:51 +0000 Subject: [PATCH 1/2] chore: regen --- CHANGELOG.md | 6 ++++++ README.md | 4 ++-- install.ps1 | 4 ++-- install.sh | 2 +- lib/client.js | 4 ++-- lib/parser.js | 2 +- package.json | 2 +- scoop/appwrite.config.json | 6 +++--- 8 files changed, 18 insertions(+), 12 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index db3898dd..ad355682 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Change Log +## 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 + ## 10.2.1 * Add transaction support for Databases and TablesDB diff --git a/README.md b/README.md index dacca34f..afbc11c5 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 -10.2.1 +10.2.2 ``` ### Install using prebuilt binaries @@ -60,7 +60,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 -10.2.1 +10.2.2 ``` ## Getting Started diff --git a/install.ps1 b/install.ps1 index c16a666e..d4876043 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/10.2.1/appwrite-cli-win-x64.exe" -$GITHUB_arm64_URL = "https://github.com/appwrite/sdk-for-cli/releases/download/10.2.1/appwrite-cli-win-arm64.exe" +$GITHUB_x64_URL = "https://github.com/appwrite/sdk-for-cli/releases/download/10.2.2/appwrite-cli-win-x64.exe" +$GITHUB_arm64_URL = "https://github.com/appwrite/sdk-for-cli/releases/download/10.2.2/appwrite-cli-win-arm64.exe" $APPWRITE_BINARY_NAME = "appwrite.exe" diff --git a/install.sh b/install.sh index 624db626..9f379df7 100644 --- a/install.sh +++ b/install.sh @@ -97,7 +97,7 @@ printSuccess() { downloadBinary() { echo "[2/4] Downloading executable for $OS ($ARCH) ..." - GITHUB_LATEST_VERSION="10.2.1" + GITHUB_LATEST_VERSION="10.2.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.js b/lib/client.js index 879fd9c9..bb565c50 100644 --- a/lib/client.js +++ b/lib/client.js @@ -16,8 +16,8 @@ class Client { 'x-sdk-name': 'Command Line', 'x-sdk-platform': 'console', 'x-sdk-language': 'cli', - 'x-sdk-version': '10.2.1', - 'user-agent' : `AppwriteCLI/10.2.1 (${os.type()} ${os.version()}; ${os.arch()})`, + 'x-sdk-version': '10.2.2', + 'user-agent' : `AppwriteCLI/10.2.2 (${os.type()} ${os.version()}; ${os.arch()})`, 'X-Appwrite-Response-Format' : '1.8.0', }; } diff --git a/lib/parser.js b/lib/parser.js index f83f220f..6f25b719 100644 --- a/lib/parser.js +++ b/lib/parser.js @@ -122,7 +122,7 @@ const parseError = (err) => { } catch { } - const version = '10.2.1'; + const version = '10.2.2'; const stepsToReproduce = `Running \`appwrite ${cliConfig.reportData.data.args.join(' ')}\``; const yourEnvironment = `CLI version: ${version}\nOperation System: ${os.type()}\nAppwrite version: ${appwriteVersion}\nIs Cloud: ${isCloud()}`; diff --git a/package.json b/package.json index f5d2f174..6a4b9b50 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "appwrite-cli", "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": "10.2.1", + "version": "10.2.2", "license": "BSD-3-Clause", "main": "index.js", "bin": { diff --git a/scoop/appwrite.config.json b/scoop/appwrite.config.json index 50984714..9472896f 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": "10.2.1", + "version": "10.2.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/10.2.1/appwrite-cli-win-x64.exe", + "url": "https://github.com/appwrite/sdk-for-cli/releases/download/10.2.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/10.2.1/appwrite-cli-win-arm64.exe", + "url": "https://github.com/appwrite/sdk-for-cli/releases/download/10.2.2/appwrite-cli-win-arm64.exe", "bin": [ [ "appwrite-cli-win-arm64.exe", From ab7089717836306c83230dc86b36345f589a76c0 Mon Sep 17 00:00:00 2001 From: root Date: Tue, 21 Oct 2025 07:19:19 +0000 Subject: [PATCH 2/2] regen --- lib/commands/generic.js | 8 +- lib/commands/push.js | 198 +++++++++++++++++++++++++++++++++------- lib/config.js | 24 +++-- 3 files changed, 186 insertions(+), 44 deletions(-) diff --git a/lib/commands/generic.js b/lib/commands/generic.js index 3f8c08e3..d269dcc5 100644 --- a/lib/commands/generic.js +++ b/lib/commands/generic.js @@ -171,12 +171,11 @@ const deleteSession = async (accountId) => { parseOutput: false, sdk: client }) - - globalConfig.removeSession(accountId); } catch (e) { error('Unable to log out, removing locally saved session information') + } finally { + globalConfig.removeSession(accountId); } - globalConfig.removeSession(accountId); } const logout = new Command("logout") @@ -194,6 +193,7 @@ const logout = new Command("logout") } if (sessions.length === 1) { await deleteSession(current); + globalConfig.setCurrentSession(''); success("Logging out"); return; @@ -215,6 +215,8 @@ const logout = new Command("logout") globalConfig.setCurrentSession(accountId); success(`Current account is ${accountId}`); + } else if (remainingSessions.length === 0) { + globalConfig.setCurrentSession(''); } success("Logging out"); diff --git a/lib/commands/push.js b/lib/commands/push.js index 1655e734..e18dd26d 100644 --- a/lib/commands/push.js +++ b/lib/commands/push.js @@ -55,7 +55,10 @@ const { tablesDBUpdate, tablesDBCreateTable, tablesDBGetTable, - tablesDBUpdateTable + tablesDBUpdateTable, + tablesDBList, + tablesDBDelete, + tablesDBListTables } = require("./tables-db"); const { storageGetBucket, storageUpdateBucket, storageCreateBucket @@ -1700,6 +1703,147 @@ const pushFunction = async ({ functionId, async, code, withVariables } = { retur } } +const checkAndApplyTablesDBChanges = async () => { + log('Checking for tablesDB changes ...'); + + const localTablesDBs = localConfig.getTablesDBs(); + const { databases: remoteTablesDBs } = await paginate(tablesDBList, { parseOutput: false }, 100, 'databases'); + + if (localTablesDBs.length === 0 && remoteTablesDBs.length === 0) { + return { applied: false, resyncNeeded: false }; + } + + const changes = []; + const toCreate = []; + const toUpdate = []; + const toDelete = []; + + // Check for deletions - remote DBs that aren't in local config + for (const remoteDB of remoteTablesDBs) { + const localDB = localTablesDBs.find(db => db.$id === remoteDB.$id); + if (!localDB) { + toDelete.push(remoteDB); + changes.push({ + id: remoteDB.$id, + key: 'Database', + remote: chalk.red(`${remoteDB.name} (${remoteDB.$id})`), + local: chalk.green('(deleted locally)') + }); + } + } + + // Check for additions and updates + for (const localDB of localTablesDBs) { + const remoteDB = remoteTablesDBs.find(db => db.$id === localDB.$id); + + if (!remoteDB) { + toCreate.push(localDB); + changes.push({ + id: localDB.$id, + key: 'Database', + remote: chalk.red('(does not exist)'), + local: chalk.green(`${localDB.name} (${localDB.$id})`) + }); + } else { + let hasChanges = false; + + if (remoteDB.name !== localDB.name) { + hasChanges = true; + changes.push({ + id: localDB.$id, + key: 'Name', + remote: chalk.red(remoteDB.name), + local: chalk.green(localDB.name) + }); + } + + if (remoteDB.enabled !== localDB.enabled) { + hasChanges = true; + changes.push({ + id: localDB.$id, + key: 'Enabled?', + remote: chalk.red(remoteDB.enabled), + local: chalk.green(localDB.enabled) + }); + } + + if (hasChanges) { + toUpdate.push(localDB); + } + } + } + + if (changes.length === 0) { + return { applied: false, resyncNeeded: false }; + } + + log('Found changes in tablesDB resources:'); + 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('-------------------------------------------------------------------')}`); + } + + if ((await getConfirmation()) !== true) { + 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) { + 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) { + 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) { + 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.`); + } + } + + return { applied: true, resyncNeeded: needsResync }; +}; + const pushTable = async ({ returnOnZero, attempts } = { returnOnZero: false }) => { const tables = []; @@ -1707,6 +1851,25 @@ const pushTable = async ({ returnOnZero, attempts } = { returnOnZero: false }) = 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 => db.$id)); + const localTables = localConfig.getTables(); + const validTables = localTables.filter(table => remoteDatabaseIds.has(table.databaseId)); + + localConfig.set('tables', validTables); + + const validTablesDBs = localTablesDBs.filter(db => remoteDatabaseIds.has(db.$id)); + localConfig.set('tablesDB', validTablesDBs); + + success('Configuration resynced successfully.'); + } + if (cliConfig.all) { checkDeployConditions(localConfig); tables.push(...localConfig.getTables()); @@ -1730,39 +1893,6 @@ const pushTable = async ({ returnOnZero, attempts } = { returnOnZero: false }) = return; } - const databases = Array.from(new Set(tables.map(table => table['databaseId']))); - - // Parallel tablesDB actions - await Promise.all(databases.map(async (databaseId) => { - const localDatabase = localConfig.getTablesDB(databaseId); - - try { - const database = await tablesDBGet({ - databaseId: databaseId, - parseOutput: false, - }); - - if (database.name !== (localDatabase.name ?? databaseId)) { - await tablesDBUpdate({ - 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 tablesDBCreate({ - databaseId: databaseId, - name: localDatabase.name ?? databaseId, - parseOutput: false, - }); - } - })); - - if (!(await approveChanges(tables, tablesDBGetTable, KeysTable, 'tableId', 'tables', ['columns', 'indexes'], 'databaseId', 'databaseId'))) { return; } diff --git a/lib/config.js b/lib/config.js index 8756b558..a8c76678 100644 --- a/lib/config.js +++ b/lib/config.js @@ -681,15 +681,25 @@ class Global extends Config { getSessions() { const sessions = Object.keys(this.data).filter((key) => !Global.IGNORE_ATTRIBUTES.includes(key)) + const current = this.getCurrentSession(); - return sessions.map((session) => { - - return { - id: session, - endpoint: this.data[session][Global.PREFERENCE_ENDPOINT], - email: this.data[session][Global.PREFERENCE_EMAIL] + const sessionMap = new Map(); + + sessions.forEach((sessionId) => { + const email = this.data[sessionId][Global.PREFERENCE_EMAIL]; + const endpoint = this.data[sessionId][Global.PREFERENCE_ENDPOINT]; + const key = `${email}|${endpoint}`; + + if (sessionId === current || !sessionMap.has(key)) { + sessionMap.set(key, { + id: sessionId, + endpoint: this.data[sessionId][Global.PREFERENCE_ENDPOINT], + email: this.data[sessionId][Global.PREFERENCE_EMAIL] + }); } - }) + }); + + return Array.from(sessionMap.values()); } addSession(session, data) {