Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Change Log

## 20.3.2

* Fix OAuth2 browser infinite redirect issue

## 20.3.1

* Fix passing of `null` values and stripping only non-nullable optional parameters from the request body
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ Add this to your package's `pubspec.yaml` file:

```yml
dependencies:
appwrite: ^20.3.1
appwrite: ^20.3.2
```

You can install packages from the command line:
Expand Down
2 changes: 1 addition & 1 deletion docs/examples/avatars/get-browser.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ Client client = Client()
Avatars avatars = Avatars(client);

// Downloading file
UInt8List bytes = await avatars.getBrowser(
Uint8List bytes = await avatars.getBrowser(
code: Browser.avantBrowser,
width: 0, // optional
height: 0, // optional
Expand Down
2 changes: 1 addition & 1 deletion docs/examples/avatars/get-credit-card.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ Client client = Client()
Avatars avatars = Avatars(client);

// Downloading file
UInt8List bytes = await avatars.getCreditCard(
Uint8List bytes = await avatars.getCreditCard(
code: CreditCard.americanExpress,
width: 0, // optional
height: 0, // optional
Expand Down
2 changes: 1 addition & 1 deletion docs/examples/avatars/get-favicon.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ Client client = Client()
Avatars avatars = Avatars(client);

// Downloading file
UInt8List bytes = await avatars.getFavicon(
Uint8List bytes = await avatars.getFavicon(
url: 'https://example.com',
)

Expand Down
2 changes: 1 addition & 1 deletion docs/examples/avatars/get-flag.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ Client client = Client()
Avatars avatars = Avatars(client);

// Downloading file
UInt8List bytes = await avatars.getFlag(
Uint8List bytes = await avatars.getFlag(
code: Flag.afghanistan,
width: 0, // optional
height: 0, // optional
Expand Down
2 changes: 1 addition & 1 deletion docs/examples/avatars/get-image.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ Client client = Client()
Avatars avatars = Avatars(client);

// Downloading file
UInt8List bytes = await avatars.getImage(
Uint8List bytes = await avatars.getImage(
url: 'https://example.com',
width: 0, // optional
height: 0, // optional
Expand Down
2 changes: 1 addition & 1 deletion docs/examples/avatars/get-initials.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ Client client = Client()
Avatars avatars = Avatars(client);

// Downloading file
UInt8List bytes = await avatars.getInitials(
Uint8List bytes = await avatars.getInitials(
name: '<NAME>', // optional
width: 0, // optional
height: 0, // optional
Expand Down
2 changes: 1 addition & 1 deletion docs/examples/avatars/get-qr.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ Client client = Client()
Avatars avatars = Avatars(client);

// Downloading file
UInt8List bytes = await avatars.getQR(
Uint8List bytes = await avatars.getQR(
text: '<TEXT>',
size: 1, // optional
margin: 0, // optional
Expand Down
14 changes: 7 additions & 7 deletions docs/examples/avatars/get-screenshot.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,17 @@ Client client = Client()
Avatars avatars = Avatars(client);

// Downloading file
UInt8List bytes = await avatars.getScreenshot(
Uint8List bytes = await avatars.getScreenshot(
url: 'https://example.com',
headers: {}, // optional
viewportWidth: 1, // optional
viewportHeight: 1, // optional
scale: 0.1, // optional
theme: .light, // optional
theme: Theme.light, // optional
userAgent: '<USER_AGENT>', // optional
fullpage: false, // optional
locale: '<LOCALE>', // optional
timezone: .africaAbidjan, // optional
timezone: Timezone.africaAbidjan, // optional
latitude: -90, // optional
longitude: -180, // optional
accuracy: 0, // optional
Expand All @@ -27,7 +27,7 @@ UInt8List bytes = await avatars.getScreenshot(
width: 0, // optional
height: 0, // optional
quality: -1, // optional
output: .jpg, // optional
output: Output.jpg, // optional
)

final file = File('path_to_file/filename.ext');
Expand All @@ -41,11 +41,11 @@ FutureBuilder(
viewportWidth:1 , // optional
viewportHeight:1 , // optional
scale:0.1 , // optional
theme: .light, // optional
theme: Theme.light, // optional
userAgent:'<USER_AGENT>' , // optional
fullpage:false , // optional
locale:'<LOCALE>' , // optional
timezone: .africaAbidjan, // optional
timezone: Timezone.africaAbidjan, // optional
latitude:-90 , // optional
longitude:-180 , // optional
accuracy:0 , // optional
Expand All @@ -55,7 +55,7 @@ FutureBuilder(
width:0 , // optional
height:0 , // optional
quality:-1 , // optional
output: .jpg, // optional
output: Output.jpg, // optional
), // Works for both public file and private file, for private files you need to be logged in
builder: (context, snapshot) {
return snapshot.hasData && snapshot.data != null
Expand Down
2 changes: 1 addition & 1 deletion docs/examples/storage/get-file-download.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ Client client = Client()
Storage storage = Storage(client);

// Downloading file
UInt8List bytes = await storage.getFileDownload(
Uint8List bytes = await storage.getFileDownload(
bucketId: '<BUCKET_ID>',
fileId: '<FILE_ID>',
token: '<TOKEN>', // optional
Expand Down
2 changes: 1 addition & 1 deletion docs/examples/storage/get-file-preview.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ Client client = Client()
Storage storage = Storage(client);

// Downloading file
UInt8List bytes = await storage.getFilePreview(
Uint8List bytes = await storage.getFilePreview(
bucketId: '<BUCKET_ID>',
fileId: '<FILE_ID>',
width: 0, // optional
Expand Down
2 changes: 1 addition & 1 deletion docs/examples/storage/get-file-view.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ Client client = Client()
Storage storage = Storage(client);

// Downloading file
UInt8List bytes = await storage.getFileView(
Uint8List bytes = await storage.getFileView(
bucketId: '<BUCKET_ID>',
fileId: '<FILE_ID>',
token: '<TOKEN>', // optional
Expand Down
22 changes: 11 additions & 11 deletions lib/services/databases.dart
Original file line number Diff line number Diff line change
Expand Up @@ -165,8 +165,8 @@ class Databases extends Service {
final Map<String, dynamic> apiParams = {
'documentId': documentId,
'data': data,
if (permissions != null) 'permissions': permissions,
if (transactionId != null) 'transactionId': transactionId,
'permissions': permissions,
'transactionId': transactionId,
};

final Map<String, String> apiHeaders = {
Expand Down Expand Up @@ -229,8 +229,8 @@ class Databases extends Service {

final Map<String, dynamic> apiParams = {
'data': data,
if (permissions != null) 'permissions': permissions,
if (transactionId != null) 'transactionId': transactionId,
'permissions': permissions,
'transactionId': transactionId,
};

final Map<String, String> apiHeaders = {
Expand Down Expand Up @@ -262,8 +262,8 @@ class Databases extends Service {

final Map<String, dynamic> apiParams = {
if (data != null) 'data': data,
if (permissions != null) 'permissions': permissions,
if (transactionId != null) 'transactionId': transactionId,
'permissions': permissions,
'transactionId': transactionId,
};

final Map<String, String> apiHeaders = {
Expand Down Expand Up @@ -291,7 +291,7 @@ class Databases extends Service {
.replaceAll('{documentId}', documentId);

final Map<String, dynamic> apiParams = {
if (transactionId != null) 'transactionId': transactionId,
'transactionId': transactionId,
};

final Map<String, String> apiHeaders = {
Expand Down Expand Up @@ -324,8 +324,8 @@ class Databases extends Service {

final Map<String, dynamic> apiParams = {
if (value != null) 'value': value,
if (min != null) 'min': min,
if (transactionId != null) 'transactionId': transactionId,
'min': min,
'transactionId': transactionId,
};

final Map<String, String> apiHeaders = {
Expand Down Expand Up @@ -358,8 +358,8 @@ class Databases extends Service {

final Map<String, dynamic> apiParams = {
if (value != null) 'value': value,
if (max != null) 'max': max,
if (transactionId != null) 'transactionId': transactionId,
'max': max,
'transactionId': transactionId,
};

final Map<String, String> apiHeaders = {
Expand Down
2 changes: 1 addition & 1 deletion lib/services/functions.dart
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ class Functions extends Service {
if (path != null) 'path': path,
if (method != null) 'method': method!.value,
if (headers != null) 'headers': headers,
if (scheduledAt != null) 'scheduledAt': scheduledAt,
'scheduledAt': scheduledAt,
};

final Map<String, String> apiHeaders = {
Expand Down
4 changes: 2 additions & 2 deletions lib/services/storage.dart
Original file line number Diff line number Diff line change
Expand Up @@ -111,8 +111,8 @@ class Storage extends Service {
.replaceAll('{fileId}', fileId);

final Map<String, dynamic> apiParams = {
if (name != null) 'name': name,
if (permissions != null) 'permissions': permissions,
'name': name,
'permissions': permissions,
};
Comment on lines 113 to 116
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

Verify backend compatibility with null parameter values.

The name and permissions parameters are now always included in the API request payload, even when their values are null. Previously, these fields were conditionally included only when non-null. Ensure that the backend API endpoint /storage/buckets/{bucketId}/files/{fileId} correctly handles receiving explicit null values for these fields versus the fields being omitted entirely.


🏁 Script executed:

#!/bin/bash
# Description: Check if similar unconditional inclusion patterns exist in other service files to understand the scope of this API contract change.

# Search for updateFile-like methods and their parameter handling
rg -n -B5 -A10 "Future<models\.File> update" lib/services/storage.dart lib/services/databases.dart --type dart

Length of output: 1022


I need to examine the complete updateFile method and verify the actual change. Let me gather more information:


---

🏁 Script executed:

```shell
#!/bin/bash
# View the complete updateFile method to see how apiParams are used
sed -n '104,140p' lib/services/storage.dart

Length of output: 1176


🏁 Script executed:

#!/bin/bash
# Check for similar patterns in other service files (databases, users, etc.)
fd -e dart -path "lib/services/*.dart" -type f -exec basename {} \; | sort

Length of output: 168


🏁 Script executed:

#!/bin/bash
# Search for conditional parameter inclusion patterns in the codebase
rg -n "if.*\?" lib/services/storage.dart -A2 -B2 | head -40

Length of output: 0


Let me check the git history and look for conditional parameter patterns across the codebase:


---

🏁 Script executed:

```shell
#!/bin/bash
# Check git diff to see what changed in this method
git diff HEAD -- lib/services/storage.dart | grep -A30 -B5 "updateFile"

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Search for conditional parameter inclusion patterns across all service files
find lib/services -name "*.dart" -type f | xargs grep -n "if.*!= null" | head -20

Length of output: 1519


🏁 Script executed:

#!/bin/bash
# Look for similar update methods and their parameter handling patterns
find lib/services -name "*.dart" -type f | xargs grep -n "Future.*update" -A15 | grep -E "(Future|if|apiParams|permissions)" | head -40

Length of output: 3313


Let me verify if this pattern violation is specific to updateFile or if storage.dart generally lacks conditional patterns:


---

🏁 Script executed:

```shell
#!/bin/bash
# Check if other methods in storage.dart use conditional inclusion patterns
grep -n "if.*!= null" lib/services/storage.dart

Length of output: 951


🏁 Script executed:

#!/bin/bash
# View other update/create methods in storage.dart to see their parameter handling
grep -n "apiParams = {" lib/services/storage.dart -A10 | head -50

Length of output: 1495


Use conditional inclusion for nullable parameters to match the established pattern in this file.

The updateFile method unconditionally includes name and permissions in the API request, even when null. This violates the established pattern used throughout storage.dart—other methods like listBuckets() (lines 19-21), createFile() (line 62), and getFilePreview() (lines 191-202) all conditionally include nullable parameters only when non-null.

Update lines 113-115 to:

final Map<String, dynamic> apiParams = {
  if (name != null) 'name': name,
  if (permissions != null) 'permissions': permissions,
};

This ensures consistency with the codebase pattern and prevents sending explicit null values to the backend, which may be handled differently than omitted fields.

🤖 Prompt for AI Agents
In lib/services/storage.dart around lines 113 to 116, the apiParams map for
updateFile unconditionally includes name and permissions (which may be null);
change it to use conditional map entries so nullable fields are only added when
non-null (i.e., include 'name' only if name != null and 'permissions' only if
permissions != null) to match the established pattern and avoid sending explicit
nulls to the backend.


final Map<String, String> apiHeaders = {
Expand Down
22 changes: 11 additions & 11 deletions lib/services/tables_db.dart
Original file line number Diff line number Diff line change
Expand Up @@ -157,8 +157,8 @@ class TablesDB extends Service {
final Map<String, dynamic> apiParams = {
'rowId': rowId,
'data': data,
if (permissions != null) 'permissions': permissions,
if (transactionId != null) 'transactionId': transactionId,
'permissions': permissions,
'transactionId': transactionId,
};

final Map<String, String> apiHeaders = {
Expand Down Expand Up @@ -217,8 +217,8 @@ class TablesDB extends Service {

final Map<String, dynamic> apiParams = {
if (data != null) 'data': data,
if (permissions != null) 'permissions': permissions,
if (transactionId != null) 'transactionId': transactionId,
'permissions': permissions,
'transactionId': transactionId,
};

final Map<String, String> apiHeaders = {
Expand Down Expand Up @@ -248,8 +248,8 @@ class TablesDB extends Service {

final Map<String, dynamic> apiParams = {
if (data != null) 'data': data,
if (permissions != null) 'permissions': permissions,
if (transactionId != null) 'transactionId': transactionId,
'permissions': permissions,
'transactionId': transactionId,
};

final Map<String, String> apiHeaders = {
Expand All @@ -275,7 +275,7 @@ class TablesDB extends Service {
.replaceAll('{rowId}', rowId);

final Map<String, dynamic> apiParams = {
if (transactionId != null) 'transactionId': transactionId,
'transactionId': transactionId,
};

final Map<String, String> apiHeaders = {
Expand Down Expand Up @@ -306,8 +306,8 @@ class TablesDB extends Service {

final Map<String, dynamic> apiParams = {
if (value != null) 'value': value,
if (min != null) 'min': min,
if (transactionId != null) 'transactionId': transactionId,
'min': min,
'transactionId': transactionId,
};

final Map<String, String> apiHeaders = {
Expand Down Expand Up @@ -338,8 +338,8 @@ class TablesDB extends Service {

final Map<String, dynamic> apiParams = {
if (value != null) 'value': value,
if (max != null) 'max': max,
if (transactionId != null) 'transactionId': transactionId,
'max': max,
'transactionId': transactionId,
};

final Map<String, String> apiHeaders = {
Expand Down
2 changes: 1 addition & 1 deletion lib/src/client_browser.dart
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ class ClientBrowser extends ClientBase with ClientMixin {
'x-sdk-name': 'Flutter',
'x-sdk-platform': 'client',
'x-sdk-language': 'flutter',
'x-sdk-version': '20.3.1',
'x-sdk-version': '20.3.2',
'X-Appwrite-Response-Format': '1.8.0',
};

Expand Down
2 changes: 1 addition & 1 deletion lib/src/client_io.dart
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ class ClientIO extends ClientBase with ClientMixin {
'x-sdk-name': 'Flutter',
'x-sdk-platform': 'client',
'x-sdk-language': 'flutter',
'x-sdk-version': '20.3.1',
'x-sdk-version': '20.3.2',
'X-Appwrite-Response-Format': '1.8.0',
};

Expand Down
4 changes: 2 additions & 2 deletions pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name: appwrite
version: 20.3.1
version: 20.3.2
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
homepage: https://appwrite.io
repository: https://github.com/appwrite/sdk-for-flutter
Expand All @@ -20,7 +20,7 @@ dependencies:
sdk: flutter
cookie_jar: ^4.0.8
device_info_plus: '>=11.5.0 <13.0.0'
flutter_web_auth_2: ^4.1.0
flutter_web_auth_2: ^5.0.0-alpha.3
http: '>=0.13.6 <2.0.0'
package_info_plus: '>=8.0.2 <10.0.0'
path_provider: ^2.1.4
Expand Down