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('/'); }