diff --git a/CHANGELOG.md b/CHANGELOG.md index fe74f4a8..9a893dda 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Change log +## 0.25.0 + +* [BREAKING] Changed `$sequence` type from `int` to `string` for rows and documents + ## 0.24.1 * Fix very large double values (for example 1.7976931348623157e+308) from being expanded into giant integer literals. diff --git a/README.md b/README.md index 5452c01f..da4140d5 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-1.8.1-blue.svg?style=flat-square) +![Version](https://img.shields.io/badge/api%20version-1.9.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 is compatible with Appwrite server version latest. For older versions, please check [previous releases](https://github.com/appwrite/sdk-for-react-native/releases).** +**This SDK is compatible with Appwrite server version 1.9.x. For older versions, please check [previous releases](https://github.com/appwrite/sdk-for-react-native/releases).** Appwrite is an open-source backend as a service server that abstracts and simplifies complex and repetitive development tasks behind a very simple to use REST API. Appwrite aims to help you develop your apps faster and in a more secure way. Use the React Native SDK to integrate your app with the Appwrite server to easily start interacting with all of Appwrite backend APIs and tools. For full API documentation and tutorials go to [https://appwrite.io/docs](https://appwrite.io/docs) diff --git a/docs/examples/databases/upsert-documents.md b/docs/examples/databases/upsert-documents.md new file mode 100644 index 00000000..8a3b45a6 --- /dev/null +++ b/docs/examples/databases/upsert-documents.md @@ -0,0 +1,18 @@ +```javascript +import { Client, Databases } from "react-native-appwrite"; + +const client = new Client() + .setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint + .setProject(''); // Your project ID + +const databases = new Databases(client); + +const result = await databases.upsertDocuments({ + databaseId: '', + collectionId: '', + documents: [], + transactionId: '' // optional +}); + +console.log(result); +``` diff --git a/package.json b/package.json index 53463dbc..4545f282 100644 --- a/package.json +++ b/package.json @@ -25,13 +25,13 @@ "build:libs": "rollup -c" }, "devDependencies": { - "@rollup/plugin-typescript": "8.3.2", + "@rollup/plugin-typescript": "11.1.6", "@types/json-bigint": "1.0.4", "playwright": "1.56.1", - "rollup": "2.75.4", + "rollup": "3.29.5", "serve-handler": "6.1.0", - "tslib": "2.4.0", - "typescript": "^5.3.3" + "tslib": "2.8.1", + "typescript": "5.7.3" }, "dependencies": { "expo-file-system": "18.*.*", diff --git a/rollup.config.js b/rollup.config.js index cfcba7da..f01c4a64 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -1,4 +1,5 @@ -import pkg from "./package.json"; +import { readFileSync } from "fs"; +const pkg = JSON.parse(readFileSync("./package.json", "utf8")); import typescript from "@rollup/plugin-typescript"; const external = Object.keys(pkg.dependencies ?? {}); diff --git a/src/client.ts b/src/client.ts index d6bfc9fe..e14516de 100644 --- a/src/client.ts +++ b/src/client.ts @@ -152,6 +152,9 @@ class Client { locale: '', session: '', devkey: '', + impersonateuserid: '', + impersonateuseremail: '', + impersonateuserphone: '', platform: '', }; headers: Headers = { @@ -159,7 +162,7 @@ class Client { 'x-sdk-platform': 'client', 'x-sdk-language': 'reactnative', 'x-sdk-version': '0.25.0', - 'X-Appwrite-Response-Format': '1.8.0', + 'X-Appwrite-Response-Format': '1.9.0', }; /** @@ -293,6 +296,69 @@ class Client { return this; } + /** + * Set ImpersonateUserId + * + * Impersonate a user by ID on an already user-authenticated request. Requires + * the current request to be authenticated as a user with impersonator + * capability; X-Appwrite-Key alone is not sufficient. Impersonator users are + * intentionally granted users.read so they can discover a target before + * impersonation begins. Internal audit logs still attribute actions to the + * original impersonator and record the impersonated target only in internal + * audit payload data. + * + * @param value string + * + * @return {this} + */ + setImpersonateUserId(value: string): this { + this.headers['X-Appwrite-Impersonate-User-Id'] = value; + this.config.impersonateuserid = value; + return this; + } + + /** + * Set ImpersonateUserEmail + * + * Impersonate a user by email on an already user-authenticated request. + * Requires the current request to be authenticated as a user with + * impersonator capability; X-Appwrite-Key alone is not sufficient. + * Impersonator users are intentionally granted users.read so they can + * discover a target before impersonation begins. Internal audit logs still + * attribute actions to the original impersonator and record the impersonated + * target only in internal audit payload data. + * + * @param value string + * + * @return {this} + */ + setImpersonateUserEmail(value: string): this { + this.headers['X-Appwrite-Impersonate-User-Email'] = value; + this.config.impersonateuseremail = value; + return this; + } + + /** + * Set ImpersonateUserPhone + * + * Impersonate a user by phone on an already user-authenticated request. + * Requires the current request to be authenticated as a user with + * impersonator capability; X-Appwrite-Key alone is not sufficient. + * Impersonator users are intentionally granted users.read so they can + * discover a target before impersonation begins. Internal audit logs still + * attribute actions to the original impersonator and record the impersonated + * target only in internal audit payload data. + * + * @param value string + * + * @return {this} + */ + setImpersonateUserPhone(value: string): this { + this.headers['X-Appwrite-Impersonate-User-Phone'] = value; + this.config.impersonateuserphone = value; + return this; + } + private realtime: Realtime = { socket: undefined, @@ -588,6 +654,10 @@ class Client { window.localStorage.setItem('cookieFallback', cookieFallback); } + if (data && typeof data === 'object') { + data.toString = () => JSONbig.stringify(data); + } + return data; } catch (e) { if (e instanceof AppwriteException) { diff --git a/src/models.ts b/src/models.ts index 06c8d712..dc2e4ff7 100644 --- a/src/models.ts +++ b/src/models.ts @@ -240,7 +240,7 @@ export namespace Models { /** * Row sequence ID. */ - $sequence: number; + $sequence: string; /** * Table ID. */ @@ -279,7 +279,7 @@ export namespace Models { /** * Document sequence ID. */ - $sequence: number; + $sequence: string; /** * Collection ID. */ @@ -316,15 +316,15 @@ export namespace Models { */ event: string; /** - * User ID. + * User ID of the actor recorded for this log. During impersonation, this is the original impersonator, not the impersonated target user. */ userId: string; /** - * User Email. + * User email of the actor recorded for this log. During impersonation, this is the original impersonator. */ userEmail: string; /** - * User Name. + * User name of the actor recorded for this log. During impersonation, this is the original impersonator. */ userName: string; /** @@ -477,6 +477,14 @@ export namespace Models { * Most recent access date in ISO 8601 format. This attribute is only updated again after 24 hours. */ accessedAt: string; + /** + * Whether the user can impersonate other users. + */ + impersonator?: boolean; + /** + * ID of the original actor performing the impersonation. Present only when the current request is impersonating another user. Internal audit logs attribute the action to this user, while the impersonated target is recorded only in internal audit payload data. + */ + impersonatorUserId?: string; } /** diff --git a/src/services/databases.ts b/src/services/databases.ts index 92bae343..39edb06b 100644 --- a/src/services/databases.ts +++ b/src/services/databases.ts @@ -488,6 +488,83 @@ export class Databases extends Service { }, payload); } + /** + * Create or update Documents. 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. + * + * + * @param {string} params.databaseId - Database ID. + * @param {string} params.collectionId - Collection ID. + * @param {object[]} params.documents - Array of document data as JSON objects. May contain partial documents. + * @param {string} 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.upsertRows` instead. + */ + upsertDocuments(params: { databaseId: string, collectionId: string, documents: object[], transactionId?: string }): Promise>; + /** + * Create or update Documents. 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. + * + * + * @param {string} databaseId - Database ID. + * @param {string} collectionId - Collection ID. + * @param {object[]} documents - Array of document data as JSON objects. May contain partial documents. + * @param {string} transactionId - Transaction ID for staging the operation. + * @throws {AppwriteException} + * @returns {Promise>} + * @deprecated Use the object parameter style method for a better developer experience. + */ + upsertDocuments(databaseId: string, collectionId: string, documents: object[], transactionId?: string): Promise>; + upsertDocuments( + paramsOrFirst: { databaseId: string, collectionId: string, documents: object[], transactionId?: string } | string, + ...rest: [(string)?, (object[])?, (string)?] + ): Promise> { + let params: { databaseId: string, collectionId: string, documents: object[], transactionId?: string }; + + if ((paramsOrFirst && typeof paramsOrFirst === 'object' && !Array.isArray(paramsOrFirst))) { + params = (paramsOrFirst || {}) as { databaseId: string, collectionId: string, documents: object[], transactionId?: string }; + } else { + params = { + databaseId: paramsOrFirst as string, + collectionId: rest[0] as string, + documents: rest[1] as object[], + transactionId: rest[2] as string + }; + } + + const databaseId = params.databaseId; + const collectionId = params.collectionId; + const documents = params.documents; + const transactionId = params.transactionId; + + if (typeof databaseId === 'undefined') { + throw new AppwriteException('Missing required parameter: "databaseId"'); + } + + if (typeof collectionId === 'undefined') { + throw new AppwriteException('Missing required parameter: "collectionId"'); + } + + if (typeof documents === 'undefined') { + throw new AppwriteException('Missing required parameter: "documents"'); + } + + const apiPath = '/databases/{databaseId}/collections/{collectionId}/documents'.replace('{databaseId}', databaseId).replace('{collectionId}', collectionId); + const payload: Payload = {}; + + if (typeof documents !== 'undefined') { + payload['documents'] = documents; + } + + if (typeof transactionId !== 'undefined') { + payload['transactionId'] = transactionId; + } + + const uri = new URL(this.client.config.endpoint + apiPath); + return this.client.call('put', uri, { + 'content-type': 'application/json', + }, payload); + } + /** * Get a document by its unique ID. This endpoint response returns a JSON object with the document data. *