@@ -18,6 +18,7 @@ import { Auth } from '../../model/public_types';
1818import { AuthErrorCode } from '../errors' ;
1919import { _assert } from '../util/assert' ;
2020import { _castAuth } from './auth_impl' ;
21+ import { deepEqual } from '@firebase/util' ;
2122
2223/**
2324 * Changes the {@link Auth} instance to communicate with the Firebase Auth Emulator, instead of production
@@ -47,12 +48,6 @@ export function connectAuthEmulator(
4748 options ?: { disableWarnings : boolean }
4849) : void {
4950 const authInternal = _castAuth ( auth ) ;
50- _assert (
51- authInternal . _canInitEmulator ,
52- authInternal ,
53- AuthErrorCode . EMULATOR_CONFIG_FAILED
54- ) ;
55-
5651 _assert (
5752 / ^ h t t p s ? : \/ \/ / . test ( url ) ,
5853 authInternal ,
@@ -66,15 +61,42 @@ export function connectAuthEmulator(
6661 const portStr = port === null ? '' : `:${ port } ` ;
6762
6863 // Always replace path with "/" (even if input url had no path at all, or had a different one).
69- authInternal . config . emulator = { url : `${ protocol } //${ host } ${ portStr } /` } ;
70- authInternal . settings . appVerificationDisabledForTesting = true ;
71- authInternal . emulatorConfig = Object . freeze ( {
64+ const emulator = { url : `${ protocol } //${ host } ${ portStr } /` } ;
65+ const emulatorConfig = Object . freeze ( {
7266 host,
7367 port,
7468 protocol : protocol . replace ( ':' , '' ) ,
7569 options : Object . freeze ( { disableWarnings } )
7670 } ) ;
7771
72+ // There are a few scenarios to guard against if the Auth instance has already started:
73+ if ( ! authInternal . _canInitEmulator ) {
74+ // Applications may not initialize the emulator for the first time if Auth has already started
75+ // to make network requests.
76+ _assert (
77+ authInternal . config . emulator && authInternal . emulatorConfig ,
78+ authInternal ,
79+ AuthErrorCode . EMULATOR_CONFIG_FAILED
80+ ) ;
81+
82+ // Applications may not alter the configuration of the emulator (aka pass a different config)
83+ // once Auth has started to make network requests.
84+ _assert (
85+ deepEqual ( emulator , authInternal . config . emulator ) &&
86+ deepEqual ( emulatorConfig , authInternal . emulatorConfig ) ,
87+ authInternal ,
88+ AuthErrorCode . EMULATOR_CONFIG_FAILED
89+ ) ;
90+
91+ // It's valid, however, to invoke connectAuthEmulator() after Auth has started making
92+ // connections, so long as the config matches the existing config. This results in a no-op.
93+ return ;
94+ }
95+
96+ authInternal . config . emulator = emulator ;
97+ authInternal . emulatorConfig = emulatorConfig ;
98+ authInternal . settings . appVerificationDisabledForTesting = true ;
99+
78100 if ( ! disableWarnings ) {
79101 emitEmulatorWarning ( ) ;
80102 }
0 commit comments