@firebase/app-check 0.5.12 → 0.5.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -689,13 +689,27 @@ async function getToken$2(appCheck, forceRefresh = false) {
689
689
  let token = state.token;
690
690
  let error = undefined;
691
691
  /**
692
- * If there is no token in memory, try to load token from indexedDB.
692
+ * If an invalid token was found in memory, clear token from
693
+ * memory and unset the local variable `token`.
694
+ */
695
+ if (token && !isValid(token)) {
696
+ setState(app, Object.assign(Object.assign({}, state), { token: undefined }));
697
+ token = undefined;
698
+ }
699
+ /**
700
+ * If there is no valid token in memory, try to load token from indexedDB.
693
701
  */
694
702
  if (!token) {
695
703
  // cachedTokenPromise contains the token found in IndexedDB or undefined if not found.
696
704
  const cachedToken = await state.cachedTokenPromise;
697
- if (cachedToken && isValid(cachedToken)) {
698
- token = cachedToken;
705
+ if (cachedToken) {
706
+ if (isValid(cachedToken)) {
707
+ token = cachedToken;
708
+ }
709
+ else {
710
+ // If there was an invalid token in the indexedDB cache, clear it.
711
+ await writeTokenToStorage(app, undefined);
712
+ }
699
713
  }
700
714
  }
701
715
  // Return the cached token (from either memory or indexedDB) if it's valid
@@ -716,9 +730,9 @@ async function getToken$2(appCheck, forceRefresh = false) {
716
730
  if (isDebugMode()) {
717
731
  // Avoid making another call to the exchange endpoint if one is in flight.
718
732
  if (!state.exchangeTokenPromise) {
719
- state.exchangeTokenPromise = exchangeToken(getExchangeDebugTokenRequest(app, await getDebugToken()), appCheck.heartbeatServiceProvider).then(token => {
733
+ state.exchangeTokenPromise = exchangeToken(getExchangeDebugTokenRequest(app, await getDebugToken()), appCheck.heartbeatServiceProvider).finally(() => {
734
+ // Clear promise when settled - either resolved or rejected.
720
735
  state.exchangeTokenPromise = undefined;
721
- return token;
722
736
  });
723
737
  shouldCallListeners = true;
724
738
  }
@@ -730,7 +744,9 @@ async function getToken$2(appCheck, forceRefresh = false) {
730
744
  return { token: tokenFromDebugExchange.token };
731
745
  }
732
746
  /**
733
- * request a new token
747
+ * There are no valid tokens in memory or indexedDB and we are not in
748
+ * debug mode.
749
+ * Request a new token from the exchange endpoint.
734
750
  */
735
751
  try {
736
752
  // Avoid making another call to the exchange endpoint if one is in flight.
@@ -738,9 +754,9 @@ async function getToken$2(appCheck, forceRefresh = false) {
738
754
  // state.provider is populated in initializeAppCheck()
739
755
  // ensureActivated() at the top of this function checks that
740
756
  // initializeAppCheck() has been called.
741
- state.exchangeTokenPromise = state.provider.getToken().then(token => {
757
+ state.exchangeTokenPromise = state.provider.getToken().finally(() => {
758
+ // Clear promise when settled - either resolved or rejected.
742
759
  state.exchangeTokenPromise = undefined;
743
- return token;
744
760
  });
745
761
  shouldCallListeners = true;
746
762
  }
@@ -760,10 +776,30 @@ async function getToken$2(appCheck, forceRefresh = false) {
760
776
  }
761
777
  let interopTokenResult;
762
778
  if (!token) {
763
- // if token is undefined, there must be an error.
764
- // we return a dummy token along with the error
779
+ // If token is undefined, there must be an error.
780
+ // Return a dummy token along with the error.
765
781
  interopTokenResult = makeDummyTokenResult(error);
766
782
  }
783
+ else if (error) {
784
+ if (isValid(token)) {
785
+ // It's also possible a valid token exists, but there's also an error.
786
+ // (Such as if the token is almost expired, tries to refresh, and
787
+ // the exchange request fails.)
788
+ // We add a special error property here so that the refresher will
789
+ // count this as a failed attempt and use the backoff instead of
790
+ // retrying repeatedly with no delay, but any 3P listeners will not
791
+ // be hindered in getting the still-valid token.
792
+ interopTokenResult = {
793
+ token: token.token,
794
+ internalError: error
795
+ };
796
+ }
797
+ else {
798
+ // No invalid tokens should make it to this step. Memory and cached tokens
799
+ // are checked. Other tokens are from fresh exchanges. But just in case.
800
+ interopTokenResult = makeDummyTokenResult(error);
801
+ }
802
+ }
767
803
  else {
768
804
  interopTokenResult = {
769
805
  token: token.token
@@ -855,10 +891,24 @@ function createTokenRefresher(appCheck) {
855
891
  else {
856
892
  result = await getToken$2(appCheck, true);
857
893
  }
858
- // getToken() always resolves. In case the result has an error field defined, it means the operation failed, and we should retry.
894
+ /**
895
+ * getToken() always resolves. In case the result has an error field defined, it means
896
+ * the operation failed, and we should retry.
897
+ */
859
898
  if (result.error) {
860
899
  throw result.error;
861
900
  }
901
+ /**
902
+ * A special `internalError` field reflects that there was an error
903
+ * getting a new token from the exchange endpoint, but there's still a
904
+ * previous token that's valid for now and this should be passed to 2P/3P
905
+ * requests for a token. But we want this callback (`this.operation` in
906
+ * `Refresher`) to throw in order to kick off the Refresher's retry
907
+ * backoff. (Setting `hasSucceeded` to false.)
908
+ */
909
+ if (result.internalError) {
910
+ throw result.internalError;
911
+ }
862
912
  }, () => {
863
913
  return true;
864
914
  }, () => {
@@ -955,7 +1005,7 @@ function internalFactory(appCheck) {
955
1005
  }
956
1006
 
957
1007
  const name = "@firebase/app-check";
958
- const version = "0.5.12";
1008
+ const version = "0.5.13";
959
1009
 
960
1010
  /**
961
1011
  * @license