From 349ba8cd08caa12e2af018839408221806ff0bdc Mon Sep 17 00:00:00 2001 From: Torsten Dittmann Date: Thu, 21 May 2026 17:20:46 +0400 Subject: [PATCH 01/13] feat: support concurrent chunk uploads --- lib/src/client_browser.dart | 280 ++++++++++++++++++++-------------- lib/src/client_io.dart | 292 +++++++++++++++++++++--------------- 2 files changed, 345 insertions(+), 227 deletions(-) diff --git a/lib/src/client_browser.dart b/lib/src/client_browser.dart index 8da3c72a..4dd355c1 100644 --- a/lib/src/client_browser.dart +++ b/lib/src/client_browser.dart @@ -16,7 +16,7 @@ ClientBase createClient({ ClientBrowser(endPoint: endPoint, selfSigned: selfSigned); class ClientBrowser extends ClientBase with ClientMixin { - static const int chunkSize = 5 * 1024 * 1024; + static const int chunkSize = 5*1024*1024; String _endPoint; Map? _headers; @override @@ -34,7 +34,7 @@ class ClientBrowser extends ClientBase with ClientMixin { 'x-sdk-platform': 'server', 'x-sdk-language': 'dart', 'x-sdk-version': '24.1.0', - 'X-Appwrite-Response-Format': '1.9.5', + 'X-Appwrite-Response-Format' : '1.9.5', }; config = {}; @@ -46,92 +46,82 @@ class ClientBrowser extends ClientBase with ClientMixin { @override String get endPoint => _endPoint; - /// Your project ID - @override - ClientBrowser setProject(value) { - config['project'] = value; - addHeader('X-Appwrite-Project', value); - return this; - } - - /// Your secret API key - @override - ClientBrowser setKey(value) { - config['key'] = value; - addHeader('X-Appwrite-Key', value); - return this; - } - - /// Your secret JSON Web Token - @override - ClientBrowser setJWT(value) { - config['jWT'] = value; - addHeader('X-Appwrite-JWT', value); - return this; - } - - @override - ClientBrowser setLocale(value) { - config['locale'] = value; - addHeader('X-Appwrite-Locale', value); - return this; - } - - /// The user session to authenticate with - @override - ClientBrowser setSession(value) { - config['session'] = value; - addHeader('X-Appwrite-Session', value); - return this; - } - - /// The user agent string of the client that made the request - @override - ClientBrowser setForwardedUserAgent(value) { - config['forwardedUserAgent'] = value; - addHeader('X-Forwarded-User-Agent', value); - return this; - } - - /// Your secret dev API key - @override - ClientBrowser setDevKey(value) { - config['devKey'] = value; - addHeader('X-Appwrite-Dev-Key', value); - return this; - } - - /// The user cookie to authenticate with. Used by SDKs that forward an incoming Cookie header in server-side runtimes. - @override - ClientBrowser setCookie(value) { - config['cookie'] = value; - addHeader('Cookie', value); - return this; - } - - /// 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. - @override - ClientBrowser setImpersonateUserId(value) { - config['impersonateUserId'] = value; - addHeader('X-Appwrite-Impersonate-User-Id', value); - return this; - } - - /// 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. - @override - ClientBrowser setImpersonateUserEmail(value) { - config['impersonateUserEmail'] = value; - addHeader('X-Appwrite-Impersonate-User-Email', value); - return this; - } - - /// 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. - @override - ClientBrowser setImpersonateUserPhone(value) { - config['impersonateUserPhone'] = value; - addHeader('X-Appwrite-Impersonate-User-Phone', value); - return this; - } + /// Your project ID + @override + ClientBrowser setProject(value) { + config['project'] = value; + addHeader('X-Appwrite-Project', value); + return this; + } + /// Your secret API key + @override + ClientBrowser setKey(value) { + config['key'] = value; + addHeader('X-Appwrite-Key', value); + return this; + } + /// Your secret JSON Web Token + @override + ClientBrowser setJWT(value) { + config['jWT'] = value; + addHeader('X-Appwrite-JWT', value); + return this; + } + @override + ClientBrowser setLocale(value) { + config['locale'] = value; + addHeader('X-Appwrite-Locale', value); + return this; + } + /// The user session to authenticate with + @override + ClientBrowser setSession(value) { + config['session'] = value; + addHeader('X-Appwrite-Session', value); + return this; + } + /// The user agent string of the client that made the request + @override + ClientBrowser setForwardedUserAgent(value) { + config['forwardedUserAgent'] = value; + addHeader('X-Forwarded-User-Agent', value); + return this; + } + /// Your secret dev API key + @override + ClientBrowser setDevKey(value) { + config['devKey'] = value; + addHeader('X-Appwrite-Dev-Key', value); + return this; + } + /// The user cookie to authenticate with. Used by SDKs that forward an incoming Cookie header in server-side runtimes. + @override + ClientBrowser setCookie(value) { + config['cookie'] = value; + addHeader('Cookie', value); + return this; + } + /// 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. + @override + ClientBrowser setImpersonateUserId(value) { + config['impersonateUserId'] = value; + addHeader('X-Appwrite-Impersonate-User-Id', value); + return this; + } + /// 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. + @override + ClientBrowser setImpersonateUserEmail(value) { + config['impersonateUserEmail'] = value; + addHeader('X-Appwrite-Impersonate-User-Email', value); + return this; + } + /// 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. + @override + ClientBrowser setImpersonateUserPhone(value) { + config['impersonateUserPhone'] = value; + addHeader('X-Appwrite-Impersonate-User-Phone', value); + return this; + } @override ClientBrowser setSelfSigned({bool status = true}) { @@ -185,8 +175,7 @@ class ClientBrowser extends ClientBase with ClientMixin { late Response res; if (size <= chunkSize) { - params[paramName] = http.MultipartFile.fromBytes(paramName, file.bytes!, - filename: file.filename); + params[paramName] = http.MultipartFile.fromBytes(paramName, file.bytes!, filename: file.filename); return call( HttpMethod.post, path: path, @@ -196,6 +185,7 @@ class ClientBrowser extends ClientBase with ClientMixin { } var offset = 0; + String? uploadId; if (idParamName.isNotEmpty) { //make a request to check if a file already exists try { @@ -206,33 +196,103 @@ class ClientBrowser extends ClientBase with ClientMixin { ); final int chunksUploaded = res.data['chunksUploaded'] as int; offset = chunksUploaded * chunkSize; + uploadId = res.data['\$id'] ?? params[idParamName]?.toString(); } on AppwriteException catch (_) {} } - while (offset < size) { + if (offset >= size) { + return res; + } + + final totalChunks = (size / chunkSize).ceil(); + + Future uploadChunk(int index, int start, int end, String? id) async { List chunk = []; - final end = min(offset + chunkSize, size); - chunk = file.bytes!.getRange(offset, end).toList(); - params[paramName] = http.MultipartFile.fromBytes(paramName, chunk, - filename: file.filename); - headers['content-range'] = - 'bytes $offset-${min((offset + chunkSize - 1), size - 1)}/$size'; - res = await call(HttpMethod.post, - path: path, headers: headers, params: params); - offset += chunkSize; - if (offset < size) { - headers['x-appwrite-id'] = res.data['\$id']; + chunk = file.bytes!.getRange(start, end).toList(); + + final chunkParams = Map.from(params); + chunkParams[paramName] = + http.MultipartFile.fromBytes(paramName, chunk, filename: file.filename); + final chunkHeaders = Map.from(headers); + if (id != null && id.isNotEmpty) { + chunkHeaders['x-appwrite-id'] = id; } - final progress = UploadProgress( - $id: res.data['\$id'] ?? '', - progress: min(offset, size) / size * 100, - sizeUploaded: min(offset, size), - chunksTotal: res.data['chunksTotal'] ?? 0, - chunksUploaded: res.data['chunksUploaded'] ?? 0, + chunkHeaders['content-range'] = 'bytes $start-${end - 1}/$size'; + + return call( + HttpMethod.post, + path: path, + headers: chunkHeaders, + params: chunkParams, ); - onProgress?.call(progress); } - return res; + + final firstStart = offset; + final firstEnd = min(firstStart + chunkSize, size); + final firstIndex = firstStart ~/ chunkSize; + res = await uploadChunk(firstIndex, firstStart, firstEnd, uploadId); + uploadId = res.data['\$id'] ?? uploadId; + + var completedChunks = firstIndex + 1; + var uploadedBytes = firstEnd; + var lastResponse = res; + + bool isUploadComplete(Response response) { + final chunksUploaded = response.data['chunksUploaded']; + final chunksTotal = response.data['chunksTotal'] ?? totalChunks; + return chunksUploaded is num && chunksTotal is num && chunksUploaded >= chunksTotal; + } + + final progress = UploadProgress( + $id: uploadId ?? '', + progress: min(uploadedBytes, size) / size * 100, + sizeUploaded: min(uploadedBytes, size), + chunksTotal: totalChunks, + chunksUploaded: completedChunks, + ); + onProgress?.call(progress); + + final chunks = >[]; + for (var start = firstEnd; start < size; start += chunkSize) { + final end = min(start + chunkSize, size); + chunks.add({ + 'index': start ~/ chunkSize, + 'start': start, + 'end': end, + }); + } + + var nextChunk = 0; + Future uploadNext() async { + while (nextChunk < chunks.length) { + final chunk = chunks[nextChunk++]; + final chunkResponse = await uploadChunk( + chunk['index']!, + chunk['start']!, + chunk['end']!, + uploadId, + ); + completedChunks++; + uploadedBytes += chunk['end']! - chunk['start']!; + if (isUploadComplete(chunkResponse)) { + lastResponse = chunkResponse; + } + + final progress = UploadProgress( + $id: uploadId ?? '', + progress: min(uploadedBytes, size) / size * 100, + sizeUploaded: min(uploadedBytes, size), + chunksTotal: totalChunks, + chunksUploaded: completedChunks, + ); + onProgress?.call(progress); + } + } + + final concurrency = min(8, chunks.length); + await Future.wait(List.generate(concurrency, (_) => uploadNext())); + + return lastResponse; } @override diff --git a/lib/src/client_io.dart b/lib/src/client_io.dart index ec7385e9..33859923 100644 --- a/lib/src/client_io.dart +++ b/lib/src/client_io.dart @@ -20,7 +20,7 @@ ClientBase createClient({ ); class ClientIO extends ClientBase with ClientMixin { - static const int chunkSize = 5 * 1024 * 1024; + static const int chunkSize = 5*1024*1024; String _endPoint; Map? _headers; @override @@ -43,9 +43,8 @@ class ClientIO extends ClientBase with ClientMixin { 'x-sdk-platform': 'server', 'x-sdk-language': 'dart', 'x-sdk-version': '24.1.0', - 'user-agent': - 'AppwriteDartSDK/24.1.0 (${Platform.operatingSystem}; ${Platform.operatingSystemVersion})', - 'X-Appwrite-Response-Format': '1.9.5', + 'user-agent' : 'AppwriteDartSDK/24.1.0 (${Platform.operatingSystem}; ${Platform.operatingSystemVersion})', + 'X-Appwrite-Response-Format' : '1.9.5', }; config = {}; @@ -57,92 +56,82 @@ class ClientIO extends ClientBase with ClientMixin { @override String get endPoint => _endPoint; - /// Your project ID - @override - ClientIO setProject(value) { - config['project'] = value; - addHeader('X-Appwrite-Project', value); - return this; - } - - /// Your secret API key - @override - ClientIO setKey(value) { - config['key'] = value; - addHeader('X-Appwrite-Key', value); - return this; - } - - /// Your secret JSON Web Token - @override - ClientIO setJWT(value) { - config['jWT'] = value; - addHeader('X-Appwrite-JWT', value); - return this; - } - - @override - ClientIO setLocale(value) { - config['locale'] = value; - addHeader('X-Appwrite-Locale', value); - return this; - } - - /// The user session to authenticate with - @override - ClientIO setSession(value) { - config['session'] = value; - addHeader('X-Appwrite-Session', value); - return this; - } - - /// The user agent string of the client that made the request - @override - ClientIO setForwardedUserAgent(value) { - config['forwardedUserAgent'] = value; - addHeader('X-Forwarded-User-Agent', value); - return this; - } - - /// Your secret dev API key - @override - ClientIO setDevKey(value) { - config['devKey'] = value; - addHeader('X-Appwrite-Dev-Key', value); - return this; - } - - /// The user cookie to authenticate with. Used by SDKs that forward an incoming Cookie header in server-side runtimes. - @override - ClientIO setCookie(value) { - config['cookie'] = value; - addHeader('Cookie', value); - return this; - } - - /// 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. - @override - ClientIO setImpersonateUserId(value) { - config['impersonateUserId'] = value; - addHeader('X-Appwrite-Impersonate-User-Id', value); - return this; - } - - /// 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. - @override - ClientIO setImpersonateUserEmail(value) { - config['impersonateUserEmail'] = value; - addHeader('X-Appwrite-Impersonate-User-Email', value); - return this; - } - - /// 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. - @override - ClientIO setImpersonateUserPhone(value) { - config['impersonateUserPhone'] = value; - addHeader('X-Appwrite-Impersonate-User-Phone', value); - return this; - } + /// Your project ID + @override + ClientIO setProject(value) { + config['project'] = value; + addHeader('X-Appwrite-Project', value); + return this; + } + /// Your secret API key + @override + ClientIO setKey(value) { + config['key'] = value; + addHeader('X-Appwrite-Key', value); + return this; + } + /// Your secret JSON Web Token + @override + ClientIO setJWT(value) { + config['jWT'] = value; + addHeader('X-Appwrite-JWT', value); + return this; + } + @override + ClientIO setLocale(value) { + config['locale'] = value; + addHeader('X-Appwrite-Locale', value); + return this; + } + /// The user session to authenticate with + @override + ClientIO setSession(value) { + config['session'] = value; + addHeader('X-Appwrite-Session', value); + return this; + } + /// The user agent string of the client that made the request + @override + ClientIO setForwardedUserAgent(value) { + config['forwardedUserAgent'] = value; + addHeader('X-Forwarded-User-Agent', value); + return this; + } + /// Your secret dev API key + @override + ClientIO setDevKey(value) { + config['devKey'] = value; + addHeader('X-Appwrite-Dev-Key', value); + return this; + } + /// The user cookie to authenticate with. Used by SDKs that forward an incoming Cookie header in server-side runtimes. + @override + ClientIO setCookie(value) { + config['cookie'] = value; + addHeader('Cookie', value); + return this; + } + /// 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. + @override + ClientIO setImpersonateUserId(value) { + config['impersonateUserId'] = value; + addHeader('X-Appwrite-Impersonate-User-Id', value); + return this; + } + /// 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. + @override + ClientIO setImpersonateUserEmail(value) { + config['impersonateUserEmail'] = value; + addHeader('X-Appwrite-Impersonate-User-Email', value); + return this; + } + /// 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. + @override + ClientIO setImpersonateUserPhone(value) { + config['impersonateUserPhone'] = value; + addHeader('X-Appwrite-Impersonate-User-Phone', value); + return this; + } @override ClientIO setSelfSigned({bool status = true}) { @@ -217,6 +206,7 @@ class ClientIO extends ClientBase with ClientMixin { } var offset = 0; + String? uploadId; if (idParamName.isNotEmpty) { //make a request to check if a file already exists try { @@ -227,45 +217,113 @@ class ClientIO extends ClientBase with ClientMixin { ); final int chunksUploaded = res.data['chunksUploaded'] as int; offset = chunksUploaded * chunkSize; + uploadId = res.data['\$id'] ?? params[idParamName]?.toString(); } on AppwriteException catch (_) {} } - RandomAccessFile? raf; - // read chunk and upload each chunk - if (iofile != null) { - raf = await iofile.open(mode: FileMode.read); + if (offset >= size) { + return res; } - while (offset < size) { + final totalChunks = (size / chunkSize).ceil(); + + Future uploadChunk(int index, int start, int end, String? id) async { List chunk = []; if (file.bytes != null) { - final end = min(offset + chunkSize, size); - chunk = file.bytes!.getRange(offset, end).toList(); + chunk = file.bytes!.getRange(start, end).toList(); } else { - raf!.setPositionSync(offset); - chunk = raf.readSync(chunkSize); + final raf = await iofile!.open(mode: FileMode.read); + try { + await raf.setPosition(start); + chunk = await raf.read(end - start); + } finally { + await raf.close(); + } } - params[paramName] = http.MultipartFile.fromBytes(paramName, chunk, - filename: file.filename); - headers['content-range'] = - 'bytes $offset-${min((offset + chunkSize - 1), size - 1)}/$size'; - res = await call(HttpMethod.post, - path: path, headers: headers, params: params); - offset += chunkSize; - if (offset < size) { - headers['x-appwrite-id'] = res.data['\$id']; + + final chunkParams = Map.from(params); + chunkParams[paramName] = + http.MultipartFile.fromBytes(paramName, chunk, filename: file.filename); + final chunkHeaders = Map.from(headers); + if (id != null && id.isNotEmpty) { + chunkHeaders['x-appwrite-id'] = id; } - final progress = UploadProgress( - $id: res.data['\$id'] ?? '', - progress: min(offset, size) / size * 100, - sizeUploaded: min(offset, size), - chunksTotal: res.data['chunksTotal'] ?? 0, - chunksUploaded: res.data['chunksUploaded'] ?? 0, + chunkHeaders['content-range'] = 'bytes $start-${end - 1}/$size'; + + return call( + HttpMethod.post, + path: path, + headers: chunkHeaders, + params: chunkParams, ); - onProgress?.call(progress); } - raf?.close(); - return res; + + final firstStart = offset; + final firstEnd = min(firstStart + chunkSize, size); + final firstIndex = firstStart ~/ chunkSize; + res = await uploadChunk(firstIndex, firstStart, firstEnd, uploadId); + uploadId = res.data['\$id'] ?? uploadId; + + var completedChunks = firstIndex + 1; + var uploadedBytes = firstEnd; + var lastResponse = res; + + bool isUploadComplete(Response response) { + final chunksUploaded = response.data['chunksUploaded']; + final chunksTotal = response.data['chunksTotal'] ?? totalChunks; + return chunksUploaded is num && chunksTotal is num && chunksUploaded >= chunksTotal; + } + + final progress = UploadProgress( + $id: uploadId ?? '', + progress: min(uploadedBytes, size) / size * 100, + sizeUploaded: min(uploadedBytes, size), + chunksTotal: totalChunks, + chunksUploaded: completedChunks, + ); + onProgress?.call(progress); + + final chunks = >[]; + for (var start = firstEnd; start < size; start += chunkSize) { + final end = min(start + chunkSize, size); + chunks.add({ + 'index': start ~/ chunkSize, + 'start': start, + 'end': end, + }); + } + + var nextChunk = 0; + Future uploadNext() async { + while (nextChunk < chunks.length) { + final chunk = chunks[nextChunk++]; + final chunkResponse = await uploadChunk( + chunk['index']!, + chunk['start']!, + chunk['end']!, + uploadId, + ); + completedChunks++; + uploadedBytes += chunk['end']! - chunk['start']!; + if (isUploadComplete(chunkResponse)) { + lastResponse = chunkResponse; + } + + final progress = UploadProgress( + $id: uploadId ?? '', + progress: min(uploadedBytes, size) / size * 100, + sizeUploaded: min(uploadedBytes, size), + chunksTotal: totalChunks, + chunksUploaded: completedChunks, + ); + onProgress?.call(progress); + } + } + + final concurrency = min(8, chunks.length); + await Future.wait(List.generate(concurrency, (_) => uploadNext())); + + return lastResponse; } @override From 6d888934994c6211fe08a8a6b67f3690c4677df4 Mon Sep 17 00:00:00 2001 From: TorstenDittmann Date: Thu, 21 May 2026 13:21:18 +0000 Subject: [PATCH 02/13] Commit from GitHub Actions (Format and push) --- lib/src/client_browser.dart | 180 +++++++++++++++++++----------------- lib/src/client_io.dart | 180 +++++++++++++++++++----------------- 2 files changed, 194 insertions(+), 166 deletions(-) diff --git a/lib/src/client_browser.dart b/lib/src/client_browser.dart index 4dd355c1..4aff3aae 100644 --- a/lib/src/client_browser.dart +++ b/lib/src/client_browser.dart @@ -16,7 +16,7 @@ ClientBase createClient({ ClientBrowser(endPoint: endPoint, selfSigned: selfSigned); class ClientBrowser extends ClientBase with ClientMixin { - static const int chunkSize = 5*1024*1024; + static const int chunkSize = 5 * 1024 * 1024; String _endPoint; Map? _headers; @override @@ -34,7 +34,7 @@ class ClientBrowser extends ClientBase with ClientMixin { 'x-sdk-platform': 'server', 'x-sdk-language': 'dart', 'x-sdk-version': '24.1.0', - 'X-Appwrite-Response-Format' : '1.9.5', + 'X-Appwrite-Response-Format': '1.9.5', }; config = {}; @@ -46,82 +46,92 @@ class ClientBrowser extends ClientBase with ClientMixin { @override String get endPoint => _endPoint; - /// Your project ID - @override - ClientBrowser setProject(value) { - config['project'] = value; - addHeader('X-Appwrite-Project', value); - return this; - } - /// Your secret API key - @override - ClientBrowser setKey(value) { - config['key'] = value; - addHeader('X-Appwrite-Key', value); - return this; - } - /// Your secret JSON Web Token - @override - ClientBrowser setJWT(value) { - config['jWT'] = value; - addHeader('X-Appwrite-JWT', value); - return this; - } - @override - ClientBrowser setLocale(value) { - config['locale'] = value; - addHeader('X-Appwrite-Locale', value); - return this; - } - /// The user session to authenticate with - @override - ClientBrowser setSession(value) { - config['session'] = value; - addHeader('X-Appwrite-Session', value); - return this; - } - /// The user agent string of the client that made the request - @override - ClientBrowser setForwardedUserAgent(value) { - config['forwardedUserAgent'] = value; - addHeader('X-Forwarded-User-Agent', value); - return this; - } - /// Your secret dev API key - @override - ClientBrowser setDevKey(value) { - config['devKey'] = value; - addHeader('X-Appwrite-Dev-Key', value); - return this; - } - /// The user cookie to authenticate with. Used by SDKs that forward an incoming Cookie header in server-side runtimes. - @override - ClientBrowser setCookie(value) { - config['cookie'] = value; - addHeader('Cookie', value); - return this; - } - /// 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. - @override - ClientBrowser setImpersonateUserId(value) { - config['impersonateUserId'] = value; - addHeader('X-Appwrite-Impersonate-User-Id', value); - return this; - } - /// 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. - @override - ClientBrowser setImpersonateUserEmail(value) { - config['impersonateUserEmail'] = value; - addHeader('X-Appwrite-Impersonate-User-Email', value); - return this; - } - /// 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. - @override - ClientBrowser setImpersonateUserPhone(value) { - config['impersonateUserPhone'] = value; - addHeader('X-Appwrite-Impersonate-User-Phone', value); - return this; - } + /// Your project ID + @override + ClientBrowser setProject(value) { + config['project'] = value; + addHeader('X-Appwrite-Project', value); + return this; + } + + /// Your secret API key + @override + ClientBrowser setKey(value) { + config['key'] = value; + addHeader('X-Appwrite-Key', value); + return this; + } + + /// Your secret JSON Web Token + @override + ClientBrowser setJWT(value) { + config['jWT'] = value; + addHeader('X-Appwrite-JWT', value); + return this; + } + + @override + ClientBrowser setLocale(value) { + config['locale'] = value; + addHeader('X-Appwrite-Locale', value); + return this; + } + + /// The user session to authenticate with + @override + ClientBrowser setSession(value) { + config['session'] = value; + addHeader('X-Appwrite-Session', value); + return this; + } + + /// The user agent string of the client that made the request + @override + ClientBrowser setForwardedUserAgent(value) { + config['forwardedUserAgent'] = value; + addHeader('X-Forwarded-User-Agent', value); + return this; + } + + /// Your secret dev API key + @override + ClientBrowser setDevKey(value) { + config['devKey'] = value; + addHeader('X-Appwrite-Dev-Key', value); + return this; + } + + /// The user cookie to authenticate with. Used by SDKs that forward an incoming Cookie header in server-side runtimes. + @override + ClientBrowser setCookie(value) { + config['cookie'] = value; + addHeader('Cookie', value); + return this; + } + + /// 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. + @override + ClientBrowser setImpersonateUserId(value) { + config['impersonateUserId'] = value; + addHeader('X-Appwrite-Impersonate-User-Id', value); + return this; + } + + /// 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. + @override + ClientBrowser setImpersonateUserEmail(value) { + config['impersonateUserEmail'] = value; + addHeader('X-Appwrite-Impersonate-User-Email', value); + return this; + } + + /// 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. + @override + ClientBrowser setImpersonateUserPhone(value) { + config['impersonateUserPhone'] = value; + addHeader('X-Appwrite-Impersonate-User-Phone', value); + return this; + } @override ClientBrowser setSelfSigned({bool status = true}) { @@ -175,7 +185,8 @@ class ClientBrowser extends ClientBase with ClientMixin { late Response res; if (size <= chunkSize) { - params[paramName] = http.MultipartFile.fromBytes(paramName, file.bytes!, filename: file.filename); + params[paramName] = http.MultipartFile.fromBytes(paramName, file.bytes!, + filename: file.filename); return call( HttpMethod.post, path: path, @@ -206,13 +217,14 @@ class ClientBrowser extends ClientBase with ClientMixin { final totalChunks = (size / chunkSize).ceil(); - Future uploadChunk(int index, int start, int end, String? id) async { + Future uploadChunk( + int index, int start, int end, String? id) async { List chunk = []; chunk = file.bytes!.getRange(start, end).toList(); final chunkParams = Map.from(params); - chunkParams[paramName] = - http.MultipartFile.fromBytes(paramName, chunk, filename: file.filename); + chunkParams[paramName] = http.MultipartFile.fromBytes(paramName, chunk, + filename: file.filename); final chunkHeaders = Map.from(headers); if (id != null && id.isNotEmpty) { chunkHeaders['x-appwrite-id'] = id; @@ -240,7 +252,9 @@ class ClientBrowser extends ClientBase with ClientMixin { bool isUploadComplete(Response response) { final chunksUploaded = response.data['chunksUploaded']; final chunksTotal = response.data['chunksTotal'] ?? totalChunks; - return chunksUploaded is num && chunksTotal is num && chunksUploaded >= chunksTotal; + return chunksUploaded is num && + chunksTotal is num && + chunksUploaded >= chunksTotal; } final progress = UploadProgress( diff --git a/lib/src/client_io.dart b/lib/src/client_io.dart index 33859923..46d9633f 100644 --- a/lib/src/client_io.dart +++ b/lib/src/client_io.dart @@ -20,7 +20,7 @@ ClientBase createClient({ ); class ClientIO extends ClientBase with ClientMixin { - static const int chunkSize = 5*1024*1024; + static const int chunkSize = 5 * 1024 * 1024; String _endPoint; Map? _headers; @override @@ -43,8 +43,9 @@ class ClientIO extends ClientBase with ClientMixin { 'x-sdk-platform': 'server', 'x-sdk-language': 'dart', 'x-sdk-version': '24.1.0', - 'user-agent' : 'AppwriteDartSDK/24.1.0 (${Platform.operatingSystem}; ${Platform.operatingSystemVersion})', - 'X-Appwrite-Response-Format' : '1.9.5', + 'user-agent': + 'AppwriteDartSDK/24.1.0 (${Platform.operatingSystem}; ${Platform.operatingSystemVersion})', + 'X-Appwrite-Response-Format': '1.9.5', }; config = {}; @@ -56,82 +57,92 @@ class ClientIO extends ClientBase with ClientMixin { @override String get endPoint => _endPoint; - /// Your project ID - @override - ClientIO setProject(value) { - config['project'] = value; - addHeader('X-Appwrite-Project', value); - return this; - } - /// Your secret API key - @override - ClientIO setKey(value) { - config['key'] = value; - addHeader('X-Appwrite-Key', value); - return this; - } - /// Your secret JSON Web Token - @override - ClientIO setJWT(value) { - config['jWT'] = value; - addHeader('X-Appwrite-JWT', value); - return this; - } - @override - ClientIO setLocale(value) { - config['locale'] = value; - addHeader('X-Appwrite-Locale', value); - return this; - } - /// The user session to authenticate with - @override - ClientIO setSession(value) { - config['session'] = value; - addHeader('X-Appwrite-Session', value); - return this; - } - /// The user agent string of the client that made the request - @override - ClientIO setForwardedUserAgent(value) { - config['forwardedUserAgent'] = value; - addHeader('X-Forwarded-User-Agent', value); - return this; - } - /// Your secret dev API key - @override - ClientIO setDevKey(value) { - config['devKey'] = value; - addHeader('X-Appwrite-Dev-Key', value); - return this; - } - /// The user cookie to authenticate with. Used by SDKs that forward an incoming Cookie header in server-side runtimes. - @override - ClientIO setCookie(value) { - config['cookie'] = value; - addHeader('Cookie', value); - return this; - } - /// 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. - @override - ClientIO setImpersonateUserId(value) { - config['impersonateUserId'] = value; - addHeader('X-Appwrite-Impersonate-User-Id', value); - return this; - } - /// 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. - @override - ClientIO setImpersonateUserEmail(value) { - config['impersonateUserEmail'] = value; - addHeader('X-Appwrite-Impersonate-User-Email', value); - return this; - } - /// 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. - @override - ClientIO setImpersonateUserPhone(value) { - config['impersonateUserPhone'] = value; - addHeader('X-Appwrite-Impersonate-User-Phone', value); - return this; - } + /// Your project ID + @override + ClientIO setProject(value) { + config['project'] = value; + addHeader('X-Appwrite-Project', value); + return this; + } + + /// Your secret API key + @override + ClientIO setKey(value) { + config['key'] = value; + addHeader('X-Appwrite-Key', value); + return this; + } + + /// Your secret JSON Web Token + @override + ClientIO setJWT(value) { + config['jWT'] = value; + addHeader('X-Appwrite-JWT', value); + return this; + } + + @override + ClientIO setLocale(value) { + config['locale'] = value; + addHeader('X-Appwrite-Locale', value); + return this; + } + + /// The user session to authenticate with + @override + ClientIO setSession(value) { + config['session'] = value; + addHeader('X-Appwrite-Session', value); + return this; + } + + /// The user agent string of the client that made the request + @override + ClientIO setForwardedUserAgent(value) { + config['forwardedUserAgent'] = value; + addHeader('X-Forwarded-User-Agent', value); + return this; + } + + /// Your secret dev API key + @override + ClientIO setDevKey(value) { + config['devKey'] = value; + addHeader('X-Appwrite-Dev-Key', value); + return this; + } + + /// The user cookie to authenticate with. Used by SDKs that forward an incoming Cookie header in server-side runtimes. + @override + ClientIO setCookie(value) { + config['cookie'] = value; + addHeader('Cookie', value); + return this; + } + + /// 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. + @override + ClientIO setImpersonateUserId(value) { + config['impersonateUserId'] = value; + addHeader('X-Appwrite-Impersonate-User-Id', value); + return this; + } + + /// 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. + @override + ClientIO setImpersonateUserEmail(value) { + config['impersonateUserEmail'] = value; + addHeader('X-Appwrite-Impersonate-User-Email', value); + return this; + } + + /// 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. + @override + ClientIO setImpersonateUserPhone(value) { + config['impersonateUserPhone'] = value; + addHeader('X-Appwrite-Impersonate-User-Phone', value); + return this; + } @override ClientIO setSelfSigned({bool status = true}) { @@ -227,7 +238,8 @@ class ClientIO extends ClientBase with ClientMixin { final totalChunks = (size / chunkSize).ceil(); - Future uploadChunk(int index, int start, int end, String? id) async { + Future uploadChunk( + int index, int start, int end, String? id) async { List chunk = []; if (file.bytes != null) { chunk = file.bytes!.getRange(start, end).toList(); @@ -242,8 +254,8 @@ class ClientIO extends ClientBase with ClientMixin { } final chunkParams = Map.from(params); - chunkParams[paramName] = - http.MultipartFile.fromBytes(paramName, chunk, filename: file.filename); + chunkParams[paramName] = http.MultipartFile.fromBytes(paramName, chunk, + filename: file.filename); final chunkHeaders = Map.from(headers); if (id != null && id.isNotEmpty) { chunkHeaders['x-appwrite-id'] = id; @@ -271,7 +283,9 @@ class ClientIO extends ClientBase with ClientMixin { bool isUploadComplete(Response response) { final chunksUploaded = response.data['chunksUploaded']; final chunksTotal = response.data['chunksTotal'] ?? totalChunks; - return chunksUploaded is num && chunksTotal is num && chunksUploaded >= chunksTotal; + return chunksUploaded is num && + chunksTotal is num && + chunksUploaded >= chunksTotal; } final progress = UploadProgress( From 13c8f559bc18f459786e7326f2be4f5cd400efb1 Mon Sep 17 00:00:00 2001 From: Torsten Dittmann Date: Thu, 21 May 2026 20:42:42 +0400 Subject: [PATCH 03/13] feat: support concurrent chunk uploads --- lib/src/client_browser.dart | 180 +++++++++++++++++------------------- lib/src/client_io.dart | 180 +++++++++++++++++------------------- 2 files changed, 166 insertions(+), 194 deletions(-) diff --git a/lib/src/client_browser.dart b/lib/src/client_browser.dart index 4aff3aae..4dd355c1 100644 --- a/lib/src/client_browser.dart +++ b/lib/src/client_browser.dart @@ -16,7 +16,7 @@ ClientBase createClient({ ClientBrowser(endPoint: endPoint, selfSigned: selfSigned); class ClientBrowser extends ClientBase with ClientMixin { - static const int chunkSize = 5 * 1024 * 1024; + static const int chunkSize = 5*1024*1024; String _endPoint; Map? _headers; @override @@ -34,7 +34,7 @@ class ClientBrowser extends ClientBase with ClientMixin { 'x-sdk-platform': 'server', 'x-sdk-language': 'dart', 'x-sdk-version': '24.1.0', - 'X-Appwrite-Response-Format': '1.9.5', + 'X-Appwrite-Response-Format' : '1.9.5', }; config = {}; @@ -46,92 +46,82 @@ class ClientBrowser extends ClientBase with ClientMixin { @override String get endPoint => _endPoint; - /// Your project ID - @override - ClientBrowser setProject(value) { - config['project'] = value; - addHeader('X-Appwrite-Project', value); - return this; - } - - /// Your secret API key - @override - ClientBrowser setKey(value) { - config['key'] = value; - addHeader('X-Appwrite-Key', value); - return this; - } - - /// Your secret JSON Web Token - @override - ClientBrowser setJWT(value) { - config['jWT'] = value; - addHeader('X-Appwrite-JWT', value); - return this; - } - - @override - ClientBrowser setLocale(value) { - config['locale'] = value; - addHeader('X-Appwrite-Locale', value); - return this; - } - - /// The user session to authenticate with - @override - ClientBrowser setSession(value) { - config['session'] = value; - addHeader('X-Appwrite-Session', value); - return this; - } - - /// The user agent string of the client that made the request - @override - ClientBrowser setForwardedUserAgent(value) { - config['forwardedUserAgent'] = value; - addHeader('X-Forwarded-User-Agent', value); - return this; - } - - /// Your secret dev API key - @override - ClientBrowser setDevKey(value) { - config['devKey'] = value; - addHeader('X-Appwrite-Dev-Key', value); - return this; - } - - /// The user cookie to authenticate with. Used by SDKs that forward an incoming Cookie header in server-side runtimes. - @override - ClientBrowser setCookie(value) { - config['cookie'] = value; - addHeader('Cookie', value); - return this; - } - - /// 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. - @override - ClientBrowser setImpersonateUserId(value) { - config['impersonateUserId'] = value; - addHeader('X-Appwrite-Impersonate-User-Id', value); - return this; - } - - /// 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. - @override - ClientBrowser setImpersonateUserEmail(value) { - config['impersonateUserEmail'] = value; - addHeader('X-Appwrite-Impersonate-User-Email', value); - return this; - } - - /// 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. - @override - ClientBrowser setImpersonateUserPhone(value) { - config['impersonateUserPhone'] = value; - addHeader('X-Appwrite-Impersonate-User-Phone', value); - return this; - } + /// Your project ID + @override + ClientBrowser setProject(value) { + config['project'] = value; + addHeader('X-Appwrite-Project', value); + return this; + } + /// Your secret API key + @override + ClientBrowser setKey(value) { + config['key'] = value; + addHeader('X-Appwrite-Key', value); + return this; + } + /// Your secret JSON Web Token + @override + ClientBrowser setJWT(value) { + config['jWT'] = value; + addHeader('X-Appwrite-JWT', value); + return this; + } + @override + ClientBrowser setLocale(value) { + config['locale'] = value; + addHeader('X-Appwrite-Locale', value); + return this; + } + /// The user session to authenticate with + @override + ClientBrowser setSession(value) { + config['session'] = value; + addHeader('X-Appwrite-Session', value); + return this; + } + /// The user agent string of the client that made the request + @override + ClientBrowser setForwardedUserAgent(value) { + config['forwardedUserAgent'] = value; + addHeader('X-Forwarded-User-Agent', value); + return this; + } + /// Your secret dev API key + @override + ClientBrowser setDevKey(value) { + config['devKey'] = value; + addHeader('X-Appwrite-Dev-Key', value); + return this; + } + /// The user cookie to authenticate with. Used by SDKs that forward an incoming Cookie header in server-side runtimes. + @override + ClientBrowser setCookie(value) { + config['cookie'] = value; + addHeader('Cookie', value); + return this; + } + /// 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. + @override + ClientBrowser setImpersonateUserId(value) { + config['impersonateUserId'] = value; + addHeader('X-Appwrite-Impersonate-User-Id', value); + return this; + } + /// 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. + @override + ClientBrowser setImpersonateUserEmail(value) { + config['impersonateUserEmail'] = value; + addHeader('X-Appwrite-Impersonate-User-Email', value); + return this; + } + /// 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. + @override + ClientBrowser setImpersonateUserPhone(value) { + config['impersonateUserPhone'] = value; + addHeader('X-Appwrite-Impersonate-User-Phone', value); + return this; + } @override ClientBrowser setSelfSigned({bool status = true}) { @@ -185,8 +175,7 @@ class ClientBrowser extends ClientBase with ClientMixin { late Response res; if (size <= chunkSize) { - params[paramName] = http.MultipartFile.fromBytes(paramName, file.bytes!, - filename: file.filename); + params[paramName] = http.MultipartFile.fromBytes(paramName, file.bytes!, filename: file.filename); return call( HttpMethod.post, path: path, @@ -217,14 +206,13 @@ class ClientBrowser extends ClientBase with ClientMixin { final totalChunks = (size / chunkSize).ceil(); - Future uploadChunk( - int index, int start, int end, String? id) async { + Future uploadChunk(int index, int start, int end, String? id) async { List chunk = []; chunk = file.bytes!.getRange(start, end).toList(); final chunkParams = Map.from(params); - chunkParams[paramName] = http.MultipartFile.fromBytes(paramName, chunk, - filename: file.filename); + chunkParams[paramName] = + http.MultipartFile.fromBytes(paramName, chunk, filename: file.filename); final chunkHeaders = Map.from(headers); if (id != null && id.isNotEmpty) { chunkHeaders['x-appwrite-id'] = id; @@ -252,9 +240,7 @@ class ClientBrowser extends ClientBase with ClientMixin { bool isUploadComplete(Response response) { final chunksUploaded = response.data['chunksUploaded']; final chunksTotal = response.data['chunksTotal'] ?? totalChunks; - return chunksUploaded is num && - chunksTotal is num && - chunksUploaded >= chunksTotal; + return chunksUploaded is num && chunksTotal is num && chunksUploaded >= chunksTotal; } final progress = UploadProgress( diff --git a/lib/src/client_io.dart b/lib/src/client_io.dart index 46d9633f..33859923 100644 --- a/lib/src/client_io.dart +++ b/lib/src/client_io.dart @@ -20,7 +20,7 @@ ClientBase createClient({ ); class ClientIO extends ClientBase with ClientMixin { - static const int chunkSize = 5 * 1024 * 1024; + static const int chunkSize = 5*1024*1024; String _endPoint; Map? _headers; @override @@ -43,9 +43,8 @@ class ClientIO extends ClientBase with ClientMixin { 'x-sdk-platform': 'server', 'x-sdk-language': 'dart', 'x-sdk-version': '24.1.0', - 'user-agent': - 'AppwriteDartSDK/24.1.0 (${Platform.operatingSystem}; ${Platform.operatingSystemVersion})', - 'X-Appwrite-Response-Format': '1.9.5', + 'user-agent' : 'AppwriteDartSDK/24.1.0 (${Platform.operatingSystem}; ${Platform.operatingSystemVersion})', + 'X-Appwrite-Response-Format' : '1.9.5', }; config = {}; @@ -57,92 +56,82 @@ class ClientIO extends ClientBase with ClientMixin { @override String get endPoint => _endPoint; - /// Your project ID - @override - ClientIO setProject(value) { - config['project'] = value; - addHeader('X-Appwrite-Project', value); - return this; - } - - /// Your secret API key - @override - ClientIO setKey(value) { - config['key'] = value; - addHeader('X-Appwrite-Key', value); - return this; - } - - /// Your secret JSON Web Token - @override - ClientIO setJWT(value) { - config['jWT'] = value; - addHeader('X-Appwrite-JWT', value); - return this; - } - - @override - ClientIO setLocale(value) { - config['locale'] = value; - addHeader('X-Appwrite-Locale', value); - return this; - } - - /// The user session to authenticate with - @override - ClientIO setSession(value) { - config['session'] = value; - addHeader('X-Appwrite-Session', value); - return this; - } - - /// The user agent string of the client that made the request - @override - ClientIO setForwardedUserAgent(value) { - config['forwardedUserAgent'] = value; - addHeader('X-Forwarded-User-Agent', value); - return this; - } - - /// Your secret dev API key - @override - ClientIO setDevKey(value) { - config['devKey'] = value; - addHeader('X-Appwrite-Dev-Key', value); - return this; - } - - /// The user cookie to authenticate with. Used by SDKs that forward an incoming Cookie header in server-side runtimes. - @override - ClientIO setCookie(value) { - config['cookie'] = value; - addHeader('Cookie', value); - return this; - } - - /// 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. - @override - ClientIO setImpersonateUserId(value) { - config['impersonateUserId'] = value; - addHeader('X-Appwrite-Impersonate-User-Id', value); - return this; - } - - /// 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. - @override - ClientIO setImpersonateUserEmail(value) { - config['impersonateUserEmail'] = value; - addHeader('X-Appwrite-Impersonate-User-Email', value); - return this; - } - - /// 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. - @override - ClientIO setImpersonateUserPhone(value) { - config['impersonateUserPhone'] = value; - addHeader('X-Appwrite-Impersonate-User-Phone', value); - return this; - } + /// Your project ID + @override + ClientIO setProject(value) { + config['project'] = value; + addHeader('X-Appwrite-Project', value); + return this; + } + /// Your secret API key + @override + ClientIO setKey(value) { + config['key'] = value; + addHeader('X-Appwrite-Key', value); + return this; + } + /// Your secret JSON Web Token + @override + ClientIO setJWT(value) { + config['jWT'] = value; + addHeader('X-Appwrite-JWT', value); + return this; + } + @override + ClientIO setLocale(value) { + config['locale'] = value; + addHeader('X-Appwrite-Locale', value); + return this; + } + /// The user session to authenticate with + @override + ClientIO setSession(value) { + config['session'] = value; + addHeader('X-Appwrite-Session', value); + return this; + } + /// The user agent string of the client that made the request + @override + ClientIO setForwardedUserAgent(value) { + config['forwardedUserAgent'] = value; + addHeader('X-Forwarded-User-Agent', value); + return this; + } + /// Your secret dev API key + @override + ClientIO setDevKey(value) { + config['devKey'] = value; + addHeader('X-Appwrite-Dev-Key', value); + return this; + } + /// The user cookie to authenticate with. Used by SDKs that forward an incoming Cookie header in server-side runtimes. + @override + ClientIO setCookie(value) { + config['cookie'] = value; + addHeader('Cookie', value); + return this; + } + /// 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. + @override + ClientIO setImpersonateUserId(value) { + config['impersonateUserId'] = value; + addHeader('X-Appwrite-Impersonate-User-Id', value); + return this; + } + /// 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. + @override + ClientIO setImpersonateUserEmail(value) { + config['impersonateUserEmail'] = value; + addHeader('X-Appwrite-Impersonate-User-Email', value); + return this; + } + /// 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. + @override + ClientIO setImpersonateUserPhone(value) { + config['impersonateUserPhone'] = value; + addHeader('X-Appwrite-Impersonate-User-Phone', value); + return this; + } @override ClientIO setSelfSigned({bool status = true}) { @@ -238,8 +227,7 @@ class ClientIO extends ClientBase with ClientMixin { final totalChunks = (size / chunkSize).ceil(); - Future uploadChunk( - int index, int start, int end, String? id) async { + Future uploadChunk(int index, int start, int end, String? id) async { List chunk = []; if (file.bytes != null) { chunk = file.bytes!.getRange(start, end).toList(); @@ -254,8 +242,8 @@ class ClientIO extends ClientBase with ClientMixin { } final chunkParams = Map.from(params); - chunkParams[paramName] = http.MultipartFile.fromBytes(paramName, chunk, - filename: file.filename); + chunkParams[paramName] = + http.MultipartFile.fromBytes(paramName, chunk, filename: file.filename); final chunkHeaders = Map.from(headers); if (id != null && id.isNotEmpty) { chunkHeaders['x-appwrite-id'] = id; @@ -283,9 +271,7 @@ class ClientIO extends ClientBase with ClientMixin { bool isUploadComplete(Response response) { final chunksUploaded = response.data['chunksUploaded']; final chunksTotal = response.data['chunksTotal'] ?? totalChunks; - return chunksUploaded is num && - chunksTotal is num && - chunksUploaded >= chunksTotal; + return chunksUploaded is num && chunksTotal is num && chunksUploaded >= chunksTotal; } final progress = UploadProgress( From 3ef20d6c4ec9bc37127fbbe967284c5644aa7faf Mon Sep 17 00:00:00 2001 From: TorstenDittmann Date: Thu, 21 May 2026 16:43:14 +0000 Subject: [PATCH 04/13] Commit from GitHub Actions (Format and push) --- lib/src/client_browser.dart | 180 +++++++++++++++++++----------------- lib/src/client_io.dart | 180 +++++++++++++++++++----------------- 2 files changed, 194 insertions(+), 166 deletions(-) diff --git a/lib/src/client_browser.dart b/lib/src/client_browser.dart index 4dd355c1..4aff3aae 100644 --- a/lib/src/client_browser.dart +++ b/lib/src/client_browser.dart @@ -16,7 +16,7 @@ ClientBase createClient({ ClientBrowser(endPoint: endPoint, selfSigned: selfSigned); class ClientBrowser extends ClientBase with ClientMixin { - static const int chunkSize = 5*1024*1024; + static const int chunkSize = 5 * 1024 * 1024; String _endPoint; Map? _headers; @override @@ -34,7 +34,7 @@ class ClientBrowser extends ClientBase with ClientMixin { 'x-sdk-platform': 'server', 'x-sdk-language': 'dart', 'x-sdk-version': '24.1.0', - 'X-Appwrite-Response-Format' : '1.9.5', + 'X-Appwrite-Response-Format': '1.9.5', }; config = {}; @@ -46,82 +46,92 @@ class ClientBrowser extends ClientBase with ClientMixin { @override String get endPoint => _endPoint; - /// Your project ID - @override - ClientBrowser setProject(value) { - config['project'] = value; - addHeader('X-Appwrite-Project', value); - return this; - } - /// Your secret API key - @override - ClientBrowser setKey(value) { - config['key'] = value; - addHeader('X-Appwrite-Key', value); - return this; - } - /// Your secret JSON Web Token - @override - ClientBrowser setJWT(value) { - config['jWT'] = value; - addHeader('X-Appwrite-JWT', value); - return this; - } - @override - ClientBrowser setLocale(value) { - config['locale'] = value; - addHeader('X-Appwrite-Locale', value); - return this; - } - /// The user session to authenticate with - @override - ClientBrowser setSession(value) { - config['session'] = value; - addHeader('X-Appwrite-Session', value); - return this; - } - /// The user agent string of the client that made the request - @override - ClientBrowser setForwardedUserAgent(value) { - config['forwardedUserAgent'] = value; - addHeader('X-Forwarded-User-Agent', value); - return this; - } - /// Your secret dev API key - @override - ClientBrowser setDevKey(value) { - config['devKey'] = value; - addHeader('X-Appwrite-Dev-Key', value); - return this; - } - /// The user cookie to authenticate with. Used by SDKs that forward an incoming Cookie header in server-side runtimes. - @override - ClientBrowser setCookie(value) { - config['cookie'] = value; - addHeader('Cookie', value); - return this; - } - /// 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. - @override - ClientBrowser setImpersonateUserId(value) { - config['impersonateUserId'] = value; - addHeader('X-Appwrite-Impersonate-User-Id', value); - return this; - } - /// 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. - @override - ClientBrowser setImpersonateUserEmail(value) { - config['impersonateUserEmail'] = value; - addHeader('X-Appwrite-Impersonate-User-Email', value); - return this; - } - /// 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. - @override - ClientBrowser setImpersonateUserPhone(value) { - config['impersonateUserPhone'] = value; - addHeader('X-Appwrite-Impersonate-User-Phone', value); - return this; - } + /// Your project ID + @override + ClientBrowser setProject(value) { + config['project'] = value; + addHeader('X-Appwrite-Project', value); + return this; + } + + /// Your secret API key + @override + ClientBrowser setKey(value) { + config['key'] = value; + addHeader('X-Appwrite-Key', value); + return this; + } + + /// Your secret JSON Web Token + @override + ClientBrowser setJWT(value) { + config['jWT'] = value; + addHeader('X-Appwrite-JWT', value); + return this; + } + + @override + ClientBrowser setLocale(value) { + config['locale'] = value; + addHeader('X-Appwrite-Locale', value); + return this; + } + + /// The user session to authenticate with + @override + ClientBrowser setSession(value) { + config['session'] = value; + addHeader('X-Appwrite-Session', value); + return this; + } + + /// The user agent string of the client that made the request + @override + ClientBrowser setForwardedUserAgent(value) { + config['forwardedUserAgent'] = value; + addHeader('X-Forwarded-User-Agent', value); + return this; + } + + /// Your secret dev API key + @override + ClientBrowser setDevKey(value) { + config['devKey'] = value; + addHeader('X-Appwrite-Dev-Key', value); + return this; + } + + /// The user cookie to authenticate with. Used by SDKs that forward an incoming Cookie header in server-side runtimes. + @override + ClientBrowser setCookie(value) { + config['cookie'] = value; + addHeader('Cookie', value); + return this; + } + + /// 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. + @override + ClientBrowser setImpersonateUserId(value) { + config['impersonateUserId'] = value; + addHeader('X-Appwrite-Impersonate-User-Id', value); + return this; + } + + /// 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. + @override + ClientBrowser setImpersonateUserEmail(value) { + config['impersonateUserEmail'] = value; + addHeader('X-Appwrite-Impersonate-User-Email', value); + return this; + } + + /// 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. + @override + ClientBrowser setImpersonateUserPhone(value) { + config['impersonateUserPhone'] = value; + addHeader('X-Appwrite-Impersonate-User-Phone', value); + return this; + } @override ClientBrowser setSelfSigned({bool status = true}) { @@ -175,7 +185,8 @@ class ClientBrowser extends ClientBase with ClientMixin { late Response res; if (size <= chunkSize) { - params[paramName] = http.MultipartFile.fromBytes(paramName, file.bytes!, filename: file.filename); + params[paramName] = http.MultipartFile.fromBytes(paramName, file.bytes!, + filename: file.filename); return call( HttpMethod.post, path: path, @@ -206,13 +217,14 @@ class ClientBrowser extends ClientBase with ClientMixin { final totalChunks = (size / chunkSize).ceil(); - Future uploadChunk(int index, int start, int end, String? id) async { + Future uploadChunk( + int index, int start, int end, String? id) async { List chunk = []; chunk = file.bytes!.getRange(start, end).toList(); final chunkParams = Map.from(params); - chunkParams[paramName] = - http.MultipartFile.fromBytes(paramName, chunk, filename: file.filename); + chunkParams[paramName] = http.MultipartFile.fromBytes(paramName, chunk, + filename: file.filename); final chunkHeaders = Map.from(headers); if (id != null && id.isNotEmpty) { chunkHeaders['x-appwrite-id'] = id; @@ -240,7 +252,9 @@ class ClientBrowser extends ClientBase with ClientMixin { bool isUploadComplete(Response response) { final chunksUploaded = response.data['chunksUploaded']; final chunksTotal = response.data['chunksTotal'] ?? totalChunks; - return chunksUploaded is num && chunksTotal is num && chunksUploaded >= chunksTotal; + return chunksUploaded is num && + chunksTotal is num && + chunksUploaded >= chunksTotal; } final progress = UploadProgress( diff --git a/lib/src/client_io.dart b/lib/src/client_io.dart index 33859923..46d9633f 100644 --- a/lib/src/client_io.dart +++ b/lib/src/client_io.dart @@ -20,7 +20,7 @@ ClientBase createClient({ ); class ClientIO extends ClientBase with ClientMixin { - static const int chunkSize = 5*1024*1024; + static const int chunkSize = 5 * 1024 * 1024; String _endPoint; Map? _headers; @override @@ -43,8 +43,9 @@ class ClientIO extends ClientBase with ClientMixin { 'x-sdk-platform': 'server', 'x-sdk-language': 'dart', 'x-sdk-version': '24.1.0', - 'user-agent' : 'AppwriteDartSDK/24.1.0 (${Platform.operatingSystem}; ${Platform.operatingSystemVersion})', - 'X-Appwrite-Response-Format' : '1.9.5', + 'user-agent': + 'AppwriteDartSDK/24.1.0 (${Platform.operatingSystem}; ${Platform.operatingSystemVersion})', + 'X-Appwrite-Response-Format': '1.9.5', }; config = {}; @@ -56,82 +57,92 @@ class ClientIO extends ClientBase with ClientMixin { @override String get endPoint => _endPoint; - /// Your project ID - @override - ClientIO setProject(value) { - config['project'] = value; - addHeader('X-Appwrite-Project', value); - return this; - } - /// Your secret API key - @override - ClientIO setKey(value) { - config['key'] = value; - addHeader('X-Appwrite-Key', value); - return this; - } - /// Your secret JSON Web Token - @override - ClientIO setJWT(value) { - config['jWT'] = value; - addHeader('X-Appwrite-JWT', value); - return this; - } - @override - ClientIO setLocale(value) { - config['locale'] = value; - addHeader('X-Appwrite-Locale', value); - return this; - } - /// The user session to authenticate with - @override - ClientIO setSession(value) { - config['session'] = value; - addHeader('X-Appwrite-Session', value); - return this; - } - /// The user agent string of the client that made the request - @override - ClientIO setForwardedUserAgent(value) { - config['forwardedUserAgent'] = value; - addHeader('X-Forwarded-User-Agent', value); - return this; - } - /// Your secret dev API key - @override - ClientIO setDevKey(value) { - config['devKey'] = value; - addHeader('X-Appwrite-Dev-Key', value); - return this; - } - /// The user cookie to authenticate with. Used by SDKs that forward an incoming Cookie header in server-side runtimes. - @override - ClientIO setCookie(value) { - config['cookie'] = value; - addHeader('Cookie', value); - return this; - } - /// 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. - @override - ClientIO setImpersonateUserId(value) { - config['impersonateUserId'] = value; - addHeader('X-Appwrite-Impersonate-User-Id', value); - return this; - } - /// 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. - @override - ClientIO setImpersonateUserEmail(value) { - config['impersonateUserEmail'] = value; - addHeader('X-Appwrite-Impersonate-User-Email', value); - return this; - } - /// 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. - @override - ClientIO setImpersonateUserPhone(value) { - config['impersonateUserPhone'] = value; - addHeader('X-Appwrite-Impersonate-User-Phone', value); - return this; - } + /// Your project ID + @override + ClientIO setProject(value) { + config['project'] = value; + addHeader('X-Appwrite-Project', value); + return this; + } + + /// Your secret API key + @override + ClientIO setKey(value) { + config['key'] = value; + addHeader('X-Appwrite-Key', value); + return this; + } + + /// Your secret JSON Web Token + @override + ClientIO setJWT(value) { + config['jWT'] = value; + addHeader('X-Appwrite-JWT', value); + return this; + } + + @override + ClientIO setLocale(value) { + config['locale'] = value; + addHeader('X-Appwrite-Locale', value); + return this; + } + + /// The user session to authenticate with + @override + ClientIO setSession(value) { + config['session'] = value; + addHeader('X-Appwrite-Session', value); + return this; + } + + /// The user agent string of the client that made the request + @override + ClientIO setForwardedUserAgent(value) { + config['forwardedUserAgent'] = value; + addHeader('X-Forwarded-User-Agent', value); + return this; + } + + /// Your secret dev API key + @override + ClientIO setDevKey(value) { + config['devKey'] = value; + addHeader('X-Appwrite-Dev-Key', value); + return this; + } + + /// The user cookie to authenticate with. Used by SDKs that forward an incoming Cookie header in server-side runtimes. + @override + ClientIO setCookie(value) { + config['cookie'] = value; + addHeader('Cookie', value); + return this; + } + + /// 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. + @override + ClientIO setImpersonateUserId(value) { + config['impersonateUserId'] = value; + addHeader('X-Appwrite-Impersonate-User-Id', value); + return this; + } + + /// 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. + @override + ClientIO setImpersonateUserEmail(value) { + config['impersonateUserEmail'] = value; + addHeader('X-Appwrite-Impersonate-User-Email', value); + return this; + } + + /// 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. + @override + ClientIO setImpersonateUserPhone(value) { + config['impersonateUserPhone'] = value; + addHeader('X-Appwrite-Impersonate-User-Phone', value); + return this; + } @override ClientIO setSelfSigned({bool status = true}) { @@ -227,7 +238,8 @@ class ClientIO extends ClientBase with ClientMixin { final totalChunks = (size / chunkSize).ceil(); - Future uploadChunk(int index, int start, int end, String? id) async { + Future uploadChunk( + int index, int start, int end, String? id) async { List chunk = []; if (file.bytes != null) { chunk = file.bytes!.getRange(start, end).toList(); @@ -242,8 +254,8 @@ class ClientIO extends ClientBase with ClientMixin { } final chunkParams = Map.from(params); - chunkParams[paramName] = - http.MultipartFile.fromBytes(paramName, chunk, filename: file.filename); + chunkParams[paramName] = http.MultipartFile.fromBytes(paramName, chunk, + filename: file.filename); final chunkHeaders = Map.from(headers); if (id != null && id.isNotEmpty) { chunkHeaders['x-appwrite-id'] = id; @@ -271,7 +283,9 @@ class ClientIO extends ClientBase with ClientMixin { bool isUploadComplete(Response response) { final chunksUploaded = response.data['chunksUploaded']; final chunksTotal = response.data['chunksTotal'] ?? totalChunks; - return chunksUploaded is num && chunksTotal is num && chunksUploaded >= chunksTotal; + return chunksUploaded is num && + chunksTotal is num && + chunksUploaded >= chunksTotal; } final progress = UploadProgress( From 103bf091a4f2285cdfcff808d490ac2eff735436 Mon Sep 17 00:00:00 2001 From: Torsten Dittmann Date: Thu, 21 May 2026 20:46:31 +0400 Subject: [PATCH 05/13] feat: support concurrent chunk uploads --- lib/src/client_browser.dart | 186 +++++++++++++-------------- lib/src/client_io.dart | 244 ++++++++++++++++++------------------ 2 files changed, 209 insertions(+), 221 deletions(-) diff --git a/lib/src/client_browser.dart b/lib/src/client_browser.dart index 4aff3aae..1ed26c56 100644 --- a/lib/src/client_browser.dart +++ b/lib/src/client_browser.dart @@ -16,7 +16,7 @@ ClientBase createClient({ ClientBrowser(endPoint: endPoint, selfSigned: selfSigned); class ClientBrowser extends ClientBase with ClientMixin { - static const int chunkSize = 5 * 1024 * 1024; + static const int chunkSize = 5*1024*1024; String _endPoint; Map? _headers; @override @@ -34,7 +34,7 @@ class ClientBrowser extends ClientBase with ClientMixin { 'x-sdk-platform': 'server', 'x-sdk-language': 'dart', 'x-sdk-version': '24.1.0', - 'X-Appwrite-Response-Format': '1.9.5', + 'X-Appwrite-Response-Format' : '1.9.5', }; config = {}; @@ -46,92 +46,82 @@ class ClientBrowser extends ClientBase with ClientMixin { @override String get endPoint => _endPoint; - /// Your project ID - @override - ClientBrowser setProject(value) { - config['project'] = value; - addHeader('X-Appwrite-Project', value); - return this; - } - - /// Your secret API key - @override - ClientBrowser setKey(value) { - config['key'] = value; - addHeader('X-Appwrite-Key', value); - return this; - } - - /// Your secret JSON Web Token - @override - ClientBrowser setJWT(value) { - config['jWT'] = value; - addHeader('X-Appwrite-JWT', value); - return this; - } - - @override - ClientBrowser setLocale(value) { - config['locale'] = value; - addHeader('X-Appwrite-Locale', value); - return this; - } - - /// The user session to authenticate with - @override - ClientBrowser setSession(value) { - config['session'] = value; - addHeader('X-Appwrite-Session', value); - return this; - } - - /// The user agent string of the client that made the request - @override - ClientBrowser setForwardedUserAgent(value) { - config['forwardedUserAgent'] = value; - addHeader('X-Forwarded-User-Agent', value); - return this; - } - - /// Your secret dev API key - @override - ClientBrowser setDevKey(value) { - config['devKey'] = value; - addHeader('X-Appwrite-Dev-Key', value); - return this; - } - - /// The user cookie to authenticate with. Used by SDKs that forward an incoming Cookie header in server-side runtimes. - @override - ClientBrowser setCookie(value) { - config['cookie'] = value; - addHeader('Cookie', value); - return this; - } - - /// 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. - @override - ClientBrowser setImpersonateUserId(value) { - config['impersonateUserId'] = value; - addHeader('X-Appwrite-Impersonate-User-Id', value); - return this; - } - - /// 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. - @override - ClientBrowser setImpersonateUserEmail(value) { - config['impersonateUserEmail'] = value; - addHeader('X-Appwrite-Impersonate-User-Email', value); - return this; - } - - /// 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. - @override - ClientBrowser setImpersonateUserPhone(value) { - config['impersonateUserPhone'] = value; - addHeader('X-Appwrite-Impersonate-User-Phone', value); - return this; - } + /// Your project ID + @override + ClientBrowser setProject(value) { + config['project'] = value; + addHeader('X-Appwrite-Project', value); + return this; + } + /// Your secret API key + @override + ClientBrowser setKey(value) { + config['key'] = value; + addHeader('X-Appwrite-Key', value); + return this; + } + /// Your secret JSON Web Token + @override + ClientBrowser setJWT(value) { + config['jWT'] = value; + addHeader('X-Appwrite-JWT', value); + return this; + } + @override + ClientBrowser setLocale(value) { + config['locale'] = value; + addHeader('X-Appwrite-Locale', value); + return this; + } + /// The user session to authenticate with + @override + ClientBrowser setSession(value) { + config['session'] = value; + addHeader('X-Appwrite-Session', value); + return this; + } + /// The user agent string of the client that made the request + @override + ClientBrowser setForwardedUserAgent(value) { + config['forwardedUserAgent'] = value; + addHeader('X-Forwarded-User-Agent', value); + return this; + } + /// Your secret dev API key + @override + ClientBrowser setDevKey(value) { + config['devKey'] = value; + addHeader('X-Appwrite-Dev-Key', value); + return this; + } + /// The user cookie to authenticate with. Used by SDKs that forward an incoming Cookie header in server-side runtimes. + @override + ClientBrowser setCookie(value) { + config['cookie'] = value; + addHeader('Cookie', value); + return this; + } + /// 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. + @override + ClientBrowser setImpersonateUserId(value) { + config['impersonateUserId'] = value; + addHeader('X-Appwrite-Impersonate-User-Id', value); + return this; + } + /// 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. + @override + ClientBrowser setImpersonateUserEmail(value) { + config['impersonateUserEmail'] = value; + addHeader('X-Appwrite-Impersonate-User-Email', value); + return this; + } + /// 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. + @override + ClientBrowser setImpersonateUserPhone(value) { + config['impersonateUserPhone'] = value; + addHeader('X-Appwrite-Impersonate-User-Phone', value); + return this; + } @override ClientBrowser setSelfSigned({bool status = true}) { @@ -185,8 +175,7 @@ class ClientBrowser extends ClientBase with ClientMixin { late Response res; if (size <= chunkSize) { - params[paramName] = http.MultipartFile.fromBytes(paramName, file.bytes!, - filename: file.filename); + params[paramName] = http.MultipartFile.fromBytes(paramName, file.bytes!, filename: file.filename); return call( HttpMethod.post, path: path, @@ -217,14 +206,13 @@ class ClientBrowser extends ClientBase with ClientMixin { final totalChunks = (size / chunkSize).ceil(); - Future uploadChunk( - int index, int start, int end, String? id) async { + Future uploadChunk(int index, int start, int end, String? id) async { List chunk = []; chunk = file.bytes!.getRange(start, end).toList(); final chunkParams = Map.from(params); - chunkParams[paramName] = http.MultipartFile.fromBytes(paramName, chunk, - filename: file.filename); + chunkParams[paramName] = + http.MultipartFile.fromBytes(paramName, chunk, filename: file.filename); final chunkHeaders = Map.from(headers); if (id != null && id.isNotEmpty) { chunkHeaders['x-appwrite-id'] = id; @@ -248,13 +236,12 @@ class ClientBrowser extends ClientBase with ClientMixin { var completedChunks = firstIndex + 1; var uploadedBytes = firstEnd; var lastResponse = res; + Response? finalResponse; bool isUploadComplete(Response response) { final chunksUploaded = response.data['chunksUploaded']; final chunksTotal = response.data['chunksTotal'] ?? totalChunks; - return chunksUploaded is num && - chunksTotal is num && - chunksUploaded >= chunksTotal; + return chunksUploaded is num && chunksTotal is num && chunksUploaded >= chunksTotal; } final progress = UploadProgress( @@ -288,8 +275,9 @@ class ClientBrowser extends ClientBase with ClientMixin { ); completedChunks++; uploadedBytes += chunk['end']! - chunk['start']!; + lastResponse = chunkResponse; if (isUploadComplete(chunkResponse)) { - lastResponse = chunkResponse; + finalResponse = chunkResponse; } final progress = UploadProgress( @@ -306,7 +294,7 @@ class ClientBrowser extends ClientBase with ClientMixin { final concurrency = min(8, chunks.length); await Future.wait(List.generate(concurrency, (_) => uploadNext())); - return lastResponse; + return finalResponse ?? lastResponse; } @override diff --git a/lib/src/client_io.dart b/lib/src/client_io.dart index 46d9633f..6b80ec70 100644 --- a/lib/src/client_io.dart +++ b/lib/src/client_io.dart @@ -20,7 +20,7 @@ ClientBase createClient({ ); class ClientIO extends ClientBase with ClientMixin { - static const int chunkSize = 5 * 1024 * 1024; + static const int chunkSize = 5*1024*1024; String _endPoint; Map? _headers; @override @@ -43,9 +43,8 @@ class ClientIO extends ClientBase with ClientMixin { 'x-sdk-platform': 'server', 'x-sdk-language': 'dart', 'x-sdk-version': '24.1.0', - 'user-agent': - 'AppwriteDartSDK/24.1.0 (${Platform.operatingSystem}; ${Platform.operatingSystemVersion})', - 'X-Appwrite-Response-Format': '1.9.5', + 'user-agent' : 'AppwriteDartSDK/24.1.0 (${Platform.operatingSystem}; ${Platform.operatingSystemVersion})', + 'X-Appwrite-Response-Format' : '1.9.5', }; config = {}; @@ -57,92 +56,82 @@ class ClientIO extends ClientBase with ClientMixin { @override String get endPoint => _endPoint; - /// Your project ID - @override - ClientIO setProject(value) { - config['project'] = value; - addHeader('X-Appwrite-Project', value); - return this; - } - - /// Your secret API key - @override - ClientIO setKey(value) { - config['key'] = value; - addHeader('X-Appwrite-Key', value); - return this; - } - - /// Your secret JSON Web Token - @override - ClientIO setJWT(value) { - config['jWT'] = value; - addHeader('X-Appwrite-JWT', value); - return this; - } - - @override - ClientIO setLocale(value) { - config['locale'] = value; - addHeader('X-Appwrite-Locale', value); - return this; - } - - /// The user session to authenticate with - @override - ClientIO setSession(value) { - config['session'] = value; - addHeader('X-Appwrite-Session', value); - return this; - } - - /// The user agent string of the client that made the request - @override - ClientIO setForwardedUserAgent(value) { - config['forwardedUserAgent'] = value; - addHeader('X-Forwarded-User-Agent', value); - return this; - } - - /// Your secret dev API key - @override - ClientIO setDevKey(value) { - config['devKey'] = value; - addHeader('X-Appwrite-Dev-Key', value); - return this; - } - - /// The user cookie to authenticate with. Used by SDKs that forward an incoming Cookie header in server-side runtimes. - @override - ClientIO setCookie(value) { - config['cookie'] = value; - addHeader('Cookie', value); - return this; - } - - /// 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. - @override - ClientIO setImpersonateUserId(value) { - config['impersonateUserId'] = value; - addHeader('X-Appwrite-Impersonate-User-Id', value); - return this; - } - - /// 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. - @override - ClientIO setImpersonateUserEmail(value) { - config['impersonateUserEmail'] = value; - addHeader('X-Appwrite-Impersonate-User-Email', value); - return this; - } - - /// 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. - @override - ClientIO setImpersonateUserPhone(value) { - config['impersonateUserPhone'] = value; - addHeader('X-Appwrite-Impersonate-User-Phone', value); - return this; - } + /// Your project ID + @override + ClientIO setProject(value) { + config['project'] = value; + addHeader('X-Appwrite-Project', value); + return this; + } + /// Your secret API key + @override + ClientIO setKey(value) { + config['key'] = value; + addHeader('X-Appwrite-Key', value); + return this; + } + /// Your secret JSON Web Token + @override + ClientIO setJWT(value) { + config['jWT'] = value; + addHeader('X-Appwrite-JWT', value); + return this; + } + @override + ClientIO setLocale(value) { + config['locale'] = value; + addHeader('X-Appwrite-Locale', value); + return this; + } + /// The user session to authenticate with + @override + ClientIO setSession(value) { + config['session'] = value; + addHeader('X-Appwrite-Session', value); + return this; + } + /// The user agent string of the client that made the request + @override + ClientIO setForwardedUserAgent(value) { + config['forwardedUserAgent'] = value; + addHeader('X-Forwarded-User-Agent', value); + return this; + } + /// Your secret dev API key + @override + ClientIO setDevKey(value) { + config['devKey'] = value; + addHeader('X-Appwrite-Dev-Key', value); + return this; + } + /// The user cookie to authenticate with. Used by SDKs that forward an incoming Cookie header in server-side runtimes. + @override + ClientIO setCookie(value) { + config['cookie'] = value; + addHeader('Cookie', value); + return this; + } + /// 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. + @override + ClientIO setImpersonateUserId(value) { + config['impersonateUserId'] = value; + addHeader('X-Appwrite-Impersonate-User-Id', value); + return this; + } + /// 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. + @override + ClientIO setImpersonateUserEmail(value) { + config['impersonateUserEmail'] = value; + addHeader('X-Appwrite-Impersonate-User-Email', value); + return this; + } + /// 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. + @override + ClientIO setImpersonateUserPhone(value) { + config['impersonateUserPhone'] = value; + addHeader('X-Appwrite-Impersonate-User-Phone', value); + return this; + } @override ClientIO setSelfSigned({bool status = true}) { @@ -238,24 +227,29 @@ class ClientIO extends ClientBase with ClientMixin { final totalChunks = (size / chunkSize).ceil(); - Future uploadChunk( - int index, int start, int end, String? id) async { + Future uploadChunk(int index, int start, int end, String? id, + [RandomAccessFile? raf]) async { List chunk = []; if (file.bytes != null) { chunk = file.bytes!.getRange(start, end).toList(); } else { - final raf = await iofile!.open(mode: FileMode.read); - try { + if (raf != null) { await raf.setPosition(start); chunk = await raf.read(end - start); - } finally { - await raf.close(); + } else { + final chunkFile = await iofile!.open(mode: FileMode.read); + try { + await chunkFile.setPosition(start); + chunk = await chunkFile.read(end - start); + } finally { + await chunkFile.close(); + } } } final chunkParams = Map.from(params); - chunkParams[paramName] = http.MultipartFile.fromBytes(paramName, chunk, - filename: file.filename); + chunkParams[paramName] = + http.MultipartFile.fromBytes(paramName, chunk, filename: file.filename); final chunkHeaders = Map.from(headers); if (id != null && id.isNotEmpty) { chunkHeaders['x-appwrite-id'] = id; @@ -279,13 +273,12 @@ class ClientIO extends ClientBase with ClientMixin { var completedChunks = firstIndex + 1; var uploadedBytes = firstEnd; var lastResponse = res; + Response? finalResponse; bool isUploadComplete(Response response) { final chunksUploaded = response.data['chunksUploaded']; final chunksTotal = response.data['chunksTotal'] ?? totalChunks; - return chunksUploaded is num && - chunksTotal is num && - chunksUploaded >= chunksTotal; + return chunksUploaded is num && chunksTotal is num && chunksUploaded >= chunksTotal; } final progress = UploadProgress( @@ -309,35 +302,42 @@ class ClientIO extends ClientBase with ClientMixin { var nextChunk = 0; Future uploadNext() async { - while (nextChunk < chunks.length) { - final chunk = chunks[nextChunk++]; - final chunkResponse = await uploadChunk( - chunk['index']!, - chunk['start']!, - chunk['end']!, - uploadId, - ); - completedChunks++; - uploadedBytes += chunk['end']! - chunk['start']!; - if (isUploadComplete(chunkResponse)) { + final raf = file.bytes == null ? await iofile!.open(mode: FileMode.read) : null; + try { + while (nextChunk < chunks.length) { + final chunk = chunks[nextChunk++]; + final chunkResponse = await uploadChunk( + chunk['index']!, + chunk['start']!, + chunk['end']!, + uploadId, + raf, + ); + completedChunks++; + uploadedBytes += chunk['end']! - chunk['start']!; lastResponse = chunkResponse; + if (isUploadComplete(chunkResponse)) { + finalResponse = chunkResponse; + } + + final progress = UploadProgress( + $id: uploadId ?? '', + progress: min(uploadedBytes, size) / size * 100, + sizeUploaded: min(uploadedBytes, size), + chunksTotal: totalChunks, + chunksUploaded: completedChunks, + ); + onProgress?.call(progress); } - - final progress = UploadProgress( - $id: uploadId ?? '', - progress: min(uploadedBytes, size) / size * 100, - sizeUploaded: min(uploadedBytes, size), - chunksTotal: totalChunks, - chunksUploaded: completedChunks, - ); - onProgress?.call(progress); + } finally { + await raf?.close(); } } final concurrency = min(8, chunks.length); await Future.wait(List.generate(concurrency, (_) => uploadNext())); - return lastResponse; + return finalResponse ?? lastResponse; } @override From 88545f5ee5f2bef0672231f2adab94fe30bd5f44 Mon Sep 17 00:00:00 2001 From: TorstenDittmann Date: Thu, 21 May 2026 16:47:01 +0000 Subject: [PATCH 06/13] Commit from GitHub Actions (Format and push) --- lib/src/client_browser.dart | 180 +++++++++++++++++++----------------- lib/src/client_io.dart | 180 +++++++++++++++++++----------------- 2 files changed, 194 insertions(+), 166 deletions(-) diff --git a/lib/src/client_browser.dart b/lib/src/client_browser.dart index 1ed26c56..3cb2eb4b 100644 --- a/lib/src/client_browser.dart +++ b/lib/src/client_browser.dart @@ -16,7 +16,7 @@ ClientBase createClient({ ClientBrowser(endPoint: endPoint, selfSigned: selfSigned); class ClientBrowser extends ClientBase with ClientMixin { - static const int chunkSize = 5*1024*1024; + static const int chunkSize = 5 * 1024 * 1024; String _endPoint; Map? _headers; @override @@ -34,7 +34,7 @@ class ClientBrowser extends ClientBase with ClientMixin { 'x-sdk-platform': 'server', 'x-sdk-language': 'dart', 'x-sdk-version': '24.1.0', - 'X-Appwrite-Response-Format' : '1.9.5', + 'X-Appwrite-Response-Format': '1.9.5', }; config = {}; @@ -46,82 +46,92 @@ class ClientBrowser extends ClientBase with ClientMixin { @override String get endPoint => _endPoint; - /// Your project ID - @override - ClientBrowser setProject(value) { - config['project'] = value; - addHeader('X-Appwrite-Project', value); - return this; - } - /// Your secret API key - @override - ClientBrowser setKey(value) { - config['key'] = value; - addHeader('X-Appwrite-Key', value); - return this; - } - /// Your secret JSON Web Token - @override - ClientBrowser setJWT(value) { - config['jWT'] = value; - addHeader('X-Appwrite-JWT', value); - return this; - } - @override - ClientBrowser setLocale(value) { - config['locale'] = value; - addHeader('X-Appwrite-Locale', value); - return this; - } - /// The user session to authenticate with - @override - ClientBrowser setSession(value) { - config['session'] = value; - addHeader('X-Appwrite-Session', value); - return this; - } - /// The user agent string of the client that made the request - @override - ClientBrowser setForwardedUserAgent(value) { - config['forwardedUserAgent'] = value; - addHeader('X-Forwarded-User-Agent', value); - return this; - } - /// Your secret dev API key - @override - ClientBrowser setDevKey(value) { - config['devKey'] = value; - addHeader('X-Appwrite-Dev-Key', value); - return this; - } - /// The user cookie to authenticate with. Used by SDKs that forward an incoming Cookie header in server-side runtimes. - @override - ClientBrowser setCookie(value) { - config['cookie'] = value; - addHeader('Cookie', value); - return this; - } - /// 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. - @override - ClientBrowser setImpersonateUserId(value) { - config['impersonateUserId'] = value; - addHeader('X-Appwrite-Impersonate-User-Id', value); - return this; - } - /// 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. - @override - ClientBrowser setImpersonateUserEmail(value) { - config['impersonateUserEmail'] = value; - addHeader('X-Appwrite-Impersonate-User-Email', value); - return this; - } - /// 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. - @override - ClientBrowser setImpersonateUserPhone(value) { - config['impersonateUserPhone'] = value; - addHeader('X-Appwrite-Impersonate-User-Phone', value); - return this; - } + /// Your project ID + @override + ClientBrowser setProject(value) { + config['project'] = value; + addHeader('X-Appwrite-Project', value); + return this; + } + + /// Your secret API key + @override + ClientBrowser setKey(value) { + config['key'] = value; + addHeader('X-Appwrite-Key', value); + return this; + } + + /// Your secret JSON Web Token + @override + ClientBrowser setJWT(value) { + config['jWT'] = value; + addHeader('X-Appwrite-JWT', value); + return this; + } + + @override + ClientBrowser setLocale(value) { + config['locale'] = value; + addHeader('X-Appwrite-Locale', value); + return this; + } + + /// The user session to authenticate with + @override + ClientBrowser setSession(value) { + config['session'] = value; + addHeader('X-Appwrite-Session', value); + return this; + } + + /// The user agent string of the client that made the request + @override + ClientBrowser setForwardedUserAgent(value) { + config['forwardedUserAgent'] = value; + addHeader('X-Forwarded-User-Agent', value); + return this; + } + + /// Your secret dev API key + @override + ClientBrowser setDevKey(value) { + config['devKey'] = value; + addHeader('X-Appwrite-Dev-Key', value); + return this; + } + + /// The user cookie to authenticate with. Used by SDKs that forward an incoming Cookie header in server-side runtimes. + @override + ClientBrowser setCookie(value) { + config['cookie'] = value; + addHeader('Cookie', value); + return this; + } + + /// 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. + @override + ClientBrowser setImpersonateUserId(value) { + config['impersonateUserId'] = value; + addHeader('X-Appwrite-Impersonate-User-Id', value); + return this; + } + + /// 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. + @override + ClientBrowser setImpersonateUserEmail(value) { + config['impersonateUserEmail'] = value; + addHeader('X-Appwrite-Impersonate-User-Email', value); + return this; + } + + /// 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. + @override + ClientBrowser setImpersonateUserPhone(value) { + config['impersonateUserPhone'] = value; + addHeader('X-Appwrite-Impersonate-User-Phone', value); + return this; + } @override ClientBrowser setSelfSigned({bool status = true}) { @@ -175,7 +185,8 @@ class ClientBrowser extends ClientBase with ClientMixin { late Response res; if (size <= chunkSize) { - params[paramName] = http.MultipartFile.fromBytes(paramName, file.bytes!, filename: file.filename); + params[paramName] = http.MultipartFile.fromBytes(paramName, file.bytes!, + filename: file.filename); return call( HttpMethod.post, path: path, @@ -206,13 +217,14 @@ class ClientBrowser extends ClientBase with ClientMixin { final totalChunks = (size / chunkSize).ceil(); - Future uploadChunk(int index, int start, int end, String? id) async { + Future uploadChunk( + int index, int start, int end, String? id) async { List chunk = []; chunk = file.bytes!.getRange(start, end).toList(); final chunkParams = Map.from(params); - chunkParams[paramName] = - http.MultipartFile.fromBytes(paramName, chunk, filename: file.filename); + chunkParams[paramName] = http.MultipartFile.fromBytes(paramName, chunk, + filename: file.filename); final chunkHeaders = Map.from(headers); if (id != null && id.isNotEmpty) { chunkHeaders['x-appwrite-id'] = id; @@ -241,7 +253,9 @@ class ClientBrowser extends ClientBase with ClientMixin { bool isUploadComplete(Response response) { final chunksUploaded = response.data['chunksUploaded']; final chunksTotal = response.data['chunksTotal'] ?? totalChunks; - return chunksUploaded is num && chunksTotal is num && chunksUploaded >= chunksTotal; + return chunksUploaded is num && + chunksTotal is num && + chunksUploaded >= chunksTotal; } final progress = UploadProgress( diff --git a/lib/src/client_io.dart b/lib/src/client_io.dart index 6b80ec70..6aee80e8 100644 --- a/lib/src/client_io.dart +++ b/lib/src/client_io.dart @@ -20,7 +20,7 @@ ClientBase createClient({ ); class ClientIO extends ClientBase with ClientMixin { - static const int chunkSize = 5*1024*1024; + static const int chunkSize = 5 * 1024 * 1024; String _endPoint; Map? _headers; @override @@ -43,8 +43,9 @@ class ClientIO extends ClientBase with ClientMixin { 'x-sdk-platform': 'server', 'x-sdk-language': 'dart', 'x-sdk-version': '24.1.0', - 'user-agent' : 'AppwriteDartSDK/24.1.0 (${Platform.operatingSystem}; ${Platform.operatingSystemVersion})', - 'X-Appwrite-Response-Format' : '1.9.5', + 'user-agent': + 'AppwriteDartSDK/24.1.0 (${Platform.operatingSystem}; ${Platform.operatingSystemVersion})', + 'X-Appwrite-Response-Format': '1.9.5', }; config = {}; @@ -56,82 +57,92 @@ class ClientIO extends ClientBase with ClientMixin { @override String get endPoint => _endPoint; - /// Your project ID - @override - ClientIO setProject(value) { - config['project'] = value; - addHeader('X-Appwrite-Project', value); - return this; - } - /// Your secret API key - @override - ClientIO setKey(value) { - config['key'] = value; - addHeader('X-Appwrite-Key', value); - return this; - } - /// Your secret JSON Web Token - @override - ClientIO setJWT(value) { - config['jWT'] = value; - addHeader('X-Appwrite-JWT', value); - return this; - } - @override - ClientIO setLocale(value) { - config['locale'] = value; - addHeader('X-Appwrite-Locale', value); - return this; - } - /// The user session to authenticate with - @override - ClientIO setSession(value) { - config['session'] = value; - addHeader('X-Appwrite-Session', value); - return this; - } - /// The user agent string of the client that made the request - @override - ClientIO setForwardedUserAgent(value) { - config['forwardedUserAgent'] = value; - addHeader('X-Forwarded-User-Agent', value); - return this; - } - /// Your secret dev API key - @override - ClientIO setDevKey(value) { - config['devKey'] = value; - addHeader('X-Appwrite-Dev-Key', value); - return this; - } - /// The user cookie to authenticate with. Used by SDKs that forward an incoming Cookie header in server-side runtimes. - @override - ClientIO setCookie(value) { - config['cookie'] = value; - addHeader('Cookie', value); - return this; - } - /// 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. - @override - ClientIO setImpersonateUserId(value) { - config['impersonateUserId'] = value; - addHeader('X-Appwrite-Impersonate-User-Id', value); - return this; - } - /// 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. - @override - ClientIO setImpersonateUserEmail(value) { - config['impersonateUserEmail'] = value; - addHeader('X-Appwrite-Impersonate-User-Email', value); - return this; - } - /// 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. - @override - ClientIO setImpersonateUserPhone(value) { - config['impersonateUserPhone'] = value; - addHeader('X-Appwrite-Impersonate-User-Phone', value); - return this; - } + /// Your project ID + @override + ClientIO setProject(value) { + config['project'] = value; + addHeader('X-Appwrite-Project', value); + return this; + } + + /// Your secret API key + @override + ClientIO setKey(value) { + config['key'] = value; + addHeader('X-Appwrite-Key', value); + return this; + } + + /// Your secret JSON Web Token + @override + ClientIO setJWT(value) { + config['jWT'] = value; + addHeader('X-Appwrite-JWT', value); + return this; + } + + @override + ClientIO setLocale(value) { + config['locale'] = value; + addHeader('X-Appwrite-Locale', value); + return this; + } + + /// The user session to authenticate with + @override + ClientIO setSession(value) { + config['session'] = value; + addHeader('X-Appwrite-Session', value); + return this; + } + + /// The user agent string of the client that made the request + @override + ClientIO setForwardedUserAgent(value) { + config['forwardedUserAgent'] = value; + addHeader('X-Forwarded-User-Agent', value); + return this; + } + + /// Your secret dev API key + @override + ClientIO setDevKey(value) { + config['devKey'] = value; + addHeader('X-Appwrite-Dev-Key', value); + return this; + } + + /// The user cookie to authenticate with. Used by SDKs that forward an incoming Cookie header in server-side runtimes. + @override + ClientIO setCookie(value) { + config['cookie'] = value; + addHeader('Cookie', value); + return this; + } + + /// 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. + @override + ClientIO setImpersonateUserId(value) { + config['impersonateUserId'] = value; + addHeader('X-Appwrite-Impersonate-User-Id', value); + return this; + } + + /// 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. + @override + ClientIO setImpersonateUserEmail(value) { + config['impersonateUserEmail'] = value; + addHeader('X-Appwrite-Impersonate-User-Email', value); + return this; + } + + /// 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. + @override + ClientIO setImpersonateUserPhone(value) { + config['impersonateUserPhone'] = value; + addHeader('X-Appwrite-Impersonate-User-Phone', value); + return this; + } @override ClientIO setSelfSigned({bool status = true}) { @@ -248,8 +259,8 @@ class ClientIO extends ClientBase with ClientMixin { } final chunkParams = Map.from(params); - chunkParams[paramName] = - http.MultipartFile.fromBytes(paramName, chunk, filename: file.filename); + chunkParams[paramName] = http.MultipartFile.fromBytes(paramName, chunk, + filename: file.filename); final chunkHeaders = Map.from(headers); if (id != null && id.isNotEmpty) { chunkHeaders['x-appwrite-id'] = id; @@ -278,7 +289,9 @@ class ClientIO extends ClientBase with ClientMixin { bool isUploadComplete(Response response) { final chunksUploaded = response.data['chunksUploaded']; final chunksTotal = response.data['chunksTotal'] ?? totalChunks; - return chunksUploaded is num && chunksTotal is num && chunksUploaded >= chunksTotal; + return chunksUploaded is num && + chunksTotal is num && + chunksUploaded >= chunksTotal; } final progress = UploadProgress( @@ -302,7 +315,8 @@ class ClientIO extends ClientBase with ClientMixin { var nextChunk = 0; Future uploadNext() async { - final raf = file.bytes == null ? await iofile!.open(mode: FileMode.read) : null; + final raf = + file.bytes == null ? await iofile!.open(mode: FileMode.read) : null; try { while (nextChunk < chunks.length) { final chunk = chunks[nextChunk++]; From 3229d209b275b5075ee055e89f2727607fb082c8 Mon Sep 17 00:00:00 2001 From: Torsten Dittmann Date: Thu, 21 May 2026 21:10:47 +0400 Subject: [PATCH 07/13] feat: support concurrent chunk uploads --- lib/src/client_browser.dart | 180 +++++++++++++++++------------------- lib/src/client_io.dart | 180 +++++++++++++++++------------------- 2 files changed, 166 insertions(+), 194 deletions(-) diff --git a/lib/src/client_browser.dart b/lib/src/client_browser.dart index 3cb2eb4b..1ed26c56 100644 --- a/lib/src/client_browser.dart +++ b/lib/src/client_browser.dart @@ -16,7 +16,7 @@ ClientBase createClient({ ClientBrowser(endPoint: endPoint, selfSigned: selfSigned); class ClientBrowser extends ClientBase with ClientMixin { - static const int chunkSize = 5 * 1024 * 1024; + static const int chunkSize = 5*1024*1024; String _endPoint; Map? _headers; @override @@ -34,7 +34,7 @@ class ClientBrowser extends ClientBase with ClientMixin { 'x-sdk-platform': 'server', 'x-sdk-language': 'dart', 'x-sdk-version': '24.1.0', - 'X-Appwrite-Response-Format': '1.9.5', + 'X-Appwrite-Response-Format' : '1.9.5', }; config = {}; @@ -46,92 +46,82 @@ class ClientBrowser extends ClientBase with ClientMixin { @override String get endPoint => _endPoint; - /// Your project ID - @override - ClientBrowser setProject(value) { - config['project'] = value; - addHeader('X-Appwrite-Project', value); - return this; - } - - /// Your secret API key - @override - ClientBrowser setKey(value) { - config['key'] = value; - addHeader('X-Appwrite-Key', value); - return this; - } - - /// Your secret JSON Web Token - @override - ClientBrowser setJWT(value) { - config['jWT'] = value; - addHeader('X-Appwrite-JWT', value); - return this; - } - - @override - ClientBrowser setLocale(value) { - config['locale'] = value; - addHeader('X-Appwrite-Locale', value); - return this; - } - - /// The user session to authenticate with - @override - ClientBrowser setSession(value) { - config['session'] = value; - addHeader('X-Appwrite-Session', value); - return this; - } - - /// The user agent string of the client that made the request - @override - ClientBrowser setForwardedUserAgent(value) { - config['forwardedUserAgent'] = value; - addHeader('X-Forwarded-User-Agent', value); - return this; - } - - /// Your secret dev API key - @override - ClientBrowser setDevKey(value) { - config['devKey'] = value; - addHeader('X-Appwrite-Dev-Key', value); - return this; - } - - /// The user cookie to authenticate with. Used by SDKs that forward an incoming Cookie header in server-side runtimes. - @override - ClientBrowser setCookie(value) { - config['cookie'] = value; - addHeader('Cookie', value); - return this; - } - - /// 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. - @override - ClientBrowser setImpersonateUserId(value) { - config['impersonateUserId'] = value; - addHeader('X-Appwrite-Impersonate-User-Id', value); - return this; - } - - /// 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. - @override - ClientBrowser setImpersonateUserEmail(value) { - config['impersonateUserEmail'] = value; - addHeader('X-Appwrite-Impersonate-User-Email', value); - return this; - } - - /// 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. - @override - ClientBrowser setImpersonateUserPhone(value) { - config['impersonateUserPhone'] = value; - addHeader('X-Appwrite-Impersonate-User-Phone', value); - return this; - } + /// Your project ID + @override + ClientBrowser setProject(value) { + config['project'] = value; + addHeader('X-Appwrite-Project', value); + return this; + } + /// Your secret API key + @override + ClientBrowser setKey(value) { + config['key'] = value; + addHeader('X-Appwrite-Key', value); + return this; + } + /// Your secret JSON Web Token + @override + ClientBrowser setJWT(value) { + config['jWT'] = value; + addHeader('X-Appwrite-JWT', value); + return this; + } + @override + ClientBrowser setLocale(value) { + config['locale'] = value; + addHeader('X-Appwrite-Locale', value); + return this; + } + /// The user session to authenticate with + @override + ClientBrowser setSession(value) { + config['session'] = value; + addHeader('X-Appwrite-Session', value); + return this; + } + /// The user agent string of the client that made the request + @override + ClientBrowser setForwardedUserAgent(value) { + config['forwardedUserAgent'] = value; + addHeader('X-Forwarded-User-Agent', value); + return this; + } + /// Your secret dev API key + @override + ClientBrowser setDevKey(value) { + config['devKey'] = value; + addHeader('X-Appwrite-Dev-Key', value); + return this; + } + /// The user cookie to authenticate with. Used by SDKs that forward an incoming Cookie header in server-side runtimes. + @override + ClientBrowser setCookie(value) { + config['cookie'] = value; + addHeader('Cookie', value); + return this; + } + /// 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. + @override + ClientBrowser setImpersonateUserId(value) { + config['impersonateUserId'] = value; + addHeader('X-Appwrite-Impersonate-User-Id', value); + return this; + } + /// 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. + @override + ClientBrowser setImpersonateUserEmail(value) { + config['impersonateUserEmail'] = value; + addHeader('X-Appwrite-Impersonate-User-Email', value); + return this; + } + /// 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. + @override + ClientBrowser setImpersonateUserPhone(value) { + config['impersonateUserPhone'] = value; + addHeader('X-Appwrite-Impersonate-User-Phone', value); + return this; + } @override ClientBrowser setSelfSigned({bool status = true}) { @@ -185,8 +175,7 @@ class ClientBrowser extends ClientBase with ClientMixin { late Response res; if (size <= chunkSize) { - params[paramName] = http.MultipartFile.fromBytes(paramName, file.bytes!, - filename: file.filename); + params[paramName] = http.MultipartFile.fromBytes(paramName, file.bytes!, filename: file.filename); return call( HttpMethod.post, path: path, @@ -217,14 +206,13 @@ class ClientBrowser extends ClientBase with ClientMixin { final totalChunks = (size / chunkSize).ceil(); - Future uploadChunk( - int index, int start, int end, String? id) async { + Future uploadChunk(int index, int start, int end, String? id) async { List chunk = []; chunk = file.bytes!.getRange(start, end).toList(); final chunkParams = Map.from(params); - chunkParams[paramName] = http.MultipartFile.fromBytes(paramName, chunk, - filename: file.filename); + chunkParams[paramName] = + http.MultipartFile.fromBytes(paramName, chunk, filename: file.filename); final chunkHeaders = Map.from(headers); if (id != null && id.isNotEmpty) { chunkHeaders['x-appwrite-id'] = id; @@ -253,9 +241,7 @@ class ClientBrowser extends ClientBase with ClientMixin { bool isUploadComplete(Response response) { final chunksUploaded = response.data['chunksUploaded']; final chunksTotal = response.data['chunksTotal'] ?? totalChunks; - return chunksUploaded is num && - chunksTotal is num && - chunksUploaded >= chunksTotal; + return chunksUploaded is num && chunksTotal is num && chunksUploaded >= chunksTotal; } final progress = UploadProgress( diff --git a/lib/src/client_io.dart b/lib/src/client_io.dart index 6aee80e8..6b80ec70 100644 --- a/lib/src/client_io.dart +++ b/lib/src/client_io.dart @@ -20,7 +20,7 @@ ClientBase createClient({ ); class ClientIO extends ClientBase with ClientMixin { - static const int chunkSize = 5 * 1024 * 1024; + static const int chunkSize = 5*1024*1024; String _endPoint; Map? _headers; @override @@ -43,9 +43,8 @@ class ClientIO extends ClientBase with ClientMixin { 'x-sdk-platform': 'server', 'x-sdk-language': 'dart', 'x-sdk-version': '24.1.0', - 'user-agent': - 'AppwriteDartSDK/24.1.0 (${Platform.operatingSystem}; ${Platform.operatingSystemVersion})', - 'X-Appwrite-Response-Format': '1.9.5', + 'user-agent' : 'AppwriteDartSDK/24.1.0 (${Platform.operatingSystem}; ${Platform.operatingSystemVersion})', + 'X-Appwrite-Response-Format' : '1.9.5', }; config = {}; @@ -57,92 +56,82 @@ class ClientIO extends ClientBase with ClientMixin { @override String get endPoint => _endPoint; - /// Your project ID - @override - ClientIO setProject(value) { - config['project'] = value; - addHeader('X-Appwrite-Project', value); - return this; - } - - /// Your secret API key - @override - ClientIO setKey(value) { - config['key'] = value; - addHeader('X-Appwrite-Key', value); - return this; - } - - /// Your secret JSON Web Token - @override - ClientIO setJWT(value) { - config['jWT'] = value; - addHeader('X-Appwrite-JWT', value); - return this; - } - - @override - ClientIO setLocale(value) { - config['locale'] = value; - addHeader('X-Appwrite-Locale', value); - return this; - } - - /// The user session to authenticate with - @override - ClientIO setSession(value) { - config['session'] = value; - addHeader('X-Appwrite-Session', value); - return this; - } - - /// The user agent string of the client that made the request - @override - ClientIO setForwardedUserAgent(value) { - config['forwardedUserAgent'] = value; - addHeader('X-Forwarded-User-Agent', value); - return this; - } - - /// Your secret dev API key - @override - ClientIO setDevKey(value) { - config['devKey'] = value; - addHeader('X-Appwrite-Dev-Key', value); - return this; - } - - /// The user cookie to authenticate with. Used by SDKs that forward an incoming Cookie header in server-side runtimes. - @override - ClientIO setCookie(value) { - config['cookie'] = value; - addHeader('Cookie', value); - return this; - } - - /// 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. - @override - ClientIO setImpersonateUserId(value) { - config['impersonateUserId'] = value; - addHeader('X-Appwrite-Impersonate-User-Id', value); - return this; - } - - /// 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. - @override - ClientIO setImpersonateUserEmail(value) { - config['impersonateUserEmail'] = value; - addHeader('X-Appwrite-Impersonate-User-Email', value); - return this; - } - - /// 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. - @override - ClientIO setImpersonateUserPhone(value) { - config['impersonateUserPhone'] = value; - addHeader('X-Appwrite-Impersonate-User-Phone', value); - return this; - } + /// Your project ID + @override + ClientIO setProject(value) { + config['project'] = value; + addHeader('X-Appwrite-Project', value); + return this; + } + /// Your secret API key + @override + ClientIO setKey(value) { + config['key'] = value; + addHeader('X-Appwrite-Key', value); + return this; + } + /// Your secret JSON Web Token + @override + ClientIO setJWT(value) { + config['jWT'] = value; + addHeader('X-Appwrite-JWT', value); + return this; + } + @override + ClientIO setLocale(value) { + config['locale'] = value; + addHeader('X-Appwrite-Locale', value); + return this; + } + /// The user session to authenticate with + @override + ClientIO setSession(value) { + config['session'] = value; + addHeader('X-Appwrite-Session', value); + return this; + } + /// The user agent string of the client that made the request + @override + ClientIO setForwardedUserAgent(value) { + config['forwardedUserAgent'] = value; + addHeader('X-Forwarded-User-Agent', value); + return this; + } + /// Your secret dev API key + @override + ClientIO setDevKey(value) { + config['devKey'] = value; + addHeader('X-Appwrite-Dev-Key', value); + return this; + } + /// The user cookie to authenticate with. Used by SDKs that forward an incoming Cookie header in server-side runtimes. + @override + ClientIO setCookie(value) { + config['cookie'] = value; + addHeader('Cookie', value); + return this; + } + /// 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. + @override + ClientIO setImpersonateUserId(value) { + config['impersonateUserId'] = value; + addHeader('X-Appwrite-Impersonate-User-Id', value); + return this; + } + /// 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. + @override + ClientIO setImpersonateUserEmail(value) { + config['impersonateUserEmail'] = value; + addHeader('X-Appwrite-Impersonate-User-Email', value); + return this; + } + /// 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. + @override + ClientIO setImpersonateUserPhone(value) { + config['impersonateUserPhone'] = value; + addHeader('X-Appwrite-Impersonate-User-Phone', value); + return this; + } @override ClientIO setSelfSigned({bool status = true}) { @@ -259,8 +248,8 @@ class ClientIO extends ClientBase with ClientMixin { } final chunkParams = Map.from(params); - chunkParams[paramName] = http.MultipartFile.fromBytes(paramName, chunk, - filename: file.filename); + chunkParams[paramName] = + http.MultipartFile.fromBytes(paramName, chunk, filename: file.filename); final chunkHeaders = Map.from(headers); if (id != null && id.isNotEmpty) { chunkHeaders['x-appwrite-id'] = id; @@ -289,9 +278,7 @@ class ClientIO extends ClientBase with ClientMixin { bool isUploadComplete(Response response) { final chunksUploaded = response.data['chunksUploaded']; final chunksTotal = response.data['chunksTotal'] ?? totalChunks; - return chunksUploaded is num && - chunksTotal is num && - chunksUploaded >= chunksTotal; + return chunksUploaded is num && chunksTotal is num && chunksUploaded >= chunksTotal; } final progress = UploadProgress( @@ -315,8 +302,7 @@ class ClientIO extends ClientBase with ClientMixin { var nextChunk = 0; Future uploadNext() async { - final raf = - file.bytes == null ? await iofile!.open(mode: FileMode.read) : null; + final raf = file.bytes == null ? await iofile!.open(mode: FileMode.read) : null; try { while (nextChunk < chunks.length) { final chunk = chunks[nextChunk++]; From 770aa8077193eb48ba5d98df4b3f05fac7f94787 Mon Sep 17 00:00:00 2001 From: TorstenDittmann Date: Thu, 21 May 2026 17:11:19 +0000 Subject: [PATCH 08/13] Commit from GitHub Actions (Format and push) --- lib/src/client_browser.dart | 180 +++++++++++++++++++----------------- lib/src/client_io.dart | 180 +++++++++++++++++++----------------- 2 files changed, 194 insertions(+), 166 deletions(-) diff --git a/lib/src/client_browser.dart b/lib/src/client_browser.dart index 1ed26c56..3cb2eb4b 100644 --- a/lib/src/client_browser.dart +++ b/lib/src/client_browser.dart @@ -16,7 +16,7 @@ ClientBase createClient({ ClientBrowser(endPoint: endPoint, selfSigned: selfSigned); class ClientBrowser extends ClientBase with ClientMixin { - static const int chunkSize = 5*1024*1024; + static const int chunkSize = 5 * 1024 * 1024; String _endPoint; Map? _headers; @override @@ -34,7 +34,7 @@ class ClientBrowser extends ClientBase with ClientMixin { 'x-sdk-platform': 'server', 'x-sdk-language': 'dart', 'x-sdk-version': '24.1.0', - 'X-Appwrite-Response-Format' : '1.9.5', + 'X-Appwrite-Response-Format': '1.9.5', }; config = {}; @@ -46,82 +46,92 @@ class ClientBrowser extends ClientBase with ClientMixin { @override String get endPoint => _endPoint; - /// Your project ID - @override - ClientBrowser setProject(value) { - config['project'] = value; - addHeader('X-Appwrite-Project', value); - return this; - } - /// Your secret API key - @override - ClientBrowser setKey(value) { - config['key'] = value; - addHeader('X-Appwrite-Key', value); - return this; - } - /// Your secret JSON Web Token - @override - ClientBrowser setJWT(value) { - config['jWT'] = value; - addHeader('X-Appwrite-JWT', value); - return this; - } - @override - ClientBrowser setLocale(value) { - config['locale'] = value; - addHeader('X-Appwrite-Locale', value); - return this; - } - /// The user session to authenticate with - @override - ClientBrowser setSession(value) { - config['session'] = value; - addHeader('X-Appwrite-Session', value); - return this; - } - /// The user agent string of the client that made the request - @override - ClientBrowser setForwardedUserAgent(value) { - config['forwardedUserAgent'] = value; - addHeader('X-Forwarded-User-Agent', value); - return this; - } - /// Your secret dev API key - @override - ClientBrowser setDevKey(value) { - config['devKey'] = value; - addHeader('X-Appwrite-Dev-Key', value); - return this; - } - /// The user cookie to authenticate with. Used by SDKs that forward an incoming Cookie header in server-side runtimes. - @override - ClientBrowser setCookie(value) { - config['cookie'] = value; - addHeader('Cookie', value); - return this; - } - /// 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. - @override - ClientBrowser setImpersonateUserId(value) { - config['impersonateUserId'] = value; - addHeader('X-Appwrite-Impersonate-User-Id', value); - return this; - } - /// 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. - @override - ClientBrowser setImpersonateUserEmail(value) { - config['impersonateUserEmail'] = value; - addHeader('X-Appwrite-Impersonate-User-Email', value); - return this; - } - /// 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. - @override - ClientBrowser setImpersonateUserPhone(value) { - config['impersonateUserPhone'] = value; - addHeader('X-Appwrite-Impersonate-User-Phone', value); - return this; - } + /// Your project ID + @override + ClientBrowser setProject(value) { + config['project'] = value; + addHeader('X-Appwrite-Project', value); + return this; + } + + /// Your secret API key + @override + ClientBrowser setKey(value) { + config['key'] = value; + addHeader('X-Appwrite-Key', value); + return this; + } + + /// Your secret JSON Web Token + @override + ClientBrowser setJWT(value) { + config['jWT'] = value; + addHeader('X-Appwrite-JWT', value); + return this; + } + + @override + ClientBrowser setLocale(value) { + config['locale'] = value; + addHeader('X-Appwrite-Locale', value); + return this; + } + + /// The user session to authenticate with + @override + ClientBrowser setSession(value) { + config['session'] = value; + addHeader('X-Appwrite-Session', value); + return this; + } + + /// The user agent string of the client that made the request + @override + ClientBrowser setForwardedUserAgent(value) { + config['forwardedUserAgent'] = value; + addHeader('X-Forwarded-User-Agent', value); + return this; + } + + /// Your secret dev API key + @override + ClientBrowser setDevKey(value) { + config['devKey'] = value; + addHeader('X-Appwrite-Dev-Key', value); + return this; + } + + /// The user cookie to authenticate with. Used by SDKs that forward an incoming Cookie header in server-side runtimes. + @override + ClientBrowser setCookie(value) { + config['cookie'] = value; + addHeader('Cookie', value); + return this; + } + + /// 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. + @override + ClientBrowser setImpersonateUserId(value) { + config['impersonateUserId'] = value; + addHeader('X-Appwrite-Impersonate-User-Id', value); + return this; + } + + /// 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. + @override + ClientBrowser setImpersonateUserEmail(value) { + config['impersonateUserEmail'] = value; + addHeader('X-Appwrite-Impersonate-User-Email', value); + return this; + } + + /// 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. + @override + ClientBrowser setImpersonateUserPhone(value) { + config['impersonateUserPhone'] = value; + addHeader('X-Appwrite-Impersonate-User-Phone', value); + return this; + } @override ClientBrowser setSelfSigned({bool status = true}) { @@ -175,7 +185,8 @@ class ClientBrowser extends ClientBase with ClientMixin { late Response res; if (size <= chunkSize) { - params[paramName] = http.MultipartFile.fromBytes(paramName, file.bytes!, filename: file.filename); + params[paramName] = http.MultipartFile.fromBytes(paramName, file.bytes!, + filename: file.filename); return call( HttpMethod.post, path: path, @@ -206,13 +217,14 @@ class ClientBrowser extends ClientBase with ClientMixin { final totalChunks = (size / chunkSize).ceil(); - Future uploadChunk(int index, int start, int end, String? id) async { + Future uploadChunk( + int index, int start, int end, String? id) async { List chunk = []; chunk = file.bytes!.getRange(start, end).toList(); final chunkParams = Map.from(params); - chunkParams[paramName] = - http.MultipartFile.fromBytes(paramName, chunk, filename: file.filename); + chunkParams[paramName] = http.MultipartFile.fromBytes(paramName, chunk, + filename: file.filename); final chunkHeaders = Map.from(headers); if (id != null && id.isNotEmpty) { chunkHeaders['x-appwrite-id'] = id; @@ -241,7 +253,9 @@ class ClientBrowser extends ClientBase with ClientMixin { bool isUploadComplete(Response response) { final chunksUploaded = response.data['chunksUploaded']; final chunksTotal = response.data['chunksTotal'] ?? totalChunks; - return chunksUploaded is num && chunksTotal is num && chunksUploaded >= chunksTotal; + return chunksUploaded is num && + chunksTotal is num && + chunksUploaded >= chunksTotal; } final progress = UploadProgress( diff --git a/lib/src/client_io.dart b/lib/src/client_io.dart index 6b80ec70..6aee80e8 100644 --- a/lib/src/client_io.dart +++ b/lib/src/client_io.dart @@ -20,7 +20,7 @@ ClientBase createClient({ ); class ClientIO extends ClientBase with ClientMixin { - static const int chunkSize = 5*1024*1024; + static const int chunkSize = 5 * 1024 * 1024; String _endPoint; Map? _headers; @override @@ -43,8 +43,9 @@ class ClientIO extends ClientBase with ClientMixin { 'x-sdk-platform': 'server', 'x-sdk-language': 'dart', 'x-sdk-version': '24.1.0', - 'user-agent' : 'AppwriteDartSDK/24.1.0 (${Platform.operatingSystem}; ${Platform.operatingSystemVersion})', - 'X-Appwrite-Response-Format' : '1.9.5', + 'user-agent': + 'AppwriteDartSDK/24.1.0 (${Platform.operatingSystem}; ${Platform.operatingSystemVersion})', + 'X-Appwrite-Response-Format': '1.9.5', }; config = {}; @@ -56,82 +57,92 @@ class ClientIO extends ClientBase with ClientMixin { @override String get endPoint => _endPoint; - /// Your project ID - @override - ClientIO setProject(value) { - config['project'] = value; - addHeader('X-Appwrite-Project', value); - return this; - } - /// Your secret API key - @override - ClientIO setKey(value) { - config['key'] = value; - addHeader('X-Appwrite-Key', value); - return this; - } - /// Your secret JSON Web Token - @override - ClientIO setJWT(value) { - config['jWT'] = value; - addHeader('X-Appwrite-JWT', value); - return this; - } - @override - ClientIO setLocale(value) { - config['locale'] = value; - addHeader('X-Appwrite-Locale', value); - return this; - } - /// The user session to authenticate with - @override - ClientIO setSession(value) { - config['session'] = value; - addHeader('X-Appwrite-Session', value); - return this; - } - /// The user agent string of the client that made the request - @override - ClientIO setForwardedUserAgent(value) { - config['forwardedUserAgent'] = value; - addHeader('X-Forwarded-User-Agent', value); - return this; - } - /// Your secret dev API key - @override - ClientIO setDevKey(value) { - config['devKey'] = value; - addHeader('X-Appwrite-Dev-Key', value); - return this; - } - /// The user cookie to authenticate with. Used by SDKs that forward an incoming Cookie header in server-side runtimes. - @override - ClientIO setCookie(value) { - config['cookie'] = value; - addHeader('Cookie', value); - return this; - } - /// 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. - @override - ClientIO setImpersonateUserId(value) { - config['impersonateUserId'] = value; - addHeader('X-Appwrite-Impersonate-User-Id', value); - return this; - } - /// 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. - @override - ClientIO setImpersonateUserEmail(value) { - config['impersonateUserEmail'] = value; - addHeader('X-Appwrite-Impersonate-User-Email', value); - return this; - } - /// 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. - @override - ClientIO setImpersonateUserPhone(value) { - config['impersonateUserPhone'] = value; - addHeader('X-Appwrite-Impersonate-User-Phone', value); - return this; - } + /// Your project ID + @override + ClientIO setProject(value) { + config['project'] = value; + addHeader('X-Appwrite-Project', value); + return this; + } + + /// Your secret API key + @override + ClientIO setKey(value) { + config['key'] = value; + addHeader('X-Appwrite-Key', value); + return this; + } + + /// Your secret JSON Web Token + @override + ClientIO setJWT(value) { + config['jWT'] = value; + addHeader('X-Appwrite-JWT', value); + return this; + } + + @override + ClientIO setLocale(value) { + config['locale'] = value; + addHeader('X-Appwrite-Locale', value); + return this; + } + + /// The user session to authenticate with + @override + ClientIO setSession(value) { + config['session'] = value; + addHeader('X-Appwrite-Session', value); + return this; + } + + /// The user agent string of the client that made the request + @override + ClientIO setForwardedUserAgent(value) { + config['forwardedUserAgent'] = value; + addHeader('X-Forwarded-User-Agent', value); + return this; + } + + /// Your secret dev API key + @override + ClientIO setDevKey(value) { + config['devKey'] = value; + addHeader('X-Appwrite-Dev-Key', value); + return this; + } + + /// The user cookie to authenticate with. Used by SDKs that forward an incoming Cookie header in server-side runtimes. + @override + ClientIO setCookie(value) { + config['cookie'] = value; + addHeader('Cookie', value); + return this; + } + + /// 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. + @override + ClientIO setImpersonateUserId(value) { + config['impersonateUserId'] = value; + addHeader('X-Appwrite-Impersonate-User-Id', value); + return this; + } + + /// 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. + @override + ClientIO setImpersonateUserEmail(value) { + config['impersonateUserEmail'] = value; + addHeader('X-Appwrite-Impersonate-User-Email', value); + return this; + } + + /// 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. + @override + ClientIO setImpersonateUserPhone(value) { + config['impersonateUserPhone'] = value; + addHeader('X-Appwrite-Impersonate-User-Phone', value); + return this; + } @override ClientIO setSelfSigned({bool status = true}) { @@ -248,8 +259,8 @@ class ClientIO extends ClientBase with ClientMixin { } final chunkParams = Map.from(params); - chunkParams[paramName] = - http.MultipartFile.fromBytes(paramName, chunk, filename: file.filename); + chunkParams[paramName] = http.MultipartFile.fromBytes(paramName, chunk, + filename: file.filename); final chunkHeaders = Map.from(headers); if (id != null && id.isNotEmpty) { chunkHeaders['x-appwrite-id'] = id; @@ -278,7 +289,9 @@ class ClientIO extends ClientBase with ClientMixin { bool isUploadComplete(Response response) { final chunksUploaded = response.data['chunksUploaded']; final chunksTotal = response.data['chunksTotal'] ?? totalChunks; - return chunksUploaded is num && chunksTotal is num && chunksUploaded >= chunksTotal; + return chunksUploaded is num && + chunksTotal is num && + chunksUploaded >= chunksTotal; } final progress = UploadProgress( @@ -302,7 +315,8 @@ class ClientIO extends ClientBase with ClientMixin { var nextChunk = 0; Future uploadNext() async { - final raf = file.bytes == null ? await iofile!.open(mode: FileMode.read) : null; + final raf = + file.bytes == null ? await iofile!.open(mode: FileMode.read) : null; try { while (nextChunk < chunks.length) { final chunk = chunks[nextChunk++]; From 9878e2ea9c7ffe9cf15e740b62b11d4c73e47d64 Mon Sep 17 00:00:00 2001 From: Torsten Dittmann Date: Thu, 21 May 2026 21:33:16 +0400 Subject: [PATCH 09/13] feat: support concurrent chunk uploads --- lib/src/client_browser.dart | 180 +++++++++++++++++------------------- lib/src/client_io.dart | 180 +++++++++++++++++------------------- 2 files changed, 166 insertions(+), 194 deletions(-) diff --git a/lib/src/client_browser.dart b/lib/src/client_browser.dart index 3cb2eb4b..1ed26c56 100644 --- a/lib/src/client_browser.dart +++ b/lib/src/client_browser.dart @@ -16,7 +16,7 @@ ClientBase createClient({ ClientBrowser(endPoint: endPoint, selfSigned: selfSigned); class ClientBrowser extends ClientBase with ClientMixin { - static const int chunkSize = 5 * 1024 * 1024; + static const int chunkSize = 5*1024*1024; String _endPoint; Map? _headers; @override @@ -34,7 +34,7 @@ class ClientBrowser extends ClientBase with ClientMixin { 'x-sdk-platform': 'server', 'x-sdk-language': 'dart', 'x-sdk-version': '24.1.0', - 'X-Appwrite-Response-Format': '1.9.5', + 'X-Appwrite-Response-Format' : '1.9.5', }; config = {}; @@ -46,92 +46,82 @@ class ClientBrowser extends ClientBase with ClientMixin { @override String get endPoint => _endPoint; - /// Your project ID - @override - ClientBrowser setProject(value) { - config['project'] = value; - addHeader('X-Appwrite-Project', value); - return this; - } - - /// Your secret API key - @override - ClientBrowser setKey(value) { - config['key'] = value; - addHeader('X-Appwrite-Key', value); - return this; - } - - /// Your secret JSON Web Token - @override - ClientBrowser setJWT(value) { - config['jWT'] = value; - addHeader('X-Appwrite-JWT', value); - return this; - } - - @override - ClientBrowser setLocale(value) { - config['locale'] = value; - addHeader('X-Appwrite-Locale', value); - return this; - } - - /// The user session to authenticate with - @override - ClientBrowser setSession(value) { - config['session'] = value; - addHeader('X-Appwrite-Session', value); - return this; - } - - /// The user agent string of the client that made the request - @override - ClientBrowser setForwardedUserAgent(value) { - config['forwardedUserAgent'] = value; - addHeader('X-Forwarded-User-Agent', value); - return this; - } - - /// Your secret dev API key - @override - ClientBrowser setDevKey(value) { - config['devKey'] = value; - addHeader('X-Appwrite-Dev-Key', value); - return this; - } - - /// The user cookie to authenticate with. Used by SDKs that forward an incoming Cookie header in server-side runtimes. - @override - ClientBrowser setCookie(value) { - config['cookie'] = value; - addHeader('Cookie', value); - return this; - } - - /// 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. - @override - ClientBrowser setImpersonateUserId(value) { - config['impersonateUserId'] = value; - addHeader('X-Appwrite-Impersonate-User-Id', value); - return this; - } - - /// 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. - @override - ClientBrowser setImpersonateUserEmail(value) { - config['impersonateUserEmail'] = value; - addHeader('X-Appwrite-Impersonate-User-Email', value); - return this; - } - - /// 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. - @override - ClientBrowser setImpersonateUserPhone(value) { - config['impersonateUserPhone'] = value; - addHeader('X-Appwrite-Impersonate-User-Phone', value); - return this; - } + /// Your project ID + @override + ClientBrowser setProject(value) { + config['project'] = value; + addHeader('X-Appwrite-Project', value); + return this; + } + /// Your secret API key + @override + ClientBrowser setKey(value) { + config['key'] = value; + addHeader('X-Appwrite-Key', value); + return this; + } + /// Your secret JSON Web Token + @override + ClientBrowser setJWT(value) { + config['jWT'] = value; + addHeader('X-Appwrite-JWT', value); + return this; + } + @override + ClientBrowser setLocale(value) { + config['locale'] = value; + addHeader('X-Appwrite-Locale', value); + return this; + } + /// The user session to authenticate with + @override + ClientBrowser setSession(value) { + config['session'] = value; + addHeader('X-Appwrite-Session', value); + return this; + } + /// The user agent string of the client that made the request + @override + ClientBrowser setForwardedUserAgent(value) { + config['forwardedUserAgent'] = value; + addHeader('X-Forwarded-User-Agent', value); + return this; + } + /// Your secret dev API key + @override + ClientBrowser setDevKey(value) { + config['devKey'] = value; + addHeader('X-Appwrite-Dev-Key', value); + return this; + } + /// The user cookie to authenticate with. Used by SDKs that forward an incoming Cookie header in server-side runtimes. + @override + ClientBrowser setCookie(value) { + config['cookie'] = value; + addHeader('Cookie', value); + return this; + } + /// 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. + @override + ClientBrowser setImpersonateUserId(value) { + config['impersonateUserId'] = value; + addHeader('X-Appwrite-Impersonate-User-Id', value); + return this; + } + /// 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. + @override + ClientBrowser setImpersonateUserEmail(value) { + config['impersonateUserEmail'] = value; + addHeader('X-Appwrite-Impersonate-User-Email', value); + return this; + } + /// 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. + @override + ClientBrowser setImpersonateUserPhone(value) { + config['impersonateUserPhone'] = value; + addHeader('X-Appwrite-Impersonate-User-Phone', value); + return this; + } @override ClientBrowser setSelfSigned({bool status = true}) { @@ -185,8 +175,7 @@ class ClientBrowser extends ClientBase with ClientMixin { late Response res; if (size <= chunkSize) { - params[paramName] = http.MultipartFile.fromBytes(paramName, file.bytes!, - filename: file.filename); + params[paramName] = http.MultipartFile.fromBytes(paramName, file.bytes!, filename: file.filename); return call( HttpMethod.post, path: path, @@ -217,14 +206,13 @@ class ClientBrowser extends ClientBase with ClientMixin { final totalChunks = (size / chunkSize).ceil(); - Future uploadChunk( - int index, int start, int end, String? id) async { + Future uploadChunk(int index, int start, int end, String? id) async { List chunk = []; chunk = file.bytes!.getRange(start, end).toList(); final chunkParams = Map.from(params); - chunkParams[paramName] = http.MultipartFile.fromBytes(paramName, chunk, - filename: file.filename); + chunkParams[paramName] = + http.MultipartFile.fromBytes(paramName, chunk, filename: file.filename); final chunkHeaders = Map.from(headers); if (id != null && id.isNotEmpty) { chunkHeaders['x-appwrite-id'] = id; @@ -253,9 +241,7 @@ class ClientBrowser extends ClientBase with ClientMixin { bool isUploadComplete(Response response) { final chunksUploaded = response.data['chunksUploaded']; final chunksTotal = response.data['chunksTotal'] ?? totalChunks; - return chunksUploaded is num && - chunksTotal is num && - chunksUploaded >= chunksTotal; + return chunksUploaded is num && chunksTotal is num && chunksUploaded >= chunksTotal; } final progress = UploadProgress( diff --git a/lib/src/client_io.dart b/lib/src/client_io.dart index 6aee80e8..6b80ec70 100644 --- a/lib/src/client_io.dart +++ b/lib/src/client_io.dart @@ -20,7 +20,7 @@ ClientBase createClient({ ); class ClientIO extends ClientBase with ClientMixin { - static const int chunkSize = 5 * 1024 * 1024; + static const int chunkSize = 5*1024*1024; String _endPoint; Map? _headers; @override @@ -43,9 +43,8 @@ class ClientIO extends ClientBase with ClientMixin { 'x-sdk-platform': 'server', 'x-sdk-language': 'dart', 'x-sdk-version': '24.1.0', - 'user-agent': - 'AppwriteDartSDK/24.1.0 (${Platform.operatingSystem}; ${Platform.operatingSystemVersion})', - 'X-Appwrite-Response-Format': '1.9.5', + 'user-agent' : 'AppwriteDartSDK/24.1.0 (${Platform.operatingSystem}; ${Platform.operatingSystemVersion})', + 'X-Appwrite-Response-Format' : '1.9.5', }; config = {}; @@ -57,92 +56,82 @@ class ClientIO extends ClientBase with ClientMixin { @override String get endPoint => _endPoint; - /// Your project ID - @override - ClientIO setProject(value) { - config['project'] = value; - addHeader('X-Appwrite-Project', value); - return this; - } - - /// Your secret API key - @override - ClientIO setKey(value) { - config['key'] = value; - addHeader('X-Appwrite-Key', value); - return this; - } - - /// Your secret JSON Web Token - @override - ClientIO setJWT(value) { - config['jWT'] = value; - addHeader('X-Appwrite-JWT', value); - return this; - } - - @override - ClientIO setLocale(value) { - config['locale'] = value; - addHeader('X-Appwrite-Locale', value); - return this; - } - - /// The user session to authenticate with - @override - ClientIO setSession(value) { - config['session'] = value; - addHeader('X-Appwrite-Session', value); - return this; - } - - /// The user agent string of the client that made the request - @override - ClientIO setForwardedUserAgent(value) { - config['forwardedUserAgent'] = value; - addHeader('X-Forwarded-User-Agent', value); - return this; - } - - /// Your secret dev API key - @override - ClientIO setDevKey(value) { - config['devKey'] = value; - addHeader('X-Appwrite-Dev-Key', value); - return this; - } - - /// The user cookie to authenticate with. Used by SDKs that forward an incoming Cookie header in server-side runtimes. - @override - ClientIO setCookie(value) { - config['cookie'] = value; - addHeader('Cookie', value); - return this; - } - - /// 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. - @override - ClientIO setImpersonateUserId(value) { - config['impersonateUserId'] = value; - addHeader('X-Appwrite-Impersonate-User-Id', value); - return this; - } - - /// 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. - @override - ClientIO setImpersonateUserEmail(value) { - config['impersonateUserEmail'] = value; - addHeader('X-Appwrite-Impersonate-User-Email', value); - return this; - } - - /// 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. - @override - ClientIO setImpersonateUserPhone(value) { - config['impersonateUserPhone'] = value; - addHeader('X-Appwrite-Impersonate-User-Phone', value); - return this; - } + /// Your project ID + @override + ClientIO setProject(value) { + config['project'] = value; + addHeader('X-Appwrite-Project', value); + return this; + } + /// Your secret API key + @override + ClientIO setKey(value) { + config['key'] = value; + addHeader('X-Appwrite-Key', value); + return this; + } + /// Your secret JSON Web Token + @override + ClientIO setJWT(value) { + config['jWT'] = value; + addHeader('X-Appwrite-JWT', value); + return this; + } + @override + ClientIO setLocale(value) { + config['locale'] = value; + addHeader('X-Appwrite-Locale', value); + return this; + } + /// The user session to authenticate with + @override + ClientIO setSession(value) { + config['session'] = value; + addHeader('X-Appwrite-Session', value); + return this; + } + /// The user agent string of the client that made the request + @override + ClientIO setForwardedUserAgent(value) { + config['forwardedUserAgent'] = value; + addHeader('X-Forwarded-User-Agent', value); + return this; + } + /// Your secret dev API key + @override + ClientIO setDevKey(value) { + config['devKey'] = value; + addHeader('X-Appwrite-Dev-Key', value); + return this; + } + /// The user cookie to authenticate with. Used by SDKs that forward an incoming Cookie header in server-side runtimes. + @override + ClientIO setCookie(value) { + config['cookie'] = value; + addHeader('Cookie', value); + return this; + } + /// 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. + @override + ClientIO setImpersonateUserId(value) { + config['impersonateUserId'] = value; + addHeader('X-Appwrite-Impersonate-User-Id', value); + return this; + } + /// 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. + @override + ClientIO setImpersonateUserEmail(value) { + config['impersonateUserEmail'] = value; + addHeader('X-Appwrite-Impersonate-User-Email', value); + return this; + } + /// 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. + @override + ClientIO setImpersonateUserPhone(value) { + config['impersonateUserPhone'] = value; + addHeader('X-Appwrite-Impersonate-User-Phone', value); + return this; + } @override ClientIO setSelfSigned({bool status = true}) { @@ -259,8 +248,8 @@ class ClientIO extends ClientBase with ClientMixin { } final chunkParams = Map.from(params); - chunkParams[paramName] = http.MultipartFile.fromBytes(paramName, chunk, - filename: file.filename); + chunkParams[paramName] = + http.MultipartFile.fromBytes(paramName, chunk, filename: file.filename); final chunkHeaders = Map.from(headers); if (id != null && id.isNotEmpty) { chunkHeaders['x-appwrite-id'] = id; @@ -289,9 +278,7 @@ class ClientIO extends ClientBase with ClientMixin { bool isUploadComplete(Response response) { final chunksUploaded = response.data['chunksUploaded']; final chunksTotal = response.data['chunksTotal'] ?? totalChunks; - return chunksUploaded is num && - chunksTotal is num && - chunksUploaded >= chunksTotal; + return chunksUploaded is num && chunksTotal is num && chunksUploaded >= chunksTotal; } final progress = UploadProgress( @@ -315,8 +302,7 @@ class ClientIO extends ClientBase with ClientMixin { var nextChunk = 0; Future uploadNext() async { - final raf = - file.bytes == null ? await iofile!.open(mode: FileMode.read) : null; + final raf = file.bytes == null ? await iofile!.open(mode: FileMode.read) : null; try { while (nextChunk < chunks.length) { final chunk = chunks[nextChunk++]; From 08eea660492f0d340b9ecaedbd4ac75bf2c4d9fb Mon Sep 17 00:00:00 2001 From: TorstenDittmann Date: Thu, 21 May 2026 17:33:48 +0000 Subject: [PATCH 10/13] Commit from GitHub Actions (Format and push) --- lib/src/client_browser.dart | 180 +++++++++++++++++++----------------- lib/src/client_io.dart | 180 +++++++++++++++++++----------------- 2 files changed, 194 insertions(+), 166 deletions(-) diff --git a/lib/src/client_browser.dart b/lib/src/client_browser.dart index 1ed26c56..3cb2eb4b 100644 --- a/lib/src/client_browser.dart +++ b/lib/src/client_browser.dart @@ -16,7 +16,7 @@ ClientBase createClient({ ClientBrowser(endPoint: endPoint, selfSigned: selfSigned); class ClientBrowser extends ClientBase with ClientMixin { - static const int chunkSize = 5*1024*1024; + static const int chunkSize = 5 * 1024 * 1024; String _endPoint; Map? _headers; @override @@ -34,7 +34,7 @@ class ClientBrowser extends ClientBase with ClientMixin { 'x-sdk-platform': 'server', 'x-sdk-language': 'dart', 'x-sdk-version': '24.1.0', - 'X-Appwrite-Response-Format' : '1.9.5', + 'X-Appwrite-Response-Format': '1.9.5', }; config = {}; @@ -46,82 +46,92 @@ class ClientBrowser extends ClientBase with ClientMixin { @override String get endPoint => _endPoint; - /// Your project ID - @override - ClientBrowser setProject(value) { - config['project'] = value; - addHeader('X-Appwrite-Project', value); - return this; - } - /// Your secret API key - @override - ClientBrowser setKey(value) { - config['key'] = value; - addHeader('X-Appwrite-Key', value); - return this; - } - /// Your secret JSON Web Token - @override - ClientBrowser setJWT(value) { - config['jWT'] = value; - addHeader('X-Appwrite-JWT', value); - return this; - } - @override - ClientBrowser setLocale(value) { - config['locale'] = value; - addHeader('X-Appwrite-Locale', value); - return this; - } - /// The user session to authenticate with - @override - ClientBrowser setSession(value) { - config['session'] = value; - addHeader('X-Appwrite-Session', value); - return this; - } - /// The user agent string of the client that made the request - @override - ClientBrowser setForwardedUserAgent(value) { - config['forwardedUserAgent'] = value; - addHeader('X-Forwarded-User-Agent', value); - return this; - } - /// Your secret dev API key - @override - ClientBrowser setDevKey(value) { - config['devKey'] = value; - addHeader('X-Appwrite-Dev-Key', value); - return this; - } - /// The user cookie to authenticate with. Used by SDKs that forward an incoming Cookie header in server-side runtimes. - @override - ClientBrowser setCookie(value) { - config['cookie'] = value; - addHeader('Cookie', value); - return this; - } - /// 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. - @override - ClientBrowser setImpersonateUserId(value) { - config['impersonateUserId'] = value; - addHeader('X-Appwrite-Impersonate-User-Id', value); - return this; - } - /// 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. - @override - ClientBrowser setImpersonateUserEmail(value) { - config['impersonateUserEmail'] = value; - addHeader('X-Appwrite-Impersonate-User-Email', value); - return this; - } - /// 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. - @override - ClientBrowser setImpersonateUserPhone(value) { - config['impersonateUserPhone'] = value; - addHeader('X-Appwrite-Impersonate-User-Phone', value); - return this; - } + /// Your project ID + @override + ClientBrowser setProject(value) { + config['project'] = value; + addHeader('X-Appwrite-Project', value); + return this; + } + + /// Your secret API key + @override + ClientBrowser setKey(value) { + config['key'] = value; + addHeader('X-Appwrite-Key', value); + return this; + } + + /// Your secret JSON Web Token + @override + ClientBrowser setJWT(value) { + config['jWT'] = value; + addHeader('X-Appwrite-JWT', value); + return this; + } + + @override + ClientBrowser setLocale(value) { + config['locale'] = value; + addHeader('X-Appwrite-Locale', value); + return this; + } + + /// The user session to authenticate with + @override + ClientBrowser setSession(value) { + config['session'] = value; + addHeader('X-Appwrite-Session', value); + return this; + } + + /// The user agent string of the client that made the request + @override + ClientBrowser setForwardedUserAgent(value) { + config['forwardedUserAgent'] = value; + addHeader('X-Forwarded-User-Agent', value); + return this; + } + + /// Your secret dev API key + @override + ClientBrowser setDevKey(value) { + config['devKey'] = value; + addHeader('X-Appwrite-Dev-Key', value); + return this; + } + + /// The user cookie to authenticate with. Used by SDKs that forward an incoming Cookie header in server-side runtimes. + @override + ClientBrowser setCookie(value) { + config['cookie'] = value; + addHeader('Cookie', value); + return this; + } + + /// 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. + @override + ClientBrowser setImpersonateUserId(value) { + config['impersonateUserId'] = value; + addHeader('X-Appwrite-Impersonate-User-Id', value); + return this; + } + + /// 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. + @override + ClientBrowser setImpersonateUserEmail(value) { + config['impersonateUserEmail'] = value; + addHeader('X-Appwrite-Impersonate-User-Email', value); + return this; + } + + /// 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. + @override + ClientBrowser setImpersonateUserPhone(value) { + config['impersonateUserPhone'] = value; + addHeader('X-Appwrite-Impersonate-User-Phone', value); + return this; + } @override ClientBrowser setSelfSigned({bool status = true}) { @@ -175,7 +185,8 @@ class ClientBrowser extends ClientBase with ClientMixin { late Response res; if (size <= chunkSize) { - params[paramName] = http.MultipartFile.fromBytes(paramName, file.bytes!, filename: file.filename); + params[paramName] = http.MultipartFile.fromBytes(paramName, file.bytes!, + filename: file.filename); return call( HttpMethod.post, path: path, @@ -206,13 +217,14 @@ class ClientBrowser extends ClientBase with ClientMixin { final totalChunks = (size / chunkSize).ceil(); - Future uploadChunk(int index, int start, int end, String? id) async { + Future uploadChunk( + int index, int start, int end, String? id) async { List chunk = []; chunk = file.bytes!.getRange(start, end).toList(); final chunkParams = Map.from(params); - chunkParams[paramName] = - http.MultipartFile.fromBytes(paramName, chunk, filename: file.filename); + chunkParams[paramName] = http.MultipartFile.fromBytes(paramName, chunk, + filename: file.filename); final chunkHeaders = Map.from(headers); if (id != null && id.isNotEmpty) { chunkHeaders['x-appwrite-id'] = id; @@ -241,7 +253,9 @@ class ClientBrowser extends ClientBase with ClientMixin { bool isUploadComplete(Response response) { final chunksUploaded = response.data['chunksUploaded']; final chunksTotal = response.data['chunksTotal'] ?? totalChunks; - return chunksUploaded is num && chunksTotal is num && chunksUploaded >= chunksTotal; + return chunksUploaded is num && + chunksTotal is num && + chunksUploaded >= chunksTotal; } final progress = UploadProgress( diff --git a/lib/src/client_io.dart b/lib/src/client_io.dart index 6b80ec70..6aee80e8 100644 --- a/lib/src/client_io.dart +++ b/lib/src/client_io.dart @@ -20,7 +20,7 @@ ClientBase createClient({ ); class ClientIO extends ClientBase with ClientMixin { - static const int chunkSize = 5*1024*1024; + static const int chunkSize = 5 * 1024 * 1024; String _endPoint; Map? _headers; @override @@ -43,8 +43,9 @@ class ClientIO extends ClientBase with ClientMixin { 'x-sdk-platform': 'server', 'x-sdk-language': 'dart', 'x-sdk-version': '24.1.0', - 'user-agent' : 'AppwriteDartSDK/24.1.0 (${Platform.operatingSystem}; ${Platform.operatingSystemVersion})', - 'X-Appwrite-Response-Format' : '1.9.5', + 'user-agent': + 'AppwriteDartSDK/24.1.0 (${Platform.operatingSystem}; ${Platform.operatingSystemVersion})', + 'X-Appwrite-Response-Format': '1.9.5', }; config = {}; @@ -56,82 +57,92 @@ class ClientIO extends ClientBase with ClientMixin { @override String get endPoint => _endPoint; - /// Your project ID - @override - ClientIO setProject(value) { - config['project'] = value; - addHeader('X-Appwrite-Project', value); - return this; - } - /// Your secret API key - @override - ClientIO setKey(value) { - config['key'] = value; - addHeader('X-Appwrite-Key', value); - return this; - } - /// Your secret JSON Web Token - @override - ClientIO setJWT(value) { - config['jWT'] = value; - addHeader('X-Appwrite-JWT', value); - return this; - } - @override - ClientIO setLocale(value) { - config['locale'] = value; - addHeader('X-Appwrite-Locale', value); - return this; - } - /// The user session to authenticate with - @override - ClientIO setSession(value) { - config['session'] = value; - addHeader('X-Appwrite-Session', value); - return this; - } - /// The user agent string of the client that made the request - @override - ClientIO setForwardedUserAgent(value) { - config['forwardedUserAgent'] = value; - addHeader('X-Forwarded-User-Agent', value); - return this; - } - /// Your secret dev API key - @override - ClientIO setDevKey(value) { - config['devKey'] = value; - addHeader('X-Appwrite-Dev-Key', value); - return this; - } - /// The user cookie to authenticate with. Used by SDKs that forward an incoming Cookie header in server-side runtimes. - @override - ClientIO setCookie(value) { - config['cookie'] = value; - addHeader('Cookie', value); - return this; - } - /// 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. - @override - ClientIO setImpersonateUserId(value) { - config['impersonateUserId'] = value; - addHeader('X-Appwrite-Impersonate-User-Id', value); - return this; - } - /// 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. - @override - ClientIO setImpersonateUserEmail(value) { - config['impersonateUserEmail'] = value; - addHeader('X-Appwrite-Impersonate-User-Email', value); - return this; - } - /// 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. - @override - ClientIO setImpersonateUserPhone(value) { - config['impersonateUserPhone'] = value; - addHeader('X-Appwrite-Impersonate-User-Phone', value); - return this; - } + /// Your project ID + @override + ClientIO setProject(value) { + config['project'] = value; + addHeader('X-Appwrite-Project', value); + return this; + } + + /// Your secret API key + @override + ClientIO setKey(value) { + config['key'] = value; + addHeader('X-Appwrite-Key', value); + return this; + } + + /// Your secret JSON Web Token + @override + ClientIO setJWT(value) { + config['jWT'] = value; + addHeader('X-Appwrite-JWT', value); + return this; + } + + @override + ClientIO setLocale(value) { + config['locale'] = value; + addHeader('X-Appwrite-Locale', value); + return this; + } + + /// The user session to authenticate with + @override + ClientIO setSession(value) { + config['session'] = value; + addHeader('X-Appwrite-Session', value); + return this; + } + + /// The user agent string of the client that made the request + @override + ClientIO setForwardedUserAgent(value) { + config['forwardedUserAgent'] = value; + addHeader('X-Forwarded-User-Agent', value); + return this; + } + + /// Your secret dev API key + @override + ClientIO setDevKey(value) { + config['devKey'] = value; + addHeader('X-Appwrite-Dev-Key', value); + return this; + } + + /// The user cookie to authenticate with. Used by SDKs that forward an incoming Cookie header in server-side runtimes. + @override + ClientIO setCookie(value) { + config['cookie'] = value; + addHeader('Cookie', value); + return this; + } + + /// 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. + @override + ClientIO setImpersonateUserId(value) { + config['impersonateUserId'] = value; + addHeader('X-Appwrite-Impersonate-User-Id', value); + return this; + } + + /// 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. + @override + ClientIO setImpersonateUserEmail(value) { + config['impersonateUserEmail'] = value; + addHeader('X-Appwrite-Impersonate-User-Email', value); + return this; + } + + /// 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. + @override + ClientIO setImpersonateUserPhone(value) { + config['impersonateUserPhone'] = value; + addHeader('X-Appwrite-Impersonate-User-Phone', value); + return this; + } @override ClientIO setSelfSigned({bool status = true}) { @@ -248,8 +259,8 @@ class ClientIO extends ClientBase with ClientMixin { } final chunkParams = Map.from(params); - chunkParams[paramName] = - http.MultipartFile.fromBytes(paramName, chunk, filename: file.filename); + chunkParams[paramName] = http.MultipartFile.fromBytes(paramName, chunk, + filename: file.filename); final chunkHeaders = Map.from(headers); if (id != null && id.isNotEmpty) { chunkHeaders['x-appwrite-id'] = id; @@ -278,7 +289,9 @@ class ClientIO extends ClientBase with ClientMixin { bool isUploadComplete(Response response) { final chunksUploaded = response.data['chunksUploaded']; final chunksTotal = response.data['chunksTotal'] ?? totalChunks; - return chunksUploaded is num && chunksTotal is num && chunksUploaded >= chunksTotal; + return chunksUploaded is num && + chunksTotal is num && + chunksUploaded >= chunksTotal; } final progress = UploadProgress( @@ -302,7 +315,8 @@ class ClientIO extends ClientBase with ClientMixin { var nextChunk = 0; Future uploadNext() async { - final raf = file.bytes == null ? await iofile!.open(mode: FileMode.read) : null; + final raf = + file.bytes == null ? await iofile!.open(mode: FileMode.read) : null; try { while (nextChunk < chunks.length) { final chunk = chunks[nextChunk++]; From 3b0b501f10b5daf45f47864f6c02d1af071cb6cd Mon Sep 17 00:00:00 2001 From: Torsten Dittmann Date: Thu, 21 May 2026 22:17:47 +0400 Subject: [PATCH 11/13] chore: trigger CI From 9629bc8fcd94712a897d10dd24ddad67863d1039 Mon Sep 17 00:00:00 2001 From: Torsten Dittmann Date: Thu, 21 May 2026 22:42:06 +0400 Subject: [PATCH 12/13] chore: bump SDK version to 24.2.0 --- README.md | 2 +- lib/src/client_browser.dart | 182 +++++++++++++++++------------------- lib/src/client_io.dart | 182 +++++++++++++++++------------------- pubspec.yaml | 2 +- 4 files changed, 170 insertions(+), 198 deletions(-) diff --git a/README.md b/README.md index 5aa2a72c..c4c7bac9 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ Add this to your package's `pubspec.yaml` file: ```yml dependencies: - dart_appwrite: ^24.1.0 + dart_appwrite: ^24.2.0 ``` You can install packages from the command line: diff --git a/lib/src/client_browser.dart b/lib/src/client_browser.dart index 3cb2eb4b..e362fe55 100644 --- a/lib/src/client_browser.dart +++ b/lib/src/client_browser.dart @@ -16,7 +16,7 @@ ClientBase createClient({ ClientBrowser(endPoint: endPoint, selfSigned: selfSigned); class ClientBrowser extends ClientBase with ClientMixin { - static const int chunkSize = 5 * 1024 * 1024; + static const int chunkSize = 5*1024*1024; String _endPoint; Map? _headers; @override @@ -33,8 +33,8 @@ class ClientBrowser extends ClientBase with ClientMixin { 'x-sdk-name': 'Dart', 'x-sdk-platform': 'server', 'x-sdk-language': 'dart', - 'x-sdk-version': '24.1.0', - 'X-Appwrite-Response-Format': '1.9.5', + 'x-sdk-version': '24.2.0', + 'X-Appwrite-Response-Format' : '1.9.5', }; config = {}; @@ -46,92 +46,82 @@ class ClientBrowser extends ClientBase with ClientMixin { @override String get endPoint => _endPoint; - /// Your project ID - @override - ClientBrowser setProject(value) { - config['project'] = value; - addHeader('X-Appwrite-Project', value); - return this; - } - - /// Your secret API key - @override - ClientBrowser setKey(value) { - config['key'] = value; - addHeader('X-Appwrite-Key', value); - return this; - } - - /// Your secret JSON Web Token - @override - ClientBrowser setJWT(value) { - config['jWT'] = value; - addHeader('X-Appwrite-JWT', value); - return this; - } - - @override - ClientBrowser setLocale(value) { - config['locale'] = value; - addHeader('X-Appwrite-Locale', value); - return this; - } - - /// The user session to authenticate with - @override - ClientBrowser setSession(value) { - config['session'] = value; - addHeader('X-Appwrite-Session', value); - return this; - } - - /// The user agent string of the client that made the request - @override - ClientBrowser setForwardedUserAgent(value) { - config['forwardedUserAgent'] = value; - addHeader('X-Forwarded-User-Agent', value); - return this; - } - - /// Your secret dev API key - @override - ClientBrowser setDevKey(value) { - config['devKey'] = value; - addHeader('X-Appwrite-Dev-Key', value); - return this; - } - - /// The user cookie to authenticate with. Used by SDKs that forward an incoming Cookie header in server-side runtimes. - @override - ClientBrowser setCookie(value) { - config['cookie'] = value; - addHeader('Cookie', value); - return this; - } - - /// 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. - @override - ClientBrowser setImpersonateUserId(value) { - config['impersonateUserId'] = value; - addHeader('X-Appwrite-Impersonate-User-Id', value); - return this; - } - - /// 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. - @override - ClientBrowser setImpersonateUserEmail(value) { - config['impersonateUserEmail'] = value; - addHeader('X-Appwrite-Impersonate-User-Email', value); - return this; - } - - /// 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. - @override - ClientBrowser setImpersonateUserPhone(value) { - config['impersonateUserPhone'] = value; - addHeader('X-Appwrite-Impersonate-User-Phone', value); - return this; - } + /// Your project ID + @override + ClientBrowser setProject(value) { + config['project'] = value; + addHeader('X-Appwrite-Project', value); + return this; + } + /// Your secret API key + @override + ClientBrowser setKey(value) { + config['key'] = value; + addHeader('X-Appwrite-Key', value); + return this; + } + /// Your secret JSON Web Token + @override + ClientBrowser setJWT(value) { + config['jWT'] = value; + addHeader('X-Appwrite-JWT', value); + return this; + } + @override + ClientBrowser setLocale(value) { + config['locale'] = value; + addHeader('X-Appwrite-Locale', value); + return this; + } + /// The user session to authenticate with + @override + ClientBrowser setSession(value) { + config['session'] = value; + addHeader('X-Appwrite-Session', value); + return this; + } + /// The user agent string of the client that made the request + @override + ClientBrowser setForwardedUserAgent(value) { + config['forwardedUserAgent'] = value; + addHeader('X-Forwarded-User-Agent', value); + return this; + } + /// Your secret dev API key + @override + ClientBrowser setDevKey(value) { + config['devKey'] = value; + addHeader('X-Appwrite-Dev-Key', value); + return this; + } + /// The user cookie to authenticate with. Used by SDKs that forward an incoming Cookie header in server-side runtimes. + @override + ClientBrowser setCookie(value) { + config['cookie'] = value; + addHeader('Cookie', value); + return this; + } + /// 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. + @override + ClientBrowser setImpersonateUserId(value) { + config['impersonateUserId'] = value; + addHeader('X-Appwrite-Impersonate-User-Id', value); + return this; + } + /// 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. + @override + ClientBrowser setImpersonateUserEmail(value) { + config['impersonateUserEmail'] = value; + addHeader('X-Appwrite-Impersonate-User-Email', value); + return this; + } + /// 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. + @override + ClientBrowser setImpersonateUserPhone(value) { + config['impersonateUserPhone'] = value; + addHeader('X-Appwrite-Impersonate-User-Phone', value); + return this; + } @override ClientBrowser setSelfSigned({bool status = true}) { @@ -185,8 +175,7 @@ class ClientBrowser extends ClientBase with ClientMixin { late Response res; if (size <= chunkSize) { - params[paramName] = http.MultipartFile.fromBytes(paramName, file.bytes!, - filename: file.filename); + params[paramName] = http.MultipartFile.fromBytes(paramName, file.bytes!, filename: file.filename); return call( HttpMethod.post, path: path, @@ -217,14 +206,13 @@ class ClientBrowser extends ClientBase with ClientMixin { final totalChunks = (size / chunkSize).ceil(); - Future uploadChunk( - int index, int start, int end, String? id) async { + Future uploadChunk(int index, int start, int end, String? id) async { List chunk = []; chunk = file.bytes!.getRange(start, end).toList(); final chunkParams = Map.from(params); - chunkParams[paramName] = http.MultipartFile.fromBytes(paramName, chunk, - filename: file.filename); + chunkParams[paramName] = + http.MultipartFile.fromBytes(paramName, chunk, filename: file.filename); final chunkHeaders = Map.from(headers); if (id != null && id.isNotEmpty) { chunkHeaders['x-appwrite-id'] = id; @@ -253,9 +241,7 @@ class ClientBrowser extends ClientBase with ClientMixin { bool isUploadComplete(Response response) { final chunksUploaded = response.data['chunksUploaded']; final chunksTotal = response.data['chunksTotal'] ?? totalChunks; - return chunksUploaded is num && - chunksTotal is num && - chunksUploaded >= chunksTotal; + return chunksUploaded is num && chunksTotal is num && chunksUploaded >= chunksTotal; } final progress = UploadProgress( diff --git a/lib/src/client_io.dart b/lib/src/client_io.dart index 6aee80e8..7a177dde 100644 --- a/lib/src/client_io.dart +++ b/lib/src/client_io.dart @@ -20,7 +20,7 @@ ClientBase createClient({ ); class ClientIO extends ClientBase with ClientMixin { - static const int chunkSize = 5 * 1024 * 1024; + static const int chunkSize = 5*1024*1024; String _endPoint; Map? _headers; @override @@ -42,10 +42,9 @@ class ClientIO extends ClientBase with ClientMixin { 'x-sdk-name': 'Dart', 'x-sdk-platform': 'server', 'x-sdk-language': 'dart', - 'x-sdk-version': '24.1.0', - 'user-agent': - 'AppwriteDartSDK/24.1.0 (${Platform.operatingSystem}; ${Platform.operatingSystemVersion})', - 'X-Appwrite-Response-Format': '1.9.5', + 'x-sdk-version': '24.2.0', + 'user-agent' : 'AppwriteDartSDK/24.2.0 (${Platform.operatingSystem}; ${Platform.operatingSystemVersion})', + 'X-Appwrite-Response-Format' : '1.9.5', }; config = {}; @@ -57,92 +56,82 @@ class ClientIO extends ClientBase with ClientMixin { @override String get endPoint => _endPoint; - /// Your project ID - @override - ClientIO setProject(value) { - config['project'] = value; - addHeader('X-Appwrite-Project', value); - return this; - } - - /// Your secret API key - @override - ClientIO setKey(value) { - config['key'] = value; - addHeader('X-Appwrite-Key', value); - return this; - } - - /// Your secret JSON Web Token - @override - ClientIO setJWT(value) { - config['jWT'] = value; - addHeader('X-Appwrite-JWT', value); - return this; - } - - @override - ClientIO setLocale(value) { - config['locale'] = value; - addHeader('X-Appwrite-Locale', value); - return this; - } - - /// The user session to authenticate with - @override - ClientIO setSession(value) { - config['session'] = value; - addHeader('X-Appwrite-Session', value); - return this; - } - - /// The user agent string of the client that made the request - @override - ClientIO setForwardedUserAgent(value) { - config['forwardedUserAgent'] = value; - addHeader('X-Forwarded-User-Agent', value); - return this; - } - - /// Your secret dev API key - @override - ClientIO setDevKey(value) { - config['devKey'] = value; - addHeader('X-Appwrite-Dev-Key', value); - return this; - } - - /// The user cookie to authenticate with. Used by SDKs that forward an incoming Cookie header in server-side runtimes. - @override - ClientIO setCookie(value) { - config['cookie'] = value; - addHeader('Cookie', value); - return this; - } - - /// 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. - @override - ClientIO setImpersonateUserId(value) { - config['impersonateUserId'] = value; - addHeader('X-Appwrite-Impersonate-User-Id', value); - return this; - } - - /// 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. - @override - ClientIO setImpersonateUserEmail(value) { - config['impersonateUserEmail'] = value; - addHeader('X-Appwrite-Impersonate-User-Email', value); - return this; - } - - /// 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. - @override - ClientIO setImpersonateUserPhone(value) { - config['impersonateUserPhone'] = value; - addHeader('X-Appwrite-Impersonate-User-Phone', value); - return this; - } + /// Your project ID + @override + ClientIO setProject(value) { + config['project'] = value; + addHeader('X-Appwrite-Project', value); + return this; + } + /// Your secret API key + @override + ClientIO setKey(value) { + config['key'] = value; + addHeader('X-Appwrite-Key', value); + return this; + } + /// Your secret JSON Web Token + @override + ClientIO setJWT(value) { + config['jWT'] = value; + addHeader('X-Appwrite-JWT', value); + return this; + } + @override + ClientIO setLocale(value) { + config['locale'] = value; + addHeader('X-Appwrite-Locale', value); + return this; + } + /// The user session to authenticate with + @override + ClientIO setSession(value) { + config['session'] = value; + addHeader('X-Appwrite-Session', value); + return this; + } + /// The user agent string of the client that made the request + @override + ClientIO setForwardedUserAgent(value) { + config['forwardedUserAgent'] = value; + addHeader('X-Forwarded-User-Agent', value); + return this; + } + /// Your secret dev API key + @override + ClientIO setDevKey(value) { + config['devKey'] = value; + addHeader('X-Appwrite-Dev-Key', value); + return this; + } + /// The user cookie to authenticate with. Used by SDKs that forward an incoming Cookie header in server-side runtimes. + @override + ClientIO setCookie(value) { + config['cookie'] = value; + addHeader('Cookie', value); + return this; + } + /// 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. + @override + ClientIO setImpersonateUserId(value) { + config['impersonateUserId'] = value; + addHeader('X-Appwrite-Impersonate-User-Id', value); + return this; + } + /// 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. + @override + ClientIO setImpersonateUserEmail(value) { + config['impersonateUserEmail'] = value; + addHeader('X-Appwrite-Impersonate-User-Email', value); + return this; + } + /// 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. + @override + ClientIO setImpersonateUserPhone(value) { + config['impersonateUserPhone'] = value; + addHeader('X-Appwrite-Impersonate-User-Phone', value); + return this; + } @override ClientIO setSelfSigned({bool status = true}) { @@ -259,8 +248,8 @@ class ClientIO extends ClientBase with ClientMixin { } final chunkParams = Map.from(params); - chunkParams[paramName] = http.MultipartFile.fromBytes(paramName, chunk, - filename: file.filename); + chunkParams[paramName] = + http.MultipartFile.fromBytes(paramName, chunk, filename: file.filename); final chunkHeaders = Map.from(headers); if (id != null && id.isNotEmpty) { chunkHeaders['x-appwrite-id'] = id; @@ -289,9 +278,7 @@ class ClientIO extends ClientBase with ClientMixin { bool isUploadComplete(Response response) { final chunksUploaded = response.data['chunksUploaded']; final chunksTotal = response.data['chunksTotal'] ?? totalChunks; - return chunksUploaded is num && - chunksTotal is num && - chunksUploaded >= chunksTotal; + return chunksUploaded is num && chunksTotal is num && chunksUploaded >= chunksTotal; } final progress = UploadProgress( @@ -315,8 +302,7 @@ class ClientIO extends ClientBase with ClientMixin { var nextChunk = 0; Future uploadNext() async { - final raf = - file.bytes == null ? await iofile!.open(mode: FileMode.read) : null; + final raf = file.bytes == null ? await iofile!.open(mode: FileMode.read) : null; try { while (nextChunk < chunks.length) { final chunk = chunks[nextChunk++]; diff --git a/pubspec.yaml b/pubspec.yaml index 1bf18467..9764db99 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,5 +1,5 @@ name: dart_appwrite -version: 24.1.0 +version: 24.2.0 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 homepage: https://appwrite.io repository: https://github.com/appwrite/sdk-for-dart From 5a875bb971a97f9fa3bf372e6cb88d1dd839cd4a Mon Sep 17 00:00:00 2001 From: TorstenDittmann Date: Thu, 21 May 2026 18:42:36 +0000 Subject: [PATCH 13/13] Commit from GitHub Actions (Format and push) --- lib/src/client_browser.dart | 180 +++++++++++++++++++----------------- lib/src/client_io.dart | 180 +++++++++++++++++++----------------- 2 files changed, 194 insertions(+), 166 deletions(-) diff --git a/lib/src/client_browser.dart b/lib/src/client_browser.dart index e362fe55..2630f0eb 100644 --- a/lib/src/client_browser.dart +++ b/lib/src/client_browser.dart @@ -16,7 +16,7 @@ ClientBase createClient({ ClientBrowser(endPoint: endPoint, selfSigned: selfSigned); class ClientBrowser extends ClientBase with ClientMixin { - static const int chunkSize = 5*1024*1024; + static const int chunkSize = 5 * 1024 * 1024; String _endPoint; Map? _headers; @override @@ -34,7 +34,7 @@ class ClientBrowser extends ClientBase with ClientMixin { 'x-sdk-platform': 'server', 'x-sdk-language': 'dart', 'x-sdk-version': '24.2.0', - 'X-Appwrite-Response-Format' : '1.9.5', + 'X-Appwrite-Response-Format': '1.9.5', }; config = {}; @@ -46,82 +46,92 @@ class ClientBrowser extends ClientBase with ClientMixin { @override String get endPoint => _endPoint; - /// Your project ID - @override - ClientBrowser setProject(value) { - config['project'] = value; - addHeader('X-Appwrite-Project', value); - return this; - } - /// Your secret API key - @override - ClientBrowser setKey(value) { - config['key'] = value; - addHeader('X-Appwrite-Key', value); - return this; - } - /// Your secret JSON Web Token - @override - ClientBrowser setJWT(value) { - config['jWT'] = value; - addHeader('X-Appwrite-JWT', value); - return this; - } - @override - ClientBrowser setLocale(value) { - config['locale'] = value; - addHeader('X-Appwrite-Locale', value); - return this; - } - /// The user session to authenticate with - @override - ClientBrowser setSession(value) { - config['session'] = value; - addHeader('X-Appwrite-Session', value); - return this; - } - /// The user agent string of the client that made the request - @override - ClientBrowser setForwardedUserAgent(value) { - config['forwardedUserAgent'] = value; - addHeader('X-Forwarded-User-Agent', value); - return this; - } - /// Your secret dev API key - @override - ClientBrowser setDevKey(value) { - config['devKey'] = value; - addHeader('X-Appwrite-Dev-Key', value); - return this; - } - /// The user cookie to authenticate with. Used by SDKs that forward an incoming Cookie header in server-side runtimes. - @override - ClientBrowser setCookie(value) { - config['cookie'] = value; - addHeader('Cookie', value); - return this; - } - /// 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. - @override - ClientBrowser setImpersonateUserId(value) { - config['impersonateUserId'] = value; - addHeader('X-Appwrite-Impersonate-User-Id', value); - return this; - } - /// 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. - @override - ClientBrowser setImpersonateUserEmail(value) { - config['impersonateUserEmail'] = value; - addHeader('X-Appwrite-Impersonate-User-Email', value); - return this; - } - /// 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. - @override - ClientBrowser setImpersonateUserPhone(value) { - config['impersonateUserPhone'] = value; - addHeader('X-Appwrite-Impersonate-User-Phone', value); - return this; - } + /// Your project ID + @override + ClientBrowser setProject(value) { + config['project'] = value; + addHeader('X-Appwrite-Project', value); + return this; + } + + /// Your secret API key + @override + ClientBrowser setKey(value) { + config['key'] = value; + addHeader('X-Appwrite-Key', value); + return this; + } + + /// Your secret JSON Web Token + @override + ClientBrowser setJWT(value) { + config['jWT'] = value; + addHeader('X-Appwrite-JWT', value); + return this; + } + + @override + ClientBrowser setLocale(value) { + config['locale'] = value; + addHeader('X-Appwrite-Locale', value); + return this; + } + + /// The user session to authenticate with + @override + ClientBrowser setSession(value) { + config['session'] = value; + addHeader('X-Appwrite-Session', value); + return this; + } + + /// The user agent string of the client that made the request + @override + ClientBrowser setForwardedUserAgent(value) { + config['forwardedUserAgent'] = value; + addHeader('X-Forwarded-User-Agent', value); + return this; + } + + /// Your secret dev API key + @override + ClientBrowser setDevKey(value) { + config['devKey'] = value; + addHeader('X-Appwrite-Dev-Key', value); + return this; + } + + /// The user cookie to authenticate with. Used by SDKs that forward an incoming Cookie header in server-side runtimes. + @override + ClientBrowser setCookie(value) { + config['cookie'] = value; + addHeader('Cookie', value); + return this; + } + + /// 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. + @override + ClientBrowser setImpersonateUserId(value) { + config['impersonateUserId'] = value; + addHeader('X-Appwrite-Impersonate-User-Id', value); + return this; + } + + /// 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. + @override + ClientBrowser setImpersonateUserEmail(value) { + config['impersonateUserEmail'] = value; + addHeader('X-Appwrite-Impersonate-User-Email', value); + return this; + } + + /// 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. + @override + ClientBrowser setImpersonateUserPhone(value) { + config['impersonateUserPhone'] = value; + addHeader('X-Appwrite-Impersonate-User-Phone', value); + return this; + } @override ClientBrowser setSelfSigned({bool status = true}) { @@ -175,7 +185,8 @@ class ClientBrowser extends ClientBase with ClientMixin { late Response res; if (size <= chunkSize) { - params[paramName] = http.MultipartFile.fromBytes(paramName, file.bytes!, filename: file.filename); + params[paramName] = http.MultipartFile.fromBytes(paramName, file.bytes!, + filename: file.filename); return call( HttpMethod.post, path: path, @@ -206,13 +217,14 @@ class ClientBrowser extends ClientBase with ClientMixin { final totalChunks = (size / chunkSize).ceil(); - Future uploadChunk(int index, int start, int end, String? id) async { + Future uploadChunk( + int index, int start, int end, String? id) async { List chunk = []; chunk = file.bytes!.getRange(start, end).toList(); final chunkParams = Map.from(params); - chunkParams[paramName] = - http.MultipartFile.fromBytes(paramName, chunk, filename: file.filename); + chunkParams[paramName] = http.MultipartFile.fromBytes(paramName, chunk, + filename: file.filename); final chunkHeaders = Map.from(headers); if (id != null && id.isNotEmpty) { chunkHeaders['x-appwrite-id'] = id; @@ -241,7 +253,9 @@ class ClientBrowser extends ClientBase with ClientMixin { bool isUploadComplete(Response response) { final chunksUploaded = response.data['chunksUploaded']; final chunksTotal = response.data['chunksTotal'] ?? totalChunks; - return chunksUploaded is num && chunksTotal is num && chunksUploaded >= chunksTotal; + return chunksUploaded is num && + chunksTotal is num && + chunksUploaded >= chunksTotal; } final progress = UploadProgress( diff --git a/lib/src/client_io.dart b/lib/src/client_io.dart index 7a177dde..6bb86255 100644 --- a/lib/src/client_io.dart +++ b/lib/src/client_io.dart @@ -20,7 +20,7 @@ ClientBase createClient({ ); class ClientIO extends ClientBase with ClientMixin { - static const int chunkSize = 5*1024*1024; + static const int chunkSize = 5 * 1024 * 1024; String _endPoint; Map? _headers; @override @@ -43,8 +43,9 @@ class ClientIO extends ClientBase with ClientMixin { 'x-sdk-platform': 'server', 'x-sdk-language': 'dart', 'x-sdk-version': '24.2.0', - 'user-agent' : 'AppwriteDartSDK/24.2.0 (${Platform.operatingSystem}; ${Platform.operatingSystemVersion})', - 'X-Appwrite-Response-Format' : '1.9.5', + 'user-agent': + 'AppwriteDartSDK/24.2.0 (${Platform.operatingSystem}; ${Platform.operatingSystemVersion})', + 'X-Appwrite-Response-Format': '1.9.5', }; config = {}; @@ -56,82 +57,92 @@ class ClientIO extends ClientBase with ClientMixin { @override String get endPoint => _endPoint; - /// Your project ID - @override - ClientIO setProject(value) { - config['project'] = value; - addHeader('X-Appwrite-Project', value); - return this; - } - /// Your secret API key - @override - ClientIO setKey(value) { - config['key'] = value; - addHeader('X-Appwrite-Key', value); - return this; - } - /// Your secret JSON Web Token - @override - ClientIO setJWT(value) { - config['jWT'] = value; - addHeader('X-Appwrite-JWT', value); - return this; - } - @override - ClientIO setLocale(value) { - config['locale'] = value; - addHeader('X-Appwrite-Locale', value); - return this; - } - /// The user session to authenticate with - @override - ClientIO setSession(value) { - config['session'] = value; - addHeader('X-Appwrite-Session', value); - return this; - } - /// The user agent string of the client that made the request - @override - ClientIO setForwardedUserAgent(value) { - config['forwardedUserAgent'] = value; - addHeader('X-Forwarded-User-Agent', value); - return this; - } - /// Your secret dev API key - @override - ClientIO setDevKey(value) { - config['devKey'] = value; - addHeader('X-Appwrite-Dev-Key', value); - return this; - } - /// The user cookie to authenticate with. Used by SDKs that forward an incoming Cookie header in server-side runtimes. - @override - ClientIO setCookie(value) { - config['cookie'] = value; - addHeader('Cookie', value); - return this; - } - /// 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. - @override - ClientIO setImpersonateUserId(value) { - config['impersonateUserId'] = value; - addHeader('X-Appwrite-Impersonate-User-Id', value); - return this; - } - /// 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. - @override - ClientIO setImpersonateUserEmail(value) { - config['impersonateUserEmail'] = value; - addHeader('X-Appwrite-Impersonate-User-Email', value); - return this; - } - /// 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. - @override - ClientIO setImpersonateUserPhone(value) { - config['impersonateUserPhone'] = value; - addHeader('X-Appwrite-Impersonate-User-Phone', value); - return this; - } + /// Your project ID + @override + ClientIO setProject(value) { + config['project'] = value; + addHeader('X-Appwrite-Project', value); + return this; + } + + /// Your secret API key + @override + ClientIO setKey(value) { + config['key'] = value; + addHeader('X-Appwrite-Key', value); + return this; + } + + /// Your secret JSON Web Token + @override + ClientIO setJWT(value) { + config['jWT'] = value; + addHeader('X-Appwrite-JWT', value); + return this; + } + + @override + ClientIO setLocale(value) { + config['locale'] = value; + addHeader('X-Appwrite-Locale', value); + return this; + } + + /// The user session to authenticate with + @override + ClientIO setSession(value) { + config['session'] = value; + addHeader('X-Appwrite-Session', value); + return this; + } + + /// The user agent string of the client that made the request + @override + ClientIO setForwardedUserAgent(value) { + config['forwardedUserAgent'] = value; + addHeader('X-Forwarded-User-Agent', value); + return this; + } + + /// Your secret dev API key + @override + ClientIO setDevKey(value) { + config['devKey'] = value; + addHeader('X-Appwrite-Dev-Key', value); + return this; + } + + /// The user cookie to authenticate with. Used by SDKs that forward an incoming Cookie header in server-side runtimes. + @override + ClientIO setCookie(value) { + config['cookie'] = value; + addHeader('Cookie', value); + return this; + } + + /// 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. + @override + ClientIO setImpersonateUserId(value) { + config['impersonateUserId'] = value; + addHeader('X-Appwrite-Impersonate-User-Id', value); + return this; + } + + /// 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. + @override + ClientIO setImpersonateUserEmail(value) { + config['impersonateUserEmail'] = value; + addHeader('X-Appwrite-Impersonate-User-Email', value); + return this; + } + + /// 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. + @override + ClientIO setImpersonateUserPhone(value) { + config['impersonateUserPhone'] = value; + addHeader('X-Appwrite-Impersonate-User-Phone', value); + return this; + } @override ClientIO setSelfSigned({bool status = true}) { @@ -248,8 +259,8 @@ class ClientIO extends ClientBase with ClientMixin { } final chunkParams = Map.from(params); - chunkParams[paramName] = - http.MultipartFile.fromBytes(paramName, chunk, filename: file.filename); + chunkParams[paramName] = http.MultipartFile.fromBytes(paramName, chunk, + filename: file.filename); final chunkHeaders = Map.from(headers); if (id != null && id.isNotEmpty) { chunkHeaders['x-appwrite-id'] = id; @@ -278,7 +289,9 @@ class ClientIO extends ClientBase with ClientMixin { bool isUploadComplete(Response response) { final chunksUploaded = response.data['chunksUploaded']; final chunksTotal = response.data['chunksTotal'] ?? totalChunks; - return chunksUploaded is num && chunksTotal is num && chunksUploaded >= chunksTotal; + return chunksUploaded is num && + chunksTotal is num && + chunksUploaded >= chunksTotal; } final progress = UploadProgress( @@ -302,7 +315,8 @@ class ClientIO extends ClientBase with ClientMixin { var nextChunk = 0; Future uploadNext() async { - final raf = file.bytes == null ? await iofile!.open(mode: FileMode.read) : null; + final raf = + file.bytes == null ? await iofile!.open(mode: FileMode.read) : null; try { while (nextChunk < chunks.length) { final chunk = chunks[nextChunk++];