update stream_transform example to package:web

Fixes a deprecation warning from the latest SDK.
diff --git a/pkgs/pubspec_parse/CHANGELOG.md b/pkgs/pubspec_parse/CHANGELOG.md
index 124b5e4..5aeb498 100644
--- a/pkgs/pubspec_parse/CHANGELOG.md
+++ b/pkgs/pubspec_parse/CHANGELOG.md
@@ -1,6 +1,6 @@
-## 1.5.0-wip
+## 1.5.0
 
-- Add `Pubspec.workspace` and `Pubspec.resolution` fields.
+- Added fields to `Pubspec`: `executables`, `resolution`, `workspace`.
 - Require Dart 3.6
 - Update dependencies.
 
diff --git a/pkgs/pubspec_parse/lib/src/pubspec.dart b/pkgs/pubspec_parse/lib/src/pubspec.dart
index cdfc8ff..eb77908 100644
--- a/pkgs/pubspec_parse/lib/src/pubspec.dart
+++ b/pkgs/pubspec_parse/lib/src/pubspec.dart
@@ -93,6 +93,10 @@
   /// and other settings.
   final Map<String, dynamic>? flutter;
 
+  /// Optional field to specify executables
+  @JsonKey(fromJson: _executablesMap)
+  final Map<String, String?> executables;
+
   /// If this package is a Pub Workspace, this field lists the sub-packages.
   final List<String>? workspace;
 
@@ -129,12 +133,14 @@
     Map<String, Dependency>? devDependencies,
     Map<String, Dependency>? dependencyOverrides,
     this.flutter,
+    Map<String, String?>? executables,
   })  :
         // ignore: deprecated_member_use_from_same_package
         authors = _normalizeAuthors(author, authors),
         environment = environment ?? const {},
         dependencies = dependencies ?? const {},
         devDependencies = devDependencies ?? const {},
+        executables = executables ?? const {},
         dependencyOverrides = dependencyOverrides ?? const {} {
     if (name.isEmpty) {
       throw ArgumentError.value(name, 'name', '"name" cannot be empty.');
@@ -232,3 +238,21 @@
       return MapEntry(key, constraint);
     }) ??
     {};
+
+Map<String, String?> _executablesMap(Map? source) =>
+    source?.map((k, value) {
+      final key = k as String;
+      if (value == null) {
+        return MapEntry(key, null);
+      } else if (value is String) {
+        return MapEntry(key, value);
+      } else {
+        throw CheckedFromJsonException(
+          source,
+          key,
+          'String',
+          '`$value` is not a String.',
+        );
+      }
+    }) ??
+    {};
diff --git a/pkgs/pubspec_parse/lib/src/pubspec.g.dart b/pkgs/pubspec_parse/lib/src/pubspec.g.dart
index f0fb79e..58e015a 100644
--- a/pkgs/pubspec_parse/lib/src/pubspec.g.dart
+++ b/pkgs/pubspec_parse/lib/src/pubspec.g.dart
@@ -54,6 +54,8 @@
               (v) => (v as Map?)?.map(
                     (k, e) => MapEntry(k as String, e),
                   )),
+          executables:
+              $checkedConvert('executables', (v) => _executablesMap(v as Map?)),
         );
         return val;
       },
diff --git a/pkgs/pubspec_parse/pubspec.yaml b/pkgs/pubspec_parse/pubspec.yaml
index 6bf96bb..73a1117 100644
--- a/pkgs/pubspec_parse/pubspec.yaml
+++ b/pkgs/pubspec_parse/pubspec.yaml
@@ -1,5 +1,5 @@
 name: pubspec_parse
-version: 1.5.0-wip
+version: 1.5.0
 description: >-
   Simple package for parsing pubspec.yaml files with a type-safe API and rich
   error reporting.
diff --git a/pkgs/pubspec_parse/test/parse_test.dart b/pkgs/pubspec_parse/test/parse_test.dart
index 5570b60..e0698af 100644
--- a/pkgs/pubspec_parse/test/parse_test.dart
+++ b/pkgs/pubspec_parse/test/parse_test.dart
@@ -34,6 +34,7 @@
     expect(value.screenshots, isEmpty);
     expect(value.workspace, isNull);
     expect(value.resolution, isNull);
+    expect(value.executables, isEmpty);
   });
 
   test('all fields set', () async {
@@ -64,6 +65,10 @@
           'pkg2',
         ],
         'resolution': 'workspace',
+        'executables': {
+          'my_script': 'bin/my_script.dart',
+          'my_script2': 'bin/my_script2.dart',
+        },
       },
       skipTryPub: true,
     );
@@ -96,6 +101,11 @@
     expect(value.screenshots, hasLength(1));
     expect(value.screenshots!.first.description, 'my screenshot');
     expect(value.screenshots!.first.path, 'path/to/screenshot');
+    expect(value.executables, hasLength(2));
+    expect(value.executables.keys, contains('my_script'));
+    expect(value.executables.keys, contains('my_script2'));
+    expect(value.executables['my_script'], 'bin/my_script.dart');
+    expect(value.executables['my_script2'], 'bin/my_script2.dart');
     expect(value.workspace, hasLength(2));
     expect(value.workspace!.first, 'pkg1');
     expect(value.workspace!.last, 'pkg2');
@@ -222,6 +232,58 @@
     });
   });
 
+  group('executables', () {
+    test('one executable', () async {
+      final value = await parse({
+        ...defaultPubspec,
+        'executables': {'my_script': 'bin/my_script.dart'},
+      });
+      expect(value.executables, hasLength(1));
+      expect(value.executables.keys, contains('my_script'));
+      expect(value.executables['my_script'], 'bin/my_script.dart');
+    });
+
+    test('many executables', () async {
+      final value = await parse({
+        ...defaultPubspec,
+        'executables': {
+          'my_script': 'bin/my_script.dart',
+          'my_script2': 'bin/my_script2.dart',
+        },
+      });
+      expect(value.executables, hasLength(2));
+      expect(value.executables.keys, contains('my_script'));
+      expect(value.executables.keys, contains('my_script2'));
+      expect(value.executables['my_script'], 'bin/my_script.dart');
+      expect(value.executables['my_script2'], 'bin/my_script2.dart');
+    });
+
+    test('invalid value', () async {
+      expectParseThrowsContaining(
+        {
+          ...defaultPubspec,
+          'executables': {
+            'script': 32,
+          },
+        },
+        'Unsupported value for "script". `32` is not a String.',
+        skipTryPub: true,
+      );
+    });
+
+    test('invalid executable - lenient', () async {
+      final value = await parse(
+        {
+          ...defaultPubspec,
+          'executables': 'Invalid value',
+        },
+        lenient: true,
+      );
+      expect(value.name, 'sample');
+      expect(value.executables, isEmpty);
+    });
+  });
+
   group('invalid', () {
     test('null', () {
       expectParseThrows(
diff --git a/pkgs/stream_channel/CHANGELOG.md b/pkgs/stream_channel/CHANGELOG.md
index 30f7d32..9dd3990 100644
--- a/pkgs/stream_channel/CHANGELOG.md
+++ b/pkgs/stream_channel/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 2.1.4
+
+* Fix `StreamChannelMixin` so that it can be used as a mixin again.
+
 ## 2.1.3
 
 * Require Dart 3.3
diff --git a/pkgs/stream_channel/lib/stream_channel.dart b/pkgs/stream_channel/lib/stream_channel.dart
index 85f9a97..8e53096 100644
--- a/pkgs/stream_channel/lib/stream_channel.dart
+++ b/pkgs/stream_channel/lib/stream_channel.dart
@@ -148,7 +148,7 @@
 
 /// A mixin that implements the instance methods of [StreamChannel] in terms of
 /// [stream] and [sink].
-abstract class StreamChannelMixin<T> implements StreamChannel<T> {
+abstract mixin class StreamChannelMixin<T> implements StreamChannel<T> {
   @override
   void pipe(StreamChannel<T> other) {
     stream.pipe(other.sink);
diff --git a/pkgs/stream_channel/pubspec.yaml b/pkgs/stream_channel/pubspec.yaml
index eec8c1b..f050fca 100644
--- a/pkgs/stream_channel/pubspec.yaml
+++ b/pkgs/stream_channel/pubspec.yaml
@@ -1,5 +1,5 @@
 name: stream_channel
-version: 2.1.3
+version: 2.1.4
 description: >-
   An abstraction for two-way communication channels based on the Dart Stream
   class.
diff --git a/pkgs/stream_channel/test/stream_channel_test.dart b/pkgs/stream_channel/test/stream_channel_test.dart
index c44b6ab..166671d 100644
--- a/pkgs/stream_channel/test/stream_channel_test.dart
+++ b/pkgs/stream_channel/test/stream_channel_test.dart
@@ -135,4 +135,46 @@
     changed.sink.add(10);
     changed.sink.close();
   });
+
+  group('StreamChannelMixin', () {
+    test('can be used as a mixin', () async {
+      var channel = StreamChannelMixinAsMixin<int>();
+      expect(channel.stream, emitsInOrder([1, 2, 3]));
+      channel.sink
+        ..add(1)
+        ..add(2)
+        ..add(3);
+      await channel.controller.close();
+    });
+
+    test('can be extended', () async {
+      var channel = StreamChannelMixinAsSuperclass<int>();
+      expect(channel.stream, emitsInOrder([1, 2, 3]));
+      channel.sink
+        ..add(1)
+        ..add(2)
+        ..add(3);
+      await channel.controller.close();
+    });
+  });
+}
+
+class StreamChannelMixinAsMixin<T> with StreamChannelMixin<T> {
+  final controller = StreamController<T>();
+
+  @override
+  StreamSink<T> get sink => controller.sink;
+
+  @override
+  Stream<T> get stream => controller.stream;
+}
+
+class StreamChannelMixinAsSuperclass<T> extends StreamChannelMixin<T> {
+  final controller = StreamController<T>();
+
+  @override
+  StreamSink<T> get sink => controller.sink;
+
+  @override
+  Stream<T> get stream => controller.stream;
 }