From d7a6881db85c7ed2ae50e0162bfff9bb1cebfe9c Mon Sep 17 00:00:00 2001 From: stevensJourney Date: Wed, 26 Nov 2025 11:47:00 +0200 Subject: [PATCH] feat: app metadata --- demos/benchmarks/pubspec.lock | 8 ++-- demos/django-todolist/pubspec.lock | 8 ++-- demos/firebase-nodejs-todolist/pubspec.lock | 8 ++-- demos/supabase-anonymous-auth/pubspec.lock | 8 ++-- .../supabase-edge-function-auth/pubspec.lock | 8 ++-- demos/supabase-simple-chat/pubspec.lock | 8 ++-- demos/supabase-todolist-drift/pubspec.lock | 8 ++-- .../pubspec.lock | 8 ++-- demos/supabase-todolist/lib/powersync.dart | 4 +- demos/supabase-todolist/macos/Podfile.lock | 12 +++--- demos/supabase-todolist/pubspec.lock | 23 ++++------- demos/supabase-trello/pubspec.lock | 8 ++-- .../powersync_core/lib/src/sync/options.dart | 12 ++++++ .../powersync_core/lib/src/sync/protocol.dart | 7 +++- .../lib/src/sync/streaming_sync.dart | 33 ++++++++++++--- .../powersync_sqlcipher/example/pubspec.lock | 41 +++++++++---------- 16 files changed, 116 insertions(+), 88 deletions(-) diff --git a/demos/benchmarks/pubspec.lock b/demos/benchmarks/pubspec.lock index b2fb290b..bb759c1e 100644 --- a/demos/benchmarks/pubspec.lock +++ b/demos/benchmarks/pubspec.lock @@ -191,10 +191,10 @@ packages: dependency: transitive description: name: meta - sha256: "23f08335362185a5ea2ad3a4e597f1375e78bce8a040df5c600c8d3552ef2394" + sha256: e3641ec5d63ebf0d9b41bd43201a66e3fc79a65db5f61fc181f04cd27aab950c url: "https://pub.dev" source: hosted - version: "1.17.0" + version: "1.16.0" mutex: dependency: transitive description: @@ -401,10 +401,10 @@ packages: dependency: transitive description: name: test_api - sha256: ab2726c1a94d3176a45960b6234466ec367179b87dd74f1611adb1f3b5fb9d55 + sha256: "522f00f556e73044315fa4585ec3270f1808a4b186c936e612cab0b565ff1e00" url: "https://pub.dev" source: hosted - version: "0.7.7" + version: "0.7.6" typed_data: dependency: transitive description: diff --git a/demos/django-todolist/pubspec.lock b/demos/django-todolist/pubspec.lock index 0cbb85ee..aae9c9f3 100644 --- a/demos/django-todolist/pubspec.lock +++ b/demos/django-todolist/pubspec.lock @@ -204,10 +204,10 @@ packages: dependency: transitive description: name: meta - sha256: "23f08335362185a5ea2ad3a4e597f1375e78bce8a040df5c600c8d3552ef2394" + sha256: e3641ec5d63ebf0d9b41bd43201a66e3fc79a65db5f61fc181f04cd27aab950c url: "https://pub.dev" source: hosted - version: "1.17.0" + version: "1.16.0" mutex: dependency: transitive description: @@ -470,10 +470,10 @@ packages: dependency: transitive description: name: test_api - sha256: ab2726c1a94d3176a45960b6234466ec367179b87dd74f1611adb1f3b5fb9d55 + sha256: "522f00f556e73044315fa4585ec3270f1808a4b186c936e612cab0b565ff1e00" url: "https://pub.dev" source: hosted - version: "0.7.7" + version: "0.7.6" typed_data: dependency: transitive description: diff --git a/demos/firebase-nodejs-todolist/pubspec.lock b/demos/firebase-nodejs-todolist/pubspec.lock index 30b59fdd..3c01b04d 100644 --- a/demos/firebase-nodejs-todolist/pubspec.lock +++ b/demos/firebase-nodejs-todolist/pubspec.lock @@ -324,10 +324,10 @@ packages: dependency: transitive description: name: meta - sha256: "23f08335362185a5ea2ad3a4e597f1375e78bce8a040df5c600c8d3552ef2394" + sha256: e3641ec5d63ebf0d9b41bd43201a66e3fc79a65db5f61fc181f04cd27aab950c url: "https://pub.dev" source: hosted - version: "1.17.0" + version: "1.16.0" mime: dependency: transitive description: @@ -654,10 +654,10 @@ packages: dependency: transitive description: name: test_api - sha256: ab2726c1a94d3176a45960b6234466ec367179b87dd74f1611adb1f3b5fb9d55 + sha256: "522f00f556e73044315fa4585ec3270f1808a4b186c936e612cab0b565ff1e00" url: "https://pub.dev" source: hosted - version: "0.7.7" + version: "0.7.6" typed_data: dependency: transitive description: diff --git a/demos/supabase-anonymous-auth/pubspec.lock b/demos/supabase-anonymous-auth/pubspec.lock index a988c291..f36ba2ac 100644 --- a/demos/supabase-anonymous-auth/pubspec.lock +++ b/demos/supabase-anonymous-auth/pubspec.lock @@ -268,10 +268,10 @@ packages: dependency: transitive description: name: meta - sha256: "23f08335362185a5ea2ad3a4e597f1375e78bce8a040df5c600c8d3552ef2394" + sha256: e3641ec5d63ebf0d9b41bd43201a66e3fc79a65db5f61fc181f04cd27aab950c url: "https://pub.dev" source: hosted - version: "1.17.0" + version: "1.16.0" mime: dependency: transitive description: @@ -598,10 +598,10 @@ packages: dependency: transitive description: name: test_api - sha256: ab2726c1a94d3176a45960b6234466ec367179b87dd74f1611adb1f3b5fb9d55 + sha256: "522f00f556e73044315fa4585ec3270f1808a4b186c936e612cab0b565ff1e00" url: "https://pub.dev" source: hosted - version: "0.7.7" + version: "0.7.6" typed_data: dependency: transitive description: diff --git a/demos/supabase-edge-function-auth/pubspec.lock b/demos/supabase-edge-function-auth/pubspec.lock index a988c291..f36ba2ac 100644 --- a/demos/supabase-edge-function-auth/pubspec.lock +++ b/demos/supabase-edge-function-auth/pubspec.lock @@ -268,10 +268,10 @@ packages: dependency: transitive description: name: meta - sha256: "23f08335362185a5ea2ad3a4e597f1375e78bce8a040df5c600c8d3552ef2394" + sha256: e3641ec5d63ebf0d9b41bd43201a66e3fc79a65db5f61fc181f04cd27aab950c url: "https://pub.dev" source: hosted - version: "1.17.0" + version: "1.16.0" mime: dependency: transitive description: @@ -598,10 +598,10 @@ packages: dependency: transitive description: name: test_api - sha256: ab2726c1a94d3176a45960b6234466ec367179b87dd74f1611adb1f3b5fb9d55 + sha256: "522f00f556e73044315fa4585ec3270f1808a4b186c936e612cab0b565ff1e00" url: "https://pub.dev" source: hosted - version: "0.7.7" + version: "0.7.6" typed_data: dependency: transitive description: diff --git a/demos/supabase-simple-chat/pubspec.lock b/demos/supabase-simple-chat/pubspec.lock index 8a63472b..dba63e09 100644 --- a/demos/supabase-simple-chat/pubspec.lock +++ b/demos/supabase-simple-chat/pubspec.lock @@ -284,10 +284,10 @@ packages: dependency: transitive description: name: meta - sha256: "23f08335362185a5ea2ad3a4e597f1375e78bce8a040df5c600c8d3552ef2394" + sha256: e3641ec5d63ebf0d9b41bd43201a66e3fc79a65db5f61fc181f04cd27aab950c url: "https://pub.dev" source: hosted - version: "1.17.0" + version: "1.16.0" mime: dependency: transitive description: @@ -614,10 +614,10 @@ packages: dependency: transitive description: name: test_api - sha256: ab2726c1a94d3176a45960b6234466ec367179b87dd74f1611adb1f3b5fb9d55 + sha256: "522f00f556e73044315fa4585ec3270f1808a4b186c936e612cab0b565ff1e00" url: "https://pub.dev" source: hosted - version: "0.7.7" + version: "0.7.6" timeago: dependency: "direct main" description: diff --git a/demos/supabase-todolist-drift/pubspec.lock b/demos/supabase-todolist-drift/pubspec.lock index be3cba5f..940c8d19 100644 --- a/demos/supabase-todolist-drift/pubspec.lock +++ b/demos/supabase-todolist-drift/pubspec.lock @@ -604,10 +604,10 @@ packages: dependency: transitive description: name: meta - sha256: "23f08335362185a5ea2ad3a4e597f1375e78bce8a040df5c600c8d3552ef2394" + sha256: e3641ec5d63ebf0d9b41bd43201a66e3fc79a65db5f61fc181f04cd27aab950c url: "https://pub.dev" source: hosted - version: "1.17.0" + version: "1.16.0" mime: dependency: transitive description: @@ -1061,10 +1061,10 @@ packages: dependency: transitive description: name: test_api - sha256: ab2726c1a94d3176a45960b6234466ec367179b87dd74f1611adb1f3b5fb9d55 + sha256: "522f00f556e73044315fa4585ec3270f1808a4b186c936e612cab0b565ff1e00" url: "https://pub.dev" source: hosted - version: "0.7.7" + version: "0.7.6" timing: dependency: transitive description: diff --git a/demos/supabase-todolist-optional-sync/pubspec.lock b/demos/supabase-todolist-optional-sync/pubspec.lock index 6aa2c4a3..c7f1562b 100644 --- a/demos/supabase-todolist-optional-sync/pubspec.lock +++ b/demos/supabase-todolist-optional-sync/pubspec.lock @@ -340,10 +340,10 @@ packages: dependency: transitive description: name: meta - sha256: "23f08335362185a5ea2ad3a4e597f1375e78bce8a040df5c600c8d3552ef2394" + sha256: e3641ec5d63ebf0d9b41bd43201a66e3fc79a65db5f61fc181f04cd27aab950c url: "https://pub.dev" source: hosted - version: "1.17.0" + version: "1.16.0" mime: dependency: transitive description: @@ -694,10 +694,10 @@ packages: dependency: transitive description: name: test_api - sha256: ab2726c1a94d3176a45960b6234466ec367179b87dd74f1611adb1f3b5fb9d55 + sha256: "522f00f556e73044315fa4585ec3270f1808a4b186c936e612cab0b565ff1e00" url: "https://pub.dev" source: hosted - version: "0.7.7" + version: "0.7.6" typed_data: dependency: transitive description: diff --git a/demos/supabase-todolist/lib/powersync.dart b/demos/supabase-todolist/lib/powersync.dart index 412e53c7..d6e5973d 100644 --- a/demos/supabase-todolist/lib/powersync.dart +++ b/demos/supabase-todolist/lib/powersync.dart @@ -153,7 +153,9 @@ Future getDatabasePath() async { return join(dir.path, dbFilename); } -const options = SyncOptions(syncImplementation: SyncClientImplementation.rust); +const options = SyncOptions( + syncImplementation: SyncClientImplementation.rust, + appMetadata: {'app_version': '1.0.1'}); Future openDatabase() async { // Open the local database diff --git a/demos/supabase-todolist/macos/Podfile.lock b/demos/supabase-todolist/macos/Podfile.lock index 51b6fdad..0bdf6b82 100644 --- a/demos/supabase-todolist/macos/Podfile.lock +++ b/demos/supabase-todolist/macos/Podfile.lock @@ -72,15 +72,15 @@ EXTERNAL SOURCES: :path: Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos SPEC CHECKSUMS: - app_links: 05a6ec2341985eb05e9f97dc63f5837c39895c3f + app_links: c3185399a5cabc2e610ee5ad52fb7269b84ff869 FlutterMacOS: d0db08ddef1a9af05a5ec4b724367152bb0500b1 - path_provider_foundation: 080d55be775b7414fd5a5ef3ac137b97b097e564 + path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46 powersync-sqlite-core: 42c4a42a692b3b770a5488778789430d67a39b49 - powersync_flutter_libs: 19fc6b96ff8155ffea72a08990f6c9f2e712b8a6 - shared_preferences_foundation: 9e1978ff2562383bd5676f64ec4e9aa8fa06a6f7 + powersync_flutter_libs: 6d1e96884e20082a54b3ceec06939649d038f572 + shared_preferences_foundation: fcdcbc04712aee1108ac7fda236f363274528f78 sqlite3: 73513155ec6979715d3904ef53a8d68892d4032b - sqlite3_flutter_libs: 83f8e9f5b6554077f1d93119fe20ebaa5f3a9ef1 - url_launcher_macos: 0fba8ddabfc33ce0a9afe7c5fef5aab3d8d2d673 + sqlite3_flutter_libs: 86f82662868ee26ff3451f73cac9c5fc2a1f57fa + url_launcher_macos: c82c93949963e55b228a30115bd219499a6fe404 PODFILE CHECKSUM: 9ebaf0ce3d369aaa26a9ea0e159195ed94724cf3 diff --git a/demos/supabase-todolist/pubspec.lock b/demos/supabase-todolist/pubspec.lock index 2e88f33f..916c0aca 100644 --- a/demos/supabase-todolist/pubspec.lock +++ b/demos/supabase-todolist/pubspec.lock @@ -420,10 +420,10 @@ packages: dependency: transitive description: name: meta - sha256: "23f08335362185a5ea2ad3a4e597f1375e78bce8a040df5c600c8d3552ef2394" + sha256: e3641ec5d63ebf0d9b41bd43201a66e3fc79a65db5f61fc181f04cd27aab950c url: "https://pub.dev" source: hosted - version: "1.17.0" + version: "1.16.0" mime: dependency: transitive description: @@ -567,13 +567,6 @@ packages: relative: true source: path version: "1.16.1" - powersync_attachments_helper: - dependency: "direct overridden" - description: - path: "../../packages/powersync_attachments_helper" - relative: true - source: path - version: "0.6.20" powersync_core: dependency: "direct main" description: @@ -853,26 +846,26 @@ packages: dependency: "direct dev" description: name: test - sha256: "75906bf273541b676716d1ca7627a17e4c4070a3a16272b7a3dc7da3b9f3f6b7" + sha256: "65e29d831719be0591f7b3b1a32a3cda258ec98c58c7b25f7b84241bc31215bb" url: "https://pub.dev" source: hosted - version: "1.26.3" + version: "1.26.2" test_api: dependency: transitive description: name: test_api - sha256: ab2726c1a94d3176a45960b6234466ec367179b87dd74f1611adb1f3b5fb9d55 + sha256: "522f00f556e73044315fa4585ec3270f1808a4b186c936e612cab0b565ff1e00" url: "https://pub.dev" source: hosted - version: "0.7.7" + version: "0.7.6" test_core: dependency: transitive description: name: test_core - sha256: "0cc24b5ff94b38d2ae73e1eb43cc302b77964fbf67abad1e296025b78deb53d0" + sha256: "80bf5a02b60af04b09e14f6fe68b921aad119493e26e490deaca5993fef1b05a" url: "https://pub.dev" source: hosted - version: "0.6.12" + version: "0.6.11" typed_data: dependency: transitive description: diff --git a/demos/supabase-trello/pubspec.lock b/demos/supabase-trello/pubspec.lock index c2e77eb7..b2c6c349 100644 --- a/demos/supabase-trello/pubspec.lock +++ b/demos/supabase-trello/pubspec.lock @@ -428,10 +428,10 @@ packages: dependency: transitive description: name: meta - sha256: "23f08335362185a5ea2ad3a4e597f1375e78bce8a040df5c600c8d3552ef2394" + sha256: e3641ec5d63ebf0d9b41bd43201a66e3fc79a65db5f61fc181f04cd27aab950c url: "https://pub.dev" source: hosted - version: "1.17.0" + version: "1.16.0" mime: dependency: transitive description: @@ -782,10 +782,10 @@ packages: dependency: transitive description: name: test_api - sha256: ab2726c1a94d3176a45960b6234466ec367179b87dd74f1611adb1f3b5fb9d55 + sha256: "522f00f556e73044315fa4585ec3270f1808a4b186c936e612cab0b565ff1e00" url: "https://pub.dev" source: hosted - version: "0.7.7" + version: "0.7.6" typed_data: dependency: transitive description: diff --git a/packages/powersync_core/lib/src/sync/options.dart b/packages/powersync_core/lib/src/sync/options.dart index ee8b3c63..94a70046 100644 --- a/packages/powersync_core/lib/src/sync/options.dart +++ b/packages/powersync_core/lib/src/sync/options.dart @@ -3,6 +3,11 @@ import 'package:meta/meta.dart'; /// Options that affect how the sync client connects to the sync service. final class SyncOptions { + /// A map of application metadata that is passed to the PowerSync service. + /// + /// Application metadata that will be displayed in PowerSync service logs. + final Map? appMetadata; + /// A JSON object that is passed to the sync service and forwarded to sync /// rules. /// @@ -39,12 +44,14 @@ final class SyncOptions { this.params, this.syncImplementation = SyncClientImplementation.defaultClient, this.includeDefaultStreams, + this.appMetadata, }); SyncOptions _copyWith({ Duration? crudThrottleTime, Duration? retryDelay, Map? params, + Map? appMetadata, }) { return SyncOptions( crudThrottleTime: crudThrottleTime ?? this.crudThrottleTime, @@ -52,6 +59,7 @@ final class SyncOptions { params: params ?? this.params, syncImplementation: syncImplementation, includeDefaultStreams: includeDefaultStreams, + appMetadata: appMetadata ?? this.appMetadata, ); } } @@ -89,14 +97,18 @@ extension type ResolvedSyncOptions(SyncOptions source) { Duration? crudThrottleTime, Duration? retryDelay, Map? params, + Map? appMetadata, }) { return ResolvedSyncOptions((source ?? SyncOptions())._copyWith( crudThrottleTime: crudThrottleTime, retryDelay: retryDelay, params: params, + appMetadata: appMetadata, )); } + Map get appMetadata => source.appMetadata ?? const {}; + Duration get crudThrottleTime => source.crudThrottleTime ?? const Duration(milliseconds: 10); diff --git a/packages/powersync_core/lib/src/sync/protocol.dart b/packages/powersync_core/lib/src/sync/protocol.dart index 4e07334b..8ca27312 100644 --- a/packages/powersync_core/lib/src/sync/protocol.dart +++ b/packages/powersync_core/lib/src/sync/protocol.dart @@ -247,15 +247,18 @@ class StreamingSyncRequest { bool includeChecksum = true; String clientId; Map? parameters; + Map? appMetadata; - StreamingSyncRequest(this.buckets, this.parameters, this.clientId); + StreamingSyncRequest( + this.buckets, this.parameters, this.clientId, this.appMetadata); Map toJson() { final Map json = { 'buckets': buckets, 'include_checksum': includeChecksum, 'raw_data': true, - 'client_id': clientId + 'client_id': clientId, + 'app_metadata': appMetadata, }; if (parameters != null) { diff --git a/packages/powersync_core/lib/src/sync/streaming_sync.dart b/packages/powersync_core/lib/src/sync/streaming_sync.dart index 60deef12..fd974db9 100644 --- a/packages/powersync_core/lib/src/sync/streaming_sync.dart +++ b/packages/powersync_core/lib/src/sync/streaming_sync.dart @@ -12,14 +12,14 @@ import 'package:powersync_core/src/sync/options.dart'; import 'package:powersync_core/src/user_agent/user_agent.dart'; import 'package:sqlite_async/mutex.dart'; -import 'bucket_storage.dart'; import '../crud.dart'; +import 'bucket_storage.dart'; import 'instruction.dart'; import 'internal_connector.dart'; import 'mutable_sync_status.dart'; +import 'protocol.dart'; import 'stream_utils.dart'; import 'sync_status.dart'; -import 'protocol.dart'; typedef SubscribedStream = ({String name, String parameters}); @@ -339,8 +339,8 @@ class StreamingSyncImplementation implements StreamingSync { Checkpoint? targetCheckpoint; - var requestStream = _streamingSyncRequest( - StreamingSyncRequest(bucketRequests, options.params, clientId!)) + var requestStream = _streamingSyncRequest(StreamingSyncRequest( + bucketRequests, options.params, clientId!, options.appMetadata)) .map(ReceivedLine.new); var merged = addBroadcast(requestStream, _nonLineSyncEvents.stream); @@ -632,6 +632,7 @@ final class _ActiveRustStreamingIteration { await _control( 'start', convert.json.encode({ + 'app_metadata': sync.options.appMetadata, 'parameters': sync.options.params, 'schema': convert.json.decode(sync.schemaJson), 'include_defaults': sync.options.includeDefaultStreams, @@ -766,8 +767,28 @@ final class _ActiveRustStreamingIteration { _ => Level.WARNING, }, line); - case EstablishSyncStream(): - _completedStream.complete(_handleLines(instruction)); + case EstablishSyncStream(:final request): + // FIXME + // Merge app_metadata from options into the instruction request + // since the Rust instruction does not yet merge app_metadata from the supplied options. + // Rust client values will override options values if present. + final mergedRequest = Map.from(request); + final appMetadata = sync.options.appMetadata; + if (appMetadata.isNotEmpty) { + final existingMetadata = request['app_metadata']; + if (existingMetadata is Map) { + // Merge: start with options, then let Rust override + mergedRequest['app_metadata'] = { + ...appMetadata, + ...existingMetadata.cast(), + }; + } else { + // No existing metadata, just use options + mergedRequest['app_metadata'] = appMetadata; + } + } + _completedStream + .complete(_handleLines(EstablishSyncStream(mergedRequest))); case UpdateSyncStatus(:final status): sync._state.updateStatus((m) => m.applyFromCore(status)); case FetchCredentials(:final didExpire): diff --git a/packages/powersync_sqlcipher/example/pubspec.lock b/packages/powersync_sqlcipher/example/pubspec.lock index 29f874c6..30c2fbc5 100644 --- a/packages/powersync_sqlcipher/example/pubspec.lock +++ b/packages/powersync_sqlcipher/example/pubspec.lock @@ -222,10 +222,10 @@ packages: dependency: transitive description: name: meta - sha256: "23f08335362185a5ea2ad3a4e597f1375e78bce8a040df5c600c8d3552ef2394" + sha256: e3641ec5d63ebf0d9b41bd43201a66e3fc79a65db5f61fc181f04cd27aab950c url: "https://pub.dev" source: hosted - version: "1.17.0" + version: "1.16.0" mime: dependency: transitive description: @@ -315,28 +315,25 @@ packages: source: hosted version: "2.1.8" powersync_core: - dependency: transitive + dependency: "direct overridden" description: - name: powersync_core - sha256: "878f335489bffa7f92167b42ce4ac2c0895015387a74285d4f2f2a11d47e08d2" - url: "https://pub.dev" - source: hosted + path: "../../powersync_core" + relative: true + source: path version: "1.6.1" powersync_flutter_libs: - dependency: transitive + dependency: "direct overridden" description: - name: powersync_flutter_libs - sha256: "6385c74c3537b72086f62becd038e1f4a50bff57783e260de95f89f1c2a16aa2" - url: "https://pub.dev" - source: hosted + path: "../../powersync_flutter_libs" + relative: true + source: path version: "0.4.12" powersync_sqlcipher: dependency: "direct main" description: - name: powersync_sqlcipher - sha256: d22a358480d60f4f4091b03100a58da6651389ca21e23427a90812148da9d196 - url: "https://pub.dev" - source: hosted + path: ".." + relative: true + source: path version: "0.1.13" process: dependency: transitive @@ -419,18 +416,18 @@ packages: dependency: transitive description: name: sqlite3_web - sha256: "0f6ebcb4992d1892ac5c8b5ecd22a458ab9c5eb6428b11ae5ecb5d63545844da" + sha256: "3973adf9ee74e485d5552319e1903129f4ed999fe675aa0b4b5d35d112b2aa1c" url: "https://pub.dev" source: hosted - version: "0.3.2" + version: "0.4.1" sqlite_async: dependency: transitive description: name: sqlite_async - sha256: cf1871971324cccc03d26762ff10406fc6384af9a1ea538f12352aa5906164ec + sha256: ba3acc93e20a810ce6bde7ba1a3356ca5b162d34906f186374398106f1458f52 url: "https://pub.dev" source: hosted - version: "0.12.2" + version: "0.13.0" stack_trace: dependency: transitive description: @@ -475,10 +472,10 @@ packages: dependency: transitive description: name: test_api - sha256: ab2726c1a94d3176a45960b6234466ec367179b87dd74f1611adb1f3b5fb9d55 + sha256: "522f00f556e73044315fa4585ec3270f1808a4b186c936e612cab0b565ff1e00" url: "https://pub.dev" source: hosted - version: "0.7.7" + version: "0.7.6" typed_data: dependency: transitive description: