From f5214794ea53741cbb1bdc5775e08d9cba40421e Mon Sep 17 00:00:00 2001 From: Chirag Aggarwal Date: Tue, 13 Oct 2026 11:18:54 +0100 Subject: [PATCH] feat: add analytics events, profile photos and OAuth2 state for version 1.3.0 --- CHANGELOG.md | 11 + .../account/create-email-password-session.md | 1 + .../account/create-o-auth-2-session.md | 1 + .../examples/account/create-o-auth-2-token.md | 1 + docs/examples/account/delete-sessions.md | 4 +- docs/examples/account/list-sessions.md | 4 +- docs/examples/analytics/create-event.md | 27 ++ docs/examples/avatars/delete-photo.md | 13 + docs/examples/avatars/update-photo.md | 20 ++ docs/examples/databases/list-transactions.md | 1 + .../examples/documentsdb/list-transactions.md | 1 + docs/examples/locale/list-codes.md | 4 +- docs/examples/locale/list-continents.md | 4 +- docs/examples/locale/list-countries-eu.md | 4 +- docs/examples/locale/list-countries-phones.md | 4 +- docs/examples/locale/list-countries.md | 4 +- docs/examples/locale/list-currencies.md | 4 +- docs/examples/locale/list-languages.md | 4 +- docs/examples/tablesdb/list-transactions.md | 1 + docs/examples/teams/create-membership.md | 1 + docs/examples/vectorsdb/list-transactions.md | 1 + package-lock.json | 4 +- package.json | 2 +- src/client.ts | 2 +- src/enums/o-auth-provider.ts | 1 + src/index.ts | 1 + src/models.ts | 104 ++++++ src/services/account.ts | 134 +++++++- src/services/analytics.ts | 260 +++++++++++++++ src/services/avatars.ts | 315 +++++++++++++++++- src/services/databases.ts | 26 +- src/services/documents-db.ts | 26 +- src/services/locale.ts | 254 +++++++++++++- src/services/tables-db.ts | 26 +- src/services/teams.ts | 23 +- src/services/vectors-db.ts | 26 +- 36 files changed, 1264 insertions(+), 55 deletions(-) create mode 100644 docs/examples/analytics/create-event.md create mode 100644 docs/examples/avatars/delete-photo.md create mode 100644 docs/examples/avatars/update-photo.md create mode 100644 src/services/analytics.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index 8838ed3a..65dea41e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,16 @@ # Change log +## 1.3.0 + +* Added: `analytics.createEvent` in a new `Analytics` service to send tracking events +* Added: `avatars.updatePhoto` and `avatars.deletePhoto` to manage the user's custom profile photo, and the `Account` model +* Added: `Webflow` to the `OAuthProvider` enum +* Added: optional `state` on `account.createOAuth2Session` and `account.createOAuth2Token`, returned unchanged on the success and failure URLs +* Added: optional `duration` on `account.createEmailPasswordSession` to set the session length +* Added: optional `current` on `account.deleteSessions` to keep the current session signed in +* Added: optional `membershipId` on `teams.createMembership` +* Added: optional `total` on `account.listSessions`, the `locale` list methods and `listTransactions` + ## 1.2.0 * Added: `account` passkey methods `listPasskeys`, `createPasskey`, `getPasskey`, `updatePasskey`, `deletePasskey` and `updatePasskeyVerification` diff --git a/docs/examples/account/create-email-password-session.md b/docs/examples/account/create-email-password-session.md index e38beaf7..f52da467 100644 --- a/docs/examples/account/create-email-password-session.md +++ b/docs/examples/account/create-email-password-session.md @@ -10,6 +10,7 @@ const account = new Account(client); const result = await account.createEmailPasswordSession({ email: 'email@example.com', password: 'password', + duration: 60, // optional }); console.log(result); diff --git a/docs/examples/account/create-o-auth-2-session.md b/docs/examples/account/create-o-auth-2-session.md index c90edc14..48c50d96 100644 --- a/docs/examples/account/create-o-auth-2-session.md +++ b/docs/examples/account/create-o-auth-2-session.md @@ -12,5 +12,6 @@ account.createOAuth2Session({ success: 'https://example.com', // optional failure: 'https://example.com', // optional scopes: [], // optional + state: '', // optional }); ``` diff --git a/docs/examples/account/create-o-auth-2-token.md b/docs/examples/account/create-o-auth-2-token.md index c043fb78..da5ee9c8 100644 --- a/docs/examples/account/create-o-auth-2-token.md +++ b/docs/examples/account/create-o-auth-2-token.md @@ -12,5 +12,6 @@ account.createOAuth2Token({ success: 'https://example.com', // optional failure: 'https://example.com', // optional scopes: [], // optional + state: '', // optional }); ``` diff --git a/docs/examples/account/delete-sessions.md b/docs/examples/account/delete-sessions.md index 0f1bc281..60045053 100644 --- a/docs/examples/account/delete-sessions.md +++ b/docs/examples/account/delete-sessions.md @@ -7,7 +7,9 @@ const client = new Client() const account = new Account(client); -const result = await account.deleteSessions(); +const result = await account.deleteSessions({ + current: false, // optional +}); console.log(result); ``` diff --git a/docs/examples/account/list-sessions.md b/docs/examples/account/list-sessions.md index c8acda4d..ddf9c133 100644 --- a/docs/examples/account/list-sessions.md +++ b/docs/examples/account/list-sessions.md @@ -7,7 +7,9 @@ const client = new Client() const account = new Account(client); -const result = await account.listSessions(); +const result = await account.listSessions({ + total: false, // optional +}); console.log(result); ``` diff --git a/docs/examples/analytics/create-event.md b/docs/examples/analytics/create-event.md new file mode 100644 index 00000000..eefca061 --- /dev/null +++ b/docs/examples/analytics/create-event.md @@ -0,0 +1,27 @@ +```javascript +import { Client, Analytics } from 'react-native-appwrite'; + +const client = new Client() + .setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint + .setProject(''); // Your project ID + +const analytics = new Analytics(client); + +const result = await analytics.createEvent({ + propertyId: '', + name: '', + url: 'https://example.com', + domain: '', // optional + referrer: '', // optional + screenWidth: null, // optional + sessionHash: '', // optional + scrollDepth: 0, // optional + engagementTime: 0, // optional + props: [], // optional + userId: '', // optional + ip: '', // optional + userAgent: '', // optional +}); + +console.log(result); +``` diff --git a/docs/examples/avatars/delete-photo.md b/docs/examples/avatars/delete-photo.md new file mode 100644 index 00000000..a0120a62 --- /dev/null +++ b/docs/examples/avatars/delete-photo.md @@ -0,0 +1,13 @@ +```javascript +import { Client, Avatars } from 'react-native-appwrite'; + +const client = new Client() + .setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint + .setProject(''); // Your project ID + +const avatars = new Avatars(client); + +const result = await avatars.deletePhoto(); + +console.log(result); +``` diff --git a/docs/examples/avatars/update-photo.md b/docs/examples/avatars/update-photo.md new file mode 100644 index 00000000..05204200 --- /dev/null +++ b/docs/examples/avatars/update-photo.md @@ -0,0 +1,20 @@ +```javascript +import { Client, Avatars } from 'react-native-appwrite'; + +const client = new Client() + .setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint + .setProject(''); // Your project ID + +const avatars = new Avatars(client); + +const result = await avatars.updatePhoto({ + file: { + name: 'image.png', + type: 'image/png', + size: 1024, + uri: 'file:///path/to/image.png', + }, +}); + +console.log(result); +``` diff --git a/docs/examples/databases/list-transactions.md b/docs/examples/databases/list-transactions.md index 051ea0f3..bc62da26 100644 --- a/docs/examples/databases/list-transactions.md +++ b/docs/examples/databases/list-transactions.md @@ -9,6 +9,7 @@ const databases = new Databases(client); const result = await databases.listTransactions({ queries: [], // optional + total: false, // optional }); console.log(result); diff --git a/docs/examples/documentsdb/list-transactions.md b/docs/examples/documentsdb/list-transactions.md index 24c8dbdb..d4a8c4ea 100644 --- a/docs/examples/documentsdb/list-transactions.md +++ b/docs/examples/documentsdb/list-transactions.md @@ -9,6 +9,7 @@ const documentsDB = new DocumentsDB(client); const result = await documentsDB.listTransactions({ queries: [], // optional + total: false, // optional }); console.log(result); diff --git a/docs/examples/locale/list-codes.md b/docs/examples/locale/list-codes.md index f96a7ee3..7157d5d8 100644 --- a/docs/examples/locale/list-codes.md +++ b/docs/examples/locale/list-codes.md @@ -7,7 +7,9 @@ const client = new Client() const locale = new Locale(client); -const result = await locale.listCodes(); +const result = await locale.listCodes({ + total: false, // optional +}); console.log(result); ``` diff --git a/docs/examples/locale/list-continents.md b/docs/examples/locale/list-continents.md index 8973cfd4..296b39d3 100644 --- a/docs/examples/locale/list-continents.md +++ b/docs/examples/locale/list-continents.md @@ -7,7 +7,9 @@ const client = new Client() const locale = new Locale(client); -const result = await locale.listContinents(); +const result = await locale.listContinents({ + total: false, // optional +}); console.log(result); ``` diff --git a/docs/examples/locale/list-countries-eu.md b/docs/examples/locale/list-countries-eu.md index f948ee69..4667a26f 100644 --- a/docs/examples/locale/list-countries-eu.md +++ b/docs/examples/locale/list-countries-eu.md @@ -7,7 +7,9 @@ const client = new Client() const locale = new Locale(client); -const result = await locale.listCountriesEU(); +const result = await locale.listCountriesEU({ + total: false, // optional +}); console.log(result); ``` diff --git a/docs/examples/locale/list-countries-phones.md b/docs/examples/locale/list-countries-phones.md index 7974d60e..4f719b3e 100644 --- a/docs/examples/locale/list-countries-phones.md +++ b/docs/examples/locale/list-countries-phones.md @@ -7,7 +7,9 @@ const client = new Client() const locale = new Locale(client); -const result = await locale.listCountriesPhones(); +const result = await locale.listCountriesPhones({ + total: false, // optional +}); console.log(result); ``` diff --git a/docs/examples/locale/list-countries.md b/docs/examples/locale/list-countries.md index b46bc615..ef9ff569 100644 --- a/docs/examples/locale/list-countries.md +++ b/docs/examples/locale/list-countries.md @@ -7,7 +7,9 @@ const client = new Client() const locale = new Locale(client); -const result = await locale.listCountries(); +const result = await locale.listCountries({ + total: false, // optional +}); console.log(result); ``` diff --git a/docs/examples/locale/list-currencies.md b/docs/examples/locale/list-currencies.md index 28498d9a..f3db19f3 100644 --- a/docs/examples/locale/list-currencies.md +++ b/docs/examples/locale/list-currencies.md @@ -7,7 +7,9 @@ const client = new Client() const locale = new Locale(client); -const result = await locale.listCurrencies(); +const result = await locale.listCurrencies({ + total: false, // optional +}); console.log(result); ``` diff --git a/docs/examples/locale/list-languages.md b/docs/examples/locale/list-languages.md index 835b04de..beb495b0 100644 --- a/docs/examples/locale/list-languages.md +++ b/docs/examples/locale/list-languages.md @@ -7,7 +7,9 @@ const client = new Client() const locale = new Locale(client); -const result = await locale.listLanguages(); +const result = await locale.listLanguages({ + total: false, // optional +}); console.log(result); ``` diff --git a/docs/examples/tablesdb/list-transactions.md b/docs/examples/tablesdb/list-transactions.md index e28ff141..ef26c6bf 100644 --- a/docs/examples/tablesdb/list-transactions.md +++ b/docs/examples/tablesdb/list-transactions.md @@ -9,6 +9,7 @@ const tablesDB = new TablesDB(client); const result = await tablesDB.listTransactions({ queries: [], // optional + total: false, // optional }); console.log(result); diff --git a/docs/examples/teams/create-membership.md b/docs/examples/teams/create-membership.md index e7fe0d72..c7173d2a 100644 --- a/docs/examples/teams/create-membership.md +++ b/docs/examples/teams/create-membership.md @@ -15,6 +15,7 @@ const result = await teams.createMembership({ phone: '+12065550100', // optional url: 'https://example.com', // optional name: '', // optional + membershipId: '', // optional }); console.log(result); diff --git a/docs/examples/vectorsdb/list-transactions.md b/docs/examples/vectorsdb/list-transactions.md index 8a009a98..d29cc045 100644 --- a/docs/examples/vectorsdb/list-transactions.md +++ b/docs/examples/vectorsdb/list-transactions.md @@ -9,6 +9,7 @@ const vectorsDB = new VectorsDB(client); const result = await vectorsDB.listTransactions({ queries: [], // optional + total: false, // optional }); console.log(result); diff --git a/package-lock.json b/package-lock.json index cbc7277f..65d1c8fa 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "react-native-appwrite", - "version": "1.2.0", + "version": "1.3.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "react-native-appwrite", - "version": "1.2.0", + "version": "1.3.0", "license": "BSD-3-Clause", "dependencies": { "expo-file-system": "18.*.*", diff --git a/package.json b/package.json index b8135180..2bbc2693 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "react-native-appwrite", "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": "1.2.0", + "version": "1.3.0", "license": "BSD-3-Clause", "main": "dist/cjs/sdk.js", "exports": { diff --git a/src/client.ts b/src/client.ts index 7cbc4828..9a8e4e40 100644 --- a/src/client.ts +++ b/src/client.ts @@ -208,7 +208,7 @@ class Client { 'x-sdk-name': 'React Native', 'x-sdk-platform': 'client', 'x-sdk-language': 'reactnative', - 'x-sdk-version': '1.2.0', + 'x-sdk-version': '1.3.0', 'X-Appwrite-Response-Format': '2.3.0', }; diff --git a/src/enums/o-auth-provider.ts b/src/enums/o-auth-provider.ts index 92a95970..3dab5fb3 100644 --- a/src/enums/o-auth-provider.ts +++ b/src/enums/o-auth-provider.ts @@ -41,6 +41,7 @@ export enum OAuthProvider { Tradeshift = 'tradeshift', TradeshiftBox = 'tradeshiftBox', Twitch = 'twitch', + Webflow = 'webflow', Wordpress = 'wordpress', X = 'x', Yahoo = 'yahoo', diff --git a/src/index.ts b/src/index.ts index bef0780a..c1e43eec 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,5 +1,6 @@ export { Client, AppwriteException } from './client'; export { Account } from './services/account'; +export { Analytics } from './services/analytics'; export { Avatars } from './services/avatars'; export { Databases } from './services/databases'; export { DocumentsDB } from './services/documents-db'; diff --git a/src/models.ts b/src/models.ts index d9617e63..09c3df82 100644 --- a/src/models.ts +++ b/src/models.ts @@ -480,6 +480,110 @@ export namespace Models { threads: number; }; + /** + * Account + */ + export type Account< + Preferences extends Models.Preferences = Models.DefaultPreferences, + > = { + /** + * User ID. + */ + $id: string; + /** + * User creation date in ISO 8601 format. + */ + $createdAt: string; + /** + * User update date in ISO 8601 format. + */ + $updatedAt: string; + /** + * User name. + */ + name: string; + /** + * User registration date in ISO 8601 format. + */ + registration: string; + /** + * User status. Pass `true` for enabled and `false` for disabled. + */ + status: boolean; + /** + * Labels for the user. + */ + labels: string[]; + /** + * Password update time in ISO 8601 format. + */ + passwordUpdate: string; + /** + * User email address. + */ + email: string; + /** + * User phone number in E.164 format. + */ + phone: string; + /** + * Email verification status. + */ + emailVerification: boolean; + /** + * Canonical form of the user email address. + */ + emailCanonical?: string; + /** + * Whether the user email is from a free email provider. + */ + emailIsFree?: boolean; + /** + * Whether the user email is from a disposable email provider. + */ + emailIsDisposable?: boolean; + /** + * Whether the user email is from a corporate domain. + */ + emailIsCorporate?: boolean; + /** + * Whether the user email is in its canonical form. + */ + emailIsCanonical?: boolean; + /** + * Whether the password was found in a known data breach the last time it was checked. Null when the password has never been checked. + */ + passwordPwned?: boolean; + /** + * Phone verification status. + */ + phoneVerification: boolean; + /** + * Multi factor authentication status. + */ + mfa: boolean; + /** + * User preferences as a key-value object + */ + prefs: Preferences; + /** + * A user-owned message receiver. A single user may have multiple e.g. emails, phones, and a browser. Each target is registered with a single provider. + */ + targets: Target[]; + /** + * Most recent access date in ISO 8601 format. This attribute is only updated again after 24 hours. + */ + accessedAt: string; + /** + * Whether the user can impersonate other users. + */ + impersonator?: boolean; + /** + * ID of the original actor performing the impersonation. Present only when the current request is impersonating another user. Internal audit logs attribute the action to this user, while the impersonated target is recorded only in internal audit payload data. + */ + impersonatorUserId?: string; + }; + /** * Preferences */ diff --git a/src/services/account.ts b/src/services/account.ts index 891fd2bc..a96b6cc9 100644 --- a/src/services/account.ts +++ b/src/services/account.ts @@ -2977,13 +2977,47 @@ export class Account extends Service { /** * Get the list of active sessions across different devices for the currently logged in user. * + * @param {boolean} params.total - When set to false, the total count returned will be 0 and will not be calculated. * @throws {AppwriteException} * @returns {Promise} */ - listSessions(): Promise { + listSessions(params?: { total?: boolean }): Promise; + /** + * Get the list of active sessions across different devices for the currently logged in user. + * + * @param {boolean} total - When set to false, the total count returned will be 0 and will not be calculated. + * @throws {AppwriteException} + * @returns {Promise} + * @deprecated Use the object parameter style method for a better developer experience. + */ + listSessions(total?: boolean): Promise; + listSessions( + paramsOrFirst?: { total?: boolean } | boolean, + ): Promise { + let params: { total?: boolean }; + + if ( + typeof paramsOrFirst === 'undefined' || + (paramsOrFirst && + typeof paramsOrFirst === 'object' && + !Array.isArray(paramsOrFirst)) + ) { + params = (paramsOrFirst || {}) as { total?: boolean }; + } else { + params = { + total: paramsOrFirst as boolean, + }; + } + + const total = params.total; + const apiPath = '/account/sessions'; const payload: Payload = {}; + if (typeof total !== 'undefined') { + payload['total'] = total; + } + const uri = new URL(this.client.config.endpoint + apiPath); return this.client.call( 'get', @@ -2999,13 +3033,47 @@ export class Account extends Service { /** * Delete all sessions from the user account and remove any sessions cookies from the end client. * + * @param {boolean} params.current - Delete the current session too. Use false to sign out of every other session while staying signed in on this one. * @throws {AppwriteException} * @returns {Promise} */ - deleteSessions(): Promise<{}> { + deleteSessions(params?: { current?: boolean }): Promise<{}>; + /** + * Delete all sessions from the user account and remove any sessions cookies from the end client. Pass `current` as false to keep the session making the request and sign out of every other session. + * + * @param {boolean} current - Delete the current session too. Use false to sign out of every other session while staying signed in on this one. + * @throws {AppwriteException} + * @returns {Promise<{}>} + * @deprecated Use the object parameter style method for a better developer experience. + */ + deleteSessions(current?: boolean): Promise<{}>; + deleteSessions( + paramsOrFirst?: { current?: boolean } | boolean, + ): Promise<{}> { + let params: { current?: boolean }; + + if ( + typeof paramsOrFirst === 'undefined' || + (paramsOrFirst && + typeof paramsOrFirst === 'object' && + !Array.isArray(paramsOrFirst)) + ) { + params = (paramsOrFirst || {}) as { current?: boolean }; + } else { + params = { + current: paramsOrFirst as boolean, + }; + } + + const current = params.current; + const apiPath = '/account/sessions'; const payload: Payload = {}; + if (typeof current !== 'undefined') { + payload['current'] = current; + } + const uri = new URL(this.client.config.endpoint + apiPath); return this.client.call( 'delete', @@ -3049,12 +3117,14 @@ export class Account extends Service { * * @param {string} params.email - User email. * @param {string} params.password - User password. Must be at least 8 chars. + * @param {number} params.duration - Session length in seconds. Minimum is 60 seconds, and it cannot exceed the project maximum session length. Defaults to the project maximum session length. * @throws {AppwriteException} * @returns {Promise} */ createEmailPasswordSession(params: { email: string; password: string; + duration?: number; }): Promise; /** * 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. @@ -3063,6 +3133,7 @@ export class Account extends Service { * * @param {string} email - User email. * @param {string} password - User password. Must be at least 8 chars. + * @param {number} duration - Session length in seconds. Minimum is 60 seconds, and it cannot exceed the project maximum session length. Defaults to the project maximum session length. * @throws {AppwriteException} * @returns {Promise} * @deprecated Use the object parameter style method for a better developer experience. @@ -3070,12 +3141,14 @@ export class Account extends Service { createEmailPasswordSession( email: string, password: string, + duration?: number, ): Promise; createEmailPasswordSession( - paramsOrFirst: { email: string; password: string } | string, - ...rest: [string?] + paramsOrFirst: + { email: string; password: string; duration?: number } | string, + ...rest: [string?, number?] ): Promise { - let params: { email: string; password: string }; + let params: { email: string; password: string; duration?: number }; if ( paramsOrFirst && @@ -3085,16 +3158,19 @@ export class Account extends Service { params = (paramsOrFirst || {}) as { email: string; password: string; + duration?: number; }; } else { params = { email: paramsOrFirst as string, password: rest[0] as string, + duration: rest[1] as number, }; } const email = params.email; const password = params.password; + const duration = params.duration; if (typeof email === 'undefined') { throw new AppwriteException('Missing required parameter: "email"'); @@ -3117,6 +3193,10 @@ export class Account extends Service { payload['password'] = password; } + if (typeof duration !== 'undefined') { + payload['duration'] = duration; + } + const uri = new URL(this.client.config.endpoint + apiPath); return this.client.call( 'post', @@ -3395,10 +3475,11 @@ export class Account extends Service { * 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). * * - * @param {OAuthProvider} params.provider - OAuth2 Provider. Currently, supported providers are: amazon, apple, appwrite, auth0, authentik, autodesk, bitbucket, bitly, box, cloudflare, dailymotion, discord, disqus, dropbox, etsy, facebook, figma, fusionauth, github, gitlab, google, huggingface, kakao, keycloak, kick, linkedin, microsoft, notion, oidc, okta, paypal, paypalSandbox, podio, resend, salesforce, slack, spotify, stripe, tiktok, tradeshift, tradeshiftBox, twitch, wordpress, x, yahoo, yammer, yandex, zoho, zoom. + * @param {OAuthProvider} params.provider - OAuth2 Provider. Currently, supported providers are: amazon, apple, appwrite, auth0, authentik, autodesk, bitbucket, bitly, box, cloudflare, dailymotion, discord, disqus, dropbox, etsy, facebook, figma, fusionauth, github, gitlab, google, huggingface, kakao, keycloak, kick, linkedin, microsoft, notion, oidc, okta, paypal, paypalSandbox, podio, resend, salesforce, slack, spotify, stripe, tiktok, tradeshift, tradeshiftBox, twitch, webflow, wordpress, x, yahoo, yammer, yandex, zoho, zoom. * @param {string} params.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. * @param {string} params.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. * @param {string[]} params.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. + * @param {string} params.state - An opaque value your app generates and keeps, for example in a cookie. It is returned unchanged as the `state` query parameter on the success and failure URLs, so your app can check that the sign-in it receives is one it started. Printable ASCII only (RFC 6749 Appendix A.5). Max length: 256 chars. * @throws {AppwriteException} * @returns {void|string} */ @@ -3407,6 +3488,7 @@ export class Account extends Service { success?: string; failure?: string; scopes?: string[]; + state?: string; }): void | URL; /** * 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. @@ -3416,10 +3498,11 @@ export class Account extends Service { * 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). * * - * @param {OAuthProvider} provider - OAuth2 Provider. Currently, supported providers are: amazon, apple, appwrite, auth0, authentik, autodesk, bitbucket, bitly, box, cloudflare, dailymotion, discord, disqus, dropbox, etsy, facebook, figma, fusionauth, github, gitlab, google, huggingface, kakao, keycloak, kick, linkedin, microsoft, notion, oidc, okta, paypal, paypalSandbox, podio, resend, salesforce, slack, spotify, stripe, tiktok, tradeshift, tradeshiftBox, twitch, wordpress, x, yahoo, yammer, yandex, zoho, zoom. + * @param {OAuthProvider} provider - OAuth2 Provider. Currently, supported providers are: amazon, apple, appwrite, auth0, authentik, autodesk, bitbucket, bitly, box, cloudflare, dailymotion, discord, disqus, dropbox, etsy, facebook, figma, fusionauth, github, gitlab, google, huggingface, kakao, keycloak, kick, linkedin, microsoft, notion, oidc, okta, paypal, paypalSandbox, podio, resend, salesforce, slack, spotify, stripe, tiktok, tradeshift, tradeshiftBox, twitch, webflow, wordpress, x, yahoo, yammer, yandex, zoho, zoom. * @param {string} 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. * @param {string} 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. * @param {string[]} 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. + * @param {string} state - An opaque value your app generates and keeps, for example in a cookie. It is returned unchanged as the `state` query parameter on the success and failure URLs, so your app can check that the sign-in it receives is one it started. Printable ASCII only (RFC 6749 Appendix A.5). Max length: 256 chars. * @throws {AppwriteException} * @returns {void | URL} * @deprecated Use the object parameter style method for a better developer experience. @@ -3429,6 +3512,7 @@ export class Account extends Service { success?: string, failure?: string, scopes?: string[], + state?: string, ): void | URL; createOAuth2Session( paramsOrFirst: @@ -3437,15 +3521,17 @@ export class Account extends Service { success?: string; failure?: string; scopes?: string[]; + state?: string; } | OAuthProvider, - ...rest: [string?, string?, string[]?] + ...rest: [string?, string?, string[]?, string?] ): void | URL { let params: { provider: OAuthProvider; success?: string; failure?: string; scopes?: string[]; + state?: string; }; if ( @@ -3455,13 +3541,15 @@ export class Account extends Service { ('provider' in paramsOrFirst || 'success' in paramsOrFirst || 'failure' in paramsOrFirst || - 'scopes' in paramsOrFirst) + 'scopes' in paramsOrFirst || + 'state' in paramsOrFirst) ) { params = (paramsOrFirst || {}) as { provider: OAuthProvider; success?: string; failure?: string; scopes?: string[]; + state?: string; }; } else { params = { @@ -3469,6 +3557,7 @@ export class Account extends Service { success: rest[0] as string, failure: rest[1] as string, scopes: rest[2] as string[], + state: rest[3] as string, }; } @@ -3476,6 +3565,7 @@ export class Account extends Service { const success = params.success; const failure = params.failure; const scopes = params.scopes; + const state = params.state; if (typeof provider === 'undefined') { throw new AppwriteException( @@ -3501,6 +3591,10 @@ export class Account extends Service { payload['scopes'] = scopes; } + if (typeof state !== 'undefined') { + payload['state'] = state; + } + const uri = new URL(this.client.config.endpoint + apiPath); payload['project'] = this.client.config.project; @@ -4349,10 +4443,11 @@ export class Account extends Service { * * 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). * - * @param {OAuthProvider} params.provider - OAuth2 Provider. Currently, supported providers are: amazon, apple, appwrite, auth0, authentik, autodesk, bitbucket, bitly, box, cloudflare, dailymotion, discord, disqus, dropbox, etsy, facebook, figma, fusionauth, github, gitlab, google, huggingface, kakao, keycloak, kick, linkedin, microsoft, notion, oidc, okta, paypal, paypalSandbox, podio, resend, salesforce, slack, spotify, stripe, tiktok, tradeshift, tradeshiftBox, twitch, wordpress, x, yahoo, yammer, yandex, zoho, zoom. + * @param {OAuthProvider} params.provider - OAuth2 Provider. Currently, supported providers are: amazon, apple, appwrite, auth0, authentik, autodesk, bitbucket, bitly, box, cloudflare, dailymotion, discord, disqus, dropbox, etsy, facebook, figma, fusionauth, github, gitlab, google, huggingface, kakao, keycloak, kick, linkedin, microsoft, notion, oidc, okta, paypal, paypalSandbox, podio, resend, salesforce, slack, spotify, stripe, tiktok, tradeshift, tradeshiftBox, twitch, webflow, wordpress, x, yahoo, yammer, yandex, zoho, zoom. * @param {string} params.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. * @param {string} params.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. * @param {string[]} params.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. + * @param {string} params.state - An opaque value your app generates and keeps, for example in a cookie. It is returned unchanged as the `state` query parameter on the success and failure URLs, so your app can check that the sign-in it receives is one it started. Printable ASCII only (RFC 6749 Appendix A.5). Max length: 256 chars. * @throws {AppwriteException} * @returns {void|string} */ @@ -4361,6 +4456,7 @@ export class Account extends Service { success?: string; failure?: string; scopes?: string[]; + state?: string; }): void | URL; /** * 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. @@ -4371,10 +4467,11 @@ export class Account extends Service { * * 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). * - * @param {OAuthProvider} provider - OAuth2 Provider. Currently, supported providers are: amazon, apple, appwrite, auth0, authentik, autodesk, bitbucket, bitly, box, cloudflare, dailymotion, discord, disqus, dropbox, etsy, facebook, figma, fusionauth, github, gitlab, google, huggingface, kakao, keycloak, kick, linkedin, microsoft, notion, oidc, okta, paypal, paypalSandbox, podio, resend, salesforce, slack, spotify, stripe, tiktok, tradeshift, tradeshiftBox, twitch, wordpress, x, yahoo, yammer, yandex, zoho, zoom. + * @param {OAuthProvider} provider - OAuth2 Provider. Currently, supported providers are: amazon, apple, appwrite, auth0, authentik, autodesk, bitbucket, bitly, box, cloudflare, dailymotion, discord, disqus, dropbox, etsy, facebook, figma, fusionauth, github, gitlab, google, huggingface, kakao, keycloak, kick, linkedin, microsoft, notion, oidc, okta, paypal, paypalSandbox, podio, resend, salesforce, slack, spotify, stripe, tiktok, tradeshift, tradeshiftBox, twitch, webflow, wordpress, x, yahoo, yammer, yandex, zoho, zoom. * @param {string} 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. * @param {string} 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. * @param {string[]} 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. + * @param {string} state - An opaque value your app generates and keeps, for example in a cookie. It is returned unchanged as the `state` query parameter on the success and failure URLs, so your app can check that the sign-in it receives is one it started. Printable ASCII only (RFC 6749 Appendix A.5). Max length: 256 chars. * @throws {AppwriteException} * @returns {void | URL} * @deprecated Use the object parameter style method for a better developer experience. @@ -4384,6 +4481,7 @@ export class Account extends Service { success?: string, failure?: string, scopes?: string[], + state?: string, ): void | URL; createOAuth2Token( paramsOrFirst: @@ -4392,15 +4490,17 @@ export class Account extends Service { success?: string; failure?: string; scopes?: string[]; + state?: string; } | OAuthProvider, - ...rest: [string?, string?, string[]?] + ...rest: [string?, string?, string[]?, string?] ): void | URL { let params: { provider: OAuthProvider; success?: string; failure?: string; scopes?: string[]; + state?: string; }; if ( @@ -4410,13 +4510,15 @@ export class Account extends Service { ('provider' in paramsOrFirst || 'success' in paramsOrFirst || 'failure' in paramsOrFirst || - 'scopes' in paramsOrFirst) + 'scopes' in paramsOrFirst || + 'state' in paramsOrFirst) ) { params = (paramsOrFirst || {}) as { provider: OAuthProvider; success?: string; failure?: string; scopes?: string[]; + state?: string; }; } else { params = { @@ -4424,6 +4526,7 @@ export class Account extends Service { success: rest[0] as string, failure: rest[1] as string, scopes: rest[2] as string[], + state: rest[3] as string, }; } @@ -4431,6 +4534,7 @@ export class Account extends Service { const success = params.success; const failure = params.failure; const scopes = params.scopes; + const state = params.state; if (typeof provider === 'undefined') { throw new AppwriteException( @@ -4456,6 +4560,10 @@ export class Account extends Service { payload['scopes'] = scopes; } + if (typeof state !== 'undefined') { + payload['state'] = state; + } + const uri = new URL(this.client.config.endpoint + apiPath); payload['project'] = this.client.config.project; diff --git a/src/services/analytics.ts b/src/services/analytics.ts new file mode 100644 index 00000000..af61d584 --- /dev/null +++ b/src/services/analytics.ts @@ -0,0 +1,260 @@ +import { Service } from '../service'; +import { AppwriteException, Client } from '../client'; +import type { Payload } from '../client'; + +export class Analytics extends Service { + constructor(client: Client) { + super(client); + } + + /** + * Send a tracking event from a browser, native app, or server-side SDK. + * + * @param {string} params.propertyId - Analytics property ID. + * @param {string} params.name - Event name. "pageview" is just a conventional event name; events are not modeled specially. + * @param {string} params.url - Full page URL or screen identifier. + * @param {string} params.domain - Hostname (e.g. example.com). + * @param {string} params.referrer - Referrer URL. + * @param {number} params.screenWidth - Viewport width in CSS pixels. + * @param {string} params.sessionHash - Optional session hash (provided by SDK). + * @param {number} params.scrollDepth - Scroll depth percentage 0-100. + * @param {number} params.engagementTime - Engagement time in seconds, 0-4294967295. + * @param {string[]} params.props - Custom string properties as a flat key=value list (max 32 entries, alternating key,value). + * @param {string} params.userId - Override user ID. Requires API-key auth with analytics.write scope. + * @param {string} params.ip - Override IP address. Requires API-key auth with analytics.write scope. + * @param {string} params.userAgent - Override user agent. Requires API-key auth with analytics.write scope. + * @throws {AppwriteException} + * @returns {Promise} + */ + createEvent(params: { + propertyId: string; + name: string; + url: string; + domain?: string; + referrer?: string; + screenWidth?: number; + sessionHash?: string; + scrollDepth?: number; + engagementTime?: number; + props?: string[]; + userId?: string; + ip?: string; + userAgent?: string; + }): Promise<{}>; + /** + * Send a tracking event from a browser, native app, or server-side SDK. + * + * @param {string} propertyId - Analytics property ID. + * @param {string} name - Event name. "pageview" is just a conventional event name; events are not modeled specially. + * @param {string} url - Full page URL or screen identifier. + * @param {string} domain - Hostname (e.g. example.com). + * @param {string} referrer - Referrer URL. + * @param {number} screenWidth - Viewport width in CSS pixels. + * @param {string} sessionHash - Optional session hash (provided by SDK). + * @param {number} scrollDepth - Scroll depth percentage 0-100. + * @param {number} engagementTime - Engagement time in seconds, 0-4294967295. + * @param {string[]} props - Custom string properties as a flat key=value list (max 32 entries, alternating key,value). + * @param {string} userId - Override user ID. Requires API-key auth with analytics.write scope. + * @param {string} ip - Override IP address. Requires API-key auth with analytics.write scope. + * @param {string} userAgent - Override user agent. Requires API-key auth with analytics.write scope. + * @throws {AppwriteException} + * @returns {Promise<{}>} + * @deprecated Use the object parameter style method for a better developer experience. + */ + createEvent( + propertyId: string, + name: string, + url: string, + domain?: string, + referrer?: string, + screenWidth?: number, + sessionHash?: string, + scrollDepth?: number, + engagementTime?: number, + props?: string[], + userId?: string, + ip?: string, + userAgent?: string, + ): Promise<{}>; + createEvent( + paramsOrFirst: + | { + propertyId: string; + name: string; + url: string; + domain?: string; + referrer?: string; + screenWidth?: number; + sessionHash?: string; + scrollDepth?: number; + engagementTime?: number; + props?: string[]; + userId?: string; + ip?: string; + userAgent?: string; + } + | string, + ...rest: [ + string?, + string?, + string?, + string?, + number?, + string?, + number?, + number?, + string[]?, + string?, + string?, + string?, + ] + ): Promise<{}> { + let params: { + propertyId: string; + name: string; + url: string; + domain?: string; + referrer?: string; + screenWidth?: number; + sessionHash?: string; + scrollDepth?: number; + engagementTime?: number; + props?: string[]; + userId?: string; + ip?: string; + userAgent?: string; + }; + + if ( + paramsOrFirst && + typeof paramsOrFirst === 'object' && + !Array.isArray(paramsOrFirst) + ) { + params = (paramsOrFirst || {}) as { + propertyId: string; + name: string; + url: string; + domain?: string; + referrer?: string; + screenWidth?: number; + sessionHash?: string; + scrollDepth?: number; + engagementTime?: number; + props?: string[]; + userId?: string; + ip?: string; + userAgent?: string; + }; + } else { + params = { + propertyId: paramsOrFirst as string, + name: rest[0] as string, + url: rest[1] as string, + domain: rest[2] as string, + referrer: rest[3] as string, + screenWidth: rest[4] as number, + sessionHash: rest[5] as string, + scrollDepth: rest[6] as number, + engagementTime: rest[7] as number, + props: rest[8] as string[], + userId: rest[9] as string, + ip: rest[10] as string, + userAgent: rest[11] as string, + }; + } + + const propertyId = params.propertyId; + const name = params.name; + const url = params.url; + const domain = params.domain; + const referrer = params.referrer; + const screenWidth = params.screenWidth; + const sessionHash = params.sessionHash; + const scrollDepth = params.scrollDepth; + const engagementTime = params.engagementTime; + const props = params.props; + const userId = params.userId; + const ip = params.ip; + const userAgent = params.userAgent; + + if (typeof propertyId === 'undefined' || propertyId === '') { + throw new AppwriteException( + 'Missing required parameter: "propertyId"', + ); + } + + if (typeof name === 'undefined') { + throw new AppwriteException('Missing required parameter: "name"'); + } + + if (typeof url === 'undefined') { + throw new AppwriteException('Missing required parameter: "url"'); + } + + const apiPath = '/analytics/properties/{propertyId}/events'.replace( + '{propertyId}', + encodeURIComponent(String(propertyId)), + ); + const apiPayload: Payload = {}; + + if (typeof name !== 'undefined') { + apiPayload['name'] = name; + } + + if (typeof url !== 'undefined') { + apiPayload['url'] = url; + } + + if (typeof domain !== 'undefined') { + apiPayload['domain'] = domain; + } + + if (typeof referrer !== 'undefined') { + apiPayload['referrer'] = referrer; + } + + if (typeof screenWidth !== 'undefined') { + apiPayload['screenWidth'] = screenWidth; + } + + if (typeof sessionHash !== 'undefined') { + apiPayload['sessionHash'] = sessionHash; + } + + if (typeof scrollDepth !== 'undefined') { + apiPayload['scrollDepth'] = scrollDepth; + } + + if (typeof engagementTime !== 'undefined') { + apiPayload['engagementTime'] = engagementTime; + } + + if (typeof props !== 'undefined') { + apiPayload['props'] = props; + } + + if (typeof userId !== 'undefined') { + apiPayload['userId'] = userId; + } + + if (typeof ip !== 'undefined') { + apiPayload['ip'] = ip; + } + + if (typeof userAgent !== 'undefined') { + apiPayload['userAgent'] = userAgent; + } + + const uri = new URL(this.client.config.endpoint + apiPath); + return this.client.call( + 'post', + uri, + { + 'X-Appwrite-Project': this.client.config.project, + 'content-type': 'application/json', + accept: 'application/json', + }, + apiPayload, + ); + } +} diff --git a/src/services/avatars.ts b/src/services/avatars.ts index 68c702e8..9eb7aa36 100644 --- a/src/services/avatars.ts +++ b/src/services/avatars.ts @@ -1,6 +1,9 @@ import { Service } from '../service'; import { AppwriteException, Client } from '../client'; -import type { Payload } from '../client'; +import type { Models } from '../models'; +import type { UploadProgress, Payload } from '../client'; +import * as FileSystem from 'expo-file-system'; +import { Platform as RNPlatform } from 'react-native'; import { Browser } from '../enums/browser'; import { CreditCard } from '../enums/credit-card'; @@ -863,6 +866,316 @@ export class Avatars extends Service { ); } + /** + * Update the profile photo of the currently authenticated user. The uploaded image takes priority over every other photo source, including OAuth2 identity photos, Gravatar, and Libravatar. Updating an already customized photo replaces it. The image must be at most 5MB and is sent in a single request. + * + * @param {{ name: string; type: string; size: number; uri: string }} params.file - Binary image file of at most 5MB. Allowed file types are png, jpg, jpeg, and webp. + * @throws {AppwriteException} + * @returns {Promise} + */ + async updatePhoto< + Preferences extends Models.Preferences = Models.DefaultPreferences, + >(params: { + file: { name: string; type: string; size: number; uri: string }; + onProgress?: (progress: UploadProgress) => void; + }): Promise>; + /** + * Update the profile photo of the currently authenticated user. The uploaded image takes priority over every other photo source, including OAuth2 identity photos, Gravatar, and Libravatar. Updating an already customized photo replaces it. The image must be at most 5MB and is sent in a single request. + * + * @param {{ name: string; type: string; size: number; uri: string }} file - Binary image file of at most 5MB. Allowed file types are png, jpg, jpeg, and webp. + * @throws {AppwriteException} + * @returns {Promise>} + * @deprecated Use the object parameter style method for a better developer experience. + */ + async updatePhoto< + Preferences extends Models.Preferences = Models.DefaultPreferences, + >( + file: { name: string; type: string; size: number; uri: string }, + onProgress?: (progress: UploadProgress) => void, + ): Promise>; + async updatePhoto< + Preferences extends Models.Preferences = Models.DefaultPreferences, + >( + paramsOrFirst: + | { + file: { + name: string; + type: string; + size: number; + uri: string; + }; + onProgress?: (progress: UploadProgress) => void; + } + | { name: string; type: string; size: number; uri: string }, + ...rest: [((progress: UploadProgress) => void)?] + ): Promise> { + let params: { + file: { name: string; type: string; size: number; uri: string }; + }; + let onProgress: (progress: UploadProgress) => void; + + if ( + paramsOrFirst && + typeof paramsOrFirst === 'object' && + !Array.isArray(paramsOrFirst) && + ('file' in paramsOrFirst || 'onProgress' in paramsOrFirst) + ) { + params = (paramsOrFirst || {}) as { + file: { name: string; type: string; size: number; uri: string }; + }; + onProgress = paramsOrFirst?.onProgress as ( + progress: UploadProgress, + ) => void; + } else { + params = { + file: paramsOrFirst as { + name: string; + type: string; + size: number; + uri: string; + }, + }; + onProgress = rest[0] as (progress: UploadProgress) => void; + } + + const file = params.file; + + if (typeof file === 'undefined') { + throw new AppwriteException('Missing required parameter: "file"'); + } + + const apiPath = '/avatars/photo'; + const apiPayload: Payload = {}; + + if (typeof file !== 'undefined') { + apiPayload['file'] = file; + } + + const uri = new URL(this.client.config.endpoint + apiPath); + + const apiHeaders: { [header: string]: string } = { + 'X-Appwrite-Project': this.client.config.project, + 'content-type': 'multipart/form-data', + accept: 'application/json', + }; + + const size = file.size; + + if (size <= Service.CHUNK_SIZE) { + apiPayload['file'] = Service.filePart( + file.uri, + file.name, + file.type, + () => + FileSystem.readAsStringAsync(file.uri, { + encoding: FileSystem.EncodingType.Base64, + }), + ); + + return this.client.call('put', uri, apiHeaders, apiPayload); + } + + let offset = 0; + let response = undefined; + + const totalChunks = Math.ceil(size / Service.CHUNK_SIZE); + + // Upload first chunk alone to get the upload ID + if (offset === 0) { + const firstChunkEnd = Math.min(Service.CHUNK_SIZE, size); + const firstChunkHeaders = { + ...apiHeaders, + 'content-range': 'bytes 0-' + (firstChunkEnd - 1) + '/' + size, + }; + + const firstChunk = await FileSystem.readAsStringAsync(file.uri, { + encoding: FileSystem.EncodingType.Base64, + position: 0, + length: Service.CHUNK_SIZE, + }); + let firstPath = `data:${file.type};base64,${firstChunk}`; + if (RNPlatform.OS.toLowerCase() === 'android') { + firstPath = + FileSystem.cacheDirectory + + '/tmp_chunk_' + + new Date().getTime(); + await FileSystem.writeAsStringAsync(firstPath, firstChunk, { + encoding: FileSystem.EncodingType.Base64, + }); + } + + apiPayload['file'] = Service.filePart( + firstPath, + file.name, + file.type, + async () => firstChunk, + ); + + response = await this.client.call( + 'put', + uri, + firstChunkHeaders, + apiPayload, + ); + offset = firstChunkEnd; + + if (onProgress) { + onProgress({ + $id: response.$id, + progress: (offset / size) * 100, + sizeUploaded: offset, + chunksTotal: totalChunks, + chunksUploaded: 1, + }); + } + } + + if (offset >= size) { + return response; + } + + const uploadId = response?.$id; + const chunks: { index: number; start: number; end: number }[] = []; + const startChunkIndex = Math.ceil(offset / Service.CHUNK_SIZE); + for (let i = startChunkIndex; i < totalChunks; i++) { + const start = i * Service.CHUNK_SIZE; + const end = Math.min(start + Service.CHUNK_SIZE, size); + chunks.push({ index: i, start, end }); + } + + // Upload remaining chunks with max concurrency of 8 + const CONCURRENCY = 8; + let completedCount = startChunkIndex; + let uploadedBytes = offset; + let finalResponse = null; + let failed = false; + + const isUploadComplete = (chunkResponse: any) => { + const chunksUploaded = chunkResponse?.chunksUploaded; + const chunksTotal = chunkResponse?.chunksTotal ?? totalChunks; + return ( + typeof chunksUploaded === 'number' && + typeof chunksTotal === 'number' && + chunksUploaded >= chunksTotal + ); + }; + + const uploadChunk = async (chunk: (typeof chunks)[0]) => { + const chunkHeaders = { ...apiHeaders }; + if (uploadId) { + chunkHeaders['x-appwrite-id'] = uploadId; + } + chunkHeaders['content-range'] = + 'bytes ' + chunk.start + '-' + (chunk.end - 1) + '/' + size; + + const chunkData = await FileSystem.readAsStringAsync(file.uri, { + encoding: FileSystem.EncodingType.Base64, + position: chunk.start, + length: chunk.end - chunk.start, + }); + + let chunkPath = `data:${file.type};base64,${chunkData}`; + if (RNPlatform.OS.toLowerCase() === 'android') { + chunkPath = + FileSystem.cacheDirectory + + '/tmp_chunk_' + + new Date().getTime() + + '_' + + chunk.index; + await FileSystem.writeAsStringAsync(chunkPath, chunkData, { + encoding: FileSystem.EncodingType.Base64, + }); + } + + const chunkPayload = { ...apiPayload }; + chunkPayload['file'] = Service.filePart( + chunkPath, + file.name, + file.type, + async () => chunkData, + ); + + const chunkResponse = await this.client.call( + 'put', + uri, + chunkHeaders, + chunkPayload, + ); + + if (failed) { + return chunkResponse; + } + + completedCount++; + uploadedBytes += chunk.end - chunk.start; + + response = chunkResponse; + if (isUploadComplete(chunkResponse)) { + finalResponse = chunkResponse; + } + + if (onProgress) { + onProgress({ + $id: uploadId, + progress: (uploadedBytes / size) * 100, + sizeUploaded: uploadedBytes, + chunksTotal: totalChunks, + chunksUploaded: completedCount, + }); + } + + return chunkResponse; + }; + + // Process with limited concurrency using a worker pool + const queue = [...chunks]; + const workers: Promise[] = []; + const workerCount = Math.min(CONCURRENCY, queue.length); + + for (let i = 0; i < workerCount; i++) { + workers.push( + (async () => { + while (!failed && queue.length > 0) { + const chunk = queue.shift()!; + try { + await uploadChunk(chunk); + } catch (error) { + failed = true; + throw error; + } + } + })(), + ); + } + + await Promise.all(workers); + + return finalResponse ?? response; + } + + /** + * Delete the profile photo of the currently authenticated user and store the built-in static placeholder in its place. The placeholder is the user's photo from then on, so it takes priority over every other photo source — OAuth2 identity photos, Gravatar, Libravatar, and initials — until a new photo is uploaded with avatars.updatePhoto. + * + * @throws {AppwriteException} + * @returns {Promise} + */ + deletePhoto(): Promise<{}> { + const apiPath = '/avatars/photo'; + const apiPayload: Payload = {}; + + const uri = new URL(this.client.config.endpoint + apiPath); + return this.client.call( + 'delete', + uri, + { + 'X-Appwrite-Project': this.client.config.project, + 'content-type': 'application/json', + accept: 'application/json', + }, + apiPayload, + ); + } + /** * 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. * diff --git a/src/services/databases.ts b/src/services/databases.ts index 8bf59521..eeb39020 100644 --- a/src/services/databases.ts +++ b/src/services/databases.ts @@ -12,41 +12,53 @@ export class Databases extends Service { * List transactions across all databases. * * @param {string[]} params.queries - Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). + * @param {boolean} params.total - When set to false, the total count returned will be 0 and will not be calculated. * @throws {AppwriteException} * @returns {Promise} * @deprecated This API has been deprecated since 1.8.0. Please use `TablesDB.listTransactions` instead. */ listTransactions(params?: { queries?: string[]; + total?: boolean; }): Promise; /** * List transactions across all databases. * * @param {string[]} queries - Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). + * @param {boolean} total - When set to false, the total count returned will be 0 and will not be calculated. * @throws {AppwriteException} * @returns {Promise} * @deprecated Use the object parameter style method for a better developer experience. */ - listTransactions(queries?: string[]): Promise; listTransactions( - paramsOrFirst?: { queries?: string[] } | string[], + queries?: string[], + total?: boolean, + ): Promise; + listTransactions( + paramsOrFirst?: { queries?: string[]; total?: boolean } | string[], + ...rest: [boolean?] ): Promise { - let params: { queries?: string[] }; + let params: { queries?: string[]; total?: boolean }; if ( - typeof paramsOrFirst === 'undefined' || + (typeof paramsOrFirst === 'undefined' && rest.length === 0) || (paramsOrFirst && typeof paramsOrFirst === 'object' && !Array.isArray(paramsOrFirst)) ) { - params = (paramsOrFirst || {}) as { queries?: string[] }; + params = (paramsOrFirst || {}) as { + queries?: string[]; + total?: boolean; + }; } else { params = { queries: paramsOrFirst as string[], + total: rest[0] as boolean, }; } const queries = params.queries; + const total = params.total; const apiPath = '/databases/transactions'; const payload: Payload = {}; @@ -55,6 +67,10 @@ export class Databases extends Service { payload['queries'] = queries; } + if (typeof total !== 'undefined') { + payload['total'] = total; + } + const uri = new URL(this.client.config.endpoint + apiPath); return this.client.call( 'get', diff --git a/src/services/documents-db.ts b/src/services/documents-db.ts index 082627d1..47924672 100644 --- a/src/services/documents-db.ts +++ b/src/services/documents-db.ts @@ -12,40 +12,52 @@ export class DocumentsDB extends Service { * List transactions across all databases. * * @param {string[]} params.queries - Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). + * @param {boolean} params.total - When set to false, the total count returned will be 0 and will not be calculated. * @throws {AppwriteException} * @returns {Promise} */ listTransactions(params?: { queries?: string[]; + total?: boolean; }): Promise; /** * List transactions across all databases. * * @param {string[]} queries - Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). + * @param {boolean} total - When set to false, the total count returned will be 0 and will not be calculated. * @throws {AppwriteException} * @returns {Promise} * @deprecated Use the object parameter style method for a better developer experience. */ - listTransactions(queries?: string[]): Promise; listTransactions( - paramsOrFirst?: { queries?: string[] } | string[], + queries?: string[], + total?: boolean, + ): Promise; + listTransactions( + paramsOrFirst?: { queries?: string[]; total?: boolean } | string[], + ...rest: [boolean?] ): Promise { - let params: { queries?: string[] }; + let params: { queries?: string[]; total?: boolean }; if ( - typeof paramsOrFirst === 'undefined' || + (typeof paramsOrFirst === 'undefined' && rest.length === 0) || (paramsOrFirst && typeof paramsOrFirst === 'object' && !Array.isArray(paramsOrFirst)) ) { - params = (paramsOrFirst || {}) as { queries?: string[] }; + params = (paramsOrFirst || {}) as { + queries?: string[]; + total?: boolean; + }; } else { params = { queries: paramsOrFirst as string[], + total: rest[0] as boolean, }; } const queries = params.queries; + const total = params.total; const apiPath = '/documentsdb/transactions'; const payload: Payload = {}; @@ -54,6 +66,10 @@ export class DocumentsDB extends Service { payload['queries'] = queries; } + if (typeof total !== 'undefined') { + payload['total'] = total; + } + const uri = new URL(this.client.config.endpoint + apiPath); return this.client.call( 'get', diff --git a/src/services/locale.ts b/src/services/locale.ts index 6259730a..96ff59bb 100644 --- a/src/services/locale.ts +++ b/src/services/locale.ts @@ -35,13 +35,47 @@ export class Locale extends Service { /** * List of all locale codes in [ISO 639-1](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes). * + * @param {boolean} params.total - When set to false, the total count returned will be 0 and will not be calculated. * @throws {AppwriteException} * @returns {Promise} */ - listCodes(): Promise { + listCodes(params?: { total?: boolean }): Promise; + /** + * List of all locale codes in [ISO 639-1](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes). + * + * @param {boolean} total - When set to false, the total count returned will be 0 and will not be calculated. + * @throws {AppwriteException} + * @returns {Promise} + * @deprecated Use the object parameter style method for a better developer experience. + */ + listCodes(total?: boolean): Promise; + listCodes( + paramsOrFirst?: { total?: boolean } | boolean, + ): Promise { + let params: { total?: boolean }; + + if ( + typeof paramsOrFirst === 'undefined' || + (paramsOrFirst && + typeof paramsOrFirst === 'object' && + !Array.isArray(paramsOrFirst)) + ) { + params = (paramsOrFirst || {}) as { total?: boolean }; + } else { + params = { + total: paramsOrFirst as boolean, + }; + } + + const total = params.total; + const apiPath = '/locale/codes'; const payload: Payload = {}; + if (typeof total !== 'undefined') { + payload['total'] = total; + } + const uri = new URL(this.client.config.endpoint + apiPath); return this.client.call( 'get', @@ -57,13 +91,47 @@ export class Locale extends Service { /** * List of all continents. You can use the locale header to get the data in a supported language. * + * @param {boolean} params.total - When set to false, the total count returned will be 0 and will not be calculated. * @throws {AppwriteException} * @returns {Promise} */ - listContinents(): Promise { + listContinents(params?: { total?: boolean }): Promise; + /** + * List of all continents. You can use the locale header to get the data in a supported language. + * + * @param {boolean} total - When set to false, the total count returned will be 0 and will not be calculated. + * @throws {AppwriteException} + * @returns {Promise} + * @deprecated Use the object parameter style method for a better developer experience. + */ + listContinents(total?: boolean): Promise; + listContinents( + paramsOrFirst?: { total?: boolean } | boolean, + ): Promise { + let params: { total?: boolean }; + + if ( + typeof paramsOrFirst === 'undefined' || + (paramsOrFirst && + typeof paramsOrFirst === 'object' && + !Array.isArray(paramsOrFirst)) + ) { + params = (paramsOrFirst || {}) as { total?: boolean }; + } else { + params = { + total: paramsOrFirst as boolean, + }; + } + + const total = params.total; + const apiPath = '/locale/continents'; const payload: Payload = {}; + if (typeof total !== 'undefined') { + payload['total'] = total; + } + const uri = new URL(this.client.config.endpoint + apiPath); return this.client.call( 'get', @@ -79,13 +147,47 @@ export class Locale extends Service { /** * List of all countries. You can use the locale header to get the data in a supported language. * + * @param {boolean} params.total - When set to false, the total count returned will be 0 and will not be calculated. * @throws {AppwriteException} * @returns {Promise} */ - listCountries(): Promise { + listCountries(params?: { total?: boolean }): Promise; + /** + * List of all countries. You can use the locale header to get the data in a supported language. + * + * @param {boolean} total - When set to false, the total count returned will be 0 and will not be calculated. + * @throws {AppwriteException} + * @returns {Promise} + * @deprecated Use the object parameter style method for a better developer experience. + */ + listCountries(total?: boolean): Promise; + listCountries( + paramsOrFirst?: { total?: boolean } | boolean, + ): Promise { + let params: { total?: boolean }; + + if ( + typeof paramsOrFirst === 'undefined' || + (paramsOrFirst && + typeof paramsOrFirst === 'object' && + !Array.isArray(paramsOrFirst)) + ) { + params = (paramsOrFirst || {}) as { total?: boolean }; + } else { + params = { + total: paramsOrFirst as boolean, + }; + } + + const total = params.total; + const apiPath = '/locale/countries'; const payload: Payload = {}; + if (typeof total !== 'undefined') { + payload['total'] = total; + } + const uri = new URL(this.client.config.endpoint + apiPath); return this.client.call( 'get', @@ -101,13 +203,47 @@ export class Locale extends Service { /** * 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. * + * @param {boolean} params.total - When set to false, the total count returned will be 0 and will not be calculated. * @throws {AppwriteException} * @returns {Promise} */ - listCountriesEU(): Promise { + listCountriesEU(params?: { total?: boolean }): Promise; + /** + * 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. + * + * @param {boolean} total - When set to false, the total count returned will be 0 and will not be calculated. + * @throws {AppwriteException} + * @returns {Promise} + * @deprecated Use the object parameter style method for a better developer experience. + */ + listCountriesEU(total?: boolean): Promise; + listCountriesEU( + paramsOrFirst?: { total?: boolean } | boolean, + ): Promise { + let params: { total?: boolean }; + + if ( + typeof paramsOrFirst === 'undefined' || + (paramsOrFirst && + typeof paramsOrFirst === 'object' && + !Array.isArray(paramsOrFirst)) + ) { + params = (paramsOrFirst || {}) as { total?: boolean }; + } else { + params = { + total: paramsOrFirst as boolean, + }; + } + + const total = params.total; + const apiPath = '/locale/countries/eu'; const payload: Payload = {}; + if (typeof total !== 'undefined') { + payload['total'] = total; + } + const uri = new URL(this.client.config.endpoint + apiPath); return this.client.call( 'get', @@ -123,13 +259,49 @@ export class Locale extends Service { /** * List of all countries phone codes. You can use the locale header to get the data in a supported language. * + * @param {boolean} params.total - When set to false, the total count returned will be 0 and will not be calculated. * @throws {AppwriteException} * @returns {Promise} */ - listCountriesPhones(): Promise { + listCountriesPhones(params?: { + total?: boolean; + }): Promise; + /** + * List of all countries phone codes. You can use the locale header to get the data in a supported language. + * + * @param {boolean} total - When set to false, the total count returned will be 0 and will not be calculated. + * @throws {AppwriteException} + * @returns {Promise} + * @deprecated Use the object parameter style method for a better developer experience. + */ + listCountriesPhones(total?: boolean): Promise; + listCountriesPhones( + paramsOrFirst?: { total?: boolean } | boolean, + ): Promise { + let params: { total?: boolean }; + + if ( + typeof paramsOrFirst === 'undefined' || + (paramsOrFirst && + typeof paramsOrFirst === 'object' && + !Array.isArray(paramsOrFirst)) + ) { + params = (paramsOrFirst || {}) as { total?: boolean }; + } else { + params = { + total: paramsOrFirst as boolean, + }; + } + + const total = params.total; + const apiPath = '/locale/countries/phones'; const payload: Payload = {}; + if (typeof total !== 'undefined') { + payload['total'] = total; + } + const uri = new URL(this.client.config.endpoint + apiPath); return this.client.call( 'get', @@ -145,13 +317,47 @@ export class Locale extends Service { /** * 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. * + * @param {boolean} params.total - When set to false, the total count returned will be 0 and will not be calculated. * @throws {AppwriteException} * @returns {Promise} */ - listCurrencies(): Promise { + listCurrencies(params?: { total?: boolean }): Promise; + /** + * 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. + * + * @param {boolean} total - When set to false, the total count returned will be 0 and will not be calculated. + * @throws {AppwriteException} + * @returns {Promise} + * @deprecated Use the object parameter style method for a better developer experience. + */ + listCurrencies(total?: boolean): Promise; + listCurrencies( + paramsOrFirst?: { total?: boolean } | boolean, + ): Promise { + let params: { total?: boolean }; + + if ( + typeof paramsOrFirst === 'undefined' || + (paramsOrFirst && + typeof paramsOrFirst === 'object' && + !Array.isArray(paramsOrFirst)) + ) { + params = (paramsOrFirst || {}) as { total?: boolean }; + } else { + params = { + total: paramsOrFirst as boolean, + }; + } + + const total = params.total; + const apiPath = '/locale/currencies'; const payload: Payload = {}; + if (typeof total !== 'undefined') { + payload['total'] = total; + } + const uri = new URL(this.client.config.endpoint + apiPath); return this.client.call( 'get', @@ -167,13 +373,47 @@ export class Locale extends Service { /** * List of all languages classified by ISO 639-1 including 2-letter code, name in English, and name in the respective language. * + * @param {boolean} params.total - When set to false, the total count returned will be 0 and will not be calculated. * @throws {AppwriteException} * @returns {Promise} */ - listLanguages(): Promise { + listLanguages(params?: { total?: boolean }): Promise; + /** + * List of all languages classified by ISO 639-1 including 2-letter code, name in English, and name in the respective language. + * + * @param {boolean} total - When set to false, the total count returned will be 0 and will not be calculated. + * @throws {AppwriteException} + * @returns {Promise} + * @deprecated Use the object parameter style method for a better developer experience. + */ + listLanguages(total?: boolean): Promise; + listLanguages( + paramsOrFirst?: { total?: boolean } | boolean, + ): Promise { + let params: { total?: boolean }; + + if ( + typeof paramsOrFirst === 'undefined' || + (paramsOrFirst && + typeof paramsOrFirst === 'object' && + !Array.isArray(paramsOrFirst)) + ) { + params = (paramsOrFirst || {}) as { total?: boolean }; + } else { + params = { + total: paramsOrFirst as boolean, + }; + } + + const total = params.total; + const apiPath = '/locale/languages'; const payload: Payload = {}; + if (typeof total !== 'undefined') { + payload['total'] = total; + } + const uri = new URL(this.client.config.endpoint + apiPath); return this.client.call( 'get', diff --git a/src/services/tables-db.ts b/src/services/tables-db.ts index 4e73fb6d..0dda4d23 100644 --- a/src/services/tables-db.ts +++ b/src/services/tables-db.ts @@ -12,40 +12,52 @@ export class TablesDB extends Service { * List transactions across all databases. * * @param {string[]} params.queries - Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). + * @param {boolean} params.total - When set to false, the total count returned will be 0 and will not be calculated. * @throws {AppwriteException} * @returns {Promise} */ listTransactions(params?: { queries?: string[]; + total?: boolean; }): Promise; /** * List transactions across all databases. * * @param {string[]} queries - Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). + * @param {boolean} total - When set to false, the total count returned will be 0 and will not be calculated. * @throws {AppwriteException} * @returns {Promise} * @deprecated Use the object parameter style method for a better developer experience. */ - listTransactions(queries?: string[]): Promise; listTransactions( - paramsOrFirst?: { queries?: string[] } | string[], + queries?: string[], + total?: boolean, + ): Promise; + listTransactions( + paramsOrFirst?: { queries?: string[]; total?: boolean } | string[], + ...rest: [boolean?] ): Promise { - let params: { queries?: string[] }; + let params: { queries?: string[]; total?: boolean }; if ( - typeof paramsOrFirst === 'undefined' || + (typeof paramsOrFirst === 'undefined' && rest.length === 0) || (paramsOrFirst && typeof paramsOrFirst === 'object' && !Array.isArray(paramsOrFirst)) ) { - params = (paramsOrFirst || {}) as { queries?: string[] }; + params = (paramsOrFirst || {}) as { + queries?: string[]; + total?: boolean; + }; } else { params = { queries: paramsOrFirst as string[], + total: rest[0] as boolean, }; } const queries = params.queries; + const total = params.total; const apiPath = '/tablesdb/transactions'; const payload: Payload = {}; @@ -54,6 +66,10 @@ export class TablesDB extends Service { payload['queries'] = queries; } + if (typeof total !== 'undefined') { + payload['total'] = total; + } + const uri = new URL(this.client.config.endpoint + apiPath); return this.client.call( 'get', diff --git a/src/services/teams.ts b/src/services/teams.ts index 4bc7e806..b1c364f2 100644 --- a/src/services/teams.ts +++ b/src/services/teams.ts @@ -965,6 +965,7 @@ export class Teams extends Service { * @param {string} params.phone - Phone number. Format this number with a leading '+' and a country code, e.g., +16175551212. * @param {string} params.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. * @param {string} params.name - Name of the new team member. Max length: 128 chars. + * @param {string} params.membershipId - Membership 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. * @throws {AppwriteException} * @returns {Promise} */ @@ -976,6 +977,7 @@ export class Teams extends Service { phone?: string; url?: string; name?: string; + membershipId?: string; }): Promise; /** * 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. @@ -994,6 +996,7 @@ export class Teams extends Service { * @param {string} phone - Phone number. Format this number with a leading '+' and a country code, e.g., +16175551212. * @param {string} 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. * @param {string} name - Name of the new team member. Max length: 128 chars. + * @param {string} membershipId - Membership 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. * @throws {AppwriteException} * @returns {Promise} * @deprecated Use the object parameter style method for a better developer experience. @@ -1006,6 +1009,7 @@ export class Teams extends Service { phone?: string, url?: string, name?: string, + membershipId?: string, ): Promise; createMembership( paramsOrFirst: @@ -1017,9 +1021,18 @@ export class Teams extends Service { phone?: string; url?: string; name?: string; + membershipId?: string; } | string, - ...rest: [string[]?, string?, string?, string?, string?, string?] + ...rest: [ + string[]?, + string?, + string?, + string?, + string?, + string?, + string?, + ] ): Promise { let params: { teamId: string; @@ -1029,6 +1042,7 @@ export class Teams extends Service { phone?: string; url?: string; name?: string; + membershipId?: string; }; if ( @@ -1044,6 +1058,7 @@ export class Teams extends Service { phone?: string; url?: string; name?: string; + membershipId?: string; }; } else { params = { @@ -1054,6 +1069,7 @@ export class Teams extends Service { phone: rest[3] as string, url: rest[4] as string, name: rest[5] as string, + membershipId: rest[6] as string, }; } @@ -1064,6 +1080,7 @@ export class Teams extends Service { const phone = params.phone; const url = params.url; const name = params.name; + const membershipId = params.membershipId; if (typeof teamId === 'undefined' || teamId === '') { throw new AppwriteException('Missing required parameter: "teamId"'); @@ -1103,6 +1120,10 @@ export class Teams extends Service { payload['name'] = name; } + if (typeof membershipId !== 'undefined') { + payload['membershipId'] = membershipId; + } + const uri = new URL(this.client.config.endpoint + apiPath); return this.client.call( 'post', diff --git a/src/services/vectors-db.ts b/src/services/vectors-db.ts index 02fc557a..50cd44a8 100644 --- a/src/services/vectors-db.ts +++ b/src/services/vectors-db.ts @@ -12,40 +12,52 @@ export class VectorsDB extends Service { * List transactions across all databases. * * @param {string[]} params.queries - Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). + * @param {boolean} params.total - When set to false, the total count returned will be 0 and will not be calculated. * @throws {AppwriteException} * @returns {Promise} */ listTransactions(params?: { queries?: string[]; + total?: boolean; }): Promise; /** * List transactions across all databases. * * @param {string[]} queries - Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). + * @param {boolean} total - When set to false, the total count returned will be 0 and will not be calculated. * @throws {AppwriteException} * @returns {Promise} * @deprecated Use the object parameter style method for a better developer experience. */ - listTransactions(queries?: string[]): Promise; listTransactions( - paramsOrFirst?: { queries?: string[] } | string[], + queries?: string[], + total?: boolean, + ): Promise; + listTransactions( + paramsOrFirst?: { queries?: string[]; total?: boolean } | string[], + ...rest: [boolean?] ): Promise { - let params: { queries?: string[] }; + let params: { queries?: string[]; total?: boolean }; if ( - typeof paramsOrFirst === 'undefined' || + (typeof paramsOrFirst === 'undefined' && rest.length === 0) || (paramsOrFirst && typeof paramsOrFirst === 'object' && !Array.isArray(paramsOrFirst)) ) { - params = (paramsOrFirst || {}) as { queries?: string[] }; + params = (paramsOrFirst || {}) as { + queries?: string[]; + total?: boolean; + }; } else { params = { queries: paramsOrFirst as string[], + total: rest[0] as boolean, }; } const queries = params.queries; + const total = params.total; const apiPath = '/vectorsdb/transactions'; const payload: Payload = {}; @@ -54,6 +66,10 @@ export class VectorsDB extends Service { payload['queries'] = queries; } + if (typeof total !== 'undefined') { + payload['total'] = total; + } + const uri = new URL(this.client.config.endpoint + apiPath); return this.client.call( 'get',