diff --git a/packages/amber/pubspec.lock b/packages/amber/pubspec.lock index 949f5a38..d580538d 100644 --- a/packages/amber/pubspec.lock +++ b/packages/amber/pubspec.lock @@ -469,7 +469,7 @@ packages: path: "../ndk" relative: true source: path - version: "0.2.0" + version: "0.2.4" package_config: dependency: transitive description: diff --git a/packages/isar/pubspec.lock b/packages/isar/pubspec.lock index f3ec2d1c..8fe8f3a1 100644 --- a/packages/isar/pubspec.lock +++ b/packages/isar/pubspec.lock @@ -375,7 +375,7 @@ packages: path: "../ndk" relative: true source: path - version: "0.2.0" + version: "0.2.4" node_preamble: dependency: transitive description: diff --git a/packages/ndk/lib/data_layer/data_sources/http_request.dart b/packages/ndk/lib/data_layer/data_sources/http_request.dart index a21f382f..43b84890 100644 --- a/packages/ndk/lib/data_layer/data_sources/http_request.dart +++ b/packages/ndk/lib/data_layer/data_sources/http_request.dart @@ -1,4 +1,5 @@ import 'dart:convert'; +import 'dart:typed_data'; import 'package:http/http.dart' as http; @@ -21,4 +22,45 @@ class HttpRequestDS { } return jsonDecode(response.body); } + + Future put({ + required Uri url, + required Uint8List body, + required headers, + }) async { + http.Response response = await _client.put( + url, + body: body, + headers: headers, + ); + + if (response.statusCode != 200) { + throw Exception( + "error fetching STATUS: ${response.statusCode}, Link: $url"); + } + + return response; + } + + Future get(Uri url) async { + http.Response response = await _client.get(url); + + if (response.statusCode != 200) { + throw Exception( + "error fetching STATUS: ${response.statusCode}, Link: $url"); + } + + return response; + } + + Future delete(Uri url) async { + http.Response response = await _client.delete(url); + + if (response.statusCode != 200) { + throw Exception( + "error fetching STATUS: ${response.statusCode}, Link: $url"); + } + + return response; + } } diff --git a/packages/ndk/lib/data_layer/repositories/blossom/blossom_impl.dart b/packages/ndk/lib/data_layer/repositories/blossom/blossom_impl.dart new file mode 100644 index 00000000..791d5dba --- /dev/null +++ b/packages/ndk/lib/data_layer/repositories/blossom/blossom_impl.dart @@ -0,0 +1,207 @@ +import 'dart:convert'; +import 'dart:typed_data'; + +import '../../../domain_layer/repositories/blossom.dart'; +import '../../data_sources/http_request.dart'; + +class BlossomRepositoryImpl implements BlossomRepository { + final HttpRequestDS client; + final List serverUrls; + + BlossomRepositoryImpl({ + required this.client, + required this.serverUrls, + }) { + if (serverUrls.isEmpty) { + throw ArgumentError('At least one server URL must be provided'); + } + } + + @override + Future> uploadBlob( + Uint8List data, { + String? contentType, + UploadStrategy strategy = UploadStrategy.mirrorAfterSuccess, + }) async { + switch (strategy) { + case UploadStrategy.mirrorAfterSuccess: + return _uploadWithMirroring(data, contentType); + case UploadStrategy.allSimultaneous: + return _uploadToAllServers(data, contentType); + case UploadStrategy.firstSuccess: + return _uploadToFirstSuccess(data, contentType); + } + } + + Future> _uploadWithMirroring( + Uint8List data, + String? contentType, + ) async { + final results = []; + + // Try primary upload + final primaryResult = await _uploadToServer( + serverUrls.first, + data, + contentType, + ); + results.add(primaryResult); + + if (primaryResult.success) { + // Mirror to other servers + final mirrorResults = await Future.wait(serverUrls + .skip(1) + .map((url) => _uploadToServer(url, data, contentType))); + results.addAll(mirrorResults); + } + + return results; + } + + Future> _uploadToAllServers( + Uint8List data, + String? contentType, + ) async { + final results = await Future.wait( + serverUrls.map((url) => _uploadToServer(url, data, contentType))); + return results; + } + + Future> _uploadToFirstSuccess( + Uint8List data, + String? contentType, + ) async { + for (final url in serverUrls) { + final result = await _uploadToServer(url, data, contentType); + if (result.success) { + return [result]; + } + } + + // If all servers failed, return all errors + final results = await _uploadToAllServers(data, contentType); + return results; + } + + Future _uploadToServer( + String serverUrl, + Uint8List data, + String? contentType, + ) async { + try { + final response = await client.put( + url: Uri.parse('$serverUrl/upload'), + body: data, + headers: { + if (contentType != null) 'Content-Type': contentType, + 'Content-Length': '${data.length}', + }, + ); + + if (response.statusCode != 200) { + return BlobUploadResult( + serverUrl: serverUrl, + success: false, + error: 'HTTP ${response.statusCode}', + ); + } + + return BlobUploadResult( + serverUrl: serverUrl, + success: true, + descriptor: BlobDescriptor.fromJson(jsonDecode(response.body)), + ); + } catch (e) { + return BlobUploadResult( + serverUrl: serverUrl, + success: false, + error: e.toString(), + ); + } + } + + @override + Future getBlob(String sha256) async { + Exception? lastError; + + for (final url in serverUrls) { + try { + final response = await client.get( + Uri.parse('$url/$sha256'), + ); + + if (response.statusCode == 200) { + return response.bodyBytes; + } + lastError = Exception('HTTP ${response.statusCode}'); + } catch (e) { + lastError = e is Exception ? e : Exception(e.toString()); + } + } + + throw Exception( + 'Failed to get blob from all servers. Last error: $lastError'); + } + + @override + Future> listBlobs( + String pubkey, { + DateTime? since, + DateTime? until, + }) async { + Exception? lastError; + + for (final url in serverUrls) { + try { + final queryParams = { + if (since != null) 'since': '${since.millisecondsSinceEpoch ~/ 1000}', + if (until != null) 'until': '${until.millisecondsSinceEpoch ~/ 1000}', + }; + + final response = await client.get( + Uri.parse('$url/list/$pubkey').replace(queryParameters: queryParams), + ); + + if (response.statusCode == 200) { + final List json = jsonDecode(response.body); + return json.map((j) => BlobDescriptor.fromJson(j)).toList(); + } + lastError = Exception('HTTP ${response.statusCode}'); + } catch (e) { + lastError = e is Exception ? e : Exception(e.toString()); + } + } + + throw Exception( + 'Failed to list blobs from all servers. Last error: $lastError'); + } + + @override + Future> deleteBlob(String sha256) async { + final results = await Future.wait( + serverUrls.map((url) => _deleteFromServer(url, sha256))); + return results; + } + + Future _deleteFromServer( + String serverUrl, String sha256) async { + try { + final response = await client.delete( + Uri.parse('$serverUrl/$sha256'), + ); + + return BlobDeleteResult( + serverUrl: serverUrl, + success: response.statusCode == 200, + error: + response.statusCode != 200 ? 'HTTP ${response.statusCode}' : null, + ); + } catch (e) { + return BlobDeleteResult( + serverUrl: serverUrl, + success: false, + error: e.toString(), + ); + } + } +} diff --git a/packages/ndk/lib/domain_layer/repositories/blossom.dart b/packages/ndk/lib/domain_layer/repositories/blossom.dart new file mode 100644 index 00000000..e482c620 --- /dev/null +++ b/packages/ndk/lib/domain_layer/repositories/blossom.dart @@ -0,0 +1,81 @@ +import 'dart:typed_data'; + +enum UploadStrategy { + /// Upload to first server, then mirror to others + mirrorAfterSuccess, + + /// Upload to all servers simultaneously + allSimultaneous, + + /// Upload to first successful server only + firstSuccess +} + +abstract class BlossomRepository { + /// Uploads a blob using the specified strategy + Future> uploadBlob( + Uint8List data, { + String? contentType, + UploadStrategy strategy = UploadStrategy.mirrorAfterSuccess, + }); + + /// Gets a blob by trying servers sequentially until success + Future getBlob(String sha256); + + /// Lists blobs from the first successful server + Future> listBlobs(String pubkey, + {DateTime? since, DateTime? until}); + + /// Attempts to delete blob from all servers + Future> deleteBlob(String sha256); +} + +class BlobDescriptor { + final String url; + final String sha256; + final int size; + final String? type; + final DateTime uploaded; + + BlobDescriptor( + {required this.url, + required this.sha256, + required this.size, + this.type, + required this.uploaded}); + + factory BlobDescriptor.fromJson(Map json) { + return BlobDescriptor( + url: json['url'], + sha256: json['sha256'], + size: json['size'], + type: json['type'], + uploaded: DateTime.fromMillisecondsSinceEpoch(json['uploaded'] * 1000)); + } +} + +class BlobUploadResult { + final String serverUrl; + final bool success; + final BlobDescriptor? descriptor; + final String? error; + + BlobUploadResult({ + required this.serverUrl, + required this.success, + this.descriptor, + this.error, + }); +} + +class BlobDeleteResult { + final String serverUrl; + final bool success; + final String? error; + + BlobDeleteResult({ + required this.serverUrl, + required this.success, + this.error, + }); +} diff --git a/packages/ndk/lib/domain_layer/usecases/files/files.dart b/packages/ndk/lib/domain_layer/usecases/files/files.dart new file mode 100644 index 00000000..4c0c0cf5 --- /dev/null +++ b/packages/ndk/lib/domain_layer/usecases/files/files.dart @@ -0,0 +1,39 @@ +import 'dart:typed_data'; + +import '../../repositories/blossom.dart'; + +class Files { + final BlossomRepository repository; + + Files(this.repository); + + Future> uploadBlob({ + required Uint8List data, + String? contentType, + UploadStrategy strategy = UploadStrategy.mirrorAfterSuccess, + }) { + return repository.uploadBlob( + data, + contentType: contentType, + strategy: strategy, + ); + } + + Future getBlob(String sha256) { + return repository.getBlob(sha256); + } + + Future> listBlobs( + String pubkey, { + DateTime? since, + DateTime? until, + }) { + return repository.listBlobs(pubkey, since: since, until: until); + } + +// lib/domain/usecases/delete_blob_usecase.dart + + Future delteBlob(String sha256) { + return repository.deleteBlob(sha256); + } +} diff --git a/packages/ndk/pubspec.lock b/packages/ndk/pubspec.lock index 62339a40..73ea5f66 100644 --- a/packages/ndk/pubspec.lock +++ b/packages/ndk/pubspec.lock @@ -141,10 +141,10 @@ packages: dependency: "direct main" description: name: collection - sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a + sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76" url: "https://pub.dev" source: hosted - version: "1.18.0" + version: "1.19.1" convert: dependency: "direct main" description: @@ -273,6 +273,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.2.2" + http_methods: + dependency: transitive + description: + name: http_methods + sha256: "6bccce8f1ec7b5d701e7921dca35e202d425b57e317ba1a37f2638590e29e566" + url: "https://pub.dev" + source: hosted + version: "1.1.1" http_multi_server: dependency: transitive description: @@ -285,10 +293,10 @@ packages: dependency: transitive description: name: http_parser - sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b" + sha256: "178d74305e7866013777bab2c3d8726205dc5a4dd935297175b19a23a2e66571" url: "https://pub.dev" source: hosted - version: "4.0.2" + version: "4.1.2" io: dependency: transitive description: @@ -434,13 +442,13 @@ packages: source: hosted version: "0.28.0" shelf: - dependency: transitive + dependency: "direct dev" description: name: shelf - sha256: ad29c505aee705f41a4d8963641f91ac4cee3c8fad5947e033390a7bd8180fa4 + sha256: e7dd780a7ffb623c57850b33f43309312fc863fb6aa3d276a754bb299839ef12 url: "https://pub.dev" source: hosted - version: "1.4.1" + version: "1.4.2" shelf_packages_handler: dependency: transitive description: @@ -449,6 +457,14 @@ packages: url: "https://pub.dev" source: hosted version: "3.0.2" + shelf_router: + dependency: "direct dev" + description: + name: shelf_router + sha256: f5e5d492440a7fb165fe1e2e1a623f31f734d3370900070b2b1e0d0428d59864 + url: "https://pub.dev" + source: hosted + version: "1.1.4" shelf_static: dependency: transitive description: diff --git a/packages/ndk/pubspec.yaml b/packages/ndk/pubspec.yaml index ed4d6b89..554697bd 100644 --- a/packages/ndk/pubspec.yaml +++ b/packages/ndk/pubspec.yaml @@ -37,3 +37,7 @@ dev_dependencies: flutter_lints: ^5.0.0 mockito: ^5.0.17 test: any + # shelf used for blossom mock server + shelf: ^1.4.2 + shelf_router: ^1.1.4 + diff --git a/packages/ndk/test/mocks/mock_blossom_server.dart b/packages/ndk/test/mocks/mock_blossom_server.dart new file mode 100644 index 00000000..eb7cb5ca --- /dev/null +++ b/packages/ndk/test/mocks/mock_blossom_server.dart @@ -0,0 +1,194 @@ +import 'dart:convert'; +import 'dart:io'; +import 'dart:typed_data'; +import 'package:crypto/crypto.dart'; +import 'package:shelf/shelf.dart'; +import 'package:shelf/shelf_io.dart'; +import 'package:shelf_router/shelf_router.dart'; + +class MockBlossomServer { + // In-memory storage for blobs + final Map _blobs = {}; + final int port; + HttpServer? _server; + + MockBlossomServer({this.port = 3000}); + + Router _createRouter() { + final router = Router(); + + // GET / - Get Blob + router.get('/', (Request request, String sha256) { + if (!_blobs.containsKey(sha256)) { + return Response.notFound('Blob not found'); + } + return Response.ok(_blobs[sha256]!.data, + headers: {'Content-Type': _blobs[sha256]!.contentType}); + }); + + // HEAD / - Has Blob + router.head('/', (Request request, String sha256) { + if (!_blobs.containsKey(sha256)) { + return Response.notFound('Blob not found'); + } + return Response(200, headers: { + 'Content-Length': _blobs[sha256]!.data.length.toString(), + 'Content-Type': _blobs[sha256]!.contentType, + }); + }); + + // PUT /upload - Upload Blob + router.put('/upload', (Request request) async { + // Check for authorization header + final authHeader = request.headers['authorization']; + if (authHeader == null) { + return Response.forbidden('Missing authorization'); + } + + try { + final authEvent = json.decode(authHeader); + if (!_verifyAuthEvent(authEvent, 'upload')) { + return Response.forbidden('Invalid authorization event'); + } + } catch (e) { + return Response.forbidden('Invalid authorization format'); + } + + // Read the request body + final bytes = await request.read().expand((chunk) => chunk).toList(); + final data = Uint8List.fromList(bytes); + + final sha256 = _computeSha256(data); + final contentType = + request.headers['content-type'] ?? 'application/octet-stream'; + + _blobs[sha256] = _BlobEntry( + data: data, + contentType: contentType, + uploader: 'test_pubkey', + uploadedAt: DateTime.now(), + ); + + return Response.ok( + json.encode({ + 'url': 'http://localhost:$port/$sha256', + 'sha256': sha256, + 'size': data.length, + 'type': contentType, + 'uploaded': DateTime.now().millisecondsSinceEpoch ~/ 1000, + }), + headers: {'Content-Type': 'application/json'}, + ); + }); + + // GET /list/ - List Blobs + router.get('/list/', (Request request, String pubkey) { + final since = int.tryParse(request.url.queryParameters['since'] ?? ''); + final until = int.tryParse(request.url.queryParameters['until'] ?? ''); + + final blobs = _blobs.entries + .where((entry) => entry.value.uploader == pubkey) + .where((entry) { + final timestamp = + entry.value.uploadedAt.millisecondsSinceEpoch ~/ 1000; + if (since != null && timestamp < since) return false; + if (until != null && timestamp > until) return false; + return true; + }) + .map((entry) => { + 'url': 'http://localhost:$port/${entry.key}', + 'sha256': entry.key, + 'size': entry.value.data.length, + 'type': entry.value.contentType, + 'uploaded': + entry.value.uploadedAt.millisecondsSinceEpoch ~/ 1000, + }) + .toList(); + + return Response.ok( + json.encode(blobs), + headers: {'Content-Type': 'application/json'}, + ); + }); + + // DELETE / - Delete Blob + router.delete('/', (Request request, String sha256) { + final authHeader = request.headers['authorization']; + if (authHeader == null) { + return Response.forbidden('Missing authorization'); + } + + try { + final authEvent = json.decode(authHeader); + if (!_verifyAuthEvent(authEvent, 'delete')) { + return Response.forbidden('Invalid authorization event'); + } + } catch (e) { + return Response.forbidden('Invalid authorization format'); + } + + if (!_blobs.containsKey(sha256)) { + return Response.notFound('Blob not found'); + } + + _blobs.remove(sha256); + return Response(200); + }); + + return router; + } + + Future start() async { + final handler = Pipeline() + .addMiddleware(logRequests()) + .addHandler(_createRouter().call); + + _server = await serve(handler, 'localhost', port); + print('Mock Blossom Server running on port $port'); + } + + Future stop() async { + await _server?.close(); + _server = null; + } + + // Helper methods + String _computeSha256(List data) { + return sha256.convert(data).toString(); + } + + bool _verifyAuthEvent(Map event, String type) { + // Simple verification for testing purposes + if (event['kind'] != 24242) return false; + + final tags = List>.from(event['tags']); + final hasTypeTag = + tags.any((tag) => tag.length >= 2 && tag[0] == 't' && tag[1] == type); + + return hasTypeTag; + } +} + +class _BlobEntry { + final Uint8List data; + final String contentType; + final String uploader; + final DateTime uploadedAt; + + _BlobEntry({ + required this.data, + required this.contentType, + required this.uploader, + required this.uploadedAt, + }); +} + +// Example usage in tests +void main() async { + final server = MockBlossomServer(port: 3000); + await server.start(); + + // Run your tests here + + await server.stop(); +} diff --git a/packages/ndk/test/usecases/files/files_test.dart b/packages/ndk/test/usecases/files/files_test.dart new file mode 100644 index 00000000..ed2860c4 --- /dev/null +++ b/packages/ndk/test/usecases/files/files_test.dart @@ -0,0 +1,82 @@ +import 'dart:convert'; +import 'dart:typed_data'; +import 'package:http/http.dart' as http; + +import 'package:ndk/data_layer/data_sources/http_request.dart'; +import 'package:ndk/data_layer/repositories/blossom/blossom_impl.dart'; +import 'package:ndk/domain_layer/usecases/files/files.dart'; +import 'package:test/test.dart'; + +import '../../mocks/mock_blossom_server.dart'; + +void main() { + late MockBlossomServer server; + late Files client; + + setUp(() async { + server = MockBlossomServer(port: 3000); + await server.start(); + + final blossomRepo = BlossomRepositoryImpl( + client: HttpRequestDS(http.Client()), + serverUrls: ['http://localhost:3000'], + ); + client = Files(blossomRepo); + }); + + tearDown(() async { + await server.stop(); + }); + + group('Blossom Client Integration Tests', () { + test('Upload and retrieve blob', () async { + final testData = Uint8List.fromList(utf8.encode('Hello, Blossom!')); + final authEvent = createTestAuthEvent('upload'); + + // Upload blob + final uploadResponse = await client.uploadBlob( + data: testData, + //authorization: authEvent, + ); + expect(uploadResponse.first.success, true); + + final sha256 = uploadResponse.first.descriptor!.sha256; + + // Retrieve blob + final getResponse = await client.getBlob(sha256); + expect(utf8.decode(getResponse), equals('Hello, Blossom!')); + }); + + test('List blobs for user', () async { + // Upload some test blobs first + final testData1 = Uint8List.fromList(utf8.encode('Test 1')); + final testData2 = Uint8List.fromList(utf8.encode('Test 2')); + + await client.uploadBlob( + data: testData1, + //authorization: createTestAuthEvent('upload'), + ); + await client.uploadBlob( + data: testData2, + //authorization: createTestAuthEvent('upload'), + ); + + final listResponse = await client.listBlobs('test_pubkey'); + + expect(listResponse.length, equals(2)); + }); + }); +} + +Map createTestAuthEvent(String type) { + return { + 'kind': 24242, + 'pubkey': 'test_pubkey', + 'created_at': DateTime.now().millisecondsSinceEpoch ~/ 1000, + 'tags': [ + ['t', type], + ['x', 'test_hash'], + ], + 'sig': 'test_signature', + }; +} diff --git a/packages/objectbox/pubspec.lock b/packages/objectbox/pubspec.lock index efe69acf..ba98e49a 100644 --- a/packages/objectbox/pubspec.lock +++ b/packages/objectbox/pubspec.lock @@ -401,7 +401,7 @@ packages: path: "../ndk" relative: true source: path - version: "0.2.0" + version: "0.2.4" node_preamble: dependency: transitive description: diff --git a/packages/rust_verifier/.flutter-plugins b/packages/rust_verifier/.flutter-plugins index 522dd75a..206f100c 100644 --- a/packages/rust_verifier/.flutter-plugins +++ b/packages/rust_verifier/.flutter-plugins @@ -1,8 +1,8 @@ # This is a generated file; do not edit or check into version control. -integration_test=/usr/bin/flutter/packages/integration_test/ -path_provider=/home/fmar/.pub-cache/hosted/pub.dev/path_provider-2.1.5/ -path_provider_android=/home/fmar/.pub-cache/hosted/pub.dev/path_provider_android-2.2.12/ -path_provider_foundation=/home/fmar/.pub-cache/hosted/pub.dev/path_provider_foundation-2.4.0/ -path_provider_linux=/home/fmar/.pub-cache/hosted/pub.dev/path_provider_linux-2.2.1/ -path_provider_windows=/home/fmar/.pub-cache/hosted/pub.dev/path_provider_windows-2.3.0/ -rust_lib_ndk=/home/fmar/workspace/ndk/packages/rust_verifier/rust_builder/ +integration_test=C:\\Users\\Beonde\\Documents\\flutterSDK\\flutter\\packages\\integration_test\\ +path_provider=C:\\Users\\Beonde\\AppData\\Local\\Pub\\Cache\\hosted\\pub.dev\\path_provider-2.1.5\\ +path_provider_android=C:\\Users\\Beonde\\AppData\\Local\\Pub\\Cache\\hosted\\pub.dev\\path_provider_android-2.2.12\\ +path_provider_foundation=C:\\Users\\Beonde\\AppData\\Local\\Pub\\Cache\\hosted\\pub.dev\\path_provider_foundation-2.4.0\\ +path_provider_linux=C:\\Users\\Beonde\\AppData\\Local\\Pub\\Cache\\hosted\\pub.dev\\path_provider_linux-2.2.1\\ +path_provider_windows=C:\\Users\\Beonde\\AppData\\Local\\Pub\\Cache\\hosted\\pub.dev\\path_provider_windows-2.3.0\\ +rust_lib_ndk=c:\\Users\\Beonde\\AndroidStudioProjects\\ndk\\packages\\rust_verifier\\rust_builder\\ diff --git a/packages/rust_verifier/.flutter-plugins-dependencies b/packages/rust_verifier/.flutter-plugins-dependencies index b6416a02..0be33c7f 100644 --- a/packages/rust_verifier/.flutter-plugins-dependencies +++ b/packages/rust_verifier/.flutter-plugins-dependencies @@ -1 +1 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"integration_test","path":"/usr/bin/flutter/packages/integration_test/","native_build":true,"dependencies":[]},{"name":"path_provider_foundation","path":"/home/fmar/.pub-cache/hosted/pub.dev/path_provider_foundation-2.4.0/","shared_darwin_source":true,"native_build":true,"dependencies":[]},{"name":"rust_lib_ndk","path":"/home/fmar/workspace/ndk/packages/rust_verifier/rust_builder/","native_build":true,"dependencies":[]}],"android":[{"name":"integration_test","path":"/usr/bin/flutter/packages/integration_test/","native_build":true,"dependencies":[]},{"name":"path_provider_android","path":"/home/fmar/.pub-cache/hosted/pub.dev/path_provider_android-2.2.12/","native_build":true,"dependencies":[]},{"name":"rust_lib_ndk","path":"/home/fmar/workspace/ndk/packages/rust_verifier/rust_builder/","native_build":true,"dependencies":[]}],"macos":[{"name":"path_provider_foundation","path":"/home/fmar/.pub-cache/hosted/pub.dev/path_provider_foundation-2.4.0/","shared_darwin_source":true,"native_build":true,"dependencies":[]},{"name":"rust_lib_ndk","path":"/home/fmar/workspace/ndk/packages/rust_verifier/rust_builder/","native_build":true,"dependencies":[]}],"linux":[{"name":"path_provider_linux","path":"/home/fmar/.pub-cache/hosted/pub.dev/path_provider_linux-2.2.1/","native_build":false,"dependencies":[]},{"name":"rust_lib_ndk","path":"/home/fmar/workspace/ndk/packages/rust_verifier/rust_builder/","native_build":true,"dependencies":[]}],"windows":[{"name":"path_provider_windows","path":"/home/fmar/.pub-cache/hosted/pub.dev/path_provider_windows-2.3.0/","native_build":false,"dependencies":[]},{"name":"rust_lib_ndk","path":"/home/fmar/workspace/ndk/packages/rust_verifier/rust_builder/","native_build":true,"dependencies":[]}],"web":[]},"dependencyGraph":[{"name":"integration_test","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_android","path_provider_foundation","path_provider_linux","path_provider_windows"]},{"name":"path_provider_android","dependencies":[]},{"name":"path_provider_foundation","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"rust_lib_ndk","dependencies":[]}],"date_created":"2024-12-18 00:22:24.640813","version":"3.27.0","swift_package_manager_enabled":false} \ No newline at end of file +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"integration_test","path":"C:\\\\Users\\\\Beonde\\\\Documents\\\\flutterSDK\\\\flutter\\\\packages\\\\integration_test\\\\","native_build":true,"dependencies":[]},{"name":"path_provider_foundation","path":"C:\\\\Users\\\\Beonde\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dev\\\\path_provider_foundation-2.4.0\\\\","shared_darwin_source":true,"native_build":true,"dependencies":[]},{"name":"rust_lib_ndk","path":"c:\\\\Users\\\\Beonde\\\\AndroidStudioProjects\\\\ndk\\\\packages\\\\rust_verifier\\\\rust_builder\\\\","native_build":true,"dependencies":[]}],"android":[{"name":"integration_test","path":"C:\\\\Users\\\\Beonde\\\\Documents\\\\flutterSDK\\\\flutter\\\\packages\\\\integration_test\\\\","native_build":true,"dependencies":[]},{"name":"path_provider_android","path":"C:\\\\Users\\\\Beonde\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dev\\\\path_provider_android-2.2.12\\\\","native_build":true,"dependencies":[]},{"name":"rust_lib_ndk","path":"c:\\\\Users\\\\Beonde\\\\AndroidStudioProjects\\\\ndk\\\\packages\\\\rust_verifier\\\\rust_builder\\\\","native_build":true,"dependencies":[]}],"macos":[{"name":"path_provider_foundation","path":"C:\\\\Users\\\\Beonde\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dev\\\\path_provider_foundation-2.4.0\\\\","shared_darwin_source":true,"native_build":true,"dependencies":[]},{"name":"rust_lib_ndk","path":"c:\\\\Users\\\\Beonde\\\\AndroidStudioProjects\\\\ndk\\\\packages\\\\rust_verifier\\\\rust_builder\\\\","native_build":true,"dependencies":[]}],"linux":[{"name":"path_provider_linux","path":"C:\\\\Users\\\\Beonde\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dev\\\\path_provider_linux-2.2.1\\\\","native_build":false,"dependencies":[]},{"name":"rust_lib_ndk","path":"c:\\\\Users\\\\Beonde\\\\AndroidStudioProjects\\\\ndk\\\\packages\\\\rust_verifier\\\\rust_builder\\\\","native_build":true,"dependencies":[]}],"windows":[{"name":"path_provider_windows","path":"C:\\\\Users\\\\Beonde\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dev\\\\path_provider_windows-2.3.0\\\\","native_build":false,"dependencies":[]},{"name":"rust_lib_ndk","path":"c:\\\\Users\\\\Beonde\\\\AndroidStudioProjects\\\\ndk\\\\packages\\\\rust_verifier\\\\rust_builder\\\\","native_build":true,"dependencies":[]}],"web":[]},"dependencyGraph":[{"name":"integration_test","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_android","path_provider_foundation","path_provider_linux","path_provider_windows"]},{"name":"path_provider_android","dependencies":[]},{"name":"path_provider_foundation","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"rust_lib_ndk","dependencies":[]}],"date_created":"2025-01-10 11:17:04.830361","version":"3.27.1","swift_package_manager_enabled":false} \ No newline at end of file diff --git a/packages/rust_verifier/pubspec.lock b/packages/rust_verifier/pubspec.lock index cc8561c6..7de95040 100644 --- a/packages/rust_verifier/pubspec.lock +++ b/packages/rust_verifier/pubspec.lock @@ -477,7 +477,7 @@ packages: path: "../ndk" relative: true source: path - version: "0.2.0" + version: "0.2.4" package_config: dependency: transitive description: