Complete `onConnected` with error if connection fails to open (#42)

* Complete `onConnected` with error if connection fails to open

This prevents `onConnected` from hanging indefinitely if the `SseClient`
immediately fails to open.

Fixes https://github.com/dart-lang/sse/issues/41.

* Recompile the test app

* Add changelog entry and update version
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 0ed01c9..4b921c2 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,8 @@
+## 3.8.2
+
+- Complete `onConnected` with an error if the `SseClient` receives an error
+  before the connection is successfully opened.
+
 ## 3.8.1
 
 - Fix an issue where closing the `SseConnection` stream would result in
diff --git a/lib/client/sse_client.dart b/lib/client/sse_client.dart
index 2958bed..00def10 100644
--- a/lib/client/sse_client.dart
+++ b/lib/client/sse_client.dart
@@ -57,6 +57,11 @@
         _errorTimer = Timer(const Duration(seconds: 5), () {
           _incomingController.addError(error);
           close();
+          if (!_onConnected.isCompleted) {
+            // This call must happen after the call to close() which checks
+            // whether the completer was completed earlier.
+            _onConnected.completeError(error);
+          }
         });
       }
     });
diff --git a/pubspec.yaml b/pubspec.yaml
index 9a44e4c..a99fd02 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -1,5 +1,5 @@
 name: sse
-version: 3.8.1
+version: 3.8.2
 homepage: https://github.com/dart-lang/sse
 description: >-
   Provides client and server functionality for setting up bi-directional
diff --git a/test/web/index.dart.js b/test/web/index.dart.js
index 614df07..5f962b9 100644
--- a/test/web/index.dart.js
+++ b/test/web/index.dart.js
@@ -1,4 +1,4 @@
-// Generated by dart2js (fast startup emitter, strong), the Dart to JavaScript compiler version: 2.12.0-223.0.dev.
+// Generated by dart2js (fast startup emitter, strong), the Dart to JavaScript compiler version: 2.12.0-133.2.beta.
 // The code supports the following hooks:
 // dartPrint(message):
 //    if this function is defined it is called instead of the Dart [print]
@@ -27,14 +27,6 @@
       to[key] = from[key];
     }
   }
-  function mixinProperties(from, to) {
-    var keys = Object.keys(from);
-    for (var i = 0; i < keys.length; i++) {
-      var key = keys[i];
-      if (!to.hasOwnProperty(key))
-        to[key] = from[key];
-    }
-  }
   var supportsDirectProtoAccess = function() {
     var cls = function() {
     };
@@ -66,7 +58,7 @@
       for (var j = 0; j < keys.length; j++) {
         var key = keys[j];
         var f = holder[key];
-        if (typeof f == "function")
+        if (typeof f == 'function')
           f.name = key;
       }
     }
@@ -89,7 +81,7 @@
       inherit(classes[i], sup);
   }
   function mixin(cls, mixin) {
-    mixinProperties(mixin.prototype, cls.prototype);
+    copyProperties(mixin.prototype, cls.prototype);
     cls.prototype.constructor = cls;
   }
   function lazyOld(holder, name, getterName, initializer) {
@@ -178,7 +170,7 @@
     var funs = [];
     for (var i = 0; i < funsOrNames.length; i++) {
       var fun = funsOrNames[i];
-      if (typeof fun == "string")
+      if (typeof fun == 'string')
         fun = container[fun];
       fun.$callName = callNames[i];
       funs.push(fun);
@@ -267,7 +259,7 @@
     LateError: function LateError(t0) {
       this._message = t0;
     },
-    nullFuture_closure: function nullFuture_closure() {
+    closure: function closure() {
     },
     NotNullableError: function NotNullableError(t0, t1) {
       this.__internal$_name = t0;
@@ -455,7 +447,7 @@
     },
     TypeErrorDecoder_extractPattern: function(message) {
       var match, $arguments, argumentsExpr, expr, method, receiver;
-      message = H.quoteStringForRegExp(message.replace(String({}), "$receiver$"));
+      message = H.quoteStringForRegExp(message.replace(String({}), '$receiver$'));
       match = message.match(/\\\$[a-zA-Z]+\\\$/g);
       if (match == null)
         match = H.setRuntimeTypeInfo([], type$.JSArray_String);
@@ -464,11 +456,11 @@
       expr = match.indexOf("\\$expr\\$");
       method = match.indexOf("\\$method\\$");
       receiver = match.indexOf("\\$receiver\\$");
-      return new H.TypeErrorDecoder(message.replace(new RegExp("\\\\\\$arguments\\\\\\$", "g"), "((?:x|[^x])*)").replace(new RegExp("\\\\\\$argumentsExpr\\\\\\$", "g"), "((?:x|[^x])*)").replace(new RegExp("\\\\\\$expr\\\\\\$", "g"), "((?:x|[^x])*)").replace(new RegExp("\\\\\\$method\\\\\\$", "g"), "((?:x|[^x])*)").replace(new RegExp("\\\\\\$receiver\\\\\\$", "g"), "((?:x|[^x])*)"), $arguments, argumentsExpr, expr, method, receiver);
+      return new H.TypeErrorDecoder(message.replace(new RegExp('\\\\\\$arguments\\\\\\$', 'g'), '((?:x|[^x])*)').replace(new RegExp('\\\\\\$argumentsExpr\\\\\\$', 'g'), '((?:x|[^x])*)').replace(new RegExp('\\\\\\$expr\\\\\\$', 'g'), '((?:x|[^x])*)').replace(new RegExp('\\\\\\$method\\\\\\$', 'g'), '((?:x|[^x])*)').replace(new RegExp('\\\\\\$receiver\\\\\\$', 'g'), '((?:x|[^x])*)'), $arguments, argumentsExpr, expr, method, receiver);
     },
     TypeErrorDecoder_provokeCallErrorOn: function(expression) {
       return function($expr$) {
-        var $argumentsExpr$ = "$arguments$";
+        var $argumentsExpr$ = '$arguments$';
         try {
           $expr$.$method$($argumentsExpr$);
         } catch (e) {
@@ -2898,6 +2890,22 @@
       }($function, 1);
       return $.Zone__current.registerBinaryCallback$3$1(new P._wrapJsFunctionForAsync_closure($protected), type$.void, type$.int, type$.dynamic);
     },
+    Future_Future$value: function(value, $T) {
+      var t1 = new P._Future($.Zone__current, $T._eval$1("_Future<0>"));
+      t1._asyncComplete$1(value);
+      return t1;
+    },
+    _Future__chainForeignFuture: function(source, target) {
+      var e, s, exception;
+      target._state = 1;
+      try {
+        source.then$1$2$onError(new P._Future__chainForeignFuture_closure(target), new P._Future__chainForeignFuture_closure0(target), type$.Null);
+      } catch (exception) {
+        e = H.unwrapException(exception);
+        s = H.getTraceFromException(exception);
+        P.scheduleMicrotask(new P._Future__chainForeignFuture_closure1(target, e, s));
+      }
+    },
     _Future__chainCoreFuture: function(source, target) {
       var t1, t2, listeners;
       for (t1 = type$._Future_dynamic; t2 = source._state, t2 === 2;)
@@ -2974,26 +2982,17 @@
             $.Zone__current = oldZone;
           t1 = _box_0.listenerValueOrError;
           if (t4._is(t1)) {
-            t5 = _box_0.listener.$ti;
-            t5 = t5._eval$1("Future<2>")._is(t1) || !t5._rest[1]._is(t1);
-          } else
-            t5 = false;
-          if (t5) {
-            t4._as(t1);
             result = _box_0.listener.result;
-            if (t1 instanceof P._Future)
-              if (t1._state >= 4) {
-                current = t3._as(result._resultOrListeners);
-                result._resultOrListeners = null;
-                listeners = result._reverseListeners$1(current);
-                result._state = t1._state;
-                result._resultOrListeners = t1._resultOrListeners;
-                _box_1.source = t1;
-                continue;
-              } else
-                P._Future__chainCoreFuture(t1, result);
-            else
-              result._chainForeignFuture$1(t1);
+            if (t1._state >= 4) {
+              current = t3._as(result._resultOrListeners);
+              result._resultOrListeners = null;
+              listeners = result._reverseListeners$1(current);
+              result._state = t1._state;
+              result._resultOrListeners = t1._resultOrListeners;
+              _box_1.source = t1;
+              continue;
+            } else
+              P._Future__chainCoreFuture(t1, result);
             return;
           }
         }
@@ -3023,7 +3022,7 @@
       t1 = type$.dynamic_Function_Object;
       if (t1._is(errorHandler))
         return t1._as(errorHandler);
-      throw H.wrapException(P.ArgumentError$value(errorHandler, "onError", "Error handler must accept one Object or one Object and a StackTrace as arguments, and return a valid result"));
+      throw H.wrapException(P.ArgumentError$value(errorHandler, "onError", "Error handler must accept one Object or one Object and a StackTrace as arguments, and return a a valid result"));
     },
     _microtaskLoop: function() {
       var entry, next;
@@ -3263,13 +3262,13 @@
       this.$this = t1;
     },
     _Future__chainForeignFuture_closure: function _Future__chainForeignFuture_closure(t0) {
-      this.$this = t0;
+      this.target = t0;
     },
     _Future__chainForeignFuture_closure0: function _Future__chainForeignFuture_closure0(t0) {
-      this.$this = t0;
+      this.target = t0;
     },
     _Future__chainForeignFuture_closure1: function _Future__chainForeignFuture_closure1(t0, t1, t2) {
-      this.$this = t0;
+      this.target = t0;
       this.e = t1;
       this.s = t2;
     },
@@ -4449,11 +4448,9 @@
       return message != null ? "LateInitializationError: " + message : "LateInitializationError";
     }
   };
-  H.nullFuture_closure.prototype = {
+  H.closure.prototype = {
     call$0: function() {
-      var t1 = new P._Future($.Zone__current, type$._Future_Null);
-      t1._asyncComplete$1(null);
-      return t1;
+      return P.Future_Future$value(null, type$.Null);
     },
     $signature: 14
   };
@@ -5192,17 +5189,6 @@
       }
       return prev;
     },
-    _chainForeignFuture$1: function(source) {
-      var e, s, exception, _this = this;
-      _this._state = 1;
-      try {
-        source.then$1$2$onError(new P._Future__chainForeignFuture_closure(_this), new P._Future__chainForeignFuture_closure0(_this), type$.Null);
-      } catch (exception) {
-        e = H.unwrapException(exception);
-        s = H.getTraceFromException(exception);
-        P.scheduleMicrotask(new P._Future__chainForeignFuture_closure1(_this, e, s));
-      }
-    },
     _complete$1: function(value) {
       var listeners, _this = this,
         t1 = _this.$ti;
@@ -5211,7 +5197,7 @@
         if (t1._is(value))
           P._Future__chainCoreFuture(value, _this);
         else
-          _this._chainForeignFuture$1(value);
+          P._Future__chainForeignFuture(value, _this);
       else {
         listeners = _this._removeListeners$0();
         t1._precomputed1._as(value);
@@ -5264,7 +5250,7 @@
           P._Future__chainCoreFuture(value, _this);
         return;
       }
-      _this._chainForeignFuture$1(value);
+      P._Future__chainForeignFuture(value, _this);
     },
     _asyncCompleteError$2: function(error, stackTrace) {
       type$.StackTrace._as(stackTrace);
@@ -5287,28 +5273,21 @@
   };
   P._Future__chainForeignFuture_closure.prototype = {
     call$1: function(value) {
-      var error, stackTrace, exception,
-        t1 = this.$this;
+      var t1 = this.target;
       t1._state = 0;
-      try {
-        t1._completeWithValue$1(t1.$ti._precomputed1._as(value));
-      } catch (exception) {
-        error = H.unwrapException(exception);
-        stackTrace = H.getTraceFromException(exception);
-        t1._completeError$2(error, stackTrace);
-      }
+      t1._complete$1(value);
     },
     $signature: 5
   };
   P._Future__chainForeignFuture_closure0.prototype = {
     call$2: function(error, stackTrace) {
-      this.$this._completeError$2(error, type$.StackTrace._as(stackTrace));
+      this.target._completeError$2(error, type$.StackTrace._as(stackTrace));
     },
     $signature: 7
   };
   P._Future__chainForeignFuture_closure1.prototype = {
     call$0: function() {
-      this.$this._completeError$2(this.e, this.s);
+      this.target._completeError$2(this.e, this.s);
     },
     $signature: 0
   };
@@ -6887,11 +6866,11 @@
     cancel$0: function() {
       var _this = this;
       if (_this._target == null)
-        return $.$get$nullFuture();
+        return null;
       _this._unlisten$0();
       _this._target = null;
       _this.set$_html$_onData(null);
-      return $.$get$nullFuture();
+      return null;
     },
     onData$1: function(handleData) {
       var t1, _this = this;
@@ -7303,6 +7282,9 @@
       else if ((t3 & 3) === 0)
         t2._ensurePendingEvents$0().add$1(0, new P._DelayedError(error, stackTrace));
       t1.close$0(0);
+      t1 = t1._onConnected;
+      if (t1.future._state === 0)
+        t1.completeError$1(error);
     },
     $signature: 1
   };
@@ -7405,7 +7387,7 @@
     _inherit(J.JSUnmodifiableArray, J.JSArray);
     _inheritMany(J.JSNumber, [J.JSInt, J.JSDouble]);
     _inheritMany(P.Error, [H.LateError, H.NotNullableError, P.TypeError, H.JsNoSuchMethodError, H.UnknownJsTypeError, H.RuntimeError, P.AssertionError, H._Error, P.JsonUnsupportedObjectError, P.NullThrownError, P.ArgumentError, P.UnsupportedError, P.UnimplementedError, P.StateError, P.ConcurrentModificationError, P.CyclicInitializationError]);
-    _inheritMany(H.Closure, [H.nullFuture_closure, H.TearOffClosure, H.initHooks_closure, H.initHooks_closure0, H.initHooks_closure1, P._AsyncRun__initializeScheduleImmediate_internalCallback, P._AsyncRun__initializeScheduleImmediate_closure, P._AsyncRun__scheduleImmediateJsOverride_internalCallback, P._AsyncRun__scheduleImmediateWithSetImmediate_internalCallback, P._TimerImpl_internalCallback, P._awaitOnObject_closure, P._awaitOnObject_closure0, P._wrapJsFunctionForAsync_closure, P._Future__addListener_closure, P._Future__prependListeners_closure, P._Future__chainForeignFuture_closure, P._Future__chainForeignFuture_closure0, P._Future__chainForeignFuture_closure1, P._Future__asyncCompleteWithValue_closure, P._Future__chainFuture_closure, P._Future__asyncCompleteError_closure, P._Future__propagateToListeners_handleWhenCompleteCallback, P._Future__propagateToListeners_handleWhenCompleteCallback_closure, P._Future__propagateToListeners_handleValueCallback, P._Future__propagateToListeners_handleError, P.Stream_length_closure, P.Stream_length_closure0, P.Stream_first_closure, P.Stream_first_closure0, P._StreamController__subscribe_closure, P._StreamController__recordCancel_complete, P._BufferingStreamSubscription_asFuture_closure, P._BufferingStreamSubscription_asFuture_closure0, P._BufferingStreamSubscription_asFuture__closure, P._BufferingStreamSubscription__sendError_sendError, P._BufferingStreamSubscription__sendDone_sendDone, P._PendingEvents_schedule_closure, P._cancelAndValue_closure, P._rootHandleUncaughtError_closure, P._RootZone_bindCallback_closure, P._RootZone_bindCallbackGuarded_closure, P._RootZone_bindUnaryCallbackGuarded_closure, P.MapBase_mapToString_closure, P._JsonStringifier_writeMap_closure, P.Duration_toString_sixDigits, P.Duration_toString_twoDigits, W.HttpRequest_request_closure, W._EventStreamSubscription_closure, W._EventStreamSubscription_onData_closure, P._AcceptStructuredClone_walk_closure, P._convertDartToNative_Value_closure, P.convertDartToNative_Dictionary_closure, P.promiseToFuture_closure, P.promiseToFuture_closure0, F.Logger_Logger_closure, M.SseClient_closure, M.SseClient_closure0, M.SseClient_closure1, M.SseClient__closure, T.generateUuidV4__generateBits, T.generateUuidV4__printDigits, T.generateUuidV4__bitsDigits, E.main_closure, E.main_closure0]);
+    _inheritMany(H.Closure, [H.closure, H.TearOffClosure, H.initHooks_closure, H.initHooks_closure0, H.initHooks_closure1, P._AsyncRun__initializeScheduleImmediate_internalCallback, P._AsyncRun__initializeScheduleImmediate_closure, P._AsyncRun__scheduleImmediateJsOverride_internalCallback, P._AsyncRun__scheduleImmediateWithSetImmediate_internalCallback, P._TimerImpl_internalCallback, P._awaitOnObject_closure, P._awaitOnObject_closure0, P._wrapJsFunctionForAsync_closure, P._Future__addListener_closure, P._Future__prependListeners_closure, P._Future__chainForeignFuture_closure, P._Future__chainForeignFuture_closure0, P._Future__chainForeignFuture_closure1, P._Future__asyncCompleteWithValue_closure, P._Future__chainFuture_closure, P._Future__asyncCompleteError_closure, P._Future__propagateToListeners_handleWhenCompleteCallback, P._Future__propagateToListeners_handleWhenCompleteCallback_closure, P._Future__propagateToListeners_handleValueCallback, P._Future__propagateToListeners_handleError, P.Stream_length_closure, P.Stream_length_closure0, P.Stream_first_closure, P.Stream_first_closure0, P._StreamController__subscribe_closure, P._StreamController__recordCancel_complete, P._BufferingStreamSubscription_asFuture_closure, P._BufferingStreamSubscription_asFuture_closure0, P._BufferingStreamSubscription_asFuture__closure, P._BufferingStreamSubscription__sendError_sendError, P._BufferingStreamSubscription__sendDone_sendDone, P._PendingEvents_schedule_closure, P._cancelAndValue_closure, P._rootHandleUncaughtError_closure, P._RootZone_bindCallback_closure, P._RootZone_bindCallbackGuarded_closure, P._RootZone_bindUnaryCallbackGuarded_closure, P.MapBase_mapToString_closure, P._JsonStringifier_writeMap_closure, P.Duration_toString_sixDigits, P.Duration_toString_twoDigits, W.HttpRequest_request_closure, W._EventStreamSubscription_closure, W._EventStreamSubscription_onData_closure, P._AcceptStructuredClone_walk_closure, P._convertDartToNative_Value_closure, P.convertDartToNative_Dictionary_closure, P.promiseToFuture_closure, P.promiseToFuture_closure0, F.Logger_Logger_closure, M.SseClient_closure, M.SseClient_closure0, M.SseClient_closure1, M.SseClient__closure, T.generateUuidV4__generateBits, T.generateUuidV4__printDigits, T.generateUuidV4__bitsDigits, E.main_closure, E.main_closure0]);
     _inherit(H.EfficientLengthIterable, P.Iterable);
     _inheritMany(H.EfficientLengthIterable, [H.ListIterable, H.LinkedHashMapKeyIterable]);
     _inherit(H.NullError, P.TypeError);
@@ -7496,7 +7478,6 @@
       _ElementEventStreamImpl_legacy_MouseEvent: findType("_ElementEventStreamImpl<MouseEvent*>"),
       _EventStream_legacy_Event: findType("_EventStream<Event*>"),
       _Future_HttpRequest: findType("_Future<HttpRequest>"),
-      _Future_Null: findType("_Future<Null>"),
       _Future_dynamic: findType("_Future<@>"),
       _Future_int: findType("_Future<int>"),
       _Future_void: findType("_Future<~>"),
@@ -7711,7 +7692,7 @@
       return H.getIsolateAffinityTag("_$dart_dartClosure");
     });
     _lazyFinal($, "nullFuture", "$get$nullFuture", function() {
-      return C.C__RootZone.run$1$1(new H.nullFuture_closure(), H.findType("Future<Null>"));
+      return C.C__RootZone.run$1$1(new H.closure(), H.findType("Future<Null>"));
     });
     _lazyFinal($, "TypeErrorDecoder_noSuchMethodPattern", "$get$TypeErrorDecoder_noSuchMethodPattern", function() {
       return H.TypeErrorDecoder_extractPattern(H.TypeErrorDecoder_provokeCallErrorOn({
@@ -7732,7 +7713,7 @@
     });
     _lazyFinal($, "TypeErrorDecoder_nullLiteralCallPattern", "$get$TypeErrorDecoder_nullLiteralCallPattern", function() {
       return H.TypeErrorDecoder_extractPattern(function() {
-        var $argumentsExpr$ = "$arguments$";
+        var $argumentsExpr$ = '$arguments$';
         try {
           null.$method$($argumentsExpr$);
         } catch (e) {
@@ -7745,7 +7726,7 @@
     });
     _lazyFinal($, "TypeErrorDecoder_undefinedLiteralCallPattern", "$get$TypeErrorDecoder_undefinedLiteralCallPattern", function() {
       return H.TypeErrorDecoder_extractPattern(function() {
-        var $argumentsExpr$ = "$arguments$";
+        var $argumentsExpr$ = '$arguments$';
         try {
           (void 0).$method$($argumentsExpr$);
         } catch (e) {
@@ -7781,7 +7762,7 @@
       return P._AsyncRun__initializeScheduleImmediate();
     });
     _lazyFinal($, "Future__nullFuture", "$get$Future__nullFuture", function() {
-      return type$._Future_Null._as($.$get$nullFuture());
+      return H.findType("_Future<Null>")._as($.$get$nullFuture());
     });
     _lazy($, "_hasErrorStackProperty", "$get$_hasErrorStackProperty", function() {
       return new Error().stack != void 0;
@@ -7830,7 +7811,7 @@
       callback(null);
       return;
     }
-    if (typeof document.currentScript != "undefined") {
+    if (typeof document.currentScript != 'undefined') {
       callback(document.currentScript);
       return;
     }
@@ -7844,11 +7825,10 @@
       scripts[i].addEventListener("load", onLoad, false);
   })(function(currentScript) {
     init.currentScript = currentScript;
-    var callMain = E.main;
     if (typeof dartMainRunner === "function")
-      dartMainRunner(callMain, []);
+      dartMainRunner(E.main, []);
     else
-      callMain([]);
+      E.main([]);
   });
 })();