diff --git a/LICENSE b/LICENSE index 5479bb8e..c1602fcd 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2024 Appwrite (https://appwrite.io) and individual contributors. +Copyright (c) 2025 Appwrite (https://appwrite.io) and individual contributors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/README.md b/README.md index 805d7372..66d8ec22 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # 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-1.6.0-blue.svg?style=flat-square) +![Version](https://img.shields.io/badge/api%20version-1.6.1-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) diff --git a/package.json b/package.json index 72e8ca1d..d1df893b 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 abstract and simplify complex and repetitive development tasks behind a very simple REST API", - "version": "0.5.0", + "version": "0.7.0", "license": "BSD-3-Clause", "main": "dist/cjs/sdk.js", "exports": { diff --git a/src/client.ts b/src/client.ts index 27f67635..66e57aa9 100644 --- a/src/client.ts +++ b/src/client.ts @@ -11,8 +11,8 @@ type Headers = { } type RealtimeResponse = { - type: 'error' | 'event' | 'connected' | 'response'; - data: RealtimeResponseAuthenticated | RealtimeResponseConnected | RealtimeResponseError | RealtimeResponseEvent; + type: 'error' | 'event' | 'connected' | 'response' | 'pong'; + data: RealtimeResponseAuthenticated | RealtimeResponseConnected | RealtimeResponseError | RealtimeResponseEvent | undefined; } type RealtimeRequest = { @@ -49,7 +49,17 @@ type RealtimeRequestAuthenticate = { type Realtime = { socket?: WebSocket; + + /** + * Timeout for reconnect operations. + */ timeout?: number; + + /** + * Heartbeat interval for the realtime connection. + */ + heartbeat?: number; + url?: string; lastMessage?: RealtimeResponse; channels: Set; @@ -63,6 +73,7 @@ type Realtime = { getTimeout: () => number; connect: () => void; createSocket: () => void; + createHeartbeat: () => void; cleanUp: (channels: string[]) => void; onMessage: (event: MessageEvent) => void; } @@ -103,7 +114,7 @@ class Client { 'x-sdk-name': 'React Native', 'x-sdk-platform': 'client', 'x-sdk-language': 'reactnative', - 'x-sdk-version': '0.5.0', + 'x-sdk-version': '0.7.0', 'X-Appwrite-Response-Format': '1.6.0', }; @@ -212,6 +223,7 @@ class Client { private realtime: Realtime = { socket: undefined, timeout: undefined, + heartbeat: undefined, url: '', channels: new Set(), subscriptions: new Map(), @@ -237,6 +249,17 @@ class Client { return 60_000; } }, + createHeartbeat: () => { + if (this.realtime.heartbeat) { + clearTimeout(this.realtime.heartbeat); + } + + this.realtime.heartbeat = window?.setInterval(() => { + this.realtime.socket?.send(JSON.stringify({ + type: 'ping' + })); + }, 20_000); + }, createSocket: () => { if (this.realtime.channels.size < 1) { this.realtime.reconnect = false; @@ -275,6 +298,7 @@ class Client { this.realtime.socket.addEventListener('message', this.realtime.onMessage); this.realtime.socket.addEventListener('open', _event => { this.realtime.reconnectAttempts = 0; + this.realtime.createHeartbeat(); }); this.realtime.socket.addEventListener('close', event => { if ( @@ -315,6 +339,8 @@ class Client { }) } break; + case 'pong': + break; // Handle pong response if needed case 'error': throw message.data; default: diff --git a/src/enums/image-format.ts b/src/enums/image-format.ts index 7e96fd8c..bcbe3e93 100644 --- a/src/enums/image-format.ts +++ b/src/enums/image-format.ts @@ -4,4 +4,6 @@ export enum ImageFormat { Gif = 'gif', Png = 'png', Webp = 'webp', + Heic = 'heic', + Avif = 'avif', } \ No newline at end of file diff --git a/src/models.ts b/src/models.ts index 874d37a0..02394388 100644 --- a/src/models.ts +++ b/src/models.ts @@ -839,11 +839,11 @@ export namespace Models { */ userId: string; /** - * User name. + * User name. Hide this attribute by toggling membership privacy in the Console. */ userName: string; /** - * User email address. + * User email address. Hide this attribute by toggling membership privacy in the Console. */ userEmail: string; /** @@ -867,7 +867,7 @@ export namespace Models { */ confirm: boolean; /** - * Multi factor authentication status, true if the user has MFA enabled or false otherwise. + * Multi factor authentication status, true if the user has MFA enabled or false otherwise. Hide this attribute by toggling membership privacy in the Console. */ mfa: boolean; /** @@ -1195,5 +1195,9 @@ export namespace Models { * The target identifier. */ identifier: string; + /** + * Is the target expired. + */ + expired: boolean; } } diff --git a/src/services/account.ts b/src/services/account.ts index b9e315d8..14740891 100644 --- a/src/services/account.ts +++ b/src/services/account.ts @@ -134,7 +134,7 @@ export class Account extends Service { } /** - * List Identities + * List identities * * Get the list of identities for the currently logged in user. * @@ -253,7 +253,7 @@ export class Account extends Service { } /** - * Create Authenticator + * Create authenticator * * Add an authenticator app to be used as an MFA factor. Verify the * authenticator using the [verify @@ -279,7 +279,7 @@ export class Account extends Service { } /** - * Verify Authenticator + * Verify authenticator * * Verify an authenticator app after adding it using the [add * authenticator](/docs/references/cloud/client-web/account#createMfaAuthenticator) @@ -313,7 +313,7 @@ export class Account extends Service { } /** - * Delete Authenticator + * Delete authenticator * * Delete an authenticator for a user by ID. * @@ -336,7 +336,7 @@ export class Account extends Service { } /** - * Create MFA Challenge + * Create MFA challenge * * Begin the process of MFA verification after sign-in. Finish the flow with * [updateMfaChallenge](/docs/references/cloud/client-web/account#updateMfaChallenge) @@ -365,7 +365,7 @@ export class Account extends Service { } /** - * Create MFA Challenge (confirmation) + * Create MFA challenge (confirmation) * * Complete the MFA challenge by providing the one-time password. Finish the * process of MFA verification by providing the one-time password. To begin @@ -378,7 +378,7 @@ export class Account extends Service { * @throws {AppwriteException} * @returns {Promise} */ - async updateMfaChallenge(challengeId: string, otp: string): Promise<{}> { + async updateMfaChallenge(challengeId: string, otp: string): Promise { if (typeof challengeId === 'undefined') { throw new AppwriteException('Missing required parameter: "challengeId"'); } @@ -405,7 +405,7 @@ export class Account extends Service { } /** - * List Factors + * List factors * * List the factors available on the account to be used as a MFA challange. * @@ -423,7 +423,7 @@ export class Account extends Service { } /** - * Get MFA Recovery Codes + * Get MFA recovery codes * * Get recovery codes that can be used as backup for MFA flow. Before getting * codes, they must be generated using @@ -444,7 +444,7 @@ export class Account extends Service { } /** - * Create MFA Recovery Codes + * Create MFA recovery codes * * Generate recovery codes as backup for MFA flow. It's recommended to * generate and show then immediately after user successfully adds their @@ -466,7 +466,7 @@ export class Account extends Service { } /** - * Regenerate MFA Recovery Codes + * Regenerate MFA recovery codes * * Regenerate recovery codes that can be used as backup for MFA flow. Before * regenerating codes, they must be first generated using @@ -1104,6 +1104,11 @@ export class Account extends Service { /** * Create push target * + * Use this endpoint to register a device for push notifications. Provide a + * target ID (custom or generated using ID.unique()), a device identifier + * (usually a device token), and optionally specify which provider should send + * notifications to this target. The target is automatically linked to the + * current session and includes device information like brand and model. * * @param {string} targetId * @param {string} identifier @@ -1144,6 +1149,11 @@ export class Account extends Service { /** * Update push target * + * Update the currently logged in user's push notification target. You can + * modify the target's identifier (device token) and provider ID (token, + * email, phone etc.). The target must exist and belong to the current user. + * If you change the provider ID, notifications will be sent through the new + * messaging provider instead. * * @param {string} targetId * @param {string} identifier @@ -1175,6 +1185,9 @@ export class Account extends Service { /** * Delete push target * + * Delete a push notification target for the currently logged in user. After + * deletion, the device will no longer receive push notifications. The target + * must exist and belong to the current user. * * @param {string} targetId * @throws {AppwriteException} @@ -1255,9 +1268,7 @@ export class Account extends Service { * [POST * /v1/account/sessions/token](https://appwrite.io/docs/references/cloud/client-web/account#createSession) * endpoint to complete the login process. The link sent to the user's email - * address is valid for 1 hour. If you are on a mobile device you can leave - * the URL parameter empty, so that the login completion will be handled by - * your Appwrite instance by default. + * address is valid for 1 hour. * * A user is limited to 10 active sessions at a time by default. [Learn more * about session diff --git a/src/services/locale.ts b/src/services/locale.ts index de62cfb7..7850948d 100644 --- a/src/services/locale.ts +++ b/src/services/locale.ts @@ -37,7 +37,7 @@ export class Locale extends Service { } /** - * List Locale Codes + * List locale codes * * List of all locale codes in [ISO * 639-1](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes). diff --git a/src/services/storage.ts b/src/services/storage.ts index 1f1ebd42..6661387b 100644 --- a/src/services/storage.ts +++ b/src/services/storage.ts @@ -122,12 +122,10 @@ export class Storage extends Service { let offset = 0; let response = undefined; - if(fileId != 'unique()') { - try { - response = await this.client.call('GET', new URL(this.client.config.endpoint + apiPath + '/' + fileId), apiHeaders); - offset = response.chunksUploaded * Service.CHUNK_SIZE; - } catch(e) { - } + try { + response = await this.client.call('GET', new URL(this.client.config.endpoint + apiPath + '/' + fileId), apiHeaders); + offset = response.chunksUploaded * Service.CHUNK_SIZE; + } catch(e) { } let timestamp = new Date().getTime(); @@ -237,7 +235,7 @@ export class Storage extends Service { } /** - * Delete File + * Delete file * * Delete a file by its unique ID. Only users with write permissions have * access to delete this resource. diff --git a/src/services/teams.ts b/src/services/teams.ts index 88a71eca..61917206 100644 --- a/src/services/teams.ts +++ b/src/services/teams.ts @@ -168,7 +168,8 @@ export class Teams extends Service { * List team memberships * * Use this endpoint to list a team's members using the team's ID. All team - * members have read access to this endpoint. + * members have read access to this endpoint. Hide sensitive attributes from + * the response by toggling membership privacy in the Console. * * @param {string} teamId * @param {string[]} queries @@ -279,7 +280,8 @@ export class Teams extends Service { * Get team membership * * Get a team member by the membership unique id. All team members have read - * access for this resource. + * access for this resource. Hide sensitive attributes from the response by + * toggling membership privacy in the Console. * * @param {string} teamId * @param {string} membershipId