@azure/msal-browser 3.24.0 → 3.26.0

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.
Files changed (132) hide show
  1. package/README.md +1 -1
  2. package/dist/app/IPublicClientApplication.d.ts +2 -1
  3. package/dist/app/IPublicClientApplication.d.ts.map +1 -1
  4. package/dist/app/IPublicClientApplication.mjs +1 -1
  5. package/dist/app/IPublicClientApplication.mjs.map +1 -1
  6. package/dist/app/PublicClientApplication.d.ts +3 -1
  7. package/dist/app/PublicClientApplication.d.ts.map +1 -1
  8. package/dist/app/PublicClientApplication.mjs +4 -3
  9. package/dist/app/PublicClientApplication.mjs.map +1 -1
  10. package/dist/app/PublicClientNext.d.ts +2 -1
  11. package/dist/app/PublicClientNext.d.ts.map +1 -1
  12. package/dist/app/PublicClientNext.mjs +3 -3
  13. package/dist/app/PublicClientNext.mjs.map +1 -1
  14. package/dist/broker/nativeBroker/NativeMessageHandler.mjs +1 -1
  15. package/dist/broker/nativeBroker/NativeStatusCodes.mjs +1 -1
  16. package/dist/cache/AccountManager.mjs +1 -1
  17. package/dist/cache/AsyncMemoryStorage.mjs +1 -1
  18. package/dist/cache/BrowserCacheManager.mjs +1 -1
  19. package/dist/cache/BrowserStorage.mjs +1 -1
  20. package/dist/cache/DatabaseStorage.mjs +1 -1
  21. package/dist/cache/MemoryStorage.mjs +1 -1
  22. package/dist/cache/TokenCache.mjs +1 -1
  23. package/dist/config/Configuration.mjs +1 -1
  24. package/dist/controllers/ControllerFactory.mjs +1 -1
  25. package/dist/controllers/IController.d.ts +2 -4
  26. package/dist/controllers/IController.d.ts.map +1 -1
  27. package/dist/controllers/NestedAppAuthController.d.ts +3 -6
  28. package/dist/controllers/NestedAppAuthController.d.ts.map +1 -1
  29. package/dist/controllers/NestedAppAuthController.mjs +5 -11
  30. package/dist/controllers/NestedAppAuthController.mjs.map +1 -1
  31. package/dist/controllers/StandardController.d.ts +7 -5
  32. package/dist/controllers/StandardController.d.ts.map +1 -1
  33. package/dist/controllers/StandardController.mjs +78 -14
  34. package/dist/controllers/StandardController.mjs.map +1 -1
  35. package/dist/controllers/UnknownOperatingContextController.d.ts +2 -4
  36. package/dist/controllers/UnknownOperatingContextController.d.ts.map +1 -1
  37. package/dist/controllers/UnknownOperatingContextController.mjs +10 -11
  38. package/dist/controllers/UnknownOperatingContextController.mjs.map +1 -1
  39. package/dist/crypto/BrowserCrypto.mjs +1 -1
  40. package/dist/crypto/CryptoOps.mjs +1 -1
  41. package/dist/crypto/PkceGenerator.mjs +1 -1
  42. package/dist/crypto/SignedHttpRequest.mjs +1 -1
  43. package/dist/encode/Base64Decode.mjs +1 -1
  44. package/dist/encode/Base64Encode.mjs +1 -1
  45. package/dist/error/BrowserAuthError.mjs +1 -1
  46. package/dist/error/BrowserAuthErrorCodes.mjs +1 -1
  47. package/dist/error/BrowserConfigurationAuthError.mjs +1 -1
  48. package/dist/error/BrowserConfigurationAuthErrorCodes.mjs +1 -1
  49. package/dist/error/NativeAuthError.mjs +1 -1
  50. package/dist/error/NativeAuthErrorCodes.mjs +1 -1
  51. package/dist/error/NestedAppAuthError.mjs +1 -1
  52. package/dist/event/EventHandler.d.ts +6 -18
  53. package/dist/event/EventHandler.d.ts.map +1 -1
  54. package/dist/event/EventHandler.mjs +23 -87
  55. package/dist/event/EventHandler.mjs.map +1 -1
  56. package/dist/event/EventMessage.mjs +1 -1
  57. package/dist/event/EventType.mjs +1 -1
  58. package/dist/index.d.ts +1 -0
  59. package/dist/index.d.ts.map +1 -1
  60. package/dist/index.mjs +2 -1
  61. package/dist/index.mjs.map +1 -1
  62. package/dist/interaction_client/BaseInteractionClient.mjs +1 -1
  63. package/dist/interaction_client/HybridSpaAuthorizationCodeClient.mjs +1 -1
  64. package/dist/interaction_client/NativeInteractionClient.mjs +1 -1
  65. package/dist/interaction_client/PopupClient.mjs +1 -1
  66. package/dist/interaction_client/RedirectClient.d.ts.map +1 -1
  67. package/dist/interaction_client/RedirectClient.mjs +20 -2
  68. package/dist/interaction_client/RedirectClient.mjs.map +1 -1
  69. package/dist/interaction_client/SilentAuthCodeClient.mjs +1 -1
  70. package/dist/interaction_client/SilentCacheClient.mjs +1 -1
  71. package/dist/interaction_client/SilentIframeClient.mjs +1 -1
  72. package/dist/interaction_client/SilentRefreshClient.mjs +1 -1
  73. package/dist/interaction_client/StandardInteractionClient.mjs +1 -1
  74. package/dist/interaction_handler/InteractionHandler.mjs +1 -1
  75. package/dist/interaction_handler/RedirectHandler.mjs +1 -1
  76. package/dist/interaction_handler/SilentHandler.mjs +1 -1
  77. package/dist/naa/BridgeError.mjs +1 -1
  78. package/dist/naa/BridgeProxy.mjs +1 -1
  79. package/dist/naa/BridgeStatusCode.mjs +1 -1
  80. package/dist/naa/mapping/NestedAppAuthAdapter.mjs +1 -1
  81. package/dist/navigation/NavigationClient.mjs +1 -1
  82. package/dist/network/FetchClient.mjs +1 -1
  83. package/dist/operatingcontext/BaseOperatingContext.mjs +1 -1
  84. package/dist/operatingcontext/NestedAppOperatingContext.mjs +1 -1
  85. package/dist/operatingcontext/StandardOperatingContext.mjs +1 -1
  86. package/dist/operatingcontext/UnknownOperatingContext.mjs +1 -1
  87. package/dist/packageMetadata.d.ts +1 -1
  88. package/dist/packageMetadata.mjs +2 -2
  89. package/dist/request/RequestHelpers.mjs +1 -1
  90. package/dist/response/ResponseHandler.mjs +1 -1
  91. package/dist/telemetry/BrowserPerformanceClient.mjs +1 -1
  92. package/dist/telemetry/BrowserPerformanceMeasurement.mjs +1 -1
  93. package/dist/utils/BrowserConstants.mjs +1 -1
  94. package/dist/utils/BrowserProtocolUtils.mjs +1 -1
  95. package/dist/utils/BrowserUtils.mjs +1 -1
  96. package/lib/msal-browser.cjs +198 -183
  97. package/lib/msal-browser.cjs.map +1 -1
  98. package/lib/msal-browser.js +198 -183
  99. package/lib/msal-browser.js.map +1 -1
  100. package/lib/msal-browser.min.js +61 -61
  101. package/lib/types/app/IPublicClientApplication.d.ts +2 -1
  102. package/lib/types/app/IPublicClientApplication.d.ts.map +1 -1
  103. package/lib/types/app/PublicClientApplication.d.ts +3 -1
  104. package/lib/types/app/PublicClientApplication.d.ts.map +1 -1
  105. package/lib/types/app/PublicClientNext.d.ts +2 -1
  106. package/lib/types/app/PublicClientNext.d.ts.map +1 -1
  107. package/lib/types/controllers/IController.d.ts +2 -4
  108. package/lib/types/controllers/IController.d.ts.map +1 -1
  109. package/lib/types/controllers/NestedAppAuthController.d.ts +3 -6
  110. package/lib/types/controllers/NestedAppAuthController.d.ts.map +1 -1
  111. package/lib/types/controllers/StandardController.d.ts +7 -5
  112. package/lib/types/controllers/StandardController.d.ts.map +1 -1
  113. package/lib/types/controllers/UnknownOperatingContextController.d.ts +2 -4
  114. package/lib/types/controllers/UnknownOperatingContextController.d.ts.map +1 -1
  115. package/lib/types/event/EventHandler.d.ts +6 -18
  116. package/lib/types/event/EventHandler.d.ts.map +1 -1
  117. package/lib/types/index.d.ts +1 -0
  118. package/lib/types/index.d.ts.map +1 -1
  119. package/lib/types/interaction_client/RedirectClient.d.ts.map +1 -1
  120. package/lib/types/packageMetadata.d.ts +1 -1
  121. package/package.json +2 -4
  122. package/src/app/IPublicClientApplication.ts +5 -1
  123. package/src/app/PublicClientApplication.ts +7 -2
  124. package/src/app/PublicClientNext.ts +6 -2
  125. package/src/controllers/IController.ts +5 -5
  126. package/src/controllers/NestedAppAuthController.ts +7 -11
  127. package/src/controllers/StandardController.ts +105 -13
  128. package/src/controllers/UnknownOperatingContextController.ts +12 -14
  129. package/src/event/EventHandler.ts +42 -117
  130. package/src/index.ts +1 -0
  131. package/src/interaction_client/RedirectClient.ts +25 -1
  132. package/src/packageMetadata.ts +1 -1
@@ -118,7 +118,7 @@ export class NestedAppAuthController implements IController {
118
118
  this.logger
119
119
  );
120
120
 
121
- this.eventHandler = new EventHandler(this.logger, this.browserCrypto);
121
+ this.eventHandler = new EventHandler(this.logger);
122
122
 
123
123
  this.nestedAppAuthAdapter = new NestedAppAuthAdapter(
124
124
  this.config.auth.clientId,
@@ -140,14 +140,6 @@ export class NestedAppAuthController implements IController {
140
140
  }
141
141
  }
142
142
 
143
- /**
144
- * Returns the event handler instance
145
- * @returns EventHandler
146
- */
147
- getEventHandler(): EventHandler {
148
- return this.eventHandler;
149
- }
150
-
151
143
  /**
152
144
  * Factory function to create a new instance of NestedAppAuthController
153
145
  * @param operatingContext
@@ -588,9 +580,13 @@ export class NestedAppAuthController implements IController {
588
580
  /**
589
581
  * Adds event callbacks to array
590
582
  * @param callback
583
+ * @param eventTypes
591
584
  */
592
- addEventCallback(callback: EventCallbackFunction): string | null {
593
- return this.eventHandler.addEventCallback(callback);
585
+ addEventCallback(
586
+ callback: EventCallbackFunction,
587
+ eventTypes?: Array<EventType>
588
+ ): string | null {
589
+ return this.eventHandler.addEventCallback(callback, eventTypes);
594
590
  }
595
591
 
596
592
  /**
@@ -28,6 +28,8 @@ import {
28
28
  AccountFilter,
29
29
  buildStaticAuthorityOptions,
30
30
  InteractionRequiredAuthErrorCodes,
31
+ PersistentCacheKeys,
32
+ CacheManager,
31
33
  } from "@azure/msal-common/browser";
32
34
  import {
33
35
  BrowserCacheManager,
@@ -176,6 +178,9 @@ export class StandardController implements IController {
176
178
 
177
179
  private ssoSilentMeasurement?: InProgressPerformanceEvent;
178
180
  private acquireTokenByCodeAsyncMeasurement?: InProgressPerformanceEvent;
181
+
182
+ // Flag which indicates if we're currently listening for account storage events
183
+ private listeningToStorageEvents: boolean;
179
184
  /**
180
185
  * @constructor
181
186
  * Constructor for the PublicClientApplication used to instantiate the PublicClientApplication object
@@ -228,7 +233,7 @@ export class StandardController implements IController {
228
233
  ? new CryptoOps(this.logger, this.performanceClient)
229
234
  : DEFAULT_CRYPTO_IMPLEMENTATION;
230
235
 
231
- this.eventHandler = new EventHandler(this.logger, this.browserCrypto);
236
+ this.eventHandler = new EventHandler(this.logger);
232
237
 
233
238
  // Initialize the browser storage class.
234
239
  this.browserStorage = this.isBrowserEnvironment
@@ -279,6 +284,11 @@ export class StandardController implements IController {
279
284
  // Register listener functions
280
285
  this.trackPageVisibilityWithMeasurement =
281
286
  this.trackPageVisibilityWithMeasurement.bind(this);
287
+
288
+ // account storage events
289
+ this.listeningToStorageEvents = false;
290
+ this.handleAccountCacheChange =
291
+ this.handleAccountCacheChange.bind(this);
282
292
  }
283
293
 
284
294
  static async createController(
@@ -314,6 +324,13 @@ export class StandardController implements IController {
314
324
  return;
315
325
  }
316
326
 
327
+ if (!this.isBrowserEnvironment) {
328
+ this.logger.info("in non-browser environment, exiting early.");
329
+ this.initialized = true;
330
+ this.eventHandler.emitEvent(EventType.INITIALIZE_END);
331
+ return;
332
+ }
333
+
317
334
  const initCorrelationId =
318
335
  request?.correlationId || this.getRequestCorrelationId();
319
336
  const allowNativeBroker = this.config.system.allowNativeBroker;
@@ -354,7 +371,6 @@ export class StandardController implements IController {
354
371
 
355
372
  this.initialized = true;
356
373
  this.eventHandler.emitEvent(EventType.INITIALIZE_END);
357
-
358
374
  initMeasurement.end({ allowNativeBroker, success: true });
359
375
  }
360
376
 
@@ -1336,6 +1352,10 @@ export class StandardController implements IController {
1336
1352
  * @param logoutRequest
1337
1353
  */
1338
1354
  async clearCache(logoutRequest?: ClearCacheRequest): Promise<void> {
1355
+ if (!this.isBrowserEnvironment) {
1356
+ this.logger.info("in non-browser environment, returning early.");
1357
+ return;
1358
+ }
1339
1359
  const correlationId = this.getRequestCorrelationId(logoutRequest);
1340
1360
  const cacheClient = this.createSilentCacheClient(correlationId);
1341
1361
  return cacheClient.logout(logoutRequest);
@@ -1697,8 +1717,11 @@ export class StandardController implements IController {
1697
1717
  * Adds event callbacks to array
1698
1718
  * @param callback
1699
1719
  */
1700
- addEventCallback(callback: EventCallbackFunction): string | null {
1701
- return this.eventHandler.addEventCallback(callback);
1720
+ addEventCallback(
1721
+ callback: EventCallbackFunction,
1722
+ eventTypes?: Array<EventType>
1723
+ ): string | null {
1724
+ return this.eventHandler.addEventCallback(callback, eventTypes);
1702
1725
  }
1703
1726
 
1704
1727
  /**
@@ -1716,6 +1739,7 @@ export class StandardController implements IController {
1716
1739
  * @returns {string}
1717
1740
  */
1718
1741
  addPerformanceCallback(callback: PerformanceCallbackFunction): string {
1742
+ BrowserUtils.blockNonBrowserEnvironment();
1719
1743
  return this.performanceClient.addPerformanceCallback(callback);
1720
1744
  }
1721
1745
 
@@ -1733,14 +1757,89 @@ export class StandardController implements IController {
1733
1757
  * Adds event listener that emits an event when a user account is added or removed from localstorage in a different browser tab or window
1734
1758
  */
1735
1759
  enableAccountStorageEvents(): void {
1736
- this.eventHandler.enableAccountStorageEvents();
1760
+ if (typeof window === "undefined") {
1761
+ return;
1762
+ }
1763
+
1764
+ if (!this.listeningToStorageEvents) {
1765
+ this.logger.verbose("Adding account storage listener.");
1766
+ this.listeningToStorageEvents = true;
1767
+ window.addEventListener("storage", this.handleAccountCacheChange);
1768
+ } else {
1769
+ this.logger.verbose("Account storage listener already registered.");
1770
+ }
1737
1771
  }
1738
1772
 
1739
1773
  /**
1740
1774
  * Removes event listener that emits an event when a user account is added or removed from localstorage in a different browser tab or window
1741
1775
  */
1742
1776
  disableAccountStorageEvents(): void {
1743
- this.eventHandler.disableAccountStorageEvents();
1777
+ if (typeof window === "undefined") {
1778
+ return;
1779
+ }
1780
+
1781
+ if (this.listeningToStorageEvents) {
1782
+ this.logger.verbose("Removing account storage listener.");
1783
+ window.removeEventListener(
1784
+ "storage",
1785
+ this.handleAccountCacheChange
1786
+ );
1787
+ this.listeningToStorageEvents = false;
1788
+ } else {
1789
+ this.logger.verbose("No account storage listener registered.");
1790
+ }
1791
+ }
1792
+
1793
+ /**
1794
+ * Emit account added/removed events when cached accounts are changed in a different tab or frame
1795
+ */
1796
+ protected handleAccountCacheChange(e: StorageEvent): void {
1797
+ try {
1798
+ // Handle active account filter change
1799
+ if (e.key?.includes(PersistentCacheKeys.ACTIVE_ACCOUNT_FILTERS)) {
1800
+ // This event has no payload, it only signals cross-tab app instances that the results of calling getActiveAccount() will have changed
1801
+ this.eventHandler.emitEvent(EventType.ACTIVE_ACCOUNT_CHANGED);
1802
+ }
1803
+
1804
+ // Handle account object change
1805
+ const cacheValue = e.newValue || e.oldValue;
1806
+ if (!cacheValue) {
1807
+ return;
1808
+ }
1809
+ const parsedValue = JSON.parse(cacheValue);
1810
+ if (
1811
+ typeof parsedValue !== "object" ||
1812
+ !AccountEntity.isAccountEntity(parsedValue)
1813
+ ) {
1814
+ return;
1815
+ }
1816
+ const accountEntity = CacheManager.toObject<AccountEntity>(
1817
+ new AccountEntity(),
1818
+ parsedValue
1819
+ );
1820
+ const accountInfo = accountEntity.getAccountInfo();
1821
+ if (!e.oldValue && e.newValue) {
1822
+ this.logger.info(
1823
+ "Account was added to cache in a different window"
1824
+ );
1825
+ this.eventHandler.emitEvent(
1826
+ EventType.ACCOUNT_ADDED,
1827
+ undefined,
1828
+ accountInfo
1829
+ );
1830
+ } else if (!e.newValue && e.oldValue) {
1831
+ this.logger.info(
1832
+ "Account was removed from cache in a different window"
1833
+ );
1834
+ this.eventHandler.emitEvent(
1835
+ EventType.ACCOUNT_REMOVED,
1836
+ undefined,
1837
+ accountInfo
1838
+ );
1839
+ }
1840
+ } catch (e) {
1841
+ return;
1842
+ }
1744
1843
  }
1745
1844
 
1746
1845
  /**
@@ -1804,13 +1903,6 @@ export class StandardController implements IController {
1804
1903
  return this.isBrowserEnvironment;
1805
1904
  }
1806
1905
 
1807
- /**
1808
- * Returns the event handler
1809
- */
1810
- getEventHandler(): EventHandler {
1811
- return this.eventHandler;
1812
- }
1813
-
1814
1906
  /**
1815
1907
  * Generates a correlation id for a request if none is provided.
1816
1908
  *
@@ -37,9 +37,9 @@ import {
37
37
  blockAPICallsBeforeInitialize,
38
38
  blockNonBrowserEnvironment,
39
39
  } from "../utils/BrowserUtils.js";
40
- import { EventHandler } from "../event/EventHandler.js";
41
40
  import { EventCallbackFunction } from "../event/EventMessage.js";
42
41
  import { ClearCacheRequest } from "../request/ClearCacheRequest.js";
42
+ import { EventType } from "../event/EventType.js";
43
43
 
44
44
  /**
45
45
  * UnknownOperatingContextController class
@@ -80,8 +80,6 @@ export class UnknownOperatingContextController implements IController {
80
80
  // Flag representing whether or not the initialize API has been called and completed
81
81
  protected initialized: boolean = false;
82
82
 
83
- protected readonly eventHandler: EventHandler;
84
-
85
83
  constructor(operatingContext: UnknownOperatingContext) {
86
84
  this.operatingContext = operatingContext;
87
85
 
@@ -114,17 +112,11 @@ export class UnknownOperatingContextController implements IController {
114
112
  this.config.auth.clientId,
115
113
  this.logger
116
114
  );
117
-
118
- this.eventHandler = new EventHandler(this.logger, this.browserCrypto);
119
115
  }
120
116
  getBrowserStorage(): BrowserCacheManager {
121
117
  return this.browserStorage;
122
118
  }
123
119
 
124
- getEventHandler(): EventHandler {
125
- return this.eventHandler;
126
- }
127
-
128
120
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
129
121
  getAccount(accountFilter: AccountFilter): AccountInfo | null {
130
122
  return null;
@@ -210,12 +202,18 @@ export class UnknownOperatingContextController implements IController {
210
202
  blockNonBrowserEnvironment();
211
203
  return {} as Promise<AuthenticationResult>;
212
204
  }
213
- addEventCallback(callback: EventCallbackFunction): string | null {
214
- return this.eventHandler.addEventCallback(callback);
215
- }
216
- removeEventCallback(callbackId: string): void {
217
- this.eventHandler.removeEventCallback(callbackId);
205
+ addEventCallback(
206
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
207
+ callback: EventCallbackFunction,
208
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
209
+ eventTypes?: Array<EventType>
210
+ ): string | null {
211
+ return null;
218
212
  }
213
+ removeEventCallback(
214
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
215
+ callbackId: string
216
+ ): void {}
219
217
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
220
218
  addPerformanceCallback(callback: PerformanceCallbackFunction): string {
221
219
  blockAPICallsBeforeInitialize(this.initialized);
@@ -3,13 +3,7 @@
3
3
  * Licensed under the MIT License.
4
4
  */
5
5
 
6
- import {
7
- ICrypto,
8
- Logger,
9
- AccountEntity,
10
- CacheManager,
11
- PersistentCacheKeys,
12
- } from "@azure/msal-common/browser";
6
+ import { Logger } from "@azure/msal-common/browser";
13
7
  import { InteractionType } from "../utils/BrowserConstants.js";
14
8
  import {
15
9
  EventCallbackFunction,
@@ -18,37 +12,44 @@ import {
18
12
  EventPayload,
19
13
  } from "./EventMessage.js";
20
14
  import { EventType } from "./EventType.js";
21
- import { createNewGuid } from "../crypto/BrowserCrypto.js";
15
+ import { createGuid } from "../utils/BrowserUtils.js";
22
16
 
23
17
  export class EventHandler {
24
18
  // Callback for subscribing to events
25
- private eventCallbacks: Map<string, EventCallbackFunction>;
19
+ private eventCallbacks: Map<
20
+ string,
21
+ [EventCallbackFunction, Array<EventType>]
22
+ >;
26
23
  private logger: Logger;
27
- private browserCrypto: ICrypto;
28
- private listeningToStorageEvents: boolean;
29
24
 
30
- constructor(logger: Logger, browserCrypto: ICrypto) {
25
+ constructor(logger?: Logger) {
31
26
  this.eventCallbacks = new Map();
32
- this.logger = logger;
33
- this.browserCrypto = browserCrypto;
34
- this.listeningToStorageEvents = false;
35
- this.handleAccountCacheChange =
36
- this.handleAccountCacheChange.bind(this);
27
+ this.logger = logger || new Logger({});
37
28
  }
38
29
 
39
30
  /**
40
31
  * Adds event callbacks to array
41
- * @param callback
32
+ * @param callback - callback to be invoked when an event is raised
33
+ * @param eventTypes - list of events that this callback will be invoked for, if not provided callback will be invoked for all events
34
+ * @param callbackId - Identifier for the callback, used to locate and remove the callback when no longer required
42
35
  */
43
- addEventCallback(callback: EventCallbackFunction): string | null {
36
+ addEventCallback(
37
+ callback: EventCallbackFunction,
38
+ eventTypes?: Array<EventType>,
39
+ callbackId?: string
40
+ ): string | null {
44
41
  if (typeof window !== "undefined") {
45
- const callbackId = createNewGuid();
46
- this.eventCallbacks.set(callbackId, callback);
47
- this.logger.verbose(
48
- `Event callback registered with id: ${callbackId}`
49
- );
42
+ const id = callbackId || createGuid();
43
+ if (this.eventCallbacks.has(id)) {
44
+ this.logger.error(
45
+ `Event callback with id: ${id} is already registered. Please provide a unique id or remove the existing callback and try again.`
46
+ );
47
+ return null;
48
+ }
49
+ this.eventCallbacks.set(id, [callback, eventTypes || []]);
50
+ this.logger.verbose(`Event callback registered with id: ${id}`);
50
51
 
51
- return callbackId;
52
+ return id;
52
53
  }
53
54
 
54
55
  return null;
@@ -63,43 +64,6 @@ export class EventHandler {
63
64
  this.logger.verbose(`Event callback ${callbackId} removed.`);
64
65
  }
65
66
 
66
- /**
67
- * Adds event listener that emits an event when a user account is added or removed from localstorage in a different browser tab or window
68
- */
69
- enableAccountStorageEvents(): void {
70
- if (typeof window === "undefined") {
71
- return;
72
- }
73
-
74
- if (!this.listeningToStorageEvents) {
75
- this.logger.verbose("Adding account storage listener.");
76
- this.listeningToStorageEvents = true;
77
- window.addEventListener("storage", this.handleAccountCacheChange);
78
- } else {
79
- this.logger.verbose("Account storage listener already registered.");
80
- }
81
- }
82
-
83
- /**
84
- * Removes event listener that emits an event when a user account is added or removed from localstorage in a different browser tab or window
85
- */
86
- disableAccountStorageEvents(): void {
87
- if (typeof window === "undefined") {
88
- return;
89
- }
90
-
91
- if (this.listeningToStorageEvents) {
92
- this.logger.verbose("Removing account storage listener.");
93
- window.removeEventListener(
94
- "storage",
95
- this.handleAccountCacheChange
96
- );
97
- this.listeningToStorageEvents = false;
98
- } else {
99
- this.logger.verbose("No account storage listener registered.");
100
- }
101
- }
102
-
103
67
  /**
104
68
  * Emits events by calling callback with event message
105
69
  * @param eventType
@@ -122,64 +86,25 @@ export class EventHandler {
122
86
  timestamp: Date.now(),
123
87
  };
124
88
 
125
- this.logger.info(`Emitting event: ${eventType}`);
126
-
127
89
  this.eventCallbacks.forEach(
128
- (callback: EventCallbackFunction, callbackId: string) => {
129
- this.logger.verbose(
130
- `Emitting event to callback ${callbackId}: ${eventType}`
131
- );
132
- callback.apply(null, [message]);
90
+ (
91
+ [callback, eventTypes]: [
92
+ EventCallbackFunction,
93
+ Array<EventType>
94
+ ],
95
+ callbackId: string
96
+ ) => {
97
+ if (
98
+ eventTypes.length === 0 ||
99
+ eventTypes.includes(eventType)
100
+ ) {
101
+ this.logger.verbose(
102
+ `Emitting event to callback ${callbackId}: ${eventType}`
103
+ );
104
+ callback.apply(null, [message]);
105
+ }
133
106
  }
134
107
  );
135
108
  }
136
109
  }
137
-
138
- /**
139
- * Emit account added/removed events when cached accounts are changed in a different tab or frame
140
- */
141
- private handleAccountCacheChange(e: StorageEvent): void {
142
- try {
143
- // Handle active account filter change
144
- if (e.key?.includes(PersistentCacheKeys.ACTIVE_ACCOUNT_FILTERS)) {
145
- // This event has no payload, it only signals cross-tab app instances that the results of calling getActiveAccount() will have changed
146
- this.emitEvent(EventType.ACTIVE_ACCOUNT_CHANGED);
147
- }
148
-
149
- // Handle account object change
150
- const cacheValue = e.newValue || e.oldValue;
151
- if (!cacheValue) {
152
- return;
153
- }
154
- const parsedValue = JSON.parse(cacheValue);
155
- if (
156
- typeof parsedValue !== "object" ||
157
- !AccountEntity.isAccountEntity(parsedValue)
158
- ) {
159
- return;
160
- }
161
- const accountEntity = CacheManager.toObject<AccountEntity>(
162
- new AccountEntity(),
163
- parsedValue
164
- );
165
- const accountInfo = accountEntity.getAccountInfo();
166
- if (!e.oldValue && e.newValue) {
167
- this.logger.info(
168
- "Account was added to cache in a different window"
169
- );
170
- this.emitEvent(EventType.ACCOUNT_ADDED, undefined, accountInfo);
171
- } else if (!e.newValue && e.oldValue) {
172
- this.logger.info(
173
- "Account was removed from cache in a different window"
174
- );
175
- this.emitEvent(
176
- EventType.ACCOUNT_REMOVED,
177
- undefined,
178
- accountInfo
179
- );
180
- }
181
- } catch (e) {
182
- return;
183
- }
184
- }
185
110
  }
package/src/index.ts CHANGED
@@ -86,6 +86,7 @@ export {
86
86
  PopupEvent,
87
87
  } from "./event/EventMessage.js";
88
88
  export { EventType } from "./event/EventType.js";
89
+ export { EventHandler } from "./event/EventHandler.js";
89
90
 
90
91
  export {
91
92
  SignedHttpRequest,
@@ -49,6 +49,22 @@ import { EventError } from "../event/EventMessage.js";
49
49
  import { AuthenticationResult } from "../response/AuthenticationResult.js";
50
50
  import * as ResponseHandler from "../response/ResponseHandler.js";
51
51
 
52
+ function getNavigationType(): NavigationTimingType | undefined {
53
+ if (
54
+ typeof window === "undefined" ||
55
+ typeof window.performance === "undefined" ||
56
+ typeof window.performance.getEntriesByType !== "function"
57
+ ) {
58
+ return undefined;
59
+ }
60
+
61
+ const navigationEntries = window.performance.getEntriesByType("navigation");
62
+ const navigation = navigationEntries.length
63
+ ? (navigationEntries[0] as PerformanceNavigationTiming)
64
+ : undefined;
65
+ return navigation?.type;
66
+ }
67
+
52
68
  export class RedirectClient extends StandardInteractionClient {
53
69
  protected nativeStorage: BrowserCacheManager;
54
70
 
@@ -223,7 +239,15 @@ export class RedirectClient extends StandardInteractionClient {
223
239
  this.browserStorage.cleanRequestByInteractionType(
224
240
  InteractionType.Redirect
225
241
  );
226
- parentMeasurement.event.errorCode = "no_server_response";
242
+
243
+ // Do not instrument "no_server_response" if user clicked back button
244
+ if (getNavigationType() !== "back_forward") {
245
+ parentMeasurement.event.errorCode = "no_server_response";
246
+ } else {
247
+ this.logger.verbose(
248
+ "Back navigation event detected. Muting no_server_response error"
249
+ );
250
+ }
227
251
  return null;
228
252
  }
229
253
 
@@ -1,3 +1,3 @@
1
1
  /* eslint-disable header/header */
2
2
  export const name = "@azure/msal-browser";
3
- export const version = "3.24.0";
3
+ export const version = "3.26.0";