From b7514d10c1cbaaab25d1cf7e25b1404300c3aa66 Mon Sep 17 00:00:00 2001 From: Chirag Aggarwal Date: Mon, 12 Oct 2026 16:55:38 +0100 Subject: [PATCH 1/6] chore: update React Native SDK to 2.0.0 --- CHANGELOG.md | 56 +- README.md | 4 +- .../account/create-o-auth-2-session.md | 1 + .../examples/account/create-o-auth-2-token.md | 1 + docs/examples/account/create-passkey-token.md | 13 + docs/examples/account/create-passkey.md | 16 + docs/examples/account/delete-passkey.md | 15 + docs/examples/account/get-passkey.md | 15 + docs/examples/account/list-passkeys.md | 16 + docs/examples/account/update-passkey-token.md | 16 + .../account/update-passkey-verification.md | 16 + docs/examples/account/update-passkey.md | 16 + docs/examples/analytics/create-event.md | 27 + docs/examples/oauth2/authorize-post.md | 2 +- docs/examples/oauth2/authorize.md | 2 +- .../oauth2/create-device-authorization.md | 2 +- docs/examples/oauth2/create-par.md | 2 +- docs/examples/oauth2/create-token.md | 2 +- docs/examples/teams/create-membership.md | 1 + package-lock.json | 4 +- package.json | 2 +- src/client.ts | 48 +- src/index.ts | 1 + src/models.ts | 96 + src/services/account.ts | 2384 ++++++++++++++++- src/services/analytics.ts | 260 ++ src/services/apps.ts | 561 +++- src/services/avatars.ts | 2 +- src/services/databases.ts | 250 +- src/services/documents-db.ts | 279 +- src/services/functions.ts | 132 +- src/services/locale.ts | 204 +- src/services/messaging.ts | 23 +- src/services/oauth-2.ts | 302 ++- src/services/organization.ts | 100 +- src/services/presences.ts | 84 +- src/services/storage.ts | 99 +- src/services/tables-db.ts | 250 +- src/services/teams.ts | 365 ++- src/services/vectors-db.ts | 241 +- 40 files changed, 5597 insertions(+), 313 deletions(-) create mode 100644 docs/examples/account/create-passkey-token.md create mode 100644 docs/examples/account/create-passkey.md create mode 100644 docs/examples/account/delete-passkey.md create mode 100644 docs/examples/account/get-passkey.md create mode 100644 docs/examples/account/list-passkeys.md create mode 100644 docs/examples/account/update-passkey-token.md create mode 100644 docs/examples/account/update-passkey-verification.md create mode 100644 docs/examples/account/update-passkey.md create mode 100644 docs/examples/analytics/create-event.md create mode 100644 src/services/analytics.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index c6c7bcb3..d78aef15 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,49 +1,31 @@ # Change log -## 1.2.0-rc.4 - -* Fixed: `host()` resolves with the live connection state instead of always `null` -* Fixed: `onConnection(false)` fires when a retired or background connection closes -* Fixed: notification taps are recorded after launching the app, so tap-opened screens land on top -* Fixed: `host()` reports `false` when there was nothing to subscribe instead of a spurious open - -## 1.2.0-rc.3 - -* Added: `getInitialNotification()`, `onNotificationOpened()`, and the `PushNotificationOpened` type (topic + data) -* Added: live push connection open/close events surfaced via `onOpen`/`onClose` -* Fixed: notification taps delivered reliably once, via a `PushTaps` queue -* Fixed: foreground notifications de-duplicated per title -* Updated: `resume` leaves a live Push host's connection untouched - -## 1.2.0-rc.2 - -* Added: `Push.getInitialNotification()` returns the notification whose tap launched the app -* Added: `Push.onNotificationOpened(callback)` fires on each notification tap -* Added: `Push.backgroundStatus()` reports Android exact-alarm, battery, and foreground-service state -* Added: `Push.requestExactAlarms()` and `Push.requestIgnoreBatteryOptimizations()` helpers -* Added: `SubscribeOptions.notifyInForeground` to post notifications while the app is visible -* Added: `PushBackgroundStatus` and `PushNotificationOpened` exported types -* Fixed: reliable Android background wake-ups via a periodic watchdog and alternating jobs -* Fixed: `resume` keeps subscriptions only for the same signed-in user -* Fixed: notification images are size-capped to prevent out-of-memory crashes - -## 1.2.0-rc.1 +## 2.0.0 +* Breaking: `Teams.createMembership` takes `membershipId` after `roles`; positional callers must update +* Added: `Account.listPasskeys`, `createPasskey`, `getPasskey`, `updatePasskey` and `deletePasskey` +* Added: `Account.updatePasskeyVerification` to finish registering a passkey +* Added: `Account.createPasskeyToken` and `Account.updatePasskeyToken` for passkey sign-in +* Added: `Passkey`, `PasskeyList`, `PasskeyChallenge` and `TokenSecret` models +* Added: `Push` service for MQTT realtime push with Android background delivery +* Added: `Topic` builder, `Client.setPushEndpoint()` and `Client.setPushClientId()` * Added: background push notifications render the server `notification` title, body, and image -* Added: Android shows notification images (BigPictureStyle) and long bodies (BigTextStyle) -* Added: the SDK requests Android 13+ `POST_NOTIFICATIONS` itself on first background subscribe -* Added: notification `data` now carries `topic` and `payload` -* Fixed: a server-sent title dedupes to one notification per topic instead of one per subscription - -## 1.2.0-rc.0 - +* Added: `getInitialNotification()`, `onNotificationOpened()` and the `PushNotificationOpened` type +* Added: `onOpen`/`onClose` events for live push connections +* Added: `Push.backgroundStatus()`, `requestExactAlarms()` and `requestIgnoreBatteryOptimizations()` for Android +* Added: `SubscribeOptions.notifyInForeground` to post notifications while the app is visible +* Added: the SDK requests Android 13+ `POST_NOTIFICATIONS` on first background subscribe +* Added: `Analytics` service with `createEvent` * Added: `Apps` service to manage OAuth2 apps, keys, secrets, and installations * Added: `Oauth2` service for authorization, consent, device, PAR, and token flows -* Added: `Push` service for MQTT realtime push with Android background delivery -* Added: `Topic` builder and native TCP modules for push * Added: `Avatars.updatePhoto()` and `Avatars.deletePhoto()` methods * Added: `App`, `Oauth2*`, and `Account` models +* Added: `state` parameter to `Account.createOAuth2Session` and `Account.createOAuth2Token` +* Added: `duration` on `createEmailPasswordSession` and `current` on `deleteSessions` +* Added: `total` parameter to `Account.listSessions`, `Locale` list methods and `listTransactions` * Added: `Webflow` to the `OAuthProvider` enum +* Fixed: response models fill missing fields from spec defaults instead of throwing +* Updated: SDK now targets Appwrite 2.4 (`X-Appwrite-Response-Format: 2.4.0`) * Fixed: cookie session fallback is guarded to Expo web where `localStorage` exists ## 1.1.0 diff --git a/README.md b/README.md index 0ba50f82..ba02d900 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,12 @@ # Appwrite React Native SDK ![License](https://img.shields.io/github/license/appwrite/sdk-for-react-native.svg?style=flat-square) -![Version](https://img.shields.io/badge/api%20version-2.3.0-blue.svg?style=flat-square) +![Version](https://img.shields.io/badge/api%20version-2.4.0-blue.svg?style=flat-square) [![Build Status](https://img.shields.io/travis/com/appwrite/sdk-generator?style=flat-square)](https://travis-ci.com/appwrite/sdk-generator) [![Twitter Account](https://img.shields.io/twitter/follow/appwrite?color=00acee&label=twitter&style=flat-square)](https://twitter.com/appwrite) [![Discord](https://img.shields.io/discord/564160730845151244?label=discord&style=flat-square)](https://appwrite.io/discord) -**This SDK targets Appwrite server version 2.3.x as shipped on Appwrite Cloud.** Self-hosted releases can lag behind Cloud — if you run an older self-hosted build, use a matching older SDK from [previous releases](https://github.com/appwrite/sdk-for-react-native/releases) when APIs differ. +**This SDK targets Appwrite server version 2.4.x as shipped on Appwrite Cloud.** Self-hosted releases can lag behind Cloud — if you run an older self-hosted build, use a matching older SDK from [previous releases](https://github.com/appwrite/sdk-for-react-native/releases) when APIs differ. Appwrite is an open-source backend as a service server that abstracts and simplifies complex and repetitive development tasks behind a very simple to use REST API. Appwrite aims to help you develop your apps faster and in a more secure way. Use the React Native SDK to integrate your app with the Appwrite server to easily start interacting with all of Appwrite backend APIs and tools. For full API documentation and tutorials go to [https://appwrite.io/docs](https://appwrite.io/docs) 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/create-passkey-token.md b/docs/examples/account/create-passkey-token.md new file mode 100644 index 00000000..5695859f --- /dev/null +++ b/docs/examples/account/create-passkey-token.md @@ -0,0 +1,13 @@ +```javascript +import { Client, Account } from 'react-native-appwrite'; + +const client = new Client() + .setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint + .setProject(''); // Your project ID + +const account = new Account(client); + +const result = await account.createPasskeyToken(); + +console.log(result); +``` diff --git a/docs/examples/account/create-passkey.md b/docs/examples/account/create-passkey.md new file mode 100644 index 00000000..66968b14 --- /dev/null +++ b/docs/examples/account/create-passkey.md @@ -0,0 +1,16 @@ +```javascript +import { Client, Account } from 'react-native-appwrite'; + +const client = new Client() + .setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint + .setProject(''); // Your project ID + +const account = new Account(client); + +const result = await account.createPasskey({ + passkeyId: '', // optional + name: '', // optional +}); + +console.log(result); +``` diff --git a/docs/examples/account/delete-passkey.md b/docs/examples/account/delete-passkey.md new file mode 100644 index 00000000..61aec153 --- /dev/null +++ b/docs/examples/account/delete-passkey.md @@ -0,0 +1,15 @@ +```javascript +import { Client, Account } from 'react-native-appwrite'; + +const client = new Client() + .setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint + .setProject(''); // Your project ID + +const account = new Account(client); + +const result = await account.deletePasskey({ + passkeyId: '', +}); + +console.log(result); +``` diff --git a/docs/examples/account/get-passkey.md b/docs/examples/account/get-passkey.md new file mode 100644 index 00000000..04b7f8fb --- /dev/null +++ b/docs/examples/account/get-passkey.md @@ -0,0 +1,15 @@ +```javascript +import { Client, Account } from 'react-native-appwrite'; + +const client = new Client() + .setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint + .setProject(''); // Your project ID + +const account = new Account(client); + +const result = await account.getPasskey({ + passkeyId: '', +}); + +console.log(result); +``` diff --git a/docs/examples/account/list-passkeys.md b/docs/examples/account/list-passkeys.md new file mode 100644 index 00000000..f1f68985 --- /dev/null +++ b/docs/examples/account/list-passkeys.md @@ -0,0 +1,16 @@ +```javascript +import { Client, Account } from 'react-native-appwrite'; + +const client = new Client() + .setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint + .setProject(''); // Your project ID + +const account = new Account(client); + +const result = await account.listPasskeys({ + queries: [], // optional + total: false, // optional +}); + +console.log(result); +``` diff --git a/docs/examples/account/update-passkey-token.md b/docs/examples/account/update-passkey-token.md new file mode 100644 index 00000000..a8e22f7a --- /dev/null +++ b/docs/examples/account/update-passkey-token.md @@ -0,0 +1,16 @@ +```javascript +import { Client, Account } from 'react-native-appwrite'; + +const client = new Client() + .setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint + .setProject(''); // Your project ID + +const account = new Account(client); + +const result = await account.updatePasskeyToken({ + challengeId: '', + credential: {}, +}); + +console.log(result); +``` diff --git a/docs/examples/account/update-passkey-verification.md b/docs/examples/account/update-passkey-verification.md new file mode 100644 index 00000000..c46c0a63 --- /dev/null +++ b/docs/examples/account/update-passkey-verification.md @@ -0,0 +1,16 @@ +```javascript +import { Client, Account } from 'react-native-appwrite'; + +const client = new Client() + .setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint + .setProject(''); // Your project ID + +const account = new Account(client); + +const result = await account.updatePasskeyVerification({ + passkeyId: '', + credential: {}, +}); + +console.log(result); +``` diff --git a/docs/examples/account/update-passkey.md b/docs/examples/account/update-passkey.md new file mode 100644 index 00000000..2f925b98 --- /dev/null +++ b/docs/examples/account/update-passkey.md @@ -0,0 +1,16 @@ +```javascript +import { Client, Account } from 'react-native-appwrite'; + +const client = new Client() + .setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint + .setProject(''); // Your project ID + +const account = new Account(client); + +const result = await account.updatePasskey({ + passkeyId: '', + name: '', +}); + +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/oauth2/authorize-post.md b/docs/examples/oauth2/authorize-post.md index e27aa7e3..f7dd540c 100644 --- a/docs/examples/oauth2/authorize-post.md +++ b/docs/examples/oauth2/authorize-post.md @@ -19,7 +19,7 @@ const result = await oauth2.authorizePost({ prompt: '', // optional maxAge: 0, // optional authorizationDetails: '', // optional - resource: '', // optional + resource: [], // optional audience: '', // optional requestUri: '', // optional }); diff --git a/docs/examples/oauth2/authorize.md b/docs/examples/oauth2/authorize.md index 039dc744..256e9cb6 100644 --- a/docs/examples/oauth2/authorize.md +++ b/docs/examples/oauth2/authorize.md @@ -19,7 +19,7 @@ const result = await oauth2.authorize({ prompt: '', // optional maxAge: 0, // optional authorizationDetails: '', // optional - resource: '', // optional + resource: [], // optional audience: '', // optional requestUri: '', // optional }); diff --git a/docs/examples/oauth2/create-device-authorization.md b/docs/examples/oauth2/create-device-authorization.md index c136011b..1219db51 100644 --- a/docs/examples/oauth2/create-device-authorization.md +++ b/docs/examples/oauth2/create-device-authorization.md @@ -11,7 +11,7 @@ const result = await oauth2.createDeviceAuthorization({ clientId: '', // optional scope: '', // optional authorizationDetails: '', // optional - resource: '', // optional + resource: [], // optional audience: '', // optional }); diff --git a/docs/examples/oauth2/create-par.md b/docs/examples/oauth2/create-par.md index 5d9b5783..425e7a86 100644 --- a/docs/examples/oauth2/create-par.md +++ b/docs/examples/oauth2/create-par.md @@ -19,7 +19,7 @@ const result = await oauth2.createPAR({ prompt: '', // optional maxAge: 0, // optional authorizationDetails: '', // optional - resource: '', // optional + resource: [], // optional audience: '', // optional }); diff --git a/docs/examples/oauth2/create-token.md b/docs/examples/oauth2/create-token.md index 3be9ff4a..567bfb74 100644 --- a/docs/examples/oauth2/create-token.md +++ b/docs/examples/oauth2/create-token.md @@ -16,7 +16,7 @@ const result = await oauth2.createToken({ clientSecret: '', // optional codeVerifier: '', // optional redirectUri: 'https://example.com', // optional - resource: '', // optional + resource: [], // optional audience: '', // optional }); diff --git a/docs/examples/teams/create-membership.md b/docs/examples/teams/create-membership.md index 3c6ee849..e2d206e7 100644 --- a/docs/examples/teams/create-membership.md +++ b/docs/examples/teams/create-membership.md @@ -10,6 +10,7 @@ const teams = new Teams(client); const result = await teams.createMembership({ teamId: '', roles: ['editor'], + membershipId: '', // optional email: 'email@example.com', // optional userId: '', // optional phone: '+12065550100', // optional diff --git a/package-lock.json b/package-lock.json index 33230e5f..bbf4775e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "react-native-appwrite", - "version": "1.2.0-rc.4", + "version": "2.0.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "react-native-appwrite", - "version": "1.2.0-rc.4", + "version": "2.0.0", "license": "BSD-3-Clause", "dependencies": { "buffer": "6.0.3", diff --git a/package.json b/package.json index 12b4f76a..b36e9cfc 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-rc.4", + "version": "2.0.0", "license": "BSD-3-Clause", "main": "dist/cjs/sdk.js", "exports": { diff --git a/src/client.ts b/src/client.ts index 4bc8575c..2fa4bf31 100644 --- a/src/client.ts +++ b/src/client.ts @@ -45,6 +45,50 @@ export const JSONbig = { stringify: JSONbigSerializer.stringify, }; +type DefaultsShape = string | { items: DefaultsShape }; + +type DefaultsModel = { + defaults?: Record; + properties?: Record; +}; + +type Defaults = { + root: DefaultsShape; + models: Record; +}; + +export function applyDefaults(value: T, tree: Defaults): T { + return fillDefaults(value, tree.root, tree.models) as T; +} + +function fillDefaults( + value: unknown, + shape: DefaultsShape, + models: Record, +): unknown { + if (typeof shape !== 'string') { + if (!Array.isArray(value)) { + return value; + } + const items = shape.items; + return value.map((item) => fillDefaults(item, items, models)); + } + const model = models[shape]; + if (!model || typeof value !== 'object' || value === null) { + return value; + } + if (Array.isArray(value)) { + return value; + } + const result: Record = { ...model.defaults, ...value }; + for (const [key, child] of Object.entries(model.properties ?? {})) { + if (key in result) { + result[key] = fillDefaults(result[key], child, models); + } + } + return result; +} + type Payload = { [key: string]: any; }; @@ -218,8 +262,8 @@ class Client { 'x-sdk-name': 'React Native', 'x-sdk-platform': 'client', 'x-sdk-language': 'reactnative', - 'x-sdk-version': '1.2.0-rc.4', - 'X-Appwrite-Response-Format': '2.3.0', + 'x-sdk-version': '2.0.0', + 'X-Appwrite-Response-Format': '2.4.0', }; /** diff --git a/src/index.ts b/src/index.ts index 579ed73a..a5b728ec 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 { Apps } from './services/apps'; export { Avatars } from './services/avatars'; export { Databases } from './services/databases'; diff --git a/src/models.ts b/src/models.ts index 09b8b39c..f11c898e 100644 --- a/src/models.ts +++ b/src/models.ts @@ -1381,6 +1381,102 @@ export namespace Models { expire: string; }; + /** + * Token Secret + */ + export type TokenSecret = { + /** + * Token ID. + */ + $id: string; + /** + * Token creation date in ISO 8601 format. + */ + $createdAt: string; + /** + * User ID. + */ + userId: string; + /** + * Token secret key. Exchange it for a session with the create session endpoint. + */ + secret: string; + /** + * Token expiration date in ISO 8601 format. + */ + expire: string; + /** + * Security phrase of a token. Empty if security phrase was not requested when creating a token. It includes randomly generated phrase which is also sent in the external resource such as email. + */ + phrase: string; + }; + + /** + * Passkey + */ + export type Passkey = { + /** + * Passkey ID. + */ + $id: string; + /** + * Passkey creation date in ISO 8601 format. + */ + $createdAt: string; + /** + * Passkey update date in ISO 8601 format. + */ + $updatedAt: string; + /** + * Passkey name. + */ + name: string; + /** + * Most recent sign-in with this passkey in ISO 8601 format. Empty until the passkey is used to sign in. + */ + accessedAt: string; + }; + + /** + * Passkey Challenge + */ + export type PasskeyChallenge = { + /** + * Challenge ID. When signing in, pass it back with the credential to receive a token. + */ + $id: string; + /** + * Challenge creation date in ISO 8601 format. + */ + $createdAt: string; + /** + * ID of the passkey being registered. Empty for sign-in challenges. + */ + passkeyId: string; + /** + * Challenge expiration date in ISO 8601 format. + */ + expire: string; + /** + * WebAuthn options in JSON form. Pass them to `PublicKeyCredential.parseCreationOptionsFromJSON()` when registering, or `PublicKeyCredential.parseRequestOptionsFromJSON()` when signing in. + */ + publicKey: object; + }; + + /** + * Passkeys List + */ + export type PasskeyList = { + /** + * Total number of passkeys that matched your query. + */ + total: number; + /** + * List of passkeys. + */ + passkeys: Passkey[]; + }; + /** * MFA Recovery Codes */ diff --git a/src/services/account.ts b/src/services/account.ts index fb3d545b..60361c99 100644 --- a/src/services/account.ts +++ b/src/services/account.ts @@ -1,5 +1,5 @@ import { Service } from '../service'; -import { AppwriteException, Client } from '../client'; +import { AppwriteException, Client, applyDefaults } from '../client'; import type { Models } from '../models'; import type { Payload } from '../client'; @@ -25,7 +25,7 @@ export class Account extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -34,6 +34,48 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'user', + models: { + user: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + registration: '', + status: true, + labels: [], + passwordUpdate: '', + email: '', + phone: '', + emailVerification: false, + phoneVerification: false, + mfa: false, + accessedAt: '', + }, + properties: { + targets: { + items: 'target', + }, + }, + }, + target: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + userId: '', + providerType: '', + identifier: '', + expired: false, + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -143,7 +185,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -153,6 +195,48 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'user', + models: { + user: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + registration: '', + status: true, + labels: [], + passwordUpdate: '', + email: '', + phone: '', + emailVerification: false, + phoneVerification: false, + mfa: false, + accessedAt: '', + }, + properties: { + targets: { + items: 'target', + }, + }, + }, + target: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + userId: '', + providerType: '', + identifier: '', + expired: false, + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -218,7 +302,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -227,6 +311,37 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'oauth2ConsentList', + models: { + oauth2ConsentList: { + defaults: { + total: 0, + }, + properties: { + consents: { + items: 'oauth2Consent', + }, + }, + }, + oauth2Consent: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + userId: '', + appId: '', + cimdUrl: '', + scopes: [], + resources: [], + authorizationDetails: '[]', + expire: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -278,7 +393,7 @@ export class Account extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -287,6 +402,27 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'oauth2Consent', + models: { + oauth2Consent: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + userId: '', + appId: '', + cimdUrl: '', + scopes: [], + resources: [], + authorizationDetails: '[]', + expire: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -427,7 +563,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -436,6 +572,38 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'oauth2ConsentTokenList', + models: { + oauth2ConsentTokenList: { + defaults: { + total: 0, + }, + properties: { + tokens: { + items: 'oauth2ConsentToken', + }, + }, + }, + oauth2ConsentToken: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + consentId: '', + userId: '', + appId: '', + cimdUrl: '', + scopes: [], + resources: [], + authorizationDetails: '[]', + expire: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -506,7 +674,7 @@ export class Account extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -515,6 +683,28 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'oauth2ConsentToken', + models: { + oauth2ConsentToken: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + consentId: '', + userId: '', + appId: '', + cimdUrl: '', + scopes: [], + resources: [], + authorizationDetails: '[]', + expire: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -673,7 +863,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'patch', uri, { @@ -683,6 +873,48 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'user', + models: { + user: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + registration: '', + status: true, + labels: [], + passwordUpdate: '', + email: '', + phone: '', + emailVerification: false, + phoneVerification: false, + mfa: false, + accessedAt: '', + }, + properties: { + targets: { + items: 'target', + }, + }, + }, + target: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + userId: '', + providerType: '', + identifier: '', + expired: false, + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -748,7 +980,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -757,6 +989,38 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'identityList', + models: { + identityList: { + defaults: { + total: 0, + }, + properties: { + identities: { + items: 'identity', + }, + }, + }, + identity: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + userId: '', + provider: '', + providerUid: '', + providerEmail: '', + providerAccessToken: '', + providerAccessTokenExpiry: '', + providerRefreshToken: '', + providerIdToken: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -865,7 +1129,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -875,6 +1139,18 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'jwt', + models: { + jwt: { + defaults: { + jwt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -931,7 +1207,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'patch', uri, { @@ -941,6 +1217,48 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'user', + models: { + user: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + registration: '', + status: true, + labels: [], + passwordUpdate: '', + email: '', + phone: '', + emailVerification: false, + phoneVerification: false, + mfa: false, + accessedAt: '', + }, + properties: { + targets: { + items: 'target', + }, + }, + }, + target: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + userId: '', + providerType: '', + identifier: '', + expired: false, + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -994,7 +1312,7 @@ export class Account extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -1004,6 +1322,19 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'mfaType', + models: { + mfaType: { + defaults: { + secret: '', + uri: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1056,7 +1387,7 @@ export class Account extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -1066,6 +1397,19 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'mfaType', + models: { + mfaType: { + defaults: { + secret: '', + uri: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1143,7 +1487,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'put', uri, { @@ -1153,6 +1497,48 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'user', + models: { + user: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + registration: '', + status: true, + labels: [], + passwordUpdate: '', + email: '', + phone: '', + emailVerification: false, + phoneVerification: false, + mfa: false, + accessedAt: '', + }, + properties: { + targets: { + items: 'target', + }, + }, + }, + target: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + userId: '', + providerType: '', + identifier: '', + expired: false, + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1229,7 +1615,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'put', uri, { @@ -1239,6 +1625,48 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'user', + models: { + user: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + registration: '', + status: true, + labels: [], + passwordUpdate: '', + email: '', + phone: '', + emailVerification: false, + phoneVerification: false, + mfa: false, + accessedAt: '', + }, + properties: { + targets: { + items: 'target', + }, + }, + }, + target: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + userId: '', + providerType: '', + identifier: '', + expired: false, + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1416,7 +1844,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -1426,6 +1854,21 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'mfaChallenge', + models: { + mfaChallenge: { + defaults: { + $id: '', + $createdAt: '', + userId: '', + expire: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1481,7 +1924,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -1491,6 +1934,21 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'mfaChallenge', + models: { + mfaChallenge: { + defaults: { + $id: '', + $createdAt: '', + userId: '', + expire: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1566,7 +2024,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'put', uri, { @@ -1576,6 +2034,46 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'session', + models: { + session: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + userId: '', + expire: '', + provider: '', + providerUid: '', + providerAccessToken: '', + providerAccessTokenExpiry: '', + providerRefreshToken: '', + ip: '', + osCode: '', + osName: '', + osVersion: '', + clientType: '', + clientCode: '', + clientName: '', + clientVersion: '', + clientEngine: '', + clientEngineVersion: '', + deviceName: '', + deviceBrand: '', + deviceModel: '', + countryCode: '', + countryName: '', + current: false, + factors: [], + secret: '', + mfaUpdatedAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1650,7 +2148,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'put', uri, { @@ -1660,6 +2158,46 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'session', + models: { + session: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + userId: '', + expire: '', + provider: '', + providerUid: '', + providerAccessToken: '', + providerAccessTokenExpiry: '', + providerRefreshToken: '', + ip: '', + osCode: '', + osName: '', + osVersion: '', + clientType: '', + clientCode: '', + clientName: '', + clientVersion: '', + clientEngine: '', + clientEngineVersion: '', + deviceName: '', + deviceBrand: '', + deviceModel: '', + countryCode: '', + countryName: '', + current: false, + factors: [], + secret: '', + mfaUpdatedAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1674,7 +2212,7 @@ export class Account extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -1683,6 +2221,22 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'mfaFactors', + models: { + mfaFactors: { + defaults: { + totp: false, + phone: false, + email: false, + recoveryCode: false, + custom: false, + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1696,7 +2250,7 @@ export class Account extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -1705,6 +2259,22 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'mfaFactors', + models: { + mfaFactors: { + defaults: { + totp: false, + phone: false, + email: false, + recoveryCode: false, + custom: false, + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1719,7 +2289,7 @@ export class Account extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -1728,6 +2298,18 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'mfaRecoveryCodes', + models: { + mfaRecoveryCodes: { + defaults: { + recoveryCodes: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1741,7 +2323,7 @@ export class Account extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -1750,6 +2332,18 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'mfaRecoveryCodes', + models: { + mfaRecoveryCodes: { + defaults: { + recoveryCodes: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1764,7 +2358,7 @@ export class Account extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -1774,6 +2368,18 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'mfaRecoveryCodes', + models: { + mfaRecoveryCodes: { + defaults: { + recoveryCodes: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1787,7 +2393,7 @@ export class Account extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -1797,6 +2403,18 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'mfaRecoveryCodes', + models: { + mfaRecoveryCodes: { + defaults: { + recoveryCodes: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1811,7 +2429,7 @@ export class Account extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'patch', uri, { @@ -1821,6 +2439,18 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'mfaRecoveryCodes', + models: { + mfaRecoveryCodes: { + defaults: { + recoveryCodes: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1833,9 +2463,551 @@ export class Account extends Service { const apiPath = '/account/mfa/recovery-codes'; const apiPayload: Payload = {}; + const uri = new URL(this.client.config.endpoint + apiPath); + const request = this.client.call( + 'patch', + uri, + { + 'X-Appwrite-Project': this.client.config.project, + 'content-type': 'application/json', + accept: 'application/json', + }, + apiPayload, + ); + const defaults = { + root: 'mfaRecoveryCodes', + models: { + mfaRecoveryCodes: { + defaults: { + recoveryCodes: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); + } + + /** + * Update currently logged in user account name. + * + * @param {string} params.name - User name. Max length: 128 chars. + * @throws {AppwriteException} + * @returns {Promise} + */ + updateName< + Preferences extends Models.Preferences = Models.DefaultPreferences, + >(params: { name: string }): Promise>; + /** + * Update currently logged in user account name. + * + * @param {string} name - User name. Max length: 128 chars. + * @throws {AppwriteException} + * @returns {Promise>} + * @deprecated Use the object parameter style method for a better developer experience. + */ + updateName< + Preferences extends Models.Preferences = Models.DefaultPreferences, + >(name: string): Promise>; + updateName< + Preferences extends Models.Preferences = Models.DefaultPreferences, + >( + paramsOrFirst: { name: string } | string, + ): Promise> { + let params: { name: string }; + + if ( + paramsOrFirst && + typeof paramsOrFirst === 'object' && + !Array.isArray(paramsOrFirst) + ) { + params = (paramsOrFirst || {}) as { name: string }; + } else { + params = { + name: paramsOrFirst as string, + }; + } + + const name = params.name; + + if (typeof name === 'undefined') { + throw new AppwriteException('Missing required parameter: "name"'); + } + + const apiPath = '/account/name'; + const apiPayload: Payload = {}; + + if (typeof name !== 'undefined') { + apiPayload['name'] = name; + } + + const uri = new URL(this.client.config.endpoint + apiPath); + const request = this.client.call( + 'patch', + uri, + { + 'X-Appwrite-Project': this.client.config.project, + 'content-type': 'application/json', + accept: 'application/json', + }, + apiPayload, + ); + const defaults = { + root: 'user', + models: { + user: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + registration: '', + status: true, + labels: [], + passwordUpdate: '', + email: '', + phone: '', + emailVerification: false, + phoneVerification: false, + mfa: false, + accessedAt: '', + }, + properties: { + targets: { + items: 'target', + }, + }, + }, + target: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + userId: '', + providerType: '', + identifier: '', + expired: false, + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); + } + + /** + * Get the list of verified passkeys registered by the currently logged in user. + * + * @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). Maximum of 100 queries are allowed, each 4096 characters long. You may filter and order on the following attributes: $id, $createdAt, $updatedAt, name, accessedAt + * @param {boolean} params.total - When set to false, the total count returned will be 0 and will not be calculated. + * @throws {AppwriteException} + * @returns {Promise} + */ + listPasskeys(params?: { + queries?: string[]; + total?: boolean; + }): Promise; + /** + * Get the list of verified passkeys registered by the currently logged in user. + * + * @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). Maximum of 100 queries are allowed, each 4096 characters long. You may filter and order on the following attributes: $id, $createdAt, $updatedAt, name, accessedAt + * @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. + */ + listPasskeys( + queries?: string[], + total?: boolean, + ): Promise; + listPasskeys( + paramsOrFirst?: { queries?: string[]; total?: boolean } | string[], + ...rest: [boolean?] + ): Promise { + let params: { queries?: string[]; total?: boolean }; + + if ( + (typeof paramsOrFirst === 'undefined' && rest.length === 0) || + (paramsOrFirst && + typeof paramsOrFirst === 'object' && + !Array.isArray(paramsOrFirst)) + ) { + 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 = '/account/passkeys'; + const apiPayload: Payload = {}; + + if (typeof queries !== 'undefined') { + apiPayload['queries'] = queries; + } + + if (typeof total !== 'undefined') { + apiPayload['total'] = total; + } + + const uri = new URL(this.client.config.endpoint + apiPath); + const request = this.client.call( + 'get', + uri, + { + 'X-Appwrite-Project': this.client.config.project, + accept: 'application/json', + }, + apiPayload, + ); + const defaults = { + root: 'passkeyList', + models: { + passkeyList: { + defaults: { + total: 0, + }, + properties: { + passkeys: { + items: 'passkey', + }, + }, + }, + passkey: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + accessedAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); + } + + /** + * Start registering a passkey for the currently logged in user. The session must have signed in or completed an MFA challenge within the last 10 minutes. Pass the returned `publicKey` options to `navigator.credentials.create()`, then complete the registration with [Update passkey verification](/docs/references/cloud/client-web/account#updatePasskeyVerification). The passkey stays pending until verified, and the challenge expires after 5 minutes. + * + * @param {string} params.passkeyId - Passkey 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. + * @param {string} params.name - Passkey name, shown when listing passkeys. Max length: 128 chars. + * @throws {AppwriteException} + * @returns {Promise} + */ + createPasskey(params?: { + passkeyId?: string; + name?: string; + }): Promise; + /** + * Start registering a passkey for the currently logged in user. The session must have signed in or completed an MFA challenge within the last 10 minutes. Pass the returned `publicKey` options to `navigator.credentials.create()`, then complete the registration with [Update passkey verification](/docs/references/cloud/client-web/account#updatePasskeyVerification). The passkey stays pending until verified, and the challenge expires after 5 minutes. + * + * @param {string} passkeyId - Passkey 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. + * @param {string} name - Passkey name, shown when listing passkeys. Max length: 128 chars. + * @throws {AppwriteException} + * @returns {Promise} + * @deprecated Use the object parameter style method for a better developer experience. + */ + createPasskey( + passkeyId?: string, + name?: string, + ): Promise; + createPasskey( + paramsOrFirst?: { passkeyId?: string; name?: string } | string, + ...rest: [string?] + ): Promise { + let params: { passkeyId?: string; name?: string }; + + if ( + (typeof paramsOrFirst === 'undefined' && rest.length === 0) || + (paramsOrFirst && + typeof paramsOrFirst === 'object' && + !Array.isArray(paramsOrFirst)) + ) { + params = (paramsOrFirst || {}) as { + passkeyId?: string; + name?: string; + }; + } else { + params = { + passkeyId: paramsOrFirst as string, + name: rest[0] as string, + }; + } + + const passkeyId = params.passkeyId; + const name = params.name; + + const apiPath = '/account/passkeys'; + const apiPayload: Payload = {}; + + if (typeof passkeyId !== 'undefined') { + apiPayload['passkeyId'] = passkeyId; + } + + if (typeof name !== 'undefined') { + apiPayload['name'] = name; + } + + const uri = new URL(this.client.config.endpoint + apiPath); + const request = this.client.call( + 'post', + uri, + { + 'X-Appwrite-Project': this.client.config.project, + 'content-type': 'application/json', + accept: 'application/json', + }, + apiPayload, + ); + const defaults = { + root: 'passkeyChallenge', + models: { + passkeyChallenge: { + defaults: { + $id: '', + $createdAt: '', + passkeyId: '', + expire: '', + publicKey: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); + } + + /** + * Get a verified passkey of the currently logged in user by its unique ID. + * + * @param {string} params.passkeyId - Passkey ID. + * @throws {AppwriteException} + * @returns {Promise} + */ + getPasskey(params: { passkeyId: string }): Promise; + /** + * Get a verified passkey of the currently logged in user by its unique ID. + * + * @param {string} passkeyId - Passkey ID. + * @throws {AppwriteException} + * @returns {Promise} + * @deprecated Use the object parameter style method for a better developer experience. + */ + getPasskey(passkeyId: string): Promise; + getPasskey( + paramsOrFirst: { passkeyId: string } | string, + ): Promise { + let params: { passkeyId: string }; + + if ( + paramsOrFirst && + typeof paramsOrFirst === 'object' && + !Array.isArray(paramsOrFirst) + ) { + params = (paramsOrFirst || {}) as { passkeyId: string }; + } else { + params = { + passkeyId: paramsOrFirst as string, + }; + } + + const passkeyId = params.passkeyId; + + if (typeof passkeyId === 'undefined' || passkeyId === '') { + throw new AppwriteException( + 'Missing required parameter: "passkeyId"', + ); + } + + const apiPath = '/account/passkeys/{passkeyId}'.replace( + '{passkeyId}', + encodeURIComponent(String(passkeyId)), + ); + const apiPayload: Payload = {}; + + const uri = new URL(this.client.config.endpoint + apiPath); + const request = this.client.call( + 'get', + uri, + { + 'X-Appwrite-Project': this.client.config.project, + accept: 'application/json', + }, + apiPayload, + ); + const defaults = { + root: 'passkey', + models: { + passkey: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + accessedAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); + } + + /** + * Rename a passkey of the currently logged in user. + * + * @param {string} params.passkeyId - Passkey ID. + * @param {string} params.name - Passkey name. Max length: 128 chars. + * @throws {AppwriteException} + * @returns {Promise} + */ + updatePasskey(params: { + passkeyId: string; + name: string; + }): Promise; + /** + * Rename a passkey of the currently logged in user. + * + * @param {string} passkeyId - Passkey ID. + * @param {string} name - Passkey name. Max length: 128 chars. + * @throws {AppwriteException} + * @returns {Promise} + * @deprecated Use the object parameter style method for a better developer experience. + */ + updatePasskey(passkeyId: string, name: string): Promise; + updatePasskey( + paramsOrFirst: { passkeyId: string; name: string } | string, + ...rest: [string?] + ): Promise { + let params: { passkeyId: string; name: string }; + + if ( + paramsOrFirst && + typeof paramsOrFirst === 'object' && + !Array.isArray(paramsOrFirst) + ) { + params = (paramsOrFirst || {}) as { + passkeyId: string; + name: string; + }; + } else { + params = { + passkeyId: paramsOrFirst as string, + name: rest[0] as string, + }; + } + + const passkeyId = params.passkeyId; + const name = params.name; + + if (typeof passkeyId === 'undefined' || passkeyId === '') { + throw new AppwriteException( + 'Missing required parameter: "passkeyId"', + ); + } + + if (typeof name === 'undefined') { + throw new AppwriteException('Missing required parameter: "name"'); + } + + const apiPath = '/account/passkeys/{passkeyId}'.replace( + '{passkeyId}', + encodeURIComponent(String(passkeyId)), + ); + const apiPayload: Payload = {}; + + if (typeof name !== 'undefined') { + apiPayload['name'] = name; + } + + const uri = new URL(this.client.config.endpoint + apiPath); + const request = this.client.call( + 'patch', + uri, + { + 'X-Appwrite-Project': this.client.config.project, + 'content-type': 'application/json', + accept: 'application/json', + }, + apiPayload, + ); + const defaults = { + root: 'passkey', + models: { + passkey: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + accessedAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); + } + + /** + * Delete a passkey from the currently logged in user. The passkey can no longer be used to sign in, although it may remain stored on the user's device. The session must have signed in or completed an MFA challenge within the last 10 minutes. + * + * @param {string} params.passkeyId - Passkey ID. + * @throws {AppwriteException} + * @returns {Promise} + */ + deletePasskey(params: { passkeyId: string }): Promise<{}>; + /** + * Delete a passkey from the currently logged in user. The passkey can no longer be used to sign in, although it may remain stored on the user's device. The session must have signed in or completed an MFA challenge within the last 10 minutes. + * + * @param {string} passkeyId - Passkey ID. + * @throws {AppwriteException} + * @returns {Promise<{}>} + * @deprecated Use the object parameter style method for a better developer experience. + */ + deletePasskey(passkeyId: string): Promise<{}>; + deletePasskey(paramsOrFirst: { passkeyId: string } | string): Promise<{}> { + let params: { passkeyId: string }; + + if ( + paramsOrFirst && + typeof paramsOrFirst === 'object' && + !Array.isArray(paramsOrFirst) + ) { + params = (paramsOrFirst || {}) as { passkeyId: string }; + } else { + params = { + passkeyId: paramsOrFirst as string, + }; + } + + const passkeyId = params.passkeyId; + + if (typeof passkeyId === 'undefined' || passkeyId === '') { + throw new AppwriteException( + 'Missing required parameter: "passkeyId"', + ); + } + + const apiPath = '/account/passkeys/{passkeyId}'.replace( + '{passkeyId}', + encodeURIComponent(String(passkeyId)), + ); + const apiPayload: Payload = {}; + const uri = new URL(this.client.config.endpoint + apiPath); return this.client.call( - 'patch', + 'delete', uri, { 'X-Appwrite-Project': this.client.config.project, @@ -1847,61 +3019,80 @@ export class Account extends Service { } /** - * Update currently logged in user account name. + * Complete a passkey registration started with [Create passkey](/docs/references/cloud/client-web/account#createPasskey). Pass the JSON form of the credential returned by `navigator.credentials.create()`, for example `credential.toJSON()`. Each registration can be verified once; a failed attempt requires starting it again. * - * @param {string} params.name - User name. Max length: 128 chars. + * @param {string} params.passkeyId - Passkey ID. + * @param {object} params.credential - Registration credential returned by the authenticator, in the JSON form produced by `PublicKeyCredential.toJSON()`. * @throws {AppwriteException} * @returns {Promise} */ - updateName< - Preferences extends Models.Preferences = Models.DefaultPreferences, - >(params: { name: string }): Promise>; + updatePasskeyVerification(params: { + passkeyId: string; + credential: object; + }): Promise; /** - * Update currently logged in user account name. + * Complete a passkey registration started with [Create passkey](/docs/references/cloud/client-web/account#createPasskey). Pass the JSON form of the credential returned by `navigator.credentials.create()`, for example `credential.toJSON()`. Each registration can be verified once; a failed attempt requires starting it again. * - * @param {string} name - User name. Max length: 128 chars. + * @param {string} passkeyId - Passkey ID. + * @param {object} credential - Registration credential returned by the authenticator, in the JSON form produced by `PublicKeyCredential.toJSON()`. * @throws {AppwriteException} - * @returns {Promise>} + * @returns {Promise} * @deprecated Use the object parameter style method for a better developer experience. */ - updateName< - Preferences extends Models.Preferences = Models.DefaultPreferences, - >(name: string): Promise>; - updateName< - Preferences extends Models.Preferences = Models.DefaultPreferences, - >( - paramsOrFirst: { name: string } | string, - ): Promise> { - let params: { name: string }; + updatePasskeyVerification( + passkeyId: string, + credential: object, + ): Promise; + updatePasskeyVerification( + paramsOrFirst: { passkeyId: string; credential: object } | string, + ...rest: [object?] + ): Promise { + let params: { passkeyId: string; credential: object }; if ( paramsOrFirst && typeof paramsOrFirst === 'object' && !Array.isArray(paramsOrFirst) ) { - params = (paramsOrFirst || {}) as { name: string }; + params = (paramsOrFirst || {}) as { + passkeyId: string; + credential: object; + }; } else { params = { - name: paramsOrFirst as string, + passkeyId: paramsOrFirst as string, + credential: rest[0] as object, }; } - const name = params.name; + const passkeyId = params.passkeyId; + const credential = params.credential; - if (typeof name === 'undefined') { - throw new AppwriteException('Missing required parameter: "name"'); + if (typeof passkeyId === 'undefined' || passkeyId === '') { + throw new AppwriteException( + 'Missing required parameter: "passkeyId"', + ); } - const apiPath = '/account/name'; + if (typeof credential === 'undefined') { + throw new AppwriteException( + 'Missing required parameter: "credential"', + ); + } + + const apiPath = '/account/passkeys/{passkeyId}/verification'.replace( + '{passkeyId}', + encodeURIComponent(String(passkeyId)), + ); const apiPayload: Payload = {}; - if (typeof name !== 'undefined') { - apiPayload['name'] = name; + if (typeof credential !== 'undefined') { + apiPayload['credential'] = credential; } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( - 'patch', + const request = this.client.call( + 'put', uri, { 'X-Appwrite-Project': this.client.config.project, @@ -1910,6 +3101,22 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'passkey', + models: { + passkey: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + accessedAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1986,7 +3193,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'patch', uri, { @@ -1996,6 +3203,48 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'user', + models: { + user: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + registration: '', + status: true, + labels: [], + passwordUpdate: '', + email: '', + phone: '', + emailVerification: false, + phoneVerification: false, + mfa: false, + accessedAt: '', + }, + properties: { + targets: { + items: 'target', + }, + }, + }, + target: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + userId: '', + providerType: '', + identifier: '', + expired: false, + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -2073,7 +3322,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'patch', uri, { @@ -2083,6 +3332,48 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'user', + models: { + user: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + registration: '', + status: true, + labels: [], + passwordUpdate: '', + email: '', + phone: '', + emailVerification: false, + phoneVerification: false, + mfa: false, + accessedAt: '', + }, + properties: { + targets: { + items: 'target', + }, + }, + }, + target: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + userId: '', + providerType: '', + identifier: '', + expired: false, + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -2166,7 +3457,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'patch', uri, { @@ -2176,6 +3467,48 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'user', + models: { + user: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + registration: '', + status: true, + labels: [], + passwordUpdate: '', + email: '', + phone: '', + emailVerification: false, + phoneVerification: false, + mfa: false, + accessedAt: '', + }, + properties: { + targets: { + items: 'target', + }, + }, + }, + target: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + userId: '', + providerType: '', + identifier: '', + expired: false, + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -2242,7 +3575,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -2252,6 +3585,23 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'token', + models: { + token: { + defaults: { + $id: '', + $createdAt: '', + userId: '', + secret: '', + expire: '', + phrase: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -2346,7 +3696,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'put', uri, { @@ -2356,6 +3706,23 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'token', + models: { + token: { + defaults: { + $id: '', + $createdAt: '', + userId: '', + secret: '', + expire: '', + phrase: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -2427,7 +3794,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -2437,6 +3804,23 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'token', + models: { + token: { + defaults: { + $id: '', + $createdAt: '', + userId: '', + secret: '', + expire: '', + phrase: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -2529,7 +3913,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'put', uri, { @@ -2539,6 +3923,23 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'token', + models: { + token: { + defaults: { + $id: '', + $createdAt: '', + userId: '', + secret: '', + expire: '', + phrase: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -2586,7 +3987,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -2595,6 +3996,56 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'sessionList', + models: { + sessionList: { + defaults: { + total: 0, + }, + properties: { + sessions: { + items: 'session', + }, + }, + }, + session: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + userId: '', + expire: '', + provider: '', + providerUid: '', + providerAccessToken: '', + providerAccessTokenExpiry: '', + providerRefreshToken: '', + ip: '', + osCode: '', + osName: '', + osVersion: '', + clientType: '', + clientCode: '', + clientName: '', + clientVersion: '', + clientEngine: '', + clientEngineVersion: '', + deviceName: '', + deviceBrand: '', + deviceModel: '', + countryCode: '', + countryName: '', + current: false, + factors: [], + secret: '', + mfaUpdatedAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -2665,7 +4116,7 @@ export class Account extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -2675,6 +4126,46 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'session', + models: { + session: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + userId: '', + expire: '', + provider: '', + providerUid: '', + providerAccessToken: '', + providerAccessTokenExpiry: '', + providerRefreshToken: '', + ip: '', + osCode: '', + osName: '', + osVersion: '', + clientType: '', + clientCode: '', + clientName: '', + clientVersion: '', + clientEngine: '', + clientEngineVersion: '', + deviceName: '', + deviceBrand: '', + deviceModel: '', + countryCode: '', + countryName: '', + current: false, + factors: [], + secret: '', + mfaUpdatedAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -2765,7 +4256,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -2775,6 +4266,46 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'session', + models: { + session: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + userId: '', + expire: '', + provider: '', + providerUid: '', + providerAccessToken: '', + providerAccessTokenExpiry: '', + providerRefreshToken: '', + ip: '', + osCode: '', + osName: '', + osVersion: '', + clientType: '', + clientCode: '', + clientName: '', + clientVersion: '', + clientEngine: '', + clientEngineVersion: '', + deviceName: '', + deviceBrand: '', + deviceModel: '', + countryCode: '', + countryName: '', + current: false, + factors: [], + secret: '', + mfaUpdatedAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -2939,7 +4470,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -2949,6 +4480,46 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'session', + models: { + session: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + userId: '', + expire: '', + provider: '', + providerUid: '', + providerAccessToken: '', + providerAccessTokenExpiry: '', + providerRefreshToken: '', + ip: '', + osCode: '', + osName: '', + osVersion: '', + clientType: '', + clientCode: '', + clientName: '', + clientVersion: '', + clientEngine: '', + clientEngineVersion: '', + deviceName: '', + deviceBrand: '', + deviceModel: '', + countryCode: '', + countryName: '', + current: false, + factors: [], + secret: '', + mfaUpdatedAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -3022,7 +4593,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'put', uri, { @@ -3032,6 +4603,46 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'session', + models: { + session: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + userId: '', + expire: '', + provider: '', + providerUid: '', + providerAccessToken: '', + providerAccessTokenExpiry: '', + providerRefreshToken: '', + ip: '', + osCode: '', + osName: '', + osVersion: '', + clientType: '', + clientCode: '', + clientName: '', + clientVersion: '', + clientEngine: '', + clientEngineVersion: '', + deviceName: '', + deviceBrand: '', + deviceModel: '', + countryCode: '', + countryName: '', + current: false, + factors: [], + secret: '', + mfaUpdatedAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -3046,6 +4657,7 @@ export class Account extends Service { * @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} */ @@ -3054,6 +4666,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. @@ -3067,6 +4680,7 @@ export class Account extends Service { * @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. @@ -3076,6 +4690,7 @@ export class Account extends Service { success?: string, failure?: string, scopes?: string[], + state?: string, ): void | URL; createOAuth2Session( paramsOrFirst: @@ -3084,15 +4699,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 ( @@ -3102,13 +4719,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 = { @@ -3116,6 +4735,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, }; } @@ -3123,6 +4743,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( @@ -3148,6 +4769,10 @@ export class Account extends Service { apiPayload['scopes'] = scopes; } + if (typeof state !== 'undefined') { + apiPayload['state'] = state; + } + const uri = new URL(this.client.config.endpoint + apiPath); apiPayload['project'] = this.client.config.project; @@ -3227,7 +4852,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'put', uri, { @@ -3237,6 +4862,46 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'session', + models: { + session: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + userId: '', + expire: '', + provider: '', + providerUid: '', + providerAccessToken: '', + providerAccessTokenExpiry: '', + providerRefreshToken: '', + ip: '', + osCode: '', + osName: '', + osVersion: '', + clientType: '', + clientCode: '', + clientName: '', + clientVersion: '', + clientEngine: '', + clientEngineVersion: '', + deviceName: '', + deviceBrand: '', + deviceModel: '', + countryCode: '', + countryName: '', + current: false, + factors: [], + secret: '', + mfaUpdatedAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -3306,7 +4971,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -3316,6 +4981,46 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'session', + models: { + session: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + userId: '', + expire: '', + provider: '', + providerUid: '', + providerAccessToken: '', + providerAccessTokenExpiry: '', + providerRefreshToken: '', + ip: '', + osCode: '', + osName: '', + osVersion: '', + clientType: '', + clientCode: '', + clientName: '', + clientVersion: '', + clientEngine: '', + clientEngineVersion: '', + deviceName: '', + deviceBrand: '', + deviceModel: '', + countryCode: '', + countryName: '', + current: false, + factors: [], + secret: '', + mfaUpdatedAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -3367,7 +5072,7 @@ export class Account extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -3376,6 +5081,46 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'session', + models: { + session: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + userId: '', + expire: '', + provider: '', + providerUid: '', + providerAccessToken: '', + providerAccessTokenExpiry: '', + providerRefreshToken: '', + ip: '', + osCode: '', + osName: '', + osVersion: '', + clientType: '', + clientCode: '', + clientName: '', + clientVersion: '', + clientEngine: '', + clientEngineVersion: '', + deviceName: '', + deviceBrand: '', + deviceModel: '', + countryCode: '', + countryName: '', + current: false, + factors: [], + secret: '', + mfaUpdatedAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -3427,7 +5172,7 @@ export class Account extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'patch', uri, { @@ -3437,6 +5182,46 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'session', + models: { + session: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + userId: '', + expire: '', + provider: '', + providerUid: '', + providerAccessToken: '', + providerAccessTokenExpiry: '', + providerRefreshToken: '', + ip: '', + osCode: '', + osName: '', + osVersion: '', + clientType: '', + clientCode: '', + clientName: '', + clientVersion: '', + clientEngine: '', + clientEngineVersion: '', + deviceName: '', + deviceBrand: '', + deviceModel: '', + countryCode: '', + countryName: '', + current: false, + factors: [], + secret: '', + mfaUpdatedAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -3511,7 +5296,7 @@ export class Account extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'patch', uri, { @@ -3521,6 +5306,48 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'user', + models: { + user: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + registration: '', + status: true, + labels: [], + passwordUpdate: '', + email: '', + phone: '', + emailVerification: false, + phoneVerification: false, + mfa: false, + accessedAt: '', + }, + properties: { + targets: { + items: 'target', + }, + }, + }, + target: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + userId: '', + providerType: '', + identifier: '', + expired: false, + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -3614,7 +5441,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -3624,6 +5451,25 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'target', + models: { + target: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + userId: '', + providerType: '', + identifier: '', + expired: false, + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -3699,7 +5545,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'put', uri, { @@ -3709,6 +5555,25 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'target', + models: { + target: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + userId: '', + providerType: '', + identifier: '', + expired: false, + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -3860,7 +5725,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -3870,6 +5735,23 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'token', + models: { + token: { + defaults: { + $id: '', + $createdAt: '', + userId: '', + secret: '', + expire: '', + phrase: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -3977,7 +5859,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -3987,6 +5869,23 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'token', + models: { + token: { + defaults: { + $id: '', + $createdAt: '', + userId: '', + secret: '', + expire: '', + phrase: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -4002,6 +5901,7 @@ export class Account extends Service { * @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} */ @@ -4010,6 +5910,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. @@ -4024,6 +5925,7 @@ export class Account extends Service { * @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. @@ -4033,6 +5935,7 @@ export class Account extends Service { success?: string, failure?: string, scopes?: string[], + state?: string, ): void | URL; createOAuth2Token( paramsOrFirst: @@ -4041,15 +5944,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 ( @@ -4059,13 +5964,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 = { @@ -4073,6 +5980,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, }; } @@ -4080,6 +5988,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( @@ -4105,6 +6014,10 @@ export class Account extends Service { apiPayload['scopes'] = scopes; } + if (typeof state !== 'undefined') { + apiPayload['state'] = state; + } + const uri = new URL(this.client.config.endpoint + apiPath); apiPayload['project'] = this.client.config.project; @@ -4116,6 +6029,148 @@ export class Account extends Service { return uri; } + /** + * Start signing in with a passkey. No email or user ID is needed: pass the returned `publicKey` options to `navigator.credentials.get()` and the user picks one of their passkeys. Then call [Update passkey token](/docs/references/cloud/client-web/account#updatePasskeyToken) with the credential to receive a token, and exchange it with [Create session](/docs/references/cloud/client-web/account#createSession). The challenge expires after 5 minutes. + * + * @throws {AppwriteException} + * @returns {Promise} + */ + createPasskeyToken(): Promise { + const apiPath = '/account/tokens/passkey'; + const apiPayload: Payload = {}; + + const uri = new URL(this.client.config.endpoint + apiPath); + const request = this.client.call( + 'post', + uri, + { + 'X-Appwrite-Project': this.client.config.project, + 'content-type': 'application/json', + accept: 'application/json', + }, + apiPayload, + ); + const defaults = { + root: 'passkeyChallenge', + models: { + passkeyChallenge: { + defaults: { + $id: '', + $createdAt: '', + passkeyId: '', + expire: '', + publicKey: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); + } + + /** + * Complete a passkey sign-in started with [Create passkey token](/docs/references/cloud/client-web/account#createPasskeyToken). Pass the challenge ID and the JSON form of the credential returned by `navigator.credentials.get()`, for example `credential.toJSON()`. The returned token includes its secret and expires after 1 minute: exchange it for a session with [Create session](/docs/references/cloud/client-web/account#createSession). Passkeys require user verification, so the session also satisfies MFA. Each challenge can only be used once. + * + * @param {string} params.challengeId - Challenge ID returned by createPasskeyToken. + * @param {object} params.credential - Authentication credential returned by the authenticator, in the JSON form produced by `PublicKeyCredential.toJSON()`. + * @throws {AppwriteException} + * @returns {Promise} + */ + updatePasskeyToken(params: { + challengeId: string; + credential: object; + }): Promise; + /** + * Complete a passkey sign-in started with [Create passkey token](/docs/references/cloud/client-web/account#createPasskeyToken). Pass the challenge ID and the JSON form of the credential returned by `navigator.credentials.get()`, for example `credential.toJSON()`. The returned token includes its secret and expires after 1 minute: exchange it for a session with [Create session](/docs/references/cloud/client-web/account#createSession). Passkeys require user verification, so the session also satisfies MFA. Each challenge can only be used once. + * + * @param {string} challengeId - Challenge ID returned by createPasskeyToken. + * @param {object} credential - Authentication credential returned by the authenticator, in the JSON form produced by `PublicKeyCredential.toJSON()`. + * @throws {AppwriteException} + * @returns {Promise} + * @deprecated Use the object parameter style method for a better developer experience. + */ + updatePasskeyToken( + challengeId: string, + credential: object, + ): Promise; + updatePasskeyToken( + paramsOrFirst: { challengeId: string; credential: object } | string, + ...rest: [object?] + ): Promise { + let params: { challengeId: string; credential: object }; + + if ( + paramsOrFirst && + typeof paramsOrFirst === 'object' && + !Array.isArray(paramsOrFirst) + ) { + params = (paramsOrFirst || {}) as { + challengeId: string; + credential: object; + }; + } else { + params = { + challengeId: paramsOrFirst as string, + credential: rest[0] as object, + }; + } + + const challengeId = params.challengeId; + const credential = params.credential; + + if (typeof challengeId === 'undefined') { + throw new AppwriteException( + 'Missing required parameter: "challengeId"', + ); + } + + if (typeof credential === 'undefined') { + throw new AppwriteException( + 'Missing required parameter: "credential"', + ); + } + + const apiPath = '/account/tokens/passkey'; + const apiPayload: Payload = {}; + + if (typeof challengeId !== 'undefined') { + apiPayload['challengeId'] = challengeId; + } + + if (typeof credential !== 'undefined') { + apiPayload['credential'] = credential; + } + + const uri = new URL(this.client.config.endpoint + apiPath); + const request = this.client.call( + 'put', + uri, + { + 'X-Appwrite-Project': this.client.config.project, + 'content-type': 'application/json', + accept: 'application/json', + }, + apiPayload, + ); + const defaults = { + root: 'tokenSecret', + models: { + tokenSecret: { + defaults: { + $id: '', + $createdAt: '', + userId: '', + secret: '', + expire: '', + phrase: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); + } + /** * Sends the user an SMS with a secret key for creating a session. If the provided user ID has not be registered, a new user will be created. Use the returned user ID and secret and submit a request to the [POST /v1/account/sessions/token](https://appwrite.io/docs/references/cloud/client-web/account#createSession) endpoint to complete the login process. The secret sent to the user's phone is valid for 15 minutes. * @@ -4184,7 +6239,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -4194,6 +6249,23 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'token', + models: { + token: { + defaults: { + $id: '', + $createdAt: '', + userId: '', + secret: '', + expire: '', + phrase: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -4250,7 +6322,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -4260,6 +6332,23 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'token', + models: { + token: { + defaults: { + $id: '', + $createdAt: '', + userId: '', + secret: '', + expire: '', + phrase: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -4317,7 +6406,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -4327,6 +6416,23 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'token', + models: { + token: { + defaults: { + $id: '', + $createdAt: '', + userId: '', + secret: '', + expire: '', + phrase: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -4399,7 +6505,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'put', uri, { @@ -4409,6 +6515,23 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'token', + models: { + token: { + defaults: { + $id: '', + $createdAt: '', + userId: '', + secret: '', + expire: '', + phrase: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -4479,7 +6602,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'put', uri, { @@ -4489,6 +6612,23 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'token', + models: { + token: { + defaults: { + $id: '', + $createdAt: '', + userId: '', + secret: '', + expire: '', + phrase: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -4544,7 +6684,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -4554,6 +6694,23 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'token', + models: { + token: { + defaults: { + $id: '', + $createdAt: '', + userId: '', + secret: '', + expire: '', + phrase: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -4628,7 +6785,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'put', uri, { @@ -4638,6 +6795,23 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'token', + models: { + token: { + defaults: { + $id: '', + $createdAt: '', + userId: '', + secret: '', + expire: '', + phrase: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -4651,7 +6825,7 @@ export class Account extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -4661,6 +6835,23 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'token', + models: { + token: { + defaults: { + $id: '', + $createdAt: '', + userId: '', + secret: '', + expire: '', + phrase: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -4733,7 +6924,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'put', uri, { @@ -4743,5 +6934,22 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'token', + models: { + token: { + defaults: { + $id: '', + $createdAt: '', + userId: '', + secret: '', + expire: '', + phrase: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } } 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/apps.ts b/src/services/apps.ts index 02554ba4..7bc1cb9e 100644 --- a/src/services/apps.ts +++ b/src/services/apps.ts @@ -1,5 +1,5 @@ import { Service } from '../service'; -import { AppwriteException, Client } from '../client'; +import { AppwriteException, Client, applyDefaults } from '../client'; import type { Models } from '../models'; import type { Payload } from '../client'; @@ -68,7 +68,7 @@ export class Apps extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -77,6 +77,69 @@ export class Apps extends Service { }, apiPayload, ); + const defaults = { + root: 'appsList', + models: { + appsList: { + defaults: { + total: 0, + }, + properties: { + apps: { + items: 'app', + }, + }, + }, + app: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + description: '', + clientUri: '', + logoUri: '', + privacyPolicyUrl: '', + termsUrl: '', + contacts: [], + tagline: '', + tags: [], + labels: [], + images: [], + supportUrl: '', + dataDeletionUrl: '', + redirectUris: [], + postLogoutRedirectUris: [], + enabled: true, + type: 'confidential', + deviceFlow: false, + teamId: '', + userId: '', + installationScopes: [], + installationRedirectUrl: '', + }, + properties: { + secrets: { + items: 'appSecret', + }, + }, + }, + appSecret: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + appId: '', + secret: '', + hint: '', + createdById: '', + createdByName: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -403,7 +466,7 @@ export class Apps extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -413,6 +476,59 @@ export class Apps extends Service { }, apiPayload, ); + const defaults = { + root: 'app', + models: { + app: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + description: '', + clientUri: '', + logoUri: '', + privacyPolicyUrl: '', + termsUrl: '', + contacts: [], + tagline: '', + tags: [], + labels: [], + images: [], + supportUrl: '', + dataDeletionUrl: '', + redirectUris: [], + postLogoutRedirectUris: [], + enabled: true, + type: 'confidential', + deviceFlow: false, + teamId: '', + userId: '', + installationScopes: [], + installationRedirectUrl: '', + }, + properties: { + secrets: { + items: 'appSecret', + }, + }, + }, + appSecret: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + appId: '', + secret: '', + hint: '', + createdById: '', + createdByName: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -426,7 +542,7 @@ export class Apps extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -435,6 +551,32 @@ export class Apps extends Service { }, apiPayload, ); + const defaults = { + root: 'appScopeList', + models: { + appScopeList: { + defaults: { + total: 0, + }, + properties: { + scopes: { + items: 'appScope', + }, + }, + }, + appScope: { + defaults: { + value: '', + description: '', + type: '', + category: '', + deprecated: false, + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -448,7 +590,7 @@ export class Apps extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -457,6 +599,32 @@ export class Apps extends Service { }, apiPayload, ); + const defaults = { + root: 'appScopeList', + models: { + appScopeList: { + defaults: { + total: 0, + }, + properties: { + scopes: { + items: 'appScope', + }, + }, + }, + appScope: { + defaults: { + value: '', + description: '', + type: '', + category: '', + deprecated: false, + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -504,7 +672,7 @@ export class Apps extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -513,6 +681,59 @@ export class Apps extends Service { }, apiPayload, ); + const defaults = { + root: 'app', + models: { + app: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + description: '', + clientUri: '', + logoUri: '', + privacyPolicyUrl: '', + termsUrl: '', + contacts: [], + tagline: '', + tags: [], + labels: [], + images: [], + supportUrl: '', + dataDeletionUrl: '', + redirectUris: [], + postLogoutRedirectUris: [], + enabled: true, + type: 'confidential', + deviceFlow: false, + teamId: '', + userId: '', + installationScopes: [], + installationRedirectUrl: '', + }, + properties: { + secrets: { + items: 'appSecret', + }, + }, + }, + appSecret: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + appId: '', + secret: '', + hint: '', + createdById: '', + createdByName: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -846,7 +1067,7 @@ export class Apps extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'put', uri, { @@ -856,6 +1077,59 @@ export class Apps extends Service { }, apiPayload, ); + const defaults = { + root: 'app', + models: { + app: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + description: '', + clientUri: '', + logoUri: '', + privacyPolicyUrl: '', + termsUrl: '', + contacts: [], + tagline: '', + tags: [], + labels: [], + images: [], + supportUrl: '', + dataDeletionUrl: '', + redirectUris: [], + postLogoutRedirectUris: [], + enabled: true, + type: 'confidential', + deviceFlow: false, + teamId: '', + userId: '', + installationScopes: [], + installationRedirectUrl: '', + }, + properties: { + secrets: { + items: 'appSecret', + }, + }, + }, + appSecret: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + appId: '', + secret: '', + hint: '', + createdById: '', + createdByName: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -992,7 +1266,7 @@ export class Apps extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -1001,6 +1275,36 @@ export class Apps extends Service { }, apiPayload, ); + const defaults = { + root: 'appInstallationList', + models: { + appInstallationList: { + defaults: { + total: 0, + }, + properties: { + installations: { + items: 'appInstallation', + }, + }, + }, + appInstallation: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + appId: '', + teamId: '', + scopes: [], + authorizationDetails: [], + createdById: '', + createdByName: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1072,7 +1376,7 @@ export class Apps extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -1081,6 +1385,26 @@ export class Apps extends Service { }, apiPayload, ); + const defaults = { + root: 'appInstallation', + models: { + appInstallation: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + appId: '', + teamId: '', + scopes: [], + authorizationDetails: [], + createdById: '', + createdByName: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1230,7 +1554,7 @@ export class Apps extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -1240,6 +1564,22 @@ export class Apps extends Service { }, apiPayload, ); + const defaults = { + root: 'oauth2Token', + models: { + oauth2Token: { + defaults: { + access_token: '', + token_type: 'Bearer', + expires_in: 0, + refresh_token: '', + scope: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1319,7 +1659,7 @@ export class Apps extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -1328,6 +1668,35 @@ export class Apps extends Service { }, apiPayload, ); + const defaults = { + root: 'appKeyList', + models: { + appKeyList: { + defaults: { + total: 0, + }, + properties: { + keys: { + items: 'appKey', + }, + }, + }, + appKey: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + appId: '', + secret: '', + hint: '', + createdById: '', + createdByName: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1377,7 +1746,7 @@ export class Apps extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -1387,6 +1756,25 @@ export class Apps extends Service { }, apiPayload, ); + const defaults = { + root: 'appKey', + models: { + appKey: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + appId: '', + secret: '', + hint: '', + createdById: '', + createdByName: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1444,7 +1832,7 @@ export class Apps extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -1453,6 +1841,25 @@ export class Apps extends Service { }, apiPayload, ); + const defaults = { + root: 'appKey', + models: { + appKey: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + appId: '', + secret: '', + hint: '', + createdById: '', + createdByName: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1599,7 +2006,7 @@ export class Apps extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -1608,6 +2015,35 @@ export class Apps extends Service { }, apiPayload, ); + const defaults = { + root: 'appSecretList', + models: { + appSecretList: { + defaults: { + total: 0, + }, + properties: { + secrets: { + items: 'appSecret', + }, + }, + }, + appSecret: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + appId: '', + secret: '', + hint: '', + createdById: '', + createdByName: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1657,7 +2093,7 @@ export class Apps extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -1667,6 +2103,25 @@ export class Apps extends Service { }, apiPayload, ); + const defaults = { + root: 'appSecretPlaintext', + models: { + appSecretPlaintext: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + appId: '', + secret: '', + hint: '', + createdById: '', + createdByName: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1732,7 +2187,7 @@ export class Apps extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -1741,6 +2196,25 @@ export class Apps extends Service { }, apiPayload, ); + const defaults = { + root: 'appSecret', + models: { + appSecret: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + appId: '', + secret: '', + hint: '', + createdById: '', + createdByName: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1875,7 +2349,7 @@ export class Apps extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'patch', uri, { @@ -1885,6 +2359,59 @@ export class Apps extends Service { }, apiPayload, ); + const defaults = { + root: 'app', + models: { + app: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + description: '', + clientUri: '', + logoUri: '', + privacyPolicyUrl: '', + termsUrl: '', + contacts: [], + tagline: '', + tags: [], + labels: [], + images: [], + supportUrl: '', + dataDeletionUrl: '', + redirectUris: [], + postLogoutRedirectUris: [], + enabled: true, + type: 'confidential', + deviceFlow: false, + teamId: '', + userId: '', + installationScopes: [], + installationRedirectUrl: '', + }, + properties: { + secrets: { + items: 'appSecret', + }, + }, + }, + appSecret: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + appId: '', + secret: '', + hint: '', + createdById: '', + createdByName: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** diff --git a/src/services/avatars.ts b/src/services/avatars.ts index e634ce6d..062ed1b6 100644 --- a/src/services/avatars.ts +++ b/src/services/avatars.ts @@ -1,5 +1,5 @@ import { Service } from '../service'; -import { AppwriteException, Client } from '../client'; +import { AppwriteException, Client, applyDefaults } from '../client'; import type { Models } from '../models'; import type { UploadProgress, Payload } from '../client'; import * as FileSystem from 'expo-file-system'; diff --git a/src/services/databases.ts b/src/services/databases.ts index 94d2ad16..faef7447 100644 --- a/src/services/databases.ts +++ b/src/services/databases.ts @@ -1,5 +1,5 @@ import { Service } from '../service'; -import { AppwriteException, Client } from '../client'; +import { AppwriteException, Client, applyDefaults } from '../client'; import type { Models } from '../models'; import type { Payload } from '../client'; @@ -72,7 +72,7 @@ export class Databases extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -81,6 +81,33 @@ export class Databases extends Service { }, apiPayload, ); + const defaults = { + root: 'transactionList', + models: { + transactionList: { + defaults: { + total: 0, + }, + properties: { + transactions: { + items: 'transaction', + }, + }, + }, + transaction: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + status: 'pending', + operations: 0, + expiresAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -129,7 +156,7 @@ export class Databases extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -139,6 +166,23 @@ export class Databases extends Service { }, apiPayload, ); + const defaults = { + root: 'transaction', + models: { + transaction: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + status: 'pending', + operations: 0, + expiresAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -193,7 +237,7 @@ export class Databases extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -202,6 +246,23 @@ export class Databases extends Service { }, apiPayload, ); + const defaults = { + root: 'transaction', + models: { + transaction: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + status: 'pending', + operations: 0, + expiresAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -289,7 +350,7 @@ export class Databases extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'patch', uri, { @@ -299,6 +360,23 @@ export class Databases extends Service { }, apiPayload, ); + const defaults = { + root: 'transaction', + models: { + transaction: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + status: 'pending', + operations: 0, + expiresAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -433,7 +511,7 @@ export class Databases extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -443,6 +521,23 @@ export class Databases extends Service { }, apiPayload, ); + const defaults = { + root: 'transaction', + models: { + transaction: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + status: 'pending', + operations: 0, + expiresAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -580,7 +675,7 @@ export class Databases extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -589,6 +684,33 @@ export class Databases extends Service { }, apiPayload, ); + const defaults = { + root: 'documentList', + models: { + documentList: { + defaults: { + total: 0, + }, + properties: { + documents: { + items: 'document', + }, + }, + }, + document: { + defaults: { + $id: '', + $sequence: '', + $collectionId: '', + $databaseId: '', + $createdAt: '', + $updatedAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -761,7 +883,7 @@ export class Databases extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -771,6 +893,23 @@ export class Databases extends Service { }, apiPayload, ); + const defaults = { + root: 'document', + models: { + document: { + defaults: { + $id: '', + $sequence: '', + $collectionId: '', + $databaseId: '', + $createdAt: '', + $updatedAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -901,7 +1040,7 @@ export class Databases extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -910,6 +1049,23 @@ export class Databases extends Service { }, apiPayload, ); + const defaults = { + root: 'document', + models: { + document: { + defaults: { + $id: '', + $sequence: '', + $collectionId: '', + $databaseId: '', + $createdAt: '', + $updatedAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1080,7 +1236,7 @@ export class Databases extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'put', uri, { @@ -1090,6 +1246,23 @@ export class Databases extends Service { }, apiPayload, ); + const defaults = { + root: 'document', + models: { + document: { + defaults: { + $id: '', + $sequence: '', + $collectionId: '', + $databaseId: '', + $createdAt: '', + $updatedAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1260,7 +1433,7 @@ export class Databases extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'patch', uri, { @@ -1270,6 +1443,23 @@ export class Databases extends Service { }, apiPayload, ); + const defaults = { + root: 'document', + models: { + document: { + defaults: { + $id: '', + $sequence: '', + $collectionId: '', + $databaseId: '', + $createdAt: '', + $updatedAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1555,7 +1745,7 @@ export class Databases extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'patch', uri, { @@ -1565,6 +1755,23 @@ export class Databases extends Service { }, apiPayload, ); + const defaults = { + root: 'document', + models: { + document: { + defaults: { + $id: '', + $sequence: '', + $collectionId: '', + $databaseId: '', + $createdAt: '', + $updatedAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1725,7 +1932,7 @@ export class Databases extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'patch', uri, { @@ -1735,5 +1942,22 @@ export class Databases extends Service { }, apiPayload, ); + const defaults = { + root: 'document', + models: { + document: { + defaults: { + $id: '', + $sequence: '', + $collectionId: '', + $databaseId: '', + $createdAt: '', + $updatedAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } } diff --git a/src/services/documents-db.ts b/src/services/documents-db.ts index 6f10966e..6efc2e4b 100644 --- a/src/services/documents-db.ts +++ b/src/services/documents-db.ts @@ -1,5 +1,5 @@ import { Service } from '../service'; -import { AppwriteException, Client } from '../client'; +import { AppwriteException, Client, applyDefaults } from '../client'; import type { Models } from '../models'; import type { Payload } from '../client'; @@ -71,7 +71,7 @@ export class DocumentsDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -80,6 +80,33 @@ export class DocumentsDB extends Service { }, apiPayload, ); + const defaults = { + root: 'transactionList', + models: { + transactionList: { + defaults: { + total: 0, + }, + properties: { + transactions: { + items: 'transaction', + }, + }, + }, + transaction: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + status: 'pending', + operations: 0, + expiresAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -127,7 +154,7 @@ export class DocumentsDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -137,6 +164,23 @@ export class DocumentsDB extends Service { }, apiPayload, ); + const defaults = { + root: 'transaction', + models: { + transaction: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + status: 'pending', + operations: 0, + expiresAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -190,7 +234,7 @@ export class DocumentsDB extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -199,6 +243,23 @@ export class DocumentsDB extends Service { }, apiPayload, ); + const defaults = { + root: 'transaction', + models: { + transaction: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + status: 'pending', + operations: 0, + expiresAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -285,7 +346,7 @@ export class DocumentsDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'patch', uri, { @@ -295,6 +356,23 @@ export class DocumentsDB extends Service { }, apiPayload, ); + const defaults = { + root: 'transaction', + models: { + transaction: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + status: 'pending', + operations: 0, + expiresAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -427,7 +505,7 @@ export class DocumentsDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -437,6 +515,23 @@ export class DocumentsDB extends Service { }, apiPayload, ); + const defaults = { + root: 'transaction', + models: { + transaction: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + status: 'pending', + operations: 0, + expiresAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -573,7 +668,7 @@ export class DocumentsDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -582,6 +677,33 @@ export class DocumentsDB extends Service { }, apiPayload, ); + const defaults = { + root: 'documentList', + models: { + documentList: { + defaults: { + total: 0, + }, + properties: { + documents: { + items: 'document', + }, + }, + }, + document: { + defaults: { + $id: '', + $sequence: '', + $collectionId: '', + $databaseId: '', + $createdAt: '', + $updatedAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -753,7 +875,7 @@ export class DocumentsDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -763,6 +885,23 @@ export class DocumentsDB extends Service { }, apiPayload, ); + const defaults = { + root: 'document', + models: { + document: { + defaults: { + $id: '', + $sequence: '', + $collectionId: '', + $databaseId: '', + $createdAt: '', + $updatedAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -879,7 +1018,7 @@ export class DocumentsDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -889,6 +1028,33 @@ export class DocumentsDB extends Service { }, apiPayload, ); + const defaults = { + root: 'documentList', + models: { + documentList: { + defaults: { + total: 0, + }, + properties: { + documents: { + items: 'document', + }, + }, + }, + document: { + defaults: { + $id: '', + $sequence: '', + $collectionId: '', + $databaseId: '', + $createdAt: '', + $updatedAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1018,7 +1184,7 @@ export class DocumentsDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -1027,6 +1193,23 @@ export class DocumentsDB extends Service { }, apiPayload, ); + const defaults = { + root: 'document', + models: { + document: { + defaults: { + $id: '', + $sequence: '', + $collectionId: '', + $databaseId: '', + $createdAt: '', + $updatedAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1196,7 +1379,7 @@ export class DocumentsDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'put', uri, { @@ -1206,6 +1389,23 @@ export class DocumentsDB extends Service { }, apiPayload, ); + const defaults = { + root: 'document', + models: { + document: { + defaults: { + $id: '', + $sequence: '', + $collectionId: '', + $databaseId: '', + $createdAt: '', + $updatedAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1375,7 +1575,7 @@ export class DocumentsDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'patch', uri, { @@ -1385,6 +1585,23 @@ export class DocumentsDB extends Service { }, apiPayload, ); + const defaults = { + root: 'document', + models: { + document: { + defaults: { + $id: '', + $sequence: '', + $collectionId: '', + $databaseId: '', + $createdAt: '', + $updatedAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1668,7 +1885,7 @@ export class DocumentsDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'patch', uri, { @@ -1678,6 +1895,23 @@ export class DocumentsDB extends Service { }, apiPayload, ); + const defaults = { + root: 'document', + models: { + document: { + defaults: { + $id: '', + $sequence: '', + $collectionId: '', + $databaseId: '', + $createdAt: '', + $updatedAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1837,7 +2071,7 @@ export class DocumentsDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'patch', uri, { @@ -1847,5 +2081,22 @@ export class DocumentsDB extends Service { }, apiPayload, ); + const defaults = { + root: 'document', + models: { + document: { + defaults: { + $id: '', + $sequence: '', + $collectionId: '', + $databaseId: '', + $createdAt: '', + $updatedAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } } diff --git a/src/services/functions.ts b/src/services/functions.ts index 230ffe70..54a4b2b7 100644 --- a/src/services/functions.ts +++ b/src/services/functions.ts @@ -1,5 +1,5 @@ import { Service } from '../service'; -import { AppwriteException, Client } from '../client'; +import { AppwriteException, Client, applyDefaults } from '../client'; import type { Models } from '../models'; import type { Payload } from '../client'; @@ -89,7 +89,7 @@ export class Functions extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -98,6 +98,54 @@ export class Functions extends Service { }, apiPayload, ); + const defaults = { + root: 'executionList', + models: { + executionList: { + defaults: { + total: 0, + }, + properties: { + executions: { + items: 'execution', + }, + }, + }, + execution: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + resourceId: '', + resourceType: 'functions', + deploymentId: '', + requestMethod: '', + requestPath: '', + responseStatusCode: 0, + responseBody: '', + logs: '', + errors: '', + duration: 0, + }, + properties: { + requestHeaders: { + items: 'headers', + }, + responseHeaders: { + items: 'headers', + }, + }, + }, + headers: { + defaults: { + name: '', + value: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -247,7 +295,7 @@ export class Functions extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -257,6 +305,44 @@ export class Functions extends Service { }, apiPayload, ); + const defaults = { + root: 'execution', + models: { + execution: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + resourceId: '', + resourceType: 'functions', + deploymentId: '', + requestMethod: '', + requestPath: '', + responseStatusCode: 0, + responseBody: '', + logs: '', + errors: '', + duration: 0, + }, + properties: { + requestHeaders: { + items: 'headers', + }, + responseHeaders: { + items: 'headers', + }, + }, + }, + headers: { + defaults: { + name: '', + value: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -327,7 +413,7 @@ export class Functions extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -336,5 +422,43 @@ export class Functions extends Service { }, apiPayload, ); + const defaults = { + root: 'execution', + models: { + execution: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + resourceId: '', + resourceType: 'functions', + deploymentId: '', + requestMethod: '', + requestPath: '', + responseStatusCode: 0, + responseBody: '', + logs: '', + errors: '', + duration: 0, + }, + properties: { + requestHeaders: { + items: 'headers', + }, + responseHeaders: { + items: 'headers', + }, + }, + }, + headers: { + defaults: { + name: '', + value: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } } diff --git a/src/services/locale.ts b/src/services/locale.ts index ce9e92b2..6eaeb512 100644 --- a/src/services/locale.ts +++ b/src/services/locale.ts @@ -1,5 +1,5 @@ import { Service } from '../service'; -import { Client } from '../client'; +import { Client, applyDefaults } from '../client'; import type { Models } from '../models'; import type { Payload } from '../client'; @@ -21,7 +21,7 @@ export class Locale extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -30,6 +30,24 @@ export class Locale extends Service { }, apiPayload, ); + const defaults = { + root: 'locale', + models: { + locale: { + defaults: { + ip: '', + countryCode: '', + country: '', + continentCode: '', + continent: '', + eu: false, + currency: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -77,7 +95,7 @@ export class Locale extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -86,6 +104,29 @@ export class Locale extends Service { }, apiPayload, ); + const defaults = { + root: 'localeCodeList', + models: { + localeCodeList: { + defaults: { + total: 0, + }, + properties: { + localeCodes: { + items: 'localeCode', + }, + }, + }, + localeCode: { + defaults: { + code: '', + name: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -133,7 +174,7 @@ export class Locale extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -142,6 +183,29 @@ export class Locale extends Service { }, apiPayload, ); + const defaults = { + root: 'continentList', + models: { + continentList: { + defaults: { + total: 0, + }, + properties: { + continents: { + items: 'continent', + }, + }, + }, + continent: { + defaults: { + name: '', + code: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -189,7 +253,7 @@ export class Locale extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -198,6 +262,29 @@ export class Locale extends Service { }, apiPayload, ); + const defaults = { + root: 'countryList', + models: { + countryList: { + defaults: { + total: 0, + }, + properties: { + countries: { + items: 'country', + }, + }, + }, + country: { + defaults: { + name: '', + code: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -245,7 +332,7 @@ export class Locale extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -254,6 +341,29 @@ export class Locale extends Service { }, apiPayload, ); + const defaults = { + root: 'countryList', + models: { + countryList: { + defaults: { + total: 0, + }, + properties: { + countries: { + items: 'country', + }, + }, + }, + country: { + defaults: { + name: '', + code: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -303,7 +413,7 @@ export class Locale extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -312,6 +422,30 @@ export class Locale extends Service { }, apiPayload, ); + const defaults = { + root: 'phoneList', + models: { + phoneList: { + defaults: { + total: 0, + }, + properties: { + phones: { + items: 'phone', + }, + }, + }, + phone: { + defaults: { + code: '', + countryCode: '', + countryName: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -359,7 +493,7 @@ export class Locale extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -368,6 +502,34 @@ export class Locale extends Service { }, apiPayload, ); + const defaults = { + root: 'currencyList', + models: { + currencyList: { + defaults: { + total: 0, + }, + properties: { + currencies: { + items: 'currency', + }, + }, + }, + currency: { + defaults: { + symbol: '', + name: '', + symbolNative: '', + decimalDigits: 0, + rounding: 0, + code: '', + namePlural: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -415,7 +577,7 @@ export class Locale extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -424,5 +586,29 @@ export class Locale extends Service { }, apiPayload, ); + const defaults = { + root: 'languageList', + models: { + languageList: { + defaults: { + total: 0, + }, + properties: { + languages: { + items: 'language', + }, + }, + }, + language: { + defaults: { + name: '', + code: '', + nativeName: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } } diff --git a/src/services/messaging.ts b/src/services/messaging.ts index 33e94c19..b1939ddf 100644 --- a/src/services/messaging.ts +++ b/src/services/messaging.ts @@ -1,5 +1,5 @@ import { Service } from '../service'; -import { AppwriteException, Client } from '../client'; +import { AppwriteException, Client, applyDefaults } from '../client'; import type { Models } from '../models'; import type { Payload } from '../client'; @@ -100,7 +100,7 @@ export class Messaging extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -110,6 +110,25 @@ export class Messaging extends Service { }, apiPayload, ); + const defaults = { + root: 'subscriber', + models: { + subscriber: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + targetId: '', + userId: '', + userName: '', + topicId: '', + providerType: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** diff --git a/src/services/oauth-2.ts b/src/services/oauth-2.ts index 1920bc1a..cbcaf3ad 100644 --- a/src/services/oauth-2.ts +++ b/src/services/oauth-2.ts @@ -1,5 +1,5 @@ import { Service } from '../service'; -import { AppwriteException, Client } from '../client'; +import { AppwriteException, Client, applyDefaults } from '../client'; import type { Models } from '../models'; import type { Payload } from '../client'; @@ -96,7 +96,7 @@ export class Oauth2 extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -105,6 +105,18 @@ export class Oauth2 extends Service { }, apiPayload, ); + const defaults = { + root: 'oauth2Approve', + models: { + oauth2Approve: { + defaults: { + redirectUrl: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -121,7 +133,7 @@ export class Oauth2 extends Service { * @param {string} params.prompt - OIDC prompt parameter for customization of consent screen. Space-separated list of: none, login, consent, select_account. * @param {number} params.maxAge - OIDC max_age paraleter for customization of consent screen. Maximum allowable elapsed time in seconds since the user last authenticated. If exceeded, re-authentication is required. * @param {string} params.authorizationDetails - Rich authorization request. JSON array of objects, each with a `type` and project-defined fields - * @param {string} params.resource - RFC 8707 resource indicator URI or URI list. Each value must be an absolute URI without a fragment. + * @param {string[]} params.resource - RFC 8707 resource indicator URI or URI list. Each value must be an absolute URI without a fragment. * @param {string} params.audience - Compatibility alias for a single OAuth2 resource indicator URI. * @param {string} params.requestUri - OAuth2 authorization request handle returned by the pushed authorization request endpoint. * @throws {AppwriteException} @@ -139,7 +151,7 @@ export class Oauth2 extends Service { prompt?: string; maxAge?: number; authorizationDetails?: string; - resource?: string; + resource?: string[]; audience?: string; requestUri?: string; }): Promise; @@ -157,7 +169,7 @@ export class Oauth2 extends Service { * @param {string} prompt - OIDC prompt parameter for customization of consent screen. Space-separated list of: none, login, consent, select_account. * @param {number} maxAge - OIDC max_age paraleter for customization of consent screen. Maximum allowable elapsed time in seconds since the user last authenticated. If exceeded, re-authentication is required. * @param {string} authorizationDetails - Rich authorization request. JSON array of objects, each with a `type` and project-defined fields - * @param {string} resource - RFC 8707 resource indicator URI or URI list. Each value must be an absolute URI without a fragment. + * @param {string[]} resource - RFC 8707 resource indicator URI or URI list. Each value must be an absolute URI without a fragment. * @param {string} audience - Compatibility alias for a single OAuth2 resource indicator URI. * @param {string} requestUri - OAuth2 authorization request handle returned by the pushed authorization request endpoint. * @throws {AppwriteException} @@ -176,7 +188,7 @@ export class Oauth2 extends Service { prompt?: string, maxAge?: number, authorizationDetails?: string, - resource?: string, + resource?: string[], audience?: string, requestUri?: string, ): Promise; @@ -194,7 +206,7 @@ export class Oauth2 extends Service { prompt?: string; maxAge?: number; authorizationDetails?: string; - resource?: string; + resource?: string[]; audience?: string; requestUri?: string; } @@ -210,7 +222,7 @@ export class Oauth2 extends Service { string?, number?, string?, - string?, + string[]?, string?, string?, ] @@ -227,7 +239,7 @@ export class Oauth2 extends Service { prompt?: string; maxAge?: number; authorizationDetails?: string; - resource?: string; + resource?: string[]; audience?: string; requestUri?: string; }; @@ -250,7 +262,7 @@ export class Oauth2 extends Service { prompt?: string; maxAge?: number; authorizationDetails?: string; - resource?: string; + resource?: string[]; audience?: string; requestUri?: string; }; @@ -267,7 +279,7 @@ export class Oauth2 extends Service { prompt: rest[7] as string, maxAge: rest[8] as number, authorizationDetails: rest[9] as string, - resource: rest[10] as string, + resource: rest[10] as string[], audience: rest[11] as string, requestUri: rest[12] as string, }; @@ -351,7 +363,7 @@ export class Oauth2 extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -359,6 +371,19 @@ export class Oauth2 extends Service { }, apiPayload, ); + const defaults = { + root: 'oauth2Authorize', + models: { + oauth2Authorize: { + defaults: { + grantId: '', + redirectUrl: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -375,7 +400,7 @@ export class Oauth2 extends Service { * @param {string} params.prompt - OIDC prompt parameter for customization of consent screen. Space-separated list of: none, login, consent, select_account. * @param {number} params.maxAge - OIDC max_age paraleter for customization of consent screen. Maximum allowable elapsed time in seconds since the user last authenticated. If exceeded, re-authentication is required. * @param {string} params.authorizationDetails - Rich authorization request. JSON array of objects, each with a `type` and project-defined fields - * @param {string} params.resource - RFC 8707 resource indicator URI or URI list. Each value must be an absolute URI without a fragment. + * @param {string[]} params.resource - RFC 8707 resource indicator URI or URI list. Each value must be an absolute URI without a fragment. * @param {string} params.audience - Compatibility alias for a single OAuth2 resource indicator URI. * @param {string} params.requestUri - OAuth2 authorization request handle returned by the pushed authorization request endpoint. * @throws {AppwriteException} @@ -393,7 +418,7 @@ export class Oauth2 extends Service { prompt?: string; maxAge?: number; authorizationDetails?: string; - resource?: string; + resource?: string[]; audience?: string; requestUri?: string; }): Promise; @@ -411,7 +436,7 @@ export class Oauth2 extends Service { * @param {string} prompt - OIDC prompt parameter for customization of consent screen. Space-separated list of: none, login, consent, select_account. * @param {number} maxAge - OIDC max_age paraleter for customization of consent screen. Maximum allowable elapsed time in seconds since the user last authenticated. If exceeded, re-authentication is required. * @param {string} authorizationDetails - Rich authorization request. JSON array of objects, each with a `type` and project-defined fields - * @param {string} resource - RFC 8707 resource indicator URI or URI list. Each value must be an absolute URI without a fragment. + * @param {string[]} resource - RFC 8707 resource indicator URI or URI list. Each value must be an absolute URI without a fragment. * @param {string} audience - Compatibility alias for a single OAuth2 resource indicator URI. * @param {string} requestUri - OAuth2 authorization request handle returned by the pushed authorization request endpoint. * @throws {AppwriteException} @@ -430,7 +455,7 @@ export class Oauth2 extends Service { prompt?: string, maxAge?: number, authorizationDetails?: string, - resource?: string, + resource?: string[], audience?: string, requestUri?: string, ): Promise; @@ -448,7 +473,7 @@ export class Oauth2 extends Service { prompt?: string; maxAge?: number; authorizationDetails?: string; - resource?: string; + resource?: string[]; audience?: string; requestUri?: string; } @@ -464,7 +489,7 @@ export class Oauth2 extends Service { string?, number?, string?, - string?, + string[]?, string?, string?, ] @@ -481,7 +506,7 @@ export class Oauth2 extends Service { prompt?: string; maxAge?: number; authorizationDetails?: string; - resource?: string; + resource?: string[]; audience?: string; requestUri?: string; }; @@ -504,7 +529,7 @@ export class Oauth2 extends Service { prompt?: string; maxAge?: number; authorizationDetails?: string; - resource?: string; + resource?: string[]; audience?: string; requestUri?: string; }; @@ -521,7 +546,7 @@ export class Oauth2 extends Service { prompt: rest[7] as string, maxAge: rest[8] as number, authorizationDetails: rest[9] as string, - resource: rest[10] as string, + resource: rest[10] as string[], audience: rest[11] as string, requestUri: rest[12] as string, }; @@ -605,7 +630,7 @@ export class Oauth2 extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -614,6 +639,19 @@ export class Oauth2 extends Service { }, apiPayload, ); + const defaults = { + root: 'oauth2Authorize', + models: { + oauth2Authorize: { + defaults: { + grantId: '', + redirectUrl: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -622,7 +660,7 @@ export class Oauth2 extends Service { * @param {string} params.clientId - OAuth2 client ID. Either a registered app ID or an HTTPS client ID metadata document URL. * @param {string} params.scope - Space-separated OAuth2 scopes. Can include project scopes, and built-in scopes: `openid`, `email`, `profile`. * @param {string} params.authorizationDetails - Rich authorization request. JSON array of objects, each with a `type` and project-defined fields - * @param {string} params.resource - RFC 8707 resource indicator URI or URI list. Each value must be an absolute URI without a fragment. + * @param {string[]} params.resource - RFC 8707 resource indicator URI or URI list. Each value must be an absolute URI without a fragment. * @param {string} params.audience - Compatibility alias for a single OAuth2 resource indicator URI. * @throws {AppwriteException} * @returns {Promise} @@ -631,7 +669,7 @@ export class Oauth2 extends Service { clientId?: string; scope?: string; authorizationDetails?: string; - resource?: string; + resource?: string[]; audience?: string; }): Promise; /** @@ -640,7 +678,7 @@ export class Oauth2 extends Service { * @param {string} clientId - OAuth2 client ID. Either a registered app ID or an HTTPS client ID metadata document URL. * @param {string} scope - Space-separated OAuth2 scopes. Can include project scopes, and built-in scopes: `openid`, `email`, `profile`. * @param {string} authorizationDetails - Rich authorization request. JSON array of objects, each with a `type` and project-defined fields - * @param {string} resource - RFC 8707 resource indicator URI or URI list. Each value must be an absolute URI without a fragment. + * @param {string[]} resource - RFC 8707 resource indicator URI or URI list. Each value must be an absolute URI without a fragment. * @param {string} audience - Compatibility alias for a single OAuth2 resource indicator URI. * @throws {AppwriteException} * @returns {Promise} @@ -650,7 +688,7 @@ export class Oauth2 extends Service { clientId?: string, scope?: string, authorizationDetails?: string, - resource?: string, + resource?: string[], audience?: string, ): Promise; createDeviceAuthorization( @@ -659,17 +697,17 @@ export class Oauth2 extends Service { clientId?: string; scope?: string; authorizationDetails?: string; - resource?: string; + resource?: string[]; audience?: string; } | string, - ...rest: [string?, string?, string?, string?] + ...rest: [string?, string?, string[]?, string?] ): Promise { let params: { clientId?: string; scope?: string; authorizationDetails?: string; - resource?: string; + resource?: string[]; audience?: string; }; @@ -683,7 +721,7 @@ export class Oauth2 extends Service { clientId?: string; scope?: string; authorizationDetails?: string; - resource?: string; + resource?: string[]; audience?: string; }; } else { @@ -691,7 +729,7 @@ export class Oauth2 extends Service { clientId: paramsOrFirst as string, scope: rest[0] as string, authorizationDetails: rest[1] as string, - resource: rest[2] as string, + resource: rest[2] as string[], audience: rest[3] as string, }; } @@ -729,7 +767,7 @@ export class Oauth2 extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -738,6 +776,23 @@ export class Oauth2 extends Service { }, apiPayload, ); + const defaults = { + root: 'oauth2DeviceAuthorization', + models: { + oauth2DeviceAuthorization: { + defaults: { + device_code: '', + user_code: '', + verification_uri: '', + verification_uri_complete: '', + expires_in: 0, + interval: 0, + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -793,7 +848,7 @@ export class Oauth2 extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -802,6 +857,29 @@ export class Oauth2 extends Service { }, apiPayload, ); + const defaults = { + root: 'oauth2Grant', + models: { + oauth2Grant: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + userId: '', + appId: '', + scopes: [], + resources: [], + authorizationDetails: '[]', + prompt: '', + redirectUri: '', + authTime: 0, + expire: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -855,7 +933,7 @@ export class Oauth2 extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -863,6 +941,29 @@ export class Oauth2 extends Service { }, apiPayload, ); + const defaults = { + root: 'oauth2Grant', + models: { + oauth2Grant: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + userId: '', + appId: '', + scopes: [], + resources: [], + authorizationDetails: '[]', + prompt: '', + redirectUri: '', + authTime: 0, + expire: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1216,7 +1317,7 @@ export class Oauth2 extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -1224,6 +1325,28 @@ export class Oauth2 extends Service { }, apiPayload, ); + const defaults = { + root: 'oauth2OrganizationList', + models: { + oauth2OrganizationList: { + defaults: { + total: 0, + }, + properties: { + organizations: { + items: 'oauth2Organization', + }, + }, + }, + oauth2Organization: { + defaults: { + $id: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1240,7 +1363,7 @@ export class Oauth2 extends Service { * @param {string} params.prompt - OIDC prompt parameter for customization of consent screen. Space-separated list of: none, login, consent, select_account. * @param {number} params.maxAge - OIDC max_age parameter for customization of consent screen. * @param {string} params.authorizationDetails - Rich authorization request. JSON array of objects, each with a `type` and project-defined fields - * @param {string} params.resource - RFC 8707 resource indicator URI or URI list. Each value must be an absolute URI without a fragment. + * @param {string[]} params.resource - RFC 8707 resource indicator URI or URI list. Each value must be an absolute URI without a fragment. * @param {string} params.audience - Compatibility alias for a single OAuth2 resource indicator URI. * @throws {AppwriteException} * @returns {Promise} @@ -1257,7 +1380,7 @@ export class Oauth2 extends Service { prompt?: string; maxAge?: number; authorizationDetails?: string; - resource?: string; + resource?: string[]; audience?: string; }): Promise; /** @@ -1274,7 +1397,7 @@ export class Oauth2 extends Service { * @param {string} prompt - OIDC prompt parameter for customization of consent screen. Space-separated list of: none, login, consent, select_account. * @param {number} maxAge - OIDC max_age parameter for customization of consent screen. * @param {string} authorizationDetails - Rich authorization request. JSON array of objects, each with a `type` and project-defined fields - * @param {string} resource - RFC 8707 resource indicator URI or URI list. Each value must be an absolute URI without a fragment. + * @param {string[]} resource - RFC 8707 resource indicator URI or URI list. Each value must be an absolute URI without a fragment. * @param {string} audience - Compatibility alias for a single OAuth2 resource indicator URI. * @throws {AppwriteException} * @returns {Promise} @@ -1292,7 +1415,7 @@ export class Oauth2 extends Service { prompt?: string, maxAge?: number, authorizationDetails?: string, - resource?: string, + resource?: string[], audience?: string, ): Promise; createPAR( @@ -1309,7 +1432,7 @@ export class Oauth2 extends Service { prompt?: string; maxAge?: number; authorizationDetails?: string; - resource?: string; + resource?: string[]; audience?: string; } | string, @@ -1324,7 +1447,7 @@ export class Oauth2 extends Service { string?, number?, string?, - string?, + string[]?, string?, ] ): Promise { @@ -1340,7 +1463,7 @@ export class Oauth2 extends Service { prompt?: string; maxAge?: number; authorizationDetails?: string; - resource?: string; + resource?: string[]; audience?: string; }; @@ -1361,7 +1484,7 @@ export class Oauth2 extends Service { prompt?: string; maxAge?: number; authorizationDetails?: string; - resource?: string; + resource?: string[]; audience?: string; }; } else { @@ -1377,7 +1500,7 @@ export class Oauth2 extends Service { prompt: rest[7] as string, maxAge: rest[8] as number, authorizationDetails: rest[9] as string, - resource: rest[10] as string, + resource: rest[10] as string[], audience: rest[11] as string, }; } @@ -1473,7 +1596,7 @@ export class Oauth2 extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -1482,6 +1605,19 @@ export class Oauth2 extends Service { }, apiPayload, ); + const defaults = { + root: 'oauth2PAR', + models: { + oauth2PAR: { + defaults: { + request_uri: '', + expires_in: 0, + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1562,7 +1698,7 @@ export class Oauth2 extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -1570,6 +1706,30 @@ export class Oauth2 extends Service { }, apiPayload, ); + const defaults = { + root: 'oauth2ProjectList', + models: { + oauth2ProjectList: { + defaults: { + total: 0, + }, + properties: { + projects: { + items: 'oauth2Project', + }, + }, + }, + oauth2Project: { + defaults: { + $id: '', + region: '', + endpoint: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1625,7 +1785,7 @@ export class Oauth2 extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -1634,6 +1794,18 @@ export class Oauth2 extends Service { }, apiPayload, ); + const defaults = { + root: 'oauth2Reject', + models: { + oauth2Reject: { + defaults: { + redirectUrl: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1761,7 +1933,7 @@ export class Oauth2 extends Service { * @param {string} params.clientSecret - OAuth2 client secret. Required for confidential apps. * @param {string} params.codeVerifier - PKCE code verifier. Required for public apps. * @param {string} params.redirectUri - Redirect URI. Required for `authorization_code` grant type. - * @param {string} params.resource - RFC 8707 resource indicator URI or URI list. Each value must be an absolute URI without a fragment. + * @param {string[]} params.resource - RFC 8707 resource indicator URI or URI list. Each value must be an absolute URI without a fragment. * @param {string} params.audience - Compatibility alias for a single OAuth2 resource indicator URI. * @throws {AppwriteException} * @returns {Promise} @@ -1775,7 +1947,7 @@ export class Oauth2 extends Service { clientSecret?: string; codeVerifier?: string; redirectUri?: string; - resource?: string; + resource?: string[]; audience?: string; }): Promise; /** @@ -1789,7 +1961,7 @@ export class Oauth2 extends Service { * @param {string} clientSecret - OAuth2 client secret. Required for confidential apps. * @param {string} codeVerifier - PKCE code verifier. Required for public apps. * @param {string} redirectUri - Redirect URI. Required for `authorization_code` grant type. - * @param {string} resource - RFC 8707 resource indicator URI or URI list. Each value must be an absolute URI without a fragment. + * @param {string[]} resource - RFC 8707 resource indicator URI or URI list. Each value must be an absolute URI without a fragment. * @param {string} audience - Compatibility alias for a single OAuth2 resource indicator URI. * @throws {AppwriteException} * @returns {Promise} @@ -1804,7 +1976,7 @@ export class Oauth2 extends Service { clientSecret?: string, codeVerifier?: string, redirectUri?: string, - resource?: string, + resource?: string[], audience?: string, ): Promise; createToken( @@ -1818,7 +1990,7 @@ export class Oauth2 extends Service { clientSecret?: string; codeVerifier?: string; redirectUri?: string; - resource?: string; + resource?: string[]; audience?: string; } | string, @@ -1830,7 +2002,7 @@ export class Oauth2 extends Service { string?, string?, string?, - string?, + string[]?, string?, ] ): Promise { @@ -1843,7 +2015,7 @@ export class Oauth2 extends Service { clientSecret?: string; codeVerifier?: string; redirectUri?: string; - resource?: string; + resource?: string[]; audience?: string; }; @@ -1861,7 +2033,7 @@ export class Oauth2 extends Service { clientSecret?: string; codeVerifier?: string; redirectUri?: string; - resource?: string; + resource?: string[]; audience?: string; }; } else { @@ -1874,7 +2046,7 @@ export class Oauth2 extends Service { clientSecret: rest[4] as string, codeVerifier: rest[5] as string, redirectUri: rest[6] as string, - resource: rest[7] as string, + resource: rest[7] as string[], audience: rest[8] as string, }; } @@ -1943,7 +2115,7 @@ export class Oauth2 extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -1952,5 +2124,21 @@ export class Oauth2 extends Service { }, apiPayload, ); + const defaults = { + root: 'oauth2Token', + models: { + oauth2Token: { + defaults: { + access_token: '', + token_type: 'Bearer', + expires_in: 0, + refresh_token: '', + scope: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } } diff --git a/src/services/organization.ts b/src/services/organization.ts index 3542965f..3bf9c9b8 100644 --- a/src/services/organization.ts +++ b/src/services/organization.ts @@ -1,5 +1,5 @@ import { Service } from '../service'; -import { AppwriteException, Client } from '../client'; +import { AppwriteException, Client, applyDefaults } from '../client'; import type { Models } from '../models'; import type { Payload } from '../client'; @@ -71,7 +71,7 @@ export class Organization extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -80,6 +80,36 @@ export class Organization extends Service { }, apiPayload, ); + const defaults = { + root: 'appInstallationList', + models: { + appInstallationList: { + defaults: { + total: 0, + }, + properties: { + installations: { + items: 'appInstallation', + }, + }, + }, + appInstallation: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + appId: '', + teamId: '', + scopes: [], + authorizationDetails: [], + createdById: '', + createdByName: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -149,7 +179,7 @@ export class Organization extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -159,6 +189,26 @@ export class Organization extends Service { }, apiPayload, ); + const defaults = { + root: 'appInstallation', + models: { + appInstallation: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + appId: '', + teamId: '', + scopes: [], + authorizationDetails: [], + createdById: '', + createdByName: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -212,7 +262,7 @@ export class Organization extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -221,6 +271,26 @@ export class Organization extends Service { }, apiPayload, ); + const defaults = { + root: 'appInstallation', + models: { + appInstallation: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + appId: '', + teamId: '', + scopes: [], + authorizationDetails: [], + createdById: '', + createdByName: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -291,7 +361,7 @@ export class Organization extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'put', uri, { @@ -301,6 +371,26 @@ export class Organization extends Service { }, apiPayload, ); + const defaults = { + root: 'appInstallation', + models: { + appInstallation: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + appId: '', + teamId: '', + scopes: [], + authorizationDetails: [], + createdById: '', + createdByName: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** diff --git a/src/services/presences.ts b/src/services/presences.ts index 5fb3a364..883d330b 100644 --- a/src/services/presences.ts +++ b/src/services/presences.ts @@ -1,5 +1,5 @@ import { Service } from '../service'; -import { AppwriteException, Client } from '../client'; +import { AppwriteException, Client, applyDefaults } from '../client'; import type { Models } from '../models'; import type { Payload } from '../client'; @@ -85,7 +85,7 @@ export class Presences extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -94,6 +94,32 @@ export class Presences extends Service { }, apiPayload, ); + const defaults = { + root: 'presenceList', + models: { + presenceList: { + defaults: { + total: 0, + }, + properties: { + presences: { + items: 'presence', + }, + }, + }, + presence: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + userId: '', + source: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -147,7 +173,7 @@ export class Presences extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -156,6 +182,22 @@ export class Presences extends Service { }, apiPayload, ); + const defaults = { + root: 'presence', + models: { + presence: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + userId: '', + source: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -278,7 +320,7 @@ export class Presences extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'put', uri, { @@ -288,6 +330,22 @@ export class Presences extends Service { }, apiPayload, ); + const defaults = { + root: 'presence', + models: { + presence: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + userId: '', + source: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -419,7 +477,7 @@ export class Presences extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'patch', uri, { @@ -429,6 +487,22 @@ export class Presences extends Service { }, apiPayload, ); + const defaults = { + root: 'presence', + models: { + presence: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + userId: '', + source: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** diff --git a/src/services/storage.ts b/src/services/storage.ts index fdca28a8..c956d2ab 100644 --- a/src/services/storage.ts +++ b/src/services/storage.ts @@ -1,5 +1,5 @@ import { Service } from '../service'; -import { AppwriteException, Client } from '../client'; +import { AppwriteException, Client, applyDefaults } from '../client'; import type { Models } from '../models'; import type { UploadProgress, Payload } from '../client'; import * as FileSystem from 'expo-file-system'; @@ -113,7 +113,7 @@ export class Storage extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -122,6 +122,43 @@ export class Storage extends Service { }, apiPayload, ); + const defaults = { + root: 'fileList', + models: { + fileList: { + defaults: { + total: 0, + }, + properties: { + files: { + items: 'file', + }, + }, + }, + file: { + defaults: { + $id: '', + bucketId: '', + $createdAt: '', + $updatedAt: '', + $permissions: [], + name: '', + folder: '', + key: '', + signature: '', + mimeType: '', + sizeOriginal: 0, + sizeActual: 0, + chunksTotal: 0, + chunksUploaded: 0, + encryption: false, + compression: 'none', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -563,7 +600,7 @@ export class Storage extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -572,6 +609,33 @@ export class Storage extends Service { }, apiPayload, ); + const defaults = { + root: 'file', + models: { + file: { + defaults: { + $id: '', + bucketId: '', + $createdAt: '', + $updatedAt: '', + $permissions: [], + name: '', + folder: '', + key: '', + signature: '', + mimeType: '', + sizeOriginal: 0, + sizeActual: 0, + chunksTotal: 0, + chunksUploaded: 0, + encryption: false, + compression: 'none', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -674,7 +738,7 @@ export class Storage extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'put', uri, { @@ -684,6 +748,33 @@ export class Storage extends Service { }, apiPayload, ); + const defaults = { + root: 'file', + models: { + file: { + defaults: { + $id: '', + bucketId: '', + $createdAt: '', + $updatedAt: '', + $permissions: [], + name: '', + folder: '', + key: '', + signature: '', + mimeType: '', + sizeOriginal: 0, + sizeActual: 0, + chunksTotal: 0, + chunksUploaded: 0, + encryption: false, + compression: 'none', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** diff --git a/src/services/tables-db.ts b/src/services/tables-db.ts index ae5d11d1..a41dc9a5 100644 --- a/src/services/tables-db.ts +++ b/src/services/tables-db.ts @@ -1,5 +1,5 @@ import { Service } from '../service'; -import { AppwriteException, Client } from '../client'; +import { AppwriteException, Client, applyDefaults } from '../client'; import type { Models } from '../models'; import type { Payload } from '../client'; @@ -71,7 +71,7 @@ export class TablesDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -80,6 +80,33 @@ export class TablesDB extends Service { }, apiPayload, ); + const defaults = { + root: 'transactionList', + models: { + transactionList: { + defaults: { + total: 0, + }, + properties: { + transactions: { + items: 'transaction', + }, + }, + }, + transaction: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + status: 'pending', + operations: 0, + expiresAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -127,7 +154,7 @@ export class TablesDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -137,6 +164,23 @@ export class TablesDB extends Service { }, apiPayload, ); + const defaults = { + root: 'transaction', + models: { + transaction: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + status: 'pending', + operations: 0, + expiresAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -190,7 +234,7 @@ export class TablesDB extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -199,6 +243,23 @@ export class TablesDB extends Service { }, apiPayload, ); + const defaults = { + root: 'transaction', + models: { + transaction: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + status: 'pending', + operations: 0, + expiresAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -285,7 +346,7 @@ export class TablesDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'patch', uri, { @@ -295,6 +356,23 @@ export class TablesDB extends Service { }, apiPayload, ); + const defaults = { + root: 'transaction', + models: { + transaction: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + status: 'pending', + operations: 0, + expiresAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -427,7 +505,7 @@ export class TablesDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -437,6 +515,23 @@ export class TablesDB extends Service { }, apiPayload, ); + const defaults = { + root: 'transaction', + models: { + transaction: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + status: 'pending', + operations: 0, + expiresAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -567,7 +662,7 @@ export class TablesDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -576,6 +671,33 @@ export class TablesDB extends Service { }, apiPayload, ); + const defaults = { + root: 'rowList', + models: { + rowList: { + defaults: { + total: 0, + }, + properties: { + rows: { + items: 'row', + }, + }, + }, + row: { + defaults: { + $id: '', + $sequence: '', + $tableId: '', + $databaseId: '', + $createdAt: '', + $updatedAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -734,7 +856,7 @@ export class TablesDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -744,6 +866,23 @@ export class TablesDB extends Service { }, apiPayload, ); + const defaults = { + root: 'row', + models: { + row: { + defaults: { + $id: '', + $sequence: '', + $tableId: '', + $databaseId: '', + $createdAt: '', + $updatedAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -862,7 +1001,7 @@ export class TablesDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -871,6 +1010,23 @@ export class TablesDB extends Service { }, apiPayload, ); + const defaults = { + root: 'row', + models: { + row: { + defaults: { + $id: '', + $sequence: '', + $tableId: '', + $databaseId: '', + $createdAt: '', + $updatedAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1025,7 +1181,7 @@ export class TablesDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'put', uri, { @@ -1035,6 +1191,23 @@ export class TablesDB extends Service { }, apiPayload, ); + const defaults = { + root: 'row', + models: { + row: { + defaults: { + $id: '', + $sequence: '', + $tableId: '', + $databaseId: '', + $createdAt: '', + $updatedAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1189,7 +1362,7 @@ export class TablesDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'patch', uri, { @@ -1199,6 +1372,23 @@ export class TablesDB extends Service { }, apiPayload, ); + const defaults = { + root: 'row', + models: { + row: { + defaults: { + $id: '', + $sequence: '', + $tableId: '', + $databaseId: '', + $createdAt: '', + $updatedAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1460,7 +1650,7 @@ export class TablesDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'patch', uri, { @@ -1470,6 +1660,23 @@ export class TablesDB extends Service { }, apiPayload, ); + const defaults = { + root: 'row', + models: { + row: { + defaults: { + $id: '', + $sequence: '', + $tableId: '', + $databaseId: '', + $createdAt: '', + $updatedAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1616,7 +1823,7 @@ export class TablesDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'patch', uri, { @@ -1626,5 +1833,22 @@ export class TablesDB extends Service { }, apiPayload, ); + const defaults = { + root: 'row', + models: { + row: { + defaults: { + $id: '', + $sequence: '', + $tableId: '', + $databaseId: '', + $createdAt: '', + $updatedAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } } diff --git a/src/services/teams.ts b/src/services/teams.ts index a4424fcd..caf37d38 100644 --- a/src/services/teams.ts +++ b/src/services/teams.ts @@ -1,5 +1,5 @@ import { Service } from '../service'; -import { AppwriteException, Client } from '../client'; +import { AppwriteException, Client, applyDefaults } from '../client'; import type { Models } from '../models'; import type { Payload } from '../client'; @@ -85,7 +85,7 @@ export class Teams extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -94,6 +94,32 @@ export class Teams extends Service { }, apiPayload, ); + const defaults = { + root: 'teamList', + models: { + teamList: { + defaults: { + total: 0, + }, + properties: { + teams: { + items: 'team', + }, + }, + }, + team: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + total: 0, + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -180,7 +206,7 @@ export class Teams extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -190,6 +216,22 @@ export class Teams extends Service { }, apiPayload, ); + const defaults = { + root: 'team', + models: { + team: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + total: 0, + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -243,7 +285,7 @@ export class Teams extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -252,6 +294,22 @@ export class Teams extends Service { }, apiPayload, ); + const defaults = { + root: 'team', + models: { + team: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + total: 0, + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -323,7 +381,7 @@ export class Teams extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'put', uri, { @@ -333,6 +391,22 @@ export class Teams extends Service { }, apiPayload, ); + const defaults = { + root: 'team', + models: { + team: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + total: 0, + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -469,7 +543,7 @@ export class Teams extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -478,6 +552,36 @@ export class Teams extends Service { }, apiPayload, ); + const defaults = { + root: 'appInstallationList', + models: { + appInstallationList: { + defaults: { + total: 0, + }, + properties: { + installations: { + items: 'appInstallation', + }, + }, + }, + appInstallation: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + appId: '', + teamId: '', + scopes: [], + authorizationDetails: [], + createdById: '', + createdByName: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -566,7 +670,7 @@ export class Teams extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -576,6 +680,26 @@ export class Teams extends Service { }, apiPayload, ); + const defaults = { + root: 'appInstallation', + models: { + appInstallation: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + appId: '', + teamId: '', + scopes: [], + authorizationDetails: [], + createdById: '', + createdByName: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -647,7 +771,7 @@ export class Teams extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -656,6 +780,26 @@ export class Teams extends Service { }, apiPayload, ); + const defaults = { + root: 'appInstallation', + models: { + appInstallation: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + appId: '', + teamId: '', + scopes: [], + authorizationDetails: [], + createdById: '', + createdByName: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -748,7 +892,7 @@ export class Teams extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'put', uri, { @@ -758,6 +902,26 @@ export class Teams extends Service { }, apiPayload, ); + const defaults = { + root: 'appInstallation', + models: { + appInstallation: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + appId: '', + teamId: '', + scopes: [], + authorizationDetails: [], + createdById: '', + createdByName: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -937,7 +1101,7 @@ export class Teams extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -946,6 +1110,42 @@ export class Teams extends Service { }, apiPayload, ); + const defaults = { + root: 'membershipList', + models: { + membershipList: { + defaults: { + total: 0, + }, + properties: { + memberships: { + items: 'membership', + }, + }, + }, + membership: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + userId: '', + userName: '', + userEmail: '', + userPhone: '', + teamId: '', + teamName: '', + invited: '', + joined: '', + confirm: false, + mfa: false, + userAccessedAt: '', + roles: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -960,6 +1160,7 @@ export class Teams extends Service { * * @param {string} params.teamId - Team ID. * @param {string[]} params.roles - Array of strings. Use this param to set the user roles in the team. A role can be any string. Learn more about [roles and permissions](https://appwrite.io/docs/permissions). Maximum of 100 roles are allowed, each 81 characters long. + * @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. * @param {string} params.email - Email of the new team member. * @param {string} params.userId - ID of the user to be added to a team. * @param {string} params.phone - Phone number. Format this number with a leading '+' and a country code, e.g., +16175551212. @@ -971,6 +1172,7 @@ export class Teams extends Service { createMembership(params: { teamId: string; roles: string[]; + membershipId?: string; email?: string; userId?: string; phone?: string; @@ -989,6 +1191,7 @@ export class Teams extends Service { * * @param {string} teamId - Team ID. * @param {string[]} roles - Array of strings. Use this param to set the user roles in the team. A role can be any string. Learn more about [roles and permissions](https://appwrite.io/docs/permissions). Maximum of 100 roles are allowed, each 81 characters long. + * @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. * @param {string} email - Email of the new team member. * @param {string} userId - ID of the user to be added to a team. * @param {string} phone - Phone number. Format this number with a leading '+' and a country code, e.g., +16175551212. @@ -1001,6 +1204,7 @@ export class Teams extends Service { createMembership( teamId: string, roles: string[], + membershipId?: string, email?: string, userId?: string, phone?: string, @@ -1012,6 +1216,7 @@ export class Teams extends Service { | { teamId: string; roles: string[]; + membershipId?: string; email?: string; userId?: string; phone?: string; @@ -1019,11 +1224,20 @@ export class Teams extends Service { name?: string; } | string, - ...rest: [string[]?, string?, string?, string?, string?, string?] + ...rest: [ + string[]?, + string?, + string?, + string?, + string?, + string?, + string?, + ] ): Promise { let params: { teamId: string; roles: string[]; + membershipId?: string; email?: string; userId?: string; phone?: string; @@ -1039,6 +1253,7 @@ export class Teams extends Service { params = (paramsOrFirst || {}) as { teamId: string; roles: string[]; + membershipId?: string; email?: string; userId?: string; phone?: string; @@ -1049,16 +1264,18 @@ export class Teams extends Service { params = { teamId: paramsOrFirst as string, roles: rest[0] as string[], - email: rest[1] as string, - userId: rest[2] as string, - phone: rest[3] as string, - url: rest[4] as string, - name: rest[5] as string, + membershipId: rest[1] as string, + email: rest[2] as string, + userId: rest[3] as string, + phone: rest[4] as string, + url: rest[5] as string, + name: rest[6] as string, }; } const teamId = params.teamId; const roles = params.roles; + const membershipId = params.membershipId; const email = params.email; const userId = params.userId; const phone = params.phone; @@ -1079,6 +1296,10 @@ export class Teams extends Service { ); const apiPayload: Payload = {}; + if (typeof membershipId !== 'undefined') { + apiPayload['membershipId'] = membershipId; + } + if (typeof email !== 'undefined') { apiPayload['email'] = email; } @@ -1104,7 +1325,7 @@ export class Teams extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -1114,6 +1335,32 @@ export class Teams extends Service { }, apiPayload, ); + const defaults = { + root: 'membership', + models: { + membership: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + userId: '', + userName: '', + userEmail: '', + userPhone: '', + teamId: '', + teamName: '', + invited: '', + joined: '', + confirm: false, + mfa: false, + userAccessedAt: '', + roles: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1185,7 +1432,7 @@ export class Teams extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -1194,6 +1441,32 @@ export class Teams extends Service { }, apiPayload, ); + const defaults = { + root: 'membership', + models: { + membership: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + userId: '', + userName: '', + userEmail: '', + userPhone: '', + teamId: '', + teamName: '', + invited: '', + joined: '', + confirm: false, + mfa: false, + userAccessedAt: '', + roles: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1283,7 +1556,7 @@ export class Teams extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'patch', uri, { @@ -1293,6 +1566,32 @@ export class Teams extends Service { }, apiPayload, ); + const defaults = { + root: 'membership', + models: { + membership: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + userId: '', + userName: '', + userEmail: '', + userPhone: '', + teamId: '', + teamName: '', + invited: '', + joined: '', + confirm: false, + mfa: false, + userAccessedAt: '', + roles: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1490,7 +1789,7 @@ export class Teams extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'patch', uri, { @@ -1500,6 +1799,32 @@ export class Teams extends Service { }, apiPayload, ); + const defaults = { + root: 'membership', + models: { + membership: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + userId: '', + userName: '', + userEmail: '', + userPhone: '', + teamId: '', + teamName: '', + invited: '', + joined: '', + confirm: false, + mfa: false, + userAccessedAt: '', + roles: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** diff --git a/src/services/vectors-db.ts b/src/services/vectors-db.ts index 710e8b44..1329e910 100644 --- a/src/services/vectors-db.ts +++ b/src/services/vectors-db.ts @@ -1,5 +1,5 @@ import { Service } from '../service'; -import { AppwriteException, Client } from '../client'; +import { AppwriteException, Client, applyDefaults } from '../client'; import type { Models } from '../models'; import type { Payload } from '../client'; @@ -71,7 +71,7 @@ export class VectorsDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -80,6 +80,33 @@ export class VectorsDB extends Service { }, apiPayload, ); + const defaults = { + root: 'transactionList', + models: { + transactionList: { + defaults: { + total: 0, + }, + properties: { + transactions: { + items: 'transaction', + }, + }, + }, + transaction: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + status: 'pending', + operations: 0, + expiresAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -127,7 +154,7 @@ export class VectorsDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -137,6 +164,23 @@ export class VectorsDB extends Service { }, apiPayload, ); + const defaults = { + root: 'transaction', + models: { + transaction: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + status: 'pending', + operations: 0, + expiresAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -190,7 +234,7 @@ export class VectorsDB extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -199,6 +243,23 @@ export class VectorsDB extends Service { }, apiPayload, ); + const defaults = { + root: 'transaction', + models: { + transaction: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + status: 'pending', + operations: 0, + expiresAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -285,7 +346,7 @@ export class VectorsDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'patch', uri, { @@ -295,6 +356,23 @@ export class VectorsDB extends Service { }, apiPayload, ); + const defaults = { + root: 'transaction', + models: { + transaction: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + status: 'pending', + operations: 0, + expiresAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -427,7 +505,7 @@ export class VectorsDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -437,6 +515,23 @@ export class VectorsDB extends Service { }, apiPayload, ); + const defaults = { + root: 'transaction', + models: { + transaction: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + status: 'pending', + operations: 0, + expiresAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -573,7 +668,7 @@ export class VectorsDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -582,6 +677,33 @@ export class VectorsDB extends Service { }, apiPayload, ); + const defaults = { + root: 'documentList', + models: { + documentList: { + defaults: { + total: 0, + }, + properties: { + documents: { + items: 'document', + }, + }, + }, + document: { + defaults: { + $id: '', + $sequence: '', + $collectionId: '', + $databaseId: '', + $createdAt: '', + $updatedAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -753,7 +875,7 @@ export class VectorsDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -763,6 +885,23 @@ export class VectorsDB extends Service { }, apiPayload, ); + const defaults = { + root: 'document', + models: { + document: { + defaults: { + $id: '', + $sequence: '', + $collectionId: '', + $databaseId: '', + $createdAt: '', + $updatedAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -901,7 +1040,7 @@ export class VectorsDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -911,6 +1050,33 @@ export class VectorsDB extends Service { }, apiPayload, ); + const defaults = { + root: 'documentList', + models: { + documentList: { + defaults: { + total: 0, + }, + properties: { + documents: { + items: 'document', + }, + }, + }, + document: { + defaults: { + $id: '', + $sequence: '', + $collectionId: '', + $databaseId: '', + $createdAt: '', + $updatedAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1040,7 +1206,7 @@ export class VectorsDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -1049,6 +1215,23 @@ export class VectorsDB extends Service { }, apiPayload, ); + const defaults = { + root: 'document', + models: { + document: { + defaults: { + $id: '', + $sequence: '', + $collectionId: '', + $databaseId: '', + $createdAt: '', + $updatedAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1218,7 +1401,7 @@ export class VectorsDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'put', uri, { @@ -1228,6 +1411,23 @@ export class VectorsDB extends Service { }, apiPayload, ); + const defaults = { + root: 'document', + models: { + document: { + defaults: { + $id: '', + $sequence: '', + $collectionId: '', + $databaseId: '', + $createdAt: '', + $updatedAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1397,7 +1597,7 @@ export class VectorsDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'patch', uri, { @@ -1407,6 +1607,23 @@ export class VectorsDB extends Service { }, apiPayload, ); + const defaults = { + root: 'document', + models: { + document: { + defaults: { + $id: '', + $sequence: '', + $collectionId: '', + $databaseId: '', + $createdAt: '', + $updatedAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** From 1ce30d6afc35325418c8ecfe159cc7558d0b71d2 Mon Sep 17 00:00:00 2001 From: Chirag Aggarwal Date: Mon, 12 Oct 2026 17:26:27 +0100 Subject: [PATCH 2/6] revert: undo the superseded SDK update on dev --- CHANGELOG.md | 56 +- README.md | 4 +- .../account/create-o-auth-2-session.md | 1 - .../examples/account/create-o-auth-2-token.md | 1 - docs/examples/account/create-passkey-token.md | 13 - docs/examples/account/create-passkey.md | 16 - docs/examples/account/delete-passkey.md | 15 - docs/examples/account/get-passkey.md | 15 - docs/examples/account/list-passkeys.md | 16 - docs/examples/account/update-passkey-token.md | 16 - .../account/update-passkey-verification.md | 16 - docs/examples/account/update-passkey.md | 16 - docs/examples/analytics/create-event.md | 27 - docs/examples/oauth2/authorize-post.md | 2 +- docs/examples/oauth2/authorize.md | 2 +- .../oauth2/create-device-authorization.md | 2 +- docs/examples/oauth2/create-par.md | 2 +- docs/examples/oauth2/create-token.md | 2 +- docs/examples/teams/create-membership.md | 1 - package-lock.json | 4 +- package.json | 2 +- src/client.ts | 48 +- src/index.ts | 1 - src/models.ts | 96 - src/services/account.ts | 2396 +---------------- src/services/analytics.ts | 260 -- src/services/apps.ts | 561 +--- src/services/avatars.ts | 2 +- src/services/databases.ts | 250 +- src/services/documents-db.ts | 279 +- src/services/functions.ts | 132 +- src/services/locale.ts | 204 +- src/services/messaging.ts | 23 +- src/services/oauth-2.ts | 302 +-- src/services/organization.ts | 100 +- src/services/presences.ts | 84 +- src/services/storage.ts | 99 +- src/services/tables-db.ts | 250 +- src/services/teams.ts | 365 +-- src/services/vectors-db.ts | 241 +- 40 files changed, 319 insertions(+), 5603 deletions(-) delete mode 100644 docs/examples/account/create-passkey-token.md delete mode 100644 docs/examples/account/create-passkey.md delete mode 100644 docs/examples/account/delete-passkey.md delete mode 100644 docs/examples/account/get-passkey.md delete mode 100644 docs/examples/account/list-passkeys.md delete mode 100644 docs/examples/account/update-passkey-token.md delete mode 100644 docs/examples/account/update-passkey-verification.md delete mode 100644 docs/examples/account/update-passkey.md delete mode 100644 docs/examples/analytics/create-event.md delete mode 100644 src/services/analytics.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index d78aef15..c6c7bcb3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,31 +1,49 @@ # Change log -## 2.0.0 +## 1.2.0-rc.4 -* Breaking: `Teams.createMembership` takes `membershipId` after `roles`; positional callers must update -* Added: `Account.listPasskeys`, `createPasskey`, `getPasskey`, `updatePasskey` and `deletePasskey` -* Added: `Account.updatePasskeyVerification` to finish registering a passkey -* Added: `Account.createPasskeyToken` and `Account.updatePasskeyToken` for passkey sign-in -* Added: `Passkey`, `PasskeyList`, `PasskeyChallenge` and `TokenSecret` models -* Added: `Push` service for MQTT realtime push with Android background delivery -* Added: `Topic` builder, `Client.setPushEndpoint()` and `Client.setPushClientId()` -* Added: background push notifications render the server `notification` title, body, and image -* Added: `getInitialNotification()`, `onNotificationOpened()` and the `PushNotificationOpened` type -* Added: `onOpen`/`onClose` events for live push connections -* Added: `Push.backgroundStatus()`, `requestExactAlarms()` and `requestIgnoreBatteryOptimizations()` for Android +* Fixed: `host()` resolves with the live connection state instead of always `null` +* Fixed: `onConnection(false)` fires when a retired or background connection closes +* Fixed: notification taps are recorded after launching the app, so tap-opened screens land on top +* Fixed: `host()` reports `false` when there was nothing to subscribe instead of a spurious open + +## 1.2.0-rc.3 + +* Added: `getInitialNotification()`, `onNotificationOpened()`, and the `PushNotificationOpened` type (topic + data) +* Added: live push connection open/close events surfaced via `onOpen`/`onClose` +* Fixed: notification taps delivered reliably once, via a `PushTaps` queue +* Fixed: foreground notifications de-duplicated per title +* Updated: `resume` leaves a live Push host's connection untouched + +## 1.2.0-rc.2 + +* Added: `Push.getInitialNotification()` returns the notification whose tap launched the app +* Added: `Push.onNotificationOpened(callback)` fires on each notification tap +* Added: `Push.backgroundStatus()` reports Android exact-alarm, battery, and foreground-service state +* Added: `Push.requestExactAlarms()` and `Push.requestIgnoreBatteryOptimizations()` helpers * Added: `SubscribeOptions.notifyInForeground` to post notifications while the app is visible -* Added: the SDK requests Android 13+ `POST_NOTIFICATIONS` on first background subscribe -* Added: `Analytics` service with `createEvent` +* Added: `PushBackgroundStatus` and `PushNotificationOpened` exported types +* Fixed: reliable Android background wake-ups via a periodic watchdog and alternating jobs +* Fixed: `resume` keeps subscriptions only for the same signed-in user +* Fixed: notification images are size-capped to prevent out-of-memory crashes + +## 1.2.0-rc.1 + +* Added: background push notifications render the server `notification` title, body, and image +* Added: Android shows notification images (BigPictureStyle) and long bodies (BigTextStyle) +* Added: the SDK requests Android 13+ `POST_NOTIFICATIONS` itself on first background subscribe +* Added: notification `data` now carries `topic` and `payload` +* Fixed: a server-sent title dedupes to one notification per topic instead of one per subscription + +## 1.2.0-rc.0 + * Added: `Apps` service to manage OAuth2 apps, keys, secrets, and installations * Added: `Oauth2` service for authorization, consent, device, PAR, and token flows +* Added: `Push` service for MQTT realtime push with Android background delivery +* Added: `Topic` builder and native TCP modules for push * Added: `Avatars.updatePhoto()` and `Avatars.deletePhoto()` methods * Added: `App`, `Oauth2*`, and `Account` models -* Added: `state` parameter to `Account.createOAuth2Session` and `Account.createOAuth2Token` -* Added: `duration` on `createEmailPasswordSession` and `current` on `deleteSessions` -* Added: `total` parameter to `Account.listSessions`, `Locale` list methods and `listTransactions` * Added: `Webflow` to the `OAuthProvider` enum -* Fixed: response models fill missing fields from spec defaults instead of throwing -* Updated: SDK now targets Appwrite 2.4 (`X-Appwrite-Response-Format: 2.4.0`) * Fixed: cookie session fallback is guarded to Expo web where `localStorage` exists ## 1.1.0 diff --git a/README.md b/README.md index ba02d900..0ba50f82 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,12 @@ # Appwrite React Native SDK ![License](https://img.shields.io/github/license/appwrite/sdk-for-react-native.svg?style=flat-square) -![Version](https://img.shields.io/badge/api%20version-2.4.0-blue.svg?style=flat-square) +![Version](https://img.shields.io/badge/api%20version-2.3.0-blue.svg?style=flat-square) [![Build Status](https://img.shields.io/travis/com/appwrite/sdk-generator?style=flat-square)](https://travis-ci.com/appwrite/sdk-generator) [![Twitter Account](https://img.shields.io/twitter/follow/appwrite?color=00acee&label=twitter&style=flat-square)](https://twitter.com/appwrite) [![Discord](https://img.shields.io/discord/564160730845151244?label=discord&style=flat-square)](https://appwrite.io/discord) -**This SDK targets Appwrite server version 2.4.x as shipped on Appwrite Cloud.** Self-hosted releases can lag behind Cloud — if you run an older self-hosted build, use a matching older SDK from [previous releases](https://github.com/appwrite/sdk-for-react-native/releases) when APIs differ. +**This SDK targets Appwrite server version 2.3.x as shipped on Appwrite Cloud.** Self-hosted releases can lag behind Cloud — if you run an older self-hosted build, use a matching older SDK from [previous releases](https://github.com/appwrite/sdk-for-react-native/releases) when APIs differ. Appwrite is an open-source backend as a service server that abstracts and simplifies complex and repetitive development tasks behind a very simple to use REST API. Appwrite aims to help you develop your apps faster and in a more secure way. Use the React Native SDK to integrate your app with the Appwrite server to easily start interacting with all of Appwrite backend APIs and tools. For full API documentation and tutorials go to [https://appwrite.io/docs](https://appwrite.io/docs) diff --git a/docs/examples/account/create-o-auth-2-session.md b/docs/examples/account/create-o-auth-2-session.md index 48c50d96..c90edc14 100644 --- a/docs/examples/account/create-o-auth-2-session.md +++ b/docs/examples/account/create-o-auth-2-session.md @@ -12,6 +12,5 @@ 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 da5ee9c8..c043fb78 100644 --- a/docs/examples/account/create-o-auth-2-token.md +++ b/docs/examples/account/create-o-auth-2-token.md @@ -12,6 +12,5 @@ account.createOAuth2Token({ success: 'https://example.com', // optional failure: 'https://example.com', // optional scopes: [], // optional - state: '', // optional }); ``` diff --git a/docs/examples/account/create-passkey-token.md b/docs/examples/account/create-passkey-token.md deleted file mode 100644 index 5695859f..00000000 --- a/docs/examples/account/create-passkey-token.md +++ /dev/null @@ -1,13 +0,0 @@ -```javascript -import { Client, Account } from 'react-native-appwrite'; - -const client = new Client() - .setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint - .setProject(''); // Your project ID - -const account = new Account(client); - -const result = await account.createPasskeyToken(); - -console.log(result); -``` diff --git a/docs/examples/account/create-passkey.md b/docs/examples/account/create-passkey.md deleted file mode 100644 index 66968b14..00000000 --- a/docs/examples/account/create-passkey.md +++ /dev/null @@ -1,16 +0,0 @@ -```javascript -import { Client, Account } from 'react-native-appwrite'; - -const client = new Client() - .setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint - .setProject(''); // Your project ID - -const account = new Account(client); - -const result = await account.createPasskey({ - passkeyId: '', // optional - name: '', // optional -}); - -console.log(result); -``` diff --git a/docs/examples/account/delete-passkey.md b/docs/examples/account/delete-passkey.md deleted file mode 100644 index 61aec153..00000000 --- a/docs/examples/account/delete-passkey.md +++ /dev/null @@ -1,15 +0,0 @@ -```javascript -import { Client, Account } from 'react-native-appwrite'; - -const client = new Client() - .setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint - .setProject(''); // Your project ID - -const account = new Account(client); - -const result = await account.deletePasskey({ - passkeyId: '', -}); - -console.log(result); -``` diff --git a/docs/examples/account/get-passkey.md b/docs/examples/account/get-passkey.md deleted file mode 100644 index 04b7f8fb..00000000 --- a/docs/examples/account/get-passkey.md +++ /dev/null @@ -1,15 +0,0 @@ -```javascript -import { Client, Account } from 'react-native-appwrite'; - -const client = new Client() - .setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint - .setProject(''); // Your project ID - -const account = new Account(client); - -const result = await account.getPasskey({ - passkeyId: '', -}); - -console.log(result); -``` diff --git a/docs/examples/account/list-passkeys.md b/docs/examples/account/list-passkeys.md deleted file mode 100644 index f1f68985..00000000 --- a/docs/examples/account/list-passkeys.md +++ /dev/null @@ -1,16 +0,0 @@ -```javascript -import { Client, Account } from 'react-native-appwrite'; - -const client = new Client() - .setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint - .setProject(''); // Your project ID - -const account = new Account(client); - -const result = await account.listPasskeys({ - queries: [], // optional - total: false, // optional -}); - -console.log(result); -``` diff --git a/docs/examples/account/update-passkey-token.md b/docs/examples/account/update-passkey-token.md deleted file mode 100644 index a8e22f7a..00000000 --- a/docs/examples/account/update-passkey-token.md +++ /dev/null @@ -1,16 +0,0 @@ -```javascript -import { Client, Account } from 'react-native-appwrite'; - -const client = new Client() - .setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint - .setProject(''); // Your project ID - -const account = new Account(client); - -const result = await account.updatePasskeyToken({ - challengeId: '', - credential: {}, -}); - -console.log(result); -``` diff --git a/docs/examples/account/update-passkey-verification.md b/docs/examples/account/update-passkey-verification.md deleted file mode 100644 index c46c0a63..00000000 --- a/docs/examples/account/update-passkey-verification.md +++ /dev/null @@ -1,16 +0,0 @@ -```javascript -import { Client, Account } from 'react-native-appwrite'; - -const client = new Client() - .setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint - .setProject(''); // Your project ID - -const account = new Account(client); - -const result = await account.updatePasskeyVerification({ - passkeyId: '', - credential: {}, -}); - -console.log(result); -``` diff --git a/docs/examples/account/update-passkey.md b/docs/examples/account/update-passkey.md deleted file mode 100644 index 2f925b98..00000000 --- a/docs/examples/account/update-passkey.md +++ /dev/null @@ -1,16 +0,0 @@ -```javascript -import { Client, Account } from 'react-native-appwrite'; - -const client = new Client() - .setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint - .setProject(''); // Your project ID - -const account = new Account(client); - -const result = await account.updatePasskey({ - passkeyId: '', - name: '', -}); - -console.log(result); -``` diff --git a/docs/examples/analytics/create-event.md b/docs/examples/analytics/create-event.md deleted file mode 100644 index eefca061..00000000 --- a/docs/examples/analytics/create-event.md +++ /dev/null @@ -1,27 +0,0 @@ -```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/oauth2/authorize-post.md b/docs/examples/oauth2/authorize-post.md index f7dd540c..e27aa7e3 100644 --- a/docs/examples/oauth2/authorize-post.md +++ b/docs/examples/oauth2/authorize-post.md @@ -19,7 +19,7 @@ const result = await oauth2.authorizePost({ prompt: '', // optional maxAge: 0, // optional authorizationDetails: '', // optional - resource: [], // optional + resource: '', // optional audience: '', // optional requestUri: '', // optional }); diff --git a/docs/examples/oauth2/authorize.md b/docs/examples/oauth2/authorize.md index 256e9cb6..039dc744 100644 --- a/docs/examples/oauth2/authorize.md +++ b/docs/examples/oauth2/authorize.md @@ -19,7 +19,7 @@ const result = await oauth2.authorize({ prompt: '', // optional maxAge: 0, // optional authorizationDetails: '', // optional - resource: [], // optional + resource: '', // optional audience: '', // optional requestUri: '', // optional }); diff --git a/docs/examples/oauth2/create-device-authorization.md b/docs/examples/oauth2/create-device-authorization.md index 1219db51..c136011b 100644 --- a/docs/examples/oauth2/create-device-authorization.md +++ b/docs/examples/oauth2/create-device-authorization.md @@ -11,7 +11,7 @@ const result = await oauth2.createDeviceAuthorization({ clientId: '', // optional scope: '', // optional authorizationDetails: '', // optional - resource: [], // optional + resource: '', // optional audience: '', // optional }); diff --git a/docs/examples/oauth2/create-par.md b/docs/examples/oauth2/create-par.md index 425e7a86..5d9b5783 100644 --- a/docs/examples/oauth2/create-par.md +++ b/docs/examples/oauth2/create-par.md @@ -19,7 +19,7 @@ const result = await oauth2.createPAR({ prompt: '', // optional maxAge: 0, // optional authorizationDetails: '', // optional - resource: [], // optional + resource: '', // optional audience: '', // optional }); diff --git a/docs/examples/oauth2/create-token.md b/docs/examples/oauth2/create-token.md index 567bfb74..3be9ff4a 100644 --- a/docs/examples/oauth2/create-token.md +++ b/docs/examples/oauth2/create-token.md @@ -16,7 +16,7 @@ const result = await oauth2.createToken({ clientSecret: '', // optional codeVerifier: '', // optional redirectUri: 'https://example.com', // optional - resource: [], // optional + resource: '', // optional audience: '', // optional }); diff --git a/docs/examples/teams/create-membership.md b/docs/examples/teams/create-membership.md index e2d206e7..3c6ee849 100644 --- a/docs/examples/teams/create-membership.md +++ b/docs/examples/teams/create-membership.md @@ -10,7 +10,6 @@ const teams = new Teams(client); const result = await teams.createMembership({ teamId: '', roles: ['editor'], - membershipId: '', // optional email: 'email@example.com', // optional userId: '', // optional phone: '+12065550100', // optional diff --git a/package-lock.json b/package-lock.json index bbf4775e..33230e5f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "react-native-appwrite", - "version": "2.0.0", + "version": "1.2.0-rc.4", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "react-native-appwrite", - "version": "2.0.0", + "version": "1.2.0-rc.4", "license": "BSD-3-Clause", "dependencies": { "buffer": "6.0.3", diff --git a/package.json b/package.json index b36e9cfc..12b4f76a 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": "2.0.0", + "version": "1.2.0-rc.4", "license": "BSD-3-Clause", "main": "dist/cjs/sdk.js", "exports": { diff --git a/src/client.ts b/src/client.ts index 2fa4bf31..4bc8575c 100644 --- a/src/client.ts +++ b/src/client.ts @@ -45,50 +45,6 @@ export const JSONbig = { stringify: JSONbigSerializer.stringify, }; -type DefaultsShape = string | { items: DefaultsShape }; - -type DefaultsModel = { - defaults?: Record; - properties?: Record; -}; - -type Defaults = { - root: DefaultsShape; - models: Record; -}; - -export function applyDefaults(value: T, tree: Defaults): T { - return fillDefaults(value, tree.root, tree.models) as T; -} - -function fillDefaults( - value: unknown, - shape: DefaultsShape, - models: Record, -): unknown { - if (typeof shape !== 'string') { - if (!Array.isArray(value)) { - return value; - } - const items = shape.items; - return value.map((item) => fillDefaults(item, items, models)); - } - const model = models[shape]; - if (!model || typeof value !== 'object' || value === null) { - return value; - } - if (Array.isArray(value)) { - return value; - } - const result: Record = { ...model.defaults, ...value }; - for (const [key, child] of Object.entries(model.properties ?? {})) { - if (key in result) { - result[key] = fillDefaults(result[key], child, models); - } - } - return result; -} - type Payload = { [key: string]: any; }; @@ -262,8 +218,8 @@ class Client { 'x-sdk-name': 'React Native', 'x-sdk-platform': 'client', 'x-sdk-language': 'reactnative', - 'x-sdk-version': '2.0.0', - 'X-Appwrite-Response-Format': '2.4.0', + 'x-sdk-version': '1.2.0-rc.4', + 'X-Appwrite-Response-Format': '2.3.0', }; /** diff --git a/src/index.ts b/src/index.ts index a5b728ec..579ed73a 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,6 +1,5 @@ export { Client, AppwriteException } from './client'; export { Account } from './services/account'; -export { Analytics } from './services/analytics'; export { Apps } from './services/apps'; export { Avatars } from './services/avatars'; export { Databases } from './services/databases'; diff --git a/src/models.ts b/src/models.ts index f11c898e..09b8b39c 100644 --- a/src/models.ts +++ b/src/models.ts @@ -1381,102 +1381,6 @@ export namespace Models { expire: string; }; - /** - * Token Secret - */ - export type TokenSecret = { - /** - * Token ID. - */ - $id: string; - /** - * Token creation date in ISO 8601 format. - */ - $createdAt: string; - /** - * User ID. - */ - userId: string; - /** - * Token secret key. Exchange it for a session with the create session endpoint. - */ - secret: string; - /** - * Token expiration date in ISO 8601 format. - */ - expire: string; - /** - * Security phrase of a token. Empty if security phrase was not requested when creating a token. It includes randomly generated phrase which is also sent in the external resource such as email. - */ - phrase: string; - }; - - /** - * Passkey - */ - export type Passkey = { - /** - * Passkey ID. - */ - $id: string; - /** - * Passkey creation date in ISO 8601 format. - */ - $createdAt: string; - /** - * Passkey update date in ISO 8601 format. - */ - $updatedAt: string; - /** - * Passkey name. - */ - name: string; - /** - * Most recent sign-in with this passkey in ISO 8601 format. Empty until the passkey is used to sign in. - */ - accessedAt: string; - }; - - /** - * Passkey Challenge - */ - export type PasskeyChallenge = { - /** - * Challenge ID. When signing in, pass it back with the credential to receive a token. - */ - $id: string; - /** - * Challenge creation date in ISO 8601 format. - */ - $createdAt: string; - /** - * ID of the passkey being registered. Empty for sign-in challenges. - */ - passkeyId: string; - /** - * Challenge expiration date in ISO 8601 format. - */ - expire: string; - /** - * WebAuthn options in JSON form. Pass them to `PublicKeyCredential.parseCreationOptionsFromJSON()` when registering, or `PublicKeyCredential.parseRequestOptionsFromJSON()` when signing in. - */ - publicKey: object; - }; - - /** - * Passkeys List - */ - export type PasskeyList = { - /** - * Total number of passkeys that matched your query. - */ - total: number; - /** - * List of passkeys. - */ - passkeys: Passkey[]; - }; - /** * MFA Recovery Codes */ diff --git a/src/services/account.ts b/src/services/account.ts index 60361c99..fb3d545b 100644 --- a/src/services/account.ts +++ b/src/services/account.ts @@ -1,5 +1,5 @@ import { Service } from '../service'; -import { AppwriteException, Client, applyDefaults } from '../client'; +import { AppwriteException, Client } from '../client'; import type { Models } from '../models'; import type { Payload } from '../client'; @@ -25,7 +25,7 @@ export class Account extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'get', uri, { @@ -34,48 +34,6 @@ export class Account extends Service { }, apiPayload, ); - const defaults = { - root: 'user', - models: { - user: { - defaults: { - $id: '', - $createdAt: '', - $updatedAt: '', - name: '', - registration: '', - status: true, - labels: [], - passwordUpdate: '', - email: '', - phone: '', - emailVerification: false, - phoneVerification: false, - mfa: false, - accessedAt: '', - }, - properties: { - targets: { - items: 'target', - }, - }, - }, - target: { - defaults: { - $id: '', - $createdAt: '', - $updatedAt: '', - name: '', - userId: '', - providerType: '', - identifier: '', - expired: false, - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** @@ -185,7 +143,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'post', uri, { @@ -195,48 +153,6 @@ export class Account extends Service { }, apiPayload, ); - const defaults = { - root: 'user', - models: { - user: { - defaults: { - $id: '', - $createdAt: '', - $updatedAt: '', - name: '', - registration: '', - status: true, - labels: [], - passwordUpdate: '', - email: '', - phone: '', - emailVerification: false, - phoneVerification: false, - mfa: false, - accessedAt: '', - }, - properties: { - targets: { - items: 'target', - }, - }, - }, - target: { - defaults: { - $id: '', - $createdAt: '', - $updatedAt: '', - name: '', - userId: '', - providerType: '', - identifier: '', - expired: false, - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** @@ -302,7 +218,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'get', uri, { @@ -311,37 +227,6 @@ export class Account extends Service { }, apiPayload, ); - const defaults = { - root: 'oauth2ConsentList', - models: { - oauth2ConsentList: { - defaults: { - total: 0, - }, - properties: { - consents: { - items: 'oauth2Consent', - }, - }, - }, - oauth2Consent: { - defaults: { - $id: '', - $createdAt: '', - $updatedAt: '', - userId: '', - appId: '', - cimdUrl: '', - scopes: [], - resources: [], - authorizationDetails: '[]', - expire: '', - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** @@ -393,7 +278,7 @@ export class Account extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'get', uri, { @@ -402,27 +287,6 @@ export class Account extends Service { }, apiPayload, ); - const defaults = { - root: 'oauth2Consent', - models: { - oauth2Consent: { - defaults: { - $id: '', - $createdAt: '', - $updatedAt: '', - userId: '', - appId: '', - cimdUrl: '', - scopes: [], - resources: [], - authorizationDetails: '[]', - expire: '', - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** @@ -563,7 +427,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'get', uri, { @@ -572,38 +436,6 @@ export class Account extends Service { }, apiPayload, ); - const defaults = { - root: 'oauth2ConsentTokenList', - models: { - oauth2ConsentTokenList: { - defaults: { - total: 0, - }, - properties: { - tokens: { - items: 'oauth2ConsentToken', - }, - }, - }, - oauth2ConsentToken: { - defaults: { - $id: '', - $createdAt: '', - $updatedAt: '', - consentId: '', - userId: '', - appId: '', - cimdUrl: '', - scopes: [], - resources: [], - authorizationDetails: '[]', - expire: '', - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** @@ -674,7 +506,7 @@ export class Account extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'get', uri, { @@ -683,28 +515,6 @@ export class Account extends Service { }, apiPayload, ); - const defaults = { - root: 'oauth2ConsentToken', - models: { - oauth2ConsentToken: { - defaults: { - $id: '', - $createdAt: '', - $updatedAt: '', - consentId: '', - userId: '', - appId: '', - cimdUrl: '', - scopes: [], - resources: [], - authorizationDetails: '[]', - expire: '', - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** @@ -863,7 +673,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'patch', uri, { @@ -873,48 +683,6 @@ export class Account extends Service { }, apiPayload, ); - const defaults = { - root: 'user', - models: { - user: { - defaults: { - $id: '', - $createdAt: '', - $updatedAt: '', - name: '', - registration: '', - status: true, - labels: [], - passwordUpdate: '', - email: '', - phone: '', - emailVerification: false, - phoneVerification: false, - mfa: false, - accessedAt: '', - }, - properties: { - targets: { - items: 'target', - }, - }, - }, - target: { - defaults: { - $id: '', - $createdAt: '', - $updatedAt: '', - name: '', - userId: '', - providerType: '', - identifier: '', - expired: false, - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** @@ -980,7 +748,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'get', uri, { @@ -989,38 +757,6 @@ export class Account extends Service { }, apiPayload, ); - const defaults = { - root: 'identityList', - models: { - identityList: { - defaults: { - total: 0, - }, - properties: { - identities: { - items: 'identity', - }, - }, - }, - identity: { - defaults: { - $id: '', - $createdAt: '', - $updatedAt: '', - userId: '', - provider: '', - providerUid: '', - providerEmail: '', - providerAccessToken: '', - providerAccessTokenExpiry: '', - providerRefreshToken: '', - providerIdToken: '', - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1129,7 +865,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'post', uri, { @@ -1139,18 +875,6 @@ export class Account extends Service { }, apiPayload, ); - const defaults = { - root: 'jwt', - models: { - jwt: { - defaults: { - jwt: '', - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1207,7 +931,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'patch', uri, { @@ -1217,48 +941,6 @@ export class Account extends Service { }, apiPayload, ); - const defaults = { - root: 'user', - models: { - user: { - defaults: { - $id: '', - $createdAt: '', - $updatedAt: '', - name: '', - registration: '', - status: true, - labels: [], - passwordUpdate: '', - email: '', - phone: '', - emailVerification: false, - phoneVerification: false, - mfa: false, - accessedAt: '', - }, - properties: { - targets: { - items: 'target', - }, - }, - }, - target: { - defaults: { - $id: '', - $createdAt: '', - $updatedAt: '', - name: '', - userId: '', - providerType: '', - identifier: '', - expired: false, - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1312,7 +994,7 @@ export class Account extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'post', uri, { @@ -1322,19 +1004,6 @@ export class Account extends Service { }, apiPayload, ); - const defaults = { - root: 'mfaType', - models: { - mfaType: { - defaults: { - secret: '', - uri: '', - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1387,7 +1056,7 @@ export class Account extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'post', uri, { @@ -1397,19 +1066,6 @@ export class Account extends Service { }, apiPayload, ); - const defaults = { - root: 'mfaType', - models: { - mfaType: { - defaults: { - secret: '', - uri: '', - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1487,7 +1143,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'put', uri, { @@ -1497,48 +1153,6 @@ export class Account extends Service { }, apiPayload, ); - const defaults = { - root: 'user', - models: { - user: { - defaults: { - $id: '', - $createdAt: '', - $updatedAt: '', - name: '', - registration: '', - status: true, - labels: [], - passwordUpdate: '', - email: '', - phone: '', - emailVerification: false, - phoneVerification: false, - mfa: false, - accessedAt: '', - }, - properties: { - targets: { - items: 'target', - }, - }, - }, - target: { - defaults: { - $id: '', - $createdAt: '', - $updatedAt: '', - name: '', - userId: '', - providerType: '', - identifier: '', - expired: false, - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1615,7 +1229,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'put', uri, { @@ -1625,48 +1239,6 @@ export class Account extends Service { }, apiPayload, ); - const defaults = { - root: 'user', - models: { - user: { - defaults: { - $id: '', - $createdAt: '', - $updatedAt: '', - name: '', - registration: '', - status: true, - labels: [], - passwordUpdate: '', - email: '', - phone: '', - emailVerification: false, - phoneVerification: false, - mfa: false, - accessedAt: '', - }, - properties: { - targets: { - items: 'target', - }, - }, - }, - target: { - defaults: { - $id: '', - $createdAt: '', - $updatedAt: '', - name: '', - userId: '', - providerType: '', - identifier: '', - expired: false, - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1844,7 +1416,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'post', uri, { @@ -1854,21 +1426,6 @@ export class Account extends Service { }, apiPayload, ); - const defaults = { - root: 'mfaChallenge', - models: { - mfaChallenge: { - defaults: { - $id: '', - $createdAt: '', - userId: '', - expire: '', - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1924,7 +1481,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'post', uri, { @@ -1934,21 +1491,6 @@ export class Account extends Service { }, apiPayload, ); - const defaults = { - root: 'mfaChallenge', - models: { - mfaChallenge: { - defaults: { - $id: '', - $createdAt: '', - userId: '', - expire: '', - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** @@ -2024,7 +1566,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'put', uri, { @@ -2034,46 +1576,6 @@ export class Account extends Service { }, apiPayload, ); - const defaults = { - root: 'session', - models: { - session: { - defaults: { - $id: '', - $createdAt: '', - $updatedAt: '', - userId: '', - expire: '', - provider: '', - providerUid: '', - providerAccessToken: '', - providerAccessTokenExpiry: '', - providerRefreshToken: '', - ip: '', - osCode: '', - osName: '', - osVersion: '', - clientType: '', - clientCode: '', - clientName: '', - clientVersion: '', - clientEngine: '', - clientEngineVersion: '', - deviceName: '', - deviceBrand: '', - deviceModel: '', - countryCode: '', - countryName: '', - current: false, - factors: [], - secret: '', - mfaUpdatedAt: '', - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** @@ -2148,7 +1650,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'put', uri, { @@ -2158,46 +1660,6 @@ export class Account extends Service { }, apiPayload, ); - const defaults = { - root: 'session', - models: { - session: { - defaults: { - $id: '', - $createdAt: '', - $updatedAt: '', - userId: '', - expire: '', - provider: '', - providerUid: '', - providerAccessToken: '', - providerAccessTokenExpiry: '', - providerRefreshToken: '', - ip: '', - osCode: '', - osName: '', - osVersion: '', - clientType: '', - clientCode: '', - clientName: '', - clientVersion: '', - clientEngine: '', - clientEngineVersion: '', - deviceName: '', - deviceBrand: '', - deviceModel: '', - countryCode: '', - countryName: '', - current: false, - factors: [], - secret: '', - mfaUpdatedAt: '', - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** @@ -2212,7 +1674,7 @@ export class Account extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'get', uri, { @@ -2221,22 +1683,6 @@ export class Account extends Service { }, apiPayload, ); - const defaults = { - root: 'mfaFactors', - models: { - mfaFactors: { - defaults: { - totp: false, - phone: false, - email: false, - recoveryCode: false, - custom: false, - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** @@ -2250,7 +1696,7 @@ export class Account extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'get', uri, { @@ -2259,22 +1705,6 @@ export class Account extends Service { }, apiPayload, ); - const defaults = { - root: 'mfaFactors', - models: { - mfaFactors: { - defaults: { - totp: false, - phone: false, - email: false, - recoveryCode: false, - custom: false, - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** @@ -2289,7 +1719,7 @@ export class Account extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'get', uri, { @@ -2298,18 +1728,6 @@ export class Account extends Service { }, apiPayload, ); - const defaults = { - root: 'mfaRecoveryCodes', - models: { - mfaRecoveryCodes: { - defaults: { - recoveryCodes: [], - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** @@ -2323,7 +1741,7 @@ export class Account extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'get', uri, { @@ -2332,18 +1750,6 @@ export class Account extends Service { }, apiPayload, ); - const defaults = { - root: 'mfaRecoveryCodes', - models: { - mfaRecoveryCodes: { - defaults: { - recoveryCodes: [], - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** @@ -2358,7 +1764,7 @@ export class Account extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'post', uri, { @@ -2368,18 +1774,6 @@ export class Account extends Service { }, apiPayload, ); - const defaults = { - root: 'mfaRecoveryCodes', - models: { - mfaRecoveryCodes: { - defaults: { - recoveryCodes: [], - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** @@ -2393,7 +1787,7 @@ export class Account extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'post', uri, { @@ -2403,18 +1797,6 @@ export class Account extends Service { }, apiPayload, ); - const defaults = { - root: 'mfaRecoveryCodes', - models: { - mfaRecoveryCodes: { - defaults: { - recoveryCodes: [], - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** @@ -2429,7 +1811,7 @@ export class Account extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'patch', uri, { @@ -2439,575 +1821,21 @@ export class Account extends Service { }, apiPayload, ); - const defaults = { - root: 'mfaRecoveryCodes', - models: { - mfaRecoveryCodes: { - defaults: { - recoveryCodes: [], - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** * Regenerate recovery codes that can be used as backup for MFA flow. Before regenerating codes, they must be first generated using [createMfaRecoveryCodes](/docs/references/cloud/client-web/account#createMfaRecoveryCodes) method. An OTP challenge is required to regenreate recovery codes. - * - * @throws {AppwriteException} - * @returns {Promise} - */ - updateMFARecoveryCodes(): Promise { - const apiPath = '/account/mfa/recovery-codes'; - const apiPayload: Payload = {}; - - const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( - 'patch', - uri, - { - 'X-Appwrite-Project': this.client.config.project, - 'content-type': 'application/json', - accept: 'application/json', - }, - apiPayload, - ); - const defaults = { - root: 'mfaRecoveryCodes', - models: { - mfaRecoveryCodes: { - defaults: { - recoveryCodes: [], - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); - } - - /** - * Update currently logged in user account name. - * - * @param {string} params.name - User name. Max length: 128 chars. - * @throws {AppwriteException} - * @returns {Promise} - */ - updateName< - Preferences extends Models.Preferences = Models.DefaultPreferences, - >(params: { name: string }): Promise>; - /** - * Update currently logged in user account name. - * - * @param {string} name - User name. Max length: 128 chars. - * @throws {AppwriteException} - * @returns {Promise>} - * @deprecated Use the object parameter style method for a better developer experience. - */ - updateName< - Preferences extends Models.Preferences = Models.DefaultPreferences, - >(name: string): Promise>; - updateName< - Preferences extends Models.Preferences = Models.DefaultPreferences, - >( - paramsOrFirst: { name: string } | string, - ): Promise> { - let params: { name: string }; - - if ( - paramsOrFirst && - typeof paramsOrFirst === 'object' && - !Array.isArray(paramsOrFirst) - ) { - params = (paramsOrFirst || {}) as { name: string }; - } else { - params = { - name: paramsOrFirst as string, - }; - } - - const name = params.name; - - if (typeof name === 'undefined') { - throw new AppwriteException('Missing required parameter: "name"'); - } - - const apiPath = '/account/name'; - const apiPayload: Payload = {}; - - if (typeof name !== 'undefined') { - apiPayload['name'] = name; - } - - const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( - 'patch', - uri, - { - 'X-Appwrite-Project': this.client.config.project, - 'content-type': 'application/json', - accept: 'application/json', - }, - apiPayload, - ); - const defaults = { - root: 'user', - models: { - user: { - defaults: { - $id: '', - $createdAt: '', - $updatedAt: '', - name: '', - registration: '', - status: true, - labels: [], - passwordUpdate: '', - email: '', - phone: '', - emailVerification: false, - phoneVerification: false, - mfa: false, - accessedAt: '', - }, - properties: { - targets: { - items: 'target', - }, - }, - }, - target: { - defaults: { - $id: '', - $createdAt: '', - $updatedAt: '', - name: '', - userId: '', - providerType: '', - identifier: '', - expired: false, - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); - } - - /** - * Get the list of verified passkeys registered by the currently logged in user. - * - * @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). Maximum of 100 queries are allowed, each 4096 characters long. You may filter and order on the following attributes: $id, $createdAt, $updatedAt, name, accessedAt - * @param {boolean} params.total - When set to false, the total count returned will be 0 and will not be calculated. - * @throws {AppwriteException} - * @returns {Promise} - */ - listPasskeys(params?: { - queries?: string[]; - total?: boolean; - }): Promise; - /** - * Get the list of verified passkeys registered by the currently logged in user. - * - * @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). Maximum of 100 queries are allowed, each 4096 characters long. You may filter and order on the following attributes: $id, $createdAt, $updatedAt, name, accessedAt - * @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. - */ - listPasskeys( - queries?: string[], - total?: boolean, - ): Promise; - listPasskeys( - paramsOrFirst?: { queries?: string[]; total?: boolean } | string[], - ...rest: [boolean?] - ): Promise { - let params: { queries?: string[]; total?: boolean }; - - if ( - (typeof paramsOrFirst === 'undefined' && rest.length === 0) || - (paramsOrFirst && - typeof paramsOrFirst === 'object' && - !Array.isArray(paramsOrFirst)) - ) { - 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 = '/account/passkeys'; - const apiPayload: Payload = {}; - - if (typeof queries !== 'undefined') { - apiPayload['queries'] = queries; - } - - if (typeof total !== 'undefined') { - apiPayload['total'] = total; - } - - const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( - 'get', - uri, - { - 'X-Appwrite-Project': this.client.config.project, - accept: 'application/json', - }, - apiPayload, - ); - const defaults = { - root: 'passkeyList', - models: { - passkeyList: { - defaults: { - total: 0, - }, - properties: { - passkeys: { - items: 'passkey', - }, - }, - }, - passkey: { - defaults: { - $id: '', - $createdAt: '', - $updatedAt: '', - name: '', - accessedAt: '', - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); - } - - /** - * Start registering a passkey for the currently logged in user. The session must have signed in or completed an MFA challenge within the last 10 minutes. Pass the returned `publicKey` options to `navigator.credentials.create()`, then complete the registration with [Update passkey verification](/docs/references/cloud/client-web/account#updatePasskeyVerification). The passkey stays pending until verified, and the challenge expires after 5 minutes. - * - * @param {string} params.passkeyId - Passkey 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. - * @param {string} params.name - Passkey name, shown when listing passkeys. Max length: 128 chars. - * @throws {AppwriteException} - * @returns {Promise} - */ - createPasskey(params?: { - passkeyId?: string; - name?: string; - }): Promise; - /** - * Start registering a passkey for the currently logged in user. The session must have signed in or completed an MFA challenge within the last 10 minutes. Pass the returned `publicKey` options to `navigator.credentials.create()`, then complete the registration with [Update passkey verification](/docs/references/cloud/client-web/account#updatePasskeyVerification). The passkey stays pending until verified, and the challenge expires after 5 minutes. - * - * @param {string} passkeyId - Passkey 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. - * @param {string} name - Passkey name, shown when listing passkeys. Max length: 128 chars. - * @throws {AppwriteException} - * @returns {Promise} - * @deprecated Use the object parameter style method for a better developer experience. - */ - createPasskey( - passkeyId?: string, - name?: string, - ): Promise; - createPasskey( - paramsOrFirst?: { passkeyId?: string; name?: string } | string, - ...rest: [string?] - ): Promise { - let params: { passkeyId?: string; name?: string }; - - if ( - (typeof paramsOrFirst === 'undefined' && rest.length === 0) || - (paramsOrFirst && - typeof paramsOrFirst === 'object' && - !Array.isArray(paramsOrFirst)) - ) { - params = (paramsOrFirst || {}) as { - passkeyId?: string; - name?: string; - }; - } else { - params = { - passkeyId: paramsOrFirst as string, - name: rest[0] as string, - }; - } - - const passkeyId = params.passkeyId; - const name = params.name; - - const apiPath = '/account/passkeys'; - const apiPayload: Payload = {}; - - if (typeof passkeyId !== 'undefined') { - apiPayload['passkeyId'] = passkeyId; - } - - if (typeof name !== 'undefined') { - apiPayload['name'] = name; - } - - const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( - 'post', - uri, - { - 'X-Appwrite-Project': this.client.config.project, - 'content-type': 'application/json', - accept: 'application/json', - }, - apiPayload, - ); - const defaults = { - root: 'passkeyChallenge', - models: { - passkeyChallenge: { - defaults: { - $id: '', - $createdAt: '', - passkeyId: '', - expire: '', - publicKey: [], - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); - } - - /** - * Get a verified passkey of the currently logged in user by its unique ID. - * - * @param {string} params.passkeyId - Passkey ID. - * @throws {AppwriteException} - * @returns {Promise} - */ - getPasskey(params: { passkeyId: string }): Promise; - /** - * Get a verified passkey of the currently logged in user by its unique ID. - * - * @param {string} passkeyId - Passkey ID. - * @throws {AppwriteException} - * @returns {Promise} - * @deprecated Use the object parameter style method for a better developer experience. - */ - getPasskey(passkeyId: string): Promise; - getPasskey( - paramsOrFirst: { passkeyId: string } | string, - ): Promise { - let params: { passkeyId: string }; - - if ( - paramsOrFirst && - typeof paramsOrFirst === 'object' && - !Array.isArray(paramsOrFirst) - ) { - params = (paramsOrFirst || {}) as { passkeyId: string }; - } else { - params = { - passkeyId: paramsOrFirst as string, - }; - } - - const passkeyId = params.passkeyId; - - if (typeof passkeyId === 'undefined' || passkeyId === '') { - throw new AppwriteException( - 'Missing required parameter: "passkeyId"', - ); - } - - const apiPath = '/account/passkeys/{passkeyId}'.replace( - '{passkeyId}', - encodeURIComponent(String(passkeyId)), - ); - const apiPayload: Payload = {}; - - const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( - 'get', - uri, - { - 'X-Appwrite-Project': this.client.config.project, - accept: 'application/json', - }, - apiPayload, - ); - const defaults = { - root: 'passkey', - models: { - passkey: { - defaults: { - $id: '', - $createdAt: '', - $updatedAt: '', - name: '', - accessedAt: '', - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); - } - - /** - * Rename a passkey of the currently logged in user. - * - * @param {string} params.passkeyId - Passkey ID. - * @param {string} params.name - Passkey name. Max length: 128 chars. - * @throws {AppwriteException} - * @returns {Promise} - */ - updatePasskey(params: { - passkeyId: string; - name: string; - }): Promise; - /** - * Rename a passkey of the currently logged in user. - * - * @param {string} passkeyId - Passkey ID. - * @param {string} name - Passkey name. Max length: 128 chars. - * @throws {AppwriteException} - * @returns {Promise} - * @deprecated Use the object parameter style method for a better developer experience. - */ - updatePasskey(passkeyId: string, name: string): Promise; - updatePasskey( - paramsOrFirst: { passkeyId: string; name: string } | string, - ...rest: [string?] - ): Promise { - let params: { passkeyId: string; name: string }; - - if ( - paramsOrFirst && - typeof paramsOrFirst === 'object' && - !Array.isArray(paramsOrFirst) - ) { - params = (paramsOrFirst || {}) as { - passkeyId: string; - name: string; - }; - } else { - params = { - passkeyId: paramsOrFirst as string, - name: rest[0] as string, - }; - } - - const passkeyId = params.passkeyId; - const name = params.name; - - if (typeof passkeyId === 'undefined' || passkeyId === '') { - throw new AppwriteException( - 'Missing required parameter: "passkeyId"', - ); - } - - if (typeof name === 'undefined') { - throw new AppwriteException('Missing required parameter: "name"'); - } - - const apiPath = '/account/passkeys/{passkeyId}'.replace( - '{passkeyId}', - encodeURIComponent(String(passkeyId)), - ); - const apiPayload: Payload = {}; - - if (typeof name !== 'undefined') { - apiPayload['name'] = name; - } - - const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( - 'patch', - uri, - { - 'X-Appwrite-Project': this.client.config.project, - 'content-type': 'application/json', - accept: 'application/json', - }, - apiPayload, - ); - const defaults = { - root: 'passkey', - models: { - passkey: { - defaults: { - $id: '', - $createdAt: '', - $updatedAt: '', - name: '', - accessedAt: '', - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); - } - - /** - * Delete a passkey from the currently logged in user. The passkey can no longer be used to sign in, although it may remain stored on the user's device. The session must have signed in or completed an MFA challenge within the last 10 minutes. - * - * @param {string} params.passkeyId - Passkey ID. - * @throws {AppwriteException} - * @returns {Promise} - */ - deletePasskey(params: { passkeyId: string }): Promise<{}>; - /** - * Delete a passkey from the currently logged in user. The passkey can no longer be used to sign in, although it may remain stored on the user's device. The session must have signed in or completed an MFA challenge within the last 10 minutes. - * - * @param {string} passkeyId - Passkey ID. - * @throws {AppwriteException} - * @returns {Promise<{}>} - * @deprecated Use the object parameter style method for a better developer experience. - */ - deletePasskey(passkeyId: string): Promise<{}>; - deletePasskey(paramsOrFirst: { passkeyId: string } | string): Promise<{}> { - let params: { passkeyId: string }; - - if ( - paramsOrFirst && - typeof paramsOrFirst === 'object' && - !Array.isArray(paramsOrFirst) - ) { - params = (paramsOrFirst || {}) as { passkeyId: string }; - } else { - params = { - passkeyId: paramsOrFirst as string, - }; - } - - const passkeyId = params.passkeyId; - - if (typeof passkeyId === 'undefined' || passkeyId === '') { - throw new AppwriteException( - 'Missing required parameter: "passkeyId"', - ); - } - - const apiPath = '/account/passkeys/{passkeyId}'.replace( - '{passkeyId}', - encodeURIComponent(String(passkeyId)), - ); + * + * @throws {AppwriteException} + * @returns {Promise} + */ + updateMFARecoveryCodes(): Promise { + const apiPath = '/account/mfa/recovery-codes'; const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); return this.client.call( - 'delete', + 'patch', uri, { 'X-Appwrite-Project': this.client.config.project, @@ -3019,80 +1847,61 @@ export class Account extends Service { } /** - * Complete a passkey registration started with [Create passkey](/docs/references/cloud/client-web/account#createPasskey). Pass the JSON form of the credential returned by `navigator.credentials.create()`, for example `credential.toJSON()`. Each registration can be verified once; a failed attempt requires starting it again. + * Update currently logged in user account name. * - * @param {string} params.passkeyId - Passkey ID. - * @param {object} params.credential - Registration credential returned by the authenticator, in the JSON form produced by `PublicKeyCredential.toJSON()`. + * @param {string} params.name - User name. Max length: 128 chars. * @throws {AppwriteException} * @returns {Promise} */ - updatePasskeyVerification(params: { - passkeyId: string; - credential: object; - }): Promise; + updateName< + Preferences extends Models.Preferences = Models.DefaultPreferences, + >(params: { name: string }): Promise>; /** - * Complete a passkey registration started with [Create passkey](/docs/references/cloud/client-web/account#createPasskey). Pass the JSON form of the credential returned by `navigator.credentials.create()`, for example `credential.toJSON()`. Each registration can be verified once; a failed attempt requires starting it again. + * Update currently logged in user account name. * - * @param {string} passkeyId - Passkey ID. - * @param {object} credential - Registration credential returned by the authenticator, in the JSON form produced by `PublicKeyCredential.toJSON()`. + * @param {string} name - User name. Max length: 128 chars. * @throws {AppwriteException} - * @returns {Promise} + * @returns {Promise>} * @deprecated Use the object parameter style method for a better developer experience. */ - updatePasskeyVerification( - passkeyId: string, - credential: object, - ): Promise; - updatePasskeyVerification( - paramsOrFirst: { passkeyId: string; credential: object } | string, - ...rest: [object?] - ): Promise { - let params: { passkeyId: string; credential: object }; + updateName< + Preferences extends Models.Preferences = Models.DefaultPreferences, + >(name: string): Promise>; + updateName< + Preferences extends Models.Preferences = Models.DefaultPreferences, + >( + paramsOrFirst: { name: string } | string, + ): Promise> { + let params: { name: string }; if ( paramsOrFirst && typeof paramsOrFirst === 'object' && !Array.isArray(paramsOrFirst) ) { - params = (paramsOrFirst || {}) as { - passkeyId: string; - credential: object; - }; + params = (paramsOrFirst || {}) as { name: string }; } else { params = { - passkeyId: paramsOrFirst as string, - credential: rest[0] as object, + name: paramsOrFirst as string, }; } - const passkeyId = params.passkeyId; - const credential = params.credential; - - if (typeof passkeyId === 'undefined' || passkeyId === '') { - throw new AppwriteException( - 'Missing required parameter: "passkeyId"', - ); - } + const name = params.name; - if (typeof credential === 'undefined') { - throw new AppwriteException( - 'Missing required parameter: "credential"', - ); + if (typeof name === 'undefined') { + throw new AppwriteException('Missing required parameter: "name"'); } - const apiPath = '/account/passkeys/{passkeyId}/verification'.replace( - '{passkeyId}', - encodeURIComponent(String(passkeyId)), - ); + const apiPath = '/account/name'; const apiPayload: Payload = {}; - if (typeof credential !== 'undefined') { - apiPayload['credential'] = credential; + if (typeof name !== 'undefined') { + apiPayload['name'] = name; } const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( - 'put', + return this.client.call( + 'patch', uri, { 'X-Appwrite-Project': this.client.config.project, @@ -3101,22 +1910,6 @@ export class Account extends Service { }, apiPayload, ); - const defaults = { - root: 'passkey', - models: { - passkey: { - defaults: { - $id: '', - $createdAt: '', - $updatedAt: '', - name: '', - accessedAt: '', - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** @@ -3193,7 +1986,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'patch', uri, { @@ -3203,48 +1996,6 @@ export class Account extends Service { }, apiPayload, ); - const defaults = { - root: 'user', - models: { - user: { - defaults: { - $id: '', - $createdAt: '', - $updatedAt: '', - name: '', - registration: '', - status: true, - labels: [], - passwordUpdate: '', - email: '', - phone: '', - emailVerification: false, - phoneVerification: false, - mfa: false, - accessedAt: '', - }, - properties: { - targets: { - items: 'target', - }, - }, - }, - target: { - defaults: { - $id: '', - $createdAt: '', - $updatedAt: '', - name: '', - userId: '', - providerType: '', - identifier: '', - expired: false, - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** @@ -3322,7 +2073,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'patch', uri, { @@ -3332,48 +2083,6 @@ export class Account extends Service { }, apiPayload, ); - const defaults = { - root: 'user', - models: { - user: { - defaults: { - $id: '', - $createdAt: '', - $updatedAt: '', - name: '', - registration: '', - status: true, - labels: [], - passwordUpdate: '', - email: '', - phone: '', - emailVerification: false, - phoneVerification: false, - mfa: false, - accessedAt: '', - }, - properties: { - targets: { - items: 'target', - }, - }, - }, - target: { - defaults: { - $id: '', - $createdAt: '', - $updatedAt: '', - name: '', - userId: '', - providerType: '', - identifier: '', - expired: false, - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** @@ -3457,7 +2166,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'patch', uri, { @@ -3467,48 +2176,6 @@ export class Account extends Service { }, apiPayload, ); - const defaults = { - root: 'user', - models: { - user: { - defaults: { - $id: '', - $createdAt: '', - $updatedAt: '', - name: '', - registration: '', - status: true, - labels: [], - passwordUpdate: '', - email: '', - phone: '', - emailVerification: false, - phoneVerification: false, - mfa: false, - accessedAt: '', - }, - properties: { - targets: { - items: 'target', - }, - }, - }, - target: { - defaults: { - $id: '', - $createdAt: '', - $updatedAt: '', - name: '', - userId: '', - providerType: '', - identifier: '', - expired: false, - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** @@ -3575,7 +2242,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'post', uri, { @@ -3585,23 +2252,6 @@ export class Account extends Service { }, apiPayload, ); - const defaults = { - root: 'token', - models: { - token: { - defaults: { - $id: '', - $createdAt: '', - userId: '', - secret: '', - expire: '', - phrase: '', - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** @@ -3696,7 +2346,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'put', uri, { @@ -3706,23 +2356,6 @@ export class Account extends Service { }, apiPayload, ); - const defaults = { - root: 'token', - models: { - token: { - defaults: { - $id: '', - $createdAt: '', - userId: '', - secret: '', - expire: '', - phrase: '', - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** @@ -3794,7 +2427,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'post', uri, { @@ -3804,23 +2437,6 @@ export class Account extends Service { }, apiPayload, ); - const defaults = { - root: 'token', - models: { - token: { - defaults: { - $id: '', - $createdAt: '', - userId: '', - secret: '', - expire: '', - phrase: '', - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** @@ -3913,7 +2529,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'put', uri, { @@ -3923,23 +2539,6 @@ export class Account extends Service { }, apiPayload, ); - const defaults = { - root: 'token', - models: { - token: { - defaults: { - $id: '', - $createdAt: '', - userId: '', - secret: '', - expire: '', - phrase: '', - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** @@ -3987,7 +2586,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'get', uri, { @@ -3996,56 +2595,6 @@ export class Account extends Service { }, apiPayload, ); - const defaults = { - root: 'sessionList', - models: { - sessionList: { - defaults: { - total: 0, - }, - properties: { - sessions: { - items: 'session', - }, - }, - }, - session: { - defaults: { - $id: '', - $createdAt: '', - $updatedAt: '', - userId: '', - expire: '', - provider: '', - providerUid: '', - providerAccessToken: '', - providerAccessTokenExpiry: '', - providerRefreshToken: '', - ip: '', - osCode: '', - osName: '', - osVersion: '', - clientType: '', - clientCode: '', - clientName: '', - clientVersion: '', - clientEngine: '', - clientEngineVersion: '', - deviceName: '', - deviceBrand: '', - deviceModel: '', - countryCode: '', - countryName: '', - current: false, - factors: [], - secret: '', - mfaUpdatedAt: '', - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** @@ -4116,7 +2665,7 @@ export class Account extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'post', uri, { @@ -4126,46 +2675,6 @@ export class Account extends Service { }, apiPayload, ); - const defaults = { - root: 'session', - models: { - session: { - defaults: { - $id: '', - $createdAt: '', - $updatedAt: '', - userId: '', - expire: '', - provider: '', - providerUid: '', - providerAccessToken: '', - providerAccessTokenExpiry: '', - providerRefreshToken: '', - ip: '', - osCode: '', - osName: '', - osVersion: '', - clientType: '', - clientCode: '', - clientName: '', - clientVersion: '', - clientEngine: '', - clientEngineVersion: '', - deviceName: '', - deviceBrand: '', - deviceModel: '', - countryCode: '', - countryName: '', - current: false, - factors: [], - secret: '', - mfaUpdatedAt: '', - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** @@ -4256,7 +2765,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'post', uri, { @@ -4266,46 +2775,6 @@ export class Account extends Service { }, apiPayload, ); - const defaults = { - root: 'session', - models: { - session: { - defaults: { - $id: '', - $createdAt: '', - $updatedAt: '', - userId: '', - expire: '', - provider: '', - providerUid: '', - providerAccessToken: '', - providerAccessTokenExpiry: '', - providerRefreshToken: '', - ip: '', - osCode: '', - osName: '', - osVersion: '', - clientType: '', - clientCode: '', - clientName: '', - clientVersion: '', - clientEngine: '', - clientEngineVersion: '', - deviceName: '', - deviceBrand: '', - deviceModel: '', - countryCode: '', - countryName: '', - current: false, - factors: [], - secret: '', - mfaUpdatedAt: '', - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** @@ -4470,7 +2939,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'post', uri, { @@ -4480,46 +2949,6 @@ export class Account extends Service { }, apiPayload, ); - const defaults = { - root: 'session', - models: { - session: { - defaults: { - $id: '', - $createdAt: '', - $updatedAt: '', - userId: '', - expire: '', - provider: '', - providerUid: '', - providerAccessToken: '', - providerAccessTokenExpiry: '', - providerRefreshToken: '', - ip: '', - osCode: '', - osName: '', - osVersion: '', - clientType: '', - clientCode: '', - clientName: '', - clientVersion: '', - clientEngine: '', - clientEngineVersion: '', - deviceName: '', - deviceBrand: '', - deviceModel: '', - countryCode: '', - countryName: '', - current: false, - factors: [], - secret: '', - mfaUpdatedAt: '', - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** @@ -4593,7 +3022,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'put', uri, { @@ -4603,46 +3032,6 @@ export class Account extends Service { }, apiPayload, ); - const defaults = { - root: 'session', - models: { - session: { - defaults: { - $id: '', - $createdAt: '', - $updatedAt: '', - userId: '', - expire: '', - provider: '', - providerUid: '', - providerAccessToken: '', - providerAccessTokenExpiry: '', - providerRefreshToken: '', - ip: '', - osCode: '', - osName: '', - osVersion: '', - clientType: '', - clientCode: '', - clientName: '', - clientVersion: '', - clientEngine: '', - clientEngineVersion: '', - deviceName: '', - deviceBrand: '', - deviceModel: '', - countryCode: '', - countryName: '', - current: false, - factors: [], - secret: '', - mfaUpdatedAt: '', - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** @@ -4657,7 +3046,6 @@ export class Account extends Service { * @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} */ @@ -4666,7 +3054,6 @@ 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. @@ -4680,7 +3067,6 @@ export class Account extends Service { * @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. @@ -4690,7 +3076,6 @@ export class Account extends Service { success?: string, failure?: string, scopes?: string[], - state?: string, ): void | URL; createOAuth2Session( paramsOrFirst: @@ -4699,17 +3084,15 @@ export class Account extends Service { success?: string; failure?: string; scopes?: string[]; - state?: string; } | OAuthProvider, - ...rest: [string?, string?, string[]?, string?] + ...rest: [string?, string?, string[]?] ): void | URL { let params: { provider: OAuthProvider; success?: string; failure?: string; scopes?: string[]; - state?: string; }; if ( @@ -4719,15 +3102,13 @@ export class Account extends Service { ('provider' in paramsOrFirst || 'success' in paramsOrFirst || 'failure' in paramsOrFirst || - 'scopes' in paramsOrFirst || - 'state' in paramsOrFirst) + 'scopes' in paramsOrFirst) ) { params = (paramsOrFirst || {}) as { provider: OAuthProvider; success?: string; failure?: string; scopes?: string[]; - state?: string; }; } else { params = { @@ -4735,7 +3116,6 @@ 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, }; } @@ -4743,7 +3123,6 @@ 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( @@ -4769,10 +3148,6 @@ export class Account extends Service { apiPayload['scopes'] = scopes; } - if (typeof state !== 'undefined') { - apiPayload['state'] = state; - } - const uri = new URL(this.client.config.endpoint + apiPath); apiPayload['project'] = this.client.config.project; @@ -4852,7 +3227,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'put', uri, { @@ -4862,46 +3237,6 @@ export class Account extends Service { }, apiPayload, ); - const defaults = { - root: 'session', - models: { - session: { - defaults: { - $id: '', - $createdAt: '', - $updatedAt: '', - userId: '', - expire: '', - provider: '', - providerUid: '', - providerAccessToken: '', - providerAccessTokenExpiry: '', - providerRefreshToken: '', - ip: '', - osCode: '', - osName: '', - osVersion: '', - clientType: '', - clientCode: '', - clientName: '', - clientVersion: '', - clientEngine: '', - clientEngineVersion: '', - deviceName: '', - deviceBrand: '', - deviceModel: '', - countryCode: '', - countryName: '', - current: false, - factors: [], - secret: '', - mfaUpdatedAt: '', - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** @@ -4971,7 +3306,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'post', uri, { @@ -4981,46 +3316,6 @@ export class Account extends Service { }, apiPayload, ); - const defaults = { - root: 'session', - models: { - session: { - defaults: { - $id: '', - $createdAt: '', - $updatedAt: '', - userId: '', - expire: '', - provider: '', - providerUid: '', - providerAccessToken: '', - providerAccessTokenExpiry: '', - providerRefreshToken: '', - ip: '', - osCode: '', - osName: '', - osVersion: '', - clientType: '', - clientCode: '', - clientName: '', - clientVersion: '', - clientEngine: '', - clientEngineVersion: '', - deviceName: '', - deviceBrand: '', - deviceModel: '', - countryCode: '', - countryName: '', - current: false, - factors: [], - secret: '', - mfaUpdatedAt: '', - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** @@ -5072,7 +3367,7 @@ export class Account extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'get', uri, { @@ -5081,46 +3376,6 @@ export class Account extends Service { }, apiPayload, ); - const defaults = { - root: 'session', - models: { - session: { - defaults: { - $id: '', - $createdAt: '', - $updatedAt: '', - userId: '', - expire: '', - provider: '', - providerUid: '', - providerAccessToken: '', - providerAccessTokenExpiry: '', - providerRefreshToken: '', - ip: '', - osCode: '', - osName: '', - osVersion: '', - clientType: '', - clientCode: '', - clientName: '', - clientVersion: '', - clientEngine: '', - clientEngineVersion: '', - deviceName: '', - deviceBrand: '', - deviceModel: '', - countryCode: '', - countryName: '', - current: false, - factors: [], - secret: '', - mfaUpdatedAt: '', - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** @@ -5172,7 +3427,7 @@ export class Account extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'patch', uri, { @@ -5182,46 +3437,6 @@ export class Account extends Service { }, apiPayload, ); - const defaults = { - root: 'session', - models: { - session: { - defaults: { - $id: '', - $createdAt: '', - $updatedAt: '', - userId: '', - expire: '', - provider: '', - providerUid: '', - providerAccessToken: '', - providerAccessTokenExpiry: '', - providerRefreshToken: '', - ip: '', - osCode: '', - osName: '', - osVersion: '', - clientType: '', - clientCode: '', - clientName: '', - clientVersion: '', - clientEngine: '', - clientEngineVersion: '', - deviceName: '', - deviceBrand: '', - deviceModel: '', - countryCode: '', - countryName: '', - current: false, - factors: [], - secret: '', - mfaUpdatedAt: '', - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** @@ -5296,7 +3511,7 @@ export class Account extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'patch', uri, { @@ -5306,48 +3521,6 @@ export class Account extends Service { }, apiPayload, ); - const defaults = { - root: 'user', - models: { - user: { - defaults: { - $id: '', - $createdAt: '', - $updatedAt: '', - name: '', - registration: '', - status: true, - labels: [], - passwordUpdate: '', - email: '', - phone: '', - emailVerification: false, - phoneVerification: false, - mfa: false, - accessedAt: '', - }, - properties: { - targets: { - items: 'target', - }, - }, - }, - target: { - defaults: { - $id: '', - $createdAt: '', - $updatedAt: '', - name: '', - userId: '', - providerType: '', - identifier: '', - expired: false, - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** @@ -5441,7 +3614,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'post', uri, { @@ -5451,25 +3624,6 @@ export class Account extends Service { }, apiPayload, ); - const defaults = { - root: 'target', - models: { - target: { - defaults: { - $id: '', - $createdAt: '', - $updatedAt: '', - name: '', - userId: '', - providerType: '', - identifier: '', - expired: false, - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** @@ -5545,7 +3699,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'put', uri, { @@ -5555,25 +3709,6 @@ export class Account extends Service { }, apiPayload, ); - const defaults = { - root: 'target', - models: { - target: { - defaults: { - $id: '', - $createdAt: '', - $updatedAt: '', - name: '', - userId: '', - providerType: '', - identifier: '', - expired: false, - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** @@ -5725,7 +3860,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'post', uri, { @@ -5735,23 +3870,6 @@ export class Account extends Service { }, apiPayload, ); - const defaults = { - root: 'token', - models: { - token: { - defaults: { - $id: '', - $createdAt: '', - userId: '', - secret: '', - expire: '', - phrase: '', - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** @@ -5859,7 +3977,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'post', uri, { @@ -5869,23 +3987,6 @@ export class Account extends Service { }, apiPayload, ); - const defaults = { - root: 'token', - models: { - token: { - defaults: { - $id: '', - $createdAt: '', - userId: '', - secret: '', - expire: '', - phrase: '', - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** @@ -5901,7 +4002,6 @@ export class Account extends Service { * @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} */ @@ -5910,7 +4010,6 @@ 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. @@ -5925,7 +4024,6 @@ export class Account extends Service { * @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. @@ -5935,7 +4033,6 @@ export class Account extends Service { success?: string, failure?: string, scopes?: string[], - state?: string, ): void | URL; createOAuth2Token( paramsOrFirst: @@ -5944,17 +4041,15 @@ export class Account extends Service { success?: string; failure?: string; scopes?: string[]; - state?: string; } | OAuthProvider, - ...rest: [string?, string?, string[]?, string?] + ...rest: [string?, string?, string[]?] ): void | URL { let params: { provider: OAuthProvider; success?: string; failure?: string; scopes?: string[]; - state?: string; }; if ( @@ -5964,15 +4059,13 @@ export class Account extends Service { ('provider' in paramsOrFirst || 'success' in paramsOrFirst || 'failure' in paramsOrFirst || - 'scopes' in paramsOrFirst || - 'state' in paramsOrFirst) + 'scopes' in paramsOrFirst) ) { params = (paramsOrFirst || {}) as { provider: OAuthProvider; success?: string; failure?: string; scopes?: string[]; - state?: string; }; } else { params = { @@ -5980,7 +4073,6 @@ 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, }; } @@ -5988,7 +4080,6 @@ 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( @@ -6014,10 +4105,6 @@ export class Account extends Service { apiPayload['scopes'] = scopes; } - if (typeof state !== 'undefined') { - apiPayload['state'] = state; - } - const uri = new URL(this.client.config.endpoint + apiPath); apiPayload['project'] = this.client.config.project; @@ -6029,148 +4116,6 @@ export class Account extends Service { return uri; } - /** - * Start signing in with a passkey. No email or user ID is needed: pass the returned `publicKey` options to `navigator.credentials.get()` and the user picks one of their passkeys. Then call [Update passkey token](/docs/references/cloud/client-web/account#updatePasskeyToken) with the credential to receive a token, and exchange it with [Create session](/docs/references/cloud/client-web/account#createSession). The challenge expires after 5 minutes. - * - * @throws {AppwriteException} - * @returns {Promise} - */ - createPasskeyToken(): Promise { - const apiPath = '/account/tokens/passkey'; - const apiPayload: Payload = {}; - - const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( - 'post', - uri, - { - 'X-Appwrite-Project': this.client.config.project, - 'content-type': 'application/json', - accept: 'application/json', - }, - apiPayload, - ); - const defaults = { - root: 'passkeyChallenge', - models: { - passkeyChallenge: { - defaults: { - $id: '', - $createdAt: '', - passkeyId: '', - expire: '', - publicKey: [], - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); - } - - /** - * Complete a passkey sign-in started with [Create passkey token](/docs/references/cloud/client-web/account#createPasskeyToken). Pass the challenge ID and the JSON form of the credential returned by `navigator.credentials.get()`, for example `credential.toJSON()`. The returned token includes its secret and expires after 1 minute: exchange it for a session with [Create session](/docs/references/cloud/client-web/account#createSession). Passkeys require user verification, so the session also satisfies MFA. Each challenge can only be used once. - * - * @param {string} params.challengeId - Challenge ID returned by createPasskeyToken. - * @param {object} params.credential - Authentication credential returned by the authenticator, in the JSON form produced by `PublicKeyCredential.toJSON()`. - * @throws {AppwriteException} - * @returns {Promise} - */ - updatePasskeyToken(params: { - challengeId: string; - credential: object; - }): Promise; - /** - * Complete a passkey sign-in started with [Create passkey token](/docs/references/cloud/client-web/account#createPasskeyToken). Pass the challenge ID and the JSON form of the credential returned by `navigator.credentials.get()`, for example `credential.toJSON()`. The returned token includes its secret and expires after 1 minute: exchange it for a session with [Create session](/docs/references/cloud/client-web/account#createSession). Passkeys require user verification, so the session also satisfies MFA. Each challenge can only be used once. - * - * @param {string} challengeId - Challenge ID returned by createPasskeyToken. - * @param {object} credential - Authentication credential returned by the authenticator, in the JSON form produced by `PublicKeyCredential.toJSON()`. - * @throws {AppwriteException} - * @returns {Promise} - * @deprecated Use the object parameter style method for a better developer experience. - */ - updatePasskeyToken( - challengeId: string, - credential: object, - ): Promise; - updatePasskeyToken( - paramsOrFirst: { challengeId: string; credential: object } | string, - ...rest: [object?] - ): Promise { - let params: { challengeId: string; credential: object }; - - if ( - paramsOrFirst && - typeof paramsOrFirst === 'object' && - !Array.isArray(paramsOrFirst) - ) { - params = (paramsOrFirst || {}) as { - challengeId: string; - credential: object; - }; - } else { - params = { - challengeId: paramsOrFirst as string, - credential: rest[0] as object, - }; - } - - const challengeId = params.challengeId; - const credential = params.credential; - - if (typeof challengeId === 'undefined') { - throw new AppwriteException( - 'Missing required parameter: "challengeId"', - ); - } - - if (typeof credential === 'undefined') { - throw new AppwriteException( - 'Missing required parameter: "credential"', - ); - } - - const apiPath = '/account/tokens/passkey'; - const apiPayload: Payload = {}; - - if (typeof challengeId !== 'undefined') { - apiPayload['challengeId'] = challengeId; - } - - if (typeof credential !== 'undefined') { - apiPayload['credential'] = credential; - } - - const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( - 'put', - uri, - { - 'X-Appwrite-Project': this.client.config.project, - 'content-type': 'application/json', - accept: 'application/json', - }, - apiPayload, - ); - const defaults = { - root: 'tokenSecret', - models: { - tokenSecret: { - defaults: { - $id: '', - $createdAt: '', - userId: '', - secret: '', - expire: '', - phrase: '', - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); - } - /** * Sends the user an SMS with a secret key for creating a session. If the provided user ID has not be registered, a new user will be created. Use the returned user ID and secret and submit a request to the [POST /v1/account/sessions/token](https://appwrite.io/docs/references/cloud/client-web/account#createSession) endpoint to complete the login process. The secret sent to the user's phone is valid for 15 minutes. * @@ -6239,7 +4184,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'post', uri, { @@ -6249,23 +4194,6 @@ export class Account extends Service { }, apiPayload, ); - const defaults = { - root: 'token', - models: { - token: { - defaults: { - $id: '', - $createdAt: '', - userId: '', - secret: '', - expire: '', - phrase: '', - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** @@ -6322,7 +4250,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'post', uri, { @@ -6332,23 +4260,6 @@ export class Account extends Service { }, apiPayload, ); - const defaults = { - root: 'token', - models: { - token: { - defaults: { - $id: '', - $createdAt: '', - userId: '', - secret: '', - expire: '', - phrase: '', - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** @@ -6406,7 +4317,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'post', uri, { @@ -6416,23 +4327,6 @@ export class Account extends Service { }, apiPayload, ); - const defaults = { - root: 'token', - models: { - token: { - defaults: { - $id: '', - $createdAt: '', - userId: '', - secret: '', - expire: '', - phrase: '', - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** @@ -6505,7 +4399,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'put', uri, { @@ -6515,23 +4409,6 @@ export class Account extends Service { }, apiPayload, ); - const defaults = { - root: 'token', - models: { - token: { - defaults: { - $id: '', - $createdAt: '', - userId: '', - secret: '', - expire: '', - phrase: '', - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** @@ -6602,7 +4479,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'put', uri, { @@ -6612,23 +4489,6 @@ export class Account extends Service { }, apiPayload, ); - const defaults = { - root: 'token', - models: { - token: { - defaults: { - $id: '', - $createdAt: '', - userId: '', - secret: '', - expire: '', - phrase: '', - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** @@ -6684,7 +4544,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'post', uri, { @@ -6694,23 +4554,6 @@ export class Account extends Service { }, apiPayload, ); - const defaults = { - root: 'token', - models: { - token: { - defaults: { - $id: '', - $createdAt: '', - userId: '', - secret: '', - expire: '', - phrase: '', - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** @@ -6785,7 +4628,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'put', uri, { @@ -6795,23 +4638,6 @@ export class Account extends Service { }, apiPayload, ); - const defaults = { - root: 'token', - models: { - token: { - defaults: { - $id: '', - $createdAt: '', - userId: '', - secret: '', - expire: '', - phrase: '', - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** @@ -6825,7 +4651,7 @@ export class Account extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'post', uri, { @@ -6835,23 +4661,6 @@ export class Account extends Service { }, apiPayload, ); - const defaults = { - root: 'token', - models: { - token: { - defaults: { - $id: '', - $createdAt: '', - userId: '', - secret: '', - expire: '', - phrase: '', - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** @@ -6924,7 +4733,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'put', uri, { @@ -6934,22 +4743,5 @@ export class Account extends Service { }, apiPayload, ); - const defaults = { - root: 'token', - models: { - token: { - defaults: { - $id: '', - $createdAt: '', - userId: '', - secret: '', - expire: '', - phrase: '', - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } } diff --git a/src/services/analytics.ts b/src/services/analytics.ts deleted file mode 100644 index af61d584..00000000 --- a/src/services/analytics.ts +++ /dev/null @@ -1,260 +0,0 @@ -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/apps.ts b/src/services/apps.ts index 7bc1cb9e..02554ba4 100644 --- a/src/services/apps.ts +++ b/src/services/apps.ts @@ -1,5 +1,5 @@ import { Service } from '../service'; -import { AppwriteException, Client, applyDefaults } from '../client'; +import { AppwriteException, Client } from '../client'; import type { Models } from '../models'; import type { Payload } from '../client'; @@ -68,7 +68,7 @@ export class Apps extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'get', uri, { @@ -77,69 +77,6 @@ export class Apps extends Service { }, apiPayload, ); - const defaults = { - root: 'appsList', - models: { - appsList: { - defaults: { - total: 0, - }, - properties: { - apps: { - items: 'app', - }, - }, - }, - app: { - defaults: { - $id: '', - $createdAt: '', - $updatedAt: '', - name: '', - description: '', - clientUri: '', - logoUri: '', - privacyPolicyUrl: '', - termsUrl: '', - contacts: [], - tagline: '', - tags: [], - labels: [], - images: [], - supportUrl: '', - dataDeletionUrl: '', - redirectUris: [], - postLogoutRedirectUris: [], - enabled: true, - type: 'confidential', - deviceFlow: false, - teamId: '', - userId: '', - installationScopes: [], - installationRedirectUrl: '', - }, - properties: { - secrets: { - items: 'appSecret', - }, - }, - }, - appSecret: { - defaults: { - $id: '', - $createdAt: '', - $updatedAt: '', - appId: '', - secret: '', - hint: '', - createdById: '', - createdByName: '', - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** @@ -466,7 +403,7 @@ export class Apps extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'post', uri, { @@ -476,59 +413,6 @@ export class Apps extends Service { }, apiPayload, ); - const defaults = { - root: 'app', - models: { - app: { - defaults: { - $id: '', - $createdAt: '', - $updatedAt: '', - name: '', - description: '', - clientUri: '', - logoUri: '', - privacyPolicyUrl: '', - termsUrl: '', - contacts: [], - tagline: '', - tags: [], - labels: [], - images: [], - supportUrl: '', - dataDeletionUrl: '', - redirectUris: [], - postLogoutRedirectUris: [], - enabled: true, - type: 'confidential', - deviceFlow: false, - teamId: '', - userId: '', - installationScopes: [], - installationRedirectUrl: '', - }, - properties: { - secrets: { - items: 'appSecret', - }, - }, - }, - appSecret: { - defaults: { - $id: '', - $createdAt: '', - $updatedAt: '', - appId: '', - secret: '', - hint: '', - createdById: '', - createdByName: '', - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** @@ -542,7 +426,7 @@ export class Apps extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'get', uri, { @@ -551,32 +435,6 @@ export class Apps extends Service { }, apiPayload, ); - const defaults = { - root: 'appScopeList', - models: { - appScopeList: { - defaults: { - total: 0, - }, - properties: { - scopes: { - items: 'appScope', - }, - }, - }, - appScope: { - defaults: { - value: '', - description: '', - type: '', - category: '', - deprecated: false, - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** @@ -590,7 +448,7 @@ export class Apps extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'get', uri, { @@ -599,32 +457,6 @@ export class Apps extends Service { }, apiPayload, ); - const defaults = { - root: 'appScopeList', - models: { - appScopeList: { - defaults: { - total: 0, - }, - properties: { - scopes: { - items: 'appScope', - }, - }, - }, - appScope: { - defaults: { - value: '', - description: '', - type: '', - category: '', - deprecated: false, - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** @@ -672,7 +504,7 @@ export class Apps extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'get', uri, { @@ -681,59 +513,6 @@ export class Apps extends Service { }, apiPayload, ); - const defaults = { - root: 'app', - models: { - app: { - defaults: { - $id: '', - $createdAt: '', - $updatedAt: '', - name: '', - description: '', - clientUri: '', - logoUri: '', - privacyPolicyUrl: '', - termsUrl: '', - contacts: [], - tagline: '', - tags: [], - labels: [], - images: [], - supportUrl: '', - dataDeletionUrl: '', - redirectUris: [], - postLogoutRedirectUris: [], - enabled: true, - type: 'confidential', - deviceFlow: false, - teamId: '', - userId: '', - installationScopes: [], - installationRedirectUrl: '', - }, - properties: { - secrets: { - items: 'appSecret', - }, - }, - }, - appSecret: { - defaults: { - $id: '', - $createdAt: '', - $updatedAt: '', - appId: '', - secret: '', - hint: '', - createdById: '', - createdByName: '', - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1067,7 +846,7 @@ export class Apps extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'put', uri, { @@ -1077,59 +856,6 @@ export class Apps extends Service { }, apiPayload, ); - const defaults = { - root: 'app', - models: { - app: { - defaults: { - $id: '', - $createdAt: '', - $updatedAt: '', - name: '', - description: '', - clientUri: '', - logoUri: '', - privacyPolicyUrl: '', - termsUrl: '', - contacts: [], - tagline: '', - tags: [], - labels: [], - images: [], - supportUrl: '', - dataDeletionUrl: '', - redirectUris: [], - postLogoutRedirectUris: [], - enabled: true, - type: 'confidential', - deviceFlow: false, - teamId: '', - userId: '', - installationScopes: [], - installationRedirectUrl: '', - }, - properties: { - secrets: { - items: 'appSecret', - }, - }, - }, - appSecret: { - defaults: { - $id: '', - $createdAt: '', - $updatedAt: '', - appId: '', - secret: '', - hint: '', - createdById: '', - createdByName: '', - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1266,7 +992,7 @@ export class Apps extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'get', uri, { @@ -1275,36 +1001,6 @@ export class Apps extends Service { }, apiPayload, ); - const defaults = { - root: 'appInstallationList', - models: { - appInstallationList: { - defaults: { - total: 0, - }, - properties: { - installations: { - items: 'appInstallation', - }, - }, - }, - appInstallation: { - defaults: { - $id: '', - $createdAt: '', - $updatedAt: '', - appId: '', - teamId: '', - scopes: [], - authorizationDetails: [], - createdById: '', - createdByName: '', - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1376,7 +1072,7 @@ export class Apps extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'get', uri, { @@ -1385,26 +1081,6 @@ export class Apps extends Service { }, apiPayload, ); - const defaults = { - root: 'appInstallation', - models: { - appInstallation: { - defaults: { - $id: '', - $createdAt: '', - $updatedAt: '', - appId: '', - teamId: '', - scopes: [], - authorizationDetails: [], - createdById: '', - createdByName: '', - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1554,7 +1230,7 @@ export class Apps extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'post', uri, { @@ -1564,22 +1240,6 @@ export class Apps extends Service { }, apiPayload, ); - const defaults = { - root: 'oauth2Token', - models: { - oauth2Token: { - defaults: { - access_token: '', - token_type: 'Bearer', - expires_in: 0, - refresh_token: '', - scope: '', - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1659,7 +1319,7 @@ export class Apps extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'get', uri, { @@ -1668,35 +1328,6 @@ export class Apps extends Service { }, apiPayload, ); - const defaults = { - root: 'appKeyList', - models: { - appKeyList: { - defaults: { - total: 0, - }, - properties: { - keys: { - items: 'appKey', - }, - }, - }, - appKey: { - defaults: { - $id: '', - $createdAt: '', - $updatedAt: '', - appId: '', - secret: '', - hint: '', - createdById: '', - createdByName: '', - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1746,7 +1377,7 @@ export class Apps extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'post', uri, { @@ -1756,25 +1387,6 @@ export class Apps extends Service { }, apiPayload, ); - const defaults = { - root: 'appKey', - models: { - appKey: { - defaults: { - $id: '', - $createdAt: '', - $updatedAt: '', - appId: '', - secret: '', - hint: '', - createdById: '', - createdByName: '', - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1832,7 +1444,7 @@ export class Apps extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'get', uri, { @@ -1841,25 +1453,6 @@ export class Apps extends Service { }, apiPayload, ); - const defaults = { - root: 'appKey', - models: { - appKey: { - defaults: { - $id: '', - $createdAt: '', - $updatedAt: '', - appId: '', - secret: '', - hint: '', - createdById: '', - createdByName: '', - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** @@ -2006,7 +1599,7 @@ export class Apps extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'get', uri, { @@ -2015,35 +1608,6 @@ export class Apps extends Service { }, apiPayload, ); - const defaults = { - root: 'appSecretList', - models: { - appSecretList: { - defaults: { - total: 0, - }, - properties: { - secrets: { - items: 'appSecret', - }, - }, - }, - appSecret: { - defaults: { - $id: '', - $createdAt: '', - $updatedAt: '', - appId: '', - secret: '', - hint: '', - createdById: '', - createdByName: '', - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** @@ -2093,7 +1657,7 @@ export class Apps extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'post', uri, { @@ -2103,25 +1667,6 @@ export class Apps extends Service { }, apiPayload, ); - const defaults = { - root: 'appSecretPlaintext', - models: { - appSecretPlaintext: { - defaults: { - $id: '', - $createdAt: '', - $updatedAt: '', - appId: '', - secret: '', - hint: '', - createdById: '', - createdByName: '', - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** @@ -2187,7 +1732,7 @@ export class Apps extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'get', uri, { @@ -2196,25 +1741,6 @@ export class Apps extends Service { }, apiPayload, ); - const defaults = { - root: 'appSecret', - models: { - appSecret: { - defaults: { - $id: '', - $createdAt: '', - $updatedAt: '', - appId: '', - secret: '', - hint: '', - createdById: '', - createdByName: '', - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** @@ -2349,7 +1875,7 @@ export class Apps extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'patch', uri, { @@ -2359,59 +1885,6 @@ export class Apps extends Service { }, apiPayload, ); - const defaults = { - root: 'app', - models: { - app: { - defaults: { - $id: '', - $createdAt: '', - $updatedAt: '', - name: '', - description: '', - clientUri: '', - logoUri: '', - privacyPolicyUrl: '', - termsUrl: '', - contacts: [], - tagline: '', - tags: [], - labels: [], - images: [], - supportUrl: '', - dataDeletionUrl: '', - redirectUris: [], - postLogoutRedirectUris: [], - enabled: true, - type: 'confidential', - deviceFlow: false, - teamId: '', - userId: '', - installationScopes: [], - installationRedirectUrl: '', - }, - properties: { - secrets: { - items: 'appSecret', - }, - }, - }, - appSecret: { - defaults: { - $id: '', - $createdAt: '', - $updatedAt: '', - appId: '', - secret: '', - hint: '', - createdById: '', - createdByName: '', - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** diff --git a/src/services/avatars.ts b/src/services/avatars.ts index 062ed1b6..e634ce6d 100644 --- a/src/services/avatars.ts +++ b/src/services/avatars.ts @@ -1,5 +1,5 @@ import { Service } from '../service'; -import { AppwriteException, Client, applyDefaults } from '../client'; +import { AppwriteException, Client } from '../client'; import type { Models } from '../models'; import type { UploadProgress, Payload } from '../client'; import * as FileSystem from 'expo-file-system'; diff --git a/src/services/databases.ts b/src/services/databases.ts index faef7447..94d2ad16 100644 --- a/src/services/databases.ts +++ b/src/services/databases.ts @@ -1,5 +1,5 @@ import { Service } from '../service'; -import { AppwriteException, Client, applyDefaults } from '../client'; +import { AppwriteException, Client } from '../client'; import type { Models } from '../models'; import type { Payload } from '../client'; @@ -72,7 +72,7 @@ export class Databases extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'get', uri, { @@ -81,33 +81,6 @@ export class Databases extends Service { }, apiPayload, ); - const defaults = { - root: 'transactionList', - models: { - transactionList: { - defaults: { - total: 0, - }, - properties: { - transactions: { - items: 'transaction', - }, - }, - }, - transaction: { - defaults: { - $id: '', - $createdAt: '', - $updatedAt: '', - status: 'pending', - operations: 0, - expiresAt: '', - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** @@ -156,7 +129,7 @@ export class Databases extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'post', uri, { @@ -166,23 +139,6 @@ export class Databases extends Service { }, apiPayload, ); - const defaults = { - root: 'transaction', - models: { - transaction: { - defaults: { - $id: '', - $createdAt: '', - $updatedAt: '', - status: 'pending', - operations: 0, - expiresAt: '', - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** @@ -237,7 +193,7 @@ export class Databases extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'get', uri, { @@ -246,23 +202,6 @@ export class Databases extends Service { }, apiPayload, ); - const defaults = { - root: 'transaction', - models: { - transaction: { - defaults: { - $id: '', - $createdAt: '', - $updatedAt: '', - status: 'pending', - operations: 0, - expiresAt: '', - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** @@ -350,7 +289,7 @@ export class Databases extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'patch', uri, { @@ -360,23 +299,6 @@ export class Databases extends Service { }, apiPayload, ); - const defaults = { - root: 'transaction', - models: { - transaction: { - defaults: { - $id: '', - $createdAt: '', - $updatedAt: '', - status: 'pending', - operations: 0, - expiresAt: '', - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** @@ -511,7 +433,7 @@ export class Databases extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'post', uri, { @@ -521,23 +443,6 @@ export class Databases extends Service { }, apiPayload, ); - const defaults = { - root: 'transaction', - models: { - transaction: { - defaults: { - $id: '', - $createdAt: '', - $updatedAt: '', - status: 'pending', - operations: 0, - expiresAt: '', - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** @@ -675,7 +580,7 @@ export class Databases extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'get', uri, { @@ -684,33 +589,6 @@ export class Databases extends Service { }, apiPayload, ); - const defaults = { - root: 'documentList', - models: { - documentList: { - defaults: { - total: 0, - }, - properties: { - documents: { - items: 'document', - }, - }, - }, - document: { - defaults: { - $id: '', - $sequence: '', - $collectionId: '', - $databaseId: '', - $createdAt: '', - $updatedAt: '', - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** @@ -883,7 +761,7 @@ export class Databases extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'post', uri, { @@ -893,23 +771,6 @@ export class Databases extends Service { }, apiPayload, ); - const defaults = { - root: 'document', - models: { - document: { - defaults: { - $id: '', - $sequence: '', - $collectionId: '', - $databaseId: '', - $createdAt: '', - $updatedAt: '', - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1040,7 +901,7 @@ export class Databases extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'get', uri, { @@ -1049,23 +910,6 @@ export class Databases extends Service { }, apiPayload, ); - const defaults = { - root: 'document', - models: { - document: { - defaults: { - $id: '', - $sequence: '', - $collectionId: '', - $databaseId: '', - $createdAt: '', - $updatedAt: '', - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1236,7 +1080,7 @@ export class Databases extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'put', uri, { @@ -1246,23 +1090,6 @@ export class Databases extends Service { }, apiPayload, ); - const defaults = { - root: 'document', - models: { - document: { - defaults: { - $id: '', - $sequence: '', - $collectionId: '', - $databaseId: '', - $createdAt: '', - $updatedAt: '', - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1433,7 +1260,7 @@ export class Databases extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'patch', uri, { @@ -1443,23 +1270,6 @@ export class Databases extends Service { }, apiPayload, ); - const defaults = { - root: 'document', - models: { - document: { - defaults: { - $id: '', - $sequence: '', - $collectionId: '', - $databaseId: '', - $createdAt: '', - $updatedAt: '', - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1745,7 +1555,7 @@ export class Databases extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'patch', uri, { @@ -1755,23 +1565,6 @@ export class Databases extends Service { }, apiPayload, ); - const defaults = { - root: 'document', - models: { - document: { - defaults: { - $id: '', - $sequence: '', - $collectionId: '', - $databaseId: '', - $createdAt: '', - $updatedAt: '', - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1932,7 +1725,7 @@ export class Databases extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'patch', uri, { @@ -1942,22 +1735,5 @@ export class Databases extends Service { }, apiPayload, ); - const defaults = { - root: 'document', - models: { - document: { - defaults: { - $id: '', - $sequence: '', - $collectionId: '', - $databaseId: '', - $createdAt: '', - $updatedAt: '', - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } } diff --git a/src/services/documents-db.ts b/src/services/documents-db.ts index 6efc2e4b..6f10966e 100644 --- a/src/services/documents-db.ts +++ b/src/services/documents-db.ts @@ -1,5 +1,5 @@ import { Service } from '../service'; -import { AppwriteException, Client, applyDefaults } from '../client'; +import { AppwriteException, Client } from '../client'; import type { Models } from '../models'; import type { Payload } from '../client'; @@ -71,7 +71,7 @@ export class DocumentsDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'get', uri, { @@ -80,33 +80,6 @@ export class DocumentsDB extends Service { }, apiPayload, ); - const defaults = { - root: 'transactionList', - models: { - transactionList: { - defaults: { - total: 0, - }, - properties: { - transactions: { - items: 'transaction', - }, - }, - }, - transaction: { - defaults: { - $id: '', - $createdAt: '', - $updatedAt: '', - status: 'pending', - operations: 0, - expiresAt: '', - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** @@ -154,7 +127,7 @@ export class DocumentsDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'post', uri, { @@ -164,23 +137,6 @@ export class DocumentsDB extends Service { }, apiPayload, ); - const defaults = { - root: 'transaction', - models: { - transaction: { - defaults: { - $id: '', - $createdAt: '', - $updatedAt: '', - status: 'pending', - operations: 0, - expiresAt: '', - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** @@ -234,7 +190,7 @@ export class DocumentsDB extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'get', uri, { @@ -243,23 +199,6 @@ export class DocumentsDB extends Service { }, apiPayload, ); - const defaults = { - root: 'transaction', - models: { - transaction: { - defaults: { - $id: '', - $createdAt: '', - $updatedAt: '', - status: 'pending', - operations: 0, - expiresAt: '', - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** @@ -346,7 +285,7 @@ export class DocumentsDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'patch', uri, { @@ -356,23 +295,6 @@ export class DocumentsDB extends Service { }, apiPayload, ); - const defaults = { - root: 'transaction', - models: { - transaction: { - defaults: { - $id: '', - $createdAt: '', - $updatedAt: '', - status: 'pending', - operations: 0, - expiresAt: '', - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** @@ -505,7 +427,7 @@ export class DocumentsDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'post', uri, { @@ -515,23 +437,6 @@ export class DocumentsDB extends Service { }, apiPayload, ); - const defaults = { - root: 'transaction', - models: { - transaction: { - defaults: { - $id: '', - $createdAt: '', - $updatedAt: '', - status: 'pending', - operations: 0, - expiresAt: '', - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** @@ -668,7 +573,7 @@ export class DocumentsDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'get', uri, { @@ -677,33 +582,6 @@ export class DocumentsDB extends Service { }, apiPayload, ); - const defaults = { - root: 'documentList', - models: { - documentList: { - defaults: { - total: 0, - }, - properties: { - documents: { - items: 'document', - }, - }, - }, - document: { - defaults: { - $id: '', - $sequence: '', - $collectionId: '', - $databaseId: '', - $createdAt: '', - $updatedAt: '', - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** @@ -875,7 +753,7 @@ export class DocumentsDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'post', uri, { @@ -885,23 +763,6 @@ export class DocumentsDB extends Service { }, apiPayload, ); - const defaults = { - root: 'document', - models: { - document: { - defaults: { - $id: '', - $sequence: '', - $collectionId: '', - $databaseId: '', - $createdAt: '', - $updatedAt: '', - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1018,7 +879,7 @@ export class DocumentsDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'post', uri, { @@ -1028,33 +889,6 @@ export class DocumentsDB extends Service { }, apiPayload, ); - const defaults = { - root: 'documentList', - models: { - documentList: { - defaults: { - total: 0, - }, - properties: { - documents: { - items: 'document', - }, - }, - }, - document: { - defaults: { - $id: '', - $sequence: '', - $collectionId: '', - $databaseId: '', - $createdAt: '', - $updatedAt: '', - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1184,7 +1018,7 @@ export class DocumentsDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'get', uri, { @@ -1193,23 +1027,6 @@ export class DocumentsDB extends Service { }, apiPayload, ); - const defaults = { - root: 'document', - models: { - document: { - defaults: { - $id: '', - $sequence: '', - $collectionId: '', - $databaseId: '', - $createdAt: '', - $updatedAt: '', - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1379,7 +1196,7 @@ export class DocumentsDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'put', uri, { @@ -1389,23 +1206,6 @@ export class DocumentsDB extends Service { }, apiPayload, ); - const defaults = { - root: 'document', - models: { - document: { - defaults: { - $id: '', - $sequence: '', - $collectionId: '', - $databaseId: '', - $createdAt: '', - $updatedAt: '', - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1575,7 +1375,7 @@ export class DocumentsDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'patch', uri, { @@ -1585,23 +1385,6 @@ export class DocumentsDB extends Service { }, apiPayload, ); - const defaults = { - root: 'document', - models: { - document: { - defaults: { - $id: '', - $sequence: '', - $collectionId: '', - $databaseId: '', - $createdAt: '', - $updatedAt: '', - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1885,7 +1668,7 @@ export class DocumentsDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'patch', uri, { @@ -1895,23 +1678,6 @@ export class DocumentsDB extends Service { }, apiPayload, ); - const defaults = { - root: 'document', - models: { - document: { - defaults: { - $id: '', - $sequence: '', - $collectionId: '', - $databaseId: '', - $createdAt: '', - $updatedAt: '', - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** @@ -2071,7 +1837,7 @@ export class DocumentsDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'patch', uri, { @@ -2081,22 +1847,5 @@ export class DocumentsDB extends Service { }, apiPayload, ); - const defaults = { - root: 'document', - models: { - document: { - defaults: { - $id: '', - $sequence: '', - $collectionId: '', - $databaseId: '', - $createdAt: '', - $updatedAt: '', - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } } diff --git a/src/services/functions.ts b/src/services/functions.ts index 54a4b2b7..230ffe70 100644 --- a/src/services/functions.ts +++ b/src/services/functions.ts @@ -1,5 +1,5 @@ import { Service } from '../service'; -import { AppwriteException, Client, applyDefaults } from '../client'; +import { AppwriteException, Client } from '../client'; import type { Models } from '../models'; import type { Payload } from '../client'; @@ -89,7 +89,7 @@ export class Functions extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'get', uri, { @@ -98,54 +98,6 @@ export class Functions extends Service { }, apiPayload, ); - const defaults = { - root: 'executionList', - models: { - executionList: { - defaults: { - total: 0, - }, - properties: { - executions: { - items: 'execution', - }, - }, - }, - execution: { - defaults: { - $id: '', - $createdAt: '', - $updatedAt: '', - resourceId: '', - resourceType: 'functions', - deploymentId: '', - requestMethod: '', - requestPath: '', - responseStatusCode: 0, - responseBody: '', - logs: '', - errors: '', - duration: 0, - }, - properties: { - requestHeaders: { - items: 'headers', - }, - responseHeaders: { - items: 'headers', - }, - }, - }, - headers: { - defaults: { - name: '', - value: '', - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** @@ -295,7 +247,7 @@ export class Functions extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'post', uri, { @@ -305,44 +257,6 @@ export class Functions extends Service { }, apiPayload, ); - const defaults = { - root: 'execution', - models: { - execution: { - defaults: { - $id: '', - $createdAt: '', - $updatedAt: '', - resourceId: '', - resourceType: 'functions', - deploymentId: '', - requestMethod: '', - requestPath: '', - responseStatusCode: 0, - responseBody: '', - logs: '', - errors: '', - duration: 0, - }, - properties: { - requestHeaders: { - items: 'headers', - }, - responseHeaders: { - items: 'headers', - }, - }, - }, - headers: { - defaults: { - name: '', - value: '', - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** @@ -413,7 +327,7 @@ export class Functions extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'get', uri, { @@ -422,43 +336,5 @@ export class Functions extends Service { }, apiPayload, ); - const defaults = { - root: 'execution', - models: { - execution: { - defaults: { - $id: '', - $createdAt: '', - $updatedAt: '', - resourceId: '', - resourceType: 'functions', - deploymentId: '', - requestMethod: '', - requestPath: '', - responseStatusCode: 0, - responseBody: '', - logs: '', - errors: '', - duration: 0, - }, - properties: { - requestHeaders: { - items: 'headers', - }, - responseHeaders: { - items: 'headers', - }, - }, - }, - headers: { - defaults: { - name: '', - value: '', - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } } diff --git a/src/services/locale.ts b/src/services/locale.ts index 6eaeb512..ce9e92b2 100644 --- a/src/services/locale.ts +++ b/src/services/locale.ts @@ -1,5 +1,5 @@ import { Service } from '../service'; -import { Client, applyDefaults } from '../client'; +import { Client } from '../client'; import type { Models } from '../models'; import type { Payload } from '../client'; @@ -21,7 +21,7 @@ export class Locale extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'get', uri, { @@ -30,24 +30,6 @@ export class Locale extends Service { }, apiPayload, ); - const defaults = { - root: 'locale', - models: { - locale: { - defaults: { - ip: '', - countryCode: '', - country: '', - continentCode: '', - continent: '', - eu: false, - currency: '', - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** @@ -95,7 +77,7 @@ export class Locale extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'get', uri, { @@ -104,29 +86,6 @@ export class Locale extends Service { }, apiPayload, ); - const defaults = { - root: 'localeCodeList', - models: { - localeCodeList: { - defaults: { - total: 0, - }, - properties: { - localeCodes: { - items: 'localeCode', - }, - }, - }, - localeCode: { - defaults: { - code: '', - name: '', - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** @@ -174,7 +133,7 @@ export class Locale extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'get', uri, { @@ -183,29 +142,6 @@ export class Locale extends Service { }, apiPayload, ); - const defaults = { - root: 'continentList', - models: { - continentList: { - defaults: { - total: 0, - }, - properties: { - continents: { - items: 'continent', - }, - }, - }, - continent: { - defaults: { - name: '', - code: '', - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** @@ -253,7 +189,7 @@ export class Locale extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'get', uri, { @@ -262,29 +198,6 @@ export class Locale extends Service { }, apiPayload, ); - const defaults = { - root: 'countryList', - models: { - countryList: { - defaults: { - total: 0, - }, - properties: { - countries: { - items: 'country', - }, - }, - }, - country: { - defaults: { - name: '', - code: '', - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** @@ -332,7 +245,7 @@ export class Locale extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'get', uri, { @@ -341,29 +254,6 @@ export class Locale extends Service { }, apiPayload, ); - const defaults = { - root: 'countryList', - models: { - countryList: { - defaults: { - total: 0, - }, - properties: { - countries: { - items: 'country', - }, - }, - }, - country: { - defaults: { - name: '', - code: '', - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** @@ -413,7 +303,7 @@ export class Locale extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'get', uri, { @@ -422,30 +312,6 @@ export class Locale extends Service { }, apiPayload, ); - const defaults = { - root: 'phoneList', - models: { - phoneList: { - defaults: { - total: 0, - }, - properties: { - phones: { - items: 'phone', - }, - }, - }, - phone: { - defaults: { - code: '', - countryCode: '', - countryName: '', - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** @@ -493,7 +359,7 @@ export class Locale extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'get', uri, { @@ -502,34 +368,6 @@ export class Locale extends Service { }, apiPayload, ); - const defaults = { - root: 'currencyList', - models: { - currencyList: { - defaults: { - total: 0, - }, - properties: { - currencies: { - items: 'currency', - }, - }, - }, - currency: { - defaults: { - symbol: '', - name: '', - symbolNative: '', - decimalDigits: 0, - rounding: 0, - code: '', - namePlural: '', - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** @@ -577,7 +415,7 @@ export class Locale extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'get', uri, { @@ -586,29 +424,5 @@ export class Locale extends Service { }, apiPayload, ); - const defaults = { - root: 'languageList', - models: { - languageList: { - defaults: { - total: 0, - }, - properties: { - languages: { - items: 'language', - }, - }, - }, - language: { - defaults: { - name: '', - code: '', - nativeName: '', - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } } diff --git a/src/services/messaging.ts b/src/services/messaging.ts index b1939ddf..33e94c19 100644 --- a/src/services/messaging.ts +++ b/src/services/messaging.ts @@ -1,5 +1,5 @@ import { Service } from '../service'; -import { AppwriteException, Client, applyDefaults } from '../client'; +import { AppwriteException, Client } from '../client'; import type { Models } from '../models'; import type { Payload } from '../client'; @@ -100,7 +100,7 @@ export class Messaging extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'post', uri, { @@ -110,25 +110,6 @@ export class Messaging extends Service { }, apiPayload, ); - const defaults = { - root: 'subscriber', - models: { - subscriber: { - defaults: { - $id: '', - $createdAt: '', - $updatedAt: '', - targetId: '', - userId: '', - userName: '', - topicId: '', - providerType: '', - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** diff --git a/src/services/oauth-2.ts b/src/services/oauth-2.ts index cbcaf3ad..1920bc1a 100644 --- a/src/services/oauth-2.ts +++ b/src/services/oauth-2.ts @@ -1,5 +1,5 @@ import { Service } from '../service'; -import { AppwriteException, Client, applyDefaults } from '../client'; +import { AppwriteException, Client } from '../client'; import type { Models } from '../models'; import type { Payload } from '../client'; @@ -96,7 +96,7 @@ export class Oauth2 extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'post', uri, { @@ -105,18 +105,6 @@ export class Oauth2 extends Service { }, apiPayload, ); - const defaults = { - root: 'oauth2Approve', - models: { - oauth2Approve: { - defaults: { - redirectUrl: '', - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** @@ -133,7 +121,7 @@ export class Oauth2 extends Service { * @param {string} params.prompt - OIDC prompt parameter for customization of consent screen. Space-separated list of: none, login, consent, select_account. * @param {number} params.maxAge - OIDC max_age paraleter for customization of consent screen. Maximum allowable elapsed time in seconds since the user last authenticated. If exceeded, re-authentication is required. * @param {string} params.authorizationDetails - Rich authorization request. JSON array of objects, each with a `type` and project-defined fields - * @param {string[]} params.resource - RFC 8707 resource indicator URI or URI list. Each value must be an absolute URI without a fragment. + * @param {string} params.resource - RFC 8707 resource indicator URI or URI list. Each value must be an absolute URI without a fragment. * @param {string} params.audience - Compatibility alias for a single OAuth2 resource indicator URI. * @param {string} params.requestUri - OAuth2 authorization request handle returned by the pushed authorization request endpoint. * @throws {AppwriteException} @@ -151,7 +139,7 @@ export class Oauth2 extends Service { prompt?: string; maxAge?: number; authorizationDetails?: string; - resource?: string[]; + resource?: string; audience?: string; requestUri?: string; }): Promise; @@ -169,7 +157,7 @@ export class Oauth2 extends Service { * @param {string} prompt - OIDC prompt parameter for customization of consent screen. Space-separated list of: none, login, consent, select_account. * @param {number} maxAge - OIDC max_age paraleter for customization of consent screen. Maximum allowable elapsed time in seconds since the user last authenticated. If exceeded, re-authentication is required. * @param {string} authorizationDetails - Rich authorization request. JSON array of objects, each with a `type` and project-defined fields - * @param {string[]} resource - RFC 8707 resource indicator URI or URI list. Each value must be an absolute URI without a fragment. + * @param {string} resource - RFC 8707 resource indicator URI or URI list. Each value must be an absolute URI without a fragment. * @param {string} audience - Compatibility alias for a single OAuth2 resource indicator URI. * @param {string} requestUri - OAuth2 authorization request handle returned by the pushed authorization request endpoint. * @throws {AppwriteException} @@ -188,7 +176,7 @@ export class Oauth2 extends Service { prompt?: string, maxAge?: number, authorizationDetails?: string, - resource?: string[], + resource?: string, audience?: string, requestUri?: string, ): Promise; @@ -206,7 +194,7 @@ export class Oauth2 extends Service { prompt?: string; maxAge?: number; authorizationDetails?: string; - resource?: string[]; + resource?: string; audience?: string; requestUri?: string; } @@ -222,7 +210,7 @@ export class Oauth2 extends Service { string?, number?, string?, - string[]?, + string?, string?, string?, ] @@ -239,7 +227,7 @@ export class Oauth2 extends Service { prompt?: string; maxAge?: number; authorizationDetails?: string; - resource?: string[]; + resource?: string; audience?: string; requestUri?: string; }; @@ -262,7 +250,7 @@ export class Oauth2 extends Service { prompt?: string; maxAge?: number; authorizationDetails?: string; - resource?: string[]; + resource?: string; audience?: string; requestUri?: string; }; @@ -279,7 +267,7 @@ export class Oauth2 extends Service { prompt: rest[7] as string, maxAge: rest[8] as number, authorizationDetails: rest[9] as string, - resource: rest[10] as string[], + resource: rest[10] as string, audience: rest[11] as string, requestUri: rest[12] as string, }; @@ -363,7 +351,7 @@ export class Oauth2 extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'get', uri, { @@ -371,19 +359,6 @@ export class Oauth2 extends Service { }, apiPayload, ); - const defaults = { - root: 'oauth2Authorize', - models: { - oauth2Authorize: { - defaults: { - grantId: '', - redirectUrl: '', - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** @@ -400,7 +375,7 @@ export class Oauth2 extends Service { * @param {string} params.prompt - OIDC prompt parameter for customization of consent screen. Space-separated list of: none, login, consent, select_account. * @param {number} params.maxAge - OIDC max_age paraleter for customization of consent screen. Maximum allowable elapsed time in seconds since the user last authenticated. If exceeded, re-authentication is required. * @param {string} params.authorizationDetails - Rich authorization request. JSON array of objects, each with a `type` and project-defined fields - * @param {string[]} params.resource - RFC 8707 resource indicator URI or URI list. Each value must be an absolute URI without a fragment. + * @param {string} params.resource - RFC 8707 resource indicator URI or URI list. Each value must be an absolute URI without a fragment. * @param {string} params.audience - Compatibility alias for a single OAuth2 resource indicator URI. * @param {string} params.requestUri - OAuth2 authorization request handle returned by the pushed authorization request endpoint. * @throws {AppwriteException} @@ -418,7 +393,7 @@ export class Oauth2 extends Service { prompt?: string; maxAge?: number; authorizationDetails?: string; - resource?: string[]; + resource?: string; audience?: string; requestUri?: string; }): Promise; @@ -436,7 +411,7 @@ export class Oauth2 extends Service { * @param {string} prompt - OIDC prompt parameter for customization of consent screen. Space-separated list of: none, login, consent, select_account. * @param {number} maxAge - OIDC max_age paraleter for customization of consent screen. Maximum allowable elapsed time in seconds since the user last authenticated. If exceeded, re-authentication is required. * @param {string} authorizationDetails - Rich authorization request. JSON array of objects, each with a `type` and project-defined fields - * @param {string[]} resource - RFC 8707 resource indicator URI or URI list. Each value must be an absolute URI without a fragment. + * @param {string} resource - RFC 8707 resource indicator URI or URI list. Each value must be an absolute URI without a fragment. * @param {string} audience - Compatibility alias for a single OAuth2 resource indicator URI. * @param {string} requestUri - OAuth2 authorization request handle returned by the pushed authorization request endpoint. * @throws {AppwriteException} @@ -455,7 +430,7 @@ export class Oauth2 extends Service { prompt?: string, maxAge?: number, authorizationDetails?: string, - resource?: string[], + resource?: string, audience?: string, requestUri?: string, ): Promise; @@ -473,7 +448,7 @@ export class Oauth2 extends Service { prompt?: string; maxAge?: number; authorizationDetails?: string; - resource?: string[]; + resource?: string; audience?: string; requestUri?: string; } @@ -489,7 +464,7 @@ export class Oauth2 extends Service { string?, number?, string?, - string[]?, + string?, string?, string?, ] @@ -506,7 +481,7 @@ export class Oauth2 extends Service { prompt?: string; maxAge?: number; authorizationDetails?: string; - resource?: string[]; + resource?: string; audience?: string; requestUri?: string; }; @@ -529,7 +504,7 @@ export class Oauth2 extends Service { prompt?: string; maxAge?: number; authorizationDetails?: string; - resource?: string[]; + resource?: string; audience?: string; requestUri?: string; }; @@ -546,7 +521,7 @@ export class Oauth2 extends Service { prompt: rest[7] as string, maxAge: rest[8] as number, authorizationDetails: rest[9] as string, - resource: rest[10] as string[], + resource: rest[10] as string, audience: rest[11] as string, requestUri: rest[12] as string, }; @@ -630,7 +605,7 @@ export class Oauth2 extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'post', uri, { @@ -639,19 +614,6 @@ export class Oauth2 extends Service { }, apiPayload, ); - const defaults = { - root: 'oauth2Authorize', - models: { - oauth2Authorize: { - defaults: { - grantId: '', - redirectUrl: '', - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** @@ -660,7 +622,7 @@ export class Oauth2 extends Service { * @param {string} params.clientId - OAuth2 client ID. Either a registered app ID or an HTTPS client ID metadata document URL. * @param {string} params.scope - Space-separated OAuth2 scopes. Can include project scopes, and built-in scopes: `openid`, `email`, `profile`. * @param {string} params.authorizationDetails - Rich authorization request. JSON array of objects, each with a `type` and project-defined fields - * @param {string[]} params.resource - RFC 8707 resource indicator URI or URI list. Each value must be an absolute URI without a fragment. + * @param {string} params.resource - RFC 8707 resource indicator URI or URI list. Each value must be an absolute URI without a fragment. * @param {string} params.audience - Compatibility alias for a single OAuth2 resource indicator URI. * @throws {AppwriteException} * @returns {Promise} @@ -669,7 +631,7 @@ export class Oauth2 extends Service { clientId?: string; scope?: string; authorizationDetails?: string; - resource?: string[]; + resource?: string; audience?: string; }): Promise; /** @@ -678,7 +640,7 @@ export class Oauth2 extends Service { * @param {string} clientId - OAuth2 client ID. Either a registered app ID or an HTTPS client ID metadata document URL. * @param {string} scope - Space-separated OAuth2 scopes. Can include project scopes, and built-in scopes: `openid`, `email`, `profile`. * @param {string} authorizationDetails - Rich authorization request. JSON array of objects, each with a `type` and project-defined fields - * @param {string[]} resource - RFC 8707 resource indicator URI or URI list. Each value must be an absolute URI without a fragment. + * @param {string} resource - RFC 8707 resource indicator URI or URI list. Each value must be an absolute URI without a fragment. * @param {string} audience - Compatibility alias for a single OAuth2 resource indicator URI. * @throws {AppwriteException} * @returns {Promise} @@ -688,7 +650,7 @@ export class Oauth2 extends Service { clientId?: string, scope?: string, authorizationDetails?: string, - resource?: string[], + resource?: string, audience?: string, ): Promise; createDeviceAuthorization( @@ -697,17 +659,17 @@ export class Oauth2 extends Service { clientId?: string; scope?: string; authorizationDetails?: string; - resource?: string[]; + resource?: string; audience?: string; } | string, - ...rest: [string?, string?, string[]?, string?] + ...rest: [string?, string?, string?, string?] ): Promise { let params: { clientId?: string; scope?: string; authorizationDetails?: string; - resource?: string[]; + resource?: string; audience?: string; }; @@ -721,7 +683,7 @@ export class Oauth2 extends Service { clientId?: string; scope?: string; authorizationDetails?: string; - resource?: string[]; + resource?: string; audience?: string; }; } else { @@ -729,7 +691,7 @@ export class Oauth2 extends Service { clientId: paramsOrFirst as string, scope: rest[0] as string, authorizationDetails: rest[1] as string, - resource: rest[2] as string[], + resource: rest[2] as string, audience: rest[3] as string, }; } @@ -767,7 +729,7 @@ export class Oauth2 extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'post', uri, { @@ -776,23 +738,6 @@ export class Oauth2 extends Service { }, apiPayload, ); - const defaults = { - root: 'oauth2DeviceAuthorization', - models: { - oauth2DeviceAuthorization: { - defaults: { - device_code: '', - user_code: '', - verification_uri: '', - verification_uri_complete: '', - expires_in: 0, - interval: 0, - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** @@ -848,7 +793,7 @@ export class Oauth2 extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'post', uri, { @@ -857,29 +802,6 @@ export class Oauth2 extends Service { }, apiPayload, ); - const defaults = { - root: 'oauth2Grant', - models: { - oauth2Grant: { - defaults: { - $id: '', - $createdAt: '', - $updatedAt: '', - userId: '', - appId: '', - scopes: [], - resources: [], - authorizationDetails: '[]', - prompt: '', - redirectUri: '', - authTime: 0, - expire: '', - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** @@ -933,7 +855,7 @@ export class Oauth2 extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'get', uri, { @@ -941,29 +863,6 @@ export class Oauth2 extends Service { }, apiPayload, ); - const defaults = { - root: 'oauth2Grant', - models: { - oauth2Grant: { - defaults: { - $id: '', - $createdAt: '', - $updatedAt: '', - userId: '', - appId: '', - scopes: [], - resources: [], - authorizationDetails: '[]', - prompt: '', - redirectUri: '', - authTime: 0, - expire: '', - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1317,7 +1216,7 @@ export class Oauth2 extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'get', uri, { @@ -1325,28 +1224,6 @@ export class Oauth2 extends Service { }, apiPayload, ); - const defaults = { - root: 'oauth2OrganizationList', - models: { - oauth2OrganizationList: { - defaults: { - total: 0, - }, - properties: { - organizations: { - items: 'oauth2Organization', - }, - }, - }, - oauth2Organization: { - defaults: { - $id: '', - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1363,7 +1240,7 @@ export class Oauth2 extends Service { * @param {string} params.prompt - OIDC prompt parameter for customization of consent screen. Space-separated list of: none, login, consent, select_account. * @param {number} params.maxAge - OIDC max_age parameter for customization of consent screen. * @param {string} params.authorizationDetails - Rich authorization request. JSON array of objects, each with a `type` and project-defined fields - * @param {string[]} params.resource - RFC 8707 resource indicator URI or URI list. Each value must be an absolute URI without a fragment. + * @param {string} params.resource - RFC 8707 resource indicator URI or URI list. Each value must be an absolute URI without a fragment. * @param {string} params.audience - Compatibility alias for a single OAuth2 resource indicator URI. * @throws {AppwriteException} * @returns {Promise} @@ -1380,7 +1257,7 @@ export class Oauth2 extends Service { prompt?: string; maxAge?: number; authorizationDetails?: string; - resource?: string[]; + resource?: string; audience?: string; }): Promise; /** @@ -1397,7 +1274,7 @@ export class Oauth2 extends Service { * @param {string} prompt - OIDC prompt parameter for customization of consent screen. Space-separated list of: none, login, consent, select_account. * @param {number} maxAge - OIDC max_age parameter for customization of consent screen. * @param {string} authorizationDetails - Rich authorization request. JSON array of objects, each with a `type` and project-defined fields - * @param {string[]} resource - RFC 8707 resource indicator URI or URI list. Each value must be an absolute URI without a fragment. + * @param {string} resource - RFC 8707 resource indicator URI or URI list. Each value must be an absolute URI without a fragment. * @param {string} audience - Compatibility alias for a single OAuth2 resource indicator URI. * @throws {AppwriteException} * @returns {Promise} @@ -1415,7 +1292,7 @@ export class Oauth2 extends Service { prompt?: string, maxAge?: number, authorizationDetails?: string, - resource?: string[], + resource?: string, audience?: string, ): Promise; createPAR( @@ -1432,7 +1309,7 @@ export class Oauth2 extends Service { prompt?: string; maxAge?: number; authorizationDetails?: string; - resource?: string[]; + resource?: string; audience?: string; } | string, @@ -1447,7 +1324,7 @@ export class Oauth2 extends Service { string?, number?, string?, - string[]?, + string?, string?, ] ): Promise { @@ -1463,7 +1340,7 @@ export class Oauth2 extends Service { prompt?: string; maxAge?: number; authorizationDetails?: string; - resource?: string[]; + resource?: string; audience?: string; }; @@ -1484,7 +1361,7 @@ export class Oauth2 extends Service { prompt?: string; maxAge?: number; authorizationDetails?: string; - resource?: string[]; + resource?: string; audience?: string; }; } else { @@ -1500,7 +1377,7 @@ export class Oauth2 extends Service { prompt: rest[7] as string, maxAge: rest[8] as number, authorizationDetails: rest[9] as string, - resource: rest[10] as string[], + resource: rest[10] as string, audience: rest[11] as string, }; } @@ -1596,7 +1473,7 @@ export class Oauth2 extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'post', uri, { @@ -1605,19 +1482,6 @@ export class Oauth2 extends Service { }, apiPayload, ); - const defaults = { - root: 'oauth2PAR', - models: { - oauth2PAR: { - defaults: { - request_uri: '', - expires_in: 0, - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1698,7 +1562,7 @@ export class Oauth2 extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'get', uri, { @@ -1706,30 +1570,6 @@ export class Oauth2 extends Service { }, apiPayload, ); - const defaults = { - root: 'oauth2ProjectList', - models: { - oauth2ProjectList: { - defaults: { - total: 0, - }, - properties: { - projects: { - items: 'oauth2Project', - }, - }, - }, - oauth2Project: { - defaults: { - $id: '', - region: '', - endpoint: '', - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1785,7 +1625,7 @@ export class Oauth2 extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'post', uri, { @@ -1794,18 +1634,6 @@ export class Oauth2 extends Service { }, apiPayload, ); - const defaults = { - root: 'oauth2Reject', - models: { - oauth2Reject: { - defaults: { - redirectUrl: '', - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1933,7 +1761,7 @@ export class Oauth2 extends Service { * @param {string} params.clientSecret - OAuth2 client secret. Required for confidential apps. * @param {string} params.codeVerifier - PKCE code verifier. Required for public apps. * @param {string} params.redirectUri - Redirect URI. Required for `authorization_code` grant type. - * @param {string[]} params.resource - RFC 8707 resource indicator URI or URI list. Each value must be an absolute URI without a fragment. + * @param {string} params.resource - RFC 8707 resource indicator URI or URI list. Each value must be an absolute URI without a fragment. * @param {string} params.audience - Compatibility alias for a single OAuth2 resource indicator URI. * @throws {AppwriteException} * @returns {Promise} @@ -1947,7 +1775,7 @@ export class Oauth2 extends Service { clientSecret?: string; codeVerifier?: string; redirectUri?: string; - resource?: string[]; + resource?: string; audience?: string; }): Promise; /** @@ -1961,7 +1789,7 @@ export class Oauth2 extends Service { * @param {string} clientSecret - OAuth2 client secret. Required for confidential apps. * @param {string} codeVerifier - PKCE code verifier. Required for public apps. * @param {string} redirectUri - Redirect URI. Required for `authorization_code` grant type. - * @param {string[]} resource - RFC 8707 resource indicator URI or URI list. Each value must be an absolute URI without a fragment. + * @param {string} resource - RFC 8707 resource indicator URI or URI list. Each value must be an absolute URI without a fragment. * @param {string} audience - Compatibility alias for a single OAuth2 resource indicator URI. * @throws {AppwriteException} * @returns {Promise} @@ -1976,7 +1804,7 @@ export class Oauth2 extends Service { clientSecret?: string, codeVerifier?: string, redirectUri?: string, - resource?: string[], + resource?: string, audience?: string, ): Promise; createToken( @@ -1990,7 +1818,7 @@ export class Oauth2 extends Service { clientSecret?: string; codeVerifier?: string; redirectUri?: string; - resource?: string[]; + resource?: string; audience?: string; } | string, @@ -2002,7 +1830,7 @@ export class Oauth2 extends Service { string?, string?, string?, - string[]?, + string?, string?, ] ): Promise { @@ -2015,7 +1843,7 @@ export class Oauth2 extends Service { clientSecret?: string; codeVerifier?: string; redirectUri?: string; - resource?: string[]; + resource?: string; audience?: string; }; @@ -2033,7 +1861,7 @@ export class Oauth2 extends Service { clientSecret?: string; codeVerifier?: string; redirectUri?: string; - resource?: string[]; + resource?: string; audience?: string; }; } else { @@ -2046,7 +1874,7 @@ export class Oauth2 extends Service { clientSecret: rest[4] as string, codeVerifier: rest[5] as string, redirectUri: rest[6] as string, - resource: rest[7] as string[], + resource: rest[7] as string, audience: rest[8] as string, }; } @@ -2115,7 +1943,7 @@ export class Oauth2 extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'post', uri, { @@ -2124,21 +1952,5 @@ export class Oauth2 extends Service { }, apiPayload, ); - const defaults = { - root: 'oauth2Token', - models: { - oauth2Token: { - defaults: { - access_token: '', - token_type: 'Bearer', - expires_in: 0, - refresh_token: '', - scope: '', - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } } diff --git a/src/services/organization.ts b/src/services/organization.ts index 3bf9c9b8..3542965f 100644 --- a/src/services/organization.ts +++ b/src/services/organization.ts @@ -1,5 +1,5 @@ import { Service } from '../service'; -import { AppwriteException, Client, applyDefaults } from '../client'; +import { AppwriteException, Client } from '../client'; import type { Models } from '../models'; import type { Payload } from '../client'; @@ -71,7 +71,7 @@ export class Organization extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'get', uri, { @@ -80,36 +80,6 @@ export class Organization extends Service { }, apiPayload, ); - const defaults = { - root: 'appInstallationList', - models: { - appInstallationList: { - defaults: { - total: 0, - }, - properties: { - installations: { - items: 'appInstallation', - }, - }, - }, - appInstallation: { - defaults: { - $id: '', - $createdAt: '', - $updatedAt: '', - appId: '', - teamId: '', - scopes: [], - authorizationDetails: [], - createdById: '', - createdByName: '', - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** @@ -179,7 +149,7 @@ export class Organization extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'post', uri, { @@ -189,26 +159,6 @@ export class Organization extends Service { }, apiPayload, ); - const defaults = { - root: 'appInstallation', - models: { - appInstallation: { - defaults: { - $id: '', - $createdAt: '', - $updatedAt: '', - appId: '', - teamId: '', - scopes: [], - authorizationDetails: [], - createdById: '', - createdByName: '', - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** @@ -262,7 +212,7 @@ export class Organization extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'get', uri, { @@ -271,26 +221,6 @@ export class Organization extends Service { }, apiPayload, ); - const defaults = { - root: 'appInstallation', - models: { - appInstallation: { - defaults: { - $id: '', - $createdAt: '', - $updatedAt: '', - appId: '', - teamId: '', - scopes: [], - authorizationDetails: [], - createdById: '', - createdByName: '', - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** @@ -361,7 +291,7 @@ export class Organization extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'put', uri, { @@ -371,26 +301,6 @@ export class Organization extends Service { }, apiPayload, ); - const defaults = { - root: 'appInstallation', - models: { - appInstallation: { - defaults: { - $id: '', - $createdAt: '', - $updatedAt: '', - appId: '', - teamId: '', - scopes: [], - authorizationDetails: [], - createdById: '', - createdByName: '', - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** diff --git a/src/services/presences.ts b/src/services/presences.ts index 883d330b..5fb3a364 100644 --- a/src/services/presences.ts +++ b/src/services/presences.ts @@ -1,5 +1,5 @@ import { Service } from '../service'; -import { AppwriteException, Client, applyDefaults } from '../client'; +import { AppwriteException, Client } from '../client'; import type { Models } from '../models'; import type { Payload } from '../client'; @@ -85,7 +85,7 @@ export class Presences extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'get', uri, { @@ -94,32 +94,6 @@ export class Presences extends Service { }, apiPayload, ); - const defaults = { - root: 'presenceList', - models: { - presenceList: { - defaults: { - total: 0, - }, - properties: { - presences: { - items: 'presence', - }, - }, - }, - presence: { - defaults: { - $id: '', - $createdAt: '', - $updatedAt: '', - userId: '', - source: '', - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** @@ -173,7 +147,7 @@ export class Presences extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'get', uri, { @@ -182,22 +156,6 @@ export class Presences extends Service { }, apiPayload, ); - const defaults = { - root: 'presence', - models: { - presence: { - defaults: { - $id: '', - $createdAt: '', - $updatedAt: '', - userId: '', - source: '', - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** @@ -320,7 +278,7 @@ export class Presences extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'put', uri, { @@ -330,22 +288,6 @@ export class Presences extends Service { }, apiPayload, ); - const defaults = { - root: 'presence', - models: { - presence: { - defaults: { - $id: '', - $createdAt: '', - $updatedAt: '', - userId: '', - source: '', - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** @@ -477,7 +419,7 @@ export class Presences extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'patch', uri, { @@ -487,22 +429,6 @@ export class Presences extends Service { }, apiPayload, ); - const defaults = { - root: 'presence', - models: { - presence: { - defaults: { - $id: '', - $createdAt: '', - $updatedAt: '', - userId: '', - source: '', - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** diff --git a/src/services/storage.ts b/src/services/storage.ts index c956d2ab..fdca28a8 100644 --- a/src/services/storage.ts +++ b/src/services/storage.ts @@ -1,5 +1,5 @@ import { Service } from '../service'; -import { AppwriteException, Client, applyDefaults } from '../client'; +import { AppwriteException, Client } from '../client'; import type { Models } from '../models'; import type { UploadProgress, Payload } from '../client'; import * as FileSystem from 'expo-file-system'; @@ -113,7 +113,7 @@ export class Storage extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'get', uri, { @@ -122,43 +122,6 @@ export class Storage extends Service { }, apiPayload, ); - const defaults = { - root: 'fileList', - models: { - fileList: { - defaults: { - total: 0, - }, - properties: { - files: { - items: 'file', - }, - }, - }, - file: { - defaults: { - $id: '', - bucketId: '', - $createdAt: '', - $updatedAt: '', - $permissions: [], - name: '', - folder: '', - key: '', - signature: '', - mimeType: '', - sizeOriginal: 0, - sizeActual: 0, - chunksTotal: 0, - chunksUploaded: 0, - encryption: false, - compression: 'none', - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** @@ -600,7 +563,7 @@ export class Storage extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'get', uri, { @@ -609,33 +572,6 @@ export class Storage extends Service { }, apiPayload, ); - const defaults = { - root: 'file', - models: { - file: { - defaults: { - $id: '', - bucketId: '', - $createdAt: '', - $updatedAt: '', - $permissions: [], - name: '', - folder: '', - key: '', - signature: '', - mimeType: '', - sizeOriginal: 0, - sizeActual: 0, - chunksTotal: 0, - chunksUploaded: 0, - encryption: false, - compression: 'none', - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** @@ -738,7 +674,7 @@ export class Storage extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'put', uri, { @@ -748,33 +684,6 @@ export class Storage extends Service { }, apiPayload, ); - const defaults = { - root: 'file', - models: { - file: { - defaults: { - $id: '', - bucketId: '', - $createdAt: '', - $updatedAt: '', - $permissions: [], - name: '', - folder: '', - key: '', - signature: '', - mimeType: '', - sizeOriginal: 0, - sizeActual: 0, - chunksTotal: 0, - chunksUploaded: 0, - encryption: false, - compression: 'none', - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** diff --git a/src/services/tables-db.ts b/src/services/tables-db.ts index a41dc9a5..ae5d11d1 100644 --- a/src/services/tables-db.ts +++ b/src/services/tables-db.ts @@ -1,5 +1,5 @@ import { Service } from '../service'; -import { AppwriteException, Client, applyDefaults } from '../client'; +import { AppwriteException, Client } from '../client'; import type { Models } from '../models'; import type { Payload } from '../client'; @@ -71,7 +71,7 @@ export class TablesDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'get', uri, { @@ -80,33 +80,6 @@ export class TablesDB extends Service { }, apiPayload, ); - const defaults = { - root: 'transactionList', - models: { - transactionList: { - defaults: { - total: 0, - }, - properties: { - transactions: { - items: 'transaction', - }, - }, - }, - transaction: { - defaults: { - $id: '', - $createdAt: '', - $updatedAt: '', - status: 'pending', - operations: 0, - expiresAt: '', - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** @@ -154,7 +127,7 @@ export class TablesDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'post', uri, { @@ -164,23 +137,6 @@ export class TablesDB extends Service { }, apiPayload, ); - const defaults = { - root: 'transaction', - models: { - transaction: { - defaults: { - $id: '', - $createdAt: '', - $updatedAt: '', - status: 'pending', - operations: 0, - expiresAt: '', - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** @@ -234,7 +190,7 @@ export class TablesDB extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'get', uri, { @@ -243,23 +199,6 @@ export class TablesDB extends Service { }, apiPayload, ); - const defaults = { - root: 'transaction', - models: { - transaction: { - defaults: { - $id: '', - $createdAt: '', - $updatedAt: '', - status: 'pending', - operations: 0, - expiresAt: '', - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** @@ -346,7 +285,7 @@ export class TablesDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'patch', uri, { @@ -356,23 +295,6 @@ export class TablesDB extends Service { }, apiPayload, ); - const defaults = { - root: 'transaction', - models: { - transaction: { - defaults: { - $id: '', - $createdAt: '', - $updatedAt: '', - status: 'pending', - operations: 0, - expiresAt: '', - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** @@ -505,7 +427,7 @@ export class TablesDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'post', uri, { @@ -515,23 +437,6 @@ export class TablesDB extends Service { }, apiPayload, ); - const defaults = { - root: 'transaction', - models: { - transaction: { - defaults: { - $id: '', - $createdAt: '', - $updatedAt: '', - status: 'pending', - operations: 0, - expiresAt: '', - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** @@ -662,7 +567,7 @@ export class TablesDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'get', uri, { @@ -671,33 +576,6 @@ export class TablesDB extends Service { }, apiPayload, ); - const defaults = { - root: 'rowList', - models: { - rowList: { - defaults: { - total: 0, - }, - properties: { - rows: { - items: 'row', - }, - }, - }, - row: { - defaults: { - $id: '', - $sequence: '', - $tableId: '', - $databaseId: '', - $createdAt: '', - $updatedAt: '', - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** @@ -856,7 +734,7 @@ export class TablesDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'post', uri, { @@ -866,23 +744,6 @@ export class TablesDB extends Service { }, apiPayload, ); - const defaults = { - root: 'row', - models: { - row: { - defaults: { - $id: '', - $sequence: '', - $tableId: '', - $databaseId: '', - $createdAt: '', - $updatedAt: '', - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1001,7 +862,7 @@ export class TablesDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'get', uri, { @@ -1010,23 +871,6 @@ export class TablesDB extends Service { }, apiPayload, ); - const defaults = { - root: 'row', - models: { - row: { - defaults: { - $id: '', - $sequence: '', - $tableId: '', - $databaseId: '', - $createdAt: '', - $updatedAt: '', - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1181,7 +1025,7 @@ export class TablesDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'put', uri, { @@ -1191,23 +1035,6 @@ export class TablesDB extends Service { }, apiPayload, ); - const defaults = { - root: 'row', - models: { - row: { - defaults: { - $id: '', - $sequence: '', - $tableId: '', - $databaseId: '', - $createdAt: '', - $updatedAt: '', - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1362,7 +1189,7 @@ export class TablesDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'patch', uri, { @@ -1372,23 +1199,6 @@ export class TablesDB extends Service { }, apiPayload, ); - const defaults = { - root: 'row', - models: { - row: { - defaults: { - $id: '', - $sequence: '', - $tableId: '', - $databaseId: '', - $createdAt: '', - $updatedAt: '', - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1650,7 +1460,7 @@ export class TablesDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'patch', uri, { @@ -1660,23 +1470,6 @@ export class TablesDB extends Service { }, apiPayload, ); - const defaults = { - root: 'row', - models: { - row: { - defaults: { - $id: '', - $sequence: '', - $tableId: '', - $databaseId: '', - $createdAt: '', - $updatedAt: '', - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1823,7 +1616,7 @@ export class TablesDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'patch', uri, { @@ -1833,22 +1626,5 @@ export class TablesDB extends Service { }, apiPayload, ); - const defaults = { - root: 'row', - models: { - row: { - defaults: { - $id: '', - $sequence: '', - $tableId: '', - $databaseId: '', - $createdAt: '', - $updatedAt: '', - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } } diff --git a/src/services/teams.ts b/src/services/teams.ts index caf37d38..a4424fcd 100644 --- a/src/services/teams.ts +++ b/src/services/teams.ts @@ -1,5 +1,5 @@ import { Service } from '../service'; -import { AppwriteException, Client, applyDefaults } from '../client'; +import { AppwriteException, Client } from '../client'; import type { Models } from '../models'; import type { Payload } from '../client'; @@ -85,7 +85,7 @@ export class Teams extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'get', uri, { @@ -94,32 +94,6 @@ export class Teams extends Service { }, apiPayload, ); - const defaults = { - root: 'teamList', - models: { - teamList: { - defaults: { - total: 0, - }, - properties: { - teams: { - items: 'team', - }, - }, - }, - team: { - defaults: { - $id: '', - $createdAt: '', - $updatedAt: '', - name: '', - total: 0, - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** @@ -206,7 +180,7 @@ export class Teams extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'post', uri, { @@ -216,22 +190,6 @@ export class Teams extends Service { }, apiPayload, ); - const defaults = { - root: 'team', - models: { - team: { - defaults: { - $id: '', - $createdAt: '', - $updatedAt: '', - name: '', - total: 0, - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** @@ -285,7 +243,7 @@ export class Teams extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'get', uri, { @@ -294,22 +252,6 @@ export class Teams extends Service { }, apiPayload, ); - const defaults = { - root: 'team', - models: { - team: { - defaults: { - $id: '', - $createdAt: '', - $updatedAt: '', - name: '', - total: 0, - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** @@ -381,7 +323,7 @@ export class Teams extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'put', uri, { @@ -391,22 +333,6 @@ export class Teams extends Service { }, apiPayload, ); - const defaults = { - root: 'team', - models: { - team: { - defaults: { - $id: '', - $createdAt: '', - $updatedAt: '', - name: '', - total: 0, - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** @@ -543,7 +469,7 @@ export class Teams extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'get', uri, { @@ -552,36 +478,6 @@ export class Teams extends Service { }, apiPayload, ); - const defaults = { - root: 'appInstallationList', - models: { - appInstallationList: { - defaults: { - total: 0, - }, - properties: { - installations: { - items: 'appInstallation', - }, - }, - }, - appInstallation: { - defaults: { - $id: '', - $createdAt: '', - $updatedAt: '', - appId: '', - teamId: '', - scopes: [], - authorizationDetails: [], - createdById: '', - createdByName: '', - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** @@ -670,7 +566,7 @@ export class Teams extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'post', uri, { @@ -680,26 +576,6 @@ export class Teams extends Service { }, apiPayload, ); - const defaults = { - root: 'appInstallation', - models: { - appInstallation: { - defaults: { - $id: '', - $createdAt: '', - $updatedAt: '', - appId: '', - teamId: '', - scopes: [], - authorizationDetails: [], - createdById: '', - createdByName: '', - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** @@ -771,7 +647,7 @@ export class Teams extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'get', uri, { @@ -780,26 +656,6 @@ export class Teams extends Service { }, apiPayload, ); - const defaults = { - root: 'appInstallation', - models: { - appInstallation: { - defaults: { - $id: '', - $createdAt: '', - $updatedAt: '', - appId: '', - teamId: '', - scopes: [], - authorizationDetails: [], - createdById: '', - createdByName: '', - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** @@ -892,7 +748,7 @@ export class Teams extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'put', uri, { @@ -902,26 +758,6 @@ export class Teams extends Service { }, apiPayload, ); - const defaults = { - root: 'appInstallation', - models: { - appInstallation: { - defaults: { - $id: '', - $createdAt: '', - $updatedAt: '', - appId: '', - teamId: '', - scopes: [], - authorizationDetails: [], - createdById: '', - createdByName: '', - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1101,7 +937,7 @@ export class Teams extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'get', uri, { @@ -1110,42 +946,6 @@ export class Teams extends Service { }, apiPayload, ); - const defaults = { - root: 'membershipList', - models: { - membershipList: { - defaults: { - total: 0, - }, - properties: { - memberships: { - items: 'membership', - }, - }, - }, - membership: { - defaults: { - $id: '', - $createdAt: '', - $updatedAt: '', - userId: '', - userName: '', - userEmail: '', - userPhone: '', - teamId: '', - teamName: '', - invited: '', - joined: '', - confirm: false, - mfa: false, - userAccessedAt: '', - roles: [], - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1160,7 +960,6 @@ export class Teams extends Service { * * @param {string} params.teamId - Team ID. * @param {string[]} params.roles - Array of strings. Use this param to set the user roles in the team. A role can be any string. Learn more about [roles and permissions](https://appwrite.io/docs/permissions). Maximum of 100 roles are allowed, each 81 characters long. - * @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. * @param {string} params.email - Email of the new team member. * @param {string} params.userId - ID of the user to be added to a team. * @param {string} params.phone - Phone number. Format this number with a leading '+' and a country code, e.g., +16175551212. @@ -1172,7 +971,6 @@ export class Teams extends Service { createMembership(params: { teamId: string; roles: string[]; - membershipId?: string; email?: string; userId?: string; phone?: string; @@ -1191,7 +989,6 @@ export class Teams extends Service { * * @param {string} teamId - Team ID. * @param {string[]} roles - Array of strings. Use this param to set the user roles in the team. A role can be any string. Learn more about [roles and permissions](https://appwrite.io/docs/permissions). Maximum of 100 roles are allowed, each 81 characters long. - * @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. * @param {string} email - Email of the new team member. * @param {string} userId - ID of the user to be added to a team. * @param {string} phone - Phone number. Format this number with a leading '+' and a country code, e.g., +16175551212. @@ -1204,7 +1001,6 @@ export class Teams extends Service { createMembership( teamId: string, roles: string[], - membershipId?: string, email?: string, userId?: string, phone?: string, @@ -1216,7 +1012,6 @@ export class Teams extends Service { | { teamId: string; roles: string[]; - membershipId?: string; email?: string; userId?: string; phone?: string; @@ -1224,20 +1019,11 @@ export class Teams extends Service { name?: string; } | string, - ...rest: [ - string[]?, - string?, - string?, - string?, - string?, - string?, - string?, - ] + ...rest: [string[]?, string?, string?, string?, string?, string?] ): Promise { let params: { teamId: string; roles: string[]; - membershipId?: string; email?: string; userId?: string; phone?: string; @@ -1253,7 +1039,6 @@ export class Teams extends Service { params = (paramsOrFirst || {}) as { teamId: string; roles: string[]; - membershipId?: string; email?: string; userId?: string; phone?: string; @@ -1264,18 +1049,16 @@ export class Teams extends Service { params = { teamId: paramsOrFirst as string, roles: rest[0] as string[], - membershipId: rest[1] as string, - email: rest[2] as string, - userId: rest[3] as string, - phone: rest[4] as string, - url: rest[5] as string, - name: rest[6] as string, + email: rest[1] as string, + userId: rest[2] as string, + phone: rest[3] as string, + url: rest[4] as string, + name: rest[5] as string, }; } const teamId = params.teamId; const roles = params.roles; - const membershipId = params.membershipId; const email = params.email; const userId = params.userId; const phone = params.phone; @@ -1296,10 +1079,6 @@ export class Teams extends Service { ); const apiPayload: Payload = {}; - if (typeof membershipId !== 'undefined') { - apiPayload['membershipId'] = membershipId; - } - if (typeof email !== 'undefined') { apiPayload['email'] = email; } @@ -1325,7 +1104,7 @@ export class Teams extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'post', uri, { @@ -1335,32 +1114,6 @@ export class Teams extends Service { }, apiPayload, ); - const defaults = { - root: 'membership', - models: { - membership: { - defaults: { - $id: '', - $createdAt: '', - $updatedAt: '', - userId: '', - userName: '', - userEmail: '', - userPhone: '', - teamId: '', - teamName: '', - invited: '', - joined: '', - confirm: false, - mfa: false, - userAccessedAt: '', - roles: [], - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1432,7 +1185,7 @@ export class Teams extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'get', uri, { @@ -1441,32 +1194,6 @@ export class Teams extends Service { }, apiPayload, ); - const defaults = { - root: 'membership', - models: { - membership: { - defaults: { - $id: '', - $createdAt: '', - $updatedAt: '', - userId: '', - userName: '', - userEmail: '', - userPhone: '', - teamId: '', - teamName: '', - invited: '', - joined: '', - confirm: false, - mfa: false, - userAccessedAt: '', - roles: [], - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1556,7 +1283,7 @@ export class Teams extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'patch', uri, { @@ -1566,32 +1293,6 @@ export class Teams extends Service { }, apiPayload, ); - const defaults = { - root: 'membership', - models: { - membership: { - defaults: { - $id: '', - $createdAt: '', - $updatedAt: '', - userId: '', - userName: '', - userEmail: '', - userPhone: '', - teamId: '', - teamName: '', - invited: '', - joined: '', - confirm: false, - mfa: false, - userAccessedAt: '', - roles: [], - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1789,7 +1490,7 @@ export class Teams extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'patch', uri, { @@ -1799,32 +1500,6 @@ export class Teams extends Service { }, apiPayload, ); - const defaults = { - root: 'membership', - models: { - membership: { - defaults: { - $id: '', - $createdAt: '', - $updatedAt: '', - userId: '', - userName: '', - userEmail: '', - userPhone: '', - teamId: '', - teamName: '', - invited: '', - joined: '', - confirm: false, - mfa: false, - userAccessedAt: '', - roles: [], - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** diff --git a/src/services/vectors-db.ts b/src/services/vectors-db.ts index 1329e910..710e8b44 100644 --- a/src/services/vectors-db.ts +++ b/src/services/vectors-db.ts @@ -1,5 +1,5 @@ import { Service } from '../service'; -import { AppwriteException, Client, applyDefaults } from '../client'; +import { AppwriteException, Client } from '../client'; import type { Models } from '../models'; import type { Payload } from '../client'; @@ -71,7 +71,7 @@ export class VectorsDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'get', uri, { @@ -80,33 +80,6 @@ export class VectorsDB extends Service { }, apiPayload, ); - const defaults = { - root: 'transactionList', - models: { - transactionList: { - defaults: { - total: 0, - }, - properties: { - transactions: { - items: 'transaction', - }, - }, - }, - transaction: { - defaults: { - $id: '', - $createdAt: '', - $updatedAt: '', - status: 'pending', - operations: 0, - expiresAt: '', - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** @@ -154,7 +127,7 @@ export class VectorsDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'post', uri, { @@ -164,23 +137,6 @@ export class VectorsDB extends Service { }, apiPayload, ); - const defaults = { - root: 'transaction', - models: { - transaction: { - defaults: { - $id: '', - $createdAt: '', - $updatedAt: '', - status: 'pending', - operations: 0, - expiresAt: '', - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** @@ -234,7 +190,7 @@ export class VectorsDB extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'get', uri, { @@ -243,23 +199,6 @@ export class VectorsDB extends Service { }, apiPayload, ); - const defaults = { - root: 'transaction', - models: { - transaction: { - defaults: { - $id: '', - $createdAt: '', - $updatedAt: '', - status: 'pending', - operations: 0, - expiresAt: '', - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** @@ -346,7 +285,7 @@ export class VectorsDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'patch', uri, { @@ -356,23 +295,6 @@ export class VectorsDB extends Service { }, apiPayload, ); - const defaults = { - root: 'transaction', - models: { - transaction: { - defaults: { - $id: '', - $createdAt: '', - $updatedAt: '', - status: 'pending', - operations: 0, - expiresAt: '', - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** @@ -505,7 +427,7 @@ export class VectorsDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'post', uri, { @@ -515,23 +437,6 @@ export class VectorsDB extends Service { }, apiPayload, ); - const defaults = { - root: 'transaction', - models: { - transaction: { - defaults: { - $id: '', - $createdAt: '', - $updatedAt: '', - status: 'pending', - operations: 0, - expiresAt: '', - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** @@ -668,7 +573,7 @@ export class VectorsDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'get', uri, { @@ -677,33 +582,6 @@ export class VectorsDB extends Service { }, apiPayload, ); - const defaults = { - root: 'documentList', - models: { - documentList: { - defaults: { - total: 0, - }, - properties: { - documents: { - items: 'document', - }, - }, - }, - document: { - defaults: { - $id: '', - $sequence: '', - $collectionId: '', - $databaseId: '', - $createdAt: '', - $updatedAt: '', - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** @@ -875,7 +753,7 @@ export class VectorsDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'post', uri, { @@ -885,23 +763,6 @@ export class VectorsDB extends Service { }, apiPayload, ); - const defaults = { - root: 'document', - models: { - document: { - defaults: { - $id: '', - $sequence: '', - $collectionId: '', - $databaseId: '', - $createdAt: '', - $updatedAt: '', - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1040,7 +901,7 @@ export class VectorsDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'post', uri, { @@ -1050,33 +911,6 @@ export class VectorsDB extends Service { }, apiPayload, ); - const defaults = { - root: 'documentList', - models: { - documentList: { - defaults: { - total: 0, - }, - properties: { - documents: { - items: 'document', - }, - }, - }, - document: { - defaults: { - $id: '', - $sequence: '', - $collectionId: '', - $databaseId: '', - $createdAt: '', - $updatedAt: '', - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1206,7 +1040,7 @@ export class VectorsDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'get', uri, { @@ -1215,23 +1049,6 @@ export class VectorsDB extends Service { }, apiPayload, ); - const defaults = { - root: 'document', - models: { - document: { - defaults: { - $id: '', - $sequence: '', - $collectionId: '', - $databaseId: '', - $createdAt: '', - $updatedAt: '', - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1401,7 +1218,7 @@ export class VectorsDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'put', uri, { @@ -1411,23 +1228,6 @@ export class VectorsDB extends Service { }, apiPayload, ); - const defaults = { - root: 'document', - models: { - document: { - defaults: { - $id: '', - $sequence: '', - $collectionId: '', - $databaseId: '', - $createdAt: '', - $updatedAt: '', - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1597,7 +1397,7 @@ export class VectorsDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - const request = this.client.call( + return this.client.call( 'patch', uri, { @@ -1607,23 +1407,6 @@ export class VectorsDB extends Service { }, apiPayload, ); - const defaults = { - root: 'document', - models: { - document: { - defaults: { - $id: '', - $sequence: '', - $collectionId: '', - $databaseId: '', - $createdAt: '', - $updatedAt: '', - }, - }, - }, - }; - - return request.then((response) => applyDefaults(response, defaults)); } /** From c863d47e225135904da0b5e1fe7a21b9d2e248bc Mon Sep 17 00:00:00 2001 From: Chirag Aggarwal Date: Wed, 14 Oct 2026 16:39:46 +0100 Subject: [PATCH 3/6] feat: SDK update for the 2.5.x majors --- CHANGELOG.md | 67 +- README.md | 127 +- android/.editorconfig | 39 - android/build.gradle | 40 - android/consumer-rules.pro | 27 - android/src/main/AndroidManifest.xml | 48 - .../appwrite/exceptions/AppwriteException.kt | 6 - .../reactnative/AppwriteCookiesModule.kt | 31 - .../reactnative/AppwritePushModule.kt | 175 -- .../reactnative/AppwritePushPackage.kt | 17 - .../io/appwrite/services/PushBackground.kt | 1457 ---------- .../java/io/appwrite/services/PushBridge.kt | 198 -- .../java/io/appwrite/services/PushCore.kt | 454 --- .../io/appwrite/services/PushOpenActivity.kt | 57 - .../java/io/appwrite/services/PushReceiver.kt | 33 - .../java/io/appwrite/services/PushService.kt | 67 - .../java/io/appwrite/services/PushWakeups.kt | 55 - .../account/create-o-auth-2-session.md | 1 + .../examples/account/create-o-auth-2-token.md | 1 + docs/examples/account/create-passkey-token.md | 13 + docs/examples/account/create-passkey.md | 16 + docs/examples/account/delete-passkey.md | 15 + docs/examples/account/get-passkey.md | 15 + docs/examples/account/list-passkeys.md | 16 + docs/examples/account/update-passkey-token.md | 16 + .../account/update-passkey-verification.md | 16 + docs/examples/account/update-passkey.md | 16 + docs/examples/analytics/create-event.md | 27 + docs/examples/oauth2/authorize-post.md | 2 +- docs/examples/oauth2/authorize.md | 2 +- .../oauth2/create-device-authorization.md | 2 +- docs/examples/oauth2/create-par.md | 2 +- docs/examples/oauth2/create-token.md | 2 +- docs/examples/teams/create-membership.md | 1 + ios/AppwriteCookies.m | 35 - package-lock.json | 4 +- package.json | 7 +- react-native-appwrite.podspec | 21 - react-native.config.js | 12 - src/client.ts | 98 +- src/index.ts | 11 +- src/lib/polyfills.ts | 29 - src/lib/tcp-stream.ts | 125 - src/models.ts | 176 +- src/react-native-shim.d.ts | 130 - src/services/account.ts | 2423 ++++++++++++++++- src/services/analytics.ts | 260 ++ src/services/apps.ts | 572 +++- src/services/databases.ts | 449 ++- src/services/documents-db.ts | 290 +- src/services/functions.ts | 160 +- src/services/locale.ts | 211 +- src/services/messaging.ts | 23 +- src/services/oauth-2.ts | 340 ++- src/services/organization.ts | 123 +- src/services/presences.ts | 89 +- src/services/push.ts | 1909 ------------- src/services/storage.ts | 118 +- src/services/tables-db.ts | 449 ++- src/services/teams.ts | 376 ++- src/services/vectors-db.ts | 250 +- src/topic.ts | 103 - 62 files changed, 6014 insertions(+), 5840 deletions(-) delete mode 100644 android/.editorconfig delete mode 100644 android/build.gradle delete mode 100644 android/consumer-rules.pro delete mode 100644 android/src/main/AndroidManifest.xml delete mode 100644 android/src/main/java/io/appwrite/exceptions/AppwriteException.kt delete mode 100644 android/src/main/java/io/appwrite/reactnative/AppwriteCookiesModule.kt delete mode 100644 android/src/main/java/io/appwrite/reactnative/AppwritePushModule.kt delete mode 100644 android/src/main/java/io/appwrite/reactnative/AppwritePushPackage.kt delete mode 100644 android/src/main/java/io/appwrite/services/PushBackground.kt delete mode 100644 android/src/main/java/io/appwrite/services/PushBridge.kt delete mode 100644 android/src/main/java/io/appwrite/services/PushCore.kt delete mode 100644 android/src/main/java/io/appwrite/services/PushOpenActivity.kt delete mode 100644 android/src/main/java/io/appwrite/services/PushReceiver.kt delete mode 100644 android/src/main/java/io/appwrite/services/PushService.kt delete mode 100644 android/src/main/java/io/appwrite/services/PushWakeups.kt create mode 100644 docs/examples/account/create-passkey-token.md create mode 100644 docs/examples/account/create-passkey.md create mode 100644 docs/examples/account/delete-passkey.md create mode 100644 docs/examples/account/get-passkey.md create mode 100644 docs/examples/account/list-passkeys.md create mode 100644 docs/examples/account/update-passkey-token.md create mode 100644 docs/examples/account/update-passkey-verification.md create mode 100644 docs/examples/account/update-passkey.md create mode 100644 docs/examples/analytics/create-event.md delete mode 100644 ios/AppwriteCookies.m delete mode 100644 react-native-appwrite.podspec delete mode 100644 react-native.config.js delete mode 100644 src/lib/polyfills.ts delete mode 100644 src/lib/tcp-stream.ts create mode 100644 src/services/analytics.ts delete mode 100644 src/services/push.ts delete mode 100644 src/topic.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index c6c7bcb3..78f7ef33 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,50 +1,29 @@ # Change log -## 1.2.0-rc.4 - -* Fixed: `host()` resolves with the live connection state instead of always `null` -* Fixed: `onConnection(false)` fires when a retired or background connection closes -* Fixed: notification taps are recorded after launching the app, so tap-opened screens land on top -* Fixed: `host()` reports `false` when there was nothing to subscribe instead of a spurious open - -## 1.2.0-rc.3 - -* Added: `getInitialNotification()`, `onNotificationOpened()`, and the `PushNotificationOpened` type (topic + data) -* Added: live push connection open/close events surfaced via `onOpen`/`onClose` -* Fixed: notification taps delivered reliably once, via a `PushTaps` queue -* Fixed: foreground notifications de-duplicated per title -* Updated: `resume` leaves a live Push host's connection untouched - -## 1.2.0-rc.2 - -* Added: `Push.getInitialNotification()` returns the notification whose tap launched the app -* Added: `Push.onNotificationOpened(callback)` fires on each notification tap -* Added: `Push.backgroundStatus()` reports Android exact-alarm, battery, and foreground-service state -* Added: `Push.requestExactAlarms()` and `Push.requestIgnoreBatteryOptimizations()` helpers -* Added: `SubscribeOptions.notifyInForeground` to post notifications while the app is visible -* Added: `PushBackgroundStatus` and `PushNotificationOpened` exported types -* Fixed: reliable Android background wake-ups via a periodic watchdog and alternating jobs -* Fixed: `resume` keeps subscriptions only for the same signed-in user -* Fixed: notification images are size-capped to prevent out-of-memory crashes - -## 1.2.0-rc.1 - -* Added: background push notifications render the server `notification` title, body, and image -* Added: Android shows notification images (BigPictureStyle) and long bodies (BigTextStyle) -* Added: the SDK requests Android 13+ `POST_NOTIFICATIONS` itself on first background subscribe -* Added: notification `data` now carries `topic` and `payload` -* Fixed: a server-sent title dedupes to one notification per topic instead of one per subscription - -## 1.2.0-rc.0 - -* Added: `Apps` service to manage OAuth2 apps, keys, secrets, and installations -* Added: `Oauth2` service for authorization, consent, device, PAR, and token flows -* Added: `Push` service for MQTT realtime push with Android background delivery -* Added: `Topic` builder and native TCP modules for push -* Added: `Avatars.updatePhoto()` and `Avatars.deletePhoto()` methods -* Added: `App`, `Oauth2*`, and `Account` models +## 2.0.0 + +* Breaking: requests send `X-Appwrite-Response-Format: 2.5.0`; responses follow the 2.5 shapes +* Breaking: missing response fields are filled with their documented defaults +* Breaking: nullable model fields are typed `T | null`, such as `Locale.city` and `Presence.status` +* Added: `Apps` service to manage apps, installations, keys and secrets +* Added: `Oauth2` service for the OAuth2 authorize, token, device and grant flows + +## 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 -* Fixed: cookie session fallback is guarded to Expo web where `localStorage` exists +* 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` +* Added: `account.createPasskeyToken` and `account.updatePasskeyToken` for passkey sign-in +* Added: `Passkey`, `PasskeyList`, `PasskeyChallenge` and `TokenSecret` models ## 1.1.0 diff --git a/README.md b/README.md index 0ba50f82..9e7e1cdf 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,12 @@ # Appwrite React Native SDK ![License](https://img.shields.io/github/license/appwrite/sdk-for-react-native.svg?style=flat-square) -![Version](https://img.shields.io/badge/api%20version-2.3.0-blue.svg?style=flat-square) +![Version](https://img.shields.io/badge/api%20version-2.5.0-blue.svg?style=flat-square) [![Build Status](https://img.shields.io/travis/com/appwrite/sdk-generator?style=flat-square)](https://travis-ci.com/appwrite/sdk-generator) [![Twitter Account](https://img.shields.io/twitter/follow/appwrite?color=00acee&label=twitter&style=flat-square)](https://twitter.com/appwrite) [![Discord](https://img.shields.io/discord/564160730845151244?label=discord&style=flat-square)](https://appwrite.io/discord) -**This SDK targets Appwrite server version 2.3.x as shipped on Appwrite Cloud.** Self-hosted releases can lag behind Cloud — if you run an older self-hosted build, use a matching older SDK from [previous releases](https://github.com/appwrite/sdk-for-react-native/releases) when APIs differ. +**This SDK targets Appwrite server version 2.5.x as shipped on Appwrite Cloud.** Self-hosted releases can lag behind Cloud — if you run an older self-hosted build, use a matching older SDK from [previous releases](https://github.com/appwrite/sdk-for-react-native/releases) when APIs differ. Appwrite is an open-source backend as a service server that abstracts and simplifies complex and repetitive development tasks behind a very simple to use REST API. Appwrite aims to help you develop your apps faster and in a more secure way. Use the React Native SDK to integrate your app with the Appwrite server to easily start interacting with all of Appwrite backend APIs and tools. For full API documentation and tutorials go to [https://appwrite.io/docs](https://appwrite.io/docs) @@ -20,129 +20,6 @@ To install npx expo install react-native-appwrite react-native-url-polyfill ``` -### Push - -`Push` connects over a raw TCP socket, so it needs `react-native-tcp-socket` and a development -or standalone build (native modules do not run in Expo Go). - -On Expo SDK 52 and older, enable package exports in `metro.config.js` so `mqtt` resolves to its -React Native build (Expo SDK 53 and later do this by default): - -```js -config.resolver.unstable_enablePackageExports = true; -``` - -#### Background delivery on Android - -A subscription with `background: true` keeps delivering after the app is backgrounded, killed or -the device restarts, until it is unsubscribed or `push.close()` is called (do this on sign-out). -The SDK's native Android module (autolinked) saves the subscription, and a scheduled job and -alarm wake the app every 15 to 60 seconds to reconnect; the broker replays what was sent in -between (`retry: true`). While the app is not on screen, each message is posted as a -notification that opens the app. It reconnects with the credential saved at subscribe time, so use a session rather -than a short-lived JWT. - -On Android 13 and later, the first background subscription asks the user for the -`POST_NOTIFICATIONS` runtime permission. If they decline, the subscription still delivers to your -callback but posts no notification. Notifications show the title, body and image sent with -`createPush`, and fall back to the subscription's `title` and the raw payload for other messages. - -```js -const sub = await push.subscribe('news', (message) => console.log(message.data), { - background: true, - title: 'News', -}); - -// Optional: immediate delivery even after a kill and during Doze, with a quiet ongoing -// notification (call while the app is in the foreground). -await push.setForeground(true); -``` - -Notifications are posted while the app is backgrounded or closed. While it is on screen your -callback shows the message, so none is posted unless the subscription passes -`notifyInForeground: true`. - -#### Delivery while the app is closed - -Messages sent while the app is closed arrive at the next scheduled wake-up. While the device is -awake that is about every 15 seconds, or about every 60 seconds once exact alarms are allowed; -without exact alarms the wake-ups are inexact, so battery saver can defer them further. In Doze -(screen off and idle for a while) Android limits background alarms, exact ones included, to about -one every nine minutes, so a closed app can take several minutes to receive a message: allowing -exact alarms makes wake-ups punctual, it does not lift Doze. For immediate delivery, also in -Doze, use `push.setForeground(true)` (see above). - -The SDK uses exact alarms on its own whenever the app may schedule them. To allow it: - -1. Declare the permissions in your app's `AndroidManifest.xml`. Both are optional and subject to - Google Play policy: `SCHEDULE_EXACT_ALARM` needs a declaration in the Play Console, and - `USE_EXACT_ALARM` is reserved for alarm, clock and calendar apps (the SDK does not use it). - - ```xml - - - ``` - -With Expo, list them under `android.permissions` in `app.json` instead. - -2. On Android 13 and later the user has to allow exact alarms, under Settings > Apps > Special app - access > Alarms & reminders. Android 12 grants a declared `SCHEDULE_EXACT_ALARM` - automatically, and older versions need nothing. Check with `await push.backgroundStatus()`: when `bestEffort` is - true, explain why to the user, then from a user action open that screen with `push.requestExactAlarms()`, or - ask for the battery-optimisation exemption with `push.requestIgnoreBatteryOptimizations()`. Both return false when there is - nothing to ask, including when the permission is not declared. The SDK never opens these - screens on its own. - -If the user force-stops the app (Settings > Force stop, and on some devices swiping it away from -recents), Android cancels its alarms and jobs: nothing is delivered until the app is opened -again, and the broker then replays what was sent meanwhile. - -Set the notification icon with -`` in your -``; without it a generic icon is used. - -```js -const status = await push.backgroundStatus(); // null outside Android -if (status?.bestEffort) { - // Explain why, then from a button press: - await push.requestExactAlarms(); -} -``` - -Saved background delivery follows the app's current session, also while the app is closed: each -background run re-reads the session cookie, so a rotated session of the same user replaces the -saved one, and signing out (no session) or signing in as someone else stops background delivery. -If the broker still refuses the credential, delivery stops and `onError` reports it the next time -the app registers one. Still call `push.close()` on sign-out. - -#### Upgrading from an earlier release candidate - -The Expo config plugin is gone: the native module now declares everything background delivery -needs. Remove `"react-native-appwrite"` from the `plugins` list in `app.json`, or `expo config` -fails to load it. - -#### Opening a tapped notification - -Read the `data` sent with `createPush` when the user taps a background notification: - -```js -// The tap that launched the app (reported once, so call it at startup). -const opened = await push.getInitialNotification(); -if (opened) { - openSale(opened.data.saleId); -} - -// Taps while the app is running, including in the background. -const stop = push.onNotificationOpened(({ topic, data }) => openSale(data.saleId)); -``` - -On Android the SDK's native module reports the taps. Elsewhere they come from `expo-notifications`. - -Foreground mode runs a `remoteMessaging` foreground service, which Google Play asks apps to -declare in the Play Console. Apps that never enable it can remove the service from their merged -manifest with `tools:node="remove"` on `io.appwrite.services.PushService` and -`android.permission.FOREGROUND_SERVICE_REMOTE_MESSAGING`. - ## Getting Started diff --git a/android/.editorconfig b/android/.editorconfig deleted file mode 100644 index f0895a33..00000000 --- a/android/.editorconfig +++ /dev/null @@ -1,39 +0,0 @@ -root = true - -[*.{kt,kts}] -ktlint_code_style = ktlint_official -ktlint_standard_annotation = disabled -ktlint_standard_argument-list-wrapping = disabled -ktlint_standard_blank-line-before-declaration = disabled -ktlint_standard_blank-line-between-when-conditions = disabled -ktlint_standard_chain-method-continuation = disabled -ktlint_standard_class-signature = disabled -ktlint_standard_function-expression-body = disabled -ktlint_standard_function-signature = disabled -ktlint_standard_function-start-of-body-spacing = disabled -ktlint_standard_if-else-bracing = disabled -ktlint_standard_if-else-wrapping = disabled -ktlint_standard_max-line-length = disabled -ktlint_standard_multiline-expression-wrapping = disabled -ktlint_standard_multiline-if-else = disabled -ktlint_standard_no-blank-line-before-rbrace = disabled -ktlint_standard_no-blank-line-in-list = disabled -ktlint_standard_no-empty-first-line-in-class-body = disabled -ktlint_standard_no-line-break-before-assignment = disabled -ktlint_standard_no-wildcard-imports = disabled -ktlint_standard_parameter-list-wrapping = disabled -ktlint_standard_spacing-between-declarations-with-annotations = disabled -ktlint_standard_spacing-between-declarations-with-comments = disabled -ktlint_standard_string-template = disabled -ktlint_standard_trailing-comma-on-call-site = disabled -ktlint_standard_trailing-comma-on-declaration-site = disabled -ktlint_standard_when-entry-bracing = disabled -ktlint_standard_wrapping = disabled - -[**/Channel.kt] -# Marker types intentionally use leading underscores to distinguish channel states. -ktlint_standard_class-naming = disabled - -[**/models/*.kt] -# Model imports follow schema property order so generated declarations stay deterministic. -ktlint_standard_import-ordering = disabled diff --git a/android/build.gradle b/android/build.gradle deleted file mode 100644 index 024c3a52..00000000 --- a/android/build.gradle +++ /dev/null @@ -1,40 +0,0 @@ -// The native half of Push on Android: background delivery that survives the process being -// killed, a reboot and an app update, shared with the Appwrite Android SDK. -def safeExtGet(prop, fallback) { - rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback -} - -apply plugin: "com.android.library" -apply plugin: "kotlin-android" - -android { - namespace "io.appwrite.reactnative" - compileSdkVersion safeExtGet("compileSdkVersion", 35) - - defaultConfig { - minSdkVersion safeExtGet("minSdkVersion", 24) - targetSdkVersion safeExtGet("targetSdkVersion", 35) - // R8 rules for the bundled MQTT client, applied to the app. - consumerProguardFiles "consumer-rules.pro" - } - - compileOptions { - sourceCompatibility JavaVersion.VERSION_17 - targetCompatibility JavaVersion.VERSION_17 - } - - kotlinOptions { - jvmTarget = "17" - } -} - -repositories { - google() - mavenCentral() -} - -dependencies { - implementation "com.facebook.react:react-android" - implementation "com.hivemq:hivemq-mqtt-client-shaded:1.3.6" - implementation "androidx.core:core-ktx:1.13.1" -} diff --git a/android/consumer-rules.pro b/android/consumer-rules.pro deleted file mode 100644 index 04d7db2c..00000000 --- a/android/consumer-rules.pro +++ /dev/null @@ -1,27 +0,0 @@ -# Push: rules applied to apps that shrink with R8. -# -# The shaded HiveMQ MQTT client relocates Netty and JCTools under -# com.hivemq.client.internal.shaded. Netty references optional classes that are never loaded -# on Android: native transports, the HTTP/WebSocket codecs, proxy handlers, alternative TLS -# providers (tcnative, BouncyCastle, Conscrypt, Jetty ALPN) and logging backends. --dontwarn com.hivemq.client.internal.shaded.io.netty.channel.epoll.** --dontwarn com.hivemq.client.internal.shaded.io.netty.channel.kqueue.** --dontwarn com.hivemq.client.internal.shaded.io.netty.handler.codec.http.** --dontwarn com.hivemq.client.internal.shaded.io.netty.handler.proxy.** --dontwarn com.hivemq.client.internal.shaded.io.netty.internal.tcnative.** --dontwarn org.bouncycastle.** --dontwarn org.conscrypt.** --dontwarn org.eclipse.jetty.** --dontwarn org.apache.log4j.** --dontwarn org.apache.logging.log4j.** --dontwarn org.slf4j.** --dontwarn reactor.blockhound.** - -# Netty and JCTools reach their own fields by name, through atomic field updaters and Unsafe offsets. --keepclassmembernames class com.hivemq.client.internal.shaded.io.netty.** { ; } --keepclassmembers class com.hivemq.client.internal.shaded.org.jctools.** { ; } - -# Netty's leak detector looks these methods up by name when its classes load. --keepclassmembers class com.hivemq.client.internal.shaded.io.netty.buffer.AbstractByteBufAllocator { *** toLeakAwareBuffer(...); } --keepclassmembers class com.hivemq.client.internal.shaded.io.netty.buffer.AdvancedLeakAwareByteBuf { *** recordLeakNonRefCountingOperation(...); } --keepclassmembers class com.hivemq.client.internal.shaded.io.netty.util.ReferenceCountUtil { *** touch(...); } diff --git a/android/src/main/AndroidManifest.xml b/android/src/main/AndroidManifest.xml deleted file mode 100644 index d2b7d500..00000000 --- a/android/src/main/AndroidManifest.xml +++ /dev/null @@ -1,48 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/android/src/main/java/io/appwrite/exceptions/AppwriteException.kt b/android/src/main/java/io/appwrite/exceptions/AppwriteException.kt deleted file mode 100644 index 81b0d30e..00000000 --- a/android/src/main/java/io/appwrite/exceptions/AppwriteException.kt +++ /dev/null @@ -1,6 +0,0 @@ -package io.appwrite.exceptions - -/** A push error. When the broker explained a refusal or a disconnect, that is its message. */ -class AppwriteException( - override val message: String? = null, -) : Exception(message) diff --git a/android/src/main/java/io/appwrite/reactnative/AppwriteCookiesModule.kt b/android/src/main/java/io/appwrite/reactnative/AppwriteCookiesModule.kt deleted file mode 100644 index 8e1dce18..00000000 --- a/android/src/main/java/io/appwrite/reactnative/AppwriteCookiesModule.kt +++ /dev/null @@ -1,31 +0,0 @@ -package io.appwrite.reactnative - -import android.webkit.CookieManager -import com.facebook.react.bridge.Promise -import com.facebook.react.bridge.ReactApplicationContext -import com.facebook.react.bridge.ReactContextBaseJavaModule -import com.facebook.react.bridge.ReactMethod - -class AppwriteCookiesModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaModule(reactContext) { - override fun getName(): String = NAME - - @ReactMethod - fun session(url: String, project: String, promise: Promise) { - val name = "a_session_$project" - try { - val value = CookieManager.getInstance().getCookie(url) - ?.split(";") - ?.map { it.trim() } - ?.firstOrNull { it.substringBefore("=") == name } - ?.substringAfter("=") - promise.resolve(value) - } catch (e: Exception) { - promise.reject(ERROR_CODE, e.message, e) - } - } - - companion object { - const val NAME = "AppwriteCookies" - private const val ERROR_CODE = "appwrite_cookies" - } -} diff --git a/android/src/main/java/io/appwrite/reactnative/AppwritePushModule.kt b/android/src/main/java/io/appwrite/reactnative/AppwritePushModule.kt deleted file mode 100644 index c6c46889..00000000 --- a/android/src/main/java/io/appwrite/reactnative/AppwritePushModule.kt +++ /dev/null @@ -1,175 +0,0 @@ -package io.appwrite.reactnative - -import android.util.Base64 -import com.facebook.react.bridge.Arguments -import com.facebook.react.bridge.Promise -import com.facebook.react.bridge.ReactApplicationContext -import com.facebook.react.bridge.ReactContextBaseJavaModule -import com.facebook.react.bridge.ReactMethod -import com.facebook.react.modules.core.DeviceEventManagerModule -import io.appwrite.services.PushBridge -import io.appwrite.services.PushMessage -import io.appwrite.services.PushTap -import io.appwrite.services.PushTaps -import org.json.JSONObject - -/** - * The React Native side of [PushBridge]: the SDK's `Push` hosts its background subscriptions - * here on Android, and receives their messages and errors as events. It also reports taps on the - * notifications they post: the one that launched the app, and later ones as events. - * - * [emit] sends an event to JS; tests replace it to observe what JS would receive. - */ -class AppwritePushModule internal constructor( - private val reactContext: ReactApplicationContext, - private val emit: (String, Map) -> Unit, -) : ReactContextBaseJavaModule(reactContext) { - constructor(reactContext: ReactApplicationContext) : this( - reactContext, - { event, body -> - if (reactContext.hasActiveReactInstance()) { - reactContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java) - .emit(event, Arguments.makeNativeMap(body)) - } - }, - ) - - private val bridge = PushBridge( - reactContext, - object : PushBridge.Events { - override fun onMessage(subscriptionId: String, message: PushMessage, ackToken: String) = emit( - MESSAGE_EVENT, - mapOf( - "id" to subscriptionId, - "topic" to message.topic, - "payload" to Base64.encodeToString(message.payload, Base64.NO_WRAP), - "qos" to message.qos, - "ackToken" to ackToken, - ), - ) - - override fun onError(message: String) = emit(ERROR_EVENT, mapOf("message" to message)) - - override fun onConnection(connected: Boolean) = emit(CONNECTION_EVENT, mapOf("connected" to connected)) - }, - ) - - private var openedListeners = 0 - private var stopOpened: (() -> Unit)? = null - - override fun getName(): String = NAME - - // Resolves with the tapped notification that launched the app as JSON (topic and payload), - // once, or null. - @ReactMethod - fun getInitialNotification(promise: Promise) = settle(promise) { - PushTaps.take()?.let { JSONObject(opened(it)).toString() } - } - - // Emits each tap while JS listens for them; until then a tap waits for getInitialNotification. - @ReactMethod - fun listenOpened(listening: Boolean, promise: Promise) = settle(promise) { - openedListeners = (openedListeners + if (listening) 1 else -1).coerceAtLeast(0) - if (openedListeners > 0 && stopOpened == null) { - stopOpened = PushTaps.listen { tap -> emit(OPENED_EVENT, opened(tap)) } - } else if (openedListeners == 0) { - stopOpened?.invoke() - stopOpened = null - } - null - } - - override fun invalidate() { - stopOpened?.invoke() - stopOpened = null - super.invalidate() - } - - // Resolves once the connection is up and every filter is subscribed, or rejects with why not. - @ReactMethod - fun host(config: String, subscriptions: String, promise: Promise) { - try { - bridge.host(config, subscriptions) { error -> - if (error == null) { - promise.resolve(bridge.isConnected()) - } else { - promise.reject(ERROR_CODE, error) - } - } - } catch (e: Exception) { - promise.reject(ERROR_CODE, e.message, e) - } - } - - @ReactMethod - fun ack(token: String) = bridge.ack(token) - - @ReactMethod - fun release(promise: Promise) = settle(promise) { - bridge.release() - null - } - - @ReactMethod - fun stop(promise: Promise) = settle(promise) { - bridge.stop() - null - } - - @ReactMethod - fun setForeground(enabled: Boolean, promise: Promise) = settle(promise) { - bridge.setForeground(enabled) - null - } - - @ReactMethod - fun hasSaved(promise: Promise) = settle(promise) { bridge.hasSaved() } - - @ReactMethod - fun resume(authMethod: String?, credential: String?, signedOutWhenMissing: Boolean, promise: Promise) = settle(promise) { - bridge.resume(authMethod, credential, signedOutWhenMissing) - null - } - - @ReactMethod - fun backgroundStatus(promise: Promise) = settle(promise) { bridge.backgroundStatus() } - - @ReactMethod - fun requestExactAlarms(promise: Promise) = settle(promise) { bridge.requestExactAlarms() } - - @ReactMethod - fun requestIgnoreBatteryOptimizations(promise: Promise) = settle(promise) { bridge.requestIgnoreBatteryOptimizations() } - - @ReactMethod - fun setErrorCallback(registered: Boolean, promise: Promise) = settle(promise) { bridge.setErrorCallback(registered) } - - @ReactMethod - fun defaultClientId(authMethod: String, credential: String, promise: Promise) = - settle(promise) { bridge.defaultClientId(authMethod, credential) } - - // Required by NativeEventEmitter; events are emitted whether or not anyone listens. - @ReactMethod - fun addListener(eventName: String) = Unit - - @ReactMethod - fun removeListeners(count: Double) = Unit - - private fun opened(tap: PushTap): Map = mapOf("topic" to tap.topic, "payload" to tap.payload) - - private fun settle(promise: Promise, block: () -> Any?) { - try { - promise.resolve(block()) - } catch (e: Exception) { - promise.reject(ERROR_CODE, e.message, e) - } - } - - companion object { - const val NAME = "AppwritePush" - const val MESSAGE_EVENT = "AppwritePushMessage" - const val ERROR_EVENT = "AppwritePushError" - const val OPENED_EVENT = "AppwritePushOpened" - const val CONNECTION_EVENT = "AppwritePushConnection" - private const val ERROR_CODE = "appwrite_push" - } -} diff --git a/android/src/main/java/io/appwrite/reactnative/AppwritePushPackage.kt b/android/src/main/java/io/appwrite/reactnative/AppwritePushPackage.kt deleted file mode 100644 index 728186af..00000000 --- a/android/src/main/java/io/appwrite/reactnative/AppwritePushPackage.kt +++ /dev/null @@ -1,17 +0,0 @@ -package io.appwrite.reactnative - -import com.facebook.react.ReactPackage -import com.facebook.react.bridge.NativeModule -import com.facebook.react.bridge.ReactApplicationContext -import com.facebook.react.uimanager.ViewManager - -/** Registers [AppwritePushModule] and [AppwriteCookiesModule]; found by React Native autolinking. */ -class AppwritePushPackage : ReactPackage { - override fun createNativeModules(reactContext: ReactApplicationContext): List = - listOf( - AppwritePushModule(reactContext), - AppwriteCookiesModule(reactContext), - ) - - override fun createViewManagers(reactContext: ReactApplicationContext): List> = emptyList() -} diff --git a/android/src/main/java/io/appwrite/services/PushBackground.kt b/android/src/main/java/io/appwrite/services/PushBackground.kt deleted file mode 100644 index e06dfabe..00000000 --- a/android/src/main/java/io/appwrite/services/PushBackground.kt +++ /dev/null @@ -1,1457 +0,0 @@ -package io.appwrite.services - -import android.Manifest -import android.app.ActivityManager -import android.app.AlarmManager -import android.app.NotificationChannel -import android.app.NotificationManager -import android.app.PendingIntent -import android.app.job.JobInfo -import android.app.job.JobScheduler -import android.content.ComponentName -import android.content.Context -import android.content.Intent -import android.content.pm.PackageManager -import android.graphics.Bitmap -import android.graphics.BitmapFactory -import android.net.ConnectivityManager -import android.net.Network -import android.net.Uri -import android.os.Build -import android.os.PowerManager -import android.os.SystemClock -import android.provider.Settings -import android.util.AtomicFile -import android.util.Log -import android.webkit.CookieManager -import androidx.core.app.NotificationCompat -import androidx.core.app.NotificationManagerCompat -import androidx.core.content.ContextCompat -import com.hivemq.client.mqtt.MqttGlobalPublishFilter -import com.hivemq.client.mqtt.datatypes.MqttQos -import com.hivemq.client.mqtt.mqtt5.Mqtt5AsyncClient -import com.hivemq.client.mqtt.mqtt5.exceptions.Mqtt5ConnAckException -import com.hivemq.client.mqtt.mqtt5.message.publish.Mqtt5Publish -import io.appwrite.exceptions.AppwriteException -import org.json.JSONArray -import org.json.JSONObject -import java.io.ByteArrayOutputStream -import java.io.File -import java.io.IOException -import java.io.InputStream -import java.net.HttpURLConnection -import java.net.URL -import java.util.UUID -import java.util.concurrent.CopyOnWriteArrayList -import java.util.concurrent.ExecutionException -import java.util.concurrent.Executors -import java.util.concurrent.TimeUnit -import java.util.concurrent.TimeoutException -import java.util.concurrent.atomic.AtomicBoolean -import java.util.concurrent.atomic.AtomicInteger - -private const val LOG_TAG = "AppwritePush" - -/** What a message's `notification` block asks a background notification to show; [present] is false without one. */ -internal data class PushNotificationContent(val present: Boolean, val title: String?, val body: String?, val image: String?) - -/** A background subscription saved across restarts: its filter, QoS choice and notification title. */ -internal data class PushEntry( - val filter: String, - val retry: Boolean, - val title: String?, - val notifyInForeground: Boolean = false, -) - -/** - * The adaptive heartbeat: its interval, the current streak of failed heartbeats, and when the - * interval last shrank (wall-clock ms, as it must survive reboots). - */ -internal data class PushHeartbeat( - val intervalMs: Long, - val failures: Int = 0, - val shrunkAt: Long = 0L, -) - -/** - * The process-wide host of the background push connection, modelled on how socket push - * services survive on Android without keeping a service alive. - * - * The background subscriptions and their connection config are saved to private storage (see - * [PushStore]), so delivery survives the process being killed, a reboot and an app update. A - * job ([PushJobService]) that reschedules itself on every run, backed by an alarm - * ([PushAlarmReceiver]), wakes the process every 15 seconds (60 when the app may use exact - * alarms or is exempt from battery optimisation). Each run holds a short wakelock and - * reconnects when the connection is gone or the default network changed, sends a heartbeat - * when one is due, and re-arms the job. While the process is alive between runs the socket - * stays open and messages arrive immediately; while it is dead the broker keeps the backlog - * for this client id and replays it when the next run subscribes again. - * - * With foreground mode enabled ([Push.setForeground]) a foreground service ([PushService]) also keeps - * the process at foreground priority, so delivery is immediate after a kill and during Doze. - * - * Messages go to the live in-app callbacks that match them. When none match (the process was - * started in the background), a declared [PushReceiver] gets the message, and a notification - * is posted unless it returns true. - */ -internal object PushBackground { - const val CHANNEL_ID = "appwrite-push" - const val NOTIFICATION_ID = 1911 - const val ACTION_TICK = "io.appwrite.push.TICK" - const val ACTION_MESSAGE = "io.appwrite.push.MESSAGE" - const val NOTIFICATION_ICON = "io.appwrite.push.notification_icon" - const val EXTRA_TOPIC = "io.appwrite.push.TOPIC" - const val EXTRA_PAYLOAD = "io.appwrite.push.PAYLOAD" - - private const val SERVICE_CHANNEL_ID = "appwrite-push-service" - const val JOB_ID = 0x50555348 - const val NEXT_JOB_ID = 0x5055534A - const val EXPEDITED_JOB_ID = 0x5055534B - const val WATCHDOG_JOB_ID = 0x50555349 - private const val WATCHDOG_INTERVAL_MS = 15 * 60 * 1_000L - private const val INTERVAL_MS = 15_000L - private const val PRIVILEGED_INTERVAL_MS = 60_000L - private const val RESTART_DELAY_MS = 3_000L - // An upper bound covering a run's connect (20 s) and its requests (10 s each); the wakelock is - // released as soon as the run finishes. - private const val WAKE_LOCK_MS = 60_000L - private const val KEEP_ALIVE_SECONDS = 300 - - // The heartbeat interval: below the broker's 1.5 x keep-alive expiry, measured on a clock that - // counts deep sleep. Networks that drop idle connections sooner (carrier NATs) make heartbeats - // fail; after HEARTBEAT_FAILURES in a row the interval shrinks by a quarter, down to - // MIN_HEARTBEAT_MS, and returns to the default HEARTBEAT_RESET_MS after the last shrink, in - // case the device moved to a better network. - const val HEARTBEAT_MS = 180_000L - private const val MIN_HEARTBEAT_MS = 60_000L - private const val HEARTBEAT_FAILURES = 3 - private const val HEARTBEAT_RESET_MS = 3 * 24 * 60 * 60 * 1_000L - private const val REQUEST_TIMEOUT_SECONDS = 10L - private const val IMAGE_TIMEOUT_MS = 5_000 - - // How long a scheduled run stays up after connecting so the broker can replay what was missed: - // until nothing arrived for DRAIN_QUIET_MS and nothing is being delivered, at most the run's cap. - const val JOB_DRAIN_MS = 15_000L - const val RECEIVER_DRAIN_MS = 5_000L - private const val DRAIN_QUIET_MS = 2_000L - private const val DRAIN_POLL_MS = 200L - private const val IMAGE_MAX_BYTES = 5 * 1024 * 1024 - private const val IMAGE_MAX_PX = 1_024 - private const val CONNECT_TIMEOUT_SECONDS = 20L - - // How long a message waits for a listener that acknowledges it itself (the React Native and - // Flutter bridges, once their callback has run) before it is acknowledged anyway, so one stuck - // callback cannot hold back the acknowledgements after it. - private const val ACK_TIMEOUT_SECONDS = 10L - - // Unsubscribing a filter nothing subscribes to is a harmless round trip the broker always - // acknowledges, so it proves the connection is alive. The broker ignores client PUBLISHes - // without a PUBACK, so a publish cannot serve as the heartbeat. - private const val HEARTBEAT_FILTER = "\$heartbeat" - - @Volatile - var channelName: String = "Notifications" - - @Volatile - var ongoingTitle: String = "Appwrite" - - // Reports errors to the Push instance that hosts its subscriptions here. Returns whether the - // app's onError received the error (false when it registered none). - @Volatile - var errorHandler: ((Throwable) -> Boolean)? = null - - // Tells the Push instance that hosts its subscriptions here when the connection opens (true) - // or closes (false). - @Volatile - var connectionHandler: ((Boolean) -> Unit)? = null - - // Whether the live connection (not a retired one) is open. - @Volatile - var isConnected = false - private set - - @Volatile - var serviceRunning = false - - // Whether a refused service start was reported, so a job that retries it every run does not - // report the same failure every 15 seconds. - @Volatile - private var serviceStartReported = false - - // The live in-app subscriptions hosted here, each with its callback. Empty after the process - // was restarted in the background, until the app subscribes again. - val listeners = CopyOnWriteArrayList() - - // Guards the saved state below and its copy on disk. - private val lock = Any() - private var loaded = false - private var config: PushConfig? = null - - // Background subscriptions saved by an earlier run that no live subscription has taken over. - private var saved: List = emptyList() - - // Every MQTT call runs on this thread, in order, so the connection state below needs no lock. - private val worker = Executors.newSingleThreadScheduledExecutor { runnable -> - Thread(runnable, "AppwritePushBackground").apply { isDaemon = true } - } - private var mqtt: Mqtt5AsyncClient? = null - - // Set when [mqtt] is replaced or closed, so that client stops reconnecting and delivering. - private var mqttRetired: AtomicBoolean? = null - - // Messages being delivered, and when one last arrived or finished, for a run's drain window. - private val delivering = AtomicInteger(0) - - @Volatile - private var lastDelivery = 0L - private var connectedConfig: PushConfig? = null - private var connectedNetwork: Network? = null - private var lastHeartbeat = 0L - private var heartbeatState: PushHeartbeat? = null - private val subscribed = mutableMapOf() - private var networkCallback: ConnectivityManager.NetworkCallback? = null - - // Worker thread only. While a caller waits for a converge (host with a completion), its - // failures go to that caller, which reports them, instead of onError. - private var waiting = false - private var failure: Throwable? = null - - /** - * Host [newListeners] (the app's live subscriptions) on the background connection with - * [newConfig], save the background ones, and arm the scheduled wake-ups. Saved subscriptions - * from an earlier run stay unless a live subscription on the same filter takes them over - * (with background on or off), or [newConfig] is for another client id (another user), whose - * saved subscriptions are dropped. - * - * With [done], it is called once the connection is up and every filter is subscribed (SUBACK), - * or with the failure, which is then not reported to onError: the caller reports it. - */ - fun host( - context: Context, - newConfig: PushConfig, - newListeners: List, - done: ((Throwable?) -> Unit)? = null, - ) { - val app = context.applicationContext - synchronized(lock) { - load(app) - if (config != null && config?.clientId != newConfig.clientId) { - saved = emptyList() - } - // A live subscription on a saved filter takes it over, whether or not it wants background: - // one that turned background off, or is later unsubscribed, must not leave the saved - // entry delivering in the background. - saved = saved.filter { entry -> newListeners.none { entry.filter in it.topics } } - config = newConfig - listeners.clear() - listeners.addAll(newListeners) - persist(app) - } - activate(app, done) - } - - /** - * Stop hosting the app's live subscriptions, keeping the saved ones from an earlier run. - * Shuts down when none remain. - */ - fun release(context: Context) { - val app = context.applicationContext - val active = synchronized(lock) { - listeners.clear() - persist(app) - isActive() - } - if (active) { - worker.execute { converge(app, heartbeat = false) } - } else { - shutdown(app) - } - } - - /** Stop background delivery completely and forget every saved subscription. */ - fun stop(context: Context) { - val app = context.applicationContext - synchronized(lock) { - listeners.clear() - config = null - saved = emptyList() - loaded = true - PushStore.clearState(app) - } - shutdown(app) - } - - /** Whether subscriptions saved by an earlier run are still delivered in the background. */ - fun hasSaved(context: Context): Boolean = synchronized(lock) { - load(context.applicationContext) - saved.isNotEmpty() - } - - /** Persist the foreground-mode choice and start or stop the foreground service to match. */ - fun setForeground(context: Context, enabled: Boolean) { - val app = context.applicationContext - PushStore.setForeground(app, enabled) - serviceStartReported = false - ensureService(app) - } - - /** Whether the foreground service should run: foreground mode is enabled and there is work to do. */ - fun wantsService(context: Context): Boolean { - val app = context.applicationContext - return PushStore.foreground(app) && synchronized(lock) { - load(app) - isActive() - } - } - - /** - * Resume saved background delivery when the app starts, without waiting for the next run, with - * the app's current credential. A rotated session of the same user replaces the saved one; a - * different user drops the saved subscriptions, as does no credential when - * [signedOutWhenMissing] (the caller read the session store, so none means signed out). - * While a live Push hosts subscriptions here, it does nothing: that Push owns the connection. - */ - fun resume(context: Context, authMethod: String? = null, credential: String? = null, signedOutWhenMissing: Boolean = false) { - val app = context.applicationContext - val resume = synchronized(lock) { - load(app) - val current = config - when { - !isActive() || current == null -> null - // A live Push hosts here and owns the connection and its credential; resuming only - // reconciles saved delivery, so it leaves a live host alone. - listeners.isNotEmpty() -> null - // No credential: signed out when the caller can tell, else possibly not set yet. - authMethod == null || credential == null -> if (signedOutWhenMissing) false else null - current.authMethod == authMethod && current.credential == credential -> true - // A new credential for the same user (a rotated session) replaces the saved one, - // so the stale one is never sent and refused. - sameUser(current.authMethod, current.credential, authMethod, credential) -> { - config = current.copy(authMethod = authMethod, credential = credential) - persist(app) - true - } - // Another user signed in: the saved subscriptions were not theirs. - else -> false - } - } - when (resume) { - true -> tick(app) {} - false -> stop(app) - null -> Unit - } - } - - private enum class CredentialRefresh { UNCHANGED, CHANGED, GONE } - - // Bring the saved credential up to date with the session cookie the app - // signs in with, when it comes from one (see [PushConfig.sessionCookieUrl]): a rotated session of - // the same user replaces it, and no session or another user's is GONE. UNCHANGED when there is - // no cookie source or it cannot be read. - private fun refreshCredential(context: Context): CredentialRefresh { - val current = synchronized(lock) { config } ?: return CredentialRefresh.UNCHANGED - val url = current.sessionCookieUrl ?: return CredentialRefresh.UNCHANGED - val session = readSessionCookie(url, current.project) ?: return CredentialRefresh.UNCHANGED - return when { - session.isEmpty() -> CredentialRefresh.GONE - current.authMethod == "appwrite-session" && session == current.credential -> CredentialRefresh.UNCHANGED - sameUser(current.authMethod, current.credential, "appwrite-session", session) -> { - synchronized(lock) { - config = current.copy(authMethod = "appwrite-session", credential = session) - persist(context.applicationContext) - } - CredentialRefresh.CHANGED - } - else -> CredentialRefresh.GONE - } - } - - // The credential to send for a connection made with [connected]: the session re-read from the - // cookie store when one backs it (so an automatic reconnect uses a rotated session), else the - // one it connected with. Only a newer credential of the same user, for the same connection - // (broker, client id, project), is borrowed: a connection being replaced by [host] keeps its - // own. Null when the app signed out or another user signed in: authentication is aborted and - // delivery stops. - private fun currentCredential(context: Context, connected: PushConfig): String? { - if (refreshCredential(context) == CredentialRefresh.GONE) { - worker.execute { stop(context) } - return null - } - val current = synchronized(lock) { config } ?: return connected.credential - val sameConnection = current.host == connected.host && current.port == connected.port && - current.clientId == connected.clientId && current.project == connected.project && - current.authMethod == connected.authMethod - return if (sameConnection && sameUser(connected.authMethod, connected.credential, current.authMethod, current.credential)) { - current.credential - } else { - connected.credential - } - } - - // The `a_session_` cookie for [url] in the WebView cookie store, decoded; "" when there - // is none, and null when the store cannot be read. - private fun readSessionCookie(url: String, project: String): String? = runCatching { - val name = "a_session_$project" - CookieManager.getInstance().getCookie(url) - ?.split(";") - ?.map { it.trim() } - ?.firstOrNull { it.substringBefore("=") == name } - ?.substringAfter("=") - ?.let { Uri.decode(it) } - ?: "" - }.getOrNull() - - private fun sameUser(savedMethod: String, saved: String, method: String, credential: String): Boolean { - fun userId(method: String, credential: String) = - if (method == "appwrite-session") userIdFromSession(credential) else userIdFromJwt(credential) - val user = userId(method, credential) - return user.isNotEmpty() && user == userId(savedMethod, saved) - } - - /** - * One scheduled run: under a wakelock, reconnect if needed, send a heartbeat when one is due, - * re-arm the next run, and call [done] once finished. Shuts down when nothing is saved. - * - * A run of a chained job ([jobId]) arms the next run under the other chained id: scheduling the - * id that is running would stop the run in progress. With [drainMs], the run stays up after - * connecting while the broker replays what was missed (at most that long), so a process woken - * from the background is not cached and frozen before the messages are delivered. - */ - fun tick(context: Context, jobId: Int? = null, drainMs: Long = 0, done: () -> Unit) { - val app = context.applicationContext - val wakeLock = acquireWakeLock(app) - worker.execute { - try { - val active = synchronized(lock) { - load(app) - isActive() - } - if (active) { - // Arm the next run first, so a run cut short (killed, or a slow broker outlasting - // the wakelock) still leaves the chain armed; the watchdog job restarts a chain - // that was dropped anyway. A refused credential in converge() shuts down, - // cancelling them again. - schedule(app, INTERVAL_MS, runningJobId = jobId) - ensureWatchdog(app) - ensureService(app) - registerNetworkCallback(app) - converge(app, heartbeat = true) - if (drainMs > 0 && mqtt != null) { - awaitDeliveries(drainMs) - } - } else { - shutdown(app) - } - } catch (e: Exception) { - report(e) - } finally { - releaseWakeLock(wakeLock) - done() - } - } - } - - // Worker thread only. Wait until no message arrived for DRAIN_QUIET_MS and none is being - // delivered, at most [maxMs]. Timed with the real monotonic clock ([nowMs]), which keeps moving - // while this thread sleeps. - private fun awaitDeliveries(maxMs: Long) { - val start = nowMs() - if (lastDelivery < start) { - lastDelivery = start - } - while (nowMs() - start < maxMs) { - if (delivering.get() == 0 && nowMs() - lastDelivery >= DRAIN_QUIET_MS) { - return - } - Thread.sleep(DRAIN_POLL_MS) - } - } - - private fun nowMs(): Long = System.nanoTime() / 1_000_000 - - /** - * Android 12+: hand a run to an expedited job, which starts at once with network access and - * keeps the process runnable until it finishes. A broadcast receiver woken in a cached process - * runs at background priority and can be frozen before it connects. Returns false when the - * job cannot be scheduled (older Android, or the expedited quota is used up), so the caller - * runs the tick itself. - */ - fun runExpedited(context: Context): Boolean { - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S) { - return false - } - return try { - val job = JobInfo.Builder(EXPEDITED_JOB_ID, ComponentName(context, PushJobService::class.java)) - .setExpedited(true) - .setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY) - .build() - context.getSystemService(JobScheduler::class.java)?.schedule(job) == JobScheduler.RESULT_SUCCESS - } catch (e: Exception) { - false - } - } - - /** Run once more shortly after the task was removed, so an OEM kill that follows is undone. */ - fun scheduleRestart(context: Context) { - schedule(context.applicationContext, RESTART_DELAY_MS, alarmOnly = true) - } - - /** - * Forget everything held in memory, as the process dying does, keeping only what is saved. - * For tests of what happens after the app's process was killed. - */ - internal fun dropProcessState(context: Context) { - synchronized(lock) { - listeners.clear() - config = null - saved = emptyList() - loaded = false - } - errorHandler = null - connectionHandler = null - unregisterNetworkCallback(context.applicationContext) - worker.submit { disconnect() }.get() - } - - /** Report an error to the hosting Push instance's onError; logged when there is none. */ - fun report(error: Throwable): Boolean { - val delivered = try { - errorHandler?.invoke(error) ?: false - } catch (callbackError: Exception) { - Log.e(LOG_TAG, "Push onError threw", callbackError) - true - } - if (!delivered) { - Log.e(LOG_TAG, "Push background error", error) - } - return delivered - } - - // Must hold [lock]. - private fun load(context: Context) { - if (loaded) { - return - } - loaded = true - val state = PushStore.loadState(context) ?: return - config = state.first - saved = state.second - } - - // Must hold [lock]. - private fun isActive(): Boolean = config != null && (saved.isNotEmpty() || listeners.isNotEmpty()) - - // Must hold [lock]. Every background subscription, live or saved, one per filter and title. - // Subscriptions sharing a filter and title are saved once, with QoS 1 when any of them wants it. - private fun entries(): List = - (saved + liveEntries()) - .groupBy { it.filter to it.title } - .map { (key, group) -> PushEntry(key.first, group.any { it.retry }, key.second, group.any { it.notifyInForeground }) } - - // Must hold [lock]. - private fun liveEntries(): List = listeners.filter { it.background }.flatMap { listener -> - listener.topics.map { PushEntry(it, listener.retry, listener.title, listener.notifyInForeground) } - } - - // Must hold [lock]. - private fun persist(context: Context) { - val current = config - val entries = entries() - if (current == null || entries.isEmpty()) { - PushStore.clearState(context) - } else { - PushStore.saveState(context, current, entries) - } - } - - // Must hold [lock]. The broker subscriptions wanted, at the highest QoS any subscription on a - // filter asks for. - private fun wanted(): Map { - val qos = linkedMapOf() - fun want(filter: String, retry: Boolean) { - if (retry) { - qos[filter] = MqttQos.AT_LEAST_ONCE - } else if (filter !in qos) { - qos[filter] = MqttQos.AT_MOST_ONCE - } - } - for (listener in listeners) { - listener.topics.forEach { want(it, listener.retry) } - } - saved.forEach { want(it.filter, it.retry) } - return qos - } - - private fun activate(context: Context, done: ((Throwable?) -> Unit)? = null) { - registerNetworkCallback(context) - schedule(context, INTERVAL_MS) - ensureWatchdog(context) - ensureService(context) - worker.execute { converge(context, heartbeat = false, done) } - } - - private fun shutdown(context: Context) { - cancelSchedule(context) - unregisterNetworkCallback(context) - if (serviceRunning) { - context.stopService(Intent(context, PushService::class.java)) - } - worker.execute { disconnect() } - } - - // Worker thread only. Bring the connection to the wanted state: reconnect when the config or - // the default network changed or a due heartbeat fails, then subscribe and unsubscribe the - // difference. With [done], failures go to it (see [waiting]) instead of onError. - private fun converge(context: Context, heartbeat: Boolean, done: ((Throwable?) -> Unit)? = null) { - waiting = done != null - failure = null - try { - convergeOnce(context, heartbeat) - } catch (e: Exception) { - fail(e) - } finally { - waiting = false - done?.invoke(failure) - } - } - - // Worker thread only. Record a failure for the waiting caller, or report it. - private fun fail(error: Throwable) { - if (failure == null) { - failure = error - } - if (!waiting) { - report(error) - } - } - - private fun convergeOnce(context: Context, heartbeat: Boolean) { - // Signed out, or signed in as someone else, since the subscriptions were saved. - if (refreshCredential(context) == CredentialRefresh.GONE) { - stop(context) - return - } - val (current, wanted) = synchronized(lock) { config to wanted() } - if (current == null || wanted.isEmpty()) { - disconnect() - return - } - var client = mqtt - if (client != null && (current != connectedConfig || networkChanged(context))) { - disconnect() - client = null - } - if (client != null && heartbeat && SystemClock.elapsedRealtime() - lastHeartbeat >= heartbeatInterval(context)) { - val alive = sendHeartbeat(client) - recordHeartbeat(context, alive) - if (alive) { - lastHeartbeat = SystemClock.elapsedRealtime() - } else { - disconnect() - client = null - } - } - if (client == null) { - client = connect(context, current) ?: return - } - for (filter in subscribed.keys - wanted.keys) { - request { client.unsubscribeWith().topicFilter(filter).send().get(REQUEST_TIMEOUT_SECONDS, TimeUnit.SECONDS) } - subscribed.remove(filter) - } - for ((filter, qos) in wanted) { - if (subscribed[filter] != qos && subscribe(client, filter, qos)) { - subscribed[filter] = qos - } - } - } - - // Worker thread only. Connect with [config], or report why not and return null. A refused - // credential stops background delivery: retrying it would only be refused again. - private fun connect(context: Context, config: PushConfig): Mqtt5AsyncClient? { - // A failed first connect of a waited-for converge goes to the waiting caller only. - val quiet = waiting - val connected = AtomicBoolean(false) - val retired = AtomicBoolean(false) - val client = buildPushClient( - config.copy(keepAlive = KEEP_ALIVE_SECONDS), - onConnected = { - if (!retired.get()) { - isConnected = true - connectionHandler?.invoke(true) - } - }, - onDisconnected = { - if (!retired.get()) { - isConnected = false - connectionHandler?.invoke(false) - } - }, - onError = { error -> - if (!quiet || connected.get()) { - report(error) - } - }, - onAuthRefused = { error -> worker.execute { refused(context, error) } }, - credential = { currentCredential(context, config) }, - retired = retired, - ) - // Registered before connecting, so the backlog the broker replays right after each - // SUBSCRIBE reaches the app however the subscription was made (including the ones the - // client restores itself after an automatic reconnect). Acknowledged by hand, once the - // message was delivered (see [deliver]). - client.publishes( - MqttGlobalPublishFilter.ALL, - { publish -> - if (!retired.get()) { - deliver(context, publish) - } - }, - true, - ) - try { - client.sendPushConnect(config.copy(keepAlive = KEEP_ALIVE_SECONDS), CONNECT_TIMEOUT_SECONDS) { - currentCredential(context, config) - } - } catch (e: Exception) { - val cause = (e as? ExecutionException)?.cause ?: e - retired.set(true) - client.disconnect() - val error = connectError(cause) - when { - isAuthRefusal(cause) -> refused(context, error) - waiting -> fail(error) - // A network failure already reached onError through the client's disconnect - // listener; a refused CONNECT and a timeout did not. - cause is Mqtt5ConnAckException || cause is TimeoutException -> report(error) - } - return null - } - connected.set(true) - mqtt = client - mqttRetired = retired - connectedConfig = config - connectedNetwork = activeNetwork(context) - lastHeartbeat = SystemClock.elapsedRealtime() - subscribed.clear() - return client - } - - // Worker thread only. - private fun subscribe(client: Mqtt5AsyncClient, filter: String, qos: MqttQos): Boolean = request { - val subAck = client.subscribeWith().topicFilter(filter).qos(qos).send().get(REQUEST_TIMEOUT_SECONDS, TimeUnit.SECONDS) - val code = subAck.reasonCodes.firstOrNull { it.isError } - if (code != null) { - throw AppwriteException( - subAck.reasonString.map { it.toString() }.orElse("Subscribing to $filter was refused (reason $code)"), - ) - } - } - - // Worker thread only. The current heartbeat interval, back at the default once a shrink is - // old enough. - private fun heartbeatInterval(context: Context): Long { - val state = heartbeatState ?: PushStore.heartbeat(context).also { heartbeatState = it } - if (state.intervalMs < HEARTBEAT_MS && System.currentTimeMillis() - state.shrunkAt >= HEARTBEAT_RESET_MS) { - saveHeartbeat(context, PushHeartbeat(HEARTBEAT_MS)) - return HEARTBEAT_MS - } - return state.intervalMs - } - - // Worker thread only. Count a failed heartbeat (a connection the network dropped silently), - // shrinking the interval after HEARTBEAT_FAILURES in a row; a delivered one ends the streak. - private fun recordHeartbeat(context: Context, alive: Boolean) { - val state = heartbeatState ?: PushStore.heartbeat(context) - val next = when { - alive -> state.copy(failures = 0) - state.failures + 1 < HEARTBEAT_FAILURES -> state.copy(failures = state.failures + 1) - else -> PushHeartbeat(maxOf(MIN_HEARTBEAT_MS, state.intervalMs * 3 / 4), 0, System.currentTimeMillis()) - } - if (next != state) { - saveHeartbeat(context, next) - } - } - - private fun saveHeartbeat(context: Context, state: PushHeartbeat) { - heartbeatState = state - PushStore.setHeartbeat(context, state) - } - - // Worker thread only. - private fun sendHeartbeat(client: Mqtt5AsyncClient): Boolean = try { - client.unsubscribeWith().topicFilter(HEARTBEAT_FILTER).send().get(REQUEST_TIMEOUT_SECONDS, TimeUnit.SECONDS) - true - } catch (e: Exception) { - false - } - - // Run a broker request, recording or reporting its failure. Returns whether it succeeded. - private fun request(block: () -> Unit): Boolean = try { - block() - true - } catch (e: Exception) { - fail((e as? ExecutionException)?.cause ?: e) - false - } - - // Worker thread only. - private fun disconnect() { - mqttRetired?.set(true) - mqttRetired = null - // A retired client's own disconnect is not reported, so report the live one closing here. - if (isConnected) { - isConnected = false - connectionHandler?.invoke(false) - } - mqtt?.disconnect() - mqtt = null - connectedConfig = null - connectedNetwork = null - subscribed.clear() - } - - // Worker thread only. The broker refused the credential: report it and stop. With no onError - // registered the message is also saved, and the next onError registration receives it. A - // waiting caller receives it instead. - private fun refused(context: Context, error: Throwable) { - // The saved credential may be a session the app has since rotated: retry once with the - // current one. Refused again, it is unchanged and delivery stops below. - if (!waiting) { - when (refreshCredential(context)) { - CredentialRefresh.CHANGED -> { - converge(context, heartbeat = false) - return - } - CredentialRefresh.GONE -> { - stop(context) - return - } - CredentialRefresh.UNCHANGED -> Unit - } - } - if (waiting) { - fail(error) - } else if (!report(error)) { - PushStore.setStoppedError(context, error.message ?: "Push connection refused") - } - stop(context) - } - - // Deliver a message, then acknowledge it: right away, or once every listener that acknowledges - // messages itself has done so (at most ACK_TIMEOUT_SECONDS later). - // A message counts as being delivered until it is acknowledged: for the React Native and Flutter - // bridges, once their callback has run (or the acknowledgement times out), not when the event is - // handed over, so a run's drain window waits for it. - private fun deliver(context: Context, publish: Mqtt5Publish) { - delivering.incrementAndGet() - lastDelivery = nowMs() - deliverAcknowledged(context, publish) { - lastDelivery = nowMs() - delivering.decrementAndGet() - } - } - - private fun deliverAcknowledged(context: Context, publish: Mqtt5Publish, settled: () -> Unit) { - val acknowledged = AtomicBoolean(false) - val acknowledge = { - if (acknowledged.compareAndSet(false, true)) { - runCatching { publish.acknowledge() } - settled() - } - } - val pending = AtomicInteger(1) - val settle = { - if (pending.decrementAndGet() == 0) { - acknowledge() - } - } - try { - deliverMessage(context, publish.toPushMessage()) { - pending.incrementAndGet() - val once = AtomicBoolean(false) - val ack: () -> Unit = { - if (once.compareAndSet(false, true)) { - settle() - } - } - ack - } - } finally { - settle() - } - if (!acknowledged.get()) { - ackTimer.schedule({ acknowledge() }, ACK_TIMEOUT_SECONDS, TimeUnit.SECONDS) - } - } - - // Deliver a message to the matching live callbacks; with none, to the declared PushReceiver - // and/or a notification per saved subscription that matches it. [deferAck] hands a listener - // that acknowledges messages itself its acknowledgement. - private fun deliverMessage(context: Context, message: PushMessage, deferAck: () -> () -> Unit) { - val matching = listeners.filter { listener -> listener.topics.any { matchesTopic(it, message.topic) } } - // Saved background subscriptions no live one has taken over; they deliver even when a live - // foreground-only subscription on an overlapping filter received the message too. - val entries = synchronized(lock) { saved }.filter { matchesTopic(it.filter, message.topic) } - if (matching.isEmpty() && entries.isEmpty()) { - return - } - for (listener in matching) { - try { - val acknowledging = listener.acknowledgingCallback - if (acknowledging != null) { - acknowledging(message, deferAck()) - } else { - listener.callback(message) - } - } catch (e: Exception) { - report(e) - } - } - val wakeLock = acquireWakeLock(context) - try { - // The app's PushReceiver gets only messages no live callback received. - val handled = matching.isEmpty() && deliverToReceivers(context, message) - val content = notificationContent(message) - // Background subscriptions notify while the app is not visible; on screen, only those - // that opted in with notifyInForeground do, since the app shows the message itself. A - // message no live callback received still notifies, as the app has not shown it. - val foreground = appInForeground() - val shown = foreground && matching.isNotEmpty() - val titles = matching.filter { it.background && (!foreground || it.notifyInForeground) }.map { it.title ?: message.topic } + - if (handled) emptyList() else entries.filter { !shown || it.notifyInForeground }.map { it.title ?: message.topic } - // A title the server sent replaces every subscription's, so one notification is posted. - titles.map { content.title ?: it }.distinct().forEach { notify(context, message, it, content) } - } finally { - releaseWakeLock(wakeLock) - } - } - - // Call every PushReceiver the app declares. Returns whether one handled the message. - private fun deliverToReceivers(context: Context, message: PushMessage): Boolean { - val intent = Intent(ACTION_MESSAGE).setPackage(context.packageName) - val receivers = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { - context.packageManager.queryBroadcastReceivers(intent, PackageManager.ResolveInfoFlags.of(0)) - } else { - @Suppress("DEPRECATION") - context.packageManager.queryBroadcastReceivers(intent, 0) - } - var handled = false - for (info in receivers) { - val name = info.activityInfo?.name ?: continue - try { - val receiver = Class.forName(name, true, context.classLoader).getDeclaredConstructor().newInstance() - if (receiver is PushReceiver && receiver.onMessage(context, message)) { - handled = true - } - } catch (e: Exception) { - report(e) - } - } - return handled - } - - /** - * Post a notification for [message] that opens the app, with the message in its extras. It shows - * the server's title, body and image from [content], falling back to [title] and the raw payload. - */ - fun notify(context: Context, message: PushMessage, title: String, content: PushNotificationContent = notificationContent(message)) { - val manager = NotificationManagerCompat.from(context) - if (!manager.areNotificationsEnabled()) { - return - } - createChannels(context) - val id = 31 * message.hashCode() + title.hashCode() - val body = content.body ?: message.data.takeIf { !content.present } - val builder = NotificationCompat.Builder(context, CHANNEL_ID) - .setContentTitle(content.title ?: title) - .setSmallIcon(notificationIcon(context)) - .setAutoCancel(true) - if (body != null) { - builder.setContentText(body).setStyle(NotificationCompat.BigTextStyle().bigText(body)) - } - content.image?.let { loadImage(it) }?.let { image -> - builder.setLargeIcon(image) - .setStyle(NotificationCompat.BigPictureStyle().bigPicture(image).bigLargeIcon(null as Bitmap?).setSummaryText(body)) - } - val open = Intent(context, PushOpenActivity::class.java) - .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_NO_ANIMATION) - .putExtra(EXTRA_TOPIC, message.topic) - .putExtra(EXTRA_PAYLOAD, message.data) - builder.setContentIntent( - PendingIntent.getActivity(context, id, open, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE), - ) - try { - manager.notify(id, builder.build()) - } catch (e: SecurityException) { - // POST_NOTIFICATIONS not granted; nothing to show. - } - } - - // Whether one of the app's activities is visible: a foreground service alone does not count. - private fun appInForeground(): Boolean = ActivityManager.RunningAppProcessInfo() - .also { ActivityManager.getMyMemoryState(it) } - .importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND - - /** The server's `notification` block in [message]: nulls when the payload has none or is not JSON. */ - fun notificationContent(message: PushMessage): PushNotificationContent { - val notification = runCatching { JSONObject(message.data) }.getOrNull()?.optJSONObject("notification") - ?: return PushNotificationContent(false, null, null, null) - fun field(name: String) = (notification.opt(name) as? String)?.takeIf { it.isNotEmpty() } - return PushNotificationContent(true, field("title"), field("body"), field("image")) - } - - // Downloads notification images, so a slow one is abandoned without holding up delivery. - // Acknowledgement timeouts, apart from [worker] so they fire while a run's drain window holds it. - private val ackTimer = Executors.newSingleThreadScheduledExecutor { runnable -> - Thread(runnable, "AppwritePushAck").apply { isDaemon = true } - } - - private val imageLoader = Executors.newCachedThreadPool { runnable -> - Thread(runnable, "AppwritePushImage").apply { isDaemon = true } - } - - // Download a notification image, or null when it cannot be fetched and decoded within - // IMAGE_TIMEOUT_MS overall. On timeout the connection is closed, which ends a read in progress. - private fun loadImage(url: String): Bitmap? { - val connection = runCatching { URL(url).openConnection() as HttpURLConnection }.getOrNull() ?: return null - connection.connectTimeout = IMAGE_TIMEOUT_MS - connection.readTimeout = IMAGE_TIMEOUT_MS - val download = imageLoader.submit { connection.inputStream.use { readLimited(it, IMAGE_MAX_BYTES) }?.let { decodeImage(it) } } - return try { - download.get(IMAGE_TIMEOUT_MS.toLong(), TimeUnit.MILLISECONDS) - } catch (e: Exception) { - download.cancel(true) - null - } finally { - connection.disconnect() - } - } - - // At most [limit] bytes of [input], or null when it holds more. - private fun readLimited(input: InputStream, limit: Int): ByteArray? { - val out = ByteArrayOutputStream() - val buffer = ByteArray(8_192) - while (true) { - val read = input.read(buffer) - if (read < 0) { - return out.toByteArray() - } - if (out.size() + read > limit) { - return null - } - out.write(buffer, 0, read) - } - } - - // Decode [bytes] downsampled so neither side exceeds IMAGE_MAX_PX, so a large photo cannot - // exhaust memory while a notification is posted. - private fun decodeImage(bytes: ByteArray): Bitmap? { - val bounds = BitmapFactory.Options().apply { inJustDecodeBounds = true } - BitmapFactory.decodeByteArray(bytes, 0, bytes.size, bounds) - if (bounds.outWidth <= 0 || bounds.outHeight <= 0) { - return null - } - var sample = 1 - while (bounds.outWidth / sample > IMAGE_MAX_PX || bounds.outHeight / sample > IMAGE_MAX_PX) { - sample *= 2 - } - return BitmapFactory.decodeByteArray(bytes, 0, bytes.size, BitmapFactory.Options().apply { inSampleSize = sample }) - } - - /** The ongoing notification the foreground service shows, on its own quiet channel. */ - fun ongoingNotification(context: Context) = NotificationCompat.Builder(context, SERVICE_CHANNEL_ID) - .also { createChannels(context) } - .setContentTitle(ongoingTitle) - .setContentText("Listening for messages") - .setSmallIcon(notificationIcon(context)) - .setPriority(NotificationCompat.PRIORITY_LOW) - .setOngoing(true) - .build() - - private fun createChannels(context: Context) { - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) { - return - } - val manager = context.getSystemService(NotificationManager::class.java) ?: return - manager.createNotificationChannel(NotificationChannel(CHANNEL_ID, channelName, NotificationManager.IMPORTANCE_HIGH)) - manager.createNotificationChannel( - NotificationChannel(SERVICE_CHANNEL_ID, "Background connection", NotificationManager.IMPORTANCE_LOW), - ) - } - - // The icon named by the app's ``, else a - // generic one. - private fun notificationIcon(context: Context): Int { - val metaData = runCatching { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { - context.packageManager.getApplicationInfo(context.packageName, PackageManager.ApplicationInfoFlags.of(PackageManager.GET_META_DATA.toLong())) - } else { - @Suppress("DEPRECATION") - context.packageManager.getApplicationInfo(context.packageName, PackageManager.GET_META_DATA) - }.metaData - }.getOrNull() - return metaData?.getInt(NOTIFICATION_ICON, 0)?.takeIf { it != 0 } ?: android.R.drawable.stat_notify_chat - } - - private fun ensureService(context: Context) { - if (!wantsService(context)) { - if (serviceRunning) { - context.stopService(Intent(context, PushService::class.java)) - } - return - } - if (serviceRunning) { - return - } - try { - ContextCompat.startForegroundService(context, Intent(context, PushService::class.java)) - } catch (e: Exception) { - // Android 12+ refuses a foreground-service start from the background; the scheduled - // runs keep delivering, and the next start from the foreground succeeds. - if (!serviceStartReported) { - serviceStartReported = true - report(e) - } - } - } - - // Arm the next run in [delayMs]: the job, and an alarm just after it in case the job is late. - // The chained job alternates between two ids, so a run ([runningJobId]) never schedules its - // own id, which would stop it; the other id is cancelled only when it is not the one running. - private fun schedule(context: Context, delayMs: Long, alarmOnly: Boolean = false, runningJobId: Int? = null) { - val interval = interval(context, delayMs) - if (!alarmOnly) { - val next = if (runningJobId == JOB_ID) NEXT_JOB_ID else JOB_ID - if (runningJobId == null) { - context.getSystemService(JobScheduler::class.java)?.cancel(if (next == JOB_ID) NEXT_JOB_ID else JOB_ID) - } - scheduleJob(context, delayMs, next) - } - val alarms = context.getSystemService(AlarmManager::class.java) ?: return - val at = SystemClock.elapsedRealtime() + interval + 1_000L - val intent = tickIntent(context) - try { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S && !alarms.canScheduleExactAlarms()) { - alarms.setAndAllowWhileIdle(AlarmManager.ELAPSED_REALTIME_WAKEUP, at, intent) - } else { - alarms.setExactAndAllowWhileIdle(AlarmManager.ELAPSED_REALTIME_WAKEUP, at, intent) - } - } catch (e: SecurityException) { - alarms.setAndAllowWhileIdle(AlarmManager.ELAPSED_REALTIME_WAKEUP, at, intent) - } - } - - private fun interval(context: Context, delayMs: Long): Long = - if (delayMs == INTERVAL_MS && privileged(context)) PRIVILEGED_INTERVAL_MS else delayMs - - private fun scheduleJob(context: Context, delayMs: Long, id: Int) { - try { - val job = JobInfo.Builder(id, ComponentName(context, PushJobService::class.java)) - .setMinimumLatency(interval(context, delayMs)) - .setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY) - .setPersisted(true) - .build() - context.getSystemService(JobScheduler::class.java)?.schedule(job) - } catch (e: Exception) { - report(e) - } - } - - // A periodic job, independent of the chain of runs, that restarts the chain when a run was - // dropped (the process killed between runs, a deferred alarm, a throttled job). Scheduled once, - // so its period is not reset by every run. - private fun ensureWatchdog(context: Context) { - val jobs = context.getSystemService(JobScheduler::class.java) ?: return - try { - if (jobs.allPendingJobs.any { it.id == WATCHDOG_JOB_ID }) { - return - } - jobs.schedule( - JobInfo.Builder(WATCHDOG_JOB_ID, ComponentName(context, PushJobService::class.java)) - .setPeriodic(WATCHDOG_INTERVAL_MS) - .setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY) - .setPersisted(true) - .build(), - ) - } catch (e: Exception) { - report(e) - } - } - - private fun cancelSchedule(context: Context) { - context.getSystemService(JobScheduler::class.java)?.cancel(JOB_ID) - context.getSystemService(JobScheduler::class.java)?.cancel(NEXT_JOB_ID) - context.getSystemService(JobScheduler::class.java)?.cancel(EXPEDITED_JOB_ID) - context.getSystemService(JobScheduler::class.java)?.cancel(WATCHDOG_JOB_ID) - context.getSystemService(AlarmManager::class.java)?.cancel(tickIntent(context)) - } - - private fun tickIntent(context: Context): PendingIntent = PendingIntent.getBroadcast( - context, - 0, - Intent(context, PushAlarmReceiver::class.java).setAction(ACTION_TICK), - PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE, - ) - - /** What background delivery can rely on now; see [PushBackgroundStatus]. */ - fun backgroundStatus(context: Context): PushBackgroundStatus { - val app = context.applicationContext - return PushBackgroundStatus( - exactAlarms = Build.VERSION.SDK_INT < Build.VERSION_CODES.S || - app.getSystemService(AlarmManager::class.java)?.canScheduleExactAlarms() == true, - ignoringBatteryOptimizations = app.getSystemService(PowerManager::class.java)?.isIgnoringBatteryOptimizations(app.packageName) == true, - foregroundService = PushStore.foreground(app), - ) - } - - /** - * Open the system screen where the user allows exact alarms (Android 12+). Returns false when - * there is nothing to ask: already allowed, older Android, or the app does not declare - * `SCHEDULE_EXACT_ALARM`. - */ - fun requestExactAlarms(context: Context): Boolean { - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S || backgroundStatus(context).exactAlarms) { - return false - } - return openSettings(context, Settings.ACTION_REQUEST_SCHEDULE_EXACT_ALARM, Manifest.permission.SCHEDULE_EXACT_ALARM) - } - - /** - * Ask the user to exempt the app from battery optimisation. Returns false when there is - * nothing to ask: already exempt, or the app does not declare - * `REQUEST_IGNORE_BATTERY_OPTIMIZATIONS`. - */ - fun requestIgnoreBatteryOptimizations(context: Context): Boolean { - if (backgroundStatus(context).ignoringBatteryOptimizations) { - return false - } - return openSettings( - context, - Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS, - Manifest.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS, - ) - } - - // Open a settings screen for this package when the app declares [permission]. - private fun openSettings(context: Context, action: String, permission: String): Boolean { - val app = context.applicationContext - val declared = runCatching { - @Suppress("DEPRECATION") - app.packageManager.getPackageInfo(app.packageName, PackageManager.GET_PERMISSIONS).requestedPermissions - }.getOrNull()?.contains(permission) == true - if (!declared) { - return false - } - return try { - app.startActivity(Intent(action, Uri.parse("package:${app.packageName}")).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)) - true - } catch (e: Exception) { - false - } - } - - // Allowed exact alarms or exempt from battery optimisation: the alarm is reliable, so the - // runs can be spaced further apart. - private fun privileged(context: Context): Boolean = - Build.VERSION.SDK_INT < Build.VERSION_CODES.S || - context.getSystemService(AlarmManager::class.java)?.canScheduleExactAlarms() == true || - context.getSystemService(PowerManager::class.java)?.isIgnoringBatteryOptimizations(context.packageName) == true - - private fun activeNetwork(context: Context): Network? = - runCatching { context.getSystemService(ConnectivityManager::class.java)?.activeNetwork }.getOrNull() - - private fun networkChanged(context: Context): Boolean { - val now = activeNetwork(context) - return now != null && connectedNetwork != null && now != connectedNetwork - } - - // Reconnect as soon as the default network changes (e.g. from cellular to Wi-Fi) while the - // process is alive, instead of waiting for the next run to notice. - private fun registerNetworkCallback(context: Context) { - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) { - return - } - synchronized(lock) { - if (networkCallback != null) { - return - } - val callback = object : ConnectivityManager.NetworkCallback() { - override fun onAvailable(network: Network) { - worker.execute { - if (mqtt != null && network != connectedNetwork) { - converge(context, heartbeat = false) - } - } - } - } - try { - context.getSystemService(ConnectivityManager::class.java)?.registerDefaultNetworkCallback(callback) - networkCallback = callback - } catch (e: Exception) { - report(e) - } - } - } - - private fun unregisterNetworkCallback(context: Context) { - val callback = synchronized(lock) { networkCallback.also { networkCallback = null } } ?: return - runCatching { context.getSystemService(ConnectivityManager::class.java)?.unregisterNetworkCallback(callback) } - } - - private fun acquireWakeLock(context: Context): PowerManager.WakeLock? = runCatching { - context.getSystemService(PowerManager::class.java) - ?.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "Appwrite:push") - ?.apply { - setReferenceCounted(false) - acquire(WAKE_LOCK_MS) - } - }.getOrNull() - - private fun releaseWakeLock(wakeLock: PowerManager.WakeLock?) { - runCatching { - if (wakeLock?.isHeld == true) { - wakeLock.release() - } - } - } -} - -/** - * Background push state in the app's no-backup directory, so a restored backup on another - * device never carries this install's id or credential: the saved subscriptions with their - * connection config (cleared when background delivery stops), and the settings that outlive - * it (the install id, the foreground-mode choice, a refusal waiting for onError). - */ -internal object PushStore { - private const val STATE_FILE = "appwrite_push_state.json" - private const val SETTINGS_FILE = "appwrite_push_settings.json" - - fun loadState(context: Context): Pair>? = synchronized(this) { - val json = read(context, STATE_FILE) ?: return null - runCatching { - val config = json.getJSONObject("config").let { - PushConfig( - host = it.getString("host"), - port = it.getInt("port"), - tls = it.getBoolean("tls"), - tlsInsecure = it.getBoolean("tlsInsecure"), - clientId = it.getString("clientId"), - keepAlive = it.getInt("keepAlive"), - authMethod = it.getString("authMethod"), - credential = it.getString("credential"), - project = it.getString("project"), - sessionCookieUrl = if (it.isNull("sessionCookieUrl")) null else it.optString("sessionCookieUrl").ifEmpty { null }, - ) - } - val list = json.getJSONArray("entries") - val entries = (0 until list.length()).map { index -> - val entry = list.getJSONObject(index) - PushEntry( - filter = entry.getString("filter"), - retry = entry.getBoolean("retry"), - title = if (entry.isNull("title")) null else entry.getString("title"), - notifyInForeground = entry.optBoolean("notifyInForeground", false), - ) - } - config to entries - }.getOrNull() - } - - fun saveState(context: Context, config: PushConfig, entries: List) = synchronized(this) { - val json = JSONObject() - .put( - "config", - JSONObject() - .put("host", config.host) - .put("port", config.port) - .put("tls", config.tls) - .put("tlsInsecure", config.tlsInsecure) - .put("clientId", config.clientId) - .put("keepAlive", config.keepAlive) - .put("authMethod", config.authMethod) - .put("credential", config.credential) - .put("project", config.project) - .put("sessionCookieUrl", config.sessionCookieUrl ?: JSONObject.NULL), - ) - .put( - "entries", - JSONArray(entries.map { JSONObject().put("filter", it.filter).put("retry", it.retry).put("title", it.title ?: JSONObject.NULL).put("notifyInForeground", it.notifyInForeground) }), - ) - write(context, STATE_FILE, json) - } - - fun clearState(context: Context) = synchronized(this) { - file(context, STATE_FILE).delete() - } - - /** A random id for this install, created once, which keeps the broker's replay position. */ - fun installId(context: Context): String = synchronized(this) { - val settings = read(context, SETTINGS_FILE) ?: JSONObject() - settings.optString("installId").ifEmpty { - val id = UUID.randomUUID().toString() - write(context, SETTINGS_FILE, settings.put("installId", id)) - id - } - } - - fun foreground(context: Context): Boolean = synchronized(this) { - read(context, SETTINGS_FILE)?.optBoolean("foreground", false) ?: false - } - - fun setForeground(context: Context, enabled: Boolean) = synchronized(this) { - write(context, SETTINGS_FILE, (read(context, SETTINGS_FILE) ?: JSONObject()).put("foreground", enabled)) - } - - /** The saved adaptive heartbeat; the default interval until one was saved. */ - fun heartbeat(context: Context): PushHeartbeat = synchronized(this) { - val json = read(context, SETTINGS_FILE)?.optJSONObject("heartbeat") ?: return PushHeartbeat(PushBackground.HEARTBEAT_MS) - PushHeartbeat( - intervalMs = json.optLong("intervalMs", PushBackground.HEARTBEAT_MS), - failures = json.optInt("failures", 0), - shrunkAt = json.optLong("shrunkAt", 0L), - ) - } - - fun setHeartbeat(context: Context, state: PushHeartbeat) = synchronized(this) { - val heartbeat = JSONObject() - .put("intervalMs", state.intervalMs) - .put("failures", state.failures) - .put("shrunkAt", state.shrunkAt) - write(context, SETTINGS_FILE, (read(context, SETTINGS_FILE) ?: JSONObject()).put("heartbeat", heartbeat)) - } - - fun setStoppedError(context: Context, message: String) = synchronized(this) { - write(context, SETTINGS_FILE, (read(context, SETTINGS_FILE) ?: JSONObject()).put("stoppedError", message)) - } - - /** The refusal that stopped background delivery while no onError was registered, once. */ - fun takeStoppedError(context: Context): String? = synchronized(this) { - val settings = read(context, SETTINGS_FILE) ?: return null - val message = settings.optString("stoppedError").ifEmpty { return null } - settings.remove("stoppedError") - write(context, SETTINGS_FILE, settings) - message - } - - private fun file(context: Context, name: String) = AtomicFile(File(context.noBackupFilesDir, name)) - - private fun read(context: Context, name: String): JSONObject? = - runCatching { JSONObject(String(file(context, name).readFully(), Charsets.UTF_8)) }.getOrNull() - - private fun write(context: Context, name: String, json: JSONObject) { - val file = file(context, name) - val out = try { - file.startWrite() - } catch (e: IOException) { - Log.e(LOG_TAG, "Could not save push state", e) - return - } - try { - out.write(json.toString().toByteArray(Charsets.UTF_8)) - file.finishWrite(out) - } catch (e: IOException) { - file.failWrite(out) - Log.e(LOG_TAG, "Could not save push state", e) - } - } -} diff --git a/android/src/main/java/io/appwrite/services/PushBridge.kt b/android/src/main/java/io/appwrite/services/PushBridge.kt deleted file mode 100644 index e5cb5aae..00000000 --- a/android/src/main/java/io/appwrite/services/PushBridge.kt +++ /dev/null @@ -1,198 +0,0 @@ -package io.appwrite.services - -import android.content.Context -import android.os.SystemClock -import org.json.JSONArray -import org.json.JSONObject -import java.util.UUID -import java.util.concurrent.ConcurrentHashMap - -/** - * The contract the React Native and Flutter SDKs use to host their background push - * subscriptions on this Android core, so they get the same delivery as the Android SDK: saved - * subscriptions, scheduled wake-ups after the process dies, notifications, and foreground mode. - * - * Both SDKs pass the same JSON: [host] takes the connection config and every live subscription, - * and each message for a live subscription comes back through [Events.onMessage] with its id and - * an acknowledgement token, which the SDK passes to [ack] once its callback has run (the broker's - * PUBACK waits for it, at most ten seconds). One bridge per process; hosting again replaces the - * live subscriptions. - */ -class PushBridge(context: Context, private val events: Events) { - /** Where messages and errors go; called on a background thread. */ - interface Events { - fun onMessage(subscriptionId: String, message: PushMessage, ackToken: String) - - fun onError(message: String) - - fun onConnection(connected: Boolean) - } - - private val appContext = context.applicationContext - // Acknowledgement token -> (when it was handed out, the acknowledgement). A token the SDK never - // acknowledges (its JS or Dart side was gone) is dropped once the core has acknowledged the - // message anyway, so the map stays bounded. - private val acks = ConcurrentHashMap Unit>>() - - // Whether the app registered onError; without one, errors are logged and a refused - // credential is kept for the next registration. - @Volatile - private var errorCallback = false - - private var connected: Boolean? = null - - /** - * Host the subscriptions in [subscriptionsJson] on the background connection described by - * [configJson]. - * - * Config: `{"host", "port", "tls", "tlsInsecure", "clientId" (optional; per user and install - * when empty), "authMethod", "credential", "project", "sessionCookieUrl" (optional: the endpoint - * whose session cookie in the WebView cookie store holds the credential, so background runs - * follow a rotated session)}`. Subscriptions: an array of - * `{"id", "topic", "background", "title" (optional), "retry", "notifyInForeground" (optional)}`. - * - * [done] is called once the connection is up and every filter is subscribed, or with the - * failure's message; the SDK rejects its subscribe with it and reports it itself. - */ - fun host(configJson: String, subscriptionsJson: String, done: (String?) -> Unit) { - val json = JSONObject(configJson) - val authMethod = json.getString("authMethod") - val credential = json.getString("credential") - val config = PushConfig( - host = json.getString("host"), - port = json.getInt("port"), - tls = json.optBoolean("tls", false), - tlsInsecure = json.optBoolean("tlsInsecure", false), - clientId = json.optString("clientId").ifEmpty { defaultPushClientId(appContext, authMethod, credential) }, - keepAlive = KEEP_ALIVE_SECONDS, - authMethod = authMethod, - credential = credential, - project = json.optString("project"), - sessionCookieUrl = if (json.isNull("sessionCookieUrl")) null else json.optString("sessionCookieUrl").ifEmpty { null }, - ) - val list = JSONArray(subscriptionsJson) - val listeners = (0 until list.length()).map { index -> - val subscription = list.getJSONObject(index) - val id = subscription.getString("id") - PushListener( - topics = setOf(subscription.getString("topic")), - callback = {}, - acknowledgingCallback = { message, ack -> - val token = UUID.randomUUID().toString() - val now = SystemClock.elapsedRealtime() - acks.entries.removeIf { now - it.value.first > STALE_ACK_MS } - acks[token] = now to ack - events.onMessage(id, message, token) - }, - background = subscription.optBoolean("background", false), - title = if (subscription.isNull("title")) null else subscription.optString("title").ifEmpty { null }, - retry = subscription.optBoolean("retry", true), - notifyInForeground = subscription.optBoolean("notifyInForeground", false), - ) - } - PushBackground.errorHandler = { error -> - if (errorCallback) { - events.onError(error.message ?: error.toString()) - } - errorCallback - } - PushBackground.connectionHandler = { connection(it) } - PushBackground.host(appContext, config, listeners) { error -> - if (error == null && PushBackground.isConnected) { - connection(true) - } - done(error?.let { it.message ?: it.toString() }) - } - } - - /** Whether the background connection is open now. */ - fun isConnected(): Boolean = PushBackground.isConnected - - private fun connection(open: Boolean) { - synchronized(this) { - if (connected == open) { - return - } - connected = open - } - events.onConnection(open) - } - - /** Acknowledge a message once the SDK's callback for it has run. */ - fun ack(token: String) { - acks.remove(token)?.second?.invoke() - } - - /** Stop hosting the live subscriptions, keeping the ones saved by an earlier run. */ - fun release() { - forgetConnection() - PushBackground.release(appContext) - } - - /** Stop background delivery and forget every saved subscription (sign-out). */ - fun stop() { - forgetConnection() - PushBackground.stop(appContext) - } - - private fun forgetConnection() { - PushBackground.connectionHandler = null - val wasOpen = synchronized(this) { - (connected == true).also { connected = null } - } - if (wasOpen) { - events.onConnection(false) - } - } - - /** Run background delivery in a foreground service; saved across restarts. */ - fun setForeground(enabled: Boolean) = PushBackground.setForeground(appContext, enabled) - - /** Whether an earlier run saved background subscriptions that are still delivered. */ - fun hasSaved(): Boolean = PushBackground.hasSaved(appContext) - - /** - * Resume saved background delivery now instead of at the next scheduled run, with the app's - * current credential (null when it has none). A rotated session of the same user replaces - * the saved one; another user, or none when [signedOutWhenMissing], drops the saved - * subscriptions without reporting an error. - */ - fun resume(authMethod: String?, credential: String?, signedOutWhenMissing: Boolean) = - PushBackground.resume(appContext, authMethod, credential, signedOutWhenMissing) - - /** - * Record whether the app has an onError callback. Returns the refusal that stopped background - * delivery while it had none, once, so the app can deliver it now. - */ - fun setErrorCallback(registered: Boolean): String? { - errorCallback = registered - return if (registered) PushStore.takeStoppedError(appContext) else null - } - - /** What background delivery can rely on, as `{"exactAlarms", "ignoringBatteryOptimizations", "foregroundService", "bestEffort"}`. */ - fun backgroundStatus(): String = PushBackground.backgroundStatus(appContext).let { - JSONObject() - .put("exactAlarms", it.exactAlarms) - .put("ignoringBatteryOptimizations", it.ignoringBatteryOptimizations) - .put("foregroundService", it.foregroundService) - .put("bestEffort", it.bestEffort) - .toString() - } - - /** Open the system screen that allows exact alarms; false when there is nothing to ask. */ - fun requestExactAlarms(): Boolean = PushBackground.requestExactAlarms(appContext) - - /** Ask to exempt the app from battery optimisation; false when there is nothing to ask. */ - fun requestIgnoreBatteryOptimizations(): Boolean = PushBackground.requestIgnoreBatteryOptimizations(appContext) - - /** The default client id for a credential, so a foreground connection shares its session. */ - fun defaultClientId(authMethod: String, credential: String): String = - defaultPushClientId(appContext, authMethod, credential) - - private companion object { - const val KEEP_ALIVE_SECONDS = 60 - - // Past the core's ten-second acknowledgement cap, after which the message was acknowledged. - const val STALE_ACK_MS = 30_000L - } -} diff --git a/android/src/main/java/io/appwrite/services/PushCore.kt b/android/src/main/java/io/appwrite/services/PushCore.kt deleted file mode 100644 index 15f86b6a..00000000 --- a/android/src/main/java/io/appwrite/services/PushCore.kt +++ /dev/null @@ -1,454 +0,0 @@ -package io.appwrite.services - -import android.content.Context -import android.os.Build -import android.util.Base64 -import com.hivemq.client.mqtt.MqttClient -import com.hivemq.client.mqtt.datatypes.MqttUtf8String -import com.hivemq.client.mqtt.lifecycle.MqttClientDisconnectedContext -import com.hivemq.client.mqtt.lifecycle.MqttDisconnectSource -import com.hivemq.client.mqtt.mqtt5.Mqtt5AsyncClient -import com.hivemq.client.mqtt.mqtt5.Mqtt5ClientConfig -import com.hivemq.client.mqtt.mqtt5.auth.Mqtt5EnhancedAuthMechanism -import com.hivemq.client.mqtt.mqtt5.exceptions.Mqtt5ConnAckException -import com.hivemq.client.mqtt.mqtt5.exceptions.Mqtt5DisconnectException -import com.hivemq.client.mqtt.mqtt5.lifecycle.Mqtt5ClientReconnector -import com.hivemq.client.mqtt.mqtt5.message.auth.Mqtt5Auth -import com.hivemq.client.mqtt.mqtt5.message.auth.Mqtt5AuthBuilder -import com.hivemq.client.mqtt.mqtt5.message.auth.Mqtt5EnhancedAuthBuilder -import com.hivemq.client.mqtt.mqtt5.message.connect.Mqtt5Connect -import com.hivemq.client.mqtt.mqtt5.message.connect.connack.Mqtt5ConnAck -import com.hivemq.client.mqtt.mqtt5.message.connect.connack.Mqtt5ConnAckReasonCode -import com.hivemq.client.mqtt.mqtt5.message.disconnect.Mqtt5Disconnect -import com.hivemq.client.mqtt.mqtt5.message.disconnect.Mqtt5DisconnectReasonCode -import com.hivemq.client.mqtt.mqtt5.message.publish.Mqtt5Publish -import io.appwrite.exceptions.AppwriteException -import org.json.JSONObject -import java.security.KeyStore -import java.security.Provider -import java.security.cert.X509Certificate -import java.util.concurrent.CompletableFuture -import java.util.concurrent.ExecutionException -import java.util.concurrent.TimeUnit -import java.util.concurrent.atomic.AtomicBoolean -import java.util.concurrent.atomic.AtomicReference -import javax.net.ssl.ManagerFactoryParameters -import javax.net.ssl.TrustManager -import javax.net.ssl.TrustManagerFactory -import javax.net.ssl.TrustManagerFactorySpi -import javax.net.ssl.X509TrustManager - -/** - * A message delivered on a subscribed topic — the MQTT push analog of a realtime event. - */ -data class PushMessage( - val topic: String, - val payload: ByteArray, - val qos: Int, -) { - /** The payload decoded as UTF-8 text, as it was sent. */ - val data: String - get() = String(payload, Charsets.UTF_8) -} - -/** - * What background delivery can rely on. Without exact alarms, the scheduled wake-ups are inexact - * and Doze can defer them, so delivery is [bestEffort] unless foreground mode keeps the - * connection open. - */ -data class PushBackgroundStatus( - /** The app may schedule exact alarms (`SCHEDULE_EXACT_ALARM`, granted). */ - val exactAlarms: Boolean, - /** The app is exempt from battery optimisation. */ - val ignoringBatteryOptimizations: Boolean, - /** Foreground mode (`setForeground(true)`) keeps the connection open in a service. */ - val foregroundService: Boolean, -) { - /** Wake-ups may be deferred by Doze, so messages can arrive late while the app is closed. */ - val bestEffort: Boolean - get() = !exactAlarms && !foregroundService -} - -/** Connection parameters shared between the in-process client and the foreground service. */ -internal data class PushConfig( - val host: String, - val port: Int, - val tls: Boolean, - val tlsInsecure: Boolean, - val clientId: String, - val keepAlive: Int, - val authMethod: String, - val credential: String, - val project: String, - // The endpoint whose `a_session_` cookie in the WebView cookie store holds the app's - // session, when its credential comes from there (React Native). Background runs read it, so - // they keep up with a rotated session while no app code runs. - val sessionCookieUrl: String? = null, -) - -/** - * The userId claim from an Appwrite JWT, used as the default MQTT client id so the - * broker's replay cursor is stable per user. Returns "" when the token is not a decodable JWT - * (e.g. a session secret), so the caller can fall back to the raw credential. - */ -internal fun userIdFromJwt(jwt: String): String { - val parts = jwt.split('.') - if (parts.size < 2) { - return "" - } - return runCatching { - val json = String( - Base64.decode(parts[1], Base64.URL_SAFE or Base64.NO_WRAP or Base64.NO_PADDING), - Charsets.UTF_8, - ) - JSONObject(json).optString("userId", "") - }.getOrDefault("") -} - -/** The user `id` from an Appwrite session secret, or "" when it is not decodable. */ -internal fun userIdFromSession(session: String): String = runCatching { - val json = String(Base64.decode(session, Base64.DEFAULT), Charsets.UTF_8) - JSONObject(json).optString("id", "") -}.getOrDefault("") - -/** - * The default MQTT client id: one per user and install (`-`, or the install id - * alone when the credential names no user). The broker keeps the replay position per user and - * client id, so each device resumes its own backlog across restarts, and two devices of one user - * do not take over each other's session. - */ -internal fun defaultPushClientId(context: Context, authMethod: String, credential: String): String { - val userId = if (authMethod == "appwrite-session") userIdFromSession(credential) else userIdFromJwt(credential) - val installId = PushStore.installId(context) - return if (userId.isEmpty()) installId else "$userId-$installId" -} - -/** - * Build (but do not connect) an MQTT 5 client from [config]. [onError] receives every connection - * error (a lost connection, a failed automatic reconnect, a broker DISCONNECT) except a refused - * initial CONNECT, which [pushConnect] throws instead. - */ -internal fun buildPushClient( - config: PushConfig, - onConnected: (() -> Unit)? = null, - onDisconnected: (() -> Unit)? = null, - onError: ((Throwable) -> Unit)? = null, - onAuthRefused: ((Throwable) -> Unit)? = null, - credential: () -> String? = { config.credential }, - retired: AtomicBoolean? = null, -): Mqtt5AsyncClient { - // config.clientId is stable per user (see buildConfig), so a reconnect rebuild reuses it - // and resumes the same session. - var builder = MqttClient.builder() - .useMqttVersion5() - .serverHost(config.host) - .serverPort(config.port) - // Recover from an unexpected disconnect (network drop, broker restart) with HiveMQ's - // exponential backoff. A user-initiated disconnect() (see close()) does not trigger it. - // Because clean start is off and the broker resumes the same session, subscriptions and - // the QoS-1 replay cursor persist, so delivery continues without resubscribing (which - // would stack a second per-subscription callback). - .automaticReconnectWithDefaultConfig() - - if (config.clientId.isNotEmpty()) { - builder = builder.identifier(config.clientId) - } - - // Whether this client has connected yet: until it has, a refused CONNECT is final. - val connected = AtomicBoolean(false) - val client = AtomicReference() - builder = builder.addConnectedListener { - // A reconnect that was already under way when the client was retired disconnects at once, - // so it never competes with its replacement for the broker session. - if (retired?.get() == true) { - client.get()?.disconnect() - return@addConnectedListener - } - connected.set(true) - onConnected?.invoke() - } - builder = builder.addDisconnectedListener { context -> - // A client its owner replaced or closed ([retired]) never reconnects: one still retrying - // in the background would otherwise come back as a second connection for the same id. - if (retired?.get() == true) { - context.reconnector.reconnect(false) - onDisconnected?.invoke() - return@addDisconnectedListener - } - // A refused first CONNECT (bad credential, rate limit) is final: stop the automatic - // reconnect so pushConnect fails with the broker's reason instead of retrying forever. - val refused = !connected.get() && context.cause is Mqtt5ConnAckException - // With [onAuthRefused], a credential refused later (a failed automatic reconnect or - // re-auth) is final too, instead of being retried with the same credential forever. - val authRefused = onAuthRefused != null && connected.get() && - context.source != MqttDisconnectSource.USER && isAuthRefusal(context.cause) - // Authentication was aborted because the app has no current credential (signed out): there - // is nothing to reconnect with, so the attempt fails now instead of retrying until timeout. - val noCredential = generateSequence(context.cause) { it.cause }.any { it is PushNoCredentialException } - if (refused || authRefused || noCredential) { - context.reconnector.reconnect(false) - } else if (context.reconnector.isReconnect) { - // HiveMQ's automatic reconnect sends a CONNECT it builds itself, without user - // properties: the broker then misses the project and refuses the credential. Reconnect - // with the same CONNECT this client connects with instead. - (context.reconnector as? Mqtt5ClientReconnector)?.connect(pushConnectMessage(config, credential)) - } - onDisconnected?.invoke() - if (!refused) { - val error = pushDisconnectError(context) - if (authRefused && error != null) { - // Reported by onAuthRefused, which also stops for good. - onAuthRefused?.invoke(error) - } else { - error?.let { onError?.invoke(it) } - } - } - } - - if (config.tls) { - builder = if (config.tlsInsecure) { - builder.sslConfig() - .trustManagerFactory(PushInsecureTrustManagerFactory) - .hostnameVerifier { _, _ -> true } - .applySslConfig() - } else { - builder.sslWithDefaultConfig() - } - } - - return builder.buildAsync().also { client.set(it) } -} - -/** - * Connect with Appwrite enhanced auth; blocks until CONNACK. Throws an - * [AppwriteException] on failure, whose message is the broker's MQTT 5 - * Reason String when it refused the CONNECT with one. - */ -internal fun Mqtt5AsyncClient.pushConnect(config: PushConfig) { - try { - sendPushConnect(config) - } catch (e: Exception) { - throw connectError((e as? ExecutionException)?.cause ?: e) - } -} - -/** The error a failed CONNECT reports: the broker's Reason String when it refused one. */ -internal fun connectError(cause: Throwable): AppwriteException = - if (cause is Mqtt5ConnAckException) { - connAckError(cause) - } else { - AppwriteException(cause.message ?: "MQTT connection failed") - } - -/** - * Whether [error] is the broker refusing the credential (a CONNECT or re-auth), which retrying - * with the same credential cannot fix, unlike a rate limit or a network failure. - */ -internal fun isAuthRefusal(error: Throwable?): Boolean = when (error) { - is Mqtt5ConnAckException -> error.mqttMessage.reasonCode in setOf( - Mqtt5ConnAckReasonCode.NOT_AUTHORIZED, - Mqtt5ConnAckReasonCode.BAD_USER_NAME_OR_PASSWORD, - Mqtt5ConnAckReasonCode.BAD_AUTHENTICATION_METHOD, - Mqtt5ConnAckReasonCode.BANNED, - ) - is Mqtt5DisconnectException -> error.mqttMessage.reasonCode == Mqtt5DisconnectReasonCode.NOT_AUTHORIZED - else -> false -} - -/** - * Send the CONNECT and wait for the CONNACK, at most [timeoutSeconds] when given. [credential] - * supplies the credential each time one is sent, including on the client's automatic reconnects - * and re-auths, so they can use a session rotated since this CONNECT; null aborts the attempt. - */ -internal fun Mqtt5AsyncClient.sendPushConnect( - config: PushConfig, - timeoutSeconds: Long? = null, - credential: () -> String? = { config.credential }, -) { - val connAck = connect(pushConnectMessage(config, credential)) - if (timeoutSeconds == null) { - connAck.get() - } else { - connAck.get(timeoutSeconds, TimeUnit.SECONDS) - } -} - -/** - * The CONNECT for [config]: enhanced auth with the credential from [credential], and the project - * as a user property, which the broker resolves the credential against. - */ -internal fun pushConnectMessage(config: PushConfig, credential: () -> String?): Mqtt5Connect = - Mqtt5Connect.builder() - .enhancedAuth(PushAuthMechanism(config.authMethod, config.project, credential)) - // Clean start is always off, so the broker keeps this client's session and can - // redeliver missed messages to QoS-1 subscriptions on reconnect. - .cleanStart(false) - .keepAlive(config.keepAlive) - .userProperties() - .add("projectId", config.project) - .applyUserProperties() - .build() - -/** - * The error a lost connection reports, or null when it is not an error (a disconnect the app - * asked for, or a broker DISCONNECT with a success reason code). The broker explains a refused - * CONNECT or a DISCONNECT it sends with an MQTT 5 Reason String, which becomes the message. - */ -internal fun pushDisconnectError(context: MqttClientDisconnectedContext): Throwable? { - val cause = context.cause - return when { - context.source == MqttDisconnectSource.USER -> null - cause is Mqtt5ConnAckException -> connAckError(cause) - cause is Mqtt5DisconnectException && context.source == MqttDisconnectSource.SERVER -> { - val disconnect = cause.mqttMessage - if (disconnect.reasonCode.isError) { - AppwriteException( - disconnect.reasonString.map { it.toString() } - .orElse("Disconnected by the broker (reason ${disconnect.reasonCode})"), - ) - } else { - null - } - } - else -> cause - } -} - -/** A refused CONNECT, with the CONNACK Reason String as its message when the broker sent one. */ -internal fun connAckError(e: Mqtt5ConnAckException): AppwriteException = - AppwriteException( - e.mqttMessage.reasonString.map { it.toString() }.orElse(e.message ?: "MQTT connection refused"), - ) - -internal fun Mqtt5Publish.toPushMessage(): PushMessage = - PushMessage( - topic = topic.toString(), - payload = payloadAsBytes, - qos = qos.code, - ) - -/** - * Single-step MQTT 5 enhanced auth: the method and credential are placed in the CONNECT - * packet and the broker accepts them in the CONNACK, with no AUTH round-trip. The credential is - * read from [credential] each time, so an automatic reconnect or re-auth sends the current one; - * when it has none, the attempt fails instead of sending a credential known to be stale. - */ -internal class PushAuthMechanism( - private val method: String, - private val project: String, - private val credential: () -> String?, -) : Mqtt5EnhancedAuthMechanism { - - override fun getMethod(): MqttUtf8String = MqttUtf8String.of(method) - - override fun getTimeout(): Int = 30 - - override fun onAuth( - clientConfig: Mqtt5ClientConfig, - connect: Mqtt5Connect, - authBuilder: Mqtt5EnhancedAuthBuilder, - ): CompletableFuture { - val current = credential() ?: return failedAuth() - authBuilder.data(current.toByteArray(Charsets.UTF_8)) - return CompletableFuture.completedFuture(null) - } - - override fun onReAuth( - clientConfig: Mqtt5ClientConfig, - authBuilder: Mqtt5AuthBuilder, - ): CompletableFuture { - val current = credential() ?: return failedAuth() - // The broker resolves a re-auth against the project in its user properties too. - authBuilder.data(current.toByteArray(Charsets.UTF_8)) - .userProperties() - .add("projectId", project) - .applyUserProperties() - return CompletableFuture.completedFuture(null) - } - - override fun onContinue( - clientConfig: Mqtt5ClientConfig, - auth: Mqtt5Auth, - authBuilder: Mqtt5AuthBuilder, - ): CompletableFuture = CompletableFuture.completedFuture(true) - - override fun onAuthSuccess( - clientConfig: Mqtt5ClientConfig, - connAck: Mqtt5ConnAck, - ): CompletableFuture = CompletableFuture.completedFuture(true) - - override fun onReAuthSuccess( - clientConfig: Mqtt5ClientConfig, - auth: Mqtt5Auth, - ): CompletableFuture = CompletableFuture.completedFuture(true) - - override fun onAuthRejected(clientConfig: Mqtt5ClientConfig, connAck: Mqtt5ConnAck) = Unit - - override fun onReAuthRejected(clientConfig: Mqtt5ClientConfig, disconnect: Mqtt5Disconnect) = Unit - - override fun onAuthError(clientConfig: Mqtt5ClientConfig, cause: Throwable) = Unit - - override fun onReAuthError(clientConfig: Mqtt5ClientConfig, cause: Throwable) = Unit - - private fun failedAuth(): CompletableFuture = - CompletableFuture().apply { completeExceptionally(PushNoCredentialException()) } -} - -/** Authentication aborted because there is no current credential to send (the app signed out). */ -internal class PushNoCredentialException : IllegalStateException("No current credential to authenticate with") - -/** - * A [TrustManagerFactory] that accepts any certificate — used when `tlsInsecure` is set - * (for a broker whose certificate does not chain to a public root). - */ -internal object PushInsecureTrustManagerFactory : TrustManagerFactory( - object : TrustManagerFactorySpi() { - override fun engineInit(keyStore: KeyStore?) = Unit - - override fun engineInit(parameters: ManagerFactoryParameters?) = Unit - - override fun engineGetTrustManagers(): Array = arrayOf( - object : X509TrustManager { - override fun checkClientTrusted(chain: Array?, authType: String?) = Unit - - override fun checkServerTrusted(chain: Array?, authType: String?) = Unit - - override fun getAcceptedIssuers(): Array = emptyArray() - }, - ) - }, - @Suppress("DEPRECATION") object : Provider("AppwriteInsecure", 1.0, "insecure trust-all") {}, - "AppwriteInsecure", -) - -/** A live in-app subscription hosted in the background: its topics, callback, notification opt-in and QoS. */ -internal class PushListener( - val topics: Set, - val callback: (PushMessage) -> Unit, - val background: Boolean, - val title: String?, - val retry: Boolean, - // Called instead of [callback] when set, with the acknowledgement to run once the message was - // handled: the React Native and Flutter bridges acknowledge after their callback has run. - val acknowledgingCallback: ((PushMessage, () -> Unit) -> Unit)? = null, - // Also post a background notification while the app is visible. - val notifyInForeground: Boolean = false, -) - -/** MQTT topic-filter match with '+' (single level) and '#' (multi level). */ -internal fun matchesTopic(filter: String, topic: String): Boolean { - val filterParts = filter.split('/') - val topicParts = topic.split('/') - for (i in filterParts.indices) { - if (filterParts[i] == "#") { - return true - } - if (i >= topicParts.size) { - return false - } - if (filterParts[i] != "+" && filterParts[i] != topicParts[i]) { - return false - } - } - return filterParts.size == topicParts.size -} diff --git a/android/src/main/java/io/appwrite/services/PushOpenActivity.kt b/android/src/main/java/io/appwrite/services/PushOpenActivity.kt deleted file mode 100644 index 354ca6f0..00000000 --- a/android/src/main/java/io/appwrite/services/PushOpenActivity.kt +++ /dev/null @@ -1,57 +0,0 @@ -package io.appwrite.services - -import android.app.Activity -import android.content.Intent -import android.os.Bundle - -class PushOpenActivity : Activity() { - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - val topic = intent.getStringExtra(PushBackground.EXTRA_TOPIC) - val payload = intent.getStringExtra(PushBackground.EXTRA_PAYLOAD) - packageManager.getLaunchIntentForPackage(packageName)?.let { launch -> - launch.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_SINGLE_TOP) - if (topic != null && payload != null) { - launch.putExtra(PushBackground.EXTRA_TOPIC, topic).putExtra(PushBackground.EXTRA_PAYLOAD, payload) - } - startActivity(launch) - } - // After opening the app, so a screen a tap callback opens lands on top of it. - if (topic != null && payload != null) { - PushTaps.record(PushTap(topic, payload)) - } - finish() - } -} - -internal data class PushTap(val topic: String, val payload: String) - -internal object PushTaps { - private var pending: PushTap? = null - private val listeners = mutableListOf<(PushTap) -> Unit>() - - fun record(tap: PushTap) { - val deliver = synchronized(this) { - listeners.toList().also { - if (it.isEmpty()) { - pending = tap - } - } - } - deliver.forEach { it(tap) } - } - - @Synchronized - fun take(): PushTap? = pending.also { pending = null } - - fun listen(onTap: (PushTap) -> Unit): () -> Unit { - synchronized(this) { - listeners.add(onTap) - } - return { - synchronized(this) { - listeners.remove(onTap) - } - } - } -} diff --git a/android/src/main/java/io/appwrite/services/PushReceiver.kt b/android/src/main/java/io/appwrite/services/PushReceiver.kt deleted file mode 100644 index 92d04727..00000000 --- a/android/src/main/java/io/appwrite/services/PushReceiver.kt +++ /dev/null @@ -1,33 +0,0 @@ -package io.appwrite.services - -import android.content.BroadcastReceiver -import android.content.Context -import android.content.Intent - -/** - * Handles background push messages in code when no in-app callback is listening, e.g. after - * the process was started in the background to reconnect. Subclass it and declare it in your - * manifest with the push message action: - * - * ```xml - * - * - * - * - * - * ``` - * - * The SDK calls [onMessage] directly on a background thread, under a wakelock of about ten - * seconds, so hand longer work to WorkManager. Messages a live callback receives do not - * reach it. - */ -abstract class PushReceiver : BroadcastReceiver() { - /** - * Handle [message]. Return true when you handled it yourself, so the SDK does not post its - * default notification; return false to have it posted as well. - */ - abstract fun onMessage(context: Context, message: PushMessage): Boolean - - // Messages arrive through onMessage, never as a broadcast. - final override fun onReceive(context: Context, intent: Intent) = Unit -} diff --git a/android/src/main/java/io/appwrite/services/PushService.kt b/android/src/main/java/io/appwrite/services/PushService.kt deleted file mode 100644 index e2a05f89..00000000 --- a/android/src/main/java/io/appwrite/services/PushService.kt +++ /dev/null @@ -1,67 +0,0 @@ -package io.appwrite.services - -import android.app.Service -import android.content.Intent -import android.content.pm.ServiceInfo -import android.os.Build -import android.os.IBinder -import androidx.core.app.ServiceCompat - -/** - * The foreground mode of background push delivery ([Push.setForeground]): a foreground service - * that keeps the process at foreground priority, so the connection held by the process stays - * up and delivers immediately, also during Doze. The system restarts it after a kill, and it - * restores the saved subscriptions. Started by the SDK; not meant to be started directly. - */ -class PushService : Service() { - override fun onBind(intent: Intent?): IBinder? = null - - override fun onCreate() { - super.onCreate() - PushBackground.serviceRunning = true - } - - override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { - if (!PushBackground.wantsService(this)) { - stopSelf() - return START_NOT_STICKY - } - try { - startForegroundCompat() - } catch (e: Exception) { - // E.g. a background start refused on Android 12+; the scheduled runs keep delivering. - stopSelf() - PushBackground.report(e) - return START_NOT_STICKY - } - PushBackground.tick(this) {} - // Recreated after a kill with a null intent; the saved subscriptions are restored then. - return START_STICKY - } - - private fun startForegroundCompat() { - val notification = PushBackground.ongoingNotification(this) - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) { - ServiceCompat.startForeground( - this, - PushBackground.NOTIFICATION_ID, - notification, - ServiceInfo.FOREGROUND_SERVICE_TYPE_REMOTE_MESSAGING, - ) - } else { - startForeground(PushBackground.NOTIFICATION_ID, notification) - } - } - - // Some devices kill the process shortly after its task is swiped away; a run a few seconds - // later restarts the service. - override fun onTaskRemoved(rootIntent: Intent?) { - PushBackground.scheduleRestart(this) - super.onTaskRemoved(rootIntent) - } - - override fun onDestroy() { - PushBackground.serviceRunning = false - super.onDestroy() - } -} diff --git a/android/src/main/java/io/appwrite/services/PushWakeups.kt b/android/src/main/java/io/appwrite/services/PushWakeups.kt deleted file mode 100644 index c6d56165..00000000 --- a/android/src/main/java/io/appwrite/services/PushWakeups.kt +++ /dev/null @@ -1,55 +0,0 @@ -package io.appwrite.services - -import android.app.job.JobParameters -import android.app.job.JobService -import android.content.BroadcastReceiver -import android.content.Context -import android.content.Intent - -/** - * The scheduled run of background push delivery: reconnects and re-arms itself. Scheduled - * by the SDK; not meant to be started directly. - */ -class PushJobService : JobService() { - override fun onStartJob(params: JobParameters): Boolean { - // A chained job arms the next under the other chained id; the watchdog and an expedited - // run (handed over by the alarm) only run once. Each stays up while missed messages arrive. - val chained = params.jobId.takeIf { it == PushBackground.JOB_ID || it == PushBackground.NEXT_JOB_ID } - PushBackground.tick(this, chained, PushBackground.JOB_DRAIN_MS) { jobFinished(params, false) } - return true - } - - // The run re-arms the next one itself, and the watchdog repeats on its own, so a stopped run - // needs no retry. - override fun onStopJob(params: JobParameters): Boolean = false -} - -/** - * The alarm that backs up the scheduled job when it runs late. Scheduled by the SDK; not meant - * to be sent directly. - */ -class PushAlarmReceiver : BroadcastReceiver() { - override fun onReceive(context: Context, intent: Intent) { - if (intent.action != PushBackground.ACTION_TICK) { - return - } - // On Android 12+ the run goes to an expedited job, which keeps the process runnable while it - // connects and the broker replays; it runs here when the system refuses one. - if (PushBackground.runExpedited(context)) { - return - } - val pending = goAsync() - PushBackground.tick(context, drainMs = PushBackground.RECEIVER_DRAIN_MS) { pending.finish() } - } -} - -/** Resumes background push delivery after a reboot or an app update. */ -class PushBootReceiver : BroadcastReceiver() { - override fun onReceive(context: Context, intent: Intent) { - if (intent.action != Intent.ACTION_BOOT_COMPLETED && intent.action != Intent.ACTION_MY_PACKAGE_REPLACED) { - return - } - val pending = goAsync() - PushBackground.tick(context) { pending.finish() } - } -} 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/create-passkey-token.md b/docs/examples/account/create-passkey-token.md new file mode 100644 index 00000000..5695859f --- /dev/null +++ b/docs/examples/account/create-passkey-token.md @@ -0,0 +1,13 @@ +```javascript +import { Client, Account } from 'react-native-appwrite'; + +const client = new Client() + .setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint + .setProject(''); // Your project ID + +const account = new Account(client); + +const result = await account.createPasskeyToken(); + +console.log(result); +``` diff --git a/docs/examples/account/create-passkey.md b/docs/examples/account/create-passkey.md new file mode 100644 index 00000000..66968b14 --- /dev/null +++ b/docs/examples/account/create-passkey.md @@ -0,0 +1,16 @@ +```javascript +import { Client, Account } from 'react-native-appwrite'; + +const client = new Client() + .setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint + .setProject(''); // Your project ID + +const account = new Account(client); + +const result = await account.createPasskey({ + passkeyId: '', // optional + name: '', // optional +}); + +console.log(result); +``` diff --git a/docs/examples/account/delete-passkey.md b/docs/examples/account/delete-passkey.md new file mode 100644 index 00000000..61aec153 --- /dev/null +++ b/docs/examples/account/delete-passkey.md @@ -0,0 +1,15 @@ +```javascript +import { Client, Account } from 'react-native-appwrite'; + +const client = new Client() + .setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint + .setProject(''); // Your project ID + +const account = new Account(client); + +const result = await account.deletePasskey({ + passkeyId: '', +}); + +console.log(result); +``` diff --git a/docs/examples/account/get-passkey.md b/docs/examples/account/get-passkey.md new file mode 100644 index 00000000..04b7f8fb --- /dev/null +++ b/docs/examples/account/get-passkey.md @@ -0,0 +1,15 @@ +```javascript +import { Client, Account } from 'react-native-appwrite'; + +const client = new Client() + .setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint + .setProject(''); // Your project ID + +const account = new Account(client); + +const result = await account.getPasskey({ + passkeyId: '', +}); + +console.log(result); +``` diff --git a/docs/examples/account/list-passkeys.md b/docs/examples/account/list-passkeys.md new file mode 100644 index 00000000..f1f68985 --- /dev/null +++ b/docs/examples/account/list-passkeys.md @@ -0,0 +1,16 @@ +```javascript +import { Client, Account } from 'react-native-appwrite'; + +const client = new Client() + .setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint + .setProject(''); // Your project ID + +const account = new Account(client); + +const result = await account.listPasskeys({ + queries: [], // optional + total: false, // optional +}); + +console.log(result); +``` diff --git a/docs/examples/account/update-passkey-token.md b/docs/examples/account/update-passkey-token.md new file mode 100644 index 00000000..a8e22f7a --- /dev/null +++ b/docs/examples/account/update-passkey-token.md @@ -0,0 +1,16 @@ +```javascript +import { Client, Account } from 'react-native-appwrite'; + +const client = new Client() + .setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint + .setProject(''); // Your project ID + +const account = new Account(client); + +const result = await account.updatePasskeyToken({ + challengeId: '', + credential: {}, +}); + +console.log(result); +``` diff --git a/docs/examples/account/update-passkey-verification.md b/docs/examples/account/update-passkey-verification.md new file mode 100644 index 00000000..c46c0a63 --- /dev/null +++ b/docs/examples/account/update-passkey-verification.md @@ -0,0 +1,16 @@ +```javascript +import { Client, Account } from 'react-native-appwrite'; + +const client = new Client() + .setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint + .setProject(''); // Your project ID + +const account = new Account(client); + +const result = await account.updatePasskeyVerification({ + passkeyId: '', + credential: {}, +}); + +console.log(result); +``` diff --git a/docs/examples/account/update-passkey.md b/docs/examples/account/update-passkey.md new file mode 100644 index 00000000..2f925b98 --- /dev/null +++ b/docs/examples/account/update-passkey.md @@ -0,0 +1,16 @@ +```javascript +import { Client, Account } from 'react-native-appwrite'; + +const client = new Client() + .setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint + .setProject(''); // Your project ID + +const account = new Account(client); + +const result = await account.updatePasskey({ + passkeyId: '', + name: '', +}); + +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/oauth2/authorize-post.md b/docs/examples/oauth2/authorize-post.md index e27aa7e3..f7dd540c 100644 --- a/docs/examples/oauth2/authorize-post.md +++ b/docs/examples/oauth2/authorize-post.md @@ -19,7 +19,7 @@ const result = await oauth2.authorizePost({ prompt: '', // optional maxAge: 0, // optional authorizationDetails: '', // optional - resource: '', // optional + resource: [], // optional audience: '', // optional requestUri: '', // optional }); diff --git a/docs/examples/oauth2/authorize.md b/docs/examples/oauth2/authorize.md index 039dc744..256e9cb6 100644 --- a/docs/examples/oauth2/authorize.md +++ b/docs/examples/oauth2/authorize.md @@ -19,7 +19,7 @@ const result = await oauth2.authorize({ prompt: '', // optional maxAge: 0, // optional authorizationDetails: '', // optional - resource: '', // optional + resource: [], // optional audience: '', // optional requestUri: '', // optional }); diff --git a/docs/examples/oauth2/create-device-authorization.md b/docs/examples/oauth2/create-device-authorization.md index c136011b..1219db51 100644 --- a/docs/examples/oauth2/create-device-authorization.md +++ b/docs/examples/oauth2/create-device-authorization.md @@ -11,7 +11,7 @@ const result = await oauth2.createDeviceAuthorization({ clientId: '', // optional scope: '', // optional authorizationDetails: '', // optional - resource: '', // optional + resource: [], // optional audience: '', // optional }); diff --git a/docs/examples/oauth2/create-par.md b/docs/examples/oauth2/create-par.md index 5d9b5783..425e7a86 100644 --- a/docs/examples/oauth2/create-par.md +++ b/docs/examples/oauth2/create-par.md @@ -19,7 +19,7 @@ const result = await oauth2.createPAR({ prompt: '', // optional maxAge: 0, // optional authorizationDetails: '', // optional - resource: '', // optional + resource: [], // optional audience: '', // optional }); diff --git a/docs/examples/oauth2/create-token.md b/docs/examples/oauth2/create-token.md index 3be9ff4a..567bfb74 100644 --- a/docs/examples/oauth2/create-token.md +++ b/docs/examples/oauth2/create-token.md @@ -16,7 +16,7 @@ const result = await oauth2.createToken({ clientSecret: '', // optional codeVerifier: '', // optional redirectUri: 'https://example.com', // optional - resource: '', // optional + resource: [], // optional audience: '', // optional }); diff --git a/docs/examples/teams/create-membership.md b/docs/examples/teams/create-membership.md index 3c6ee849..9a4828a9 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/ios/AppwriteCookies.m b/ios/AppwriteCookies.m deleted file mode 100644 index 7e1506a8..00000000 --- a/ios/AppwriteCookies.m +++ /dev/null @@ -1,35 +0,0 @@ -#import - -@interface AppwriteCookies : NSObject -@end - -@implementation AppwriteCookies - -RCT_EXPORT_MODULE() - -+ (BOOL)requiresMainQueueSetup -{ - return NO; -} - -RCT_EXPORT_METHOD(session:(NSString *)url - project:(NSString *)project - resolve:(RCTPromiseResolveBlock)resolve - reject:(RCTPromiseRejectBlock)reject) -{ - NSString *name = [@"a_session_" stringByAppendingString:project]; - NSURL *target = [NSURL URLWithString:url]; - if (target == nil) { - resolve([NSNull null]); - return; - } - for (NSHTTPCookie *cookie in [[NSHTTPCookieStorage sharedHTTPCookieStorage] cookiesForURL:target]) { - if ([cookie.name isEqualToString:name]) { - resolve(cookie.value); - return; - } - } - resolve([NSNull null]); -} - -@end diff --git a/package-lock.json b/package-lock.json index 33230e5f..bbf4775e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "react-native-appwrite", - "version": "1.2.0-rc.4", + "version": "2.0.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "react-native-appwrite", - "version": "1.2.0-rc.4", + "version": "2.0.0", "license": "BSD-3-Clause", "dependencies": { "buffer": "6.0.3", diff --git a/package.json b/package.json index 12b4f76a..7ebd869b 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-rc.4", + "version": "2.0.0", "license": "BSD-3-Clause", "main": "dist/cjs/sdk.js", "exports": { @@ -16,12 +16,7 @@ "module": "dist/esm/sdk.js", "types": "types/index.d.ts", "files": [ - "android", - "!android/build", "dist", - "ios", - "*.podspec", - "react-native.config.js", "types" ], "repository": { diff --git a/react-native-appwrite.podspec b/react-native-appwrite.podspec deleted file mode 100644 index 46bd90e3..00000000 --- a/react-native-appwrite.podspec +++ /dev/null @@ -1,21 +0,0 @@ -require 'json' - -package = JSON.parse(File.read(File.join(__dir__, 'package.json'))) - -Pod::Spec.new do |s| - s.name = package['name'] - s.version = package['version'] - s.summary = package['description'] - s.homepage = package['homepage'] - s.license = package['license'] - s.authors = 'Appwrite Team' - s.platforms = { :ios => '15.1' } - s.source = { :git => 'https://github.com/appwrite/sdk-for-react-native', :tag => s.version.to_s } - s.source_files = 'ios/**/*.{h,m,mm}' - - if respond_to?(:install_modules_dependencies, true) - install_modules_dependencies(s) - else - s.dependency 'React-Core' - end -end diff --git a/react-native.config.js b/react-native.config.js deleted file mode 100644 index 4bfcf04a..00000000 --- a/react-native.config.js +++ /dev/null @@ -1,12 +0,0 @@ -// Autolinking: the native modules Push uses, found on iOS through the package's podspec. -module.exports = { - dependency: { - platforms: { - android: { - packageImportPath: - 'import io.appwrite.reactnative.AppwritePushPackage;', - packageInstance: 'new AppwritePushPackage()', - }, - }, - }, -}; diff --git a/src/client.ts b/src/client.ts index 4bc8575c..6738faf3 100644 --- a/src/client.ts +++ b/src/client.ts @@ -45,6 +45,59 @@ export const JSONbig = { stringify: JSONbigSerializer.stringify, }; +type DefaultsShape = string | { items: DefaultsShape }; + +type DefaultsModel = { + defaults?: Record; + properties?: Record; +}; + +type Defaults = { + root: DefaultsShape; + models: Record; +}; + +export function applyDefaults(value: T, tree: Defaults): T { + return fillDefaults(value, tree.root, tree.models) as T; +} + +function fillDefaults( + value: unknown, + shape: DefaultsShape, + models: Record, +): unknown { + if (typeof shape !== 'string') { + if (!Array.isArray(value)) { + return value; + } + const items = shape.items; + return value.map((item) => fillDefaults(item, items, models)); + } + const model = models[shape]; + if (!model || typeof value !== 'object' || value === null) { + return value; + } + if (Array.isArray(value)) { + return value; + } + const result: Record = { ...model.defaults, ...value }; + for (const [key, child] of Object.entries(model.properties ?? {})) { + if (key in result) { + result[key] = fillDefaults(result[key], child, models); + } + } + // The spread drops the non-enumerable JSON toString that Client.call attaches. + if (Object.prototype.hasOwnProperty.call(value, 'toString')) { + Object.defineProperty(result, 'toString', { + value: () => JSONbig.stringify(result), + writable: true, + enumerable: false, + configurable: true, + }); + } + return result; +} + type Payload = { [key: string]: any; }; @@ -201,8 +254,6 @@ class Client { config: { [key: string]: string } = { endpoint: 'https://cloud.appwrite.io/v1', endpointRealtime: '', - endpointPush: '', - pushClientId: '', platform: '', project: '', jwt: '', @@ -218,8 +269,8 @@ class Client { 'x-sdk-name': 'React Native', 'x-sdk-platform': 'client', 'x-sdk-language': 'reactnative', - 'x-sdk-version': '1.2.0-rc.4', - 'X-Appwrite-Response-Format': '2.3.0', + 'x-sdk-version': '2.0.0', + 'X-Appwrite-Response-Format': '2.5.0', }; /** @@ -288,45 +339,6 @@ class Client { return this; } - /** - * Set Push Endpoint - * - * The MQTT broker URL the AppwritePush service connects to, e.g. - * `mqtt://host:1883` or `mqtts://host:8883`. - * - * @param {string} endpointPush - * - * @returns {this} - */ - setPushEndpoint(endpointPush: string): this { - if (!endpointPush || typeof endpointPush !== 'string') { - throw new AppwriteException('Endpoint must be a valid string'); - } - - this.config.endpointPush = endpointPush; - return this; - } - - /** - * Set Push Client Id - * - * A stable client id for the AppwritePush service. The broker keys its - * offline-replay cursor on this id, so pass a stable value to resume replay across - * app restarts. Defaults to a per-connection id when unset. - * - * @param {string} pushClientId - * - * @returns {this} - */ - setPushClientId(pushClientId: string): this { - if (!pushClientId || typeof pushClientId !== 'string') { - throw new AppwriteException('Client id must be a valid string'); - } - - this.config.pushClientId = pushClientId; - return this; - } - /** * Set platform * diff --git a/src/index.ts b/src/index.ts index 579ed73a..c854a2c6 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 { Apps } from './services/apps'; export { Avatars } from './services/avatars'; export { Databases } from './services/databases'; @@ -16,15 +17,6 @@ export { TablesDB } from './services/tables-db'; export { Teams } from './services/teams'; export { VectorsDB } from './services/vectors-db'; export { Realtime } from './services/realtime'; -export { Push } from './services/push'; -export type { - PushBackgroundStatus, - PushMessage, - PushNotificationOpened, - PushSubscription, - SubscribeOptions, - MessageCallback, -} from './services/push'; export type { Models, Payload, @@ -37,7 +29,6 @@ export { Query } from './query'; export { Permission } from './permission'; export { Role } from './role'; export { ID } from './id'; -export { Topic, ResolvedTopic } from './topic'; export { Channel } from './channel'; export { Operator, Condition } from './operator'; export { AuthenticatorType } from './enums/authenticator-type'; diff --git a/src/lib/polyfills.ts b/src/lib/polyfills.ts deleted file mode 100644 index 08b3f64e..00000000 --- a/src/lib/polyfills.ts +++ /dev/null @@ -1,29 +0,0 @@ -// Node-core globals that `mqtt` and `readable-stream` expect but React Native's -// runtime does not provide. Imported for side effects by the MQTT modules so the -// transport works without the app entry having to set anything up. Each shim is -// installed only when missing, so it never clobbers a real (or Node) global. -import { Buffer } from 'buffer'; -import process from 'process'; - -const g = globalThis as unknown as { - Buffer?: typeof Buffer; - process?: NodeJS.Process; -}; - -if (typeof g.Buffer === 'undefined') { - g.Buffer = Buffer; -} - -if (typeof g.process === 'undefined') { - g.process = process as unknown as NodeJS.Process; -} - -// readable-stream schedules work on process.nextTick; RN's process may lack it. -if (typeof g.process.nextTick !== 'function') { - g.process.nextTick = (( - cb: (...a: unknown[]) => void, - ...args: unknown[] - ) => { - setTimeout(() => cb(...args), 0); - }) as typeof process.nextTick; -} diff --git a/src/lib/tcp-stream.ts b/src/lib/tcp-stream.ts deleted file mode 100644 index 11d8f53c..00000000 --- a/src/lib/tcp-stream.ts +++ /dev/null @@ -1,125 +0,0 @@ -import './polyfills'; - -import { Buffer } from 'buffer'; -import { Duplex } from 'readable-stream'; -import type TcpSocketType from 'react-native-tcp-socket'; -import type { IStream } from 'mqtt'; - -export interface TcpStreamOptions { - host: string; - port: number; - /** Wrap the connection in TLS (mqtts). */ - tls: boolean; - /** - * Skip certificate validation. A broker behind a certificate that does not - * chain to a public root either pins its root or turns validation off for - * testing. - */ - tlsInsecure: boolean; -} - -/** - * A Node-style Duplex over a raw TCP (or TLS) socket, for MQTT.js to run on. - * - * React Native has no `net` module, so MQTT.js cannot open a TCP connection on its - * own. `react-native-tcp-socket` provides the native socket; this adapts its - * EventEmitter-shaped `Socket` into the `readable-stream` Duplex MQTT.js pipes - * through its parser and writes packets to. - */ -export function createTcpStream({ - host, - port, - tls, - tlsInsecure, -}: TcpStreamOptions): IStream { - // `react-native-tcp-socket` is an optional peer. Requiring it inside try/catch marks it - // as an optional dependency for Metro, so merely importing the SDK (without native push) - // does not fail the bundler when the peer is absent; it is also only required lazily here, - // when a native push connection is actually opened. A missing peer surfaces as a clear - // error at that point rather than a Metro resolution failure on any SDK import. - /* eslint-disable @typescript-eslint/no-require-imports */ - let TcpSocket: typeof TcpSocketType; - try { - // react-native-tcp-socket is a CommonJS module (module.exports = { ... }) with no - // `.default`, so read that off first and fall back to the module for ESM interop. - const mod = require('react-native-tcp-socket'); - TcpSocket = mod.default ?? mod; - } catch { - throw new Error( - "Native push requires the optional peer 'react-native-tcp-socket'. Install it to use Push on React Native.", - ); - } - /* eslint-enable @typescript-eslint/no-require-imports */ - - let connected = false; - // Writes MQTT.js issues before the TCP handshake completes are held here and - // flushed on connect, so the CONNECT packet is never dropped on the opening socket. - const pending: { chunk: Buffer; cb: (err?: Error | null) => void }[] = []; - - // TLS must go through connectTLS(): plain Socket.connect() ignores a `tls` - // option entirely (it never performs a handshake), so sending MQTT bytes into - // the mqtts listener that way hangs until the broker's connack timeout. connectTLS - // returns a TLSSocket that does the handshake and emits 'secureConnect' when ready. - const socket = tls - ? TcpSocket.connectTLS( - // NB: react-native-tcp-socket disables certificate validation ONLY via - // `rejectUnauthorized: false` (its native BlindTrustManager). The documented - // `tlsCheckValidity` field is a dead type annotation the Android code ignores. - { - host, - port, - rejectUnauthorized: !tlsInsecure, - } as Parameters[0], - () => { - /* secureConnect — the handler below flushes the queue */ - }, - ) - : TcpSocket.createConnection({ host, port }, () => {}); - socket.setNoDelay(true); - - const duplex = new Duplex({ - read() { - socket.resume(); - }, - write(chunk: Buffer, _encoding, cb) { - if (!connected) { - pending.push({ chunk, cb }); - return; - } - socket.write(chunk, undefined, (err) => cb(err ?? null)); - }, - destroy(err, cb) { - socket.destroy(); - cb(err); - }, - }); - - const onConnect = () => { - if (connected) { - return; - } - connected = true; - for (const { chunk, cb } of pending) { - socket.write(chunk, undefined, (err) => cb(err ?? null)); - } - pending.length = 0; - }; - socket.on('connect', onConnect); - socket.on('secureConnect', onConnect); - - socket.on('data', (data) => { - // The native socket delivers Buffers by default (no encoding set); guard the - // string case just in case, decoding it as raw bytes. - const buf = - typeof data === 'string' ? Buffer.from(data, 'binary') : data; - if (!duplex.push(buf)) { - socket.pause(); - } - }); - socket.on('error', (err) => duplex.destroy(err)); - socket.on('close', () => { - duplex.push(null); - }); - - return duplex as unknown as IStream; -} diff --git a/src/models.ts b/src/models.ts index 09b8b39c..1b754aa9 100644 --- a/src/models.ts +++ b/src/models.ts @@ -338,7 +338,7 @@ export namespace Models { /** * Presence status. */ - status?: string; + status?: string | null; /** * Presence source. */ @@ -346,7 +346,7 @@ export namespace Models { /** * Presence expiry date in ISO 8601 format. */ - expiresAt?: string; + expiresAt?: string | null; /** * Presence metadata. */ @@ -378,15 +378,15 @@ export namespace Models { /** * Hashed user password. */ - password?: string; + password?: string | null; /** * Password hashing algorithm. */ - hash?: string; + hash?: string | null; /** * Password hashing algorithm configuration. */ - hashOptions?: object; + hashOptions?: object | null; /** * User registration date in ISO 8601 format. */ @@ -418,27 +418,27 @@ export namespace Models { /** * Canonical form of the user email address. */ - emailCanonical?: string; + emailCanonical?: string | null; /** * Whether the user email is from a free email provider. */ - emailIsFree?: boolean; + emailIsFree?: boolean | null; /** * Whether the user email is from a disposable email provider. */ - emailIsDisposable?: boolean; + emailIsDisposable?: boolean | null; /** * Whether the user email is from a corporate domain. */ - emailIsCorporate?: boolean; + emailIsCorporate?: boolean | null; /** * Whether the user email is in its canonical form. */ - emailIsCanonical?: boolean; + emailIsCanonical?: boolean | null; /** * 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; + passwordPwned?: boolean | null; /** * Phone verification status. */ @@ -462,11 +462,11 @@ export namespace Models { /** * Whether the user can impersonate other users. */ - impersonator?: boolean; + impersonator?: boolean | null; /** * 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; + impersonatorUserId?: string | null; }; /** @@ -632,27 +632,27 @@ export namespace Models { /** * Canonical form of the user email address. */ - emailCanonical?: string; + emailCanonical?: string | null; /** * Whether the user email is from a free email provider. */ - emailIsFree?: boolean; + emailIsFree?: boolean | null; /** * Whether the user email is from a disposable email provider. */ - emailIsDisposable?: boolean; + emailIsDisposable?: boolean | null; /** * Whether the user email is from a corporate domain. */ - emailIsCorporate?: boolean; + emailIsCorporate?: boolean | null; /** * Whether the user email is in its canonical form. */ - emailIsCanonical?: boolean; + emailIsCanonical?: boolean | null; /** * 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; + passwordPwned?: boolean | null; /** * Phone verification status. */ @@ -676,11 +676,11 @@ export namespace Models { /** * Whether the user can impersonate other users. */ - impersonator?: boolean; + impersonator?: boolean | null; /** * 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; + impersonatorUserId?: string | null; }; /** @@ -940,47 +940,47 @@ export namespace Models { /** * City */ - city?: string; + city?: string | null; /** * Name of timezone */ - timeZone?: string; + timeZone?: string | null; /** * Postal code */ - postalCode?: string; + postalCode?: string | null; /** * Latitude */ - latitude?: number; + latitude?: number | null; /** * Longitude */ - longitude?: number; + longitude?: number | null; /** * Autonomous System Number (ASN) of the IP */ - autonomousSystemNumber?: string; + autonomousSystemNumber?: string | null; /** * Organization that owns the ASN */ - autonomousSystemOrganization?: string; + autonomousSystemOrganization?: string | null; /** * Internet service provider of the IP */ - isp?: string; + isp?: string | null; /** * Connection type of the IP (e.g. cable, cellular, corporate) */ - connectionType?: string; + connectionType?: string | null; /** * User type classification of the IP (e.g. residential, business, hosting) */ - connectionUsageType?: string; + connectionUsageType?: string | null; /** * Registered organization of the IP */ - connectionOrganization?: string; + connectionOrganization?: string | null; }; /** @@ -1244,7 +1244,7 @@ export namespace Models { /** * The scheduled time for execution. If left empty, execution will be queued immediately. */ - scheduledAt?: string; + scheduledAt?: string | null; }; /** @@ -1381,6 +1381,102 @@ export namespace Models { expire: string; }; + /** + * Token Secret + */ + export type TokenSecret = { + /** + * Token ID. + */ + $id: string; + /** + * Token creation date in ISO 8601 format. + */ + $createdAt: string; + /** + * User ID. + */ + userId: string; + /** + * Token secret key. Exchange it for a session with the create session endpoint. + */ + secret: string; + /** + * Token expiration date in ISO 8601 format. + */ + expire: string; + /** + * Security phrase of a token. Empty if security phrase was not requested when creating a token. It includes randomly generated phrase which is also sent in the external resource such as email. + */ + phrase: string; + }; + + /** + * Passkey + */ + export type Passkey = { + /** + * Passkey ID. + */ + $id: string; + /** + * Passkey creation date in ISO 8601 format. + */ + $createdAt: string; + /** + * Passkey update date in ISO 8601 format. + */ + $updatedAt: string; + /** + * Passkey name. + */ + name: string; + /** + * Most recent sign-in with this passkey in ISO 8601 format. Empty until the passkey is used to sign in. + */ + accessedAt: string; + }; + + /** + * Passkey Challenge + */ + export type PasskeyChallenge = { + /** + * Challenge ID. When signing in, pass it back with the credential to receive a token. + */ + $id: string; + /** + * Challenge creation date in ISO 8601 format. + */ + $createdAt: string; + /** + * ID of the passkey being registered. Empty for sign-in challenges. + */ + passkeyId: string; + /** + * Challenge expiration date in ISO 8601 format. + */ + expire: string; + /** + * WebAuthn options in JSON form. Pass them to `PublicKeyCredential.parseCreationOptionsFromJSON()` when registering, or `PublicKeyCredential.parseRequestOptionsFromJSON()` when signing in. + */ + publicKey: object; + }; + + /** + * Passkeys List + */ + export type PasskeyList = { + /** + * Total number of passkeys that matched your query. + */ + total: number; + /** + * List of passkeys. + */ + passkeys: Passkey[]; + }; + /** * MFA Recovery Codes */ @@ -1530,7 +1626,7 @@ export namespace Models { /** * Provider ID. */ - providerId?: string; + providerId?: string | null; /** * The target provider type. Can be one of the following: `email`, `sms` or `push`. */ @@ -1694,7 +1790,7 @@ export namespace Models { /** * Time the secret was last used for authentication in ISO 8601 format. Null if never used. */ - lastAccessedAt?: string; + lastAccessedAt?: string | null; }; /** @@ -1736,7 +1832,7 @@ export namespace Models { /** * Time the secret was last used for authentication in ISO 8601 format. Null if never used. */ - lastAccessedAt?: string; + lastAccessedAt?: string | null; }; /** @@ -1808,7 +1904,7 @@ export namespace Models { /** * Time an access token was last issued for the installation in ISO 8601 format. Null if never used. */ - lastAccessedAt?: string; + lastAccessedAt?: string | null; }; /** @@ -1850,7 +1946,7 @@ export namespace Models { /** * Time the app key was last used for authentication in ISO 8601 format. Null if never used. */ - lastAccessedAt?: string; + lastAccessedAt?: string | null; }; /** @@ -2012,11 +2108,11 @@ export namespace Models { /** * Granted RFC 9396 authorization details as a JSON string. */ - authorization_details?: string; + authorization_details?: string | null; /** * OpenID Connect ID token. Returned when the `openid` scope is granted. */ - id_token?: string; + id_token?: string | null; }; /** diff --git a/src/react-native-shim.d.ts b/src/react-native-shim.d.ts index cd64d011..fd9952a7 100644 --- a/src/react-native-shim.d.ts +++ b/src/react-native-shim.d.ts @@ -1,135 +1,5 @@ declare module 'react-native' { - export const AppState: { - readonly currentState: string | null; - }; - export const Platform: { readonly OS: string; - readonly Version: number | string; - }; - - // The slice of the permissions API Push uses to ask for POST_NOTIFICATIONS on Android 13+. - export const PermissionsAndroid: { - readonly PERMISSIONS: { readonly POST_NOTIFICATIONS: string }; - check(permission: string): Promise; - request(permission: string): Promise; }; - - // The slice of the native module API the Push service uses on Android. - export const NativeModules: Record | undefined; - - export interface EmitterSubscription { - remove(): void; - } - - export class NativeEventEmitter { - constructor(nativeModule?: unknown); - addListener( - eventType: string, - listener: (event: T) => void, - ): EmitterSubscription; - } -} - -// `react-native-tcp-socket` is an optional peer dependency (a native module), -// so it is not installed when type-checking the SDK in isolation. Declare just -// the slice of its API the MQTT transport uses so `tsc` resolves the import. -declare module 'react-native-tcp-socket' { - import type { Buffer } from 'buffer'; - - export interface Socket { - setNoDelay(noDelay?: boolean): Socket; - write( - buffer: string | Buffer, - encoding?: unknown, - cb?: (err?: Error) => void, - ): boolean; - destroy(error?: Error): void; - resume(): Socket; - pause(): Socket; - on(event: 'data', listener: (data: Buffer | string) => void): Socket; - on(event: 'error', listener: (error: Error) => void): Socket; - on( - event: 'connect' | 'secureConnect' | 'close', - listener: () => void, - ): Socket; - } - - export interface TcpSocketConnectOpts { - host?: string; - port: number; - } - - export interface TLSSocketOptions extends TcpSocketConnectOpts { - rejectUnauthorized?: boolean; - } - - interface TcpSocketStatic { - createConnection( - options: TcpSocketConnectOpts, - callback?: () => void, - ): Socket; - connectTLS(options: TLSSocketOptions, callback?: () => void): Socket; - } - - const TcpSockets: TcpSocketStatic; - export default TcpSockets; -} - -// Optional peer dependencies used only by Push.setForeground() (Android foreground -// service + local notifications). Declared so `tsc` resolves the dynamic imports even -// when the app has not installed them; at runtime the imports are guarded. -declare module 'react-native-background-actions' { - interface BackgroundTaskOptions { - taskName: string; - taskTitle: string; - taskDesc: string; - // Required by react-native-background-actions for its ongoing notification; - // omitting it makes start() throw "Task icon not found". - taskIcon: { name: string; type: string }; - foregroundServiceType?: string[]; - } - - interface BackgroundActions { - start( - task: (args?: unknown) => Promise, - options: BackgroundTaskOptions, - ): Promise; - stop(): Promise; - isRunning(): boolean; - } - - const backgroundActions: BackgroundActions; - export default backgroundActions; -} - -declare module 'expo-notifications' { - export const AndroidImportance: { readonly HIGH: number }; - - export function requestPermissionsAsync(): Promise<{ granted: boolean }>; - export function setNotificationChannelAsync( - channelId: string, - channel: { name: string; importance: number }, - ): Promise; - export interface NotificationResponse { - notification: { - request: { content: { data?: Record | null } }; - }; - } - - export function getLastNotificationResponseAsync(): Promise; - // Missing from older expo-notifications versions. - export const clearLastNotificationResponseAsync: - (() => Promise) | undefined; - export function addNotificationResponseReceivedListener( - listener: (response: NotificationResponse) => void, - ): { remove(): void }; - export function scheduleNotificationAsync(request: { - content: { - title: string; - body: string | null; - data?: Record; - }; - trigger: null; - }): Promise; } diff --git a/src/services/account.ts b/src/services/account.ts index fb3d545b..53e5331f 100644 --- a/src/services/account.ts +++ b/src/services/account.ts @@ -1,5 +1,5 @@ import { Service } from '../service'; -import { AppwriteException, Client } from '../client'; +import { AppwriteException, Client, applyDefaults } from '../client'; import type { Models } from '../models'; import type { Payload } from '../client'; @@ -25,7 +25,7 @@ export class Account extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -34,6 +34,49 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'user', + models: { + user: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + registration: '', + status: true, + labels: [], + passwordUpdate: '', + email: '', + phone: '', + emailVerification: false, + phoneVerification: false, + mfa: false, + targets: [], + accessedAt: '', + }, + properties: { + targets: { + items: 'target', + }, + }, + }, + target: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + userId: '', + providerType: '', + identifier: '', + expired: false, + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -143,7 +186,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -153,6 +196,49 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'user', + models: { + user: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + registration: '', + status: true, + labels: [], + passwordUpdate: '', + email: '', + phone: '', + emailVerification: false, + phoneVerification: false, + mfa: false, + targets: [], + accessedAt: '', + }, + properties: { + targets: { + items: 'target', + }, + }, + }, + target: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + userId: '', + providerType: '', + identifier: '', + expired: false, + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -218,7 +304,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -227,6 +313,38 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'oauth2ConsentList', + models: { + oauth2ConsentList: { + defaults: { + total: 0, + consents: [], + }, + properties: { + consents: { + items: 'oauth2Consent', + }, + }, + }, + oauth2Consent: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + userId: '', + appId: '', + cimdUrl: '', + scopes: [], + resources: [], + authorizationDetails: '[]', + expire: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -278,7 +396,7 @@ export class Account extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -287,6 +405,27 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'oauth2Consent', + models: { + oauth2Consent: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + userId: '', + appId: '', + cimdUrl: '', + scopes: [], + resources: [], + authorizationDetails: '[]', + expire: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -427,7 +566,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -436,6 +575,39 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'oauth2ConsentTokenList', + models: { + oauth2ConsentTokenList: { + defaults: { + total: 0, + tokens: [], + }, + properties: { + tokens: { + items: 'oauth2ConsentToken', + }, + }, + }, + oauth2ConsentToken: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + consentId: '', + userId: '', + appId: '', + cimdUrl: '', + scopes: [], + resources: [], + authorizationDetails: '[]', + expire: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -506,7 +678,7 @@ export class Account extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -515,6 +687,28 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'oauth2ConsentToken', + models: { + oauth2ConsentToken: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + consentId: '', + userId: '', + appId: '', + cimdUrl: '', + scopes: [], + resources: [], + authorizationDetails: '[]', + expire: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -673,7 +867,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'patch', uri, { @@ -683,6 +877,49 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'user', + models: { + user: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + registration: '', + status: true, + labels: [], + passwordUpdate: '', + email: '', + phone: '', + emailVerification: false, + phoneVerification: false, + mfa: false, + targets: [], + accessedAt: '', + }, + properties: { + targets: { + items: 'target', + }, + }, + }, + target: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + userId: '', + providerType: '', + identifier: '', + expired: false, + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -748,7 +985,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -757,6 +994,39 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'identityList', + models: { + identityList: { + defaults: { + total: 0, + identities: [], + }, + properties: { + identities: { + items: 'identity', + }, + }, + }, + identity: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + userId: '', + provider: '', + providerUid: '', + providerEmail: '', + providerAccessToken: '', + providerAccessTokenExpiry: '', + providerRefreshToken: '', + providerIdToken: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -865,7 +1135,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -875,6 +1145,18 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'jwt', + models: { + jwt: { + defaults: { + jwt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -931,7 +1213,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'patch', uri, { @@ -941,6 +1223,49 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'user', + models: { + user: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + registration: '', + status: true, + labels: [], + passwordUpdate: '', + email: '', + phone: '', + emailVerification: false, + phoneVerification: false, + mfa: false, + targets: [], + accessedAt: '', + }, + properties: { + targets: { + items: 'target', + }, + }, + }, + target: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + userId: '', + providerType: '', + identifier: '', + expired: false, + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -994,7 +1319,7 @@ export class Account extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -1004,6 +1329,19 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'mfaType', + models: { + mfaType: { + defaults: { + secret: '', + uri: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1056,7 +1394,7 @@ export class Account extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -1066,6 +1404,19 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'mfaType', + models: { + mfaType: { + defaults: { + secret: '', + uri: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1143,7 +1494,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'put', uri, { @@ -1153,6 +1504,49 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'user', + models: { + user: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + registration: '', + status: true, + labels: [], + passwordUpdate: '', + email: '', + phone: '', + emailVerification: false, + phoneVerification: false, + mfa: false, + targets: [], + accessedAt: '', + }, + properties: { + targets: { + items: 'target', + }, + }, + }, + target: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + userId: '', + providerType: '', + identifier: '', + expired: false, + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1229,7 +1623,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'put', uri, { @@ -1239,6 +1633,49 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'user', + models: { + user: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + registration: '', + status: true, + labels: [], + passwordUpdate: '', + email: '', + phone: '', + emailVerification: false, + phoneVerification: false, + mfa: false, + targets: [], + accessedAt: '', + }, + properties: { + targets: { + items: 'target', + }, + }, + }, + target: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + userId: '', + providerType: '', + identifier: '', + expired: false, + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1416,7 +1853,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -1426,6 +1863,21 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'mfaChallenge', + models: { + mfaChallenge: { + defaults: { + $id: '', + $createdAt: '', + userId: '', + expire: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1481,7 +1933,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -1491,6 +1943,21 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'mfaChallenge', + models: { + mfaChallenge: { + defaults: { + $id: '', + $createdAt: '', + userId: '', + expire: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1566,7 +2033,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'put', uri, { @@ -1576,6 +2043,46 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'session', + models: { + session: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + userId: '', + expire: '', + provider: '', + providerUid: '', + providerAccessToken: '', + providerAccessTokenExpiry: '', + providerRefreshToken: '', + ip: '', + osCode: '', + osName: '', + osVersion: '', + clientType: '', + clientCode: '', + clientName: '', + clientVersion: '', + clientEngine: '', + clientEngineVersion: '', + deviceName: '', + deviceBrand: '', + deviceModel: '', + countryCode: '', + countryName: '', + current: false, + factors: [], + secret: '', + mfaUpdatedAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1650,7 +2157,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'put', uri, { @@ -1660,6 +2167,46 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'session', + models: { + session: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + userId: '', + expire: '', + provider: '', + providerUid: '', + providerAccessToken: '', + providerAccessTokenExpiry: '', + providerRefreshToken: '', + ip: '', + osCode: '', + osName: '', + osVersion: '', + clientType: '', + clientCode: '', + clientName: '', + clientVersion: '', + clientEngine: '', + clientEngineVersion: '', + deviceName: '', + deviceBrand: '', + deviceModel: '', + countryCode: '', + countryName: '', + current: false, + factors: [], + secret: '', + mfaUpdatedAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1674,7 +2221,7 @@ export class Account extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -1683,6 +2230,22 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'mfaFactors', + models: { + mfaFactors: { + defaults: { + totp: false, + phone: false, + email: false, + recoveryCode: false, + custom: false, + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1696,7 +2259,7 @@ export class Account extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -1705,6 +2268,22 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'mfaFactors', + models: { + mfaFactors: { + defaults: { + totp: false, + phone: false, + email: false, + recoveryCode: false, + custom: false, + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1719,7 +2298,7 @@ export class Account extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -1728,6 +2307,18 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'mfaRecoveryCodes', + models: { + mfaRecoveryCodes: { + defaults: { + recoveryCodes: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1741,7 +2332,7 @@ export class Account extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -1750,6 +2341,18 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'mfaRecoveryCodes', + models: { + mfaRecoveryCodes: { + defaults: { + recoveryCodes: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1764,7 +2367,7 @@ export class Account extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -1774,6 +2377,18 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'mfaRecoveryCodes', + models: { + mfaRecoveryCodes: { + defaults: { + recoveryCodes: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1787,7 +2402,7 @@ export class Account extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -1797,6 +2412,18 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'mfaRecoveryCodes', + models: { + mfaRecoveryCodes: { + defaults: { + recoveryCodes: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1811,7 +2438,7 @@ export class Account extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'patch', uri, { @@ -1821,6 +2448,18 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'mfaRecoveryCodes', + models: { + mfaRecoveryCodes: { + defaults: { + recoveryCodes: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1833,9 +2472,553 @@ export class Account extends Service { const apiPath = '/account/mfa/recovery-codes'; const apiPayload: Payload = {}; + const uri = new URL(this.client.config.endpoint + apiPath); + const request = this.client.call( + 'patch', + uri, + { + 'X-Appwrite-Project': this.client.config.project, + 'content-type': 'application/json', + accept: 'application/json', + }, + apiPayload, + ); + const defaults = { + root: 'mfaRecoveryCodes', + models: { + mfaRecoveryCodes: { + defaults: { + recoveryCodes: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); + } + + /** + * Update currently logged in user account name. + * + * @param {string} params.name - User name. Max length: 128 chars. + * @throws {AppwriteException} + * @returns {Promise} + */ + updateName< + Preferences extends Models.Preferences = Models.DefaultPreferences, + >(params: { name: string }): Promise>; + /** + * Update currently logged in user account name. + * + * @param {string} name - User name. Max length: 128 chars. + * @throws {AppwriteException} + * @returns {Promise>} + * @deprecated Use the object parameter style method for a better developer experience. + */ + updateName< + Preferences extends Models.Preferences = Models.DefaultPreferences, + >(name: string): Promise>; + updateName< + Preferences extends Models.Preferences = Models.DefaultPreferences, + >( + paramsOrFirst: { name: string } | string, + ): Promise> { + let params: { name: string }; + + if ( + paramsOrFirst && + typeof paramsOrFirst === 'object' && + !Array.isArray(paramsOrFirst) + ) { + params = (paramsOrFirst || {}) as { name: string }; + } else { + params = { + name: paramsOrFirst as string, + }; + } + + const name = params.name; + + if (typeof name === 'undefined') { + throw new AppwriteException('Missing required parameter: "name"'); + } + + const apiPath = '/account/name'; + const apiPayload: Payload = {}; + + if (typeof name !== 'undefined') { + apiPayload['name'] = name; + } + + const uri = new URL(this.client.config.endpoint + apiPath); + const request = this.client.call( + 'patch', + uri, + { + 'X-Appwrite-Project': this.client.config.project, + 'content-type': 'application/json', + accept: 'application/json', + }, + apiPayload, + ); + const defaults = { + root: 'user', + models: { + user: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + registration: '', + status: true, + labels: [], + passwordUpdate: '', + email: '', + phone: '', + emailVerification: false, + phoneVerification: false, + mfa: false, + targets: [], + accessedAt: '', + }, + properties: { + targets: { + items: 'target', + }, + }, + }, + target: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + userId: '', + providerType: '', + identifier: '', + expired: false, + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); + } + + /** + * Get the list of verified passkeys registered by the currently logged in user. + * + * @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). Maximum of 100 queries are allowed, each 4096 characters long. You may filter and order on the following attributes: $id, $createdAt, $updatedAt, name, accessedAt + * @param {boolean} params.total - When set to false, the total count returned will be 0 and will not be calculated. + * @throws {AppwriteException} + * @returns {Promise} + */ + listPasskeys(params?: { + queries?: string[]; + total?: boolean; + }): Promise; + /** + * Get the list of verified passkeys registered by the currently logged in user. + * + * @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). Maximum of 100 queries are allowed, each 4096 characters long. You may filter and order on the following attributes: $id, $createdAt, $updatedAt, name, accessedAt + * @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. + */ + listPasskeys( + queries?: string[], + total?: boolean, + ): Promise; + listPasskeys( + paramsOrFirst?: { queries?: string[]; total?: boolean } | string[], + ...rest: [boolean?] + ): Promise { + let params: { queries?: string[]; total?: boolean }; + + if ( + (typeof paramsOrFirst === 'undefined' && rest.length === 0) || + (paramsOrFirst && + typeof paramsOrFirst === 'object' && + !Array.isArray(paramsOrFirst)) + ) { + 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 = '/account/passkeys'; + const apiPayload: Payload = {}; + + if (typeof queries !== 'undefined') { + apiPayload['queries'] = queries; + } + + if (typeof total !== 'undefined') { + apiPayload['total'] = total; + } + + const uri = new URL(this.client.config.endpoint + apiPath); + const request = this.client.call( + 'get', + uri, + { + 'X-Appwrite-Project': this.client.config.project, + accept: 'application/json', + }, + apiPayload, + ); + const defaults = { + root: 'passkeyList', + models: { + passkeyList: { + defaults: { + total: 0, + passkeys: [], + }, + properties: { + passkeys: { + items: 'passkey', + }, + }, + }, + passkey: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + accessedAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); + } + + /** + * Start registering a passkey for the currently logged in user. The session must have signed in or completed an MFA challenge within the last 10 minutes. Pass the returned `publicKey` options to `navigator.credentials.create()`, then complete the registration with [Update passkey verification](/docs/references/cloud/client-web/account#updatePasskeyVerification). The passkey stays pending until verified, and the challenge expires after 5 minutes. + * + * @param {string} params.passkeyId - Passkey 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. + * @param {string} params.name - Passkey name, shown when listing passkeys. Max length: 128 chars. + * @throws {AppwriteException} + * @returns {Promise} + */ + createPasskey(params?: { + passkeyId?: string; + name?: string; + }): Promise; + /** + * Start registering a passkey for the currently logged in user. The session must have signed in or completed an MFA challenge within the last 10 minutes. Pass the returned `publicKey` options to `navigator.credentials.create()`, then complete the registration with [Update passkey verification](/docs/references/cloud/client-web/account#updatePasskeyVerification). The passkey stays pending until verified, and the challenge expires after 5 minutes. + * + * @param {string} passkeyId - Passkey 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. + * @param {string} name - Passkey name, shown when listing passkeys. Max length: 128 chars. + * @throws {AppwriteException} + * @returns {Promise} + * @deprecated Use the object parameter style method for a better developer experience. + */ + createPasskey( + passkeyId?: string, + name?: string, + ): Promise; + createPasskey( + paramsOrFirst?: { passkeyId?: string; name?: string } | string, + ...rest: [string?] + ): Promise { + let params: { passkeyId?: string; name?: string }; + + if ( + (typeof paramsOrFirst === 'undefined' && rest.length === 0) || + (paramsOrFirst && + typeof paramsOrFirst === 'object' && + !Array.isArray(paramsOrFirst)) + ) { + params = (paramsOrFirst || {}) as { + passkeyId?: string; + name?: string; + }; + } else { + params = { + passkeyId: paramsOrFirst as string, + name: rest[0] as string, + }; + } + + const passkeyId = params.passkeyId; + const name = params.name; + + const apiPath = '/account/passkeys'; + const apiPayload: Payload = {}; + + if (typeof passkeyId !== 'undefined') { + apiPayload['passkeyId'] = passkeyId; + } + + if (typeof name !== 'undefined') { + apiPayload['name'] = name; + } + + const uri = new URL(this.client.config.endpoint + apiPath); + const request = this.client.call( + 'post', + uri, + { + 'X-Appwrite-Project': this.client.config.project, + 'content-type': 'application/json', + accept: 'application/json', + }, + apiPayload, + ); + const defaults = { + root: 'passkeyChallenge', + models: { + passkeyChallenge: { + defaults: { + $id: '', + $createdAt: '', + passkeyId: '', + expire: '', + publicKey: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); + } + + /** + * Get a verified passkey of the currently logged in user by its unique ID. + * + * @param {string} params.passkeyId - Passkey ID. + * @throws {AppwriteException} + * @returns {Promise} + */ + getPasskey(params: { passkeyId: string }): Promise; + /** + * Get a verified passkey of the currently logged in user by its unique ID. + * + * @param {string} passkeyId - Passkey ID. + * @throws {AppwriteException} + * @returns {Promise} + * @deprecated Use the object parameter style method for a better developer experience. + */ + getPasskey(passkeyId: string): Promise; + getPasskey( + paramsOrFirst: { passkeyId: string } | string, + ): Promise { + let params: { passkeyId: string }; + + if ( + paramsOrFirst && + typeof paramsOrFirst === 'object' && + !Array.isArray(paramsOrFirst) + ) { + params = (paramsOrFirst || {}) as { passkeyId: string }; + } else { + params = { + passkeyId: paramsOrFirst as string, + }; + } + + const passkeyId = params.passkeyId; + + if (typeof passkeyId === 'undefined' || passkeyId === '') { + throw new AppwriteException( + 'Missing required parameter: "passkeyId"', + ); + } + + const apiPath = '/account/passkeys/{passkeyId}'.replace( + '{passkeyId}', + encodeURIComponent(String(passkeyId)), + ); + const apiPayload: Payload = {}; + + const uri = new URL(this.client.config.endpoint + apiPath); + const request = this.client.call( + 'get', + uri, + { + 'X-Appwrite-Project': this.client.config.project, + accept: 'application/json', + }, + apiPayload, + ); + const defaults = { + root: 'passkey', + models: { + passkey: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + accessedAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); + } + + /** + * Rename a passkey of the currently logged in user. + * + * @param {string} params.passkeyId - Passkey ID. + * @param {string} params.name - Passkey name. Max length: 128 chars. + * @throws {AppwriteException} + * @returns {Promise} + */ + updatePasskey(params: { + passkeyId: string; + name: string; + }): Promise; + /** + * Rename a passkey of the currently logged in user. + * + * @param {string} passkeyId - Passkey ID. + * @param {string} name - Passkey name. Max length: 128 chars. + * @throws {AppwriteException} + * @returns {Promise} + * @deprecated Use the object parameter style method for a better developer experience. + */ + updatePasskey(passkeyId: string, name: string): Promise; + updatePasskey( + paramsOrFirst: { passkeyId: string; name: string } | string, + ...rest: [string?] + ): Promise { + let params: { passkeyId: string; name: string }; + + if ( + paramsOrFirst && + typeof paramsOrFirst === 'object' && + !Array.isArray(paramsOrFirst) + ) { + params = (paramsOrFirst || {}) as { + passkeyId: string; + name: string; + }; + } else { + params = { + passkeyId: paramsOrFirst as string, + name: rest[0] as string, + }; + } + + const passkeyId = params.passkeyId; + const name = params.name; + + if (typeof passkeyId === 'undefined' || passkeyId === '') { + throw new AppwriteException( + 'Missing required parameter: "passkeyId"', + ); + } + + if (typeof name === 'undefined') { + throw new AppwriteException('Missing required parameter: "name"'); + } + + const apiPath = '/account/passkeys/{passkeyId}'.replace( + '{passkeyId}', + encodeURIComponent(String(passkeyId)), + ); + const apiPayload: Payload = {}; + + if (typeof name !== 'undefined') { + apiPayload['name'] = name; + } + + const uri = new URL(this.client.config.endpoint + apiPath); + const request = this.client.call( + 'patch', + uri, + { + 'X-Appwrite-Project': this.client.config.project, + 'content-type': 'application/json', + accept: 'application/json', + }, + apiPayload, + ); + const defaults = { + root: 'passkey', + models: { + passkey: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + accessedAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); + } + + /** + * Delete a passkey from the currently logged in user. The passkey can no longer be used to sign in, although it may remain stored on the user's device. The session must have signed in or completed an MFA challenge within the last 10 minutes. + * + * @param {string} params.passkeyId - Passkey ID. + * @throws {AppwriteException} + * @returns {Promise} + */ + deletePasskey(params: { passkeyId: string }): Promise<{}>; + /** + * Delete a passkey from the currently logged in user. The passkey can no longer be used to sign in, although it may remain stored on the user's device. The session must have signed in or completed an MFA challenge within the last 10 minutes. + * + * @param {string} passkeyId - Passkey ID. + * @throws {AppwriteException} + * @returns {Promise<{}>} + * @deprecated Use the object parameter style method for a better developer experience. + */ + deletePasskey(passkeyId: string): Promise<{}>; + deletePasskey(paramsOrFirst: { passkeyId: string } | string): Promise<{}> { + let params: { passkeyId: string }; + + if ( + paramsOrFirst && + typeof paramsOrFirst === 'object' && + !Array.isArray(paramsOrFirst) + ) { + params = (paramsOrFirst || {}) as { passkeyId: string }; + } else { + params = { + passkeyId: paramsOrFirst as string, + }; + } + + const passkeyId = params.passkeyId; + + if (typeof passkeyId === 'undefined' || passkeyId === '') { + throw new AppwriteException( + 'Missing required parameter: "passkeyId"', + ); + } + + const apiPath = '/account/passkeys/{passkeyId}'.replace( + '{passkeyId}', + encodeURIComponent(String(passkeyId)), + ); + const apiPayload: Payload = {}; + const uri = new URL(this.client.config.endpoint + apiPath); return this.client.call( - 'patch', + 'delete', uri, { 'X-Appwrite-Project': this.client.config.project, @@ -1847,61 +3030,80 @@ export class Account extends Service { } /** - * Update currently logged in user account name. + * Complete a passkey registration started with [Create passkey](/docs/references/cloud/client-web/account#createPasskey). Pass the JSON form of the credential returned by `navigator.credentials.create()`, for example `credential.toJSON()`. Each registration can be verified once; a failed attempt requires starting it again. * - * @param {string} params.name - User name. Max length: 128 chars. + * @param {string} params.passkeyId - Passkey ID. + * @param {object} params.credential - Registration credential returned by the authenticator, in the JSON form produced by `PublicKeyCredential.toJSON()`. * @throws {AppwriteException} * @returns {Promise} */ - updateName< - Preferences extends Models.Preferences = Models.DefaultPreferences, - >(params: { name: string }): Promise>; + updatePasskeyVerification(params: { + passkeyId: string; + credential: object; + }): Promise; /** - * Update currently logged in user account name. + * Complete a passkey registration started with [Create passkey](/docs/references/cloud/client-web/account#createPasskey). Pass the JSON form of the credential returned by `navigator.credentials.create()`, for example `credential.toJSON()`. Each registration can be verified once; a failed attempt requires starting it again. * - * @param {string} name - User name. Max length: 128 chars. + * @param {string} passkeyId - Passkey ID. + * @param {object} credential - Registration credential returned by the authenticator, in the JSON form produced by `PublicKeyCredential.toJSON()`. * @throws {AppwriteException} - * @returns {Promise>} + * @returns {Promise} * @deprecated Use the object parameter style method for a better developer experience. */ - updateName< - Preferences extends Models.Preferences = Models.DefaultPreferences, - >(name: string): Promise>; - updateName< - Preferences extends Models.Preferences = Models.DefaultPreferences, - >( - paramsOrFirst: { name: string } | string, - ): Promise> { - let params: { name: string }; + updatePasskeyVerification( + passkeyId: string, + credential: object, + ): Promise; + updatePasskeyVerification( + paramsOrFirst: { passkeyId: string; credential: object } | string, + ...rest: [object?] + ): Promise { + let params: { passkeyId: string; credential: object }; if ( paramsOrFirst && typeof paramsOrFirst === 'object' && !Array.isArray(paramsOrFirst) ) { - params = (paramsOrFirst || {}) as { name: string }; + params = (paramsOrFirst || {}) as { + passkeyId: string; + credential: object; + }; } else { params = { - name: paramsOrFirst as string, + passkeyId: paramsOrFirst as string, + credential: rest[0] as object, }; } - const name = params.name; + const passkeyId = params.passkeyId; + const credential = params.credential; - if (typeof name === 'undefined') { - throw new AppwriteException('Missing required parameter: "name"'); + if (typeof passkeyId === 'undefined' || passkeyId === '') { + throw new AppwriteException( + 'Missing required parameter: "passkeyId"', + ); } - const apiPath = '/account/name'; + if (typeof credential === 'undefined') { + throw new AppwriteException( + 'Missing required parameter: "credential"', + ); + } + + const apiPath = '/account/passkeys/{passkeyId}/verification'.replace( + '{passkeyId}', + encodeURIComponent(String(passkeyId)), + ); const apiPayload: Payload = {}; - if (typeof name !== 'undefined') { - apiPayload['name'] = name; + if (typeof credential !== 'undefined') { + apiPayload['credential'] = credential; } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( - 'patch', + const request = this.client.call( + 'put', uri, { 'X-Appwrite-Project': this.client.config.project, @@ -1910,6 +3112,22 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'passkey', + models: { + passkey: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + accessedAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1986,7 +3204,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'patch', uri, { @@ -1996,6 +3214,49 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'user', + models: { + user: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + registration: '', + status: true, + labels: [], + passwordUpdate: '', + email: '', + phone: '', + emailVerification: false, + phoneVerification: false, + mfa: false, + targets: [], + accessedAt: '', + }, + properties: { + targets: { + items: 'target', + }, + }, + }, + target: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + userId: '', + providerType: '', + identifier: '', + expired: false, + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -2073,7 +3334,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'patch', uri, { @@ -2083,6 +3344,49 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'user', + models: { + user: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + registration: '', + status: true, + labels: [], + passwordUpdate: '', + email: '', + phone: '', + emailVerification: false, + phoneVerification: false, + mfa: false, + targets: [], + accessedAt: '', + }, + properties: { + targets: { + items: 'target', + }, + }, + }, + target: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + userId: '', + providerType: '', + identifier: '', + expired: false, + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -2166,7 +3470,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'patch', uri, { @@ -2176,6 +3480,49 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'user', + models: { + user: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + registration: '', + status: true, + labels: [], + passwordUpdate: '', + email: '', + phone: '', + emailVerification: false, + phoneVerification: false, + mfa: false, + targets: [], + accessedAt: '', + }, + properties: { + targets: { + items: 'target', + }, + }, + }, + target: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + userId: '', + providerType: '', + identifier: '', + expired: false, + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -2242,7 +3589,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -2252,6 +3599,23 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'token', + models: { + token: { + defaults: { + $id: '', + $createdAt: '', + userId: '', + secret: '', + expire: '', + phrase: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -2346,7 +3710,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'put', uri, { @@ -2356,6 +3720,23 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'token', + models: { + token: { + defaults: { + $id: '', + $createdAt: '', + userId: '', + secret: '', + expire: '', + phrase: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -2427,7 +3808,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -2437,6 +3818,23 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'token', + models: { + token: { + defaults: { + $id: '', + $createdAt: '', + userId: '', + secret: '', + expire: '', + phrase: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -2529,7 +3927,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'put', uri, { @@ -2539,6 +3937,23 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'token', + models: { + token: { + defaults: { + $id: '', + $createdAt: '', + userId: '', + secret: '', + expire: '', + phrase: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -2586,7 +4001,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -2595,6 +4010,57 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'sessionList', + models: { + sessionList: { + defaults: { + total: 0, + sessions: [], + }, + properties: { + sessions: { + items: 'session', + }, + }, + }, + session: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + userId: '', + expire: '', + provider: '', + providerUid: '', + providerAccessToken: '', + providerAccessTokenExpiry: '', + providerRefreshToken: '', + ip: '', + osCode: '', + osName: '', + osVersion: '', + clientType: '', + clientCode: '', + clientName: '', + clientVersion: '', + clientEngine: '', + clientEngineVersion: '', + deviceName: '', + deviceBrand: '', + deviceModel: '', + countryCode: '', + countryName: '', + current: false, + factors: [], + secret: '', + mfaUpdatedAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -2665,7 +4131,7 @@ export class Account extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -2675,6 +4141,46 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'session', + models: { + session: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + userId: '', + expire: '', + provider: '', + providerUid: '', + providerAccessToken: '', + providerAccessTokenExpiry: '', + providerRefreshToken: '', + ip: '', + osCode: '', + osName: '', + osVersion: '', + clientType: '', + clientCode: '', + clientName: '', + clientVersion: '', + clientEngine: '', + clientEngineVersion: '', + deviceName: '', + deviceBrand: '', + deviceModel: '', + countryCode: '', + countryName: '', + current: false, + factors: [], + secret: '', + mfaUpdatedAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -2684,14 +4190,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. + * @param {number | null} 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; + duration?: number | null; }): 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. Use the optional `duration` parameter to create a shorter session, for example when the user doesn't choose "remember me". It must be at least 60 seconds and cannot exceed the project maximum session length. @@ -2700,7 +4206,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. + * @param {number | null} 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. @@ -2708,14 +4214,19 @@ export class Account extends Service { createEmailPasswordSession( email: string, password: string, - duration?: number, + duration?: number | null, ): Promise; createEmailPasswordSession( paramsOrFirst: - { email: string; password: string; duration?: number } | string, - ...rest: [string?, number?] + | { email: string; password: string; duration?: number | null } + | string, + ...rest: [string?, (number | null)?] ): Promise { - let params: { email: string; password: string; duration?: number }; + let params: { + email: string; + password: string; + duration?: number | null; + }; if ( paramsOrFirst && @@ -2725,13 +4236,13 @@ export class Account extends Service { params = (paramsOrFirst || {}) as { email: string; password: string; - duration?: number; + duration?: number | null; }; } else { params = { email: paramsOrFirst as string, password: rest[0] as string, - duration: rest[1] as number, + duration: rest[1] as number | null, }; } @@ -2765,7 +4276,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -2775,6 +4286,46 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'session', + models: { + session: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + userId: '', + expire: '', + provider: '', + providerUid: '', + providerAccessToken: '', + providerAccessTokenExpiry: '', + providerRefreshToken: '', + ip: '', + osCode: '', + osName: '', + osVersion: '', + clientType: '', + clientCode: '', + clientName: '', + clientVersion: '', + clientEngine: '', + clientEngineVersion: '', + deviceName: '', + deviceBrand: '', + deviceModel: '', + countryCode: '', + countryName: '', + current: false, + factors: [], + secret: '', + mfaUpdatedAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -2939,7 +4490,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -2949,6 +4500,46 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'session', + models: { + session: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + userId: '', + expire: '', + provider: '', + providerUid: '', + providerAccessToken: '', + providerAccessTokenExpiry: '', + providerRefreshToken: '', + ip: '', + osCode: '', + osName: '', + osVersion: '', + clientType: '', + clientCode: '', + clientName: '', + clientVersion: '', + clientEngine: '', + clientEngineVersion: '', + deviceName: '', + deviceBrand: '', + deviceModel: '', + countryCode: '', + countryName: '', + current: false, + factors: [], + secret: '', + mfaUpdatedAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -3022,7 +4613,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'put', uri, { @@ -3032,6 +4623,46 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'session', + models: { + session: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + userId: '', + expire: '', + provider: '', + providerUid: '', + providerAccessToken: '', + providerAccessTokenExpiry: '', + providerRefreshToken: '', + ip: '', + osCode: '', + osName: '', + osVersion: '', + clientType: '', + clientCode: '', + clientName: '', + clientVersion: '', + clientEngine: '', + clientEngineVersion: '', + deviceName: '', + deviceBrand: '', + deviceModel: '', + countryCode: '', + countryName: '', + current: false, + factors: [], + secret: '', + mfaUpdatedAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -3046,6 +4677,7 @@ export class Account extends Service { * @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} */ @@ -3054,6 +4686,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. @@ -3067,6 +4700,7 @@ export class Account extends Service { * @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. @@ -3076,6 +4710,7 @@ export class Account extends Service { success?: string, failure?: string, scopes?: string[], + state?: string, ): void | URL; createOAuth2Session( paramsOrFirst: @@ -3084,15 +4719,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 ( @@ -3102,13 +4739,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 = { @@ -3116,6 +4755,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, }; } @@ -3123,6 +4763,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( @@ -3148,6 +4789,10 @@ export class Account extends Service { apiPayload['scopes'] = scopes; } + if (typeof state !== 'undefined') { + apiPayload['state'] = state; + } + const uri = new URL(this.client.config.endpoint + apiPath); apiPayload['project'] = this.client.config.project; @@ -3227,7 +4872,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'put', uri, { @@ -3237,6 +4882,46 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'session', + models: { + session: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + userId: '', + expire: '', + provider: '', + providerUid: '', + providerAccessToken: '', + providerAccessTokenExpiry: '', + providerRefreshToken: '', + ip: '', + osCode: '', + osName: '', + osVersion: '', + clientType: '', + clientCode: '', + clientName: '', + clientVersion: '', + clientEngine: '', + clientEngineVersion: '', + deviceName: '', + deviceBrand: '', + deviceModel: '', + countryCode: '', + countryName: '', + current: false, + factors: [], + secret: '', + mfaUpdatedAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -3306,7 +4991,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -3316,6 +5001,46 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'session', + models: { + session: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + userId: '', + expire: '', + provider: '', + providerUid: '', + providerAccessToken: '', + providerAccessTokenExpiry: '', + providerRefreshToken: '', + ip: '', + osCode: '', + osName: '', + osVersion: '', + clientType: '', + clientCode: '', + clientName: '', + clientVersion: '', + clientEngine: '', + clientEngineVersion: '', + deviceName: '', + deviceBrand: '', + deviceModel: '', + countryCode: '', + countryName: '', + current: false, + factors: [], + secret: '', + mfaUpdatedAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -3367,7 +5092,7 @@ export class Account extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -3376,6 +5101,46 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'session', + models: { + session: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + userId: '', + expire: '', + provider: '', + providerUid: '', + providerAccessToken: '', + providerAccessTokenExpiry: '', + providerRefreshToken: '', + ip: '', + osCode: '', + osName: '', + osVersion: '', + clientType: '', + clientCode: '', + clientName: '', + clientVersion: '', + clientEngine: '', + clientEngineVersion: '', + deviceName: '', + deviceBrand: '', + deviceModel: '', + countryCode: '', + countryName: '', + current: false, + factors: [], + secret: '', + mfaUpdatedAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -3427,7 +5192,7 @@ export class Account extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'patch', uri, { @@ -3437,6 +5202,46 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'session', + models: { + session: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + userId: '', + expire: '', + provider: '', + providerUid: '', + providerAccessToken: '', + providerAccessTokenExpiry: '', + providerRefreshToken: '', + ip: '', + osCode: '', + osName: '', + osVersion: '', + clientType: '', + clientCode: '', + clientName: '', + clientVersion: '', + clientEngine: '', + clientEngineVersion: '', + deviceName: '', + deviceBrand: '', + deviceModel: '', + countryCode: '', + countryName: '', + current: false, + factors: [], + secret: '', + mfaUpdatedAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -3511,7 +5316,7 @@ export class Account extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'patch', uri, { @@ -3521,6 +5326,49 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'user', + models: { + user: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + registration: '', + status: true, + labels: [], + passwordUpdate: '', + email: '', + phone: '', + emailVerification: false, + phoneVerification: false, + mfa: false, + targets: [], + accessedAt: '', + }, + properties: { + targets: { + items: 'target', + }, + }, + }, + target: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + userId: '', + providerType: '', + identifier: '', + expired: false, + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -3614,7 +5462,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -3624,6 +5472,25 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'target', + models: { + target: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + userId: '', + providerType: '', + identifier: '', + expired: false, + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -3699,7 +5566,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'put', uri, { @@ -3709,6 +5576,25 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'target', + models: { + target: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + userId: '', + providerType: '', + identifier: '', + expired: false, + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -3860,7 +5746,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -3870,6 +5756,23 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'token', + models: { + token: { + defaults: { + $id: '', + $createdAt: '', + userId: '', + secret: '', + expire: '', + phrase: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -3977,7 +5880,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -3987,6 +5890,23 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'token', + models: { + token: { + defaults: { + $id: '', + $createdAt: '', + userId: '', + secret: '', + expire: '', + phrase: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -4002,6 +5922,7 @@ export class Account extends Service { * @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} */ @@ -4010,6 +5931,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. @@ -4024,6 +5946,7 @@ export class Account extends Service { * @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. @@ -4033,6 +5956,7 @@ export class Account extends Service { success?: string, failure?: string, scopes?: string[], + state?: string, ): void | URL; createOAuth2Token( paramsOrFirst: @@ -4041,15 +5965,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 ( @@ -4059,13 +5985,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 = { @@ -4073,6 +6001,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, }; } @@ -4080,6 +6009,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( @@ -4105,6 +6035,10 @@ export class Account extends Service { apiPayload['scopes'] = scopes; } + if (typeof state !== 'undefined') { + apiPayload['state'] = state; + } + const uri = new URL(this.client.config.endpoint + apiPath); apiPayload['project'] = this.client.config.project; @@ -4116,6 +6050,148 @@ export class Account extends Service { return uri; } + /** + * Start signing in with a passkey. No email or user ID is needed: pass the returned `publicKey` options to `navigator.credentials.get()` and the user picks one of their passkeys. Then call [Update passkey token](/docs/references/cloud/client-web/account#updatePasskeyToken) with the credential to receive a token, and exchange it with [Create session](/docs/references/cloud/client-web/account#createSession). The challenge expires after 5 minutes. + * + * @throws {AppwriteException} + * @returns {Promise} + */ + createPasskeyToken(): Promise { + const apiPath = '/account/tokens/passkey'; + const apiPayload: Payload = {}; + + const uri = new URL(this.client.config.endpoint + apiPath); + const request = this.client.call( + 'post', + uri, + { + 'X-Appwrite-Project': this.client.config.project, + 'content-type': 'application/json', + accept: 'application/json', + }, + apiPayload, + ); + const defaults = { + root: 'passkeyChallenge', + models: { + passkeyChallenge: { + defaults: { + $id: '', + $createdAt: '', + passkeyId: '', + expire: '', + publicKey: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); + } + + /** + * Complete a passkey sign-in started with [Create passkey token](/docs/references/cloud/client-web/account#createPasskeyToken). Pass the challenge ID and the JSON form of the credential returned by `navigator.credentials.get()`, for example `credential.toJSON()`. The returned token includes its secret and expires after 1 minute: exchange it for a session with [Create session](/docs/references/cloud/client-web/account#createSession). Passkeys require user verification, so the session also satisfies MFA. Each challenge can only be used once. + * + * @param {string} params.challengeId - Challenge ID returned by createPasskeyToken. + * @param {object} params.credential - Authentication credential returned by the authenticator, in the JSON form produced by `PublicKeyCredential.toJSON()`. + * @throws {AppwriteException} + * @returns {Promise} + */ + updatePasskeyToken(params: { + challengeId: string; + credential: object; + }): Promise; + /** + * Complete a passkey sign-in started with [Create passkey token](/docs/references/cloud/client-web/account#createPasskeyToken). Pass the challenge ID and the JSON form of the credential returned by `navigator.credentials.get()`, for example `credential.toJSON()`. The returned token includes its secret and expires after 1 minute: exchange it for a session with [Create session](/docs/references/cloud/client-web/account#createSession). Passkeys require user verification, so the session also satisfies MFA. Each challenge can only be used once. + * + * @param {string} challengeId - Challenge ID returned by createPasskeyToken. + * @param {object} credential - Authentication credential returned by the authenticator, in the JSON form produced by `PublicKeyCredential.toJSON()`. + * @throws {AppwriteException} + * @returns {Promise} + * @deprecated Use the object parameter style method for a better developer experience. + */ + updatePasskeyToken( + challengeId: string, + credential: object, + ): Promise; + updatePasskeyToken( + paramsOrFirst: { challengeId: string; credential: object } | string, + ...rest: [object?] + ): Promise { + let params: { challengeId: string; credential: object }; + + if ( + paramsOrFirst && + typeof paramsOrFirst === 'object' && + !Array.isArray(paramsOrFirst) + ) { + params = (paramsOrFirst || {}) as { + challengeId: string; + credential: object; + }; + } else { + params = { + challengeId: paramsOrFirst as string, + credential: rest[0] as object, + }; + } + + const challengeId = params.challengeId; + const credential = params.credential; + + if (typeof challengeId === 'undefined') { + throw new AppwriteException( + 'Missing required parameter: "challengeId"', + ); + } + + if (typeof credential === 'undefined') { + throw new AppwriteException( + 'Missing required parameter: "credential"', + ); + } + + const apiPath = '/account/tokens/passkey'; + const apiPayload: Payload = {}; + + if (typeof challengeId !== 'undefined') { + apiPayload['challengeId'] = challengeId; + } + + if (typeof credential !== 'undefined') { + apiPayload['credential'] = credential; + } + + const uri = new URL(this.client.config.endpoint + apiPath); + const request = this.client.call( + 'put', + uri, + { + 'X-Appwrite-Project': this.client.config.project, + 'content-type': 'application/json', + accept: 'application/json', + }, + apiPayload, + ); + const defaults = { + root: 'tokenSecret', + models: { + tokenSecret: { + defaults: { + $id: '', + $createdAt: '', + userId: '', + secret: '', + expire: '', + phrase: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); + } + /** * Sends the user an SMS with a secret key for creating a session. If the provided user ID has not be registered, a new user will be created. Use the returned user ID and secret and submit a request to the [POST /v1/account/sessions/token](https://appwrite.io/docs/references/cloud/client-web/account#createSession) endpoint to complete the login process. The secret sent to the user's phone is valid for 15 minutes. * @@ -4184,7 +6260,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -4194,6 +6270,23 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'token', + models: { + token: { + defaults: { + $id: '', + $createdAt: '', + userId: '', + secret: '', + expire: '', + phrase: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -4250,7 +6343,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -4260,6 +6353,23 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'token', + models: { + token: { + defaults: { + $id: '', + $createdAt: '', + userId: '', + secret: '', + expire: '', + phrase: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -4317,7 +6427,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -4327,6 +6437,23 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'token', + models: { + token: { + defaults: { + $id: '', + $createdAt: '', + userId: '', + secret: '', + expire: '', + phrase: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -4399,7 +6526,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'put', uri, { @@ -4409,6 +6536,23 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'token', + models: { + token: { + defaults: { + $id: '', + $createdAt: '', + userId: '', + secret: '', + expire: '', + phrase: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -4479,7 +6623,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'put', uri, { @@ -4489,6 +6633,23 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'token', + models: { + token: { + defaults: { + $id: '', + $createdAt: '', + userId: '', + secret: '', + expire: '', + phrase: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -4544,7 +6705,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -4554,6 +6715,23 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'token', + models: { + token: { + defaults: { + $id: '', + $createdAt: '', + userId: '', + secret: '', + expire: '', + phrase: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -4628,7 +6806,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'put', uri, { @@ -4638,6 +6816,23 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'token', + models: { + token: { + defaults: { + $id: '', + $createdAt: '', + userId: '', + secret: '', + expire: '', + phrase: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -4651,7 +6846,7 @@ export class Account extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -4661,6 +6856,23 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'token', + models: { + token: { + defaults: { + $id: '', + $createdAt: '', + userId: '', + secret: '', + expire: '', + phrase: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -4733,7 +6945,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'put', uri, { @@ -4743,5 +6955,22 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'token', + models: { + token: { + defaults: { + $id: '', + $createdAt: '', + userId: '', + secret: '', + expire: '', + phrase: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } } 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/apps.ts b/src/services/apps.ts index 02554ba4..896038d7 100644 --- a/src/services/apps.ts +++ b/src/services/apps.ts @@ -1,5 +1,5 @@ import { Service } from '../service'; -import { AppwriteException, Client } from '../client'; +import { AppwriteException, Client, applyDefaults } from '../client'; import type { Models } from '../models'; import type { Payload } from '../client'; @@ -68,7 +68,7 @@ export class Apps extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -77,6 +77,71 @@ export class Apps extends Service { }, apiPayload, ); + const defaults = { + root: 'appsList', + models: { + appsList: { + defaults: { + total: 0, + apps: [], + }, + properties: { + apps: { + items: 'app', + }, + }, + }, + app: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + description: '', + clientUri: '', + logoUri: '', + privacyPolicyUrl: '', + termsUrl: '', + contacts: [], + tagline: '', + tags: [], + labels: [], + images: [], + supportUrl: '', + dataDeletionUrl: '', + redirectUris: [], + postLogoutRedirectUris: [], + enabled: true, + type: 'confidential', + deviceFlow: false, + teamId: '', + userId: '', + installationScopes: [], + installationRedirectUrl: '', + secrets: [], + }, + properties: { + secrets: { + items: 'appSecret', + }, + }, + }, + appSecret: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + appId: '', + secret: '', + hint: '', + createdById: '', + createdByName: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -403,7 +468,7 @@ export class Apps extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -413,6 +478,60 @@ export class Apps extends Service { }, apiPayload, ); + const defaults = { + root: 'app', + models: { + app: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + description: '', + clientUri: '', + logoUri: '', + privacyPolicyUrl: '', + termsUrl: '', + contacts: [], + tagline: '', + tags: [], + labels: [], + images: [], + supportUrl: '', + dataDeletionUrl: '', + redirectUris: [], + postLogoutRedirectUris: [], + enabled: true, + type: 'confidential', + deviceFlow: false, + teamId: '', + userId: '', + installationScopes: [], + installationRedirectUrl: '', + secrets: [], + }, + properties: { + secrets: { + items: 'appSecret', + }, + }, + }, + appSecret: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + appId: '', + secret: '', + hint: '', + createdById: '', + createdByName: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -426,7 +545,7 @@ export class Apps extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -435,6 +554,33 @@ export class Apps extends Service { }, apiPayload, ); + const defaults = { + root: 'appScopeList', + models: { + appScopeList: { + defaults: { + total: 0, + scopes: [], + }, + properties: { + scopes: { + items: 'appScope', + }, + }, + }, + appScope: { + defaults: { + value: '', + description: '', + type: '', + category: '', + deprecated: false, + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -448,7 +594,7 @@ export class Apps extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -457,6 +603,33 @@ export class Apps extends Service { }, apiPayload, ); + const defaults = { + root: 'appScopeList', + models: { + appScopeList: { + defaults: { + total: 0, + scopes: [], + }, + properties: { + scopes: { + items: 'appScope', + }, + }, + }, + appScope: { + defaults: { + value: '', + description: '', + type: '', + category: '', + deprecated: false, + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -504,7 +677,7 @@ export class Apps extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -513,6 +686,60 @@ export class Apps extends Service { }, apiPayload, ); + const defaults = { + root: 'app', + models: { + app: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + description: '', + clientUri: '', + logoUri: '', + privacyPolicyUrl: '', + termsUrl: '', + contacts: [], + tagline: '', + tags: [], + labels: [], + images: [], + supportUrl: '', + dataDeletionUrl: '', + redirectUris: [], + postLogoutRedirectUris: [], + enabled: true, + type: 'confidential', + deviceFlow: false, + teamId: '', + userId: '', + installationScopes: [], + installationRedirectUrl: '', + secrets: [], + }, + properties: { + secrets: { + items: 'appSecret', + }, + }, + }, + appSecret: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + appId: '', + secret: '', + hint: '', + createdById: '', + createdByName: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -846,7 +1073,7 @@ export class Apps extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'put', uri, { @@ -856,6 +1083,60 @@ export class Apps extends Service { }, apiPayload, ); + const defaults = { + root: 'app', + models: { + app: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + description: '', + clientUri: '', + logoUri: '', + privacyPolicyUrl: '', + termsUrl: '', + contacts: [], + tagline: '', + tags: [], + labels: [], + images: [], + supportUrl: '', + dataDeletionUrl: '', + redirectUris: [], + postLogoutRedirectUris: [], + enabled: true, + type: 'confidential', + deviceFlow: false, + teamId: '', + userId: '', + installationScopes: [], + installationRedirectUrl: '', + secrets: [], + }, + properties: { + secrets: { + items: 'appSecret', + }, + }, + }, + appSecret: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + appId: '', + secret: '', + hint: '', + createdById: '', + createdByName: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -992,7 +1273,7 @@ export class Apps extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -1001,6 +1282,37 @@ export class Apps extends Service { }, apiPayload, ); + const defaults = { + root: 'appInstallationList', + models: { + appInstallationList: { + defaults: { + total: 0, + installations: [], + }, + properties: { + installations: { + items: 'appInstallation', + }, + }, + }, + appInstallation: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + appId: '', + teamId: '', + scopes: [], + authorizationDetails: [], + createdById: '', + createdByName: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1072,7 +1384,7 @@ export class Apps extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -1081,6 +1393,26 @@ export class Apps extends Service { }, apiPayload, ); + const defaults = { + root: 'appInstallation', + models: { + appInstallation: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + appId: '', + teamId: '', + scopes: [], + authorizationDetails: [], + createdById: '', + createdByName: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1230,7 +1562,7 @@ export class Apps extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -1240,6 +1572,22 @@ export class Apps extends Service { }, apiPayload, ); + const defaults = { + root: 'oauth2Token', + models: { + oauth2Token: { + defaults: { + access_token: '', + token_type: 'Bearer', + expires_in: 0, + refresh_token: '', + scope: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1319,7 +1667,7 @@ export class Apps extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -1328,6 +1676,36 @@ export class Apps extends Service { }, apiPayload, ); + const defaults = { + root: 'appKeyList', + models: { + appKeyList: { + defaults: { + total: 0, + keys: [], + }, + properties: { + keys: { + items: 'appKey', + }, + }, + }, + appKey: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + appId: '', + secret: '', + hint: '', + createdById: '', + createdByName: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1377,7 +1755,7 @@ export class Apps extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -1387,6 +1765,25 @@ export class Apps extends Service { }, apiPayload, ); + const defaults = { + root: 'appKey', + models: { + appKey: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + appId: '', + secret: '', + hint: '', + createdById: '', + createdByName: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1444,7 +1841,7 @@ export class Apps extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -1453,6 +1850,25 @@ export class Apps extends Service { }, apiPayload, ); + const defaults = { + root: 'appKey', + models: { + appKey: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + appId: '', + secret: '', + hint: '', + createdById: '', + createdByName: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1599,7 +2015,7 @@ export class Apps extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -1608,6 +2024,36 @@ export class Apps extends Service { }, apiPayload, ); + const defaults = { + root: 'appSecretList', + models: { + appSecretList: { + defaults: { + total: 0, + secrets: [], + }, + properties: { + secrets: { + items: 'appSecret', + }, + }, + }, + appSecret: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + appId: '', + secret: '', + hint: '', + createdById: '', + createdByName: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1657,7 +2103,7 @@ export class Apps extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -1667,6 +2113,25 @@ export class Apps extends Service { }, apiPayload, ); + const defaults = { + root: 'appSecretPlaintext', + models: { + appSecretPlaintext: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + appId: '', + secret: '', + hint: '', + createdById: '', + createdByName: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1732,7 +2197,7 @@ export class Apps extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -1741,6 +2206,25 @@ export class Apps extends Service { }, apiPayload, ); + const defaults = { + root: 'appSecret', + models: { + appSecret: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + appId: '', + secret: '', + hint: '', + createdById: '', + createdByName: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1875,7 +2359,7 @@ export class Apps extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'patch', uri, { @@ -1885,6 +2369,60 @@ export class Apps extends Service { }, apiPayload, ); + const defaults = { + root: 'app', + models: { + app: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + description: '', + clientUri: '', + logoUri: '', + privacyPolicyUrl: '', + termsUrl: '', + contacts: [], + tagline: '', + tags: [], + labels: [], + images: [], + supportUrl: '', + dataDeletionUrl: '', + redirectUris: [], + postLogoutRedirectUris: [], + enabled: true, + type: 'confidential', + deviceFlow: false, + teamId: '', + userId: '', + installationScopes: [], + installationRedirectUrl: '', + secrets: [], + }, + properties: { + secrets: { + items: 'appSecret', + }, + }, + }, + appSecret: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + appId: '', + secret: '', + hint: '', + createdById: '', + createdByName: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** diff --git a/src/services/databases.ts b/src/services/databases.ts index 94d2ad16..43e4b4a9 100644 --- a/src/services/databases.ts +++ b/src/services/databases.ts @@ -1,5 +1,5 @@ import { Service } from '../service'; -import { AppwriteException, Client } from '../client'; +import { AppwriteException, Client, applyDefaults } from '../client'; import type { Models } from '../models'; import type { Payload } from '../client'; @@ -72,7 +72,7 @@ export class Databases extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -81,6 +81,34 @@ export class Databases extends Service { }, apiPayload, ); + const defaults = { + root: 'transactionList', + models: { + transactionList: { + defaults: { + total: 0, + transactions: [], + }, + properties: { + transactions: { + items: 'transaction', + }, + }, + }, + transaction: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + status: 'pending', + operations: 0, + expiresAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -129,7 +157,7 @@ export class Databases extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -139,6 +167,23 @@ export class Databases extends Service { }, apiPayload, ); + const defaults = { + root: 'transaction', + models: { + transaction: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + status: 'pending', + operations: 0, + expiresAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -193,7 +238,7 @@ export class Databases extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -202,6 +247,23 @@ export class Databases extends Service { }, apiPayload, ); + const defaults = { + root: 'transaction', + models: { + transaction: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + status: 'pending', + operations: 0, + expiresAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -289,7 +351,7 @@ export class Databases extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'patch', uri, { @@ -299,6 +361,23 @@ export class Databases extends Service { }, apiPayload, ); + const defaults = { + root: 'transaction', + models: { + transaction: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + status: 'pending', + operations: 0, + expiresAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -433,7 +512,7 @@ export class Databases extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -443,6 +522,23 @@ export class Databases extends Service { }, apiPayload, ); + const defaults = { + root: 'transaction', + models: { + transaction: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + status: 'pending', + operations: 0, + expiresAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -580,7 +676,7 @@ export class Databases extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -589,6 +685,35 @@ export class Databases extends Service { }, apiPayload, ); + const defaults = { + root: 'documentList', + models: { + documentList: { + defaults: { + total: 0, + documents: [], + }, + properties: { + documents: { + items: 'document', + }, + }, + }, + document: { + defaults: { + $id: '', + $sequence: '', + $collectionId: '', + $databaseId: '', + $createdAt: '', + $updatedAt: '', + $permissions: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -598,8 +723,8 @@ export class Databases extends Service { * @param {string} params.collectionId - Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection). Make sure to define attributes before creating documents. * @param {string} params.documentId - Document ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars. * @param {Document extends Models.DefaultDocument ? Partial & Record : Partial & Omit} params.data - Document data as JSON object. - * @param {string[]} params.permissions - An array of permissions strings. By default, only the current user is granted all permissions. [Learn more about permissions](https://appwrite.io/docs/permissions). - * @param {string} params.transactionId - Transaction ID for staging the operation. + * @param {string[] | null} params.permissions - An array of permissions strings. By default, only the current user is granted all permissions. [Learn more about permissions](https://appwrite.io/docs/permissions). + * @param {string | null} params.transactionId - Transaction ID for staging the operation. * @throws {AppwriteException} * @returns {Promise} * @deprecated This API has been deprecated since 1.8.0. Please use `TablesDB.createRow` instead. @@ -613,8 +738,8 @@ export class Databases extends Service { data: Document extends Models.DefaultDocument ? Partial & Record : Partial & Omit; - permissions?: string[]; - transactionId?: string; + permissions?: string[] | null; + transactionId?: string | null; }): Promise; /** * Create a new Document. Before using this route, you should create a new collection resource using either a [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection) API or directly from your database console. @@ -623,8 +748,8 @@ export class Databases extends Service { * @param {string} collectionId - Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection). Make sure to define attributes before creating documents. * @param {string} documentId - Document ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars. * @param {Document extends Models.DefaultDocument ? Partial & Record : Partial & Omit} data - Document data as JSON object. - * @param {string[]} permissions - An array of permissions strings. By default, only the current user is granted all permissions. [Learn more about permissions](https://appwrite.io/docs/permissions). - * @param {string} transactionId - Transaction ID for staging the operation. + * @param {string[] | null} permissions - An array of permissions strings. By default, only the current user is granted all permissions. [Learn more about permissions](https://appwrite.io/docs/permissions). + * @param {string | null} transactionId - Transaction ID for staging the operation. * @throws {AppwriteException} * @returns {Promise} * @deprecated Use the object parameter style method for a better developer experience. @@ -636,8 +761,8 @@ export class Databases extends Service { data: Document extends Models.DefaultDocument ? Partial & Record : Partial & Omit, - permissions?: string[], - transactionId?: string, + permissions?: string[] | null, + transactionId?: string | null, ): Promise; createDocument( paramsOrFirst: @@ -649,8 +774,8 @@ export class Databases extends Service { ? Partial & Record : Partial & Omit; - permissions?: string[]; - transactionId?: string; + permissions?: string[] | null; + transactionId?: string | null; } | string, ...rest: [ @@ -660,8 +785,8 @@ export class Databases extends Service { ? Partial & Record : Partial & Omit)?, - string[]?, - string?, + (string[] | null)?, + (string | null)?, ] ): Promise { let params: { @@ -672,8 +797,8 @@ export class Databases extends Service { ? Partial & Record : Partial & Omit; - permissions?: string[]; - transactionId?: string; + permissions?: string[] | null; + transactionId?: string | null; }; if ( @@ -689,8 +814,8 @@ export class Databases extends Service { ? Partial & Record : Partial & Omit; - permissions?: string[]; - transactionId?: string; + permissions?: string[] | null; + transactionId?: string | null; }; } else { params = { @@ -701,8 +826,8 @@ export class Databases extends Service { ? Partial & Record : Partial & Omit, - permissions: rest[3] as string[], - transactionId: rest[4] as string, + permissions: rest[3] as string[] | null, + transactionId: rest[4] as string | null, }; } @@ -761,7 +886,7 @@ export class Databases extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -771,6 +896,24 @@ export class Databases extends Service { }, apiPayload, ); + const defaults = { + root: 'document', + models: { + document: { + defaults: { + $id: '', + $sequence: '', + $collectionId: '', + $databaseId: '', + $createdAt: '', + $updatedAt: '', + $permissions: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -901,7 +1044,7 @@ export class Databases extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -910,6 +1053,24 @@ export class Databases extends Service { }, apiPayload, ); + const defaults = { + root: 'document', + models: { + document: { + defaults: { + $id: '', + $sequence: '', + $collectionId: '', + $databaseId: '', + $createdAt: '', + $updatedAt: '', + $permissions: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -919,8 +1080,8 @@ export class Databases extends Service { * @param {string} params.collectionId - Collection ID. * @param {string} params.documentId - Document ID. * @param {Document extends Models.DefaultDocument ? Partial & Record : Partial & Partial>} params.data - Document data as JSON object. Include all required attributes of the document to be created or updated. - * @param {string[]} params.permissions - An array of permissions strings. By default, the current permissions are inherited. [Learn more about permissions](https://appwrite.io/docs/permissions). - * @param {string} params.transactionId - Transaction ID for staging the operation. + * @param {string[] | null} params.permissions - An array of permissions strings. By default, the current permissions are inherited. [Learn more about permissions](https://appwrite.io/docs/permissions). + * @param {string | null} params.transactionId - Transaction ID for staging the operation. * @throws {AppwriteException} * @returns {Promise} * @deprecated This API has been deprecated since 1.8.0. Please use `TablesDB.upsertRow` instead. @@ -935,8 +1096,8 @@ export class Databases extends Service { ? Partial & Record : Partial & Partial>; - permissions?: string[]; - transactionId?: string; + permissions?: string[] | null; + transactionId?: string | null; }): Promise; /** * Create or update a Document. Before using this route, you should create a new collection resource using either a [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection) API or directly from your database console. @@ -945,8 +1106,8 @@ export class Databases extends Service { * @param {string} collectionId - Collection ID. * @param {string} documentId - Document ID. * @param {Document extends Models.DefaultDocument ? Partial & Record : Partial & Partial>} data - Document data as JSON object. Include all required attributes of the document to be created or updated. - * @param {string[]} permissions - An array of permissions strings. By default, the current permissions are inherited. [Learn more about permissions](https://appwrite.io/docs/permissions). - * @param {string} transactionId - Transaction ID for staging the operation. + * @param {string[] | null} permissions - An array of permissions strings. By default, the current permissions are inherited. [Learn more about permissions](https://appwrite.io/docs/permissions). + * @param {string | null} transactionId - Transaction ID for staging the operation. * @throws {AppwriteException} * @returns {Promise} * @deprecated Use the object parameter style method for a better developer experience. @@ -959,8 +1120,8 @@ export class Databases extends Service { ? Partial & Record : Partial & Partial>, - permissions?: string[], - transactionId?: string, + permissions?: string[] | null, + transactionId?: string | null, ): Promise; upsertDocument( paramsOrFirst: @@ -972,8 +1133,8 @@ export class Databases extends Service { ? Partial & Record : Partial & Partial>; - permissions?: string[]; - transactionId?: string; + permissions?: string[] | null; + transactionId?: string | null; } | string, ...rest: [ @@ -983,8 +1144,8 @@ export class Databases extends Service { ? Partial & Record : Partial & Partial>)?, - string[]?, - string?, + (string[] | null)?, + (string | null)?, ] ): Promise { let params: { @@ -995,8 +1156,8 @@ export class Databases extends Service { ? Partial & Record : Partial & Partial>; - permissions?: string[]; - transactionId?: string; + permissions?: string[] | null; + transactionId?: string | null; }; if ( @@ -1012,8 +1173,8 @@ export class Databases extends Service { ? Partial & Record : Partial & Partial>; - permissions?: string[]; - transactionId?: string; + permissions?: string[] | null; + transactionId?: string | null; }; } else { params = { @@ -1024,8 +1185,8 @@ export class Databases extends Service { ? Partial & Record : Partial & Partial>, - permissions: rest[3] as string[], - transactionId: rest[4] as string, + permissions: rest[3] as string[] | null, + transactionId: rest[4] as string | null, }; } @@ -1080,7 +1241,7 @@ export class Databases extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'put', uri, { @@ -1090,6 +1251,24 @@ export class Databases extends Service { }, apiPayload, ); + const defaults = { + root: 'document', + models: { + document: { + defaults: { + $id: '', + $sequence: '', + $collectionId: '', + $databaseId: '', + $createdAt: '', + $updatedAt: '', + $permissions: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1099,8 +1278,8 @@ export class Databases extends Service { * @param {string} params.collectionId - Collection ID. * @param {string} params.documentId - Document ID. * @param {Document extends Models.DefaultDocument ? Partial & Record : Partial & Partial>} params.data - Document data as JSON object. Include only attribute and value pairs to be updated. - * @param {string[]} params.permissions - An array of permissions strings. By default, the current permissions are inherited. [Learn more about permissions](https://appwrite.io/docs/permissions). - * @param {string} params.transactionId - Transaction ID for staging the operation. + * @param {string[] | null} params.permissions - An array of permissions strings. By default, the current permissions are inherited. [Learn more about permissions](https://appwrite.io/docs/permissions). + * @param {string | null} params.transactionId - Transaction ID for staging the operation. * @throws {AppwriteException} * @returns {Promise} * @deprecated This API has been deprecated since 1.8.0. Please use `TablesDB.updateRow` instead. @@ -1115,8 +1294,8 @@ export class Databases extends Service { ? Partial & Record : Partial & Partial>; - permissions?: string[]; - transactionId?: string; + permissions?: string[] | null; + transactionId?: string | null; }): Promise; /** * Update a document by its unique ID. Using the patch method you can pass only specific fields that will get updated. @@ -1125,8 +1304,8 @@ export class Databases extends Service { * @param {string} collectionId - Collection ID. * @param {string} documentId - Document ID. * @param {Document extends Models.DefaultDocument ? Partial & Record : Partial & Partial>} data - Document data as JSON object. Include only attribute and value pairs to be updated. - * @param {string[]} permissions - An array of permissions strings. By default, the current permissions are inherited. [Learn more about permissions](https://appwrite.io/docs/permissions). - * @param {string} transactionId - Transaction ID for staging the operation. + * @param {string[] | null} permissions - An array of permissions strings. By default, the current permissions are inherited. [Learn more about permissions](https://appwrite.io/docs/permissions). + * @param {string | null} transactionId - Transaction ID for staging the operation. * @throws {AppwriteException} * @returns {Promise} * @deprecated Use the object parameter style method for a better developer experience. @@ -1139,8 +1318,8 @@ export class Databases extends Service { ? Partial & Record : Partial & Partial>, - permissions?: string[], - transactionId?: string, + permissions?: string[] | null, + transactionId?: string | null, ): Promise; updateDocument( paramsOrFirst: @@ -1152,8 +1331,8 @@ export class Databases extends Service { ? Partial & Record : Partial & Partial>; - permissions?: string[]; - transactionId?: string; + permissions?: string[] | null; + transactionId?: string | null; } | string, ...rest: [ @@ -1163,8 +1342,8 @@ export class Databases extends Service { ? Partial & Record : Partial & Partial>)?, - string[]?, - string?, + (string[] | null)?, + (string | null)?, ] ): Promise { let params: { @@ -1175,8 +1354,8 @@ export class Databases extends Service { ? Partial & Record : Partial & Partial>; - permissions?: string[]; - transactionId?: string; + permissions?: string[] | null; + transactionId?: string | null; }; if ( @@ -1192,8 +1371,8 @@ export class Databases extends Service { ? Partial & Record : Partial & Partial>; - permissions?: string[]; - transactionId?: string; + permissions?: string[] | null; + transactionId?: string | null; }; } else { params = { @@ -1204,8 +1383,8 @@ export class Databases extends Service { ? Partial & Record : Partial & Partial>, - permissions: rest[3] as string[], - transactionId: rest[4] as string, + permissions: rest[3] as string[] | null, + transactionId: rest[4] as string | null, }; } @@ -1260,7 +1439,7 @@ export class Databases extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'patch', uri, { @@ -1270,6 +1449,24 @@ export class Databases extends Service { }, apiPayload, ); + const defaults = { + root: 'document', + models: { + document: { + defaults: { + $id: '', + $sequence: '', + $collectionId: '', + $databaseId: '', + $createdAt: '', + $updatedAt: '', + $permissions: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1405,8 +1602,8 @@ export class Databases extends Service { * @param {string} params.documentId - Document ID. * @param {string} params.attribute - Attribute key. * @param {number} params.value - Value to increment the attribute by. The value must be a number. - * @param {number} params.min - Minimum value for the attribute. If the current value is lesser than this value, an exception will be thrown. - * @param {string} params.transactionId - Transaction ID for staging the operation. + * @param {number | null} params.min - Minimum value for the attribute. If the current value is lesser than this value, an exception will be thrown. + * @param {string | null} params.transactionId - Transaction ID for staging the operation. * @throws {AppwriteException} * @returns {Promise} * @deprecated This API has been deprecated since 1.8.0. Please use `TablesDB.decrementRowColumn` instead. @@ -1419,8 +1616,8 @@ export class Databases extends Service { documentId: string; attribute: string; value?: number; - min?: number; - transactionId?: string; + min?: number | null; + transactionId?: string | null; }): Promise; /** * Decrement a specific attribute of a document by a given value. @@ -1430,8 +1627,8 @@ export class Databases extends Service { * @param {string} documentId - Document ID. * @param {string} attribute - Attribute key. * @param {number} value - Value to increment the attribute by. The value must be a number. - * @param {number} min - Minimum value for the attribute. If the current value is lesser than this value, an exception will be thrown. - * @param {string} transactionId - Transaction ID for staging the operation. + * @param {number | null} min - Minimum value for the attribute. If the current value is lesser than this value, an exception will be thrown. + * @param {string | null} transactionId - Transaction ID for staging the operation. * @throws {AppwriteException} * @returns {Promise} * @deprecated Use the object parameter style method for a better developer experience. @@ -1444,8 +1641,8 @@ export class Databases extends Service { documentId: string, attribute: string, value?: number, - min?: number, - transactionId?: string, + min?: number | null, + transactionId?: string | null, ): Promise; decrementDocumentAttribute< Document extends Models.Document = Models.DefaultDocument, @@ -1457,11 +1654,18 @@ export class Databases extends Service { documentId: string; attribute: string; value?: number; - min?: number; - transactionId?: string; + min?: number | null; + transactionId?: string | null; } | string, - ...rest: [string?, string?, string?, number?, number?, string?] + ...rest: [ + string?, + string?, + string?, + number?, + (number | null)?, + (string | null)?, + ] ): Promise { let params: { databaseId: string; @@ -1469,8 +1673,8 @@ export class Databases extends Service { documentId: string; attribute: string; value?: number; - min?: number; - transactionId?: string; + min?: number | null; + transactionId?: string | null; }; if ( @@ -1484,8 +1688,8 @@ export class Databases extends Service { documentId: string; attribute: string; value?: number; - min?: number; - transactionId?: string; + min?: number | null; + transactionId?: string | null; }; } else { params = { @@ -1494,8 +1698,8 @@ export class Databases extends Service { documentId: rest[1] as string, attribute: rest[2] as string, value: rest[3] as number, - min: rest[4] as number, - transactionId: rest[5] as string, + min: rest[4] as number | null, + transactionId: rest[5] as string | null, }; } @@ -1555,7 +1759,7 @@ export class Databases extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'patch', uri, { @@ -1565,6 +1769,24 @@ export class Databases extends Service { }, apiPayload, ); + const defaults = { + root: 'document', + models: { + document: { + defaults: { + $id: '', + $sequence: '', + $collectionId: '', + $databaseId: '', + $createdAt: '', + $updatedAt: '', + $permissions: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1575,8 +1797,8 @@ export class Databases extends Service { * @param {string} params.documentId - Document ID. * @param {string} params.attribute - Attribute key. * @param {number} params.value - Value to increment the attribute by. The value must be a number. - * @param {number} params.max - Maximum value for the attribute. If the current value is greater than this value, an error will be thrown. - * @param {string} params.transactionId - Transaction ID for staging the operation. + * @param {number | null} params.max - Maximum value for the attribute. If the current value is greater than this value, an error will be thrown. + * @param {string | null} params.transactionId - Transaction ID for staging the operation. * @throws {AppwriteException} * @returns {Promise} * @deprecated This API has been deprecated since 1.8.0. Please use `TablesDB.incrementRowColumn` instead. @@ -1589,8 +1811,8 @@ export class Databases extends Service { documentId: string; attribute: string; value?: number; - max?: number; - transactionId?: string; + max?: number | null; + transactionId?: string | null; }): Promise; /** * Increment a specific attribute of a document by a given value. @@ -1600,8 +1822,8 @@ export class Databases extends Service { * @param {string} documentId - Document ID. * @param {string} attribute - Attribute key. * @param {number} value - Value to increment the attribute by. The value must be a number. - * @param {number} max - Maximum value for the attribute. If the current value is greater than this value, an error will be thrown. - * @param {string} transactionId - Transaction ID for staging the operation. + * @param {number | null} max - Maximum value for the attribute. If the current value is greater than this value, an error will be thrown. + * @param {string | null} transactionId - Transaction ID for staging the operation. * @throws {AppwriteException} * @returns {Promise} * @deprecated Use the object parameter style method for a better developer experience. @@ -1614,8 +1836,8 @@ export class Databases extends Service { documentId: string, attribute: string, value?: number, - max?: number, - transactionId?: string, + max?: number | null, + transactionId?: string | null, ): Promise; incrementDocumentAttribute< Document extends Models.Document = Models.DefaultDocument, @@ -1627,11 +1849,18 @@ export class Databases extends Service { documentId: string; attribute: string; value?: number; - max?: number; - transactionId?: string; + max?: number | null; + transactionId?: string | null; } | string, - ...rest: [string?, string?, string?, number?, number?, string?] + ...rest: [ + string?, + string?, + string?, + number?, + (number | null)?, + (string | null)?, + ] ): Promise { let params: { databaseId: string; @@ -1639,8 +1868,8 @@ export class Databases extends Service { documentId: string; attribute: string; value?: number; - max?: number; - transactionId?: string; + max?: number | null; + transactionId?: string | null; }; if ( @@ -1654,8 +1883,8 @@ export class Databases extends Service { documentId: string; attribute: string; value?: number; - max?: number; - transactionId?: string; + max?: number | null; + transactionId?: string | null; }; } else { params = { @@ -1664,8 +1893,8 @@ export class Databases extends Service { documentId: rest[1] as string, attribute: rest[2] as string, value: rest[3] as number, - max: rest[4] as number, - transactionId: rest[5] as string, + max: rest[4] as number | null, + transactionId: rest[5] as string | null, }; } @@ -1725,7 +1954,7 @@ export class Databases extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'patch', uri, { @@ -1735,5 +1964,23 @@ export class Databases extends Service { }, apiPayload, ); + const defaults = { + root: 'document', + models: { + document: { + defaults: { + $id: '', + $sequence: '', + $collectionId: '', + $databaseId: '', + $createdAt: '', + $updatedAt: '', + $permissions: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } } diff --git a/src/services/documents-db.ts b/src/services/documents-db.ts index 6f10966e..d43db5a9 100644 --- a/src/services/documents-db.ts +++ b/src/services/documents-db.ts @@ -1,5 +1,5 @@ import { Service } from '../service'; -import { AppwriteException, Client } from '../client'; +import { AppwriteException, Client, applyDefaults } from '../client'; import type { Models } from '../models'; import type { Payload } from '../client'; @@ -71,7 +71,7 @@ export class DocumentsDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -80,6 +80,34 @@ export class DocumentsDB extends Service { }, apiPayload, ); + const defaults = { + root: 'transactionList', + models: { + transactionList: { + defaults: { + total: 0, + transactions: [], + }, + properties: { + transactions: { + items: 'transaction', + }, + }, + }, + transaction: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + status: 'pending', + operations: 0, + expiresAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -127,7 +155,7 @@ export class DocumentsDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -137,6 +165,23 @@ export class DocumentsDB extends Service { }, apiPayload, ); + const defaults = { + root: 'transaction', + models: { + transaction: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + status: 'pending', + operations: 0, + expiresAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -190,7 +235,7 @@ export class DocumentsDB extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -199,6 +244,23 @@ export class DocumentsDB extends Service { }, apiPayload, ); + const defaults = { + root: 'transaction', + models: { + transaction: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + status: 'pending', + operations: 0, + expiresAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -285,7 +347,7 @@ export class DocumentsDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'patch', uri, { @@ -295,6 +357,23 @@ export class DocumentsDB extends Service { }, apiPayload, ); + const defaults = { + root: 'transaction', + models: { + transaction: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + status: 'pending', + operations: 0, + expiresAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -427,7 +506,7 @@ export class DocumentsDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -437,6 +516,23 @@ export class DocumentsDB extends Service { }, apiPayload, ); + const defaults = { + root: 'transaction', + models: { + transaction: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + status: 'pending', + operations: 0, + expiresAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -573,7 +669,7 @@ export class DocumentsDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -582,6 +678,35 @@ export class DocumentsDB extends Service { }, apiPayload, ); + const defaults = { + root: 'documentList', + models: { + documentList: { + defaults: { + total: 0, + documents: [], + }, + properties: { + documents: { + items: 'document', + }, + }, + }, + document: { + defaults: { + $id: '', + $sequence: '', + $collectionId: '', + $databaseId: '', + $createdAt: '', + $updatedAt: '', + $permissions: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -753,7 +878,7 @@ export class DocumentsDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -763,6 +888,24 @@ export class DocumentsDB extends Service { }, apiPayload, ); + const defaults = { + root: 'document', + models: { + document: { + defaults: { + $id: '', + $sequence: '', + $collectionId: '', + $databaseId: '', + $createdAt: '', + $updatedAt: '', + $permissions: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -879,7 +1022,7 @@ export class DocumentsDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -889,6 +1032,35 @@ export class DocumentsDB extends Service { }, apiPayload, ); + const defaults = { + root: 'documentList', + models: { + documentList: { + defaults: { + total: 0, + documents: [], + }, + properties: { + documents: { + items: 'document', + }, + }, + }, + document: { + defaults: { + $id: '', + $sequence: '', + $collectionId: '', + $databaseId: '', + $createdAt: '', + $updatedAt: '', + $permissions: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1018,7 +1190,7 @@ export class DocumentsDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -1027,6 +1199,24 @@ export class DocumentsDB extends Service { }, apiPayload, ); + const defaults = { + root: 'document', + models: { + document: { + defaults: { + $id: '', + $sequence: '', + $collectionId: '', + $databaseId: '', + $createdAt: '', + $updatedAt: '', + $permissions: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1196,7 +1386,7 @@ export class DocumentsDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'put', uri, { @@ -1206,6 +1396,24 @@ export class DocumentsDB extends Service { }, apiPayload, ); + const defaults = { + root: 'document', + models: { + document: { + defaults: { + $id: '', + $sequence: '', + $collectionId: '', + $databaseId: '', + $createdAt: '', + $updatedAt: '', + $permissions: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1375,7 +1583,7 @@ export class DocumentsDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'patch', uri, { @@ -1385,6 +1593,24 @@ export class DocumentsDB extends Service { }, apiPayload, ); + const defaults = { + root: 'document', + models: { + document: { + defaults: { + $id: '', + $sequence: '', + $collectionId: '', + $databaseId: '', + $createdAt: '', + $updatedAt: '', + $permissions: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1668,7 +1894,7 @@ export class DocumentsDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'patch', uri, { @@ -1678,6 +1904,24 @@ export class DocumentsDB extends Service { }, apiPayload, ); + const defaults = { + root: 'document', + models: { + document: { + defaults: { + $id: '', + $sequence: '', + $collectionId: '', + $databaseId: '', + $createdAt: '', + $updatedAt: '', + $permissions: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1837,7 +2081,7 @@ export class DocumentsDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'patch', uri, { @@ -1847,5 +2091,23 @@ export class DocumentsDB extends Service { }, apiPayload, ); + const defaults = { + root: 'document', + models: { + document: { + defaults: { + $id: '', + $sequence: '', + $collectionId: '', + $databaseId: '', + $createdAt: '', + $updatedAt: '', + $permissions: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } } diff --git a/src/services/functions.ts b/src/services/functions.ts index 230ffe70..db74d35c 100644 --- a/src/services/functions.ts +++ b/src/services/functions.ts @@ -1,5 +1,5 @@ import { Service } from '../service'; -import { AppwriteException, Client } from '../client'; +import { AppwriteException, Client, applyDefaults } from '../client'; import type { Models } from '../models'; import type { Payload } from '../client'; @@ -89,7 +89,7 @@ export class Functions extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -98,6 +98,58 @@ export class Functions extends Service { }, apiPayload, ); + const defaults = { + root: 'executionList', + models: { + executionList: { + defaults: { + total: 0, + executions: [], + }, + properties: { + executions: { + items: 'execution', + }, + }, + }, + execution: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + $permissions: [], + resourceId: '', + resourceType: 'functions', + deploymentId: '', + requestMethod: '', + requestPath: '', + requestHeaders: [], + responseStatusCode: 0, + responseBody: '', + responseHeaders: [], + logs: '', + errors: '', + duration: 0, + }, + properties: { + requestHeaders: { + items: 'headers', + }, + responseHeaders: { + items: 'headers', + }, + }, + }, + headers: { + defaults: { + name: '', + value: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -109,7 +161,7 @@ export class Functions extends Service { * @param {string} params.xpath - HTTP path of execution. Path can include query params. Default value is / * @param {ExecutionMethod} params.method - HTTP method of execution. Default value is POST. * @param {object} params.headers - HTTP headers of execution. Defaults to empty. - * @param {string} params.scheduledAt - Scheduled execution time in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format. DateTime value must be in future with precision in minutes. + * @param {string | null} params.scheduledAt - Scheduled execution time in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format. DateTime value must be in future with precision in minutes. * @throws {AppwriteException} * @returns {Promise} */ @@ -120,7 +172,7 @@ export class Functions extends Service { xpath?: string; method?: ExecutionMethod; headers?: object; - scheduledAt?: string; + scheduledAt?: string | null; }): Promise; /** * Trigger a function execution. The returned object will return you the current execution status. You can ping the `Get Execution` endpoint to get updates on the current execution status. Once this endpoint is called, your function execution process will start asynchronously. @@ -131,7 +183,7 @@ export class Functions extends Service { * @param {string} xpath - HTTP path of execution. Path can include query params. Default value is / * @param {ExecutionMethod} method - HTTP method of execution. Default value is POST. * @param {object} headers - HTTP headers of execution. Defaults to empty. - * @param {string} scheduledAt - Scheduled execution time in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format. DateTime value must be in future with precision in minutes. + * @param {string | null} scheduledAt - Scheduled execution time in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format. DateTime value must be in future with precision in minutes. * @throws {AppwriteException} * @returns {Promise} * @deprecated Use the object parameter style method for a better developer experience. @@ -143,7 +195,7 @@ export class Functions extends Service { xpath?: string, method?: ExecutionMethod, headers?: object, - scheduledAt?: string, + scheduledAt?: string | null, ): Promise; createExecution( paramsOrFirst: @@ -154,7 +206,7 @@ export class Functions extends Service { xpath?: string; method?: ExecutionMethod; headers?: object; - scheduledAt?: string; + scheduledAt?: string | null; } | string, ...rest: [ @@ -163,7 +215,7 @@ export class Functions extends Service { string?, ExecutionMethod?, object?, - string?, + (string | null)?, ] ): Promise { let params: { @@ -173,7 +225,7 @@ export class Functions extends Service { xpath?: string; method?: ExecutionMethod; headers?: object; - scheduledAt?: string; + scheduledAt?: string | null; }; if ( @@ -188,7 +240,7 @@ export class Functions extends Service { xpath?: string; method?: ExecutionMethod; headers?: object; - scheduledAt?: string; + scheduledAt?: string | null; }; } else { params = { @@ -198,7 +250,7 @@ export class Functions extends Service { xpath: rest[2] as string, method: rest[3] as ExecutionMethod, headers: rest[4] as object, - scheduledAt: rest[5] as string, + scheduledAt: rest[5] as string | null, }; } @@ -247,7 +299,7 @@ export class Functions extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -257,6 +309,47 @@ export class Functions extends Service { }, apiPayload, ); + const defaults = { + root: 'execution', + models: { + execution: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + $permissions: [], + resourceId: '', + resourceType: 'functions', + deploymentId: '', + requestMethod: '', + requestPath: '', + requestHeaders: [], + responseStatusCode: 0, + responseBody: '', + responseHeaders: [], + logs: '', + errors: '', + duration: 0, + }, + properties: { + requestHeaders: { + items: 'headers', + }, + responseHeaders: { + items: 'headers', + }, + }, + }, + headers: { + defaults: { + name: '', + value: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -327,7 +420,7 @@ export class Functions extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -336,5 +429,46 @@ export class Functions extends Service { }, apiPayload, ); + const defaults = { + root: 'execution', + models: { + execution: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + $permissions: [], + resourceId: '', + resourceType: 'functions', + deploymentId: '', + requestMethod: '', + requestPath: '', + requestHeaders: [], + responseStatusCode: 0, + responseBody: '', + responseHeaders: [], + logs: '', + errors: '', + duration: 0, + }, + properties: { + requestHeaders: { + items: 'headers', + }, + responseHeaders: { + items: 'headers', + }, + }, + }, + headers: { + defaults: { + name: '', + value: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } } diff --git a/src/services/locale.ts b/src/services/locale.ts index ce9e92b2..7ab026b5 100644 --- a/src/services/locale.ts +++ b/src/services/locale.ts @@ -1,5 +1,5 @@ import { Service } from '../service'; -import { Client } from '../client'; +import { Client, applyDefaults } from '../client'; import type { Models } from '../models'; import type { Payload } from '../client'; @@ -21,7 +21,7 @@ export class Locale extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -30,6 +30,24 @@ export class Locale extends Service { }, apiPayload, ); + const defaults = { + root: 'locale', + models: { + locale: { + defaults: { + ip: '', + countryCode: '', + country: '', + continentCode: '', + continent: '', + eu: false, + currency: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -77,7 +95,7 @@ export class Locale extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -86,6 +104,30 @@ export class Locale extends Service { }, apiPayload, ); + const defaults = { + root: 'localeCodeList', + models: { + localeCodeList: { + defaults: { + total: 0, + localeCodes: [], + }, + properties: { + localeCodes: { + items: 'localeCode', + }, + }, + }, + localeCode: { + defaults: { + code: '', + name: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -133,7 +175,7 @@ export class Locale extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -142,6 +184,30 @@ export class Locale extends Service { }, apiPayload, ); + const defaults = { + root: 'continentList', + models: { + continentList: { + defaults: { + total: 0, + continents: [], + }, + properties: { + continents: { + items: 'continent', + }, + }, + }, + continent: { + defaults: { + name: '', + code: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -189,7 +255,7 @@ export class Locale extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -198,6 +264,30 @@ export class Locale extends Service { }, apiPayload, ); + const defaults = { + root: 'countryList', + models: { + countryList: { + defaults: { + total: 0, + countries: [], + }, + properties: { + countries: { + items: 'country', + }, + }, + }, + country: { + defaults: { + name: '', + code: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -245,7 +335,7 @@ export class Locale extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -254,6 +344,30 @@ export class Locale extends Service { }, apiPayload, ); + const defaults = { + root: 'countryList', + models: { + countryList: { + defaults: { + total: 0, + countries: [], + }, + properties: { + countries: { + items: 'country', + }, + }, + }, + country: { + defaults: { + name: '', + code: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -303,7 +417,7 @@ export class Locale extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -312,6 +426,31 @@ export class Locale extends Service { }, apiPayload, ); + const defaults = { + root: 'phoneList', + models: { + phoneList: { + defaults: { + total: 0, + phones: [], + }, + properties: { + phones: { + items: 'phone', + }, + }, + }, + phone: { + defaults: { + code: '', + countryCode: '', + countryName: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -359,7 +498,7 @@ export class Locale extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -368,6 +507,35 @@ export class Locale extends Service { }, apiPayload, ); + const defaults = { + root: 'currencyList', + models: { + currencyList: { + defaults: { + total: 0, + currencies: [], + }, + properties: { + currencies: { + items: 'currency', + }, + }, + }, + currency: { + defaults: { + symbol: '', + name: '', + symbolNative: '', + decimalDigits: 0, + rounding: 0, + code: '', + namePlural: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -415,7 +583,7 @@ export class Locale extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -424,5 +592,30 @@ export class Locale extends Service { }, apiPayload, ); + const defaults = { + root: 'languageList', + models: { + languageList: { + defaults: { + total: 0, + languages: [], + }, + properties: { + languages: { + items: 'language', + }, + }, + }, + language: { + defaults: { + name: '', + code: '', + nativeName: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } } diff --git a/src/services/messaging.ts b/src/services/messaging.ts index 33e94c19..b1939ddf 100644 --- a/src/services/messaging.ts +++ b/src/services/messaging.ts @@ -1,5 +1,5 @@ import { Service } from '../service'; -import { AppwriteException, Client } from '../client'; +import { AppwriteException, Client, applyDefaults } from '../client'; import type { Models } from '../models'; import type { Payload } from '../client'; @@ -100,7 +100,7 @@ export class Messaging extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -110,6 +110,25 @@ export class Messaging extends Service { }, apiPayload, ); + const defaults = { + root: 'subscriber', + models: { + subscriber: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + targetId: '', + userId: '', + userName: '', + topicId: '', + providerType: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** diff --git a/src/services/oauth-2.ts b/src/services/oauth-2.ts index 1920bc1a..185fad00 100644 --- a/src/services/oauth-2.ts +++ b/src/services/oauth-2.ts @@ -1,5 +1,5 @@ import { Service } from '../service'; -import { AppwriteException, Client } from '../client'; +import { AppwriteException, Client, applyDefaults } from '../client'; import type { Models } from '../models'; import type { Payload } from '../client'; @@ -96,7 +96,7 @@ export class Oauth2 extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -105,6 +105,18 @@ export class Oauth2 extends Service { }, apiPayload, ); + const defaults = { + root: 'oauth2Approve', + models: { + oauth2Approve: { + defaults: { + redirectUrl: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -121,7 +133,7 @@ export class Oauth2 extends Service { * @param {string} params.prompt - OIDC prompt parameter for customization of consent screen. Space-separated list of: none, login, consent, select_account. * @param {number} params.maxAge - OIDC max_age paraleter for customization of consent screen. Maximum allowable elapsed time in seconds since the user last authenticated. If exceeded, re-authentication is required. * @param {string} params.authorizationDetails - Rich authorization request. JSON array of objects, each with a `type` and project-defined fields - * @param {string} params.resource - RFC 8707 resource indicator URI or URI list. Each value must be an absolute URI without a fragment. + * @param {string[]} params.resource - RFC 8707 resource indicator URI or URI list. Each value must be an absolute URI without a fragment. * @param {string} params.audience - Compatibility alias for a single OAuth2 resource indicator URI. * @param {string} params.requestUri - OAuth2 authorization request handle returned by the pushed authorization request endpoint. * @throws {AppwriteException} @@ -139,7 +151,7 @@ export class Oauth2 extends Service { prompt?: string; maxAge?: number; authorizationDetails?: string; - resource?: string; + resource?: string[]; audience?: string; requestUri?: string; }): Promise; @@ -157,7 +169,7 @@ export class Oauth2 extends Service { * @param {string} prompt - OIDC prompt parameter for customization of consent screen. Space-separated list of: none, login, consent, select_account. * @param {number} maxAge - OIDC max_age paraleter for customization of consent screen. Maximum allowable elapsed time in seconds since the user last authenticated. If exceeded, re-authentication is required. * @param {string} authorizationDetails - Rich authorization request. JSON array of objects, each with a `type` and project-defined fields - * @param {string} resource - RFC 8707 resource indicator URI or URI list. Each value must be an absolute URI without a fragment. + * @param {string[]} resource - RFC 8707 resource indicator URI or URI list. Each value must be an absolute URI without a fragment. * @param {string} audience - Compatibility alias for a single OAuth2 resource indicator URI. * @param {string} requestUri - OAuth2 authorization request handle returned by the pushed authorization request endpoint. * @throws {AppwriteException} @@ -176,7 +188,7 @@ export class Oauth2 extends Service { prompt?: string, maxAge?: number, authorizationDetails?: string, - resource?: string, + resource?: string[], audience?: string, requestUri?: string, ): Promise; @@ -194,7 +206,7 @@ export class Oauth2 extends Service { prompt?: string; maxAge?: number; authorizationDetails?: string; - resource?: string; + resource?: string[]; audience?: string; requestUri?: string; } @@ -210,7 +222,7 @@ export class Oauth2 extends Service { string?, number?, string?, - string?, + string[]?, string?, string?, ] @@ -227,7 +239,7 @@ export class Oauth2 extends Service { prompt?: string; maxAge?: number; authorizationDetails?: string; - resource?: string; + resource?: string[]; audience?: string; requestUri?: string; }; @@ -250,7 +262,7 @@ export class Oauth2 extends Service { prompt?: string; maxAge?: number; authorizationDetails?: string; - resource?: string; + resource?: string[]; audience?: string; requestUri?: string; }; @@ -267,7 +279,7 @@ export class Oauth2 extends Service { prompt: rest[7] as string, maxAge: rest[8] as number, authorizationDetails: rest[9] as string, - resource: rest[10] as string, + resource: rest[10] as string[], audience: rest[11] as string, requestUri: rest[12] as string, }; @@ -351,7 +363,7 @@ export class Oauth2 extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -359,6 +371,19 @@ export class Oauth2 extends Service { }, apiPayload, ); + const defaults = { + root: 'oauth2Authorize', + models: { + oauth2Authorize: { + defaults: { + grantId: '', + redirectUrl: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -373,9 +398,9 @@ export class Oauth2 extends Service { * @param {string} params.codeChallenge - PKCE code challenge. Required when OAuth2 app is public. * @param {string} params.codeChallengeMethod - PKCE code challenge method. Required when OAuth2 app is public. * @param {string} params.prompt - OIDC prompt parameter for customization of consent screen. Space-separated list of: none, login, consent, select_account. - * @param {number} params.maxAge - OIDC max_age paraleter for customization of consent screen. Maximum allowable elapsed time in seconds since the user last authenticated. If exceeded, re-authentication is required. + * @param {number | null} params.maxAge - OIDC max_age paraleter for customization of consent screen. Maximum allowable elapsed time in seconds since the user last authenticated. If exceeded, re-authentication is required. * @param {string} params.authorizationDetails - Rich authorization request. JSON array of objects, each with a `type` and project-defined fields - * @param {string} params.resource - RFC 8707 resource indicator URI or URI list. Each value must be an absolute URI without a fragment. + * @param {string[]} params.resource - RFC 8707 resource indicator URI or URI list. Each value must be an absolute URI without a fragment. * @param {string} params.audience - Compatibility alias for a single OAuth2 resource indicator URI. * @param {string} params.requestUri - OAuth2 authorization request handle returned by the pushed authorization request endpoint. * @throws {AppwriteException} @@ -391,9 +416,9 @@ export class Oauth2 extends Service { codeChallenge?: string; codeChallengeMethod?: string; prompt?: string; - maxAge?: number; + maxAge?: number | null; authorizationDetails?: string; - resource?: string; + resource?: string[]; audience?: string; requestUri?: string; }): Promise; @@ -409,9 +434,9 @@ export class Oauth2 extends Service { * @param {string} codeChallenge - PKCE code challenge. Required when OAuth2 app is public. * @param {string} codeChallengeMethod - PKCE code challenge method. Required when OAuth2 app is public. * @param {string} prompt - OIDC prompt parameter for customization of consent screen. Space-separated list of: none, login, consent, select_account. - * @param {number} maxAge - OIDC max_age paraleter for customization of consent screen. Maximum allowable elapsed time in seconds since the user last authenticated. If exceeded, re-authentication is required. + * @param {number | null} maxAge - OIDC max_age paraleter for customization of consent screen. Maximum allowable elapsed time in seconds since the user last authenticated. If exceeded, re-authentication is required. * @param {string} authorizationDetails - Rich authorization request. JSON array of objects, each with a `type` and project-defined fields - * @param {string} resource - RFC 8707 resource indicator URI or URI list. Each value must be an absolute URI without a fragment. + * @param {string[]} resource - RFC 8707 resource indicator URI or URI list. Each value must be an absolute URI without a fragment. * @param {string} audience - Compatibility alias for a single OAuth2 resource indicator URI. * @param {string} requestUri - OAuth2 authorization request handle returned by the pushed authorization request endpoint. * @throws {AppwriteException} @@ -428,9 +453,9 @@ export class Oauth2 extends Service { codeChallenge?: string, codeChallengeMethod?: string, prompt?: string, - maxAge?: number, + maxAge?: number | null, authorizationDetails?: string, - resource?: string, + resource?: string[], audience?: string, requestUri?: string, ): Promise; @@ -446,9 +471,9 @@ export class Oauth2 extends Service { codeChallenge?: string; codeChallengeMethod?: string; prompt?: string; - maxAge?: number; + maxAge?: number | null; authorizationDetails?: string; - resource?: string; + resource?: string[]; audience?: string; requestUri?: string; } @@ -462,9 +487,9 @@ export class Oauth2 extends Service { string?, string?, string?, - number?, - string?, + (number | null)?, string?, + string[]?, string?, string?, ] @@ -479,9 +504,9 @@ export class Oauth2 extends Service { codeChallenge?: string; codeChallengeMethod?: string; prompt?: string; - maxAge?: number; + maxAge?: number | null; authorizationDetails?: string; - resource?: string; + resource?: string[]; audience?: string; requestUri?: string; }; @@ -502,9 +527,9 @@ export class Oauth2 extends Service { codeChallenge?: string; codeChallengeMethod?: string; prompt?: string; - maxAge?: number; + maxAge?: number | null; authorizationDetails?: string; - resource?: string; + resource?: string[]; audience?: string; requestUri?: string; }; @@ -519,9 +544,9 @@ export class Oauth2 extends Service { codeChallenge: rest[5] as string, codeChallengeMethod: rest[6] as string, prompt: rest[7] as string, - maxAge: rest[8] as number, + maxAge: rest[8] as number | null, authorizationDetails: rest[9] as string, - resource: rest[10] as string, + resource: rest[10] as string[], audience: rest[11] as string, requestUri: rest[12] as string, }; @@ -605,7 +630,7 @@ export class Oauth2 extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -614,6 +639,19 @@ export class Oauth2 extends Service { }, apiPayload, ); + const defaults = { + root: 'oauth2Authorize', + models: { + oauth2Authorize: { + defaults: { + grantId: '', + redirectUrl: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -622,7 +660,7 @@ export class Oauth2 extends Service { * @param {string} params.clientId - OAuth2 client ID. Either a registered app ID or an HTTPS client ID metadata document URL. * @param {string} params.scope - Space-separated OAuth2 scopes. Can include project scopes, and built-in scopes: `openid`, `email`, `profile`. * @param {string} params.authorizationDetails - Rich authorization request. JSON array of objects, each with a `type` and project-defined fields - * @param {string} params.resource - RFC 8707 resource indicator URI or URI list. Each value must be an absolute URI without a fragment. + * @param {string[]} params.resource - RFC 8707 resource indicator URI or URI list. Each value must be an absolute URI without a fragment. * @param {string} params.audience - Compatibility alias for a single OAuth2 resource indicator URI. * @throws {AppwriteException} * @returns {Promise} @@ -631,7 +669,7 @@ export class Oauth2 extends Service { clientId?: string; scope?: string; authorizationDetails?: string; - resource?: string; + resource?: string[]; audience?: string; }): Promise; /** @@ -640,7 +678,7 @@ export class Oauth2 extends Service { * @param {string} clientId - OAuth2 client ID. Either a registered app ID or an HTTPS client ID metadata document URL. * @param {string} scope - Space-separated OAuth2 scopes. Can include project scopes, and built-in scopes: `openid`, `email`, `profile`. * @param {string} authorizationDetails - Rich authorization request. JSON array of objects, each with a `type` and project-defined fields - * @param {string} resource - RFC 8707 resource indicator URI or URI list. Each value must be an absolute URI without a fragment. + * @param {string[]} resource - RFC 8707 resource indicator URI or URI list. Each value must be an absolute URI without a fragment. * @param {string} audience - Compatibility alias for a single OAuth2 resource indicator URI. * @throws {AppwriteException} * @returns {Promise} @@ -650,7 +688,7 @@ export class Oauth2 extends Service { clientId?: string, scope?: string, authorizationDetails?: string, - resource?: string, + resource?: string[], audience?: string, ): Promise; createDeviceAuthorization( @@ -659,17 +697,17 @@ export class Oauth2 extends Service { clientId?: string; scope?: string; authorizationDetails?: string; - resource?: string; + resource?: string[]; audience?: string; } | string, - ...rest: [string?, string?, string?, string?] + ...rest: [string?, string?, string[]?, string?] ): Promise { let params: { clientId?: string; scope?: string; authorizationDetails?: string; - resource?: string; + resource?: string[]; audience?: string; }; @@ -683,7 +721,7 @@ export class Oauth2 extends Service { clientId?: string; scope?: string; authorizationDetails?: string; - resource?: string; + resource?: string[]; audience?: string; }; } else { @@ -691,7 +729,7 @@ export class Oauth2 extends Service { clientId: paramsOrFirst as string, scope: rest[0] as string, authorizationDetails: rest[1] as string, - resource: rest[2] as string, + resource: rest[2] as string[], audience: rest[3] as string, }; } @@ -729,7 +767,7 @@ export class Oauth2 extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -738,6 +776,23 @@ export class Oauth2 extends Service { }, apiPayload, ); + const defaults = { + root: 'oauth2DeviceAuthorization', + models: { + oauth2DeviceAuthorization: { + defaults: { + device_code: '', + user_code: '', + verification_uri: '', + verification_uri_complete: '', + expires_in: 0, + interval: 0, + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -793,7 +848,7 @@ export class Oauth2 extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -802,6 +857,29 @@ export class Oauth2 extends Service { }, apiPayload, ); + const defaults = { + root: 'oauth2Grant', + models: { + oauth2Grant: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + userId: '', + appId: '', + scopes: [], + resources: [], + authorizationDetails: '[]', + prompt: '', + redirectUri: '', + authTime: 0, + expire: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -855,7 +933,7 @@ export class Oauth2 extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -863,6 +941,29 @@ export class Oauth2 extends Service { }, apiPayload, ); + const defaults = { + root: 'oauth2Grant', + models: { + oauth2Grant: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + userId: '', + appId: '', + scopes: [], + resources: [], + authorizationDetails: '[]', + prompt: '', + redirectUri: '', + authTime: 0, + expire: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1216,7 +1317,7 @@ export class Oauth2 extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -1224,6 +1325,29 @@ export class Oauth2 extends Service { }, apiPayload, ); + const defaults = { + root: 'oauth2OrganizationList', + models: { + oauth2OrganizationList: { + defaults: { + total: 0, + organizations: [], + }, + properties: { + organizations: { + items: 'oauth2Organization', + }, + }, + }, + oauth2Organization: { + defaults: { + $id: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1238,9 +1362,9 @@ export class Oauth2 extends Service { * @param {string} params.codeChallenge - PKCE code challenge. Required when OAuth2 app is public. * @param {string} params.codeChallengeMethod - PKCE code challenge method. Required when OAuth2 app is public. * @param {string} params.prompt - OIDC prompt parameter for customization of consent screen. Space-separated list of: none, login, consent, select_account. - * @param {number} params.maxAge - OIDC max_age parameter for customization of consent screen. + * @param {number | null} params.maxAge - OIDC max_age parameter for customization of consent screen. * @param {string} params.authorizationDetails - Rich authorization request. JSON array of objects, each with a `type` and project-defined fields - * @param {string} params.resource - RFC 8707 resource indicator URI or URI list. Each value must be an absolute URI without a fragment. + * @param {string[]} params.resource - RFC 8707 resource indicator URI or URI list. Each value must be an absolute URI without a fragment. * @param {string} params.audience - Compatibility alias for a single OAuth2 resource indicator URI. * @throws {AppwriteException} * @returns {Promise} @@ -1255,9 +1379,9 @@ export class Oauth2 extends Service { codeChallenge?: string; codeChallengeMethod?: string; prompt?: string; - maxAge?: number; + maxAge?: number | null; authorizationDetails?: string; - resource?: string; + resource?: string[]; audience?: string; }): Promise; /** @@ -1272,9 +1396,9 @@ export class Oauth2 extends Service { * @param {string} codeChallenge - PKCE code challenge. Required when OAuth2 app is public. * @param {string} codeChallengeMethod - PKCE code challenge method. Required when OAuth2 app is public. * @param {string} prompt - OIDC prompt parameter for customization of consent screen. Space-separated list of: none, login, consent, select_account. - * @param {number} maxAge - OIDC max_age parameter for customization of consent screen. + * @param {number | null} maxAge - OIDC max_age parameter for customization of consent screen. * @param {string} authorizationDetails - Rich authorization request. JSON array of objects, each with a `type` and project-defined fields - * @param {string} resource - RFC 8707 resource indicator URI or URI list. Each value must be an absolute URI without a fragment. + * @param {string[]} resource - RFC 8707 resource indicator URI or URI list. Each value must be an absolute URI without a fragment. * @param {string} audience - Compatibility alias for a single OAuth2 resource indicator URI. * @throws {AppwriteException} * @returns {Promise} @@ -1290,9 +1414,9 @@ export class Oauth2 extends Service { codeChallenge?: string, codeChallengeMethod?: string, prompt?: string, - maxAge?: number, + maxAge?: number | null, authorizationDetails?: string, - resource?: string, + resource?: string[], audience?: string, ): Promise; createPAR( @@ -1307,9 +1431,9 @@ export class Oauth2 extends Service { codeChallenge?: string; codeChallengeMethod?: string; prompt?: string; - maxAge?: number; + maxAge?: number | null; authorizationDetails?: string; - resource?: string; + resource?: string[]; audience?: string; } | string, @@ -1322,9 +1446,9 @@ export class Oauth2 extends Service { string?, string?, string?, - number?, - string?, + (number | null)?, string?, + string[]?, string?, ] ): Promise { @@ -1338,9 +1462,9 @@ export class Oauth2 extends Service { codeChallenge?: string; codeChallengeMethod?: string; prompt?: string; - maxAge?: number; + maxAge?: number | null; authorizationDetails?: string; - resource?: string; + resource?: string[]; audience?: string; }; @@ -1359,9 +1483,9 @@ export class Oauth2 extends Service { codeChallenge?: string; codeChallengeMethod?: string; prompt?: string; - maxAge?: number; + maxAge?: number | null; authorizationDetails?: string; - resource?: string; + resource?: string[]; audience?: string; }; } else { @@ -1375,9 +1499,9 @@ export class Oauth2 extends Service { codeChallenge: rest[5] as string, codeChallengeMethod: rest[6] as string, prompt: rest[7] as string, - maxAge: rest[8] as number, + maxAge: rest[8] as number | null, authorizationDetails: rest[9] as string, - resource: rest[10] as string, + resource: rest[10] as string[], audience: rest[11] as string, }; } @@ -1473,7 +1597,7 @@ export class Oauth2 extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -1482,6 +1606,19 @@ export class Oauth2 extends Service { }, apiPayload, ); + const defaults = { + root: 'oauth2PAR', + models: { + oauth2PAR: { + defaults: { + request_uri: '', + expires_in: 0, + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1562,7 +1699,7 @@ export class Oauth2 extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -1570,6 +1707,31 @@ export class Oauth2 extends Service { }, apiPayload, ); + const defaults = { + root: 'oauth2ProjectList', + models: { + oauth2ProjectList: { + defaults: { + total: 0, + projects: [], + }, + properties: { + projects: { + items: 'oauth2Project', + }, + }, + }, + oauth2Project: { + defaults: { + $id: '', + region: '', + endpoint: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1625,7 +1787,7 @@ export class Oauth2 extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -1634,6 +1796,18 @@ export class Oauth2 extends Service { }, apiPayload, ); + const defaults = { + root: 'oauth2Reject', + models: { + oauth2Reject: { + defaults: { + redirectUrl: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1761,7 +1935,7 @@ export class Oauth2 extends Service { * @param {string} params.clientSecret - OAuth2 client secret. Required for confidential apps. * @param {string} params.codeVerifier - PKCE code verifier. Required for public apps. * @param {string} params.redirectUri - Redirect URI. Required for `authorization_code` grant type. - * @param {string} params.resource - RFC 8707 resource indicator URI or URI list. Each value must be an absolute URI without a fragment. + * @param {string[]} params.resource - RFC 8707 resource indicator URI or URI list. Each value must be an absolute URI without a fragment. * @param {string} params.audience - Compatibility alias for a single OAuth2 resource indicator URI. * @throws {AppwriteException} * @returns {Promise} @@ -1775,7 +1949,7 @@ export class Oauth2 extends Service { clientSecret?: string; codeVerifier?: string; redirectUri?: string; - resource?: string; + resource?: string[]; audience?: string; }): Promise; /** @@ -1789,7 +1963,7 @@ export class Oauth2 extends Service { * @param {string} clientSecret - OAuth2 client secret. Required for confidential apps. * @param {string} codeVerifier - PKCE code verifier. Required for public apps. * @param {string} redirectUri - Redirect URI. Required for `authorization_code` grant type. - * @param {string} resource - RFC 8707 resource indicator URI or URI list. Each value must be an absolute URI without a fragment. + * @param {string[]} resource - RFC 8707 resource indicator URI or URI list. Each value must be an absolute URI without a fragment. * @param {string} audience - Compatibility alias for a single OAuth2 resource indicator URI. * @throws {AppwriteException} * @returns {Promise} @@ -1804,7 +1978,7 @@ export class Oauth2 extends Service { clientSecret?: string, codeVerifier?: string, redirectUri?: string, - resource?: string, + resource?: string[], audience?: string, ): Promise; createToken( @@ -1818,7 +1992,7 @@ export class Oauth2 extends Service { clientSecret?: string; codeVerifier?: string; redirectUri?: string; - resource?: string; + resource?: string[]; audience?: string; } | string, @@ -1830,7 +2004,7 @@ export class Oauth2 extends Service { string?, string?, string?, - string?, + string[]?, string?, ] ): Promise { @@ -1843,7 +2017,7 @@ export class Oauth2 extends Service { clientSecret?: string; codeVerifier?: string; redirectUri?: string; - resource?: string; + resource?: string[]; audience?: string; }; @@ -1861,7 +2035,7 @@ export class Oauth2 extends Service { clientSecret?: string; codeVerifier?: string; redirectUri?: string; - resource?: string; + resource?: string[]; audience?: string; }; } else { @@ -1874,7 +2048,7 @@ export class Oauth2 extends Service { clientSecret: rest[4] as string, codeVerifier: rest[5] as string, redirectUri: rest[6] as string, - resource: rest[7] as string, + resource: rest[7] as string[], audience: rest[8] as string, }; } @@ -1943,7 +2117,7 @@ export class Oauth2 extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -1952,5 +2126,21 @@ export class Oauth2 extends Service { }, apiPayload, ); + const defaults = { + root: 'oauth2Token', + models: { + oauth2Token: { + defaults: { + access_token: '', + token_type: 'Bearer', + expires_in: 0, + refresh_token: '', + scope: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } } diff --git a/src/services/organization.ts b/src/services/organization.ts index 3542965f..4ec51e57 100644 --- a/src/services/organization.ts +++ b/src/services/organization.ts @@ -1,5 +1,5 @@ import { Service } from '../service'; -import { AppwriteException, Client } from '../client'; +import { AppwriteException, Client, applyDefaults } from '../client'; import type { Models } from '../models'; import type { Payload } from '../client'; @@ -71,7 +71,7 @@ export class Organization extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -80,6 +80,37 @@ export class Organization extends Service { }, apiPayload, ); + const defaults = { + root: 'appInstallationList', + models: { + appInstallationList: { + defaults: { + total: 0, + installations: [], + }, + properties: { + installations: { + items: 'appInstallation', + }, + }, + }, + appInstallation: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + appId: '', + teamId: '', + scopes: [], + authorizationDetails: [], + createdById: '', + createdByName: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -149,7 +180,7 @@ export class Organization extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -159,6 +190,26 @@ export class Organization extends Service { }, apiPayload, ); + const defaults = { + root: 'appInstallation', + models: { + appInstallation: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + appId: '', + teamId: '', + scopes: [], + authorizationDetails: [], + createdById: '', + createdByName: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -212,7 +263,7 @@ export class Organization extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -221,39 +272,63 @@ export class Organization extends Service { }, apiPayload, ); + const defaults = { + root: 'appInstallation', + models: { + appInstallation: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + appId: '', + teamId: '', + scopes: [], + authorizationDetails: [], + createdById: '', + createdByName: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** * Update an app installation on the organization. Only organization members with the owner role can update installations. The installation's granted scopes are refreshed to the scopes the app currently requests; previously issued installation access tokens are revoked. * * @param {string} params.installationId - Installation unique ID. - * @param {string} params.authorizationDetails - Authorization details granted to the installation as a JSON array of objects, each with a `type` and app-defined fields. Omit to keep the current value. + * @param {string | null} params.authorizationDetails - Authorization details granted to the installation as a JSON array of objects, each with a `type` and app-defined fields. Omit to keep the current value. * @throws {AppwriteException} * @returns {Promise} */ updateInstallation(params: { installationId: string; - authorizationDetails?: string; + authorizationDetails?: string | null; }): Promise; /** * Update an app installation on the organization. Only organization members with the owner role can update installations. The installation's granted scopes are refreshed to the scopes the app currently requests; previously issued installation access tokens are revoked. * * @param {string} installationId - Installation unique ID. - * @param {string} authorizationDetails - Authorization details granted to the installation as a JSON array of objects, each with a `type` and app-defined fields. Omit to keep the current value. + * @param {string | null} authorizationDetails - Authorization details granted to the installation as a JSON array of objects, each with a `type` and app-defined fields. Omit to keep the current value. * @throws {AppwriteException} * @returns {Promise} * @deprecated Use the object parameter style method for a better developer experience. */ updateInstallation( installationId: string, - authorizationDetails?: string, + authorizationDetails?: string | null, ): Promise; updateInstallation( paramsOrFirst: - { installationId: string; authorizationDetails?: string } | string, - ...rest: [string?] + | { installationId: string; authorizationDetails?: string | null } + | string, + ...rest: [(string | null)?] ): Promise { - let params: { installationId: string; authorizationDetails?: string }; + let params: { + installationId: string; + authorizationDetails?: string | null; + }; if ( paramsOrFirst && @@ -262,12 +337,12 @@ export class Organization extends Service { ) { params = (paramsOrFirst || {}) as { installationId: string; - authorizationDetails?: string; + authorizationDetails?: string | null; }; } else { params = { installationId: paramsOrFirst as string, - authorizationDetails: rest[0] as string, + authorizationDetails: rest[0] as string | null, }; } @@ -291,7 +366,7 @@ export class Organization extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'put', uri, { @@ -301,6 +376,26 @@ export class Organization extends Service { }, apiPayload, ); + const defaults = { + root: 'appInstallation', + models: { + appInstallation: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + appId: '', + teamId: '', + scopes: [], + authorizationDetails: [], + createdById: '', + createdByName: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** diff --git a/src/services/presences.ts b/src/services/presences.ts index 5fb3a364..4cc36d8b 100644 --- a/src/services/presences.ts +++ b/src/services/presences.ts @@ -1,5 +1,5 @@ import { Service } from '../service'; -import { AppwriteException, Client } from '../client'; +import { AppwriteException, Client, applyDefaults } from '../client'; import type { Models } from '../models'; import type { Payload } from '../client'; @@ -85,7 +85,7 @@ export class Presences extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -94,6 +94,34 @@ export class Presences extends Service { }, apiPayload, ); + const defaults = { + root: 'presenceList', + models: { + presenceList: { + defaults: { + total: 0, + presences: [], + }, + properties: { + presences: { + items: 'presence', + }, + }, + }, + presence: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + $permissions: [], + userId: '', + source: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -147,7 +175,7 @@ export class Presences extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -156,6 +184,23 @@ export class Presences extends Service { }, apiPayload, ); + const defaults = { + root: 'presence', + models: { + presence: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + $permissions: [], + userId: '', + source: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -278,7 +323,7 @@ export class Presences extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'put', uri, { @@ -288,6 +333,23 @@ export class Presences extends Service { }, apiPayload, ); + const defaults = { + root: 'presence', + models: { + presence: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + $permissions: [], + userId: '', + source: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -419,7 +481,7 @@ export class Presences extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'patch', uri, { @@ -429,6 +491,23 @@ export class Presences extends Service { }, apiPayload, ); + const defaults = { + root: 'presence', + models: { + presence: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + $permissions: [], + userId: '', + source: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** diff --git a/src/services/push.ts b/src/services/push.ts deleted file mode 100644 index 880e4f4c..00000000 --- a/src/services/push.ts +++ /dev/null @@ -1,1909 +0,0 @@ -import '../lib/polyfills'; - -import { Buffer } from 'buffer'; -// The RN/Metro build of `mqtt` (dist/mqtt.esm.js, picked via the package's -// "react-native" export condition) exposes ONLY a default export — there is no -// named `MqttClient` at runtime, so importing it as a value yields undefined -// ("undefined cannot be used as a constructor"). Import the default and read the -// class off it; keep MqttClient as a type-only import (erased at runtime). -import mqtt, { - type IClientOptions, - type IConnackPacket, - type IPublishPacket, - type MqttClient, -} from 'mqtt'; -import { - AppState, - NativeEventEmitter, - NativeModules, - Platform, -} from 'react-native'; - -import { Client } from '../client'; -import { createTcpStream } from '../lib/tcp-stream'; -import { Service } from '../service'; -import type { ResolvedTopic, Topic } from '../topic'; - -/** A message delivered on a subscribed topic (the MQTT analog of a Realtime event). */ -export interface PushMessage { - topic: string; - /** The payload decoded as UTF-8 text, as it was sent. */ - data: string; - /** The raw payload, for binary messages. */ - payload: Buffer; - qos: number; -} - -export type MessageCallback = (message: PushMessage) => void | Promise; - -/** What Android background delivery can rely on; see {@link Push.backgroundStatus}. */ -export interface PushBackgroundStatus { - /** The app may schedule exact alarms (`SCHEDULE_EXACT_ALARM`, granted). */ - exactAlarms: boolean; - /** The app is exempt from battery optimisation. */ - ignoringBatteryOptimizations: boolean; - /** Foreground mode ({@link Push.setForeground}) keeps the connection open in a service. */ - foregroundService: boolean; - /** Wake-ups may be deferred by Doze, so messages can arrive late while the app is closed. */ - bestEffort: boolean; -} - -/** A background notification the user tapped. */ -export interface PushNotificationOpened { - /** The topic the message was published to. */ - topic: string; - /** The `data` sent with the message (e.g. `createPush`), parsed; `{}` when it had none. */ - data: Record; -} - -/** Per-subscription options passed to `subscribe` and `PushSubscription.update`. */ -export interface SubscribeOptions { - /** - * Keep receiving this subscription's messages while the app is backgrounded or closed, - * posting a local notification per message. Defaults to false. - * - * On Android the SDK's native module (autolinked; it does not run in Expo Go) saves the - * subscription and keeps delivering after the app is killed, the device restarts or the app - * updates, until it is unsubscribed or {@link Push.close} is called: a scheduled job and - * alarm wake the app every 15 to 60 seconds to reconnect, and the broker replays what was - * sent in between (`retry`). {@link Push.setForeground} adds a foreground service for - * immediate delivery. It reconnects with the credential saved at subscribe time, so use a - * session rather than a short-lived JWT. - * - * Elsewhere it runs the connection in a background task via - * `react-native-background-actions` and posts notifications via `expo-notifications`, - * both peer dependencies. - */ - background?: boolean; - /** Notification title for this subscription's messages. Defaults to the message topic. */ - title?: string; - /** - * Also post the background notification while the app is on screen. Defaults to false: - * while the app is visible it shows the message itself through the callback, so - * notifications are posted only while it is backgrounded or closed. - */ - notifyInForeground?: boolean; - /** - * Retry delivery of messages missed while disconnected. `true` (the default) subscribes - * at QoS 1 so the broker holds this topic's messages and redelivers them on reconnect; - * `false` uses QoS 0 (at-most-once, may be lost). Per-subscription — the connection - * always keeps its session (clean start off). - */ - retry?: boolean; -} - -/** - * Handle for a live subscription. `unsubscribe()` drops it (and closes the connection - * once the last one is gone); `update()` toggles this subscription's background/title - * without resubscribing. - */ -export interface PushSubscription { - unsubscribe(): void; - update(options: SubscribeOptions): void; -} - -type AuthMethod = 'appwrite-jwt' | 'appwrite-session' | ''; - -// Fixed connection tuning — not exposed as options. -const KEEP_ALIVE_SECONDS = 60; -const RECONNECT_PERIOD_MS = 2000; - -/** - * Appwrite native push service — the Realtime analog over an MQTT broker, without - * FCM or APNS. While the app is in the foreground the connection stays open and each - * message is handed to your callback; a subscription can also opt into background - * delivery (Android foreground service + local notification per message). - * - * The connection has no tunables — it always keeps its session (clean start off) so the - * broker can redeliver missed messages, and reliability is chosen per subscription via - * `retry`. TLS (and skipping cert verification via a `?tlsInsecure=true` query - * flag) is derived from the endpoint URL, so the whole connection is described in one - * place. `subscribe` opens the connection lazily and returns a {@link PushSubscription} - * handle (unlike Realtime's bare - * unsubscribe callable — Push carries per-subscription state). The credential is read off - * the client — set a JWT or session on it (`Client.setJWT` / `Client.setSession`), the - * same way every other service reads auth. - * - * const client = new Client().setEndpoint(...).setProject(...).setJWT(jwt); - * const push = new Push(client); - * const sub = await push.subscribe('user/123/#', (m) => - * console.log(m.topic, m.data), - * ); - * // sub.update({ background: true }); sub.unsubscribe(); - */ -export class Push extends Service { - private readonly host: string; - private readonly port: number; - private readonly tls: boolean; - private readonly tlsInsecure: boolean; - - private mqtt: MqttClient | null = null; - private connecting: Promise | null = null; - /** Set once the first CONNACK lands, so 'connect' events after are reconnects. */ - private everConnected = false; - - /** Whether the background task (outside Android) is currently running. */ - private backgroundActive = false; - - /** The native Android module that hosts background delivery; null elsewhere. */ - private readonly native: NativePush | null = nativePush(); - /** Whether the subscriptions currently live on the native module's connection. */ - private nativeActive = false; - private nativeOpen = false; - /** Bumped when the subscriptions move to the native host, superseding an open() in flight. */ - private connectionEpoch = 0; - /** Bumped by close(), so a subscribe that was waiting on a connection stops instead of reopening it. */ - private closeGeneration = 0; - private nativeEvents: { remove(): void }[] | null = null; - - private onOpenCb?: () => void; - private onCloseCb?: () => void; - private onErrorCb?: (error: Error) => void; - /** Errors already handed to onError, so one failure is reported once. */ - private reported = new WeakSet(); - /** mqtt.js connect errors mapped to the error handed out for them (see connectError). */ - private connectErrors = new WeakMap(); - /** True while the first connect is in flight: its errors go to the waiting caller. */ - private opening = false; - - // Local id -> subscription state. The id is never sent to the broker; it only lets - // the same topic carry more than one callback (each with its own options). - /** - * The client id when the credential names no user (and none was set): random, but kept for - * this instance so reconnects resume the same broker session. - */ - private readonly fallbackClientId = randomId(); - - private cookieSession = ''; - private connectedKey = ''; - - private readonly subscriptions = new Map< - string, - { - topic: string; - callback: MessageCallback; - background: boolean; - title?: string; - notifyInForeground: boolean; - qos: 0 | 1; - } - >(); - - constructor(client: Client) { - super(client); - - // The broker location comes from Client.setPushEndpoint() when set (e.g. - // "mqtts://host:8883"), otherwise from the regular endpoint. - let endpointHost = ''; - let endpointSecure = false; - let endpointPort: number | null = null; - let endpointInsecure = false; - try { - const url = new URL( - client.config.endpointPush || client.config.endpoint || '', - ); - endpointHost = url.hostname; - endpointSecure = ['https:', 'wss:', 'mqtts:', 'ssl:'].includes( - url.protocol, - ); - // Take the port from the push endpoint only (a regular http/https endpoint's - // port is the API port, not the broker's). - endpointPort = - client.config.endpointPush && url.port - ? Number(url.port) - : null; - // Skip TLS cert verification (self-signed brokers / testing) via a query flag - // on the push endpoint, e.g. "mqtts://host:8883?tlsInsecure=true" — so the - // whole connection is described by one URL, not a second config knob. - const insecure = url.searchParams.get('tlsInsecure'); - endpointInsecure = insecure === 'true' || insecure === '1'; - } catch { - // leave defaults - } - - // When no explicit push endpoint is set, default to a `push.` host on the regular - // endpoint (mirroring how realtime derives from the endpoint, on the push subdomain). - if (endpointHost && !client.config.endpointPush) { - endpointHost = `push.${endpointHost}`; - } - this.host = endpointHost || 'localhost'; - // Secure by default: TLS on when the endpoint scheme is secure, so the credential - // in the CONNECT packet is not sent over a plaintext socket. - this.tls = endpointSecure; - this.port = endpointPort ?? (this.tls ? 8883 : 1883); - this.tlsInsecure = endpointInsecure; - - // Resume background delivery saved by an earlier run now, instead of at its next - // scheduled wake-up, with the current session: a rotated session of the same user - // replaces the saved one, and signed out (no session cookie) drops the saved - // subscriptions. - if (this.native) { - this.resumeNative(this.native).catch((err) => this.report(err)); - } - } - - // The broker subscription for a filter uses the highest QoS any local subscription on - // it wants, so a QoS-0 subscription never downgrades a QoS-1 one sharing the filter. - private effectiveQos(filter: string): 0 | 1 { - for (const sub of this.subscriptions.values()) { - if (sub.topic === filter && sub.qos === 1) { - return 1; - } - } - return 0; - } - - /** Register a callback invoked when the connection opens (CONNACK success). */ - onOpen(callback: () => void): this { - this.onOpenCb = callback; - return this; - } - - /** Register a callback invoked when the connection closes. */ - onClose(callback: () => void): this { - this.onCloseCb = callback; - return this; - } - - /** Register a callback invoked on a connection error. */ - onError(callback: (error: Error) => void): this { - this.onErrorCb = callback; - // On Android, a refused credential that stopped background delivery while no callback - // was registered is delivered now. - this.native - ?.setErrorCallback(true) - .then((stopped) => { - if (stopped) { - this.report(new Error(stopped)); - } - }) - .catch((err) => this.report(err)); - return this; - } - - /** - * Android: run background delivery in a foreground service (with a quiet ongoing - * notification), for immediate delivery even after the app is killed and during Doze, - * instead of only the scheduled wake-ups. Saved, so it applies after restarts too. Call it - * while the app is in the foreground: Android 12+ refuses to start the service from the - * background. It only affects `background: true` subscriptions. A no-op elsewhere. - */ - async setForeground(enabled: boolean): Promise { - await this.native?.setForeground(enabled); - } - - /** - * Android: what background delivery can rely on. When `bestEffort` is true the scheduled - * wake-ups are inexact and Doze can defer them, so messages may arrive late while the app is - * closed; explain why, then ask with {@link requestExactAlarms} or - * {@link requestIgnoreBatteryOptimizations}. Null elsewhere. - */ - async backgroundStatus(): Promise { - const json = await this.native?.backgroundStatus(); - return json ? (JSON.parse(json) as PushBackgroundStatus) : null; - } - - /** - * Android 12+: open the system screen where the user allows exact alarms, for punctual - * background wake-ups. Call it from a user action, never on its own. Resolves false when - * there is nothing to ask: already allowed, older Android, the app does not declare - * `SCHEDULE_EXACT_ALARM`, or not Android. - */ - async requestExactAlarms(): Promise { - return (await this.native?.requestExactAlarms()) ?? false; - } - - /** - * Android: ask the user to exempt the app from battery optimisation. Call it from a user - * action. Resolves false when there is nothing to ask: already exempt, the app does not - * declare `REQUEST_IGNORE_BATTERY_OPTIMIZATIONS`, or not Android. - */ - async requestIgnoreBatteryOptimizations(): Promise { - return ( - (await this.native?.requestIgnoreBatteryOptimizations()) ?? false - ); - } - - /** - * The background notification whose tap launched the app, or null. Call it once at startup: - * on Android a tap is reported only once. Elsewhere it reads `expo-notifications`. - * - * ```ts - * const opened = await push.getInitialNotification(); - * if (opened) openSale(opened.data.saleId); - * ``` - */ - async getInitialNotification(): Promise { - if (Platform.OS === 'android') { - const json = await this.native?.getInitialNotification(); - if (!json) { - return null; - } - const opened = JSON.parse(json) as NativeOpened; - return toOpened(opened.topic, opened.payload); - } - const notifications = expoNotifications(); - if (!notifications) { - return null; - } - const response = await notifications.getLastNotificationResponseAsync(); - const opened = response ? openedFromExpo(response) : null; - if (opened) { - await notifications.clearLastNotificationResponseAsync?.(); - } - return opened; - } - - /** - * Call [callback] each time the user taps a background notification while the app is - * running, including in the background. Returns a function that stops listening. The tap - * that launched the app comes from `getInitialNotification()` instead. - * - * ```ts - * const stop = push.onNotificationOpened(({ data }) => openSale(data.saleId)); - * ``` - */ - onNotificationOpened( - callback: (opened: PushNotificationOpened) => void, - ): () => void { - if (Platform.OS === 'android') { - if (!this.native) { - return () => undefined; - } - const native = this.native; - const emitter = new NativeEventEmitter(native); - const subscription = emitter.addListener( - 'AppwritePushOpened', - (event: NativeOpened) => - callback(toOpened(event.topic, event.payload)), - ); - native.listenOpened(true).catch((err) => this.report(err)); - let listening = true; - return () => { - if (!listening) { - return; - } - listening = false; - subscription.remove(); - native.listenOpened(false).catch((err) => this.report(err)); - }; - } - const notifications = expoNotifications(); - if (!notifications) { - return () => undefined; - } - const listener = ( - response: import('expo-notifications').NotificationResponse, - ): void => { - const opened = openedFromExpo(response); - if (opened) { - callback(opened); - } - }; - const subscription = - notifications.addNotificationResponseReceivedListener(listener); - return () => subscription.remove(); - } - - /** - * The signed-in user's own topic, `users/`, for a topic-less subscribe. The id comes - * from the credential the connection authenticates with: the JWT when one is set (never - * the session, which could belong to a different user), else the session. - */ - private userTopic(): string { - const { jwt, session } = this.client.config; - const userId = jwt - ? userIdFromJwt(jwt) - : userIdFromSession(session || this.cookieSession); - if (!userId) { - throw new Error( - 'subscribe() without a topic needs a signed-in user: set a JWT or session on the client', - ); - } - return `users/${userId}`; - } - - /** - * Hand an error to the onError callback, once per error. These errors happen outside any - * call (reconnects, broker DISCONNECTs, background re-subscribes), so they are never - * thrown, which would crash the app from inside mqtt.js: with no callback registered - * they are logged, like Realtime does. - */ - private report(error: unknown): void { - if (error instanceof SupersededError) { - // Internal: a connection superseded by the native host, not a failure. - return; - } - const err = toError(error); - if (this.reported.has(err)) { - return; - } - this.reported.add(err); - if (!this.onErrorCb) { - console.error('Appwrite Push error:', err); - return; - } - try { - this.onErrorCb(err); - } catch (callbackError) { - console.error('Appwrite Push onError threw:', callbackError); - } - } - - /** - * For a call that fails to its caller: report the error to onError when a callback is - * registered, then throw it to the caller, who can catch it. - */ - private fail(error: unknown): never { - const err = toError(error); - if (this.onErrorCb) { - this.report(err); - } - throw err; - } - - // --- realtime-like API --- - - /** - * Subscribe to one or more topics. Resolves to a {@link PushSubscription} handle. - * - * Each topic is a string or a `Topic` builder, e.g. - * `Topic.path(['user', userId]).all()`. - * - * Called with only a callback, `subscribe((message) => {...}, options)` subscribes to the - * signed-in user's own topic, `users/`, like FCM/APNs delivery to a device. The - * user id is read from the JWT (or session) set on the client. This form defaults to - * `background: true` and `retry: true` (QoS 1); pass either in the options to override. - * The default falls back to foreground delivery when background delivery is unavailable - * (no native module on Android, e.g. Expo Go; the peer dependencies elsewhere); an explicit - * `background: true` still requires it, and any other background startup failure is thrown. - * - * Awaiting resolves only once the broker has acked every SUBSCRIBE (SUBACK): - * the broker only starts routing a topic once its subscription is registered, - * so publishing before the ack races the message ahead of the subscription and - * it is dropped (no retained replay on MQTT). Awaiting here makes - * subscribe-then-publish reliable. - * - * Pass `{ background: true, title }` to also keep receiving while backgrounded and - * post a notification per matching message, and `{ retry: false }` for - * at-most-once (QoS 0) delivery; toggle either later with the handle's `update`. - */ - subscribe( - callback: MessageCallback, - options?: SubscribeOptions, - ): Promise; - subscribe( - topics: - string | Topic | ResolvedTopic | (string | Topic | ResolvedTopic)[], - callback: MessageCallback, - options?: SubscribeOptions, - ): Promise; - async subscribe( - topicsOrCallback: - | string - | Topic - | ResolvedTopic - | (string | Topic | ResolvedTopic)[] - | MessageCallback, - callbackOrOptions?: MessageCallback | SubscribeOptions, - topicOptions: SubscribeOptions = {}, - ): Promise { - // Every failure reaches onError (when registered) and is thrown to the caller. - try { - return await this.subscribeWith( - topicsOrCallback, - callbackOrOptions, - topicOptions, - ); - } catch (err) { - this.fail(err); - } - } - - private async subscribeWith( - topicsOrCallback: - | string - | Topic - | ResolvedTopic - | (string | Topic | ResolvedTopic)[] - | MessageCallback, - callbackOrOptions: MessageCallback | SubscribeOptions | undefined, - topicOptions: SubscribeOptions, - ): Promise { - const generation = this.closeGeneration; - await this.loadCookieSession(); - this.throwIfClosedSince(generation); - // Topic-less form: subscribe(callback, options) targets the signed-in user's topic. - const userForm = typeof topicsOrCallback === 'function'; - const topics = userForm ? this.userTopic() : topicsOrCallback; - const callback = ( - userForm ? topicsOrCallback : callbackOrOptions - ) as MessageCallback; - const options = ( - userForm ? (callbackOrOptions ?? {}) : topicOptions - ) as SubscribeOptions; - const topicList = (Array.isArray(topics) ? topics : [topics]).map( - (topic) => topic.toString(), - ); - // The user topic defaults to background delivery, like FCM/APNs; topics default off. - let background = options.background ?? userForm; - const qos: 0 | 1 = (options.retry ?? true) ? 1 : 0; - livePushes.add(this); - - // Only an explicit `background: true` requires background delivery: when background is - // just the user topic's default and it is unavailable, deliver in the foreground - // instead. Any other background startup failure still throws. - if ( - background && - options.background === undefined && - !this.backgroundAvailable() - ) { - background = false; - } - - if (background && Platform.OS === 'android' && !this.native) { - throw new Error( - "background delivery needs the SDK's native Android module: rebuild the app " + - '(native modules do not run in Expo Go)', - ); - } - - // Android: the native module hosts the connection while any subscription, live or saved - // by an earlier run, wants background. Two connections with the same client id would - // take over each other's broker session, so every subscription, of every Push, moves - // there. - if ( - this.native && - (background || - nativeHosts.size > 0 || - (await this.native.hasSaved())) - ) { - this.throwIfClosedSince(generation); - const ids = topicList.map((topic) => { - const id = randomId(); - this.subscriptions.set(id, { - topic, - callback, - background, - title: options.title, - notifyInForeground: options.notifyInForeground ?? false, - qos, - }); - return id; - }); - try { - await this.hostNative(); - } catch (err) { - for (const id of ids) { - this.subscriptions.delete(id); - } - await this.reconcileNative(); - throw err; - } - return this.handle(ids); - } - - // Start the background task before connecting so a missing peer dependency surfaces a - // clear error up front, matching the connection failure path. - if (background) { - await this.startBackground(); - } - this.throwIfClosedSince(generation); - - let client: MqttClient; - try { - client = await this.connect(); - } catch (err) { - // Another Push moved this one's subscriptions to the native host meanwhile: this - // subscribe goes there too. - if (err instanceof SupersededError) { - this.throwIfClosedSince(generation); - return this.subscribeWith( - topicsOrCallback, - callbackOrOptions, - topicOptions, - ); - } - throw err; - } - const epoch = this.connectionEpoch; - - const ids: string[] = []; - const acks: Promise[] = []; - for (const topic of topicList) { - const id = randomId(); - ids.push(id); - this.subscriptions.set(id, { - topic, - callback, - background, - title: options.title, - notifyInForeground: options.notifyInForeground ?? false, - qos, - }); - acks.push( - new Promise((resolve, reject) => { - client.subscribe( - topic, - { qos: this.effectiveQos(topic) }, - (err) => (err ? reject(err) : resolve()), - ); - }), - ); - } - - // If any topic's subscribe fails, roll this call's registrations back (and drop - // any now-unused broker filter) so a failed subscribe leaks no callback, then rethrow. - try { - await Promise.all(acks); - } catch (err) { - // Another Push moved this one's subscriptions to the native host while it waited for - // SUBACK, which closed the connection: this subscribe continues there. - if (this.nativeActive) { - try { - await this.hostNative(); - } catch (hostErr) { - for (const id of ids) { - this.subscriptions.delete(id); - } - await this.reconcileNative(); - throw hostErr; - } - return this.handle(ids); - } - if (epoch !== this.connectionEpoch) { - for (const id of ids) { - this.subscriptions.delete(id); - } - this.throwIfClosedSince(generation); - return this.subscribeWith( - topicsOrCallback, - callbackOrOptions, - topicOptions, - ); - } - this.unsubscribeInProcess(ids); - throw err; - } - - return this.handle(ids); - } - - /** - * The handle for a subscribe call's subscriptions. Each call goes to wherever they live now: - * they move to the native module (Android) when a background subscription is added later, - * and back when none is left. - */ - private handle(ids: string[]): PushSubscription { - return { - unsubscribe: () => - this.nativeActive - ? this.unsubscribeNative(ids) - : this.unsubscribeInProcess(ids), - update: (next: SubscribeOptions) => - this.nativeActive - ? this.updateNative(ids, next) - : this.updateInProcess(ids, next), - }; - } - - private unsubscribeInProcess(ids: string[]): void { - // Filters whose removed sub was QoS 1: their effective QoS may now drop. - const maybeDowngrade = new Set(); - for (const id of ids) { - const entry = this.subscriptions.get(id); - this.subscriptions.delete(id); - if (entry?.qos === 1) { - maybeDowngrade.add(entry.topic); - } - // Only unsubscribe the broker filter once its last local callback is gone. - const stillUsed = [...this.subscriptions.values()].some( - (s) => s.topic === entry?.topic, - ); - const connection = this.mqtt; - if (entry && connection && !stillUsed) { - connection.unsubscribe(entry.topic, (err) => { - // Closing the connection (the last subscription is gone) fails its - // in-flight requests on purpose; that is not an error to report. - if (err && this.mqtt === connection) { - this.report(err); - } - }); - } - } - // A filter that lost its last QoS-1 sub but still has QoS-0 subs must be - // re-SUBSCRIBEd at the lower QoS, or the broker keeps replaying to at-most-once subs. - for (const filter of maybeDowngrade) { - const stillUsed = [...this.subscriptions.values()].some( - (s) => s.topic === filter, - ); - if (stillUsed && this.effectiveQos(filter) === 0) { - this.mqtt?.subscribe(filter, { qos: 0 }, (err) => { - if (err) { - this.report(err); - } - }); - } - } - if (this.subscriptions.size === 0) { - this.teardown(); - } else { - // A removed sub may have been the last background one. - this.syncBackground(); - } - } - - private updateInProcess(ids: string[], next: SubscribeOptions): void { - const changedFilters = new Set(); - // Remember the pre-update QoS per id so a rejected re-SUBSCRIBE can be rolled back. - const previous = new Map(); - for (const id of ids) { - const entry = this.subscriptions.get(id); - if (!entry) { - continue; - } - if (next.background !== undefined) { - entry.background = next.background; - } - if (next.title !== undefined) { - entry.title = next.title; - } - if (next.notifyInForeground !== undefined) { - entry.notifyInForeground = next.notifyInForeground; - } - if (next.retry !== undefined) { - const q: 0 | 1 = next.retry ? 1 : 0; - if (q !== entry.qos) { - previous.set(id, entry.qos); - entry.qos = q; - changedFilters.add(entry.topic); - } - } - } - // Re-SUBSCRIBE the affected filters at their new effective QoS (a SUBSCRIBE to an - // existing filter just updates its QoS — no unsubscribe gap). If the broker rejects - // it, the old subscription still stands, so restore the local QoS to match and - // surface the error rather than silently assuming the change took effect. - for (const filter of changedFilters) { - this.mqtt?.subscribe( - filter, - { qos: this.effectiveQos(filter) }, - (err) => { - if (!err) { - return; - } - for (const [id, q] of previous) { - const entry = this.subscriptions.get(id); - if (entry && entry.topic === filter) { - entry.qos = q; - } - } - this.report(err); - }, - ); - } - // Turning background on moves the subscriptions to the native module on Android. - this.syncBackground(); - } - - private unsubscribeNative(ids: string[]): void { - for (const id of ids) { - this.subscriptions.delete(id); - } - this.reconcileNative().catch((err) => this.report(err)); - } - - private updateNative(ids: string[], next: SubscribeOptions): void { - for (const id of ids) { - const entry = this.subscriptions.get(id); - if (!entry) { - continue; - } - if (next.background !== undefined) { - entry.background = next.background; - } - if (next.title !== undefined) { - entry.title = next.title; - } - if (next.notifyInForeground !== undefined) { - entry.notifyInForeground = next.notifyInForeground; - } - if (next.retry !== undefined) { - entry.qos = next.retry ? 1 : 0; - } - } - this.reconcileNative().catch((err) => this.report(err)); - } - - /** After an in-process change: the native module on Android, the background task elsewhere. */ - private syncBackground(): void { - if (this.native) { - this.reconcileNative().catch((err) => this.report(err)); - } else { - this.syncBackgroundService(); - } - } - - /** Whether background delivery can run: the native module on Android, the peers elsewhere. */ - private backgroundAvailable(): boolean { - return Platform.OS === 'android' - ? this.native !== null - : backgroundPeersInstalled(); - } - - /** - * Host every subscription of every Push on the native module's connection, closing this - * one's in-process connection. Resolves once the connection is up and every filter is - * subscribed (SUBACK), or rejects with why not. - */ - private hostNative(): Promise { - const native = this.native!; - const key = this.credentialKey(); - // The native host carries one connection, so it serves one credential: instances hosted - // for another move back to their own connection. Instances with this credential share - // its client id, so their in-process connections would take over the broker session: - // they move to the native host too. - for (const push of nativeHosts) { - if (push.credentialKey() !== key) { - push.leaveToInProcess(); - if (push.hasBackgroundSubs()) { - push.report(new Error(BACKGROUND_DISPLACED)); - } - } - } - // Once moved, they stay: if hosting fails, the native host keeps their subscriptions and - // retries on its scheduled runs, and a second connection with the same client id would - // take over its broker session. - for (const push of livePushes) { - if (push.subscriptions.size > 0 && push.credentialKey() === key) { - push.joinNative(native); - } - } - this.joinNative(native); - // Instances that joined an open connection hear onOpen now; the others when it opens. - return enqueueNative(() => this.sendToNative(native)).then((open) => { - if (open) { - for (const push of nativeHosts) { - push.nativeConnection(true); - } - } - }); - } - - /** This Push's view of the native host's connection, reported once per change. */ - private nativeConnection(open: boolean): void { - if (!this.nativeActive || this.nativeOpen === open) { - return; - } - this.nativeOpen = open; - if (open) { - this.onOpenCb?.(); - } else { - this.onCloseCb?.(); - } - } - - /** - * Host every native host's subscriptions with this Push's credential. Resolves with whether - * the connection is open (false when there was nothing to host). - */ - private async sendToNative(native: NativePush): Promise { - // Host what is subscribed when this runs, so a close() or an unsubscribe queued - // meanwhile is not undone by an older request. - const subscriptions = [...nativeHosts].flatMap((push) => - push.nativeEntries(), - ); - if (subscriptions.length === 0) { - return false; - } - if ([...nativeHosts].some((push) => push.hasBackgroundSubs())) { - requestNotificationPermission(); - } - const { authMethod, credential } = this.credential(); - const config = { - host: this.host, - port: this.port, - tls: this.tls, - tlsInsecure: this.tlsInsecure, - clientId: this.client.config.pushClientId || '', - authMethod, - credential, - project: this.client.config.project ?? '', - // A session from the cookie store: background runs re-read it there, so they follow - // a rotated session while no JS runs. - sessionCookieUrl: - credential === this.cookieSession && !this.client.config.jwt - ? (this.client.config.endpoint ?? '') - : '', - }; - await native.setErrorCallback( - [...nativeHosts].some((push) => push.onErrorCb !== undefined), - ); - const open = await native.host( - JSON.stringify(config), - JSON.stringify(subscriptions), - ); - return open === true; - } - - /** Move this Push's subscriptions onto the native host, closing its own connection. */ - private joinNative(native: NativePush): void { - // An open() still in flight sees this and closes what it opened. - this.connectionEpoch++; - if (this.mqtt) { - this.mqtt.end(true); - this.mqtt = null; - } - this.connecting = null; - this.everConnected = false; - this.listenNative(native); - nativeHosts.add(this); - if (!this.nativeActive) { - this.nativeOpen = false; - } - this.nativeActive = true; - } - - /** Move this Push's subscriptions back onto its own connection. */ - private leaveToInProcess(): void { - nativeHosts.delete(this); - this.nativeActive = false; - this.connect() - .then(() => this.resubscribeAll()) - .catch((err) => this.report(err)); - } - - /** Identifies the connection this Push authenticates: one native host serves one. */ - private credentialKey(): string { - try { - const { authMethod, credential } = this.credential(); - return [ - this.host, - this.port, - this.client.config.project ?? '', - this.client.config.pushClientId ?? '', - authMethod, - credential, - ].join('|'); - } catch { - return ''; - } - } - - /** This Push's subscriptions in the native module's format. */ - private nativeEntries(): object[] { - return [...this.subscriptions].map(([id, sub]) => ({ - id, - topic: sub.topic, - background: sub.background, - title: sub.title ?? null, - retry: sub.qos === 1, - notifyInForeground: sub.notifyInForeground, - })); - } - - /** - * After an unsubscribe or update: keep the native module hosting while any subscription, - * live (of any Push) or saved, wants background, else move the live ones back in-process. - */ - private async reconcileNative(): Promise { - const native = this.native; - if (!native) { - return; - } - if (this.subscriptions.size === 0) { - // This Push has nothing left; saved subscriptions keep delivering in the background. - if (this.nativeActive) { - await this.leaveNative(native); - } - return; - } - const wanted = - [...nativeHosts, this].some((push) => push.hasBackgroundSubs()) || - (await native.hasSaved()); - if (wanted) { - await this.hostNative(); - return; - } - // Nothing wants background: every Push moves back to its own connection. - const hosts = [...nativeHosts]; - nativeHosts.clear(); - for (const push of hosts) { - push.nativeActive = false; - } - await enqueueNative(() => native.release()); - for (const push of hosts) { - if (push.subscriptions.size > 0) { - await push.connect(); - push.resubscribeAll(); - } - } - } - - /** Stop hosting this Push natively; the others' subscriptions stay hosted. */ - private leaveNative(native: NativePush): Promise { - nativeHosts.delete(this); - this.nativeActive = false; - const [other] = nativeHosts; - return other - ? other.hostNative() - : enqueueNative(() => native.release()); - } - - /** - * Route the native module's messages to their subscriptions, and its errors to onError. A - * message is acknowledged once its callback has run, as on the in-process connection. - */ - private listenNative(native: NativePush): void { - if (this.nativeEvents) { - return; - } - const emitter = new NativeEventEmitter(native); - this.nativeEvents = [ - emitter.addListener( - 'AppwritePushMessage', - (event: NativeMessage) => { - const sub = this.subscriptions.get(event.id); - if (!sub) { - return; - } - const payload = Buffer.from(event.payload, 'base64'); - const message: PushMessage = { - topic: event.topic, - data: payload.toString('utf8'), - payload, - qos: event.qos, - }; - Promise.resolve() - .then(() => sub.callback(message)) - .catch((err) => this.report(err)) - .finally(() => native.ack(event.ackToken)); - }, - ), - emitter.addListener( - 'AppwritePushError', - (event: { message: string }) => - this.report(new Error(event.message)), - ), - emitter.addListener( - 'AppwritePushConnection', - (event: { connected: boolean }) => - this.nativeConnection(event.connected), - ), - ]; - } - - /** - * Tear down the connection and drop all subscriptions. On Android, closing the last Push - * that uses background delivery also stops it, including subscriptions saved by an earlier - * run: call it on sign-out. While other Push instances still use it, it keeps delivering - * their subscriptions and the saved ones. - */ - close(): void { - this.connectionEpoch++; - this.closeGeneration++; - this.teardown(); - const native = this.native; - if (!native) { - return; - } - nativeHosts.delete(this); - this.nativeActive = false; - this.nativeEvents?.forEach((subscription) => subscription.remove()); - this.nativeEvents = null; - const [other] = nativeHosts; - if (other) { - other.hostNative().catch((err) => other.report(err)); - return; - } - enqueueNative(() => native.stop()).catch((err) => this.report(err)); - } - - /** Close the in-process connection and drop the live subscriptions. */ - private teardown(): void { - livePushes.delete(this); - if (this.mqtt) { - this.mqtt.end(true); - this.mqtt = null; - } - this.connecting = null; - this.everConnected = false; - this.subscriptions.clear(); - this.stopBackground(); - } - - /** Throws once close() has run since `generation` was read, so a subscribe started before it stops. */ - private throwIfClosedSince(generation: number): void { - if (generation !== this.closeGeneration) { - throw closedError(); - } - } - - /** True while any live subscription has opted into background delivery. */ - private hasBackgroundSubs(): boolean { - for (const sub of this.subscriptions.values()) { - if (sub.background) { - return true; - } - } - return false; - } - - // Reconcile the reference-counted foreground service with whether any live - // subscription still wants background delivery. - private syncBackgroundService(): void { - const want = this.hasBackgroundSubs(); - if (want && !this.backgroundActive) { - this.startBackground().catch((err) => this.report(err)); - } else if (!want && this.backgroundActive) { - this.stopBackground(); - } - } - - /** Stop the Android foreground service if it is running (no-op otherwise). */ - private stopBackground(): void { - if (!this.backgroundActive) { - return; - } - this.backgroundActive = false; - try { - /* eslint-disable @typescript-eslint/no-require-imports */ - const backgroundActions: typeof import('react-native-background-actions').default = - require('react-native-background-actions').default; - /* eslint-enable @typescript-eslint/no-require-imports */ - backgroundActions.stop().catch((err) => this.report(err)); - } catch { - // not installed or already stopped - } - } - - /** - * Start the Android foreground service (keeps the process alive so the in-process - * MQTT socket keeps delivering) and request notification permission. No-op after - * the first call. - */ - private async startBackground(): Promise { - if (this.backgroundActive) { - return; - } - this.backgroundActive = true; - try { - /* eslint-disable @typescript-eslint/no-require-imports */ - const notifications: typeof import('expo-notifications') = require('expo-notifications'); - const backgroundActions: typeof import('react-native-background-actions').default = - require('react-native-background-actions').default; - /* eslint-enable @typescript-eslint/no-require-imports */ - await notifications.requestPermissionsAsync(); - await notifications.setNotificationChannelAsync('appwrite-push', { - name: 'Notifications', - importance: notifications.AndroidImportance.HIGH, - }); - if (!backgroundActions.isRunning()) { - await backgroundActions.start( - // The MQTT client runs in this same JS context; the task only has to - // stay pending to keep the foreground service (and process) alive. - () => new Promise(() => undefined), - { - taskName: 'appwritePush', - taskTitle: 'Appwrite', - taskDesc: 'Listening for messages', - // taskIcon is required by react-native-background-actions — without - // it start() throws "Task icon not found". ic_launcher/mipmap exists - // in every Expo/RN Android app, so it is a safe default. - taskIcon: { name: 'ic_launcher', type: 'mipmap' }, - // Match the dataSync foregroundServiceType the config plugin injects - // into the manifest, so the service is valid on Android 14+. - foregroundServiceType: ['dataSync'], - }, - ); - } - } catch (err) { - this.backgroundActive = false; - // Surface the real failure (e.g. a missing taskIcon, or a missing peer module) - // instead of assuming it is always a missing dependency. - const detail = err instanceof Error ? err.message : String(err); - throw new Error( - `background delivery failed to start: ${detail} (it needs the ` + - '"react-native-background-actions" and "expo-notifications" peer ' + - 'dependencies)', - { cause: err }, - ); - } - } - - /** Post a local notification for a message a background subscription matched. */ - private async notify(message: PushMessage, title: string): Promise { - try { - /* eslint-disable @typescript-eslint/no-require-imports */ - const notifications: typeof import('expo-notifications') = require('expo-notifications'); - /* eslint-enable @typescript-eslint/no-require-imports */ - const content = notificationContent(message); - const raw = !content.present; - await notifications.scheduleNotificationAsync({ - content: { - title: content.title ?? title, - body: content.body ?? (raw ? message.data : null), - data: { topic: message.topic, payload: message.data }, - }, - trigger: null, - }); - } catch { - // expo-notifications not installed; skip. - } - } - - /** - * Re-register every active subscription. Called on each reconnect: with - * a fresh (or cleared) session the broker keeps no subscriptions, so a reconnected client starts with - * zero subscriptions and would otherwise silently stop receiving. - */ - private resubscribeAll(): void { - const client = this.mqtt; - if (!client) { - return; - } - const filters = new Set( - [...this.subscriptions.values()].map((s) => s.topic), - ); - for (const filter of filters) { - client.subscribe( - filter, - { qos: this.effectiveQos(filter) }, - (err) => { - if (err) { - this.report(err); - } - }, - ); - } - } - - // --- internals --- - - private connect(): Promise { - if ( - (this.mqtt || this.connecting) && - this.connectedKey !== this.credentialKey() - ) { - this.connectionEpoch++; - this.mqtt?.end(true); - this.mqtt = null; - this.connecting = null; - this.everConnected = this.subscriptions.size > 0; - } - if (this.mqtt && !this.connecting) { - return Promise.resolve(this.mqtt); - } - if (!this.connecting) { - const connecting = this.open(); - this.connecting = connecting; - // A failed open must not poison future attempts — clear the cached - // in-flight promise so a later subscribe/publish can retry. - connecting.catch(() => { - if (this.connecting === connecting) { - this.connecting = null; - } - }); - } - return this.connecting.then(() => this.mqtt!); - } - - /** - * Resume saved native delivery with the current credential. Only a cookie lookup that - * succeeded and found no session counts as signed out; a failed or impossible lookup keeps - * the saved subscriptions. - */ - private async resumeNative(native: NativePush): Promise { - const { jwt, session, endpoint, project } = this.client.config; - let signedOut = false; - if (!jwt && !session) { - const lookup = await lookupSessionCookie(endpoint, project); - this.cookieSession = lookup.session; - signedOut = lookup.found === false; - } - const current = this.currentCredential(); - await native.resume( - current?.authMethod ?? null, - current?.credential ?? null, - signedOut, - ); - } - - private async loadCookieSession(): Promise { - const { jwt, session, endpoint, project } = this.client.config; - if (jwt || session) { - return; - } - this.cookieSession = await sessionCookie(endpoint, project); - } - - /** The credential the connection would use, or null when there is none. */ - private currentCredential(): { - authMethod: AuthMethod; - credential: string; - } | null { - try { - return this.credential(); - } catch { - return null; - } - } - - /** The credential set on the client (via Client.setJWT / setSession). */ - private credential(): { authMethod: AuthMethod; credential: string } { - if (this.client.config.jwt) { - return { - authMethod: 'appwrite-jwt', - credential: this.client.config.jwt, - }; - } - const session = this.client.config.session || this.cookieSession; - if (session) { - return { - authMethod: 'appwrite-session', - credential: session, - }; - } - throw new Error( - 'No credential set on the client; call Client.setJWT() or Client.setSession() first.', - ); - } - - private async open(): Promise { - const { authMethod, credential } = this.credential(); - this.connectedKey = this.credentialKey(); - const epoch = this.connectionEpoch; - - const project = this.client.config.project ?? ''; - // Client id, when the app did not set one with Client.setPushClientId(). Unlike the - // native SDKs (which send an empty id and let the broker derive a stable one), mqtt.js - // rejects an empty id with clean start off, so derive a stable per-user id here from the - // credential this connection authenticates with: the JWT's userId, or the session's user - // id. A stable id keeps the broker's replay cursor resuming across restarts. The - // credential itself is never used as the id. - // On Android the native module's per-user-and-install id is used, so this connection - // and the background one share the broker session. - const clientId = - this.client.config.pushClientId || - (this.native - ? await this.native.defaultClientId(authMethod, credential) - : (authMethod === 'appwrite-jwt' - ? userIdFromJwt(credential) - : userIdFromSession(credential)) || - this.fallbackClientId); - // The subscriptions moved to the native host while this was waiting: its connection - // would share the host's client id and take over the broker session. - if (epoch !== this.connectionEpoch) { - throw new SupersededError(); - } - - const options: IClientOptions = { - clientId, - protocolVersion: 5, - clean: false, // always keep the session so the broker can replay QoS-1 topics - keepalive: KEEP_ALIVE_SECONDS, - reconnectPeriod: RECONNECT_PERIOD_MS, - manualConnect: true, - // Enhanced auth carried in CONNECT properties. - properties: { - authenticationMethod: authMethod, - authenticationData: Buffer.from(credential), - userProperties: { projectId: project }, - }, - // Ack QoS 1 deliveries by hand, after the callback has processed the - // message. On the broker a subscriber's PUBACK is what advances its replay - // cursor, so acking automatically on arrival — before the callback runs — - // would advance past a message a failing callback never actually handled. - customHandleAcks: (_topic, _message, packet, cb) => { - this.dispatch(packet as IPublishPacket) - // cb(0): send the PUBACK now that the callback has processed it. - .then(() => cb(0)) - // On failure, do not ack: the message stays unacked and the broker - // replays it on reconnect (at-least-once). - .catch((err) => { - this.report(err); - cb(toError(err)); - }); - }, - }; - - // Raw TCP only: build the transport from a native socket, never a WebSocket. - const client = new mqtt.MqttClient( - () => - createTcpStream({ - host: this.host, - port: this.port, - tls: this.tls, - tlsInsecure: this.tlsInsecure, - }), - options, - ); - this.mqtt = client; - - // Dispatch QoS 0 deliveries (which never reach customHandleAcks). QoS 1/2 are - // dispatched from customHandleAcks; ignore them here to avoid a double dispatch. - client.on('message', (_topic, _payload, packet) => { - if (packet.qos === 0) { - this.dispatch(packet).catch((err) => this.report(err)); - } - }); - - // Persistent lifecycle listeners. On a reconnect the broker has no session for - // us on a cleared session, so we must re-register every subscription. - client.on('connect', () => { - if (this.everConnected) { - this.resubscribeAll(); - } - this.everConnected = true; - this.onOpenCb?.(); - }); - client.on('close', () => this.onCloseCb?.()); - // The broker explains a refused CONNECT (CONNACK) or a server-initiated DISCONNECT - // with an MQTT 5 Reason String. mqtt.js reports only the reason code, so capture the - // string off the packet (packetreceive fires before mqtt.js handles it) and hand it - // to onError as the error message. - let refusedReason: string | undefined; - client.on('packetreceive', (packet) => { - if (packet.cmd === 'connack') { - refusedReason = - (packet.reasonCode ?? 0) !== 0 - ? packet.properties?.reasonString - : undefined; - } - }); - // A persistent error listener also prevents mqtt.js from throwing on - // post-connect errors once the one-shot handler below is removed. - client.on('error', (err) => { - if (epoch !== this.connectionEpoch) { - return; - } - const error = this.connectError(err, refusedReason); - // While the first connect is pending its caller receives the error (and reports it - // through fail()); afterwards, e.g. on reconnect, report it here. - if (!this.opening) { - this.report(error); - } - }); - client.on('disconnect', (packet) => { - if ((packet.reasonCode ?? 0) !== 0) { - this.report( - new Error( - packet.properties?.reasonString ?? - `Disconnected by the broker (reason ${packet.reasonCode})`, - ), - ); - } - }); - - this.opening = true; - await new Promise((resolve, reject) => { - const onConnect = (packet: IConnackPacket) => { - cleanup(); - if (epoch !== this.connectionEpoch) { - reject(new SupersededError()); - return; - } - // reasonCode (v5) / returnCode (v3) of 0 means accepted. - const rc = packet.reasonCode ?? packet.returnCode ?? 0; - if (rc !== 0) { - this.teardown(); - reject( - new Error( - refusedReason ?? - `MQTT authentication failed (CONNACK reason ${rc})`, - ), - ); - } else { - resolve(); - } - }; - const onError = (err: Error) => { - cleanup(); - if (epoch !== this.connectionEpoch) { - reject(new SupersededError()); - return; - } - this.teardown(); - reject(this.connectError(err, refusedReason)); - }; - // The subscriptions moved to the native host, which ended this client before CONNACK. - const onClose = () => { - if (epoch !== this.connectionEpoch) { - cleanup(); - reject(new SupersededError()); - } - }; - const cleanup = () => { - if (epoch === this.connectionEpoch) { - this.opening = false; - } - client.removeListener('connect', onConnect); - client.removeListener('error', onError); - client.removeListener('close', onClose); - }; - client.on('connect', onConnect); - client.on('error', onError); - client.on('close', onClose); - client.connect(); - }); - } - - /** - * The error for a failed connect: the broker's Reason String when it sent one (a refused - * CONNACK), else mqtt.js's error. Memoized so both error listeners hand out the same - * object and it is reported once. - */ - private connectError(err: unknown, reason: string | undefined): Error { - const source = toError(err); - let error = this.connectErrors.get(source); - if (!error) { - error = reason ? new Error(reason) : source; - this.connectErrors.set(source, error); - } - return error; - } - - /** Fan a delivered packet out to every subscription whose filter matches. */ - private async dispatch(packet: IPublishPacket): Promise { - const payload = Buffer.isBuffer(packet.payload) - ? packet.payload - : Buffer.from(packet.payload); - const message: PushMessage = { - topic: packet.topic.toString(), - data: payload.toString('utf8'), - payload, - qos: packet.qos, - }; - const serverTitle = notificationContent(message).title; - const postedTitles = new Set(); - // While the app is on screen it shows the message itself: only subscriptions that - // opted in with notifyInForeground also post a notification then. - const foreground = AppState.currentState === 'active'; - for (const sub of this.subscriptions.values()) { - if (matches(sub.topic, message.topic)) { - await sub.callback(message); - // Notification is per-subscription: only subs that opted in post one, each - // title once. A title the server sent replaces theirs, so it posts once. - const title = serverTitle ?? sub.title ?? message.topic; - if ( - sub.background && - (!foreground || sub.notifyInForeground) && - !postedTitles.has(title) - ) { - postedTitles.add(title); - await this.notify(message, title); - } - } - } - } -} - -/** The SDK's native Android module (see android/), which hosts background delivery. */ -interface NativePush { - /** Resolves with whether the connection is open once every filter is subscribed. */ - host(config: string, subscriptions: string): Promise; - ack(token: string): void; - release(): Promise; - stop(): Promise; - setForeground(enabled: boolean): Promise; - hasSaved(): Promise; - resume( - authMethod: string | null, - credential: string | null, - signedOutWhenMissing: boolean, - ): Promise; - /** {@link PushBackgroundStatus} as JSON. */ - backgroundStatus(): Promise; - requestExactAlarms(): Promise; - requestIgnoreBatteryOptimizations(): Promise; - setErrorCallback(registered: boolean): Promise; - defaultClientId(authMethod: string, credential: string): Promise; - /** The tapped notification that launched the app, as {@link NativeOpened} JSON. */ - getInitialNotification(): Promise; - listenOpened(listening: boolean): Promise; - addListener(eventName: string): void; - removeListeners(count: number): void; -} - -/** A tapped notification the native module reports: its topic and raw payload. */ -interface NativeOpened { - topic: string; - payload: string; -} - -/** A message the native module delivers for a hosted subscription. */ -interface NativeMessage { - id: string; - topic: string; - payload: string; - qos: number; - ackToken: string; -} - -/** - * Every Push on Android shares the one native host (one connection per client id), which hosts - * the union of their subscriptions. Native calls run one at a time in call order, so a sign-out - * is never undone by a subscribe still on its way. - */ -const nativeHosts = new Set(); -/** Every Push with live subscriptions, so the native host can take over their connections. */ -const livePushes = new Set(); -let nativeQueue: Promise = Promise.resolve(); - -let notificationPermissionRequested = false; - -/** - * Android 13+: ask once per run for the notification permission that background messages are - * posted with. It does not wait for the answer, and a denial only leaves notifications off. - */ -function requestNotificationPermission(): void { - if ( - notificationPermissionRequested || - Platform.OS !== 'android' || - Number(Platform.Version) < 33 - ) { - return; - } - notificationPermissionRequested = true; - // Required here rather than imported: react-native-web, which web builds alias, lacks it. - /* eslint-disable @typescript-eslint/no-require-imports */ - const reactNative: typeof import('react-native') = require('react-native'); - /* eslint-enable @typescript-eslint/no-require-imports */ - const { PermissionsAndroid } = reactNative; - const permission = PermissionsAndroid.PERMISSIONS.POST_NOTIFICATIONS; - PermissionsAndroid.check(permission) - .then((granted) => - granted ? undefined : PermissionsAndroid.request(permission), - ) - .catch(() => undefined); -} - -/** A tapped notification's topic and message `data`, parsed from its payload. */ -function toOpened(topic: string, payload: string): PushNotificationOpened { - let data: unknown; - try { - data = (JSON.parse(payload) as { data?: unknown })?.data; - } catch { - data = undefined; - } - return { - topic, - data: - typeof data === 'object' && data !== null && !Array.isArray(data) - ? (data as Record) - : {}, - }; -} - -/** A tap on a notification this SDK posted through expo-notifications, else null. */ -function openedFromExpo( - response: import('expo-notifications').NotificationResponse, -): PushNotificationOpened | null { - const data = response.notification.request.content.data; - return typeof data?.topic === 'string' && typeof data.payload === 'string' - ? toOpened(data.topic, data.payload) - : null; -} - -/** expo-notifications when the app has installed it, else null. */ -function expoNotifications(): typeof import('expo-notifications') | null { - try { - /* eslint-disable @typescript-eslint/no-require-imports */ - return require('expo-notifications'); - /* eslint-enable @typescript-eslint/no-require-imports */ - } catch { - return null; - } -} - -/** What a message's `notification` block asks a background notification to show. */ -interface NotificationContent { - /** Whether the message has a `notification` block at all. */ - present: boolean; - title?: string; - body?: string; - image?: string; -} - -/** The server's `notification` block in a message; empty when the payload has none or is not JSON. */ -function notificationContent(message: PushMessage): NotificationContent { - let notification: unknown; - try { - notification = (JSON.parse(message.data) as { notification?: unknown }) - ?.notification; - } catch { - return { present: false }; - } - if (typeof notification !== 'object' || notification === null) { - return { present: false }; - } - const field = (name: string): string | undefined => { - const value = (notification as Record)[name]; - return typeof value === 'string' && value !== '' ? value : undefined; - }; - return { - present: true, - title: field('title'), - body: field('body'), - image: field('image'), - }; -} - -function enqueueNative(op: () => Promise): Promise { - const result = nativeQueue.then(op); - nativeQueue = result.catch(() => undefined); - return result; -} - -/** The native module on Android when the app was built with it (not in Expo Go), else null. */ -function nativePush(): NativePush | null { - if (Platform.OS !== 'android') { - return null; - } - return (NativeModules?.AppwritePush as NativePush | undefined) ?? null; -} - -/** - * Reported to a Push whose background delivery stopped because a Push with another credential - * took over the native host, which carries one connection and so serves one credential. - */ -const BACKGROUND_DISPLACED = - 'Background delivery stopped: a Push with another credential started background delivery, ' + - 'and the device hosts one. These subscriptions still deliver while the app runs.'; - -/** An in-process connect superseded by the native host or by a connect with another credential. */ -function closedError(): Error { - return new Error('Push was closed before the subscription was established'); -} - -class SupersededError extends Error { - constructor() { - super('The push connection was superseded'); - } -} - -/** Normalize anything thrown or passed to an error handler into an `Error`. */ -function toError(error: unknown): Error { - return error instanceof Error ? error : new Error(String(error)); -} - -/** - * The userId claim from an Appwrite JWT, used as the default MQTT client id so the - * broker's replay cursor is stable per user. Returns '' when the token is not a decodable JWT - * (e.g. a plain string), so the caller can fall back to the session or raw credential. - */ -function userIdFromJwt(jwt?: string): string { - if (!jwt) { - return ''; - } - const parts = jwt.split('.'); - if (parts.length < 2) { - return ''; - } - try { - const json = Buffer.from( - parts[1].replace(/-/g, '+').replace(/_/g, '/'), - 'base64', - ).toString('utf-8'); - const payload = JSON.parse(json); - return typeof payload.userId === 'string' ? payload.userId : ''; - } catch { - return ''; - } -} - -/** - * Whether the optional background-delivery peers (`expo-notifications` and - * `react-native-background-actions`) are installed. - */ -function backgroundPeersInstalled(): boolean { - try { - /* eslint-disable @typescript-eslint/no-require-imports */ - require('expo-notifications'); - require('react-native-background-actions'); - /* eslint-enable @typescript-eslint/no-require-imports */ - return true; - } catch { - return false; - } -} - -interface NativeCookies { - session(url: string, project: string): Promise; -} - -async function sessionCookie( - endpoint: string | undefined, - project: string | undefined, -): Promise { - return (await lookupSessionCookie(endpoint, project)).session; -} - -/** - * Look up the session cookie. `found` is false only when the lookup succeeded and there is no - * session, and null when it could not be looked up (no cookie module, endpoint or project, or - * the lookup failed). - */ -async function lookupSessionCookie( - endpoint: string | undefined, - project: string | undefined, -): Promise<{ found: boolean | null; session: string }> { - const cookies = NativeModules?.AppwriteCookies as NativeCookies | undefined; - if (!cookies || !endpoint || !project) { - return { found: null, session: '' }; - } - try { - const value = await cookies.session(endpoint, project); - return value - ? { found: true, session: decodeURIComponent(value) } - : { found: false, session: '' }; - } catch { - return { found: null, session: '' }; - } -} - -/** - * The user id inside a session secret, which is base64 of JSON `{"id": , "secret": ...}`. - * Returns '' when the value is not such a secret. - */ -function userIdFromSession(session?: string): string { - if (!session) { - return ''; - } - try { - const payload = JSON.parse( - Buffer.from(session, 'base64').toString('utf-8'), - ); - return typeof payload.id === 'string' ? payload.id : ''; - } catch { - return ''; - } -} - -/** A hex id, uuid4-like enough for a client-generated subId / client id suffix. */ -function randomId(): string { - let out = ''; - for (let i = 0; i < 32; i++) { - out += Math.floor(Math.random() * 16).toString(16); - } - return out; -} - -/** MQTT topic-filter match with '+' (single level) and '#' (multi level). */ -function matches(filter: string, topic: string): boolean { - const filterParts = filter.split('/'); - const topicParts = topic.split('/'); - for (let i = 0; i < filterParts.length; i++) { - const part = filterParts[i]; - if (part === '#') { - return true; - } - if (i >= topicParts.length) { - return false; - } - if (part !== '+' && part !== topicParts[i]) { - return false; - } - } - return filterParts.length === topicParts.length; -} diff --git a/src/services/storage.ts b/src/services/storage.ts index fdca28a8..f14c66cf 100644 --- a/src/services/storage.ts +++ b/src/services/storage.ts @@ -1,5 +1,5 @@ import { Service } from '../service'; -import { AppwriteException, Client } from '../client'; +import { AppwriteException, Client, applyDefaults } from '../client'; import type { Models } from '../models'; import type { UploadProgress, Payload } from '../client'; import * as FileSystem from 'expo-file-system'; @@ -113,7 +113,7 @@ export class Storage extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -122,6 +122,44 @@ export class Storage extends Service { }, apiPayload, ); + const defaults = { + root: 'fileList', + models: { + fileList: { + defaults: { + total: 0, + files: [], + }, + properties: { + files: { + items: 'file', + }, + }, + }, + file: { + defaults: { + $id: '', + bucketId: '', + $createdAt: '', + $updatedAt: '', + $permissions: [], + name: '', + folder: '', + key: '', + signature: '', + mimeType: '', + sizeOriginal: 0, + sizeActual: 0, + chunksTotal: 0, + chunksUploaded: 0, + encryption: false, + compression: 'none', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -563,7 +601,7 @@ export class Storage extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -572,6 +610,33 @@ export class Storage extends Service { }, apiPayload, ); + const defaults = { + root: 'file', + models: { + file: { + defaults: { + $id: '', + bucketId: '', + $createdAt: '', + $updatedAt: '', + $permissions: [], + name: '', + folder: '', + key: '', + signature: '', + mimeType: '', + sizeOriginal: 0, + sizeActual: 0, + chunksTotal: 0, + chunksUploaded: 0, + encryption: false, + compression: 'none', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -580,7 +645,7 @@ export class Storage extends Service { * @param {string} params.bucketId - Bucket unique ID. * @param {string} params.fileId - File ID. * @param {string} params.name - File name. - * @param {string[]} params.permissions - An array of permission strings. By default, the current permissions are inherited. [Learn more about permissions](https://appwrite.io/docs/permissions). + * @param {string[] | null} params.permissions - An array of permission strings. By default, the current permissions are inherited. [Learn more about permissions](https://appwrite.io/docs/permissions). * @throws {AppwriteException} * @returns {Promise} */ @@ -588,7 +653,7 @@ export class Storage extends Service { bucketId: string; fileId: string; name?: string; - permissions?: string[]; + permissions?: string[] | null; }): Promise; /** * Update a file by its unique ID. Only users with write permissions have access to update this resource. @@ -596,7 +661,7 @@ export class Storage extends Service { * @param {string} bucketId - Bucket unique ID. * @param {string} fileId - File ID. * @param {string} name - File name. - * @param {string[]} permissions - An array of permission strings. By default, the current permissions are inherited. [Learn more about permissions](https://appwrite.io/docs/permissions). + * @param {string[] | null} permissions - An array of permission strings. By default, the current permissions are inherited. [Learn more about permissions](https://appwrite.io/docs/permissions). * @throws {AppwriteException} * @returns {Promise} * @deprecated Use the object parameter style method for a better developer experience. @@ -605,7 +670,7 @@ export class Storage extends Service { bucketId: string, fileId: string, name?: string, - permissions?: string[], + permissions?: string[] | null, ): Promise; updateFile( paramsOrFirst: @@ -613,16 +678,16 @@ export class Storage extends Service { bucketId: string; fileId: string; name?: string; - permissions?: string[]; + permissions?: string[] | null; } | string, - ...rest: [string?, string?, string[]?] + ...rest: [string?, string?, (string[] | null)?] ): Promise { let params: { bucketId: string; fileId: string; name?: string; - permissions?: string[]; + permissions?: string[] | null; }; if ( @@ -634,14 +699,14 @@ export class Storage extends Service { bucketId: string; fileId: string; name?: string; - permissions?: string[]; + permissions?: string[] | null; }; } else { params = { bucketId: paramsOrFirst as string, fileId: rest[0] as string, name: rest[1] as string, - permissions: rest[2] as string[], + permissions: rest[2] as string[] | null, }; } @@ -674,7 +739,7 @@ export class Storage extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'put', uri, { @@ -684,6 +749,33 @@ export class Storage extends Service { }, apiPayload, ); + const defaults = { + root: 'file', + models: { + file: { + defaults: { + $id: '', + bucketId: '', + $createdAt: '', + $updatedAt: '', + $permissions: [], + name: '', + folder: '', + key: '', + signature: '', + mimeType: '', + sizeOriginal: 0, + sizeActual: 0, + chunksTotal: 0, + chunksUploaded: 0, + encryption: false, + compression: 'none', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** diff --git a/src/services/tables-db.ts b/src/services/tables-db.ts index ae5d11d1..20a11bc1 100644 --- a/src/services/tables-db.ts +++ b/src/services/tables-db.ts @@ -1,5 +1,5 @@ import { Service } from '../service'; -import { AppwriteException, Client } from '../client'; +import { AppwriteException, Client, applyDefaults } from '../client'; import type { Models } from '../models'; import type { Payload } from '../client'; @@ -71,7 +71,7 @@ export class TablesDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -80,6 +80,34 @@ export class TablesDB extends Service { }, apiPayload, ); + const defaults = { + root: 'transactionList', + models: { + transactionList: { + defaults: { + total: 0, + transactions: [], + }, + properties: { + transactions: { + items: 'transaction', + }, + }, + }, + transaction: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + status: 'pending', + operations: 0, + expiresAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -127,7 +155,7 @@ export class TablesDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -137,6 +165,23 @@ export class TablesDB extends Service { }, apiPayload, ); + const defaults = { + root: 'transaction', + models: { + transaction: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + status: 'pending', + operations: 0, + expiresAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -190,7 +235,7 @@ export class TablesDB extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -199,6 +244,23 @@ export class TablesDB extends Service { }, apiPayload, ); + const defaults = { + root: 'transaction', + models: { + transaction: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + status: 'pending', + operations: 0, + expiresAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -285,7 +347,7 @@ export class TablesDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'patch', uri, { @@ -295,6 +357,23 @@ export class TablesDB extends Service { }, apiPayload, ); + const defaults = { + root: 'transaction', + models: { + transaction: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + status: 'pending', + operations: 0, + expiresAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -427,7 +506,7 @@ export class TablesDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -437,6 +516,23 @@ export class TablesDB extends Service { }, apiPayload, ); + const defaults = { + root: 'transaction', + models: { + transaction: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + status: 'pending', + operations: 0, + expiresAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -567,7 +663,7 @@ export class TablesDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -576,6 +672,35 @@ export class TablesDB extends Service { }, apiPayload, ); + const defaults = { + root: 'rowList', + models: { + rowList: { + defaults: { + total: 0, + rows: [], + }, + properties: { + rows: { + items: 'row', + }, + }, + }, + row: { + defaults: { + $id: '', + $sequence: '', + $tableId: '', + $databaseId: '', + $createdAt: '', + $updatedAt: '', + $permissions: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -585,8 +710,8 @@ export class TablesDB extends Service { * @param {string} params.tableId - Table ID. You can create a new table using the Database service [server integration](https://appwrite.io/docs/references/cloud/server-dart/tablesDB#createTable). Make sure to define columns before creating rows. * @param {string} params.rowId - Row ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars. * @param {Row extends Models.DefaultRow ? Partial & Record : Partial & Omit} params.data - Row data as JSON object. - * @param {string[]} params.permissions - An array of permissions strings. By default, only the current user is granted all permissions. [Learn more about permissions](https://appwrite.io/docs/permissions). - * @param {string} params.transactionId - Transaction ID for staging the operation. + * @param {string[] | null} params.permissions - An array of permissions strings. By default, only the current user is granted all permissions. [Learn more about permissions](https://appwrite.io/docs/permissions). + * @param {string | null} params.transactionId - Transaction ID for staging the operation. * @throws {AppwriteException} * @returns {Promise} */ @@ -597,8 +722,8 @@ export class TablesDB extends Service { data: Row extends Models.DefaultRow ? Partial & Record : Partial & Omit; - permissions?: string[]; - transactionId?: string; + permissions?: string[] | null; + transactionId?: string | null; }): Promise; /** * Create a new Row. Before using this route, you should create a new table resource using either a [server integration](https://appwrite.io/docs/references/cloud/server-dart/tablesDB#createTable) API or directly from your database console. @@ -607,8 +732,8 @@ export class TablesDB extends Service { * @param {string} tableId - Table ID. You can create a new table using the Database service [server integration](https://appwrite.io/docs/references/cloud/server-dart/tablesDB#createTable). Make sure to define columns before creating rows. * @param {string} rowId - Row ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars. * @param {Row extends Models.DefaultRow ? Partial & Record : Partial & Omit} data - Row data as JSON object. - * @param {string[]} permissions - An array of permissions strings. By default, only the current user is granted all permissions. [Learn more about permissions](https://appwrite.io/docs/permissions). - * @param {string} transactionId - Transaction ID for staging the operation. + * @param {string[] | null} permissions - An array of permissions strings. By default, only the current user is granted all permissions. [Learn more about permissions](https://appwrite.io/docs/permissions). + * @param {string | null} transactionId - Transaction ID for staging the operation. * @throws {AppwriteException} * @returns {Promise} * @deprecated Use the object parameter style method for a better developer experience. @@ -620,8 +745,8 @@ export class TablesDB extends Service { data: Row extends Models.DefaultRow ? Partial & Record : Partial & Omit, - permissions?: string[], - transactionId?: string, + permissions?: string[] | null, + transactionId?: string | null, ): Promise; createRow( paramsOrFirst: @@ -632,8 +757,8 @@ export class TablesDB extends Service { data: Row extends Models.DefaultRow ? Partial & Record : Partial & Omit; - permissions?: string[]; - transactionId?: string; + permissions?: string[] | null; + transactionId?: string | null; } | string, ...rest: [ @@ -642,8 +767,8 @@ export class TablesDB extends Service { (Row extends Models.DefaultRow ? Partial & Record : Partial & Omit)?, - string[]?, - string?, + (string[] | null)?, + (string | null)?, ] ): Promise { let params: { @@ -653,8 +778,8 @@ export class TablesDB extends Service { data: Row extends Models.DefaultRow ? Partial & Record : Partial & Omit; - permissions?: string[]; - transactionId?: string; + permissions?: string[] | null; + transactionId?: string | null; }; if ( @@ -669,8 +794,8 @@ export class TablesDB extends Service { data: Row extends Models.DefaultRow ? Partial & Record : Partial & Omit; - permissions?: string[]; - transactionId?: string; + permissions?: string[] | null; + transactionId?: string | null; }; } else { params = { @@ -680,8 +805,8 @@ export class TablesDB extends Service { data: rest[2] as Row extends Models.DefaultRow ? Partial & Record : Partial & Omit, - permissions: rest[3] as string[], - transactionId: rest[4] as string, + permissions: rest[3] as string[] | null, + transactionId: rest[4] as string | null, }; } @@ -734,7 +859,7 @@ export class TablesDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -744,6 +869,24 @@ export class TablesDB extends Service { }, apiPayload, ); + const defaults = { + root: 'row', + models: { + row: { + defaults: { + $id: '', + $sequence: '', + $tableId: '', + $databaseId: '', + $createdAt: '', + $updatedAt: '', + $permissions: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -862,7 +1005,7 @@ export class TablesDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -871,6 +1014,24 @@ export class TablesDB extends Service { }, apiPayload, ); + const defaults = { + root: 'row', + models: { + row: { + defaults: { + $id: '', + $sequence: '', + $tableId: '', + $databaseId: '', + $createdAt: '', + $updatedAt: '', + $permissions: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -880,8 +1041,8 @@ export class TablesDB extends Service { * @param {string} params.tableId - Table ID. * @param {string} params.rowId - Row ID. * @param {Row extends Models.DefaultRow ? Partial & Record : Partial & Partial>} params.data - Row data as JSON object. Include all required columns of the row to be created or updated. - * @param {string[]} params.permissions - An array of permissions strings. By default, the current permissions are inherited. [Learn more about permissions](https://appwrite.io/docs/permissions). - * @param {string} params.transactionId - Transaction ID for staging the operation. + * @param {string[] | null} params.permissions - An array of permissions strings. By default, the current permissions are inherited. [Learn more about permissions](https://appwrite.io/docs/permissions). + * @param {string | null} params.transactionId - Transaction ID for staging the operation. * @throws {AppwriteException} * @returns {Promise} */ @@ -892,8 +1053,8 @@ export class TablesDB extends Service { data?: Row extends Models.DefaultRow ? Partial & Record : Partial & Partial>; - permissions?: string[]; - transactionId?: string; + permissions?: string[] | null; + transactionId?: string | null; }): Promise; /** * Create or update a Row. Before using this route, you should create a new table resource using either a [server integration](https://appwrite.io/docs/references/cloud/server-dart/tablesDB#createTable) API or directly from your database console. @@ -902,8 +1063,8 @@ export class TablesDB extends Service { * @param {string} tableId - Table ID. * @param {string} rowId - Row ID. * @param {Row extends Models.DefaultRow ? Partial & Record : Partial & Partial>} data - Row data as JSON object. Include all required columns of the row to be created or updated. - * @param {string[]} permissions - An array of permissions strings. By default, the current permissions are inherited. [Learn more about permissions](https://appwrite.io/docs/permissions). - * @param {string} transactionId - Transaction ID for staging the operation. + * @param {string[] | null} permissions - An array of permissions strings. By default, the current permissions are inherited. [Learn more about permissions](https://appwrite.io/docs/permissions). + * @param {string | null} transactionId - Transaction ID for staging the operation. * @throws {AppwriteException} * @returns {Promise} * @deprecated Use the object parameter style method for a better developer experience. @@ -915,8 +1076,8 @@ export class TablesDB extends Service { data?: Row extends Models.DefaultRow ? Partial & Record : Partial & Partial>, - permissions?: string[], - transactionId?: string, + permissions?: string[] | null, + transactionId?: string | null, ): Promise; upsertRow( paramsOrFirst: @@ -928,8 +1089,8 @@ export class TablesDB extends Service { ? Partial & Record : Partial & Partial>; - permissions?: string[]; - transactionId?: string; + permissions?: string[] | null; + transactionId?: string | null; } | string, ...rest: [ @@ -938,8 +1099,8 @@ export class TablesDB extends Service { (Row extends Models.DefaultRow ? Partial & Record : Partial & Partial>)?, - string[]?, - string?, + (string[] | null)?, + (string | null)?, ] ): Promise { let params: { @@ -949,8 +1110,8 @@ export class TablesDB extends Service { data?: Row extends Models.DefaultRow ? Partial & Record : Partial & Partial>; - permissions?: string[]; - transactionId?: string; + permissions?: string[] | null; + transactionId?: string | null; }; if ( @@ -966,8 +1127,8 @@ export class TablesDB extends Service { ? Partial & Record : Partial & Partial>; - permissions?: string[]; - transactionId?: string; + permissions?: string[] | null; + transactionId?: string | null; }; } else { params = { @@ -978,8 +1139,8 @@ export class TablesDB extends Service { ? Partial & Record : Partial & Partial>, - permissions: rest[3] as string[], - transactionId: rest[4] as string, + permissions: rest[3] as string[] | null, + transactionId: rest[4] as string | null, }; } @@ -1025,7 +1186,7 @@ export class TablesDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'put', uri, { @@ -1035,6 +1196,24 @@ export class TablesDB extends Service { }, apiPayload, ); + const defaults = { + root: 'row', + models: { + row: { + defaults: { + $id: '', + $sequence: '', + $tableId: '', + $databaseId: '', + $createdAt: '', + $updatedAt: '', + $permissions: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1044,8 +1223,8 @@ export class TablesDB extends Service { * @param {string} params.tableId - Table ID. * @param {string} params.rowId - Row ID. * @param {Row extends Models.DefaultRow ? Partial & Record : Partial & Partial>} params.data - Row data as JSON object. Include only columns and value pairs to be updated. - * @param {string[]} params.permissions - An array of permissions strings. By default, the current permissions are inherited. [Learn more about permissions](https://appwrite.io/docs/permissions). - * @param {string} params.transactionId - Transaction ID for staging the operation. + * @param {string[] | null} params.permissions - An array of permissions strings. By default, the current permissions are inherited. [Learn more about permissions](https://appwrite.io/docs/permissions). + * @param {string | null} params.transactionId - Transaction ID for staging the operation. * @throws {AppwriteException} * @returns {Promise} */ @@ -1056,8 +1235,8 @@ export class TablesDB extends Service { data?: Row extends Models.DefaultRow ? Partial & Record : Partial & Partial>; - permissions?: string[]; - transactionId?: string; + permissions?: string[] | null; + transactionId?: string | null; }): Promise; /** * Update a row by its unique ID. Using the patch method you can pass only specific fields that will get updated. @@ -1066,8 +1245,8 @@ export class TablesDB extends Service { * @param {string} tableId - Table ID. * @param {string} rowId - Row ID. * @param {Row extends Models.DefaultRow ? Partial & Record : Partial & Partial>} data - Row data as JSON object. Include only columns and value pairs to be updated. - * @param {string[]} permissions - An array of permissions strings. By default, the current permissions are inherited. [Learn more about permissions](https://appwrite.io/docs/permissions). - * @param {string} transactionId - Transaction ID for staging the operation. + * @param {string[] | null} permissions - An array of permissions strings. By default, the current permissions are inherited. [Learn more about permissions](https://appwrite.io/docs/permissions). + * @param {string | null} transactionId - Transaction ID for staging the operation. * @throws {AppwriteException} * @returns {Promise} * @deprecated Use the object parameter style method for a better developer experience. @@ -1079,8 +1258,8 @@ export class TablesDB extends Service { data?: Row extends Models.DefaultRow ? Partial & Record : Partial & Partial>, - permissions?: string[], - transactionId?: string, + permissions?: string[] | null, + transactionId?: string | null, ): Promise; updateRow( paramsOrFirst: @@ -1092,8 +1271,8 @@ export class TablesDB extends Service { ? Partial & Record : Partial & Partial>; - permissions?: string[]; - transactionId?: string; + permissions?: string[] | null; + transactionId?: string | null; } | string, ...rest: [ @@ -1102,8 +1281,8 @@ export class TablesDB extends Service { (Row extends Models.DefaultRow ? Partial & Record : Partial & Partial>)?, - string[]?, - string?, + (string[] | null)?, + (string | null)?, ] ): Promise { let params: { @@ -1113,8 +1292,8 @@ export class TablesDB extends Service { data?: Row extends Models.DefaultRow ? Partial & Record : Partial & Partial>; - permissions?: string[]; - transactionId?: string; + permissions?: string[] | null; + transactionId?: string | null; }; if ( @@ -1130,8 +1309,8 @@ export class TablesDB extends Service { ? Partial & Record : Partial & Partial>; - permissions?: string[]; - transactionId?: string; + permissions?: string[] | null; + transactionId?: string | null; }; } else { params = { @@ -1142,8 +1321,8 @@ export class TablesDB extends Service { ? Partial & Record : Partial & Partial>, - permissions: rest[3] as string[], - transactionId: rest[4] as string, + permissions: rest[3] as string[] | null, + transactionId: rest[4] as string | null, }; } @@ -1189,7 +1368,7 @@ export class TablesDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'patch', uri, { @@ -1199,6 +1378,24 @@ export class TablesDB extends Service { }, apiPayload, ); + const defaults = { + root: 'row', + models: { + row: { + defaults: { + $id: '', + $sequence: '', + $tableId: '', + $databaseId: '', + $createdAt: '', + $updatedAt: '', + $permissions: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1324,8 +1521,8 @@ export class TablesDB extends Service { * @param {string} params.rowId - Row ID. * @param {string} params.column - Column key. * @param {number} params.value - Value to increment the column by. The value must be a number. - * @param {number} params.min - Minimum value for the column. If the current value is lesser than this value, an exception will be thrown. - * @param {string} params.transactionId - Transaction ID for staging the operation. + * @param {number | null} params.min - Minimum value for the column. If the current value is lesser than this value, an exception will be thrown. + * @param {string | null} params.transactionId - Transaction ID for staging the operation. * @throws {AppwriteException} * @returns {Promise} */ @@ -1335,8 +1532,8 @@ export class TablesDB extends Service { rowId: string; column: string; value?: number; - min?: number; - transactionId?: string; + min?: number | null; + transactionId?: string | null; }): Promise; /** * Decrement a specific column of a row by a given value. @@ -1346,8 +1543,8 @@ export class TablesDB extends Service { * @param {string} rowId - Row ID. * @param {string} column - Column key. * @param {number} value - Value to increment the column by. The value must be a number. - * @param {number} min - Minimum value for the column. If the current value is lesser than this value, an exception will be thrown. - * @param {string} transactionId - Transaction ID for staging the operation. + * @param {number | null} min - Minimum value for the column. If the current value is lesser than this value, an exception will be thrown. + * @param {string | null} transactionId - Transaction ID for staging the operation. * @throws {AppwriteException} * @returns {Promise} * @deprecated Use the object parameter style method for a better developer experience. @@ -1358,8 +1555,8 @@ export class TablesDB extends Service { rowId: string, column: string, value?: number, - min?: number, - transactionId?: string, + min?: number | null, + transactionId?: string | null, ): Promise; decrementRowColumn( paramsOrFirst: @@ -1369,11 +1566,18 @@ export class TablesDB extends Service { rowId: string; column: string; value?: number; - min?: number; - transactionId?: string; + min?: number | null; + transactionId?: string | null; } | string, - ...rest: [string?, string?, string?, number?, number?, string?] + ...rest: [ + string?, + string?, + string?, + number?, + (number | null)?, + (string | null)?, + ] ): Promise { let params: { databaseId: string; @@ -1381,8 +1585,8 @@ export class TablesDB extends Service { rowId: string; column: string; value?: number; - min?: number; - transactionId?: string; + min?: number | null; + transactionId?: string | null; }; if ( @@ -1396,8 +1600,8 @@ export class TablesDB extends Service { rowId: string; column: string; value?: number; - min?: number; - transactionId?: string; + min?: number | null; + transactionId?: string | null; }; } else { params = { @@ -1406,8 +1610,8 @@ export class TablesDB extends Service { rowId: rest[1] as string, column: rest[2] as string, value: rest[3] as number, - min: rest[4] as number, - transactionId: rest[5] as string, + min: rest[4] as number | null, + transactionId: rest[5] as string | null, }; } @@ -1460,7 +1664,7 @@ export class TablesDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'patch', uri, { @@ -1470,6 +1674,24 @@ export class TablesDB extends Service { }, apiPayload, ); + const defaults = { + root: 'row', + models: { + row: { + defaults: { + $id: '', + $sequence: '', + $tableId: '', + $databaseId: '', + $createdAt: '', + $updatedAt: '', + $permissions: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1480,8 +1702,8 @@ export class TablesDB extends Service { * @param {string} params.rowId - Row ID. * @param {string} params.column - Column key. * @param {number} params.value - Value to increment the column by. The value must be a number. - * @param {number} params.max - Maximum value for the column. If the current value is greater than this value, an error will be thrown. - * @param {string} params.transactionId - Transaction ID for staging the operation. + * @param {number | null} params.max - Maximum value for the column. If the current value is greater than this value, an error will be thrown. + * @param {string | null} params.transactionId - Transaction ID for staging the operation. * @throws {AppwriteException} * @returns {Promise} */ @@ -1491,8 +1713,8 @@ export class TablesDB extends Service { rowId: string; column: string; value?: number; - max?: number; - transactionId?: string; + max?: number | null; + transactionId?: string | null; }): Promise; /** * Increment a specific column of a row by a given value. @@ -1502,8 +1724,8 @@ export class TablesDB extends Service { * @param {string} rowId - Row ID. * @param {string} column - Column key. * @param {number} value - Value to increment the column by. The value must be a number. - * @param {number} max - Maximum value for the column. If the current value is greater than this value, an error will be thrown. - * @param {string} transactionId - Transaction ID for staging the operation. + * @param {number | null} max - Maximum value for the column. If the current value is greater than this value, an error will be thrown. + * @param {string | null} transactionId - Transaction ID for staging the operation. * @throws {AppwriteException} * @returns {Promise} * @deprecated Use the object parameter style method for a better developer experience. @@ -1514,8 +1736,8 @@ export class TablesDB extends Service { rowId: string, column: string, value?: number, - max?: number, - transactionId?: string, + max?: number | null, + transactionId?: string | null, ): Promise; incrementRowColumn( paramsOrFirst: @@ -1525,11 +1747,18 @@ export class TablesDB extends Service { rowId: string; column: string; value?: number; - max?: number; - transactionId?: string; + max?: number | null; + transactionId?: string | null; } | string, - ...rest: [string?, string?, string?, number?, number?, string?] + ...rest: [ + string?, + string?, + string?, + number?, + (number | null)?, + (string | null)?, + ] ): Promise { let params: { databaseId: string; @@ -1537,8 +1766,8 @@ export class TablesDB extends Service { rowId: string; column: string; value?: number; - max?: number; - transactionId?: string; + max?: number | null; + transactionId?: string | null; }; if ( @@ -1552,8 +1781,8 @@ export class TablesDB extends Service { rowId: string; column: string; value?: number; - max?: number; - transactionId?: string; + max?: number | null; + transactionId?: string | null; }; } else { params = { @@ -1562,8 +1791,8 @@ export class TablesDB extends Service { rowId: rest[1] as string, column: rest[2] as string, value: rest[3] as number, - max: rest[4] as number, - transactionId: rest[5] as string, + max: rest[4] as number | null, + transactionId: rest[5] as string | null, }; } @@ -1616,7 +1845,7 @@ export class TablesDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'patch', uri, { @@ -1626,5 +1855,23 @@ export class TablesDB extends Service { }, apiPayload, ); + const defaults = { + root: 'row', + models: { + row: { + defaults: { + $id: '', + $sequence: '', + $tableId: '', + $databaseId: '', + $createdAt: '', + $updatedAt: '', + $permissions: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } } diff --git a/src/services/teams.ts b/src/services/teams.ts index a4424fcd..b5cd1362 100644 --- a/src/services/teams.ts +++ b/src/services/teams.ts @@ -1,5 +1,5 @@ import { Service } from '../service'; -import { AppwriteException, Client } from '../client'; +import { AppwriteException, Client, applyDefaults } from '../client'; import type { Models } from '../models'; import type { Payload } from '../client'; @@ -85,7 +85,7 @@ export class Teams extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -94,6 +94,33 @@ export class Teams extends Service { }, apiPayload, ); + const defaults = { + root: 'teamList', + models: { + teamList: { + defaults: { + total: 0, + teams: [], + }, + properties: { + teams: { + items: 'team', + }, + }, + }, + team: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + total: 0, + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -180,7 +207,7 @@ export class Teams extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -190,6 +217,22 @@ export class Teams extends Service { }, apiPayload, ); + const defaults = { + root: 'team', + models: { + team: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + total: 0, + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -243,7 +286,7 @@ export class Teams extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -252,6 +295,22 @@ export class Teams extends Service { }, apiPayload, ); + const defaults = { + root: 'team', + models: { + team: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + total: 0, + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -323,7 +382,7 @@ export class Teams extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'put', uri, { @@ -333,6 +392,22 @@ export class Teams extends Service { }, apiPayload, ); + const defaults = { + root: 'team', + models: { + team: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + total: 0, + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -469,7 +544,7 @@ export class Teams extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -478,6 +553,37 @@ export class Teams extends Service { }, apiPayload, ); + const defaults = { + root: 'appInstallationList', + models: { + appInstallationList: { + defaults: { + total: 0, + installations: [], + }, + properties: { + installations: { + items: 'appInstallation', + }, + }, + }, + appInstallation: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + appId: '', + teamId: '', + scopes: [], + authorizationDetails: [], + createdById: '', + createdByName: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -566,7 +672,7 @@ export class Teams extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -576,6 +682,26 @@ export class Teams extends Service { }, apiPayload, ); + const defaults = { + root: 'appInstallation', + models: { + appInstallation: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + appId: '', + teamId: '', + scopes: [], + authorizationDetails: [], + createdById: '', + createdByName: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -647,7 +773,7 @@ export class Teams extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -656,6 +782,26 @@ export class Teams extends Service { }, apiPayload, ); + const defaults = { + root: 'appInstallation', + models: { + appInstallation: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + appId: '', + teamId: '', + scopes: [], + authorizationDetails: [], + createdById: '', + createdByName: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -663,21 +809,21 @@ export class Teams extends Service { * * @param {string} params.teamId - Team ID. * @param {string} params.installationId - Installation unique ID. - * @param {string} params.authorizationDetails - Authorization details granted to the installation as a JSON array of objects, each with a `type` and app-defined fields. Omit to keep the current value. + * @param {string | null} params.authorizationDetails - Authorization details granted to the installation as a JSON array of objects, each with a `type` and app-defined fields. Omit to keep the current value. * @throws {AppwriteException} * @returns {Promise} */ updateInstallation(params: { teamId: string; installationId: string; - authorizationDetails?: string; + authorizationDetails?: string | null; }): Promise; /** * Update an app installation on a team. Only team members with the owner role can update installations. The installation's granted scopes are refreshed to the scopes the app currently requests; previously issued installation access tokens are revoked. * * @param {string} teamId - Team ID. * @param {string} installationId - Installation unique ID. - * @param {string} authorizationDetails - Authorization details granted to the installation as a JSON array of objects, each with a `type` and app-defined fields. Omit to keep the current value. + * @param {string | null} authorizationDetails - Authorization details granted to the installation as a JSON array of objects, each with a `type` and app-defined fields. Omit to keep the current value. * @throws {AppwriteException} * @returns {Promise} * @deprecated Use the object parameter style method for a better developer experience. @@ -685,22 +831,22 @@ export class Teams extends Service { updateInstallation( teamId: string, installationId: string, - authorizationDetails?: string, + authorizationDetails?: string | null, ): Promise; updateInstallation( paramsOrFirst: | { teamId: string; installationId: string; - authorizationDetails?: string; + authorizationDetails?: string | null; } | string, - ...rest: [string?, string?] + ...rest: [string?, (string | null)?] ): Promise { let params: { teamId: string; installationId: string; - authorizationDetails?: string; + authorizationDetails?: string | null; }; if ( @@ -711,13 +857,13 @@ export class Teams extends Service { params = (paramsOrFirst || {}) as { teamId: string; installationId: string; - authorizationDetails?: string; + authorizationDetails?: string | null; }; } else { params = { teamId: paramsOrFirst as string, installationId: rest[0] as string, - authorizationDetails: rest[1] as string, + authorizationDetails: rest[1] as string | null, }; } @@ -748,7 +894,7 @@ export class Teams extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'put', uri, { @@ -758,6 +904,26 @@ export class Teams extends Service { }, apiPayload, ); + const defaults = { + root: 'appInstallation', + models: { + appInstallation: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + appId: '', + teamId: '', + scopes: [], + authorizationDetails: [], + createdById: '', + createdByName: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -937,7 +1103,7 @@ export class Teams extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -946,6 +1112,43 @@ export class Teams extends Service { }, apiPayload, ); + const defaults = { + root: 'membershipList', + models: { + membershipList: { + defaults: { + total: 0, + memberships: [], + }, + properties: { + memberships: { + items: 'membership', + }, + }, + }, + membership: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + userId: '', + userName: '', + userEmail: '', + userPhone: '', + teamId: '', + teamName: '', + invited: '', + joined: '', + confirm: false, + mfa: false, + userAccessedAt: '', + roles: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -965,6 +1168,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 +1180,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 +1199,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 +1212,7 @@ export class Teams extends Service { phone?: string, url?: string, name?: string, + membershipId?: string, ): Promise; createMembership( paramsOrFirst: @@ -1017,9 +1224,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 +1245,7 @@ export class Teams extends Service { phone?: string; url?: string; name?: string; + membershipId?: string; }; if ( @@ -1044,6 +1261,7 @@ export class Teams extends Service { phone?: string; url?: string; name?: string; + membershipId?: string; }; } else { params = { @@ -1054,6 +1272,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 +1283,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,8 +1323,12 @@ export class Teams extends Service { apiPayload['name'] = name; } + if (typeof membershipId !== 'undefined') { + apiPayload['membershipId'] = membershipId; + } + const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -1114,6 +1338,32 @@ export class Teams extends Service { }, apiPayload, ); + const defaults = { + root: 'membership', + models: { + membership: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + userId: '', + userName: '', + userEmail: '', + userPhone: '', + teamId: '', + teamName: '', + invited: '', + joined: '', + confirm: false, + mfa: false, + userAccessedAt: '', + roles: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1185,7 +1435,7 @@ export class Teams extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -1194,6 +1444,32 @@ export class Teams extends Service { }, apiPayload, ); + const defaults = { + root: 'membership', + models: { + membership: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + userId: '', + userName: '', + userEmail: '', + userPhone: '', + teamId: '', + teamName: '', + invited: '', + joined: '', + confirm: false, + mfa: false, + userAccessedAt: '', + roles: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1283,7 +1559,7 @@ export class Teams extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'patch', uri, { @@ -1293,6 +1569,32 @@ export class Teams extends Service { }, apiPayload, ); + const defaults = { + root: 'membership', + models: { + membership: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + userId: '', + userName: '', + userEmail: '', + userPhone: '', + teamId: '', + teamName: '', + invited: '', + joined: '', + confirm: false, + mfa: false, + userAccessedAt: '', + roles: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1490,7 +1792,7 @@ export class Teams extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'patch', uri, { @@ -1500,6 +1802,32 @@ export class Teams extends Service { }, apiPayload, ); + const defaults = { + root: 'membership', + models: { + membership: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + userId: '', + userName: '', + userEmail: '', + userPhone: '', + teamId: '', + teamName: '', + invited: '', + joined: '', + confirm: false, + mfa: false, + userAccessedAt: '', + roles: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** diff --git a/src/services/vectors-db.ts b/src/services/vectors-db.ts index 710e8b44..61b4df27 100644 --- a/src/services/vectors-db.ts +++ b/src/services/vectors-db.ts @@ -1,5 +1,5 @@ import { Service } from '../service'; -import { AppwriteException, Client } from '../client'; +import { AppwriteException, Client, applyDefaults } from '../client'; import type { Models } from '../models'; import type { Payload } from '../client'; @@ -71,7 +71,7 @@ export class VectorsDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -80,6 +80,34 @@ export class VectorsDB extends Service { }, apiPayload, ); + const defaults = { + root: 'transactionList', + models: { + transactionList: { + defaults: { + total: 0, + transactions: [], + }, + properties: { + transactions: { + items: 'transaction', + }, + }, + }, + transaction: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + status: 'pending', + operations: 0, + expiresAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -127,7 +155,7 @@ export class VectorsDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -137,6 +165,23 @@ export class VectorsDB extends Service { }, apiPayload, ); + const defaults = { + root: 'transaction', + models: { + transaction: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + status: 'pending', + operations: 0, + expiresAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -190,7 +235,7 @@ export class VectorsDB extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -199,6 +244,23 @@ export class VectorsDB extends Service { }, apiPayload, ); + const defaults = { + root: 'transaction', + models: { + transaction: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + status: 'pending', + operations: 0, + expiresAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -285,7 +347,7 @@ export class VectorsDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'patch', uri, { @@ -295,6 +357,23 @@ export class VectorsDB extends Service { }, apiPayload, ); + const defaults = { + root: 'transaction', + models: { + transaction: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + status: 'pending', + operations: 0, + expiresAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -427,7 +506,7 @@ export class VectorsDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -437,6 +516,23 @@ export class VectorsDB extends Service { }, apiPayload, ); + const defaults = { + root: 'transaction', + models: { + transaction: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + status: 'pending', + operations: 0, + expiresAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -573,7 +669,7 @@ export class VectorsDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -582,6 +678,35 @@ export class VectorsDB extends Service { }, apiPayload, ); + const defaults = { + root: 'documentList', + models: { + documentList: { + defaults: { + total: 0, + documents: [], + }, + properties: { + documents: { + items: 'document', + }, + }, + }, + document: { + defaults: { + $id: '', + $sequence: '', + $collectionId: '', + $databaseId: '', + $createdAt: '', + $updatedAt: '', + $permissions: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -753,7 +878,7 @@ export class VectorsDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -763,6 +888,24 @@ export class VectorsDB extends Service { }, apiPayload, ); + const defaults = { + root: 'document', + models: { + document: { + defaults: { + $id: '', + $sequence: '', + $collectionId: '', + $databaseId: '', + $createdAt: '', + $updatedAt: '', + $permissions: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -901,7 +1044,7 @@ export class VectorsDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -911,6 +1054,35 @@ export class VectorsDB extends Service { }, apiPayload, ); + const defaults = { + root: 'documentList', + models: { + documentList: { + defaults: { + total: 0, + documents: [], + }, + properties: { + documents: { + items: 'document', + }, + }, + }, + document: { + defaults: { + $id: '', + $sequence: '', + $collectionId: '', + $databaseId: '', + $createdAt: '', + $updatedAt: '', + $permissions: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1040,7 +1212,7 @@ export class VectorsDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -1049,6 +1221,24 @@ export class VectorsDB extends Service { }, apiPayload, ); + const defaults = { + root: 'document', + models: { + document: { + defaults: { + $id: '', + $sequence: '', + $collectionId: '', + $databaseId: '', + $createdAt: '', + $updatedAt: '', + $permissions: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1218,7 +1408,7 @@ export class VectorsDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'put', uri, { @@ -1228,6 +1418,24 @@ export class VectorsDB extends Service { }, apiPayload, ); + const defaults = { + root: 'document', + models: { + document: { + defaults: { + $id: '', + $sequence: '', + $collectionId: '', + $databaseId: '', + $createdAt: '', + $updatedAt: '', + $permissions: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1397,7 +1605,7 @@ export class VectorsDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'patch', uri, { @@ -1407,6 +1615,24 @@ export class VectorsDB extends Service { }, apiPayload, ); + const defaults = { + root: 'document', + models: { + document: { + defaults: { + $id: '', + $sequence: '', + $collectionId: '', + $databaseId: '', + $createdAt: '', + $updatedAt: '', + $permissions: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** diff --git a/src/topic.ts b/src/topic.ts deleted file mode 100644 index cd6cea01..00000000 --- a/src/topic.ts +++ /dev/null @@ -1,103 +0,0 @@ -/** - * Validate the levels passed to `path()`: a non-empty array of non-empty strings, none holding - * the level separator `/` or the wildcards `+` and `#` (use `any()` and `all()` for those). - */ -function levelsOf(levels: unknown): string[] { - if (!Array.isArray(levels)) { - throw new Error("path() expects an array, e.g. path(['user'])"); - } - if (levels.length === 0) { - throw new Error('path() needs at least one level'); - } - return levels.map((level: unknown, index: number) => { - if (typeof level !== 'string') { - const type = level === null ? 'null' : typeof level; - throw new Error( - `level at index ${index} must be a string, got ${type}`, - ); - } - if (level === '') { - throw new Error(`empty level at index ${index}`); - } - if (level.includes('/')) { - const parts = level - .split('/') - .map((part) => `'${part}'`) - .join(', '); - throw new Error( - `"${level}" contains "/", split it: path([${parts}])`, - ); - } - if (level === '+') { - throw new Error('"+" is reserved, use any()'); - } - if (level.includes('+')) { - throw new Error(`"${level}" contains "+", use any() for wildcards`); - } - if (level === '#') { - throw new Error('"#" is reserved, use all()'); - } - if (level.includes('#')) { - throw new Error(`"${level}" contains "#", use all() for wildcards`); - } - return level; - }); -} - -/** - * Helper to build MQTT topics for `Push`, level by level. - * - * Topic.path(['user', userId, 'notification']); // "user/123/notification" - * Topic.path(['user']).any().path(['notification']); // "user/+/notification" - * Topic.path(['org']).any().path(['logs']).all(); // "org/+/logs/#" - * - * `any()` matches exactly one level and `all()` everything below, at any depth (including the - * parent itself). `all()` ends the topic, so it returns a {@link ResolvedTopic}. - */ -export class Topic { - private constructor(private readonly levels: readonly string[]) {} - - /** Start a topic with the given levels, e.g. `Topic.path(['user', userId])`. */ - static path(levels: string[]): Topic { - return new Topic(levelsOf(levels)); - } - - /** Start a topic with a single-level wildcard (`+`). */ - static any(): Topic { - return new Topic(['+']); - } - - /** The multi-level wildcard alone (`#`): matches every topic. */ - static all(): ResolvedTopic { - return new ResolvedTopic(['#']); - } - - /** Append the given levels. */ - path(levels: string[]): Topic { - return new Topic([...this.levels, ...levelsOf(levels)]); - } - - /** Append a single-level wildcard (`+`): matches exactly one level. */ - any(): Topic { - return new Topic([...this.levels, '+']); - } - - /** Append the multi-level wildcard (`#`) and end the topic. */ - all(): ResolvedTopic { - return new ResolvedTopic([...this.levels, '#']); - } - - toString(): string { - return this.levels.join('/'); - } -} - -/** A topic ended by `all()`: nothing can be appended after the `#` wildcard. */ -export class ResolvedTopic { - /** @internal Created by {@link Topic.all}. */ - constructor(private readonly levels: readonly string[]) {} - - toString(): string { - return this.levels.join('/'); - } -} From 5b1e51fadda9c8e4cdf92cc22a0c1a95faeaca71 Mon Sep 17 00:00:00 2001 From: Chirag Aggarwal Date: Wed, 14 Oct 2026 18:22:49 +0100 Subject: [PATCH 4/6] feat: SDK update for the 2.5.x majors --- CHANGELOG.md | 70 +- README.md | 19 +- .../io/appwrite/services/PushBackground.kt | 35 +- .../java/io/appwrite/services/PushBridge.kt | 3 +- .../java/io/appwrite/services/PushCore.kt | 25 +- .../account/create-o-auth-2-session.md | 1 + .../examples/account/create-o-auth-2-token.md | 1 + docs/examples/account/create-passkey-token.md | 13 + docs/examples/account/create-passkey.md | 16 + docs/examples/account/delete-passkey.md | 15 + docs/examples/account/get-passkey.md | 15 + docs/examples/account/list-passkeys.md | 16 + docs/examples/account/update-passkey-token.md | 16 + .../account/update-passkey-verification.md | 16 + docs/examples/account/update-passkey.md | 16 + docs/examples/analytics/create-event.md | 27 + docs/examples/oauth2/authorize-post.md | 2 +- docs/examples/oauth2/authorize.md | 2 +- .../oauth2/create-device-authorization.md | 2 +- docs/examples/oauth2/create-par.md | 2 +- docs/examples/oauth2/create-token.md | 2 +- docs/examples/teams/create-membership.md | 1 + package-lock.json | 4 +- package.json | 2 +- src/client.ts | 57 +- src/index.ts | 1 + src/models.ts | 176 +- src/services/account.ts | 2423 ++++++++++++++++- src/services/analytics.ts | 260 ++ src/services/apps.ts | 572 +++- src/services/databases.ts | 449 ++- src/services/documents-db.ts | 290 +- src/services/functions.ts | 160 +- src/services/locale.ts | 211 +- src/services/messaging.ts | 23 +- src/services/oauth-2.ts | 340 ++- src/services/organization.ts | 123 +- src/services/presences.ts | 89 +- src/services/push.ts | 93 +- src/services/storage.ts | 118 +- src/services/tables-db.ts | 449 ++- src/services/teams.ts | 376 ++- src/services/vectors-db.ts | 250 +- 43 files changed, 6145 insertions(+), 636 deletions(-) create mode 100644 docs/examples/account/create-passkey-token.md create mode 100644 docs/examples/account/create-passkey.md create mode 100644 docs/examples/account/delete-passkey.md create mode 100644 docs/examples/account/get-passkey.md create mode 100644 docs/examples/account/list-passkeys.md create mode 100644 docs/examples/account/update-passkey-token.md create mode 100644 docs/examples/account/update-passkey-verification.md create mode 100644 docs/examples/account/update-passkey.md create mode 100644 docs/examples/analytics/create-event.md create mode 100644 src/services/analytics.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index c6c7bcb3..dccb73a7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,50 +1,32 @@ # Change log -## 1.2.0-rc.4 - -* Fixed: `host()` resolves with the live connection state instead of always `null` -* Fixed: `onConnection(false)` fires when a retired or background connection closes -* Fixed: notification taps are recorded after launching the app, so tap-opened screens land on top -* Fixed: `host()` reports `false` when there was nothing to subscribe instead of a spurious open - -## 1.2.0-rc.3 - -* Added: `getInitialNotification()`, `onNotificationOpened()`, and the `PushNotificationOpened` type (topic + data) -* Added: live push connection open/close events surfaced via `onOpen`/`onClose` -* Fixed: notification taps delivered reliably once, via a `PushTaps` queue -* Fixed: foreground notifications de-duplicated per title -* Updated: `resume` leaves a live Push host's connection untouched - -## 1.2.0-rc.2 - -* Added: `Push.getInitialNotification()` returns the notification whose tap launched the app -* Added: `Push.onNotificationOpened(callback)` fires on each notification tap -* Added: `Push.backgroundStatus()` reports Android exact-alarm, battery, and foreground-service state -* Added: `Push.requestExactAlarms()` and `Push.requestIgnoreBatteryOptimizations()` helpers -* Added: `SubscribeOptions.notifyInForeground` to post notifications while the app is visible -* Added: `PushBackgroundStatus` and `PushNotificationOpened` exported types -* Fixed: reliable Android background wake-ups via a periodic watchdog and alternating jobs -* Fixed: `resume` keeps subscriptions only for the same signed-in user -* Fixed: notification images are size-capped to prevent out-of-memory crashes - -## 1.2.0-rc.1 - -* Added: background push notifications render the server `notification` title, body, and image -* Added: Android shows notification images (BigPictureStyle) and long bodies (BigTextStyle) -* Added: the SDK requests Android 13+ `POST_NOTIFICATIONS` itself on first background subscribe -* Added: notification `data` now carries `topic` and `payload` -* Fixed: a server-sent title dedupes to one notification per topic instead of one per subscription - -## 1.2.0-rc.0 - -* Added: `Apps` service to manage OAuth2 apps, keys, secrets, and installations -* Added: `Oauth2` service for authorization, consent, device, PAR, and token flows -* Added: `Push` service for MQTT realtime push with Android background delivery -* Added: `Topic` builder and native TCP modules for push -* Added: `Avatars.updatePhoto()` and `Avatars.deletePhoto()` methods -* Added: `App`, `Oauth2*`, and `Account` models +## 2.0.0 + +* Breaking: requests send `X-Appwrite-Response-Format: 2.5.0`; responses follow the 2.5 shapes +* Breaking: missing response fields are filled with their documented defaults +* Breaking: nullable model fields are typed `T | null`, such as `Locale.city` and `Presence.status` +* Breaking: the package ships native Android and iOS modules, so apps need a native rebuild and do not run in Expo Go +* Added: `Apps` service to manage apps, installations, keys and secrets +* Added: `Oauth2` service for the OAuth2 authorize, token, device and grant flows +* Added: `Push` service, with optional peers `expo-notifications`, `react-native-background-actions` and `react-native-tcp-socket` +* Added: `Topic` helper + +## 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 -* Fixed: cookie session fallback is guarded to Expo web where `localStorage` exists +* 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` +* Added: `account.createPasskeyToken` and `account.updatePasskeyToken` for passkey sign-in +* Added: `Passkey`, `PasskeyList`, `PasskeyChallenge` and `TokenSecret` models ## 1.1.0 diff --git a/README.md b/README.md index 0ba50f82..53074f8a 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,12 @@ # Appwrite React Native SDK ![License](https://img.shields.io/github/license/appwrite/sdk-for-react-native.svg?style=flat-square) -![Version](https://img.shields.io/badge/api%20version-2.3.0-blue.svg?style=flat-square) +![Version](https://img.shields.io/badge/api%20version-2.5.0-blue.svg?style=flat-square) [![Build Status](https://img.shields.io/travis/com/appwrite/sdk-generator?style=flat-square)](https://travis-ci.com/appwrite/sdk-generator) [![Twitter Account](https://img.shields.io/twitter/follow/appwrite?color=00acee&label=twitter&style=flat-square)](https://twitter.com/appwrite) [![Discord](https://img.shields.io/discord/564160730845151244?label=discord&style=flat-square)](https://appwrite.io/discord) -**This SDK targets Appwrite server version 2.3.x as shipped on Appwrite Cloud.** Self-hosted releases can lag behind Cloud — if you run an older self-hosted build, use a matching older SDK from [previous releases](https://github.com/appwrite/sdk-for-react-native/releases) when APIs differ. +**This SDK targets Appwrite server version 2.5.x as shipped on Appwrite Cloud.** Self-hosted releases can lag behind Cloud — if you run an older self-hosted build, use a matching older SDK from [previous releases](https://github.com/appwrite/sdk-for-react-native/releases) when APIs differ. Appwrite is an open-source backend as a service server that abstracts and simplifies complex and repetitive development tasks behind a very simple to use REST API. Appwrite aims to help you develop your apps faster and in a more secure way. Use the React Native SDK to integrate your app with the Appwrite server to easily start interacting with all of Appwrite backend APIs and tools. For full API documentation and tutorials go to [https://appwrite.io/docs](https://appwrite.io/docs) @@ -45,7 +45,9 @@ than a short-lived JWT. On Android 13 and later, the first background subscription asks the user for the `POST_NOTIFICATIONS` runtime permission. If they decline, the subscription still delivers to your callback but posts no notification. Notifications show the title, body and image sent with -`createPush`, and fall back to the subscription's `title` and the raw payload for other messages. +`createPush`, falling back to the subscription's `title` when only a body is sent. A push with no +title or body, such as a data-only push, posts no notification and reaches only your callback. +Messages that are not a JSON object show the subscription's `title` with the raw payload as the body. ```js const sub = await push.subscribe('news', (message) => console.log(message.data), { @@ -93,6 +95,13 @@ With Expo, list them under `android.permissions` in `app.json` instead. nothing to ask, including when the permission is not declared. The SDK never opens these screens on its own. +If `backgroundRestricted` is true, the user restricted the app's background usage and messages can +wait until the app is opened. Exact alarms don't lift it, and neither does foreground mode: Android +stops a restricted app's foreground service once it leaves the screen. Ask the user to choose +Unrestricted in the app's battery settings (Settings > Apps > your app > Battery); granting the +battery optimisation exemption also lets the SDK's alarms and jobs run, and `bestEffort` then +reflects only the exact-alarm state. It is always false below Android 9. + If the user force-stops the app (Settings > Force stop, and on some devices swiping it away from recents), Android cancels its alarms and jobs: nothing is delivered until the app is opened again, and the broker then replays what was sent meanwhile. @@ -103,7 +112,9 @@ Set the notification icon with ```js const status = await push.backgroundStatus(); // null outside Android -if (status?.bestEffort) { +if (status?.backgroundRestricted && !status.ignoringBatteryOptimizations) { + // Ask the user to choose Unrestricted in the app's battery settings. +} else if (status?.bestEffort) { // Explain why, then from a button press: await push.requestExactAlarms(); } diff --git a/android/src/main/java/io/appwrite/services/PushBackground.kt b/android/src/main/java/io/appwrite/services/PushBackground.kt index e06dfabe..73103d5d 100644 --- a/android/src/main/java/io/appwrite/services/PushBackground.kt +++ b/android/src/main/java/io/appwrite/services/PushBackground.kt @@ -52,8 +52,15 @@ import java.util.concurrent.atomic.AtomicInteger private const val LOG_TAG = "AppwritePush" -/** What a message's `notification` block asks a background notification to show; [present] is false without one. */ -internal data class PushNotificationContent(val present: Boolean, val title: String?, val body: String?, val image: String?) +/** + * What a message asks a background notification to show. A [raw] payload, one that is not a JSON + * object, is shown as the body under the subscription's title; an envelope is [visible] only with a + * title or body in its `notification`. + */ +internal data class PushNotificationContent(val raw: Boolean, val title: String?, val body: String?, val image: String?) { + val visible: Boolean + get() = raw || title != null || body != null +} /** A background subscription saved across restarts: its filter, QoS choice and notification title. */ internal data class PushEntry( @@ -887,7 +894,7 @@ internal object PushBackground { // Deliver a message to the matching live callbacks; with none, to the declared PushReceiver // and/or a notification per saved subscription that matches it. [deferAck] hands a listener // that acknowledges messages itself its acknowledgement. - private fun deliverMessage(context: Context, message: PushMessage, deferAck: () -> () -> Unit) { + internal fun deliverMessage(context: Context, message: PushMessage, deferAck: () -> () -> Unit) { val matching = listeners.filter { listener -> listener.topics.any { matchesTopic(it, message.topic) } } // Saved background subscriptions no live one has taken over; they deliver even when a live // foreground-only subscription on an overlapping filter received the message too. @@ -952,16 +959,21 @@ internal object PushBackground { /** * Post a notification for [message] that opens the app, with the message in its extras. It shows - * the server's title, body and image from [content], falling back to [title] and the raw payload. + * the server's title, body and image from [content], falling back to [title], and to the payload + * as the body when it is not a JSON object. An envelope with neither a title nor a body, such as + * a data-only push, posts nothing. */ fun notify(context: Context, message: PushMessage, title: String, content: PushNotificationContent = notificationContent(message)) { + if (!content.visible) { + return + } val manager = NotificationManagerCompat.from(context) if (!manager.areNotificationsEnabled()) { return } createChannels(context) val id = 31 * message.hashCode() + title.hashCode() - val body = content.body ?: message.data.takeIf { !content.present } + val body = content.body ?: message.data.takeIf { content.raw } val builder = NotificationCompat.Builder(context, CHANNEL_ID) .setContentTitle(content.title ?: title) .setSmallIcon(notificationIcon(context)) @@ -992,12 +1004,13 @@ internal object PushBackground { .also { ActivityManager.getMyMemoryState(it) } .importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND - /** The server's `notification` block in [message]: nulls when the payload has none or is not JSON. */ + /** The server's `notification` block in [message], [PushNotificationContent.raw] when the payload is not a JSON object. */ fun notificationContent(message: PushMessage): PushNotificationContent { - val notification = runCatching { JSONObject(message.data) }.getOrNull()?.optJSONObject("notification") - ?: return PushNotificationContent(false, null, null, null) - fun field(name: String) = (notification.opt(name) as? String)?.takeIf { it.isNotEmpty() } - return PushNotificationContent(true, field("title"), field("body"), field("image")) + val envelope = runCatching { JSONObject(message.data) }.getOrNull() + ?: return PushNotificationContent(true, null, null, null) + val notification = envelope.optJSONObject("notification") + fun field(name: String) = (notification?.opt(name) as? String)?.takeIf { it.isNotEmpty() } + return PushNotificationContent(false, field("title"), field("body"), field("image")) } // Downloads notification images, so a slow one is abandoned without holding up delivery. @@ -1201,6 +1214,8 @@ internal object PushBackground { app.getSystemService(AlarmManager::class.java)?.canScheduleExactAlarms() == true, ignoringBatteryOptimizations = app.getSystemService(PowerManager::class.java)?.isIgnoringBatteryOptimizations(app.packageName) == true, foregroundService = PushStore.foreground(app), + backgroundRestricted = Build.VERSION.SDK_INT >= Build.VERSION_CODES.P && + app.getSystemService(ActivityManager::class.java)?.isBackgroundRestricted == true, ) } diff --git a/android/src/main/java/io/appwrite/services/PushBridge.kt b/android/src/main/java/io/appwrite/services/PushBridge.kt index e5cb5aae..980214bb 100644 --- a/android/src/main/java/io/appwrite/services/PushBridge.kt +++ b/android/src/main/java/io/appwrite/services/PushBridge.kt @@ -169,12 +169,13 @@ class PushBridge(context: Context, private val events: Events) { return if (registered) PushStore.takeStoppedError(appContext) else null } - /** What background delivery can rely on, as `{"exactAlarms", "ignoringBatteryOptimizations", "foregroundService", "bestEffort"}`. */ + /** What background delivery can rely on, as `{"exactAlarms", "ignoringBatteryOptimizations", "foregroundService", "backgroundRestricted", "bestEffort"}`. */ fun backgroundStatus(): String = PushBackground.backgroundStatus(appContext).let { JSONObject() .put("exactAlarms", it.exactAlarms) .put("ignoringBatteryOptimizations", it.ignoringBatteryOptimizations) .put("foregroundService", it.foregroundService) + .put("backgroundRestricted", it.backgroundRestricted) .put("bestEffort", it.bestEffort) .toString() } diff --git a/android/src/main/java/io/appwrite/services/PushCore.kt b/android/src/main/java/io/appwrite/services/PushCore.kt index 15f86b6a..bc151295 100644 --- a/android/src/main/java/io/appwrite/services/PushCore.kt +++ b/android/src/main/java/io/appwrite/services/PushCore.kt @@ -54,19 +54,36 @@ data class PushMessage( /** * What background delivery can rely on. Without exact alarms, the scheduled wake-ups are inexact * and Doze can defer them, so delivery is [bestEffort] unless foreground mode keeps the - * connection open. + * connection open. When the user restricted background usage, delivery is [bestEffort] unless the + * app is also exempt from battery optimisation, and foreground mode no longer counts: Android stops + * a restricted app's foreground service once it leaves the screen, exemption or not. */ -data class PushBackgroundStatus( +data class PushBackgroundStatus @JvmOverloads constructor( /** The app may schedule exact alarms (`SCHEDULE_EXACT_ALARM`, granted). */ val exactAlarms: Boolean, /** The app is exempt from battery optimisation. */ val ignoringBatteryOptimizations: Boolean, /** Foreground mode (`setForeground(true)`) keeps the connection open in a service. */ val foregroundService: Boolean, + /** + * The user restricted the app's background usage in its battery settings (Android 9+). Android + * may then hold its alarms, jobs and foreground service while it is closed, so messages can + * wait until the app is opened. The battery-optimisation exemption lets the alarms and jobs + * run again, but foreground mode still stops once the app leaves the screen. + */ + val backgroundRestricted: Boolean = false, ) { - /** Wake-ups may be deferred by Doze, so messages can arrive late while the app is closed. */ + /** + * Messages can arrive late, or not until the app is opened, while the app is closed: background + * usage is restricted without the battery-optimisation exemption, or wake-ups may be deferred + * by Doze. + */ val bestEffort: Boolean - get() = !exactAlarms && !foregroundService + get() { + val held = backgroundRestricted && !ignoringBatteryOptimizations + val foreground = foregroundService && !backgroundRestricted + return held || (!exactAlarms && !foreground) + } } /** Connection parameters shared between the in-process client and the foreground service. */ 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/create-passkey-token.md b/docs/examples/account/create-passkey-token.md new file mode 100644 index 00000000..5695859f --- /dev/null +++ b/docs/examples/account/create-passkey-token.md @@ -0,0 +1,13 @@ +```javascript +import { Client, Account } from 'react-native-appwrite'; + +const client = new Client() + .setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint + .setProject(''); // Your project ID + +const account = new Account(client); + +const result = await account.createPasskeyToken(); + +console.log(result); +``` diff --git a/docs/examples/account/create-passkey.md b/docs/examples/account/create-passkey.md new file mode 100644 index 00000000..66968b14 --- /dev/null +++ b/docs/examples/account/create-passkey.md @@ -0,0 +1,16 @@ +```javascript +import { Client, Account } from 'react-native-appwrite'; + +const client = new Client() + .setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint + .setProject(''); // Your project ID + +const account = new Account(client); + +const result = await account.createPasskey({ + passkeyId: '', // optional + name: '', // optional +}); + +console.log(result); +``` diff --git a/docs/examples/account/delete-passkey.md b/docs/examples/account/delete-passkey.md new file mode 100644 index 00000000..61aec153 --- /dev/null +++ b/docs/examples/account/delete-passkey.md @@ -0,0 +1,15 @@ +```javascript +import { Client, Account } from 'react-native-appwrite'; + +const client = new Client() + .setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint + .setProject(''); // Your project ID + +const account = new Account(client); + +const result = await account.deletePasskey({ + passkeyId: '', +}); + +console.log(result); +``` diff --git a/docs/examples/account/get-passkey.md b/docs/examples/account/get-passkey.md new file mode 100644 index 00000000..04b7f8fb --- /dev/null +++ b/docs/examples/account/get-passkey.md @@ -0,0 +1,15 @@ +```javascript +import { Client, Account } from 'react-native-appwrite'; + +const client = new Client() + .setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint + .setProject(''); // Your project ID + +const account = new Account(client); + +const result = await account.getPasskey({ + passkeyId: '', +}); + +console.log(result); +``` diff --git a/docs/examples/account/list-passkeys.md b/docs/examples/account/list-passkeys.md new file mode 100644 index 00000000..f1f68985 --- /dev/null +++ b/docs/examples/account/list-passkeys.md @@ -0,0 +1,16 @@ +```javascript +import { Client, Account } from 'react-native-appwrite'; + +const client = new Client() + .setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint + .setProject(''); // Your project ID + +const account = new Account(client); + +const result = await account.listPasskeys({ + queries: [], // optional + total: false, // optional +}); + +console.log(result); +``` diff --git a/docs/examples/account/update-passkey-token.md b/docs/examples/account/update-passkey-token.md new file mode 100644 index 00000000..a8e22f7a --- /dev/null +++ b/docs/examples/account/update-passkey-token.md @@ -0,0 +1,16 @@ +```javascript +import { Client, Account } from 'react-native-appwrite'; + +const client = new Client() + .setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint + .setProject(''); // Your project ID + +const account = new Account(client); + +const result = await account.updatePasskeyToken({ + challengeId: '', + credential: {}, +}); + +console.log(result); +``` diff --git a/docs/examples/account/update-passkey-verification.md b/docs/examples/account/update-passkey-verification.md new file mode 100644 index 00000000..c46c0a63 --- /dev/null +++ b/docs/examples/account/update-passkey-verification.md @@ -0,0 +1,16 @@ +```javascript +import { Client, Account } from 'react-native-appwrite'; + +const client = new Client() + .setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint + .setProject(''); // Your project ID + +const account = new Account(client); + +const result = await account.updatePasskeyVerification({ + passkeyId: '', + credential: {}, +}); + +console.log(result); +``` diff --git a/docs/examples/account/update-passkey.md b/docs/examples/account/update-passkey.md new file mode 100644 index 00000000..2f925b98 --- /dev/null +++ b/docs/examples/account/update-passkey.md @@ -0,0 +1,16 @@ +```javascript +import { Client, Account } from 'react-native-appwrite'; + +const client = new Client() + .setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint + .setProject(''); // Your project ID + +const account = new Account(client); + +const result = await account.updatePasskey({ + passkeyId: '', + name: '', +}); + +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/oauth2/authorize-post.md b/docs/examples/oauth2/authorize-post.md index e27aa7e3..f7dd540c 100644 --- a/docs/examples/oauth2/authorize-post.md +++ b/docs/examples/oauth2/authorize-post.md @@ -19,7 +19,7 @@ const result = await oauth2.authorizePost({ prompt: '', // optional maxAge: 0, // optional authorizationDetails: '', // optional - resource: '', // optional + resource: [], // optional audience: '', // optional requestUri: '', // optional }); diff --git a/docs/examples/oauth2/authorize.md b/docs/examples/oauth2/authorize.md index 039dc744..256e9cb6 100644 --- a/docs/examples/oauth2/authorize.md +++ b/docs/examples/oauth2/authorize.md @@ -19,7 +19,7 @@ const result = await oauth2.authorize({ prompt: '', // optional maxAge: 0, // optional authorizationDetails: '', // optional - resource: '', // optional + resource: [], // optional audience: '', // optional requestUri: '', // optional }); diff --git a/docs/examples/oauth2/create-device-authorization.md b/docs/examples/oauth2/create-device-authorization.md index c136011b..1219db51 100644 --- a/docs/examples/oauth2/create-device-authorization.md +++ b/docs/examples/oauth2/create-device-authorization.md @@ -11,7 +11,7 @@ const result = await oauth2.createDeviceAuthorization({ clientId: '', // optional scope: '', // optional authorizationDetails: '', // optional - resource: '', // optional + resource: [], // optional audience: '', // optional }); diff --git a/docs/examples/oauth2/create-par.md b/docs/examples/oauth2/create-par.md index 5d9b5783..425e7a86 100644 --- a/docs/examples/oauth2/create-par.md +++ b/docs/examples/oauth2/create-par.md @@ -19,7 +19,7 @@ const result = await oauth2.createPAR({ prompt: '', // optional maxAge: 0, // optional authorizationDetails: '', // optional - resource: '', // optional + resource: [], // optional audience: '', // optional }); diff --git a/docs/examples/oauth2/create-token.md b/docs/examples/oauth2/create-token.md index 3be9ff4a..567bfb74 100644 --- a/docs/examples/oauth2/create-token.md +++ b/docs/examples/oauth2/create-token.md @@ -16,7 +16,7 @@ const result = await oauth2.createToken({ clientSecret: '', // optional codeVerifier: '', // optional redirectUri: 'https://example.com', // optional - resource: '', // optional + resource: [], // optional audience: '', // optional }); diff --git a/docs/examples/teams/create-membership.md b/docs/examples/teams/create-membership.md index 3c6ee849..9a4828a9 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/package-lock.json b/package-lock.json index 33230e5f..bbf4775e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "react-native-appwrite", - "version": "1.2.0-rc.4", + "version": "2.0.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "react-native-appwrite", - "version": "1.2.0-rc.4", + "version": "2.0.0", "license": "BSD-3-Clause", "dependencies": { "buffer": "6.0.3", diff --git a/package.json b/package.json index 12b4f76a..b36e9cfc 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-rc.4", + "version": "2.0.0", "license": "BSD-3-Clause", "main": "dist/cjs/sdk.js", "exports": { diff --git a/src/client.ts b/src/client.ts index 4bc8575c..df162542 100644 --- a/src/client.ts +++ b/src/client.ts @@ -45,6 +45,59 @@ export const JSONbig = { stringify: JSONbigSerializer.stringify, }; +type DefaultsShape = string | { items: DefaultsShape }; + +type DefaultsModel = { + defaults?: Record; + properties?: Record; +}; + +type Defaults = { + root: DefaultsShape; + models: Record; +}; + +export function applyDefaults(value: T, tree: Defaults): T { + return fillDefaults(value, tree.root, tree.models) as T; +} + +function fillDefaults( + value: unknown, + shape: DefaultsShape, + models: Record, +): unknown { + if (typeof shape !== 'string') { + if (!Array.isArray(value)) { + return value; + } + const items = shape.items; + return value.map((item) => fillDefaults(item, items, models)); + } + const model = models[shape]; + if (!model || typeof value !== 'object' || value === null) { + return value; + } + if (Array.isArray(value)) { + return value; + } + const result: Record = { ...model.defaults, ...value }; + for (const [key, child] of Object.entries(model.properties ?? {})) { + if (key in result) { + result[key] = fillDefaults(result[key], child, models); + } + } + // The spread drops the non-enumerable JSON toString that Client.call attaches. + if (Object.prototype.hasOwnProperty.call(value, 'toString')) { + Object.defineProperty(result, 'toString', { + value: () => JSONbig.stringify(result), + writable: true, + enumerable: false, + configurable: true, + }); + } + return result; +} + type Payload = { [key: string]: any; }; @@ -218,8 +271,8 @@ class Client { 'x-sdk-name': 'React Native', 'x-sdk-platform': 'client', 'x-sdk-language': 'reactnative', - 'x-sdk-version': '1.2.0-rc.4', - 'X-Appwrite-Response-Format': '2.3.0', + 'x-sdk-version': '2.0.0', + 'X-Appwrite-Response-Format': '2.5.0', }; /** diff --git a/src/index.ts b/src/index.ts index 579ed73a..a5b728ec 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 { Apps } from './services/apps'; export { Avatars } from './services/avatars'; export { Databases } from './services/databases'; diff --git a/src/models.ts b/src/models.ts index 09b8b39c..1b754aa9 100644 --- a/src/models.ts +++ b/src/models.ts @@ -338,7 +338,7 @@ export namespace Models { /** * Presence status. */ - status?: string; + status?: string | null; /** * Presence source. */ @@ -346,7 +346,7 @@ export namespace Models { /** * Presence expiry date in ISO 8601 format. */ - expiresAt?: string; + expiresAt?: string | null; /** * Presence metadata. */ @@ -378,15 +378,15 @@ export namespace Models { /** * Hashed user password. */ - password?: string; + password?: string | null; /** * Password hashing algorithm. */ - hash?: string; + hash?: string | null; /** * Password hashing algorithm configuration. */ - hashOptions?: object; + hashOptions?: object | null; /** * User registration date in ISO 8601 format. */ @@ -418,27 +418,27 @@ export namespace Models { /** * Canonical form of the user email address. */ - emailCanonical?: string; + emailCanonical?: string | null; /** * Whether the user email is from a free email provider. */ - emailIsFree?: boolean; + emailIsFree?: boolean | null; /** * Whether the user email is from a disposable email provider. */ - emailIsDisposable?: boolean; + emailIsDisposable?: boolean | null; /** * Whether the user email is from a corporate domain. */ - emailIsCorporate?: boolean; + emailIsCorporate?: boolean | null; /** * Whether the user email is in its canonical form. */ - emailIsCanonical?: boolean; + emailIsCanonical?: boolean | null; /** * 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; + passwordPwned?: boolean | null; /** * Phone verification status. */ @@ -462,11 +462,11 @@ export namespace Models { /** * Whether the user can impersonate other users. */ - impersonator?: boolean; + impersonator?: boolean | null; /** * 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; + impersonatorUserId?: string | null; }; /** @@ -632,27 +632,27 @@ export namespace Models { /** * Canonical form of the user email address. */ - emailCanonical?: string; + emailCanonical?: string | null; /** * Whether the user email is from a free email provider. */ - emailIsFree?: boolean; + emailIsFree?: boolean | null; /** * Whether the user email is from a disposable email provider. */ - emailIsDisposable?: boolean; + emailIsDisposable?: boolean | null; /** * Whether the user email is from a corporate domain. */ - emailIsCorporate?: boolean; + emailIsCorporate?: boolean | null; /** * Whether the user email is in its canonical form. */ - emailIsCanonical?: boolean; + emailIsCanonical?: boolean | null; /** * 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; + passwordPwned?: boolean | null; /** * Phone verification status. */ @@ -676,11 +676,11 @@ export namespace Models { /** * Whether the user can impersonate other users. */ - impersonator?: boolean; + impersonator?: boolean | null; /** * 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; + impersonatorUserId?: string | null; }; /** @@ -940,47 +940,47 @@ export namespace Models { /** * City */ - city?: string; + city?: string | null; /** * Name of timezone */ - timeZone?: string; + timeZone?: string | null; /** * Postal code */ - postalCode?: string; + postalCode?: string | null; /** * Latitude */ - latitude?: number; + latitude?: number | null; /** * Longitude */ - longitude?: number; + longitude?: number | null; /** * Autonomous System Number (ASN) of the IP */ - autonomousSystemNumber?: string; + autonomousSystemNumber?: string | null; /** * Organization that owns the ASN */ - autonomousSystemOrganization?: string; + autonomousSystemOrganization?: string | null; /** * Internet service provider of the IP */ - isp?: string; + isp?: string | null; /** * Connection type of the IP (e.g. cable, cellular, corporate) */ - connectionType?: string; + connectionType?: string | null; /** * User type classification of the IP (e.g. residential, business, hosting) */ - connectionUsageType?: string; + connectionUsageType?: string | null; /** * Registered organization of the IP */ - connectionOrganization?: string; + connectionOrganization?: string | null; }; /** @@ -1244,7 +1244,7 @@ export namespace Models { /** * The scheduled time for execution. If left empty, execution will be queued immediately. */ - scheduledAt?: string; + scheduledAt?: string | null; }; /** @@ -1381,6 +1381,102 @@ export namespace Models { expire: string; }; + /** + * Token Secret + */ + export type TokenSecret = { + /** + * Token ID. + */ + $id: string; + /** + * Token creation date in ISO 8601 format. + */ + $createdAt: string; + /** + * User ID. + */ + userId: string; + /** + * Token secret key. Exchange it for a session with the create session endpoint. + */ + secret: string; + /** + * Token expiration date in ISO 8601 format. + */ + expire: string; + /** + * Security phrase of a token. Empty if security phrase was not requested when creating a token. It includes randomly generated phrase which is also sent in the external resource such as email. + */ + phrase: string; + }; + + /** + * Passkey + */ + export type Passkey = { + /** + * Passkey ID. + */ + $id: string; + /** + * Passkey creation date in ISO 8601 format. + */ + $createdAt: string; + /** + * Passkey update date in ISO 8601 format. + */ + $updatedAt: string; + /** + * Passkey name. + */ + name: string; + /** + * Most recent sign-in with this passkey in ISO 8601 format. Empty until the passkey is used to sign in. + */ + accessedAt: string; + }; + + /** + * Passkey Challenge + */ + export type PasskeyChallenge = { + /** + * Challenge ID. When signing in, pass it back with the credential to receive a token. + */ + $id: string; + /** + * Challenge creation date in ISO 8601 format. + */ + $createdAt: string; + /** + * ID of the passkey being registered. Empty for sign-in challenges. + */ + passkeyId: string; + /** + * Challenge expiration date in ISO 8601 format. + */ + expire: string; + /** + * WebAuthn options in JSON form. Pass them to `PublicKeyCredential.parseCreationOptionsFromJSON()` when registering, or `PublicKeyCredential.parseRequestOptionsFromJSON()` when signing in. + */ + publicKey: object; + }; + + /** + * Passkeys List + */ + export type PasskeyList = { + /** + * Total number of passkeys that matched your query. + */ + total: number; + /** + * List of passkeys. + */ + passkeys: Passkey[]; + }; + /** * MFA Recovery Codes */ @@ -1530,7 +1626,7 @@ export namespace Models { /** * Provider ID. */ - providerId?: string; + providerId?: string | null; /** * The target provider type. Can be one of the following: `email`, `sms` or `push`. */ @@ -1694,7 +1790,7 @@ export namespace Models { /** * Time the secret was last used for authentication in ISO 8601 format. Null if never used. */ - lastAccessedAt?: string; + lastAccessedAt?: string | null; }; /** @@ -1736,7 +1832,7 @@ export namespace Models { /** * Time the secret was last used for authentication in ISO 8601 format. Null if never used. */ - lastAccessedAt?: string; + lastAccessedAt?: string | null; }; /** @@ -1808,7 +1904,7 @@ export namespace Models { /** * Time an access token was last issued for the installation in ISO 8601 format. Null if never used. */ - lastAccessedAt?: string; + lastAccessedAt?: string | null; }; /** @@ -1850,7 +1946,7 @@ export namespace Models { /** * Time the app key was last used for authentication in ISO 8601 format. Null if never used. */ - lastAccessedAt?: string; + lastAccessedAt?: string | null; }; /** @@ -2012,11 +2108,11 @@ export namespace Models { /** * Granted RFC 9396 authorization details as a JSON string. */ - authorization_details?: string; + authorization_details?: string | null; /** * OpenID Connect ID token. Returned when the `openid` scope is granted. */ - id_token?: string; + id_token?: string | null; }; /** diff --git a/src/services/account.ts b/src/services/account.ts index fb3d545b..53e5331f 100644 --- a/src/services/account.ts +++ b/src/services/account.ts @@ -1,5 +1,5 @@ import { Service } from '../service'; -import { AppwriteException, Client } from '../client'; +import { AppwriteException, Client, applyDefaults } from '../client'; import type { Models } from '../models'; import type { Payload } from '../client'; @@ -25,7 +25,7 @@ export class Account extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -34,6 +34,49 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'user', + models: { + user: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + registration: '', + status: true, + labels: [], + passwordUpdate: '', + email: '', + phone: '', + emailVerification: false, + phoneVerification: false, + mfa: false, + targets: [], + accessedAt: '', + }, + properties: { + targets: { + items: 'target', + }, + }, + }, + target: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + userId: '', + providerType: '', + identifier: '', + expired: false, + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -143,7 +186,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -153,6 +196,49 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'user', + models: { + user: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + registration: '', + status: true, + labels: [], + passwordUpdate: '', + email: '', + phone: '', + emailVerification: false, + phoneVerification: false, + mfa: false, + targets: [], + accessedAt: '', + }, + properties: { + targets: { + items: 'target', + }, + }, + }, + target: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + userId: '', + providerType: '', + identifier: '', + expired: false, + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -218,7 +304,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -227,6 +313,38 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'oauth2ConsentList', + models: { + oauth2ConsentList: { + defaults: { + total: 0, + consents: [], + }, + properties: { + consents: { + items: 'oauth2Consent', + }, + }, + }, + oauth2Consent: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + userId: '', + appId: '', + cimdUrl: '', + scopes: [], + resources: [], + authorizationDetails: '[]', + expire: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -278,7 +396,7 @@ export class Account extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -287,6 +405,27 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'oauth2Consent', + models: { + oauth2Consent: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + userId: '', + appId: '', + cimdUrl: '', + scopes: [], + resources: [], + authorizationDetails: '[]', + expire: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -427,7 +566,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -436,6 +575,39 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'oauth2ConsentTokenList', + models: { + oauth2ConsentTokenList: { + defaults: { + total: 0, + tokens: [], + }, + properties: { + tokens: { + items: 'oauth2ConsentToken', + }, + }, + }, + oauth2ConsentToken: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + consentId: '', + userId: '', + appId: '', + cimdUrl: '', + scopes: [], + resources: [], + authorizationDetails: '[]', + expire: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -506,7 +678,7 @@ export class Account extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -515,6 +687,28 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'oauth2ConsentToken', + models: { + oauth2ConsentToken: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + consentId: '', + userId: '', + appId: '', + cimdUrl: '', + scopes: [], + resources: [], + authorizationDetails: '[]', + expire: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -673,7 +867,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'patch', uri, { @@ -683,6 +877,49 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'user', + models: { + user: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + registration: '', + status: true, + labels: [], + passwordUpdate: '', + email: '', + phone: '', + emailVerification: false, + phoneVerification: false, + mfa: false, + targets: [], + accessedAt: '', + }, + properties: { + targets: { + items: 'target', + }, + }, + }, + target: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + userId: '', + providerType: '', + identifier: '', + expired: false, + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -748,7 +985,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -757,6 +994,39 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'identityList', + models: { + identityList: { + defaults: { + total: 0, + identities: [], + }, + properties: { + identities: { + items: 'identity', + }, + }, + }, + identity: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + userId: '', + provider: '', + providerUid: '', + providerEmail: '', + providerAccessToken: '', + providerAccessTokenExpiry: '', + providerRefreshToken: '', + providerIdToken: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -865,7 +1135,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -875,6 +1145,18 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'jwt', + models: { + jwt: { + defaults: { + jwt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -931,7 +1213,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'patch', uri, { @@ -941,6 +1223,49 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'user', + models: { + user: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + registration: '', + status: true, + labels: [], + passwordUpdate: '', + email: '', + phone: '', + emailVerification: false, + phoneVerification: false, + mfa: false, + targets: [], + accessedAt: '', + }, + properties: { + targets: { + items: 'target', + }, + }, + }, + target: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + userId: '', + providerType: '', + identifier: '', + expired: false, + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -994,7 +1319,7 @@ export class Account extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -1004,6 +1329,19 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'mfaType', + models: { + mfaType: { + defaults: { + secret: '', + uri: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1056,7 +1394,7 @@ export class Account extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -1066,6 +1404,19 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'mfaType', + models: { + mfaType: { + defaults: { + secret: '', + uri: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1143,7 +1494,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'put', uri, { @@ -1153,6 +1504,49 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'user', + models: { + user: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + registration: '', + status: true, + labels: [], + passwordUpdate: '', + email: '', + phone: '', + emailVerification: false, + phoneVerification: false, + mfa: false, + targets: [], + accessedAt: '', + }, + properties: { + targets: { + items: 'target', + }, + }, + }, + target: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + userId: '', + providerType: '', + identifier: '', + expired: false, + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1229,7 +1623,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'put', uri, { @@ -1239,6 +1633,49 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'user', + models: { + user: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + registration: '', + status: true, + labels: [], + passwordUpdate: '', + email: '', + phone: '', + emailVerification: false, + phoneVerification: false, + mfa: false, + targets: [], + accessedAt: '', + }, + properties: { + targets: { + items: 'target', + }, + }, + }, + target: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + userId: '', + providerType: '', + identifier: '', + expired: false, + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1416,7 +1853,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -1426,6 +1863,21 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'mfaChallenge', + models: { + mfaChallenge: { + defaults: { + $id: '', + $createdAt: '', + userId: '', + expire: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1481,7 +1933,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -1491,6 +1943,21 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'mfaChallenge', + models: { + mfaChallenge: { + defaults: { + $id: '', + $createdAt: '', + userId: '', + expire: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1566,7 +2033,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'put', uri, { @@ -1576,6 +2043,46 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'session', + models: { + session: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + userId: '', + expire: '', + provider: '', + providerUid: '', + providerAccessToken: '', + providerAccessTokenExpiry: '', + providerRefreshToken: '', + ip: '', + osCode: '', + osName: '', + osVersion: '', + clientType: '', + clientCode: '', + clientName: '', + clientVersion: '', + clientEngine: '', + clientEngineVersion: '', + deviceName: '', + deviceBrand: '', + deviceModel: '', + countryCode: '', + countryName: '', + current: false, + factors: [], + secret: '', + mfaUpdatedAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1650,7 +2157,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'put', uri, { @@ -1660,6 +2167,46 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'session', + models: { + session: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + userId: '', + expire: '', + provider: '', + providerUid: '', + providerAccessToken: '', + providerAccessTokenExpiry: '', + providerRefreshToken: '', + ip: '', + osCode: '', + osName: '', + osVersion: '', + clientType: '', + clientCode: '', + clientName: '', + clientVersion: '', + clientEngine: '', + clientEngineVersion: '', + deviceName: '', + deviceBrand: '', + deviceModel: '', + countryCode: '', + countryName: '', + current: false, + factors: [], + secret: '', + mfaUpdatedAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1674,7 +2221,7 @@ export class Account extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -1683,6 +2230,22 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'mfaFactors', + models: { + mfaFactors: { + defaults: { + totp: false, + phone: false, + email: false, + recoveryCode: false, + custom: false, + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1696,7 +2259,7 @@ export class Account extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -1705,6 +2268,22 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'mfaFactors', + models: { + mfaFactors: { + defaults: { + totp: false, + phone: false, + email: false, + recoveryCode: false, + custom: false, + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1719,7 +2298,7 @@ export class Account extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -1728,6 +2307,18 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'mfaRecoveryCodes', + models: { + mfaRecoveryCodes: { + defaults: { + recoveryCodes: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1741,7 +2332,7 @@ export class Account extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -1750,6 +2341,18 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'mfaRecoveryCodes', + models: { + mfaRecoveryCodes: { + defaults: { + recoveryCodes: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1764,7 +2367,7 @@ export class Account extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -1774,6 +2377,18 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'mfaRecoveryCodes', + models: { + mfaRecoveryCodes: { + defaults: { + recoveryCodes: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1787,7 +2402,7 @@ export class Account extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -1797,6 +2412,18 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'mfaRecoveryCodes', + models: { + mfaRecoveryCodes: { + defaults: { + recoveryCodes: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1811,7 +2438,7 @@ export class Account extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'patch', uri, { @@ -1821,6 +2448,18 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'mfaRecoveryCodes', + models: { + mfaRecoveryCodes: { + defaults: { + recoveryCodes: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1833,9 +2472,553 @@ export class Account extends Service { const apiPath = '/account/mfa/recovery-codes'; const apiPayload: Payload = {}; + const uri = new URL(this.client.config.endpoint + apiPath); + const request = this.client.call( + 'patch', + uri, + { + 'X-Appwrite-Project': this.client.config.project, + 'content-type': 'application/json', + accept: 'application/json', + }, + apiPayload, + ); + const defaults = { + root: 'mfaRecoveryCodes', + models: { + mfaRecoveryCodes: { + defaults: { + recoveryCodes: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); + } + + /** + * Update currently logged in user account name. + * + * @param {string} params.name - User name. Max length: 128 chars. + * @throws {AppwriteException} + * @returns {Promise} + */ + updateName< + Preferences extends Models.Preferences = Models.DefaultPreferences, + >(params: { name: string }): Promise>; + /** + * Update currently logged in user account name. + * + * @param {string} name - User name. Max length: 128 chars. + * @throws {AppwriteException} + * @returns {Promise>} + * @deprecated Use the object parameter style method for a better developer experience. + */ + updateName< + Preferences extends Models.Preferences = Models.DefaultPreferences, + >(name: string): Promise>; + updateName< + Preferences extends Models.Preferences = Models.DefaultPreferences, + >( + paramsOrFirst: { name: string } | string, + ): Promise> { + let params: { name: string }; + + if ( + paramsOrFirst && + typeof paramsOrFirst === 'object' && + !Array.isArray(paramsOrFirst) + ) { + params = (paramsOrFirst || {}) as { name: string }; + } else { + params = { + name: paramsOrFirst as string, + }; + } + + const name = params.name; + + if (typeof name === 'undefined') { + throw new AppwriteException('Missing required parameter: "name"'); + } + + const apiPath = '/account/name'; + const apiPayload: Payload = {}; + + if (typeof name !== 'undefined') { + apiPayload['name'] = name; + } + + const uri = new URL(this.client.config.endpoint + apiPath); + const request = this.client.call( + 'patch', + uri, + { + 'X-Appwrite-Project': this.client.config.project, + 'content-type': 'application/json', + accept: 'application/json', + }, + apiPayload, + ); + const defaults = { + root: 'user', + models: { + user: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + registration: '', + status: true, + labels: [], + passwordUpdate: '', + email: '', + phone: '', + emailVerification: false, + phoneVerification: false, + mfa: false, + targets: [], + accessedAt: '', + }, + properties: { + targets: { + items: 'target', + }, + }, + }, + target: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + userId: '', + providerType: '', + identifier: '', + expired: false, + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); + } + + /** + * Get the list of verified passkeys registered by the currently logged in user. + * + * @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). Maximum of 100 queries are allowed, each 4096 characters long. You may filter and order on the following attributes: $id, $createdAt, $updatedAt, name, accessedAt + * @param {boolean} params.total - When set to false, the total count returned will be 0 and will not be calculated. + * @throws {AppwriteException} + * @returns {Promise} + */ + listPasskeys(params?: { + queries?: string[]; + total?: boolean; + }): Promise; + /** + * Get the list of verified passkeys registered by the currently logged in user. + * + * @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). Maximum of 100 queries are allowed, each 4096 characters long. You may filter and order on the following attributes: $id, $createdAt, $updatedAt, name, accessedAt + * @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. + */ + listPasskeys( + queries?: string[], + total?: boolean, + ): Promise; + listPasskeys( + paramsOrFirst?: { queries?: string[]; total?: boolean } | string[], + ...rest: [boolean?] + ): Promise { + let params: { queries?: string[]; total?: boolean }; + + if ( + (typeof paramsOrFirst === 'undefined' && rest.length === 0) || + (paramsOrFirst && + typeof paramsOrFirst === 'object' && + !Array.isArray(paramsOrFirst)) + ) { + 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 = '/account/passkeys'; + const apiPayload: Payload = {}; + + if (typeof queries !== 'undefined') { + apiPayload['queries'] = queries; + } + + if (typeof total !== 'undefined') { + apiPayload['total'] = total; + } + + const uri = new URL(this.client.config.endpoint + apiPath); + const request = this.client.call( + 'get', + uri, + { + 'X-Appwrite-Project': this.client.config.project, + accept: 'application/json', + }, + apiPayload, + ); + const defaults = { + root: 'passkeyList', + models: { + passkeyList: { + defaults: { + total: 0, + passkeys: [], + }, + properties: { + passkeys: { + items: 'passkey', + }, + }, + }, + passkey: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + accessedAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); + } + + /** + * Start registering a passkey for the currently logged in user. The session must have signed in or completed an MFA challenge within the last 10 minutes. Pass the returned `publicKey` options to `navigator.credentials.create()`, then complete the registration with [Update passkey verification](/docs/references/cloud/client-web/account#updatePasskeyVerification). The passkey stays pending until verified, and the challenge expires after 5 minutes. + * + * @param {string} params.passkeyId - Passkey 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. + * @param {string} params.name - Passkey name, shown when listing passkeys. Max length: 128 chars. + * @throws {AppwriteException} + * @returns {Promise} + */ + createPasskey(params?: { + passkeyId?: string; + name?: string; + }): Promise; + /** + * Start registering a passkey for the currently logged in user. The session must have signed in or completed an MFA challenge within the last 10 minutes. Pass the returned `publicKey` options to `navigator.credentials.create()`, then complete the registration with [Update passkey verification](/docs/references/cloud/client-web/account#updatePasskeyVerification). The passkey stays pending until verified, and the challenge expires after 5 minutes. + * + * @param {string} passkeyId - Passkey 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. + * @param {string} name - Passkey name, shown when listing passkeys. Max length: 128 chars. + * @throws {AppwriteException} + * @returns {Promise} + * @deprecated Use the object parameter style method for a better developer experience. + */ + createPasskey( + passkeyId?: string, + name?: string, + ): Promise; + createPasskey( + paramsOrFirst?: { passkeyId?: string; name?: string } | string, + ...rest: [string?] + ): Promise { + let params: { passkeyId?: string; name?: string }; + + if ( + (typeof paramsOrFirst === 'undefined' && rest.length === 0) || + (paramsOrFirst && + typeof paramsOrFirst === 'object' && + !Array.isArray(paramsOrFirst)) + ) { + params = (paramsOrFirst || {}) as { + passkeyId?: string; + name?: string; + }; + } else { + params = { + passkeyId: paramsOrFirst as string, + name: rest[0] as string, + }; + } + + const passkeyId = params.passkeyId; + const name = params.name; + + const apiPath = '/account/passkeys'; + const apiPayload: Payload = {}; + + if (typeof passkeyId !== 'undefined') { + apiPayload['passkeyId'] = passkeyId; + } + + if (typeof name !== 'undefined') { + apiPayload['name'] = name; + } + + const uri = new URL(this.client.config.endpoint + apiPath); + const request = this.client.call( + 'post', + uri, + { + 'X-Appwrite-Project': this.client.config.project, + 'content-type': 'application/json', + accept: 'application/json', + }, + apiPayload, + ); + const defaults = { + root: 'passkeyChallenge', + models: { + passkeyChallenge: { + defaults: { + $id: '', + $createdAt: '', + passkeyId: '', + expire: '', + publicKey: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); + } + + /** + * Get a verified passkey of the currently logged in user by its unique ID. + * + * @param {string} params.passkeyId - Passkey ID. + * @throws {AppwriteException} + * @returns {Promise} + */ + getPasskey(params: { passkeyId: string }): Promise; + /** + * Get a verified passkey of the currently logged in user by its unique ID. + * + * @param {string} passkeyId - Passkey ID. + * @throws {AppwriteException} + * @returns {Promise} + * @deprecated Use the object parameter style method for a better developer experience. + */ + getPasskey(passkeyId: string): Promise; + getPasskey( + paramsOrFirst: { passkeyId: string } | string, + ): Promise { + let params: { passkeyId: string }; + + if ( + paramsOrFirst && + typeof paramsOrFirst === 'object' && + !Array.isArray(paramsOrFirst) + ) { + params = (paramsOrFirst || {}) as { passkeyId: string }; + } else { + params = { + passkeyId: paramsOrFirst as string, + }; + } + + const passkeyId = params.passkeyId; + + if (typeof passkeyId === 'undefined' || passkeyId === '') { + throw new AppwriteException( + 'Missing required parameter: "passkeyId"', + ); + } + + const apiPath = '/account/passkeys/{passkeyId}'.replace( + '{passkeyId}', + encodeURIComponent(String(passkeyId)), + ); + const apiPayload: Payload = {}; + + const uri = new URL(this.client.config.endpoint + apiPath); + const request = this.client.call( + 'get', + uri, + { + 'X-Appwrite-Project': this.client.config.project, + accept: 'application/json', + }, + apiPayload, + ); + const defaults = { + root: 'passkey', + models: { + passkey: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + accessedAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); + } + + /** + * Rename a passkey of the currently logged in user. + * + * @param {string} params.passkeyId - Passkey ID. + * @param {string} params.name - Passkey name. Max length: 128 chars. + * @throws {AppwriteException} + * @returns {Promise} + */ + updatePasskey(params: { + passkeyId: string; + name: string; + }): Promise; + /** + * Rename a passkey of the currently logged in user. + * + * @param {string} passkeyId - Passkey ID. + * @param {string} name - Passkey name. Max length: 128 chars. + * @throws {AppwriteException} + * @returns {Promise} + * @deprecated Use the object parameter style method for a better developer experience. + */ + updatePasskey(passkeyId: string, name: string): Promise; + updatePasskey( + paramsOrFirst: { passkeyId: string; name: string } | string, + ...rest: [string?] + ): Promise { + let params: { passkeyId: string; name: string }; + + if ( + paramsOrFirst && + typeof paramsOrFirst === 'object' && + !Array.isArray(paramsOrFirst) + ) { + params = (paramsOrFirst || {}) as { + passkeyId: string; + name: string; + }; + } else { + params = { + passkeyId: paramsOrFirst as string, + name: rest[0] as string, + }; + } + + const passkeyId = params.passkeyId; + const name = params.name; + + if (typeof passkeyId === 'undefined' || passkeyId === '') { + throw new AppwriteException( + 'Missing required parameter: "passkeyId"', + ); + } + + if (typeof name === 'undefined') { + throw new AppwriteException('Missing required parameter: "name"'); + } + + const apiPath = '/account/passkeys/{passkeyId}'.replace( + '{passkeyId}', + encodeURIComponent(String(passkeyId)), + ); + const apiPayload: Payload = {}; + + if (typeof name !== 'undefined') { + apiPayload['name'] = name; + } + + const uri = new URL(this.client.config.endpoint + apiPath); + const request = this.client.call( + 'patch', + uri, + { + 'X-Appwrite-Project': this.client.config.project, + 'content-type': 'application/json', + accept: 'application/json', + }, + apiPayload, + ); + const defaults = { + root: 'passkey', + models: { + passkey: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + accessedAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); + } + + /** + * Delete a passkey from the currently logged in user. The passkey can no longer be used to sign in, although it may remain stored on the user's device. The session must have signed in or completed an MFA challenge within the last 10 minutes. + * + * @param {string} params.passkeyId - Passkey ID. + * @throws {AppwriteException} + * @returns {Promise} + */ + deletePasskey(params: { passkeyId: string }): Promise<{}>; + /** + * Delete a passkey from the currently logged in user. The passkey can no longer be used to sign in, although it may remain stored on the user's device. The session must have signed in or completed an MFA challenge within the last 10 minutes. + * + * @param {string} passkeyId - Passkey ID. + * @throws {AppwriteException} + * @returns {Promise<{}>} + * @deprecated Use the object parameter style method for a better developer experience. + */ + deletePasskey(passkeyId: string): Promise<{}>; + deletePasskey(paramsOrFirst: { passkeyId: string } | string): Promise<{}> { + let params: { passkeyId: string }; + + if ( + paramsOrFirst && + typeof paramsOrFirst === 'object' && + !Array.isArray(paramsOrFirst) + ) { + params = (paramsOrFirst || {}) as { passkeyId: string }; + } else { + params = { + passkeyId: paramsOrFirst as string, + }; + } + + const passkeyId = params.passkeyId; + + if (typeof passkeyId === 'undefined' || passkeyId === '') { + throw new AppwriteException( + 'Missing required parameter: "passkeyId"', + ); + } + + const apiPath = '/account/passkeys/{passkeyId}'.replace( + '{passkeyId}', + encodeURIComponent(String(passkeyId)), + ); + const apiPayload: Payload = {}; + const uri = new URL(this.client.config.endpoint + apiPath); return this.client.call( - 'patch', + 'delete', uri, { 'X-Appwrite-Project': this.client.config.project, @@ -1847,61 +3030,80 @@ export class Account extends Service { } /** - * Update currently logged in user account name. + * Complete a passkey registration started with [Create passkey](/docs/references/cloud/client-web/account#createPasskey). Pass the JSON form of the credential returned by `navigator.credentials.create()`, for example `credential.toJSON()`. Each registration can be verified once; a failed attempt requires starting it again. * - * @param {string} params.name - User name. Max length: 128 chars. + * @param {string} params.passkeyId - Passkey ID. + * @param {object} params.credential - Registration credential returned by the authenticator, in the JSON form produced by `PublicKeyCredential.toJSON()`. * @throws {AppwriteException} * @returns {Promise} */ - updateName< - Preferences extends Models.Preferences = Models.DefaultPreferences, - >(params: { name: string }): Promise>; + updatePasskeyVerification(params: { + passkeyId: string; + credential: object; + }): Promise; /** - * Update currently logged in user account name. + * Complete a passkey registration started with [Create passkey](/docs/references/cloud/client-web/account#createPasskey). Pass the JSON form of the credential returned by `navigator.credentials.create()`, for example `credential.toJSON()`. Each registration can be verified once; a failed attempt requires starting it again. * - * @param {string} name - User name. Max length: 128 chars. + * @param {string} passkeyId - Passkey ID. + * @param {object} credential - Registration credential returned by the authenticator, in the JSON form produced by `PublicKeyCredential.toJSON()`. * @throws {AppwriteException} - * @returns {Promise>} + * @returns {Promise} * @deprecated Use the object parameter style method for a better developer experience. */ - updateName< - Preferences extends Models.Preferences = Models.DefaultPreferences, - >(name: string): Promise>; - updateName< - Preferences extends Models.Preferences = Models.DefaultPreferences, - >( - paramsOrFirst: { name: string } | string, - ): Promise> { - let params: { name: string }; + updatePasskeyVerification( + passkeyId: string, + credential: object, + ): Promise; + updatePasskeyVerification( + paramsOrFirst: { passkeyId: string; credential: object } | string, + ...rest: [object?] + ): Promise { + let params: { passkeyId: string; credential: object }; if ( paramsOrFirst && typeof paramsOrFirst === 'object' && !Array.isArray(paramsOrFirst) ) { - params = (paramsOrFirst || {}) as { name: string }; + params = (paramsOrFirst || {}) as { + passkeyId: string; + credential: object; + }; } else { params = { - name: paramsOrFirst as string, + passkeyId: paramsOrFirst as string, + credential: rest[0] as object, }; } - const name = params.name; + const passkeyId = params.passkeyId; + const credential = params.credential; - if (typeof name === 'undefined') { - throw new AppwriteException('Missing required parameter: "name"'); + if (typeof passkeyId === 'undefined' || passkeyId === '') { + throw new AppwriteException( + 'Missing required parameter: "passkeyId"', + ); } - const apiPath = '/account/name'; + if (typeof credential === 'undefined') { + throw new AppwriteException( + 'Missing required parameter: "credential"', + ); + } + + const apiPath = '/account/passkeys/{passkeyId}/verification'.replace( + '{passkeyId}', + encodeURIComponent(String(passkeyId)), + ); const apiPayload: Payload = {}; - if (typeof name !== 'undefined') { - apiPayload['name'] = name; + if (typeof credential !== 'undefined') { + apiPayload['credential'] = credential; } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( - 'patch', + const request = this.client.call( + 'put', uri, { 'X-Appwrite-Project': this.client.config.project, @@ -1910,6 +3112,22 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'passkey', + models: { + passkey: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + accessedAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1986,7 +3204,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'patch', uri, { @@ -1996,6 +3214,49 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'user', + models: { + user: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + registration: '', + status: true, + labels: [], + passwordUpdate: '', + email: '', + phone: '', + emailVerification: false, + phoneVerification: false, + mfa: false, + targets: [], + accessedAt: '', + }, + properties: { + targets: { + items: 'target', + }, + }, + }, + target: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + userId: '', + providerType: '', + identifier: '', + expired: false, + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -2073,7 +3334,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'patch', uri, { @@ -2083,6 +3344,49 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'user', + models: { + user: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + registration: '', + status: true, + labels: [], + passwordUpdate: '', + email: '', + phone: '', + emailVerification: false, + phoneVerification: false, + mfa: false, + targets: [], + accessedAt: '', + }, + properties: { + targets: { + items: 'target', + }, + }, + }, + target: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + userId: '', + providerType: '', + identifier: '', + expired: false, + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -2166,7 +3470,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'patch', uri, { @@ -2176,6 +3480,49 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'user', + models: { + user: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + registration: '', + status: true, + labels: [], + passwordUpdate: '', + email: '', + phone: '', + emailVerification: false, + phoneVerification: false, + mfa: false, + targets: [], + accessedAt: '', + }, + properties: { + targets: { + items: 'target', + }, + }, + }, + target: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + userId: '', + providerType: '', + identifier: '', + expired: false, + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -2242,7 +3589,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -2252,6 +3599,23 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'token', + models: { + token: { + defaults: { + $id: '', + $createdAt: '', + userId: '', + secret: '', + expire: '', + phrase: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -2346,7 +3710,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'put', uri, { @@ -2356,6 +3720,23 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'token', + models: { + token: { + defaults: { + $id: '', + $createdAt: '', + userId: '', + secret: '', + expire: '', + phrase: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -2427,7 +3808,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -2437,6 +3818,23 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'token', + models: { + token: { + defaults: { + $id: '', + $createdAt: '', + userId: '', + secret: '', + expire: '', + phrase: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -2529,7 +3927,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'put', uri, { @@ -2539,6 +3937,23 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'token', + models: { + token: { + defaults: { + $id: '', + $createdAt: '', + userId: '', + secret: '', + expire: '', + phrase: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -2586,7 +4001,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -2595,6 +4010,57 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'sessionList', + models: { + sessionList: { + defaults: { + total: 0, + sessions: [], + }, + properties: { + sessions: { + items: 'session', + }, + }, + }, + session: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + userId: '', + expire: '', + provider: '', + providerUid: '', + providerAccessToken: '', + providerAccessTokenExpiry: '', + providerRefreshToken: '', + ip: '', + osCode: '', + osName: '', + osVersion: '', + clientType: '', + clientCode: '', + clientName: '', + clientVersion: '', + clientEngine: '', + clientEngineVersion: '', + deviceName: '', + deviceBrand: '', + deviceModel: '', + countryCode: '', + countryName: '', + current: false, + factors: [], + secret: '', + mfaUpdatedAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -2665,7 +4131,7 @@ export class Account extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -2675,6 +4141,46 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'session', + models: { + session: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + userId: '', + expire: '', + provider: '', + providerUid: '', + providerAccessToken: '', + providerAccessTokenExpiry: '', + providerRefreshToken: '', + ip: '', + osCode: '', + osName: '', + osVersion: '', + clientType: '', + clientCode: '', + clientName: '', + clientVersion: '', + clientEngine: '', + clientEngineVersion: '', + deviceName: '', + deviceBrand: '', + deviceModel: '', + countryCode: '', + countryName: '', + current: false, + factors: [], + secret: '', + mfaUpdatedAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -2684,14 +4190,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. + * @param {number | null} 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; + duration?: number | null; }): 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. Use the optional `duration` parameter to create a shorter session, for example when the user doesn't choose "remember me". It must be at least 60 seconds and cannot exceed the project maximum session length. @@ -2700,7 +4206,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. + * @param {number | null} 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. @@ -2708,14 +4214,19 @@ export class Account extends Service { createEmailPasswordSession( email: string, password: string, - duration?: number, + duration?: number | null, ): Promise; createEmailPasswordSession( paramsOrFirst: - { email: string; password: string; duration?: number } | string, - ...rest: [string?, number?] + | { email: string; password: string; duration?: number | null } + | string, + ...rest: [string?, (number | null)?] ): Promise { - let params: { email: string; password: string; duration?: number }; + let params: { + email: string; + password: string; + duration?: number | null; + }; if ( paramsOrFirst && @@ -2725,13 +4236,13 @@ export class Account extends Service { params = (paramsOrFirst || {}) as { email: string; password: string; - duration?: number; + duration?: number | null; }; } else { params = { email: paramsOrFirst as string, password: rest[0] as string, - duration: rest[1] as number, + duration: rest[1] as number | null, }; } @@ -2765,7 +4276,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -2775,6 +4286,46 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'session', + models: { + session: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + userId: '', + expire: '', + provider: '', + providerUid: '', + providerAccessToken: '', + providerAccessTokenExpiry: '', + providerRefreshToken: '', + ip: '', + osCode: '', + osName: '', + osVersion: '', + clientType: '', + clientCode: '', + clientName: '', + clientVersion: '', + clientEngine: '', + clientEngineVersion: '', + deviceName: '', + deviceBrand: '', + deviceModel: '', + countryCode: '', + countryName: '', + current: false, + factors: [], + secret: '', + mfaUpdatedAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -2939,7 +4490,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -2949,6 +4500,46 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'session', + models: { + session: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + userId: '', + expire: '', + provider: '', + providerUid: '', + providerAccessToken: '', + providerAccessTokenExpiry: '', + providerRefreshToken: '', + ip: '', + osCode: '', + osName: '', + osVersion: '', + clientType: '', + clientCode: '', + clientName: '', + clientVersion: '', + clientEngine: '', + clientEngineVersion: '', + deviceName: '', + deviceBrand: '', + deviceModel: '', + countryCode: '', + countryName: '', + current: false, + factors: [], + secret: '', + mfaUpdatedAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -3022,7 +4613,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'put', uri, { @@ -3032,6 +4623,46 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'session', + models: { + session: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + userId: '', + expire: '', + provider: '', + providerUid: '', + providerAccessToken: '', + providerAccessTokenExpiry: '', + providerRefreshToken: '', + ip: '', + osCode: '', + osName: '', + osVersion: '', + clientType: '', + clientCode: '', + clientName: '', + clientVersion: '', + clientEngine: '', + clientEngineVersion: '', + deviceName: '', + deviceBrand: '', + deviceModel: '', + countryCode: '', + countryName: '', + current: false, + factors: [], + secret: '', + mfaUpdatedAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -3046,6 +4677,7 @@ export class Account extends Service { * @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} */ @@ -3054,6 +4686,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. @@ -3067,6 +4700,7 @@ export class Account extends Service { * @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. @@ -3076,6 +4710,7 @@ export class Account extends Service { success?: string, failure?: string, scopes?: string[], + state?: string, ): void | URL; createOAuth2Session( paramsOrFirst: @@ -3084,15 +4719,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 ( @@ -3102,13 +4739,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 = { @@ -3116,6 +4755,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, }; } @@ -3123,6 +4763,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( @@ -3148,6 +4789,10 @@ export class Account extends Service { apiPayload['scopes'] = scopes; } + if (typeof state !== 'undefined') { + apiPayload['state'] = state; + } + const uri = new URL(this.client.config.endpoint + apiPath); apiPayload['project'] = this.client.config.project; @@ -3227,7 +4872,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'put', uri, { @@ -3237,6 +4882,46 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'session', + models: { + session: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + userId: '', + expire: '', + provider: '', + providerUid: '', + providerAccessToken: '', + providerAccessTokenExpiry: '', + providerRefreshToken: '', + ip: '', + osCode: '', + osName: '', + osVersion: '', + clientType: '', + clientCode: '', + clientName: '', + clientVersion: '', + clientEngine: '', + clientEngineVersion: '', + deviceName: '', + deviceBrand: '', + deviceModel: '', + countryCode: '', + countryName: '', + current: false, + factors: [], + secret: '', + mfaUpdatedAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -3306,7 +4991,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -3316,6 +5001,46 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'session', + models: { + session: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + userId: '', + expire: '', + provider: '', + providerUid: '', + providerAccessToken: '', + providerAccessTokenExpiry: '', + providerRefreshToken: '', + ip: '', + osCode: '', + osName: '', + osVersion: '', + clientType: '', + clientCode: '', + clientName: '', + clientVersion: '', + clientEngine: '', + clientEngineVersion: '', + deviceName: '', + deviceBrand: '', + deviceModel: '', + countryCode: '', + countryName: '', + current: false, + factors: [], + secret: '', + mfaUpdatedAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -3367,7 +5092,7 @@ export class Account extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -3376,6 +5101,46 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'session', + models: { + session: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + userId: '', + expire: '', + provider: '', + providerUid: '', + providerAccessToken: '', + providerAccessTokenExpiry: '', + providerRefreshToken: '', + ip: '', + osCode: '', + osName: '', + osVersion: '', + clientType: '', + clientCode: '', + clientName: '', + clientVersion: '', + clientEngine: '', + clientEngineVersion: '', + deviceName: '', + deviceBrand: '', + deviceModel: '', + countryCode: '', + countryName: '', + current: false, + factors: [], + secret: '', + mfaUpdatedAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -3427,7 +5192,7 @@ export class Account extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'patch', uri, { @@ -3437,6 +5202,46 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'session', + models: { + session: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + userId: '', + expire: '', + provider: '', + providerUid: '', + providerAccessToken: '', + providerAccessTokenExpiry: '', + providerRefreshToken: '', + ip: '', + osCode: '', + osName: '', + osVersion: '', + clientType: '', + clientCode: '', + clientName: '', + clientVersion: '', + clientEngine: '', + clientEngineVersion: '', + deviceName: '', + deviceBrand: '', + deviceModel: '', + countryCode: '', + countryName: '', + current: false, + factors: [], + secret: '', + mfaUpdatedAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -3511,7 +5316,7 @@ export class Account extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'patch', uri, { @@ -3521,6 +5326,49 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'user', + models: { + user: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + registration: '', + status: true, + labels: [], + passwordUpdate: '', + email: '', + phone: '', + emailVerification: false, + phoneVerification: false, + mfa: false, + targets: [], + accessedAt: '', + }, + properties: { + targets: { + items: 'target', + }, + }, + }, + target: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + userId: '', + providerType: '', + identifier: '', + expired: false, + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -3614,7 +5462,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -3624,6 +5472,25 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'target', + models: { + target: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + userId: '', + providerType: '', + identifier: '', + expired: false, + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -3699,7 +5566,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'put', uri, { @@ -3709,6 +5576,25 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'target', + models: { + target: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + userId: '', + providerType: '', + identifier: '', + expired: false, + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -3860,7 +5746,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -3870,6 +5756,23 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'token', + models: { + token: { + defaults: { + $id: '', + $createdAt: '', + userId: '', + secret: '', + expire: '', + phrase: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -3977,7 +5880,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -3987,6 +5890,23 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'token', + models: { + token: { + defaults: { + $id: '', + $createdAt: '', + userId: '', + secret: '', + expire: '', + phrase: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -4002,6 +5922,7 @@ export class Account extends Service { * @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} */ @@ -4010,6 +5931,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. @@ -4024,6 +5946,7 @@ export class Account extends Service { * @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. @@ -4033,6 +5956,7 @@ export class Account extends Service { success?: string, failure?: string, scopes?: string[], + state?: string, ): void | URL; createOAuth2Token( paramsOrFirst: @@ -4041,15 +5965,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 ( @@ -4059,13 +5985,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 = { @@ -4073,6 +6001,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, }; } @@ -4080,6 +6009,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( @@ -4105,6 +6035,10 @@ export class Account extends Service { apiPayload['scopes'] = scopes; } + if (typeof state !== 'undefined') { + apiPayload['state'] = state; + } + const uri = new URL(this.client.config.endpoint + apiPath); apiPayload['project'] = this.client.config.project; @@ -4116,6 +6050,148 @@ export class Account extends Service { return uri; } + /** + * Start signing in with a passkey. No email or user ID is needed: pass the returned `publicKey` options to `navigator.credentials.get()` and the user picks one of their passkeys. Then call [Update passkey token](/docs/references/cloud/client-web/account#updatePasskeyToken) with the credential to receive a token, and exchange it with [Create session](/docs/references/cloud/client-web/account#createSession). The challenge expires after 5 minutes. + * + * @throws {AppwriteException} + * @returns {Promise} + */ + createPasskeyToken(): Promise { + const apiPath = '/account/tokens/passkey'; + const apiPayload: Payload = {}; + + const uri = new URL(this.client.config.endpoint + apiPath); + const request = this.client.call( + 'post', + uri, + { + 'X-Appwrite-Project': this.client.config.project, + 'content-type': 'application/json', + accept: 'application/json', + }, + apiPayload, + ); + const defaults = { + root: 'passkeyChallenge', + models: { + passkeyChallenge: { + defaults: { + $id: '', + $createdAt: '', + passkeyId: '', + expire: '', + publicKey: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); + } + + /** + * Complete a passkey sign-in started with [Create passkey token](/docs/references/cloud/client-web/account#createPasskeyToken). Pass the challenge ID and the JSON form of the credential returned by `navigator.credentials.get()`, for example `credential.toJSON()`. The returned token includes its secret and expires after 1 minute: exchange it for a session with [Create session](/docs/references/cloud/client-web/account#createSession). Passkeys require user verification, so the session also satisfies MFA. Each challenge can only be used once. + * + * @param {string} params.challengeId - Challenge ID returned by createPasskeyToken. + * @param {object} params.credential - Authentication credential returned by the authenticator, in the JSON form produced by `PublicKeyCredential.toJSON()`. + * @throws {AppwriteException} + * @returns {Promise} + */ + updatePasskeyToken(params: { + challengeId: string; + credential: object; + }): Promise; + /** + * Complete a passkey sign-in started with [Create passkey token](/docs/references/cloud/client-web/account#createPasskeyToken). Pass the challenge ID and the JSON form of the credential returned by `navigator.credentials.get()`, for example `credential.toJSON()`. The returned token includes its secret and expires after 1 minute: exchange it for a session with [Create session](/docs/references/cloud/client-web/account#createSession). Passkeys require user verification, so the session also satisfies MFA. Each challenge can only be used once. + * + * @param {string} challengeId - Challenge ID returned by createPasskeyToken. + * @param {object} credential - Authentication credential returned by the authenticator, in the JSON form produced by `PublicKeyCredential.toJSON()`. + * @throws {AppwriteException} + * @returns {Promise} + * @deprecated Use the object parameter style method for a better developer experience. + */ + updatePasskeyToken( + challengeId: string, + credential: object, + ): Promise; + updatePasskeyToken( + paramsOrFirst: { challengeId: string; credential: object } | string, + ...rest: [object?] + ): Promise { + let params: { challengeId: string; credential: object }; + + if ( + paramsOrFirst && + typeof paramsOrFirst === 'object' && + !Array.isArray(paramsOrFirst) + ) { + params = (paramsOrFirst || {}) as { + challengeId: string; + credential: object; + }; + } else { + params = { + challengeId: paramsOrFirst as string, + credential: rest[0] as object, + }; + } + + const challengeId = params.challengeId; + const credential = params.credential; + + if (typeof challengeId === 'undefined') { + throw new AppwriteException( + 'Missing required parameter: "challengeId"', + ); + } + + if (typeof credential === 'undefined') { + throw new AppwriteException( + 'Missing required parameter: "credential"', + ); + } + + const apiPath = '/account/tokens/passkey'; + const apiPayload: Payload = {}; + + if (typeof challengeId !== 'undefined') { + apiPayload['challengeId'] = challengeId; + } + + if (typeof credential !== 'undefined') { + apiPayload['credential'] = credential; + } + + const uri = new URL(this.client.config.endpoint + apiPath); + const request = this.client.call( + 'put', + uri, + { + 'X-Appwrite-Project': this.client.config.project, + 'content-type': 'application/json', + accept: 'application/json', + }, + apiPayload, + ); + const defaults = { + root: 'tokenSecret', + models: { + tokenSecret: { + defaults: { + $id: '', + $createdAt: '', + userId: '', + secret: '', + expire: '', + phrase: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); + } + /** * Sends the user an SMS with a secret key for creating a session. If the provided user ID has not be registered, a new user will be created. Use the returned user ID and secret and submit a request to the [POST /v1/account/sessions/token](https://appwrite.io/docs/references/cloud/client-web/account#createSession) endpoint to complete the login process. The secret sent to the user's phone is valid for 15 minutes. * @@ -4184,7 +6260,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -4194,6 +6270,23 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'token', + models: { + token: { + defaults: { + $id: '', + $createdAt: '', + userId: '', + secret: '', + expire: '', + phrase: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -4250,7 +6343,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -4260,6 +6353,23 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'token', + models: { + token: { + defaults: { + $id: '', + $createdAt: '', + userId: '', + secret: '', + expire: '', + phrase: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -4317,7 +6427,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -4327,6 +6437,23 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'token', + models: { + token: { + defaults: { + $id: '', + $createdAt: '', + userId: '', + secret: '', + expire: '', + phrase: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -4399,7 +6526,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'put', uri, { @@ -4409,6 +6536,23 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'token', + models: { + token: { + defaults: { + $id: '', + $createdAt: '', + userId: '', + secret: '', + expire: '', + phrase: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -4479,7 +6623,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'put', uri, { @@ -4489,6 +6633,23 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'token', + models: { + token: { + defaults: { + $id: '', + $createdAt: '', + userId: '', + secret: '', + expire: '', + phrase: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -4544,7 +6705,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -4554,6 +6715,23 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'token', + models: { + token: { + defaults: { + $id: '', + $createdAt: '', + userId: '', + secret: '', + expire: '', + phrase: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -4628,7 +6806,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'put', uri, { @@ -4638,6 +6816,23 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'token', + models: { + token: { + defaults: { + $id: '', + $createdAt: '', + userId: '', + secret: '', + expire: '', + phrase: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -4651,7 +6846,7 @@ export class Account extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -4661,6 +6856,23 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'token', + models: { + token: { + defaults: { + $id: '', + $createdAt: '', + userId: '', + secret: '', + expire: '', + phrase: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -4733,7 +6945,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'put', uri, { @@ -4743,5 +6955,22 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'token', + models: { + token: { + defaults: { + $id: '', + $createdAt: '', + userId: '', + secret: '', + expire: '', + phrase: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } } 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/apps.ts b/src/services/apps.ts index 02554ba4..896038d7 100644 --- a/src/services/apps.ts +++ b/src/services/apps.ts @@ -1,5 +1,5 @@ import { Service } from '../service'; -import { AppwriteException, Client } from '../client'; +import { AppwriteException, Client, applyDefaults } from '../client'; import type { Models } from '../models'; import type { Payload } from '../client'; @@ -68,7 +68,7 @@ export class Apps extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -77,6 +77,71 @@ export class Apps extends Service { }, apiPayload, ); + const defaults = { + root: 'appsList', + models: { + appsList: { + defaults: { + total: 0, + apps: [], + }, + properties: { + apps: { + items: 'app', + }, + }, + }, + app: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + description: '', + clientUri: '', + logoUri: '', + privacyPolicyUrl: '', + termsUrl: '', + contacts: [], + tagline: '', + tags: [], + labels: [], + images: [], + supportUrl: '', + dataDeletionUrl: '', + redirectUris: [], + postLogoutRedirectUris: [], + enabled: true, + type: 'confidential', + deviceFlow: false, + teamId: '', + userId: '', + installationScopes: [], + installationRedirectUrl: '', + secrets: [], + }, + properties: { + secrets: { + items: 'appSecret', + }, + }, + }, + appSecret: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + appId: '', + secret: '', + hint: '', + createdById: '', + createdByName: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -403,7 +468,7 @@ export class Apps extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -413,6 +478,60 @@ export class Apps extends Service { }, apiPayload, ); + const defaults = { + root: 'app', + models: { + app: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + description: '', + clientUri: '', + logoUri: '', + privacyPolicyUrl: '', + termsUrl: '', + contacts: [], + tagline: '', + tags: [], + labels: [], + images: [], + supportUrl: '', + dataDeletionUrl: '', + redirectUris: [], + postLogoutRedirectUris: [], + enabled: true, + type: 'confidential', + deviceFlow: false, + teamId: '', + userId: '', + installationScopes: [], + installationRedirectUrl: '', + secrets: [], + }, + properties: { + secrets: { + items: 'appSecret', + }, + }, + }, + appSecret: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + appId: '', + secret: '', + hint: '', + createdById: '', + createdByName: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -426,7 +545,7 @@ export class Apps extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -435,6 +554,33 @@ export class Apps extends Service { }, apiPayload, ); + const defaults = { + root: 'appScopeList', + models: { + appScopeList: { + defaults: { + total: 0, + scopes: [], + }, + properties: { + scopes: { + items: 'appScope', + }, + }, + }, + appScope: { + defaults: { + value: '', + description: '', + type: '', + category: '', + deprecated: false, + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -448,7 +594,7 @@ export class Apps extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -457,6 +603,33 @@ export class Apps extends Service { }, apiPayload, ); + const defaults = { + root: 'appScopeList', + models: { + appScopeList: { + defaults: { + total: 0, + scopes: [], + }, + properties: { + scopes: { + items: 'appScope', + }, + }, + }, + appScope: { + defaults: { + value: '', + description: '', + type: '', + category: '', + deprecated: false, + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -504,7 +677,7 @@ export class Apps extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -513,6 +686,60 @@ export class Apps extends Service { }, apiPayload, ); + const defaults = { + root: 'app', + models: { + app: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + description: '', + clientUri: '', + logoUri: '', + privacyPolicyUrl: '', + termsUrl: '', + contacts: [], + tagline: '', + tags: [], + labels: [], + images: [], + supportUrl: '', + dataDeletionUrl: '', + redirectUris: [], + postLogoutRedirectUris: [], + enabled: true, + type: 'confidential', + deviceFlow: false, + teamId: '', + userId: '', + installationScopes: [], + installationRedirectUrl: '', + secrets: [], + }, + properties: { + secrets: { + items: 'appSecret', + }, + }, + }, + appSecret: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + appId: '', + secret: '', + hint: '', + createdById: '', + createdByName: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -846,7 +1073,7 @@ export class Apps extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'put', uri, { @@ -856,6 +1083,60 @@ export class Apps extends Service { }, apiPayload, ); + const defaults = { + root: 'app', + models: { + app: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + description: '', + clientUri: '', + logoUri: '', + privacyPolicyUrl: '', + termsUrl: '', + contacts: [], + tagline: '', + tags: [], + labels: [], + images: [], + supportUrl: '', + dataDeletionUrl: '', + redirectUris: [], + postLogoutRedirectUris: [], + enabled: true, + type: 'confidential', + deviceFlow: false, + teamId: '', + userId: '', + installationScopes: [], + installationRedirectUrl: '', + secrets: [], + }, + properties: { + secrets: { + items: 'appSecret', + }, + }, + }, + appSecret: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + appId: '', + secret: '', + hint: '', + createdById: '', + createdByName: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -992,7 +1273,7 @@ export class Apps extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -1001,6 +1282,37 @@ export class Apps extends Service { }, apiPayload, ); + const defaults = { + root: 'appInstallationList', + models: { + appInstallationList: { + defaults: { + total: 0, + installations: [], + }, + properties: { + installations: { + items: 'appInstallation', + }, + }, + }, + appInstallation: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + appId: '', + teamId: '', + scopes: [], + authorizationDetails: [], + createdById: '', + createdByName: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1072,7 +1384,7 @@ export class Apps extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -1081,6 +1393,26 @@ export class Apps extends Service { }, apiPayload, ); + const defaults = { + root: 'appInstallation', + models: { + appInstallation: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + appId: '', + teamId: '', + scopes: [], + authorizationDetails: [], + createdById: '', + createdByName: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1230,7 +1562,7 @@ export class Apps extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -1240,6 +1572,22 @@ export class Apps extends Service { }, apiPayload, ); + const defaults = { + root: 'oauth2Token', + models: { + oauth2Token: { + defaults: { + access_token: '', + token_type: 'Bearer', + expires_in: 0, + refresh_token: '', + scope: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1319,7 +1667,7 @@ export class Apps extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -1328,6 +1676,36 @@ export class Apps extends Service { }, apiPayload, ); + const defaults = { + root: 'appKeyList', + models: { + appKeyList: { + defaults: { + total: 0, + keys: [], + }, + properties: { + keys: { + items: 'appKey', + }, + }, + }, + appKey: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + appId: '', + secret: '', + hint: '', + createdById: '', + createdByName: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1377,7 +1755,7 @@ export class Apps extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -1387,6 +1765,25 @@ export class Apps extends Service { }, apiPayload, ); + const defaults = { + root: 'appKey', + models: { + appKey: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + appId: '', + secret: '', + hint: '', + createdById: '', + createdByName: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1444,7 +1841,7 @@ export class Apps extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -1453,6 +1850,25 @@ export class Apps extends Service { }, apiPayload, ); + const defaults = { + root: 'appKey', + models: { + appKey: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + appId: '', + secret: '', + hint: '', + createdById: '', + createdByName: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1599,7 +2015,7 @@ export class Apps extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -1608,6 +2024,36 @@ export class Apps extends Service { }, apiPayload, ); + const defaults = { + root: 'appSecretList', + models: { + appSecretList: { + defaults: { + total: 0, + secrets: [], + }, + properties: { + secrets: { + items: 'appSecret', + }, + }, + }, + appSecret: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + appId: '', + secret: '', + hint: '', + createdById: '', + createdByName: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1657,7 +2103,7 @@ export class Apps extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -1667,6 +2113,25 @@ export class Apps extends Service { }, apiPayload, ); + const defaults = { + root: 'appSecretPlaintext', + models: { + appSecretPlaintext: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + appId: '', + secret: '', + hint: '', + createdById: '', + createdByName: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1732,7 +2197,7 @@ export class Apps extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -1741,6 +2206,25 @@ export class Apps extends Service { }, apiPayload, ); + const defaults = { + root: 'appSecret', + models: { + appSecret: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + appId: '', + secret: '', + hint: '', + createdById: '', + createdByName: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1875,7 +2359,7 @@ export class Apps extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'patch', uri, { @@ -1885,6 +2369,60 @@ export class Apps extends Service { }, apiPayload, ); + const defaults = { + root: 'app', + models: { + app: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + description: '', + clientUri: '', + logoUri: '', + privacyPolicyUrl: '', + termsUrl: '', + contacts: [], + tagline: '', + tags: [], + labels: [], + images: [], + supportUrl: '', + dataDeletionUrl: '', + redirectUris: [], + postLogoutRedirectUris: [], + enabled: true, + type: 'confidential', + deviceFlow: false, + teamId: '', + userId: '', + installationScopes: [], + installationRedirectUrl: '', + secrets: [], + }, + properties: { + secrets: { + items: 'appSecret', + }, + }, + }, + appSecret: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + appId: '', + secret: '', + hint: '', + createdById: '', + createdByName: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** diff --git a/src/services/databases.ts b/src/services/databases.ts index 94d2ad16..43e4b4a9 100644 --- a/src/services/databases.ts +++ b/src/services/databases.ts @@ -1,5 +1,5 @@ import { Service } from '../service'; -import { AppwriteException, Client } from '../client'; +import { AppwriteException, Client, applyDefaults } from '../client'; import type { Models } from '../models'; import type { Payload } from '../client'; @@ -72,7 +72,7 @@ export class Databases extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -81,6 +81,34 @@ export class Databases extends Service { }, apiPayload, ); + const defaults = { + root: 'transactionList', + models: { + transactionList: { + defaults: { + total: 0, + transactions: [], + }, + properties: { + transactions: { + items: 'transaction', + }, + }, + }, + transaction: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + status: 'pending', + operations: 0, + expiresAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -129,7 +157,7 @@ export class Databases extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -139,6 +167,23 @@ export class Databases extends Service { }, apiPayload, ); + const defaults = { + root: 'transaction', + models: { + transaction: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + status: 'pending', + operations: 0, + expiresAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -193,7 +238,7 @@ export class Databases extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -202,6 +247,23 @@ export class Databases extends Service { }, apiPayload, ); + const defaults = { + root: 'transaction', + models: { + transaction: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + status: 'pending', + operations: 0, + expiresAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -289,7 +351,7 @@ export class Databases extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'patch', uri, { @@ -299,6 +361,23 @@ export class Databases extends Service { }, apiPayload, ); + const defaults = { + root: 'transaction', + models: { + transaction: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + status: 'pending', + operations: 0, + expiresAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -433,7 +512,7 @@ export class Databases extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -443,6 +522,23 @@ export class Databases extends Service { }, apiPayload, ); + const defaults = { + root: 'transaction', + models: { + transaction: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + status: 'pending', + operations: 0, + expiresAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -580,7 +676,7 @@ export class Databases extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -589,6 +685,35 @@ export class Databases extends Service { }, apiPayload, ); + const defaults = { + root: 'documentList', + models: { + documentList: { + defaults: { + total: 0, + documents: [], + }, + properties: { + documents: { + items: 'document', + }, + }, + }, + document: { + defaults: { + $id: '', + $sequence: '', + $collectionId: '', + $databaseId: '', + $createdAt: '', + $updatedAt: '', + $permissions: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -598,8 +723,8 @@ export class Databases extends Service { * @param {string} params.collectionId - Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection). Make sure to define attributes before creating documents. * @param {string} params.documentId - Document ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars. * @param {Document extends Models.DefaultDocument ? Partial & Record : Partial & Omit} params.data - Document data as JSON object. - * @param {string[]} params.permissions - An array of permissions strings. By default, only the current user is granted all permissions. [Learn more about permissions](https://appwrite.io/docs/permissions). - * @param {string} params.transactionId - Transaction ID for staging the operation. + * @param {string[] | null} params.permissions - An array of permissions strings. By default, only the current user is granted all permissions. [Learn more about permissions](https://appwrite.io/docs/permissions). + * @param {string | null} params.transactionId - Transaction ID for staging the operation. * @throws {AppwriteException} * @returns {Promise} * @deprecated This API has been deprecated since 1.8.0. Please use `TablesDB.createRow` instead. @@ -613,8 +738,8 @@ export class Databases extends Service { data: Document extends Models.DefaultDocument ? Partial & Record : Partial & Omit; - permissions?: string[]; - transactionId?: string; + permissions?: string[] | null; + transactionId?: string | null; }): Promise; /** * Create a new Document. Before using this route, you should create a new collection resource using either a [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection) API or directly from your database console. @@ -623,8 +748,8 @@ export class Databases extends Service { * @param {string} collectionId - Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection). Make sure to define attributes before creating documents. * @param {string} documentId - Document ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars. * @param {Document extends Models.DefaultDocument ? Partial & Record : Partial & Omit} data - Document data as JSON object. - * @param {string[]} permissions - An array of permissions strings. By default, only the current user is granted all permissions. [Learn more about permissions](https://appwrite.io/docs/permissions). - * @param {string} transactionId - Transaction ID for staging the operation. + * @param {string[] | null} permissions - An array of permissions strings. By default, only the current user is granted all permissions. [Learn more about permissions](https://appwrite.io/docs/permissions). + * @param {string | null} transactionId - Transaction ID for staging the operation. * @throws {AppwriteException} * @returns {Promise} * @deprecated Use the object parameter style method for a better developer experience. @@ -636,8 +761,8 @@ export class Databases extends Service { data: Document extends Models.DefaultDocument ? Partial & Record : Partial & Omit, - permissions?: string[], - transactionId?: string, + permissions?: string[] | null, + transactionId?: string | null, ): Promise; createDocument( paramsOrFirst: @@ -649,8 +774,8 @@ export class Databases extends Service { ? Partial & Record : Partial & Omit; - permissions?: string[]; - transactionId?: string; + permissions?: string[] | null; + transactionId?: string | null; } | string, ...rest: [ @@ -660,8 +785,8 @@ export class Databases extends Service { ? Partial & Record : Partial & Omit)?, - string[]?, - string?, + (string[] | null)?, + (string | null)?, ] ): Promise { let params: { @@ -672,8 +797,8 @@ export class Databases extends Service { ? Partial & Record : Partial & Omit; - permissions?: string[]; - transactionId?: string; + permissions?: string[] | null; + transactionId?: string | null; }; if ( @@ -689,8 +814,8 @@ export class Databases extends Service { ? Partial & Record : Partial & Omit; - permissions?: string[]; - transactionId?: string; + permissions?: string[] | null; + transactionId?: string | null; }; } else { params = { @@ -701,8 +826,8 @@ export class Databases extends Service { ? Partial & Record : Partial & Omit, - permissions: rest[3] as string[], - transactionId: rest[4] as string, + permissions: rest[3] as string[] | null, + transactionId: rest[4] as string | null, }; } @@ -761,7 +886,7 @@ export class Databases extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -771,6 +896,24 @@ export class Databases extends Service { }, apiPayload, ); + const defaults = { + root: 'document', + models: { + document: { + defaults: { + $id: '', + $sequence: '', + $collectionId: '', + $databaseId: '', + $createdAt: '', + $updatedAt: '', + $permissions: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -901,7 +1044,7 @@ export class Databases extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -910,6 +1053,24 @@ export class Databases extends Service { }, apiPayload, ); + const defaults = { + root: 'document', + models: { + document: { + defaults: { + $id: '', + $sequence: '', + $collectionId: '', + $databaseId: '', + $createdAt: '', + $updatedAt: '', + $permissions: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -919,8 +1080,8 @@ export class Databases extends Service { * @param {string} params.collectionId - Collection ID. * @param {string} params.documentId - Document ID. * @param {Document extends Models.DefaultDocument ? Partial & Record : Partial & Partial>} params.data - Document data as JSON object. Include all required attributes of the document to be created or updated. - * @param {string[]} params.permissions - An array of permissions strings. By default, the current permissions are inherited. [Learn more about permissions](https://appwrite.io/docs/permissions). - * @param {string} params.transactionId - Transaction ID for staging the operation. + * @param {string[] | null} params.permissions - An array of permissions strings. By default, the current permissions are inherited. [Learn more about permissions](https://appwrite.io/docs/permissions). + * @param {string | null} params.transactionId - Transaction ID for staging the operation. * @throws {AppwriteException} * @returns {Promise} * @deprecated This API has been deprecated since 1.8.0. Please use `TablesDB.upsertRow` instead. @@ -935,8 +1096,8 @@ export class Databases extends Service { ? Partial & Record : Partial & Partial>; - permissions?: string[]; - transactionId?: string; + permissions?: string[] | null; + transactionId?: string | null; }): Promise; /** * Create or update a Document. Before using this route, you should create a new collection resource using either a [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection) API or directly from your database console. @@ -945,8 +1106,8 @@ export class Databases extends Service { * @param {string} collectionId - Collection ID. * @param {string} documentId - Document ID. * @param {Document extends Models.DefaultDocument ? Partial & Record : Partial & Partial>} data - Document data as JSON object. Include all required attributes of the document to be created or updated. - * @param {string[]} permissions - An array of permissions strings. By default, the current permissions are inherited. [Learn more about permissions](https://appwrite.io/docs/permissions). - * @param {string} transactionId - Transaction ID for staging the operation. + * @param {string[] | null} permissions - An array of permissions strings. By default, the current permissions are inherited. [Learn more about permissions](https://appwrite.io/docs/permissions). + * @param {string | null} transactionId - Transaction ID for staging the operation. * @throws {AppwriteException} * @returns {Promise} * @deprecated Use the object parameter style method for a better developer experience. @@ -959,8 +1120,8 @@ export class Databases extends Service { ? Partial & Record : Partial & Partial>, - permissions?: string[], - transactionId?: string, + permissions?: string[] | null, + transactionId?: string | null, ): Promise; upsertDocument( paramsOrFirst: @@ -972,8 +1133,8 @@ export class Databases extends Service { ? Partial & Record : Partial & Partial>; - permissions?: string[]; - transactionId?: string; + permissions?: string[] | null; + transactionId?: string | null; } | string, ...rest: [ @@ -983,8 +1144,8 @@ export class Databases extends Service { ? Partial & Record : Partial & Partial>)?, - string[]?, - string?, + (string[] | null)?, + (string | null)?, ] ): Promise { let params: { @@ -995,8 +1156,8 @@ export class Databases extends Service { ? Partial & Record : Partial & Partial>; - permissions?: string[]; - transactionId?: string; + permissions?: string[] | null; + transactionId?: string | null; }; if ( @@ -1012,8 +1173,8 @@ export class Databases extends Service { ? Partial & Record : Partial & Partial>; - permissions?: string[]; - transactionId?: string; + permissions?: string[] | null; + transactionId?: string | null; }; } else { params = { @@ -1024,8 +1185,8 @@ export class Databases extends Service { ? Partial & Record : Partial & Partial>, - permissions: rest[3] as string[], - transactionId: rest[4] as string, + permissions: rest[3] as string[] | null, + transactionId: rest[4] as string | null, }; } @@ -1080,7 +1241,7 @@ export class Databases extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'put', uri, { @@ -1090,6 +1251,24 @@ export class Databases extends Service { }, apiPayload, ); + const defaults = { + root: 'document', + models: { + document: { + defaults: { + $id: '', + $sequence: '', + $collectionId: '', + $databaseId: '', + $createdAt: '', + $updatedAt: '', + $permissions: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1099,8 +1278,8 @@ export class Databases extends Service { * @param {string} params.collectionId - Collection ID. * @param {string} params.documentId - Document ID. * @param {Document extends Models.DefaultDocument ? Partial & Record : Partial & Partial>} params.data - Document data as JSON object. Include only attribute and value pairs to be updated. - * @param {string[]} params.permissions - An array of permissions strings. By default, the current permissions are inherited. [Learn more about permissions](https://appwrite.io/docs/permissions). - * @param {string} params.transactionId - Transaction ID for staging the operation. + * @param {string[] | null} params.permissions - An array of permissions strings. By default, the current permissions are inherited. [Learn more about permissions](https://appwrite.io/docs/permissions). + * @param {string | null} params.transactionId - Transaction ID for staging the operation. * @throws {AppwriteException} * @returns {Promise} * @deprecated This API has been deprecated since 1.8.0. Please use `TablesDB.updateRow` instead. @@ -1115,8 +1294,8 @@ export class Databases extends Service { ? Partial & Record : Partial & Partial>; - permissions?: string[]; - transactionId?: string; + permissions?: string[] | null; + transactionId?: string | null; }): Promise; /** * Update a document by its unique ID. Using the patch method you can pass only specific fields that will get updated. @@ -1125,8 +1304,8 @@ export class Databases extends Service { * @param {string} collectionId - Collection ID. * @param {string} documentId - Document ID. * @param {Document extends Models.DefaultDocument ? Partial & Record : Partial & Partial>} data - Document data as JSON object. Include only attribute and value pairs to be updated. - * @param {string[]} permissions - An array of permissions strings. By default, the current permissions are inherited. [Learn more about permissions](https://appwrite.io/docs/permissions). - * @param {string} transactionId - Transaction ID for staging the operation. + * @param {string[] | null} permissions - An array of permissions strings. By default, the current permissions are inherited. [Learn more about permissions](https://appwrite.io/docs/permissions). + * @param {string | null} transactionId - Transaction ID for staging the operation. * @throws {AppwriteException} * @returns {Promise} * @deprecated Use the object parameter style method for a better developer experience. @@ -1139,8 +1318,8 @@ export class Databases extends Service { ? Partial & Record : Partial & Partial>, - permissions?: string[], - transactionId?: string, + permissions?: string[] | null, + transactionId?: string | null, ): Promise; updateDocument( paramsOrFirst: @@ -1152,8 +1331,8 @@ export class Databases extends Service { ? Partial & Record : Partial & Partial>; - permissions?: string[]; - transactionId?: string; + permissions?: string[] | null; + transactionId?: string | null; } | string, ...rest: [ @@ -1163,8 +1342,8 @@ export class Databases extends Service { ? Partial & Record : Partial & Partial>)?, - string[]?, - string?, + (string[] | null)?, + (string | null)?, ] ): Promise { let params: { @@ -1175,8 +1354,8 @@ export class Databases extends Service { ? Partial & Record : Partial & Partial>; - permissions?: string[]; - transactionId?: string; + permissions?: string[] | null; + transactionId?: string | null; }; if ( @@ -1192,8 +1371,8 @@ export class Databases extends Service { ? Partial & Record : Partial & Partial>; - permissions?: string[]; - transactionId?: string; + permissions?: string[] | null; + transactionId?: string | null; }; } else { params = { @@ -1204,8 +1383,8 @@ export class Databases extends Service { ? Partial & Record : Partial & Partial>, - permissions: rest[3] as string[], - transactionId: rest[4] as string, + permissions: rest[3] as string[] | null, + transactionId: rest[4] as string | null, }; } @@ -1260,7 +1439,7 @@ export class Databases extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'patch', uri, { @@ -1270,6 +1449,24 @@ export class Databases extends Service { }, apiPayload, ); + const defaults = { + root: 'document', + models: { + document: { + defaults: { + $id: '', + $sequence: '', + $collectionId: '', + $databaseId: '', + $createdAt: '', + $updatedAt: '', + $permissions: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1405,8 +1602,8 @@ export class Databases extends Service { * @param {string} params.documentId - Document ID. * @param {string} params.attribute - Attribute key. * @param {number} params.value - Value to increment the attribute by. The value must be a number. - * @param {number} params.min - Minimum value for the attribute. If the current value is lesser than this value, an exception will be thrown. - * @param {string} params.transactionId - Transaction ID for staging the operation. + * @param {number | null} params.min - Minimum value for the attribute. If the current value is lesser than this value, an exception will be thrown. + * @param {string | null} params.transactionId - Transaction ID for staging the operation. * @throws {AppwriteException} * @returns {Promise} * @deprecated This API has been deprecated since 1.8.0. Please use `TablesDB.decrementRowColumn` instead. @@ -1419,8 +1616,8 @@ export class Databases extends Service { documentId: string; attribute: string; value?: number; - min?: number; - transactionId?: string; + min?: number | null; + transactionId?: string | null; }): Promise; /** * Decrement a specific attribute of a document by a given value. @@ -1430,8 +1627,8 @@ export class Databases extends Service { * @param {string} documentId - Document ID. * @param {string} attribute - Attribute key. * @param {number} value - Value to increment the attribute by. The value must be a number. - * @param {number} min - Minimum value for the attribute. If the current value is lesser than this value, an exception will be thrown. - * @param {string} transactionId - Transaction ID for staging the operation. + * @param {number | null} min - Minimum value for the attribute. If the current value is lesser than this value, an exception will be thrown. + * @param {string | null} transactionId - Transaction ID for staging the operation. * @throws {AppwriteException} * @returns {Promise} * @deprecated Use the object parameter style method for a better developer experience. @@ -1444,8 +1641,8 @@ export class Databases extends Service { documentId: string, attribute: string, value?: number, - min?: number, - transactionId?: string, + min?: number | null, + transactionId?: string | null, ): Promise; decrementDocumentAttribute< Document extends Models.Document = Models.DefaultDocument, @@ -1457,11 +1654,18 @@ export class Databases extends Service { documentId: string; attribute: string; value?: number; - min?: number; - transactionId?: string; + min?: number | null; + transactionId?: string | null; } | string, - ...rest: [string?, string?, string?, number?, number?, string?] + ...rest: [ + string?, + string?, + string?, + number?, + (number | null)?, + (string | null)?, + ] ): Promise { let params: { databaseId: string; @@ -1469,8 +1673,8 @@ export class Databases extends Service { documentId: string; attribute: string; value?: number; - min?: number; - transactionId?: string; + min?: number | null; + transactionId?: string | null; }; if ( @@ -1484,8 +1688,8 @@ export class Databases extends Service { documentId: string; attribute: string; value?: number; - min?: number; - transactionId?: string; + min?: number | null; + transactionId?: string | null; }; } else { params = { @@ -1494,8 +1698,8 @@ export class Databases extends Service { documentId: rest[1] as string, attribute: rest[2] as string, value: rest[3] as number, - min: rest[4] as number, - transactionId: rest[5] as string, + min: rest[4] as number | null, + transactionId: rest[5] as string | null, }; } @@ -1555,7 +1759,7 @@ export class Databases extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'patch', uri, { @@ -1565,6 +1769,24 @@ export class Databases extends Service { }, apiPayload, ); + const defaults = { + root: 'document', + models: { + document: { + defaults: { + $id: '', + $sequence: '', + $collectionId: '', + $databaseId: '', + $createdAt: '', + $updatedAt: '', + $permissions: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1575,8 +1797,8 @@ export class Databases extends Service { * @param {string} params.documentId - Document ID. * @param {string} params.attribute - Attribute key. * @param {number} params.value - Value to increment the attribute by. The value must be a number. - * @param {number} params.max - Maximum value for the attribute. If the current value is greater than this value, an error will be thrown. - * @param {string} params.transactionId - Transaction ID for staging the operation. + * @param {number | null} params.max - Maximum value for the attribute. If the current value is greater than this value, an error will be thrown. + * @param {string | null} params.transactionId - Transaction ID for staging the operation. * @throws {AppwriteException} * @returns {Promise} * @deprecated This API has been deprecated since 1.8.0. Please use `TablesDB.incrementRowColumn` instead. @@ -1589,8 +1811,8 @@ export class Databases extends Service { documentId: string; attribute: string; value?: number; - max?: number; - transactionId?: string; + max?: number | null; + transactionId?: string | null; }): Promise; /** * Increment a specific attribute of a document by a given value. @@ -1600,8 +1822,8 @@ export class Databases extends Service { * @param {string} documentId - Document ID. * @param {string} attribute - Attribute key. * @param {number} value - Value to increment the attribute by. The value must be a number. - * @param {number} max - Maximum value for the attribute. If the current value is greater than this value, an error will be thrown. - * @param {string} transactionId - Transaction ID for staging the operation. + * @param {number | null} max - Maximum value for the attribute. If the current value is greater than this value, an error will be thrown. + * @param {string | null} transactionId - Transaction ID for staging the operation. * @throws {AppwriteException} * @returns {Promise} * @deprecated Use the object parameter style method for a better developer experience. @@ -1614,8 +1836,8 @@ export class Databases extends Service { documentId: string, attribute: string, value?: number, - max?: number, - transactionId?: string, + max?: number | null, + transactionId?: string | null, ): Promise; incrementDocumentAttribute< Document extends Models.Document = Models.DefaultDocument, @@ -1627,11 +1849,18 @@ export class Databases extends Service { documentId: string; attribute: string; value?: number; - max?: number; - transactionId?: string; + max?: number | null; + transactionId?: string | null; } | string, - ...rest: [string?, string?, string?, number?, number?, string?] + ...rest: [ + string?, + string?, + string?, + number?, + (number | null)?, + (string | null)?, + ] ): Promise { let params: { databaseId: string; @@ -1639,8 +1868,8 @@ export class Databases extends Service { documentId: string; attribute: string; value?: number; - max?: number; - transactionId?: string; + max?: number | null; + transactionId?: string | null; }; if ( @@ -1654,8 +1883,8 @@ export class Databases extends Service { documentId: string; attribute: string; value?: number; - max?: number; - transactionId?: string; + max?: number | null; + transactionId?: string | null; }; } else { params = { @@ -1664,8 +1893,8 @@ export class Databases extends Service { documentId: rest[1] as string, attribute: rest[2] as string, value: rest[3] as number, - max: rest[4] as number, - transactionId: rest[5] as string, + max: rest[4] as number | null, + transactionId: rest[5] as string | null, }; } @@ -1725,7 +1954,7 @@ export class Databases extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'patch', uri, { @@ -1735,5 +1964,23 @@ export class Databases extends Service { }, apiPayload, ); + const defaults = { + root: 'document', + models: { + document: { + defaults: { + $id: '', + $sequence: '', + $collectionId: '', + $databaseId: '', + $createdAt: '', + $updatedAt: '', + $permissions: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } } diff --git a/src/services/documents-db.ts b/src/services/documents-db.ts index 6f10966e..d43db5a9 100644 --- a/src/services/documents-db.ts +++ b/src/services/documents-db.ts @@ -1,5 +1,5 @@ import { Service } from '../service'; -import { AppwriteException, Client } from '../client'; +import { AppwriteException, Client, applyDefaults } from '../client'; import type { Models } from '../models'; import type { Payload } from '../client'; @@ -71,7 +71,7 @@ export class DocumentsDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -80,6 +80,34 @@ export class DocumentsDB extends Service { }, apiPayload, ); + const defaults = { + root: 'transactionList', + models: { + transactionList: { + defaults: { + total: 0, + transactions: [], + }, + properties: { + transactions: { + items: 'transaction', + }, + }, + }, + transaction: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + status: 'pending', + operations: 0, + expiresAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -127,7 +155,7 @@ export class DocumentsDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -137,6 +165,23 @@ export class DocumentsDB extends Service { }, apiPayload, ); + const defaults = { + root: 'transaction', + models: { + transaction: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + status: 'pending', + operations: 0, + expiresAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -190,7 +235,7 @@ export class DocumentsDB extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -199,6 +244,23 @@ export class DocumentsDB extends Service { }, apiPayload, ); + const defaults = { + root: 'transaction', + models: { + transaction: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + status: 'pending', + operations: 0, + expiresAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -285,7 +347,7 @@ export class DocumentsDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'patch', uri, { @@ -295,6 +357,23 @@ export class DocumentsDB extends Service { }, apiPayload, ); + const defaults = { + root: 'transaction', + models: { + transaction: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + status: 'pending', + operations: 0, + expiresAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -427,7 +506,7 @@ export class DocumentsDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -437,6 +516,23 @@ export class DocumentsDB extends Service { }, apiPayload, ); + const defaults = { + root: 'transaction', + models: { + transaction: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + status: 'pending', + operations: 0, + expiresAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -573,7 +669,7 @@ export class DocumentsDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -582,6 +678,35 @@ export class DocumentsDB extends Service { }, apiPayload, ); + const defaults = { + root: 'documentList', + models: { + documentList: { + defaults: { + total: 0, + documents: [], + }, + properties: { + documents: { + items: 'document', + }, + }, + }, + document: { + defaults: { + $id: '', + $sequence: '', + $collectionId: '', + $databaseId: '', + $createdAt: '', + $updatedAt: '', + $permissions: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -753,7 +878,7 @@ export class DocumentsDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -763,6 +888,24 @@ export class DocumentsDB extends Service { }, apiPayload, ); + const defaults = { + root: 'document', + models: { + document: { + defaults: { + $id: '', + $sequence: '', + $collectionId: '', + $databaseId: '', + $createdAt: '', + $updatedAt: '', + $permissions: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -879,7 +1022,7 @@ export class DocumentsDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -889,6 +1032,35 @@ export class DocumentsDB extends Service { }, apiPayload, ); + const defaults = { + root: 'documentList', + models: { + documentList: { + defaults: { + total: 0, + documents: [], + }, + properties: { + documents: { + items: 'document', + }, + }, + }, + document: { + defaults: { + $id: '', + $sequence: '', + $collectionId: '', + $databaseId: '', + $createdAt: '', + $updatedAt: '', + $permissions: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1018,7 +1190,7 @@ export class DocumentsDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -1027,6 +1199,24 @@ export class DocumentsDB extends Service { }, apiPayload, ); + const defaults = { + root: 'document', + models: { + document: { + defaults: { + $id: '', + $sequence: '', + $collectionId: '', + $databaseId: '', + $createdAt: '', + $updatedAt: '', + $permissions: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1196,7 +1386,7 @@ export class DocumentsDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'put', uri, { @@ -1206,6 +1396,24 @@ export class DocumentsDB extends Service { }, apiPayload, ); + const defaults = { + root: 'document', + models: { + document: { + defaults: { + $id: '', + $sequence: '', + $collectionId: '', + $databaseId: '', + $createdAt: '', + $updatedAt: '', + $permissions: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1375,7 +1583,7 @@ export class DocumentsDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'patch', uri, { @@ -1385,6 +1593,24 @@ export class DocumentsDB extends Service { }, apiPayload, ); + const defaults = { + root: 'document', + models: { + document: { + defaults: { + $id: '', + $sequence: '', + $collectionId: '', + $databaseId: '', + $createdAt: '', + $updatedAt: '', + $permissions: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1668,7 +1894,7 @@ export class DocumentsDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'patch', uri, { @@ -1678,6 +1904,24 @@ export class DocumentsDB extends Service { }, apiPayload, ); + const defaults = { + root: 'document', + models: { + document: { + defaults: { + $id: '', + $sequence: '', + $collectionId: '', + $databaseId: '', + $createdAt: '', + $updatedAt: '', + $permissions: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1837,7 +2081,7 @@ export class DocumentsDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'patch', uri, { @@ -1847,5 +2091,23 @@ export class DocumentsDB extends Service { }, apiPayload, ); + const defaults = { + root: 'document', + models: { + document: { + defaults: { + $id: '', + $sequence: '', + $collectionId: '', + $databaseId: '', + $createdAt: '', + $updatedAt: '', + $permissions: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } } diff --git a/src/services/functions.ts b/src/services/functions.ts index 230ffe70..db74d35c 100644 --- a/src/services/functions.ts +++ b/src/services/functions.ts @@ -1,5 +1,5 @@ import { Service } from '../service'; -import { AppwriteException, Client } from '../client'; +import { AppwriteException, Client, applyDefaults } from '../client'; import type { Models } from '../models'; import type { Payload } from '../client'; @@ -89,7 +89,7 @@ export class Functions extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -98,6 +98,58 @@ export class Functions extends Service { }, apiPayload, ); + const defaults = { + root: 'executionList', + models: { + executionList: { + defaults: { + total: 0, + executions: [], + }, + properties: { + executions: { + items: 'execution', + }, + }, + }, + execution: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + $permissions: [], + resourceId: '', + resourceType: 'functions', + deploymentId: '', + requestMethod: '', + requestPath: '', + requestHeaders: [], + responseStatusCode: 0, + responseBody: '', + responseHeaders: [], + logs: '', + errors: '', + duration: 0, + }, + properties: { + requestHeaders: { + items: 'headers', + }, + responseHeaders: { + items: 'headers', + }, + }, + }, + headers: { + defaults: { + name: '', + value: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -109,7 +161,7 @@ export class Functions extends Service { * @param {string} params.xpath - HTTP path of execution. Path can include query params. Default value is / * @param {ExecutionMethod} params.method - HTTP method of execution. Default value is POST. * @param {object} params.headers - HTTP headers of execution. Defaults to empty. - * @param {string} params.scheduledAt - Scheduled execution time in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format. DateTime value must be in future with precision in minutes. + * @param {string | null} params.scheduledAt - Scheduled execution time in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format. DateTime value must be in future with precision in minutes. * @throws {AppwriteException} * @returns {Promise} */ @@ -120,7 +172,7 @@ export class Functions extends Service { xpath?: string; method?: ExecutionMethod; headers?: object; - scheduledAt?: string; + scheduledAt?: string | null; }): Promise; /** * Trigger a function execution. The returned object will return you the current execution status. You can ping the `Get Execution` endpoint to get updates on the current execution status. Once this endpoint is called, your function execution process will start asynchronously. @@ -131,7 +183,7 @@ export class Functions extends Service { * @param {string} xpath - HTTP path of execution. Path can include query params. Default value is / * @param {ExecutionMethod} method - HTTP method of execution. Default value is POST. * @param {object} headers - HTTP headers of execution. Defaults to empty. - * @param {string} scheduledAt - Scheduled execution time in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format. DateTime value must be in future with precision in minutes. + * @param {string | null} scheduledAt - Scheduled execution time in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format. DateTime value must be in future with precision in minutes. * @throws {AppwriteException} * @returns {Promise} * @deprecated Use the object parameter style method for a better developer experience. @@ -143,7 +195,7 @@ export class Functions extends Service { xpath?: string, method?: ExecutionMethod, headers?: object, - scheduledAt?: string, + scheduledAt?: string | null, ): Promise; createExecution( paramsOrFirst: @@ -154,7 +206,7 @@ export class Functions extends Service { xpath?: string; method?: ExecutionMethod; headers?: object; - scheduledAt?: string; + scheduledAt?: string | null; } | string, ...rest: [ @@ -163,7 +215,7 @@ export class Functions extends Service { string?, ExecutionMethod?, object?, - string?, + (string | null)?, ] ): Promise { let params: { @@ -173,7 +225,7 @@ export class Functions extends Service { xpath?: string; method?: ExecutionMethod; headers?: object; - scheduledAt?: string; + scheduledAt?: string | null; }; if ( @@ -188,7 +240,7 @@ export class Functions extends Service { xpath?: string; method?: ExecutionMethod; headers?: object; - scheduledAt?: string; + scheduledAt?: string | null; }; } else { params = { @@ -198,7 +250,7 @@ export class Functions extends Service { xpath: rest[2] as string, method: rest[3] as ExecutionMethod, headers: rest[4] as object, - scheduledAt: rest[5] as string, + scheduledAt: rest[5] as string | null, }; } @@ -247,7 +299,7 @@ export class Functions extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -257,6 +309,47 @@ export class Functions extends Service { }, apiPayload, ); + const defaults = { + root: 'execution', + models: { + execution: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + $permissions: [], + resourceId: '', + resourceType: 'functions', + deploymentId: '', + requestMethod: '', + requestPath: '', + requestHeaders: [], + responseStatusCode: 0, + responseBody: '', + responseHeaders: [], + logs: '', + errors: '', + duration: 0, + }, + properties: { + requestHeaders: { + items: 'headers', + }, + responseHeaders: { + items: 'headers', + }, + }, + }, + headers: { + defaults: { + name: '', + value: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -327,7 +420,7 @@ export class Functions extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -336,5 +429,46 @@ export class Functions extends Service { }, apiPayload, ); + const defaults = { + root: 'execution', + models: { + execution: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + $permissions: [], + resourceId: '', + resourceType: 'functions', + deploymentId: '', + requestMethod: '', + requestPath: '', + requestHeaders: [], + responseStatusCode: 0, + responseBody: '', + responseHeaders: [], + logs: '', + errors: '', + duration: 0, + }, + properties: { + requestHeaders: { + items: 'headers', + }, + responseHeaders: { + items: 'headers', + }, + }, + }, + headers: { + defaults: { + name: '', + value: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } } diff --git a/src/services/locale.ts b/src/services/locale.ts index ce9e92b2..7ab026b5 100644 --- a/src/services/locale.ts +++ b/src/services/locale.ts @@ -1,5 +1,5 @@ import { Service } from '../service'; -import { Client } from '../client'; +import { Client, applyDefaults } from '../client'; import type { Models } from '../models'; import type { Payload } from '../client'; @@ -21,7 +21,7 @@ export class Locale extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -30,6 +30,24 @@ export class Locale extends Service { }, apiPayload, ); + const defaults = { + root: 'locale', + models: { + locale: { + defaults: { + ip: '', + countryCode: '', + country: '', + continentCode: '', + continent: '', + eu: false, + currency: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -77,7 +95,7 @@ export class Locale extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -86,6 +104,30 @@ export class Locale extends Service { }, apiPayload, ); + const defaults = { + root: 'localeCodeList', + models: { + localeCodeList: { + defaults: { + total: 0, + localeCodes: [], + }, + properties: { + localeCodes: { + items: 'localeCode', + }, + }, + }, + localeCode: { + defaults: { + code: '', + name: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -133,7 +175,7 @@ export class Locale extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -142,6 +184,30 @@ export class Locale extends Service { }, apiPayload, ); + const defaults = { + root: 'continentList', + models: { + continentList: { + defaults: { + total: 0, + continents: [], + }, + properties: { + continents: { + items: 'continent', + }, + }, + }, + continent: { + defaults: { + name: '', + code: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -189,7 +255,7 @@ export class Locale extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -198,6 +264,30 @@ export class Locale extends Service { }, apiPayload, ); + const defaults = { + root: 'countryList', + models: { + countryList: { + defaults: { + total: 0, + countries: [], + }, + properties: { + countries: { + items: 'country', + }, + }, + }, + country: { + defaults: { + name: '', + code: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -245,7 +335,7 @@ export class Locale extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -254,6 +344,30 @@ export class Locale extends Service { }, apiPayload, ); + const defaults = { + root: 'countryList', + models: { + countryList: { + defaults: { + total: 0, + countries: [], + }, + properties: { + countries: { + items: 'country', + }, + }, + }, + country: { + defaults: { + name: '', + code: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -303,7 +417,7 @@ export class Locale extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -312,6 +426,31 @@ export class Locale extends Service { }, apiPayload, ); + const defaults = { + root: 'phoneList', + models: { + phoneList: { + defaults: { + total: 0, + phones: [], + }, + properties: { + phones: { + items: 'phone', + }, + }, + }, + phone: { + defaults: { + code: '', + countryCode: '', + countryName: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -359,7 +498,7 @@ export class Locale extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -368,6 +507,35 @@ export class Locale extends Service { }, apiPayload, ); + const defaults = { + root: 'currencyList', + models: { + currencyList: { + defaults: { + total: 0, + currencies: [], + }, + properties: { + currencies: { + items: 'currency', + }, + }, + }, + currency: { + defaults: { + symbol: '', + name: '', + symbolNative: '', + decimalDigits: 0, + rounding: 0, + code: '', + namePlural: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -415,7 +583,7 @@ export class Locale extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -424,5 +592,30 @@ export class Locale extends Service { }, apiPayload, ); + const defaults = { + root: 'languageList', + models: { + languageList: { + defaults: { + total: 0, + languages: [], + }, + properties: { + languages: { + items: 'language', + }, + }, + }, + language: { + defaults: { + name: '', + code: '', + nativeName: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } } diff --git a/src/services/messaging.ts b/src/services/messaging.ts index 33e94c19..b1939ddf 100644 --- a/src/services/messaging.ts +++ b/src/services/messaging.ts @@ -1,5 +1,5 @@ import { Service } from '../service'; -import { AppwriteException, Client } from '../client'; +import { AppwriteException, Client, applyDefaults } from '../client'; import type { Models } from '../models'; import type { Payload } from '../client'; @@ -100,7 +100,7 @@ export class Messaging extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -110,6 +110,25 @@ export class Messaging extends Service { }, apiPayload, ); + const defaults = { + root: 'subscriber', + models: { + subscriber: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + targetId: '', + userId: '', + userName: '', + topicId: '', + providerType: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** diff --git a/src/services/oauth-2.ts b/src/services/oauth-2.ts index 1920bc1a..185fad00 100644 --- a/src/services/oauth-2.ts +++ b/src/services/oauth-2.ts @@ -1,5 +1,5 @@ import { Service } from '../service'; -import { AppwriteException, Client } from '../client'; +import { AppwriteException, Client, applyDefaults } from '../client'; import type { Models } from '../models'; import type { Payload } from '../client'; @@ -96,7 +96,7 @@ export class Oauth2 extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -105,6 +105,18 @@ export class Oauth2 extends Service { }, apiPayload, ); + const defaults = { + root: 'oauth2Approve', + models: { + oauth2Approve: { + defaults: { + redirectUrl: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -121,7 +133,7 @@ export class Oauth2 extends Service { * @param {string} params.prompt - OIDC prompt parameter for customization of consent screen. Space-separated list of: none, login, consent, select_account. * @param {number} params.maxAge - OIDC max_age paraleter for customization of consent screen. Maximum allowable elapsed time in seconds since the user last authenticated. If exceeded, re-authentication is required. * @param {string} params.authorizationDetails - Rich authorization request. JSON array of objects, each with a `type` and project-defined fields - * @param {string} params.resource - RFC 8707 resource indicator URI or URI list. Each value must be an absolute URI without a fragment. + * @param {string[]} params.resource - RFC 8707 resource indicator URI or URI list. Each value must be an absolute URI without a fragment. * @param {string} params.audience - Compatibility alias for a single OAuth2 resource indicator URI. * @param {string} params.requestUri - OAuth2 authorization request handle returned by the pushed authorization request endpoint. * @throws {AppwriteException} @@ -139,7 +151,7 @@ export class Oauth2 extends Service { prompt?: string; maxAge?: number; authorizationDetails?: string; - resource?: string; + resource?: string[]; audience?: string; requestUri?: string; }): Promise; @@ -157,7 +169,7 @@ export class Oauth2 extends Service { * @param {string} prompt - OIDC prompt parameter for customization of consent screen. Space-separated list of: none, login, consent, select_account. * @param {number} maxAge - OIDC max_age paraleter for customization of consent screen. Maximum allowable elapsed time in seconds since the user last authenticated. If exceeded, re-authentication is required. * @param {string} authorizationDetails - Rich authorization request. JSON array of objects, each with a `type` and project-defined fields - * @param {string} resource - RFC 8707 resource indicator URI or URI list. Each value must be an absolute URI without a fragment. + * @param {string[]} resource - RFC 8707 resource indicator URI or URI list. Each value must be an absolute URI without a fragment. * @param {string} audience - Compatibility alias for a single OAuth2 resource indicator URI. * @param {string} requestUri - OAuth2 authorization request handle returned by the pushed authorization request endpoint. * @throws {AppwriteException} @@ -176,7 +188,7 @@ export class Oauth2 extends Service { prompt?: string, maxAge?: number, authorizationDetails?: string, - resource?: string, + resource?: string[], audience?: string, requestUri?: string, ): Promise; @@ -194,7 +206,7 @@ export class Oauth2 extends Service { prompt?: string; maxAge?: number; authorizationDetails?: string; - resource?: string; + resource?: string[]; audience?: string; requestUri?: string; } @@ -210,7 +222,7 @@ export class Oauth2 extends Service { string?, number?, string?, - string?, + string[]?, string?, string?, ] @@ -227,7 +239,7 @@ export class Oauth2 extends Service { prompt?: string; maxAge?: number; authorizationDetails?: string; - resource?: string; + resource?: string[]; audience?: string; requestUri?: string; }; @@ -250,7 +262,7 @@ export class Oauth2 extends Service { prompt?: string; maxAge?: number; authorizationDetails?: string; - resource?: string; + resource?: string[]; audience?: string; requestUri?: string; }; @@ -267,7 +279,7 @@ export class Oauth2 extends Service { prompt: rest[7] as string, maxAge: rest[8] as number, authorizationDetails: rest[9] as string, - resource: rest[10] as string, + resource: rest[10] as string[], audience: rest[11] as string, requestUri: rest[12] as string, }; @@ -351,7 +363,7 @@ export class Oauth2 extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -359,6 +371,19 @@ export class Oauth2 extends Service { }, apiPayload, ); + const defaults = { + root: 'oauth2Authorize', + models: { + oauth2Authorize: { + defaults: { + grantId: '', + redirectUrl: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -373,9 +398,9 @@ export class Oauth2 extends Service { * @param {string} params.codeChallenge - PKCE code challenge. Required when OAuth2 app is public. * @param {string} params.codeChallengeMethod - PKCE code challenge method. Required when OAuth2 app is public. * @param {string} params.prompt - OIDC prompt parameter for customization of consent screen. Space-separated list of: none, login, consent, select_account. - * @param {number} params.maxAge - OIDC max_age paraleter for customization of consent screen. Maximum allowable elapsed time in seconds since the user last authenticated. If exceeded, re-authentication is required. + * @param {number | null} params.maxAge - OIDC max_age paraleter for customization of consent screen. Maximum allowable elapsed time in seconds since the user last authenticated. If exceeded, re-authentication is required. * @param {string} params.authorizationDetails - Rich authorization request. JSON array of objects, each with a `type` and project-defined fields - * @param {string} params.resource - RFC 8707 resource indicator URI or URI list. Each value must be an absolute URI without a fragment. + * @param {string[]} params.resource - RFC 8707 resource indicator URI or URI list. Each value must be an absolute URI without a fragment. * @param {string} params.audience - Compatibility alias for a single OAuth2 resource indicator URI. * @param {string} params.requestUri - OAuth2 authorization request handle returned by the pushed authorization request endpoint. * @throws {AppwriteException} @@ -391,9 +416,9 @@ export class Oauth2 extends Service { codeChallenge?: string; codeChallengeMethod?: string; prompt?: string; - maxAge?: number; + maxAge?: number | null; authorizationDetails?: string; - resource?: string; + resource?: string[]; audience?: string; requestUri?: string; }): Promise; @@ -409,9 +434,9 @@ export class Oauth2 extends Service { * @param {string} codeChallenge - PKCE code challenge. Required when OAuth2 app is public. * @param {string} codeChallengeMethod - PKCE code challenge method. Required when OAuth2 app is public. * @param {string} prompt - OIDC prompt parameter for customization of consent screen. Space-separated list of: none, login, consent, select_account. - * @param {number} maxAge - OIDC max_age paraleter for customization of consent screen. Maximum allowable elapsed time in seconds since the user last authenticated. If exceeded, re-authentication is required. + * @param {number | null} maxAge - OIDC max_age paraleter for customization of consent screen. Maximum allowable elapsed time in seconds since the user last authenticated. If exceeded, re-authentication is required. * @param {string} authorizationDetails - Rich authorization request. JSON array of objects, each with a `type` and project-defined fields - * @param {string} resource - RFC 8707 resource indicator URI or URI list. Each value must be an absolute URI without a fragment. + * @param {string[]} resource - RFC 8707 resource indicator URI or URI list. Each value must be an absolute URI without a fragment. * @param {string} audience - Compatibility alias for a single OAuth2 resource indicator URI. * @param {string} requestUri - OAuth2 authorization request handle returned by the pushed authorization request endpoint. * @throws {AppwriteException} @@ -428,9 +453,9 @@ export class Oauth2 extends Service { codeChallenge?: string, codeChallengeMethod?: string, prompt?: string, - maxAge?: number, + maxAge?: number | null, authorizationDetails?: string, - resource?: string, + resource?: string[], audience?: string, requestUri?: string, ): Promise; @@ -446,9 +471,9 @@ export class Oauth2 extends Service { codeChallenge?: string; codeChallengeMethod?: string; prompt?: string; - maxAge?: number; + maxAge?: number | null; authorizationDetails?: string; - resource?: string; + resource?: string[]; audience?: string; requestUri?: string; } @@ -462,9 +487,9 @@ export class Oauth2 extends Service { string?, string?, string?, - number?, - string?, + (number | null)?, string?, + string[]?, string?, string?, ] @@ -479,9 +504,9 @@ export class Oauth2 extends Service { codeChallenge?: string; codeChallengeMethod?: string; prompt?: string; - maxAge?: number; + maxAge?: number | null; authorizationDetails?: string; - resource?: string; + resource?: string[]; audience?: string; requestUri?: string; }; @@ -502,9 +527,9 @@ export class Oauth2 extends Service { codeChallenge?: string; codeChallengeMethod?: string; prompt?: string; - maxAge?: number; + maxAge?: number | null; authorizationDetails?: string; - resource?: string; + resource?: string[]; audience?: string; requestUri?: string; }; @@ -519,9 +544,9 @@ export class Oauth2 extends Service { codeChallenge: rest[5] as string, codeChallengeMethod: rest[6] as string, prompt: rest[7] as string, - maxAge: rest[8] as number, + maxAge: rest[8] as number | null, authorizationDetails: rest[9] as string, - resource: rest[10] as string, + resource: rest[10] as string[], audience: rest[11] as string, requestUri: rest[12] as string, }; @@ -605,7 +630,7 @@ export class Oauth2 extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -614,6 +639,19 @@ export class Oauth2 extends Service { }, apiPayload, ); + const defaults = { + root: 'oauth2Authorize', + models: { + oauth2Authorize: { + defaults: { + grantId: '', + redirectUrl: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -622,7 +660,7 @@ export class Oauth2 extends Service { * @param {string} params.clientId - OAuth2 client ID. Either a registered app ID or an HTTPS client ID metadata document URL. * @param {string} params.scope - Space-separated OAuth2 scopes. Can include project scopes, and built-in scopes: `openid`, `email`, `profile`. * @param {string} params.authorizationDetails - Rich authorization request. JSON array of objects, each with a `type` and project-defined fields - * @param {string} params.resource - RFC 8707 resource indicator URI or URI list. Each value must be an absolute URI without a fragment. + * @param {string[]} params.resource - RFC 8707 resource indicator URI or URI list. Each value must be an absolute URI without a fragment. * @param {string} params.audience - Compatibility alias for a single OAuth2 resource indicator URI. * @throws {AppwriteException} * @returns {Promise} @@ -631,7 +669,7 @@ export class Oauth2 extends Service { clientId?: string; scope?: string; authorizationDetails?: string; - resource?: string; + resource?: string[]; audience?: string; }): Promise; /** @@ -640,7 +678,7 @@ export class Oauth2 extends Service { * @param {string} clientId - OAuth2 client ID. Either a registered app ID or an HTTPS client ID metadata document URL. * @param {string} scope - Space-separated OAuth2 scopes. Can include project scopes, and built-in scopes: `openid`, `email`, `profile`. * @param {string} authorizationDetails - Rich authorization request. JSON array of objects, each with a `type` and project-defined fields - * @param {string} resource - RFC 8707 resource indicator URI or URI list. Each value must be an absolute URI without a fragment. + * @param {string[]} resource - RFC 8707 resource indicator URI or URI list. Each value must be an absolute URI without a fragment. * @param {string} audience - Compatibility alias for a single OAuth2 resource indicator URI. * @throws {AppwriteException} * @returns {Promise} @@ -650,7 +688,7 @@ export class Oauth2 extends Service { clientId?: string, scope?: string, authorizationDetails?: string, - resource?: string, + resource?: string[], audience?: string, ): Promise; createDeviceAuthorization( @@ -659,17 +697,17 @@ export class Oauth2 extends Service { clientId?: string; scope?: string; authorizationDetails?: string; - resource?: string; + resource?: string[]; audience?: string; } | string, - ...rest: [string?, string?, string?, string?] + ...rest: [string?, string?, string[]?, string?] ): Promise { let params: { clientId?: string; scope?: string; authorizationDetails?: string; - resource?: string; + resource?: string[]; audience?: string; }; @@ -683,7 +721,7 @@ export class Oauth2 extends Service { clientId?: string; scope?: string; authorizationDetails?: string; - resource?: string; + resource?: string[]; audience?: string; }; } else { @@ -691,7 +729,7 @@ export class Oauth2 extends Service { clientId: paramsOrFirst as string, scope: rest[0] as string, authorizationDetails: rest[1] as string, - resource: rest[2] as string, + resource: rest[2] as string[], audience: rest[3] as string, }; } @@ -729,7 +767,7 @@ export class Oauth2 extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -738,6 +776,23 @@ export class Oauth2 extends Service { }, apiPayload, ); + const defaults = { + root: 'oauth2DeviceAuthorization', + models: { + oauth2DeviceAuthorization: { + defaults: { + device_code: '', + user_code: '', + verification_uri: '', + verification_uri_complete: '', + expires_in: 0, + interval: 0, + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -793,7 +848,7 @@ export class Oauth2 extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -802,6 +857,29 @@ export class Oauth2 extends Service { }, apiPayload, ); + const defaults = { + root: 'oauth2Grant', + models: { + oauth2Grant: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + userId: '', + appId: '', + scopes: [], + resources: [], + authorizationDetails: '[]', + prompt: '', + redirectUri: '', + authTime: 0, + expire: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -855,7 +933,7 @@ export class Oauth2 extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -863,6 +941,29 @@ export class Oauth2 extends Service { }, apiPayload, ); + const defaults = { + root: 'oauth2Grant', + models: { + oauth2Grant: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + userId: '', + appId: '', + scopes: [], + resources: [], + authorizationDetails: '[]', + prompt: '', + redirectUri: '', + authTime: 0, + expire: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1216,7 +1317,7 @@ export class Oauth2 extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -1224,6 +1325,29 @@ export class Oauth2 extends Service { }, apiPayload, ); + const defaults = { + root: 'oauth2OrganizationList', + models: { + oauth2OrganizationList: { + defaults: { + total: 0, + organizations: [], + }, + properties: { + organizations: { + items: 'oauth2Organization', + }, + }, + }, + oauth2Organization: { + defaults: { + $id: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1238,9 +1362,9 @@ export class Oauth2 extends Service { * @param {string} params.codeChallenge - PKCE code challenge. Required when OAuth2 app is public. * @param {string} params.codeChallengeMethod - PKCE code challenge method. Required when OAuth2 app is public. * @param {string} params.prompt - OIDC prompt parameter for customization of consent screen. Space-separated list of: none, login, consent, select_account. - * @param {number} params.maxAge - OIDC max_age parameter for customization of consent screen. + * @param {number | null} params.maxAge - OIDC max_age parameter for customization of consent screen. * @param {string} params.authorizationDetails - Rich authorization request. JSON array of objects, each with a `type` and project-defined fields - * @param {string} params.resource - RFC 8707 resource indicator URI or URI list. Each value must be an absolute URI without a fragment. + * @param {string[]} params.resource - RFC 8707 resource indicator URI or URI list. Each value must be an absolute URI without a fragment. * @param {string} params.audience - Compatibility alias for a single OAuth2 resource indicator URI. * @throws {AppwriteException} * @returns {Promise} @@ -1255,9 +1379,9 @@ export class Oauth2 extends Service { codeChallenge?: string; codeChallengeMethod?: string; prompt?: string; - maxAge?: number; + maxAge?: number | null; authorizationDetails?: string; - resource?: string; + resource?: string[]; audience?: string; }): Promise; /** @@ -1272,9 +1396,9 @@ export class Oauth2 extends Service { * @param {string} codeChallenge - PKCE code challenge. Required when OAuth2 app is public. * @param {string} codeChallengeMethod - PKCE code challenge method. Required when OAuth2 app is public. * @param {string} prompt - OIDC prompt parameter for customization of consent screen. Space-separated list of: none, login, consent, select_account. - * @param {number} maxAge - OIDC max_age parameter for customization of consent screen. + * @param {number | null} maxAge - OIDC max_age parameter for customization of consent screen. * @param {string} authorizationDetails - Rich authorization request. JSON array of objects, each with a `type` and project-defined fields - * @param {string} resource - RFC 8707 resource indicator URI or URI list. Each value must be an absolute URI without a fragment. + * @param {string[]} resource - RFC 8707 resource indicator URI or URI list. Each value must be an absolute URI without a fragment. * @param {string} audience - Compatibility alias for a single OAuth2 resource indicator URI. * @throws {AppwriteException} * @returns {Promise} @@ -1290,9 +1414,9 @@ export class Oauth2 extends Service { codeChallenge?: string, codeChallengeMethod?: string, prompt?: string, - maxAge?: number, + maxAge?: number | null, authorizationDetails?: string, - resource?: string, + resource?: string[], audience?: string, ): Promise; createPAR( @@ -1307,9 +1431,9 @@ export class Oauth2 extends Service { codeChallenge?: string; codeChallengeMethod?: string; prompt?: string; - maxAge?: number; + maxAge?: number | null; authorizationDetails?: string; - resource?: string; + resource?: string[]; audience?: string; } | string, @@ -1322,9 +1446,9 @@ export class Oauth2 extends Service { string?, string?, string?, - number?, - string?, + (number | null)?, string?, + string[]?, string?, ] ): Promise { @@ -1338,9 +1462,9 @@ export class Oauth2 extends Service { codeChallenge?: string; codeChallengeMethod?: string; prompt?: string; - maxAge?: number; + maxAge?: number | null; authorizationDetails?: string; - resource?: string; + resource?: string[]; audience?: string; }; @@ -1359,9 +1483,9 @@ export class Oauth2 extends Service { codeChallenge?: string; codeChallengeMethod?: string; prompt?: string; - maxAge?: number; + maxAge?: number | null; authorizationDetails?: string; - resource?: string; + resource?: string[]; audience?: string; }; } else { @@ -1375,9 +1499,9 @@ export class Oauth2 extends Service { codeChallenge: rest[5] as string, codeChallengeMethod: rest[6] as string, prompt: rest[7] as string, - maxAge: rest[8] as number, + maxAge: rest[8] as number | null, authorizationDetails: rest[9] as string, - resource: rest[10] as string, + resource: rest[10] as string[], audience: rest[11] as string, }; } @@ -1473,7 +1597,7 @@ export class Oauth2 extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -1482,6 +1606,19 @@ export class Oauth2 extends Service { }, apiPayload, ); + const defaults = { + root: 'oauth2PAR', + models: { + oauth2PAR: { + defaults: { + request_uri: '', + expires_in: 0, + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1562,7 +1699,7 @@ export class Oauth2 extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -1570,6 +1707,31 @@ export class Oauth2 extends Service { }, apiPayload, ); + const defaults = { + root: 'oauth2ProjectList', + models: { + oauth2ProjectList: { + defaults: { + total: 0, + projects: [], + }, + properties: { + projects: { + items: 'oauth2Project', + }, + }, + }, + oauth2Project: { + defaults: { + $id: '', + region: '', + endpoint: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1625,7 +1787,7 @@ export class Oauth2 extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -1634,6 +1796,18 @@ export class Oauth2 extends Service { }, apiPayload, ); + const defaults = { + root: 'oauth2Reject', + models: { + oauth2Reject: { + defaults: { + redirectUrl: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1761,7 +1935,7 @@ export class Oauth2 extends Service { * @param {string} params.clientSecret - OAuth2 client secret. Required for confidential apps. * @param {string} params.codeVerifier - PKCE code verifier. Required for public apps. * @param {string} params.redirectUri - Redirect URI. Required for `authorization_code` grant type. - * @param {string} params.resource - RFC 8707 resource indicator URI or URI list. Each value must be an absolute URI without a fragment. + * @param {string[]} params.resource - RFC 8707 resource indicator URI or URI list. Each value must be an absolute URI without a fragment. * @param {string} params.audience - Compatibility alias for a single OAuth2 resource indicator URI. * @throws {AppwriteException} * @returns {Promise} @@ -1775,7 +1949,7 @@ export class Oauth2 extends Service { clientSecret?: string; codeVerifier?: string; redirectUri?: string; - resource?: string; + resource?: string[]; audience?: string; }): Promise; /** @@ -1789,7 +1963,7 @@ export class Oauth2 extends Service { * @param {string} clientSecret - OAuth2 client secret. Required for confidential apps. * @param {string} codeVerifier - PKCE code verifier. Required for public apps. * @param {string} redirectUri - Redirect URI. Required for `authorization_code` grant type. - * @param {string} resource - RFC 8707 resource indicator URI or URI list. Each value must be an absolute URI without a fragment. + * @param {string[]} resource - RFC 8707 resource indicator URI or URI list. Each value must be an absolute URI without a fragment. * @param {string} audience - Compatibility alias for a single OAuth2 resource indicator URI. * @throws {AppwriteException} * @returns {Promise} @@ -1804,7 +1978,7 @@ export class Oauth2 extends Service { clientSecret?: string, codeVerifier?: string, redirectUri?: string, - resource?: string, + resource?: string[], audience?: string, ): Promise; createToken( @@ -1818,7 +1992,7 @@ export class Oauth2 extends Service { clientSecret?: string; codeVerifier?: string; redirectUri?: string; - resource?: string; + resource?: string[]; audience?: string; } | string, @@ -1830,7 +2004,7 @@ export class Oauth2 extends Service { string?, string?, string?, - string?, + string[]?, string?, ] ): Promise { @@ -1843,7 +2017,7 @@ export class Oauth2 extends Service { clientSecret?: string; codeVerifier?: string; redirectUri?: string; - resource?: string; + resource?: string[]; audience?: string; }; @@ -1861,7 +2035,7 @@ export class Oauth2 extends Service { clientSecret?: string; codeVerifier?: string; redirectUri?: string; - resource?: string; + resource?: string[]; audience?: string; }; } else { @@ -1874,7 +2048,7 @@ export class Oauth2 extends Service { clientSecret: rest[4] as string, codeVerifier: rest[5] as string, redirectUri: rest[6] as string, - resource: rest[7] as string, + resource: rest[7] as string[], audience: rest[8] as string, }; } @@ -1943,7 +2117,7 @@ export class Oauth2 extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -1952,5 +2126,21 @@ export class Oauth2 extends Service { }, apiPayload, ); + const defaults = { + root: 'oauth2Token', + models: { + oauth2Token: { + defaults: { + access_token: '', + token_type: 'Bearer', + expires_in: 0, + refresh_token: '', + scope: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } } diff --git a/src/services/organization.ts b/src/services/organization.ts index 3542965f..4ec51e57 100644 --- a/src/services/organization.ts +++ b/src/services/organization.ts @@ -1,5 +1,5 @@ import { Service } from '../service'; -import { AppwriteException, Client } from '../client'; +import { AppwriteException, Client, applyDefaults } from '../client'; import type { Models } from '../models'; import type { Payload } from '../client'; @@ -71,7 +71,7 @@ export class Organization extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -80,6 +80,37 @@ export class Organization extends Service { }, apiPayload, ); + const defaults = { + root: 'appInstallationList', + models: { + appInstallationList: { + defaults: { + total: 0, + installations: [], + }, + properties: { + installations: { + items: 'appInstallation', + }, + }, + }, + appInstallation: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + appId: '', + teamId: '', + scopes: [], + authorizationDetails: [], + createdById: '', + createdByName: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -149,7 +180,7 @@ export class Organization extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -159,6 +190,26 @@ export class Organization extends Service { }, apiPayload, ); + const defaults = { + root: 'appInstallation', + models: { + appInstallation: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + appId: '', + teamId: '', + scopes: [], + authorizationDetails: [], + createdById: '', + createdByName: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -212,7 +263,7 @@ export class Organization extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -221,39 +272,63 @@ export class Organization extends Service { }, apiPayload, ); + const defaults = { + root: 'appInstallation', + models: { + appInstallation: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + appId: '', + teamId: '', + scopes: [], + authorizationDetails: [], + createdById: '', + createdByName: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** * Update an app installation on the organization. Only organization members with the owner role can update installations. The installation's granted scopes are refreshed to the scopes the app currently requests; previously issued installation access tokens are revoked. * * @param {string} params.installationId - Installation unique ID. - * @param {string} params.authorizationDetails - Authorization details granted to the installation as a JSON array of objects, each with a `type` and app-defined fields. Omit to keep the current value. + * @param {string | null} params.authorizationDetails - Authorization details granted to the installation as a JSON array of objects, each with a `type` and app-defined fields. Omit to keep the current value. * @throws {AppwriteException} * @returns {Promise} */ updateInstallation(params: { installationId: string; - authorizationDetails?: string; + authorizationDetails?: string | null; }): Promise; /** * Update an app installation on the organization. Only organization members with the owner role can update installations. The installation's granted scopes are refreshed to the scopes the app currently requests; previously issued installation access tokens are revoked. * * @param {string} installationId - Installation unique ID. - * @param {string} authorizationDetails - Authorization details granted to the installation as a JSON array of objects, each with a `type` and app-defined fields. Omit to keep the current value. + * @param {string | null} authorizationDetails - Authorization details granted to the installation as a JSON array of objects, each with a `type` and app-defined fields. Omit to keep the current value. * @throws {AppwriteException} * @returns {Promise} * @deprecated Use the object parameter style method for a better developer experience. */ updateInstallation( installationId: string, - authorizationDetails?: string, + authorizationDetails?: string | null, ): Promise; updateInstallation( paramsOrFirst: - { installationId: string; authorizationDetails?: string } | string, - ...rest: [string?] + | { installationId: string; authorizationDetails?: string | null } + | string, + ...rest: [(string | null)?] ): Promise { - let params: { installationId: string; authorizationDetails?: string }; + let params: { + installationId: string; + authorizationDetails?: string | null; + }; if ( paramsOrFirst && @@ -262,12 +337,12 @@ export class Organization extends Service { ) { params = (paramsOrFirst || {}) as { installationId: string; - authorizationDetails?: string; + authorizationDetails?: string | null; }; } else { params = { installationId: paramsOrFirst as string, - authorizationDetails: rest[0] as string, + authorizationDetails: rest[0] as string | null, }; } @@ -291,7 +366,7 @@ export class Organization extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'put', uri, { @@ -301,6 +376,26 @@ export class Organization extends Service { }, apiPayload, ); + const defaults = { + root: 'appInstallation', + models: { + appInstallation: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + appId: '', + teamId: '', + scopes: [], + authorizationDetails: [], + createdById: '', + createdByName: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** diff --git a/src/services/presences.ts b/src/services/presences.ts index 5fb3a364..4cc36d8b 100644 --- a/src/services/presences.ts +++ b/src/services/presences.ts @@ -1,5 +1,5 @@ import { Service } from '../service'; -import { AppwriteException, Client } from '../client'; +import { AppwriteException, Client, applyDefaults } from '../client'; import type { Models } from '../models'; import type { Payload } from '../client'; @@ -85,7 +85,7 @@ export class Presences extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -94,6 +94,34 @@ export class Presences extends Service { }, apiPayload, ); + const defaults = { + root: 'presenceList', + models: { + presenceList: { + defaults: { + total: 0, + presences: [], + }, + properties: { + presences: { + items: 'presence', + }, + }, + }, + presence: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + $permissions: [], + userId: '', + source: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -147,7 +175,7 @@ export class Presences extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -156,6 +184,23 @@ export class Presences extends Service { }, apiPayload, ); + const defaults = { + root: 'presence', + models: { + presence: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + $permissions: [], + userId: '', + source: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -278,7 +323,7 @@ export class Presences extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'put', uri, { @@ -288,6 +333,23 @@ export class Presences extends Service { }, apiPayload, ); + const defaults = { + root: 'presence', + models: { + presence: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + $permissions: [], + userId: '', + source: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -419,7 +481,7 @@ export class Presences extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'patch', uri, { @@ -429,6 +491,23 @@ export class Presences extends Service { }, apiPayload, ); + const defaults = { + root: 'presence', + models: { + presence: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + $permissions: [], + userId: '', + source: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** diff --git a/src/services/push.ts b/src/services/push.ts index 880e4f4c..167a6ca5 100644 --- a/src/services/push.ts +++ b/src/services/push.ts @@ -44,8 +44,20 @@ export interface PushBackgroundStatus { ignoringBatteryOptimizations: boolean; /** Foreground mode ({@link Push.setForeground}) keeps the connection open in a service. */ foregroundService: boolean; - /** Wake-ups may be deferred by Doze, so messages can arrive late while the app is closed. */ + /** + * Messages can arrive late, or not until the app is opened, while the app is closed: background + * usage is restricted without a battery optimisation exemption, or wake-ups may be deferred by + * Doze without exact alarms or foreground mode. + */ bestEffort: boolean; + /** + * The user restricted the app's background usage in the app's battery settings (Settings > + * Apps > your app > Battery), Android 9+. Android may then hold its alarms, jobs and foreground + * service while it is closed, so messages can wait until the app is opened. The battery + * optimisation exemption lets the alarms and jobs run again, but foreground mode still stops + * once the app leaves the screen. False below Android 9. + */ + backgroundRestricted: boolean; } /** A background notification the user tapped. */ @@ -293,9 +305,12 @@ export class Push extends Service { } /** - * Android: what background delivery can rely on. When `bestEffort` is true the scheduled - * wake-ups are inexact and Doze can defer them, so messages may arrive late while the app is - * closed; explain why, then ask with {@link requestExactAlarms} or + * Android: what background delivery can rely on. When `bestEffort` is true messages may arrive + * late, or not until the app is opened, while the app is closed, so explain why, then ask. If + * `backgroundRestricted` is true and the app is not `ignoringBatteryOptimizations`, ask the user + * to choose Unrestricted in the app's battery settings (Settings > Apps > your app > Battery), + * or ask with {@link requestIgnoreBatteryOptimizations}; otherwise the scheduled wake-ups are + * inexact and Doze can defer them, so ask with {@link requestExactAlarms} or * {@link requestIgnoreBatteryOptimizations}. Null elsewhere. */ async backgroundStatus(): Promise { @@ -1231,18 +1246,26 @@ export class Push extends Service { } } - /** Post a local notification for a message a background subscription matched. */ - private async notify(message: PushMessage, title: string): Promise { + /** + * Post a local notification for a message a background subscription matched. A data-only + * message, an envelope without a notification title or body, posts none. + */ + private async notify( + message: PushMessage, + title: string, + content: NotificationContent = notificationContent(message), + ): Promise { + if (!content.visible) { + return; + } try { /* eslint-disable @typescript-eslint/no-require-imports */ const notifications: typeof import('expo-notifications') = require('expo-notifications'); /* eslint-enable @typescript-eslint/no-require-imports */ - const content = notificationContent(message); - const raw = !content.present; await notifications.scheduleNotificationAsync({ content: { title: content.title ?? title, - body: content.body ?? (raw ? message.data : null), + body: content.body ?? (content.raw ? message.data : null), data: { topic: message.topic, payload: message.data }, }, trigger: null, @@ -1574,7 +1597,7 @@ export class Push extends Service { payload, qos: packet.qos, }; - const serverTitle = notificationContent(message).title; + const content = notificationContent(message); const postedTitles = new Set(); // While the app is on screen it shows the message itself: only subscriptions that // opted in with notifyInForeground also post a notification then. @@ -1584,14 +1607,14 @@ export class Push extends Service { await sub.callback(message); // Notification is per-subscription: only subs that opted in post one, each // title once. A title the server sent replaces theirs, so it posts once. - const title = serverTitle ?? sub.title ?? message.topic; + const title = content.title ?? sub.title ?? message.topic; if ( sub.background && (!foreground || sub.notifyInForeground) && !postedTitles.has(title) ) { postedTitles.add(title); - await this.notify(message, title); + await this.notify(message, title, content); } } } @@ -1718,33 +1741,51 @@ function expoNotifications(): typeof import('expo-notifications') | null { /** What a message's `notification` block asks a background notification to show. */ interface NotificationContent { - /** Whether the message has a `notification` block at all. */ - present: boolean; + /** Whether the payload is not a JSON object, so it is shown as it is. */ + raw: boolean; + /** Whether a notification is posted: raw, or an envelope with a title or body. */ + visible: boolean; title?: string; body?: string; image?: string; } -/** The server's `notification` block in a message; empty when the payload has none or is not JSON. */ -function notificationContent(message: PushMessage): NotificationContent { - let notification: unknown; +/** The server's `notification` block in a payload, or null when the payload is not a JSON object. */ +function notificationBlock(data: string): Record | null { + let envelope: unknown; try { - notification = (JSON.parse(message.data) as { notification?: unknown }) - ?.notification; + envelope = JSON.parse(data); } catch { - return { present: false }; + return null; } - if (typeof notification !== 'object' || notification === null) { - return { present: false }; + if ( + typeof envelope !== 'object' || + envelope === null || + Array.isArray(envelope) + ) { + return null; } + const notification = (envelope as { notification?: unknown }).notification; + return typeof notification === 'object' && notification !== null + ? (notification as Record) + : {}; +} + +/** What a message asks a background notification to show; raw when it is not a JSON object. */ +function notificationContent(message: PushMessage): NotificationContent { + const block = notificationBlock(message.data); + const raw = block === null; const field = (name: string): string | undefined => { - const value = (notification as Record)[name]; + const value = block?.[name]; return typeof value === 'string' && value !== '' ? value : undefined; }; + const title = field('title'); + const body = field('body'); return { - present: true, - title: field('title'), - body: field('body'), + raw, + visible: raw || title !== undefined || body !== undefined, + title, + body, image: field('image'), }; } diff --git a/src/services/storage.ts b/src/services/storage.ts index fdca28a8..f14c66cf 100644 --- a/src/services/storage.ts +++ b/src/services/storage.ts @@ -1,5 +1,5 @@ import { Service } from '../service'; -import { AppwriteException, Client } from '../client'; +import { AppwriteException, Client, applyDefaults } from '../client'; import type { Models } from '../models'; import type { UploadProgress, Payload } from '../client'; import * as FileSystem from 'expo-file-system'; @@ -113,7 +113,7 @@ export class Storage extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -122,6 +122,44 @@ export class Storage extends Service { }, apiPayload, ); + const defaults = { + root: 'fileList', + models: { + fileList: { + defaults: { + total: 0, + files: [], + }, + properties: { + files: { + items: 'file', + }, + }, + }, + file: { + defaults: { + $id: '', + bucketId: '', + $createdAt: '', + $updatedAt: '', + $permissions: [], + name: '', + folder: '', + key: '', + signature: '', + mimeType: '', + sizeOriginal: 0, + sizeActual: 0, + chunksTotal: 0, + chunksUploaded: 0, + encryption: false, + compression: 'none', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -563,7 +601,7 @@ export class Storage extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -572,6 +610,33 @@ export class Storage extends Service { }, apiPayload, ); + const defaults = { + root: 'file', + models: { + file: { + defaults: { + $id: '', + bucketId: '', + $createdAt: '', + $updatedAt: '', + $permissions: [], + name: '', + folder: '', + key: '', + signature: '', + mimeType: '', + sizeOriginal: 0, + sizeActual: 0, + chunksTotal: 0, + chunksUploaded: 0, + encryption: false, + compression: 'none', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -580,7 +645,7 @@ export class Storage extends Service { * @param {string} params.bucketId - Bucket unique ID. * @param {string} params.fileId - File ID. * @param {string} params.name - File name. - * @param {string[]} params.permissions - An array of permission strings. By default, the current permissions are inherited. [Learn more about permissions](https://appwrite.io/docs/permissions). + * @param {string[] | null} params.permissions - An array of permission strings. By default, the current permissions are inherited. [Learn more about permissions](https://appwrite.io/docs/permissions). * @throws {AppwriteException} * @returns {Promise} */ @@ -588,7 +653,7 @@ export class Storage extends Service { bucketId: string; fileId: string; name?: string; - permissions?: string[]; + permissions?: string[] | null; }): Promise; /** * Update a file by its unique ID. Only users with write permissions have access to update this resource. @@ -596,7 +661,7 @@ export class Storage extends Service { * @param {string} bucketId - Bucket unique ID. * @param {string} fileId - File ID. * @param {string} name - File name. - * @param {string[]} permissions - An array of permission strings. By default, the current permissions are inherited. [Learn more about permissions](https://appwrite.io/docs/permissions). + * @param {string[] | null} permissions - An array of permission strings. By default, the current permissions are inherited. [Learn more about permissions](https://appwrite.io/docs/permissions). * @throws {AppwriteException} * @returns {Promise} * @deprecated Use the object parameter style method for a better developer experience. @@ -605,7 +670,7 @@ export class Storage extends Service { bucketId: string, fileId: string, name?: string, - permissions?: string[], + permissions?: string[] | null, ): Promise; updateFile( paramsOrFirst: @@ -613,16 +678,16 @@ export class Storage extends Service { bucketId: string; fileId: string; name?: string; - permissions?: string[]; + permissions?: string[] | null; } | string, - ...rest: [string?, string?, string[]?] + ...rest: [string?, string?, (string[] | null)?] ): Promise { let params: { bucketId: string; fileId: string; name?: string; - permissions?: string[]; + permissions?: string[] | null; }; if ( @@ -634,14 +699,14 @@ export class Storage extends Service { bucketId: string; fileId: string; name?: string; - permissions?: string[]; + permissions?: string[] | null; }; } else { params = { bucketId: paramsOrFirst as string, fileId: rest[0] as string, name: rest[1] as string, - permissions: rest[2] as string[], + permissions: rest[2] as string[] | null, }; } @@ -674,7 +739,7 @@ export class Storage extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'put', uri, { @@ -684,6 +749,33 @@ export class Storage extends Service { }, apiPayload, ); + const defaults = { + root: 'file', + models: { + file: { + defaults: { + $id: '', + bucketId: '', + $createdAt: '', + $updatedAt: '', + $permissions: [], + name: '', + folder: '', + key: '', + signature: '', + mimeType: '', + sizeOriginal: 0, + sizeActual: 0, + chunksTotal: 0, + chunksUploaded: 0, + encryption: false, + compression: 'none', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** diff --git a/src/services/tables-db.ts b/src/services/tables-db.ts index ae5d11d1..20a11bc1 100644 --- a/src/services/tables-db.ts +++ b/src/services/tables-db.ts @@ -1,5 +1,5 @@ import { Service } from '../service'; -import { AppwriteException, Client } from '../client'; +import { AppwriteException, Client, applyDefaults } from '../client'; import type { Models } from '../models'; import type { Payload } from '../client'; @@ -71,7 +71,7 @@ export class TablesDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -80,6 +80,34 @@ export class TablesDB extends Service { }, apiPayload, ); + const defaults = { + root: 'transactionList', + models: { + transactionList: { + defaults: { + total: 0, + transactions: [], + }, + properties: { + transactions: { + items: 'transaction', + }, + }, + }, + transaction: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + status: 'pending', + operations: 0, + expiresAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -127,7 +155,7 @@ export class TablesDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -137,6 +165,23 @@ export class TablesDB extends Service { }, apiPayload, ); + const defaults = { + root: 'transaction', + models: { + transaction: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + status: 'pending', + operations: 0, + expiresAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -190,7 +235,7 @@ export class TablesDB extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -199,6 +244,23 @@ export class TablesDB extends Service { }, apiPayload, ); + const defaults = { + root: 'transaction', + models: { + transaction: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + status: 'pending', + operations: 0, + expiresAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -285,7 +347,7 @@ export class TablesDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'patch', uri, { @@ -295,6 +357,23 @@ export class TablesDB extends Service { }, apiPayload, ); + const defaults = { + root: 'transaction', + models: { + transaction: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + status: 'pending', + operations: 0, + expiresAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -427,7 +506,7 @@ export class TablesDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -437,6 +516,23 @@ export class TablesDB extends Service { }, apiPayload, ); + const defaults = { + root: 'transaction', + models: { + transaction: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + status: 'pending', + operations: 0, + expiresAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -567,7 +663,7 @@ export class TablesDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -576,6 +672,35 @@ export class TablesDB extends Service { }, apiPayload, ); + const defaults = { + root: 'rowList', + models: { + rowList: { + defaults: { + total: 0, + rows: [], + }, + properties: { + rows: { + items: 'row', + }, + }, + }, + row: { + defaults: { + $id: '', + $sequence: '', + $tableId: '', + $databaseId: '', + $createdAt: '', + $updatedAt: '', + $permissions: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -585,8 +710,8 @@ export class TablesDB extends Service { * @param {string} params.tableId - Table ID. You can create a new table using the Database service [server integration](https://appwrite.io/docs/references/cloud/server-dart/tablesDB#createTable). Make sure to define columns before creating rows. * @param {string} params.rowId - Row ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars. * @param {Row extends Models.DefaultRow ? Partial & Record : Partial & Omit} params.data - Row data as JSON object. - * @param {string[]} params.permissions - An array of permissions strings. By default, only the current user is granted all permissions. [Learn more about permissions](https://appwrite.io/docs/permissions). - * @param {string} params.transactionId - Transaction ID for staging the operation. + * @param {string[] | null} params.permissions - An array of permissions strings. By default, only the current user is granted all permissions. [Learn more about permissions](https://appwrite.io/docs/permissions). + * @param {string | null} params.transactionId - Transaction ID for staging the operation. * @throws {AppwriteException} * @returns {Promise} */ @@ -597,8 +722,8 @@ export class TablesDB extends Service { data: Row extends Models.DefaultRow ? Partial & Record : Partial & Omit; - permissions?: string[]; - transactionId?: string; + permissions?: string[] | null; + transactionId?: string | null; }): Promise; /** * Create a new Row. Before using this route, you should create a new table resource using either a [server integration](https://appwrite.io/docs/references/cloud/server-dart/tablesDB#createTable) API or directly from your database console. @@ -607,8 +732,8 @@ export class TablesDB extends Service { * @param {string} tableId - Table ID. You can create a new table using the Database service [server integration](https://appwrite.io/docs/references/cloud/server-dart/tablesDB#createTable). Make sure to define columns before creating rows. * @param {string} rowId - Row ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars. * @param {Row extends Models.DefaultRow ? Partial & Record : Partial & Omit} data - Row data as JSON object. - * @param {string[]} permissions - An array of permissions strings. By default, only the current user is granted all permissions. [Learn more about permissions](https://appwrite.io/docs/permissions). - * @param {string} transactionId - Transaction ID for staging the operation. + * @param {string[] | null} permissions - An array of permissions strings. By default, only the current user is granted all permissions. [Learn more about permissions](https://appwrite.io/docs/permissions). + * @param {string | null} transactionId - Transaction ID for staging the operation. * @throws {AppwriteException} * @returns {Promise} * @deprecated Use the object parameter style method for a better developer experience. @@ -620,8 +745,8 @@ export class TablesDB extends Service { data: Row extends Models.DefaultRow ? Partial & Record : Partial & Omit, - permissions?: string[], - transactionId?: string, + permissions?: string[] | null, + transactionId?: string | null, ): Promise; createRow( paramsOrFirst: @@ -632,8 +757,8 @@ export class TablesDB extends Service { data: Row extends Models.DefaultRow ? Partial & Record : Partial & Omit; - permissions?: string[]; - transactionId?: string; + permissions?: string[] | null; + transactionId?: string | null; } | string, ...rest: [ @@ -642,8 +767,8 @@ export class TablesDB extends Service { (Row extends Models.DefaultRow ? Partial & Record : Partial & Omit)?, - string[]?, - string?, + (string[] | null)?, + (string | null)?, ] ): Promise { let params: { @@ -653,8 +778,8 @@ export class TablesDB extends Service { data: Row extends Models.DefaultRow ? Partial & Record : Partial & Omit; - permissions?: string[]; - transactionId?: string; + permissions?: string[] | null; + transactionId?: string | null; }; if ( @@ -669,8 +794,8 @@ export class TablesDB extends Service { data: Row extends Models.DefaultRow ? Partial & Record : Partial & Omit; - permissions?: string[]; - transactionId?: string; + permissions?: string[] | null; + transactionId?: string | null; }; } else { params = { @@ -680,8 +805,8 @@ export class TablesDB extends Service { data: rest[2] as Row extends Models.DefaultRow ? Partial & Record : Partial & Omit, - permissions: rest[3] as string[], - transactionId: rest[4] as string, + permissions: rest[3] as string[] | null, + transactionId: rest[4] as string | null, }; } @@ -734,7 +859,7 @@ export class TablesDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -744,6 +869,24 @@ export class TablesDB extends Service { }, apiPayload, ); + const defaults = { + root: 'row', + models: { + row: { + defaults: { + $id: '', + $sequence: '', + $tableId: '', + $databaseId: '', + $createdAt: '', + $updatedAt: '', + $permissions: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -862,7 +1005,7 @@ export class TablesDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -871,6 +1014,24 @@ export class TablesDB extends Service { }, apiPayload, ); + const defaults = { + root: 'row', + models: { + row: { + defaults: { + $id: '', + $sequence: '', + $tableId: '', + $databaseId: '', + $createdAt: '', + $updatedAt: '', + $permissions: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -880,8 +1041,8 @@ export class TablesDB extends Service { * @param {string} params.tableId - Table ID. * @param {string} params.rowId - Row ID. * @param {Row extends Models.DefaultRow ? Partial & Record : Partial & Partial>} params.data - Row data as JSON object. Include all required columns of the row to be created or updated. - * @param {string[]} params.permissions - An array of permissions strings. By default, the current permissions are inherited. [Learn more about permissions](https://appwrite.io/docs/permissions). - * @param {string} params.transactionId - Transaction ID for staging the operation. + * @param {string[] | null} params.permissions - An array of permissions strings. By default, the current permissions are inherited. [Learn more about permissions](https://appwrite.io/docs/permissions). + * @param {string | null} params.transactionId - Transaction ID for staging the operation. * @throws {AppwriteException} * @returns {Promise} */ @@ -892,8 +1053,8 @@ export class TablesDB extends Service { data?: Row extends Models.DefaultRow ? Partial & Record : Partial & Partial>; - permissions?: string[]; - transactionId?: string; + permissions?: string[] | null; + transactionId?: string | null; }): Promise; /** * Create or update a Row. Before using this route, you should create a new table resource using either a [server integration](https://appwrite.io/docs/references/cloud/server-dart/tablesDB#createTable) API or directly from your database console. @@ -902,8 +1063,8 @@ export class TablesDB extends Service { * @param {string} tableId - Table ID. * @param {string} rowId - Row ID. * @param {Row extends Models.DefaultRow ? Partial & Record : Partial & Partial>} data - Row data as JSON object. Include all required columns of the row to be created or updated. - * @param {string[]} permissions - An array of permissions strings. By default, the current permissions are inherited. [Learn more about permissions](https://appwrite.io/docs/permissions). - * @param {string} transactionId - Transaction ID for staging the operation. + * @param {string[] | null} permissions - An array of permissions strings. By default, the current permissions are inherited. [Learn more about permissions](https://appwrite.io/docs/permissions). + * @param {string | null} transactionId - Transaction ID for staging the operation. * @throws {AppwriteException} * @returns {Promise} * @deprecated Use the object parameter style method for a better developer experience. @@ -915,8 +1076,8 @@ export class TablesDB extends Service { data?: Row extends Models.DefaultRow ? Partial & Record : Partial & Partial>, - permissions?: string[], - transactionId?: string, + permissions?: string[] | null, + transactionId?: string | null, ): Promise; upsertRow( paramsOrFirst: @@ -928,8 +1089,8 @@ export class TablesDB extends Service { ? Partial & Record : Partial & Partial>; - permissions?: string[]; - transactionId?: string; + permissions?: string[] | null; + transactionId?: string | null; } | string, ...rest: [ @@ -938,8 +1099,8 @@ export class TablesDB extends Service { (Row extends Models.DefaultRow ? Partial & Record : Partial & Partial>)?, - string[]?, - string?, + (string[] | null)?, + (string | null)?, ] ): Promise { let params: { @@ -949,8 +1110,8 @@ export class TablesDB extends Service { data?: Row extends Models.DefaultRow ? Partial & Record : Partial & Partial>; - permissions?: string[]; - transactionId?: string; + permissions?: string[] | null; + transactionId?: string | null; }; if ( @@ -966,8 +1127,8 @@ export class TablesDB extends Service { ? Partial & Record : Partial & Partial>; - permissions?: string[]; - transactionId?: string; + permissions?: string[] | null; + transactionId?: string | null; }; } else { params = { @@ -978,8 +1139,8 @@ export class TablesDB extends Service { ? Partial & Record : Partial & Partial>, - permissions: rest[3] as string[], - transactionId: rest[4] as string, + permissions: rest[3] as string[] | null, + transactionId: rest[4] as string | null, }; } @@ -1025,7 +1186,7 @@ export class TablesDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'put', uri, { @@ -1035,6 +1196,24 @@ export class TablesDB extends Service { }, apiPayload, ); + const defaults = { + root: 'row', + models: { + row: { + defaults: { + $id: '', + $sequence: '', + $tableId: '', + $databaseId: '', + $createdAt: '', + $updatedAt: '', + $permissions: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1044,8 +1223,8 @@ export class TablesDB extends Service { * @param {string} params.tableId - Table ID. * @param {string} params.rowId - Row ID. * @param {Row extends Models.DefaultRow ? Partial & Record : Partial & Partial>} params.data - Row data as JSON object. Include only columns and value pairs to be updated. - * @param {string[]} params.permissions - An array of permissions strings. By default, the current permissions are inherited. [Learn more about permissions](https://appwrite.io/docs/permissions). - * @param {string} params.transactionId - Transaction ID for staging the operation. + * @param {string[] | null} params.permissions - An array of permissions strings. By default, the current permissions are inherited. [Learn more about permissions](https://appwrite.io/docs/permissions). + * @param {string | null} params.transactionId - Transaction ID for staging the operation. * @throws {AppwriteException} * @returns {Promise} */ @@ -1056,8 +1235,8 @@ export class TablesDB extends Service { data?: Row extends Models.DefaultRow ? Partial & Record : Partial & Partial>; - permissions?: string[]; - transactionId?: string; + permissions?: string[] | null; + transactionId?: string | null; }): Promise; /** * Update a row by its unique ID. Using the patch method you can pass only specific fields that will get updated. @@ -1066,8 +1245,8 @@ export class TablesDB extends Service { * @param {string} tableId - Table ID. * @param {string} rowId - Row ID. * @param {Row extends Models.DefaultRow ? Partial & Record : Partial & Partial>} data - Row data as JSON object. Include only columns and value pairs to be updated. - * @param {string[]} permissions - An array of permissions strings. By default, the current permissions are inherited. [Learn more about permissions](https://appwrite.io/docs/permissions). - * @param {string} transactionId - Transaction ID for staging the operation. + * @param {string[] | null} permissions - An array of permissions strings. By default, the current permissions are inherited. [Learn more about permissions](https://appwrite.io/docs/permissions). + * @param {string | null} transactionId - Transaction ID for staging the operation. * @throws {AppwriteException} * @returns {Promise} * @deprecated Use the object parameter style method for a better developer experience. @@ -1079,8 +1258,8 @@ export class TablesDB extends Service { data?: Row extends Models.DefaultRow ? Partial & Record : Partial & Partial>, - permissions?: string[], - transactionId?: string, + permissions?: string[] | null, + transactionId?: string | null, ): Promise; updateRow( paramsOrFirst: @@ -1092,8 +1271,8 @@ export class TablesDB extends Service { ? Partial & Record : Partial & Partial>; - permissions?: string[]; - transactionId?: string; + permissions?: string[] | null; + transactionId?: string | null; } | string, ...rest: [ @@ -1102,8 +1281,8 @@ export class TablesDB extends Service { (Row extends Models.DefaultRow ? Partial & Record : Partial & Partial>)?, - string[]?, - string?, + (string[] | null)?, + (string | null)?, ] ): Promise { let params: { @@ -1113,8 +1292,8 @@ export class TablesDB extends Service { data?: Row extends Models.DefaultRow ? Partial & Record : Partial & Partial>; - permissions?: string[]; - transactionId?: string; + permissions?: string[] | null; + transactionId?: string | null; }; if ( @@ -1130,8 +1309,8 @@ export class TablesDB extends Service { ? Partial & Record : Partial & Partial>; - permissions?: string[]; - transactionId?: string; + permissions?: string[] | null; + transactionId?: string | null; }; } else { params = { @@ -1142,8 +1321,8 @@ export class TablesDB extends Service { ? Partial & Record : Partial & Partial>, - permissions: rest[3] as string[], - transactionId: rest[4] as string, + permissions: rest[3] as string[] | null, + transactionId: rest[4] as string | null, }; } @@ -1189,7 +1368,7 @@ export class TablesDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'patch', uri, { @@ -1199,6 +1378,24 @@ export class TablesDB extends Service { }, apiPayload, ); + const defaults = { + root: 'row', + models: { + row: { + defaults: { + $id: '', + $sequence: '', + $tableId: '', + $databaseId: '', + $createdAt: '', + $updatedAt: '', + $permissions: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1324,8 +1521,8 @@ export class TablesDB extends Service { * @param {string} params.rowId - Row ID. * @param {string} params.column - Column key. * @param {number} params.value - Value to increment the column by. The value must be a number. - * @param {number} params.min - Minimum value for the column. If the current value is lesser than this value, an exception will be thrown. - * @param {string} params.transactionId - Transaction ID for staging the operation. + * @param {number | null} params.min - Minimum value for the column. If the current value is lesser than this value, an exception will be thrown. + * @param {string | null} params.transactionId - Transaction ID for staging the operation. * @throws {AppwriteException} * @returns {Promise} */ @@ -1335,8 +1532,8 @@ export class TablesDB extends Service { rowId: string; column: string; value?: number; - min?: number; - transactionId?: string; + min?: number | null; + transactionId?: string | null; }): Promise; /** * Decrement a specific column of a row by a given value. @@ -1346,8 +1543,8 @@ export class TablesDB extends Service { * @param {string} rowId - Row ID. * @param {string} column - Column key. * @param {number} value - Value to increment the column by. The value must be a number. - * @param {number} min - Minimum value for the column. If the current value is lesser than this value, an exception will be thrown. - * @param {string} transactionId - Transaction ID for staging the operation. + * @param {number | null} min - Minimum value for the column. If the current value is lesser than this value, an exception will be thrown. + * @param {string | null} transactionId - Transaction ID for staging the operation. * @throws {AppwriteException} * @returns {Promise} * @deprecated Use the object parameter style method for a better developer experience. @@ -1358,8 +1555,8 @@ export class TablesDB extends Service { rowId: string, column: string, value?: number, - min?: number, - transactionId?: string, + min?: number | null, + transactionId?: string | null, ): Promise; decrementRowColumn( paramsOrFirst: @@ -1369,11 +1566,18 @@ export class TablesDB extends Service { rowId: string; column: string; value?: number; - min?: number; - transactionId?: string; + min?: number | null; + transactionId?: string | null; } | string, - ...rest: [string?, string?, string?, number?, number?, string?] + ...rest: [ + string?, + string?, + string?, + number?, + (number | null)?, + (string | null)?, + ] ): Promise { let params: { databaseId: string; @@ -1381,8 +1585,8 @@ export class TablesDB extends Service { rowId: string; column: string; value?: number; - min?: number; - transactionId?: string; + min?: number | null; + transactionId?: string | null; }; if ( @@ -1396,8 +1600,8 @@ export class TablesDB extends Service { rowId: string; column: string; value?: number; - min?: number; - transactionId?: string; + min?: number | null; + transactionId?: string | null; }; } else { params = { @@ -1406,8 +1610,8 @@ export class TablesDB extends Service { rowId: rest[1] as string, column: rest[2] as string, value: rest[3] as number, - min: rest[4] as number, - transactionId: rest[5] as string, + min: rest[4] as number | null, + transactionId: rest[5] as string | null, }; } @@ -1460,7 +1664,7 @@ export class TablesDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'patch', uri, { @@ -1470,6 +1674,24 @@ export class TablesDB extends Service { }, apiPayload, ); + const defaults = { + root: 'row', + models: { + row: { + defaults: { + $id: '', + $sequence: '', + $tableId: '', + $databaseId: '', + $createdAt: '', + $updatedAt: '', + $permissions: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1480,8 +1702,8 @@ export class TablesDB extends Service { * @param {string} params.rowId - Row ID. * @param {string} params.column - Column key. * @param {number} params.value - Value to increment the column by. The value must be a number. - * @param {number} params.max - Maximum value for the column. If the current value is greater than this value, an error will be thrown. - * @param {string} params.transactionId - Transaction ID for staging the operation. + * @param {number | null} params.max - Maximum value for the column. If the current value is greater than this value, an error will be thrown. + * @param {string | null} params.transactionId - Transaction ID for staging the operation. * @throws {AppwriteException} * @returns {Promise} */ @@ -1491,8 +1713,8 @@ export class TablesDB extends Service { rowId: string; column: string; value?: number; - max?: number; - transactionId?: string; + max?: number | null; + transactionId?: string | null; }): Promise; /** * Increment a specific column of a row by a given value. @@ -1502,8 +1724,8 @@ export class TablesDB extends Service { * @param {string} rowId - Row ID. * @param {string} column - Column key. * @param {number} value - Value to increment the column by. The value must be a number. - * @param {number} max - Maximum value for the column. If the current value is greater than this value, an error will be thrown. - * @param {string} transactionId - Transaction ID for staging the operation. + * @param {number | null} max - Maximum value for the column. If the current value is greater than this value, an error will be thrown. + * @param {string | null} transactionId - Transaction ID for staging the operation. * @throws {AppwriteException} * @returns {Promise} * @deprecated Use the object parameter style method for a better developer experience. @@ -1514,8 +1736,8 @@ export class TablesDB extends Service { rowId: string, column: string, value?: number, - max?: number, - transactionId?: string, + max?: number | null, + transactionId?: string | null, ): Promise; incrementRowColumn( paramsOrFirst: @@ -1525,11 +1747,18 @@ export class TablesDB extends Service { rowId: string; column: string; value?: number; - max?: number; - transactionId?: string; + max?: number | null; + transactionId?: string | null; } | string, - ...rest: [string?, string?, string?, number?, number?, string?] + ...rest: [ + string?, + string?, + string?, + number?, + (number | null)?, + (string | null)?, + ] ): Promise { let params: { databaseId: string; @@ -1537,8 +1766,8 @@ export class TablesDB extends Service { rowId: string; column: string; value?: number; - max?: number; - transactionId?: string; + max?: number | null; + transactionId?: string | null; }; if ( @@ -1552,8 +1781,8 @@ export class TablesDB extends Service { rowId: string; column: string; value?: number; - max?: number; - transactionId?: string; + max?: number | null; + transactionId?: string | null; }; } else { params = { @@ -1562,8 +1791,8 @@ export class TablesDB extends Service { rowId: rest[1] as string, column: rest[2] as string, value: rest[3] as number, - max: rest[4] as number, - transactionId: rest[5] as string, + max: rest[4] as number | null, + transactionId: rest[5] as string | null, }; } @@ -1616,7 +1845,7 @@ export class TablesDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'patch', uri, { @@ -1626,5 +1855,23 @@ export class TablesDB extends Service { }, apiPayload, ); + const defaults = { + root: 'row', + models: { + row: { + defaults: { + $id: '', + $sequence: '', + $tableId: '', + $databaseId: '', + $createdAt: '', + $updatedAt: '', + $permissions: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } } diff --git a/src/services/teams.ts b/src/services/teams.ts index a4424fcd..b5cd1362 100644 --- a/src/services/teams.ts +++ b/src/services/teams.ts @@ -1,5 +1,5 @@ import { Service } from '../service'; -import { AppwriteException, Client } from '../client'; +import { AppwriteException, Client, applyDefaults } from '../client'; import type { Models } from '../models'; import type { Payload } from '../client'; @@ -85,7 +85,7 @@ export class Teams extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -94,6 +94,33 @@ export class Teams extends Service { }, apiPayload, ); + const defaults = { + root: 'teamList', + models: { + teamList: { + defaults: { + total: 0, + teams: [], + }, + properties: { + teams: { + items: 'team', + }, + }, + }, + team: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + total: 0, + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -180,7 +207,7 @@ export class Teams extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -190,6 +217,22 @@ export class Teams extends Service { }, apiPayload, ); + const defaults = { + root: 'team', + models: { + team: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + total: 0, + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -243,7 +286,7 @@ export class Teams extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -252,6 +295,22 @@ export class Teams extends Service { }, apiPayload, ); + const defaults = { + root: 'team', + models: { + team: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + total: 0, + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -323,7 +382,7 @@ export class Teams extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'put', uri, { @@ -333,6 +392,22 @@ export class Teams extends Service { }, apiPayload, ); + const defaults = { + root: 'team', + models: { + team: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + total: 0, + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -469,7 +544,7 @@ export class Teams extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -478,6 +553,37 @@ export class Teams extends Service { }, apiPayload, ); + const defaults = { + root: 'appInstallationList', + models: { + appInstallationList: { + defaults: { + total: 0, + installations: [], + }, + properties: { + installations: { + items: 'appInstallation', + }, + }, + }, + appInstallation: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + appId: '', + teamId: '', + scopes: [], + authorizationDetails: [], + createdById: '', + createdByName: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -566,7 +672,7 @@ export class Teams extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -576,6 +682,26 @@ export class Teams extends Service { }, apiPayload, ); + const defaults = { + root: 'appInstallation', + models: { + appInstallation: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + appId: '', + teamId: '', + scopes: [], + authorizationDetails: [], + createdById: '', + createdByName: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -647,7 +773,7 @@ export class Teams extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -656,6 +782,26 @@ export class Teams extends Service { }, apiPayload, ); + const defaults = { + root: 'appInstallation', + models: { + appInstallation: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + appId: '', + teamId: '', + scopes: [], + authorizationDetails: [], + createdById: '', + createdByName: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -663,21 +809,21 @@ export class Teams extends Service { * * @param {string} params.teamId - Team ID. * @param {string} params.installationId - Installation unique ID. - * @param {string} params.authorizationDetails - Authorization details granted to the installation as a JSON array of objects, each with a `type` and app-defined fields. Omit to keep the current value. + * @param {string | null} params.authorizationDetails - Authorization details granted to the installation as a JSON array of objects, each with a `type` and app-defined fields. Omit to keep the current value. * @throws {AppwriteException} * @returns {Promise} */ updateInstallation(params: { teamId: string; installationId: string; - authorizationDetails?: string; + authorizationDetails?: string | null; }): Promise; /** * Update an app installation on a team. Only team members with the owner role can update installations. The installation's granted scopes are refreshed to the scopes the app currently requests; previously issued installation access tokens are revoked. * * @param {string} teamId - Team ID. * @param {string} installationId - Installation unique ID. - * @param {string} authorizationDetails - Authorization details granted to the installation as a JSON array of objects, each with a `type` and app-defined fields. Omit to keep the current value. + * @param {string | null} authorizationDetails - Authorization details granted to the installation as a JSON array of objects, each with a `type` and app-defined fields. Omit to keep the current value. * @throws {AppwriteException} * @returns {Promise} * @deprecated Use the object parameter style method for a better developer experience. @@ -685,22 +831,22 @@ export class Teams extends Service { updateInstallation( teamId: string, installationId: string, - authorizationDetails?: string, + authorizationDetails?: string | null, ): Promise; updateInstallation( paramsOrFirst: | { teamId: string; installationId: string; - authorizationDetails?: string; + authorizationDetails?: string | null; } | string, - ...rest: [string?, string?] + ...rest: [string?, (string | null)?] ): Promise { let params: { teamId: string; installationId: string; - authorizationDetails?: string; + authorizationDetails?: string | null; }; if ( @@ -711,13 +857,13 @@ export class Teams extends Service { params = (paramsOrFirst || {}) as { teamId: string; installationId: string; - authorizationDetails?: string; + authorizationDetails?: string | null; }; } else { params = { teamId: paramsOrFirst as string, installationId: rest[0] as string, - authorizationDetails: rest[1] as string, + authorizationDetails: rest[1] as string | null, }; } @@ -748,7 +894,7 @@ export class Teams extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'put', uri, { @@ -758,6 +904,26 @@ export class Teams extends Service { }, apiPayload, ); + const defaults = { + root: 'appInstallation', + models: { + appInstallation: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + appId: '', + teamId: '', + scopes: [], + authorizationDetails: [], + createdById: '', + createdByName: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -937,7 +1103,7 @@ export class Teams extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -946,6 +1112,43 @@ export class Teams extends Service { }, apiPayload, ); + const defaults = { + root: 'membershipList', + models: { + membershipList: { + defaults: { + total: 0, + memberships: [], + }, + properties: { + memberships: { + items: 'membership', + }, + }, + }, + membership: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + userId: '', + userName: '', + userEmail: '', + userPhone: '', + teamId: '', + teamName: '', + invited: '', + joined: '', + confirm: false, + mfa: false, + userAccessedAt: '', + roles: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -965,6 +1168,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 +1180,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 +1199,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 +1212,7 @@ export class Teams extends Service { phone?: string, url?: string, name?: string, + membershipId?: string, ): Promise; createMembership( paramsOrFirst: @@ -1017,9 +1224,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 +1245,7 @@ export class Teams extends Service { phone?: string; url?: string; name?: string; + membershipId?: string; }; if ( @@ -1044,6 +1261,7 @@ export class Teams extends Service { phone?: string; url?: string; name?: string; + membershipId?: string; }; } else { params = { @@ -1054,6 +1272,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 +1283,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,8 +1323,12 @@ export class Teams extends Service { apiPayload['name'] = name; } + if (typeof membershipId !== 'undefined') { + apiPayload['membershipId'] = membershipId; + } + const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -1114,6 +1338,32 @@ export class Teams extends Service { }, apiPayload, ); + const defaults = { + root: 'membership', + models: { + membership: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + userId: '', + userName: '', + userEmail: '', + userPhone: '', + teamId: '', + teamName: '', + invited: '', + joined: '', + confirm: false, + mfa: false, + userAccessedAt: '', + roles: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1185,7 +1435,7 @@ export class Teams extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -1194,6 +1444,32 @@ export class Teams extends Service { }, apiPayload, ); + const defaults = { + root: 'membership', + models: { + membership: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + userId: '', + userName: '', + userEmail: '', + userPhone: '', + teamId: '', + teamName: '', + invited: '', + joined: '', + confirm: false, + mfa: false, + userAccessedAt: '', + roles: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1283,7 +1559,7 @@ export class Teams extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'patch', uri, { @@ -1293,6 +1569,32 @@ export class Teams extends Service { }, apiPayload, ); + const defaults = { + root: 'membership', + models: { + membership: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + userId: '', + userName: '', + userEmail: '', + userPhone: '', + teamId: '', + teamName: '', + invited: '', + joined: '', + confirm: false, + mfa: false, + userAccessedAt: '', + roles: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1490,7 +1792,7 @@ export class Teams extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'patch', uri, { @@ -1500,6 +1802,32 @@ export class Teams extends Service { }, apiPayload, ); + const defaults = { + root: 'membership', + models: { + membership: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + userId: '', + userName: '', + userEmail: '', + userPhone: '', + teamId: '', + teamName: '', + invited: '', + joined: '', + confirm: false, + mfa: false, + userAccessedAt: '', + roles: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** diff --git a/src/services/vectors-db.ts b/src/services/vectors-db.ts index 710e8b44..61b4df27 100644 --- a/src/services/vectors-db.ts +++ b/src/services/vectors-db.ts @@ -1,5 +1,5 @@ import { Service } from '../service'; -import { AppwriteException, Client } from '../client'; +import { AppwriteException, Client, applyDefaults } from '../client'; import type { Models } from '../models'; import type { Payload } from '../client'; @@ -71,7 +71,7 @@ export class VectorsDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -80,6 +80,34 @@ export class VectorsDB extends Service { }, apiPayload, ); + const defaults = { + root: 'transactionList', + models: { + transactionList: { + defaults: { + total: 0, + transactions: [], + }, + properties: { + transactions: { + items: 'transaction', + }, + }, + }, + transaction: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + status: 'pending', + operations: 0, + expiresAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -127,7 +155,7 @@ export class VectorsDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -137,6 +165,23 @@ export class VectorsDB extends Service { }, apiPayload, ); + const defaults = { + root: 'transaction', + models: { + transaction: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + status: 'pending', + operations: 0, + expiresAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -190,7 +235,7 @@ export class VectorsDB extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -199,6 +244,23 @@ export class VectorsDB extends Service { }, apiPayload, ); + const defaults = { + root: 'transaction', + models: { + transaction: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + status: 'pending', + operations: 0, + expiresAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -285,7 +347,7 @@ export class VectorsDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'patch', uri, { @@ -295,6 +357,23 @@ export class VectorsDB extends Service { }, apiPayload, ); + const defaults = { + root: 'transaction', + models: { + transaction: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + status: 'pending', + operations: 0, + expiresAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -427,7 +506,7 @@ export class VectorsDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -437,6 +516,23 @@ export class VectorsDB extends Service { }, apiPayload, ); + const defaults = { + root: 'transaction', + models: { + transaction: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + status: 'pending', + operations: 0, + expiresAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -573,7 +669,7 @@ export class VectorsDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -582,6 +678,35 @@ export class VectorsDB extends Service { }, apiPayload, ); + const defaults = { + root: 'documentList', + models: { + documentList: { + defaults: { + total: 0, + documents: [], + }, + properties: { + documents: { + items: 'document', + }, + }, + }, + document: { + defaults: { + $id: '', + $sequence: '', + $collectionId: '', + $databaseId: '', + $createdAt: '', + $updatedAt: '', + $permissions: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -753,7 +878,7 @@ export class VectorsDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -763,6 +888,24 @@ export class VectorsDB extends Service { }, apiPayload, ); + const defaults = { + root: 'document', + models: { + document: { + defaults: { + $id: '', + $sequence: '', + $collectionId: '', + $databaseId: '', + $createdAt: '', + $updatedAt: '', + $permissions: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -901,7 +1044,7 @@ export class VectorsDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -911,6 +1054,35 @@ export class VectorsDB extends Service { }, apiPayload, ); + const defaults = { + root: 'documentList', + models: { + documentList: { + defaults: { + total: 0, + documents: [], + }, + properties: { + documents: { + items: 'document', + }, + }, + }, + document: { + defaults: { + $id: '', + $sequence: '', + $collectionId: '', + $databaseId: '', + $createdAt: '', + $updatedAt: '', + $permissions: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1040,7 +1212,7 @@ export class VectorsDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -1049,6 +1221,24 @@ export class VectorsDB extends Service { }, apiPayload, ); + const defaults = { + root: 'document', + models: { + document: { + defaults: { + $id: '', + $sequence: '', + $collectionId: '', + $databaseId: '', + $createdAt: '', + $updatedAt: '', + $permissions: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1218,7 +1408,7 @@ export class VectorsDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'put', uri, { @@ -1228,6 +1418,24 @@ export class VectorsDB extends Service { }, apiPayload, ); + const defaults = { + root: 'document', + models: { + document: { + defaults: { + $id: '', + $sequence: '', + $collectionId: '', + $databaseId: '', + $createdAt: '', + $updatedAt: '', + $permissions: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1397,7 +1605,7 @@ export class VectorsDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'patch', uri, { @@ -1407,6 +1615,24 @@ export class VectorsDB extends Service { }, apiPayload, ); + const defaults = { + root: 'document', + models: { + document: { + defaults: { + $id: '', + $sequence: '', + $collectionId: '', + $databaseId: '', + $createdAt: '', + $updatedAt: '', + $permissions: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** From 40ce15d0697e9dc36b99ac996e4afe4300839581 Mon Sep 17 00:00:00 2001 From: Chirag Aggarwal Date: Thu, 15 Oct 2026 11:12:27 +0100 Subject: [PATCH 5/6] feat: SDK update for the 2.5.x majors --- CHANGELOG.md | 75 +- README.md | 76 +- android/src/main/AndroidManifest.xml | 10 +- .../reactnative/AppwritePushModule.kt | 8 +- .../exceptions/AppwriteException.kt | 2 +- .../services/PushBackground.kt | 51 +- .../{ => reactnative}/services/PushBridge.kt | 5 +- .../{ => reactnative}/services/PushCore.kt | 29 +- .../services/PushOpenActivity.kt | 2 +- .../services/PushReceiver.kt | 4 +- .../{ => reactnative}/services/PushService.kt | 2 +- .../{ => reactnative}/services/PushWakeups.kt | 2 +- .../account/create-o-auth-2-session.md | 1 + .../examples/account/create-o-auth-2-token.md | 1 + docs/examples/account/create-passkey-token.md | 13 + docs/examples/account/create-passkey.md | 16 + docs/examples/account/delete-passkey.md | 15 + docs/examples/account/get-passkey.md | 15 + docs/examples/account/list-passkeys.md | 16 + docs/examples/account/update-passkey-token.md | 16 + .../account/update-passkey-verification.md | 16 + docs/examples/account/update-passkey.md | 16 + docs/examples/analytics/create-event.md | 27 + docs/examples/oauth2/authorize-post.md | 2 +- docs/examples/oauth2/authorize.md | 2 +- .../oauth2/create-device-authorization.md | 2 +- docs/examples/oauth2/create-par.md | 2 +- docs/examples/oauth2/create-token.md | 2 +- docs/examples/teams/create-membership.md | 1 + package-lock.json | 4 +- package.json | 2 +- src/client.ts | 83 +- src/enums/execution-trigger.ts | 1 + src/index.ts | 7 +- src/models.ts | 178 +- src/query.ts | 786 ++++++ src/services/account.ts | 2423 ++++++++++++++++- src/services/analytics.ts | 260 ++ src/services/apps.ts | 572 +++- src/services/databases.ts | 449 ++- src/services/documents-db.ts | 290 +- src/services/functions.ts | 160 +- src/services/locale.ts | 211 +- src/services/messaging.ts | 23 +- src/services/oauth-2.ts | 340 ++- src/services/organization.ts | 123 +- src/services/presences.ts | 89 +- src/services/push.ts | 114 +- src/services/realtime.ts | 51 +- src/services/storage.ts | 118 +- src/services/tables-db.ts | 449 ++- src/services/teams.ts | 376 ++- src/services/vectors-db.ts | 250 +- src/topic.ts | 51 +- 54 files changed, 7052 insertions(+), 787 deletions(-) rename android/src/main/java/io/appwrite/{ => reactnative}/exceptions/AppwriteException.kt (81%) rename android/src/main/java/io/appwrite/{ => reactnative}/services/PushBackground.kt (96%) rename android/src/main/java/io/appwrite/{ => reactnative}/services/PushBridge.kt (97%) rename android/src/main/java/io/appwrite/{ => reactnative}/services/PushCore.kt (93%) rename android/src/main/java/io/appwrite/{ => reactnative}/services/PushOpenActivity.kt (97%) rename android/src/main/java/io/appwrite/{ => reactnative}/services/PushReceiver.kt (90%) rename android/src/main/java/io/appwrite/{ => reactnative}/services/PushService.kt (98%) rename android/src/main/java/io/appwrite/{ => reactnative}/services/PushWakeups.kt (98%) create mode 100644 docs/examples/account/create-passkey-token.md create mode 100644 docs/examples/account/create-passkey.md create mode 100644 docs/examples/account/delete-passkey.md create mode 100644 docs/examples/account/get-passkey.md create mode 100644 docs/examples/account/list-passkeys.md create mode 100644 docs/examples/account/update-passkey-token.md create mode 100644 docs/examples/account/update-passkey-verification.md create mode 100644 docs/examples/account/update-passkey.md create mode 100644 docs/examples/analytics/create-event.md create mode 100644 src/services/analytics.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index c6c7bcb3..3897ac8c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,50 +1,37 @@ # Change log -## 1.2.0-rc.4 - -* Fixed: `host()` resolves with the live connection state instead of always `null` -* Fixed: `onConnection(false)` fires when a retired or background connection closes -* Fixed: notification taps are recorded after launching the app, so tap-opened screens land on top -* Fixed: `host()` reports `false` when there was nothing to subscribe instead of a spurious open - -## 1.2.0-rc.3 - -* Added: `getInitialNotification()`, `onNotificationOpened()`, and the `PushNotificationOpened` type (topic + data) -* Added: live push connection open/close events surfaced via `onOpen`/`onClose` -* Fixed: notification taps delivered reliably once, via a `PushTaps` queue -* Fixed: foreground notifications de-duplicated per title -* Updated: `resume` leaves a live Push host's connection untouched - -## 1.2.0-rc.2 - -* Added: `Push.getInitialNotification()` returns the notification whose tap launched the app -* Added: `Push.onNotificationOpened(callback)` fires on each notification tap -* Added: `Push.backgroundStatus()` reports Android exact-alarm, battery, and foreground-service state -* Added: `Push.requestExactAlarms()` and `Push.requestIgnoreBatteryOptimizations()` helpers -* Added: `SubscribeOptions.notifyInForeground` to post notifications while the app is visible -* Added: `PushBackgroundStatus` and `PushNotificationOpened` exported types -* Fixed: reliable Android background wake-ups via a periodic watchdog and alternating jobs -* Fixed: `resume` keeps subscriptions only for the same signed-in user -* Fixed: notification images are size-capped to prevent out-of-memory crashes - -## 1.2.0-rc.1 - -* Added: background push notifications render the server `notification` title, body, and image -* Added: Android shows notification images (BigPictureStyle) and long bodies (BigTextStyle) -* Added: the SDK requests Android 13+ `POST_NOTIFICATIONS` itself on first background subscribe -* Added: notification `data` now carries `topic` and `payload` -* Fixed: a server-sent title dedupes to one notification per topic instead of one per subscription - -## 1.2.0-rc.0 - -* Added: `Apps` service to manage OAuth2 apps, keys, secrets, and installations -* Added: `Oauth2` service for authorization, consent, device, PAR, and token flows -* Added: `Push` service for MQTT realtime push with Android background delivery -* Added: `Topic` builder and native TCP modules for push -* Added: `Avatars.updatePhoto()` and `Avatars.deletePhoto()` methods -* Added: `App`, `Oauth2*`, and `Account` models +## 2.0.0 + +* Breaking: requests send `X-Appwrite-Response-Format: 2.5.0`; responses follow the 2.5 shapes +* Breaking: missing response fields are filled with their documented defaults +* Breaking: nullable model fields are typed `T | null`, such as `Locale.city` and `Presence.status` +* Breaking: the package ships native Android and iOS modules, so apps need a native rebuild and do not run in Expo Go +* Added: `Apps` service to manage apps, installations, keys and secrets +* Added: `Oauth2` service for the OAuth2 authorize, token, device and grant flows +* Added: `Push` service, with optional peers `expo-notifications`, `react-native-background-actions` and `react-native-tcp-socket` +* Added: `Topic` helper +* Added: Android push code ships under `io.appwrite.reactnative`, so apps can also depend on `sdk-for-android`; set the notification icon with the `io.appwrite.reactnative.push.notification_icon` meta-data +* Added: `Query` aggregates (`count`, `countDistinct`, `sum`, `avg`, `min`, `max` and more), `groupBy`, `having`, `distinct`, joins, `relationship`, `covers`, `spatialEquals` and `page` +* Added: `Query.builder()` to chain queries; realtime subscriptions accept a builder for `queries` +* Added: `ExecutionTrigger.Email` +* Fixed: list and object defaults filled into a response are copied per model, and object defaults are `{}` instead of `[]` + +## 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 -* Fixed: cookie session fallback is guarded to Expo web where `localStorage` exists +* 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` +* Added: `account.createPasskeyToken` and `account.updatePasskeyToken` for passkey sign-in +* Added: `Passkey`, `PasskeyList`, `PasskeyChallenge` and `TokenSecret` models ## 1.1.0 diff --git a/README.md b/README.md index 0ba50f82..76d719ef 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,12 @@ # Appwrite React Native SDK ![License](https://img.shields.io/github/license/appwrite/sdk-for-react-native.svg?style=flat-square) -![Version](https://img.shields.io/badge/api%20version-2.3.0-blue.svg?style=flat-square) +![Version](https://img.shields.io/badge/api%20version-2.5.0-blue.svg?style=flat-square) [![Build Status](https://img.shields.io/travis/com/appwrite/sdk-generator?style=flat-square)](https://travis-ci.com/appwrite/sdk-generator) [![Twitter Account](https://img.shields.io/twitter/follow/appwrite?color=00acee&label=twitter&style=flat-square)](https://twitter.com/appwrite) [![Discord](https://img.shields.io/discord/564160730845151244?label=discord&style=flat-square)](https://appwrite.io/discord) -**This SDK targets Appwrite server version 2.3.x as shipped on Appwrite Cloud.** Self-hosted releases can lag behind Cloud — if you run an older self-hosted build, use a matching older SDK from [previous releases](https://github.com/appwrite/sdk-for-react-native/releases) when APIs differ. +**This SDK targets Appwrite server version 2.5.x as shipped on Appwrite Cloud.** Self-hosted releases can lag behind Cloud — if you run an older self-hosted build, use a matching older SDK from [previous releases](https://github.com/appwrite/sdk-for-react-native/releases) when APIs differ. Appwrite is an open-source backend as a service server that abstracts and simplifies complex and repetitive development tasks behind a very simple to use REST API. Appwrite aims to help you develop your apps faster and in a more secure way. Use the React Native SDK to integrate your app with the Appwrite server to easily start interacting with all of Appwrite backend APIs and tools. For full API documentation and tutorials go to [https://appwrite.io/docs](https://appwrite.io/docs) @@ -45,7 +45,9 @@ than a short-lived JWT. On Android 13 and later, the first background subscription asks the user for the `POST_NOTIFICATIONS` runtime permission. If they decline, the subscription still delivers to your callback but posts no notification. Notifications show the title, body and image sent with -`createPush`, and fall back to the subscription's `title` and the raw payload for other messages. +`createPush`, falling back to the subscription's `title` when only a body is sent. A push with no +title or body, such as a data-only push, posts no notification and reaches only your callback. +Messages that are not a JSON object show the subscription's `title` with the raw payload as the body. ```js const sub = await push.subscribe('news', (message) => console.log(message.data), { @@ -93,17 +95,26 @@ With Expo, list them under `android.permissions` in `app.json` instead. nothing to ask, including when the permission is not declared. The SDK never opens these screens on its own. +If `backgroundRestricted` is true, the user restricted the app's background usage and messages can +wait until the app is opened. Exact alarms don't lift it, and neither does foreground mode: Android +stops a restricted app's foreground service once it leaves the screen. Ask the user to choose +Unrestricted in the app's battery settings (Settings > Apps > your app > Battery); granting the +battery optimisation exemption also lets the SDK's alarms and jobs run, and `bestEffort` then +reflects only the exact-alarm state. It is always false below Android 9. + If the user force-stops the app (Settings > Force stop, and on some devices swiping it away from recents), Android cancels its alarms and jobs: nothing is delivered until the app is opened again, and the broker then replays what was sent meanwhile. Set the notification icon with -`` in your +`` in your ``; without it a generic icon is used. ```js const status = await push.backgroundStatus(); // null outside Android -if (status?.bestEffort) { +if (status?.backgroundRestricted && !status.ignoringBatteryOptimizations) { + // Ask the user to choose Unrestricted in the app's battery settings. +} else if (status?.bestEffort) { // Explain why, then from a button press: await push.requestExactAlarms(); } @@ -140,7 +151,7 @@ On Android the SDK's native module reports the taps. Elsewhere they come from `e Foreground mode runs a `remoteMessaging` foreground service, which Google Play asks apps to declare in the Play Console. Apps that never enable it can remove the service from their merged -manifest with `tools:node="remove"` on `io.appwrite.services.PushService` and +manifest with `tools:node="remove"` on `io.appwrite.reactnative.services.PushService` and `android.permission.FOREGROUND_SERVICE_REMOTE_MESSAGING`. @@ -194,7 +205,12 @@ Once your SDK object is set, access any of the Appwrite services and choose any const account = new Account(client); // Register User -account.create(ID.unique(), 'me@example.com', 'password', 'Jane Doe') +account.create({ + userId: ID.unique(), + email: 'me@example.com', + password: 'password', + name: 'Jane Doe' +}) .then(function (response) { console.log(response); }, function (error) { @@ -206,7 +222,7 @@ account.create(ID.unique(), 'me@example.com', 'password', 'Jane Doe') ### Full Example ```js -import { Client, Account } from 'react-native-appwrite'; +import { Client, Account, ID } from 'react-native-appwrite'; // Init your React Native SDK const client = new Client(); @@ -219,7 +235,12 @@ client const account = new Account(client); // Register User -account.create(ID.unique(), 'me@example.com', 'password', 'Jane Doe') +account.create({ + userId: ID.unique(), + email: 'me@example.com', + password: 'password', + name: 'Jane Doe' +}) .then(function (response) { console.log(response); }, function (error) { @@ -229,11 +250,11 @@ account.create(ID.unique(), 'me@example.com', 'password', 'Jane Doe') ### Type Safety with Models -The Appwrite React Native SDK provides type safety when working with database documents through generic methods. Methods like `listDocuments`, `getDocument`, and others accept a generic type parameter that allows you to specify your custom model type for full type safety. +The Appwrite React Native SDK provides type safety when working with table rows through generic methods. Methods like `listRows`, `getRow`, and others accept a generic type parameter that allows you to specify your custom model type for full type safety. **TypeScript:** ```typescript -interface Book { +interface Book extends Models.Row { name: string; author: string; releaseYear?: string; @@ -242,15 +263,15 @@ interface Book { isCheckedOut: boolean; } -const databases = new Databases(client); +const tablesDB = new TablesDB(client); try { - const documents = await databases.listDocuments( - 'your-database-id', - 'your-collection-id' - ); + const result = await tablesDB.listRows({ + databaseId: 'your-database-id', + tableId: 'your-table-id' + }); - documents.documents.forEach(book => { + result.rows.forEach(book => { console.log(`Book: ${book.name} by ${book.author}`); // Now you have full type safety }); } catch (error) { @@ -270,16 +291,16 @@ try { * @property {boolean} isCheckedOut */ -const databases = new Databases(client); +const tablesDB = new TablesDB(client); try { - /** @type {Models.DocumentList} */ - const documents = await databases.listDocuments( - 'your-database-id', - 'your-collection-id' - ); + /** @type {Models.RowList} */ + const result = await tablesDB.listRows({ + databaseId: 'your-database-id', + tableId: 'your-table-id' + }); - documents.documents.forEach(book => { + result.rows.forEach(book => { console.log(`Book: ${book.name} by ${book.author}`); // Type hints available in IDE }); } catch (error) { @@ -295,7 +316,12 @@ The Appwrite React Native SDK raises an `AppwriteException` object with `message ```javascript try { - const user = await account.create(ID.unique(), "email@example.com", "password", "Walter O'Brien"); + const user = await account.create({ + userId: ID.unique(), + email: "email@example.com", + password: "password", + name: "Walter O'Brien" +}); console.log('User created:', user); } catch (error) { console.error('Appwrite error:', error.message); diff --git a/android/src/main/AndroidManifest.xml b/android/src/main/AndroidManifest.xml index d2b7d500..822bd46f 100644 --- a/android/src/main/AndroidManifest.xml +++ b/android/src/main/AndroidManifest.xml @@ -17,26 +17,26 @@ diff --git a/android/src/main/java/io/appwrite/reactnative/AppwritePushModule.kt b/android/src/main/java/io/appwrite/reactnative/AppwritePushModule.kt index c6c46889..cb87b594 100644 --- a/android/src/main/java/io/appwrite/reactnative/AppwritePushModule.kt +++ b/android/src/main/java/io/appwrite/reactnative/AppwritePushModule.kt @@ -7,10 +7,10 @@ import com.facebook.react.bridge.ReactApplicationContext import com.facebook.react.bridge.ReactContextBaseJavaModule import com.facebook.react.bridge.ReactMethod import com.facebook.react.modules.core.DeviceEventManagerModule -import io.appwrite.services.PushBridge -import io.appwrite.services.PushMessage -import io.appwrite.services.PushTap -import io.appwrite.services.PushTaps +import io.appwrite.reactnative.services.PushBridge +import io.appwrite.reactnative.services.PushMessage +import io.appwrite.reactnative.services.PushTap +import io.appwrite.reactnative.services.PushTaps import org.json.JSONObject /** diff --git a/android/src/main/java/io/appwrite/exceptions/AppwriteException.kt b/android/src/main/java/io/appwrite/reactnative/exceptions/AppwriteException.kt similarity index 81% rename from android/src/main/java/io/appwrite/exceptions/AppwriteException.kt rename to android/src/main/java/io/appwrite/reactnative/exceptions/AppwriteException.kt index 81b0d30e..fb101961 100644 --- a/android/src/main/java/io/appwrite/exceptions/AppwriteException.kt +++ b/android/src/main/java/io/appwrite/reactnative/exceptions/AppwriteException.kt @@ -1,4 +1,4 @@ -package io.appwrite.exceptions +package io.appwrite.reactnative.exceptions /** A push error. When the broker explained a refusal or a disconnect, that is its message. */ class AppwriteException( diff --git a/android/src/main/java/io/appwrite/services/PushBackground.kt b/android/src/main/java/io/appwrite/reactnative/services/PushBackground.kt similarity index 96% rename from android/src/main/java/io/appwrite/services/PushBackground.kt rename to android/src/main/java/io/appwrite/reactnative/services/PushBackground.kt index e06dfabe..cc34f286 100644 --- a/android/src/main/java/io/appwrite/services/PushBackground.kt +++ b/android/src/main/java/io/appwrite/reactnative/services/PushBackground.kt @@ -1,4 +1,4 @@ -package io.appwrite.services +package io.appwrite.reactnative.services import android.Manifest import android.app.ActivityManager @@ -32,7 +32,7 @@ import com.hivemq.client.mqtt.datatypes.MqttQos import com.hivemq.client.mqtt.mqtt5.Mqtt5AsyncClient import com.hivemq.client.mqtt.mqtt5.exceptions.Mqtt5ConnAckException import com.hivemq.client.mqtt.mqtt5.message.publish.Mqtt5Publish -import io.appwrite.exceptions.AppwriteException +import io.appwrite.reactnative.exceptions.AppwriteException import org.json.JSONArray import org.json.JSONObject import java.io.ByteArrayOutputStream @@ -52,8 +52,15 @@ import java.util.concurrent.atomic.AtomicInteger private const val LOG_TAG = "AppwritePush" -/** What a message's `notification` block asks a background notification to show; [present] is false without one. */ -internal data class PushNotificationContent(val present: Boolean, val title: String?, val body: String?, val image: String?) +/** + * What a message asks a background notification to show. A [raw] payload, one that is not a JSON + * object, is shown as the body under the subscription's title; an envelope is [visible] only with a + * title or body in its `notification`. + */ +internal data class PushNotificationContent(val raw: Boolean, val title: String?, val body: String?, val image: String?) { + val visible: Boolean + get() = raw || title != null || body != null +} /** A background subscription saved across restarts: its filter, QoS choice and notification title. */ internal data class PushEntry( @@ -97,11 +104,11 @@ internal data class PushHeartbeat( internal object PushBackground { const val CHANNEL_ID = "appwrite-push" const val NOTIFICATION_ID = 1911 - const val ACTION_TICK = "io.appwrite.push.TICK" - const val ACTION_MESSAGE = "io.appwrite.push.MESSAGE" - const val NOTIFICATION_ICON = "io.appwrite.push.notification_icon" - const val EXTRA_TOPIC = "io.appwrite.push.TOPIC" - const val EXTRA_PAYLOAD = "io.appwrite.push.PAYLOAD" + const val ACTION_TICK = "io.appwrite.reactnative.push.TICK" + const val ACTION_MESSAGE = "io.appwrite.reactnative.push.MESSAGE" + const val NOTIFICATION_ICON = "io.appwrite.reactnative.push.notification_icon" + const val EXTRA_TOPIC = "io.appwrite.reactnative.push.TOPIC" + const val EXTRA_PAYLOAD = "io.appwrite.reactnative.push.PAYLOAD" private const val SERVICE_CHANNEL_ID = "appwrite-push-service" const val JOB_ID = 0x50555348 @@ -887,7 +894,7 @@ internal object PushBackground { // Deliver a message to the matching live callbacks; with none, to the declared PushReceiver // and/or a notification per saved subscription that matches it. [deferAck] hands a listener // that acknowledges messages itself its acknowledgement. - private fun deliverMessage(context: Context, message: PushMessage, deferAck: () -> () -> Unit) { + internal fun deliverMessage(context: Context, message: PushMessage, deferAck: () -> () -> Unit) { val matching = listeners.filter { listener -> listener.topics.any { matchesTopic(it, message.topic) } } // Saved background subscriptions no live one has taken over; they deliver even when a live // foreground-only subscription on an overlapping filter received the message too. @@ -952,16 +959,21 @@ internal object PushBackground { /** * Post a notification for [message] that opens the app, with the message in its extras. It shows - * the server's title, body and image from [content], falling back to [title] and the raw payload. + * the server's title, body and image from [content], falling back to [title], and to the payload + * as the body when it is not a JSON object. An envelope with neither a title nor a body, such as + * a data-only push, posts nothing. */ fun notify(context: Context, message: PushMessage, title: String, content: PushNotificationContent = notificationContent(message)) { + if (!content.visible) { + return + } val manager = NotificationManagerCompat.from(context) if (!manager.areNotificationsEnabled()) { return } createChannels(context) val id = 31 * message.hashCode() + title.hashCode() - val body = content.body ?: message.data.takeIf { !content.present } + val body = content.body ?: message.data.takeIf { content.raw } val builder = NotificationCompat.Builder(context, CHANNEL_ID) .setContentTitle(content.title ?: title) .setSmallIcon(notificationIcon(context)) @@ -992,12 +1004,13 @@ internal object PushBackground { .also { ActivityManager.getMyMemoryState(it) } .importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND - /** The server's `notification` block in [message]: nulls when the payload has none or is not JSON. */ + /** The server's `notification` block in [message], [PushNotificationContent.raw] when the payload is not a JSON object. */ fun notificationContent(message: PushMessage): PushNotificationContent { - val notification = runCatching { JSONObject(message.data) }.getOrNull()?.optJSONObject("notification") - ?: return PushNotificationContent(false, null, null, null) - fun field(name: String) = (notification.opt(name) as? String)?.takeIf { it.isNotEmpty() } - return PushNotificationContent(true, field("title"), field("body"), field("image")) + val envelope = runCatching { JSONObject(message.data) }.getOrNull() + ?: return PushNotificationContent(true, null, null, null) + val notification = envelope.optJSONObject("notification") + fun field(name: String) = (notification?.opt(name) as? String)?.takeIf { it.isNotEmpty() } + return PushNotificationContent(false, field("title"), field("body"), field("image")) } // Downloads notification images, so a slow one is abandoned without holding up delivery. @@ -1079,7 +1092,7 @@ internal object PushBackground { ) } - // The icon named by the app's ``, else a + // The icon named by the app's ``, else a // generic one. private fun notificationIcon(context: Context): Int { val metaData = runCatching { @@ -1201,6 +1214,8 @@ internal object PushBackground { app.getSystemService(AlarmManager::class.java)?.canScheduleExactAlarms() == true, ignoringBatteryOptimizations = app.getSystemService(PowerManager::class.java)?.isIgnoringBatteryOptimizations(app.packageName) == true, foregroundService = PushStore.foreground(app), + backgroundRestricted = Build.VERSION.SDK_INT >= Build.VERSION_CODES.P && + app.getSystemService(ActivityManager::class.java)?.isBackgroundRestricted == true, ) } diff --git a/android/src/main/java/io/appwrite/services/PushBridge.kt b/android/src/main/java/io/appwrite/reactnative/services/PushBridge.kt similarity index 97% rename from android/src/main/java/io/appwrite/services/PushBridge.kt rename to android/src/main/java/io/appwrite/reactnative/services/PushBridge.kt index e5cb5aae..50cd5468 100644 --- a/android/src/main/java/io/appwrite/services/PushBridge.kt +++ b/android/src/main/java/io/appwrite/reactnative/services/PushBridge.kt @@ -1,4 +1,4 @@ -package io.appwrite.services +package io.appwrite.reactnative.services import android.content.Context import android.os.SystemClock @@ -169,12 +169,13 @@ class PushBridge(context: Context, private val events: Events) { return if (registered) PushStore.takeStoppedError(appContext) else null } - /** What background delivery can rely on, as `{"exactAlarms", "ignoringBatteryOptimizations", "foregroundService", "bestEffort"}`. */ + /** What background delivery can rely on, as `{"exactAlarms", "ignoringBatteryOptimizations", "foregroundService", "backgroundRestricted", "bestEffort"}`. */ fun backgroundStatus(): String = PushBackground.backgroundStatus(appContext).let { JSONObject() .put("exactAlarms", it.exactAlarms) .put("ignoringBatteryOptimizations", it.ignoringBatteryOptimizations) .put("foregroundService", it.foregroundService) + .put("backgroundRestricted", it.backgroundRestricted) .put("bestEffort", it.bestEffort) .toString() } diff --git a/android/src/main/java/io/appwrite/services/PushCore.kt b/android/src/main/java/io/appwrite/reactnative/services/PushCore.kt similarity index 93% rename from android/src/main/java/io/appwrite/services/PushCore.kt rename to android/src/main/java/io/appwrite/reactnative/services/PushCore.kt index 15f86b6a..85fdb19e 100644 --- a/android/src/main/java/io/appwrite/services/PushCore.kt +++ b/android/src/main/java/io/appwrite/reactnative/services/PushCore.kt @@ -1,4 +1,4 @@ -package io.appwrite.services +package io.appwrite.reactnative.services import android.content.Context import android.os.Build @@ -22,7 +22,7 @@ import com.hivemq.client.mqtt.mqtt5.message.connect.connack.Mqtt5ConnAckReasonCo import com.hivemq.client.mqtt.mqtt5.message.disconnect.Mqtt5Disconnect import com.hivemq.client.mqtt.mqtt5.message.disconnect.Mqtt5DisconnectReasonCode import com.hivemq.client.mqtt.mqtt5.message.publish.Mqtt5Publish -import io.appwrite.exceptions.AppwriteException +import io.appwrite.reactnative.exceptions.AppwriteException import org.json.JSONObject import java.security.KeyStore import java.security.Provider @@ -54,19 +54,36 @@ data class PushMessage( /** * What background delivery can rely on. Without exact alarms, the scheduled wake-ups are inexact * and Doze can defer them, so delivery is [bestEffort] unless foreground mode keeps the - * connection open. + * connection open. When the user restricted background usage, delivery is [bestEffort] unless the + * app is also exempt from battery optimisation, and foreground mode no longer counts: Android stops + * a restricted app's foreground service once it leaves the screen, exemption or not. */ -data class PushBackgroundStatus( +data class PushBackgroundStatus @JvmOverloads constructor( /** The app may schedule exact alarms (`SCHEDULE_EXACT_ALARM`, granted). */ val exactAlarms: Boolean, /** The app is exempt from battery optimisation. */ val ignoringBatteryOptimizations: Boolean, /** Foreground mode (`setForeground(true)`) keeps the connection open in a service. */ val foregroundService: Boolean, + /** + * The user restricted the app's background usage in its battery settings (Android 9+). Android + * may then hold its alarms, jobs and foreground service while it is closed, so messages can + * wait until the app is opened. The battery-optimisation exemption lets the alarms and jobs + * run again, but foreground mode still stops once the app leaves the screen. + */ + val backgroundRestricted: Boolean = false, ) { - /** Wake-ups may be deferred by Doze, so messages can arrive late while the app is closed. */ + /** + * Messages can arrive late, or not until the app is opened, while the app is closed: background + * usage is restricted without the battery-optimisation exemption, or wake-ups may be deferred + * by Doze. + */ val bestEffort: Boolean - get() = !exactAlarms && !foregroundService + get() { + val held = backgroundRestricted && !ignoringBatteryOptimizations + val foreground = foregroundService && !backgroundRestricted + return held || (!exactAlarms && !foreground) + } } /** Connection parameters shared between the in-process client and the foreground service. */ diff --git a/android/src/main/java/io/appwrite/services/PushOpenActivity.kt b/android/src/main/java/io/appwrite/reactnative/services/PushOpenActivity.kt similarity index 97% rename from android/src/main/java/io/appwrite/services/PushOpenActivity.kt rename to android/src/main/java/io/appwrite/reactnative/services/PushOpenActivity.kt index 354ca6f0..5a51c808 100644 --- a/android/src/main/java/io/appwrite/services/PushOpenActivity.kt +++ b/android/src/main/java/io/appwrite/reactnative/services/PushOpenActivity.kt @@ -1,4 +1,4 @@ -package io.appwrite.services +package io.appwrite.reactnative.services import android.app.Activity import android.content.Intent diff --git a/android/src/main/java/io/appwrite/services/PushReceiver.kt b/android/src/main/java/io/appwrite/reactnative/services/PushReceiver.kt similarity index 90% rename from android/src/main/java/io/appwrite/services/PushReceiver.kt rename to android/src/main/java/io/appwrite/reactnative/services/PushReceiver.kt index 92d04727..ec0e7630 100644 --- a/android/src/main/java/io/appwrite/services/PushReceiver.kt +++ b/android/src/main/java/io/appwrite/reactnative/services/PushReceiver.kt @@ -1,4 +1,4 @@ -package io.appwrite.services +package io.appwrite.reactnative.services import android.content.BroadcastReceiver import android.content.Context @@ -12,7 +12,7 @@ import android.content.Intent * ```xml * * - * + * * * * ``` diff --git a/android/src/main/java/io/appwrite/services/PushService.kt b/android/src/main/java/io/appwrite/reactnative/services/PushService.kt similarity index 98% rename from android/src/main/java/io/appwrite/services/PushService.kt rename to android/src/main/java/io/appwrite/reactnative/services/PushService.kt index e2a05f89..1981cafc 100644 --- a/android/src/main/java/io/appwrite/services/PushService.kt +++ b/android/src/main/java/io/appwrite/reactnative/services/PushService.kt @@ -1,4 +1,4 @@ -package io.appwrite.services +package io.appwrite.reactnative.services import android.app.Service import android.content.Intent diff --git a/android/src/main/java/io/appwrite/services/PushWakeups.kt b/android/src/main/java/io/appwrite/reactnative/services/PushWakeups.kt similarity index 98% rename from android/src/main/java/io/appwrite/services/PushWakeups.kt rename to android/src/main/java/io/appwrite/reactnative/services/PushWakeups.kt index c6d56165..50bd2d81 100644 --- a/android/src/main/java/io/appwrite/services/PushWakeups.kt +++ b/android/src/main/java/io/appwrite/reactnative/services/PushWakeups.kt @@ -1,4 +1,4 @@ -package io.appwrite.services +package io.appwrite.reactnative.services import android.app.job.JobParameters import android.app.job.JobService 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/create-passkey-token.md b/docs/examples/account/create-passkey-token.md new file mode 100644 index 00000000..5695859f --- /dev/null +++ b/docs/examples/account/create-passkey-token.md @@ -0,0 +1,13 @@ +```javascript +import { Client, Account } from 'react-native-appwrite'; + +const client = new Client() + .setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint + .setProject(''); // Your project ID + +const account = new Account(client); + +const result = await account.createPasskeyToken(); + +console.log(result); +``` diff --git a/docs/examples/account/create-passkey.md b/docs/examples/account/create-passkey.md new file mode 100644 index 00000000..66968b14 --- /dev/null +++ b/docs/examples/account/create-passkey.md @@ -0,0 +1,16 @@ +```javascript +import { Client, Account } from 'react-native-appwrite'; + +const client = new Client() + .setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint + .setProject(''); // Your project ID + +const account = new Account(client); + +const result = await account.createPasskey({ + passkeyId: '', // optional + name: '', // optional +}); + +console.log(result); +``` diff --git a/docs/examples/account/delete-passkey.md b/docs/examples/account/delete-passkey.md new file mode 100644 index 00000000..61aec153 --- /dev/null +++ b/docs/examples/account/delete-passkey.md @@ -0,0 +1,15 @@ +```javascript +import { Client, Account } from 'react-native-appwrite'; + +const client = new Client() + .setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint + .setProject(''); // Your project ID + +const account = new Account(client); + +const result = await account.deletePasskey({ + passkeyId: '', +}); + +console.log(result); +``` diff --git a/docs/examples/account/get-passkey.md b/docs/examples/account/get-passkey.md new file mode 100644 index 00000000..04b7f8fb --- /dev/null +++ b/docs/examples/account/get-passkey.md @@ -0,0 +1,15 @@ +```javascript +import { Client, Account } from 'react-native-appwrite'; + +const client = new Client() + .setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint + .setProject(''); // Your project ID + +const account = new Account(client); + +const result = await account.getPasskey({ + passkeyId: '', +}); + +console.log(result); +``` diff --git a/docs/examples/account/list-passkeys.md b/docs/examples/account/list-passkeys.md new file mode 100644 index 00000000..f1f68985 --- /dev/null +++ b/docs/examples/account/list-passkeys.md @@ -0,0 +1,16 @@ +```javascript +import { Client, Account } from 'react-native-appwrite'; + +const client = new Client() + .setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint + .setProject(''); // Your project ID + +const account = new Account(client); + +const result = await account.listPasskeys({ + queries: [], // optional + total: false, // optional +}); + +console.log(result); +``` diff --git a/docs/examples/account/update-passkey-token.md b/docs/examples/account/update-passkey-token.md new file mode 100644 index 00000000..a8e22f7a --- /dev/null +++ b/docs/examples/account/update-passkey-token.md @@ -0,0 +1,16 @@ +```javascript +import { Client, Account } from 'react-native-appwrite'; + +const client = new Client() + .setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint + .setProject(''); // Your project ID + +const account = new Account(client); + +const result = await account.updatePasskeyToken({ + challengeId: '', + credential: {}, +}); + +console.log(result); +``` diff --git a/docs/examples/account/update-passkey-verification.md b/docs/examples/account/update-passkey-verification.md new file mode 100644 index 00000000..c46c0a63 --- /dev/null +++ b/docs/examples/account/update-passkey-verification.md @@ -0,0 +1,16 @@ +```javascript +import { Client, Account } from 'react-native-appwrite'; + +const client = new Client() + .setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint + .setProject(''); // Your project ID + +const account = new Account(client); + +const result = await account.updatePasskeyVerification({ + passkeyId: '', + credential: {}, +}); + +console.log(result); +``` diff --git a/docs/examples/account/update-passkey.md b/docs/examples/account/update-passkey.md new file mode 100644 index 00000000..2f925b98 --- /dev/null +++ b/docs/examples/account/update-passkey.md @@ -0,0 +1,16 @@ +```javascript +import { Client, Account } from 'react-native-appwrite'; + +const client = new Client() + .setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint + .setProject(''); // Your project ID + +const account = new Account(client); + +const result = await account.updatePasskey({ + passkeyId: '', + name: '', +}); + +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..b8b5e7eb --- /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: 0, // 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/oauth2/authorize-post.md b/docs/examples/oauth2/authorize-post.md index e27aa7e3..f7dd540c 100644 --- a/docs/examples/oauth2/authorize-post.md +++ b/docs/examples/oauth2/authorize-post.md @@ -19,7 +19,7 @@ const result = await oauth2.authorizePost({ prompt: '', // optional maxAge: 0, // optional authorizationDetails: '', // optional - resource: '', // optional + resource: [], // optional audience: '', // optional requestUri: '', // optional }); diff --git a/docs/examples/oauth2/authorize.md b/docs/examples/oauth2/authorize.md index 039dc744..256e9cb6 100644 --- a/docs/examples/oauth2/authorize.md +++ b/docs/examples/oauth2/authorize.md @@ -19,7 +19,7 @@ const result = await oauth2.authorize({ prompt: '', // optional maxAge: 0, // optional authorizationDetails: '', // optional - resource: '', // optional + resource: [], // optional audience: '', // optional requestUri: '', // optional }); diff --git a/docs/examples/oauth2/create-device-authorization.md b/docs/examples/oauth2/create-device-authorization.md index c136011b..1219db51 100644 --- a/docs/examples/oauth2/create-device-authorization.md +++ b/docs/examples/oauth2/create-device-authorization.md @@ -11,7 +11,7 @@ const result = await oauth2.createDeviceAuthorization({ clientId: '', // optional scope: '', // optional authorizationDetails: '', // optional - resource: '', // optional + resource: [], // optional audience: '', // optional }); diff --git a/docs/examples/oauth2/create-par.md b/docs/examples/oauth2/create-par.md index 5d9b5783..425e7a86 100644 --- a/docs/examples/oauth2/create-par.md +++ b/docs/examples/oauth2/create-par.md @@ -19,7 +19,7 @@ const result = await oauth2.createPAR({ prompt: '', // optional maxAge: 0, // optional authorizationDetails: '', // optional - resource: '', // optional + resource: [], // optional audience: '', // optional }); diff --git a/docs/examples/oauth2/create-token.md b/docs/examples/oauth2/create-token.md index 3be9ff4a..567bfb74 100644 --- a/docs/examples/oauth2/create-token.md +++ b/docs/examples/oauth2/create-token.md @@ -16,7 +16,7 @@ const result = await oauth2.createToken({ clientSecret: '', // optional codeVerifier: '', // optional redirectUri: 'https://example.com', // optional - resource: '', // optional + resource: [], // optional audience: '', // optional }); diff --git a/docs/examples/teams/create-membership.md b/docs/examples/teams/create-membership.md index 3c6ee849..9a4828a9 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/package-lock.json b/package-lock.json index 33230e5f..bbf4775e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "react-native-appwrite", - "version": "1.2.0-rc.4", + "version": "2.0.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "react-native-appwrite", - "version": "1.2.0-rc.4", + "version": "2.0.0", "license": "BSD-3-Clause", "dependencies": { "buffer": "6.0.3", diff --git a/package.json b/package.json index 12b4f76a..b36e9cfc 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-rc.4", + "version": "2.0.0", "license": "BSD-3-Clause", "main": "dist/cjs/sdk.js", "exports": { diff --git a/src/client.ts b/src/client.ts index 4bc8575c..8efff40a 100644 --- a/src/client.ts +++ b/src/client.ts @@ -1,7 +1,7 @@ import { Models } from './models'; import { Service } from './service'; import { Platform } from 'react-native'; -import { Query } from './query'; +import { Query, flattenParam } from './query'; import JSONbigModule from 'json-bigint'; const JSONbigParser = JSONbigModule({ storeAsString: false }); const JSONbigSerializer = JSONbigModule({ useNativeBigInt: true }); @@ -45,6 +45,79 @@ export const JSONbig = { stringify: JSONbigSerializer.stringify, }; +type DefaultsShape = string | { items: DefaultsShape }; + +type DefaultsModel = { + defaults?: Record; + properties?: Record; +}; + +type Defaults = { + root: DefaultsShape; + models: Record; +}; + +export function applyDefaults(value: T, tree: Defaults): T { + return fillDefaults(value, tree.root, tree.models) as T; +} + +function cloneDefault(value: unknown): unknown { + if (Array.isArray(value)) { + return value.map(cloneDefault); + } + if (typeof value === 'object' && value !== null) { + const copy: Record = {}; + for (const [key, member] of Object.entries(value)) { + copy[key] = cloneDefault(member); + } + return copy; + } + return value; +} + +function fillDefaults( + value: unknown, + shape: DefaultsShape, + models: Record, +): unknown { + if (typeof shape !== 'string') { + if (!Array.isArray(value)) { + return value; + } + const items = shape.items; + return value.map((item) => fillDefaults(item, items, models)); + } + const model = models[shape]; + if (!model || typeof value !== 'object' || value === null) { + return value; + } + if (Array.isArray(value)) { + return value; + } + const result: Record = { ...model.defaults, ...value }; + // Each item gets its own copy of a filled-in list or object, so mutating one doesn't change the rest + for (const key of Object.keys(model.defaults ?? {})) { + if (!Object.prototype.hasOwnProperty.call(value, key)) { + result[key] = cloneDefault(result[key]); + } + } + for (const [key, child] of Object.entries(model.properties ?? {})) { + if (key in result) { + result[key] = fillDefaults(result[key], child, models); + } + } + // The spread drops the non-enumerable JSON toString that Client.call attaches. + if (Object.prototype.hasOwnProperty.call(value, 'toString')) { + Object.defineProperty(result, 'toString', { + value: () => JSONbig.stringify(result), + writable: true, + enumerable: false, + configurable: true, + }); + } + return result; +} + type Payload = { [key: string]: any; }; @@ -218,8 +291,8 @@ class Client { 'x-sdk-name': 'React Native', 'x-sdk-platform': 'client', 'x-sdk-language': 'reactnative', - 'x-sdk-version': '1.2.0-rc.4', - 'X-Appwrite-Response-Format': '2.3.0', + 'x-sdk-version': '2.0.0', + 'X-Appwrite-Response-Format': '2.5.0', }; /** @@ -837,6 +910,10 @@ class Client { ): Promise { method = method.toUpperCase(); + for (const key of Object.keys(params)) { + params[key] = flattenParam(params[key]); + } + headers = Object.assign({}, this.headers, headers); headers.Origin = `appwrite-${Platform.OS}://${this.config.platform}`; diff --git a/src/enums/execution-trigger.ts b/src/enums/execution-trigger.ts index 84fa8f60..b16a8781 100644 --- a/src/enums/execution-trigger.ts +++ b/src/enums/execution-trigger.ts @@ -2,4 +2,5 @@ export enum ExecutionTrigger { Http = 'http', Schedule = 'schedule', Event = 'event', + Email = 'email', } diff --git a/src/index.ts b/src/index.ts index 579ed73a..c4d406c4 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 { Apps } from './services/apps'; export { Avatars } from './services/avatars'; export { Databases } from './services/databases'; @@ -32,12 +33,12 @@ export type { UploadProgress, } from './client'; export type { RealtimeSubscription } from './services/realtime'; -export type { QueryTypes, QueryTypesList } from './query'; -export { Query } from './query'; +export type { QueryTypes, QueryTypesList, QueryInput } from './query'; +export { Query, QueryBuilder, flattenParam } from './query'; export { Permission } from './permission'; export { Role } from './role'; export { ID } from './id'; -export { Topic, ResolvedTopic } from './topic'; +export { Topic } from './topic'; export { Channel } from './channel'; export { Operator, Condition } from './operator'; export { AuthenticatorType } from './enums/authenticator-type'; diff --git a/src/models.ts b/src/models.ts index 09b8b39c..03ed2f9f 100644 --- a/src/models.ts +++ b/src/models.ts @@ -338,7 +338,7 @@ export namespace Models { /** * Presence status. */ - status?: string; + status?: string | null; /** * Presence source. */ @@ -346,7 +346,7 @@ export namespace Models { /** * Presence expiry date in ISO 8601 format. */ - expiresAt?: string; + expiresAt?: string | null; /** * Presence metadata. */ @@ -378,15 +378,15 @@ export namespace Models { /** * Hashed user password. */ - password?: string; + password?: string | null; /** * Password hashing algorithm. */ - hash?: string; + hash?: string | null; /** * Password hashing algorithm configuration. */ - hashOptions?: object; + hashOptions?: object | null; /** * User registration date in ISO 8601 format. */ @@ -418,27 +418,27 @@ export namespace Models { /** * Canonical form of the user email address. */ - emailCanonical?: string; + emailCanonical?: string | null; /** * Whether the user email is from a free email provider. */ - emailIsFree?: boolean; + emailIsFree?: boolean | null; /** * Whether the user email is from a disposable email provider. */ - emailIsDisposable?: boolean; + emailIsDisposable?: boolean | null; /** * Whether the user email is from a corporate domain. */ - emailIsCorporate?: boolean; + emailIsCorporate?: boolean | null; /** * Whether the user email is in its canonical form. */ - emailIsCanonical?: boolean; + emailIsCanonical?: boolean | null; /** * 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; + passwordPwned?: boolean | null; /** * Phone verification status. */ @@ -462,11 +462,11 @@ export namespace Models { /** * Whether the user can impersonate other users. */ - impersonator?: boolean; + impersonator?: boolean | null; /** * 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; + impersonatorUserId?: string | null; }; /** @@ -632,27 +632,27 @@ export namespace Models { /** * Canonical form of the user email address. */ - emailCanonical?: string; + emailCanonical?: string | null; /** * Whether the user email is from a free email provider. */ - emailIsFree?: boolean; + emailIsFree?: boolean | null; /** * Whether the user email is from a disposable email provider. */ - emailIsDisposable?: boolean; + emailIsDisposable?: boolean | null; /** * Whether the user email is from a corporate domain. */ - emailIsCorporate?: boolean; + emailIsCorporate?: boolean | null; /** * Whether the user email is in its canonical form. */ - emailIsCanonical?: boolean; + emailIsCanonical?: boolean | null; /** * 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; + passwordPwned?: boolean | null; /** * Phone verification status. */ @@ -676,11 +676,11 @@ export namespace Models { /** * Whether the user can impersonate other users. */ - impersonator?: boolean; + impersonator?: boolean | null; /** * 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; + impersonatorUserId?: string | null; }; /** @@ -940,47 +940,47 @@ export namespace Models { /** * City */ - city?: string; + city?: string | null; /** * Name of timezone */ - timeZone?: string; + timeZone?: string | null; /** * Postal code */ - postalCode?: string; + postalCode?: string | null; /** * Latitude */ - latitude?: number; + latitude?: number | null; /** * Longitude */ - longitude?: number; + longitude?: number | null; /** * Autonomous System Number (ASN) of the IP */ - autonomousSystemNumber?: string; + autonomousSystemNumber?: string | null; /** * Organization that owns the ASN */ - autonomousSystemOrganization?: string; + autonomousSystemOrganization?: string | null; /** * Internet service provider of the IP */ - isp?: string; + isp?: string | null; /** * Connection type of the IP (e.g. cable, cellular, corporate) */ - connectionType?: string; + connectionType?: string | null; /** * User type classification of the IP (e.g. residential, business, hosting) */ - connectionUsageType?: string; + connectionUsageType?: string | null; /** * Registered organization of the IP */ - connectionOrganization?: string; + connectionOrganization?: string | null; }; /** @@ -1198,7 +1198,7 @@ export namespace Models { */ deploymentId: string; /** - * The trigger that caused the resource to execute. Possible values can be: `http`, `schedule`, or `event`. + * The trigger that caused the resource to execute. Possible values can be: `http`, `schedule`, `event`, or `email`. */ trigger: ExecutionTrigger; /** @@ -1244,7 +1244,7 @@ export namespace Models { /** * The scheduled time for execution. If left empty, execution will be queued immediately. */ - scheduledAt?: string; + scheduledAt?: string | null; }; /** @@ -1381,6 +1381,102 @@ export namespace Models { expire: string; }; + /** + * Token Secret + */ + export type TokenSecret = { + /** + * Token ID. + */ + $id: string; + /** + * Token creation date in ISO 8601 format. + */ + $createdAt: string; + /** + * User ID. + */ + userId: string; + /** + * Token secret key. Exchange it for a session with the create session endpoint. + */ + secret: string; + /** + * Token expiration date in ISO 8601 format. + */ + expire: string; + /** + * Security phrase of a token. Empty if security phrase was not requested when creating a token. It includes randomly generated phrase which is also sent in the external resource such as email. + */ + phrase: string; + }; + + /** + * Passkey + */ + export type Passkey = { + /** + * Passkey ID. + */ + $id: string; + /** + * Passkey creation date in ISO 8601 format. + */ + $createdAt: string; + /** + * Passkey update date in ISO 8601 format. + */ + $updatedAt: string; + /** + * Passkey name. + */ + name: string; + /** + * Most recent sign-in with this passkey in ISO 8601 format. Empty until the passkey is used to sign in. + */ + accessedAt: string; + }; + + /** + * Passkey Challenge + */ + export type PasskeyChallenge = { + /** + * Challenge ID. When signing in, pass it back with the credential to receive a token. + */ + $id: string; + /** + * Challenge creation date in ISO 8601 format. + */ + $createdAt: string; + /** + * ID of the passkey being registered. Empty for sign-in challenges. + */ + passkeyId: string; + /** + * Challenge expiration date in ISO 8601 format. + */ + expire: string; + /** + * WebAuthn options in JSON form. Pass them to `PublicKeyCredential.parseCreationOptionsFromJSON()` when registering, or `PublicKeyCredential.parseRequestOptionsFromJSON()` when signing in. + */ + publicKey: object; + }; + + /** + * Passkeys List + */ + export type PasskeyList = { + /** + * Total number of passkeys that matched your query. + */ + total: number; + /** + * List of passkeys. + */ + passkeys: Passkey[]; + }; + /** * MFA Recovery Codes */ @@ -1530,7 +1626,7 @@ export namespace Models { /** * Provider ID. */ - providerId?: string; + providerId?: string | null; /** * The target provider type. Can be one of the following: `email`, `sms` or `push`. */ @@ -1694,7 +1790,7 @@ export namespace Models { /** * Time the secret was last used for authentication in ISO 8601 format. Null if never used. */ - lastAccessedAt?: string; + lastAccessedAt?: string | null; }; /** @@ -1736,7 +1832,7 @@ export namespace Models { /** * Time the secret was last used for authentication in ISO 8601 format. Null if never used. */ - lastAccessedAt?: string; + lastAccessedAt?: string | null; }; /** @@ -1808,7 +1904,7 @@ export namespace Models { /** * Time an access token was last issued for the installation in ISO 8601 format. Null if never used. */ - lastAccessedAt?: string; + lastAccessedAt?: string | null; }; /** @@ -1850,7 +1946,7 @@ export namespace Models { /** * Time the app key was last used for authentication in ISO 8601 format. Null if never used. */ - lastAccessedAt?: string; + lastAccessedAt?: string | null; }; /** @@ -2012,11 +2108,11 @@ export namespace Models { /** * Granted RFC 9396 authorization details as a JSON string. */ - authorization_details?: string; + authorization_details?: string | null; /** * OpenID Connect ID token. Returned when the `openid` scope is granted. */ - id_token?: string; + id_token?: string | null; }; /** diff --git a/src/query.ts b/src/query.ts index 104b1ab9..cd2d7855 100644 --- a/src/query.ts +++ b/src/query.ts @@ -310,6 +310,20 @@ export class Query { queries.map((query) => JSONbig.parse(query)), ).toString(); + /** + * Constrain populated related documents on a relationship attribute. + * + * @param {string} attribute The relationship attribute to query. + * @param {string[]} queries Filter, order, select, and pagination queries applied to related documents. + * @returns {string} + */ + static relationship = (attribute: string, queries: string[]): string => + new Query( + 'relationship', + attribute, + queries.map((query) => JSONbig.parse(query)), + ).toString(); + /** * Filter resources where attribute is at a specific distance from the given coordinates. * @@ -501,4 +515,776 @@ export class Query { */ static notTouches = (attribute: string, values: any[]): string => new Query('notTouches', attribute, [values]).toString(); + + /** + * Count documents, optionally aliased. + */ + static count = (attribute: string = '*', alias: string = ''): string => + new Query( + 'count', + attribute, + alias !== '' ? alias : undefined, + ).toString(); + + /** + * Count distinct values of attribute, optionally aliased. + */ + static countDistinct = (attribute: string, alias: string = ''): string => + new Query( + 'countDistinct', + attribute, + alias !== '' ? alias : undefined, + ).toString(); + + static sum = (attribute: string, alias: string = ''): string => + new Query( + 'sum', + attribute, + alias !== '' ? alias : undefined, + ).toString(); + + static avg = (attribute: string, alias: string = ''): string => + new Query( + 'avg', + attribute, + alias !== '' ? alias : undefined, + ).toString(); + + static min = (attribute: string, alias: string = ''): string => + new Query( + 'min', + attribute, + alias !== '' ? alias : undefined, + ).toString(); + + static max = (attribute: string, alias: string = ''): string => + new Query( + 'max', + attribute, + alias !== '' ? alias : undefined, + ).toString(); + + static stddev = (attribute: string, alias: string = ''): string => + new Query( + 'stddev', + attribute, + alias !== '' ? alias : undefined, + ).toString(); + + static stddevPop = (attribute: string, alias: string = ''): string => + new Query( + 'stddevPop', + attribute, + alias !== '' ? alias : undefined, + ).toString(); + + static stddevSamp = (attribute: string, alias: string = ''): string => + new Query( + 'stddevSamp', + attribute, + alias !== '' ? alias : undefined, + ).toString(); + + static variance = (attribute: string, alias: string = ''): string => + new Query( + 'variance', + attribute, + alias !== '' ? alias : undefined, + ).toString(); + + static varPop = (attribute: string, alias: string = ''): string => + new Query( + 'varPop', + attribute, + alias !== '' ? alias : undefined, + ).toString(); + + static varSamp = (attribute: string, alias: string = ''): string => + new Query( + 'varSamp', + attribute, + alias !== '' ? alias : undefined, + ).toString(); + + static bitAnd = (attribute: string, alias: string = ''): string => + new Query( + 'bitAnd', + attribute, + alias !== '' ? alias : undefined, + ).toString(); + + static bitOr = (attribute: string, alias: string = ''): string => + new Query( + 'bitOr', + attribute, + alias !== '' ? alias : undefined, + ).toString(); + + static bitXor = (attribute: string, alias: string = ''): string => + new Query( + 'bitXor', + attribute, + alias !== '' ? alias : undefined, + ).toString(); + + /** + * Group results by attributes. + */ + static groupBy = (attributes: string[]): string => + new Query('groupBy', undefined, attributes).toString(); + + /** + * Filter grouped results. `queries` are nested like `and`/`or`. + */ + static having = (queries: string[]): string => + new Query( + 'having', + undefined, + queries.map((query) => JSONbig.parse(query)), + ).toString(); + + static distinct = (): string => new Query('distinct').toString(); + + /** + * Column-to-column join ON condition. + */ + static on = (left: string, right: string, operator: string = '='): string => + new Query('on', undefined, [left, operator, right]).toString(); + + /** + * Inner join. `table` is the joined collection/table ID. + */ + static join = ( + table: string, + leftOrAliasOrOn: string | string[], + rightOrOn: string | string[] = '', + operator: string = '=', + alias: string = '', + ): string => + Query.createJoin( + 'join', + table, + leftOrAliasOrOn, + rightOrOn, + operator, + alias, + ); + + static leftJoin = ( + table: string, + leftOrAliasOrOn: string | string[], + rightOrOn: string | string[] = '', + operator: string = '=', + alias: string = '', + ): string => + Query.createJoin( + 'leftJoin', + table, + leftOrAliasOrOn, + rightOrOn, + operator, + alias, + ); + + static rightJoin = ( + table: string, + leftOrAliasOrOn: string | string[], + rightOrOn: string | string[] = '', + operator: string = '=', + alias: string = '', + ): string => + Query.createJoin( + 'rightJoin', + table, + leftOrAliasOrOn, + rightOrOn, + operator, + alias, + ); + + static fullOuterJoin = ( + table: string, + leftOrAliasOrOn: string | string[], + rightOrOn: string | string[] = '', + operator: string = '=', + alias: string = '', + ): string => + Query.createJoin( + 'fullOuterJoin', + table, + leftOrAliasOrOn, + rightOrOn, + operator, + alias, + ); + + static crossJoin = (table: string, alias: string = ''): string => + new Query( + 'crossJoin', + table, + alias !== '' ? alias : undefined, + ).toString(); + + static covers = (attribute: string, values: any[]): string => + new Query('covers', attribute, [values]).toString(); + + static notCovers = (attribute: string, values: any[]): string => + new Query('notCovers', attribute, [values]).toString(); + + static spatialEquals = (attribute: string, values: any[]): string => + new Query('spatialEquals', attribute, [values]).toString(); + + static notSpatialEquals = (attribute: string, values: any[]): string => + new Query('notSpatialEquals', attribute, [values]).toString(); + + /** + * Return limit and offset queries for 1-based page pagination. + */ + static page = (page: number, perPage: number = 25): string[] => { + if (page < 1) { + throw new Error('Page must be >= 1, got ' + page); + } + if (perPage < 1) { + throw new Error('Per page must be >= 1, got ' + perPage); + } + return [Query.limit(perPage), Query.offset((page - 1) * perPage)]; + }; + + static builder = (): Query.Builder => new Query.Builder(); + + private static createJoin( + method: string, + table: string, + leftOrAliasOrOn: string | string[], + rightOrOn: string | string[] = '', + operator: string = '=', + alias: string = '', + ): string { + if (Array.isArray(leftOrAliasOrOn)) { + return Query.nestedJoin(method, table, '', leftOrAliasOrOn); + } + if (Array.isArray(rightOrOn)) { + return Query.nestedJoin(method, table, leftOrAliasOrOn, rightOrOn); + } + return new Query( + method, + table, + alias !== '' + ? [leftOrAliasOrOn, operator, rightOrOn, alias] + : [leftOrAliasOrOn, operator, rightOrOn], + ).toString(); + } + + private static nestedJoin( + method: string, + table: string, + alias: string, + on: string[], + ): string { + const values: any[] = []; + if (alias !== '') { + values.push(alias); + } + for (const query of on) { + values.push(JSONbig.parse(query)); + } + return new Query(method, table, values).toString(); + } +} + +export type QueryInput = string | Query | Query.Builder | QueryInput[]; + +/** + * Fluent collector of Query fragments. Call {@link Query.Builder.build} to + * produce the `string[]` expected by list/createQuery methods. + */ +export namespace Query { + export class Builder { + private readonly queries: string[] = []; + + build(): string[] { + return [...this.queries]; + } + + equal(attribute: string, value: QueryTypes): this { + return this.push(Query.equal(attribute, value)); + } + + notEqual(attribute: string, value: QueryTypes): this { + return this.push(Query.notEqual(attribute, value)); + } + + lessThan(attribute: string, value: QueryTypes): this { + return this.push(Query.lessThan(attribute, value)); + } + + lessThanEqual(attribute: string, value: QueryTypes): this { + return this.push(Query.lessThanEqual(attribute, value)); + } + + greaterThan(attribute: string, value: QueryTypes): this { + return this.push(Query.greaterThan(attribute, value)); + } + + greaterThanEqual(attribute: string, value: QueryTypes): this { + return this.push(Query.greaterThanEqual(attribute, value)); + } + + search(attribute: string, value: string): this { + return this.push(Query.search(attribute, value)); + } + + isNull(attribute: string): this { + return this.push(Query.isNull(attribute)); + } + + isNotNull(attribute: string): this { + return this.push(Query.isNotNull(attribute)); + } + + between( + attribute: string, + start: string | number | bigint, + end: string | number | bigint, + ): this { + return this.push(Query.between(attribute, start, end)); + } + + startsWith(attribute: string, value: string): this { + return this.push(Query.startsWith(attribute, value)); + } + + endsWith(attribute: string, value: string): this { + return this.push(Query.endsWith(attribute, value)); + } + + select(attributes: string[]): this { + return this.push(Query.select(attributes)); + } + + cursorAfter(documentId: string): this { + return this.push(Query.cursorAfter(documentId)); + } + + cursorBefore(documentId: string): this { + return this.push(Query.cursorBefore(documentId)); + } + + orderAsc(attribute: string): this { + return this.push(Query.orderAsc(attribute)); + } + + orderDesc(attribute: string): this { + return this.push(Query.orderDesc(attribute)); + } + + orderRandom(): this { + return this.push(Query.orderRandom()); + } + + limit(limit: number): this { + return this.push(Query.limit(limit)); + } + + offset(offset: number): this { + return this.push(Query.offset(offset)); + } + + contains(attribute: string, value: string | any[]): this { + return this.push(Query.contains(attribute, value)); + } + + containsAny(attribute: string, value: any[]): this { + return this.push(Query.containsAny(attribute, value)); + } + + containsAll(attribute: string, value: any[]): this { + return this.push(Query.containsAll(attribute, value)); + } + + notContains(attribute: string, value: string | any[]): this { + return this.push(Query.notContains(attribute, value)); + } + + notSearch(attribute: string, value: string): this { + return this.push(Query.notSearch(attribute, value)); + } + + notBetween( + attribute: string, + start: string | number | bigint, + end: string | number | bigint, + ): this { + return this.push(Query.notBetween(attribute, start, end)); + } + + notStartsWith(attribute: string, value: string): this { + return this.push(Query.notStartsWith(attribute, value)); + } + + notEndsWith(attribute: string, value: string): this { + return this.push(Query.notEndsWith(attribute, value)); + } + + regex(attribute: string, pattern: string): this { + return this.push(Query.regex(attribute, pattern)); + } + + exists(attributes: string[]): this { + return this.push(Query.exists(attributes)); + } + + notExists(attributes: string[]): this { + return this.push(Query.notExists(attributes)); + } + + createdBefore(value: string): this { + return this.push(Query.createdBefore(value)); + } + + createdAfter(value: string): this { + return this.push(Query.createdAfter(value)); + } + + createdBetween(start: string, end: string): this { + return this.push(Query.createdBetween(start, end)); + } + + updatedBefore(value: string): this { + return this.push(Query.updatedBefore(value)); + } + + updatedAfter(value: string): this { + return this.push(Query.updatedAfter(value)); + } + + updatedBetween(start: string, end: string): this { + return this.push(Query.updatedBetween(start, end)); + } + + or(queries: string[]): this { + return this.push(Query.or(queries)); + } + + and(queries: string[]): this { + return this.push(Query.and(queries)); + } + + elemMatch(attribute: string, queries: string[]): this { + return this.push(Query.elemMatch(attribute, queries)); + } + + relationship(attribute: string, queries: string[]): this { + return this.push(Query.relationship(attribute, queries)); + } + + distanceEqual( + attribute: string, + values: any[], + distance: number, + meters: boolean = true, + ): this { + return this.push( + Query.distanceEqual(attribute, values, distance, meters), + ); + } + + distanceNotEqual( + attribute: string, + values: any[], + distance: number, + meters: boolean = true, + ): this { + return this.push( + Query.distanceNotEqual(attribute, values, distance, meters), + ); + } + + distanceGreaterThan( + attribute: string, + values: any[], + distance: number, + meters: boolean = true, + ): this { + return this.push( + Query.distanceGreaterThan(attribute, values, distance, meters), + ); + } + + distanceLessThan( + attribute: string, + values: any[], + distance: number, + meters: boolean = true, + ): this { + return this.push( + Query.distanceLessThan(attribute, values, distance, meters), + ); + } + + intersects(attribute: string, values: any[]): this { + return this.push(Query.intersects(attribute, values)); + } + + notIntersects(attribute: string, values: any[]): this { + return this.push(Query.notIntersects(attribute, values)); + } + + crosses(attribute: string, values: any[]): this { + return this.push(Query.crosses(attribute, values)); + } + + notCrosses(attribute: string, values: any[]): this { + return this.push(Query.notCrosses(attribute, values)); + } + + overlaps(attribute: string, values: any[]): this { + return this.push(Query.overlaps(attribute, values)); + } + + notOverlaps(attribute: string, values: any[]): this { + return this.push(Query.notOverlaps(attribute, values)); + } + + touches(attribute: string, values: any[]): this { + return this.push(Query.touches(attribute, values)); + } + + notTouches(attribute: string, values: any[]): this { + return this.push(Query.notTouches(attribute, values)); + } + + count(attribute: string = '*', alias: string = ''): this { + return this.push(Query.count(attribute, alias)); + } + + countDistinct(attribute: string, alias: string = ''): this { + return this.push(Query.countDistinct(attribute, alias)); + } + + sum(attribute: string, alias: string = ''): this { + return this.push(Query.sum(attribute, alias)); + } + + avg(attribute: string, alias: string = ''): this { + return this.push(Query.avg(attribute, alias)); + } + + min(attribute: string, alias: string = ''): this { + return this.push(Query.min(attribute, alias)); + } + + max(attribute: string, alias: string = ''): this { + return this.push(Query.max(attribute, alias)); + } + + stddev(attribute: string, alias: string = ''): this { + return this.push(Query.stddev(attribute, alias)); + } + + stddevPop(attribute: string, alias: string = ''): this { + return this.push(Query.stddevPop(attribute, alias)); + } + + stddevSamp(attribute: string, alias: string = ''): this { + return this.push(Query.stddevSamp(attribute, alias)); + } + + variance(attribute: string, alias: string = ''): this { + return this.push(Query.variance(attribute, alias)); + } + + varPop(attribute: string, alias: string = ''): this { + return this.push(Query.varPop(attribute, alias)); + } + + varSamp(attribute: string, alias: string = ''): this { + return this.push(Query.varSamp(attribute, alias)); + } + + bitAnd(attribute: string, alias: string = ''): this { + return this.push(Query.bitAnd(attribute, alias)); + } + + bitOr(attribute: string, alias: string = ''): this { + return this.push(Query.bitOr(attribute, alias)); + } + + bitXor(attribute: string, alias: string = ''): this { + return this.push(Query.bitXor(attribute, alias)); + } + + groupBy(attributes: string[]): this { + return this.push(Query.groupBy(attributes)); + } + + having(queries: string[]): this { + return this.push(Query.having(queries)); + } + + distinct(): this { + return this.push(Query.distinct()); + } + + join( + table: string, + leftOrAliasOrOn: string | string[], + rightOrOn: string | string[] = '', + operator: string = '=', + alias: string = '', + ): this { + return this.push( + Query.join(table, leftOrAliasOrOn, rightOrOn, operator, alias), + ); + } + + leftJoin( + table: string, + leftOrAliasOrOn: string | string[], + rightOrOn: string | string[] = '', + operator: string = '=', + alias: string = '', + ): this { + return this.push( + Query.leftJoin( + table, + leftOrAliasOrOn, + rightOrOn, + operator, + alias, + ), + ); + } + + rightJoin( + table: string, + leftOrAliasOrOn: string | string[], + rightOrOn: string | string[] = '', + operator: string = '=', + alias: string = '', + ): this { + return this.push( + Query.rightJoin( + table, + leftOrAliasOrOn, + rightOrOn, + operator, + alias, + ), + ); + } + + fullOuterJoin( + table: string, + leftOrAliasOrOn: string | string[], + rightOrOn: string | string[] = '', + operator: string = '=', + alias: string = '', + ): this { + return this.push( + Query.fullOuterJoin( + table, + leftOrAliasOrOn, + rightOrOn, + operator, + alias, + ), + ); + } + + crossJoin(table: string, alias: string = ''): this { + return this.push(Query.crossJoin(table, alias)); + } + + vectorDot(attribute: string, vector: number[]): this { + return this.push(Query.vectorDot(attribute, vector)); + } + + vectorCosine(attribute: string, vector: number[]): this { + return this.push(Query.vectorCosine(attribute, vector)); + } + + vectorEuclidean(attribute: string, vector: number[]): this { + return this.push(Query.vectorEuclidean(attribute, vector)); + } + + covers(attribute: string, values: any[]): this { + return this.push(Query.covers(attribute, values)); + } + + notCovers(attribute: string, values: any[]): this { + return this.push(Query.notCovers(attribute, values)); + } + + spatialEquals(attribute: string, values: any[]): this { + return this.push(Query.spatialEquals(attribute, values)); + } + + notSpatialEquals(attribute: string, values: any[]): this { + return this.push(Query.notSpatialEquals(attribute, values)); + } + + page(page: number, perPage: number = 25): this { + return this.push(Query.page(page, perPage)); + } + + private push(query: string | string[]): this { + if (Array.isArray(query)) { + this.queries.push(...query); + } else { + this.queries.push(query); + } + return this; + } + } } + +export function normalizeQueries(queries?: QueryInput | null): string[] { + if (queries == null) { + return []; + } + if (queries instanceof Query.Builder) { + return queries.build(); + } + if (!Array.isArray(queries)) { + if (queries instanceof Query) { + return [queries.toString()]; + } + if (typeof queries === 'string') { + return [queries]; + } + return []; + } + + const out: string[] = []; + for (const item of queries) { + out.push(...normalizeQueries(item)); + } + return out; +} + +function isQueryValue(value: unknown): value is Query | Query.Builder { + return value instanceof Query.Builder || value instanceof Query; +} + +export function flattenParam(value: unknown): unknown { + if (isQueryValue(value)) { + return normalizeQueries(value); + } + if (!Array.isArray(value) || !value.some(isQueryValue)) { + return value; + } + + const out: unknown[] = []; + for (const item of value) { + if (isQueryValue(item)) { + out.push(...normalizeQueries(item)); + } else { + out.push(item); + } + } + return out; +} + +export const QueryBuilder = Query.Builder; +export type QueryBuilder = Query.Builder; diff --git a/src/services/account.ts b/src/services/account.ts index fb3d545b..983002d2 100644 --- a/src/services/account.ts +++ b/src/services/account.ts @@ -1,5 +1,5 @@ import { Service } from '../service'; -import { AppwriteException, Client } from '../client'; +import { AppwriteException, Client, applyDefaults } from '../client'; import type { Models } from '../models'; import type { Payload } from '../client'; @@ -25,7 +25,7 @@ export class Account extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -34,6 +34,49 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'user', + models: { + user: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + registration: '', + status: true, + labels: [], + passwordUpdate: '', + email: '', + phone: '', + emailVerification: false, + phoneVerification: false, + mfa: false, + targets: [], + accessedAt: '', + }, + properties: { + targets: { + items: 'target', + }, + }, + }, + target: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + userId: '', + providerType: '', + identifier: '', + expired: false, + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -143,7 +186,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -153,6 +196,49 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'user', + models: { + user: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + registration: '', + status: true, + labels: [], + passwordUpdate: '', + email: '', + phone: '', + emailVerification: false, + phoneVerification: false, + mfa: false, + targets: [], + accessedAt: '', + }, + properties: { + targets: { + items: 'target', + }, + }, + }, + target: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + userId: '', + providerType: '', + identifier: '', + expired: false, + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -218,7 +304,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -227,6 +313,38 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'oauth2ConsentList', + models: { + oauth2ConsentList: { + defaults: { + total: 0, + consents: [], + }, + properties: { + consents: { + items: 'oauth2Consent', + }, + }, + }, + oauth2Consent: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + userId: '', + appId: '', + cimdUrl: '', + scopes: [], + resources: [], + authorizationDetails: '[]', + expire: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -278,7 +396,7 @@ export class Account extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -287,6 +405,27 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'oauth2Consent', + models: { + oauth2Consent: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + userId: '', + appId: '', + cimdUrl: '', + scopes: [], + resources: [], + authorizationDetails: '[]', + expire: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -427,7 +566,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -436,6 +575,39 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'oauth2ConsentTokenList', + models: { + oauth2ConsentTokenList: { + defaults: { + total: 0, + tokens: [], + }, + properties: { + tokens: { + items: 'oauth2ConsentToken', + }, + }, + }, + oauth2ConsentToken: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + consentId: '', + userId: '', + appId: '', + cimdUrl: '', + scopes: [], + resources: [], + authorizationDetails: '[]', + expire: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -506,7 +678,7 @@ export class Account extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -515,6 +687,28 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'oauth2ConsentToken', + models: { + oauth2ConsentToken: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + consentId: '', + userId: '', + appId: '', + cimdUrl: '', + scopes: [], + resources: [], + authorizationDetails: '[]', + expire: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -673,7 +867,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'patch', uri, { @@ -683,6 +877,49 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'user', + models: { + user: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + registration: '', + status: true, + labels: [], + passwordUpdate: '', + email: '', + phone: '', + emailVerification: false, + phoneVerification: false, + mfa: false, + targets: [], + accessedAt: '', + }, + properties: { + targets: { + items: 'target', + }, + }, + }, + target: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + userId: '', + providerType: '', + identifier: '', + expired: false, + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -748,7 +985,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -757,6 +994,39 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'identityList', + models: { + identityList: { + defaults: { + total: 0, + identities: [], + }, + properties: { + identities: { + items: 'identity', + }, + }, + }, + identity: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + userId: '', + provider: '', + providerUid: '', + providerEmail: '', + providerAccessToken: '', + providerAccessTokenExpiry: '', + providerRefreshToken: '', + providerIdToken: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -865,7 +1135,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -875,6 +1145,18 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'jwt', + models: { + jwt: { + defaults: { + jwt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -931,7 +1213,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'patch', uri, { @@ -941,6 +1223,49 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'user', + models: { + user: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + registration: '', + status: true, + labels: [], + passwordUpdate: '', + email: '', + phone: '', + emailVerification: false, + phoneVerification: false, + mfa: false, + targets: [], + accessedAt: '', + }, + properties: { + targets: { + items: 'target', + }, + }, + }, + target: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + userId: '', + providerType: '', + identifier: '', + expired: false, + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -994,7 +1319,7 @@ export class Account extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -1004,6 +1329,19 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'mfaType', + models: { + mfaType: { + defaults: { + secret: '', + uri: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1056,7 +1394,7 @@ export class Account extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -1066,6 +1404,19 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'mfaType', + models: { + mfaType: { + defaults: { + secret: '', + uri: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1143,7 +1494,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'put', uri, { @@ -1153,6 +1504,49 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'user', + models: { + user: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + registration: '', + status: true, + labels: [], + passwordUpdate: '', + email: '', + phone: '', + emailVerification: false, + phoneVerification: false, + mfa: false, + targets: [], + accessedAt: '', + }, + properties: { + targets: { + items: 'target', + }, + }, + }, + target: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + userId: '', + providerType: '', + identifier: '', + expired: false, + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1229,7 +1623,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'put', uri, { @@ -1239,6 +1633,49 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'user', + models: { + user: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + registration: '', + status: true, + labels: [], + passwordUpdate: '', + email: '', + phone: '', + emailVerification: false, + phoneVerification: false, + mfa: false, + targets: [], + accessedAt: '', + }, + properties: { + targets: { + items: 'target', + }, + }, + }, + target: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + userId: '', + providerType: '', + identifier: '', + expired: false, + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1416,7 +1853,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -1426,6 +1863,21 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'mfaChallenge', + models: { + mfaChallenge: { + defaults: { + $id: '', + $createdAt: '', + userId: '', + expire: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1481,7 +1933,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -1491,6 +1943,21 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'mfaChallenge', + models: { + mfaChallenge: { + defaults: { + $id: '', + $createdAt: '', + userId: '', + expire: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1566,7 +2033,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'put', uri, { @@ -1576,6 +2043,46 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'session', + models: { + session: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + userId: '', + expire: '', + provider: '', + providerUid: '', + providerAccessToken: '', + providerAccessTokenExpiry: '', + providerRefreshToken: '', + ip: '', + osCode: '', + osName: '', + osVersion: '', + clientType: '', + clientCode: '', + clientName: '', + clientVersion: '', + clientEngine: '', + clientEngineVersion: '', + deviceName: '', + deviceBrand: '', + deviceModel: '', + countryCode: '', + countryName: '', + current: false, + factors: [], + secret: '', + mfaUpdatedAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1650,7 +2157,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'put', uri, { @@ -1660,6 +2167,46 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'session', + models: { + session: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + userId: '', + expire: '', + provider: '', + providerUid: '', + providerAccessToken: '', + providerAccessTokenExpiry: '', + providerRefreshToken: '', + ip: '', + osCode: '', + osName: '', + osVersion: '', + clientType: '', + clientCode: '', + clientName: '', + clientVersion: '', + clientEngine: '', + clientEngineVersion: '', + deviceName: '', + deviceBrand: '', + deviceModel: '', + countryCode: '', + countryName: '', + current: false, + factors: [], + secret: '', + mfaUpdatedAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1674,7 +2221,7 @@ export class Account extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -1683,6 +2230,22 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'mfaFactors', + models: { + mfaFactors: { + defaults: { + totp: false, + phone: false, + email: false, + recoveryCode: false, + custom: false, + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1696,7 +2259,7 @@ export class Account extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -1705,6 +2268,22 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'mfaFactors', + models: { + mfaFactors: { + defaults: { + totp: false, + phone: false, + email: false, + recoveryCode: false, + custom: false, + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1719,7 +2298,7 @@ export class Account extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -1728,6 +2307,18 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'mfaRecoveryCodes', + models: { + mfaRecoveryCodes: { + defaults: { + recoveryCodes: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1741,7 +2332,7 @@ export class Account extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -1750,6 +2341,18 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'mfaRecoveryCodes', + models: { + mfaRecoveryCodes: { + defaults: { + recoveryCodes: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1764,7 +2367,7 @@ export class Account extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -1774,6 +2377,18 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'mfaRecoveryCodes', + models: { + mfaRecoveryCodes: { + defaults: { + recoveryCodes: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1787,7 +2402,7 @@ export class Account extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -1797,6 +2412,18 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'mfaRecoveryCodes', + models: { + mfaRecoveryCodes: { + defaults: { + recoveryCodes: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1811,7 +2438,7 @@ export class Account extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'patch', uri, { @@ -1821,6 +2448,18 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'mfaRecoveryCodes', + models: { + mfaRecoveryCodes: { + defaults: { + recoveryCodes: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1833,9 +2472,553 @@ export class Account extends Service { const apiPath = '/account/mfa/recovery-codes'; const apiPayload: Payload = {}; + const uri = new URL(this.client.config.endpoint + apiPath); + const request = this.client.call( + 'patch', + uri, + { + 'X-Appwrite-Project': this.client.config.project, + 'content-type': 'application/json', + accept: 'application/json', + }, + apiPayload, + ); + const defaults = { + root: 'mfaRecoveryCodes', + models: { + mfaRecoveryCodes: { + defaults: { + recoveryCodes: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); + } + + /** + * Update currently logged in user account name. + * + * @param {string} params.name - User name. Max length: 128 chars. + * @throws {AppwriteException} + * @returns {Promise} + */ + updateName< + Preferences extends Models.Preferences = Models.DefaultPreferences, + >(params: { name: string }): Promise>; + /** + * Update currently logged in user account name. + * + * @param {string} name - User name. Max length: 128 chars. + * @throws {AppwriteException} + * @returns {Promise>} + * @deprecated Use the object parameter style method for a better developer experience. + */ + updateName< + Preferences extends Models.Preferences = Models.DefaultPreferences, + >(name: string): Promise>; + updateName< + Preferences extends Models.Preferences = Models.DefaultPreferences, + >( + paramsOrFirst: { name: string } | string, + ): Promise> { + let params: { name: string }; + + if ( + paramsOrFirst && + typeof paramsOrFirst === 'object' && + !Array.isArray(paramsOrFirst) + ) { + params = (paramsOrFirst || {}) as { name: string }; + } else { + params = { + name: paramsOrFirst as string, + }; + } + + const name = params.name; + + if (typeof name === 'undefined') { + throw new AppwriteException('Missing required parameter: "name"'); + } + + const apiPath = '/account/name'; + const apiPayload: Payload = {}; + + if (typeof name !== 'undefined') { + apiPayload['name'] = name; + } + + const uri = new URL(this.client.config.endpoint + apiPath); + const request = this.client.call( + 'patch', + uri, + { + 'X-Appwrite-Project': this.client.config.project, + 'content-type': 'application/json', + accept: 'application/json', + }, + apiPayload, + ); + const defaults = { + root: 'user', + models: { + user: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + registration: '', + status: true, + labels: [], + passwordUpdate: '', + email: '', + phone: '', + emailVerification: false, + phoneVerification: false, + mfa: false, + targets: [], + accessedAt: '', + }, + properties: { + targets: { + items: 'target', + }, + }, + }, + target: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + userId: '', + providerType: '', + identifier: '', + expired: false, + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); + } + + /** + * Get the list of verified passkeys registered by the currently logged in user. + * + * @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). Maximum of 100 queries are allowed, each 4096 characters long. You may filter and order on the following attributes: $id, $createdAt, $updatedAt, name, accessedAt + * @param {boolean} params.total - When set to false, the total count returned will be 0 and will not be calculated. + * @throws {AppwriteException} + * @returns {Promise} + */ + listPasskeys(params?: { + queries?: string[]; + total?: boolean; + }): Promise; + /** + * Get the list of verified passkeys registered by the currently logged in user. + * + * @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). Maximum of 100 queries are allowed, each 4096 characters long. You may filter and order on the following attributes: $id, $createdAt, $updatedAt, name, accessedAt + * @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. + */ + listPasskeys( + queries?: string[], + total?: boolean, + ): Promise; + listPasskeys( + paramsOrFirst?: { queries?: string[]; total?: boolean } | string[], + ...rest: [boolean?] + ): Promise { + let params: { queries?: string[]; total?: boolean }; + + if ( + (typeof paramsOrFirst === 'undefined' && rest.length === 0) || + (paramsOrFirst && + typeof paramsOrFirst === 'object' && + !Array.isArray(paramsOrFirst)) + ) { + 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 = '/account/passkeys'; + const apiPayload: Payload = {}; + + if (typeof queries !== 'undefined') { + apiPayload['queries'] = queries; + } + + if (typeof total !== 'undefined') { + apiPayload['total'] = total; + } + + const uri = new URL(this.client.config.endpoint + apiPath); + const request = this.client.call( + 'get', + uri, + { + 'X-Appwrite-Project': this.client.config.project, + accept: 'application/json', + }, + apiPayload, + ); + const defaults = { + root: 'passkeyList', + models: { + passkeyList: { + defaults: { + total: 0, + passkeys: [], + }, + properties: { + passkeys: { + items: 'passkey', + }, + }, + }, + passkey: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + accessedAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); + } + + /** + * Start registering a passkey for the currently logged in user. The session must have signed in or completed an MFA challenge within the last 10 minutes. Pass the returned `publicKey` options to `navigator.credentials.create()`, then complete the registration with [Update passkey verification](/docs/references/cloud/client-web/account#updatePasskeyVerification). The passkey stays pending until verified, and the challenge expires after 5 minutes. + * + * @param {string} params.passkeyId - Passkey 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. + * @param {string} params.name - Passkey name, shown when listing passkeys. Max length: 128 chars. + * @throws {AppwriteException} + * @returns {Promise} + */ + createPasskey(params?: { + passkeyId?: string; + name?: string; + }): Promise; + /** + * Start registering a passkey for the currently logged in user. The session must have signed in or completed an MFA challenge within the last 10 minutes. Pass the returned `publicKey` options to `navigator.credentials.create()`, then complete the registration with [Update passkey verification](/docs/references/cloud/client-web/account#updatePasskeyVerification). The passkey stays pending until verified, and the challenge expires after 5 minutes. + * + * @param {string} passkeyId - Passkey 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. + * @param {string} name - Passkey name, shown when listing passkeys. Max length: 128 chars. + * @throws {AppwriteException} + * @returns {Promise} + * @deprecated Use the object parameter style method for a better developer experience. + */ + createPasskey( + passkeyId?: string, + name?: string, + ): Promise; + createPasskey( + paramsOrFirst?: { passkeyId?: string; name?: string } | string, + ...rest: [string?] + ): Promise { + let params: { passkeyId?: string; name?: string }; + + if ( + (typeof paramsOrFirst === 'undefined' && rest.length === 0) || + (paramsOrFirst && + typeof paramsOrFirst === 'object' && + !Array.isArray(paramsOrFirst)) + ) { + params = (paramsOrFirst || {}) as { + passkeyId?: string; + name?: string; + }; + } else { + params = { + passkeyId: paramsOrFirst as string, + name: rest[0] as string, + }; + } + + const passkeyId = params.passkeyId; + const name = params.name; + + const apiPath = '/account/passkeys'; + const apiPayload: Payload = {}; + + if (typeof passkeyId !== 'undefined') { + apiPayload['passkeyId'] = passkeyId; + } + + if (typeof name !== 'undefined') { + apiPayload['name'] = name; + } + + const uri = new URL(this.client.config.endpoint + apiPath); + const request = this.client.call( + 'post', + uri, + { + 'X-Appwrite-Project': this.client.config.project, + 'content-type': 'application/json', + accept: 'application/json', + }, + apiPayload, + ); + const defaults = { + root: 'passkeyChallenge', + models: { + passkeyChallenge: { + defaults: { + $id: '', + $createdAt: '', + passkeyId: '', + expire: '', + publicKey: {}, + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); + } + + /** + * Get a verified passkey of the currently logged in user by its unique ID. + * + * @param {string} params.passkeyId - Passkey ID. + * @throws {AppwriteException} + * @returns {Promise} + */ + getPasskey(params: { passkeyId: string }): Promise; + /** + * Get a verified passkey of the currently logged in user by its unique ID. + * + * @param {string} passkeyId - Passkey ID. + * @throws {AppwriteException} + * @returns {Promise} + * @deprecated Use the object parameter style method for a better developer experience. + */ + getPasskey(passkeyId: string): Promise; + getPasskey( + paramsOrFirst: { passkeyId: string } | string, + ): Promise { + let params: { passkeyId: string }; + + if ( + paramsOrFirst && + typeof paramsOrFirst === 'object' && + !Array.isArray(paramsOrFirst) + ) { + params = (paramsOrFirst || {}) as { passkeyId: string }; + } else { + params = { + passkeyId: paramsOrFirst as string, + }; + } + + const passkeyId = params.passkeyId; + + if (typeof passkeyId === 'undefined' || passkeyId === '') { + throw new AppwriteException( + 'Missing required parameter: "passkeyId"', + ); + } + + const apiPath = '/account/passkeys/{passkeyId}'.replace( + '{passkeyId}', + encodeURIComponent(String(passkeyId)), + ); + const apiPayload: Payload = {}; + + const uri = new URL(this.client.config.endpoint + apiPath); + const request = this.client.call( + 'get', + uri, + { + 'X-Appwrite-Project': this.client.config.project, + accept: 'application/json', + }, + apiPayload, + ); + const defaults = { + root: 'passkey', + models: { + passkey: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + accessedAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); + } + + /** + * Rename a passkey of the currently logged in user. + * + * @param {string} params.passkeyId - Passkey ID. + * @param {string} params.name - Passkey name. Max length: 128 chars. + * @throws {AppwriteException} + * @returns {Promise} + */ + updatePasskey(params: { + passkeyId: string; + name: string; + }): Promise; + /** + * Rename a passkey of the currently logged in user. + * + * @param {string} passkeyId - Passkey ID. + * @param {string} name - Passkey name. Max length: 128 chars. + * @throws {AppwriteException} + * @returns {Promise} + * @deprecated Use the object parameter style method for a better developer experience. + */ + updatePasskey(passkeyId: string, name: string): Promise; + updatePasskey( + paramsOrFirst: { passkeyId: string; name: string } | string, + ...rest: [string?] + ): Promise { + let params: { passkeyId: string; name: string }; + + if ( + paramsOrFirst && + typeof paramsOrFirst === 'object' && + !Array.isArray(paramsOrFirst) + ) { + params = (paramsOrFirst || {}) as { + passkeyId: string; + name: string; + }; + } else { + params = { + passkeyId: paramsOrFirst as string, + name: rest[0] as string, + }; + } + + const passkeyId = params.passkeyId; + const name = params.name; + + if (typeof passkeyId === 'undefined' || passkeyId === '') { + throw new AppwriteException( + 'Missing required parameter: "passkeyId"', + ); + } + + if (typeof name === 'undefined') { + throw new AppwriteException('Missing required parameter: "name"'); + } + + const apiPath = '/account/passkeys/{passkeyId}'.replace( + '{passkeyId}', + encodeURIComponent(String(passkeyId)), + ); + const apiPayload: Payload = {}; + + if (typeof name !== 'undefined') { + apiPayload['name'] = name; + } + + const uri = new URL(this.client.config.endpoint + apiPath); + const request = this.client.call( + 'patch', + uri, + { + 'X-Appwrite-Project': this.client.config.project, + 'content-type': 'application/json', + accept: 'application/json', + }, + apiPayload, + ); + const defaults = { + root: 'passkey', + models: { + passkey: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + accessedAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); + } + + /** + * Delete a passkey from the currently logged in user. The passkey can no longer be used to sign in, although it may remain stored on the user's device. The session must have signed in or completed an MFA challenge within the last 10 minutes. + * + * @param {string} params.passkeyId - Passkey ID. + * @throws {AppwriteException} + * @returns {Promise} + */ + deletePasskey(params: { passkeyId: string }): Promise<{}>; + /** + * Delete a passkey from the currently logged in user. The passkey can no longer be used to sign in, although it may remain stored on the user's device. The session must have signed in or completed an MFA challenge within the last 10 minutes. + * + * @param {string} passkeyId - Passkey ID. + * @throws {AppwriteException} + * @returns {Promise<{}>} + * @deprecated Use the object parameter style method for a better developer experience. + */ + deletePasskey(passkeyId: string): Promise<{}>; + deletePasskey(paramsOrFirst: { passkeyId: string } | string): Promise<{}> { + let params: { passkeyId: string }; + + if ( + paramsOrFirst && + typeof paramsOrFirst === 'object' && + !Array.isArray(paramsOrFirst) + ) { + params = (paramsOrFirst || {}) as { passkeyId: string }; + } else { + params = { + passkeyId: paramsOrFirst as string, + }; + } + + const passkeyId = params.passkeyId; + + if (typeof passkeyId === 'undefined' || passkeyId === '') { + throw new AppwriteException( + 'Missing required parameter: "passkeyId"', + ); + } + + const apiPath = '/account/passkeys/{passkeyId}'.replace( + '{passkeyId}', + encodeURIComponent(String(passkeyId)), + ); + const apiPayload: Payload = {}; + const uri = new URL(this.client.config.endpoint + apiPath); return this.client.call( - 'patch', + 'delete', uri, { 'X-Appwrite-Project': this.client.config.project, @@ -1847,61 +3030,80 @@ export class Account extends Service { } /** - * Update currently logged in user account name. + * Complete a passkey registration started with [Create passkey](/docs/references/cloud/client-web/account#createPasskey). Pass the JSON form of the credential returned by `navigator.credentials.create()`, for example `credential.toJSON()`. Each registration can be verified once; a failed attempt requires starting it again. * - * @param {string} params.name - User name. Max length: 128 chars. + * @param {string} params.passkeyId - Passkey ID. + * @param {object} params.credential - Registration credential returned by the authenticator, in the JSON form produced by `PublicKeyCredential.toJSON()`. * @throws {AppwriteException} * @returns {Promise} */ - updateName< - Preferences extends Models.Preferences = Models.DefaultPreferences, - >(params: { name: string }): Promise>; + updatePasskeyVerification(params: { + passkeyId: string; + credential: object; + }): Promise; /** - * Update currently logged in user account name. + * Complete a passkey registration started with [Create passkey](/docs/references/cloud/client-web/account#createPasskey). Pass the JSON form of the credential returned by `navigator.credentials.create()`, for example `credential.toJSON()`. Each registration can be verified once; a failed attempt requires starting it again. * - * @param {string} name - User name. Max length: 128 chars. + * @param {string} passkeyId - Passkey ID. + * @param {object} credential - Registration credential returned by the authenticator, in the JSON form produced by `PublicKeyCredential.toJSON()`. * @throws {AppwriteException} - * @returns {Promise>} + * @returns {Promise} * @deprecated Use the object parameter style method for a better developer experience. */ - updateName< - Preferences extends Models.Preferences = Models.DefaultPreferences, - >(name: string): Promise>; - updateName< - Preferences extends Models.Preferences = Models.DefaultPreferences, - >( - paramsOrFirst: { name: string } | string, - ): Promise> { - let params: { name: string }; + updatePasskeyVerification( + passkeyId: string, + credential: object, + ): Promise; + updatePasskeyVerification( + paramsOrFirst: { passkeyId: string; credential: object } | string, + ...rest: [object?] + ): Promise { + let params: { passkeyId: string; credential: object }; if ( paramsOrFirst && typeof paramsOrFirst === 'object' && !Array.isArray(paramsOrFirst) ) { - params = (paramsOrFirst || {}) as { name: string }; + params = (paramsOrFirst || {}) as { + passkeyId: string; + credential: object; + }; } else { params = { - name: paramsOrFirst as string, + passkeyId: paramsOrFirst as string, + credential: rest[0] as object, }; } - const name = params.name; + const passkeyId = params.passkeyId; + const credential = params.credential; - if (typeof name === 'undefined') { - throw new AppwriteException('Missing required parameter: "name"'); + if (typeof passkeyId === 'undefined' || passkeyId === '') { + throw new AppwriteException( + 'Missing required parameter: "passkeyId"', + ); } - const apiPath = '/account/name'; + if (typeof credential === 'undefined') { + throw new AppwriteException( + 'Missing required parameter: "credential"', + ); + } + + const apiPath = '/account/passkeys/{passkeyId}/verification'.replace( + '{passkeyId}', + encodeURIComponent(String(passkeyId)), + ); const apiPayload: Payload = {}; - if (typeof name !== 'undefined') { - apiPayload['name'] = name; + if (typeof credential !== 'undefined') { + apiPayload['credential'] = credential; } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( - 'patch', + const request = this.client.call( + 'put', uri, { 'X-Appwrite-Project': this.client.config.project, @@ -1910,6 +3112,22 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'passkey', + models: { + passkey: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + accessedAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1986,7 +3204,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'patch', uri, { @@ -1996,6 +3214,49 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'user', + models: { + user: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + registration: '', + status: true, + labels: [], + passwordUpdate: '', + email: '', + phone: '', + emailVerification: false, + phoneVerification: false, + mfa: false, + targets: [], + accessedAt: '', + }, + properties: { + targets: { + items: 'target', + }, + }, + }, + target: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + userId: '', + providerType: '', + identifier: '', + expired: false, + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -2073,7 +3334,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'patch', uri, { @@ -2083,6 +3344,49 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'user', + models: { + user: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + registration: '', + status: true, + labels: [], + passwordUpdate: '', + email: '', + phone: '', + emailVerification: false, + phoneVerification: false, + mfa: false, + targets: [], + accessedAt: '', + }, + properties: { + targets: { + items: 'target', + }, + }, + }, + target: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + userId: '', + providerType: '', + identifier: '', + expired: false, + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -2166,7 +3470,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'patch', uri, { @@ -2176,6 +3480,49 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'user', + models: { + user: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + registration: '', + status: true, + labels: [], + passwordUpdate: '', + email: '', + phone: '', + emailVerification: false, + phoneVerification: false, + mfa: false, + targets: [], + accessedAt: '', + }, + properties: { + targets: { + items: 'target', + }, + }, + }, + target: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + userId: '', + providerType: '', + identifier: '', + expired: false, + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -2242,7 +3589,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -2252,6 +3599,23 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'token', + models: { + token: { + defaults: { + $id: '', + $createdAt: '', + userId: '', + secret: '', + expire: '', + phrase: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -2346,7 +3710,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'put', uri, { @@ -2356,6 +3720,23 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'token', + models: { + token: { + defaults: { + $id: '', + $createdAt: '', + userId: '', + secret: '', + expire: '', + phrase: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -2427,7 +3808,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -2437,6 +3818,23 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'token', + models: { + token: { + defaults: { + $id: '', + $createdAt: '', + userId: '', + secret: '', + expire: '', + phrase: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -2529,7 +3927,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'put', uri, { @@ -2539,6 +3937,23 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'token', + models: { + token: { + defaults: { + $id: '', + $createdAt: '', + userId: '', + secret: '', + expire: '', + phrase: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -2586,7 +4001,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -2595,6 +4010,57 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'sessionList', + models: { + sessionList: { + defaults: { + total: 0, + sessions: [], + }, + properties: { + sessions: { + items: 'session', + }, + }, + }, + session: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + userId: '', + expire: '', + provider: '', + providerUid: '', + providerAccessToken: '', + providerAccessTokenExpiry: '', + providerRefreshToken: '', + ip: '', + osCode: '', + osName: '', + osVersion: '', + clientType: '', + clientCode: '', + clientName: '', + clientVersion: '', + clientEngine: '', + clientEngineVersion: '', + deviceName: '', + deviceBrand: '', + deviceModel: '', + countryCode: '', + countryName: '', + current: false, + factors: [], + secret: '', + mfaUpdatedAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -2665,7 +4131,7 @@ export class Account extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -2675,6 +4141,46 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'session', + models: { + session: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + userId: '', + expire: '', + provider: '', + providerUid: '', + providerAccessToken: '', + providerAccessTokenExpiry: '', + providerRefreshToken: '', + ip: '', + osCode: '', + osName: '', + osVersion: '', + clientType: '', + clientCode: '', + clientName: '', + clientVersion: '', + clientEngine: '', + clientEngineVersion: '', + deviceName: '', + deviceBrand: '', + deviceModel: '', + countryCode: '', + countryName: '', + current: false, + factors: [], + secret: '', + mfaUpdatedAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -2684,14 +4190,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. + * @param {number | null} 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; + duration?: number | null; }): 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. Use the optional `duration` parameter to create a shorter session, for example when the user doesn't choose "remember me". It must be at least 60 seconds and cannot exceed the project maximum session length. @@ -2700,7 +4206,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. + * @param {number | null} 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. @@ -2708,14 +4214,19 @@ export class Account extends Service { createEmailPasswordSession( email: string, password: string, - duration?: number, + duration?: number | null, ): Promise; createEmailPasswordSession( paramsOrFirst: - { email: string; password: string; duration?: number } | string, - ...rest: [string?, number?] + | { email: string; password: string; duration?: number | null } + | string, + ...rest: [string?, (number | null)?] ): Promise { - let params: { email: string; password: string; duration?: number }; + let params: { + email: string; + password: string; + duration?: number | null; + }; if ( paramsOrFirst && @@ -2725,13 +4236,13 @@ export class Account extends Service { params = (paramsOrFirst || {}) as { email: string; password: string; - duration?: number; + duration?: number | null; }; } else { params = { email: paramsOrFirst as string, password: rest[0] as string, - duration: rest[1] as number, + duration: rest[1] as number | null, }; } @@ -2765,7 +4276,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -2775,6 +4286,46 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'session', + models: { + session: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + userId: '', + expire: '', + provider: '', + providerUid: '', + providerAccessToken: '', + providerAccessTokenExpiry: '', + providerRefreshToken: '', + ip: '', + osCode: '', + osName: '', + osVersion: '', + clientType: '', + clientCode: '', + clientName: '', + clientVersion: '', + clientEngine: '', + clientEngineVersion: '', + deviceName: '', + deviceBrand: '', + deviceModel: '', + countryCode: '', + countryName: '', + current: false, + factors: [], + secret: '', + mfaUpdatedAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -2939,7 +4490,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -2949,6 +4500,46 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'session', + models: { + session: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + userId: '', + expire: '', + provider: '', + providerUid: '', + providerAccessToken: '', + providerAccessTokenExpiry: '', + providerRefreshToken: '', + ip: '', + osCode: '', + osName: '', + osVersion: '', + clientType: '', + clientCode: '', + clientName: '', + clientVersion: '', + clientEngine: '', + clientEngineVersion: '', + deviceName: '', + deviceBrand: '', + deviceModel: '', + countryCode: '', + countryName: '', + current: false, + factors: [], + secret: '', + mfaUpdatedAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -3022,7 +4613,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'put', uri, { @@ -3032,6 +4623,46 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'session', + models: { + session: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + userId: '', + expire: '', + provider: '', + providerUid: '', + providerAccessToken: '', + providerAccessTokenExpiry: '', + providerRefreshToken: '', + ip: '', + osCode: '', + osName: '', + osVersion: '', + clientType: '', + clientCode: '', + clientName: '', + clientVersion: '', + clientEngine: '', + clientEngineVersion: '', + deviceName: '', + deviceBrand: '', + deviceModel: '', + countryCode: '', + countryName: '', + current: false, + factors: [], + secret: '', + mfaUpdatedAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -3046,6 +4677,7 @@ export class Account extends Service { * @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} */ @@ -3054,6 +4686,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. @@ -3067,6 +4700,7 @@ export class Account extends Service { * @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. @@ -3076,6 +4710,7 @@ export class Account extends Service { success?: string, failure?: string, scopes?: string[], + state?: string, ): void | URL; createOAuth2Session( paramsOrFirst: @@ -3084,15 +4719,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 ( @@ -3102,13 +4739,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 = { @@ -3116,6 +4755,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, }; } @@ -3123,6 +4763,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( @@ -3148,6 +4789,10 @@ export class Account extends Service { apiPayload['scopes'] = scopes; } + if (typeof state !== 'undefined') { + apiPayload['state'] = state; + } + const uri = new URL(this.client.config.endpoint + apiPath); apiPayload['project'] = this.client.config.project; @@ -3227,7 +4872,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'put', uri, { @@ -3237,6 +4882,46 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'session', + models: { + session: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + userId: '', + expire: '', + provider: '', + providerUid: '', + providerAccessToken: '', + providerAccessTokenExpiry: '', + providerRefreshToken: '', + ip: '', + osCode: '', + osName: '', + osVersion: '', + clientType: '', + clientCode: '', + clientName: '', + clientVersion: '', + clientEngine: '', + clientEngineVersion: '', + deviceName: '', + deviceBrand: '', + deviceModel: '', + countryCode: '', + countryName: '', + current: false, + factors: [], + secret: '', + mfaUpdatedAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -3306,7 +4991,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -3316,6 +5001,46 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'session', + models: { + session: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + userId: '', + expire: '', + provider: '', + providerUid: '', + providerAccessToken: '', + providerAccessTokenExpiry: '', + providerRefreshToken: '', + ip: '', + osCode: '', + osName: '', + osVersion: '', + clientType: '', + clientCode: '', + clientName: '', + clientVersion: '', + clientEngine: '', + clientEngineVersion: '', + deviceName: '', + deviceBrand: '', + deviceModel: '', + countryCode: '', + countryName: '', + current: false, + factors: [], + secret: '', + mfaUpdatedAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -3367,7 +5092,7 @@ export class Account extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -3376,6 +5101,46 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'session', + models: { + session: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + userId: '', + expire: '', + provider: '', + providerUid: '', + providerAccessToken: '', + providerAccessTokenExpiry: '', + providerRefreshToken: '', + ip: '', + osCode: '', + osName: '', + osVersion: '', + clientType: '', + clientCode: '', + clientName: '', + clientVersion: '', + clientEngine: '', + clientEngineVersion: '', + deviceName: '', + deviceBrand: '', + deviceModel: '', + countryCode: '', + countryName: '', + current: false, + factors: [], + secret: '', + mfaUpdatedAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -3427,7 +5192,7 @@ export class Account extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'patch', uri, { @@ -3437,6 +5202,46 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'session', + models: { + session: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + userId: '', + expire: '', + provider: '', + providerUid: '', + providerAccessToken: '', + providerAccessTokenExpiry: '', + providerRefreshToken: '', + ip: '', + osCode: '', + osName: '', + osVersion: '', + clientType: '', + clientCode: '', + clientName: '', + clientVersion: '', + clientEngine: '', + clientEngineVersion: '', + deviceName: '', + deviceBrand: '', + deviceModel: '', + countryCode: '', + countryName: '', + current: false, + factors: [], + secret: '', + mfaUpdatedAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -3511,7 +5316,7 @@ export class Account extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'patch', uri, { @@ -3521,6 +5326,49 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'user', + models: { + user: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + registration: '', + status: true, + labels: [], + passwordUpdate: '', + email: '', + phone: '', + emailVerification: false, + phoneVerification: false, + mfa: false, + targets: [], + accessedAt: '', + }, + properties: { + targets: { + items: 'target', + }, + }, + }, + target: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + userId: '', + providerType: '', + identifier: '', + expired: false, + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -3614,7 +5462,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -3624,6 +5472,25 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'target', + models: { + target: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + userId: '', + providerType: '', + identifier: '', + expired: false, + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -3699,7 +5566,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'put', uri, { @@ -3709,6 +5576,25 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'target', + models: { + target: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + userId: '', + providerType: '', + identifier: '', + expired: false, + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -3860,7 +5746,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -3870,6 +5756,23 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'token', + models: { + token: { + defaults: { + $id: '', + $createdAt: '', + userId: '', + secret: '', + expire: '', + phrase: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -3977,7 +5880,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -3987,6 +5890,23 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'token', + models: { + token: { + defaults: { + $id: '', + $createdAt: '', + userId: '', + secret: '', + expire: '', + phrase: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -4002,6 +5922,7 @@ export class Account extends Service { * @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} */ @@ -4010,6 +5931,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. @@ -4024,6 +5946,7 @@ export class Account extends Service { * @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. @@ -4033,6 +5956,7 @@ export class Account extends Service { success?: string, failure?: string, scopes?: string[], + state?: string, ): void | URL; createOAuth2Token( paramsOrFirst: @@ -4041,15 +5965,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 ( @@ -4059,13 +5985,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 = { @@ -4073,6 +6001,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, }; } @@ -4080,6 +6009,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( @@ -4105,6 +6035,10 @@ export class Account extends Service { apiPayload['scopes'] = scopes; } + if (typeof state !== 'undefined') { + apiPayload['state'] = state; + } + const uri = new URL(this.client.config.endpoint + apiPath); apiPayload['project'] = this.client.config.project; @@ -4116,6 +6050,148 @@ export class Account extends Service { return uri; } + /** + * Start signing in with a passkey. No email or user ID is needed: pass the returned `publicKey` options to `navigator.credentials.get()` and the user picks one of their passkeys. Then call [Update passkey token](/docs/references/cloud/client-web/account#updatePasskeyToken) with the credential to receive a token, and exchange it with [Create session](/docs/references/cloud/client-web/account#createSession). The challenge expires after 5 minutes. + * + * @throws {AppwriteException} + * @returns {Promise} + */ + createPasskeyToken(): Promise { + const apiPath = '/account/tokens/passkey'; + const apiPayload: Payload = {}; + + const uri = new URL(this.client.config.endpoint + apiPath); + const request = this.client.call( + 'post', + uri, + { + 'X-Appwrite-Project': this.client.config.project, + 'content-type': 'application/json', + accept: 'application/json', + }, + apiPayload, + ); + const defaults = { + root: 'passkeyChallenge', + models: { + passkeyChallenge: { + defaults: { + $id: '', + $createdAt: '', + passkeyId: '', + expire: '', + publicKey: {}, + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); + } + + /** + * Complete a passkey sign-in started with [Create passkey token](/docs/references/cloud/client-web/account#createPasskeyToken). Pass the challenge ID and the JSON form of the credential returned by `navigator.credentials.get()`, for example `credential.toJSON()`. The returned token includes its secret and expires after 1 minute: exchange it for a session with [Create session](/docs/references/cloud/client-web/account#createSession). Passkeys require user verification, so the session also satisfies MFA. Each challenge can only be used once. + * + * @param {string} params.challengeId - Challenge ID returned by createPasskeyToken. + * @param {object} params.credential - Authentication credential returned by the authenticator, in the JSON form produced by `PublicKeyCredential.toJSON()`. + * @throws {AppwriteException} + * @returns {Promise} + */ + updatePasskeyToken(params: { + challengeId: string; + credential: object; + }): Promise; + /** + * Complete a passkey sign-in started with [Create passkey token](/docs/references/cloud/client-web/account#createPasskeyToken). Pass the challenge ID and the JSON form of the credential returned by `navigator.credentials.get()`, for example `credential.toJSON()`. The returned token includes its secret and expires after 1 minute: exchange it for a session with [Create session](/docs/references/cloud/client-web/account#createSession). Passkeys require user verification, so the session also satisfies MFA. Each challenge can only be used once. + * + * @param {string} challengeId - Challenge ID returned by createPasskeyToken. + * @param {object} credential - Authentication credential returned by the authenticator, in the JSON form produced by `PublicKeyCredential.toJSON()`. + * @throws {AppwriteException} + * @returns {Promise} + * @deprecated Use the object parameter style method for a better developer experience. + */ + updatePasskeyToken( + challengeId: string, + credential: object, + ): Promise; + updatePasskeyToken( + paramsOrFirst: { challengeId: string; credential: object } | string, + ...rest: [object?] + ): Promise { + let params: { challengeId: string; credential: object }; + + if ( + paramsOrFirst && + typeof paramsOrFirst === 'object' && + !Array.isArray(paramsOrFirst) + ) { + params = (paramsOrFirst || {}) as { + challengeId: string; + credential: object; + }; + } else { + params = { + challengeId: paramsOrFirst as string, + credential: rest[0] as object, + }; + } + + const challengeId = params.challengeId; + const credential = params.credential; + + if (typeof challengeId === 'undefined') { + throw new AppwriteException( + 'Missing required parameter: "challengeId"', + ); + } + + if (typeof credential === 'undefined') { + throw new AppwriteException( + 'Missing required parameter: "credential"', + ); + } + + const apiPath = '/account/tokens/passkey'; + const apiPayload: Payload = {}; + + if (typeof challengeId !== 'undefined') { + apiPayload['challengeId'] = challengeId; + } + + if (typeof credential !== 'undefined') { + apiPayload['credential'] = credential; + } + + const uri = new URL(this.client.config.endpoint + apiPath); + const request = this.client.call( + 'put', + uri, + { + 'X-Appwrite-Project': this.client.config.project, + 'content-type': 'application/json', + accept: 'application/json', + }, + apiPayload, + ); + const defaults = { + root: 'tokenSecret', + models: { + tokenSecret: { + defaults: { + $id: '', + $createdAt: '', + userId: '', + secret: '', + expire: '', + phrase: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); + } + /** * Sends the user an SMS with a secret key for creating a session. If the provided user ID has not be registered, a new user will be created. Use the returned user ID and secret and submit a request to the [POST /v1/account/sessions/token](https://appwrite.io/docs/references/cloud/client-web/account#createSession) endpoint to complete the login process. The secret sent to the user's phone is valid for 15 minutes. * @@ -4184,7 +6260,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -4194,6 +6270,23 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'token', + models: { + token: { + defaults: { + $id: '', + $createdAt: '', + userId: '', + secret: '', + expire: '', + phrase: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -4250,7 +6343,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -4260,6 +6353,23 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'token', + models: { + token: { + defaults: { + $id: '', + $createdAt: '', + userId: '', + secret: '', + expire: '', + phrase: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -4317,7 +6427,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -4327,6 +6437,23 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'token', + models: { + token: { + defaults: { + $id: '', + $createdAt: '', + userId: '', + secret: '', + expire: '', + phrase: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -4399,7 +6526,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'put', uri, { @@ -4409,6 +6536,23 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'token', + models: { + token: { + defaults: { + $id: '', + $createdAt: '', + userId: '', + secret: '', + expire: '', + phrase: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -4479,7 +6623,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'put', uri, { @@ -4489,6 +6633,23 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'token', + models: { + token: { + defaults: { + $id: '', + $createdAt: '', + userId: '', + secret: '', + expire: '', + phrase: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -4544,7 +6705,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -4554,6 +6715,23 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'token', + models: { + token: { + defaults: { + $id: '', + $createdAt: '', + userId: '', + secret: '', + expire: '', + phrase: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -4628,7 +6806,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'put', uri, { @@ -4638,6 +6816,23 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'token', + models: { + token: { + defaults: { + $id: '', + $createdAt: '', + userId: '', + secret: '', + expire: '', + phrase: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -4651,7 +6846,7 @@ export class Account extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -4661,6 +6856,23 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'token', + models: { + token: { + defaults: { + $id: '', + $createdAt: '', + userId: '', + secret: '', + expire: '', + phrase: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -4733,7 +6945,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'put', uri, { @@ -4743,5 +6955,22 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'token', + models: { + token: { + defaults: { + $id: '', + $createdAt: '', + userId: '', + secret: '', + expire: '', + phrase: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } } 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/apps.ts b/src/services/apps.ts index 02554ba4..896038d7 100644 --- a/src/services/apps.ts +++ b/src/services/apps.ts @@ -1,5 +1,5 @@ import { Service } from '../service'; -import { AppwriteException, Client } from '../client'; +import { AppwriteException, Client, applyDefaults } from '../client'; import type { Models } from '../models'; import type { Payload } from '../client'; @@ -68,7 +68,7 @@ export class Apps extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -77,6 +77,71 @@ export class Apps extends Service { }, apiPayload, ); + const defaults = { + root: 'appsList', + models: { + appsList: { + defaults: { + total: 0, + apps: [], + }, + properties: { + apps: { + items: 'app', + }, + }, + }, + app: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + description: '', + clientUri: '', + logoUri: '', + privacyPolicyUrl: '', + termsUrl: '', + contacts: [], + tagline: '', + tags: [], + labels: [], + images: [], + supportUrl: '', + dataDeletionUrl: '', + redirectUris: [], + postLogoutRedirectUris: [], + enabled: true, + type: 'confidential', + deviceFlow: false, + teamId: '', + userId: '', + installationScopes: [], + installationRedirectUrl: '', + secrets: [], + }, + properties: { + secrets: { + items: 'appSecret', + }, + }, + }, + appSecret: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + appId: '', + secret: '', + hint: '', + createdById: '', + createdByName: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -403,7 +468,7 @@ export class Apps extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -413,6 +478,60 @@ export class Apps extends Service { }, apiPayload, ); + const defaults = { + root: 'app', + models: { + app: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + description: '', + clientUri: '', + logoUri: '', + privacyPolicyUrl: '', + termsUrl: '', + contacts: [], + tagline: '', + tags: [], + labels: [], + images: [], + supportUrl: '', + dataDeletionUrl: '', + redirectUris: [], + postLogoutRedirectUris: [], + enabled: true, + type: 'confidential', + deviceFlow: false, + teamId: '', + userId: '', + installationScopes: [], + installationRedirectUrl: '', + secrets: [], + }, + properties: { + secrets: { + items: 'appSecret', + }, + }, + }, + appSecret: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + appId: '', + secret: '', + hint: '', + createdById: '', + createdByName: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -426,7 +545,7 @@ export class Apps extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -435,6 +554,33 @@ export class Apps extends Service { }, apiPayload, ); + const defaults = { + root: 'appScopeList', + models: { + appScopeList: { + defaults: { + total: 0, + scopes: [], + }, + properties: { + scopes: { + items: 'appScope', + }, + }, + }, + appScope: { + defaults: { + value: '', + description: '', + type: '', + category: '', + deprecated: false, + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -448,7 +594,7 @@ export class Apps extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -457,6 +603,33 @@ export class Apps extends Service { }, apiPayload, ); + const defaults = { + root: 'appScopeList', + models: { + appScopeList: { + defaults: { + total: 0, + scopes: [], + }, + properties: { + scopes: { + items: 'appScope', + }, + }, + }, + appScope: { + defaults: { + value: '', + description: '', + type: '', + category: '', + deprecated: false, + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -504,7 +677,7 @@ export class Apps extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -513,6 +686,60 @@ export class Apps extends Service { }, apiPayload, ); + const defaults = { + root: 'app', + models: { + app: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + description: '', + clientUri: '', + logoUri: '', + privacyPolicyUrl: '', + termsUrl: '', + contacts: [], + tagline: '', + tags: [], + labels: [], + images: [], + supportUrl: '', + dataDeletionUrl: '', + redirectUris: [], + postLogoutRedirectUris: [], + enabled: true, + type: 'confidential', + deviceFlow: false, + teamId: '', + userId: '', + installationScopes: [], + installationRedirectUrl: '', + secrets: [], + }, + properties: { + secrets: { + items: 'appSecret', + }, + }, + }, + appSecret: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + appId: '', + secret: '', + hint: '', + createdById: '', + createdByName: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -846,7 +1073,7 @@ export class Apps extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'put', uri, { @@ -856,6 +1083,60 @@ export class Apps extends Service { }, apiPayload, ); + const defaults = { + root: 'app', + models: { + app: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + description: '', + clientUri: '', + logoUri: '', + privacyPolicyUrl: '', + termsUrl: '', + contacts: [], + tagline: '', + tags: [], + labels: [], + images: [], + supportUrl: '', + dataDeletionUrl: '', + redirectUris: [], + postLogoutRedirectUris: [], + enabled: true, + type: 'confidential', + deviceFlow: false, + teamId: '', + userId: '', + installationScopes: [], + installationRedirectUrl: '', + secrets: [], + }, + properties: { + secrets: { + items: 'appSecret', + }, + }, + }, + appSecret: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + appId: '', + secret: '', + hint: '', + createdById: '', + createdByName: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -992,7 +1273,7 @@ export class Apps extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -1001,6 +1282,37 @@ export class Apps extends Service { }, apiPayload, ); + const defaults = { + root: 'appInstallationList', + models: { + appInstallationList: { + defaults: { + total: 0, + installations: [], + }, + properties: { + installations: { + items: 'appInstallation', + }, + }, + }, + appInstallation: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + appId: '', + teamId: '', + scopes: [], + authorizationDetails: [], + createdById: '', + createdByName: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1072,7 +1384,7 @@ export class Apps extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -1081,6 +1393,26 @@ export class Apps extends Service { }, apiPayload, ); + const defaults = { + root: 'appInstallation', + models: { + appInstallation: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + appId: '', + teamId: '', + scopes: [], + authorizationDetails: [], + createdById: '', + createdByName: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1230,7 +1562,7 @@ export class Apps extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -1240,6 +1572,22 @@ export class Apps extends Service { }, apiPayload, ); + const defaults = { + root: 'oauth2Token', + models: { + oauth2Token: { + defaults: { + access_token: '', + token_type: 'Bearer', + expires_in: 0, + refresh_token: '', + scope: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1319,7 +1667,7 @@ export class Apps extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -1328,6 +1676,36 @@ export class Apps extends Service { }, apiPayload, ); + const defaults = { + root: 'appKeyList', + models: { + appKeyList: { + defaults: { + total: 0, + keys: [], + }, + properties: { + keys: { + items: 'appKey', + }, + }, + }, + appKey: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + appId: '', + secret: '', + hint: '', + createdById: '', + createdByName: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1377,7 +1755,7 @@ export class Apps extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -1387,6 +1765,25 @@ export class Apps extends Service { }, apiPayload, ); + const defaults = { + root: 'appKey', + models: { + appKey: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + appId: '', + secret: '', + hint: '', + createdById: '', + createdByName: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1444,7 +1841,7 @@ export class Apps extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -1453,6 +1850,25 @@ export class Apps extends Service { }, apiPayload, ); + const defaults = { + root: 'appKey', + models: { + appKey: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + appId: '', + secret: '', + hint: '', + createdById: '', + createdByName: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1599,7 +2015,7 @@ export class Apps extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -1608,6 +2024,36 @@ export class Apps extends Service { }, apiPayload, ); + const defaults = { + root: 'appSecretList', + models: { + appSecretList: { + defaults: { + total: 0, + secrets: [], + }, + properties: { + secrets: { + items: 'appSecret', + }, + }, + }, + appSecret: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + appId: '', + secret: '', + hint: '', + createdById: '', + createdByName: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1657,7 +2103,7 @@ export class Apps extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -1667,6 +2113,25 @@ export class Apps extends Service { }, apiPayload, ); + const defaults = { + root: 'appSecretPlaintext', + models: { + appSecretPlaintext: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + appId: '', + secret: '', + hint: '', + createdById: '', + createdByName: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1732,7 +2197,7 @@ export class Apps extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -1741,6 +2206,25 @@ export class Apps extends Service { }, apiPayload, ); + const defaults = { + root: 'appSecret', + models: { + appSecret: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + appId: '', + secret: '', + hint: '', + createdById: '', + createdByName: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1875,7 +2359,7 @@ export class Apps extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'patch', uri, { @@ -1885,6 +2369,60 @@ export class Apps extends Service { }, apiPayload, ); + const defaults = { + root: 'app', + models: { + app: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + description: '', + clientUri: '', + logoUri: '', + privacyPolicyUrl: '', + termsUrl: '', + contacts: [], + tagline: '', + tags: [], + labels: [], + images: [], + supportUrl: '', + dataDeletionUrl: '', + redirectUris: [], + postLogoutRedirectUris: [], + enabled: true, + type: 'confidential', + deviceFlow: false, + teamId: '', + userId: '', + installationScopes: [], + installationRedirectUrl: '', + secrets: [], + }, + properties: { + secrets: { + items: 'appSecret', + }, + }, + }, + appSecret: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + appId: '', + secret: '', + hint: '', + createdById: '', + createdByName: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** diff --git a/src/services/databases.ts b/src/services/databases.ts index 94d2ad16..43e4b4a9 100644 --- a/src/services/databases.ts +++ b/src/services/databases.ts @@ -1,5 +1,5 @@ import { Service } from '../service'; -import { AppwriteException, Client } from '../client'; +import { AppwriteException, Client, applyDefaults } from '../client'; import type { Models } from '../models'; import type { Payload } from '../client'; @@ -72,7 +72,7 @@ export class Databases extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -81,6 +81,34 @@ export class Databases extends Service { }, apiPayload, ); + const defaults = { + root: 'transactionList', + models: { + transactionList: { + defaults: { + total: 0, + transactions: [], + }, + properties: { + transactions: { + items: 'transaction', + }, + }, + }, + transaction: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + status: 'pending', + operations: 0, + expiresAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -129,7 +157,7 @@ export class Databases extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -139,6 +167,23 @@ export class Databases extends Service { }, apiPayload, ); + const defaults = { + root: 'transaction', + models: { + transaction: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + status: 'pending', + operations: 0, + expiresAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -193,7 +238,7 @@ export class Databases extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -202,6 +247,23 @@ export class Databases extends Service { }, apiPayload, ); + const defaults = { + root: 'transaction', + models: { + transaction: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + status: 'pending', + operations: 0, + expiresAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -289,7 +351,7 @@ export class Databases extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'patch', uri, { @@ -299,6 +361,23 @@ export class Databases extends Service { }, apiPayload, ); + const defaults = { + root: 'transaction', + models: { + transaction: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + status: 'pending', + operations: 0, + expiresAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -433,7 +512,7 @@ export class Databases extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -443,6 +522,23 @@ export class Databases extends Service { }, apiPayload, ); + const defaults = { + root: 'transaction', + models: { + transaction: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + status: 'pending', + operations: 0, + expiresAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -580,7 +676,7 @@ export class Databases extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -589,6 +685,35 @@ export class Databases extends Service { }, apiPayload, ); + const defaults = { + root: 'documentList', + models: { + documentList: { + defaults: { + total: 0, + documents: [], + }, + properties: { + documents: { + items: 'document', + }, + }, + }, + document: { + defaults: { + $id: '', + $sequence: '', + $collectionId: '', + $databaseId: '', + $createdAt: '', + $updatedAt: '', + $permissions: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -598,8 +723,8 @@ export class Databases extends Service { * @param {string} params.collectionId - Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection). Make sure to define attributes before creating documents. * @param {string} params.documentId - Document ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars. * @param {Document extends Models.DefaultDocument ? Partial & Record : Partial & Omit} params.data - Document data as JSON object. - * @param {string[]} params.permissions - An array of permissions strings. By default, only the current user is granted all permissions. [Learn more about permissions](https://appwrite.io/docs/permissions). - * @param {string} params.transactionId - Transaction ID for staging the operation. + * @param {string[] | null} params.permissions - An array of permissions strings. By default, only the current user is granted all permissions. [Learn more about permissions](https://appwrite.io/docs/permissions). + * @param {string | null} params.transactionId - Transaction ID for staging the operation. * @throws {AppwriteException} * @returns {Promise} * @deprecated This API has been deprecated since 1.8.0. Please use `TablesDB.createRow` instead. @@ -613,8 +738,8 @@ export class Databases extends Service { data: Document extends Models.DefaultDocument ? Partial & Record : Partial & Omit; - permissions?: string[]; - transactionId?: string; + permissions?: string[] | null; + transactionId?: string | null; }): Promise; /** * Create a new Document. Before using this route, you should create a new collection resource using either a [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection) API or directly from your database console. @@ -623,8 +748,8 @@ export class Databases extends Service { * @param {string} collectionId - Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection). Make sure to define attributes before creating documents. * @param {string} documentId - Document ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars. * @param {Document extends Models.DefaultDocument ? Partial & Record : Partial & Omit} data - Document data as JSON object. - * @param {string[]} permissions - An array of permissions strings. By default, only the current user is granted all permissions. [Learn more about permissions](https://appwrite.io/docs/permissions). - * @param {string} transactionId - Transaction ID for staging the operation. + * @param {string[] | null} permissions - An array of permissions strings. By default, only the current user is granted all permissions. [Learn more about permissions](https://appwrite.io/docs/permissions). + * @param {string | null} transactionId - Transaction ID for staging the operation. * @throws {AppwriteException} * @returns {Promise} * @deprecated Use the object parameter style method for a better developer experience. @@ -636,8 +761,8 @@ export class Databases extends Service { data: Document extends Models.DefaultDocument ? Partial & Record : Partial & Omit, - permissions?: string[], - transactionId?: string, + permissions?: string[] | null, + transactionId?: string | null, ): Promise; createDocument( paramsOrFirst: @@ -649,8 +774,8 @@ export class Databases extends Service { ? Partial & Record : Partial & Omit; - permissions?: string[]; - transactionId?: string; + permissions?: string[] | null; + transactionId?: string | null; } | string, ...rest: [ @@ -660,8 +785,8 @@ export class Databases extends Service { ? Partial & Record : Partial & Omit)?, - string[]?, - string?, + (string[] | null)?, + (string | null)?, ] ): Promise { let params: { @@ -672,8 +797,8 @@ export class Databases extends Service { ? Partial & Record : Partial & Omit; - permissions?: string[]; - transactionId?: string; + permissions?: string[] | null; + transactionId?: string | null; }; if ( @@ -689,8 +814,8 @@ export class Databases extends Service { ? Partial & Record : Partial & Omit; - permissions?: string[]; - transactionId?: string; + permissions?: string[] | null; + transactionId?: string | null; }; } else { params = { @@ -701,8 +826,8 @@ export class Databases extends Service { ? Partial & Record : Partial & Omit, - permissions: rest[3] as string[], - transactionId: rest[4] as string, + permissions: rest[3] as string[] | null, + transactionId: rest[4] as string | null, }; } @@ -761,7 +886,7 @@ export class Databases extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -771,6 +896,24 @@ export class Databases extends Service { }, apiPayload, ); + const defaults = { + root: 'document', + models: { + document: { + defaults: { + $id: '', + $sequence: '', + $collectionId: '', + $databaseId: '', + $createdAt: '', + $updatedAt: '', + $permissions: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -901,7 +1044,7 @@ export class Databases extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -910,6 +1053,24 @@ export class Databases extends Service { }, apiPayload, ); + const defaults = { + root: 'document', + models: { + document: { + defaults: { + $id: '', + $sequence: '', + $collectionId: '', + $databaseId: '', + $createdAt: '', + $updatedAt: '', + $permissions: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -919,8 +1080,8 @@ export class Databases extends Service { * @param {string} params.collectionId - Collection ID. * @param {string} params.documentId - Document ID. * @param {Document extends Models.DefaultDocument ? Partial & Record : Partial & Partial>} params.data - Document data as JSON object. Include all required attributes of the document to be created or updated. - * @param {string[]} params.permissions - An array of permissions strings. By default, the current permissions are inherited. [Learn more about permissions](https://appwrite.io/docs/permissions). - * @param {string} params.transactionId - Transaction ID for staging the operation. + * @param {string[] | null} params.permissions - An array of permissions strings. By default, the current permissions are inherited. [Learn more about permissions](https://appwrite.io/docs/permissions). + * @param {string | null} params.transactionId - Transaction ID for staging the operation. * @throws {AppwriteException} * @returns {Promise} * @deprecated This API has been deprecated since 1.8.0. Please use `TablesDB.upsertRow` instead. @@ -935,8 +1096,8 @@ export class Databases extends Service { ? Partial & Record : Partial & Partial>; - permissions?: string[]; - transactionId?: string; + permissions?: string[] | null; + transactionId?: string | null; }): Promise; /** * Create or update a Document. Before using this route, you should create a new collection resource using either a [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection) API or directly from your database console. @@ -945,8 +1106,8 @@ export class Databases extends Service { * @param {string} collectionId - Collection ID. * @param {string} documentId - Document ID. * @param {Document extends Models.DefaultDocument ? Partial & Record : Partial & Partial>} data - Document data as JSON object. Include all required attributes of the document to be created or updated. - * @param {string[]} permissions - An array of permissions strings. By default, the current permissions are inherited. [Learn more about permissions](https://appwrite.io/docs/permissions). - * @param {string} transactionId - Transaction ID for staging the operation. + * @param {string[] | null} permissions - An array of permissions strings. By default, the current permissions are inherited. [Learn more about permissions](https://appwrite.io/docs/permissions). + * @param {string | null} transactionId - Transaction ID for staging the operation. * @throws {AppwriteException} * @returns {Promise} * @deprecated Use the object parameter style method for a better developer experience. @@ -959,8 +1120,8 @@ export class Databases extends Service { ? Partial & Record : Partial & Partial>, - permissions?: string[], - transactionId?: string, + permissions?: string[] | null, + transactionId?: string | null, ): Promise; upsertDocument( paramsOrFirst: @@ -972,8 +1133,8 @@ export class Databases extends Service { ? Partial & Record : Partial & Partial>; - permissions?: string[]; - transactionId?: string; + permissions?: string[] | null; + transactionId?: string | null; } | string, ...rest: [ @@ -983,8 +1144,8 @@ export class Databases extends Service { ? Partial & Record : Partial & Partial>)?, - string[]?, - string?, + (string[] | null)?, + (string | null)?, ] ): Promise { let params: { @@ -995,8 +1156,8 @@ export class Databases extends Service { ? Partial & Record : Partial & Partial>; - permissions?: string[]; - transactionId?: string; + permissions?: string[] | null; + transactionId?: string | null; }; if ( @@ -1012,8 +1173,8 @@ export class Databases extends Service { ? Partial & Record : Partial & Partial>; - permissions?: string[]; - transactionId?: string; + permissions?: string[] | null; + transactionId?: string | null; }; } else { params = { @@ -1024,8 +1185,8 @@ export class Databases extends Service { ? Partial & Record : Partial & Partial>, - permissions: rest[3] as string[], - transactionId: rest[4] as string, + permissions: rest[3] as string[] | null, + transactionId: rest[4] as string | null, }; } @@ -1080,7 +1241,7 @@ export class Databases extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'put', uri, { @@ -1090,6 +1251,24 @@ export class Databases extends Service { }, apiPayload, ); + const defaults = { + root: 'document', + models: { + document: { + defaults: { + $id: '', + $sequence: '', + $collectionId: '', + $databaseId: '', + $createdAt: '', + $updatedAt: '', + $permissions: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1099,8 +1278,8 @@ export class Databases extends Service { * @param {string} params.collectionId - Collection ID. * @param {string} params.documentId - Document ID. * @param {Document extends Models.DefaultDocument ? Partial & Record : Partial & Partial>} params.data - Document data as JSON object. Include only attribute and value pairs to be updated. - * @param {string[]} params.permissions - An array of permissions strings. By default, the current permissions are inherited. [Learn more about permissions](https://appwrite.io/docs/permissions). - * @param {string} params.transactionId - Transaction ID for staging the operation. + * @param {string[] | null} params.permissions - An array of permissions strings. By default, the current permissions are inherited. [Learn more about permissions](https://appwrite.io/docs/permissions). + * @param {string | null} params.transactionId - Transaction ID for staging the operation. * @throws {AppwriteException} * @returns {Promise} * @deprecated This API has been deprecated since 1.8.0. Please use `TablesDB.updateRow` instead. @@ -1115,8 +1294,8 @@ export class Databases extends Service { ? Partial & Record : Partial & Partial>; - permissions?: string[]; - transactionId?: string; + permissions?: string[] | null; + transactionId?: string | null; }): Promise; /** * Update a document by its unique ID. Using the patch method you can pass only specific fields that will get updated. @@ -1125,8 +1304,8 @@ export class Databases extends Service { * @param {string} collectionId - Collection ID. * @param {string} documentId - Document ID. * @param {Document extends Models.DefaultDocument ? Partial & Record : Partial & Partial>} data - Document data as JSON object. Include only attribute and value pairs to be updated. - * @param {string[]} permissions - An array of permissions strings. By default, the current permissions are inherited. [Learn more about permissions](https://appwrite.io/docs/permissions). - * @param {string} transactionId - Transaction ID for staging the operation. + * @param {string[] | null} permissions - An array of permissions strings. By default, the current permissions are inherited. [Learn more about permissions](https://appwrite.io/docs/permissions). + * @param {string | null} transactionId - Transaction ID for staging the operation. * @throws {AppwriteException} * @returns {Promise} * @deprecated Use the object parameter style method for a better developer experience. @@ -1139,8 +1318,8 @@ export class Databases extends Service { ? Partial & Record : Partial & Partial>, - permissions?: string[], - transactionId?: string, + permissions?: string[] | null, + transactionId?: string | null, ): Promise; updateDocument( paramsOrFirst: @@ -1152,8 +1331,8 @@ export class Databases extends Service { ? Partial & Record : Partial & Partial>; - permissions?: string[]; - transactionId?: string; + permissions?: string[] | null; + transactionId?: string | null; } | string, ...rest: [ @@ -1163,8 +1342,8 @@ export class Databases extends Service { ? Partial & Record : Partial & Partial>)?, - string[]?, - string?, + (string[] | null)?, + (string | null)?, ] ): Promise { let params: { @@ -1175,8 +1354,8 @@ export class Databases extends Service { ? Partial & Record : Partial & Partial>; - permissions?: string[]; - transactionId?: string; + permissions?: string[] | null; + transactionId?: string | null; }; if ( @@ -1192,8 +1371,8 @@ export class Databases extends Service { ? Partial & Record : Partial & Partial>; - permissions?: string[]; - transactionId?: string; + permissions?: string[] | null; + transactionId?: string | null; }; } else { params = { @@ -1204,8 +1383,8 @@ export class Databases extends Service { ? Partial & Record : Partial & Partial>, - permissions: rest[3] as string[], - transactionId: rest[4] as string, + permissions: rest[3] as string[] | null, + transactionId: rest[4] as string | null, }; } @@ -1260,7 +1439,7 @@ export class Databases extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'patch', uri, { @@ -1270,6 +1449,24 @@ export class Databases extends Service { }, apiPayload, ); + const defaults = { + root: 'document', + models: { + document: { + defaults: { + $id: '', + $sequence: '', + $collectionId: '', + $databaseId: '', + $createdAt: '', + $updatedAt: '', + $permissions: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1405,8 +1602,8 @@ export class Databases extends Service { * @param {string} params.documentId - Document ID. * @param {string} params.attribute - Attribute key. * @param {number} params.value - Value to increment the attribute by. The value must be a number. - * @param {number} params.min - Minimum value for the attribute. If the current value is lesser than this value, an exception will be thrown. - * @param {string} params.transactionId - Transaction ID for staging the operation. + * @param {number | null} params.min - Minimum value for the attribute. If the current value is lesser than this value, an exception will be thrown. + * @param {string | null} params.transactionId - Transaction ID for staging the operation. * @throws {AppwriteException} * @returns {Promise} * @deprecated This API has been deprecated since 1.8.0. Please use `TablesDB.decrementRowColumn` instead. @@ -1419,8 +1616,8 @@ export class Databases extends Service { documentId: string; attribute: string; value?: number; - min?: number; - transactionId?: string; + min?: number | null; + transactionId?: string | null; }): Promise; /** * Decrement a specific attribute of a document by a given value. @@ -1430,8 +1627,8 @@ export class Databases extends Service { * @param {string} documentId - Document ID. * @param {string} attribute - Attribute key. * @param {number} value - Value to increment the attribute by. The value must be a number. - * @param {number} min - Minimum value for the attribute. If the current value is lesser than this value, an exception will be thrown. - * @param {string} transactionId - Transaction ID for staging the operation. + * @param {number | null} min - Minimum value for the attribute. If the current value is lesser than this value, an exception will be thrown. + * @param {string | null} transactionId - Transaction ID for staging the operation. * @throws {AppwriteException} * @returns {Promise} * @deprecated Use the object parameter style method for a better developer experience. @@ -1444,8 +1641,8 @@ export class Databases extends Service { documentId: string, attribute: string, value?: number, - min?: number, - transactionId?: string, + min?: number | null, + transactionId?: string | null, ): Promise; decrementDocumentAttribute< Document extends Models.Document = Models.DefaultDocument, @@ -1457,11 +1654,18 @@ export class Databases extends Service { documentId: string; attribute: string; value?: number; - min?: number; - transactionId?: string; + min?: number | null; + transactionId?: string | null; } | string, - ...rest: [string?, string?, string?, number?, number?, string?] + ...rest: [ + string?, + string?, + string?, + number?, + (number | null)?, + (string | null)?, + ] ): Promise { let params: { databaseId: string; @@ -1469,8 +1673,8 @@ export class Databases extends Service { documentId: string; attribute: string; value?: number; - min?: number; - transactionId?: string; + min?: number | null; + transactionId?: string | null; }; if ( @@ -1484,8 +1688,8 @@ export class Databases extends Service { documentId: string; attribute: string; value?: number; - min?: number; - transactionId?: string; + min?: number | null; + transactionId?: string | null; }; } else { params = { @@ -1494,8 +1698,8 @@ export class Databases extends Service { documentId: rest[1] as string, attribute: rest[2] as string, value: rest[3] as number, - min: rest[4] as number, - transactionId: rest[5] as string, + min: rest[4] as number | null, + transactionId: rest[5] as string | null, }; } @@ -1555,7 +1759,7 @@ export class Databases extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'patch', uri, { @@ -1565,6 +1769,24 @@ export class Databases extends Service { }, apiPayload, ); + const defaults = { + root: 'document', + models: { + document: { + defaults: { + $id: '', + $sequence: '', + $collectionId: '', + $databaseId: '', + $createdAt: '', + $updatedAt: '', + $permissions: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1575,8 +1797,8 @@ export class Databases extends Service { * @param {string} params.documentId - Document ID. * @param {string} params.attribute - Attribute key. * @param {number} params.value - Value to increment the attribute by. The value must be a number. - * @param {number} params.max - Maximum value for the attribute. If the current value is greater than this value, an error will be thrown. - * @param {string} params.transactionId - Transaction ID for staging the operation. + * @param {number | null} params.max - Maximum value for the attribute. If the current value is greater than this value, an error will be thrown. + * @param {string | null} params.transactionId - Transaction ID for staging the operation. * @throws {AppwriteException} * @returns {Promise} * @deprecated This API has been deprecated since 1.8.0. Please use `TablesDB.incrementRowColumn` instead. @@ -1589,8 +1811,8 @@ export class Databases extends Service { documentId: string; attribute: string; value?: number; - max?: number; - transactionId?: string; + max?: number | null; + transactionId?: string | null; }): Promise; /** * Increment a specific attribute of a document by a given value. @@ -1600,8 +1822,8 @@ export class Databases extends Service { * @param {string} documentId - Document ID. * @param {string} attribute - Attribute key. * @param {number} value - Value to increment the attribute by. The value must be a number. - * @param {number} max - Maximum value for the attribute. If the current value is greater than this value, an error will be thrown. - * @param {string} transactionId - Transaction ID for staging the operation. + * @param {number | null} max - Maximum value for the attribute. If the current value is greater than this value, an error will be thrown. + * @param {string | null} transactionId - Transaction ID for staging the operation. * @throws {AppwriteException} * @returns {Promise} * @deprecated Use the object parameter style method for a better developer experience. @@ -1614,8 +1836,8 @@ export class Databases extends Service { documentId: string, attribute: string, value?: number, - max?: number, - transactionId?: string, + max?: number | null, + transactionId?: string | null, ): Promise; incrementDocumentAttribute< Document extends Models.Document = Models.DefaultDocument, @@ -1627,11 +1849,18 @@ export class Databases extends Service { documentId: string; attribute: string; value?: number; - max?: number; - transactionId?: string; + max?: number | null; + transactionId?: string | null; } | string, - ...rest: [string?, string?, string?, number?, number?, string?] + ...rest: [ + string?, + string?, + string?, + number?, + (number | null)?, + (string | null)?, + ] ): Promise { let params: { databaseId: string; @@ -1639,8 +1868,8 @@ export class Databases extends Service { documentId: string; attribute: string; value?: number; - max?: number; - transactionId?: string; + max?: number | null; + transactionId?: string | null; }; if ( @@ -1654,8 +1883,8 @@ export class Databases extends Service { documentId: string; attribute: string; value?: number; - max?: number; - transactionId?: string; + max?: number | null; + transactionId?: string | null; }; } else { params = { @@ -1664,8 +1893,8 @@ export class Databases extends Service { documentId: rest[1] as string, attribute: rest[2] as string, value: rest[3] as number, - max: rest[4] as number, - transactionId: rest[5] as string, + max: rest[4] as number | null, + transactionId: rest[5] as string | null, }; } @@ -1725,7 +1954,7 @@ export class Databases extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'patch', uri, { @@ -1735,5 +1964,23 @@ export class Databases extends Service { }, apiPayload, ); + const defaults = { + root: 'document', + models: { + document: { + defaults: { + $id: '', + $sequence: '', + $collectionId: '', + $databaseId: '', + $createdAt: '', + $updatedAt: '', + $permissions: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } } diff --git a/src/services/documents-db.ts b/src/services/documents-db.ts index 6f10966e..d43db5a9 100644 --- a/src/services/documents-db.ts +++ b/src/services/documents-db.ts @@ -1,5 +1,5 @@ import { Service } from '../service'; -import { AppwriteException, Client } from '../client'; +import { AppwriteException, Client, applyDefaults } from '../client'; import type { Models } from '../models'; import type { Payload } from '../client'; @@ -71,7 +71,7 @@ export class DocumentsDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -80,6 +80,34 @@ export class DocumentsDB extends Service { }, apiPayload, ); + const defaults = { + root: 'transactionList', + models: { + transactionList: { + defaults: { + total: 0, + transactions: [], + }, + properties: { + transactions: { + items: 'transaction', + }, + }, + }, + transaction: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + status: 'pending', + operations: 0, + expiresAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -127,7 +155,7 @@ export class DocumentsDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -137,6 +165,23 @@ export class DocumentsDB extends Service { }, apiPayload, ); + const defaults = { + root: 'transaction', + models: { + transaction: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + status: 'pending', + operations: 0, + expiresAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -190,7 +235,7 @@ export class DocumentsDB extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -199,6 +244,23 @@ export class DocumentsDB extends Service { }, apiPayload, ); + const defaults = { + root: 'transaction', + models: { + transaction: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + status: 'pending', + operations: 0, + expiresAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -285,7 +347,7 @@ export class DocumentsDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'patch', uri, { @@ -295,6 +357,23 @@ export class DocumentsDB extends Service { }, apiPayload, ); + const defaults = { + root: 'transaction', + models: { + transaction: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + status: 'pending', + operations: 0, + expiresAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -427,7 +506,7 @@ export class DocumentsDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -437,6 +516,23 @@ export class DocumentsDB extends Service { }, apiPayload, ); + const defaults = { + root: 'transaction', + models: { + transaction: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + status: 'pending', + operations: 0, + expiresAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -573,7 +669,7 @@ export class DocumentsDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -582,6 +678,35 @@ export class DocumentsDB extends Service { }, apiPayload, ); + const defaults = { + root: 'documentList', + models: { + documentList: { + defaults: { + total: 0, + documents: [], + }, + properties: { + documents: { + items: 'document', + }, + }, + }, + document: { + defaults: { + $id: '', + $sequence: '', + $collectionId: '', + $databaseId: '', + $createdAt: '', + $updatedAt: '', + $permissions: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -753,7 +878,7 @@ export class DocumentsDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -763,6 +888,24 @@ export class DocumentsDB extends Service { }, apiPayload, ); + const defaults = { + root: 'document', + models: { + document: { + defaults: { + $id: '', + $sequence: '', + $collectionId: '', + $databaseId: '', + $createdAt: '', + $updatedAt: '', + $permissions: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -879,7 +1022,7 @@ export class DocumentsDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -889,6 +1032,35 @@ export class DocumentsDB extends Service { }, apiPayload, ); + const defaults = { + root: 'documentList', + models: { + documentList: { + defaults: { + total: 0, + documents: [], + }, + properties: { + documents: { + items: 'document', + }, + }, + }, + document: { + defaults: { + $id: '', + $sequence: '', + $collectionId: '', + $databaseId: '', + $createdAt: '', + $updatedAt: '', + $permissions: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1018,7 +1190,7 @@ export class DocumentsDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -1027,6 +1199,24 @@ export class DocumentsDB extends Service { }, apiPayload, ); + const defaults = { + root: 'document', + models: { + document: { + defaults: { + $id: '', + $sequence: '', + $collectionId: '', + $databaseId: '', + $createdAt: '', + $updatedAt: '', + $permissions: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1196,7 +1386,7 @@ export class DocumentsDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'put', uri, { @@ -1206,6 +1396,24 @@ export class DocumentsDB extends Service { }, apiPayload, ); + const defaults = { + root: 'document', + models: { + document: { + defaults: { + $id: '', + $sequence: '', + $collectionId: '', + $databaseId: '', + $createdAt: '', + $updatedAt: '', + $permissions: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1375,7 +1583,7 @@ export class DocumentsDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'patch', uri, { @@ -1385,6 +1593,24 @@ export class DocumentsDB extends Service { }, apiPayload, ); + const defaults = { + root: 'document', + models: { + document: { + defaults: { + $id: '', + $sequence: '', + $collectionId: '', + $databaseId: '', + $createdAt: '', + $updatedAt: '', + $permissions: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1668,7 +1894,7 @@ export class DocumentsDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'patch', uri, { @@ -1678,6 +1904,24 @@ export class DocumentsDB extends Service { }, apiPayload, ); + const defaults = { + root: 'document', + models: { + document: { + defaults: { + $id: '', + $sequence: '', + $collectionId: '', + $databaseId: '', + $createdAt: '', + $updatedAt: '', + $permissions: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1837,7 +2081,7 @@ export class DocumentsDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'patch', uri, { @@ -1847,5 +2091,23 @@ export class DocumentsDB extends Service { }, apiPayload, ); + const defaults = { + root: 'document', + models: { + document: { + defaults: { + $id: '', + $sequence: '', + $collectionId: '', + $databaseId: '', + $createdAt: '', + $updatedAt: '', + $permissions: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } } diff --git a/src/services/functions.ts b/src/services/functions.ts index 230ffe70..db74d35c 100644 --- a/src/services/functions.ts +++ b/src/services/functions.ts @@ -1,5 +1,5 @@ import { Service } from '../service'; -import { AppwriteException, Client } from '../client'; +import { AppwriteException, Client, applyDefaults } from '../client'; import type { Models } from '../models'; import type { Payload } from '../client'; @@ -89,7 +89,7 @@ export class Functions extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -98,6 +98,58 @@ export class Functions extends Service { }, apiPayload, ); + const defaults = { + root: 'executionList', + models: { + executionList: { + defaults: { + total: 0, + executions: [], + }, + properties: { + executions: { + items: 'execution', + }, + }, + }, + execution: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + $permissions: [], + resourceId: '', + resourceType: 'functions', + deploymentId: '', + requestMethod: '', + requestPath: '', + requestHeaders: [], + responseStatusCode: 0, + responseBody: '', + responseHeaders: [], + logs: '', + errors: '', + duration: 0, + }, + properties: { + requestHeaders: { + items: 'headers', + }, + responseHeaders: { + items: 'headers', + }, + }, + }, + headers: { + defaults: { + name: '', + value: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -109,7 +161,7 @@ export class Functions extends Service { * @param {string} params.xpath - HTTP path of execution. Path can include query params. Default value is / * @param {ExecutionMethod} params.method - HTTP method of execution. Default value is POST. * @param {object} params.headers - HTTP headers of execution. Defaults to empty. - * @param {string} params.scheduledAt - Scheduled execution time in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format. DateTime value must be in future with precision in minutes. + * @param {string | null} params.scheduledAt - Scheduled execution time in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format. DateTime value must be in future with precision in minutes. * @throws {AppwriteException} * @returns {Promise} */ @@ -120,7 +172,7 @@ export class Functions extends Service { xpath?: string; method?: ExecutionMethod; headers?: object; - scheduledAt?: string; + scheduledAt?: string | null; }): Promise; /** * Trigger a function execution. The returned object will return you the current execution status. You can ping the `Get Execution` endpoint to get updates on the current execution status. Once this endpoint is called, your function execution process will start asynchronously. @@ -131,7 +183,7 @@ export class Functions extends Service { * @param {string} xpath - HTTP path of execution. Path can include query params. Default value is / * @param {ExecutionMethod} method - HTTP method of execution. Default value is POST. * @param {object} headers - HTTP headers of execution. Defaults to empty. - * @param {string} scheduledAt - Scheduled execution time in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format. DateTime value must be in future with precision in minutes. + * @param {string | null} scheduledAt - Scheduled execution time in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format. DateTime value must be in future with precision in minutes. * @throws {AppwriteException} * @returns {Promise} * @deprecated Use the object parameter style method for a better developer experience. @@ -143,7 +195,7 @@ export class Functions extends Service { xpath?: string, method?: ExecutionMethod, headers?: object, - scheduledAt?: string, + scheduledAt?: string | null, ): Promise; createExecution( paramsOrFirst: @@ -154,7 +206,7 @@ export class Functions extends Service { xpath?: string; method?: ExecutionMethod; headers?: object; - scheduledAt?: string; + scheduledAt?: string | null; } | string, ...rest: [ @@ -163,7 +215,7 @@ export class Functions extends Service { string?, ExecutionMethod?, object?, - string?, + (string | null)?, ] ): Promise { let params: { @@ -173,7 +225,7 @@ export class Functions extends Service { xpath?: string; method?: ExecutionMethod; headers?: object; - scheduledAt?: string; + scheduledAt?: string | null; }; if ( @@ -188,7 +240,7 @@ export class Functions extends Service { xpath?: string; method?: ExecutionMethod; headers?: object; - scheduledAt?: string; + scheduledAt?: string | null; }; } else { params = { @@ -198,7 +250,7 @@ export class Functions extends Service { xpath: rest[2] as string, method: rest[3] as ExecutionMethod, headers: rest[4] as object, - scheduledAt: rest[5] as string, + scheduledAt: rest[5] as string | null, }; } @@ -247,7 +299,7 @@ export class Functions extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -257,6 +309,47 @@ export class Functions extends Service { }, apiPayload, ); + const defaults = { + root: 'execution', + models: { + execution: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + $permissions: [], + resourceId: '', + resourceType: 'functions', + deploymentId: '', + requestMethod: '', + requestPath: '', + requestHeaders: [], + responseStatusCode: 0, + responseBody: '', + responseHeaders: [], + logs: '', + errors: '', + duration: 0, + }, + properties: { + requestHeaders: { + items: 'headers', + }, + responseHeaders: { + items: 'headers', + }, + }, + }, + headers: { + defaults: { + name: '', + value: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -327,7 +420,7 @@ export class Functions extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -336,5 +429,46 @@ export class Functions extends Service { }, apiPayload, ); + const defaults = { + root: 'execution', + models: { + execution: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + $permissions: [], + resourceId: '', + resourceType: 'functions', + deploymentId: '', + requestMethod: '', + requestPath: '', + requestHeaders: [], + responseStatusCode: 0, + responseBody: '', + responseHeaders: [], + logs: '', + errors: '', + duration: 0, + }, + properties: { + requestHeaders: { + items: 'headers', + }, + responseHeaders: { + items: 'headers', + }, + }, + }, + headers: { + defaults: { + name: '', + value: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } } diff --git a/src/services/locale.ts b/src/services/locale.ts index ce9e92b2..7ab026b5 100644 --- a/src/services/locale.ts +++ b/src/services/locale.ts @@ -1,5 +1,5 @@ import { Service } from '../service'; -import { Client } from '../client'; +import { Client, applyDefaults } from '../client'; import type { Models } from '../models'; import type { Payload } from '../client'; @@ -21,7 +21,7 @@ export class Locale extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -30,6 +30,24 @@ export class Locale extends Service { }, apiPayload, ); + const defaults = { + root: 'locale', + models: { + locale: { + defaults: { + ip: '', + countryCode: '', + country: '', + continentCode: '', + continent: '', + eu: false, + currency: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -77,7 +95,7 @@ export class Locale extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -86,6 +104,30 @@ export class Locale extends Service { }, apiPayload, ); + const defaults = { + root: 'localeCodeList', + models: { + localeCodeList: { + defaults: { + total: 0, + localeCodes: [], + }, + properties: { + localeCodes: { + items: 'localeCode', + }, + }, + }, + localeCode: { + defaults: { + code: '', + name: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -133,7 +175,7 @@ export class Locale extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -142,6 +184,30 @@ export class Locale extends Service { }, apiPayload, ); + const defaults = { + root: 'continentList', + models: { + continentList: { + defaults: { + total: 0, + continents: [], + }, + properties: { + continents: { + items: 'continent', + }, + }, + }, + continent: { + defaults: { + name: '', + code: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -189,7 +255,7 @@ export class Locale extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -198,6 +264,30 @@ export class Locale extends Service { }, apiPayload, ); + const defaults = { + root: 'countryList', + models: { + countryList: { + defaults: { + total: 0, + countries: [], + }, + properties: { + countries: { + items: 'country', + }, + }, + }, + country: { + defaults: { + name: '', + code: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -245,7 +335,7 @@ export class Locale extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -254,6 +344,30 @@ export class Locale extends Service { }, apiPayload, ); + const defaults = { + root: 'countryList', + models: { + countryList: { + defaults: { + total: 0, + countries: [], + }, + properties: { + countries: { + items: 'country', + }, + }, + }, + country: { + defaults: { + name: '', + code: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -303,7 +417,7 @@ export class Locale extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -312,6 +426,31 @@ export class Locale extends Service { }, apiPayload, ); + const defaults = { + root: 'phoneList', + models: { + phoneList: { + defaults: { + total: 0, + phones: [], + }, + properties: { + phones: { + items: 'phone', + }, + }, + }, + phone: { + defaults: { + code: '', + countryCode: '', + countryName: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -359,7 +498,7 @@ export class Locale extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -368,6 +507,35 @@ export class Locale extends Service { }, apiPayload, ); + const defaults = { + root: 'currencyList', + models: { + currencyList: { + defaults: { + total: 0, + currencies: [], + }, + properties: { + currencies: { + items: 'currency', + }, + }, + }, + currency: { + defaults: { + symbol: '', + name: '', + symbolNative: '', + decimalDigits: 0, + rounding: 0, + code: '', + namePlural: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -415,7 +583,7 @@ export class Locale extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -424,5 +592,30 @@ export class Locale extends Service { }, apiPayload, ); + const defaults = { + root: 'languageList', + models: { + languageList: { + defaults: { + total: 0, + languages: [], + }, + properties: { + languages: { + items: 'language', + }, + }, + }, + language: { + defaults: { + name: '', + code: '', + nativeName: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } } diff --git a/src/services/messaging.ts b/src/services/messaging.ts index 33e94c19..b1939ddf 100644 --- a/src/services/messaging.ts +++ b/src/services/messaging.ts @@ -1,5 +1,5 @@ import { Service } from '../service'; -import { AppwriteException, Client } from '../client'; +import { AppwriteException, Client, applyDefaults } from '../client'; import type { Models } from '../models'; import type { Payload } from '../client'; @@ -100,7 +100,7 @@ export class Messaging extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -110,6 +110,25 @@ export class Messaging extends Service { }, apiPayload, ); + const defaults = { + root: 'subscriber', + models: { + subscriber: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + targetId: '', + userId: '', + userName: '', + topicId: '', + providerType: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** diff --git a/src/services/oauth-2.ts b/src/services/oauth-2.ts index 1920bc1a..185fad00 100644 --- a/src/services/oauth-2.ts +++ b/src/services/oauth-2.ts @@ -1,5 +1,5 @@ import { Service } from '../service'; -import { AppwriteException, Client } from '../client'; +import { AppwriteException, Client, applyDefaults } from '../client'; import type { Models } from '../models'; import type { Payload } from '../client'; @@ -96,7 +96,7 @@ export class Oauth2 extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -105,6 +105,18 @@ export class Oauth2 extends Service { }, apiPayload, ); + const defaults = { + root: 'oauth2Approve', + models: { + oauth2Approve: { + defaults: { + redirectUrl: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -121,7 +133,7 @@ export class Oauth2 extends Service { * @param {string} params.prompt - OIDC prompt parameter for customization of consent screen. Space-separated list of: none, login, consent, select_account. * @param {number} params.maxAge - OIDC max_age paraleter for customization of consent screen. Maximum allowable elapsed time in seconds since the user last authenticated. If exceeded, re-authentication is required. * @param {string} params.authorizationDetails - Rich authorization request. JSON array of objects, each with a `type` and project-defined fields - * @param {string} params.resource - RFC 8707 resource indicator URI or URI list. Each value must be an absolute URI without a fragment. + * @param {string[]} params.resource - RFC 8707 resource indicator URI or URI list. Each value must be an absolute URI without a fragment. * @param {string} params.audience - Compatibility alias for a single OAuth2 resource indicator URI. * @param {string} params.requestUri - OAuth2 authorization request handle returned by the pushed authorization request endpoint. * @throws {AppwriteException} @@ -139,7 +151,7 @@ export class Oauth2 extends Service { prompt?: string; maxAge?: number; authorizationDetails?: string; - resource?: string; + resource?: string[]; audience?: string; requestUri?: string; }): Promise; @@ -157,7 +169,7 @@ export class Oauth2 extends Service { * @param {string} prompt - OIDC prompt parameter for customization of consent screen. Space-separated list of: none, login, consent, select_account. * @param {number} maxAge - OIDC max_age paraleter for customization of consent screen. Maximum allowable elapsed time in seconds since the user last authenticated. If exceeded, re-authentication is required. * @param {string} authorizationDetails - Rich authorization request. JSON array of objects, each with a `type` and project-defined fields - * @param {string} resource - RFC 8707 resource indicator URI or URI list. Each value must be an absolute URI without a fragment. + * @param {string[]} resource - RFC 8707 resource indicator URI or URI list. Each value must be an absolute URI without a fragment. * @param {string} audience - Compatibility alias for a single OAuth2 resource indicator URI. * @param {string} requestUri - OAuth2 authorization request handle returned by the pushed authorization request endpoint. * @throws {AppwriteException} @@ -176,7 +188,7 @@ export class Oauth2 extends Service { prompt?: string, maxAge?: number, authorizationDetails?: string, - resource?: string, + resource?: string[], audience?: string, requestUri?: string, ): Promise; @@ -194,7 +206,7 @@ export class Oauth2 extends Service { prompt?: string; maxAge?: number; authorizationDetails?: string; - resource?: string; + resource?: string[]; audience?: string; requestUri?: string; } @@ -210,7 +222,7 @@ export class Oauth2 extends Service { string?, number?, string?, - string?, + string[]?, string?, string?, ] @@ -227,7 +239,7 @@ export class Oauth2 extends Service { prompt?: string; maxAge?: number; authorizationDetails?: string; - resource?: string; + resource?: string[]; audience?: string; requestUri?: string; }; @@ -250,7 +262,7 @@ export class Oauth2 extends Service { prompt?: string; maxAge?: number; authorizationDetails?: string; - resource?: string; + resource?: string[]; audience?: string; requestUri?: string; }; @@ -267,7 +279,7 @@ export class Oauth2 extends Service { prompt: rest[7] as string, maxAge: rest[8] as number, authorizationDetails: rest[9] as string, - resource: rest[10] as string, + resource: rest[10] as string[], audience: rest[11] as string, requestUri: rest[12] as string, }; @@ -351,7 +363,7 @@ export class Oauth2 extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -359,6 +371,19 @@ export class Oauth2 extends Service { }, apiPayload, ); + const defaults = { + root: 'oauth2Authorize', + models: { + oauth2Authorize: { + defaults: { + grantId: '', + redirectUrl: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -373,9 +398,9 @@ export class Oauth2 extends Service { * @param {string} params.codeChallenge - PKCE code challenge. Required when OAuth2 app is public. * @param {string} params.codeChallengeMethod - PKCE code challenge method. Required when OAuth2 app is public. * @param {string} params.prompt - OIDC prompt parameter for customization of consent screen. Space-separated list of: none, login, consent, select_account. - * @param {number} params.maxAge - OIDC max_age paraleter for customization of consent screen. Maximum allowable elapsed time in seconds since the user last authenticated. If exceeded, re-authentication is required. + * @param {number | null} params.maxAge - OIDC max_age paraleter for customization of consent screen. Maximum allowable elapsed time in seconds since the user last authenticated. If exceeded, re-authentication is required. * @param {string} params.authorizationDetails - Rich authorization request. JSON array of objects, each with a `type` and project-defined fields - * @param {string} params.resource - RFC 8707 resource indicator URI or URI list. Each value must be an absolute URI without a fragment. + * @param {string[]} params.resource - RFC 8707 resource indicator URI or URI list. Each value must be an absolute URI without a fragment. * @param {string} params.audience - Compatibility alias for a single OAuth2 resource indicator URI. * @param {string} params.requestUri - OAuth2 authorization request handle returned by the pushed authorization request endpoint. * @throws {AppwriteException} @@ -391,9 +416,9 @@ export class Oauth2 extends Service { codeChallenge?: string; codeChallengeMethod?: string; prompt?: string; - maxAge?: number; + maxAge?: number | null; authorizationDetails?: string; - resource?: string; + resource?: string[]; audience?: string; requestUri?: string; }): Promise; @@ -409,9 +434,9 @@ export class Oauth2 extends Service { * @param {string} codeChallenge - PKCE code challenge. Required when OAuth2 app is public. * @param {string} codeChallengeMethod - PKCE code challenge method. Required when OAuth2 app is public. * @param {string} prompt - OIDC prompt parameter for customization of consent screen. Space-separated list of: none, login, consent, select_account. - * @param {number} maxAge - OIDC max_age paraleter for customization of consent screen. Maximum allowable elapsed time in seconds since the user last authenticated. If exceeded, re-authentication is required. + * @param {number | null} maxAge - OIDC max_age paraleter for customization of consent screen. Maximum allowable elapsed time in seconds since the user last authenticated. If exceeded, re-authentication is required. * @param {string} authorizationDetails - Rich authorization request. JSON array of objects, each with a `type` and project-defined fields - * @param {string} resource - RFC 8707 resource indicator URI or URI list. Each value must be an absolute URI without a fragment. + * @param {string[]} resource - RFC 8707 resource indicator URI or URI list. Each value must be an absolute URI without a fragment. * @param {string} audience - Compatibility alias for a single OAuth2 resource indicator URI. * @param {string} requestUri - OAuth2 authorization request handle returned by the pushed authorization request endpoint. * @throws {AppwriteException} @@ -428,9 +453,9 @@ export class Oauth2 extends Service { codeChallenge?: string, codeChallengeMethod?: string, prompt?: string, - maxAge?: number, + maxAge?: number | null, authorizationDetails?: string, - resource?: string, + resource?: string[], audience?: string, requestUri?: string, ): Promise; @@ -446,9 +471,9 @@ export class Oauth2 extends Service { codeChallenge?: string; codeChallengeMethod?: string; prompt?: string; - maxAge?: number; + maxAge?: number | null; authorizationDetails?: string; - resource?: string; + resource?: string[]; audience?: string; requestUri?: string; } @@ -462,9 +487,9 @@ export class Oauth2 extends Service { string?, string?, string?, - number?, - string?, + (number | null)?, string?, + string[]?, string?, string?, ] @@ -479,9 +504,9 @@ export class Oauth2 extends Service { codeChallenge?: string; codeChallengeMethod?: string; prompt?: string; - maxAge?: number; + maxAge?: number | null; authorizationDetails?: string; - resource?: string; + resource?: string[]; audience?: string; requestUri?: string; }; @@ -502,9 +527,9 @@ export class Oauth2 extends Service { codeChallenge?: string; codeChallengeMethod?: string; prompt?: string; - maxAge?: number; + maxAge?: number | null; authorizationDetails?: string; - resource?: string; + resource?: string[]; audience?: string; requestUri?: string; }; @@ -519,9 +544,9 @@ export class Oauth2 extends Service { codeChallenge: rest[5] as string, codeChallengeMethod: rest[6] as string, prompt: rest[7] as string, - maxAge: rest[8] as number, + maxAge: rest[8] as number | null, authorizationDetails: rest[9] as string, - resource: rest[10] as string, + resource: rest[10] as string[], audience: rest[11] as string, requestUri: rest[12] as string, }; @@ -605,7 +630,7 @@ export class Oauth2 extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -614,6 +639,19 @@ export class Oauth2 extends Service { }, apiPayload, ); + const defaults = { + root: 'oauth2Authorize', + models: { + oauth2Authorize: { + defaults: { + grantId: '', + redirectUrl: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -622,7 +660,7 @@ export class Oauth2 extends Service { * @param {string} params.clientId - OAuth2 client ID. Either a registered app ID or an HTTPS client ID metadata document URL. * @param {string} params.scope - Space-separated OAuth2 scopes. Can include project scopes, and built-in scopes: `openid`, `email`, `profile`. * @param {string} params.authorizationDetails - Rich authorization request. JSON array of objects, each with a `type` and project-defined fields - * @param {string} params.resource - RFC 8707 resource indicator URI or URI list. Each value must be an absolute URI without a fragment. + * @param {string[]} params.resource - RFC 8707 resource indicator URI or URI list. Each value must be an absolute URI without a fragment. * @param {string} params.audience - Compatibility alias for a single OAuth2 resource indicator URI. * @throws {AppwriteException} * @returns {Promise} @@ -631,7 +669,7 @@ export class Oauth2 extends Service { clientId?: string; scope?: string; authorizationDetails?: string; - resource?: string; + resource?: string[]; audience?: string; }): Promise; /** @@ -640,7 +678,7 @@ export class Oauth2 extends Service { * @param {string} clientId - OAuth2 client ID. Either a registered app ID or an HTTPS client ID metadata document URL. * @param {string} scope - Space-separated OAuth2 scopes. Can include project scopes, and built-in scopes: `openid`, `email`, `profile`. * @param {string} authorizationDetails - Rich authorization request. JSON array of objects, each with a `type` and project-defined fields - * @param {string} resource - RFC 8707 resource indicator URI or URI list. Each value must be an absolute URI without a fragment. + * @param {string[]} resource - RFC 8707 resource indicator URI or URI list. Each value must be an absolute URI without a fragment. * @param {string} audience - Compatibility alias for a single OAuth2 resource indicator URI. * @throws {AppwriteException} * @returns {Promise} @@ -650,7 +688,7 @@ export class Oauth2 extends Service { clientId?: string, scope?: string, authorizationDetails?: string, - resource?: string, + resource?: string[], audience?: string, ): Promise; createDeviceAuthorization( @@ -659,17 +697,17 @@ export class Oauth2 extends Service { clientId?: string; scope?: string; authorizationDetails?: string; - resource?: string; + resource?: string[]; audience?: string; } | string, - ...rest: [string?, string?, string?, string?] + ...rest: [string?, string?, string[]?, string?] ): Promise { let params: { clientId?: string; scope?: string; authorizationDetails?: string; - resource?: string; + resource?: string[]; audience?: string; }; @@ -683,7 +721,7 @@ export class Oauth2 extends Service { clientId?: string; scope?: string; authorizationDetails?: string; - resource?: string; + resource?: string[]; audience?: string; }; } else { @@ -691,7 +729,7 @@ export class Oauth2 extends Service { clientId: paramsOrFirst as string, scope: rest[0] as string, authorizationDetails: rest[1] as string, - resource: rest[2] as string, + resource: rest[2] as string[], audience: rest[3] as string, }; } @@ -729,7 +767,7 @@ export class Oauth2 extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -738,6 +776,23 @@ export class Oauth2 extends Service { }, apiPayload, ); + const defaults = { + root: 'oauth2DeviceAuthorization', + models: { + oauth2DeviceAuthorization: { + defaults: { + device_code: '', + user_code: '', + verification_uri: '', + verification_uri_complete: '', + expires_in: 0, + interval: 0, + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -793,7 +848,7 @@ export class Oauth2 extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -802,6 +857,29 @@ export class Oauth2 extends Service { }, apiPayload, ); + const defaults = { + root: 'oauth2Grant', + models: { + oauth2Grant: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + userId: '', + appId: '', + scopes: [], + resources: [], + authorizationDetails: '[]', + prompt: '', + redirectUri: '', + authTime: 0, + expire: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -855,7 +933,7 @@ export class Oauth2 extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -863,6 +941,29 @@ export class Oauth2 extends Service { }, apiPayload, ); + const defaults = { + root: 'oauth2Grant', + models: { + oauth2Grant: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + userId: '', + appId: '', + scopes: [], + resources: [], + authorizationDetails: '[]', + prompt: '', + redirectUri: '', + authTime: 0, + expire: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1216,7 +1317,7 @@ export class Oauth2 extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -1224,6 +1325,29 @@ export class Oauth2 extends Service { }, apiPayload, ); + const defaults = { + root: 'oauth2OrganizationList', + models: { + oauth2OrganizationList: { + defaults: { + total: 0, + organizations: [], + }, + properties: { + organizations: { + items: 'oauth2Organization', + }, + }, + }, + oauth2Organization: { + defaults: { + $id: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1238,9 +1362,9 @@ export class Oauth2 extends Service { * @param {string} params.codeChallenge - PKCE code challenge. Required when OAuth2 app is public. * @param {string} params.codeChallengeMethod - PKCE code challenge method. Required when OAuth2 app is public. * @param {string} params.prompt - OIDC prompt parameter for customization of consent screen. Space-separated list of: none, login, consent, select_account. - * @param {number} params.maxAge - OIDC max_age parameter for customization of consent screen. + * @param {number | null} params.maxAge - OIDC max_age parameter for customization of consent screen. * @param {string} params.authorizationDetails - Rich authorization request. JSON array of objects, each with a `type` and project-defined fields - * @param {string} params.resource - RFC 8707 resource indicator URI or URI list. Each value must be an absolute URI without a fragment. + * @param {string[]} params.resource - RFC 8707 resource indicator URI or URI list. Each value must be an absolute URI without a fragment. * @param {string} params.audience - Compatibility alias for a single OAuth2 resource indicator URI. * @throws {AppwriteException} * @returns {Promise} @@ -1255,9 +1379,9 @@ export class Oauth2 extends Service { codeChallenge?: string; codeChallengeMethod?: string; prompt?: string; - maxAge?: number; + maxAge?: number | null; authorizationDetails?: string; - resource?: string; + resource?: string[]; audience?: string; }): Promise; /** @@ -1272,9 +1396,9 @@ export class Oauth2 extends Service { * @param {string} codeChallenge - PKCE code challenge. Required when OAuth2 app is public. * @param {string} codeChallengeMethod - PKCE code challenge method. Required when OAuth2 app is public. * @param {string} prompt - OIDC prompt parameter for customization of consent screen. Space-separated list of: none, login, consent, select_account. - * @param {number} maxAge - OIDC max_age parameter for customization of consent screen. + * @param {number | null} maxAge - OIDC max_age parameter for customization of consent screen. * @param {string} authorizationDetails - Rich authorization request. JSON array of objects, each with a `type` and project-defined fields - * @param {string} resource - RFC 8707 resource indicator URI or URI list. Each value must be an absolute URI without a fragment. + * @param {string[]} resource - RFC 8707 resource indicator URI or URI list. Each value must be an absolute URI without a fragment. * @param {string} audience - Compatibility alias for a single OAuth2 resource indicator URI. * @throws {AppwriteException} * @returns {Promise} @@ -1290,9 +1414,9 @@ export class Oauth2 extends Service { codeChallenge?: string, codeChallengeMethod?: string, prompt?: string, - maxAge?: number, + maxAge?: number | null, authorizationDetails?: string, - resource?: string, + resource?: string[], audience?: string, ): Promise; createPAR( @@ -1307,9 +1431,9 @@ export class Oauth2 extends Service { codeChallenge?: string; codeChallengeMethod?: string; prompt?: string; - maxAge?: number; + maxAge?: number | null; authorizationDetails?: string; - resource?: string; + resource?: string[]; audience?: string; } | string, @@ -1322,9 +1446,9 @@ export class Oauth2 extends Service { string?, string?, string?, - number?, - string?, + (number | null)?, string?, + string[]?, string?, ] ): Promise { @@ -1338,9 +1462,9 @@ export class Oauth2 extends Service { codeChallenge?: string; codeChallengeMethod?: string; prompt?: string; - maxAge?: number; + maxAge?: number | null; authorizationDetails?: string; - resource?: string; + resource?: string[]; audience?: string; }; @@ -1359,9 +1483,9 @@ export class Oauth2 extends Service { codeChallenge?: string; codeChallengeMethod?: string; prompt?: string; - maxAge?: number; + maxAge?: number | null; authorizationDetails?: string; - resource?: string; + resource?: string[]; audience?: string; }; } else { @@ -1375,9 +1499,9 @@ export class Oauth2 extends Service { codeChallenge: rest[5] as string, codeChallengeMethod: rest[6] as string, prompt: rest[7] as string, - maxAge: rest[8] as number, + maxAge: rest[8] as number | null, authorizationDetails: rest[9] as string, - resource: rest[10] as string, + resource: rest[10] as string[], audience: rest[11] as string, }; } @@ -1473,7 +1597,7 @@ export class Oauth2 extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -1482,6 +1606,19 @@ export class Oauth2 extends Service { }, apiPayload, ); + const defaults = { + root: 'oauth2PAR', + models: { + oauth2PAR: { + defaults: { + request_uri: '', + expires_in: 0, + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1562,7 +1699,7 @@ export class Oauth2 extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -1570,6 +1707,31 @@ export class Oauth2 extends Service { }, apiPayload, ); + const defaults = { + root: 'oauth2ProjectList', + models: { + oauth2ProjectList: { + defaults: { + total: 0, + projects: [], + }, + properties: { + projects: { + items: 'oauth2Project', + }, + }, + }, + oauth2Project: { + defaults: { + $id: '', + region: '', + endpoint: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1625,7 +1787,7 @@ export class Oauth2 extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -1634,6 +1796,18 @@ export class Oauth2 extends Service { }, apiPayload, ); + const defaults = { + root: 'oauth2Reject', + models: { + oauth2Reject: { + defaults: { + redirectUrl: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1761,7 +1935,7 @@ export class Oauth2 extends Service { * @param {string} params.clientSecret - OAuth2 client secret. Required for confidential apps. * @param {string} params.codeVerifier - PKCE code verifier. Required for public apps. * @param {string} params.redirectUri - Redirect URI. Required for `authorization_code` grant type. - * @param {string} params.resource - RFC 8707 resource indicator URI or URI list. Each value must be an absolute URI without a fragment. + * @param {string[]} params.resource - RFC 8707 resource indicator URI or URI list. Each value must be an absolute URI without a fragment. * @param {string} params.audience - Compatibility alias for a single OAuth2 resource indicator URI. * @throws {AppwriteException} * @returns {Promise} @@ -1775,7 +1949,7 @@ export class Oauth2 extends Service { clientSecret?: string; codeVerifier?: string; redirectUri?: string; - resource?: string; + resource?: string[]; audience?: string; }): Promise; /** @@ -1789,7 +1963,7 @@ export class Oauth2 extends Service { * @param {string} clientSecret - OAuth2 client secret. Required for confidential apps. * @param {string} codeVerifier - PKCE code verifier. Required for public apps. * @param {string} redirectUri - Redirect URI. Required for `authorization_code` grant type. - * @param {string} resource - RFC 8707 resource indicator URI or URI list. Each value must be an absolute URI without a fragment. + * @param {string[]} resource - RFC 8707 resource indicator URI or URI list. Each value must be an absolute URI without a fragment. * @param {string} audience - Compatibility alias for a single OAuth2 resource indicator URI. * @throws {AppwriteException} * @returns {Promise} @@ -1804,7 +1978,7 @@ export class Oauth2 extends Service { clientSecret?: string, codeVerifier?: string, redirectUri?: string, - resource?: string, + resource?: string[], audience?: string, ): Promise; createToken( @@ -1818,7 +1992,7 @@ export class Oauth2 extends Service { clientSecret?: string; codeVerifier?: string; redirectUri?: string; - resource?: string; + resource?: string[]; audience?: string; } | string, @@ -1830,7 +2004,7 @@ export class Oauth2 extends Service { string?, string?, string?, - string?, + string[]?, string?, ] ): Promise { @@ -1843,7 +2017,7 @@ export class Oauth2 extends Service { clientSecret?: string; codeVerifier?: string; redirectUri?: string; - resource?: string; + resource?: string[]; audience?: string; }; @@ -1861,7 +2035,7 @@ export class Oauth2 extends Service { clientSecret?: string; codeVerifier?: string; redirectUri?: string; - resource?: string; + resource?: string[]; audience?: string; }; } else { @@ -1874,7 +2048,7 @@ export class Oauth2 extends Service { clientSecret: rest[4] as string, codeVerifier: rest[5] as string, redirectUri: rest[6] as string, - resource: rest[7] as string, + resource: rest[7] as string[], audience: rest[8] as string, }; } @@ -1943,7 +2117,7 @@ export class Oauth2 extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -1952,5 +2126,21 @@ export class Oauth2 extends Service { }, apiPayload, ); + const defaults = { + root: 'oauth2Token', + models: { + oauth2Token: { + defaults: { + access_token: '', + token_type: 'Bearer', + expires_in: 0, + refresh_token: '', + scope: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } } diff --git a/src/services/organization.ts b/src/services/organization.ts index 3542965f..4ec51e57 100644 --- a/src/services/organization.ts +++ b/src/services/organization.ts @@ -1,5 +1,5 @@ import { Service } from '../service'; -import { AppwriteException, Client } from '../client'; +import { AppwriteException, Client, applyDefaults } from '../client'; import type { Models } from '../models'; import type { Payload } from '../client'; @@ -71,7 +71,7 @@ export class Organization extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -80,6 +80,37 @@ export class Organization extends Service { }, apiPayload, ); + const defaults = { + root: 'appInstallationList', + models: { + appInstallationList: { + defaults: { + total: 0, + installations: [], + }, + properties: { + installations: { + items: 'appInstallation', + }, + }, + }, + appInstallation: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + appId: '', + teamId: '', + scopes: [], + authorizationDetails: [], + createdById: '', + createdByName: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -149,7 +180,7 @@ export class Organization extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -159,6 +190,26 @@ export class Organization extends Service { }, apiPayload, ); + const defaults = { + root: 'appInstallation', + models: { + appInstallation: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + appId: '', + teamId: '', + scopes: [], + authorizationDetails: [], + createdById: '', + createdByName: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -212,7 +263,7 @@ export class Organization extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -221,39 +272,63 @@ export class Organization extends Service { }, apiPayload, ); + const defaults = { + root: 'appInstallation', + models: { + appInstallation: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + appId: '', + teamId: '', + scopes: [], + authorizationDetails: [], + createdById: '', + createdByName: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** * Update an app installation on the organization. Only organization members with the owner role can update installations. The installation's granted scopes are refreshed to the scopes the app currently requests; previously issued installation access tokens are revoked. * * @param {string} params.installationId - Installation unique ID. - * @param {string} params.authorizationDetails - Authorization details granted to the installation as a JSON array of objects, each with a `type` and app-defined fields. Omit to keep the current value. + * @param {string | null} params.authorizationDetails - Authorization details granted to the installation as a JSON array of objects, each with a `type` and app-defined fields. Omit to keep the current value. * @throws {AppwriteException} * @returns {Promise} */ updateInstallation(params: { installationId: string; - authorizationDetails?: string; + authorizationDetails?: string | null; }): Promise; /** * Update an app installation on the organization. Only organization members with the owner role can update installations. The installation's granted scopes are refreshed to the scopes the app currently requests; previously issued installation access tokens are revoked. * * @param {string} installationId - Installation unique ID. - * @param {string} authorizationDetails - Authorization details granted to the installation as a JSON array of objects, each with a `type` and app-defined fields. Omit to keep the current value. + * @param {string | null} authorizationDetails - Authorization details granted to the installation as a JSON array of objects, each with a `type` and app-defined fields. Omit to keep the current value. * @throws {AppwriteException} * @returns {Promise} * @deprecated Use the object parameter style method for a better developer experience. */ updateInstallation( installationId: string, - authorizationDetails?: string, + authorizationDetails?: string | null, ): Promise; updateInstallation( paramsOrFirst: - { installationId: string; authorizationDetails?: string } | string, - ...rest: [string?] + | { installationId: string; authorizationDetails?: string | null } + | string, + ...rest: [(string | null)?] ): Promise { - let params: { installationId: string; authorizationDetails?: string }; + let params: { + installationId: string; + authorizationDetails?: string | null; + }; if ( paramsOrFirst && @@ -262,12 +337,12 @@ export class Organization extends Service { ) { params = (paramsOrFirst || {}) as { installationId: string; - authorizationDetails?: string; + authorizationDetails?: string | null; }; } else { params = { installationId: paramsOrFirst as string, - authorizationDetails: rest[0] as string, + authorizationDetails: rest[0] as string | null, }; } @@ -291,7 +366,7 @@ export class Organization extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'put', uri, { @@ -301,6 +376,26 @@ export class Organization extends Service { }, apiPayload, ); + const defaults = { + root: 'appInstallation', + models: { + appInstallation: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + appId: '', + teamId: '', + scopes: [], + authorizationDetails: [], + createdById: '', + createdByName: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** diff --git a/src/services/presences.ts b/src/services/presences.ts index 5fb3a364..4cc36d8b 100644 --- a/src/services/presences.ts +++ b/src/services/presences.ts @@ -1,5 +1,5 @@ import { Service } from '../service'; -import { AppwriteException, Client } from '../client'; +import { AppwriteException, Client, applyDefaults } from '../client'; import type { Models } from '../models'; import type { Payload } from '../client'; @@ -85,7 +85,7 @@ export class Presences extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -94,6 +94,34 @@ export class Presences extends Service { }, apiPayload, ); + const defaults = { + root: 'presenceList', + models: { + presenceList: { + defaults: { + total: 0, + presences: [], + }, + properties: { + presences: { + items: 'presence', + }, + }, + }, + presence: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + $permissions: [], + userId: '', + source: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -147,7 +175,7 @@ export class Presences extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -156,6 +184,23 @@ export class Presences extends Service { }, apiPayload, ); + const defaults = { + root: 'presence', + models: { + presence: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + $permissions: [], + userId: '', + source: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -278,7 +323,7 @@ export class Presences extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'put', uri, { @@ -288,6 +333,23 @@ export class Presences extends Service { }, apiPayload, ); + const defaults = { + root: 'presence', + models: { + presence: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + $permissions: [], + userId: '', + source: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -419,7 +481,7 @@ export class Presences extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'patch', uri, { @@ -429,6 +491,23 @@ export class Presences extends Service { }, apiPayload, ); + const defaults = { + root: 'presence', + models: { + presence: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + $permissions: [], + userId: '', + source: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** diff --git a/src/services/push.ts b/src/services/push.ts index 880e4f4c..9d7e985e 100644 --- a/src/services/push.ts +++ b/src/services/push.ts @@ -22,7 +22,7 @@ import { import { Client } from '../client'; import { createTcpStream } from '../lib/tcp-stream'; import { Service } from '../service'; -import type { ResolvedTopic, Topic } from '../topic'; +import type { Topic } from '../topic'; /** A message delivered on a subscribed topic (the MQTT analog of a Realtime event). */ export interface PushMessage { @@ -44,8 +44,20 @@ export interface PushBackgroundStatus { ignoringBatteryOptimizations: boolean; /** Foreground mode ({@link Push.setForeground}) keeps the connection open in a service. */ foregroundService: boolean; - /** Wake-ups may be deferred by Doze, so messages can arrive late while the app is closed. */ + /** + * Messages can arrive late, or not until the app is opened, while the app is closed: background + * usage is restricted without a battery optimisation exemption, or wake-ups may be deferred by + * Doze without exact alarms or foreground mode. + */ bestEffort: boolean; + /** + * The user restricted the app's background usage in the app's battery settings (Settings > + * Apps > your app > Battery), Android 9+. Android may then hold its alarms, jobs and foreground + * service while it is closed, so messages can wait until the app is opened. The battery + * optimisation exemption lets the alarms and jobs run again, but foreground mode still stops + * once the app leaves the screen. False below Android 9. + */ + backgroundRestricted: boolean; } /** A background notification the user tapped. */ @@ -293,9 +305,12 @@ export class Push extends Service { } /** - * Android: what background delivery can rely on. When `bestEffort` is true the scheduled - * wake-ups are inexact and Doze can defer them, so messages may arrive late while the app is - * closed; explain why, then ask with {@link requestExactAlarms} or + * Android: what background delivery can rely on. When `bestEffort` is true messages may arrive + * late, or not until the app is opened, while the app is closed, so explain why, then ask. If + * `backgroundRestricted` is true and the app is not `ignoringBatteryOptimizations`, ask the user + * to choose Unrestricted in the app's battery settings (Settings > Apps > your app > Battery), + * or ask with {@link requestIgnoreBatteryOptimizations}; otherwise the scheduled wake-ups are + * inexact and Doze can defer them, so ask with {@link requestExactAlarms} or * {@link requestIgnoreBatteryOptimizations}. Null elsewhere. */ async backgroundStatus(): Promise { @@ -468,7 +483,7 @@ export class Push extends Service { * Subscribe to one or more topics. Resolves to a {@link PushSubscription} handle. * * Each topic is a string or a `Topic` builder, e.g. - * `Topic.path(['user', userId]).all()`. + * `Topic.path(['user', userId])`. * * Called with only a callback, `subscribe((message) => {...}, options)` subscribes to the * signed-in user's own topic, `users/`, like FCM/APNs delivery to a device. The @@ -493,18 +508,12 @@ export class Push extends Service { options?: SubscribeOptions, ): Promise; subscribe( - topics: - string | Topic | ResolvedTopic | (string | Topic | ResolvedTopic)[], + topics: string | Topic | (string | Topic)[], callback: MessageCallback, options?: SubscribeOptions, ): Promise; async subscribe( - topicsOrCallback: - | string - | Topic - | ResolvedTopic - | (string | Topic | ResolvedTopic)[] - | MessageCallback, + topicsOrCallback: string | Topic | (string | Topic)[] | MessageCallback, callbackOrOptions?: MessageCallback | SubscribeOptions, topicOptions: SubscribeOptions = {}, ): Promise { @@ -521,12 +530,7 @@ export class Push extends Service { } private async subscribeWith( - topicsOrCallback: - | string - | Topic - | ResolvedTopic - | (string | Topic | ResolvedTopic)[] - | MessageCallback, + topicsOrCallback: string | Topic | (string | Topic)[] | MessageCallback, callbackOrOptions: MessageCallback | SubscribeOptions | undefined, topicOptions: SubscribeOptions, ): Promise { @@ -1231,18 +1235,26 @@ export class Push extends Service { } } - /** Post a local notification for a message a background subscription matched. */ - private async notify(message: PushMessage, title: string): Promise { + /** + * Post a local notification for a message a background subscription matched. A data-only + * message, an envelope without a notification title or body, posts none. + */ + private async notify( + message: PushMessage, + title: string, + content: NotificationContent = notificationContent(message), + ): Promise { + if (!content.visible) { + return; + } try { /* eslint-disable @typescript-eslint/no-require-imports */ const notifications: typeof import('expo-notifications') = require('expo-notifications'); /* eslint-enable @typescript-eslint/no-require-imports */ - const content = notificationContent(message); - const raw = !content.present; await notifications.scheduleNotificationAsync({ content: { title: content.title ?? title, - body: content.body ?? (raw ? message.data : null), + body: content.body ?? (content.raw ? message.data : null), data: { topic: message.topic, payload: message.data }, }, trigger: null, @@ -1574,7 +1586,7 @@ export class Push extends Service { payload, qos: packet.qos, }; - const serverTitle = notificationContent(message).title; + const content = notificationContent(message); const postedTitles = new Set(); // While the app is on screen it shows the message itself: only subscriptions that // opted in with notifyInForeground also post a notification then. @@ -1584,14 +1596,14 @@ export class Push extends Service { await sub.callback(message); // Notification is per-subscription: only subs that opted in post one, each // title once. A title the server sent replaces theirs, so it posts once. - const title = serverTitle ?? sub.title ?? message.topic; + const title = content.title ?? sub.title ?? message.topic; if ( sub.background && (!foreground || sub.notifyInForeground) && !postedTitles.has(title) ) { postedTitles.add(title); - await this.notify(message, title); + await this.notify(message, title, content); } } } @@ -1718,33 +1730,51 @@ function expoNotifications(): typeof import('expo-notifications') | null { /** What a message's `notification` block asks a background notification to show. */ interface NotificationContent { - /** Whether the message has a `notification` block at all. */ - present: boolean; + /** Whether the payload is not a JSON object, so it is shown as it is. */ + raw: boolean; + /** Whether a notification is posted: raw, or an envelope with a title or body. */ + visible: boolean; title?: string; body?: string; image?: string; } -/** The server's `notification` block in a message; empty when the payload has none or is not JSON. */ -function notificationContent(message: PushMessage): NotificationContent { - let notification: unknown; +/** The server's `notification` block in a payload, or null when the payload is not a JSON object. */ +function notificationBlock(data: string): Record | null { + let envelope: unknown; try { - notification = (JSON.parse(message.data) as { notification?: unknown }) - ?.notification; + envelope = JSON.parse(data); } catch { - return { present: false }; + return null; } - if (typeof notification !== 'object' || notification === null) { - return { present: false }; + if ( + typeof envelope !== 'object' || + envelope === null || + Array.isArray(envelope) + ) { + return null; } + const notification = (envelope as { notification?: unknown }).notification; + return typeof notification === 'object' && notification !== null + ? (notification as Record) + : {}; +} + +/** What a message asks a background notification to show; raw when it is not a JSON object. */ +function notificationContent(message: PushMessage): NotificationContent { + const block = notificationBlock(message.data); + const raw = block === null; const field = (name: string): string | undefined => { - const value = (notification as Record)[name]; + const value = block?.[name]; return typeof value === 'string' && value !== '' ? value : undefined; }; + const title = field('title'); + const body = field('body'); return { - present: true, - title: field('title'), - body: field('body'), + raw, + visible: raw || title !== undefined || body !== undefined, + title, + body, image: field('image'), }; } diff --git a/src/services/realtime.ts b/src/services/realtime.ts index 77820844..07b5c902 100644 --- a/src/services/realtime.ts +++ b/src/services/realtime.ts @@ -1,11 +1,12 @@ import { AppwriteException, Client, JSONbig } from '../client'; import { Channel, ActionableChannel, ResolvedChannel } from '../channel'; -import { Query } from '../query'; +import { normalizeQueries, type QueryInput } from '../query'; import { ID } from '../id'; import { Platform } from 'react-native'; + export type RealtimeSubscriptionUpdate = { channels?: (string | Channel | ActionableChannel | ResolvedChannel)[]; - queries?: (string | Query)[]; + queries?: QueryInput; }; export type RealtimeSubscription = { @@ -212,6 +213,7 @@ export class Realtime { const queryParams = `project=${projectId}`; const jwt = this.client.config.jwt; + const endpoint = this.client.config.endpointRealtime !== '' ? this.client.config.endpointRealtime @@ -256,6 +258,7 @@ export class Realtime { ...(jwt ? { 'x-appwrite-jwt': jwt } : {}), }, })); + socket.addEventListener('open', () => { if (connectionId !== this.connectionId) { return; @@ -511,7 +514,7 @@ export class Realtime { public async subscribe( channel: string | Channel | ActionableChannel | ResolvedChannel, callback: (event: RealtimeResponseEvent) => void, - queries?: (string | Query)[], + queries?: QueryInput, ): Promise; /** @@ -526,7 +529,7 @@ export class Realtime { string | Channel | ActionableChannel | ResolvedChannel )[], callback: (event: RealtimeResponseEvent) => void, - queries?: (string | Query)[], + queries?: QueryInput, ): Promise; /** @@ -539,7 +542,7 @@ export class Realtime { public async subscribe( channel: string | Channel | ActionableChannel | ResolvedChannel, callback: (event: RealtimeResponseEvent) => void, - queries?: (string | Query)[], + queries?: QueryInput, ): Promise; /** @@ -554,7 +557,7 @@ export class Realtime { string | Channel | ActionableChannel | ResolvedChannel )[], callback: (event: RealtimeResponseEvent) => void, - queries?: (string | Query)[], + queries?: QueryInput, ): Promise; public async subscribe( @@ -565,7 +568,7 @@ export class Realtime { | ResolvedChannel | (string | Channel | ActionableChannel | ResolvedChannel)[], callback: (event: RealtimeResponseEvent) => void, - queries: (string | Query)[] = [], + queries: QueryInput = [], ): Promise { const channelArray = Array.isArray(channelsOrChannel) ? channelsOrChannel @@ -577,21 +580,7 @@ export class Realtime { ); const channels = new Set(channelStrings); - // Convert queries to array of strings - // Ensure each query is a separate string in the array - const queryStrings: string[] = []; - for (const q of queries ?? []) { - if (Array.isArray(q)) { - // Handle nested arrays: [[q1, q2]] -> [q1, q2] - for (const inner of q) { - queryStrings.push( - typeof inner === 'string' ? inner : inner.toString(), - ); - } - } else { - queryStrings.push(typeof q === 'string' ? q : q.toString()); - } - } + const queryStrings = normalizeQueries(queries); const subscriptionId = this.generateUniqueSubscriptionId(); @@ -642,23 +631,7 @@ export class Realtime { } if (changes.queries !== undefined) { - const nextQueries: string[] = []; - for (const q of changes.queries) { - if (Array.isArray(q)) { - for (const inner of q) { - nextQueries.push( - typeof inner === 'string' - ? inner - : (inner as Query).toString(), - ); - } - } else { - nextQueries.push( - typeof q === 'string' ? q : q.toString(), - ); - } - } - subscription.queries = nextQueries; + subscription.queries = normalizeQueries(changes.queries); } this.enqueuePendingSubscribe(subscriptionId); diff --git a/src/services/storage.ts b/src/services/storage.ts index fdca28a8..f14c66cf 100644 --- a/src/services/storage.ts +++ b/src/services/storage.ts @@ -1,5 +1,5 @@ import { Service } from '../service'; -import { AppwriteException, Client } from '../client'; +import { AppwriteException, Client, applyDefaults } from '../client'; import type { Models } from '../models'; import type { UploadProgress, Payload } from '../client'; import * as FileSystem from 'expo-file-system'; @@ -113,7 +113,7 @@ export class Storage extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -122,6 +122,44 @@ export class Storage extends Service { }, apiPayload, ); + const defaults = { + root: 'fileList', + models: { + fileList: { + defaults: { + total: 0, + files: [], + }, + properties: { + files: { + items: 'file', + }, + }, + }, + file: { + defaults: { + $id: '', + bucketId: '', + $createdAt: '', + $updatedAt: '', + $permissions: [], + name: '', + folder: '', + key: '', + signature: '', + mimeType: '', + sizeOriginal: 0, + sizeActual: 0, + chunksTotal: 0, + chunksUploaded: 0, + encryption: false, + compression: 'none', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -563,7 +601,7 @@ export class Storage extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -572,6 +610,33 @@ export class Storage extends Service { }, apiPayload, ); + const defaults = { + root: 'file', + models: { + file: { + defaults: { + $id: '', + bucketId: '', + $createdAt: '', + $updatedAt: '', + $permissions: [], + name: '', + folder: '', + key: '', + signature: '', + mimeType: '', + sizeOriginal: 0, + sizeActual: 0, + chunksTotal: 0, + chunksUploaded: 0, + encryption: false, + compression: 'none', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -580,7 +645,7 @@ export class Storage extends Service { * @param {string} params.bucketId - Bucket unique ID. * @param {string} params.fileId - File ID. * @param {string} params.name - File name. - * @param {string[]} params.permissions - An array of permission strings. By default, the current permissions are inherited. [Learn more about permissions](https://appwrite.io/docs/permissions). + * @param {string[] | null} params.permissions - An array of permission strings. By default, the current permissions are inherited. [Learn more about permissions](https://appwrite.io/docs/permissions). * @throws {AppwriteException} * @returns {Promise} */ @@ -588,7 +653,7 @@ export class Storage extends Service { bucketId: string; fileId: string; name?: string; - permissions?: string[]; + permissions?: string[] | null; }): Promise; /** * Update a file by its unique ID. Only users with write permissions have access to update this resource. @@ -596,7 +661,7 @@ export class Storage extends Service { * @param {string} bucketId - Bucket unique ID. * @param {string} fileId - File ID. * @param {string} name - File name. - * @param {string[]} permissions - An array of permission strings. By default, the current permissions are inherited. [Learn more about permissions](https://appwrite.io/docs/permissions). + * @param {string[] | null} permissions - An array of permission strings. By default, the current permissions are inherited. [Learn more about permissions](https://appwrite.io/docs/permissions). * @throws {AppwriteException} * @returns {Promise} * @deprecated Use the object parameter style method for a better developer experience. @@ -605,7 +670,7 @@ export class Storage extends Service { bucketId: string, fileId: string, name?: string, - permissions?: string[], + permissions?: string[] | null, ): Promise; updateFile( paramsOrFirst: @@ -613,16 +678,16 @@ export class Storage extends Service { bucketId: string; fileId: string; name?: string; - permissions?: string[]; + permissions?: string[] | null; } | string, - ...rest: [string?, string?, string[]?] + ...rest: [string?, string?, (string[] | null)?] ): Promise { let params: { bucketId: string; fileId: string; name?: string; - permissions?: string[]; + permissions?: string[] | null; }; if ( @@ -634,14 +699,14 @@ export class Storage extends Service { bucketId: string; fileId: string; name?: string; - permissions?: string[]; + permissions?: string[] | null; }; } else { params = { bucketId: paramsOrFirst as string, fileId: rest[0] as string, name: rest[1] as string, - permissions: rest[2] as string[], + permissions: rest[2] as string[] | null, }; } @@ -674,7 +739,7 @@ export class Storage extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'put', uri, { @@ -684,6 +749,33 @@ export class Storage extends Service { }, apiPayload, ); + const defaults = { + root: 'file', + models: { + file: { + defaults: { + $id: '', + bucketId: '', + $createdAt: '', + $updatedAt: '', + $permissions: [], + name: '', + folder: '', + key: '', + signature: '', + mimeType: '', + sizeOriginal: 0, + sizeActual: 0, + chunksTotal: 0, + chunksUploaded: 0, + encryption: false, + compression: 'none', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** diff --git a/src/services/tables-db.ts b/src/services/tables-db.ts index ae5d11d1..20a11bc1 100644 --- a/src/services/tables-db.ts +++ b/src/services/tables-db.ts @@ -1,5 +1,5 @@ import { Service } from '../service'; -import { AppwriteException, Client } from '../client'; +import { AppwriteException, Client, applyDefaults } from '../client'; import type { Models } from '../models'; import type { Payload } from '../client'; @@ -71,7 +71,7 @@ export class TablesDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -80,6 +80,34 @@ export class TablesDB extends Service { }, apiPayload, ); + const defaults = { + root: 'transactionList', + models: { + transactionList: { + defaults: { + total: 0, + transactions: [], + }, + properties: { + transactions: { + items: 'transaction', + }, + }, + }, + transaction: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + status: 'pending', + operations: 0, + expiresAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -127,7 +155,7 @@ export class TablesDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -137,6 +165,23 @@ export class TablesDB extends Service { }, apiPayload, ); + const defaults = { + root: 'transaction', + models: { + transaction: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + status: 'pending', + operations: 0, + expiresAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -190,7 +235,7 @@ export class TablesDB extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -199,6 +244,23 @@ export class TablesDB extends Service { }, apiPayload, ); + const defaults = { + root: 'transaction', + models: { + transaction: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + status: 'pending', + operations: 0, + expiresAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -285,7 +347,7 @@ export class TablesDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'patch', uri, { @@ -295,6 +357,23 @@ export class TablesDB extends Service { }, apiPayload, ); + const defaults = { + root: 'transaction', + models: { + transaction: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + status: 'pending', + operations: 0, + expiresAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -427,7 +506,7 @@ export class TablesDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -437,6 +516,23 @@ export class TablesDB extends Service { }, apiPayload, ); + const defaults = { + root: 'transaction', + models: { + transaction: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + status: 'pending', + operations: 0, + expiresAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -567,7 +663,7 @@ export class TablesDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -576,6 +672,35 @@ export class TablesDB extends Service { }, apiPayload, ); + const defaults = { + root: 'rowList', + models: { + rowList: { + defaults: { + total: 0, + rows: [], + }, + properties: { + rows: { + items: 'row', + }, + }, + }, + row: { + defaults: { + $id: '', + $sequence: '', + $tableId: '', + $databaseId: '', + $createdAt: '', + $updatedAt: '', + $permissions: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -585,8 +710,8 @@ export class TablesDB extends Service { * @param {string} params.tableId - Table ID. You can create a new table using the Database service [server integration](https://appwrite.io/docs/references/cloud/server-dart/tablesDB#createTable). Make sure to define columns before creating rows. * @param {string} params.rowId - Row ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars. * @param {Row extends Models.DefaultRow ? Partial & Record : Partial & Omit} params.data - Row data as JSON object. - * @param {string[]} params.permissions - An array of permissions strings. By default, only the current user is granted all permissions. [Learn more about permissions](https://appwrite.io/docs/permissions). - * @param {string} params.transactionId - Transaction ID for staging the operation. + * @param {string[] | null} params.permissions - An array of permissions strings. By default, only the current user is granted all permissions. [Learn more about permissions](https://appwrite.io/docs/permissions). + * @param {string | null} params.transactionId - Transaction ID for staging the operation. * @throws {AppwriteException} * @returns {Promise} */ @@ -597,8 +722,8 @@ export class TablesDB extends Service { data: Row extends Models.DefaultRow ? Partial & Record : Partial & Omit; - permissions?: string[]; - transactionId?: string; + permissions?: string[] | null; + transactionId?: string | null; }): Promise; /** * Create a new Row. Before using this route, you should create a new table resource using either a [server integration](https://appwrite.io/docs/references/cloud/server-dart/tablesDB#createTable) API or directly from your database console. @@ -607,8 +732,8 @@ export class TablesDB extends Service { * @param {string} tableId - Table ID. You can create a new table using the Database service [server integration](https://appwrite.io/docs/references/cloud/server-dart/tablesDB#createTable). Make sure to define columns before creating rows. * @param {string} rowId - Row ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars. * @param {Row extends Models.DefaultRow ? Partial & Record : Partial & Omit} data - Row data as JSON object. - * @param {string[]} permissions - An array of permissions strings. By default, only the current user is granted all permissions. [Learn more about permissions](https://appwrite.io/docs/permissions). - * @param {string} transactionId - Transaction ID for staging the operation. + * @param {string[] | null} permissions - An array of permissions strings. By default, only the current user is granted all permissions. [Learn more about permissions](https://appwrite.io/docs/permissions). + * @param {string | null} transactionId - Transaction ID for staging the operation. * @throws {AppwriteException} * @returns {Promise} * @deprecated Use the object parameter style method for a better developer experience. @@ -620,8 +745,8 @@ export class TablesDB extends Service { data: Row extends Models.DefaultRow ? Partial & Record : Partial & Omit, - permissions?: string[], - transactionId?: string, + permissions?: string[] | null, + transactionId?: string | null, ): Promise; createRow( paramsOrFirst: @@ -632,8 +757,8 @@ export class TablesDB extends Service { data: Row extends Models.DefaultRow ? Partial & Record : Partial & Omit; - permissions?: string[]; - transactionId?: string; + permissions?: string[] | null; + transactionId?: string | null; } | string, ...rest: [ @@ -642,8 +767,8 @@ export class TablesDB extends Service { (Row extends Models.DefaultRow ? Partial & Record : Partial & Omit)?, - string[]?, - string?, + (string[] | null)?, + (string | null)?, ] ): Promise { let params: { @@ -653,8 +778,8 @@ export class TablesDB extends Service { data: Row extends Models.DefaultRow ? Partial & Record : Partial & Omit; - permissions?: string[]; - transactionId?: string; + permissions?: string[] | null; + transactionId?: string | null; }; if ( @@ -669,8 +794,8 @@ export class TablesDB extends Service { data: Row extends Models.DefaultRow ? Partial & Record : Partial & Omit; - permissions?: string[]; - transactionId?: string; + permissions?: string[] | null; + transactionId?: string | null; }; } else { params = { @@ -680,8 +805,8 @@ export class TablesDB extends Service { data: rest[2] as Row extends Models.DefaultRow ? Partial & Record : Partial & Omit, - permissions: rest[3] as string[], - transactionId: rest[4] as string, + permissions: rest[3] as string[] | null, + transactionId: rest[4] as string | null, }; } @@ -734,7 +859,7 @@ export class TablesDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -744,6 +869,24 @@ export class TablesDB extends Service { }, apiPayload, ); + const defaults = { + root: 'row', + models: { + row: { + defaults: { + $id: '', + $sequence: '', + $tableId: '', + $databaseId: '', + $createdAt: '', + $updatedAt: '', + $permissions: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -862,7 +1005,7 @@ export class TablesDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -871,6 +1014,24 @@ export class TablesDB extends Service { }, apiPayload, ); + const defaults = { + root: 'row', + models: { + row: { + defaults: { + $id: '', + $sequence: '', + $tableId: '', + $databaseId: '', + $createdAt: '', + $updatedAt: '', + $permissions: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -880,8 +1041,8 @@ export class TablesDB extends Service { * @param {string} params.tableId - Table ID. * @param {string} params.rowId - Row ID. * @param {Row extends Models.DefaultRow ? Partial & Record : Partial & Partial>} params.data - Row data as JSON object. Include all required columns of the row to be created or updated. - * @param {string[]} params.permissions - An array of permissions strings. By default, the current permissions are inherited. [Learn more about permissions](https://appwrite.io/docs/permissions). - * @param {string} params.transactionId - Transaction ID for staging the operation. + * @param {string[] | null} params.permissions - An array of permissions strings. By default, the current permissions are inherited. [Learn more about permissions](https://appwrite.io/docs/permissions). + * @param {string | null} params.transactionId - Transaction ID for staging the operation. * @throws {AppwriteException} * @returns {Promise} */ @@ -892,8 +1053,8 @@ export class TablesDB extends Service { data?: Row extends Models.DefaultRow ? Partial & Record : Partial & Partial>; - permissions?: string[]; - transactionId?: string; + permissions?: string[] | null; + transactionId?: string | null; }): Promise; /** * Create or update a Row. Before using this route, you should create a new table resource using either a [server integration](https://appwrite.io/docs/references/cloud/server-dart/tablesDB#createTable) API or directly from your database console. @@ -902,8 +1063,8 @@ export class TablesDB extends Service { * @param {string} tableId - Table ID. * @param {string} rowId - Row ID. * @param {Row extends Models.DefaultRow ? Partial & Record : Partial & Partial>} data - Row data as JSON object. Include all required columns of the row to be created or updated. - * @param {string[]} permissions - An array of permissions strings. By default, the current permissions are inherited. [Learn more about permissions](https://appwrite.io/docs/permissions). - * @param {string} transactionId - Transaction ID for staging the operation. + * @param {string[] | null} permissions - An array of permissions strings. By default, the current permissions are inherited. [Learn more about permissions](https://appwrite.io/docs/permissions). + * @param {string | null} transactionId - Transaction ID for staging the operation. * @throws {AppwriteException} * @returns {Promise} * @deprecated Use the object parameter style method for a better developer experience. @@ -915,8 +1076,8 @@ export class TablesDB extends Service { data?: Row extends Models.DefaultRow ? Partial & Record : Partial & Partial>, - permissions?: string[], - transactionId?: string, + permissions?: string[] | null, + transactionId?: string | null, ): Promise; upsertRow( paramsOrFirst: @@ -928,8 +1089,8 @@ export class TablesDB extends Service { ? Partial & Record : Partial & Partial>; - permissions?: string[]; - transactionId?: string; + permissions?: string[] | null; + transactionId?: string | null; } | string, ...rest: [ @@ -938,8 +1099,8 @@ export class TablesDB extends Service { (Row extends Models.DefaultRow ? Partial & Record : Partial & Partial>)?, - string[]?, - string?, + (string[] | null)?, + (string | null)?, ] ): Promise { let params: { @@ -949,8 +1110,8 @@ export class TablesDB extends Service { data?: Row extends Models.DefaultRow ? Partial & Record : Partial & Partial>; - permissions?: string[]; - transactionId?: string; + permissions?: string[] | null; + transactionId?: string | null; }; if ( @@ -966,8 +1127,8 @@ export class TablesDB extends Service { ? Partial & Record : Partial & Partial>; - permissions?: string[]; - transactionId?: string; + permissions?: string[] | null; + transactionId?: string | null; }; } else { params = { @@ -978,8 +1139,8 @@ export class TablesDB extends Service { ? Partial & Record : Partial & Partial>, - permissions: rest[3] as string[], - transactionId: rest[4] as string, + permissions: rest[3] as string[] | null, + transactionId: rest[4] as string | null, }; } @@ -1025,7 +1186,7 @@ export class TablesDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'put', uri, { @@ -1035,6 +1196,24 @@ export class TablesDB extends Service { }, apiPayload, ); + const defaults = { + root: 'row', + models: { + row: { + defaults: { + $id: '', + $sequence: '', + $tableId: '', + $databaseId: '', + $createdAt: '', + $updatedAt: '', + $permissions: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1044,8 +1223,8 @@ export class TablesDB extends Service { * @param {string} params.tableId - Table ID. * @param {string} params.rowId - Row ID. * @param {Row extends Models.DefaultRow ? Partial & Record : Partial & Partial>} params.data - Row data as JSON object. Include only columns and value pairs to be updated. - * @param {string[]} params.permissions - An array of permissions strings. By default, the current permissions are inherited. [Learn more about permissions](https://appwrite.io/docs/permissions). - * @param {string} params.transactionId - Transaction ID for staging the operation. + * @param {string[] | null} params.permissions - An array of permissions strings. By default, the current permissions are inherited. [Learn more about permissions](https://appwrite.io/docs/permissions). + * @param {string | null} params.transactionId - Transaction ID for staging the operation. * @throws {AppwriteException} * @returns {Promise} */ @@ -1056,8 +1235,8 @@ export class TablesDB extends Service { data?: Row extends Models.DefaultRow ? Partial & Record : Partial & Partial>; - permissions?: string[]; - transactionId?: string; + permissions?: string[] | null; + transactionId?: string | null; }): Promise; /** * Update a row by its unique ID. Using the patch method you can pass only specific fields that will get updated. @@ -1066,8 +1245,8 @@ export class TablesDB extends Service { * @param {string} tableId - Table ID. * @param {string} rowId - Row ID. * @param {Row extends Models.DefaultRow ? Partial & Record : Partial & Partial>} data - Row data as JSON object. Include only columns and value pairs to be updated. - * @param {string[]} permissions - An array of permissions strings. By default, the current permissions are inherited. [Learn more about permissions](https://appwrite.io/docs/permissions). - * @param {string} transactionId - Transaction ID for staging the operation. + * @param {string[] | null} permissions - An array of permissions strings. By default, the current permissions are inherited. [Learn more about permissions](https://appwrite.io/docs/permissions). + * @param {string | null} transactionId - Transaction ID for staging the operation. * @throws {AppwriteException} * @returns {Promise} * @deprecated Use the object parameter style method for a better developer experience. @@ -1079,8 +1258,8 @@ export class TablesDB extends Service { data?: Row extends Models.DefaultRow ? Partial & Record : Partial & Partial>, - permissions?: string[], - transactionId?: string, + permissions?: string[] | null, + transactionId?: string | null, ): Promise; updateRow( paramsOrFirst: @@ -1092,8 +1271,8 @@ export class TablesDB extends Service { ? Partial & Record : Partial & Partial>; - permissions?: string[]; - transactionId?: string; + permissions?: string[] | null; + transactionId?: string | null; } | string, ...rest: [ @@ -1102,8 +1281,8 @@ export class TablesDB extends Service { (Row extends Models.DefaultRow ? Partial & Record : Partial & Partial>)?, - string[]?, - string?, + (string[] | null)?, + (string | null)?, ] ): Promise { let params: { @@ -1113,8 +1292,8 @@ export class TablesDB extends Service { data?: Row extends Models.DefaultRow ? Partial & Record : Partial & Partial>; - permissions?: string[]; - transactionId?: string; + permissions?: string[] | null; + transactionId?: string | null; }; if ( @@ -1130,8 +1309,8 @@ export class TablesDB extends Service { ? Partial & Record : Partial & Partial>; - permissions?: string[]; - transactionId?: string; + permissions?: string[] | null; + transactionId?: string | null; }; } else { params = { @@ -1142,8 +1321,8 @@ export class TablesDB extends Service { ? Partial & Record : Partial & Partial>, - permissions: rest[3] as string[], - transactionId: rest[4] as string, + permissions: rest[3] as string[] | null, + transactionId: rest[4] as string | null, }; } @@ -1189,7 +1368,7 @@ export class TablesDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'patch', uri, { @@ -1199,6 +1378,24 @@ export class TablesDB extends Service { }, apiPayload, ); + const defaults = { + root: 'row', + models: { + row: { + defaults: { + $id: '', + $sequence: '', + $tableId: '', + $databaseId: '', + $createdAt: '', + $updatedAt: '', + $permissions: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1324,8 +1521,8 @@ export class TablesDB extends Service { * @param {string} params.rowId - Row ID. * @param {string} params.column - Column key. * @param {number} params.value - Value to increment the column by. The value must be a number. - * @param {number} params.min - Minimum value for the column. If the current value is lesser than this value, an exception will be thrown. - * @param {string} params.transactionId - Transaction ID for staging the operation. + * @param {number | null} params.min - Minimum value for the column. If the current value is lesser than this value, an exception will be thrown. + * @param {string | null} params.transactionId - Transaction ID for staging the operation. * @throws {AppwriteException} * @returns {Promise} */ @@ -1335,8 +1532,8 @@ export class TablesDB extends Service { rowId: string; column: string; value?: number; - min?: number; - transactionId?: string; + min?: number | null; + transactionId?: string | null; }): Promise; /** * Decrement a specific column of a row by a given value. @@ -1346,8 +1543,8 @@ export class TablesDB extends Service { * @param {string} rowId - Row ID. * @param {string} column - Column key. * @param {number} value - Value to increment the column by. The value must be a number. - * @param {number} min - Minimum value for the column. If the current value is lesser than this value, an exception will be thrown. - * @param {string} transactionId - Transaction ID for staging the operation. + * @param {number | null} min - Minimum value for the column. If the current value is lesser than this value, an exception will be thrown. + * @param {string | null} transactionId - Transaction ID for staging the operation. * @throws {AppwriteException} * @returns {Promise} * @deprecated Use the object parameter style method for a better developer experience. @@ -1358,8 +1555,8 @@ export class TablesDB extends Service { rowId: string, column: string, value?: number, - min?: number, - transactionId?: string, + min?: number | null, + transactionId?: string | null, ): Promise; decrementRowColumn( paramsOrFirst: @@ -1369,11 +1566,18 @@ export class TablesDB extends Service { rowId: string; column: string; value?: number; - min?: number; - transactionId?: string; + min?: number | null; + transactionId?: string | null; } | string, - ...rest: [string?, string?, string?, number?, number?, string?] + ...rest: [ + string?, + string?, + string?, + number?, + (number | null)?, + (string | null)?, + ] ): Promise { let params: { databaseId: string; @@ -1381,8 +1585,8 @@ export class TablesDB extends Service { rowId: string; column: string; value?: number; - min?: number; - transactionId?: string; + min?: number | null; + transactionId?: string | null; }; if ( @@ -1396,8 +1600,8 @@ export class TablesDB extends Service { rowId: string; column: string; value?: number; - min?: number; - transactionId?: string; + min?: number | null; + transactionId?: string | null; }; } else { params = { @@ -1406,8 +1610,8 @@ export class TablesDB extends Service { rowId: rest[1] as string, column: rest[2] as string, value: rest[3] as number, - min: rest[4] as number, - transactionId: rest[5] as string, + min: rest[4] as number | null, + transactionId: rest[5] as string | null, }; } @@ -1460,7 +1664,7 @@ export class TablesDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'patch', uri, { @@ -1470,6 +1674,24 @@ export class TablesDB extends Service { }, apiPayload, ); + const defaults = { + root: 'row', + models: { + row: { + defaults: { + $id: '', + $sequence: '', + $tableId: '', + $databaseId: '', + $createdAt: '', + $updatedAt: '', + $permissions: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1480,8 +1702,8 @@ export class TablesDB extends Service { * @param {string} params.rowId - Row ID. * @param {string} params.column - Column key. * @param {number} params.value - Value to increment the column by. The value must be a number. - * @param {number} params.max - Maximum value for the column. If the current value is greater than this value, an error will be thrown. - * @param {string} params.transactionId - Transaction ID for staging the operation. + * @param {number | null} params.max - Maximum value for the column. If the current value is greater than this value, an error will be thrown. + * @param {string | null} params.transactionId - Transaction ID for staging the operation. * @throws {AppwriteException} * @returns {Promise} */ @@ -1491,8 +1713,8 @@ export class TablesDB extends Service { rowId: string; column: string; value?: number; - max?: number; - transactionId?: string; + max?: number | null; + transactionId?: string | null; }): Promise; /** * Increment a specific column of a row by a given value. @@ -1502,8 +1724,8 @@ export class TablesDB extends Service { * @param {string} rowId - Row ID. * @param {string} column - Column key. * @param {number} value - Value to increment the column by. The value must be a number. - * @param {number} max - Maximum value for the column. If the current value is greater than this value, an error will be thrown. - * @param {string} transactionId - Transaction ID for staging the operation. + * @param {number | null} max - Maximum value for the column. If the current value is greater than this value, an error will be thrown. + * @param {string | null} transactionId - Transaction ID for staging the operation. * @throws {AppwriteException} * @returns {Promise} * @deprecated Use the object parameter style method for a better developer experience. @@ -1514,8 +1736,8 @@ export class TablesDB extends Service { rowId: string, column: string, value?: number, - max?: number, - transactionId?: string, + max?: number | null, + transactionId?: string | null, ): Promise; incrementRowColumn( paramsOrFirst: @@ -1525,11 +1747,18 @@ export class TablesDB extends Service { rowId: string; column: string; value?: number; - max?: number; - transactionId?: string; + max?: number | null; + transactionId?: string | null; } | string, - ...rest: [string?, string?, string?, number?, number?, string?] + ...rest: [ + string?, + string?, + string?, + number?, + (number | null)?, + (string | null)?, + ] ): Promise { let params: { databaseId: string; @@ -1537,8 +1766,8 @@ export class TablesDB extends Service { rowId: string; column: string; value?: number; - max?: number; - transactionId?: string; + max?: number | null; + transactionId?: string | null; }; if ( @@ -1552,8 +1781,8 @@ export class TablesDB extends Service { rowId: string; column: string; value?: number; - max?: number; - transactionId?: string; + max?: number | null; + transactionId?: string | null; }; } else { params = { @@ -1562,8 +1791,8 @@ export class TablesDB extends Service { rowId: rest[1] as string, column: rest[2] as string, value: rest[3] as number, - max: rest[4] as number, - transactionId: rest[5] as string, + max: rest[4] as number | null, + transactionId: rest[5] as string | null, }; } @@ -1616,7 +1845,7 @@ export class TablesDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'patch', uri, { @@ -1626,5 +1855,23 @@ export class TablesDB extends Service { }, apiPayload, ); + const defaults = { + root: 'row', + models: { + row: { + defaults: { + $id: '', + $sequence: '', + $tableId: '', + $databaseId: '', + $createdAt: '', + $updatedAt: '', + $permissions: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } } diff --git a/src/services/teams.ts b/src/services/teams.ts index a4424fcd..b5cd1362 100644 --- a/src/services/teams.ts +++ b/src/services/teams.ts @@ -1,5 +1,5 @@ import { Service } from '../service'; -import { AppwriteException, Client } from '../client'; +import { AppwriteException, Client, applyDefaults } from '../client'; import type { Models } from '../models'; import type { Payload } from '../client'; @@ -85,7 +85,7 @@ export class Teams extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -94,6 +94,33 @@ export class Teams extends Service { }, apiPayload, ); + const defaults = { + root: 'teamList', + models: { + teamList: { + defaults: { + total: 0, + teams: [], + }, + properties: { + teams: { + items: 'team', + }, + }, + }, + team: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + total: 0, + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -180,7 +207,7 @@ export class Teams extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -190,6 +217,22 @@ export class Teams extends Service { }, apiPayload, ); + const defaults = { + root: 'team', + models: { + team: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + total: 0, + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -243,7 +286,7 @@ export class Teams extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -252,6 +295,22 @@ export class Teams extends Service { }, apiPayload, ); + const defaults = { + root: 'team', + models: { + team: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + total: 0, + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -323,7 +382,7 @@ export class Teams extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'put', uri, { @@ -333,6 +392,22 @@ export class Teams extends Service { }, apiPayload, ); + const defaults = { + root: 'team', + models: { + team: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + total: 0, + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -469,7 +544,7 @@ export class Teams extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -478,6 +553,37 @@ export class Teams extends Service { }, apiPayload, ); + const defaults = { + root: 'appInstallationList', + models: { + appInstallationList: { + defaults: { + total: 0, + installations: [], + }, + properties: { + installations: { + items: 'appInstallation', + }, + }, + }, + appInstallation: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + appId: '', + teamId: '', + scopes: [], + authorizationDetails: [], + createdById: '', + createdByName: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -566,7 +672,7 @@ export class Teams extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -576,6 +682,26 @@ export class Teams extends Service { }, apiPayload, ); + const defaults = { + root: 'appInstallation', + models: { + appInstallation: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + appId: '', + teamId: '', + scopes: [], + authorizationDetails: [], + createdById: '', + createdByName: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -647,7 +773,7 @@ export class Teams extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -656,6 +782,26 @@ export class Teams extends Service { }, apiPayload, ); + const defaults = { + root: 'appInstallation', + models: { + appInstallation: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + appId: '', + teamId: '', + scopes: [], + authorizationDetails: [], + createdById: '', + createdByName: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -663,21 +809,21 @@ export class Teams extends Service { * * @param {string} params.teamId - Team ID. * @param {string} params.installationId - Installation unique ID. - * @param {string} params.authorizationDetails - Authorization details granted to the installation as a JSON array of objects, each with a `type` and app-defined fields. Omit to keep the current value. + * @param {string | null} params.authorizationDetails - Authorization details granted to the installation as a JSON array of objects, each with a `type` and app-defined fields. Omit to keep the current value. * @throws {AppwriteException} * @returns {Promise} */ updateInstallation(params: { teamId: string; installationId: string; - authorizationDetails?: string; + authorizationDetails?: string | null; }): Promise; /** * Update an app installation on a team. Only team members with the owner role can update installations. The installation's granted scopes are refreshed to the scopes the app currently requests; previously issued installation access tokens are revoked. * * @param {string} teamId - Team ID. * @param {string} installationId - Installation unique ID. - * @param {string} authorizationDetails - Authorization details granted to the installation as a JSON array of objects, each with a `type` and app-defined fields. Omit to keep the current value. + * @param {string | null} authorizationDetails - Authorization details granted to the installation as a JSON array of objects, each with a `type` and app-defined fields. Omit to keep the current value. * @throws {AppwriteException} * @returns {Promise} * @deprecated Use the object parameter style method for a better developer experience. @@ -685,22 +831,22 @@ export class Teams extends Service { updateInstallation( teamId: string, installationId: string, - authorizationDetails?: string, + authorizationDetails?: string | null, ): Promise; updateInstallation( paramsOrFirst: | { teamId: string; installationId: string; - authorizationDetails?: string; + authorizationDetails?: string | null; } | string, - ...rest: [string?, string?] + ...rest: [string?, (string | null)?] ): Promise { let params: { teamId: string; installationId: string; - authorizationDetails?: string; + authorizationDetails?: string | null; }; if ( @@ -711,13 +857,13 @@ export class Teams extends Service { params = (paramsOrFirst || {}) as { teamId: string; installationId: string; - authorizationDetails?: string; + authorizationDetails?: string | null; }; } else { params = { teamId: paramsOrFirst as string, installationId: rest[0] as string, - authorizationDetails: rest[1] as string, + authorizationDetails: rest[1] as string | null, }; } @@ -748,7 +894,7 @@ export class Teams extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'put', uri, { @@ -758,6 +904,26 @@ export class Teams extends Service { }, apiPayload, ); + const defaults = { + root: 'appInstallation', + models: { + appInstallation: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + appId: '', + teamId: '', + scopes: [], + authorizationDetails: [], + createdById: '', + createdByName: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -937,7 +1103,7 @@ export class Teams extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -946,6 +1112,43 @@ export class Teams extends Service { }, apiPayload, ); + const defaults = { + root: 'membershipList', + models: { + membershipList: { + defaults: { + total: 0, + memberships: [], + }, + properties: { + memberships: { + items: 'membership', + }, + }, + }, + membership: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + userId: '', + userName: '', + userEmail: '', + userPhone: '', + teamId: '', + teamName: '', + invited: '', + joined: '', + confirm: false, + mfa: false, + userAccessedAt: '', + roles: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -965,6 +1168,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 +1180,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 +1199,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 +1212,7 @@ export class Teams extends Service { phone?: string, url?: string, name?: string, + membershipId?: string, ): Promise; createMembership( paramsOrFirst: @@ -1017,9 +1224,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 +1245,7 @@ export class Teams extends Service { phone?: string; url?: string; name?: string; + membershipId?: string; }; if ( @@ -1044,6 +1261,7 @@ export class Teams extends Service { phone?: string; url?: string; name?: string; + membershipId?: string; }; } else { params = { @@ -1054,6 +1272,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 +1283,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,8 +1323,12 @@ export class Teams extends Service { apiPayload['name'] = name; } + if (typeof membershipId !== 'undefined') { + apiPayload['membershipId'] = membershipId; + } + const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -1114,6 +1338,32 @@ export class Teams extends Service { }, apiPayload, ); + const defaults = { + root: 'membership', + models: { + membership: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + userId: '', + userName: '', + userEmail: '', + userPhone: '', + teamId: '', + teamName: '', + invited: '', + joined: '', + confirm: false, + mfa: false, + userAccessedAt: '', + roles: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1185,7 +1435,7 @@ export class Teams extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -1194,6 +1444,32 @@ export class Teams extends Service { }, apiPayload, ); + const defaults = { + root: 'membership', + models: { + membership: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + userId: '', + userName: '', + userEmail: '', + userPhone: '', + teamId: '', + teamName: '', + invited: '', + joined: '', + confirm: false, + mfa: false, + userAccessedAt: '', + roles: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1283,7 +1559,7 @@ export class Teams extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'patch', uri, { @@ -1293,6 +1569,32 @@ export class Teams extends Service { }, apiPayload, ); + const defaults = { + root: 'membership', + models: { + membership: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + userId: '', + userName: '', + userEmail: '', + userPhone: '', + teamId: '', + teamName: '', + invited: '', + joined: '', + confirm: false, + mfa: false, + userAccessedAt: '', + roles: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1490,7 +1792,7 @@ export class Teams extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'patch', uri, { @@ -1500,6 +1802,32 @@ export class Teams extends Service { }, apiPayload, ); + const defaults = { + root: 'membership', + models: { + membership: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + userId: '', + userName: '', + userEmail: '', + userPhone: '', + teamId: '', + teamName: '', + invited: '', + joined: '', + confirm: false, + mfa: false, + userAccessedAt: '', + roles: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** diff --git a/src/services/vectors-db.ts b/src/services/vectors-db.ts index 710e8b44..61b4df27 100644 --- a/src/services/vectors-db.ts +++ b/src/services/vectors-db.ts @@ -1,5 +1,5 @@ import { Service } from '../service'; -import { AppwriteException, Client } from '../client'; +import { AppwriteException, Client, applyDefaults } from '../client'; import type { Models } from '../models'; import type { Payload } from '../client'; @@ -71,7 +71,7 @@ export class VectorsDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -80,6 +80,34 @@ export class VectorsDB extends Service { }, apiPayload, ); + const defaults = { + root: 'transactionList', + models: { + transactionList: { + defaults: { + total: 0, + transactions: [], + }, + properties: { + transactions: { + items: 'transaction', + }, + }, + }, + transaction: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + status: 'pending', + operations: 0, + expiresAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -127,7 +155,7 @@ export class VectorsDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -137,6 +165,23 @@ export class VectorsDB extends Service { }, apiPayload, ); + const defaults = { + root: 'transaction', + models: { + transaction: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + status: 'pending', + operations: 0, + expiresAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -190,7 +235,7 @@ export class VectorsDB extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -199,6 +244,23 @@ export class VectorsDB extends Service { }, apiPayload, ); + const defaults = { + root: 'transaction', + models: { + transaction: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + status: 'pending', + operations: 0, + expiresAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -285,7 +347,7 @@ export class VectorsDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'patch', uri, { @@ -295,6 +357,23 @@ export class VectorsDB extends Service { }, apiPayload, ); + const defaults = { + root: 'transaction', + models: { + transaction: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + status: 'pending', + operations: 0, + expiresAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -427,7 +506,7 @@ export class VectorsDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -437,6 +516,23 @@ export class VectorsDB extends Service { }, apiPayload, ); + const defaults = { + root: 'transaction', + models: { + transaction: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + status: 'pending', + operations: 0, + expiresAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -573,7 +669,7 @@ export class VectorsDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -582,6 +678,35 @@ export class VectorsDB extends Service { }, apiPayload, ); + const defaults = { + root: 'documentList', + models: { + documentList: { + defaults: { + total: 0, + documents: [], + }, + properties: { + documents: { + items: 'document', + }, + }, + }, + document: { + defaults: { + $id: '', + $sequence: '', + $collectionId: '', + $databaseId: '', + $createdAt: '', + $updatedAt: '', + $permissions: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -753,7 +878,7 @@ export class VectorsDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -763,6 +888,24 @@ export class VectorsDB extends Service { }, apiPayload, ); + const defaults = { + root: 'document', + models: { + document: { + defaults: { + $id: '', + $sequence: '', + $collectionId: '', + $databaseId: '', + $createdAt: '', + $updatedAt: '', + $permissions: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -901,7 +1044,7 @@ export class VectorsDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -911,6 +1054,35 @@ export class VectorsDB extends Service { }, apiPayload, ); + const defaults = { + root: 'documentList', + models: { + documentList: { + defaults: { + total: 0, + documents: [], + }, + properties: { + documents: { + items: 'document', + }, + }, + }, + document: { + defaults: { + $id: '', + $sequence: '', + $collectionId: '', + $databaseId: '', + $createdAt: '', + $updatedAt: '', + $permissions: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1040,7 +1212,7 @@ export class VectorsDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -1049,6 +1221,24 @@ export class VectorsDB extends Service { }, apiPayload, ); + const defaults = { + root: 'document', + models: { + document: { + defaults: { + $id: '', + $sequence: '', + $collectionId: '', + $databaseId: '', + $createdAt: '', + $updatedAt: '', + $permissions: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1218,7 +1408,7 @@ export class VectorsDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'put', uri, { @@ -1228,6 +1418,24 @@ export class VectorsDB extends Service { }, apiPayload, ); + const defaults = { + root: 'document', + models: { + document: { + defaults: { + $id: '', + $sequence: '', + $collectionId: '', + $databaseId: '', + $createdAt: '', + $updatedAt: '', + $permissions: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1397,7 +1605,7 @@ export class VectorsDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'patch', uri, { @@ -1407,6 +1615,24 @@ export class VectorsDB extends Service { }, apiPayload, ); + const defaults = { + root: 'document', + models: { + document: { + defaults: { + $id: '', + $sequence: '', + $collectionId: '', + $databaseId: '', + $createdAt: '', + $updatedAt: '', + $permissions: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** diff --git a/src/topic.ts b/src/topic.ts index cd6cea01..071d5aec 100644 --- a/src/topic.ts +++ b/src/topic.ts @@ -1,6 +1,6 @@ /** * Validate the levels passed to `path()`: a non-empty array of non-empty strings, none holding - * the level separator `/` or the wildcards `+` and `#` (use `any()` and `all()` for those). + * the level separator `/` or the MQTT wildcards `+` and `#`. */ function levelsOf(levels: unknown): string[] { if (!Array.isArray(levels)) { @@ -28,17 +28,14 @@ function levelsOf(levels: unknown): string[] { `"${level}" contains "/", split it: path([${parts}])`, ); } - if (level === '+') { - throw new Error('"+" is reserved, use any()'); - } if (level.includes('+')) { - throw new Error(`"${level}" contains "+", use any() for wildcards`); - } - if (level === '#') { - throw new Error('"#" is reserved, use all()'); + throw new Error(`"${level}" contains "+", not allowed in a topic`); } if (level.includes('#')) { - throw new Error(`"${level}" contains "#", use all() for wildcards`); + throw new Error(`"${level}" contains "#", not allowed in a topic`); + } + if (level.includes('\0')) { + throw new Error(`level at index ${index} contains a NUL character`); } return level; }); @@ -48,11 +45,7 @@ function levelsOf(levels: unknown): string[] { * Helper to build MQTT topics for `Push`, level by level. * * Topic.path(['user', userId, 'notification']); // "user/123/notification" - * Topic.path(['user']).any().path(['notification']); // "user/+/notification" - * Topic.path(['org']).any().path(['logs']).all(); // "org/+/logs/#" - * - * `any()` matches exactly one level and `all()` everything below, at any depth (including the - * parent itself). `all()` ends the topic, so it returns a {@link ResolvedTopic}. + * Topic.path(['org', orgId]).path(['logs']); // "org/42/logs" */ export class Topic { private constructor(private readonly levels: readonly string[]) {} @@ -62,41 +55,11 @@ export class Topic { return new Topic(levelsOf(levels)); } - /** Start a topic with a single-level wildcard (`+`). */ - static any(): Topic { - return new Topic(['+']); - } - - /** The multi-level wildcard alone (`#`): matches every topic. */ - static all(): ResolvedTopic { - return new ResolvedTopic(['#']); - } - /** Append the given levels. */ path(levels: string[]): Topic { return new Topic([...this.levels, ...levelsOf(levels)]); } - /** Append a single-level wildcard (`+`): matches exactly one level. */ - any(): Topic { - return new Topic([...this.levels, '+']); - } - - /** Append the multi-level wildcard (`#`) and end the topic. */ - all(): ResolvedTopic { - return new ResolvedTopic([...this.levels, '#']); - } - - toString(): string { - return this.levels.join('/'); - } -} - -/** A topic ended by `all()`: nothing can be appended after the `#` wildcard. */ -export class ResolvedTopic { - /** @internal Created by {@link Topic.all}. */ - constructor(private readonly levels: readonly string[]) {} - toString(): string { return this.levels.join('/'); } From 72752a030f1b85e72b3c5e8abebdd1b08284315b Mon Sep 17 00:00:00 2001 From: Chirag Aggarwal Date: Thu, 15 Oct 2026 12:53:58 +0100 Subject: [PATCH 6/6] feat: SDK update for the 2.5.x majors --- CHANGELOG.md | 75 +- README.md | 76 +- android/src/main/AndroidManifest.xml | 10 +- .../reactnative/AppwritePushModule.kt | 8 +- .../exceptions/AppwriteException.kt | 2 +- .../services/PushBackground.kt | 51 +- .../{ => reactnative}/services/PushBridge.kt | 5 +- .../{ => reactnative}/services/PushCore.kt | 29 +- .../services/PushOpenActivity.kt | 2 +- .../services/PushReceiver.kt | 4 +- .../{ => reactnative}/services/PushService.kt | 2 +- .../{ => reactnative}/services/PushWakeups.kt | 2 +- .../account/create-o-auth-2-session.md | 1 + .../examples/account/create-o-auth-2-token.md | 1 + docs/examples/account/create-passkey-token.md | 13 + docs/examples/account/create-passkey.md | 16 + docs/examples/account/delete-passkey.md | 15 + docs/examples/account/get-passkey.md | 15 + docs/examples/account/list-passkeys.md | 16 + docs/examples/account/update-passkey-token.md | 16 + .../account/update-passkey-verification.md | 16 + docs/examples/account/update-passkey.md | 16 + docs/examples/analytics/create-event.md | 27 + docs/examples/oauth2/authorize-post.md | 2 +- docs/examples/oauth2/authorize.md | 2 +- .../oauth2/create-device-authorization.md | 2 +- docs/examples/oauth2/create-par.md | 2 +- docs/examples/oauth2/create-token.md | 2 +- docs/examples/teams/create-membership.md | 1 + package-lock.json | 4 +- package.json | 2 +- src/client.ts | 83 +- src/enums/execution-trigger.ts | 1 + src/index.ts | 7 +- src/models.ts | 178 +- src/query.ts | 786 ++++++ src/services/account.ts | 2423 ++++++++++++++++- src/services/analytics.ts | 260 ++ src/services/apps.ts | 572 +++- src/services/databases.ts | 449 ++- src/services/documents-db.ts | 290 +- src/services/functions.ts | 160 +- src/services/locale.ts | 211 +- src/services/messaging.ts | 23 +- src/services/oauth-2.ts | 340 ++- src/services/organization.ts | 123 +- src/services/presences.ts | 89 +- src/services/push.ts | 114 +- src/services/realtime.ts | 51 +- src/services/storage.ts | 118 +- src/services/tables-db.ts | 449 ++- src/services/teams.ts | 376 ++- src/services/vectors-db.ts | 250 +- src/topic.ts | 51 +- 54 files changed, 7052 insertions(+), 787 deletions(-) rename android/src/main/java/io/appwrite/{ => reactnative}/exceptions/AppwriteException.kt (81%) rename android/src/main/java/io/appwrite/{ => reactnative}/services/PushBackground.kt (96%) rename android/src/main/java/io/appwrite/{ => reactnative}/services/PushBridge.kt (97%) rename android/src/main/java/io/appwrite/{ => reactnative}/services/PushCore.kt (93%) rename android/src/main/java/io/appwrite/{ => reactnative}/services/PushOpenActivity.kt (97%) rename android/src/main/java/io/appwrite/{ => reactnative}/services/PushReceiver.kt (90%) rename android/src/main/java/io/appwrite/{ => reactnative}/services/PushService.kt (98%) rename android/src/main/java/io/appwrite/{ => reactnative}/services/PushWakeups.kt (98%) create mode 100644 docs/examples/account/create-passkey-token.md create mode 100644 docs/examples/account/create-passkey.md create mode 100644 docs/examples/account/delete-passkey.md create mode 100644 docs/examples/account/get-passkey.md create mode 100644 docs/examples/account/list-passkeys.md create mode 100644 docs/examples/account/update-passkey-token.md create mode 100644 docs/examples/account/update-passkey-verification.md create mode 100644 docs/examples/account/update-passkey.md create mode 100644 docs/examples/analytics/create-event.md create mode 100644 src/services/analytics.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index c6c7bcb3..3897ac8c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,50 +1,37 @@ # Change log -## 1.2.0-rc.4 - -* Fixed: `host()` resolves with the live connection state instead of always `null` -* Fixed: `onConnection(false)` fires when a retired or background connection closes -* Fixed: notification taps are recorded after launching the app, so tap-opened screens land on top -* Fixed: `host()` reports `false` when there was nothing to subscribe instead of a spurious open - -## 1.2.0-rc.3 - -* Added: `getInitialNotification()`, `onNotificationOpened()`, and the `PushNotificationOpened` type (topic + data) -* Added: live push connection open/close events surfaced via `onOpen`/`onClose` -* Fixed: notification taps delivered reliably once, via a `PushTaps` queue -* Fixed: foreground notifications de-duplicated per title -* Updated: `resume` leaves a live Push host's connection untouched - -## 1.2.0-rc.2 - -* Added: `Push.getInitialNotification()` returns the notification whose tap launched the app -* Added: `Push.onNotificationOpened(callback)` fires on each notification tap -* Added: `Push.backgroundStatus()` reports Android exact-alarm, battery, and foreground-service state -* Added: `Push.requestExactAlarms()` and `Push.requestIgnoreBatteryOptimizations()` helpers -* Added: `SubscribeOptions.notifyInForeground` to post notifications while the app is visible -* Added: `PushBackgroundStatus` and `PushNotificationOpened` exported types -* Fixed: reliable Android background wake-ups via a periodic watchdog and alternating jobs -* Fixed: `resume` keeps subscriptions only for the same signed-in user -* Fixed: notification images are size-capped to prevent out-of-memory crashes - -## 1.2.0-rc.1 - -* Added: background push notifications render the server `notification` title, body, and image -* Added: Android shows notification images (BigPictureStyle) and long bodies (BigTextStyle) -* Added: the SDK requests Android 13+ `POST_NOTIFICATIONS` itself on first background subscribe -* Added: notification `data` now carries `topic` and `payload` -* Fixed: a server-sent title dedupes to one notification per topic instead of one per subscription - -## 1.2.0-rc.0 - -* Added: `Apps` service to manage OAuth2 apps, keys, secrets, and installations -* Added: `Oauth2` service for authorization, consent, device, PAR, and token flows -* Added: `Push` service for MQTT realtime push with Android background delivery -* Added: `Topic` builder and native TCP modules for push -* Added: `Avatars.updatePhoto()` and `Avatars.deletePhoto()` methods -* Added: `App`, `Oauth2*`, and `Account` models +## 2.0.0 + +* Breaking: requests send `X-Appwrite-Response-Format: 2.5.0`; responses follow the 2.5 shapes +* Breaking: missing response fields are filled with their documented defaults +* Breaking: nullable model fields are typed `T | null`, such as `Locale.city` and `Presence.status` +* Breaking: the package ships native Android and iOS modules, so apps need a native rebuild and do not run in Expo Go +* Added: `Apps` service to manage apps, installations, keys and secrets +* Added: `Oauth2` service for the OAuth2 authorize, token, device and grant flows +* Added: `Push` service, with optional peers `expo-notifications`, `react-native-background-actions` and `react-native-tcp-socket` +* Added: `Topic` helper +* Added: Android push code ships under `io.appwrite.reactnative`, so apps can also depend on `sdk-for-android`; set the notification icon with the `io.appwrite.reactnative.push.notification_icon` meta-data +* Added: `Query` aggregates (`count`, `countDistinct`, `sum`, `avg`, `min`, `max` and more), `groupBy`, `having`, `distinct`, joins, `relationship`, `covers`, `spatialEquals` and `page` +* Added: `Query.builder()` to chain queries; realtime subscriptions accept a builder for `queries` +* Added: `ExecutionTrigger.Email` +* Fixed: list and object defaults filled into a response are copied per model, and object defaults are `{}` instead of `[]` + +## 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 -* Fixed: cookie session fallback is guarded to Expo web where `localStorage` exists +* 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` +* Added: `account.createPasskeyToken` and `account.updatePasskeyToken` for passkey sign-in +* Added: `Passkey`, `PasskeyList`, `PasskeyChallenge` and `TokenSecret` models ## 1.1.0 diff --git a/README.md b/README.md index 0ba50f82..76d719ef 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,12 @@ # Appwrite React Native SDK ![License](https://img.shields.io/github/license/appwrite/sdk-for-react-native.svg?style=flat-square) -![Version](https://img.shields.io/badge/api%20version-2.3.0-blue.svg?style=flat-square) +![Version](https://img.shields.io/badge/api%20version-2.5.0-blue.svg?style=flat-square) [![Build Status](https://img.shields.io/travis/com/appwrite/sdk-generator?style=flat-square)](https://travis-ci.com/appwrite/sdk-generator) [![Twitter Account](https://img.shields.io/twitter/follow/appwrite?color=00acee&label=twitter&style=flat-square)](https://twitter.com/appwrite) [![Discord](https://img.shields.io/discord/564160730845151244?label=discord&style=flat-square)](https://appwrite.io/discord) -**This SDK targets Appwrite server version 2.3.x as shipped on Appwrite Cloud.** Self-hosted releases can lag behind Cloud — if you run an older self-hosted build, use a matching older SDK from [previous releases](https://github.com/appwrite/sdk-for-react-native/releases) when APIs differ. +**This SDK targets Appwrite server version 2.5.x as shipped on Appwrite Cloud.** Self-hosted releases can lag behind Cloud — if you run an older self-hosted build, use a matching older SDK from [previous releases](https://github.com/appwrite/sdk-for-react-native/releases) when APIs differ. Appwrite is an open-source backend as a service server that abstracts and simplifies complex and repetitive development tasks behind a very simple to use REST API. Appwrite aims to help you develop your apps faster and in a more secure way. Use the React Native SDK to integrate your app with the Appwrite server to easily start interacting with all of Appwrite backend APIs and tools. For full API documentation and tutorials go to [https://appwrite.io/docs](https://appwrite.io/docs) @@ -45,7 +45,9 @@ than a short-lived JWT. On Android 13 and later, the first background subscription asks the user for the `POST_NOTIFICATIONS` runtime permission. If they decline, the subscription still delivers to your callback but posts no notification. Notifications show the title, body and image sent with -`createPush`, and fall back to the subscription's `title` and the raw payload for other messages. +`createPush`, falling back to the subscription's `title` when only a body is sent. A push with no +title or body, such as a data-only push, posts no notification and reaches only your callback. +Messages that are not a JSON object show the subscription's `title` with the raw payload as the body. ```js const sub = await push.subscribe('news', (message) => console.log(message.data), { @@ -93,17 +95,26 @@ With Expo, list them under `android.permissions` in `app.json` instead. nothing to ask, including when the permission is not declared. The SDK never opens these screens on its own. +If `backgroundRestricted` is true, the user restricted the app's background usage and messages can +wait until the app is opened. Exact alarms don't lift it, and neither does foreground mode: Android +stops a restricted app's foreground service once it leaves the screen. Ask the user to choose +Unrestricted in the app's battery settings (Settings > Apps > your app > Battery); granting the +battery optimisation exemption also lets the SDK's alarms and jobs run, and `bestEffort` then +reflects only the exact-alarm state. It is always false below Android 9. + If the user force-stops the app (Settings > Force stop, and on some devices swiping it away from recents), Android cancels its alarms and jobs: nothing is delivered until the app is opened again, and the broker then replays what was sent meanwhile. Set the notification icon with -`` in your +`` in your ``; without it a generic icon is used. ```js const status = await push.backgroundStatus(); // null outside Android -if (status?.bestEffort) { +if (status?.backgroundRestricted && !status.ignoringBatteryOptimizations) { + // Ask the user to choose Unrestricted in the app's battery settings. +} else if (status?.bestEffort) { // Explain why, then from a button press: await push.requestExactAlarms(); } @@ -140,7 +151,7 @@ On Android the SDK's native module reports the taps. Elsewhere they come from `e Foreground mode runs a `remoteMessaging` foreground service, which Google Play asks apps to declare in the Play Console. Apps that never enable it can remove the service from their merged -manifest with `tools:node="remove"` on `io.appwrite.services.PushService` and +manifest with `tools:node="remove"` on `io.appwrite.reactnative.services.PushService` and `android.permission.FOREGROUND_SERVICE_REMOTE_MESSAGING`. @@ -194,7 +205,12 @@ Once your SDK object is set, access any of the Appwrite services and choose any const account = new Account(client); // Register User -account.create(ID.unique(), 'me@example.com', 'password', 'Jane Doe') +account.create({ + userId: ID.unique(), + email: 'me@example.com', + password: 'password', + name: 'Jane Doe' +}) .then(function (response) { console.log(response); }, function (error) { @@ -206,7 +222,7 @@ account.create(ID.unique(), 'me@example.com', 'password', 'Jane Doe') ### Full Example ```js -import { Client, Account } from 'react-native-appwrite'; +import { Client, Account, ID } from 'react-native-appwrite'; // Init your React Native SDK const client = new Client(); @@ -219,7 +235,12 @@ client const account = new Account(client); // Register User -account.create(ID.unique(), 'me@example.com', 'password', 'Jane Doe') +account.create({ + userId: ID.unique(), + email: 'me@example.com', + password: 'password', + name: 'Jane Doe' +}) .then(function (response) { console.log(response); }, function (error) { @@ -229,11 +250,11 @@ account.create(ID.unique(), 'me@example.com', 'password', 'Jane Doe') ### Type Safety with Models -The Appwrite React Native SDK provides type safety when working with database documents through generic methods. Methods like `listDocuments`, `getDocument`, and others accept a generic type parameter that allows you to specify your custom model type for full type safety. +The Appwrite React Native SDK provides type safety when working with table rows through generic methods. Methods like `listRows`, `getRow`, and others accept a generic type parameter that allows you to specify your custom model type for full type safety. **TypeScript:** ```typescript -interface Book { +interface Book extends Models.Row { name: string; author: string; releaseYear?: string; @@ -242,15 +263,15 @@ interface Book { isCheckedOut: boolean; } -const databases = new Databases(client); +const tablesDB = new TablesDB(client); try { - const documents = await databases.listDocuments( - 'your-database-id', - 'your-collection-id' - ); + const result = await tablesDB.listRows({ + databaseId: 'your-database-id', + tableId: 'your-table-id' + }); - documents.documents.forEach(book => { + result.rows.forEach(book => { console.log(`Book: ${book.name} by ${book.author}`); // Now you have full type safety }); } catch (error) { @@ -270,16 +291,16 @@ try { * @property {boolean} isCheckedOut */ -const databases = new Databases(client); +const tablesDB = new TablesDB(client); try { - /** @type {Models.DocumentList} */ - const documents = await databases.listDocuments( - 'your-database-id', - 'your-collection-id' - ); + /** @type {Models.RowList} */ + const result = await tablesDB.listRows({ + databaseId: 'your-database-id', + tableId: 'your-table-id' + }); - documents.documents.forEach(book => { + result.rows.forEach(book => { console.log(`Book: ${book.name} by ${book.author}`); // Type hints available in IDE }); } catch (error) { @@ -295,7 +316,12 @@ The Appwrite React Native SDK raises an `AppwriteException` object with `message ```javascript try { - const user = await account.create(ID.unique(), "email@example.com", "password", "Walter O'Brien"); + const user = await account.create({ + userId: ID.unique(), + email: "email@example.com", + password: "password", + name: "Walter O'Brien" +}); console.log('User created:', user); } catch (error) { console.error('Appwrite error:', error.message); diff --git a/android/src/main/AndroidManifest.xml b/android/src/main/AndroidManifest.xml index d2b7d500..822bd46f 100644 --- a/android/src/main/AndroidManifest.xml +++ b/android/src/main/AndroidManifest.xml @@ -17,26 +17,26 @@ diff --git a/android/src/main/java/io/appwrite/reactnative/AppwritePushModule.kt b/android/src/main/java/io/appwrite/reactnative/AppwritePushModule.kt index c6c46889..cb87b594 100644 --- a/android/src/main/java/io/appwrite/reactnative/AppwritePushModule.kt +++ b/android/src/main/java/io/appwrite/reactnative/AppwritePushModule.kt @@ -7,10 +7,10 @@ import com.facebook.react.bridge.ReactApplicationContext import com.facebook.react.bridge.ReactContextBaseJavaModule import com.facebook.react.bridge.ReactMethod import com.facebook.react.modules.core.DeviceEventManagerModule -import io.appwrite.services.PushBridge -import io.appwrite.services.PushMessage -import io.appwrite.services.PushTap -import io.appwrite.services.PushTaps +import io.appwrite.reactnative.services.PushBridge +import io.appwrite.reactnative.services.PushMessage +import io.appwrite.reactnative.services.PushTap +import io.appwrite.reactnative.services.PushTaps import org.json.JSONObject /** diff --git a/android/src/main/java/io/appwrite/exceptions/AppwriteException.kt b/android/src/main/java/io/appwrite/reactnative/exceptions/AppwriteException.kt similarity index 81% rename from android/src/main/java/io/appwrite/exceptions/AppwriteException.kt rename to android/src/main/java/io/appwrite/reactnative/exceptions/AppwriteException.kt index 81b0d30e..fb101961 100644 --- a/android/src/main/java/io/appwrite/exceptions/AppwriteException.kt +++ b/android/src/main/java/io/appwrite/reactnative/exceptions/AppwriteException.kt @@ -1,4 +1,4 @@ -package io.appwrite.exceptions +package io.appwrite.reactnative.exceptions /** A push error. When the broker explained a refusal or a disconnect, that is its message. */ class AppwriteException( diff --git a/android/src/main/java/io/appwrite/services/PushBackground.kt b/android/src/main/java/io/appwrite/reactnative/services/PushBackground.kt similarity index 96% rename from android/src/main/java/io/appwrite/services/PushBackground.kt rename to android/src/main/java/io/appwrite/reactnative/services/PushBackground.kt index e06dfabe..cc34f286 100644 --- a/android/src/main/java/io/appwrite/services/PushBackground.kt +++ b/android/src/main/java/io/appwrite/reactnative/services/PushBackground.kt @@ -1,4 +1,4 @@ -package io.appwrite.services +package io.appwrite.reactnative.services import android.Manifest import android.app.ActivityManager @@ -32,7 +32,7 @@ import com.hivemq.client.mqtt.datatypes.MqttQos import com.hivemq.client.mqtt.mqtt5.Mqtt5AsyncClient import com.hivemq.client.mqtt.mqtt5.exceptions.Mqtt5ConnAckException import com.hivemq.client.mqtt.mqtt5.message.publish.Mqtt5Publish -import io.appwrite.exceptions.AppwriteException +import io.appwrite.reactnative.exceptions.AppwriteException import org.json.JSONArray import org.json.JSONObject import java.io.ByteArrayOutputStream @@ -52,8 +52,15 @@ import java.util.concurrent.atomic.AtomicInteger private const val LOG_TAG = "AppwritePush" -/** What a message's `notification` block asks a background notification to show; [present] is false without one. */ -internal data class PushNotificationContent(val present: Boolean, val title: String?, val body: String?, val image: String?) +/** + * What a message asks a background notification to show. A [raw] payload, one that is not a JSON + * object, is shown as the body under the subscription's title; an envelope is [visible] only with a + * title or body in its `notification`. + */ +internal data class PushNotificationContent(val raw: Boolean, val title: String?, val body: String?, val image: String?) { + val visible: Boolean + get() = raw || title != null || body != null +} /** A background subscription saved across restarts: its filter, QoS choice and notification title. */ internal data class PushEntry( @@ -97,11 +104,11 @@ internal data class PushHeartbeat( internal object PushBackground { const val CHANNEL_ID = "appwrite-push" const val NOTIFICATION_ID = 1911 - const val ACTION_TICK = "io.appwrite.push.TICK" - const val ACTION_MESSAGE = "io.appwrite.push.MESSAGE" - const val NOTIFICATION_ICON = "io.appwrite.push.notification_icon" - const val EXTRA_TOPIC = "io.appwrite.push.TOPIC" - const val EXTRA_PAYLOAD = "io.appwrite.push.PAYLOAD" + const val ACTION_TICK = "io.appwrite.reactnative.push.TICK" + const val ACTION_MESSAGE = "io.appwrite.reactnative.push.MESSAGE" + const val NOTIFICATION_ICON = "io.appwrite.reactnative.push.notification_icon" + const val EXTRA_TOPIC = "io.appwrite.reactnative.push.TOPIC" + const val EXTRA_PAYLOAD = "io.appwrite.reactnative.push.PAYLOAD" private const val SERVICE_CHANNEL_ID = "appwrite-push-service" const val JOB_ID = 0x50555348 @@ -887,7 +894,7 @@ internal object PushBackground { // Deliver a message to the matching live callbacks; with none, to the declared PushReceiver // and/or a notification per saved subscription that matches it. [deferAck] hands a listener // that acknowledges messages itself its acknowledgement. - private fun deliverMessage(context: Context, message: PushMessage, deferAck: () -> () -> Unit) { + internal fun deliverMessage(context: Context, message: PushMessage, deferAck: () -> () -> Unit) { val matching = listeners.filter { listener -> listener.topics.any { matchesTopic(it, message.topic) } } // Saved background subscriptions no live one has taken over; they deliver even when a live // foreground-only subscription on an overlapping filter received the message too. @@ -952,16 +959,21 @@ internal object PushBackground { /** * Post a notification for [message] that opens the app, with the message in its extras. It shows - * the server's title, body and image from [content], falling back to [title] and the raw payload. + * the server's title, body and image from [content], falling back to [title], and to the payload + * as the body when it is not a JSON object. An envelope with neither a title nor a body, such as + * a data-only push, posts nothing. */ fun notify(context: Context, message: PushMessage, title: String, content: PushNotificationContent = notificationContent(message)) { + if (!content.visible) { + return + } val manager = NotificationManagerCompat.from(context) if (!manager.areNotificationsEnabled()) { return } createChannels(context) val id = 31 * message.hashCode() + title.hashCode() - val body = content.body ?: message.data.takeIf { !content.present } + val body = content.body ?: message.data.takeIf { content.raw } val builder = NotificationCompat.Builder(context, CHANNEL_ID) .setContentTitle(content.title ?: title) .setSmallIcon(notificationIcon(context)) @@ -992,12 +1004,13 @@ internal object PushBackground { .also { ActivityManager.getMyMemoryState(it) } .importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND - /** The server's `notification` block in [message]: nulls when the payload has none or is not JSON. */ + /** The server's `notification` block in [message], [PushNotificationContent.raw] when the payload is not a JSON object. */ fun notificationContent(message: PushMessage): PushNotificationContent { - val notification = runCatching { JSONObject(message.data) }.getOrNull()?.optJSONObject("notification") - ?: return PushNotificationContent(false, null, null, null) - fun field(name: String) = (notification.opt(name) as? String)?.takeIf { it.isNotEmpty() } - return PushNotificationContent(true, field("title"), field("body"), field("image")) + val envelope = runCatching { JSONObject(message.data) }.getOrNull() + ?: return PushNotificationContent(true, null, null, null) + val notification = envelope.optJSONObject("notification") + fun field(name: String) = (notification?.opt(name) as? String)?.takeIf { it.isNotEmpty() } + return PushNotificationContent(false, field("title"), field("body"), field("image")) } // Downloads notification images, so a slow one is abandoned without holding up delivery. @@ -1079,7 +1092,7 @@ internal object PushBackground { ) } - // The icon named by the app's ``, else a + // The icon named by the app's ``, else a // generic one. private fun notificationIcon(context: Context): Int { val metaData = runCatching { @@ -1201,6 +1214,8 @@ internal object PushBackground { app.getSystemService(AlarmManager::class.java)?.canScheduleExactAlarms() == true, ignoringBatteryOptimizations = app.getSystemService(PowerManager::class.java)?.isIgnoringBatteryOptimizations(app.packageName) == true, foregroundService = PushStore.foreground(app), + backgroundRestricted = Build.VERSION.SDK_INT >= Build.VERSION_CODES.P && + app.getSystemService(ActivityManager::class.java)?.isBackgroundRestricted == true, ) } diff --git a/android/src/main/java/io/appwrite/services/PushBridge.kt b/android/src/main/java/io/appwrite/reactnative/services/PushBridge.kt similarity index 97% rename from android/src/main/java/io/appwrite/services/PushBridge.kt rename to android/src/main/java/io/appwrite/reactnative/services/PushBridge.kt index e5cb5aae..50cd5468 100644 --- a/android/src/main/java/io/appwrite/services/PushBridge.kt +++ b/android/src/main/java/io/appwrite/reactnative/services/PushBridge.kt @@ -1,4 +1,4 @@ -package io.appwrite.services +package io.appwrite.reactnative.services import android.content.Context import android.os.SystemClock @@ -169,12 +169,13 @@ class PushBridge(context: Context, private val events: Events) { return if (registered) PushStore.takeStoppedError(appContext) else null } - /** What background delivery can rely on, as `{"exactAlarms", "ignoringBatteryOptimizations", "foregroundService", "bestEffort"}`. */ + /** What background delivery can rely on, as `{"exactAlarms", "ignoringBatteryOptimizations", "foregroundService", "backgroundRestricted", "bestEffort"}`. */ fun backgroundStatus(): String = PushBackground.backgroundStatus(appContext).let { JSONObject() .put("exactAlarms", it.exactAlarms) .put("ignoringBatteryOptimizations", it.ignoringBatteryOptimizations) .put("foregroundService", it.foregroundService) + .put("backgroundRestricted", it.backgroundRestricted) .put("bestEffort", it.bestEffort) .toString() } diff --git a/android/src/main/java/io/appwrite/services/PushCore.kt b/android/src/main/java/io/appwrite/reactnative/services/PushCore.kt similarity index 93% rename from android/src/main/java/io/appwrite/services/PushCore.kt rename to android/src/main/java/io/appwrite/reactnative/services/PushCore.kt index 15f86b6a..85fdb19e 100644 --- a/android/src/main/java/io/appwrite/services/PushCore.kt +++ b/android/src/main/java/io/appwrite/reactnative/services/PushCore.kt @@ -1,4 +1,4 @@ -package io.appwrite.services +package io.appwrite.reactnative.services import android.content.Context import android.os.Build @@ -22,7 +22,7 @@ import com.hivemq.client.mqtt.mqtt5.message.connect.connack.Mqtt5ConnAckReasonCo import com.hivemq.client.mqtt.mqtt5.message.disconnect.Mqtt5Disconnect import com.hivemq.client.mqtt.mqtt5.message.disconnect.Mqtt5DisconnectReasonCode import com.hivemq.client.mqtt.mqtt5.message.publish.Mqtt5Publish -import io.appwrite.exceptions.AppwriteException +import io.appwrite.reactnative.exceptions.AppwriteException import org.json.JSONObject import java.security.KeyStore import java.security.Provider @@ -54,19 +54,36 @@ data class PushMessage( /** * What background delivery can rely on. Without exact alarms, the scheduled wake-ups are inexact * and Doze can defer them, so delivery is [bestEffort] unless foreground mode keeps the - * connection open. + * connection open. When the user restricted background usage, delivery is [bestEffort] unless the + * app is also exempt from battery optimisation, and foreground mode no longer counts: Android stops + * a restricted app's foreground service once it leaves the screen, exemption or not. */ -data class PushBackgroundStatus( +data class PushBackgroundStatus @JvmOverloads constructor( /** The app may schedule exact alarms (`SCHEDULE_EXACT_ALARM`, granted). */ val exactAlarms: Boolean, /** The app is exempt from battery optimisation. */ val ignoringBatteryOptimizations: Boolean, /** Foreground mode (`setForeground(true)`) keeps the connection open in a service. */ val foregroundService: Boolean, + /** + * The user restricted the app's background usage in its battery settings (Android 9+). Android + * may then hold its alarms, jobs and foreground service while it is closed, so messages can + * wait until the app is opened. The battery-optimisation exemption lets the alarms and jobs + * run again, but foreground mode still stops once the app leaves the screen. + */ + val backgroundRestricted: Boolean = false, ) { - /** Wake-ups may be deferred by Doze, so messages can arrive late while the app is closed. */ + /** + * Messages can arrive late, or not until the app is opened, while the app is closed: background + * usage is restricted without the battery-optimisation exemption, or wake-ups may be deferred + * by Doze. + */ val bestEffort: Boolean - get() = !exactAlarms && !foregroundService + get() { + val held = backgroundRestricted && !ignoringBatteryOptimizations + val foreground = foregroundService && !backgroundRestricted + return held || (!exactAlarms && !foreground) + } } /** Connection parameters shared between the in-process client and the foreground service. */ diff --git a/android/src/main/java/io/appwrite/services/PushOpenActivity.kt b/android/src/main/java/io/appwrite/reactnative/services/PushOpenActivity.kt similarity index 97% rename from android/src/main/java/io/appwrite/services/PushOpenActivity.kt rename to android/src/main/java/io/appwrite/reactnative/services/PushOpenActivity.kt index 354ca6f0..5a51c808 100644 --- a/android/src/main/java/io/appwrite/services/PushOpenActivity.kt +++ b/android/src/main/java/io/appwrite/reactnative/services/PushOpenActivity.kt @@ -1,4 +1,4 @@ -package io.appwrite.services +package io.appwrite.reactnative.services import android.app.Activity import android.content.Intent diff --git a/android/src/main/java/io/appwrite/services/PushReceiver.kt b/android/src/main/java/io/appwrite/reactnative/services/PushReceiver.kt similarity index 90% rename from android/src/main/java/io/appwrite/services/PushReceiver.kt rename to android/src/main/java/io/appwrite/reactnative/services/PushReceiver.kt index 92d04727..ec0e7630 100644 --- a/android/src/main/java/io/appwrite/services/PushReceiver.kt +++ b/android/src/main/java/io/appwrite/reactnative/services/PushReceiver.kt @@ -1,4 +1,4 @@ -package io.appwrite.services +package io.appwrite.reactnative.services import android.content.BroadcastReceiver import android.content.Context @@ -12,7 +12,7 @@ import android.content.Intent * ```xml * * - * + * * * * ``` diff --git a/android/src/main/java/io/appwrite/services/PushService.kt b/android/src/main/java/io/appwrite/reactnative/services/PushService.kt similarity index 98% rename from android/src/main/java/io/appwrite/services/PushService.kt rename to android/src/main/java/io/appwrite/reactnative/services/PushService.kt index e2a05f89..1981cafc 100644 --- a/android/src/main/java/io/appwrite/services/PushService.kt +++ b/android/src/main/java/io/appwrite/reactnative/services/PushService.kt @@ -1,4 +1,4 @@ -package io.appwrite.services +package io.appwrite.reactnative.services import android.app.Service import android.content.Intent diff --git a/android/src/main/java/io/appwrite/services/PushWakeups.kt b/android/src/main/java/io/appwrite/reactnative/services/PushWakeups.kt similarity index 98% rename from android/src/main/java/io/appwrite/services/PushWakeups.kt rename to android/src/main/java/io/appwrite/reactnative/services/PushWakeups.kt index c6d56165..50bd2d81 100644 --- a/android/src/main/java/io/appwrite/services/PushWakeups.kt +++ b/android/src/main/java/io/appwrite/reactnative/services/PushWakeups.kt @@ -1,4 +1,4 @@ -package io.appwrite.services +package io.appwrite.reactnative.services import android.app.job.JobParameters import android.app.job.JobService 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/create-passkey-token.md b/docs/examples/account/create-passkey-token.md new file mode 100644 index 00000000..5695859f --- /dev/null +++ b/docs/examples/account/create-passkey-token.md @@ -0,0 +1,13 @@ +```javascript +import { Client, Account } from 'react-native-appwrite'; + +const client = new Client() + .setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint + .setProject(''); // Your project ID + +const account = new Account(client); + +const result = await account.createPasskeyToken(); + +console.log(result); +``` diff --git a/docs/examples/account/create-passkey.md b/docs/examples/account/create-passkey.md new file mode 100644 index 00000000..66968b14 --- /dev/null +++ b/docs/examples/account/create-passkey.md @@ -0,0 +1,16 @@ +```javascript +import { Client, Account } from 'react-native-appwrite'; + +const client = new Client() + .setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint + .setProject(''); // Your project ID + +const account = new Account(client); + +const result = await account.createPasskey({ + passkeyId: '', // optional + name: '', // optional +}); + +console.log(result); +``` diff --git a/docs/examples/account/delete-passkey.md b/docs/examples/account/delete-passkey.md new file mode 100644 index 00000000..61aec153 --- /dev/null +++ b/docs/examples/account/delete-passkey.md @@ -0,0 +1,15 @@ +```javascript +import { Client, Account } from 'react-native-appwrite'; + +const client = new Client() + .setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint + .setProject(''); // Your project ID + +const account = new Account(client); + +const result = await account.deletePasskey({ + passkeyId: '', +}); + +console.log(result); +``` diff --git a/docs/examples/account/get-passkey.md b/docs/examples/account/get-passkey.md new file mode 100644 index 00000000..04b7f8fb --- /dev/null +++ b/docs/examples/account/get-passkey.md @@ -0,0 +1,15 @@ +```javascript +import { Client, Account } from 'react-native-appwrite'; + +const client = new Client() + .setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint + .setProject(''); // Your project ID + +const account = new Account(client); + +const result = await account.getPasskey({ + passkeyId: '', +}); + +console.log(result); +``` diff --git a/docs/examples/account/list-passkeys.md b/docs/examples/account/list-passkeys.md new file mode 100644 index 00000000..f1f68985 --- /dev/null +++ b/docs/examples/account/list-passkeys.md @@ -0,0 +1,16 @@ +```javascript +import { Client, Account } from 'react-native-appwrite'; + +const client = new Client() + .setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint + .setProject(''); // Your project ID + +const account = new Account(client); + +const result = await account.listPasskeys({ + queries: [], // optional + total: false, // optional +}); + +console.log(result); +``` diff --git a/docs/examples/account/update-passkey-token.md b/docs/examples/account/update-passkey-token.md new file mode 100644 index 00000000..a8e22f7a --- /dev/null +++ b/docs/examples/account/update-passkey-token.md @@ -0,0 +1,16 @@ +```javascript +import { Client, Account } from 'react-native-appwrite'; + +const client = new Client() + .setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint + .setProject(''); // Your project ID + +const account = new Account(client); + +const result = await account.updatePasskeyToken({ + challengeId: '', + credential: {}, +}); + +console.log(result); +``` diff --git a/docs/examples/account/update-passkey-verification.md b/docs/examples/account/update-passkey-verification.md new file mode 100644 index 00000000..c46c0a63 --- /dev/null +++ b/docs/examples/account/update-passkey-verification.md @@ -0,0 +1,16 @@ +```javascript +import { Client, Account } from 'react-native-appwrite'; + +const client = new Client() + .setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint + .setProject(''); // Your project ID + +const account = new Account(client); + +const result = await account.updatePasskeyVerification({ + passkeyId: '', + credential: {}, +}); + +console.log(result); +``` diff --git a/docs/examples/account/update-passkey.md b/docs/examples/account/update-passkey.md new file mode 100644 index 00000000..2f925b98 --- /dev/null +++ b/docs/examples/account/update-passkey.md @@ -0,0 +1,16 @@ +```javascript +import { Client, Account } from 'react-native-appwrite'; + +const client = new Client() + .setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint + .setProject(''); // Your project ID + +const account = new Account(client); + +const result = await account.updatePasskey({ + passkeyId: '', + name: '', +}); + +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..b8b5e7eb --- /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: 0, // 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/oauth2/authorize-post.md b/docs/examples/oauth2/authorize-post.md index e27aa7e3..f7dd540c 100644 --- a/docs/examples/oauth2/authorize-post.md +++ b/docs/examples/oauth2/authorize-post.md @@ -19,7 +19,7 @@ const result = await oauth2.authorizePost({ prompt: '', // optional maxAge: 0, // optional authorizationDetails: '', // optional - resource: '', // optional + resource: [], // optional audience: '', // optional requestUri: '', // optional }); diff --git a/docs/examples/oauth2/authorize.md b/docs/examples/oauth2/authorize.md index 039dc744..256e9cb6 100644 --- a/docs/examples/oauth2/authorize.md +++ b/docs/examples/oauth2/authorize.md @@ -19,7 +19,7 @@ const result = await oauth2.authorize({ prompt: '', // optional maxAge: 0, // optional authorizationDetails: '', // optional - resource: '', // optional + resource: [], // optional audience: '', // optional requestUri: '', // optional }); diff --git a/docs/examples/oauth2/create-device-authorization.md b/docs/examples/oauth2/create-device-authorization.md index c136011b..1219db51 100644 --- a/docs/examples/oauth2/create-device-authorization.md +++ b/docs/examples/oauth2/create-device-authorization.md @@ -11,7 +11,7 @@ const result = await oauth2.createDeviceAuthorization({ clientId: '', // optional scope: '', // optional authorizationDetails: '', // optional - resource: '', // optional + resource: [], // optional audience: '', // optional }); diff --git a/docs/examples/oauth2/create-par.md b/docs/examples/oauth2/create-par.md index 5d9b5783..425e7a86 100644 --- a/docs/examples/oauth2/create-par.md +++ b/docs/examples/oauth2/create-par.md @@ -19,7 +19,7 @@ const result = await oauth2.createPAR({ prompt: '', // optional maxAge: 0, // optional authorizationDetails: '', // optional - resource: '', // optional + resource: [], // optional audience: '', // optional }); diff --git a/docs/examples/oauth2/create-token.md b/docs/examples/oauth2/create-token.md index 3be9ff4a..567bfb74 100644 --- a/docs/examples/oauth2/create-token.md +++ b/docs/examples/oauth2/create-token.md @@ -16,7 +16,7 @@ const result = await oauth2.createToken({ clientSecret: '', // optional codeVerifier: '', // optional redirectUri: 'https://example.com', // optional - resource: '', // optional + resource: [], // optional audience: '', // optional }); diff --git a/docs/examples/teams/create-membership.md b/docs/examples/teams/create-membership.md index 3c6ee849..9a4828a9 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/package-lock.json b/package-lock.json index 33230e5f..bbf4775e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "react-native-appwrite", - "version": "1.2.0-rc.4", + "version": "2.0.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "react-native-appwrite", - "version": "1.2.0-rc.4", + "version": "2.0.0", "license": "BSD-3-Clause", "dependencies": { "buffer": "6.0.3", diff --git a/package.json b/package.json index 12b4f76a..b36e9cfc 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-rc.4", + "version": "2.0.0", "license": "BSD-3-Clause", "main": "dist/cjs/sdk.js", "exports": { diff --git a/src/client.ts b/src/client.ts index 4bc8575c..8efff40a 100644 --- a/src/client.ts +++ b/src/client.ts @@ -1,7 +1,7 @@ import { Models } from './models'; import { Service } from './service'; import { Platform } from 'react-native'; -import { Query } from './query'; +import { Query, flattenParam } from './query'; import JSONbigModule from 'json-bigint'; const JSONbigParser = JSONbigModule({ storeAsString: false }); const JSONbigSerializer = JSONbigModule({ useNativeBigInt: true }); @@ -45,6 +45,79 @@ export const JSONbig = { stringify: JSONbigSerializer.stringify, }; +type DefaultsShape = string | { items: DefaultsShape }; + +type DefaultsModel = { + defaults?: Record; + properties?: Record; +}; + +type Defaults = { + root: DefaultsShape; + models: Record; +}; + +export function applyDefaults(value: T, tree: Defaults): T { + return fillDefaults(value, tree.root, tree.models) as T; +} + +function cloneDefault(value: unknown): unknown { + if (Array.isArray(value)) { + return value.map(cloneDefault); + } + if (typeof value === 'object' && value !== null) { + const copy: Record = {}; + for (const [key, member] of Object.entries(value)) { + copy[key] = cloneDefault(member); + } + return copy; + } + return value; +} + +function fillDefaults( + value: unknown, + shape: DefaultsShape, + models: Record, +): unknown { + if (typeof shape !== 'string') { + if (!Array.isArray(value)) { + return value; + } + const items = shape.items; + return value.map((item) => fillDefaults(item, items, models)); + } + const model = models[shape]; + if (!model || typeof value !== 'object' || value === null) { + return value; + } + if (Array.isArray(value)) { + return value; + } + const result: Record = { ...model.defaults, ...value }; + // Each item gets its own copy of a filled-in list or object, so mutating one doesn't change the rest + for (const key of Object.keys(model.defaults ?? {})) { + if (!Object.prototype.hasOwnProperty.call(value, key)) { + result[key] = cloneDefault(result[key]); + } + } + for (const [key, child] of Object.entries(model.properties ?? {})) { + if (key in result) { + result[key] = fillDefaults(result[key], child, models); + } + } + // The spread drops the non-enumerable JSON toString that Client.call attaches. + if (Object.prototype.hasOwnProperty.call(value, 'toString')) { + Object.defineProperty(result, 'toString', { + value: () => JSONbig.stringify(result), + writable: true, + enumerable: false, + configurable: true, + }); + } + return result; +} + type Payload = { [key: string]: any; }; @@ -218,8 +291,8 @@ class Client { 'x-sdk-name': 'React Native', 'x-sdk-platform': 'client', 'x-sdk-language': 'reactnative', - 'x-sdk-version': '1.2.0-rc.4', - 'X-Appwrite-Response-Format': '2.3.0', + 'x-sdk-version': '2.0.0', + 'X-Appwrite-Response-Format': '2.5.0', }; /** @@ -837,6 +910,10 @@ class Client { ): Promise { method = method.toUpperCase(); + for (const key of Object.keys(params)) { + params[key] = flattenParam(params[key]); + } + headers = Object.assign({}, this.headers, headers); headers.Origin = `appwrite-${Platform.OS}://${this.config.platform}`; diff --git a/src/enums/execution-trigger.ts b/src/enums/execution-trigger.ts index 84fa8f60..b16a8781 100644 --- a/src/enums/execution-trigger.ts +++ b/src/enums/execution-trigger.ts @@ -2,4 +2,5 @@ export enum ExecutionTrigger { Http = 'http', Schedule = 'schedule', Event = 'event', + Email = 'email', } diff --git a/src/index.ts b/src/index.ts index 579ed73a..c4d406c4 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 { Apps } from './services/apps'; export { Avatars } from './services/avatars'; export { Databases } from './services/databases'; @@ -32,12 +33,12 @@ export type { UploadProgress, } from './client'; export type { RealtimeSubscription } from './services/realtime'; -export type { QueryTypes, QueryTypesList } from './query'; -export { Query } from './query'; +export type { QueryTypes, QueryTypesList, QueryInput } from './query'; +export { Query, QueryBuilder, flattenParam } from './query'; export { Permission } from './permission'; export { Role } from './role'; export { ID } from './id'; -export { Topic, ResolvedTopic } from './topic'; +export { Topic } from './topic'; export { Channel } from './channel'; export { Operator, Condition } from './operator'; export { AuthenticatorType } from './enums/authenticator-type'; diff --git a/src/models.ts b/src/models.ts index 09b8b39c..03ed2f9f 100644 --- a/src/models.ts +++ b/src/models.ts @@ -338,7 +338,7 @@ export namespace Models { /** * Presence status. */ - status?: string; + status?: string | null; /** * Presence source. */ @@ -346,7 +346,7 @@ export namespace Models { /** * Presence expiry date in ISO 8601 format. */ - expiresAt?: string; + expiresAt?: string | null; /** * Presence metadata. */ @@ -378,15 +378,15 @@ export namespace Models { /** * Hashed user password. */ - password?: string; + password?: string | null; /** * Password hashing algorithm. */ - hash?: string; + hash?: string | null; /** * Password hashing algorithm configuration. */ - hashOptions?: object; + hashOptions?: object | null; /** * User registration date in ISO 8601 format. */ @@ -418,27 +418,27 @@ export namespace Models { /** * Canonical form of the user email address. */ - emailCanonical?: string; + emailCanonical?: string | null; /** * Whether the user email is from a free email provider. */ - emailIsFree?: boolean; + emailIsFree?: boolean | null; /** * Whether the user email is from a disposable email provider. */ - emailIsDisposable?: boolean; + emailIsDisposable?: boolean | null; /** * Whether the user email is from a corporate domain. */ - emailIsCorporate?: boolean; + emailIsCorporate?: boolean | null; /** * Whether the user email is in its canonical form. */ - emailIsCanonical?: boolean; + emailIsCanonical?: boolean | null; /** * 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; + passwordPwned?: boolean | null; /** * Phone verification status. */ @@ -462,11 +462,11 @@ export namespace Models { /** * Whether the user can impersonate other users. */ - impersonator?: boolean; + impersonator?: boolean | null; /** * 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; + impersonatorUserId?: string | null; }; /** @@ -632,27 +632,27 @@ export namespace Models { /** * Canonical form of the user email address. */ - emailCanonical?: string; + emailCanonical?: string | null; /** * Whether the user email is from a free email provider. */ - emailIsFree?: boolean; + emailIsFree?: boolean | null; /** * Whether the user email is from a disposable email provider. */ - emailIsDisposable?: boolean; + emailIsDisposable?: boolean | null; /** * Whether the user email is from a corporate domain. */ - emailIsCorporate?: boolean; + emailIsCorporate?: boolean | null; /** * Whether the user email is in its canonical form. */ - emailIsCanonical?: boolean; + emailIsCanonical?: boolean | null; /** * 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; + passwordPwned?: boolean | null; /** * Phone verification status. */ @@ -676,11 +676,11 @@ export namespace Models { /** * Whether the user can impersonate other users. */ - impersonator?: boolean; + impersonator?: boolean | null; /** * 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; + impersonatorUserId?: string | null; }; /** @@ -940,47 +940,47 @@ export namespace Models { /** * City */ - city?: string; + city?: string | null; /** * Name of timezone */ - timeZone?: string; + timeZone?: string | null; /** * Postal code */ - postalCode?: string; + postalCode?: string | null; /** * Latitude */ - latitude?: number; + latitude?: number | null; /** * Longitude */ - longitude?: number; + longitude?: number | null; /** * Autonomous System Number (ASN) of the IP */ - autonomousSystemNumber?: string; + autonomousSystemNumber?: string | null; /** * Organization that owns the ASN */ - autonomousSystemOrganization?: string; + autonomousSystemOrganization?: string | null; /** * Internet service provider of the IP */ - isp?: string; + isp?: string | null; /** * Connection type of the IP (e.g. cable, cellular, corporate) */ - connectionType?: string; + connectionType?: string | null; /** * User type classification of the IP (e.g. residential, business, hosting) */ - connectionUsageType?: string; + connectionUsageType?: string | null; /** * Registered organization of the IP */ - connectionOrganization?: string; + connectionOrganization?: string | null; }; /** @@ -1198,7 +1198,7 @@ export namespace Models { */ deploymentId: string; /** - * The trigger that caused the resource to execute. Possible values can be: `http`, `schedule`, or `event`. + * The trigger that caused the resource to execute. Possible values can be: `http`, `schedule`, `event`, or `email`. */ trigger: ExecutionTrigger; /** @@ -1244,7 +1244,7 @@ export namespace Models { /** * The scheduled time for execution. If left empty, execution will be queued immediately. */ - scheduledAt?: string; + scheduledAt?: string | null; }; /** @@ -1381,6 +1381,102 @@ export namespace Models { expire: string; }; + /** + * Token Secret + */ + export type TokenSecret = { + /** + * Token ID. + */ + $id: string; + /** + * Token creation date in ISO 8601 format. + */ + $createdAt: string; + /** + * User ID. + */ + userId: string; + /** + * Token secret key. Exchange it for a session with the create session endpoint. + */ + secret: string; + /** + * Token expiration date in ISO 8601 format. + */ + expire: string; + /** + * Security phrase of a token. Empty if security phrase was not requested when creating a token. It includes randomly generated phrase which is also sent in the external resource such as email. + */ + phrase: string; + }; + + /** + * Passkey + */ + export type Passkey = { + /** + * Passkey ID. + */ + $id: string; + /** + * Passkey creation date in ISO 8601 format. + */ + $createdAt: string; + /** + * Passkey update date in ISO 8601 format. + */ + $updatedAt: string; + /** + * Passkey name. + */ + name: string; + /** + * Most recent sign-in with this passkey in ISO 8601 format. Empty until the passkey is used to sign in. + */ + accessedAt: string; + }; + + /** + * Passkey Challenge + */ + export type PasskeyChallenge = { + /** + * Challenge ID. When signing in, pass it back with the credential to receive a token. + */ + $id: string; + /** + * Challenge creation date in ISO 8601 format. + */ + $createdAt: string; + /** + * ID of the passkey being registered. Empty for sign-in challenges. + */ + passkeyId: string; + /** + * Challenge expiration date in ISO 8601 format. + */ + expire: string; + /** + * WebAuthn options in JSON form. Pass them to `PublicKeyCredential.parseCreationOptionsFromJSON()` when registering, or `PublicKeyCredential.parseRequestOptionsFromJSON()` when signing in. + */ + publicKey: object; + }; + + /** + * Passkeys List + */ + export type PasskeyList = { + /** + * Total number of passkeys that matched your query. + */ + total: number; + /** + * List of passkeys. + */ + passkeys: Passkey[]; + }; + /** * MFA Recovery Codes */ @@ -1530,7 +1626,7 @@ export namespace Models { /** * Provider ID. */ - providerId?: string; + providerId?: string | null; /** * The target provider type. Can be one of the following: `email`, `sms` or `push`. */ @@ -1694,7 +1790,7 @@ export namespace Models { /** * Time the secret was last used for authentication in ISO 8601 format. Null if never used. */ - lastAccessedAt?: string; + lastAccessedAt?: string | null; }; /** @@ -1736,7 +1832,7 @@ export namespace Models { /** * Time the secret was last used for authentication in ISO 8601 format. Null if never used. */ - lastAccessedAt?: string; + lastAccessedAt?: string | null; }; /** @@ -1808,7 +1904,7 @@ export namespace Models { /** * Time an access token was last issued for the installation in ISO 8601 format. Null if never used. */ - lastAccessedAt?: string; + lastAccessedAt?: string | null; }; /** @@ -1850,7 +1946,7 @@ export namespace Models { /** * Time the app key was last used for authentication in ISO 8601 format. Null if never used. */ - lastAccessedAt?: string; + lastAccessedAt?: string | null; }; /** @@ -2012,11 +2108,11 @@ export namespace Models { /** * Granted RFC 9396 authorization details as a JSON string. */ - authorization_details?: string; + authorization_details?: string | null; /** * OpenID Connect ID token. Returned when the `openid` scope is granted. */ - id_token?: string; + id_token?: string | null; }; /** diff --git a/src/query.ts b/src/query.ts index 104b1ab9..9c614c75 100644 --- a/src/query.ts +++ b/src/query.ts @@ -310,6 +310,20 @@ export class Query { queries.map((query) => JSONbig.parse(query)), ).toString(); + /** + * Constrain populated related documents on a relationship attribute. + * + * @param {string} attribute The relationship attribute to query. + * @param {string[]} queries Filter, order, select, and pagination queries applied to related documents. + * @returns {string} + */ + static relationship = (attribute: string, queries: string[]): string => + new Query( + 'relationship', + attribute, + queries.map((query) => JSONbig.parse(query)), + ).toString(); + /** * Filter resources where attribute is at a specific distance from the given coordinates. * @@ -501,4 +515,776 @@ export class Query { */ static notTouches = (attribute: string, values: any[]): string => new Query('notTouches', attribute, [values]).toString(); + + /** + * Count documents, optionally aliased. + */ + static count = (attribute: string = '*', alias: string = ''): string => + new Query( + 'count', + attribute, + alias !== '' ? alias : undefined, + ).toString(); + + /** + * Count distinct values of attribute, optionally aliased. + */ + static countDistinct = (attribute: string, alias: string = ''): string => + new Query( + 'countDistinct', + attribute, + alias !== '' ? alias : undefined, + ).toString(); + + static sum = (attribute: string, alias: string = ''): string => + new Query( + 'sum', + attribute, + alias !== '' ? alias : undefined, + ).toString(); + + static avg = (attribute: string, alias: string = ''): string => + new Query( + 'avg', + attribute, + alias !== '' ? alias : undefined, + ).toString(); + + static min = (attribute: string, alias: string = ''): string => + new Query( + 'min', + attribute, + alias !== '' ? alias : undefined, + ).toString(); + + static max = (attribute: string, alias: string = ''): string => + new Query( + 'max', + attribute, + alias !== '' ? alias : undefined, + ).toString(); + + static stddev = (attribute: string, alias: string = ''): string => + new Query( + 'stddev', + attribute, + alias !== '' ? alias : undefined, + ).toString(); + + static stddevPop = (attribute: string, alias: string = ''): string => + new Query( + 'stddevPop', + attribute, + alias !== '' ? alias : undefined, + ).toString(); + + static stddevSamp = (attribute: string, alias: string = ''): string => + new Query( + 'stddevSamp', + attribute, + alias !== '' ? alias : undefined, + ).toString(); + + static variance = (attribute: string, alias: string = ''): string => + new Query( + 'variance', + attribute, + alias !== '' ? alias : undefined, + ).toString(); + + static varPop = (attribute: string, alias: string = ''): string => + new Query( + 'varPop', + attribute, + alias !== '' ? alias : undefined, + ).toString(); + + static varSamp = (attribute: string, alias: string = ''): string => + new Query( + 'varSamp', + attribute, + alias !== '' ? alias : undefined, + ).toString(); + + static bitAnd = (attribute: string, alias: string = ''): string => + new Query( + 'bitAnd', + attribute, + alias !== '' ? alias : undefined, + ).toString(); + + static bitOr = (attribute: string, alias: string = ''): string => + new Query( + 'bitOr', + attribute, + alias !== '' ? alias : undefined, + ).toString(); + + static bitXor = (attribute: string, alias: string = ''): string => + new Query( + 'bitXor', + attribute, + alias !== '' ? alias : undefined, + ).toString(); + + /** + * Group results by attributes. + */ + static groupBy = (attributes: string[]): string => + new Query('groupBy', undefined, attributes).toString(); + + /** + * Filter grouped results. `queries` are nested like `and`/`or`. + */ + static having = (queries: string[]): string => + new Query( + 'having', + undefined, + queries.map((query) => JSONbig.parse(query)), + ).toString(); + + static distinct = (): string => new Query('distinct').toString(); + + /** + * Column-to-column join ON condition. + */ + static on = (left: string, right: string, operator: string = '='): string => + new Query('on', undefined, [left, operator, right]).toString(); + + /** + * Inner join. `table` is the joined collection/table ID. + */ + static join = ( + table: string, + leftOrAliasOrOn: string | string[], + rightOrOn: string | string[] = '', + operator: string = '=', + alias: string = '', + ): string => + Query.createJoin( + 'join', + table, + leftOrAliasOrOn, + rightOrOn, + operator, + alias, + ); + + static leftJoin = ( + table: string, + leftOrAliasOrOn: string | string[], + rightOrOn: string | string[] = '', + operator: string = '=', + alias: string = '', + ): string => + Query.createJoin( + 'leftJoin', + table, + leftOrAliasOrOn, + rightOrOn, + operator, + alias, + ); + + static rightJoin = ( + table: string, + leftOrAliasOrOn: string | string[], + rightOrOn: string | string[] = '', + operator: string = '=', + alias: string = '', + ): string => + Query.createJoin( + 'rightJoin', + table, + leftOrAliasOrOn, + rightOrOn, + operator, + alias, + ); + + static fullOuterJoin = ( + table: string, + leftOrAliasOrOn: string | string[], + rightOrOn: string | string[] = '', + operator: string = '=', + alias: string = '', + ): string => + Query.createJoin( + 'fullOuterJoin', + table, + leftOrAliasOrOn, + rightOrOn, + operator, + alias, + ); + + static crossJoin = (table: string, alias: string = ''): string => + new Query( + 'crossJoin', + table, + alias !== '' ? alias : undefined, + ).toString(); + + static covers = (attribute: string, values: any[]): string => + new Query('covers', attribute, [values]).toString(); + + static notCovers = (attribute: string, values: any[]): string => + new Query('notCovers', attribute, [values]).toString(); + + static spatialEquals = (attribute: string, values: any[]): string => + new Query('spatialEquals', attribute, [values]).toString(); + + static notSpatialEquals = (attribute: string, values: any[]): string => + new Query('notSpatialEquals', attribute, [values]).toString(); + + /** + * Return limit and offset queries for 1-based page pagination. + */ + static page = (page: number, perPage: number = 25): string[] => { + if (page < 1) { + throw new Error('Page must be >= 1, got ' + page); + } + if (perPage < 1) { + throw new Error('Per page must be >= 1, got ' + perPage); + } + return [Query.limit(perPage), Query.offset((page - 1) * perPage)]; + }; + + static builder = (): Query.Builder => new Query.Builder(); + + private static createJoin( + method: string, + table: string, + leftOrAliasOrOn: string | string[], + rightOrOn: string | string[] = '', + operator: string = '=', + alias: string = '', + ): string { + if (Array.isArray(leftOrAliasOrOn)) { + return Query.nestedJoin(method, table, '', leftOrAliasOrOn); + } + if (Array.isArray(rightOrOn)) { + return Query.nestedJoin(method, table, leftOrAliasOrOn, rightOrOn); + } + return new Query( + method, + table, + alias !== '' + ? [leftOrAliasOrOn, operator, rightOrOn, alias] + : [leftOrAliasOrOn, operator, rightOrOn], + ).toString(); + } + + private static nestedJoin( + method: string, + table: string, + alias: string, + on: string[], + ): string { + const values: any[] = []; + if (alias !== '') { + values.push(alias); + } + for (const query of on) { + values.push(JSONbig.parse(query)); + } + return new Query(method, table, values).toString(); + } +} + +export type QueryInput = string | Query | Query.Builder | QueryInput[]; + +/** + * Fluent collector of Query fragments. Call {@link Query.Builder.build} to + * produce the `string[]` expected by list/createQuery methods. + */ +export namespace Query { + export class Builder { + private readonly queries: string[] = []; + + build(): string[] { + return [...this.queries]; + } + + equal(attribute: string, value: QueryTypes): this { + return this.push(Query.equal(attribute, value)); + } + + notEqual(attribute: string, value: QueryTypes): this { + return this.push(Query.notEqual(attribute, value)); + } + + lessThan(attribute: string, value: QueryTypes): this { + return this.push(Query.lessThan(attribute, value)); + } + + lessThanEqual(attribute: string, value: QueryTypes): this { + return this.push(Query.lessThanEqual(attribute, value)); + } + + greaterThan(attribute: string, value: QueryTypes): this { + return this.push(Query.greaterThan(attribute, value)); + } + + greaterThanEqual(attribute: string, value: QueryTypes): this { + return this.push(Query.greaterThanEqual(attribute, value)); + } + + search(attribute: string, value: string): this { + return this.push(Query.search(attribute, value)); + } + + isNull(attribute: string): this { + return this.push(Query.isNull(attribute)); + } + + isNotNull(attribute: string): this { + return this.push(Query.isNotNull(attribute)); + } + + between( + attribute: string, + start: string | number | bigint, + end: string | number | bigint, + ): this { + return this.push(Query.between(attribute, start, end)); + } + + startsWith(attribute: string, value: string): this { + return this.push(Query.startsWith(attribute, value)); + } + + endsWith(attribute: string, value: string): this { + return this.push(Query.endsWith(attribute, value)); + } + + select(attributes: string[]): this { + return this.push(Query.select(attributes)); + } + + cursorAfter(documentId: string): this { + return this.push(Query.cursorAfter(documentId)); + } + + cursorBefore(documentId: string): this { + return this.push(Query.cursorBefore(documentId)); + } + + orderAsc(attribute: string): this { + return this.push(Query.orderAsc(attribute)); + } + + orderDesc(attribute: string): this { + return this.push(Query.orderDesc(attribute)); + } + + orderRandom(): this { + return this.push(Query.orderRandom()); + } + + limit(limit: number): this { + return this.push(Query.limit(limit)); + } + + offset(offset: number): this { + return this.push(Query.offset(offset)); + } + + contains(attribute: string, value: string | any[]): this { + return this.push(Query.contains(attribute, value)); + } + + containsAny(attribute: string, value: any[]): this { + return this.push(Query.containsAny(attribute, value)); + } + + containsAll(attribute: string, value: any[]): this { + return this.push(Query.containsAll(attribute, value)); + } + + notContains(attribute: string, value: string | any[]): this { + return this.push(Query.notContains(attribute, value)); + } + + notSearch(attribute: string, value: string): this { + return this.push(Query.notSearch(attribute, value)); + } + + notBetween( + attribute: string, + start: string | number | bigint, + end: string | number | bigint, + ): this { + return this.push(Query.notBetween(attribute, start, end)); + } + + notStartsWith(attribute: string, value: string): this { + return this.push(Query.notStartsWith(attribute, value)); + } + + notEndsWith(attribute: string, value: string): this { + return this.push(Query.notEndsWith(attribute, value)); + } + + regex(attribute: string, pattern: string): this { + return this.push(Query.regex(attribute, pattern)); + } + + exists(attributes: string[]): this { + return this.push(Query.exists(attributes)); + } + + notExists(attributes: string[]): this { + return this.push(Query.notExists(attributes)); + } + + createdBefore(value: string): this { + return this.push(Query.createdBefore(value)); + } + + createdAfter(value: string): this { + return this.push(Query.createdAfter(value)); + } + + createdBetween(start: string, end: string): this { + return this.push(Query.createdBetween(start, end)); + } + + updatedBefore(value: string): this { + return this.push(Query.updatedBefore(value)); + } + + updatedAfter(value: string): this { + return this.push(Query.updatedAfter(value)); + } + + updatedBetween(start: string, end: string): this { + return this.push(Query.updatedBetween(start, end)); + } + + or(queries: string[]): this { + return this.push(Query.or(queries)); + } + + and(queries: string[]): this { + return this.push(Query.and(queries)); + } + + elemMatch(attribute: string, queries: string[]): this { + return this.push(Query.elemMatch(attribute, queries)); + } + + relationship(attribute: string, queries: string[]): this { + return this.push(Query.relationship(attribute, queries)); + } + + distanceEqual( + attribute: string, + values: any[], + distance: number, + meters: boolean = true, + ): this { + return this.push( + Query.distanceEqual(attribute, values, distance, meters), + ); + } + + distanceNotEqual( + attribute: string, + values: any[], + distance: number, + meters: boolean = true, + ): this { + return this.push( + Query.distanceNotEqual(attribute, values, distance, meters), + ); + } + + distanceGreaterThan( + attribute: string, + values: any[], + distance: number, + meters: boolean = true, + ): this { + return this.push( + Query.distanceGreaterThan(attribute, values, distance, meters), + ); + } + + distanceLessThan( + attribute: string, + values: any[], + distance: number, + meters: boolean = true, + ): this { + return this.push( + Query.distanceLessThan(attribute, values, distance, meters), + ); + } + + intersects(attribute: string, values: any[]): this { + return this.push(Query.intersects(attribute, values)); + } + + notIntersects(attribute: string, values: any[]): this { + return this.push(Query.notIntersects(attribute, values)); + } + + crosses(attribute: string, values: any[]): this { + return this.push(Query.crosses(attribute, values)); + } + + notCrosses(attribute: string, values: any[]): this { + return this.push(Query.notCrosses(attribute, values)); + } + + overlaps(attribute: string, values: any[]): this { + return this.push(Query.overlaps(attribute, values)); + } + + notOverlaps(attribute: string, values: any[]): this { + return this.push(Query.notOverlaps(attribute, values)); + } + + touches(attribute: string, values: any[]): this { + return this.push(Query.touches(attribute, values)); + } + + notTouches(attribute: string, values: any[]): this { + return this.push(Query.notTouches(attribute, values)); + } + + count(attribute: string = '*', alias: string = ''): this { + return this.push(Query.count(attribute, alias)); + } + + countDistinct(attribute: string, alias: string = ''): this { + return this.push(Query.countDistinct(attribute, alias)); + } + + sum(attribute: string, alias: string = ''): this { + return this.push(Query.sum(attribute, alias)); + } + + avg(attribute: string, alias: string = ''): this { + return this.push(Query.avg(attribute, alias)); + } + + min(attribute: string, alias: string = ''): this { + return this.push(Query.min(attribute, alias)); + } + + max(attribute: string, alias: string = ''): this { + return this.push(Query.max(attribute, alias)); + } + + stddev(attribute: string, alias: string = ''): this { + return this.push(Query.stddev(attribute, alias)); + } + + stddevPop(attribute: string, alias: string = ''): this { + return this.push(Query.stddevPop(attribute, alias)); + } + + stddevSamp(attribute: string, alias: string = ''): this { + return this.push(Query.stddevSamp(attribute, alias)); + } + + variance(attribute: string, alias: string = ''): this { + return this.push(Query.variance(attribute, alias)); + } + + varPop(attribute: string, alias: string = ''): this { + return this.push(Query.varPop(attribute, alias)); + } + + varSamp(attribute: string, alias: string = ''): this { + return this.push(Query.varSamp(attribute, alias)); + } + + bitAnd(attribute: string, alias: string = ''): this { + return this.push(Query.bitAnd(attribute, alias)); + } + + bitOr(attribute: string, alias: string = ''): this { + return this.push(Query.bitOr(attribute, alias)); + } + + bitXor(attribute: string, alias: string = ''): this { + return this.push(Query.bitXor(attribute, alias)); + } + + groupBy(attributes: string[]): this { + return this.push(Query.groupBy(attributes)); + } + + having(queries: string[]): this { + return this.push(Query.having(queries)); + } + + distinct(): this { + return this.push(Query.distinct()); + } + + join( + table: string, + leftOrAliasOrOn: string | string[], + rightOrOn: string | string[] = '', + operator: string = '=', + alias: string = '', + ): this { + return this.push( + Query.join(table, leftOrAliasOrOn, rightOrOn, operator, alias), + ); + } + + leftJoin( + table: string, + leftOrAliasOrOn: string | string[], + rightOrOn: string | string[] = '', + operator: string = '=', + alias: string = '', + ): this { + return this.push( + Query.leftJoin( + table, + leftOrAliasOrOn, + rightOrOn, + operator, + alias, + ), + ); + } + + rightJoin( + table: string, + leftOrAliasOrOn: string | string[], + rightOrOn: string | string[] = '', + operator: string = '=', + alias: string = '', + ): this { + return this.push( + Query.rightJoin( + table, + leftOrAliasOrOn, + rightOrOn, + operator, + alias, + ), + ); + } + + fullOuterJoin( + table: string, + leftOrAliasOrOn: string | string[], + rightOrOn: string | string[] = '', + operator: string = '=', + alias: string = '', + ): this { + return this.push( + Query.fullOuterJoin( + table, + leftOrAliasOrOn, + rightOrOn, + operator, + alias, + ), + ); + } + + crossJoin(table: string, alias: string = ''): this { + return this.push(Query.crossJoin(table, alias)); + } + + vectorDot(attribute: string, vector: number[]): this { + return this.push(Query.vectorDot(attribute, vector)); + } + + vectorCosine(attribute: string, vector: number[]): this { + return this.push(Query.vectorCosine(attribute, vector)); + } + + vectorEuclidean(attribute: string, vector: number[]): this { + return this.push(Query.vectorEuclidean(attribute, vector)); + } + + covers(attribute: string, values: any[]): this { + return this.push(Query.covers(attribute, values)); + } + + notCovers(attribute: string, values: any[]): this { + return this.push(Query.notCovers(attribute, values)); + } + + spatialEquals(attribute: string, values: any[]): this { + return this.push(Query.spatialEquals(attribute, values)); + } + + notSpatialEquals(attribute: string, values: any[]): this { + return this.push(Query.notSpatialEquals(attribute, values)); + } + + page(page: number, perPage: number = 25): this { + return this.push(Query.page(page, perPage)); + } + + private push(query: string | string[]): this { + if (Array.isArray(query)) { + this.queries.push(...query); + } else { + this.queries.push(query); + } + return this; + } + } } + +export function normalizeQueries(queries?: QueryInput | null): string[] { + if (queries == null) { + return []; + } + if (queries instanceof Query.Builder) { + return queries.build(); + } + if (!Array.isArray(queries)) { + if (queries instanceof Query) { + return [queries.toString()]; + } + if (typeof queries === 'string') { + return [queries]; + } + return []; + } + + const out: string[] = []; + for (const item of queries) { + out.push(...normalizeQueries(item)); + } + return out; +} + +function isQueryValue(value: unknown): value is Query | Query.Builder { + return value instanceof Query.Builder || value instanceof Query; +} + +export function flattenParam(value: unknown): unknown { + if (isQueryValue(value)) { + return normalizeQueries(value); + } + if (!Array.isArray(value)) { + return value; + } + + const out: unknown[] = []; + for (const item of value) { + if (isQueryValue(item)) { + out.push(...normalizeQueries(item)); + } else { + out.push(flattenParam(item)); + } + } + return out; +} + +export const QueryBuilder = Query.Builder; +export type QueryBuilder = Query.Builder; diff --git a/src/services/account.ts b/src/services/account.ts index fb3d545b..983002d2 100644 --- a/src/services/account.ts +++ b/src/services/account.ts @@ -1,5 +1,5 @@ import { Service } from '../service'; -import { AppwriteException, Client } from '../client'; +import { AppwriteException, Client, applyDefaults } from '../client'; import type { Models } from '../models'; import type { Payload } from '../client'; @@ -25,7 +25,7 @@ export class Account extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -34,6 +34,49 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'user', + models: { + user: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + registration: '', + status: true, + labels: [], + passwordUpdate: '', + email: '', + phone: '', + emailVerification: false, + phoneVerification: false, + mfa: false, + targets: [], + accessedAt: '', + }, + properties: { + targets: { + items: 'target', + }, + }, + }, + target: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + userId: '', + providerType: '', + identifier: '', + expired: false, + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -143,7 +186,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -153,6 +196,49 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'user', + models: { + user: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + registration: '', + status: true, + labels: [], + passwordUpdate: '', + email: '', + phone: '', + emailVerification: false, + phoneVerification: false, + mfa: false, + targets: [], + accessedAt: '', + }, + properties: { + targets: { + items: 'target', + }, + }, + }, + target: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + userId: '', + providerType: '', + identifier: '', + expired: false, + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -218,7 +304,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -227,6 +313,38 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'oauth2ConsentList', + models: { + oauth2ConsentList: { + defaults: { + total: 0, + consents: [], + }, + properties: { + consents: { + items: 'oauth2Consent', + }, + }, + }, + oauth2Consent: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + userId: '', + appId: '', + cimdUrl: '', + scopes: [], + resources: [], + authorizationDetails: '[]', + expire: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -278,7 +396,7 @@ export class Account extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -287,6 +405,27 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'oauth2Consent', + models: { + oauth2Consent: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + userId: '', + appId: '', + cimdUrl: '', + scopes: [], + resources: [], + authorizationDetails: '[]', + expire: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -427,7 +566,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -436,6 +575,39 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'oauth2ConsentTokenList', + models: { + oauth2ConsentTokenList: { + defaults: { + total: 0, + tokens: [], + }, + properties: { + tokens: { + items: 'oauth2ConsentToken', + }, + }, + }, + oauth2ConsentToken: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + consentId: '', + userId: '', + appId: '', + cimdUrl: '', + scopes: [], + resources: [], + authorizationDetails: '[]', + expire: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -506,7 +678,7 @@ export class Account extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -515,6 +687,28 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'oauth2ConsentToken', + models: { + oauth2ConsentToken: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + consentId: '', + userId: '', + appId: '', + cimdUrl: '', + scopes: [], + resources: [], + authorizationDetails: '[]', + expire: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -673,7 +867,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'patch', uri, { @@ -683,6 +877,49 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'user', + models: { + user: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + registration: '', + status: true, + labels: [], + passwordUpdate: '', + email: '', + phone: '', + emailVerification: false, + phoneVerification: false, + mfa: false, + targets: [], + accessedAt: '', + }, + properties: { + targets: { + items: 'target', + }, + }, + }, + target: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + userId: '', + providerType: '', + identifier: '', + expired: false, + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -748,7 +985,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -757,6 +994,39 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'identityList', + models: { + identityList: { + defaults: { + total: 0, + identities: [], + }, + properties: { + identities: { + items: 'identity', + }, + }, + }, + identity: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + userId: '', + provider: '', + providerUid: '', + providerEmail: '', + providerAccessToken: '', + providerAccessTokenExpiry: '', + providerRefreshToken: '', + providerIdToken: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -865,7 +1135,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -875,6 +1145,18 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'jwt', + models: { + jwt: { + defaults: { + jwt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -931,7 +1213,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'patch', uri, { @@ -941,6 +1223,49 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'user', + models: { + user: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + registration: '', + status: true, + labels: [], + passwordUpdate: '', + email: '', + phone: '', + emailVerification: false, + phoneVerification: false, + mfa: false, + targets: [], + accessedAt: '', + }, + properties: { + targets: { + items: 'target', + }, + }, + }, + target: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + userId: '', + providerType: '', + identifier: '', + expired: false, + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -994,7 +1319,7 @@ export class Account extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -1004,6 +1329,19 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'mfaType', + models: { + mfaType: { + defaults: { + secret: '', + uri: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1056,7 +1394,7 @@ export class Account extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -1066,6 +1404,19 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'mfaType', + models: { + mfaType: { + defaults: { + secret: '', + uri: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1143,7 +1494,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'put', uri, { @@ -1153,6 +1504,49 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'user', + models: { + user: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + registration: '', + status: true, + labels: [], + passwordUpdate: '', + email: '', + phone: '', + emailVerification: false, + phoneVerification: false, + mfa: false, + targets: [], + accessedAt: '', + }, + properties: { + targets: { + items: 'target', + }, + }, + }, + target: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + userId: '', + providerType: '', + identifier: '', + expired: false, + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1229,7 +1623,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'put', uri, { @@ -1239,6 +1633,49 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'user', + models: { + user: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + registration: '', + status: true, + labels: [], + passwordUpdate: '', + email: '', + phone: '', + emailVerification: false, + phoneVerification: false, + mfa: false, + targets: [], + accessedAt: '', + }, + properties: { + targets: { + items: 'target', + }, + }, + }, + target: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + userId: '', + providerType: '', + identifier: '', + expired: false, + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1416,7 +1853,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -1426,6 +1863,21 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'mfaChallenge', + models: { + mfaChallenge: { + defaults: { + $id: '', + $createdAt: '', + userId: '', + expire: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1481,7 +1933,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -1491,6 +1943,21 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'mfaChallenge', + models: { + mfaChallenge: { + defaults: { + $id: '', + $createdAt: '', + userId: '', + expire: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1566,7 +2033,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'put', uri, { @@ -1576,6 +2043,46 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'session', + models: { + session: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + userId: '', + expire: '', + provider: '', + providerUid: '', + providerAccessToken: '', + providerAccessTokenExpiry: '', + providerRefreshToken: '', + ip: '', + osCode: '', + osName: '', + osVersion: '', + clientType: '', + clientCode: '', + clientName: '', + clientVersion: '', + clientEngine: '', + clientEngineVersion: '', + deviceName: '', + deviceBrand: '', + deviceModel: '', + countryCode: '', + countryName: '', + current: false, + factors: [], + secret: '', + mfaUpdatedAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1650,7 +2157,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'put', uri, { @@ -1660,6 +2167,46 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'session', + models: { + session: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + userId: '', + expire: '', + provider: '', + providerUid: '', + providerAccessToken: '', + providerAccessTokenExpiry: '', + providerRefreshToken: '', + ip: '', + osCode: '', + osName: '', + osVersion: '', + clientType: '', + clientCode: '', + clientName: '', + clientVersion: '', + clientEngine: '', + clientEngineVersion: '', + deviceName: '', + deviceBrand: '', + deviceModel: '', + countryCode: '', + countryName: '', + current: false, + factors: [], + secret: '', + mfaUpdatedAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1674,7 +2221,7 @@ export class Account extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -1683,6 +2230,22 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'mfaFactors', + models: { + mfaFactors: { + defaults: { + totp: false, + phone: false, + email: false, + recoveryCode: false, + custom: false, + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1696,7 +2259,7 @@ export class Account extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -1705,6 +2268,22 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'mfaFactors', + models: { + mfaFactors: { + defaults: { + totp: false, + phone: false, + email: false, + recoveryCode: false, + custom: false, + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1719,7 +2298,7 @@ export class Account extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -1728,6 +2307,18 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'mfaRecoveryCodes', + models: { + mfaRecoveryCodes: { + defaults: { + recoveryCodes: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1741,7 +2332,7 @@ export class Account extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -1750,6 +2341,18 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'mfaRecoveryCodes', + models: { + mfaRecoveryCodes: { + defaults: { + recoveryCodes: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1764,7 +2367,7 @@ export class Account extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -1774,6 +2377,18 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'mfaRecoveryCodes', + models: { + mfaRecoveryCodes: { + defaults: { + recoveryCodes: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1787,7 +2402,7 @@ export class Account extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -1797,6 +2412,18 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'mfaRecoveryCodes', + models: { + mfaRecoveryCodes: { + defaults: { + recoveryCodes: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1811,7 +2438,7 @@ export class Account extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'patch', uri, { @@ -1821,6 +2448,18 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'mfaRecoveryCodes', + models: { + mfaRecoveryCodes: { + defaults: { + recoveryCodes: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1833,9 +2472,553 @@ export class Account extends Service { const apiPath = '/account/mfa/recovery-codes'; const apiPayload: Payload = {}; + const uri = new URL(this.client.config.endpoint + apiPath); + const request = this.client.call( + 'patch', + uri, + { + 'X-Appwrite-Project': this.client.config.project, + 'content-type': 'application/json', + accept: 'application/json', + }, + apiPayload, + ); + const defaults = { + root: 'mfaRecoveryCodes', + models: { + mfaRecoveryCodes: { + defaults: { + recoveryCodes: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); + } + + /** + * Update currently logged in user account name. + * + * @param {string} params.name - User name. Max length: 128 chars. + * @throws {AppwriteException} + * @returns {Promise} + */ + updateName< + Preferences extends Models.Preferences = Models.DefaultPreferences, + >(params: { name: string }): Promise>; + /** + * Update currently logged in user account name. + * + * @param {string} name - User name. Max length: 128 chars. + * @throws {AppwriteException} + * @returns {Promise>} + * @deprecated Use the object parameter style method for a better developer experience. + */ + updateName< + Preferences extends Models.Preferences = Models.DefaultPreferences, + >(name: string): Promise>; + updateName< + Preferences extends Models.Preferences = Models.DefaultPreferences, + >( + paramsOrFirst: { name: string } | string, + ): Promise> { + let params: { name: string }; + + if ( + paramsOrFirst && + typeof paramsOrFirst === 'object' && + !Array.isArray(paramsOrFirst) + ) { + params = (paramsOrFirst || {}) as { name: string }; + } else { + params = { + name: paramsOrFirst as string, + }; + } + + const name = params.name; + + if (typeof name === 'undefined') { + throw new AppwriteException('Missing required parameter: "name"'); + } + + const apiPath = '/account/name'; + const apiPayload: Payload = {}; + + if (typeof name !== 'undefined') { + apiPayload['name'] = name; + } + + const uri = new URL(this.client.config.endpoint + apiPath); + const request = this.client.call( + 'patch', + uri, + { + 'X-Appwrite-Project': this.client.config.project, + 'content-type': 'application/json', + accept: 'application/json', + }, + apiPayload, + ); + const defaults = { + root: 'user', + models: { + user: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + registration: '', + status: true, + labels: [], + passwordUpdate: '', + email: '', + phone: '', + emailVerification: false, + phoneVerification: false, + mfa: false, + targets: [], + accessedAt: '', + }, + properties: { + targets: { + items: 'target', + }, + }, + }, + target: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + userId: '', + providerType: '', + identifier: '', + expired: false, + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); + } + + /** + * Get the list of verified passkeys registered by the currently logged in user. + * + * @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). Maximum of 100 queries are allowed, each 4096 characters long. You may filter and order on the following attributes: $id, $createdAt, $updatedAt, name, accessedAt + * @param {boolean} params.total - When set to false, the total count returned will be 0 and will not be calculated. + * @throws {AppwriteException} + * @returns {Promise} + */ + listPasskeys(params?: { + queries?: string[]; + total?: boolean; + }): Promise; + /** + * Get the list of verified passkeys registered by the currently logged in user. + * + * @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). Maximum of 100 queries are allowed, each 4096 characters long. You may filter and order on the following attributes: $id, $createdAt, $updatedAt, name, accessedAt + * @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. + */ + listPasskeys( + queries?: string[], + total?: boolean, + ): Promise; + listPasskeys( + paramsOrFirst?: { queries?: string[]; total?: boolean } | string[], + ...rest: [boolean?] + ): Promise { + let params: { queries?: string[]; total?: boolean }; + + if ( + (typeof paramsOrFirst === 'undefined' && rest.length === 0) || + (paramsOrFirst && + typeof paramsOrFirst === 'object' && + !Array.isArray(paramsOrFirst)) + ) { + 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 = '/account/passkeys'; + const apiPayload: Payload = {}; + + if (typeof queries !== 'undefined') { + apiPayload['queries'] = queries; + } + + if (typeof total !== 'undefined') { + apiPayload['total'] = total; + } + + const uri = new URL(this.client.config.endpoint + apiPath); + const request = this.client.call( + 'get', + uri, + { + 'X-Appwrite-Project': this.client.config.project, + accept: 'application/json', + }, + apiPayload, + ); + const defaults = { + root: 'passkeyList', + models: { + passkeyList: { + defaults: { + total: 0, + passkeys: [], + }, + properties: { + passkeys: { + items: 'passkey', + }, + }, + }, + passkey: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + accessedAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); + } + + /** + * Start registering a passkey for the currently logged in user. The session must have signed in or completed an MFA challenge within the last 10 minutes. Pass the returned `publicKey` options to `navigator.credentials.create()`, then complete the registration with [Update passkey verification](/docs/references/cloud/client-web/account#updatePasskeyVerification). The passkey stays pending until verified, and the challenge expires after 5 minutes. + * + * @param {string} params.passkeyId - Passkey 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. + * @param {string} params.name - Passkey name, shown when listing passkeys. Max length: 128 chars. + * @throws {AppwriteException} + * @returns {Promise} + */ + createPasskey(params?: { + passkeyId?: string; + name?: string; + }): Promise; + /** + * Start registering a passkey for the currently logged in user. The session must have signed in or completed an MFA challenge within the last 10 minutes. Pass the returned `publicKey` options to `navigator.credentials.create()`, then complete the registration with [Update passkey verification](/docs/references/cloud/client-web/account#updatePasskeyVerification). The passkey stays pending until verified, and the challenge expires after 5 minutes. + * + * @param {string} passkeyId - Passkey 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. + * @param {string} name - Passkey name, shown when listing passkeys. Max length: 128 chars. + * @throws {AppwriteException} + * @returns {Promise} + * @deprecated Use the object parameter style method for a better developer experience. + */ + createPasskey( + passkeyId?: string, + name?: string, + ): Promise; + createPasskey( + paramsOrFirst?: { passkeyId?: string; name?: string } | string, + ...rest: [string?] + ): Promise { + let params: { passkeyId?: string; name?: string }; + + if ( + (typeof paramsOrFirst === 'undefined' && rest.length === 0) || + (paramsOrFirst && + typeof paramsOrFirst === 'object' && + !Array.isArray(paramsOrFirst)) + ) { + params = (paramsOrFirst || {}) as { + passkeyId?: string; + name?: string; + }; + } else { + params = { + passkeyId: paramsOrFirst as string, + name: rest[0] as string, + }; + } + + const passkeyId = params.passkeyId; + const name = params.name; + + const apiPath = '/account/passkeys'; + const apiPayload: Payload = {}; + + if (typeof passkeyId !== 'undefined') { + apiPayload['passkeyId'] = passkeyId; + } + + if (typeof name !== 'undefined') { + apiPayload['name'] = name; + } + + const uri = new URL(this.client.config.endpoint + apiPath); + const request = this.client.call( + 'post', + uri, + { + 'X-Appwrite-Project': this.client.config.project, + 'content-type': 'application/json', + accept: 'application/json', + }, + apiPayload, + ); + const defaults = { + root: 'passkeyChallenge', + models: { + passkeyChallenge: { + defaults: { + $id: '', + $createdAt: '', + passkeyId: '', + expire: '', + publicKey: {}, + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); + } + + /** + * Get a verified passkey of the currently logged in user by its unique ID. + * + * @param {string} params.passkeyId - Passkey ID. + * @throws {AppwriteException} + * @returns {Promise} + */ + getPasskey(params: { passkeyId: string }): Promise; + /** + * Get a verified passkey of the currently logged in user by its unique ID. + * + * @param {string} passkeyId - Passkey ID. + * @throws {AppwriteException} + * @returns {Promise} + * @deprecated Use the object parameter style method for a better developer experience. + */ + getPasskey(passkeyId: string): Promise; + getPasskey( + paramsOrFirst: { passkeyId: string } | string, + ): Promise { + let params: { passkeyId: string }; + + if ( + paramsOrFirst && + typeof paramsOrFirst === 'object' && + !Array.isArray(paramsOrFirst) + ) { + params = (paramsOrFirst || {}) as { passkeyId: string }; + } else { + params = { + passkeyId: paramsOrFirst as string, + }; + } + + const passkeyId = params.passkeyId; + + if (typeof passkeyId === 'undefined' || passkeyId === '') { + throw new AppwriteException( + 'Missing required parameter: "passkeyId"', + ); + } + + const apiPath = '/account/passkeys/{passkeyId}'.replace( + '{passkeyId}', + encodeURIComponent(String(passkeyId)), + ); + const apiPayload: Payload = {}; + + const uri = new URL(this.client.config.endpoint + apiPath); + const request = this.client.call( + 'get', + uri, + { + 'X-Appwrite-Project': this.client.config.project, + accept: 'application/json', + }, + apiPayload, + ); + const defaults = { + root: 'passkey', + models: { + passkey: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + accessedAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); + } + + /** + * Rename a passkey of the currently logged in user. + * + * @param {string} params.passkeyId - Passkey ID. + * @param {string} params.name - Passkey name. Max length: 128 chars. + * @throws {AppwriteException} + * @returns {Promise} + */ + updatePasskey(params: { + passkeyId: string; + name: string; + }): Promise; + /** + * Rename a passkey of the currently logged in user. + * + * @param {string} passkeyId - Passkey ID. + * @param {string} name - Passkey name. Max length: 128 chars. + * @throws {AppwriteException} + * @returns {Promise} + * @deprecated Use the object parameter style method for a better developer experience. + */ + updatePasskey(passkeyId: string, name: string): Promise; + updatePasskey( + paramsOrFirst: { passkeyId: string; name: string } | string, + ...rest: [string?] + ): Promise { + let params: { passkeyId: string; name: string }; + + if ( + paramsOrFirst && + typeof paramsOrFirst === 'object' && + !Array.isArray(paramsOrFirst) + ) { + params = (paramsOrFirst || {}) as { + passkeyId: string; + name: string; + }; + } else { + params = { + passkeyId: paramsOrFirst as string, + name: rest[0] as string, + }; + } + + const passkeyId = params.passkeyId; + const name = params.name; + + if (typeof passkeyId === 'undefined' || passkeyId === '') { + throw new AppwriteException( + 'Missing required parameter: "passkeyId"', + ); + } + + if (typeof name === 'undefined') { + throw new AppwriteException('Missing required parameter: "name"'); + } + + const apiPath = '/account/passkeys/{passkeyId}'.replace( + '{passkeyId}', + encodeURIComponent(String(passkeyId)), + ); + const apiPayload: Payload = {}; + + if (typeof name !== 'undefined') { + apiPayload['name'] = name; + } + + const uri = new URL(this.client.config.endpoint + apiPath); + const request = this.client.call( + 'patch', + uri, + { + 'X-Appwrite-Project': this.client.config.project, + 'content-type': 'application/json', + accept: 'application/json', + }, + apiPayload, + ); + const defaults = { + root: 'passkey', + models: { + passkey: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + accessedAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); + } + + /** + * Delete a passkey from the currently logged in user. The passkey can no longer be used to sign in, although it may remain stored on the user's device. The session must have signed in or completed an MFA challenge within the last 10 minutes. + * + * @param {string} params.passkeyId - Passkey ID. + * @throws {AppwriteException} + * @returns {Promise} + */ + deletePasskey(params: { passkeyId: string }): Promise<{}>; + /** + * Delete a passkey from the currently logged in user. The passkey can no longer be used to sign in, although it may remain stored on the user's device. The session must have signed in or completed an MFA challenge within the last 10 minutes. + * + * @param {string} passkeyId - Passkey ID. + * @throws {AppwriteException} + * @returns {Promise<{}>} + * @deprecated Use the object parameter style method for a better developer experience. + */ + deletePasskey(passkeyId: string): Promise<{}>; + deletePasskey(paramsOrFirst: { passkeyId: string } | string): Promise<{}> { + let params: { passkeyId: string }; + + if ( + paramsOrFirst && + typeof paramsOrFirst === 'object' && + !Array.isArray(paramsOrFirst) + ) { + params = (paramsOrFirst || {}) as { passkeyId: string }; + } else { + params = { + passkeyId: paramsOrFirst as string, + }; + } + + const passkeyId = params.passkeyId; + + if (typeof passkeyId === 'undefined' || passkeyId === '') { + throw new AppwriteException( + 'Missing required parameter: "passkeyId"', + ); + } + + const apiPath = '/account/passkeys/{passkeyId}'.replace( + '{passkeyId}', + encodeURIComponent(String(passkeyId)), + ); + const apiPayload: Payload = {}; + const uri = new URL(this.client.config.endpoint + apiPath); return this.client.call( - 'patch', + 'delete', uri, { 'X-Appwrite-Project': this.client.config.project, @@ -1847,61 +3030,80 @@ export class Account extends Service { } /** - * Update currently logged in user account name. + * Complete a passkey registration started with [Create passkey](/docs/references/cloud/client-web/account#createPasskey). Pass the JSON form of the credential returned by `navigator.credentials.create()`, for example `credential.toJSON()`. Each registration can be verified once; a failed attempt requires starting it again. * - * @param {string} params.name - User name. Max length: 128 chars. + * @param {string} params.passkeyId - Passkey ID. + * @param {object} params.credential - Registration credential returned by the authenticator, in the JSON form produced by `PublicKeyCredential.toJSON()`. * @throws {AppwriteException} * @returns {Promise} */ - updateName< - Preferences extends Models.Preferences = Models.DefaultPreferences, - >(params: { name: string }): Promise>; + updatePasskeyVerification(params: { + passkeyId: string; + credential: object; + }): Promise; /** - * Update currently logged in user account name. + * Complete a passkey registration started with [Create passkey](/docs/references/cloud/client-web/account#createPasskey). Pass the JSON form of the credential returned by `navigator.credentials.create()`, for example `credential.toJSON()`. Each registration can be verified once; a failed attempt requires starting it again. * - * @param {string} name - User name. Max length: 128 chars. + * @param {string} passkeyId - Passkey ID. + * @param {object} credential - Registration credential returned by the authenticator, in the JSON form produced by `PublicKeyCredential.toJSON()`. * @throws {AppwriteException} - * @returns {Promise>} + * @returns {Promise} * @deprecated Use the object parameter style method for a better developer experience. */ - updateName< - Preferences extends Models.Preferences = Models.DefaultPreferences, - >(name: string): Promise>; - updateName< - Preferences extends Models.Preferences = Models.DefaultPreferences, - >( - paramsOrFirst: { name: string } | string, - ): Promise> { - let params: { name: string }; + updatePasskeyVerification( + passkeyId: string, + credential: object, + ): Promise; + updatePasskeyVerification( + paramsOrFirst: { passkeyId: string; credential: object } | string, + ...rest: [object?] + ): Promise { + let params: { passkeyId: string; credential: object }; if ( paramsOrFirst && typeof paramsOrFirst === 'object' && !Array.isArray(paramsOrFirst) ) { - params = (paramsOrFirst || {}) as { name: string }; + params = (paramsOrFirst || {}) as { + passkeyId: string; + credential: object; + }; } else { params = { - name: paramsOrFirst as string, + passkeyId: paramsOrFirst as string, + credential: rest[0] as object, }; } - const name = params.name; + const passkeyId = params.passkeyId; + const credential = params.credential; - if (typeof name === 'undefined') { - throw new AppwriteException('Missing required parameter: "name"'); + if (typeof passkeyId === 'undefined' || passkeyId === '') { + throw new AppwriteException( + 'Missing required parameter: "passkeyId"', + ); } - const apiPath = '/account/name'; + if (typeof credential === 'undefined') { + throw new AppwriteException( + 'Missing required parameter: "credential"', + ); + } + + const apiPath = '/account/passkeys/{passkeyId}/verification'.replace( + '{passkeyId}', + encodeURIComponent(String(passkeyId)), + ); const apiPayload: Payload = {}; - if (typeof name !== 'undefined') { - apiPayload['name'] = name; + if (typeof credential !== 'undefined') { + apiPayload['credential'] = credential; } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( - 'patch', + const request = this.client.call( + 'put', uri, { 'X-Appwrite-Project': this.client.config.project, @@ -1910,6 +3112,22 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'passkey', + models: { + passkey: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + accessedAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1986,7 +3204,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'patch', uri, { @@ -1996,6 +3214,49 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'user', + models: { + user: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + registration: '', + status: true, + labels: [], + passwordUpdate: '', + email: '', + phone: '', + emailVerification: false, + phoneVerification: false, + mfa: false, + targets: [], + accessedAt: '', + }, + properties: { + targets: { + items: 'target', + }, + }, + }, + target: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + userId: '', + providerType: '', + identifier: '', + expired: false, + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -2073,7 +3334,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'patch', uri, { @@ -2083,6 +3344,49 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'user', + models: { + user: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + registration: '', + status: true, + labels: [], + passwordUpdate: '', + email: '', + phone: '', + emailVerification: false, + phoneVerification: false, + mfa: false, + targets: [], + accessedAt: '', + }, + properties: { + targets: { + items: 'target', + }, + }, + }, + target: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + userId: '', + providerType: '', + identifier: '', + expired: false, + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -2166,7 +3470,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'patch', uri, { @@ -2176,6 +3480,49 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'user', + models: { + user: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + registration: '', + status: true, + labels: [], + passwordUpdate: '', + email: '', + phone: '', + emailVerification: false, + phoneVerification: false, + mfa: false, + targets: [], + accessedAt: '', + }, + properties: { + targets: { + items: 'target', + }, + }, + }, + target: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + userId: '', + providerType: '', + identifier: '', + expired: false, + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -2242,7 +3589,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -2252,6 +3599,23 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'token', + models: { + token: { + defaults: { + $id: '', + $createdAt: '', + userId: '', + secret: '', + expire: '', + phrase: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -2346,7 +3710,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'put', uri, { @@ -2356,6 +3720,23 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'token', + models: { + token: { + defaults: { + $id: '', + $createdAt: '', + userId: '', + secret: '', + expire: '', + phrase: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -2427,7 +3808,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -2437,6 +3818,23 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'token', + models: { + token: { + defaults: { + $id: '', + $createdAt: '', + userId: '', + secret: '', + expire: '', + phrase: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -2529,7 +3927,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'put', uri, { @@ -2539,6 +3937,23 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'token', + models: { + token: { + defaults: { + $id: '', + $createdAt: '', + userId: '', + secret: '', + expire: '', + phrase: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -2586,7 +4001,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -2595,6 +4010,57 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'sessionList', + models: { + sessionList: { + defaults: { + total: 0, + sessions: [], + }, + properties: { + sessions: { + items: 'session', + }, + }, + }, + session: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + userId: '', + expire: '', + provider: '', + providerUid: '', + providerAccessToken: '', + providerAccessTokenExpiry: '', + providerRefreshToken: '', + ip: '', + osCode: '', + osName: '', + osVersion: '', + clientType: '', + clientCode: '', + clientName: '', + clientVersion: '', + clientEngine: '', + clientEngineVersion: '', + deviceName: '', + deviceBrand: '', + deviceModel: '', + countryCode: '', + countryName: '', + current: false, + factors: [], + secret: '', + mfaUpdatedAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -2665,7 +4131,7 @@ export class Account extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -2675,6 +4141,46 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'session', + models: { + session: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + userId: '', + expire: '', + provider: '', + providerUid: '', + providerAccessToken: '', + providerAccessTokenExpiry: '', + providerRefreshToken: '', + ip: '', + osCode: '', + osName: '', + osVersion: '', + clientType: '', + clientCode: '', + clientName: '', + clientVersion: '', + clientEngine: '', + clientEngineVersion: '', + deviceName: '', + deviceBrand: '', + deviceModel: '', + countryCode: '', + countryName: '', + current: false, + factors: [], + secret: '', + mfaUpdatedAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -2684,14 +4190,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. + * @param {number | null} 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; + duration?: number | null; }): 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. Use the optional `duration` parameter to create a shorter session, for example when the user doesn't choose "remember me". It must be at least 60 seconds and cannot exceed the project maximum session length. @@ -2700,7 +4206,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. + * @param {number | null} 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. @@ -2708,14 +4214,19 @@ export class Account extends Service { createEmailPasswordSession( email: string, password: string, - duration?: number, + duration?: number | null, ): Promise; createEmailPasswordSession( paramsOrFirst: - { email: string; password: string; duration?: number } | string, - ...rest: [string?, number?] + | { email: string; password: string; duration?: number | null } + | string, + ...rest: [string?, (number | null)?] ): Promise { - let params: { email: string; password: string; duration?: number }; + let params: { + email: string; + password: string; + duration?: number | null; + }; if ( paramsOrFirst && @@ -2725,13 +4236,13 @@ export class Account extends Service { params = (paramsOrFirst || {}) as { email: string; password: string; - duration?: number; + duration?: number | null; }; } else { params = { email: paramsOrFirst as string, password: rest[0] as string, - duration: rest[1] as number, + duration: rest[1] as number | null, }; } @@ -2765,7 +4276,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -2775,6 +4286,46 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'session', + models: { + session: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + userId: '', + expire: '', + provider: '', + providerUid: '', + providerAccessToken: '', + providerAccessTokenExpiry: '', + providerRefreshToken: '', + ip: '', + osCode: '', + osName: '', + osVersion: '', + clientType: '', + clientCode: '', + clientName: '', + clientVersion: '', + clientEngine: '', + clientEngineVersion: '', + deviceName: '', + deviceBrand: '', + deviceModel: '', + countryCode: '', + countryName: '', + current: false, + factors: [], + secret: '', + mfaUpdatedAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -2939,7 +4490,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -2949,6 +4500,46 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'session', + models: { + session: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + userId: '', + expire: '', + provider: '', + providerUid: '', + providerAccessToken: '', + providerAccessTokenExpiry: '', + providerRefreshToken: '', + ip: '', + osCode: '', + osName: '', + osVersion: '', + clientType: '', + clientCode: '', + clientName: '', + clientVersion: '', + clientEngine: '', + clientEngineVersion: '', + deviceName: '', + deviceBrand: '', + deviceModel: '', + countryCode: '', + countryName: '', + current: false, + factors: [], + secret: '', + mfaUpdatedAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -3022,7 +4613,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'put', uri, { @@ -3032,6 +4623,46 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'session', + models: { + session: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + userId: '', + expire: '', + provider: '', + providerUid: '', + providerAccessToken: '', + providerAccessTokenExpiry: '', + providerRefreshToken: '', + ip: '', + osCode: '', + osName: '', + osVersion: '', + clientType: '', + clientCode: '', + clientName: '', + clientVersion: '', + clientEngine: '', + clientEngineVersion: '', + deviceName: '', + deviceBrand: '', + deviceModel: '', + countryCode: '', + countryName: '', + current: false, + factors: [], + secret: '', + mfaUpdatedAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -3046,6 +4677,7 @@ export class Account extends Service { * @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} */ @@ -3054,6 +4686,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. @@ -3067,6 +4700,7 @@ export class Account extends Service { * @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. @@ -3076,6 +4710,7 @@ export class Account extends Service { success?: string, failure?: string, scopes?: string[], + state?: string, ): void | URL; createOAuth2Session( paramsOrFirst: @@ -3084,15 +4719,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 ( @@ -3102,13 +4739,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 = { @@ -3116,6 +4755,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, }; } @@ -3123,6 +4763,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( @@ -3148,6 +4789,10 @@ export class Account extends Service { apiPayload['scopes'] = scopes; } + if (typeof state !== 'undefined') { + apiPayload['state'] = state; + } + const uri = new URL(this.client.config.endpoint + apiPath); apiPayload['project'] = this.client.config.project; @@ -3227,7 +4872,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'put', uri, { @@ -3237,6 +4882,46 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'session', + models: { + session: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + userId: '', + expire: '', + provider: '', + providerUid: '', + providerAccessToken: '', + providerAccessTokenExpiry: '', + providerRefreshToken: '', + ip: '', + osCode: '', + osName: '', + osVersion: '', + clientType: '', + clientCode: '', + clientName: '', + clientVersion: '', + clientEngine: '', + clientEngineVersion: '', + deviceName: '', + deviceBrand: '', + deviceModel: '', + countryCode: '', + countryName: '', + current: false, + factors: [], + secret: '', + mfaUpdatedAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -3306,7 +4991,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -3316,6 +5001,46 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'session', + models: { + session: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + userId: '', + expire: '', + provider: '', + providerUid: '', + providerAccessToken: '', + providerAccessTokenExpiry: '', + providerRefreshToken: '', + ip: '', + osCode: '', + osName: '', + osVersion: '', + clientType: '', + clientCode: '', + clientName: '', + clientVersion: '', + clientEngine: '', + clientEngineVersion: '', + deviceName: '', + deviceBrand: '', + deviceModel: '', + countryCode: '', + countryName: '', + current: false, + factors: [], + secret: '', + mfaUpdatedAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -3367,7 +5092,7 @@ export class Account extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -3376,6 +5101,46 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'session', + models: { + session: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + userId: '', + expire: '', + provider: '', + providerUid: '', + providerAccessToken: '', + providerAccessTokenExpiry: '', + providerRefreshToken: '', + ip: '', + osCode: '', + osName: '', + osVersion: '', + clientType: '', + clientCode: '', + clientName: '', + clientVersion: '', + clientEngine: '', + clientEngineVersion: '', + deviceName: '', + deviceBrand: '', + deviceModel: '', + countryCode: '', + countryName: '', + current: false, + factors: [], + secret: '', + mfaUpdatedAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -3427,7 +5192,7 @@ export class Account extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'patch', uri, { @@ -3437,6 +5202,46 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'session', + models: { + session: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + userId: '', + expire: '', + provider: '', + providerUid: '', + providerAccessToken: '', + providerAccessTokenExpiry: '', + providerRefreshToken: '', + ip: '', + osCode: '', + osName: '', + osVersion: '', + clientType: '', + clientCode: '', + clientName: '', + clientVersion: '', + clientEngine: '', + clientEngineVersion: '', + deviceName: '', + deviceBrand: '', + deviceModel: '', + countryCode: '', + countryName: '', + current: false, + factors: [], + secret: '', + mfaUpdatedAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -3511,7 +5316,7 @@ export class Account extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'patch', uri, { @@ -3521,6 +5326,49 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'user', + models: { + user: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + registration: '', + status: true, + labels: [], + passwordUpdate: '', + email: '', + phone: '', + emailVerification: false, + phoneVerification: false, + mfa: false, + targets: [], + accessedAt: '', + }, + properties: { + targets: { + items: 'target', + }, + }, + }, + target: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + userId: '', + providerType: '', + identifier: '', + expired: false, + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -3614,7 +5462,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -3624,6 +5472,25 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'target', + models: { + target: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + userId: '', + providerType: '', + identifier: '', + expired: false, + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -3699,7 +5566,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'put', uri, { @@ -3709,6 +5576,25 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'target', + models: { + target: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + userId: '', + providerType: '', + identifier: '', + expired: false, + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -3860,7 +5746,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -3870,6 +5756,23 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'token', + models: { + token: { + defaults: { + $id: '', + $createdAt: '', + userId: '', + secret: '', + expire: '', + phrase: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -3977,7 +5880,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -3987,6 +5890,23 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'token', + models: { + token: { + defaults: { + $id: '', + $createdAt: '', + userId: '', + secret: '', + expire: '', + phrase: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -4002,6 +5922,7 @@ export class Account extends Service { * @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} */ @@ -4010,6 +5931,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. @@ -4024,6 +5946,7 @@ export class Account extends Service { * @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. @@ -4033,6 +5956,7 @@ export class Account extends Service { success?: string, failure?: string, scopes?: string[], + state?: string, ): void | URL; createOAuth2Token( paramsOrFirst: @@ -4041,15 +5965,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 ( @@ -4059,13 +5985,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 = { @@ -4073,6 +6001,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, }; } @@ -4080,6 +6009,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( @@ -4105,6 +6035,10 @@ export class Account extends Service { apiPayload['scopes'] = scopes; } + if (typeof state !== 'undefined') { + apiPayload['state'] = state; + } + const uri = new URL(this.client.config.endpoint + apiPath); apiPayload['project'] = this.client.config.project; @@ -4116,6 +6050,148 @@ export class Account extends Service { return uri; } + /** + * Start signing in with a passkey. No email or user ID is needed: pass the returned `publicKey` options to `navigator.credentials.get()` and the user picks one of their passkeys. Then call [Update passkey token](/docs/references/cloud/client-web/account#updatePasskeyToken) with the credential to receive a token, and exchange it with [Create session](/docs/references/cloud/client-web/account#createSession). The challenge expires after 5 minutes. + * + * @throws {AppwriteException} + * @returns {Promise} + */ + createPasskeyToken(): Promise { + const apiPath = '/account/tokens/passkey'; + const apiPayload: Payload = {}; + + const uri = new URL(this.client.config.endpoint + apiPath); + const request = this.client.call( + 'post', + uri, + { + 'X-Appwrite-Project': this.client.config.project, + 'content-type': 'application/json', + accept: 'application/json', + }, + apiPayload, + ); + const defaults = { + root: 'passkeyChallenge', + models: { + passkeyChallenge: { + defaults: { + $id: '', + $createdAt: '', + passkeyId: '', + expire: '', + publicKey: {}, + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); + } + + /** + * Complete a passkey sign-in started with [Create passkey token](/docs/references/cloud/client-web/account#createPasskeyToken). Pass the challenge ID and the JSON form of the credential returned by `navigator.credentials.get()`, for example `credential.toJSON()`. The returned token includes its secret and expires after 1 minute: exchange it for a session with [Create session](/docs/references/cloud/client-web/account#createSession). Passkeys require user verification, so the session also satisfies MFA. Each challenge can only be used once. + * + * @param {string} params.challengeId - Challenge ID returned by createPasskeyToken. + * @param {object} params.credential - Authentication credential returned by the authenticator, in the JSON form produced by `PublicKeyCredential.toJSON()`. + * @throws {AppwriteException} + * @returns {Promise} + */ + updatePasskeyToken(params: { + challengeId: string; + credential: object; + }): Promise; + /** + * Complete a passkey sign-in started with [Create passkey token](/docs/references/cloud/client-web/account#createPasskeyToken). Pass the challenge ID and the JSON form of the credential returned by `navigator.credentials.get()`, for example `credential.toJSON()`. The returned token includes its secret and expires after 1 minute: exchange it for a session with [Create session](/docs/references/cloud/client-web/account#createSession). Passkeys require user verification, so the session also satisfies MFA. Each challenge can only be used once. + * + * @param {string} challengeId - Challenge ID returned by createPasskeyToken. + * @param {object} credential - Authentication credential returned by the authenticator, in the JSON form produced by `PublicKeyCredential.toJSON()`. + * @throws {AppwriteException} + * @returns {Promise} + * @deprecated Use the object parameter style method for a better developer experience. + */ + updatePasskeyToken( + challengeId: string, + credential: object, + ): Promise; + updatePasskeyToken( + paramsOrFirst: { challengeId: string; credential: object } | string, + ...rest: [object?] + ): Promise { + let params: { challengeId: string; credential: object }; + + if ( + paramsOrFirst && + typeof paramsOrFirst === 'object' && + !Array.isArray(paramsOrFirst) + ) { + params = (paramsOrFirst || {}) as { + challengeId: string; + credential: object; + }; + } else { + params = { + challengeId: paramsOrFirst as string, + credential: rest[0] as object, + }; + } + + const challengeId = params.challengeId; + const credential = params.credential; + + if (typeof challengeId === 'undefined') { + throw new AppwriteException( + 'Missing required parameter: "challengeId"', + ); + } + + if (typeof credential === 'undefined') { + throw new AppwriteException( + 'Missing required parameter: "credential"', + ); + } + + const apiPath = '/account/tokens/passkey'; + const apiPayload: Payload = {}; + + if (typeof challengeId !== 'undefined') { + apiPayload['challengeId'] = challengeId; + } + + if (typeof credential !== 'undefined') { + apiPayload['credential'] = credential; + } + + const uri = new URL(this.client.config.endpoint + apiPath); + const request = this.client.call( + 'put', + uri, + { + 'X-Appwrite-Project': this.client.config.project, + 'content-type': 'application/json', + accept: 'application/json', + }, + apiPayload, + ); + const defaults = { + root: 'tokenSecret', + models: { + tokenSecret: { + defaults: { + $id: '', + $createdAt: '', + userId: '', + secret: '', + expire: '', + phrase: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); + } + /** * Sends the user an SMS with a secret key for creating a session. If the provided user ID has not be registered, a new user will be created. Use the returned user ID and secret and submit a request to the [POST /v1/account/sessions/token](https://appwrite.io/docs/references/cloud/client-web/account#createSession) endpoint to complete the login process. The secret sent to the user's phone is valid for 15 minutes. * @@ -4184,7 +6260,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -4194,6 +6270,23 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'token', + models: { + token: { + defaults: { + $id: '', + $createdAt: '', + userId: '', + secret: '', + expire: '', + phrase: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -4250,7 +6343,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -4260,6 +6353,23 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'token', + models: { + token: { + defaults: { + $id: '', + $createdAt: '', + userId: '', + secret: '', + expire: '', + phrase: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -4317,7 +6427,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -4327,6 +6437,23 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'token', + models: { + token: { + defaults: { + $id: '', + $createdAt: '', + userId: '', + secret: '', + expire: '', + phrase: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -4399,7 +6526,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'put', uri, { @@ -4409,6 +6536,23 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'token', + models: { + token: { + defaults: { + $id: '', + $createdAt: '', + userId: '', + secret: '', + expire: '', + phrase: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -4479,7 +6623,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'put', uri, { @@ -4489,6 +6633,23 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'token', + models: { + token: { + defaults: { + $id: '', + $createdAt: '', + userId: '', + secret: '', + expire: '', + phrase: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -4544,7 +6705,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -4554,6 +6715,23 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'token', + models: { + token: { + defaults: { + $id: '', + $createdAt: '', + userId: '', + secret: '', + expire: '', + phrase: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -4628,7 +6806,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'put', uri, { @@ -4638,6 +6816,23 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'token', + models: { + token: { + defaults: { + $id: '', + $createdAt: '', + userId: '', + secret: '', + expire: '', + phrase: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -4651,7 +6846,7 @@ export class Account extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -4661,6 +6856,23 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'token', + models: { + token: { + defaults: { + $id: '', + $createdAt: '', + userId: '', + secret: '', + expire: '', + phrase: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -4733,7 +6945,7 @@ export class Account extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'put', uri, { @@ -4743,5 +6955,22 @@ export class Account extends Service { }, apiPayload, ); + const defaults = { + root: 'token', + models: { + token: { + defaults: { + $id: '', + $createdAt: '', + userId: '', + secret: '', + expire: '', + phrase: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } } 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/apps.ts b/src/services/apps.ts index 02554ba4..896038d7 100644 --- a/src/services/apps.ts +++ b/src/services/apps.ts @@ -1,5 +1,5 @@ import { Service } from '../service'; -import { AppwriteException, Client } from '../client'; +import { AppwriteException, Client, applyDefaults } from '../client'; import type { Models } from '../models'; import type { Payload } from '../client'; @@ -68,7 +68,7 @@ export class Apps extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -77,6 +77,71 @@ export class Apps extends Service { }, apiPayload, ); + const defaults = { + root: 'appsList', + models: { + appsList: { + defaults: { + total: 0, + apps: [], + }, + properties: { + apps: { + items: 'app', + }, + }, + }, + app: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + description: '', + clientUri: '', + logoUri: '', + privacyPolicyUrl: '', + termsUrl: '', + contacts: [], + tagline: '', + tags: [], + labels: [], + images: [], + supportUrl: '', + dataDeletionUrl: '', + redirectUris: [], + postLogoutRedirectUris: [], + enabled: true, + type: 'confidential', + deviceFlow: false, + teamId: '', + userId: '', + installationScopes: [], + installationRedirectUrl: '', + secrets: [], + }, + properties: { + secrets: { + items: 'appSecret', + }, + }, + }, + appSecret: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + appId: '', + secret: '', + hint: '', + createdById: '', + createdByName: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -403,7 +468,7 @@ export class Apps extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -413,6 +478,60 @@ export class Apps extends Service { }, apiPayload, ); + const defaults = { + root: 'app', + models: { + app: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + description: '', + clientUri: '', + logoUri: '', + privacyPolicyUrl: '', + termsUrl: '', + contacts: [], + tagline: '', + tags: [], + labels: [], + images: [], + supportUrl: '', + dataDeletionUrl: '', + redirectUris: [], + postLogoutRedirectUris: [], + enabled: true, + type: 'confidential', + deviceFlow: false, + teamId: '', + userId: '', + installationScopes: [], + installationRedirectUrl: '', + secrets: [], + }, + properties: { + secrets: { + items: 'appSecret', + }, + }, + }, + appSecret: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + appId: '', + secret: '', + hint: '', + createdById: '', + createdByName: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -426,7 +545,7 @@ export class Apps extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -435,6 +554,33 @@ export class Apps extends Service { }, apiPayload, ); + const defaults = { + root: 'appScopeList', + models: { + appScopeList: { + defaults: { + total: 0, + scopes: [], + }, + properties: { + scopes: { + items: 'appScope', + }, + }, + }, + appScope: { + defaults: { + value: '', + description: '', + type: '', + category: '', + deprecated: false, + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -448,7 +594,7 @@ export class Apps extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -457,6 +603,33 @@ export class Apps extends Service { }, apiPayload, ); + const defaults = { + root: 'appScopeList', + models: { + appScopeList: { + defaults: { + total: 0, + scopes: [], + }, + properties: { + scopes: { + items: 'appScope', + }, + }, + }, + appScope: { + defaults: { + value: '', + description: '', + type: '', + category: '', + deprecated: false, + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -504,7 +677,7 @@ export class Apps extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -513,6 +686,60 @@ export class Apps extends Service { }, apiPayload, ); + const defaults = { + root: 'app', + models: { + app: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + description: '', + clientUri: '', + logoUri: '', + privacyPolicyUrl: '', + termsUrl: '', + contacts: [], + tagline: '', + tags: [], + labels: [], + images: [], + supportUrl: '', + dataDeletionUrl: '', + redirectUris: [], + postLogoutRedirectUris: [], + enabled: true, + type: 'confidential', + deviceFlow: false, + teamId: '', + userId: '', + installationScopes: [], + installationRedirectUrl: '', + secrets: [], + }, + properties: { + secrets: { + items: 'appSecret', + }, + }, + }, + appSecret: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + appId: '', + secret: '', + hint: '', + createdById: '', + createdByName: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -846,7 +1073,7 @@ export class Apps extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'put', uri, { @@ -856,6 +1083,60 @@ export class Apps extends Service { }, apiPayload, ); + const defaults = { + root: 'app', + models: { + app: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + description: '', + clientUri: '', + logoUri: '', + privacyPolicyUrl: '', + termsUrl: '', + contacts: [], + tagline: '', + tags: [], + labels: [], + images: [], + supportUrl: '', + dataDeletionUrl: '', + redirectUris: [], + postLogoutRedirectUris: [], + enabled: true, + type: 'confidential', + deviceFlow: false, + teamId: '', + userId: '', + installationScopes: [], + installationRedirectUrl: '', + secrets: [], + }, + properties: { + secrets: { + items: 'appSecret', + }, + }, + }, + appSecret: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + appId: '', + secret: '', + hint: '', + createdById: '', + createdByName: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -992,7 +1273,7 @@ export class Apps extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -1001,6 +1282,37 @@ export class Apps extends Service { }, apiPayload, ); + const defaults = { + root: 'appInstallationList', + models: { + appInstallationList: { + defaults: { + total: 0, + installations: [], + }, + properties: { + installations: { + items: 'appInstallation', + }, + }, + }, + appInstallation: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + appId: '', + teamId: '', + scopes: [], + authorizationDetails: [], + createdById: '', + createdByName: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1072,7 +1384,7 @@ export class Apps extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -1081,6 +1393,26 @@ export class Apps extends Service { }, apiPayload, ); + const defaults = { + root: 'appInstallation', + models: { + appInstallation: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + appId: '', + teamId: '', + scopes: [], + authorizationDetails: [], + createdById: '', + createdByName: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1230,7 +1562,7 @@ export class Apps extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -1240,6 +1572,22 @@ export class Apps extends Service { }, apiPayload, ); + const defaults = { + root: 'oauth2Token', + models: { + oauth2Token: { + defaults: { + access_token: '', + token_type: 'Bearer', + expires_in: 0, + refresh_token: '', + scope: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1319,7 +1667,7 @@ export class Apps extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -1328,6 +1676,36 @@ export class Apps extends Service { }, apiPayload, ); + const defaults = { + root: 'appKeyList', + models: { + appKeyList: { + defaults: { + total: 0, + keys: [], + }, + properties: { + keys: { + items: 'appKey', + }, + }, + }, + appKey: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + appId: '', + secret: '', + hint: '', + createdById: '', + createdByName: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1377,7 +1755,7 @@ export class Apps extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -1387,6 +1765,25 @@ export class Apps extends Service { }, apiPayload, ); + const defaults = { + root: 'appKey', + models: { + appKey: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + appId: '', + secret: '', + hint: '', + createdById: '', + createdByName: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1444,7 +1841,7 @@ export class Apps extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -1453,6 +1850,25 @@ export class Apps extends Service { }, apiPayload, ); + const defaults = { + root: 'appKey', + models: { + appKey: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + appId: '', + secret: '', + hint: '', + createdById: '', + createdByName: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1599,7 +2015,7 @@ export class Apps extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -1608,6 +2024,36 @@ export class Apps extends Service { }, apiPayload, ); + const defaults = { + root: 'appSecretList', + models: { + appSecretList: { + defaults: { + total: 0, + secrets: [], + }, + properties: { + secrets: { + items: 'appSecret', + }, + }, + }, + appSecret: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + appId: '', + secret: '', + hint: '', + createdById: '', + createdByName: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1657,7 +2103,7 @@ export class Apps extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -1667,6 +2113,25 @@ export class Apps extends Service { }, apiPayload, ); + const defaults = { + root: 'appSecretPlaintext', + models: { + appSecretPlaintext: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + appId: '', + secret: '', + hint: '', + createdById: '', + createdByName: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1732,7 +2197,7 @@ export class Apps extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -1741,6 +2206,25 @@ export class Apps extends Service { }, apiPayload, ); + const defaults = { + root: 'appSecret', + models: { + appSecret: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + appId: '', + secret: '', + hint: '', + createdById: '', + createdByName: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1875,7 +2359,7 @@ export class Apps extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'patch', uri, { @@ -1885,6 +2369,60 @@ export class Apps extends Service { }, apiPayload, ); + const defaults = { + root: 'app', + models: { + app: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + description: '', + clientUri: '', + logoUri: '', + privacyPolicyUrl: '', + termsUrl: '', + contacts: [], + tagline: '', + tags: [], + labels: [], + images: [], + supportUrl: '', + dataDeletionUrl: '', + redirectUris: [], + postLogoutRedirectUris: [], + enabled: true, + type: 'confidential', + deviceFlow: false, + teamId: '', + userId: '', + installationScopes: [], + installationRedirectUrl: '', + secrets: [], + }, + properties: { + secrets: { + items: 'appSecret', + }, + }, + }, + appSecret: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + appId: '', + secret: '', + hint: '', + createdById: '', + createdByName: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** diff --git a/src/services/databases.ts b/src/services/databases.ts index 94d2ad16..43e4b4a9 100644 --- a/src/services/databases.ts +++ b/src/services/databases.ts @@ -1,5 +1,5 @@ import { Service } from '../service'; -import { AppwriteException, Client } from '../client'; +import { AppwriteException, Client, applyDefaults } from '../client'; import type { Models } from '../models'; import type { Payload } from '../client'; @@ -72,7 +72,7 @@ export class Databases extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -81,6 +81,34 @@ export class Databases extends Service { }, apiPayload, ); + const defaults = { + root: 'transactionList', + models: { + transactionList: { + defaults: { + total: 0, + transactions: [], + }, + properties: { + transactions: { + items: 'transaction', + }, + }, + }, + transaction: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + status: 'pending', + operations: 0, + expiresAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -129,7 +157,7 @@ export class Databases extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -139,6 +167,23 @@ export class Databases extends Service { }, apiPayload, ); + const defaults = { + root: 'transaction', + models: { + transaction: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + status: 'pending', + operations: 0, + expiresAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -193,7 +238,7 @@ export class Databases extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -202,6 +247,23 @@ export class Databases extends Service { }, apiPayload, ); + const defaults = { + root: 'transaction', + models: { + transaction: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + status: 'pending', + operations: 0, + expiresAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -289,7 +351,7 @@ export class Databases extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'patch', uri, { @@ -299,6 +361,23 @@ export class Databases extends Service { }, apiPayload, ); + const defaults = { + root: 'transaction', + models: { + transaction: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + status: 'pending', + operations: 0, + expiresAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -433,7 +512,7 @@ export class Databases extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -443,6 +522,23 @@ export class Databases extends Service { }, apiPayload, ); + const defaults = { + root: 'transaction', + models: { + transaction: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + status: 'pending', + operations: 0, + expiresAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -580,7 +676,7 @@ export class Databases extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -589,6 +685,35 @@ export class Databases extends Service { }, apiPayload, ); + const defaults = { + root: 'documentList', + models: { + documentList: { + defaults: { + total: 0, + documents: [], + }, + properties: { + documents: { + items: 'document', + }, + }, + }, + document: { + defaults: { + $id: '', + $sequence: '', + $collectionId: '', + $databaseId: '', + $createdAt: '', + $updatedAt: '', + $permissions: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -598,8 +723,8 @@ export class Databases extends Service { * @param {string} params.collectionId - Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection). Make sure to define attributes before creating documents. * @param {string} params.documentId - Document ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars. * @param {Document extends Models.DefaultDocument ? Partial & Record : Partial & Omit} params.data - Document data as JSON object. - * @param {string[]} params.permissions - An array of permissions strings. By default, only the current user is granted all permissions. [Learn more about permissions](https://appwrite.io/docs/permissions). - * @param {string} params.transactionId - Transaction ID for staging the operation. + * @param {string[] | null} params.permissions - An array of permissions strings. By default, only the current user is granted all permissions. [Learn more about permissions](https://appwrite.io/docs/permissions). + * @param {string | null} params.transactionId - Transaction ID for staging the operation. * @throws {AppwriteException} * @returns {Promise} * @deprecated This API has been deprecated since 1.8.0. Please use `TablesDB.createRow` instead. @@ -613,8 +738,8 @@ export class Databases extends Service { data: Document extends Models.DefaultDocument ? Partial & Record : Partial & Omit; - permissions?: string[]; - transactionId?: string; + permissions?: string[] | null; + transactionId?: string | null; }): Promise; /** * Create a new Document. Before using this route, you should create a new collection resource using either a [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection) API or directly from your database console. @@ -623,8 +748,8 @@ export class Databases extends Service { * @param {string} collectionId - Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection). Make sure to define attributes before creating documents. * @param {string} documentId - Document ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars. * @param {Document extends Models.DefaultDocument ? Partial & Record : Partial & Omit} data - Document data as JSON object. - * @param {string[]} permissions - An array of permissions strings. By default, only the current user is granted all permissions. [Learn more about permissions](https://appwrite.io/docs/permissions). - * @param {string} transactionId - Transaction ID for staging the operation. + * @param {string[] | null} permissions - An array of permissions strings. By default, only the current user is granted all permissions. [Learn more about permissions](https://appwrite.io/docs/permissions). + * @param {string | null} transactionId - Transaction ID for staging the operation. * @throws {AppwriteException} * @returns {Promise} * @deprecated Use the object parameter style method for a better developer experience. @@ -636,8 +761,8 @@ export class Databases extends Service { data: Document extends Models.DefaultDocument ? Partial & Record : Partial & Omit, - permissions?: string[], - transactionId?: string, + permissions?: string[] | null, + transactionId?: string | null, ): Promise; createDocument( paramsOrFirst: @@ -649,8 +774,8 @@ export class Databases extends Service { ? Partial & Record : Partial & Omit; - permissions?: string[]; - transactionId?: string; + permissions?: string[] | null; + transactionId?: string | null; } | string, ...rest: [ @@ -660,8 +785,8 @@ export class Databases extends Service { ? Partial & Record : Partial & Omit)?, - string[]?, - string?, + (string[] | null)?, + (string | null)?, ] ): Promise { let params: { @@ -672,8 +797,8 @@ export class Databases extends Service { ? Partial & Record : Partial & Omit; - permissions?: string[]; - transactionId?: string; + permissions?: string[] | null; + transactionId?: string | null; }; if ( @@ -689,8 +814,8 @@ export class Databases extends Service { ? Partial & Record : Partial & Omit; - permissions?: string[]; - transactionId?: string; + permissions?: string[] | null; + transactionId?: string | null; }; } else { params = { @@ -701,8 +826,8 @@ export class Databases extends Service { ? Partial & Record : Partial & Omit, - permissions: rest[3] as string[], - transactionId: rest[4] as string, + permissions: rest[3] as string[] | null, + transactionId: rest[4] as string | null, }; } @@ -761,7 +886,7 @@ export class Databases extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -771,6 +896,24 @@ export class Databases extends Service { }, apiPayload, ); + const defaults = { + root: 'document', + models: { + document: { + defaults: { + $id: '', + $sequence: '', + $collectionId: '', + $databaseId: '', + $createdAt: '', + $updatedAt: '', + $permissions: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -901,7 +1044,7 @@ export class Databases extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -910,6 +1053,24 @@ export class Databases extends Service { }, apiPayload, ); + const defaults = { + root: 'document', + models: { + document: { + defaults: { + $id: '', + $sequence: '', + $collectionId: '', + $databaseId: '', + $createdAt: '', + $updatedAt: '', + $permissions: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -919,8 +1080,8 @@ export class Databases extends Service { * @param {string} params.collectionId - Collection ID. * @param {string} params.documentId - Document ID. * @param {Document extends Models.DefaultDocument ? Partial & Record : Partial & Partial>} params.data - Document data as JSON object. Include all required attributes of the document to be created or updated. - * @param {string[]} params.permissions - An array of permissions strings. By default, the current permissions are inherited. [Learn more about permissions](https://appwrite.io/docs/permissions). - * @param {string} params.transactionId - Transaction ID for staging the operation. + * @param {string[] | null} params.permissions - An array of permissions strings. By default, the current permissions are inherited. [Learn more about permissions](https://appwrite.io/docs/permissions). + * @param {string | null} params.transactionId - Transaction ID for staging the operation. * @throws {AppwriteException} * @returns {Promise} * @deprecated This API has been deprecated since 1.8.0. Please use `TablesDB.upsertRow` instead. @@ -935,8 +1096,8 @@ export class Databases extends Service { ? Partial & Record : Partial & Partial>; - permissions?: string[]; - transactionId?: string; + permissions?: string[] | null; + transactionId?: string | null; }): Promise; /** * Create or update a Document. Before using this route, you should create a new collection resource using either a [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection) API or directly from your database console. @@ -945,8 +1106,8 @@ export class Databases extends Service { * @param {string} collectionId - Collection ID. * @param {string} documentId - Document ID. * @param {Document extends Models.DefaultDocument ? Partial & Record : Partial & Partial>} data - Document data as JSON object. Include all required attributes of the document to be created or updated. - * @param {string[]} permissions - An array of permissions strings. By default, the current permissions are inherited. [Learn more about permissions](https://appwrite.io/docs/permissions). - * @param {string} transactionId - Transaction ID for staging the operation. + * @param {string[] | null} permissions - An array of permissions strings. By default, the current permissions are inherited. [Learn more about permissions](https://appwrite.io/docs/permissions). + * @param {string | null} transactionId - Transaction ID for staging the operation. * @throws {AppwriteException} * @returns {Promise} * @deprecated Use the object parameter style method for a better developer experience. @@ -959,8 +1120,8 @@ export class Databases extends Service { ? Partial & Record : Partial & Partial>, - permissions?: string[], - transactionId?: string, + permissions?: string[] | null, + transactionId?: string | null, ): Promise; upsertDocument( paramsOrFirst: @@ -972,8 +1133,8 @@ export class Databases extends Service { ? Partial & Record : Partial & Partial>; - permissions?: string[]; - transactionId?: string; + permissions?: string[] | null; + transactionId?: string | null; } | string, ...rest: [ @@ -983,8 +1144,8 @@ export class Databases extends Service { ? Partial & Record : Partial & Partial>)?, - string[]?, - string?, + (string[] | null)?, + (string | null)?, ] ): Promise { let params: { @@ -995,8 +1156,8 @@ export class Databases extends Service { ? Partial & Record : Partial & Partial>; - permissions?: string[]; - transactionId?: string; + permissions?: string[] | null; + transactionId?: string | null; }; if ( @@ -1012,8 +1173,8 @@ export class Databases extends Service { ? Partial & Record : Partial & Partial>; - permissions?: string[]; - transactionId?: string; + permissions?: string[] | null; + transactionId?: string | null; }; } else { params = { @@ -1024,8 +1185,8 @@ export class Databases extends Service { ? Partial & Record : Partial & Partial>, - permissions: rest[3] as string[], - transactionId: rest[4] as string, + permissions: rest[3] as string[] | null, + transactionId: rest[4] as string | null, }; } @@ -1080,7 +1241,7 @@ export class Databases extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'put', uri, { @@ -1090,6 +1251,24 @@ export class Databases extends Service { }, apiPayload, ); + const defaults = { + root: 'document', + models: { + document: { + defaults: { + $id: '', + $sequence: '', + $collectionId: '', + $databaseId: '', + $createdAt: '', + $updatedAt: '', + $permissions: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1099,8 +1278,8 @@ export class Databases extends Service { * @param {string} params.collectionId - Collection ID. * @param {string} params.documentId - Document ID. * @param {Document extends Models.DefaultDocument ? Partial & Record : Partial & Partial>} params.data - Document data as JSON object. Include only attribute and value pairs to be updated. - * @param {string[]} params.permissions - An array of permissions strings. By default, the current permissions are inherited. [Learn more about permissions](https://appwrite.io/docs/permissions). - * @param {string} params.transactionId - Transaction ID for staging the operation. + * @param {string[] | null} params.permissions - An array of permissions strings. By default, the current permissions are inherited. [Learn more about permissions](https://appwrite.io/docs/permissions). + * @param {string | null} params.transactionId - Transaction ID for staging the operation. * @throws {AppwriteException} * @returns {Promise} * @deprecated This API has been deprecated since 1.8.0. Please use `TablesDB.updateRow` instead. @@ -1115,8 +1294,8 @@ export class Databases extends Service { ? Partial & Record : Partial & Partial>; - permissions?: string[]; - transactionId?: string; + permissions?: string[] | null; + transactionId?: string | null; }): Promise; /** * Update a document by its unique ID. Using the patch method you can pass only specific fields that will get updated. @@ -1125,8 +1304,8 @@ export class Databases extends Service { * @param {string} collectionId - Collection ID. * @param {string} documentId - Document ID. * @param {Document extends Models.DefaultDocument ? Partial & Record : Partial & Partial>} data - Document data as JSON object. Include only attribute and value pairs to be updated. - * @param {string[]} permissions - An array of permissions strings. By default, the current permissions are inherited. [Learn more about permissions](https://appwrite.io/docs/permissions). - * @param {string} transactionId - Transaction ID for staging the operation. + * @param {string[] | null} permissions - An array of permissions strings. By default, the current permissions are inherited. [Learn more about permissions](https://appwrite.io/docs/permissions). + * @param {string | null} transactionId - Transaction ID for staging the operation. * @throws {AppwriteException} * @returns {Promise} * @deprecated Use the object parameter style method for a better developer experience. @@ -1139,8 +1318,8 @@ export class Databases extends Service { ? Partial & Record : Partial & Partial>, - permissions?: string[], - transactionId?: string, + permissions?: string[] | null, + transactionId?: string | null, ): Promise; updateDocument( paramsOrFirst: @@ -1152,8 +1331,8 @@ export class Databases extends Service { ? Partial & Record : Partial & Partial>; - permissions?: string[]; - transactionId?: string; + permissions?: string[] | null; + transactionId?: string | null; } | string, ...rest: [ @@ -1163,8 +1342,8 @@ export class Databases extends Service { ? Partial & Record : Partial & Partial>)?, - string[]?, - string?, + (string[] | null)?, + (string | null)?, ] ): Promise { let params: { @@ -1175,8 +1354,8 @@ export class Databases extends Service { ? Partial & Record : Partial & Partial>; - permissions?: string[]; - transactionId?: string; + permissions?: string[] | null; + transactionId?: string | null; }; if ( @@ -1192,8 +1371,8 @@ export class Databases extends Service { ? Partial & Record : Partial & Partial>; - permissions?: string[]; - transactionId?: string; + permissions?: string[] | null; + transactionId?: string | null; }; } else { params = { @@ -1204,8 +1383,8 @@ export class Databases extends Service { ? Partial & Record : Partial & Partial>, - permissions: rest[3] as string[], - transactionId: rest[4] as string, + permissions: rest[3] as string[] | null, + transactionId: rest[4] as string | null, }; } @@ -1260,7 +1439,7 @@ export class Databases extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'patch', uri, { @@ -1270,6 +1449,24 @@ export class Databases extends Service { }, apiPayload, ); + const defaults = { + root: 'document', + models: { + document: { + defaults: { + $id: '', + $sequence: '', + $collectionId: '', + $databaseId: '', + $createdAt: '', + $updatedAt: '', + $permissions: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1405,8 +1602,8 @@ export class Databases extends Service { * @param {string} params.documentId - Document ID. * @param {string} params.attribute - Attribute key. * @param {number} params.value - Value to increment the attribute by. The value must be a number. - * @param {number} params.min - Minimum value for the attribute. If the current value is lesser than this value, an exception will be thrown. - * @param {string} params.transactionId - Transaction ID for staging the operation. + * @param {number | null} params.min - Minimum value for the attribute. If the current value is lesser than this value, an exception will be thrown. + * @param {string | null} params.transactionId - Transaction ID for staging the operation. * @throws {AppwriteException} * @returns {Promise} * @deprecated This API has been deprecated since 1.8.0. Please use `TablesDB.decrementRowColumn` instead. @@ -1419,8 +1616,8 @@ export class Databases extends Service { documentId: string; attribute: string; value?: number; - min?: number; - transactionId?: string; + min?: number | null; + transactionId?: string | null; }): Promise; /** * Decrement a specific attribute of a document by a given value. @@ -1430,8 +1627,8 @@ export class Databases extends Service { * @param {string} documentId - Document ID. * @param {string} attribute - Attribute key. * @param {number} value - Value to increment the attribute by. The value must be a number. - * @param {number} min - Minimum value for the attribute. If the current value is lesser than this value, an exception will be thrown. - * @param {string} transactionId - Transaction ID for staging the operation. + * @param {number | null} min - Minimum value for the attribute. If the current value is lesser than this value, an exception will be thrown. + * @param {string | null} transactionId - Transaction ID for staging the operation. * @throws {AppwriteException} * @returns {Promise} * @deprecated Use the object parameter style method for a better developer experience. @@ -1444,8 +1641,8 @@ export class Databases extends Service { documentId: string, attribute: string, value?: number, - min?: number, - transactionId?: string, + min?: number | null, + transactionId?: string | null, ): Promise; decrementDocumentAttribute< Document extends Models.Document = Models.DefaultDocument, @@ -1457,11 +1654,18 @@ export class Databases extends Service { documentId: string; attribute: string; value?: number; - min?: number; - transactionId?: string; + min?: number | null; + transactionId?: string | null; } | string, - ...rest: [string?, string?, string?, number?, number?, string?] + ...rest: [ + string?, + string?, + string?, + number?, + (number | null)?, + (string | null)?, + ] ): Promise { let params: { databaseId: string; @@ -1469,8 +1673,8 @@ export class Databases extends Service { documentId: string; attribute: string; value?: number; - min?: number; - transactionId?: string; + min?: number | null; + transactionId?: string | null; }; if ( @@ -1484,8 +1688,8 @@ export class Databases extends Service { documentId: string; attribute: string; value?: number; - min?: number; - transactionId?: string; + min?: number | null; + transactionId?: string | null; }; } else { params = { @@ -1494,8 +1698,8 @@ export class Databases extends Service { documentId: rest[1] as string, attribute: rest[2] as string, value: rest[3] as number, - min: rest[4] as number, - transactionId: rest[5] as string, + min: rest[4] as number | null, + transactionId: rest[5] as string | null, }; } @@ -1555,7 +1759,7 @@ export class Databases extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'patch', uri, { @@ -1565,6 +1769,24 @@ export class Databases extends Service { }, apiPayload, ); + const defaults = { + root: 'document', + models: { + document: { + defaults: { + $id: '', + $sequence: '', + $collectionId: '', + $databaseId: '', + $createdAt: '', + $updatedAt: '', + $permissions: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1575,8 +1797,8 @@ export class Databases extends Service { * @param {string} params.documentId - Document ID. * @param {string} params.attribute - Attribute key. * @param {number} params.value - Value to increment the attribute by. The value must be a number. - * @param {number} params.max - Maximum value for the attribute. If the current value is greater than this value, an error will be thrown. - * @param {string} params.transactionId - Transaction ID for staging the operation. + * @param {number | null} params.max - Maximum value for the attribute. If the current value is greater than this value, an error will be thrown. + * @param {string | null} params.transactionId - Transaction ID for staging the operation. * @throws {AppwriteException} * @returns {Promise} * @deprecated This API has been deprecated since 1.8.0. Please use `TablesDB.incrementRowColumn` instead. @@ -1589,8 +1811,8 @@ export class Databases extends Service { documentId: string; attribute: string; value?: number; - max?: number; - transactionId?: string; + max?: number | null; + transactionId?: string | null; }): Promise; /** * Increment a specific attribute of a document by a given value. @@ -1600,8 +1822,8 @@ export class Databases extends Service { * @param {string} documentId - Document ID. * @param {string} attribute - Attribute key. * @param {number} value - Value to increment the attribute by. The value must be a number. - * @param {number} max - Maximum value for the attribute. If the current value is greater than this value, an error will be thrown. - * @param {string} transactionId - Transaction ID for staging the operation. + * @param {number | null} max - Maximum value for the attribute. If the current value is greater than this value, an error will be thrown. + * @param {string | null} transactionId - Transaction ID for staging the operation. * @throws {AppwriteException} * @returns {Promise} * @deprecated Use the object parameter style method for a better developer experience. @@ -1614,8 +1836,8 @@ export class Databases extends Service { documentId: string, attribute: string, value?: number, - max?: number, - transactionId?: string, + max?: number | null, + transactionId?: string | null, ): Promise; incrementDocumentAttribute< Document extends Models.Document = Models.DefaultDocument, @@ -1627,11 +1849,18 @@ export class Databases extends Service { documentId: string; attribute: string; value?: number; - max?: number; - transactionId?: string; + max?: number | null; + transactionId?: string | null; } | string, - ...rest: [string?, string?, string?, number?, number?, string?] + ...rest: [ + string?, + string?, + string?, + number?, + (number | null)?, + (string | null)?, + ] ): Promise { let params: { databaseId: string; @@ -1639,8 +1868,8 @@ export class Databases extends Service { documentId: string; attribute: string; value?: number; - max?: number; - transactionId?: string; + max?: number | null; + transactionId?: string | null; }; if ( @@ -1654,8 +1883,8 @@ export class Databases extends Service { documentId: string; attribute: string; value?: number; - max?: number; - transactionId?: string; + max?: number | null; + transactionId?: string | null; }; } else { params = { @@ -1664,8 +1893,8 @@ export class Databases extends Service { documentId: rest[1] as string, attribute: rest[2] as string, value: rest[3] as number, - max: rest[4] as number, - transactionId: rest[5] as string, + max: rest[4] as number | null, + transactionId: rest[5] as string | null, }; } @@ -1725,7 +1954,7 @@ export class Databases extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'patch', uri, { @@ -1735,5 +1964,23 @@ export class Databases extends Service { }, apiPayload, ); + const defaults = { + root: 'document', + models: { + document: { + defaults: { + $id: '', + $sequence: '', + $collectionId: '', + $databaseId: '', + $createdAt: '', + $updatedAt: '', + $permissions: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } } diff --git a/src/services/documents-db.ts b/src/services/documents-db.ts index 6f10966e..d43db5a9 100644 --- a/src/services/documents-db.ts +++ b/src/services/documents-db.ts @@ -1,5 +1,5 @@ import { Service } from '../service'; -import { AppwriteException, Client } from '../client'; +import { AppwriteException, Client, applyDefaults } from '../client'; import type { Models } from '../models'; import type { Payload } from '../client'; @@ -71,7 +71,7 @@ export class DocumentsDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -80,6 +80,34 @@ export class DocumentsDB extends Service { }, apiPayload, ); + const defaults = { + root: 'transactionList', + models: { + transactionList: { + defaults: { + total: 0, + transactions: [], + }, + properties: { + transactions: { + items: 'transaction', + }, + }, + }, + transaction: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + status: 'pending', + operations: 0, + expiresAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -127,7 +155,7 @@ export class DocumentsDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -137,6 +165,23 @@ export class DocumentsDB extends Service { }, apiPayload, ); + const defaults = { + root: 'transaction', + models: { + transaction: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + status: 'pending', + operations: 0, + expiresAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -190,7 +235,7 @@ export class DocumentsDB extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -199,6 +244,23 @@ export class DocumentsDB extends Service { }, apiPayload, ); + const defaults = { + root: 'transaction', + models: { + transaction: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + status: 'pending', + operations: 0, + expiresAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -285,7 +347,7 @@ export class DocumentsDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'patch', uri, { @@ -295,6 +357,23 @@ export class DocumentsDB extends Service { }, apiPayload, ); + const defaults = { + root: 'transaction', + models: { + transaction: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + status: 'pending', + operations: 0, + expiresAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -427,7 +506,7 @@ export class DocumentsDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -437,6 +516,23 @@ export class DocumentsDB extends Service { }, apiPayload, ); + const defaults = { + root: 'transaction', + models: { + transaction: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + status: 'pending', + operations: 0, + expiresAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -573,7 +669,7 @@ export class DocumentsDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -582,6 +678,35 @@ export class DocumentsDB extends Service { }, apiPayload, ); + const defaults = { + root: 'documentList', + models: { + documentList: { + defaults: { + total: 0, + documents: [], + }, + properties: { + documents: { + items: 'document', + }, + }, + }, + document: { + defaults: { + $id: '', + $sequence: '', + $collectionId: '', + $databaseId: '', + $createdAt: '', + $updatedAt: '', + $permissions: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -753,7 +878,7 @@ export class DocumentsDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -763,6 +888,24 @@ export class DocumentsDB extends Service { }, apiPayload, ); + const defaults = { + root: 'document', + models: { + document: { + defaults: { + $id: '', + $sequence: '', + $collectionId: '', + $databaseId: '', + $createdAt: '', + $updatedAt: '', + $permissions: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -879,7 +1022,7 @@ export class DocumentsDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -889,6 +1032,35 @@ export class DocumentsDB extends Service { }, apiPayload, ); + const defaults = { + root: 'documentList', + models: { + documentList: { + defaults: { + total: 0, + documents: [], + }, + properties: { + documents: { + items: 'document', + }, + }, + }, + document: { + defaults: { + $id: '', + $sequence: '', + $collectionId: '', + $databaseId: '', + $createdAt: '', + $updatedAt: '', + $permissions: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1018,7 +1190,7 @@ export class DocumentsDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -1027,6 +1199,24 @@ export class DocumentsDB extends Service { }, apiPayload, ); + const defaults = { + root: 'document', + models: { + document: { + defaults: { + $id: '', + $sequence: '', + $collectionId: '', + $databaseId: '', + $createdAt: '', + $updatedAt: '', + $permissions: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1196,7 +1386,7 @@ export class DocumentsDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'put', uri, { @@ -1206,6 +1396,24 @@ export class DocumentsDB extends Service { }, apiPayload, ); + const defaults = { + root: 'document', + models: { + document: { + defaults: { + $id: '', + $sequence: '', + $collectionId: '', + $databaseId: '', + $createdAt: '', + $updatedAt: '', + $permissions: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1375,7 +1583,7 @@ export class DocumentsDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'patch', uri, { @@ -1385,6 +1593,24 @@ export class DocumentsDB extends Service { }, apiPayload, ); + const defaults = { + root: 'document', + models: { + document: { + defaults: { + $id: '', + $sequence: '', + $collectionId: '', + $databaseId: '', + $createdAt: '', + $updatedAt: '', + $permissions: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1668,7 +1894,7 @@ export class DocumentsDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'patch', uri, { @@ -1678,6 +1904,24 @@ export class DocumentsDB extends Service { }, apiPayload, ); + const defaults = { + root: 'document', + models: { + document: { + defaults: { + $id: '', + $sequence: '', + $collectionId: '', + $databaseId: '', + $createdAt: '', + $updatedAt: '', + $permissions: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1837,7 +2081,7 @@ export class DocumentsDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'patch', uri, { @@ -1847,5 +2091,23 @@ export class DocumentsDB extends Service { }, apiPayload, ); + const defaults = { + root: 'document', + models: { + document: { + defaults: { + $id: '', + $sequence: '', + $collectionId: '', + $databaseId: '', + $createdAt: '', + $updatedAt: '', + $permissions: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } } diff --git a/src/services/functions.ts b/src/services/functions.ts index 230ffe70..db74d35c 100644 --- a/src/services/functions.ts +++ b/src/services/functions.ts @@ -1,5 +1,5 @@ import { Service } from '../service'; -import { AppwriteException, Client } from '../client'; +import { AppwriteException, Client, applyDefaults } from '../client'; import type { Models } from '../models'; import type { Payload } from '../client'; @@ -89,7 +89,7 @@ export class Functions extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -98,6 +98,58 @@ export class Functions extends Service { }, apiPayload, ); + const defaults = { + root: 'executionList', + models: { + executionList: { + defaults: { + total: 0, + executions: [], + }, + properties: { + executions: { + items: 'execution', + }, + }, + }, + execution: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + $permissions: [], + resourceId: '', + resourceType: 'functions', + deploymentId: '', + requestMethod: '', + requestPath: '', + requestHeaders: [], + responseStatusCode: 0, + responseBody: '', + responseHeaders: [], + logs: '', + errors: '', + duration: 0, + }, + properties: { + requestHeaders: { + items: 'headers', + }, + responseHeaders: { + items: 'headers', + }, + }, + }, + headers: { + defaults: { + name: '', + value: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -109,7 +161,7 @@ export class Functions extends Service { * @param {string} params.xpath - HTTP path of execution. Path can include query params. Default value is / * @param {ExecutionMethod} params.method - HTTP method of execution. Default value is POST. * @param {object} params.headers - HTTP headers of execution. Defaults to empty. - * @param {string} params.scheduledAt - Scheduled execution time in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format. DateTime value must be in future with precision in minutes. + * @param {string | null} params.scheduledAt - Scheduled execution time in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format. DateTime value must be in future with precision in minutes. * @throws {AppwriteException} * @returns {Promise} */ @@ -120,7 +172,7 @@ export class Functions extends Service { xpath?: string; method?: ExecutionMethod; headers?: object; - scheduledAt?: string; + scheduledAt?: string | null; }): Promise; /** * Trigger a function execution. The returned object will return you the current execution status. You can ping the `Get Execution` endpoint to get updates on the current execution status. Once this endpoint is called, your function execution process will start asynchronously. @@ -131,7 +183,7 @@ export class Functions extends Service { * @param {string} xpath - HTTP path of execution. Path can include query params. Default value is / * @param {ExecutionMethod} method - HTTP method of execution. Default value is POST. * @param {object} headers - HTTP headers of execution. Defaults to empty. - * @param {string} scheduledAt - Scheduled execution time in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format. DateTime value must be in future with precision in minutes. + * @param {string | null} scheduledAt - Scheduled execution time in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format. DateTime value must be in future with precision in minutes. * @throws {AppwriteException} * @returns {Promise} * @deprecated Use the object parameter style method for a better developer experience. @@ -143,7 +195,7 @@ export class Functions extends Service { xpath?: string, method?: ExecutionMethod, headers?: object, - scheduledAt?: string, + scheduledAt?: string | null, ): Promise; createExecution( paramsOrFirst: @@ -154,7 +206,7 @@ export class Functions extends Service { xpath?: string; method?: ExecutionMethod; headers?: object; - scheduledAt?: string; + scheduledAt?: string | null; } | string, ...rest: [ @@ -163,7 +215,7 @@ export class Functions extends Service { string?, ExecutionMethod?, object?, - string?, + (string | null)?, ] ): Promise { let params: { @@ -173,7 +225,7 @@ export class Functions extends Service { xpath?: string; method?: ExecutionMethod; headers?: object; - scheduledAt?: string; + scheduledAt?: string | null; }; if ( @@ -188,7 +240,7 @@ export class Functions extends Service { xpath?: string; method?: ExecutionMethod; headers?: object; - scheduledAt?: string; + scheduledAt?: string | null; }; } else { params = { @@ -198,7 +250,7 @@ export class Functions extends Service { xpath: rest[2] as string, method: rest[3] as ExecutionMethod, headers: rest[4] as object, - scheduledAt: rest[5] as string, + scheduledAt: rest[5] as string | null, }; } @@ -247,7 +299,7 @@ export class Functions extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -257,6 +309,47 @@ export class Functions extends Service { }, apiPayload, ); + const defaults = { + root: 'execution', + models: { + execution: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + $permissions: [], + resourceId: '', + resourceType: 'functions', + deploymentId: '', + requestMethod: '', + requestPath: '', + requestHeaders: [], + responseStatusCode: 0, + responseBody: '', + responseHeaders: [], + logs: '', + errors: '', + duration: 0, + }, + properties: { + requestHeaders: { + items: 'headers', + }, + responseHeaders: { + items: 'headers', + }, + }, + }, + headers: { + defaults: { + name: '', + value: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -327,7 +420,7 @@ export class Functions extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -336,5 +429,46 @@ export class Functions extends Service { }, apiPayload, ); + const defaults = { + root: 'execution', + models: { + execution: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + $permissions: [], + resourceId: '', + resourceType: 'functions', + deploymentId: '', + requestMethod: '', + requestPath: '', + requestHeaders: [], + responseStatusCode: 0, + responseBody: '', + responseHeaders: [], + logs: '', + errors: '', + duration: 0, + }, + properties: { + requestHeaders: { + items: 'headers', + }, + responseHeaders: { + items: 'headers', + }, + }, + }, + headers: { + defaults: { + name: '', + value: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } } diff --git a/src/services/locale.ts b/src/services/locale.ts index ce9e92b2..7ab026b5 100644 --- a/src/services/locale.ts +++ b/src/services/locale.ts @@ -1,5 +1,5 @@ import { Service } from '../service'; -import { Client } from '../client'; +import { Client, applyDefaults } from '../client'; import type { Models } from '../models'; import type { Payload } from '../client'; @@ -21,7 +21,7 @@ export class Locale extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -30,6 +30,24 @@ export class Locale extends Service { }, apiPayload, ); + const defaults = { + root: 'locale', + models: { + locale: { + defaults: { + ip: '', + countryCode: '', + country: '', + continentCode: '', + continent: '', + eu: false, + currency: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -77,7 +95,7 @@ export class Locale extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -86,6 +104,30 @@ export class Locale extends Service { }, apiPayload, ); + const defaults = { + root: 'localeCodeList', + models: { + localeCodeList: { + defaults: { + total: 0, + localeCodes: [], + }, + properties: { + localeCodes: { + items: 'localeCode', + }, + }, + }, + localeCode: { + defaults: { + code: '', + name: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -133,7 +175,7 @@ export class Locale extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -142,6 +184,30 @@ export class Locale extends Service { }, apiPayload, ); + const defaults = { + root: 'continentList', + models: { + continentList: { + defaults: { + total: 0, + continents: [], + }, + properties: { + continents: { + items: 'continent', + }, + }, + }, + continent: { + defaults: { + name: '', + code: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -189,7 +255,7 @@ export class Locale extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -198,6 +264,30 @@ export class Locale extends Service { }, apiPayload, ); + const defaults = { + root: 'countryList', + models: { + countryList: { + defaults: { + total: 0, + countries: [], + }, + properties: { + countries: { + items: 'country', + }, + }, + }, + country: { + defaults: { + name: '', + code: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -245,7 +335,7 @@ export class Locale extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -254,6 +344,30 @@ export class Locale extends Service { }, apiPayload, ); + const defaults = { + root: 'countryList', + models: { + countryList: { + defaults: { + total: 0, + countries: [], + }, + properties: { + countries: { + items: 'country', + }, + }, + }, + country: { + defaults: { + name: '', + code: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -303,7 +417,7 @@ export class Locale extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -312,6 +426,31 @@ export class Locale extends Service { }, apiPayload, ); + const defaults = { + root: 'phoneList', + models: { + phoneList: { + defaults: { + total: 0, + phones: [], + }, + properties: { + phones: { + items: 'phone', + }, + }, + }, + phone: { + defaults: { + code: '', + countryCode: '', + countryName: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -359,7 +498,7 @@ export class Locale extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -368,6 +507,35 @@ export class Locale extends Service { }, apiPayload, ); + const defaults = { + root: 'currencyList', + models: { + currencyList: { + defaults: { + total: 0, + currencies: [], + }, + properties: { + currencies: { + items: 'currency', + }, + }, + }, + currency: { + defaults: { + symbol: '', + name: '', + symbolNative: '', + decimalDigits: 0, + rounding: 0, + code: '', + namePlural: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -415,7 +583,7 @@ export class Locale extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -424,5 +592,30 @@ export class Locale extends Service { }, apiPayload, ); + const defaults = { + root: 'languageList', + models: { + languageList: { + defaults: { + total: 0, + languages: [], + }, + properties: { + languages: { + items: 'language', + }, + }, + }, + language: { + defaults: { + name: '', + code: '', + nativeName: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } } diff --git a/src/services/messaging.ts b/src/services/messaging.ts index 33e94c19..b1939ddf 100644 --- a/src/services/messaging.ts +++ b/src/services/messaging.ts @@ -1,5 +1,5 @@ import { Service } from '../service'; -import { AppwriteException, Client } from '../client'; +import { AppwriteException, Client, applyDefaults } from '../client'; import type { Models } from '../models'; import type { Payload } from '../client'; @@ -100,7 +100,7 @@ export class Messaging extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -110,6 +110,25 @@ export class Messaging extends Service { }, apiPayload, ); + const defaults = { + root: 'subscriber', + models: { + subscriber: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + targetId: '', + userId: '', + userName: '', + topicId: '', + providerType: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** diff --git a/src/services/oauth-2.ts b/src/services/oauth-2.ts index 1920bc1a..185fad00 100644 --- a/src/services/oauth-2.ts +++ b/src/services/oauth-2.ts @@ -1,5 +1,5 @@ import { Service } from '../service'; -import { AppwriteException, Client } from '../client'; +import { AppwriteException, Client, applyDefaults } from '../client'; import type { Models } from '../models'; import type { Payload } from '../client'; @@ -96,7 +96,7 @@ export class Oauth2 extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -105,6 +105,18 @@ export class Oauth2 extends Service { }, apiPayload, ); + const defaults = { + root: 'oauth2Approve', + models: { + oauth2Approve: { + defaults: { + redirectUrl: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -121,7 +133,7 @@ export class Oauth2 extends Service { * @param {string} params.prompt - OIDC prompt parameter for customization of consent screen. Space-separated list of: none, login, consent, select_account. * @param {number} params.maxAge - OIDC max_age paraleter for customization of consent screen. Maximum allowable elapsed time in seconds since the user last authenticated. If exceeded, re-authentication is required. * @param {string} params.authorizationDetails - Rich authorization request. JSON array of objects, each with a `type` and project-defined fields - * @param {string} params.resource - RFC 8707 resource indicator URI or URI list. Each value must be an absolute URI without a fragment. + * @param {string[]} params.resource - RFC 8707 resource indicator URI or URI list. Each value must be an absolute URI without a fragment. * @param {string} params.audience - Compatibility alias for a single OAuth2 resource indicator URI. * @param {string} params.requestUri - OAuth2 authorization request handle returned by the pushed authorization request endpoint. * @throws {AppwriteException} @@ -139,7 +151,7 @@ export class Oauth2 extends Service { prompt?: string; maxAge?: number; authorizationDetails?: string; - resource?: string; + resource?: string[]; audience?: string; requestUri?: string; }): Promise; @@ -157,7 +169,7 @@ export class Oauth2 extends Service { * @param {string} prompt - OIDC prompt parameter for customization of consent screen. Space-separated list of: none, login, consent, select_account. * @param {number} maxAge - OIDC max_age paraleter for customization of consent screen. Maximum allowable elapsed time in seconds since the user last authenticated. If exceeded, re-authentication is required. * @param {string} authorizationDetails - Rich authorization request. JSON array of objects, each with a `type` and project-defined fields - * @param {string} resource - RFC 8707 resource indicator URI or URI list. Each value must be an absolute URI without a fragment. + * @param {string[]} resource - RFC 8707 resource indicator URI or URI list. Each value must be an absolute URI without a fragment. * @param {string} audience - Compatibility alias for a single OAuth2 resource indicator URI. * @param {string} requestUri - OAuth2 authorization request handle returned by the pushed authorization request endpoint. * @throws {AppwriteException} @@ -176,7 +188,7 @@ export class Oauth2 extends Service { prompt?: string, maxAge?: number, authorizationDetails?: string, - resource?: string, + resource?: string[], audience?: string, requestUri?: string, ): Promise; @@ -194,7 +206,7 @@ export class Oauth2 extends Service { prompt?: string; maxAge?: number; authorizationDetails?: string; - resource?: string; + resource?: string[]; audience?: string; requestUri?: string; } @@ -210,7 +222,7 @@ export class Oauth2 extends Service { string?, number?, string?, - string?, + string[]?, string?, string?, ] @@ -227,7 +239,7 @@ export class Oauth2 extends Service { prompt?: string; maxAge?: number; authorizationDetails?: string; - resource?: string; + resource?: string[]; audience?: string; requestUri?: string; }; @@ -250,7 +262,7 @@ export class Oauth2 extends Service { prompt?: string; maxAge?: number; authorizationDetails?: string; - resource?: string; + resource?: string[]; audience?: string; requestUri?: string; }; @@ -267,7 +279,7 @@ export class Oauth2 extends Service { prompt: rest[7] as string, maxAge: rest[8] as number, authorizationDetails: rest[9] as string, - resource: rest[10] as string, + resource: rest[10] as string[], audience: rest[11] as string, requestUri: rest[12] as string, }; @@ -351,7 +363,7 @@ export class Oauth2 extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -359,6 +371,19 @@ export class Oauth2 extends Service { }, apiPayload, ); + const defaults = { + root: 'oauth2Authorize', + models: { + oauth2Authorize: { + defaults: { + grantId: '', + redirectUrl: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -373,9 +398,9 @@ export class Oauth2 extends Service { * @param {string} params.codeChallenge - PKCE code challenge. Required when OAuth2 app is public. * @param {string} params.codeChallengeMethod - PKCE code challenge method. Required when OAuth2 app is public. * @param {string} params.prompt - OIDC prompt parameter for customization of consent screen. Space-separated list of: none, login, consent, select_account. - * @param {number} params.maxAge - OIDC max_age paraleter for customization of consent screen. Maximum allowable elapsed time in seconds since the user last authenticated. If exceeded, re-authentication is required. + * @param {number | null} params.maxAge - OIDC max_age paraleter for customization of consent screen. Maximum allowable elapsed time in seconds since the user last authenticated. If exceeded, re-authentication is required. * @param {string} params.authorizationDetails - Rich authorization request. JSON array of objects, each with a `type` and project-defined fields - * @param {string} params.resource - RFC 8707 resource indicator URI or URI list. Each value must be an absolute URI without a fragment. + * @param {string[]} params.resource - RFC 8707 resource indicator URI or URI list. Each value must be an absolute URI without a fragment. * @param {string} params.audience - Compatibility alias for a single OAuth2 resource indicator URI. * @param {string} params.requestUri - OAuth2 authorization request handle returned by the pushed authorization request endpoint. * @throws {AppwriteException} @@ -391,9 +416,9 @@ export class Oauth2 extends Service { codeChallenge?: string; codeChallengeMethod?: string; prompt?: string; - maxAge?: number; + maxAge?: number | null; authorizationDetails?: string; - resource?: string; + resource?: string[]; audience?: string; requestUri?: string; }): Promise; @@ -409,9 +434,9 @@ export class Oauth2 extends Service { * @param {string} codeChallenge - PKCE code challenge. Required when OAuth2 app is public. * @param {string} codeChallengeMethod - PKCE code challenge method. Required when OAuth2 app is public. * @param {string} prompt - OIDC prompt parameter for customization of consent screen. Space-separated list of: none, login, consent, select_account. - * @param {number} maxAge - OIDC max_age paraleter for customization of consent screen. Maximum allowable elapsed time in seconds since the user last authenticated. If exceeded, re-authentication is required. + * @param {number | null} maxAge - OIDC max_age paraleter for customization of consent screen. Maximum allowable elapsed time in seconds since the user last authenticated. If exceeded, re-authentication is required. * @param {string} authorizationDetails - Rich authorization request. JSON array of objects, each with a `type` and project-defined fields - * @param {string} resource - RFC 8707 resource indicator URI or URI list. Each value must be an absolute URI without a fragment. + * @param {string[]} resource - RFC 8707 resource indicator URI or URI list. Each value must be an absolute URI without a fragment. * @param {string} audience - Compatibility alias for a single OAuth2 resource indicator URI. * @param {string} requestUri - OAuth2 authorization request handle returned by the pushed authorization request endpoint. * @throws {AppwriteException} @@ -428,9 +453,9 @@ export class Oauth2 extends Service { codeChallenge?: string, codeChallengeMethod?: string, prompt?: string, - maxAge?: number, + maxAge?: number | null, authorizationDetails?: string, - resource?: string, + resource?: string[], audience?: string, requestUri?: string, ): Promise; @@ -446,9 +471,9 @@ export class Oauth2 extends Service { codeChallenge?: string; codeChallengeMethod?: string; prompt?: string; - maxAge?: number; + maxAge?: number | null; authorizationDetails?: string; - resource?: string; + resource?: string[]; audience?: string; requestUri?: string; } @@ -462,9 +487,9 @@ export class Oauth2 extends Service { string?, string?, string?, - number?, - string?, + (number | null)?, string?, + string[]?, string?, string?, ] @@ -479,9 +504,9 @@ export class Oauth2 extends Service { codeChallenge?: string; codeChallengeMethod?: string; prompt?: string; - maxAge?: number; + maxAge?: number | null; authorizationDetails?: string; - resource?: string; + resource?: string[]; audience?: string; requestUri?: string; }; @@ -502,9 +527,9 @@ export class Oauth2 extends Service { codeChallenge?: string; codeChallengeMethod?: string; prompt?: string; - maxAge?: number; + maxAge?: number | null; authorizationDetails?: string; - resource?: string; + resource?: string[]; audience?: string; requestUri?: string; }; @@ -519,9 +544,9 @@ export class Oauth2 extends Service { codeChallenge: rest[5] as string, codeChallengeMethod: rest[6] as string, prompt: rest[7] as string, - maxAge: rest[8] as number, + maxAge: rest[8] as number | null, authorizationDetails: rest[9] as string, - resource: rest[10] as string, + resource: rest[10] as string[], audience: rest[11] as string, requestUri: rest[12] as string, }; @@ -605,7 +630,7 @@ export class Oauth2 extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -614,6 +639,19 @@ export class Oauth2 extends Service { }, apiPayload, ); + const defaults = { + root: 'oauth2Authorize', + models: { + oauth2Authorize: { + defaults: { + grantId: '', + redirectUrl: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -622,7 +660,7 @@ export class Oauth2 extends Service { * @param {string} params.clientId - OAuth2 client ID. Either a registered app ID or an HTTPS client ID metadata document URL. * @param {string} params.scope - Space-separated OAuth2 scopes. Can include project scopes, and built-in scopes: `openid`, `email`, `profile`. * @param {string} params.authorizationDetails - Rich authorization request. JSON array of objects, each with a `type` and project-defined fields - * @param {string} params.resource - RFC 8707 resource indicator URI or URI list. Each value must be an absolute URI without a fragment. + * @param {string[]} params.resource - RFC 8707 resource indicator URI or URI list. Each value must be an absolute URI without a fragment. * @param {string} params.audience - Compatibility alias for a single OAuth2 resource indicator URI. * @throws {AppwriteException} * @returns {Promise} @@ -631,7 +669,7 @@ export class Oauth2 extends Service { clientId?: string; scope?: string; authorizationDetails?: string; - resource?: string; + resource?: string[]; audience?: string; }): Promise; /** @@ -640,7 +678,7 @@ export class Oauth2 extends Service { * @param {string} clientId - OAuth2 client ID. Either a registered app ID or an HTTPS client ID metadata document URL. * @param {string} scope - Space-separated OAuth2 scopes. Can include project scopes, and built-in scopes: `openid`, `email`, `profile`. * @param {string} authorizationDetails - Rich authorization request. JSON array of objects, each with a `type` and project-defined fields - * @param {string} resource - RFC 8707 resource indicator URI or URI list. Each value must be an absolute URI without a fragment. + * @param {string[]} resource - RFC 8707 resource indicator URI or URI list. Each value must be an absolute URI without a fragment. * @param {string} audience - Compatibility alias for a single OAuth2 resource indicator URI. * @throws {AppwriteException} * @returns {Promise} @@ -650,7 +688,7 @@ export class Oauth2 extends Service { clientId?: string, scope?: string, authorizationDetails?: string, - resource?: string, + resource?: string[], audience?: string, ): Promise; createDeviceAuthorization( @@ -659,17 +697,17 @@ export class Oauth2 extends Service { clientId?: string; scope?: string; authorizationDetails?: string; - resource?: string; + resource?: string[]; audience?: string; } | string, - ...rest: [string?, string?, string?, string?] + ...rest: [string?, string?, string[]?, string?] ): Promise { let params: { clientId?: string; scope?: string; authorizationDetails?: string; - resource?: string; + resource?: string[]; audience?: string; }; @@ -683,7 +721,7 @@ export class Oauth2 extends Service { clientId?: string; scope?: string; authorizationDetails?: string; - resource?: string; + resource?: string[]; audience?: string; }; } else { @@ -691,7 +729,7 @@ export class Oauth2 extends Service { clientId: paramsOrFirst as string, scope: rest[0] as string, authorizationDetails: rest[1] as string, - resource: rest[2] as string, + resource: rest[2] as string[], audience: rest[3] as string, }; } @@ -729,7 +767,7 @@ export class Oauth2 extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -738,6 +776,23 @@ export class Oauth2 extends Service { }, apiPayload, ); + const defaults = { + root: 'oauth2DeviceAuthorization', + models: { + oauth2DeviceAuthorization: { + defaults: { + device_code: '', + user_code: '', + verification_uri: '', + verification_uri_complete: '', + expires_in: 0, + interval: 0, + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -793,7 +848,7 @@ export class Oauth2 extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -802,6 +857,29 @@ export class Oauth2 extends Service { }, apiPayload, ); + const defaults = { + root: 'oauth2Grant', + models: { + oauth2Grant: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + userId: '', + appId: '', + scopes: [], + resources: [], + authorizationDetails: '[]', + prompt: '', + redirectUri: '', + authTime: 0, + expire: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -855,7 +933,7 @@ export class Oauth2 extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -863,6 +941,29 @@ export class Oauth2 extends Service { }, apiPayload, ); + const defaults = { + root: 'oauth2Grant', + models: { + oauth2Grant: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + userId: '', + appId: '', + scopes: [], + resources: [], + authorizationDetails: '[]', + prompt: '', + redirectUri: '', + authTime: 0, + expire: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1216,7 +1317,7 @@ export class Oauth2 extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -1224,6 +1325,29 @@ export class Oauth2 extends Service { }, apiPayload, ); + const defaults = { + root: 'oauth2OrganizationList', + models: { + oauth2OrganizationList: { + defaults: { + total: 0, + organizations: [], + }, + properties: { + organizations: { + items: 'oauth2Organization', + }, + }, + }, + oauth2Organization: { + defaults: { + $id: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1238,9 +1362,9 @@ export class Oauth2 extends Service { * @param {string} params.codeChallenge - PKCE code challenge. Required when OAuth2 app is public. * @param {string} params.codeChallengeMethod - PKCE code challenge method. Required when OAuth2 app is public. * @param {string} params.prompt - OIDC prompt parameter for customization of consent screen. Space-separated list of: none, login, consent, select_account. - * @param {number} params.maxAge - OIDC max_age parameter for customization of consent screen. + * @param {number | null} params.maxAge - OIDC max_age parameter for customization of consent screen. * @param {string} params.authorizationDetails - Rich authorization request. JSON array of objects, each with a `type` and project-defined fields - * @param {string} params.resource - RFC 8707 resource indicator URI or URI list. Each value must be an absolute URI without a fragment. + * @param {string[]} params.resource - RFC 8707 resource indicator URI or URI list. Each value must be an absolute URI without a fragment. * @param {string} params.audience - Compatibility alias for a single OAuth2 resource indicator URI. * @throws {AppwriteException} * @returns {Promise} @@ -1255,9 +1379,9 @@ export class Oauth2 extends Service { codeChallenge?: string; codeChallengeMethod?: string; prompt?: string; - maxAge?: number; + maxAge?: number | null; authorizationDetails?: string; - resource?: string; + resource?: string[]; audience?: string; }): Promise; /** @@ -1272,9 +1396,9 @@ export class Oauth2 extends Service { * @param {string} codeChallenge - PKCE code challenge. Required when OAuth2 app is public. * @param {string} codeChallengeMethod - PKCE code challenge method. Required when OAuth2 app is public. * @param {string} prompt - OIDC prompt parameter for customization of consent screen. Space-separated list of: none, login, consent, select_account. - * @param {number} maxAge - OIDC max_age parameter for customization of consent screen. + * @param {number | null} maxAge - OIDC max_age parameter for customization of consent screen. * @param {string} authorizationDetails - Rich authorization request. JSON array of objects, each with a `type` and project-defined fields - * @param {string} resource - RFC 8707 resource indicator URI or URI list. Each value must be an absolute URI without a fragment. + * @param {string[]} resource - RFC 8707 resource indicator URI or URI list. Each value must be an absolute URI without a fragment. * @param {string} audience - Compatibility alias for a single OAuth2 resource indicator URI. * @throws {AppwriteException} * @returns {Promise} @@ -1290,9 +1414,9 @@ export class Oauth2 extends Service { codeChallenge?: string, codeChallengeMethod?: string, prompt?: string, - maxAge?: number, + maxAge?: number | null, authorizationDetails?: string, - resource?: string, + resource?: string[], audience?: string, ): Promise; createPAR( @@ -1307,9 +1431,9 @@ export class Oauth2 extends Service { codeChallenge?: string; codeChallengeMethod?: string; prompt?: string; - maxAge?: number; + maxAge?: number | null; authorizationDetails?: string; - resource?: string; + resource?: string[]; audience?: string; } | string, @@ -1322,9 +1446,9 @@ export class Oauth2 extends Service { string?, string?, string?, - number?, - string?, + (number | null)?, string?, + string[]?, string?, ] ): Promise { @@ -1338,9 +1462,9 @@ export class Oauth2 extends Service { codeChallenge?: string; codeChallengeMethod?: string; prompt?: string; - maxAge?: number; + maxAge?: number | null; authorizationDetails?: string; - resource?: string; + resource?: string[]; audience?: string; }; @@ -1359,9 +1483,9 @@ export class Oauth2 extends Service { codeChallenge?: string; codeChallengeMethod?: string; prompt?: string; - maxAge?: number; + maxAge?: number | null; authorizationDetails?: string; - resource?: string; + resource?: string[]; audience?: string; }; } else { @@ -1375,9 +1499,9 @@ export class Oauth2 extends Service { codeChallenge: rest[5] as string, codeChallengeMethod: rest[6] as string, prompt: rest[7] as string, - maxAge: rest[8] as number, + maxAge: rest[8] as number | null, authorizationDetails: rest[9] as string, - resource: rest[10] as string, + resource: rest[10] as string[], audience: rest[11] as string, }; } @@ -1473,7 +1597,7 @@ export class Oauth2 extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -1482,6 +1606,19 @@ export class Oauth2 extends Service { }, apiPayload, ); + const defaults = { + root: 'oauth2PAR', + models: { + oauth2PAR: { + defaults: { + request_uri: '', + expires_in: 0, + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1562,7 +1699,7 @@ export class Oauth2 extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -1570,6 +1707,31 @@ export class Oauth2 extends Service { }, apiPayload, ); + const defaults = { + root: 'oauth2ProjectList', + models: { + oauth2ProjectList: { + defaults: { + total: 0, + projects: [], + }, + properties: { + projects: { + items: 'oauth2Project', + }, + }, + }, + oauth2Project: { + defaults: { + $id: '', + region: '', + endpoint: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1625,7 +1787,7 @@ export class Oauth2 extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -1634,6 +1796,18 @@ export class Oauth2 extends Service { }, apiPayload, ); + const defaults = { + root: 'oauth2Reject', + models: { + oauth2Reject: { + defaults: { + redirectUrl: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1761,7 +1935,7 @@ export class Oauth2 extends Service { * @param {string} params.clientSecret - OAuth2 client secret. Required for confidential apps. * @param {string} params.codeVerifier - PKCE code verifier. Required for public apps. * @param {string} params.redirectUri - Redirect URI. Required for `authorization_code` grant type. - * @param {string} params.resource - RFC 8707 resource indicator URI or URI list. Each value must be an absolute URI without a fragment. + * @param {string[]} params.resource - RFC 8707 resource indicator URI or URI list. Each value must be an absolute URI without a fragment. * @param {string} params.audience - Compatibility alias for a single OAuth2 resource indicator URI. * @throws {AppwriteException} * @returns {Promise} @@ -1775,7 +1949,7 @@ export class Oauth2 extends Service { clientSecret?: string; codeVerifier?: string; redirectUri?: string; - resource?: string; + resource?: string[]; audience?: string; }): Promise; /** @@ -1789,7 +1963,7 @@ export class Oauth2 extends Service { * @param {string} clientSecret - OAuth2 client secret. Required for confidential apps. * @param {string} codeVerifier - PKCE code verifier. Required for public apps. * @param {string} redirectUri - Redirect URI. Required for `authorization_code` grant type. - * @param {string} resource - RFC 8707 resource indicator URI or URI list. Each value must be an absolute URI without a fragment. + * @param {string[]} resource - RFC 8707 resource indicator URI or URI list. Each value must be an absolute URI without a fragment. * @param {string} audience - Compatibility alias for a single OAuth2 resource indicator URI. * @throws {AppwriteException} * @returns {Promise} @@ -1804,7 +1978,7 @@ export class Oauth2 extends Service { clientSecret?: string, codeVerifier?: string, redirectUri?: string, - resource?: string, + resource?: string[], audience?: string, ): Promise; createToken( @@ -1818,7 +1992,7 @@ export class Oauth2 extends Service { clientSecret?: string; codeVerifier?: string; redirectUri?: string; - resource?: string; + resource?: string[]; audience?: string; } | string, @@ -1830,7 +2004,7 @@ export class Oauth2 extends Service { string?, string?, string?, - string?, + string[]?, string?, ] ): Promise { @@ -1843,7 +2017,7 @@ export class Oauth2 extends Service { clientSecret?: string; codeVerifier?: string; redirectUri?: string; - resource?: string; + resource?: string[]; audience?: string; }; @@ -1861,7 +2035,7 @@ export class Oauth2 extends Service { clientSecret?: string; codeVerifier?: string; redirectUri?: string; - resource?: string; + resource?: string[]; audience?: string; }; } else { @@ -1874,7 +2048,7 @@ export class Oauth2 extends Service { clientSecret: rest[4] as string, codeVerifier: rest[5] as string, redirectUri: rest[6] as string, - resource: rest[7] as string, + resource: rest[7] as string[], audience: rest[8] as string, }; } @@ -1943,7 +2117,7 @@ export class Oauth2 extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -1952,5 +2126,21 @@ export class Oauth2 extends Service { }, apiPayload, ); + const defaults = { + root: 'oauth2Token', + models: { + oauth2Token: { + defaults: { + access_token: '', + token_type: 'Bearer', + expires_in: 0, + refresh_token: '', + scope: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } } diff --git a/src/services/organization.ts b/src/services/organization.ts index 3542965f..4ec51e57 100644 --- a/src/services/organization.ts +++ b/src/services/organization.ts @@ -1,5 +1,5 @@ import { Service } from '../service'; -import { AppwriteException, Client } from '../client'; +import { AppwriteException, Client, applyDefaults } from '../client'; import type { Models } from '../models'; import type { Payload } from '../client'; @@ -71,7 +71,7 @@ export class Organization extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -80,6 +80,37 @@ export class Organization extends Service { }, apiPayload, ); + const defaults = { + root: 'appInstallationList', + models: { + appInstallationList: { + defaults: { + total: 0, + installations: [], + }, + properties: { + installations: { + items: 'appInstallation', + }, + }, + }, + appInstallation: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + appId: '', + teamId: '', + scopes: [], + authorizationDetails: [], + createdById: '', + createdByName: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -149,7 +180,7 @@ export class Organization extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -159,6 +190,26 @@ export class Organization extends Service { }, apiPayload, ); + const defaults = { + root: 'appInstallation', + models: { + appInstallation: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + appId: '', + teamId: '', + scopes: [], + authorizationDetails: [], + createdById: '', + createdByName: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -212,7 +263,7 @@ export class Organization extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -221,39 +272,63 @@ export class Organization extends Service { }, apiPayload, ); + const defaults = { + root: 'appInstallation', + models: { + appInstallation: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + appId: '', + teamId: '', + scopes: [], + authorizationDetails: [], + createdById: '', + createdByName: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** * Update an app installation on the organization. Only organization members with the owner role can update installations. The installation's granted scopes are refreshed to the scopes the app currently requests; previously issued installation access tokens are revoked. * * @param {string} params.installationId - Installation unique ID. - * @param {string} params.authorizationDetails - Authorization details granted to the installation as a JSON array of objects, each with a `type` and app-defined fields. Omit to keep the current value. + * @param {string | null} params.authorizationDetails - Authorization details granted to the installation as a JSON array of objects, each with a `type` and app-defined fields. Omit to keep the current value. * @throws {AppwriteException} * @returns {Promise} */ updateInstallation(params: { installationId: string; - authorizationDetails?: string; + authorizationDetails?: string | null; }): Promise; /** * Update an app installation on the organization. Only organization members with the owner role can update installations. The installation's granted scopes are refreshed to the scopes the app currently requests; previously issued installation access tokens are revoked. * * @param {string} installationId - Installation unique ID. - * @param {string} authorizationDetails - Authorization details granted to the installation as a JSON array of objects, each with a `type` and app-defined fields. Omit to keep the current value. + * @param {string | null} authorizationDetails - Authorization details granted to the installation as a JSON array of objects, each with a `type` and app-defined fields. Omit to keep the current value. * @throws {AppwriteException} * @returns {Promise} * @deprecated Use the object parameter style method for a better developer experience. */ updateInstallation( installationId: string, - authorizationDetails?: string, + authorizationDetails?: string | null, ): Promise; updateInstallation( paramsOrFirst: - { installationId: string; authorizationDetails?: string } | string, - ...rest: [string?] + | { installationId: string; authorizationDetails?: string | null } + | string, + ...rest: [(string | null)?] ): Promise { - let params: { installationId: string; authorizationDetails?: string }; + let params: { + installationId: string; + authorizationDetails?: string | null; + }; if ( paramsOrFirst && @@ -262,12 +337,12 @@ export class Organization extends Service { ) { params = (paramsOrFirst || {}) as { installationId: string; - authorizationDetails?: string; + authorizationDetails?: string | null; }; } else { params = { installationId: paramsOrFirst as string, - authorizationDetails: rest[0] as string, + authorizationDetails: rest[0] as string | null, }; } @@ -291,7 +366,7 @@ export class Organization extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'put', uri, { @@ -301,6 +376,26 @@ export class Organization extends Service { }, apiPayload, ); + const defaults = { + root: 'appInstallation', + models: { + appInstallation: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + appId: '', + teamId: '', + scopes: [], + authorizationDetails: [], + createdById: '', + createdByName: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** diff --git a/src/services/presences.ts b/src/services/presences.ts index 5fb3a364..4cc36d8b 100644 --- a/src/services/presences.ts +++ b/src/services/presences.ts @@ -1,5 +1,5 @@ import { Service } from '../service'; -import { AppwriteException, Client } from '../client'; +import { AppwriteException, Client, applyDefaults } from '../client'; import type { Models } from '../models'; import type { Payload } from '../client'; @@ -85,7 +85,7 @@ export class Presences extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -94,6 +94,34 @@ export class Presences extends Service { }, apiPayload, ); + const defaults = { + root: 'presenceList', + models: { + presenceList: { + defaults: { + total: 0, + presences: [], + }, + properties: { + presences: { + items: 'presence', + }, + }, + }, + presence: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + $permissions: [], + userId: '', + source: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -147,7 +175,7 @@ export class Presences extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -156,6 +184,23 @@ export class Presences extends Service { }, apiPayload, ); + const defaults = { + root: 'presence', + models: { + presence: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + $permissions: [], + userId: '', + source: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -278,7 +323,7 @@ export class Presences extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'put', uri, { @@ -288,6 +333,23 @@ export class Presences extends Service { }, apiPayload, ); + const defaults = { + root: 'presence', + models: { + presence: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + $permissions: [], + userId: '', + source: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -419,7 +481,7 @@ export class Presences extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'patch', uri, { @@ -429,6 +491,23 @@ export class Presences extends Service { }, apiPayload, ); + const defaults = { + root: 'presence', + models: { + presence: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + $permissions: [], + userId: '', + source: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** diff --git a/src/services/push.ts b/src/services/push.ts index 880e4f4c..9d7e985e 100644 --- a/src/services/push.ts +++ b/src/services/push.ts @@ -22,7 +22,7 @@ import { import { Client } from '../client'; import { createTcpStream } from '../lib/tcp-stream'; import { Service } from '../service'; -import type { ResolvedTopic, Topic } from '../topic'; +import type { Topic } from '../topic'; /** A message delivered on a subscribed topic (the MQTT analog of a Realtime event). */ export interface PushMessage { @@ -44,8 +44,20 @@ export interface PushBackgroundStatus { ignoringBatteryOptimizations: boolean; /** Foreground mode ({@link Push.setForeground}) keeps the connection open in a service. */ foregroundService: boolean; - /** Wake-ups may be deferred by Doze, so messages can arrive late while the app is closed. */ + /** + * Messages can arrive late, or not until the app is opened, while the app is closed: background + * usage is restricted without a battery optimisation exemption, or wake-ups may be deferred by + * Doze without exact alarms or foreground mode. + */ bestEffort: boolean; + /** + * The user restricted the app's background usage in the app's battery settings (Settings > + * Apps > your app > Battery), Android 9+. Android may then hold its alarms, jobs and foreground + * service while it is closed, so messages can wait until the app is opened. The battery + * optimisation exemption lets the alarms and jobs run again, but foreground mode still stops + * once the app leaves the screen. False below Android 9. + */ + backgroundRestricted: boolean; } /** A background notification the user tapped. */ @@ -293,9 +305,12 @@ export class Push extends Service { } /** - * Android: what background delivery can rely on. When `bestEffort` is true the scheduled - * wake-ups are inexact and Doze can defer them, so messages may arrive late while the app is - * closed; explain why, then ask with {@link requestExactAlarms} or + * Android: what background delivery can rely on. When `bestEffort` is true messages may arrive + * late, or not until the app is opened, while the app is closed, so explain why, then ask. If + * `backgroundRestricted` is true and the app is not `ignoringBatteryOptimizations`, ask the user + * to choose Unrestricted in the app's battery settings (Settings > Apps > your app > Battery), + * or ask with {@link requestIgnoreBatteryOptimizations}; otherwise the scheduled wake-ups are + * inexact and Doze can defer them, so ask with {@link requestExactAlarms} or * {@link requestIgnoreBatteryOptimizations}. Null elsewhere. */ async backgroundStatus(): Promise { @@ -468,7 +483,7 @@ export class Push extends Service { * Subscribe to one or more topics. Resolves to a {@link PushSubscription} handle. * * Each topic is a string or a `Topic` builder, e.g. - * `Topic.path(['user', userId]).all()`. + * `Topic.path(['user', userId])`. * * Called with only a callback, `subscribe((message) => {...}, options)` subscribes to the * signed-in user's own topic, `users/`, like FCM/APNs delivery to a device. The @@ -493,18 +508,12 @@ export class Push extends Service { options?: SubscribeOptions, ): Promise; subscribe( - topics: - string | Topic | ResolvedTopic | (string | Topic | ResolvedTopic)[], + topics: string | Topic | (string | Topic)[], callback: MessageCallback, options?: SubscribeOptions, ): Promise; async subscribe( - topicsOrCallback: - | string - | Topic - | ResolvedTopic - | (string | Topic | ResolvedTopic)[] - | MessageCallback, + topicsOrCallback: string | Topic | (string | Topic)[] | MessageCallback, callbackOrOptions?: MessageCallback | SubscribeOptions, topicOptions: SubscribeOptions = {}, ): Promise { @@ -521,12 +530,7 @@ export class Push extends Service { } private async subscribeWith( - topicsOrCallback: - | string - | Topic - | ResolvedTopic - | (string | Topic | ResolvedTopic)[] - | MessageCallback, + topicsOrCallback: string | Topic | (string | Topic)[] | MessageCallback, callbackOrOptions: MessageCallback | SubscribeOptions | undefined, topicOptions: SubscribeOptions, ): Promise { @@ -1231,18 +1235,26 @@ export class Push extends Service { } } - /** Post a local notification for a message a background subscription matched. */ - private async notify(message: PushMessage, title: string): Promise { + /** + * Post a local notification for a message a background subscription matched. A data-only + * message, an envelope without a notification title or body, posts none. + */ + private async notify( + message: PushMessage, + title: string, + content: NotificationContent = notificationContent(message), + ): Promise { + if (!content.visible) { + return; + } try { /* eslint-disable @typescript-eslint/no-require-imports */ const notifications: typeof import('expo-notifications') = require('expo-notifications'); /* eslint-enable @typescript-eslint/no-require-imports */ - const content = notificationContent(message); - const raw = !content.present; await notifications.scheduleNotificationAsync({ content: { title: content.title ?? title, - body: content.body ?? (raw ? message.data : null), + body: content.body ?? (content.raw ? message.data : null), data: { topic: message.topic, payload: message.data }, }, trigger: null, @@ -1574,7 +1586,7 @@ export class Push extends Service { payload, qos: packet.qos, }; - const serverTitle = notificationContent(message).title; + const content = notificationContent(message); const postedTitles = new Set(); // While the app is on screen it shows the message itself: only subscriptions that // opted in with notifyInForeground also post a notification then. @@ -1584,14 +1596,14 @@ export class Push extends Service { await sub.callback(message); // Notification is per-subscription: only subs that opted in post one, each // title once. A title the server sent replaces theirs, so it posts once. - const title = serverTitle ?? sub.title ?? message.topic; + const title = content.title ?? sub.title ?? message.topic; if ( sub.background && (!foreground || sub.notifyInForeground) && !postedTitles.has(title) ) { postedTitles.add(title); - await this.notify(message, title); + await this.notify(message, title, content); } } } @@ -1718,33 +1730,51 @@ function expoNotifications(): typeof import('expo-notifications') | null { /** What a message's `notification` block asks a background notification to show. */ interface NotificationContent { - /** Whether the message has a `notification` block at all. */ - present: boolean; + /** Whether the payload is not a JSON object, so it is shown as it is. */ + raw: boolean; + /** Whether a notification is posted: raw, or an envelope with a title or body. */ + visible: boolean; title?: string; body?: string; image?: string; } -/** The server's `notification` block in a message; empty when the payload has none or is not JSON. */ -function notificationContent(message: PushMessage): NotificationContent { - let notification: unknown; +/** The server's `notification` block in a payload, or null when the payload is not a JSON object. */ +function notificationBlock(data: string): Record | null { + let envelope: unknown; try { - notification = (JSON.parse(message.data) as { notification?: unknown }) - ?.notification; + envelope = JSON.parse(data); } catch { - return { present: false }; + return null; } - if (typeof notification !== 'object' || notification === null) { - return { present: false }; + if ( + typeof envelope !== 'object' || + envelope === null || + Array.isArray(envelope) + ) { + return null; } + const notification = (envelope as { notification?: unknown }).notification; + return typeof notification === 'object' && notification !== null + ? (notification as Record) + : {}; +} + +/** What a message asks a background notification to show; raw when it is not a JSON object. */ +function notificationContent(message: PushMessage): NotificationContent { + const block = notificationBlock(message.data); + const raw = block === null; const field = (name: string): string | undefined => { - const value = (notification as Record)[name]; + const value = block?.[name]; return typeof value === 'string' && value !== '' ? value : undefined; }; + const title = field('title'); + const body = field('body'); return { - present: true, - title: field('title'), - body: field('body'), + raw, + visible: raw || title !== undefined || body !== undefined, + title, + body, image: field('image'), }; } diff --git a/src/services/realtime.ts b/src/services/realtime.ts index 77820844..07b5c902 100644 --- a/src/services/realtime.ts +++ b/src/services/realtime.ts @@ -1,11 +1,12 @@ import { AppwriteException, Client, JSONbig } from '../client'; import { Channel, ActionableChannel, ResolvedChannel } from '../channel'; -import { Query } from '../query'; +import { normalizeQueries, type QueryInput } from '../query'; import { ID } from '../id'; import { Platform } from 'react-native'; + export type RealtimeSubscriptionUpdate = { channels?: (string | Channel | ActionableChannel | ResolvedChannel)[]; - queries?: (string | Query)[]; + queries?: QueryInput; }; export type RealtimeSubscription = { @@ -212,6 +213,7 @@ export class Realtime { const queryParams = `project=${projectId}`; const jwt = this.client.config.jwt; + const endpoint = this.client.config.endpointRealtime !== '' ? this.client.config.endpointRealtime @@ -256,6 +258,7 @@ export class Realtime { ...(jwt ? { 'x-appwrite-jwt': jwt } : {}), }, })); + socket.addEventListener('open', () => { if (connectionId !== this.connectionId) { return; @@ -511,7 +514,7 @@ export class Realtime { public async subscribe( channel: string | Channel | ActionableChannel | ResolvedChannel, callback: (event: RealtimeResponseEvent) => void, - queries?: (string | Query)[], + queries?: QueryInput, ): Promise; /** @@ -526,7 +529,7 @@ export class Realtime { string | Channel | ActionableChannel | ResolvedChannel )[], callback: (event: RealtimeResponseEvent) => void, - queries?: (string | Query)[], + queries?: QueryInput, ): Promise; /** @@ -539,7 +542,7 @@ export class Realtime { public async subscribe( channel: string | Channel | ActionableChannel | ResolvedChannel, callback: (event: RealtimeResponseEvent) => void, - queries?: (string | Query)[], + queries?: QueryInput, ): Promise; /** @@ -554,7 +557,7 @@ export class Realtime { string | Channel | ActionableChannel | ResolvedChannel )[], callback: (event: RealtimeResponseEvent) => void, - queries?: (string | Query)[], + queries?: QueryInput, ): Promise; public async subscribe( @@ -565,7 +568,7 @@ export class Realtime { | ResolvedChannel | (string | Channel | ActionableChannel | ResolvedChannel)[], callback: (event: RealtimeResponseEvent) => void, - queries: (string | Query)[] = [], + queries: QueryInput = [], ): Promise { const channelArray = Array.isArray(channelsOrChannel) ? channelsOrChannel @@ -577,21 +580,7 @@ export class Realtime { ); const channels = new Set(channelStrings); - // Convert queries to array of strings - // Ensure each query is a separate string in the array - const queryStrings: string[] = []; - for (const q of queries ?? []) { - if (Array.isArray(q)) { - // Handle nested arrays: [[q1, q2]] -> [q1, q2] - for (const inner of q) { - queryStrings.push( - typeof inner === 'string' ? inner : inner.toString(), - ); - } - } else { - queryStrings.push(typeof q === 'string' ? q : q.toString()); - } - } + const queryStrings = normalizeQueries(queries); const subscriptionId = this.generateUniqueSubscriptionId(); @@ -642,23 +631,7 @@ export class Realtime { } if (changes.queries !== undefined) { - const nextQueries: string[] = []; - for (const q of changes.queries) { - if (Array.isArray(q)) { - for (const inner of q) { - nextQueries.push( - typeof inner === 'string' - ? inner - : (inner as Query).toString(), - ); - } - } else { - nextQueries.push( - typeof q === 'string' ? q : q.toString(), - ); - } - } - subscription.queries = nextQueries; + subscription.queries = normalizeQueries(changes.queries); } this.enqueuePendingSubscribe(subscriptionId); diff --git a/src/services/storage.ts b/src/services/storage.ts index fdca28a8..f14c66cf 100644 --- a/src/services/storage.ts +++ b/src/services/storage.ts @@ -1,5 +1,5 @@ import { Service } from '../service'; -import { AppwriteException, Client } from '../client'; +import { AppwriteException, Client, applyDefaults } from '../client'; import type { Models } from '../models'; import type { UploadProgress, Payload } from '../client'; import * as FileSystem from 'expo-file-system'; @@ -113,7 +113,7 @@ export class Storage extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -122,6 +122,44 @@ export class Storage extends Service { }, apiPayload, ); + const defaults = { + root: 'fileList', + models: { + fileList: { + defaults: { + total: 0, + files: [], + }, + properties: { + files: { + items: 'file', + }, + }, + }, + file: { + defaults: { + $id: '', + bucketId: '', + $createdAt: '', + $updatedAt: '', + $permissions: [], + name: '', + folder: '', + key: '', + signature: '', + mimeType: '', + sizeOriginal: 0, + sizeActual: 0, + chunksTotal: 0, + chunksUploaded: 0, + encryption: false, + compression: 'none', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -563,7 +601,7 @@ export class Storage extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -572,6 +610,33 @@ export class Storage extends Service { }, apiPayload, ); + const defaults = { + root: 'file', + models: { + file: { + defaults: { + $id: '', + bucketId: '', + $createdAt: '', + $updatedAt: '', + $permissions: [], + name: '', + folder: '', + key: '', + signature: '', + mimeType: '', + sizeOriginal: 0, + sizeActual: 0, + chunksTotal: 0, + chunksUploaded: 0, + encryption: false, + compression: 'none', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -580,7 +645,7 @@ export class Storage extends Service { * @param {string} params.bucketId - Bucket unique ID. * @param {string} params.fileId - File ID. * @param {string} params.name - File name. - * @param {string[]} params.permissions - An array of permission strings. By default, the current permissions are inherited. [Learn more about permissions](https://appwrite.io/docs/permissions). + * @param {string[] | null} params.permissions - An array of permission strings. By default, the current permissions are inherited. [Learn more about permissions](https://appwrite.io/docs/permissions). * @throws {AppwriteException} * @returns {Promise} */ @@ -588,7 +653,7 @@ export class Storage extends Service { bucketId: string; fileId: string; name?: string; - permissions?: string[]; + permissions?: string[] | null; }): Promise; /** * Update a file by its unique ID. Only users with write permissions have access to update this resource. @@ -596,7 +661,7 @@ export class Storage extends Service { * @param {string} bucketId - Bucket unique ID. * @param {string} fileId - File ID. * @param {string} name - File name. - * @param {string[]} permissions - An array of permission strings. By default, the current permissions are inherited. [Learn more about permissions](https://appwrite.io/docs/permissions). + * @param {string[] | null} permissions - An array of permission strings. By default, the current permissions are inherited. [Learn more about permissions](https://appwrite.io/docs/permissions). * @throws {AppwriteException} * @returns {Promise} * @deprecated Use the object parameter style method for a better developer experience. @@ -605,7 +670,7 @@ export class Storage extends Service { bucketId: string, fileId: string, name?: string, - permissions?: string[], + permissions?: string[] | null, ): Promise; updateFile( paramsOrFirst: @@ -613,16 +678,16 @@ export class Storage extends Service { bucketId: string; fileId: string; name?: string; - permissions?: string[]; + permissions?: string[] | null; } | string, - ...rest: [string?, string?, string[]?] + ...rest: [string?, string?, (string[] | null)?] ): Promise { let params: { bucketId: string; fileId: string; name?: string; - permissions?: string[]; + permissions?: string[] | null; }; if ( @@ -634,14 +699,14 @@ export class Storage extends Service { bucketId: string; fileId: string; name?: string; - permissions?: string[]; + permissions?: string[] | null; }; } else { params = { bucketId: paramsOrFirst as string, fileId: rest[0] as string, name: rest[1] as string, - permissions: rest[2] as string[], + permissions: rest[2] as string[] | null, }; } @@ -674,7 +739,7 @@ export class Storage extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'put', uri, { @@ -684,6 +749,33 @@ export class Storage extends Service { }, apiPayload, ); + const defaults = { + root: 'file', + models: { + file: { + defaults: { + $id: '', + bucketId: '', + $createdAt: '', + $updatedAt: '', + $permissions: [], + name: '', + folder: '', + key: '', + signature: '', + mimeType: '', + sizeOriginal: 0, + sizeActual: 0, + chunksTotal: 0, + chunksUploaded: 0, + encryption: false, + compression: 'none', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** diff --git a/src/services/tables-db.ts b/src/services/tables-db.ts index ae5d11d1..20a11bc1 100644 --- a/src/services/tables-db.ts +++ b/src/services/tables-db.ts @@ -1,5 +1,5 @@ import { Service } from '../service'; -import { AppwriteException, Client } from '../client'; +import { AppwriteException, Client, applyDefaults } from '../client'; import type { Models } from '../models'; import type { Payload } from '../client'; @@ -71,7 +71,7 @@ export class TablesDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -80,6 +80,34 @@ export class TablesDB extends Service { }, apiPayload, ); + const defaults = { + root: 'transactionList', + models: { + transactionList: { + defaults: { + total: 0, + transactions: [], + }, + properties: { + transactions: { + items: 'transaction', + }, + }, + }, + transaction: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + status: 'pending', + operations: 0, + expiresAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -127,7 +155,7 @@ export class TablesDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -137,6 +165,23 @@ export class TablesDB extends Service { }, apiPayload, ); + const defaults = { + root: 'transaction', + models: { + transaction: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + status: 'pending', + operations: 0, + expiresAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -190,7 +235,7 @@ export class TablesDB extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -199,6 +244,23 @@ export class TablesDB extends Service { }, apiPayload, ); + const defaults = { + root: 'transaction', + models: { + transaction: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + status: 'pending', + operations: 0, + expiresAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -285,7 +347,7 @@ export class TablesDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'patch', uri, { @@ -295,6 +357,23 @@ export class TablesDB extends Service { }, apiPayload, ); + const defaults = { + root: 'transaction', + models: { + transaction: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + status: 'pending', + operations: 0, + expiresAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -427,7 +506,7 @@ export class TablesDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -437,6 +516,23 @@ export class TablesDB extends Service { }, apiPayload, ); + const defaults = { + root: 'transaction', + models: { + transaction: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + status: 'pending', + operations: 0, + expiresAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -567,7 +663,7 @@ export class TablesDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -576,6 +672,35 @@ export class TablesDB extends Service { }, apiPayload, ); + const defaults = { + root: 'rowList', + models: { + rowList: { + defaults: { + total: 0, + rows: [], + }, + properties: { + rows: { + items: 'row', + }, + }, + }, + row: { + defaults: { + $id: '', + $sequence: '', + $tableId: '', + $databaseId: '', + $createdAt: '', + $updatedAt: '', + $permissions: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -585,8 +710,8 @@ export class TablesDB extends Service { * @param {string} params.tableId - Table ID. You can create a new table using the Database service [server integration](https://appwrite.io/docs/references/cloud/server-dart/tablesDB#createTable). Make sure to define columns before creating rows. * @param {string} params.rowId - Row ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars. * @param {Row extends Models.DefaultRow ? Partial & Record : Partial & Omit} params.data - Row data as JSON object. - * @param {string[]} params.permissions - An array of permissions strings. By default, only the current user is granted all permissions. [Learn more about permissions](https://appwrite.io/docs/permissions). - * @param {string} params.transactionId - Transaction ID for staging the operation. + * @param {string[] | null} params.permissions - An array of permissions strings. By default, only the current user is granted all permissions. [Learn more about permissions](https://appwrite.io/docs/permissions). + * @param {string | null} params.transactionId - Transaction ID for staging the operation. * @throws {AppwriteException} * @returns {Promise} */ @@ -597,8 +722,8 @@ export class TablesDB extends Service { data: Row extends Models.DefaultRow ? Partial & Record : Partial & Omit; - permissions?: string[]; - transactionId?: string; + permissions?: string[] | null; + transactionId?: string | null; }): Promise; /** * Create a new Row. Before using this route, you should create a new table resource using either a [server integration](https://appwrite.io/docs/references/cloud/server-dart/tablesDB#createTable) API or directly from your database console. @@ -607,8 +732,8 @@ export class TablesDB extends Service { * @param {string} tableId - Table ID. You can create a new table using the Database service [server integration](https://appwrite.io/docs/references/cloud/server-dart/tablesDB#createTable). Make sure to define columns before creating rows. * @param {string} rowId - Row ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars. * @param {Row extends Models.DefaultRow ? Partial & Record : Partial & Omit} data - Row data as JSON object. - * @param {string[]} permissions - An array of permissions strings. By default, only the current user is granted all permissions. [Learn more about permissions](https://appwrite.io/docs/permissions). - * @param {string} transactionId - Transaction ID for staging the operation. + * @param {string[] | null} permissions - An array of permissions strings. By default, only the current user is granted all permissions. [Learn more about permissions](https://appwrite.io/docs/permissions). + * @param {string | null} transactionId - Transaction ID for staging the operation. * @throws {AppwriteException} * @returns {Promise} * @deprecated Use the object parameter style method for a better developer experience. @@ -620,8 +745,8 @@ export class TablesDB extends Service { data: Row extends Models.DefaultRow ? Partial & Record : Partial & Omit, - permissions?: string[], - transactionId?: string, + permissions?: string[] | null, + transactionId?: string | null, ): Promise; createRow( paramsOrFirst: @@ -632,8 +757,8 @@ export class TablesDB extends Service { data: Row extends Models.DefaultRow ? Partial & Record : Partial & Omit; - permissions?: string[]; - transactionId?: string; + permissions?: string[] | null; + transactionId?: string | null; } | string, ...rest: [ @@ -642,8 +767,8 @@ export class TablesDB extends Service { (Row extends Models.DefaultRow ? Partial & Record : Partial & Omit)?, - string[]?, - string?, + (string[] | null)?, + (string | null)?, ] ): Promise { let params: { @@ -653,8 +778,8 @@ export class TablesDB extends Service { data: Row extends Models.DefaultRow ? Partial & Record : Partial & Omit; - permissions?: string[]; - transactionId?: string; + permissions?: string[] | null; + transactionId?: string | null; }; if ( @@ -669,8 +794,8 @@ export class TablesDB extends Service { data: Row extends Models.DefaultRow ? Partial & Record : Partial & Omit; - permissions?: string[]; - transactionId?: string; + permissions?: string[] | null; + transactionId?: string | null; }; } else { params = { @@ -680,8 +805,8 @@ export class TablesDB extends Service { data: rest[2] as Row extends Models.DefaultRow ? Partial & Record : Partial & Omit, - permissions: rest[3] as string[], - transactionId: rest[4] as string, + permissions: rest[3] as string[] | null, + transactionId: rest[4] as string | null, }; } @@ -734,7 +859,7 @@ export class TablesDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -744,6 +869,24 @@ export class TablesDB extends Service { }, apiPayload, ); + const defaults = { + root: 'row', + models: { + row: { + defaults: { + $id: '', + $sequence: '', + $tableId: '', + $databaseId: '', + $createdAt: '', + $updatedAt: '', + $permissions: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -862,7 +1005,7 @@ export class TablesDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -871,6 +1014,24 @@ export class TablesDB extends Service { }, apiPayload, ); + const defaults = { + root: 'row', + models: { + row: { + defaults: { + $id: '', + $sequence: '', + $tableId: '', + $databaseId: '', + $createdAt: '', + $updatedAt: '', + $permissions: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -880,8 +1041,8 @@ export class TablesDB extends Service { * @param {string} params.tableId - Table ID. * @param {string} params.rowId - Row ID. * @param {Row extends Models.DefaultRow ? Partial & Record : Partial & Partial>} params.data - Row data as JSON object. Include all required columns of the row to be created or updated. - * @param {string[]} params.permissions - An array of permissions strings. By default, the current permissions are inherited. [Learn more about permissions](https://appwrite.io/docs/permissions). - * @param {string} params.transactionId - Transaction ID for staging the operation. + * @param {string[] | null} params.permissions - An array of permissions strings. By default, the current permissions are inherited. [Learn more about permissions](https://appwrite.io/docs/permissions). + * @param {string | null} params.transactionId - Transaction ID for staging the operation. * @throws {AppwriteException} * @returns {Promise} */ @@ -892,8 +1053,8 @@ export class TablesDB extends Service { data?: Row extends Models.DefaultRow ? Partial & Record : Partial & Partial>; - permissions?: string[]; - transactionId?: string; + permissions?: string[] | null; + transactionId?: string | null; }): Promise; /** * Create or update a Row. Before using this route, you should create a new table resource using either a [server integration](https://appwrite.io/docs/references/cloud/server-dart/tablesDB#createTable) API or directly from your database console. @@ -902,8 +1063,8 @@ export class TablesDB extends Service { * @param {string} tableId - Table ID. * @param {string} rowId - Row ID. * @param {Row extends Models.DefaultRow ? Partial & Record : Partial & Partial>} data - Row data as JSON object. Include all required columns of the row to be created or updated. - * @param {string[]} permissions - An array of permissions strings. By default, the current permissions are inherited. [Learn more about permissions](https://appwrite.io/docs/permissions). - * @param {string} transactionId - Transaction ID for staging the operation. + * @param {string[] | null} permissions - An array of permissions strings. By default, the current permissions are inherited. [Learn more about permissions](https://appwrite.io/docs/permissions). + * @param {string | null} transactionId - Transaction ID for staging the operation. * @throws {AppwriteException} * @returns {Promise} * @deprecated Use the object parameter style method for a better developer experience. @@ -915,8 +1076,8 @@ export class TablesDB extends Service { data?: Row extends Models.DefaultRow ? Partial & Record : Partial & Partial>, - permissions?: string[], - transactionId?: string, + permissions?: string[] | null, + transactionId?: string | null, ): Promise; upsertRow( paramsOrFirst: @@ -928,8 +1089,8 @@ export class TablesDB extends Service { ? Partial & Record : Partial & Partial>; - permissions?: string[]; - transactionId?: string; + permissions?: string[] | null; + transactionId?: string | null; } | string, ...rest: [ @@ -938,8 +1099,8 @@ export class TablesDB extends Service { (Row extends Models.DefaultRow ? Partial & Record : Partial & Partial>)?, - string[]?, - string?, + (string[] | null)?, + (string | null)?, ] ): Promise { let params: { @@ -949,8 +1110,8 @@ export class TablesDB extends Service { data?: Row extends Models.DefaultRow ? Partial & Record : Partial & Partial>; - permissions?: string[]; - transactionId?: string; + permissions?: string[] | null; + transactionId?: string | null; }; if ( @@ -966,8 +1127,8 @@ export class TablesDB extends Service { ? Partial & Record : Partial & Partial>; - permissions?: string[]; - transactionId?: string; + permissions?: string[] | null; + transactionId?: string | null; }; } else { params = { @@ -978,8 +1139,8 @@ export class TablesDB extends Service { ? Partial & Record : Partial & Partial>, - permissions: rest[3] as string[], - transactionId: rest[4] as string, + permissions: rest[3] as string[] | null, + transactionId: rest[4] as string | null, }; } @@ -1025,7 +1186,7 @@ export class TablesDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'put', uri, { @@ -1035,6 +1196,24 @@ export class TablesDB extends Service { }, apiPayload, ); + const defaults = { + root: 'row', + models: { + row: { + defaults: { + $id: '', + $sequence: '', + $tableId: '', + $databaseId: '', + $createdAt: '', + $updatedAt: '', + $permissions: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1044,8 +1223,8 @@ export class TablesDB extends Service { * @param {string} params.tableId - Table ID. * @param {string} params.rowId - Row ID. * @param {Row extends Models.DefaultRow ? Partial & Record : Partial & Partial>} params.data - Row data as JSON object. Include only columns and value pairs to be updated. - * @param {string[]} params.permissions - An array of permissions strings. By default, the current permissions are inherited. [Learn more about permissions](https://appwrite.io/docs/permissions). - * @param {string} params.transactionId - Transaction ID for staging the operation. + * @param {string[] | null} params.permissions - An array of permissions strings. By default, the current permissions are inherited. [Learn more about permissions](https://appwrite.io/docs/permissions). + * @param {string | null} params.transactionId - Transaction ID for staging the operation. * @throws {AppwriteException} * @returns {Promise} */ @@ -1056,8 +1235,8 @@ export class TablesDB extends Service { data?: Row extends Models.DefaultRow ? Partial & Record : Partial & Partial>; - permissions?: string[]; - transactionId?: string; + permissions?: string[] | null; + transactionId?: string | null; }): Promise; /** * Update a row by its unique ID. Using the patch method you can pass only specific fields that will get updated. @@ -1066,8 +1245,8 @@ export class TablesDB extends Service { * @param {string} tableId - Table ID. * @param {string} rowId - Row ID. * @param {Row extends Models.DefaultRow ? Partial & Record : Partial & Partial>} data - Row data as JSON object. Include only columns and value pairs to be updated. - * @param {string[]} permissions - An array of permissions strings. By default, the current permissions are inherited. [Learn more about permissions](https://appwrite.io/docs/permissions). - * @param {string} transactionId - Transaction ID for staging the operation. + * @param {string[] | null} permissions - An array of permissions strings. By default, the current permissions are inherited. [Learn more about permissions](https://appwrite.io/docs/permissions). + * @param {string | null} transactionId - Transaction ID for staging the operation. * @throws {AppwriteException} * @returns {Promise} * @deprecated Use the object parameter style method for a better developer experience. @@ -1079,8 +1258,8 @@ export class TablesDB extends Service { data?: Row extends Models.DefaultRow ? Partial & Record : Partial & Partial>, - permissions?: string[], - transactionId?: string, + permissions?: string[] | null, + transactionId?: string | null, ): Promise; updateRow( paramsOrFirst: @@ -1092,8 +1271,8 @@ export class TablesDB extends Service { ? Partial & Record : Partial & Partial>; - permissions?: string[]; - transactionId?: string; + permissions?: string[] | null; + transactionId?: string | null; } | string, ...rest: [ @@ -1102,8 +1281,8 @@ export class TablesDB extends Service { (Row extends Models.DefaultRow ? Partial & Record : Partial & Partial>)?, - string[]?, - string?, + (string[] | null)?, + (string | null)?, ] ): Promise { let params: { @@ -1113,8 +1292,8 @@ export class TablesDB extends Service { data?: Row extends Models.DefaultRow ? Partial & Record : Partial & Partial>; - permissions?: string[]; - transactionId?: string; + permissions?: string[] | null; + transactionId?: string | null; }; if ( @@ -1130,8 +1309,8 @@ export class TablesDB extends Service { ? Partial & Record : Partial & Partial>; - permissions?: string[]; - transactionId?: string; + permissions?: string[] | null; + transactionId?: string | null; }; } else { params = { @@ -1142,8 +1321,8 @@ export class TablesDB extends Service { ? Partial & Record : Partial & Partial>, - permissions: rest[3] as string[], - transactionId: rest[4] as string, + permissions: rest[3] as string[] | null, + transactionId: rest[4] as string | null, }; } @@ -1189,7 +1368,7 @@ export class TablesDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'patch', uri, { @@ -1199,6 +1378,24 @@ export class TablesDB extends Service { }, apiPayload, ); + const defaults = { + root: 'row', + models: { + row: { + defaults: { + $id: '', + $sequence: '', + $tableId: '', + $databaseId: '', + $createdAt: '', + $updatedAt: '', + $permissions: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1324,8 +1521,8 @@ export class TablesDB extends Service { * @param {string} params.rowId - Row ID. * @param {string} params.column - Column key. * @param {number} params.value - Value to increment the column by. The value must be a number. - * @param {number} params.min - Minimum value for the column. If the current value is lesser than this value, an exception will be thrown. - * @param {string} params.transactionId - Transaction ID for staging the operation. + * @param {number | null} params.min - Minimum value for the column. If the current value is lesser than this value, an exception will be thrown. + * @param {string | null} params.transactionId - Transaction ID for staging the operation. * @throws {AppwriteException} * @returns {Promise} */ @@ -1335,8 +1532,8 @@ export class TablesDB extends Service { rowId: string; column: string; value?: number; - min?: number; - transactionId?: string; + min?: number | null; + transactionId?: string | null; }): Promise; /** * Decrement a specific column of a row by a given value. @@ -1346,8 +1543,8 @@ export class TablesDB extends Service { * @param {string} rowId - Row ID. * @param {string} column - Column key. * @param {number} value - Value to increment the column by. The value must be a number. - * @param {number} min - Minimum value for the column. If the current value is lesser than this value, an exception will be thrown. - * @param {string} transactionId - Transaction ID for staging the operation. + * @param {number | null} min - Minimum value for the column. If the current value is lesser than this value, an exception will be thrown. + * @param {string | null} transactionId - Transaction ID for staging the operation. * @throws {AppwriteException} * @returns {Promise} * @deprecated Use the object parameter style method for a better developer experience. @@ -1358,8 +1555,8 @@ export class TablesDB extends Service { rowId: string, column: string, value?: number, - min?: number, - transactionId?: string, + min?: number | null, + transactionId?: string | null, ): Promise; decrementRowColumn( paramsOrFirst: @@ -1369,11 +1566,18 @@ export class TablesDB extends Service { rowId: string; column: string; value?: number; - min?: number; - transactionId?: string; + min?: number | null; + transactionId?: string | null; } | string, - ...rest: [string?, string?, string?, number?, number?, string?] + ...rest: [ + string?, + string?, + string?, + number?, + (number | null)?, + (string | null)?, + ] ): Promise { let params: { databaseId: string; @@ -1381,8 +1585,8 @@ export class TablesDB extends Service { rowId: string; column: string; value?: number; - min?: number; - transactionId?: string; + min?: number | null; + transactionId?: string | null; }; if ( @@ -1396,8 +1600,8 @@ export class TablesDB extends Service { rowId: string; column: string; value?: number; - min?: number; - transactionId?: string; + min?: number | null; + transactionId?: string | null; }; } else { params = { @@ -1406,8 +1610,8 @@ export class TablesDB extends Service { rowId: rest[1] as string, column: rest[2] as string, value: rest[3] as number, - min: rest[4] as number, - transactionId: rest[5] as string, + min: rest[4] as number | null, + transactionId: rest[5] as string | null, }; } @@ -1460,7 +1664,7 @@ export class TablesDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'patch', uri, { @@ -1470,6 +1674,24 @@ export class TablesDB extends Service { }, apiPayload, ); + const defaults = { + root: 'row', + models: { + row: { + defaults: { + $id: '', + $sequence: '', + $tableId: '', + $databaseId: '', + $createdAt: '', + $updatedAt: '', + $permissions: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1480,8 +1702,8 @@ export class TablesDB extends Service { * @param {string} params.rowId - Row ID. * @param {string} params.column - Column key. * @param {number} params.value - Value to increment the column by. The value must be a number. - * @param {number} params.max - Maximum value for the column. If the current value is greater than this value, an error will be thrown. - * @param {string} params.transactionId - Transaction ID for staging the operation. + * @param {number | null} params.max - Maximum value for the column. If the current value is greater than this value, an error will be thrown. + * @param {string | null} params.transactionId - Transaction ID for staging the operation. * @throws {AppwriteException} * @returns {Promise} */ @@ -1491,8 +1713,8 @@ export class TablesDB extends Service { rowId: string; column: string; value?: number; - max?: number; - transactionId?: string; + max?: number | null; + transactionId?: string | null; }): Promise; /** * Increment a specific column of a row by a given value. @@ -1502,8 +1724,8 @@ export class TablesDB extends Service { * @param {string} rowId - Row ID. * @param {string} column - Column key. * @param {number} value - Value to increment the column by. The value must be a number. - * @param {number} max - Maximum value for the column. If the current value is greater than this value, an error will be thrown. - * @param {string} transactionId - Transaction ID for staging the operation. + * @param {number | null} max - Maximum value for the column. If the current value is greater than this value, an error will be thrown. + * @param {string | null} transactionId - Transaction ID for staging the operation. * @throws {AppwriteException} * @returns {Promise} * @deprecated Use the object parameter style method for a better developer experience. @@ -1514,8 +1736,8 @@ export class TablesDB extends Service { rowId: string, column: string, value?: number, - max?: number, - transactionId?: string, + max?: number | null, + transactionId?: string | null, ): Promise; incrementRowColumn( paramsOrFirst: @@ -1525,11 +1747,18 @@ export class TablesDB extends Service { rowId: string; column: string; value?: number; - max?: number; - transactionId?: string; + max?: number | null; + transactionId?: string | null; } | string, - ...rest: [string?, string?, string?, number?, number?, string?] + ...rest: [ + string?, + string?, + string?, + number?, + (number | null)?, + (string | null)?, + ] ): Promise { let params: { databaseId: string; @@ -1537,8 +1766,8 @@ export class TablesDB extends Service { rowId: string; column: string; value?: number; - max?: number; - transactionId?: string; + max?: number | null; + transactionId?: string | null; }; if ( @@ -1552,8 +1781,8 @@ export class TablesDB extends Service { rowId: string; column: string; value?: number; - max?: number; - transactionId?: string; + max?: number | null; + transactionId?: string | null; }; } else { params = { @@ -1562,8 +1791,8 @@ export class TablesDB extends Service { rowId: rest[1] as string, column: rest[2] as string, value: rest[3] as number, - max: rest[4] as number, - transactionId: rest[5] as string, + max: rest[4] as number | null, + transactionId: rest[5] as string | null, }; } @@ -1616,7 +1845,7 @@ export class TablesDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'patch', uri, { @@ -1626,5 +1855,23 @@ export class TablesDB extends Service { }, apiPayload, ); + const defaults = { + root: 'row', + models: { + row: { + defaults: { + $id: '', + $sequence: '', + $tableId: '', + $databaseId: '', + $createdAt: '', + $updatedAt: '', + $permissions: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } } diff --git a/src/services/teams.ts b/src/services/teams.ts index a4424fcd..b5cd1362 100644 --- a/src/services/teams.ts +++ b/src/services/teams.ts @@ -1,5 +1,5 @@ import { Service } from '../service'; -import { AppwriteException, Client } from '../client'; +import { AppwriteException, Client, applyDefaults } from '../client'; import type { Models } from '../models'; import type { Payload } from '../client'; @@ -85,7 +85,7 @@ export class Teams extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -94,6 +94,33 @@ export class Teams extends Service { }, apiPayload, ); + const defaults = { + root: 'teamList', + models: { + teamList: { + defaults: { + total: 0, + teams: [], + }, + properties: { + teams: { + items: 'team', + }, + }, + }, + team: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + total: 0, + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -180,7 +207,7 @@ export class Teams extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -190,6 +217,22 @@ export class Teams extends Service { }, apiPayload, ); + const defaults = { + root: 'team', + models: { + team: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + total: 0, + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -243,7 +286,7 @@ export class Teams extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -252,6 +295,22 @@ export class Teams extends Service { }, apiPayload, ); + const defaults = { + root: 'team', + models: { + team: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + total: 0, + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -323,7 +382,7 @@ export class Teams extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'put', uri, { @@ -333,6 +392,22 @@ export class Teams extends Service { }, apiPayload, ); + const defaults = { + root: 'team', + models: { + team: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + name: '', + total: 0, + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -469,7 +544,7 @@ export class Teams extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -478,6 +553,37 @@ export class Teams extends Service { }, apiPayload, ); + const defaults = { + root: 'appInstallationList', + models: { + appInstallationList: { + defaults: { + total: 0, + installations: [], + }, + properties: { + installations: { + items: 'appInstallation', + }, + }, + }, + appInstallation: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + appId: '', + teamId: '', + scopes: [], + authorizationDetails: [], + createdById: '', + createdByName: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -566,7 +672,7 @@ export class Teams extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -576,6 +682,26 @@ export class Teams extends Service { }, apiPayload, ); + const defaults = { + root: 'appInstallation', + models: { + appInstallation: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + appId: '', + teamId: '', + scopes: [], + authorizationDetails: [], + createdById: '', + createdByName: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -647,7 +773,7 @@ export class Teams extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -656,6 +782,26 @@ export class Teams extends Service { }, apiPayload, ); + const defaults = { + root: 'appInstallation', + models: { + appInstallation: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + appId: '', + teamId: '', + scopes: [], + authorizationDetails: [], + createdById: '', + createdByName: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -663,21 +809,21 @@ export class Teams extends Service { * * @param {string} params.teamId - Team ID. * @param {string} params.installationId - Installation unique ID. - * @param {string} params.authorizationDetails - Authorization details granted to the installation as a JSON array of objects, each with a `type` and app-defined fields. Omit to keep the current value. + * @param {string | null} params.authorizationDetails - Authorization details granted to the installation as a JSON array of objects, each with a `type` and app-defined fields. Omit to keep the current value. * @throws {AppwriteException} * @returns {Promise} */ updateInstallation(params: { teamId: string; installationId: string; - authorizationDetails?: string; + authorizationDetails?: string | null; }): Promise; /** * Update an app installation on a team. Only team members with the owner role can update installations. The installation's granted scopes are refreshed to the scopes the app currently requests; previously issued installation access tokens are revoked. * * @param {string} teamId - Team ID. * @param {string} installationId - Installation unique ID. - * @param {string} authorizationDetails - Authorization details granted to the installation as a JSON array of objects, each with a `type` and app-defined fields. Omit to keep the current value. + * @param {string | null} authorizationDetails - Authorization details granted to the installation as a JSON array of objects, each with a `type` and app-defined fields. Omit to keep the current value. * @throws {AppwriteException} * @returns {Promise} * @deprecated Use the object parameter style method for a better developer experience. @@ -685,22 +831,22 @@ export class Teams extends Service { updateInstallation( teamId: string, installationId: string, - authorizationDetails?: string, + authorizationDetails?: string | null, ): Promise; updateInstallation( paramsOrFirst: | { teamId: string; installationId: string; - authorizationDetails?: string; + authorizationDetails?: string | null; } | string, - ...rest: [string?, string?] + ...rest: [string?, (string | null)?] ): Promise { let params: { teamId: string; installationId: string; - authorizationDetails?: string; + authorizationDetails?: string | null; }; if ( @@ -711,13 +857,13 @@ export class Teams extends Service { params = (paramsOrFirst || {}) as { teamId: string; installationId: string; - authorizationDetails?: string; + authorizationDetails?: string | null; }; } else { params = { teamId: paramsOrFirst as string, installationId: rest[0] as string, - authorizationDetails: rest[1] as string, + authorizationDetails: rest[1] as string | null, }; } @@ -748,7 +894,7 @@ export class Teams extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'put', uri, { @@ -758,6 +904,26 @@ export class Teams extends Service { }, apiPayload, ); + const defaults = { + root: 'appInstallation', + models: { + appInstallation: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + appId: '', + teamId: '', + scopes: [], + authorizationDetails: [], + createdById: '', + createdByName: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -937,7 +1103,7 @@ export class Teams extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -946,6 +1112,43 @@ export class Teams extends Service { }, apiPayload, ); + const defaults = { + root: 'membershipList', + models: { + membershipList: { + defaults: { + total: 0, + memberships: [], + }, + properties: { + memberships: { + items: 'membership', + }, + }, + }, + membership: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + userId: '', + userName: '', + userEmail: '', + userPhone: '', + teamId: '', + teamName: '', + invited: '', + joined: '', + confirm: false, + mfa: false, + userAccessedAt: '', + roles: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -965,6 +1168,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 +1180,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 +1199,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 +1212,7 @@ export class Teams extends Service { phone?: string, url?: string, name?: string, + membershipId?: string, ): Promise; createMembership( paramsOrFirst: @@ -1017,9 +1224,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 +1245,7 @@ export class Teams extends Service { phone?: string; url?: string; name?: string; + membershipId?: string; }; if ( @@ -1044,6 +1261,7 @@ export class Teams extends Service { phone?: string; url?: string; name?: string; + membershipId?: string; }; } else { params = { @@ -1054,6 +1272,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 +1283,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,8 +1323,12 @@ export class Teams extends Service { apiPayload['name'] = name; } + if (typeof membershipId !== 'undefined') { + apiPayload['membershipId'] = membershipId; + } + const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -1114,6 +1338,32 @@ export class Teams extends Service { }, apiPayload, ); + const defaults = { + root: 'membership', + models: { + membership: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + userId: '', + userName: '', + userEmail: '', + userPhone: '', + teamId: '', + teamName: '', + invited: '', + joined: '', + confirm: false, + mfa: false, + userAccessedAt: '', + roles: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1185,7 +1435,7 @@ export class Teams extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -1194,6 +1444,32 @@ export class Teams extends Service { }, apiPayload, ); + const defaults = { + root: 'membership', + models: { + membership: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + userId: '', + userName: '', + userEmail: '', + userPhone: '', + teamId: '', + teamName: '', + invited: '', + joined: '', + confirm: false, + mfa: false, + userAccessedAt: '', + roles: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1283,7 +1559,7 @@ export class Teams extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'patch', uri, { @@ -1293,6 +1569,32 @@ export class Teams extends Service { }, apiPayload, ); + const defaults = { + root: 'membership', + models: { + membership: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + userId: '', + userName: '', + userEmail: '', + userPhone: '', + teamId: '', + teamName: '', + invited: '', + joined: '', + confirm: false, + mfa: false, + userAccessedAt: '', + roles: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1490,7 +1792,7 @@ export class Teams extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'patch', uri, { @@ -1500,6 +1802,32 @@ export class Teams extends Service { }, apiPayload, ); + const defaults = { + root: 'membership', + models: { + membership: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + userId: '', + userName: '', + userEmail: '', + userPhone: '', + teamId: '', + teamName: '', + invited: '', + joined: '', + confirm: false, + mfa: false, + userAccessedAt: '', + roles: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** diff --git a/src/services/vectors-db.ts b/src/services/vectors-db.ts index 710e8b44..61b4df27 100644 --- a/src/services/vectors-db.ts +++ b/src/services/vectors-db.ts @@ -1,5 +1,5 @@ import { Service } from '../service'; -import { AppwriteException, Client } from '../client'; +import { AppwriteException, Client, applyDefaults } from '../client'; import type { Models } from '../models'; import type { Payload } from '../client'; @@ -71,7 +71,7 @@ export class VectorsDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -80,6 +80,34 @@ export class VectorsDB extends Service { }, apiPayload, ); + const defaults = { + root: 'transactionList', + models: { + transactionList: { + defaults: { + total: 0, + transactions: [], + }, + properties: { + transactions: { + items: 'transaction', + }, + }, + }, + transaction: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + status: 'pending', + operations: 0, + expiresAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -127,7 +155,7 @@ export class VectorsDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -137,6 +165,23 @@ export class VectorsDB extends Service { }, apiPayload, ); + const defaults = { + root: 'transaction', + models: { + transaction: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + status: 'pending', + operations: 0, + expiresAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -190,7 +235,7 @@ export class VectorsDB extends Service { const apiPayload: Payload = {}; const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -199,6 +244,23 @@ export class VectorsDB extends Service { }, apiPayload, ); + const defaults = { + root: 'transaction', + models: { + transaction: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + status: 'pending', + operations: 0, + expiresAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -285,7 +347,7 @@ export class VectorsDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'patch', uri, { @@ -295,6 +357,23 @@ export class VectorsDB extends Service { }, apiPayload, ); + const defaults = { + root: 'transaction', + models: { + transaction: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + status: 'pending', + operations: 0, + expiresAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -427,7 +506,7 @@ export class VectorsDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -437,6 +516,23 @@ export class VectorsDB extends Service { }, apiPayload, ); + const defaults = { + root: 'transaction', + models: { + transaction: { + defaults: { + $id: '', + $createdAt: '', + $updatedAt: '', + status: 'pending', + operations: 0, + expiresAt: '', + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -573,7 +669,7 @@ export class VectorsDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -582,6 +678,35 @@ export class VectorsDB extends Service { }, apiPayload, ); + const defaults = { + root: 'documentList', + models: { + documentList: { + defaults: { + total: 0, + documents: [], + }, + properties: { + documents: { + items: 'document', + }, + }, + }, + document: { + defaults: { + $id: '', + $sequence: '', + $collectionId: '', + $databaseId: '', + $createdAt: '', + $updatedAt: '', + $permissions: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -753,7 +878,7 @@ export class VectorsDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -763,6 +888,24 @@ export class VectorsDB extends Service { }, apiPayload, ); + const defaults = { + root: 'document', + models: { + document: { + defaults: { + $id: '', + $sequence: '', + $collectionId: '', + $databaseId: '', + $createdAt: '', + $updatedAt: '', + $permissions: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -901,7 +1044,7 @@ export class VectorsDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'post', uri, { @@ -911,6 +1054,35 @@ export class VectorsDB extends Service { }, apiPayload, ); + const defaults = { + root: 'documentList', + models: { + documentList: { + defaults: { + total: 0, + documents: [], + }, + properties: { + documents: { + items: 'document', + }, + }, + }, + document: { + defaults: { + $id: '', + $sequence: '', + $collectionId: '', + $databaseId: '', + $createdAt: '', + $updatedAt: '', + $permissions: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1040,7 +1212,7 @@ export class VectorsDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'get', uri, { @@ -1049,6 +1221,24 @@ export class VectorsDB extends Service { }, apiPayload, ); + const defaults = { + root: 'document', + models: { + document: { + defaults: { + $id: '', + $sequence: '', + $collectionId: '', + $databaseId: '', + $createdAt: '', + $updatedAt: '', + $permissions: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1218,7 +1408,7 @@ export class VectorsDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'put', uri, { @@ -1228,6 +1418,24 @@ export class VectorsDB extends Service { }, apiPayload, ); + const defaults = { + root: 'document', + models: { + document: { + defaults: { + $id: '', + $sequence: '', + $collectionId: '', + $databaseId: '', + $createdAt: '', + $updatedAt: '', + $permissions: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** @@ -1397,7 +1605,7 @@ export class VectorsDB extends Service { } const uri = new URL(this.client.config.endpoint + apiPath); - return this.client.call( + const request = this.client.call( 'patch', uri, { @@ -1407,6 +1615,24 @@ export class VectorsDB extends Service { }, apiPayload, ); + const defaults = { + root: 'document', + models: { + document: { + defaults: { + $id: '', + $sequence: '', + $collectionId: '', + $databaseId: '', + $createdAt: '', + $updatedAt: '', + $permissions: [], + }, + }, + }, + }; + + return request.then((response) => applyDefaults(response, defaults)); } /** diff --git a/src/topic.ts b/src/topic.ts index cd6cea01..071d5aec 100644 --- a/src/topic.ts +++ b/src/topic.ts @@ -1,6 +1,6 @@ /** * Validate the levels passed to `path()`: a non-empty array of non-empty strings, none holding - * the level separator `/` or the wildcards `+` and `#` (use `any()` and `all()` for those). + * the level separator `/` or the MQTT wildcards `+` and `#`. */ function levelsOf(levels: unknown): string[] { if (!Array.isArray(levels)) { @@ -28,17 +28,14 @@ function levelsOf(levels: unknown): string[] { `"${level}" contains "/", split it: path([${parts}])`, ); } - if (level === '+') { - throw new Error('"+" is reserved, use any()'); - } if (level.includes('+')) { - throw new Error(`"${level}" contains "+", use any() for wildcards`); - } - if (level === '#') { - throw new Error('"#" is reserved, use all()'); + throw new Error(`"${level}" contains "+", not allowed in a topic`); } if (level.includes('#')) { - throw new Error(`"${level}" contains "#", use all() for wildcards`); + throw new Error(`"${level}" contains "#", not allowed in a topic`); + } + if (level.includes('\0')) { + throw new Error(`level at index ${index} contains a NUL character`); } return level; }); @@ -48,11 +45,7 @@ function levelsOf(levels: unknown): string[] { * Helper to build MQTT topics for `Push`, level by level. * * Topic.path(['user', userId, 'notification']); // "user/123/notification" - * Topic.path(['user']).any().path(['notification']); // "user/+/notification" - * Topic.path(['org']).any().path(['logs']).all(); // "org/+/logs/#" - * - * `any()` matches exactly one level and `all()` everything below, at any depth (including the - * parent itself). `all()` ends the topic, so it returns a {@link ResolvedTopic}. + * Topic.path(['org', orgId]).path(['logs']); // "org/42/logs" */ export class Topic { private constructor(private readonly levels: readonly string[]) {} @@ -62,41 +55,11 @@ export class Topic { return new Topic(levelsOf(levels)); } - /** Start a topic with a single-level wildcard (`+`). */ - static any(): Topic { - return new Topic(['+']); - } - - /** The multi-level wildcard alone (`#`): matches every topic. */ - static all(): ResolvedTopic { - return new ResolvedTopic(['#']); - } - /** Append the given levels. */ path(levels: string[]): Topic { return new Topic([...this.levels, ...levelsOf(levels)]); } - /** Append a single-level wildcard (`+`): matches exactly one level. */ - any(): Topic { - return new Topic([...this.levels, '+']); - } - - /** Append the multi-level wildcard (`#`) and end the topic. */ - all(): ResolvedTopic { - return new ResolvedTopic([...this.levels, '#']); - } - - toString(): string { - return this.levels.join('/'); - } -} - -/** A topic ended by `all()`: nothing can be appended after the `#` wildcard. */ -export class ResolvedTopic { - /** @internal Created by {@link Topic.all}. */ - constructor(private readonly levels: readonly string[]) {} - toString(): string { return this.levels.join('/'); }