@thefittingroom/shop-ui 1.5.1 → 1.5.3

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.
package/dist/esm/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * thefittingroom v1.5.1 (2024-09-01T17:00:41.740Z)
2
+ * thefittingroom v1.5.3 (2024-09-03T15:46:41.127Z)
3
3
  * Copyright 2022-present, TheFittingRoom, Inc. All rights reserved.
4
4
  */
5
5
  function loadImageRecursive(imageURL, imageURLs) {
@@ -47,7 +47,7 @@ const InitImageSlider = (sliderID, onChange) => {
47
47
  };
48
48
 
49
49
  /*!
50
- * thefittingroom v1.5.0 (2024-09-01T16:52:25.366Z)
50
+ * thefittingroom v1.5.2 (2024-09-03T15:43:56.403Z)
51
51
  * Copyright 2022-present, TheFittingRoom, Inc. All rights reserved.
52
52
  */
53
53
 
@@ -1986,8 +1986,8 @@ function isVersionServiceProvider(provider) {
1986
1986
  return (component === null || component === void 0 ? void 0 : component.type) === "VERSION" /* ComponentType.VERSION */;
1987
1987
  }
1988
1988
 
1989
- const name$o = "@firebase/app";
1990
- const version$1$1 = "0.9.13";
1989
+ const name$p = "@firebase/app";
1990
+ const version$1$1 = "0.10.9";
1991
1991
 
1992
1992
  /**
1993
1993
  * @license
@@ -2007,54 +2007,56 @@ const version$1$1 = "0.9.13";
2007
2007
  */
2008
2008
  const logger = new Logger$1('@firebase/app');
2009
2009
 
2010
- const name$n = "@firebase/app-compat";
2010
+ const name$o = "@firebase/app-compat";
2011
2011
 
2012
- const name$m = "@firebase/analytics-compat";
2012
+ const name$n = "@firebase/analytics-compat";
2013
2013
 
2014
- const name$l = "@firebase/analytics";
2014
+ const name$m = "@firebase/analytics";
2015
2015
 
2016
- const name$k = "@firebase/app-check-compat";
2016
+ const name$l = "@firebase/app-check-compat";
2017
2017
 
2018
- const name$j = "@firebase/app-check";
2018
+ const name$k = "@firebase/app-check";
2019
2019
 
2020
- const name$i = "@firebase/auth";
2020
+ const name$j = "@firebase/auth";
2021
2021
 
2022
- const name$h = "@firebase/auth-compat";
2022
+ const name$i = "@firebase/auth-compat";
2023
2023
 
2024
- const name$g = "@firebase/database";
2024
+ const name$h = "@firebase/database";
2025
2025
 
2026
- const name$f = "@firebase/database-compat";
2026
+ const name$g = "@firebase/database-compat";
2027
2027
 
2028
- const name$e = "@firebase/functions";
2028
+ const name$f = "@firebase/functions";
2029
2029
 
2030
- const name$d = "@firebase/functions-compat";
2030
+ const name$e = "@firebase/functions-compat";
2031
2031
 
2032
- const name$c = "@firebase/installations";
2032
+ const name$d = "@firebase/installations";
2033
2033
 
2034
- const name$b = "@firebase/installations-compat";
2034
+ const name$c = "@firebase/installations-compat";
2035
2035
 
2036
- const name$a = "@firebase/messaging";
2036
+ const name$b = "@firebase/messaging";
2037
2037
 
2038
- const name$9 = "@firebase/messaging-compat";
2038
+ const name$a = "@firebase/messaging-compat";
2039
2039
 
2040
- const name$8 = "@firebase/performance";
2040
+ const name$9 = "@firebase/performance";
2041
2041
 
2042
- const name$7 = "@firebase/performance-compat";
2042
+ const name$8 = "@firebase/performance-compat";
2043
2043
 
2044
- const name$6 = "@firebase/remote-config";
2044
+ const name$7 = "@firebase/remote-config";
2045
2045
 
2046
- const name$5 = "@firebase/remote-config-compat";
2046
+ const name$6 = "@firebase/remote-config-compat";
2047
2047
 
2048
- const name$4 = "@firebase/storage";
2048
+ const name$5 = "@firebase/storage";
2049
2049
 
2050
- const name$3 = "@firebase/storage-compat";
2050
+ const name$4 = "@firebase/storage-compat";
2051
2051
 
2052
- const name$2 = "@firebase/firestore";
2052
+ const name$3 = "@firebase/firestore";
2053
+
2054
+ const name$2 = "@firebase/vertexai-preview";
2053
2055
 
2054
2056
  const name$1$1 = "@firebase/firestore-compat";
2055
2057
 
2056
- const name$p = "firebase";
2057
- const version$2 = "9.23.0";
2058
+ const name$q = "firebase";
2059
+ const version$2 = "10.13.0";
2058
2060
 
2059
2061
  /**
2060
2062
  * @license
@@ -2079,32 +2081,33 @@ const version$2 = "9.23.0";
2079
2081
  */
2080
2082
  const DEFAULT_ENTRY_NAME = '[DEFAULT]';
2081
2083
  const PLATFORM_LOG_STRING = {
2082
- [name$o]: 'fire-core',
2083
- [name$n]: 'fire-core-compat',
2084
- [name$l]: 'fire-analytics',
2085
- [name$m]: 'fire-analytics-compat',
2086
- [name$j]: 'fire-app-check',
2087
- [name$k]: 'fire-app-check-compat',
2088
- [name$i]: 'fire-auth',
2089
- [name$h]: 'fire-auth-compat',
2090
- [name$g]: 'fire-rtdb',
2091
- [name$f]: 'fire-rtdb-compat',
2092
- [name$e]: 'fire-fn',
2093
- [name$d]: 'fire-fn-compat',
2094
- [name$c]: 'fire-iid',
2095
- [name$b]: 'fire-iid-compat',
2096
- [name$a]: 'fire-fcm',
2097
- [name$9]: 'fire-fcm-compat',
2098
- [name$8]: 'fire-perf',
2099
- [name$7]: 'fire-perf-compat',
2100
- [name$6]: 'fire-rc',
2101
- [name$5]: 'fire-rc-compat',
2102
- [name$4]: 'fire-gcs',
2103
- [name$3]: 'fire-gcs-compat',
2104
- [name$2]: 'fire-fst',
2084
+ [name$p]: 'fire-core',
2085
+ [name$o]: 'fire-core-compat',
2086
+ [name$m]: 'fire-analytics',
2087
+ [name$n]: 'fire-analytics-compat',
2088
+ [name$k]: 'fire-app-check',
2089
+ [name$l]: 'fire-app-check-compat',
2090
+ [name$j]: 'fire-auth',
2091
+ [name$i]: 'fire-auth-compat',
2092
+ [name$h]: 'fire-rtdb',
2093
+ [name$g]: 'fire-rtdb-compat',
2094
+ [name$f]: 'fire-fn',
2095
+ [name$e]: 'fire-fn-compat',
2096
+ [name$d]: 'fire-iid',
2097
+ [name$c]: 'fire-iid-compat',
2098
+ [name$b]: 'fire-fcm',
2099
+ [name$a]: 'fire-fcm-compat',
2100
+ [name$9]: 'fire-perf',
2101
+ [name$8]: 'fire-perf-compat',
2102
+ [name$7]: 'fire-rc',
2103
+ [name$6]: 'fire-rc-compat',
2104
+ [name$5]: 'fire-gcs',
2105
+ [name$4]: 'fire-gcs-compat',
2106
+ [name$3]: 'fire-fst',
2105
2107
  [name$1$1]: 'fire-fst-compat',
2108
+ [name$2]: 'fire-vertex',
2106
2109
  'fire-js': 'fire-js',
2107
- [name$p]: 'fire-js-all'
2110
+ [name$q]: 'fire-js-all'
2108
2111
  };
2109
2112
 
2110
2113
  /**
@@ -2127,6 +2130,10 @@ const PLATFORM_LOG_STRING = {
2127
2130
  * @internal
2128
2131
  */
2129
2132
  const _apps = new Map();
2133
+ /**
2134
+ * @internal
2135
+ */
2136
+ const _serverApps = new Map();
2130
2137
  /**
2131
2138
  * Registered components.
2132
2139
  *
@@ -2165,6 +2172,9 @@ function _registerComponent(component) {
2165
2172
  for (const app of _apps.values()) {
2166
2173
  _addComponent(app, component);
2167
2174
  }
2175
+ for (const serverApp of _serverApps.values()) {
2176
+ _addComponent(serverApp, component);
2177
+ }
2168
2178
  return true;
2169
2179
  }
2170
2180
  /**
@@ -2185,6 +2195,17 @@ function _getProvider(app, name) {
2185
2195
  }
2186
2196
  return app.container.getProvider(name);
2187
2197
  }
2198
+ /**
2199
+ *
2200
+ * @param obj - an object of type FirebaseApp.
2201
+ *
2202
+ * @returns true if the provided object is of type FirebaseServerAppImpl.
2203
+ *
2204
+ * @internal
2205
+ */
2206
+ function _isFirebaseServerApp(obj) {
2207
+ return obj.settings !== undefined;
2208
+ }
2188
2209
 
2189
2210
  /**
2190
2211
  * @license
@@ -2205,9 +2226,10 @@ function _getProvider(app, name) {
2205
2226
  const ERRORS = {
2206
2227
  ["no-app" /* AppError.NO_APP */]: "No Firebase App '{$appName}' has been created - " +
2207
2228
  'call initializeApp() first',
2208
- ["bad-app-name" /* AppError.BAD_APP_NAME */]: "Illegal App name: '{$appName}",
2229
+ ["bad-app-name" /* AppError.BAD_APP_NAME */]: "Illegal App name: '{$appName}'",
2209
2230
  ["duplicate-app" /* AppError.DUPLICATE_APP */]: "Firebase App named '{$appName}' already exists with different options or config",
2210
2231
  ["app-deleted" /* AppError.APP_DELETED */]: "Firebase App named '{$appName}' already deleted",
2232
+ ["server-app-deleted" /* AppError.SERVER_APP_DELETED */]: 'Firebase Server App has been deleted',
2211
2233
  ["no-options" /* AppError.NO_OPTIONS */]: 'Need to provide options, when not being deployed to hosting via source.',
2212
2234
  ["invalid-app-argument" /* AppError.INVALID_APP_ARGUMENT */]: 'firebase.{$appName}() takes either no argument or a ' +
2213
2235
  'Firebase App instance.',
@@ -2215,7 +2237,9 @@ const ERRORS = {
2215
2237
  ["idb-open" /* AppError.IDB_OPEN */]: 'Error thrown when opening IndexedDB. Original error: {$originalErrorMessage}.',
2216
2238
  ["idb-get" /* AppError.IDB_GET */]: 'Error thrown when reading from IndexedDB. Original error: {$originalErrorMessage}.',
2217
2239
  ["idb-set" /* AppError.IDB_WRITE */]: 'Error thrown when writing to IndexedDB. Original error: {$originalErrorMessage}.',
2218
- ["idb-delete" /* AppError.IDB_DELETE */]: 'Error thrown when deleting from IndexedDB. Original error: {$originalErrorMessage}.'
2240
+ ["idb-delete" /* AppError.IDB_DELETE */]: 'Error thrown when deleting from IndexedDB. Original error: {$originalErrorMessage}.',
2241
+ ["finalization-registry-not-supported" /* AppError.FINALIZATION_REGISTRY_NOT_SUPPORTED */]: 'FirebaseServerApp deleteOnDeref field defined but the JS runtime does not support FinalizationRegistry.',
2242
+ ["invalid-server-app-environment" /* AppError.INVALID_SERVER_APP_ENVIRONMENT */]: 'FirebaseServerApp is not for use in browser environments.'
2219
2243
  };
2220
2244
  const ERROR_FACTORY = new ErrorFactory$1('app', 'Firebase', ERRORS);
2221
2245
 
@@ -2451,7 +2475,15 @@ function getDbPromise() {
2451
2475
  // eslint-disable-next-line default-case
2452
2476
  switch (oldVersion) {
2453
2477
  case 0:
2454
- db.createObjectStore(STORE_NAME);
2478
+ try {
2479
+ db.createObjectStore(STORE_NAME);
2480
+ }
2481
+ catch (e) {
2482
+ // Safari/iOS browsers throw occasional exceptions on
2483
+ // db.createObjectStore() that may be a bug. Avoid blocking
2484
+ // the rest of the app functionality.
2485
+ console.warn(e);
2486
+ }
2455
2487
  }
2456
2488
  }
2457
2489
  }).catch(e => {
@@ -2465,10 +2497,11 @@ function getDbPromise() {
2465
2497
  async function readHeartbeatsFromIndexedDB(app) {
2466
2498
  try {
2467
2499
  const db = await getDbPromise();
2468
- const result = await db
2469
- .transaction(STORE_NAME)
2470
- .objectStore(STORE_NAME)
2471
- .get(computeKey(app));
2500
+ const tx = db.transaction(STORE_NAME);
2501
+ const result = await tx.objectStore(STORE_NAME).get(computeKey(app));
2502
+ // We already have the value but tx.done can throw,
2503
+ // so we need to await it here to catch errors
2504
+ await tx.done;
2472
2505
  return result;
2473
2506
  }
2474
2507
  catch (e) {
@@ -2554,33 +2587,45 @@ class HeartbeatServiceImpl {
2554
2587
  * already logged, subsequent calls to this function in the same day will be ignored.
2555
2588
  */
2556
2589
  async triggerHeartbeat() {
2557
- const platformLogger = this.container
2558
- .getProvider('platform-logger')
2559
- .getImmediate();
2560
- // This is the "Firebase user agent" string from the platform logger
2561
- // service, not the browser user agent.
2562
- const agent = platformLogger.getPlatformInfoString();
2563
- const date = getUTCDateString();
2564
- if (this._heartbeatsCache === null) {
2565
- this._heartbeatsCache = await this._heartbeatsCachePromise;
2566
- }
2567
- // Do not store a heartbeat if one is already stored for this day
2568
- // or if a header has already been sent today.
2569
- if (this._heartbeatsCache.lastSentHeartbeatDate === date ||
2570
- this._heartbeatsCache.heartbeats.some(singleDateHeartbeat => singleDateHeartbeat.date === date)) {
2571
- return;
2590
+ var _a, _b, _c;
2591
+ try {
2592
+ const platformLogger = this.container
2593
+ .getProvider('platform-logger')
2594
+ .getImmediate();
2595
+ // This is the "Firebase user agent" string from the platform logger
2596
+ // service, not the browser user agent.
2597
+ const agent = platformLogger.getPlatformInfoString();
2598
+ const date = getUTCDateString();
2599
+ console.log('heartbeats', (_a = this._heartbeatsCache) === null || _a === void 0 ? void 0 : _a.heartbeats);
2600
+ if (((_b = this._heartbeatsCache) === null || _b === void 0 ? void 0 : _b.heartbeats) == null) {
2601
+ this._heartbeatsCache = await this._heartbeatsCachePromise;
2602
+ // If we failed to construct a heartbeats cache, then return immediately.
2603
+ if (((_c = this._heartbeatsCache) === null || _c === void 0 ? void 0 : _c.heartbeats) == null) {
2604
+ return;
2605
+ }
2606
+ }
2607
+ // Do not store a heartbeat if one is already stored for this day
2608
+ // or if a header has already been sent today.
2609
+ if (this._heartbeatsCache.lastSentHeartbeatDate === date ||
2610
+ this._heartbeatsCache.heartbeats.some(singleDateHeartbeat => singleDateHeartbeat.date === date)) {
2611
+ return;
2612
+ }
2613
+ else {
2614
+ // There is no entry for this date. Create one.
2615
+ this._heartbeatsCache.heartbeats.push({ date, agent });
2616
+ }
2617
+ // Remove entries older than 30 days.
2618
+ this._heartbeatsCache.heartbeats =
2619
+ this._heartbeatsCache.heartbeats.filter(singleDateHeartbeat => {
2620
+ const hbTimestamp = new Date(singleDateHeartbeat.date).valueOf();
2621
+ const now = Date.now();
2622
+ return now - hbTimestamp <= STORED_HEARTBEAT_RETENTION_MAX_MILLIS;
2623
+ });
2624
+ return this._storage.overwrite(this._heartbeatsCache);
2625
+ }
2626
+ catch (e) {
2627
+ logger.warn(e);
2572
2628
  }
2573
- else {
2574
- // There is no entry for this date. Create one.
2575
- this._heartbeatsCache.heartbeats.push({ date, agent });
2576
- }
2577
- // Remove entries older than 30 days.
2578
- this._heartbeatsCache.heartbeats = this._heartbeatsCache.heartbeats.filter(singleDateHeartbeat => {
2579
- const hbTimestamp = new Date(singleDateHeartbeat.date).valueOf();
2580
- const now = Date.now();
2581
- return now - hbTimestamp <= STORED_HEARTBEAT_RETENTION_MAX_MILLIS;
2582
- });
2583
- return this._storage.overwrite(this._heartbeatsCache);
2584
2629
  }
2585
2630
  /**
2586
2631
  * Returns a base64 encoded string which can be attached to the heartbeat-specific header directly.
@@ -2590,34 +2635,41 @@ class HeartbeatServiceImpl {
2590
2635
  * returns an empty string.
2591
2636
  */
2592
2637
  async getHeartbeatsHeader() {
2593
- if (this._heartbeatsCache === null) {
2594
- await this._heartbeatsCachePromise;
2638
+ var _a;
2639
+ try {
2640
+ if (this._heartbeatsCache === null) {
2641
+ await this._heartbeatsCachePromise;
2642
+ }
2643
+ // If it's still null or the array is empty, there is no data to send.
2644
+ if (((_a = this._heartbeatsCache) === null || _a === void 0 ? void 0 : _a.heartbeats) == null ||
2645
+ this._heartbeatsCache.heartbeats.length === 0) {
2646
+ return '';
2647
+ }
2648
+ const date = getUTCDateString();
2649
+ // Extract as many heartbeats from the cache as will fit under the size limit.
2650
+ const { heartbeatsToSend, unsentEntries } = extractHeartbeatsForHeader(this._heartbeatsCache.heartbeats);
2651
+ const headerString = base64urlEncodeWithoutPadding$1(JSON.stringify({ version: 2, heartbeats: heartbeatsToSend }));
2652
+ // Store last sent date to prevent another being logged/sent for the same day.
2653
+ this._heartbeatsCache.lastSentHeartbeatDate = date;
2654
+ if (unsentEntries.length > 0) {
2655
+ // Store any unsent entries if they exist.
2656
+ this._heartbeatsCache.heartbeats = unsentEntries;
2657
+ // This seems more likely than emptying the array (below) to lead to some odd state
2658
+ // since the cache isn't empty and this will be called again on the next request,
2659
+ // and is probably safest if we await it.
2660
+ await this._storage.overwrite(this._heartbeatsCache);
2661
+ }
2662
+ else {
2663
+ this._heartbeatsCache.heartbeats = [];
2664
+ // Do not wait for this, to reduce latency.
2665
+ void this._storage.overwrite(this._heartbeatsCache);
2666
+ }
2667
+ return headerString;
2595
2668
  }
2596
- // If it's still null or the array is empty, there is no data to send.
2597
- if (this._heartbeatsCache === null ||
2598
- this._heartbeatsCache.heartbeats.length === 0) {
2669
+ catch (e) {
2670
+ logger.warn(e);
2599
2671
  return '';
2600
2672
  }
2601
- const date = getUTCDateString();
2602
- // Extract as many heartbeats from the cache as will fit under the size limit.
2603
- const { heartbeatsToSend, unsentEntries } = extractHeartbeatsForHeader(this._heartbeatsCache.heartbeats);
2604
- const headerString = base64urlEncodeWithoutPadding$1(JSON.stringify({ version: 2, heartbeats: heartbeatsToSend }));
2605
- // Store last sent date to prevent another being logged/sent for the same day.
2606
- this._heartbeatsCache.lastSentHeartbeatDate = date;
2607
- if (unsentEntries.length > 0) {
2608
- // Store any unsent entries if they exist.
2609
- this._heartbeatsCache.heartbeats = unsentEntries;
2610
- // This seems more likely than emptying the array (below) to lead to some odd state
2611
- // since the cache isn't empty and this will be called again on the next request,
2612
- // and is probably safest if we await it.
2613
- await this._storage.overwrite(this._heartbeatsCache);
2614
- }
2615
- else {
2616
- this._heartbeatsCache.heartbeats = [];
2617
- // Do not wait for this, to reduce latency.
2618
- void this._storage.overwrite(this._heartbeatsCache);
2619
- }
2620
- return headerString;
2621
2673
  }
2622
2674
  }
2623
2675
  function getUTCDateString() {
@@ -2690,7 +2742,12 @@ class HeartbeatStorageImpl {
2690
2742
  }
2691
2743
  else {
2692
2744
  const idbHeartbeatObject = await readHeartbeatsFromIndexedDB(this.app);
2693
- return idbHeartbeatObject || { heartbeats: [] };
2745
+ if (idbHeartbeatObject === null || idbHeartbeatObject === void 0 ? void 0 : idbHeartbeatObject.heartbeats) {
2746
+ return idbHeartbeatObject;
2747
+ }
2748
+ else {
2749
+ return { heartbeats: [] };
2750
+ }
2694
2751
  }
2695
2752
  }
2696
2753
  // overwrite the storage with the provided heartbeats
@@ -2759,9 +2816,9 @@ function registerCoreComponents(variant) {
2759
2816
  _registerComponent(new Component$1('platform-logger', container => new PlatformLoggerServiceImpl(container), "PRIVATE" /* ComponentType.PRIVATE */));
2760
2817
  _registerComponent(new Component$1('heartbeat', container => new HeartbeatServiceImpl(container), "PRIVATE" /* ComponentType.PRIVATE */));
2761
2818
  // Register `app` package.
2762
- registerVersion(name$o, version$1$1, variant);
2819
+ registerVersion(name$p, version$1$1, variant);
2763
2820
  // BUILD_TARGET will be replaced by values like esm5, esm2017, cjs5, etc during the compilation
2764
- registerVersion(name$o, version$1$1, 'esm2017');
2821
+ registerVersion(name$p, version$1$1, 'esm2017');
2765
2822
  // Register platform SDK identifier (no version).
2766
2823
  registerVersion('fire-js', '');
2767
2824
  }
@@ -17828,7 +17885,7 @@ function jl(t, ...e) {
17828
17885
  }();
17829
17886
 
17830
17887
  var name$1 = "firebase";
17831
- var version$1 = "9.23.0";
17888
+ var version$1 = "10.13.0";
17832
17889
 
17833
17890
  /**
17834
17891
  * @license
@@ -18644,6 +18701,7 @@ const AUTH_ERROR_CODES_MAP_DO_NOT_USE_INTERNALLY = {
18644
18701
  INVALID_EMAIL: 'auth/invalid-email',
18645
18702
  INVALID_EMULATOR_SCHEME: 'auth/invalid-emulator-scheme',
18646
18703
  INVALID_IDP_RESPONSE: 'auth/invalid-credential',
18704
+ INVALID_LOGIN_CREDENTIALS: 'auth/invalid-credential',
18647
18705
  INVALID_MESSAGE_PAYLOAD: 'auth/invalid-message-payload',
18648
18706
  INVALID_MFA_SESSION: 'auth/invalid-multi-factor-session',
18649
18707
  INVALID_OAUTH_CLIENT_ID: 'auth/invalid-oauth-client-id',
@@ -18773,6 +18831,9 @@ function _errorWithCustomMessage(auth, code, message) {
18773
18831
  appName: auth.name
18774
18832
  });
18775
18833
  }
18834
+ function _serverAppCurrentUserOperationNotSupportedError(auth) {
18835
+ return _errorWithCustomMessage(auth, "operation-not-supported-in-this-environment" /* AuthErrorCode.OPERATION_NOT_SUPPORTED */, 'Operations that alter the current user are not supported in conjunction with FirebaseServerApp');
18836
+ }
18776
18837
  function createErrorInternal(authOrCode, ...rest) {
18777
18838
  if (typeof authOrCode !== 'string') {
18778
18839
  const code = rest[0];
@@ -18996,6 +19057,12 @@ class FetchProvider {
18996
19057
  if (typeof self !== 'undefined' && 'fetch' in self) {
18997
19058
  return self.fetch;
18998
19059
  }
19060
+ if (typeof globalThis !== 'undefined' && globalThis.fetch) {
19061
+ return globalThis.fetch;
19062
+ }
19063
+ if (typeof fetch !== 'undefined') {
19064
+ return fetch;
19065
+ }
18999
19066
  debugFail('Could not find fetch implementation, make sure you call FetchProvider.initialize() with an appropriate polyfill');
19000
19067
  }
19001
19068
  static headers() {
@@ -19005,6 +19072,12 @@ class FetchProvider {
19005
19072
  if (typeof self !== 'undefined' && 'Headers' in self) {
19006
19073
  return self.Headers;
19007
19074
  }
19075
+ if (typeof globalThis !== 'undefined' && globalThis.Headers) {
19076
+ return globalThis.Headers;
19077
+ }
19078
+ if (typeof Headers !== 'undefined') {
19079
+ return Headers;
19080
+ }
19008
19081
  debugFail('Could not find Headers implementation, make sure you call FetchProvider.initialize() with an appropriate polyfill');
19009
19082
  }
19010
19083
  static response() {
@@ -19014,6 +19087,12 @@ class FetchProvider {
19014
19087
  if (typeof self !== 'undefined' && 'Response' in self) {
19015
19088
  return self.Response;
19016
19089
  }
19090
+ if (typeof globalThis !== 'undefined' && globalThis.Response) {
19091
+ return globalThis.Response;
19092
+ }
19093
+ if (typeof Response !== 'undefined') {
19094
+ return Response;
19095
+ }
19017
19096
  debugFail('Could not find Response implementation, make sure you call FetchProvider.initialize() with an appropriate polyfill');
19018
19097
  }
19019
19098
  }
@@ -19050,12 +19129,15 @@ const SERVER_ERROR_MAP = {
19050
19129
  ["INVALID_PASSWORD" /* ServerError.INVALID_PASSWORD */]: "wrong-password" /* AuthErrorCode.INVALID_PASSWORD */,
19051
19130
  // This can only happen if the SDK sends a bad request.
19052
19131
  ["MISSING_PASSWORD" /* ServerError.MISSING_PASSWORD */]: "missing-password" /* AuthErrorCode.MISSING_PASSWORD */,
19132
+ // Thrown if Email Enumeration Protection is enabled in the project and the email or password is
19133
+ // invalid.
19134
+ ["INVALID_LOGIN_CREDENTIALS" /* ServerError.INVALID_LOGIN_CREDENTIALS */]: "invalid-credential" /* AuthErrorCode.INVALID_CREDENTIAL */,
19053
19135
  // Sign up with email and password errors.
19054
19136
  ["EMAIL_EXISTS" /* ServerError.EMAIL_EXISTS */]: "email-already-in-use" /* AuthErrorCode.EMAIL_EXISTS */,
19055
19137
  ["PASSWORD_LOGIN_DISABLED" /* ServerError.PASSWORD_LOGIN_DISABLED */]: "operation-not-allowed" /* AuthErrorCode.OPERATION_NOT_ALLOWED */,
19056
19138
  // Verify assertion for sign in with credential errors:
19057
- ["INVALID_IDP_RESPONSE" /* ServerError.INVALID_IDP_RESPONSE */]: "invalid-credential" /* AuthErrorCode.INVALID_IDP_RESPONSE */,
19058
- ["INVALID_PENDING_TOKEN" /* ServerError.INVALID_PENDING_TOKEN */]: "invalid-credential" /* AuthErrorCode.INVALID_IDP_RESPONSE */,
19139
+ ["INVALID_IDP_RESPONSE" /* ServerError.INVALID_IDP_RESPONSE */]: "invalid-credential" /* AuthErrorCode.INVALID_CREDENTIAL */,
19140
+ ["INVALID_PENDING_TOKEN" /* ServerError.INVALID_PENDING_TOKEN */]: "invalid-credential" /* AuthErrorCode.INVALID_CREDENTIAL */,
19059
19141
  ["FEDERATED_USER_ID_ALREADY_LINKED" /* ServerError.FEDERATED_USER_ID_ALREADY_LINKED */]: "credential-already-in-use" /* AuthErrorCode.CREDENTIAL_ALREADY_IN_USE */,
19060
19142
  // This can only happen if the SDK sends a bad request.
19061
19143
  ["MISSING_REQ_TYPE" /* ServerError.MISSING_REQ_TYPE */]: "internal-error" /* AuthErrorCode.INTERNAL_ERROR */,
@@ -19073,10 +19155,11 @@ const SERVER_ERROR_MAP = {
19073
19155
  ["USER_NOT_FOUND" /* ServerError.USER_NOT_FOUND */]: "user-token-expired" /* AuthErrorCode.TOKEN_EXPIRED */,
19074
19156
  // Other errors.
19075
19157
  ["TOO_MANY_ATTEMPTS_TRY_LATER" /* ServerError.TOO_MANY_ATTEMPTS_TRY_LATER */]: "too-many-requests" /* AuthErrorCode.TOO_MANY_ATTEMPTS_TRY_LATER */,
19158
+ ["PASSWORD_DOES_NOT_MEET_REQUIREMENTS" /* ServerError.PASSWORD_DOES_NOT_MEET_REQUIREMENTS */]: "password-does-not-meet-requirements" /* AuthErrorCode.PASSWORD_DOES_NOT_MEET_REQUIREMENTS */,
19076
19159
  // Phone Auth related errors.
19077
19160
  ["INVALID_CODE" /* ServerError.INVALID_CODE */]: "invalid-verification-code" /* AuthErrorCode.INVALID_CODE */,
19078
19161
  ["INVALID_SESSION_INFO" /* ServerError.INVALID_SESSION_INFO */]: "invalid-verification-id" /* AuthErrorCode.INVALID_SESSION_INFO */,
19079
- ["INVALID_TEMPORARY_PROOF" /* ServerError.INVALID_TEMPORARY_PROOF */]: "invalid-credential" /* AuthErrorCode.INVALID_IDP_RESPONSE */,
19162
+ ["INVALID_TEMPORARY_PROOF" /* ServerError.INVALID_TEMPORARY_PROOF */]: "invalid-credential" /* AuthErrorCode.INVALID_CREDENTIAL */,
19080
19163
  ["MISSING_SESSION_INFO" /* ServerError.MISSING_SESSION_INFO */]: "missing-verification-id" /* AuthErrorCode.MISSING_SESSION_INFO */,
19081
19164
  ["SESSION_EXPIRED" /* ServerError.SESSION_EXPIRED */]: "code-expired" /* AuthErrorCode.CODE_EXPIRED */,
19082
19165
  // Other action code errors when additional settings passed.
@@ -19224,6 +19307,18 @@ function _getFinalTarget(auth, host, path, query) {
19224
19307
  }
19225
19308
  return _emulatorUrl(auth.config, base);
19226
19309
  }
19310
+ function _parseEnforcementState(enforcementStateStr) {
19311
+ switch (enforcementStateStr) {
19312
+ case 'ENFORCE':
19313
+ return "ENFORCE" /* EnforcementState.ENFORCE */;
19314
+ case 'AUDIT':
19315
+ return "AUDIT" /* EnforcementState.AUDIT */;
19316
+ case 'OFF':
19317
+ return "OFF" /* EnforcementState.OFF */;
19318
+ default:
19319
+ return "ENFORCEMENT_STATE_UNSPECIFIED" /* EnforcementState.ENFORCEMENT_STATE_UNSPECIFIED */;
19320
+ }
19321
+ }
19227
19322
  class NetworkTimeout {
19228
19323
  constructor(auth) {
19229
19324
  this.auth = auth;
@@ -19256,6 +19351,61 @@ function _makeTaggedError(auth, code, response) {
19256
19351
  error.customData._tokenResponse = response;
19257
19352
  return error;
19258
19353
  }
19354
+ function isEnterprise(grecaptcha) {
19355
+ return (grecaptcha !== undefined &&
19356
+ grecaptcha.enterprise !== undefined);
19357
+ }
19358
+ class RecaptchaConfig {
19359
+ constructor(response) {
19360
+ /**
19361
+ * The reCAPTCHA site key.
19362
+ */
19363
+ this.siteKey = '';
19364
+ /**
19365
+ * The list of providers and their enablement status for reCAPTCHA Enterprise.
19366
+ */
19367
+ this.recaptchaEnforcementState = [];
19368
+ if (response.recaptchaKey === undefined) {
19369
+ throw new Error('recaptchaKey undefined');
19370
+ }
19371
+ // Example response.recaptchaKey: "projects/proj123/keys/sitekey123"
19372
+ this.siteKey = response.recaptchaKey.split('/')[3];
19373
+ this.recaptchaEnforcementState = response.recaptchaEnforcementState;
19374
+ }
19375
+ /**
19376
+ * Returns the reCAPTCHA Enterprise enforcement state for the given provider.
19377
+ *
19378
+ * @param providerStr - The provider whose enforcement state is to be returned.
19379
+ * @returns The reCAPTCHA Enterprise enforcement state for the given provider.
19380
+ */
19381
+ getProviderEnforcementState(providerStr) {
19382
+ if (!this.recaptchaEnforcementState ||
19383
+ this.recaptchaEnforcementState.length === 0) {
19384
+ return null;
19385
+ }
19386
+ for (const recaptchaEnforcementState of this.recaptchaEnforcementState) {
19387
+ if (recaptchaEnforcementState.provider &&
19388
+ recaptchaEnforcementState.provider === providerStr) {
19389
+ return _parseEnforcementState(recaptchaEnforcementState.enforcementState);
19390
+ }
19391
+ }
19392
+ return null;
19393
+ }
19394
+ /**
19395
+ * Returns true if the reCAPTCHA Enterprise enforcement state for the provider is set to ENFORCE or AUDIT.
19396
+ *
19397
+ * @param providerStr - The provider whose enablement state is to be returned.
19398
+ * @returns Whether or not reCAPTCHA Enterprise protection is enabled for the given provider.
19399
+ */
19400
+ isProviderEnabled(providerStr) {
19401
+ return (this.getProviderEnforcementState(providerStr) ===
19402
+ "ENFORCE" /* EnforcementState.ENFORCE */ ||
19403
+ this.getProviderEnforcementState(providerStr) === "AUDIT" /* EnforcementState.AUDIT */);
19404
+ }
19405
+ }
19406
+ async function getRecaptchaConfig(auth, request) {
19407
+ return _performApiRequest(auth, "GET" /* HttpMethod.GET */, "/v2/recaptchaConfig" /* Endpoint.GET_RECAPTCHA_CONFIG */, _addTidIfNecessary(auth, request));
19408
+ }
19259
19409
 
19260
19410
  /**
19261
19411
  * @license
@@ -19660,6 +19810,9 @@ async function requestStsToken(auth, refreshToken) {
19660
19810
  expiresIn: response.expires_in,
19661
19811
  refreshToken: response.refresh_token
19662
19812
  };
19813
+ }
19814
+ async function revokeToken(auth, request) {
19815
+ return _performApiRequest(auth, "POST" /* HttpMethod.POST */, "/v2/accounts:revokeToken" /* Endpoint.REVOKE_TOKEN */, _addTidIfNecessary(auth, request));
19663
19816
  }
19664
19817
 
19665
19818
  /**
@@ -19703,11 +19856,16 @@ class StsTokenManager {
19703
19856
  : _tokenExpiresIn(response.idToken);
19704
19857
  this.updateTokensAndExpiration(response.idToken, response.refreshToken, expiresIn);
19705
19858
  }
19859
+ updateFromIdToken(idToken) {
19860
+ _assert(idToken.length !== 0, "internal-error" /* AuthErrorCode.INTERNAL_ERROR */);
19861
+ const expiresIn = _tokenExpiresIn(idToken);
19862
+ this.updateTokensAndExpiration(idToken, null, expiresIn);
19863
+ }
19706
19864
  async getToken(auth, forceRefresh = false) {
19707
- _assert(!this.accessToken || this.refreshToken, auth, "user-token-expired" /* AuthErrorCode.TOKEN_EXPIRED */);
19708
19865
  if (!forceRefresh && this.accessToken && !this.isExpired) {
19709
19866
  return this.accessToken;
19710
19867
  }
19868
+ _assert(this.refreshToken, auth, "user-token-expired" /* AuthErrorCode.TOKEN_EXPIRED */);
19711
19869
  if (this.refreshToken) {
19712
19870
  await this.refresh(auth, this.refreshToken);
19713
19871
  return this.accessToken;
@@ -19887,6 +20045,9 @@ class UserImpl {
19887
20045
  }
19888
20046
  }
19889
20047
  async delete() {
20048
+ if (_isFirebaseServerApp(this.auth.app)) {
20049
+ return Promise.reject(_serverAppCurrentUserOperationNotSupportedError(this.auth));
20050
+ }
19890
20051
  const idToken = await this.getIdToken();
19891
20052
  await _logoutIfInvalidated(this, deleteAccount(this.auth, { idToken }));
19892
20053
  this.stsTokenManager.clearRefreshToken();
@@ -19970,6 +20131,44 @@ class UserImpl {
19970
20131
  await _reloadWithoutSaving(user);
19971
20132
  return user;
19972
20133
  }
20134
+ /**
20135
+ * Initialize a User from an idToken server response
20136
+ * @param auth
20137
+ * @param idTokenResponse
20138
+ */
20139
+ static async _fromGetAccountInfoResponse(auth, response, idToken) {
20140
+ const coreAccount = response.users[0];
20141
+ _assert(coreAccount.localId !== undefined, "internal-error" /* AuthErrorCode.INTERNAL_ERROR */);
20142
+ const providerData = coreAccount.providerUserInfo !== undefined
20143
+ ? extractProviderData(coreAccount.providerUserInfo)
20144
+ : [];
20145
+ const isAnonymous = !(coreAccount.email && coreAccount.passwordHash) && !(providerData === null || providerData === void 0 ? void 0 : providerData.length);
20146
+ const stsTokenManager = new StsTokenManager();
20147
+ stsTokenManager.updateFromIdToken(idToken);
20148
+ // Initialize the Firebase Auth user.
20149
+ const user = new UserImpl({
20150
+ uid: coreAccount.localId,
20151
+ auth,
20152
+ stsTokenManager,
20153
+ isAnonymous
20154
+ });
20155
+ // update the user with data from the GetAccountInfo response.
20156
+ const updates = {
20157
+ uid: coreAccount.localId,
20158
+ displayName: coreAccount.displayName || null,
20159
+ photoURL: coreAccount.photoUrl || null,
20160
+ email: coreAccount.email || null,
20161
+ emailVerified: coreAccount.emailVerified || false,
20162
+ phoneNumber: coreAccount.phoneNumber || null,
20163
+ tenantId: coreAccount.tenantId || null,
20164
+ providerData,
20165
+ metadata: new UserMetadata(coreAccount.createdAt, coreAccount.lastLoginAt),
20166
+ isAnonymous: !(coreAccount.email && coreAccount.passwordHash) &&
20167
+ !(providerData === null || providerData === void 0 ? void 0 : providerData.length)
20168
+ };
20169
+ Object.assign(user, updates);
20170
+ return user;
20171
+ }
19973
20172
  }
19974
20173
 
19975
20174
  /**
@@ -20285,16 +20484,6 @@ function _isMobileBrowser(ua = getUA()) {
20285
20484
  _isBlackBerry(ua) ||
20286
20485
  /windows phone/i.test(ua) ||
20287
20486
  _isIEMobile(ua));
20288
- }
20289
- function _isIframe() {
20290
- try {
20291
- // Check that the current window is not the top window.
20292
- // If so, return true.
20293
- return !!(window && window !== window.top);
20294
- }
20295
- catch (e) {
20296
- return false;
20297
- }
20298
20487
  }
20299
20488
 
20300
20489
  /**
@@ -20337,36 +20526,91 @@ function _getClientVersion(clientPlatform, frameworks = []) {
20337
20526
  : 'FirebaseCore-web'; /* default value if no other framework is used */
20338
20527
  return `${reportedPlatform}/${"JsCore" /* ClientImplementation.CORE */}/${SDK_VERSION}/${reportedFrameworks}`;
20339
20528
  }
20340
- async function getRecaptchaConfig(auth, request) {
20341
- return _performApiRequest(auth, "GET" /* HttpMethod.GET */, "/v2/recaptchaConfig" /* Endpoint.GET_RECAPTCHA_CONFIG */, _addTidIfNecessary(auth, request));
20342
- }
20343
- function isEnterprise(grecaptcha) {
20344
- return (grecaptcha !== undefined &&
20345
- grecaptcha.enterprise !== undefined);
20346
- }
20347
- class RecaptchaConfig {
20348
- constructor(response) {
20349
- /**
20350
- * The reCAPTCHA site key.
20351
- */
20352
- this.siteKey = '';
20353
- /**
20354
- * The reCAPTCHA enablement status of the {@link EmailAuthProvider} for the current tenant.
20355
- */
20356
- this.emailPasswordEnabled = false;
20357
- if (response.recaptchaKey === undefined) {
20358
- throw new Error('recaptchaKey undefined');
20529
+
20530
+ /**
20531
+ * @license
20532
+ * Copyright 2022 Google LLC
20533
+ *
20534
+ * Licensed under the Apache License, Version 2.0 (the "License");
20535
+ * you may not use this file except in compliance with the License.
20536
+ * You may obtain a copy of the License at
20537
+ *
20538
+ * http://www.apache.org/licenses/LICENSE-2.0
20539
+ *
20540
+ * Unless required by applicable law or agreed to in writing, software
20541
+ * distributed under the License is distributed on an "AS IS" BASIS,
20542
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20543
+ * See the License for the specific language governing permissions and
20544
+ * limitations under the License.
20545
+ */
20546
+ class AuthMiddlewareQueue {
20547
+ constructor(auth) {
20548
+ this.auth = auth;
20549
+ this.queue = [];
20550
+ }
20551
+ pushCallback(callback, onAbort) {
20552
+ // The callback could be sync or async. Wrap it into a
20553
+ // function that is always async.
20554
+ const wrappedCallback = (user) => new Promise((resolve, reject) => {
20555
+ try {
20556
+ const result = callback(user);
20557
+ // Either resolve with existing promise or wrap a non-promise
20558
+ // return value into a promise.
20559
+ resolve(result);
20560
+ }
20561
+ catch (e) {
20562
+ // Sync callback throws.
20563
+ reject(e);
20564
+ }
20565
+ });
20566
+ // Attach the onAbort if present
20567
+ wrappedCallback.onAbort = onAbort;
20568
+ this.queue.push(wrappedCallback);
20569
+ const index = this.queue.length - 1;
20570
+ return () => {
20571
+ // Unsubscribe. Replace with no-op. Do not remove from array, or it will disturb
20572
+ // indexing of other elements.
20573
+ this.queue[index] = () => Promise.resolve();
20574
+ };
20575
+ }
20576
+ async runMiddleware(nextUser) {
20577
+ if (this.auth.currentUser === nextUser) {
20578
+ return;
20579
+ }
20580
+ // While running the middleware, build a temporary stack of onAbort
20581
+ // callbacks to call if one middleware callback rejects.
20582
+ const onAbortStack = [];
20583
+ try {
20584
+ for (const beforeStateCallback of this.queue) {
20585
+ await beforeStateCallback(nextUser);
20586
+ // Only push the onAbort if the callback succeeds
20587
+ if (beforeStateCallback.onAbort) {
20588
+ onAbortStack.push(beforeStateCallback.onAbort);
20589
+ }
20590
+ }
20591
+ }
20592
+ catch (e) {
20593
+ // Run all onAbort, with separate try/catch to ignore any errors and
20594
+ // continue
20595
+ onAbortStack.reverse();
20596
+ for (const onAbort of onAbortStack) {
20597
+ try {
20598
+ onAbort();
20599
+ }
20600
+ catch (_) {
20601
+ /* swallow error */
20602
+ }
20603
+ }
20604
+ throw this.auth._errorFactory.create("login-blocked" /* AuthErrorCode.LOGIN_BLOCKED */, {
20605
+ originalMessage: e === null || e === void 0 ? void 0 : e.message
20606
+ });
20359
20607
  }
20360
- // Example response.recaptchaKey: "projects/proj123/keys/sitekey123"
20361
- this.siteKey = response.recaptchaKey.split('/')[3];
20362
- this.emailPasswordEnabled = response.recaptchaEnforcementState.some(enforcementState => enforcementState.provider === 'EMAIL_PASSWORD_PROVIDER' &&
20363
- enforcementState.enforcementState !== 'OFF');
20364
20608
  }
20365
20609
  }
20366
20610
 
20367
20611
  /**
20368
20612
  * @license
20369
- * Copyright 2020 Google LLC
20613
+ * Copyright 2023 Google LLC
20370
20614
  *
20371
20615
  * Licensed under the Apache License, Version 2.0 (the "License");
20372
20616
  * you may not use this file except in compliance with the License.
@@ -20380,232 +20624,162 @@ class RecaptchaConfig {
20380
20624
  * See the License for the specific language governing permissions and
20381
20625
  * limitations under the License.
20382
20626
  */
20383
- function getScriptParentElement() {
20384
- var _a, _b;
20385
- return (_b = (_a = document.getElementsByTagName('head')) === null || _a === void 0 ? void 0 : _a[0]) !== null && _b !== void 0 ? _b : document;
20386
- }
20387
- function _loadJS(url) {
20388
- // TODO: consider adding timeout support & cancellation
20389
- return new Promise((resolve, reject) => {
20390
- const el = document.createElement('script');
20391
- el.setAttribute('src', url);
20392
- el.onload = resolve;
20393
- el.onerror = e => {
20394
- const error = _createError("internal-error" /* AuthErrorCode.INTERNAL_ERROR */);
20395
- error.customData = e;
20396
- reject(error);
20397
- };
20398
- el.type = 'text/javascript';
20399
- el.charset = 'UTF-8';
20400
- getScriptParentElement().appendChild(el);
20401
- });
20402
- }
20403
- function _generateCallbackName(prefix) {
20404
- return `__${prefix}${Math.floor(Math.random() * 1000000)}`;
20627
+ /**
20628
+ * Fetches the password policy for the currently set tenant or the project if no tenant is set.
20629
+ *
20630
+ * @param auth Auth object.
20631
+ * @param request Password policy request.
20632
+ * @returns Password policy response.
20633
+ */
20634
+ async function _getPasswordPolicy(auth, request = {}) {
20635
+ return _performApiRequest(auth, "GET" /* HttpMethod.GET */, "/v2/passwordPolicy" /* Endpoint.GET_PASSWORD_POLICY */, _addTidIfNecessary(auth, request));
20405
20636
  }
20406
20637
 
20407
- /* eslint-disable @typescript-eslint/no-require-imports */
20408
- const RECAPTCHA_ENTERPRISE_URL = 'https://www.google.com/recaptcha/enterprise.js?render=';
20409
- const RECAPTCHA_ENTERPRISE_VERIFIER_TYPE = 'recaptcha-enterprise';
20410
- const FAKE_TOKEN = 'NO_RECAPTCHA';
20411
- class RecaptchaEnterpriseVerifier {
20638
+ /**
20639
+ * @license
20640
+ * Copyright 2023 Google LLC
20641
+ *
20642
+ * Licensed under the Apache License, Version 2.0 (the "License");
20643
+ * you may not use this file except in compliance with the License.
20644
+ * You may obtain a copy of the License at
20645
+ *
20646
+ * http://www.apache.org/licenses/LICENSE-2.0
20647
+ *
20648
+ * Unless required by applicable law or agreed to in writing, software
20649
+ * distributed under the License is distributed on an "AS IS" BASIS,
20650
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20651
+ * See the License for the specific language governing permissions and
20652
+ * limitations under the License.
20653
+ */
20654
+ // Minimum min password length enforced by the backend, even if no minimum length is set.
20655
+ const MINIMUM_MIN_PASSWORD_LENGTH = 6;
20656
+ /**
20657
+ * Stores password policy requirements and provides password validation against the policy.
20658
+ *
20659
+ * @internal
20660
+ */
20661
+ class PasswordPolicyImpl {
20662
+ constructor(response) {
20663
+ var _a, _b, _c, _d;
20664
+ // Only include custom strength options defined in the response.
20665
+ const responseOptions = response.customStrengthOptions;
20666
+ this.customStrengthOptions = {};
20667
+ // TODO: Remove once the backend is updated to include the minimum min password length instead of undefined when there is no minimum length set.
20668
+ this.customStrengthOptions.minPasswordLength =
20669
+ (_a = responseOptions.minPasswordLength) !== null && _a !== void 0 ? _a : MINIMUM_MIN_PASSWORD_LENGTH;
20670
+ if (responseOptions.maxPasswordLength) {
20671
+ this.customStrengthOptions.maxPasswordLength =
20672
+ responseOptions.maxPasswordLength;
20673
+ }
20674
+ if (responseOptions.containsLowercaseCharacter !== undefined) {
20675
+ this.customStrengthOptions.containsLowercaseLetter =
20676
+ responseOptions.containsLowercaseCharacter;
20677
+ }
20678
+ if (responseOptions.containsUppercaseCharacter !== undefined) {
20679
+ this.customStrengthOptions.containsUppercaseLetter =
20680
+ responseOptions.containsUppercaseCharacter;
20681
+ }
20682
+ if (responseOptions.containsNumericCharacter !== undefined) {
20683
+ this.customStrengthOptions.containsNumericCharacter =
20684
+ responseOptions.containsNumericCharacter;
20685
+ }
20686
+ if (responseOptions.containsNonAlphanumericCharacter !== undefined) {
20687
+ this.customStrengthOptions.containsNonAlphanumericCharacter =
20688
+ responseOptions.containsNonAlphanumericCharacter;
20689
+ }
20690
+ this.enforcementState = response.enforcementState;
20691
+ if (this.enforcementState === 'ENFORCEMENT_STATE_UNSPECIFIED') {
20692
+ this.enforcementState = 'OFF';
20693
+ }
20694
+ // Use an empty string if no non-alphanumeric characters are specified in the response.
20695
+ this.allowedNonAlphanumericCharacters =
20696
+ (_c = (_b = response.allowedNonAlphanumericCharacters) === null || _b === void 0 ? void 0 : _b.join('')) !== null && _c !== void 0 ? _c : '';
20697
+ this.forceUpgradeOnSignin = (_d = response.forceUpgradeOnSignin) !== null && _d !== void 0 ? _d : false;
20698
+ this.schemaVersion = response.schemaVersion;
20699
+ }
20700
+ validatePassword(password) {
20701
+ var _a, _b, _c, _d, _e, _f;
20702
+ const status = {
20703
+ isValid: true,
20704
+ passwordPolicy: this
20705
+ };
20706
+ // Check the password length and character options.
20707
+ this.validatePasswordLengthOptions(password, status);
20708
+ this.validatePasswordCharacterOptions(password, status);
20709
+ // Combine the status into single isValid property.
20710
+ status.isValid && (status.isValid = (_a = status.meetsMinPasswordLength) !== null && _a !== void 0 ? _a : true);
20711
+ status.isValid && (status.isValid = (_b = status.meetsMaxPasswordLength) !== null && _b !== void 0 ? _b : true);
20712
+ status.isValid && (status.isValid = (_c = status.containsLowercaseLetter) !== null && _c !== void 0 ? _c : true);
20713
+ status.isValid && (status.isValid = (_d = status.containsUppercaseLetter) !== null && _d !== void 0 ? _d : true);
20714
+ status.isValid && (status.isValid = (_e = status.containsNumericCharacter) !== null && _e !== void 0 ? _e : true);
20715
+ status.isValid && (status.isValid = (_f = status.containsNonAlphanumericCharacter) !== null && _f !== void 0 ? _f : true);
20716
+ return status;
20717
+ }
20412
20718
  /**
20719
+ * Validates that the password meets the length options for the policy.
20413
20720
  *
20414
- * @param authExtern - The corresponding Firebase {@link Auth} instance.
20415
- *
20721
+ * @param password Password to validate.
20722
+ * @param status Validation status.
20416
20723
  */
20417
- constructor(authExtern) {
20418
- /**
20419
- * Identifies the type of application verifier (e.g. "recaptcha-enterprise").
20420
- */
20421
- this.type = RECAPTCHA_ENTERPRISE_VERIFIER_TYPE;
20422
- this.auth = _castAuth(authExtern);
20724
+ validatePasswordLengthOptions(password, status) {
20725
+ const minPasswordLength = this.customStrengthOptions.minPasswordLength;
20726
+ const maxPasswordLength = this.customStrengthOptions.maxPasswordLength;
20727
+ if (minPasswordLength) {
20728
+ status.meetsMinPasswordLength = password.length >= minPasswordLength;
20729
+ }
20730
+ if (maxPasswordLength) {
20731
+ status.meetsMaxPasswordLength = password.length <= maxPasswordLength;
20732
+ }
20423
20733
  }
20424
20734
  /**
20425
- * Executes the verification process.
20735
+ * Validates that the password meets the character options for the policy.
20426
20736
  *
20427
- * @returns A Promise for a token that can be used to assert the validity of a request.
20737
+ * @param password Password to validate.
20738
+ * @param status Validation status.
20428
20739
  */
20429
- async verify(action = 'verify', forceRefresh = false) {
20430
- async function retrieveSiteKey(auth) {
20431
- if (!forceRefresh) {
20432
- if (auth.tenantId == null && auth._agentRecaptchaConfig != null) {
20433
- return auth._agentRecaptchaConfig.siteKey;
20434
- }
20435
- if (auth.tenantId != null &&
20436
- auth._tenantRecaptchaConfigs[auth.tenantId] !== undefined) {
20437
- return auth._tenantRecaptchaConfigs[auth.tenantId].siteKey;
20438
- }
20439
- }
20440
- return new Promise(async (resolve, reject) => {
20441
- getRecaptchaConfig(auth, {
20442
- clientType: "CLIENT_TYPE_WEB" /* RecaptchaClientType.WEB */,
20443
- version: "RECAPTCHA_ENTERPRISE" /* RecaptchaVersion.ENTERPRISE */
20444
- })
20445
- .then(response => {
20446
- if (response.recaptchaKey === undefined) {
20447
- reject(new Error('recaptcha Enterprise site key undefined'));
20448
- }
20449
- else {
20450
- const config = new RecaptchaConfig(response);
20451
- if (auth.tenantId == null) {
20452
- auth._agentRecaptchaConfig = config;
20453
- }
20454
- else {
20455
- auth._tenantRecaptchaConfigs[auth.tenantId] = config;
20456
- }
20457
- return resolve(config.siteKey);
20458
- }
20459
- })
20460
- .catch(error => {
20461
- reject(error);
20462
- });
20463
- });
20740
+ validatePasswordCharacterOptions(password, status) {
20741
+ // Assign statuses for requirements even if the password is an empty string.
20742
+ this.updatePasswordCharacterOptionsStatuses(status,
20743
+ /* containsLowercaseCharacter= */ false,
20744
+ /* containsUppercaseCharacter= */ false,
20745
+ /* containsNumericCharacter= */ false,
20746
+ /* containsNonAlphanumericCharacter= */ false);
20747
+ let passwordChar;
20748
+ for (let i = 0; i < password.length; i++) {
20749
+ passwordChar = password.charAt(i);
20750
+ this.updatePasswordCharacterOptionsStatuses(status,
20751
+ /* containsLowercaseCharacter= */ passwordChar >= 'a' &&
20752
+ passwordChar <= 'z',
20753
+ /* containsUppercaseCharacter= */ passwordChar >= 'A' &&
20754
+ passwordChar <= 'Z',
20755
+ /* containsNumericCharacter= */ passwordChar >= '0' &&
20756
+ passwordChar <= '9',
20757
+ /* containsNonAlphanumericCharacter= */ this.allowedNonAlphanumericCharacters.includes(passwordChar));
20464
20758
  }
20465
- function retrieveRecaptchaToken(siteKey, resolve, reject) {
20466
- const grecaptcha = window.grecaptcha;
20467
- if (isEnterprise(grecaptcha)) {
20468
- grecaptcha.enterprise.ready(() => {
20469
- grecaptcha.enterprise
20470
- .execute(siteKey, { action })
20471
- .then(token => {
20472
- resolve(token);
20473
- })
20474
- .catch(() => {
20475
- resolve(FAKE_TOKEN);
20476
- });
20477
- });
20478
- }
20479
- else {
20480
- reject(Error('No reCAPTCHA enterprise script loaded.'));
20481
- }
20482
- }
20483
- return new Promise((resolve, reject) => {
20484
- retrieveSiteKey(this.auth)
20485
- .then(siteKey => {
20486
- if (!forceRefresh && isEnterprise(window.grecaptcha)) {
20487
- retrieveRecaptchaToken(siteKey, resolve, reject);
20488
- }
20489
- else {
20490
- if (typeof window === 'undefined') {
20491
- reject(new Error('RecaptchaVerifier is only supported in browser'));
20492
- return;
20493
- }
20494
- _loadJS(RECAPTCHA_ENTERPRISE_URL + siteKey)
20495
- .then(() => {
20496
- retrieveRecaptchaToken(siteKey, resolve, reject);
20497
- })
20498
- .catch(error => {
20499
- reject(error);
20500
- });
20501
- }
20502
- })
20503
- .catch(error => {
20504
- reject(error);
20505
- });
20506
- });
20507
- }
20508
- }
20509
- async function injectRecaptchaFields(auth, request, action, captchaResp = false) {
20510
- const verifier = new RecaptchaEnterpriseVerifier(auth);
20511
- let captchaResponse;
20512
- try {
20513
- captchaResponse = await verifier.verify(action);
20514
- }
20515
- catch (error) {
20516
- captchaResponse = await verifier.verify(action, true);
20517
- }
20518
- const newRequest = Object.assign({}, request);
20519
- if (!captchaResp) {
20520
- Object.assign(newRequest, { captchaResponse });
20521
- }
20522
- else {
20523
- Object.assign(newRequest, { 'captchaResp': captchaResponse });
20524
- }
20525
- Object.assign(newRequest, { 'clientType': "CLIENT_TYPE_WEB" /* RecaptchaClientType.WEB */ });
20526
- Object.assign(newRequest, {
20527
- 'recaptchaVersion': "RECAPTCHA_ENTERPRISE" /* RecaptchaVersion.ENTERPRISE */
20528
- });
20529
- return newRequest;
20530
- }
20531
-
20532
- /**
20533
- * @license
20534
- * Copyright 2022 Google LLC
20535
- *
20536
- * Licensed under the Apache License, Version 2.0 (the "License");
20537
- * you may not use this file except in compliance with the License.
20538
- * You may obtain a copy of the License at
20539
- *
20540
- * http://www.apache.org/licenses/LICENSE-2.0
20541
- *
20542
- * Unless required by applicable law or agreed to in writing, software
20543
- * distributed under the License is distributed on an "AS IS" BASIS,
20544
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20545
- * See the License for the specific language governing permissions and
20546
- * limitations under the License.
20547
- */
20548
- class AuthMiddlewareQueue {
20549
- constructor(auth) {
20550
- this.auth = auth;
20551
- this.queue = [];
20552
20759
  }
20553
- pushCallback(callback, onAbort) {
20554
- // The callback could be sync or async. Wrap it into a
20555
- // function that is always async.
20556
- const wrappedCallback = (user) => new Promise((resolve, reject) => {
20557
- try {
20558
- const result = callback(user);
20559
- // Either resolve with existing promise or wrap a non-promise
20560
- // return value into a promise.
20561
- resolve(result);
20562
- }
20563
- catch (e) {
20564
- // Sync callback throws.
20565
- reject(e);
20566
- }
20567
- });
20568
- // Attach the onAbort if present
20569
- wrappedCallback.onAbort = onAbort;
20570
- this.queue.push(wrappedCallback);
20571
- const index = this.queue.length - 1;
20572
- return () => {
20573
- // Unsubscribe. Replace with no-op. Do not remove from array, or it will disturb
20574
- // indexing of other elements.
20575
- this.queue[index] = () => Promise.resolve();
20576
- };
20577
- }
20578
- async runMiddleware(nextUser) {
20579
- if (this.auth.currentUser === nextUser) {
20580
- return;
20760
+ /**
20761
+ * Updates the running validation status with the statuses for the character options.
20762
+ * Expected to be called each time a character is processed to update each option status
20763
+ * based on the current character.
20764
+ *
20765
+ * @param status Validation status.
20766
+ * @param containsLowercaseCharacter Whether the character is a lowercase letter.
20767
+ * @param containsUppercaseCharacter Whether the character is an uppercase letter.
20768
+ * @param containsNumericCharacter Whether the character is a numeric character.
20769
+ * @param containsNonAlphanumericCharacter Whether the character is a non-alphanumeric character.
20770
+ */
20771
+ updatePasswordCharacterOptionsStatuses(status, containsLowercaseCharacter, containsUppercaseCharacter, containsNumericCharacter, containsNonAlphanumericCharacter) {
20772
+ if (this.customStrengthOptions.containsLowercaseLetter) {
20773
+ status.containsLowercaseLetter || (status.containsLowercaseLetter = containsLowercaseCharacter);
20581
20774
  }
20582
- // While running the middleware, build a temporary stack of onAbort
20583
- // callbacks to call if one middleware callback rejects.
20584
- const onAbortStack = [];
20585
- try {
20586
- for (const beforeStateCallback of this.queue) {
20587
- await beforeStateCallback(nextUser);
20588
- // Only push the onAbort if the callback succeeds
20589
- if (beforeStateCallback.onAbort) {
20590
- onAbortStack.push(beforeStateCallback.onAbort);
20591
- }
20592
- }
20775
+ if (this.customStrengthOptions.containsUppercaseLetter) {
20776
+ status.containsUppercaseLetter || (status.containsUppercaseLetter = containsUppercaseCharacter);
20593
20777
  }
20594
- catch (e) {
20595
- // Run all onAbort, with separate try/catch to ignore any errors and
20596
- // continue
20597
- onAbortStack.reverse();
20598
- for (const onAbort of onAbortStack) {
20599
- try {
20600
- onAbort();
20601
- }
20602
- catch (_) {
20603
- /* swallow error */
20604
- }
20605
- }
20606
- throw this.auth._errorFactory.create("login-blocked" /* AuthErrorCode.LOGIN_BLOCKED */, {
20607
- originalMessage: e === null || e === void 0 ? void 0 : e.message
20608
- });
20778
+ if (this.customStrengthOptions.containsNumericCharacter) {
20779
+ status.containsNumericCharacter || (status.containsNumericCharacter = containsNumericCharacter);
20780
+ }
20781
+ if (this.customStrengthOptions.containsNonAlphanumericCharacter) {
20782
+ status.containsNonAlphanumericCharacter || (status.containsNonAlphanumericCharacter = containsNonAlphanumericCharacter);
20609
20783
  }
20610
20784
  }
20611
20785
  }
@@ -20640,6 +20814,7 @@ class AuthImpl {
20640
20814
  this.beforeStateQueue = new AuthMiddlewareQueue(this);
20641
20815
  this.redirectUser = null;
20642
20816
  this.isProactiveRefreshEnabled = false;
20817
+ this.EXPECTED_PASSWORD_POLICY_SCHEMA_VERSION = 1;
20643
20818
  // Any network calls will set this to true and prevent subsequent emulator
20644
20819
  // initialization
20645
20820
  this._canInitEmulator = true;
@@ -20650,6 +20825,8 @@ class AuthImpl {
20650
20825
  this._errorFactory = _DEFAULT_AUTH_ERROR_FACTORY;
20651
20826
  this._agentRecaptchaConfig = null;
20652
20827
  this._tenantRecaptchaConfigs = {};
20828
+ this._projectPasswordPolicy = null;
20829
+ this._tenantPasswordPolicies = {};
20653
20830
  // Tracks the last notified UID for state change listeners to prevent
20654
20831
  // repeated calls to the callbacks. Undefined means it's never been
20655
20832
  // called, whereas null means it's been called with a signed out user
@@ -20721,8 +20898,32 @@ class AuthImpl {
20721
20898
  // Skip blocking callbacks, they should not apply to a change in another tab.
20722
20899
  await this._updateCurrentUser(user, /* skipBeforeStateCallbacks */ true);
20723
20900
  }
20901
+ async initializeCurrentUserFromIdToken(idToken) {
20902
+ try {
20903
+ const response = await getAccountInfo(this, { idToken });
20904
+ const user = await UserImpl._fromGetAccountInfoResponse(this, response, idToken);
20905
+ await this.directlySetCurrentUser(user);
20906
+ }
20907
+ catch (err) {
20908
+ console.warn('FirebaseServerApp could not login user with provided authIdToken: ', err);
20909
+ await this.directlySetCurrentUser(null);
20910
+ }
20911
+ }
20724
20912
  async initializeCurrentUser(popupRedirectResolver) {
20725
20913
  var _a;
20914
+ if (_isFirebaseServerApp(this.app)) {
20915
+ const idToken = this.app.settings.authIdToken;
20916
+ if (idToken) {
20917
+ // Start the auth operation in the next tick to allow a moment for the customer's app to
20918
+ // attach an emulator, if desired.
20919
+ return new Promise(resolve => {
20920
+ setTimeout(() => this.initializeCurrentUserFromIdToken(idToken).then(resolve, resolve));
20921
+ });
20922
+ }
20923
+ else {
20924
+ return this.directlySetCurrentUser(null);
20925
+ }
20926
+ }
20726
20927
  // First check to see if we have a pending redirect event.
20727
20928
  const previouslyStoredUser = (await this.assertedPersistence.getCurrentUser());
20728
20929
  let futureCurrentUser = previouslyStoredUser;
@@ -20828,6 +21029,9 @@ class AuthImpl {
20828
21029
  this._deleted = true;
20829
21030
  }
20830
21031
  async updateCurrentUser(userExtern) {
21032
+ if (_isFirebaseServerApp(this.app)) {
21033
+ return Promise.reject(_serverAppCurrentUserOperationNotSupportedError(this));
21034
+ }
20831
21035
  // The public updateCurrentUser method needs to make a copy of the user,
20832
21036
  // and also check that the project matches
20833
21037
  const user = userExtern
@@ -20854,6 +21058,9 @@ class AuthImpl {
20854
21058
  });
20855
21059
  }
20856
21060
  async signOut() {
21061
+ if (_isFirebaseServerApp(this.app)) {
21062
+ return Promise.reject(_serverAppCurrentUserOperationNotSupportedError(this));
21063
+ }
20857
21064
  // Run first, to block _setRedirectUser() if any callbacks fail.
20858
21065
  await this.beforeStateQueue.runMiddleware(null);
20859
21066
  // Clear the redirect user when signOut is called
@@ -20865,33 +21072,51 @@ class AuthImpl {
20865
21072
  return this._updateCurrentUser(null, /* skipBeforeStateCallbacks */ true);
20866
21073
  }
20867
21074
  setPersistence(persistence) {
21075
+ if (_isFirebaseServerApp(this.app)) {
21076
+ return Promise.reject(_serverAppCurrentUserOperationNotSupportedError(this));
21077
+ }
20868
21078
  return this.queue(async () => {
20869
21079
  await this.assertedPersistence.setPersistence(_getInstance(persistence));
20870
21080
  });
20871
21081
  }
20872
- async initializeRecaptchaConfig() {
20873
- const response = await getRecaptchaConfig(this, {
20874
- clientType: "CLIENT_TYPE_WEB" /* RecaptchaClientType.WEB */,
20875
- version: "RECAPTCHA_ENTERPRISE" /* RecaptchaVersion.ENTERPRISE */
20876
- });
20877
- const config = new RecaptchaConfig(response);
21082
+ _getRecaptchaConfig() {
20878
21083
  if (this.tenantId == null) {
20879
- this._agentRecaptchaConfig = config;
21084
+ return this._agentRecaptchaConfig;
20880
21085
  }
20881
21086
  else {
20882
- this._tenantRecaptchaConfigs[this.tenantId] = config;
21087
+ return this._tenantRecaptchaConfigs[this.tenantId];
21088
+ }
21089
+ }
21090
+ async validatePassword(password) {
21091
+ if (!this._getPasswordPolicyInternal()) {
21092
+ await this._updatePasswordPolicy();
20883
21093
  }
20884
- if (config.emailPasswordEnabled) {
20885
- const verifier = new RecaptchaEnterpriseVerifier(this);
20886
- void verifier.verify();
21094
+ // Password policy will be defined after fetching.
21095
+ const passwordPolicy = this._getPasswordPolicyInternal();
21096
+ // Check that the policy schema version is supported by the SDK.
21097
+ // TODO: Update this logic to use a max supported policy schema version once we have multiple schema versions.
21098
+ if (passwordPolicy.schemaVersion !==
21099
+ this.EXPECTED_PASSWORD_POLICY_SCHEMA_VERSION) {
21100
+ return Promise.reject(this._errorFactory.create("unsupported-password-policy-schema-version" /* AuthErrorCode.UNSUPPORTED_PASSWORD_POLICY_SCHEMA_VERSION */, {}));
20887
21101
  }
21102
+ return passwordPolicy.validatePassword(password);
20888
21103
  }
20889
- _getRecaptchaConfig() {
20890
- if (this.tenantId == null) {
20891
- return this._agentRecaptchaConfig;
21104
+ _getPasswordPolicyInternal() {
21105
+ if (this.tenantId === null) {
21106
+ return this._projectPasswordPolicy;
20892
21107
  }
20893
21108
  else {
20894
- return this._tenantRecaptchaConfigs[this.tenantId];
21109
+ return this._tenantPasswordPolicies[this.tenantId];
21110
+ }
21111
+ }
21112
+ async _updatePasswordPolicy() {
21113
+ const response = await _getPasswordPolicy(this);
21114
+ const passwordPolicy = new PasswordPolicyImpl(response);
21115
+ if (this.tenantId === null) {
21116
+ this._projectPasswordPolicy = passwordPolicy;
21117
+ }
21118
+ else {
21119
+ this._tenantPasswordPolicies[this.tenantId] = passwordPolicy;
20895
21120
  }
20896
21121
  }
20897
21122
  _getPersistence() {
@@ -20909,6 +21134,38 @@ class AuthImpl {
20909
21134
  onIdTokenChanged(nextOrObserver, error, completed) {
20910
21135
  return this.registerStateListener(this.idTokenSubscription, nextOrObserver, error, completed);
20911
21136
  }
21137
+ authStateReady() {
21138
+ return new Promise((resolve, reject) => {
21139
+ if (this.currentUser) {
21140
+ resolve();
21141
+ }
21142
+ else {
21143
+ const unsubscribe = this.onAuthStateChanged(() => {
21144
+ unsubscribe();
21145
+ resolve();
21146
+ }, reject);
21147
+ }
21148
+ });
21149
+ }
21150
+ /**
21151
+ * Revokes the given access token. Currently only supports Apple OAuth access tokens.
21152
+ */
21153
+ async revokeAccessToken(token) {
21154
+ if (this.currentUser) {
21155
+ const idToken = await this.currentUser.getIdToken();
21156
+ // Generalize this to accept other providers once supported.
21157
+ const request = {
21158
+ providerId: 'apple.com',
21159
+ tokenType: "ACCESS_TOKEN" /* TokenType.ACCESS_TOKEN */,
21160
+ token,
21161
+ idToken
21162
+ };
21163
+ if (this.tenantId != null) {
21164
+ request.tenantId = this.tenantId;
21165
+ }
21166
+ await revokeToken(this, request);
21167
+ }
21168
+ }
20912
21169
  toJSON() {
20913
21170
  var _a;
20914
21171
  return {
@@ -20999,18 +21256,32 @@ class AuthImpl {
20999
21256
  const cb = typeof nextOrObserver === 'function'
21000
21257
  ? nextOrObserver
21001
21258
  : nextOrObserver.next.bind(nextOrObserver);
21259
+ let isUnsubscribed = false;
21002
21260
  const promise = this._isInitialized
21003
21261
  ? Promise.resolve()
21004
21262
  : this._initializationPromise;
21005
21263
  _assert(promise, this, "internal-error" /* AuthErrorCode.INTERNAL_ERROR */);
21006
21264
  // The callback needs to be called asynchronously per the spec.
21007
21265
  // eslint-disable-next-line @typescript-eslint/no-floating-promises
21008
- promise.then(() => cb(this.currentUser));
21266
+ promise.then(() => {
21267
+ if (isUnsubscribed) {
21268
+ return;
21269
+ }
21270
+ cb(this.currentUser);
21271
+ });
21009
21272
  if (typeof nextOrObserver === 'function') {
21010
- return subscription.addObserver(nextOrObserver, error, completed);
21273
+ const unsubscribe = subscription.addObserver(nextOrObserver, error, completed);
21274
+ return () => {
21275
+ isUnsubscribed = true;
21276
+ unsubscribe();
21277
+ };
21011
21278
  }
21012
21279
  else {
21013
- return subscription.addObserver(nextOrObserver);
21280
+ const unsubscribe = subscription.addObserver(nextOrObserver);
21281
+ return () => {
21282
+ isUnsubscribed = true;
21283
+ unsubscribe();
21284
+ };
21014
21285
  }
21015
21286
  }
21016
21287
  /**
@@ -21095,7 +21366,7 @@ class AuthImpl {
21095
21366
  }
21096
21367
  }
21097
21368
  /**
21098
- * Method to be used to cast down to our private implmentation of Auth.
21369
+ * Method to be used to cast down to our private implementation of Auth.
21099
21370
  * It will also handle unwrapping from the compat type if necessary
21100
21371
  *
21101
21372
  * @param auth Auth object passed in from developer
@@ -21116,6 +21387,194 @@ class Subscription {
21116
21387
  }
21117
21388
  }
21118
21389
 
21390
+ /**
21391
+ * @license
21392
+ * Copyright 2020 Google LLC
21393
+ *
21394
+ * Licensed under the Apache License, Version 2.0 (the "License");
21395
+ * you may not use this file except in compliance with the License.
21396
+ * You may obtain a copy of the License at
21397
+ *
21398
+ * http://www.apache.org/licenses/LICENSE-2.0
21399
+ *
21400
+ * Unless required by applicable law or agreed to in writing, software
21401
+ * distributed under the License is distributed on an "AS IS" BASIS,
21402
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
21403
+ * See the License for the specific language governing permissions and
21404
+ * limitations under the License.
21405
+ */
21406
+ let externalJSProvider = {
21407
+ async loadJS() {
21408
+ throw new Error('Unable to load external scripts');
21409
+ },
21410
+ recaptchaV2Script: '',
21411
+ recaptchaEnterpriseScript: '',
21412
+ gapiScript: ''
21413
+ };
21414
+ function _setExternalJSProvider(p) {
21415
+ externalJSProvider = p;
21416
+ }
21417
+ function _loadJS(url) {
21418
+ return externalJSProvider.loadJS(url);
21419
+ }
21420
+ function _recaptchaEnterpriseScriptUrl() {
21421
+ return externalJSProvider.recaptchaEnterpriseScript;
21422
+ }
21423
+ function _gapiScriptUrl() {
21424
+ return externalJSProvider.gapiScript;
21425
+ }
21426
+ function _generateCallbackName(prefix) {
21427
+ return `__${prefix}${Math.floor(Math.random() * 1000000)}`;
21428
+ }
21429
+
21430
+ /* eslint-disable @typescript-eslint/no-require-imports */
21431
+ const RECAPTCHA_ENTERPRISE_VERIFIER_TYPE = 'recaptcha-enterprise';
21432
+ const FAKE_TOKEN = 'NO_RECAPTCHA';
21433
+ class RecaptchaEnterpriseVerifier {
21434
+ /**
21435
+ *
21436
+ * @param authExtern - The corresponding Firebase {@link Auth} instance.
21437
+ *
21438
+ */
21439
+ constructor(authExtern) {
21440
+ /**
21441
+ * Identifies the type of application verifier (e.g. "recaptcha-enterprise").
21442
+ */
21443
+ this.type = RECAPTCHA_ENTERPRISE_VERIFIER_TYPE;
21444
+ this.auth = _castAuth(authExtern);
21445
+ }
21446
+ /**
21447
+ * Executes the verification process.
21448
+ *
21449
+ * @returns A Promise for a token that can be used to assert the validity of a request.
21450
+ */
21451
+ async verify(action = 'verify', forceRefresh = false) {
21452
+ async function retrieveSiteKey(auth) {
21453
+ if (!forceRefresh) {
21454
+ if (auth.tenantId == null && auth._agentRecaptchaConfig != null) {
21455
+ return auth._agentRecaptchaConfig.siteKey;
21456
+ }
21457
+ if (auth.tenantId != null &&
21458
+ auth._tenantRecaptchaConfigs[auth.tenantId] !== undefined) {
21459
+ return auth._tenantRecaptchaConfigs[auth.tenantId].siteKey;
21460
+ }
21461
+ }
21462
+ return new Promise(async (resolve, reject) => {
21463
+ getRecaptchaConfig(auth, {
21464
+ clientType: "CLIENT_TYPE_WEB" /* RecaptchaClientType.WEB */,
21465
+ version: "RECAPTCHA_ENTERPRISE" /* RecaptchaVersion.ENTERPRISE */
21466
+ })
21467
+ .then(response => {
21468
+ if (response.recaptchaKey === undefined) {
21469
+ reject(new Error('recaptcha Enterprise site key undefined'));
21470
+ }
21471
+ else {
21472
+ const config = new RecaptchaConfig(response);
21473
+ if (auth.tenantId == null) {
21474
+ auth._agentRecaptchaConfig = config;
21475
+ }
21476
+ else {
21477
+ auth._tenantRecaptchaConfigs[auth.tenantId] = config;
21478
+ }
21479
+ return resolve(config.siteKey);
21480
+ }
21481
+ })
21482
+ .catch(error => {
21483
+ reject(error);
21484
+ });
21485
+ });
21486
+ }
21487
+ function retrieveRecaptchaToken(siteKey, resolve, reject) {
21488
+ const grecaptcha = window.grecaptcha;
21489
+ if (isEnterprise(grecaptcha)) {
21490
+ grecaptcha.enterprise.ready(() => {
21491
+ grecaptcha.enterprise
21492
+ .execute(siteKey, { action })
21493
+ .then(token => {
21494
+ resolve(token);
21495
+ })
21496
+ .catch(() => {
21497
+ resolve(FAKE_TOKEN);
21498
+ });
21499
+ });
21500
+ }
21501
+ else {
21502
+ reject(Error('No reCAPTCHA enterprise script loaded.'));
21503
+ }
21504
+ }
21505
+ return new Promise((resolve, reject) => {
21506
+ retrieveSiteKey(this.auth)
21507
+ .then(siteKey => {
21508
+ if (!forceRefresh && isEnterprise(window.grecaptcha)) {
21509
+ retrieveRecaptchaToken(siteKey, resolve, reject);
21510
+ }
21511
+ else {
21512
+ if (typeof window === 'undefined') {
21513
+ reject(new Error('RecaptchaVerifier is only supported in browser'));
21514
+ return;
21515
+ }
21516
+ let url = _recaptchaEnterpriseScriptUrl();
21517
+ if (url.length !== 0) {
21518
+ url += siteKey;
21519
+ }
21520
+ _loadJS(url)
21521
+ .then(() => {
21522
+ retrieveRecaptchaToken(siteKey, resolve, reject);
21523
+ })
21524
+ .catch(error => {
21525
+ reject(error);
21526
+ });
21527
+ }
21528
+ })
21529
+ .catch(error => {
21530
+ reject(error);
21531
+ });
21532
+ });
21533
+ }
21534
+ }
21535
+ async function injectRecaptchaFields(auth, request, action, captchaResp = false) {
21536
+ const verifier = new RecaptchaEnterpriseVerifier(auth);
21537
+ let captchaResponse;
21538
+ try {
21539
+ captchaResponse = await verifier.verify(action);
21540
+ }
21541
+ catch (error) {
21542
+ captchaResponse = await verifier.verify(action, true);
21543
+ }
21544
+ const newRequest = Object.assign({}, request);
21545
+ if (!captchaResp) {
21546
+ Object.assign(newRequest, { captchaResponse });
21547
+ }
21548
+ else {
21549
+ Object.assign(newRequest, { 'captchaResp': captchaResponse });
21550
+ }
21551
+ Object.assign(newRequest, { 'clientType': "CLIENT_TYPE_WEB" /* RecaptchaClientType.WEB */ });
21552
+ Object.assign(newRequest, {
21553
+ 'recaptchaVersion': "RECAPTCHA_ENTERPRISE" /* RecaptchaVersion.ENTERPRISE */
21554
+ });
21555
+ return newRequest;
21556
+ }
21557
+ async function handleRecaptchaFlow(authInstance, request, actionName, actionMethod) {
21558
+ var _a;
21559
+ if ((_a = authInstance
21560
+ ._getRecaptchaConfig()) === null || _a === void 0 ? void 0 : _a.isProviderEnabled("EMAIL_PASSWORD_PROVIDER" /* RecaptchaProvider.EMAIL_PASSWORD_PROVIDER */)) {
21561
+ const requestWithRecaptcha = await injectRecaptchaFields(authInstance, request, actionName, actionName === "getOobCode" /* RecaptchaActionName.GET_OOB_CODE */);
21562
+ return actionMethod(authInstance, requestWithRecaptcha);
21563
+ }
21564
+ else {
21565
+ return actionMethod(authInstance, request).catch(async (error) => {
21566
+ if (error.code === `auth/${"missing-recaptcha-token" /* AuthErrorCode.MISSING_RECAPTCHA_TOKEN */}`) {
21567
+ console.log(`${actionName} is protected by reCAPTCHA Enterprise for this project. Automatically triggering the reCAPTCHA flow and restarting the flow.`);
21568
+ const requestWithRecaptcha = await injectRecaptchaFields(authInstance, request, actionName, actionName === "getOobCode" /* RecaptchaActionName.GET_OOB_CODE */);
21569
+ return actionMethod(authInstance, requestWithRecaptcha);
21570
+ }
21571
+ else {
21572
+ return Promise.reject(error);
21573
+ }
21574
+ });
21575
+ }
21576
+ }
21577
+
21119
21578
  /**
21120
21579
  * @license
21121
21580
  * Copyright 2020 Google LLC
@@ -21379,8 +21838,10 @@ class AuthCredential {
21379
21838
  async function resetPassword(auth, request) {
21380
21839
  return _performApiRequest(auth, "POST" /* HttpMethod.POST */, "/v1/accounts:resetPassword" /* Endpoint.RESET_PASSWORD */, _addTidIfNecessary(auth, request));
21381
21840
  }
21382
- async function updateEmailPassword(auth, request) {
21383
- return _performApiRequest(auth, "POST" /* HttpMethod.POST */, "/v1/accounts:update" /* Endpoint.SET_ACCOUNT_INFO */, request);
21841
+ // Used for linking an email/password account to an existing idToken. Uses the same request/response
21842
+ // format as updateEmailPassword.
21843
+ async function linkEmailPassword(auth, request) {
21844
+ return _performApiRequest(auth, "POST" /* HttpMethod.POST */, "/v1/accounts:signUp" /* Endpoint.SIGN_UP */, request);
21384
21845
  }
21385
21846
 
21386
21847
  /**
@@ -21511,7 +21972,6 @@ class EmailAuthCredential extends AuthCredential {
21511
21972
  }
21512
21973
  /** @internal */
21513
21974
  async _getIdTokenResponse(auth) {
21514
- var _a;
21515
21975
  switch (this.signInMethod) {
21516
21976
  case "password" /* SignInMethod.EMAIL_PASSWORD */:
21517
21977
  const request = {
@@ -21520,22 +21980,7 @@ class EmailAuthCredential extends AuthCredential {
21520
21980
  password: this._password,
21521
21981
  clientType: "CLIENT_TYPE_WEB" /* RecaptchaClientType.WEB */
21522
21982
  };
21523
- if ((_a = auth._getRecaptchaConfig()) === null || _a === void 0 ? void 0 : _a.emailPasswordEnabled) {
21524
- const requestWithRecaptcha = await injectRecaptchaFields(auth, request, "signInWithPassword" /* RecaptchaActionName.SIGN_IN_WITH_PASSWORD */);
21525
- return signInWithPassword(auth, requestWithRecaptcha);
21526
- }
21527
- else {
21528
- return signInWithPassword(auth, request).catch(async (error) => {
21529
- if (error.code === `auth/${"missing-recaptcha-token" /* AuthErrorCode.MISSING_RECAPTCHA_TOKEN */}`) {
21530
- console.log('Sign-in with email address and password is protected by reCAPTCHA for this project. Automatically triggering the reCAPTCHA flow and restarting the sign-in flow.');
21531
- const requestWithRecaptcha = await injectRecaptchaFields(auth, request, "signInWithPassword" /* RecaptchaActionName.SIGN_IN_WITH_PASSWORD */);
21532
- return signInWithPassword(auth, requestWithRecaptcha);
21533
- }
21534
- else {
21535
- return Promise.reject(error);
21536
- }
21537
- });
21538
- }
21983
+ return handleRecaptchaFlow(auth, request, "signInWithPassword" /* RecaptchaActionName.SIGN_IN_WITH_PASSWORD */, signInWithPassword);
21539
21984
  case "emailLink" /* SignInMethod.EMAIL_LINK */:
21540
21985
  return signInWithEmailLink$1(auth, {
21541
21986
  email: this._email,
@@ -21549,12 +21994,14 @@ class EmailAuthCredential extends AuthCredential {
21549
21994
  async _linkToIdToken(auth, idToken) {
21550
21995
  switch (this.signInMethod) {
21551
21996
  case "password" /* SignInMethod.EMAIL_PASSWORD */:
21552
- return updateEmailPassword(auth, {
21997
+ const request = {
21553
21998
  idToken,
21554
21999
  returnSecureToken: true,
21555
22000
  email: this._email,
21556
- password: this._password
21557
- });
22001
+ password: this._password,
22002
+ clientType: "CLIENT_TYPE_WEB" /* RecaptchaClientType.WEB */
22003
+ };
22004
+ return handleRecaptchaFlow(auth, request, "signUpPassword" /* RecaptchaActionName.SIGN_UP_PASSWORD */, linkEmailPassword);
21558
22005
  case "emailLink" /* SignInMethod.EMAIL_LINK */:
21559
22006
  return signInWithEmailLinkForLinking(auth, {
21560
22007
  idToken,
@@ -22172,7 +22619,7 @@ FacebookAuthProvider.PROVIDER_ID = "facebook.com" /* ProviderId.FACEBOOK */;
22172
22619
  * limitations under the License.
22173
22620
  */
22174
22621
  /**
22175
- * Provider for generating an an {@link OAuthCredential} for {@link ProviderId}.GOOGLE.
22622
+ * Provider for generating an {@link OAuthCredential} for {@link ProviderId}.GOOGLE.
22176
22623
  *
22177
22624
  * @example
22178
22625
  * ```javascript
@@ -22314,7 +22761,7 @@ GoogleAuthProvider.PROVIDER_ID = "google.com" /* ProviderId.GOOGLE */;
22314
22761
  * if (result) {
22315
22762
  * // This is the signed-in user
22316
22763
  * const user = result.user;
22317
- * // This gives you a Github Access Token.
22764
+ * // This gives you a GitHub Access Token.
22318
22765
  * const credential = GithubAuthProvider.credentialFromResult(result);
22319
22766
  * const token = credential.accessToken;
22320
22767
  * }
@@ -22329,7 +22776,7 @@ GoogleAuthProvider.PROVIDER_ID = "google.com" /* ProviderId.GOOGLE */;
22329
22776
  *
22330
22777
  * // The signed-in user info.
22331
22778
  * const user = result.user;
22332
- * // This gives you a Github Access Token.
22779
+ * // This gives you a GitHub Access Token.
22333
22780
  * const credential = GithubAuthProvider.credentialFromResult(result);
22334
22781
  * const token = credential.accessToken;
22335
22782
  * ```
@@ -22340,9 +22787,9 @@ class GithubAuthProvider extends BaseOAuthProvider {
22340
22787
  super("github.com" /* ProviderId.GITHUB */);
22341
22788
  }
22342
22789
  /**
22343
- * Creates a credential for Github.
22790
+ * Creates a credential for GitHub.
22344
22791
  *
22345
- * @param accessToken - Github access token.
22792
+ * @param accessToken - GitHub access token.
22346
22793
  */
22347
22794
  static credential(accessToken) {
22348
22795
  return OAuthCredential._fromParams({
@@ -22623,6 +23070,9 @@ async function _link$1(user, credential, bypassAuthState = false) {
22623
23070
  */
22624
23071
  async function _reauthenticate(user, credential, bypassAuthState = false) {
22625
23072
  const { auth } = user;
23073
+ if (_isFirebaseServerApp(auth.app)) {
23074
+ return Promise.reject(_serverAppCurrentUserOperationNotSupportedError(auth));
23075
+ }
22626
23076
  const operationType = "reauthenticate" /* OperationType.REAUTHENTICATE */;
22627
23077
  try {
22628
23078
  const response = await _logoutIfInvalidated(user, _processCredentialSavingMfaContextIfNecessary(auth, operationType, credential, user), bypassAuthState);
@@ -22659,6 +23109,9 @@ async function _reauthenticate(user, credential, bypassAuthState = false) {
22659
23109
  * limitations under the License.
22660
23110
  */
22661
23111
  async function _signInWithCredential(auth, credential, bypassAuthState = false) {
23112
+ if (_isFirebaseServerApp(auth.app)) {
23113
+ return Promise.reject(_serverAppCurrentUserOperationNotSupportedError(auth));
23114
+ }
22662
23115
  const operationType = "signIn" /* OperationType.SIGN_IN */;
22663
23116
  const response = await _processCredentialSavingMfaContextIfNecessary(auth, operationType, credential);
22664
23117
  const userCredential = await UserCredentialImpl._fromIdTokenResponse(auth, operationType, response);
@@ -22673,6 +23126,9 @@ async function _signInWithCredential(auth, credential, bypassAuthState = false)
22673
23126
  * @remarks
22674
23127
  * An {@link AuthProvider} can be used to generate the credential.
22675
23128
  *
23129
+ * This method is not supported by {@link Auth} instances created with a
23130
+ * {@link @firebase/app#FirebaseServerApp}.
23131
+ *
22676
23132
  * @param auth - The {@link Auth} instance.
22677
23133
  * @param credential - The auth credential.
22678
23134
  *
@@ -22736,7 +23192,29 @@ function _setActionCodeSettingsOnRequest(auth, request, actionCodeSettings) {
22736
23192
  * limitations under the License.
22737
23193
  */
22738
23194
  /**
22739
- * Sends a password reset email to the given email address.
23195
+ * Updates the password policy cached in the {@link Auth} instance if a policy is already
23196
+ * cached for the project or tenant.
23197
+ *
23198
+ * @remarks
23199
+ * We only fetch the password policy if the password did not meet policy requirements and
23200
+ * there is an existing policy cached. A developer must call validatePassword at least
23201
+ * once for the cache to be automatically updated.
23202
+ *
23203
+ * @param auth - The {@link Auth} instance.
23204
+ *
23205
+ * @private
23206
+ */
23207
+ async function recachePasswordPolicy(auth) {
23208
+ const authInternal = _castAuth(auth);
23209
+ if (authInternal._getPasswordPolicyInternal()) {
23210
+ await authInternal._updatePasswordPolicy();
23211
+ }
23212
+ }
23213
+ /**
23214
+ * Sends a password reset email to the given email address. This method does not throw an error when
23215
+ * there's no user account with the given email address and
23216
+ * {@link https://cloud.google.com/identity-platform/docs/admin/email-enumeration-protection | Email Enumeration Protection}
23217
+ * is enabled.
22740
23218
  *
22741
23219
  * @remarks
22742
23220
  * To complete the password reset, call {@link confirmPasswordReset} with the code supplied in
@@ -22768,39 +23246,16 @@ function _setActionCodeSettingsOnRequest(auth, request, actionCodeSettings) {
22768
23246
  * @public
22769
23247
  */
22770
23248
  async function sendPasswordResetEmail(auth, email, actionCodeSettings) {
22771
- var _a;
22772
23249
  const authInternal = _castAuth(auth);
22773
23250
  const request = {
22774
23251
  requestType: "PASSWORD_RESET" /* ActionCodeOperation.PASSWORD_RESET */,
22775
23252
  email,
22776
23253
  clientType: "CLIENT_TYPE_WEB" /* RecaptchaClientType.WEB */
22777
23254
  };
22778
- if ((_a = authInternal._getRecaptchaConfig()) === null || _a === void 0 ? void 0 : _a.emailPasswordEnabled) {
22779
- const requestWithRecaptcha = await injectRecaptchaFields(authInternal, request, "getOobCode" /* RecaptchaActionName.GET_OOB_CODE */, true);
22780
- if (actionCodeSettings) {
22781
- _setActionCodeSettingsOnRequest(authInternal, requestWithRecaptcha, actionCodeSettings);
22782
- }
22783
- await sendPasswordResetEmail$1(authInternal, requestWithRecaptcha);
22784
- }
22785
- else {
22786
- if (actionCodeSettings) {
22787
- _setActionCodeSettingsOnRequest(authInternal, request, actionCodeSettings);
22788
- }
22789
- await sendPasswordResetEmail$1(authInternal, request)
22790
- .catch(async (error) => {
22791
- if (error.code === `auth/${"missing-recaptcha-token" /* AuthErrorCode.MISSING_RECAPTCHA_TOKEN */}`) {
22792
- console.log('Password resets are protected by reCAPTCHA for this project. Automatically triggering the reCAPTCHA flow and restarting the password reset flow.');
22793
- const requestWithRecaptcha = await injectRecaptchaFields(authInternal, request, "getOobCode" /* RecaptchaActionName.GET_OOB_CODE */, true);
22794
- if (actionCodeSettings) {
22795
- _setActionCodeSettingsOnRequest(authInternal, requestWithRecaptcha, actionCodeSettings);
22796
- }
22797
- await sendPasswordResetEmail$1(authInternal, requestWithRecaptcha);
22798
- }
22799
- else {
22800
- return Promise.reject(error);
22801
- }
22802
- });
23255
+ if (actionCodeSettings) {
23256
+ _setActionCodeSettingsOnRequest(authInternal, request, actionCodeSettings);
22803
23257
  }
23258
+ await handleRecaptchaFlow(authInternal, request, "getOobCode" /* RecaptchaActionName.GET_OOB_CODE */, sendPasswordResetEmail$1);
22804
23259
  }
22805
23260
  /**
22806
23261
  * Completes the password reset process, given a confirmation code and new password.
@@ -22815,6 +23270,13 @@ async function confirmPasswordReset(auth, oobCode, newPassword) {
22815
23270
  await resetPassword(getModularInstance$1(auth), {
22816
23271
  oobCode,
22817
23272
  newPassword
23273
+ })
23274
+ .catch(async (error) => {
23275
+ if (error.code ===
23276
+ `auth/${"password-does-not-meet-requirements" /* AuthErrorCode.PASSWORD_DOES_NOT_MEET_REQUIREMENTS */}`) {
23277
+ void recachePasswordPolicy(auth);
23278
+ }
23279
+ throw error;
22818
23280
  });
22819
23281
  // Do not return the email.
22820
23282
  }
@@ -22822,12 +23284,19 @@ async function confirmPasswordReset(auth, oobCode, newPassword) {
22822
23284
  * Asynchronously signs in using an email and password.
22823
23285
  *
22824
23286
  * @remarks
22825
- * Fails with an error if the email address and password do not match.
23287
+ * Fails with an error if the email address and password do not match. When
23288
+ * {@link https://cloud.google.com/identity-platform/docs/admin/email-enumeration-protection | Email Enumeration Protection}
23289
+ * is enabled, this method fails with "auth/invalid-credential" in case of an invalid
23290
+ * email/password.
23291
+ *
23292
+ * This method is not supported on {@link Auth} instances created with a
23293
+ * {@link @firebase/app#FirebaseServerApp}.
22826
23294
  *
22827
23295
  * Note: The user's password is NOT the password used to access the user's email account. The
22828
23296
  * email address serves as a unique identifier for the user, and the password is used to access
22829
23297
  * the user's account in your Firebase project. See also: {@link createUserWithEmailAndPassword}.
22830
23298
  *
23299
+ *
22831
23300
  * @param auth - The {@link Auth} instance.
22832
23301
  * @param email - The users email address.
22833
23302
  * @param password - The users password.
@@ -22835,7 +23304,15 @@ async function confirmPasswordReset(auth, oobCode, newPassword) {
22835
23304
  * @public
22836
23305
  */
22837
23306
  function signInWithEmailAndPassword(auth, email, password) {
22838
- return signInWithCredential(getModularInstance$1(auth), EmailAuthProvider.credential(email, password));
23307
+ if (_isFirebaseServerApp(auth.app)) {
23308
+ return Promise.reject(_serverAppCurrentUserOperationNotSupportedError(auth));
23309
+ }
23310
+ return signInWithCredential(getModularInstance$1(auth), EmailAuthProvider.credential(email, password)).catch(async (error) => {
23311
+ if (error.code === `auth/${"password-does-not-meet-requirements" /* AuthErrorCode.PASSWORD_DOES_NOT_MEET_REQUIREMENTS */}`) {
23312
+ void recachePasswordPolicy(auth);
23313
+ }
23314
+ throw error;
23315
+ });
22839
23316
  }
22840
23317
  /**
22841
23318
  * Adds an observer for changes to the signed-in user's ID token.
@@ -22942,10 +23419,6 @@ class BrowserPersistenceClass {
22942
23419
  * See the License for the specific language governing permissions and
22943
23420
  * limitations under the License.
22944
23421
  */
22945
- function _iframeCannotSyncWebStorage() {
22946
- const ua = getUA();
22947
- return _isSafari(ua) || _isIOS(ua);
22948
- }
22949
23422
  // The polling period in case events are not supported
22950
23423
  const _POLLING_INTERVAL_MS$1 = 1000;
22951
23424
  // The IE 10 localStorage cross tab synchronization delay in milliseconds
@@ -22959,8 +23432,6 @@ class BrowserLocalPersistence extends BrowserPersistenceClass {
22959
23432
  // setTimeout return value is platform specific
22960
23433
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
22961
23434
  this.pollTimer = null;
22962
- // Safari or iOS browser and embedded in an iframe.
22963
- this.safariLocalStorageNotSynced = _iframeCannotSyncWebStorage() && _isIframe();
22964
23435
  // Whether to use polling instead of depending on window events
22965
23436
  this.fallbackToPolling = _isMobileBrowser();
22966
23437
  this._shouldAllowMigration = true;
@@ -22999,27 +23470,6 @@ class BrowserLocalPersistence extends BrowserPersistenceClass {
22999
23470
  // Remove polling listener to prevent possible event duplication.
23000
23471
  this.stopPolling();
23001
23472
  }
23002
- // Safari embedded iframe. Storage event will trigger with the delta
23003
- // changes but no changes will be applied to the iframe localStorage.
23004
- if (this.safariLocalStorageNotSynced) {
23005
- // Get current iframe page value.
23006
- const storedValue = this.storage.getItem(key);
23007
- // Value not synchronized, synchronize manually.
23008
- if (event.newValue !== storedValue) {
23009
- if (event.newValue !== null) {
23010
- // Value changed from current value.
23011
- this.storage.setItem(key, event.newValue);
23012
- }
23013
- else {
23014
- // Current value deleted.
23015
- this.storage.removeItem(key);
23016
- }
23017
- }
23018
- else if (this.localCache[key] === event.newValue && !poll) {
23019
- // Already detected and processed, do not trigger listeners again.
23020
- return;
23021
- }
23022
- }
23023
23473
  const triggerListeners = () => {
23024
23474
  // Keep local map up to date in case storage event is triggered before
23025
23475
  // poll.
@@ -23310,7 +23760,7 @@ class Receiver {
23310
23760
  * Unsubscribe an event handler from a particular event.
23311
23761
  *
23312
23762
  * @param eventType - Event name to unsubscribe from.
23313
- * @param eventHandler - Optinoal event handler, if none provided, unsubscribe all handlers on this event.
23763
+ * @param eventHandler - Optional event handler, if none provided, unsubscribe all handlers on this event.
23314
23764
  *
23315
23765
  */
23316
23766
  _unsubscribe(eventType, eventHandler) {
@@ -23804,11 +24254,13 @@ class IndexedDBLocalPersistence {
23804
24254
  }
23805
24255
  const keys = [];
23806
24256
  const keysInResult = new Set();
23807
- for (const { fbase_key: key, value } of result) {
23808
- keysInResult.add(key);
23809
- if (JSON.stringify(this.localCache[key]) !== JSON.stringify(value)) {
23810
- this.notifyListeners(key, value);
23811
- keys.push(key);
24257
+ if (result.length !== 0) {
24258
+ for (const { fbase_key: key, value } of result) {
24259
+ keysInResult.add(key);
24260
+ if (JSON.stringify(this.localCache[key]) !== JSON.stringify(value)) {
24261
+ this.notifyListeners(key, value);
24262
+ keys.push(key);
24263
+ }
23812
24264
  }
23813
24265
  }
23814
24266
  for (const localKey of Object.keys(this.localCache)) {
@@ -24264,6 +24716,9 @@ function pendingRedirectKey(auth) {
24264
24716
  return _persistenceKeyName(PENDING_REDIRECT_KEY, auth.config.apiKey, auth.name);
24265
24717
  }
24266
24718
  async function _getRedirectResult(auth, resolverExtern, bypassAuthState = false) {
24719
+ if (_isFirebaseServerApp(auth.app)) {
24720
+ return Promise.reject(_serverAppCurrentUserOperationNotSupportedError(auth));
24721
+ }
24267
24722
  const authInternal = _castAuth(auth);
24268
24723
  const resolver = _withDefaultResolver(authInternal, resolverExtern);
24269
24724
  const action = new RedirectAction(authInternal, resolver, bypassAuthState);
@@ -24494,7 +24949,7 @@ function matchDomain(expected) {
24494
24949
  */
24495
24950
  const NETWORK_TIMEOUT = new Delay(30000, 60000);
24496
24951
  /**
24497
- * Reset unlaoded GApi modules. If gapi.load fails due to a network error,
24952
+ * Reset unloaded GApi modules. If gapi.load fails due to a network error,
24498
24953
  * it will stop working after a retrial. This is a hack to fix this issue.
24499
24954
  */
24500
24955
  function resetUnloadedGapiModules() {
@@ -24574,7 +25029,7 @@ function loadGapi(auth) {
24574
25029
  }
24575
25030
  };
24576
25031
  // Load GApi loader.
24577
- return _loadJS(`https://apis.google.com/js/api.js?onload=${cbName}`)
25032
+ return _loadJS(`${_gapiScriptUrl()}?onload=${cbName}`)
24578
25033
  .catch(e => reject(e));
24579
25034
  }
24580
25035
  }).catch(error => {
@@ -24829,7 +25284,7 @@ async function _getRedirectUrl(auth, provider, authType, redirectUrl, eventId, a
24829
25284
  if (auth.tenantId) {
24830
25285
  params.tid = auth.tenantId;
24831
25286
  }
24832
- // TODO: maybe set eid as endipointId
25287
+ // TODO: maybe set eid as endpointId
24833
25288
  // TODO: maybe set fw as Frameworks.join(",")
24834
25289
  const paramsDict = params;
24835
25290
  for (const key of Object.keys(paramsDict)) {
@@ -24957,12 +25412,15 @@ class BrowserPopupRedirectResolver {
24957
25412
  * An implementation of {@link PopupRedirectResolver} suitable for browser
24958
25413
  * based applications.
24959
25414
  *
25415
+ * @remarks
25416
+ * This method does not work in a Node.js environment.
25417
+ *
24960
25418
  * @public
24961
25419
  */
24962
25420
  const browserPopupRedirectResolver = BrowserPopupRedirectResolver;
24963
25421
 
24964
25422
  var name = "@firebase/auth";
24965
- var version = "0.23.2";
25423
+ var version = "1.7.7";
24966
25424
 
24967
25425
  /**
24968
25426
  * @license
@@ -25059,6 +25517,8 @@ function getVersionForPlatform(clientPlatform) {
25059
25517
  return 'webworker';
25060
25518
  case "Cordova" /* ClientPlatform.CORDOVA */:
25061
25519
  return 'cordova';
25520
+ case "WebExtension" /* ClientPlatform.WEB_EXTENSION */:
25521
+ return 'web-extension';
25062
25522
  default:
25063
25523
  return undefined;
25064
25524
  }
@@ -25168,11 +25628,18 @@ function getAuth(app = getApp()) {
25168
25628
  browserSessionPersistence
25169
25629
  ]
25170
25630
  });
25171
- const authTokenSyncUrl = getExperimentalSetting('authTokenSyncURL');
25172
- if (authTokenSyncUrl) {
25173
- const mintCookie = mintCookieFactory(authTokenSyncUrl);
25174
- beforeAuthStateChanged(auth, mintCookie, () => mintCookie(auth.currentUser));
25175
- onIdTokenChanged(auth, user => mintCookie(user));
25631
+ const authTokenSyncPath = getExperimentalSetting('authTokenSyncURL');
25632
+ // Only do the Cookie exchange in a secure context
25633
+ if (authTokenSyncPath &&
25634
+ typeof isSecureContext === 'boolean' &&
25635
+ isSecureContext) {
25636
+ // Don't allow urls (XSS possibility), only paths on the same domain
25637
+ const authTokenSyncUrl = new URL(authTokenSyncPath, location.origin);
25638
+ if (location.origin === authTokenSyncUrl.origin) {
25639
+ const mintCookie = mintCookieFactory(authTokenSyncUrl.toString());
25640
+ beforeAuthStateChanged(auth, mintCookie, () => mintCookie(auth.currentUser));
25641
+ onIdTokenChanged(auth, user => mintCookie(user));
25642
+ }
25176
25643
  }
25177
25644
  const authEmulatorHost = getDefaultEmulatorHost$1('auth');
25178
25645
  if (authEmulatorHost) {
@@ -25180,6 +25647,31 @@ function getAuth(app = getApp()) {
25180
25647
  }
25181
25648
  return auth;
25182
25649
  }
25650
+ function getScriptParentElement() {
25651
+ var _a, _b;
25652
+ return (_b = (_a = document.getElementsByTagName('head')) === null || _a === void 0 ? void 0 : _a[0]) !== null && _b !== void 0 ? _b : document;
25653
+ }
25654
+ _setExternalJSProvider({
25655
+ loadJS(url) {
25656
+ // TODO: consider adding timeout support & cancellation
25657
+ return new Promise((resolve, reject) => {
25658
+ const el = document.createElement('script');
25659
+ el.setAttribute('src', url);
25660
+ el.onload = resolve;
25661
+ el.onerror = e => {
25662
+ const error = _createError("internal-error" /* AuthErrorCode.INTERNAL_ERROR */);
25663
+ error.customData = e;
25664
+ reject(error);
25665
+ };
25666
+ el.type = 'text/javascript';
25667
+ el.charset = 'UTF-8';
25668
+ getScriptParentElement().appendChild(el);
25669
+ });
25670
+ },
25671
+ gapiScript: 'https://apis.google.com/js/api.js',
25672
+ recaptchaV2Script: 'https://www.google.com/recaptcha/api.js',
25673
+ recaptchaEnterpriseScript: 'https://www.google.com/recaptcha/enterprise.js?render='
25674
+ });
25183
25675
  registerAuth("Browser" /* ClientPlatform.BROWSER */);
25184
25676
 
25185
25677
  const fromFirebaseDate = (date) => {
@@ -25218,16 +25710,16 @@ class FirebaseUser {
25218
25710
  var _a;
25219
25711
  return (_a = this.user) === null || _a === void 0 ? void 0 : _a.uid;
25220
25712
  }
25221
- onInit(brandId) {
25222
- return new Promise((resolve) => {
25223
- const unsub = this.auth.onAuthStateChanged((user) => {
25224
- this.setUser(user);
25225
- resolve(Boolean(user));
25226
- unsub();
25227
- if (user)
25228
- this.logUserLogin(brandId, user);
25229
- });
25713
+ async onInit(brandId) {
25714
+ this.auth.onAuthStateChanged((user) => {
25715
+ this.setUser(user);
25716
+ if (user)
25717
+ this.logUserLogin(brandId, user);
25230
25718
  });
25719
+ await this.auth.authStateReady();
25720
+ const user = this.auth.currentUser;
25721
+ this.setUser(user);
25722
+ return Boolean(user);
25231
25723
  }
25232
25724
  setUser(user) {
25233
25725
  this.user = user;
@@ -26941,8 +27433,11 @@ class TfrSizeRec {
26941
27433
  size: sizeRec.available_sizes.find((size) => size.id === fit.size_id).label,
26942
27434
  locations: fit.measurement_location_fits
26943
27435
  .map((locationFit) => {
27436
+ const fitLabel = typeof locationFit.fit_label === 'string' && locationFit.fit_label
27437
+ ? locationFit.fit_label
27438
+ : index.FitNames[locationFit.fit];
26944
27439
  return {
26945
- fit: index.FitNames[locationFit.fit],
27440
+ fit: fitLabel,
26946
27441
  isPerfect: this.perfectFits.includes(locationFit.fit),
26947
27442
  location: this.tfrShop.getMeasurementLocationName(locationFit.measurement_location),
26948
27443
  sortOrder: this.tfrShop.getMeasurementLocationSortOrder(locationFit.measurement_location),