feat: React Native SDK update for version 0.24.2#94
Conversation
* Updated API version badge to `1.9.0` * Updated compatibility note to Appwrite server version `1.8.x` * Added new documentation examples for `DocumentsDB` and `VectorsDB`
WalkthroughThis pull request adds two new service classes, Estimated code review effort🎯 4 (Complex) | ⏱️ ~50 minutes 🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Greptile SummaryThis PR updates the React Native SDK to version 0.24.2, adding two new services (
Confidence Score: 2/5
Important Files Changed
Reviews (1): Last reviewed commit: "feat: update React Native SDK to 0.24.2" | Re-trigger Greptile |
| "age": 30, | ||
| "isAdmin": false | ||
| }, | ||
| permissions: ["read("any")"] // optional |
There was a problem hiding this comment.
Invalid JavaScript string syntax for permissions
The permission string "read("any")" uses double quotes inside a double-quoted string, which produces invalid JavaScript. The inner double quotes terminate the outer string literal early, resulting in a syntax error when this example is copied and run.
The same issue appears in the following files as well:
docs/examples/documentsdb/update-document.md:15docs/examples/documentsdb/upsert-document.md:15docs/examples/vectorsdb/create-document.md:25docs/examples/vectorsdb/update-document.md:15docs/examples/vectorsdb/upsert-document.md:15
Since Permission and Role are already imported in these examples, the recommended fix is to use the helper:
| permissions: ["read("any")"] // optional | |
| permissions: [Permission.read(Role.any())] // optional |
| import * as FileSystem from 'expo-file-system'; | ||
| import { Platform } from 'react-native'; |
There was a problem hiding this comment.
Unused imports:
FileSystem and Platform
FileSystem (from expo-file-system) and Platform (from react-native) are imported but never used in this service. Neither DocumentsDB nor VectorsDB (src/services/vectors-db.ts:5-6) perform any file I/O or platform-branching operations — these appear to be copy-paste artifacts from another service file. Leaving unused imports increases bundle size unnecessarily.
| import * as FileSystem from 'expo-file-system'; | |
| import { Platform } from 'react-native'; | |
| import { Service } from '../service'; | |
| import { AppwriteException, Client } from '../client'; | |
| import type { Models } from '../models'; | |
| import type { UploadProgress, Payload } from '../client'; |
|
|
||
| if (!paramsOrFirst || (paramsOrFirst && typeof paramsOrFirst === 'object' && !Array.isArray(paramsOrFirst))) { | ||
| params = (paramsOrFirst || {}) as { ttl?: number }; | ||
| } else { | ||
| params = { |
There was a problem hiding this comment.
Falsy
ttl=0 lost in overload dispatch
The condition !paramsOrFirst evaluates to true when ttl is 0 (since 0 is falsy in JavaScript). This causes the deprecated positional-argument overload createTransaction(0) to be incorrectly treated as the object-style call, and params is set to {}, silently discarding the ttl value.
The same bug exists in src/services/vectors-db.ts in its createTransaction implementation.
A safe guard would be:
| if (!paramsOrFirst || (paramsOrFirst && typeof paramsOrFirst === 'object' && !Array.isArray(paramsOrFirst))) { | |
| params = (paramsOrFirst || {}) as { ttl?: number }; | |
| } else { | |
| params = { | |
| if (paramsOrFirst === undefined || paramsOrFirst === null || (typeof paramsOrFirst === 'object' && !Array.isArray(paramsOrFirst))) { | |
| params = (paramsOrFirst || {}) as { ttl?: number }; | |
| } else { | |
| params = { | |
| ttl: paramsOrFirst as number | |
| }; | |
| } |
| "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": "0.25.0", | ||
| "version": "0.24.2", |
There was a problem hiding this comment.
Version downgraded from
0.25.0 to 0.24.2
The package version is being changed from 0.25.0 (the previously published version) back to 0.24.2. Downgrading a published npm package version causes npm install / yarn add to be unable to upgrade existing users automatically, and breaks semver range resolution for consumers that already have ^0.25.0 or >=0.25.0 pinned. Was this intentional, or should this be a new patch/minor bump (e.g. 0.24.2 → 0.25.1 or 0.26.0)?
|  | ||
| [](https://travis-ci.com/appwrite/sdk-generator) | ||
| [](https://twitter.com/appwrite) | ||
| [](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.8.x. For older versions, please check [previous releases](https://github.com/appwrite/sdk-for-react-native/releases).** | ||
|
|
There was a problem hiding this comment.
API version badge and compatibility note are inconsistent
The badge was updated to api%20version-1.9.0, but the compatibility line now reads "compatible with Appwrite server version 1.8.x". These two statements contradict each other — users targeting server version 1.8.x would expect the API version badge to reflect that same line. Please align both to the intended target version (either 1.8.x or 1.9.x).
There was a problem hiding this comment.
Actionable comments posted: 12
🧹 Nitpick comments (2)
docs/examples/documentsdb/create-documents.md (1)
10-13: Show a minimal document in the example instead of an empty array.On line 13,
documents: []will fail when copied as-is. Provide one sample document object so the snippet is runnable and demonstrates the expected payload format.const result = await documentsDB.createDocuments({ databaseId: '<DATABASE_ID>', collectionId: '<COLLECTION_ID>', documents: []🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@docs/examples/documentsdb/create-documents.md` around lines 10 - 13, The example call to documentsDB.createDocuments uses an empty documents array which will fail; replace documents: [] with a minimal sample document object to show the expected payload shape and make the snippet runnable (update the documents array passed to the documentsDB.createDocuments call to include one object with required fields such as id, content/text or metadata as used by the API so callers can copy-paste and see the correct format).src/services/documents-db.ts (1)
478-533: KeepcreateDocumentsgeneric on the input side too.
documents: object[]throws away theDocumentgeneric, so callers lose autocomplete and can pass shapes that the single-document overload would catch at compile time. Reusing thecreateDocumentinput shape for each array element would keep the new bulk API type-safe.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/services/documents-db.ts` around lines 478 - 533, The createDocuments overloads and implementation use documents: object[] which discards the Document generic; update all signatures and the params type in createDocuments<Document extends Models.Document = Models.DefaultDocument> to accept documents: Document[] (and in the params object use documents: Document[]), update the rest tuple typing accordingly, and ensure the local const documents is typed as Document[] so the payload assignment payload['documents'] = documents preserves the generic shape and enables proper autocomplete/type checking; modify both the deprecated-style overload and the implementation parameter typing for createDocuments to reference Document[] instead of object[].
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@docs/examples/documentsdb/create-document.md`:
- Line 21: The permissions syntax is invalid; replace the incorrect permissions
entry (permissions: ["read("any")"]) with the Appwrite API call using
Permission.read and Role, e.g., use Permission.read(Role.any()) so the
permissions array contains the proper Permission.read(Role.any()) expression
instead of the nested-quoted string; update the permissions value where it is
set in the document creation example.
In `@docs/examples/documentsdb/update-document.md`:
- Line 15: The permissions string contains unescaped inner quotes and will cause
a parse error; update the permissions entry (the permissions property) to a
valid expression—preferably use the helper classes Permission and Role by
replacing permissions: ["read("any")"] with permissions:
[Permission.read(Role.any())]; alternatively escape inner quotes (permissions:
["read(\"any\")"]) or switch to single outer quotes (permissions:
['read("any")']) so the code parses correctly.
In `@docs/examples/documentsdb/update-transaction.md`:
- Around line 10-14: The example for documentsDB.updateTransaction currently
passes both commit and rollback flags which are mutually exclusive; update the
sample call to pass only one of the flags (either commit or rollback) alongside
the transactionId in the documentsDB.updateTransaction invocation so the example
demonstrates proper usage (e.g., show one example with commit: true and remove
the rollback flag OR show one example with rollback: true and remove the commit
flag).
In `@docs/examples/documentsdb/upsert-document.md`:
- Line 15: The permissions array uses invalid nested quoting ("read("any")");
replace the broken string with a proper Appwrite Permission/Role construct by
using the Permission and Role helpers (referenced as Permission and Role) to
build the permission entry for the permissions field (i.e., use Permission.read
with Role.any rather than a raw quoted string) so the permissions property is
valid JavaScript and follows Appwrite's Permission/Role API.
In `@docs/examples/vectorsdb/create-document.md`:
- Line 25: The examples use an invalid string literal permissions:
["read("any")"] which causes a syntax error; locate occurrences of the
permissions key in the examples (the literal ["read("any")"]) and replace them
with the proper helper invocation (e.g., permissions: [read("any")] or
permissions: [permissionsHelper.read("any")] depending on the examples' helper
import), ensuring the helper is imported/available in each file; apply this fix
across all example docs that contain the invalid string.
In `@docs/examples/vectorsdb/update-document.md`:
- Line 15: The permissions array contains a malformed string literal causing a
JS parse error; update the permissions usage in the example to a valid
form—preferably use the helper classes Permission and Role (e.g., set the
permissions value using Permission.read(Role.any()) referencing the Permission
and Role imports), or alternatively escape the inner quotes or switch to
single-quoted outer string to produce a valid string for the permissions array;
change the permissions: ["read("any")"] line accordingly.
In `@docs/examples/vectorsdb/update-transaction.md`:
- Around line 10-14: The example for vectorsDB.updateTransaction is misleading
because it shows both commit and rollback together; updateTransaction
(vectorsDB.updateTransaction) requires exactly one mutually exclusive action.
Update the snippet so it only includes transactionId and a single action (either
commit: true or rollback: true) — for example keep transactionId and set commit:
true (or alternatively show a second example that uses rollback: true) and
remove the dual commit/rollback variant.
In `@docs/examples/vectorsdb/upsert-document.md`:
- Line 15: The snippet uses an invalid literal permissions: ["read("any")"]
which contains unescaped nested quotes; replace that literal with a call that
constructs the permission correctly—use Permission.read(Role.any()) (or
Permission.read('any')) where Permission.read and Role.any are referenced in the
file so the generated permission string becomes read("any") without syntax
errors.
In `@package.json`:
- Line 5: The package.json "version" field was rolled back to "0.24.2" but
"0.25.0" is already published; update the package.json "version" property (the
version key) to either "0.25.0" to match the published latest or bump to a
higher semver like "0.26.0" (or greater) before publishing so npm won’t reject
the publish due to a lower version.
In `@src/client.ts`:
- Around line 314-359: When setting an impersonation selector in
setImpersonateUserId, setImpersonateUserEmail, or setImpersonateUserPhone, clear
the other impersonation headers and config fields so only the newly-set selector
remains active: remove the other 'X-Appwrite-Impersonate-User-Id|Email|Phone'
keys from this.headers and unset the corresponding
this.config.impersonateuserid|impersonateuseremail|impersonateuserphone fields
before assigning the new value in the respective method (refer to the three
setter methods by name to locate the changes).
- Around line 164-165: The response format header in src/client.ts is set to
'X-Appwrite-Response-Format': '1.9.0', which is incompatible with Appwrite
1.8.x; update the header value to '1.8.0' (modify the header literal for
'X-Appwrite-Response-Format' in the client HTTP headers/config block—the
constant or object where 'x-sdk-version' and 'X-Appwrite-Response-Format' are
defined) so the client advertises 1.8.0 and matches the server compatibility.
- Around line 657-659: The code currently mutates response objects by assigning
an enumerable toString property via "data.toString = () =>
JSONbig.stringify(data)" which pollutes enumeration and can overwrite an
existing toString; instead, before adding a method, check if
Object.prototype.hasOwnProperty.call(data, 'toString') is false (or typeof
data.toString !== 'function'), and then add the method with
Object.defineProperty(data, 'toString', { value: () => JSONbig.stringify(data),
writable: true, configurable: true, enumerable: false }); this keeps the custom
toString non-enumerable and preserves any existing toString from the server.
---
Nitpick comments:
In `@docs/examples/documentsdb/create-documents.md`:
- Around line 10-13: The example call to documentsDB.createDocuments uses an
empty documents array which will fail; replace documents: [] with a minimal
sample document object to show the expected payload shape and make the snippet
runnable (update the documents array passed to the documentsDB.createDocuments
call to include one object with required fields such as id, content/text or
metadata as used by the API so callers can copy-paste and see the correct
format).
In `@src/services/documents-db.ts`:
- Around line 478-533: The createDocuments overloads and implementation use
documents: object[] which discards the Document generic; update all signatures
and the params type in createDocuments<Document extends Models.Document =
Models.DefaultDocument> to accept documents: Document[] (and in the params
object use documents: Document[]), update the rest tuple typing accordingly, and
ensure the local const documents is typed as Document[] so the payload
assignment payload['documents'] = documents preserves the generic shape and
enables proper autocomplete/type checking; modify both the deprecated-style
overload and the implementation parameter typing for createDocuments to
reference Document[] instead of object[].
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 0ba8ee17-88bc-4ef8-95dd-cd279e0100f5
📒 Files selected for processing (37)
README.mddocs/examples/databases/upsert-documents.mddocs/examples/documentsdb/create-document.mddocs/examples/documentsdb/create-documents.mddocs/examples/documentsdb/create-operations.mddocs/examples/documentsdb/create-transaction.mddocs/examples/documentsdb/decrement-document-attribute.mddocs/examples/documentsdb/delete-document.mddocs/examples/documentsdb/delete-transaction.mddocs/examples/documentsdb/get-document.mddocs/examples/documentsdb/get-transaction.mddocs/examples/documentsdb/increment-document-attribute.mddocs/examples/documentsdb/list-documents.mddocs/examples/documentsdb/list-transactions.mddocs/examples/documentsdb/update-document.mddocs/examples/documentsdb/update-transaction.mddocs/examples/documentsdb/upsert-document.mddocs/examples/vectorsdb/create-document.mddocs/examples/vectorsdb/create-operations.mddocs/examples/vectorsdb/create-transaction.mddocs/examples/vectorsdb/delete-document.mddocs/examples/vectorsdb/delete-transaction.mddocs/examples/vectorsdb/get-document.mddocs/examples/vectorsdb/get-transaction.mddocs/examples/vectorsdb/list-documents.mddocs/examples/vectorsdb/list-transactions.mddocs/examples/vectorsdb/update-document.mddocs/examples/vectorsdb/update-transaction.mddocs/examples/vectorsdb/upsert-document.mdpackage.jsonrollup.config.jssrc/client.tssrc/index.tssrc/models.tssrc/services/databases.tssrc/services/documents-db.tssrc/services/vectors-db.ts
| "age": 30, | ||
| "isAdmin": false | ||
| }, | ||
| permissions: ["read("any")"] // optional |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
cat -n docs/examples/documentsdb/create-document.md | head -30Repository: appwrite/sdk-for-react-native
Length of output: 966
🌐 Web query:
Appwrite Permission Role read() method syntax JavaScript
💡 Result:
The syntax for Appwrite's Permission.read method in JavaScript is Permission.read(role), where role is an instance from the Role class, such as Role.any, Role.user('user-id'), Role.users, or Role.team('team-id'). Example usage when creating a document: import { Client, Databases, Permission, Role, ID } from 'node-appwrite' || 'appwrite'; const client = new Client.setEndpoint('https://cloud.appwrite.io/v1').setProject('project-id'); const databases = new Databases(client); const result = await databases.createDocument( 'database-id', 'collection-id', ID.unique, { key: 'value' }, [ Permission.read(Role.any), // Anyone can read Permission.read(Role.user('user-id')), // Specific user can read Permission.update(Role.team('team-id')), // Team can update ] ); This grants read access to the specified role(s). Permissions are combined in an array for create/updateDocument methods. Server SDKs bypass permissions checks.
Citations:
Correct the permissions syntax to use valid Appwrite API.
Line 21 has invalid nested quotes that won't parse. The correct Appwrite syntax uses Permission.read() with a Role property, not a method call.
Proposed fix
- permissions: ["read("any")"] // optional
+ permissions: [Permission.read(Role.any)] // optional📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| permissions: ["read("any")"] // optional | |
| permissions: [Permission.read(Role.any)] // optional |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@docs/examples/documentsdb/create-document.md` at line 21, The permissions
syntax is invalid; replace the incorrect permissions entry (permissions:
["read("any")"]) with the Appwrite API call using Permission.read and Role,
e.g., use Permission.read(Role.any()) so the permissions array contains the
proper Permission.read(Role.any()) expression instead of the nested-quoted
string; update the permissions value where it is set in the document creation
example.
| collectionId: '<COLLECTION_ID>', | ||
| documentId: '<DOCUMENT_ID>', | ||
| data: {}, // optional | ||
| permissions: ["read("any")"], // optional |
There was a problem hiding this comment.
Fix syntax error in permissions string literal.
The permissions string has unescaped quotes that will cause a JavaScript parse error:
permissions: ["read("any")"]The inner quotes terminate the string prematurely. Choose one of these solutions:
-
Recommended: Use the
PermissionandRolehelper classes (already imported):permissions: [Permission.read(Role.any())]
-
Escape the inner quotes:
permissions: ["read(\"any\")"]
-
Use single quotes for the outer string:
permissions: ['read("any")']
🐛 Proposed fix using helper classes (recommended)
- permissions: ["read("any")"], // optional
+ permissions: [Permission.read(Role.any())], // optional🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@docs/examples/documentsdb/update-document.md` at line 15, The permissions
string contains unescaped inner quotes and will cause a parse error; update the
permissions entry (the permissions property) to a valid expression—preferably
use the helper classes Permission and Role by replacing permissions:
["read("any")"] with permissions: [Permission.read(Role.any())]; alternatively
escape inner quotes (permissions: ["read(\"any\")"]) or switch to single outer
quotes (permissions: ['read("any")']) so the code parses correctly.
| const result = await documentsDB.updateTransaction({ | ||
| transactionId: '<TRANSACTION_ID>', | ||
| commit: false, // optional | ||
| rollback: false // optional | ||
| }); |
There was a problem hiding this comment.
🧩 Analysis chain
🌐 Web query:
For Appwrite DocumentsDB transaction update in API 1.9.0, should docs examples pass only one of commitorrollback per request? Please confirm the canonical example from official docs.
💡 Result:
Yes, Appwrite DocumentsDB (now TablesDB) transaction updates in API 1.9.0 require passing only one of commit or rollback per updateTransaction request. The official documentation shows mutually exclusive examples: either {commit: true} to commit or {rollback: true} to rollback, never both in the same call. Passing both would likely result in an error, as they represent opposing actions.
Citations:
- 1: https://appwrite.io/docs/products/databases/transactions
- 2: https://www.linktr.ee/fashionforallfoundation
- 3: https://www.shiningexamples.net
- 4: https://www.ydb.tech
- 5: https://www.tms-bd.or.
- 6: http://www.appwrite.io/docs/products/databases/transactions
- 7: https://appwrite.io/docs/references/1.8.x/client-web/tablesDB
- 8: https://pub.dev/documentation/appwrite/latest/appwrite/TablesDB-class.html
Update example to show only one of commit or rollback per request.
The example shows both flags set to false, creating ambiguity about proper usage. Appwrite DocumentsDB API requires commit and rollback to be mutually exclusive—only one should be passed per updateTransaction request.
Suggested fix
const result = await documentsDB.updateTransaction({
transactionId: '<TRANSACTION_ID>',
- commit: false, // optional
- rollback: false // optional
+ rollback: true // optional (use either `commit` or `rollback`)
});📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const result = await documentsDB.updateTransaction({ | |
| transactionId: '<TRANSACTION_ID>', | |
| commit: false, // optional | |
| rollback: false // optional | |
| }); | |
| const result = await documentsDB.updateTransaction({ | |
| transactionId: '<TRANSACTION_ID>', | |
| rollback: true // optional (use either `commit` or `rollback`) | |
| }); |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@docs/examples/documentsdb/update-transaction.md` around lines 10 - 14, The
example for documentsDB.updateTransaction currently passes both commit and
rollback flags which are mutually exclusive; update the sample call to pass only
one of the flags (either commit or rollback) alongside the transactionId in the
documentsDB.updateTransaction invocation so the example demonstrates proper
usage (e.g., show one example with commit: true and remove the rollback flag OR
show one example with rollback: true and remove the commit flag).
| collectionId: '<COLLECTION_ID>', | ||
| documentId: '<DOCUMENT_ID>', | ||
| data: {}, // optional | ||
| permissions: ["read("any")"], // optional |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
cat -n docs/examples/documentsdb/upsert-document.md | head -30Repository: appwrite/sdk-for-react-native
Length of output: 824
🏁 Script executed:
# Search for Permission and Role usage patterns in the codebase
rg "Permission\.|Role\." --type md -A 2 -B 2 | head -50Repository: appwrite/sdk-for-react-native
Length of output: 481
🌐 Web query:
Appwrite Permission.read Role.any() syntax documentation
💡 Result:
The syntax for Appwrite Permission.read Role.any is Permission.read(Role.any), used in SDKs to grant read access to any user for resources like database rows, documents, files, etc. This is a static method call from the Permission and Role classes. Example from official docs for creating a database row readable by anyone: import { Client, Databases, Permission, Role } from "node-appwrite"; const client = new Client .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint .setProject('<PROJECT_ID>'); // Your project ID const databases = new Databases(client); databases.createDocument( '<DATABASE_ID>', '<COLLECTION_ID>', 'unique', { 'actorName': 'Chris Evans', 'height': 183 }, [ Permission.read(Role.any), // Anyone can read this row // Additional permissions... ] ); Similar syntax applies across Client and Server SDKs (Web, Node.js, etc.). Permissions are arrays passed to create/update methods for resources. Role.any grants access to anyone (wildcard), while Permission.read specifies read access. Users can only grant permissions they own.
Citations:
Permissions example has broken JavaScript syntax.
Line 15 uses invalid nested quoting that won't parse. The string "read("any")" has unescaped inner quotes that terminate the string prematurely.
Fix
- permissions: ["read("any")"], // optional
+ permissions: [Permission.read(Role.any())], // optionalThe fix uses the correct Appwrite Permission and Role API (already imported at line 2).
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| permissions: ["read("any")"], // optional | |
| permissions: [Permission.read(Role.any())], // optional |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@docs/examples/documentsdb/upsert-document.md` at line 15, The permissions
array uses invalid nested quoting ("read("any")"); replace the broken string
with a proper Appwrite Permission/Role construct by using the Permission and
Role helpers (referenced as Permission and Role) to build the permission entry
for the permissions field (i.e., use Permission.read with Role.any rather than a
raw quoted string) so the permissions property is valid JavaScript and follows
Appwrite's Permission/Role API.
| "key": "value" | ||
| } | ||
| }, | ||
| permissions: ["read("any")"] // optional |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Verify all docs examples still containing the invalid nested-quote permission literal.
rg -n --type=md 'permissions:\s*\["read\("any"\)"\]'Repository: appwrite/sdk-for-react-native
Length of output: 1332
🏁 Script executed:
cat -n docs/examples/vectorsdb/create-document.mdRepository: appwrite/sdk-for-react-native
Length of output: 987
🏁 Script executed:
rg -n --type=md 'Permission\.' docs/examples/ -A 1 -B 1 | head -50Repository: appwrite/sdk-for-react-native
Length of output: 351
🏁 Script executed:
rg -n 'Permission\.read' docs/examples/ -B 2 -A 2Repository: appwrite/sdk-for-react-native
Length of output: 55
🏁 Script executed:
find . -type f -name "*.md" | xargs rg -l "Permission\|permissions" | head -5Repository: appwrite/sdk-for-react-native
Length of output: 55
🏁 Script executed:
rg -n "Permission\s*\(" --type=typescript --type=javascript . | head -20Repository: appwrite/sdk-for-react-native
Length of output: 107
🏁 Script executed:
cat -n README.md | head -100Repository: appwrite/sdk-for-react-native
Length of output: 4723
🏁 Script executed:
find . -type f -name "*.ts" -o -name "*.js" | grep -E "(Permission|Role)" | head -10Repository: appwrite/sdk-for-react-native
Length of output: 55
🏁 Script executed:
fd -t f "Permission\|Role" src/ --type f | head -20Repository: appwrite/sdk-for-react-native
Length of output: 55
🏁 Script executed:
ls -la src/ 2>/dev/null || find . -type d -name src | head -5Repository: appwrite/sdk-for-react-native
Length of output: 902
🏁 Script executed:
cat -n src/permission.tsRepository: appwrite/sdk-for-react-native
Length of output: 698
🏁 Script executed:
cat -n src/role.tsRepository: appwrite/sdk-for-react-native
Length of output: 3160
Fix invalid permissions syntax in the example.
Line 25 uses an invalid JavaScript string (["read("any")"]) with unescaped nested quotes, causing a syntax error. The correct approach is to use the helper functions.
Proposed fix
- permissions: ["read("any")"] // optional
+ permissions: [Permission.read(Role.any())] // optionalThis same issue appears in 14 documentation files across the examples directory (databases, documents, storage, tables, and vectors examples).
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| permissions: ["read("any")"] // optional | |
| permissions: [Permission.read(Role.any())] // optional |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@docs/examples/vectorsdb/create-document.md` at line 25, The examples use an
invalid string literal permissions: ["read("any")"] which causes a syntax error;
locate occurrences of the permissions key in the examples (the literal
["read("any")"]) and replace them with the proper helper invocation (e.g.,
permissions: [read("any")] or permissions: [permissionsHelper.read("any")]
depending on the examples' helper import), ensuring the helper is
imported/available in each file; apply this fix across all example docs that
contain the invalid string.
| collectionId: '<COLLECTION_ID>', | ||
| documentId: '<DOCUMENT_ID>', | ||
| data: {}, // optional | ||
| permissions: ["read("any")"], // optional |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
find . -name "upsert-document.md" -type fRepository: appwrite/sdk-for-react-native
Length of output: 209
🏁 Script executed:
cat -n ./docs/examples/vectorsdb/upsert-document.md | head -20Repository: appwrite/sdk-for-react-native
Length of output: 816
🏁 Script executed:
# Check if there are other examples in the codebase showing correct permissions syntax
rg "permissions:\s*\[" docs/examples/ -A 1 -B 1 | head -40Repository: appwrite/sdk-for-react-native
Length of output: 2380
🏁 Script executed:
# Search for correct Permission/Role usage in the codebase
rg "Permission\." docs/examples/ -A 1 -B 1 | head -50Repository: appwrite/sdk-for-react-native
Length of output: 342
🏁 Script executed:
# Search for Role usage to find the correct permission syntax
rg "Role\." docs/examples/ -A 1 -B 1 | head -50Repository: appwrite/sdk-for-react-native
Length of output: 55
🏁 Script executed:
# Search the entire codebase for Permission.read and Role patterns
rg "Permission\.read" . -A 1 -B 1 | head -50Repository: appwrite/sdk-for-react-native
Length of output: 55
🏁 Script executed:
# Check if there's any TypeScript/type definitions for Permission and Role
find . -name "*.ts" -o -name "*.d.ts" | xargs grep -l "Permission\|Role" | head -10Repository: appwrite/sdk-for-react-native
Length of output: 181
🏁 Script executed:
cat -n ./src/permission.tsRepository: appwrite/sdk-for-react-native
Length of output: 698
🏁 Script executed:
cat -n ./src/role.tsRepository: appwrite/sdk-for-react-native
Length of output: 3160
Invalid permission literal with unescaped quotes breaks this snippet.
Line 15 contains a syntax error: permissions: ["read("any")"] has nested unescaped quotes and will not execute.
Fix
- permissions: ["read("any")"], // optional
+ permissions: [Permission.read(Role.any())], // optionalUse Permission.read(Role.any()) to generate the correct permission string. Role.any() returns 'any', and Permission.read('any') generates the properly escaped string read("any").
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| permissions: ["read("any")"], // optional | |
| permissions: [Permission.read(Role.any())], // optional |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@docs/examples/vectorsdb/upsert-document.md` at line 15, The snippet uses an
invalid literal permissions: ["read("any")"] which contains unescaped nested
quotes; replace that literal with a call that constructs the permission
correctly—use Permission.read(Role.any()) (or Permission.read('any')) where
Permission.read and Role.any are referenced in the file so the generated
permission string becomes read("any") without syntax errors.
| "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": "0.25.0", | ||
| "version": "0.24.2", |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
PACKAGE="react-native-appwrite"
echo "Checking published versions for ${PACKAGE}..."
curl -s "https://registry.npmjs.org/${PACKAGE}" \
| jq -r '.versions | keys[]' \
| rg '^(0\.24\.2|0\.25\.0)$' || true
echo "Current dist-tags:"
curl -s "https://registry.npmjs.org/${PACKAGE}" | jq '.["dist-tags"]'Repository: appwrite/sdk-for-react-native
Length of output: 180
Do not rollback package version to 0.24.2 after 0.25.0 has been published.
Line 5 attempts to set version to 0.24.2, but 0.25.0 is already published to npm as the "latest" release. Publishing 0.24.2 after a higher version violates semver conventions and npm publish will fail or require --allow-same-version / force flags. Either keep the version at 0.25.0 or increment to 0.26.0 (or higher).
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@package.json` at line 5, The package.json "version" field was rolled back to
"0.24.2" but "0.25.0" is already published; update the package.json "version"
property (the version key) to either "0.25.0" to match the published latest or
bump to a higher semver like "0.26.0" (or greater) before publishing so npm
won’t reject the publish due to a lower version.
| 'x-sdk-version': '0.24.2', | ||
| 'X-Appwrite-Response-Format': '1.9.0', |
There was a problem hiding this comment.
🧩 Analysis chain
🌐 Web query:
Does Appwrite server version 1.8.x support the X-Appwrite-Response-Format: 1.9.0 header, and what response format should the React Native SDK 0.24.2 send?
💡 Result:
No, Appwrite server version 1.8.x does not support the X-Appwrite-Response-Format: 1.9.0 header. The server validates requested response formats to ensure they are semantic versions <= APP_VERSION_STABLE (which is 1.8.x for the 1.8.x branch), rejecting higher versions like 1.9.0. The React Native SDK 0.24.2 should send X-Appwrite-Response-Format: 1.8.0, matching the server version for compatibility. SDKs typically set this header to their generated version, which aligns with the target server (1.8.x support added in recent SDK updates).
Citations:
- 1: Allow running tests with specific response format appwrite#10418
- 2: 🐛 Bug Report: Rest API request to List Documents returns 400 (Bad Request) if X-Appwrite-Response-Format is not set appwrite#7774
- 3: http://www.appwrite.io/docs/apis/rest
- 4: feat: add warning header appwrite#8063
Change X-Appwrite-Response-Format from 1.9.0 to 1.8.0 for Appwrite 1.8.x compatibility.
The header at line 165 is set to 1.9.0, but Appwrite server 1.8.x rejects response format versions higher than the server version. This breaks compatibility with the stated server target (1.8.x). Update to 1.8.0 to match.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/client.ts` around lines 164 - 165, The response format header in
src/client.ts is set to 'X-Appwrite-Response-Format': '1.9.0', which is
incompatible with Appwrite 1.8.x; update the header value to '1.8.0' (modify the
header literal for 'X-Appwrite-Response-Format' in the client HTTP
headers/config block—the constant or object where 'x-sdk-version' and
'X-Appwrite-Response-Format' are defined) so the client advertises 1.8.0 and
matches the server compatibility.
| 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; |
There was a problem hiding this comment.
Keep only one impersonation selector active at a time.
Calling these setters sequentially leaves multiple X-Appwrite-Impersonate-* headers and config values live. The next request can carry conflicting selectors instead of the last one the caller chose.
One way to enforce a single active selector
+ private clearImpersonation(): void {
+ delete this.headers['X-Appwrite-Impersonate-User-Id'];
+ delete this.headers['X-Appwrite-Impersonate-User-Email'];
+ delete this.headers['X-Appwrite-Impersonate-User-Phone'];
+ this.config.impersonateuserid = '';
+ this.config.impersonateuseremail = '';
+ this.config.impersonateuserphone = '';
+ }
+
setImpersonateUserId(value: string): this {
+ this.clearImpersonation();
this.headers['X-Appwrite-Impersonate-User-Id'] = value;
this.config.impersonateuserid = value;
return this;
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| 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 clearImpersonation(): void { | |
| delete this.headers['X-Appwrite-Impersonate-User-Id']; | |
| delete this.headers['X-Appwrite-Impersonate-User-Email']; | |
| delete this.headers['X-Appwrite-Impersonate-User-Phone']; | |
| this.config.impersonateuserid = ''; | |
| this.config.impersonateuseremail = ''; | |
| this.config.impersonateuserphone = ''; | |
| } | |
| setImpersonateUserId(value: string): this { | |
| this.clearImpersonation(); | |
| 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; | |
| } |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/client.ts` around lines 314 - 359, When setting an impersonation selector
in setImpersonateUserId, setImpersonateUserEmail, or setImpersonateUserPhone,
clear the other impersonation headers and config fields so only the newly-set
selector remains active: remove the other
'X-Appwrite-Impersonate-User-Id|Email|Phone' keys from this.headers and unset
the corresponding
this.config.impersonateuserid|impersonateuseremail|impersonateuserphone fields
before assigning the new value in the respective method (refer to the three
setter methods by name to locate the changes).
| if (data && typeof data === 'object') { | ||
| data.toString = () => JSONbig.stringify(data); | ||
| } |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
cat -n src/client.ts | sed -n '650,670p'Repository: appwrite/sdk-for-react-native
Length of output: 995
🏁 Script executed:
cat -n src/client.ts | sed -n '630,670p'Repository: appwrite/sdk-for-react-native
Length of output: 1965
🏁 Script executed:
python3 << 'EOF'
# Verify enumerable property behavior
code = """
// Direct property assignment (current approach)
const obj1 = { name: 'test' };
obj1.toString = () => 'custom';
console.log('Direct assignment:');
console.log('Object.keys includes toString:', Object.keys(obj1).includes('toString'));
console.log('for...in includes toString:');
for (let key in obj1) {
console.log(' -', key);
}
// Using Object.defineProperty with enumerable: false (proposed approach)
const obj2 = { name: 'test' };
Object.defineProperty(obj2, 'toString', {
value: () => 'custom',
enumerable: false,
configurable: true
});
console.log('\\nObject.defineProperty with enumerable: false:');
console.log('Object.keys includes toString:', Object.keys(obj2).includes('toString'));
console.log('for...in includes toString:');
for (let key in obj2) {
console.log(' -', key);
}
// Check if existing toString is overwritten
const obj3 = { toString: 'original' };
obj3.toString = () => 'overwritten';
console.log('\\nOverwriting existing toString:', obj3.toString);
"""
print("JavaScript enumerable property behavior:")
print(code)
print("\nThis demonstrates that:")
print("1. Direct assignment creates enumerable properties (included in Object.keys/for...in)")
print("2. Object.defineProperty with enumerable:false excludes from enumeration")
print("3. Direct assignment overwrites existing properties")
EOFRepository: appwrite/sdk-for-react-native
Length of output: 1337
🏁 Script executed:
cat -n src/client.ts | sed -n '620,665p'Repository: appwrite/sdk-for-react-native
Length of output: 2251
Remove the enumerable toString property assignment from response objects.
The current code mutates every response object by adding an enumerable toString property, which causes it to appear in Object.keys() and for...in loops. More critically, it overwrites any legitimate toString field that may exist in the server response data (since this parses JSON directly from the API response).
Use Object.defineProperty() with enumerable: false to add the custom method without polluting enumeration, and check for existing toString fields first:
Suggested fix
- if (data && typeof data === 'object') {
- data.toString = () => JSONbig.stringify(data);
- }
+ if (
+ data &&
+ typeof data === 'object' &&
+ !Object.prototype.hasOwnProperty.call(data, 'toString')
+ ) {
+ Object.defineProperty(data, 'toString', {
+ value: () => JSONbig.stringify(data),
+ enumerable: false,
+ configurable: true,
+ });
+ }📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| if (data && typeof data === 'object') { | |
| data.toString = () => JSONbig.stringify(data); | |
| } | |
| if ( | |
| data && | |
| typeof data === 'object' && | |
| !Object.prototype.hasOwnProperty.call(data, 'toString') | |
| ) { | |
| Object.defineProperty(data, 'toString', { | |
| value: () => JSONbig.stringify(data), | |
| enumerable: false, | |
| configurable: true, | |
| }); | |
| } |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/client.ts` around lines 657 - 659, The code currently mutates response
objects by assigning an enumerable toString property via "data.toString = () =>
JSONbig.stringify(data)" which pollutes enumeration and can overwrite an
existing toString; instead, before adding a method, check if
Object.prototype.hasOwnProperty.call(data, 'toString') is false (or typeof
data.toString !== 'function'), and then add the method with
Object.defineProperty(data, 'toString', { value: () => JSONbig.stringify(data),
writable: true, configurable: true, enumerable: false }); this keeps the custom
toString non-enumerable and preserves any existing toString from the server.
This PR contains updates to the React Native SDK for version 0.24.2.
Changes
1.9.01.8.xDocumentsDBandVectorsDBSummary by CodeRabbit
Release Notes
New Features
DocumentsDBservice for transaction management and document operations.VectorsDBservice for vector database operations.upsertDocumentsmethod to databases service.Documentation
Chores