Skip to content

Commit 111f5f6

Browse files
fix(auth, web): ensure exact same streams are not unsubscribed (#13033)
1 parent 110dfae commit 111f5f6

File tree

1 file changed

+44
-9
lines changed
  • packages/firebase_auth/firebase_auth_web/lib/src/interop

1 file changed

+44
-9
lines changed

packages/firebase_auth/firebase_auth_web/lib/src/interop/auth.dart

+44-9
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import 'dart:async';
1010
import 'dart:js_interop';
1111
import 'package:firebase_auth_platform_interface/firebase_auth_platform_interface.dart';
1212
import 'package:firebase_core_web/firebase_core_web_interop.dart';
13+
import 'package:flutter/foundation.dart';
1314
import 'package:http_parser/http_parser.dart';
1415

1516
import 'auth_interop.dart' as auth_interop;
@@ -392,9 +393,35 @@ class Auth extends JsObjectWrapper<auth_interop.AuthJsImpl> {
392393
// ignore: close_sinks
393394
StreamController<User?>? _changeController;
394395

395-
String get _authStateWindowsKey => 'flutterfire-${app.name}_authStateChanges';
396-
String get _idTokenStateWindowsKey =>
397-
'flutterfire-${app.name}_idTokenChanges';
396+
// purely for debug mode and tracking listeners to clean up on "hot restart"
397+
final Map<String, int> _authStateListeners = {};
398+
String _authStateWindowsKey() {
399+
if (kDebugMode) {
400+
final key = 'flutterfire-${app.name}_authStateChanges';
401+
if (_authStateListeners.containsKey(key)) {
402+
_authStateListeners[key] = _authStateListeners[key]! + 1;
403+
} else {
404+
_authStateListeners[key] = 0;
405+
}
406+
return '$key-${_authStateListeners[key]}';
407+
}
408+
return 'no-op';
409+
}
410+
411+
// purely for debug mode and tracking listeners to clean up on "hot restart"
412+
final Map<String, int> _idTokenStateListeners = {};
413+
String _idTokenStateWindowsKey() {
414+
if (kDebugMode) {
415+
final key = 'flutterfire-${app.name}_idTokenChanges';
416+
if (_idTokenStateListeners.containsKey(key)) {
417+
_idTokenStateListeners[key] = _idTokenStateListeners[key]! + 1;
418+
} else {
419+
_idTokenStateListeners[key] = 0;
420+
}
421+
return '$key-${_idTokenStateListeners[key]}';
422+
}
423+
return 'no-op';
424+
}
398425

399426
/// Sends events when the users sign-in state changes.
400427
///
@@ -403,7 +430,8 @@ class Auth extends JsObjectWrapper<auth_interop.AuthJsImpl> {
403430
///
404431
/// If the value is `null`, there is no signed-in user.
405432
Stream<User?> get onAuthStateChanged {
406-
unsubscribeWindowsListener(_authStateWindowsKey);
433+
final authStateKey = _authStateWindowsKey();
434+
unsubscribeWindowsListener(authStateKey);
407435

408436
if (_changeController == null) {
409437
final nextWrapper = (auth_interop.UserJsImpl? user) {
@@ -417,14 +445,17 @@ class Auth extends JsObjectWrapper<auth_interop.AuthJsImpl> {
417445
final unsubscribe =
418446
jsObject.onAuthStateChanged(nextWrapper.toJS, errorWrapper.toJS);
419447
_onAuthUnsubscribe = unsubscribe;
420-
setWindowsListener(_authStateWindowsKey, unsubscribe);
448+
setWindowsListener(
449+
authStateKey,
450+
unsubscribe,
451+
);
421452
}
422453

423454
void stopListen() {
424455
_onAuthUnsubscribe!.callAsFunction();
425456
_onAuthUnsubscribe = null;
426457
_changeController = null;
427-
removeWindowsListener(_authStateWindowsKey);
458+
removeWindowsListener(authStateKey);
428459
}
429460

430461
_changeController = StreamController<User?>.broadcast(
@@ -450,7 +481,8 @@ class Auth extends JsObjectWrapper<auth_interop.AuthJsImpl> {
450481
///
451482
/// If the value is `null`, there is no signed-in user.
452483
Stream<User?> get onIdTokenChanged {
453-
unsubscribeWindowsListener(_idTokenStateWindowsKey);
484+
final idTokenKey = _idTokenStateWindowsKey();
485+
unsubscribeWindowsListener(idTokenKey);
454486
if (_idTokenChangedController == null) {
455487
final nextWrapper = (auth_interop.UserJsImpl? user) {
456488
_idTokenChangedController!.add(User.getInstance(user));
@@ -463,14 +495,17 @@ class Auth extends JsObjectWrapper<auth_interop.AuthJsImpl> {
463495
final unsubscribe =
464496
jsObject.onIdTokenChanged(nextWrapper.toJS, errorWrapper.toJS);
465497
_onIdTokenChangedUnsubscribe = unsubscribe;
466-
setWindowsListener(_idTokenStateWindowsKey, unsubscribe);
498+
setWindowsListener(
499+
idTokenKey,
500+
unsubscribe,
501+
);
467502
}
468503

469504
void stopListen() {
470505
_onIdTokenChangedUnsubscribe!.callAsFunction();
471506
_onIdTokenChangedUnsubscribe = null;
472507
_idTokenChangedController = null;
473-
removeWindowsListener(_idTokenStateWindowsKey);
508+
removeWindowsListener(idTokenKey);
474509
}
475510

476511
_idTokenChangedController = StreamController<User?>.broadcast(

0 commit comments

Comments
 (0)