@jetbrains/ring-ui-built 7.0.94 → 7.0.96

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.
@@ -8,6 +8,7 @@ import TokenValidator, { type TokenValidationError, type TokenValidatorConfig }
8
8
  import type AuthDialogService from '../auth-dialog-service/auth-dialog-service';
9
9
  export declare const DEFAULT_EXPIRES_TIMEOUT: number;
10
10
  export declare const DEFAULT_BACKGROUND_TIMEOUT: number;
11
+ export declare const TOKEN_REFRESH_RETRY_DELAYS: number[];
11
12
  export declare const USER_CHANGED_EVENT = "userChange";
12
13
  export declare const DOMAIN_USER_CHANGED_EVENT = "domainUser";
13
14
  export declare const LOGOUT_EVENT = "logout";
@@ -80,6 +81,8 @@ export interface AuthConfig extends TokenValidatorConfig {
80
81
  translations?: AuthTranslations | null | undefined;
81
82
  userParams?: RequestParams | undefined;
82
83
  waitForRedirectTimeout: number;
84
+ tokenRefreshRetryDelays: readonly number[];
85
+ rpInitiatedLogout: boolean;
83
86
  }
84
87
  type AuthPayloadMap = {
85
88
  userChange: [AuthUser | undefined | void, void];
@@ -120,6 +123,7 @@ declare class Auth implements HTTPAuth {
120
123
  static DEFAULT_CONFIG: Omit<AuthConfig, "serverUri">;
121
124
  static API_PATH: string;
122
125
  static API_AUTH_PATH: string;
126
+ static API_LOGOUT_PATH: string;
123
127
  static API_PROFILE_PATH: string;
124
128
  static CLOSE_BACKEND_DOWN_MESSAGE: string;
125
129
  static CLOSE_WINDOW_MESSAGE: string;
@@ -137,6 +141,7 @@ declare class Auth implements HTTPAuth {
137
141
  _tokenValidator: TokenValidator | null;
138
142
  private _postponed;
139
143
  private _backendCheckPromise;
144
+ private _forceTokenUpdatePromise;
140
145
  private _authDialogService;
141
146
  _domainStorage: AuthStorage<UserChange>;
142
147
  user: AuthUser | null;
@@ -166,9 +171,18 @@ declare class Auth implements HTTPAuth {
166
171
  requestToken(): Promise<string | null>;
167
172
  /**
168
173
  * Get new token in the background or redirect to the login page.
169
- * @return {Promise.<string>}
174
+ *
175
+ * Retries background token refresh with delays from {@link AuthConfig.tokenRefreshRetryDelays}
176
+ * with increasing delays before showing the auth dialog.
177
+ * This handles transient failures that commonly occur after network
178
+ * recovery (e.g. waking from sleep, switching networks) where the first
179
+ * iframe-based auth attempt fails but a subsequent one succeeds once
180
+ * the Hub session is re-established.
181
+ *
182
+ * @return {Promise.<string | null>}
170
183
  */
171
184
  forceTokenUpdate(): Promise<string | null>;
185
+ private _doForceTokenUpdate;
172
186
  loadCurrentService(): Promise<void>;
173
187
  getAPIPath(): string;
174
188
  /**
@@ -187,7 +201,10 @@ declare class Auth implements HTTPAuth {
187
201
  private _extractErrorMessage;
188
202
  private _showBackendDownDialog;
189
203
  /**
190
- * Wipe accessToken and redirect to auth page with required authorization
204
+ * Wipe accessToken and redirect to logout endpoint.
205
+ * Uses RP-initiated logout flow (oauth2/logout) when rpInitiatedLogout config is enabled,
206
+ * falls back to oauth2/auth redirect otherwise.
207
+ * See: https://youtrack.jetbrains.com/projects/HUB/articles/HUB-A-43#rp-initiated-logout
191
208
  */
192
209
  logout(extraParams?: Record<string, unknown>): Promise<void>;
193
210
  private _runEmbeddedLogin;
@@ -47,6 +47,7 @@ const DEFAULT_BACKGROUND_TIMEOUT = 10 * 1000;
47
47
  const DEFAULT_BACKEND_CHECK_TIMEOUT = 10 * 1000;
48
48
  const BACKGROUND_REDIRECT_TIMEOUT = 20 * 1000;
49
49
  const DEFAULT_WAIT_FOR_REDIRECT_TIMEOUT = 5 * 1000;
50
+ const TOKEN_REFRESH_RETRY_DELAYS = [0, 2000, 5000];
50
51
  const USER_CHANGED_EVENT = 'userChange';
51
52
  const DOMAIN_USER_CHANGED_EVENT = 'domainUser';
52
53
  const LOGOUT_EVENT = 'logout';
@@ -75,12 +76,15 @@ const DEFAULT_CONFIG = {
75
76
  onBackendDown: () => () => {},
76
77
  defaultExpiresIn: DEFAULT_EXPIRES_TIMEOUT,
77
78
  waitForRedirectTimeout: DEFAULT_WAIT_FOR_REDIRECT_TIMEOUT,
79
+ tokenRefreshRetryDelays: TOKEN_REFRESH_RETRY_DELAYS,
80
+ rpInitiatedLogout: true,
78
81
  translations: null
79
82
  };
80
83
  class Auth {
81
84
  static DEFAULT_CONFIG = DEFAULT_CONFIG;
82
85
  static API_PATH = 'api/rest/';
83
86
  static API_AUTH_PATH = 'oauth2/auth';
87
+ static API_LOGOUT_PATH = 'oauth2/logout';
84
88
  static API_PROFILE_PATH = 'users/me';
85
89
  static CLOSE_BACKEND_DOWN_MESSAGE = 'backend-check-succeeded';
86
90
  static CLOSE_WINDOW_MESSAGE = 'close-login-window';
@@ -98,6 +102,7 @@ class Auth {
98
102
  _tokenValidator = null;
99
103
  _postponed = false;
100
104
  _backendCheckPromise = null;
105
+ _forceTokenUpdatePromise = null;
101
106
  _authDialogService = undefined;
102
107
  _domainStorage;
103
108
  user = null;
@@ -149,6 +154,7 @@ class Auth {
149
154
  });
150
155
  this._requestBuilder = new AuthRequestBuilder({
151
156
  authorization: this.config.serverUri + Auth.API_PATH + Auth.API_AUTH_PATH,
157
+ logout: this.config.serverUri + Auth.API_PATH + Auth.API_LOGOUT_PATH,
152
158
  clientId,
153
159
  redirect,
154
160
  redirectUri,
@@ -251,6 +257,8 @@ class Auth {
251
257
  throw error;
252
258
  }
253
259
  if (this._canShowDialogs()) {
260
+ // eslint-disable-next-line no-console
261
+ console.error('RingUI Auth: Init failure', error);
254
262
  this._showAuthDialog({
255
263
  nonInteractive: true,
256
264
  error
@@ -270,7 +278,7 @@ class Auth {
270
278
  if (this.user && userID === this.user.id) {
271
279
  return;
272
280
  }
273
- this.forceTokenUpdate();
281
+ this.forceTokenUpdate().catch(noop);
274
282
  });
275
283
  let state;
276
284
  try {
@@ -294,7 +302,7 @@ class Auth {
294
302
  serviceID
295
303
  } = message;
296
304
  if (serviceID !== this.config.clientId && (!userID || this.user?.id !== userID)) {
297
- this.forceTokenUpdate();
305
+ this.forceTokenUpdate().catch(noop);
298
306
  }
299
307
  }
300
308
  // Access token appears to be valid.
@@ -389,9 +397,27 @@ class Auth {
389
397
  }
390
398
  /**
391
399
  * Get new token in the background or redirect to the login page.
392
- * @return {Promise.<string>}
400
+ *
401
+ * Retries background token refresh with delays from {@link AuthConfig.tokenRefreshRetryDelays}
402
+ * with increasing delays before showing the auth dialog.
403
+ * This handles transient failures that commonly occur after network
404
+ * recovery (e.g. waking from sleep, switching networks) where the first
405
+ * iframe-based auth attempt fails but a subsequent one succeeds once
406
+ * the Hub session is re-established.
407
+ *
408
+ * @return {Promise.<string | null>}
393
409
  */
394
- async forceTokenUpdate() {
410
+ forceTokenUpdate() {
411
+ if (this._forceTokenUpdatePromise) {
412
+ return this._forceTokenUpdatePromise;
413
+ }
414
+ this._forceTokenUpdatePromise = this._doForceTokenUpdate().finally(() => {
415
+ this._forceTokenUpdatePromise = null;
416
+ });
417
+ return this._forceTokenUpdatePromise;
418
+ }
419
+ async _doForceTokenUpdate() {
420
+ var _lastError$message;
395
421
  try {
396
422
  if (!this._backendCheckPromise) {
397
423
  this._backendCheckPromise = this._checkBackendsStatusesIfEnabled();
@@ -402,43 +428,47 @@ class Auth {
402
428
  } finally {
403
429
  this._backendCheckPromise = null;
404
430
  }
405
- try {
406
- var _await$this$_backgrou;
407
- return (_await$this$_backgrou = await this._backgroundFlow?.authorize()) !== null && _await$this$_backgrou !== void 0 ? _await$this$_backgrou : null;
408
- } catch (error) {
409
- if (!(error instanceof Error)) {
410
- return null;
431
+ let lastError = null;
432
+ for (const delay of this.config.tokenRefreshRetryDelays) {
433
+ if (delay > 0) {
434
+ await new Promise(resolve => setTimeout(resolve, delay));
411
435
  }
412
- if (this._canShowDialogs()) {
413
- return new Promise(resolve => {
414
- const onTryAgain = async () => {
415
- try {
416
- const result = await this._backgroundFlow?.authorize();
417
- resolve(result !== null && result !== void 0 ? result : null);
418
- } catch (retryError) {
419
- if (retryError instanceof Error) {
420
- this._showAuthDialog({
421
- nonInteractive: true,
422
- error: retryError,
423
- onTryAgain
424
- });
425
- }
426
- throw retryError;
436
+ try {
437
+ var _await$this$_backgrou;
438
+ return (_await$this$_backgrou = await this._backgroundFlow?.authorize()) !== null && _await$this$_backgrou !== void 0 ? _await$this$_backgrou : null;
439
+ } catch (error) {
440
+ lastError = error instanceof Error ? error : new Error(String(error));
441
+ }
442
+ }
443
+ if (this._canShowDialogs()) {
444
+ return new Promise(resolve => {
445
+ const onTryAgain = async () => {
446
+ try {
447
+ const result = await this._backgroundFlow?.authorize();
448
+ resolve(result !== null && result !== void 0 ? result : null);
449
+ } catch (retryError) {
450
+ if (retryError instanceof Error) {
451
+ this._showAuthDialog({
452
+ nonInteractive: true,
453
+ error: retryError,
454
+ onTryAgain
455
+ });
427
456
  }
428
- };
429
- this._showAuthDialog({
430
- nonInteractive: true,
431
- error: error,
432
- onTryAgain
433
- });
457
+ throw retryError;
458
+ }
459
+ };
460
+ this._showAuthDialog({
461
+ nonInteractive: true,
462
+ error: lastError,
463
+ onTryAgain
434
464
  });
435
- }
436
- const authRequest = await this._requestBuilder?.prepareAuthRequest();
437
- if (authRequest) {
438
- this._redirectCurrentPage(authRequest.url);
439
- }
440
- throw new TokenValidator.TokenValidationError(error.message);
465
+ });
466
+ }
467
+ const authRequest = await this._requestBuilder?.prepareAuthRequest();
468
+ if (authRequest) {
469
+ this._redirectCurrentPage(authRequest.url);
441
470
  }
471
+ throw new TokenValidator.TokenValidationError((_lastError$message = lastError?.message) !== null && _lastError$message !== void 0 ? _lastError$message : 'Failed to refresh token');
442
472
  }
443
473
  async loadCurrentService() {
444
474
  if (this._service.serviceName) {
@@ -523,7 +553,13 @@ class Auth {
523
553
  }
524
554
  _beforeLogout(params) {
525
555
  if (this._canShowDialogs()) {
526
- this._showAuthDialog(params);
556
+ const onTryAgain = async () => {
557
+ await this.forceTokenUpdate();
558
+ };
559
+ this._showAuthDialog({
560
+ onTryAgain,
561
+ ...params
562
+ });
527
563
  return;
528
564
  }
529
565
  this.logout();
@@ -568,7 +604,7 @@ class Auth {
568
604
  return;
569
605
  }
570
606
  if (this.user?.guest && nonInteractive) {
571
- this.forceTokenUpdate();
607
+ this.forceTokenUpdate().catch(noop);
572
608
  } else {
573
609
  this._initDeferred?.resolve?.();
574
610
  }
@@ -698,20 +734,22 @@ class Auth {
698
734
  });
699
735
  }
700
736
  /**
701
- * Wipe accessToken and redirect to auth page with required authorization
737
+ * Wipe accessToken and redirect to logout endpoint.
738
+ * Uses RP-initiated logout flow (oauth2/logout) when rpInitiatedLogout config is enabled,
739
+ * falls back to oauth2/auth redirect otherwise.
740
+ * See: https://youtrack.jetbrains.com/projects/HUB/articles/HUB-A-43#rp-initiated-logout
702
741
  */
703
742
  async logout(extraParams) {
704
- const requestParams = {
705
- request_credentials: 'required',
706
- ...extraParams
707
- };
708
743
  await this._checkBackendsStatusesIfEnabled();
709
744
  await this.listeners.trigger('logout');
710
745
  this._updateDomainUser(null);
711
746
  await this._storage?.wipeToken();
712
- const authRequest = await this._requestBuilder?.prepareAuthRequest(requestParams);
713
- if (authRequest) {
714
- this._redirectCurrentPage(authRequest.url);
747
+ const request = this.config.rpInitiatedLogout ? await this._requestBuilder?.prepareLogoutRequest(extraParams) : await this._requestBuilder?.prepareAuthRequest({
748
+ request_credentials: 'required',
749
+ ...extraParams
750
+ });
751
+ if (request) {
752
+ this._redirectCurrentPage(request.url);
715
753
  }
716
754
  }
717
755
  async _runEmbeddedLogin() {
@@ -743,6 +781,8 @@ class Auth {
743
781
  this.listeners.trigger(USER_CHANGED_EVENT, user);
744
782
  }
745
783
  } catch (e) {
784
+ // eslint-disable-next-line no-console
785
+ console.error('RingUI Auth: login failure', e);
746
786
  this._beforeLogout();
747
787
  }
748
788
  }
@@ -916,4 +956,4 @@ class Auth {
916
956
  }
917
957
  }
918
958
 
919
- export { Auth, DEFAULT_BACKGROUND_TIMEOUT, DEFAULT_EXPIRES_TIMEOUT, DOMAIN_USER_CHANGED_EVENT, LOGOUT_EVENT, LOGOUT_POSTPONED_EVENT, USER_CHANGED_EVENT, USER_CHANGE_POSTPONED_EVENT, Auth as default };
959
+ export { Auth, DEFAULT_BACKGROUND_TIMEOUT, DEFAULT_EXPIRES_TIMEOUT, DOMAIN_USER_CHANGED_EVENT, LOGOUT_EVENT, LOGOUT_POSTPONED_EVENT, TOKEN_REFRESH_RETRY_DELAYS, USER_CHANGED_EVENT, USER_CHANGE_POSTPONED_EVENT, Auth as default };
@@ -1,7 +1,7 @@
1
1
  import WindowFlow from './window-flow.js';
2
2
  import onBackendDown from './down-notification.js';
3
3
  import { Auth } from './auth-core.js';
4
- export { DEFAULT_BACKGROUND_TIMEOUT, DEFAULT_EXPIRES_TIMEOUT, DOMAIN_USER_CHANGED_EVENT, LOGOUT_EVENT, LOGOUT_POSTPONED_EVENT, USER_CHANGED_EVENT, USER_CHANGE_POSTPONED_EVENT } from './auth-core.js';
4
+ export { DEFAULT_BACKGROUND_TIMEOUT, DEFAULT_EXPIRES_TIMEOUT, DOMAIN_USER_CHANGED_EVENT, LOGOUT_EVENT, LOGOUT_POSTPONED_EVENT, TOKEN_REFRESH_RETRY_DELAYS, USER_CHANGED_EVENT, USER_CHANGE_POSTPONED_EVENT } from './auth-core.js';
5
5
  import './response-parser.js';
6
6
  import '../global/url.js';
7
7
  import 'react-compiler-runtime';
@@ -3,6 +3,7 @@ import type { AuthState } from './storage';
3
3
  import type AuthStorage from './storage';
4
4
  export interface AuthRequestBuilderConfig {
5
5
  authorization: string;
6
+ logout?: string | null | undefined;
6
7
  redirectUri?: string | null | undefined;
7
8
  requestCredentials?: string | null | undefined;
8
9
  clientId?: string | null | undefined;
@@ -38,6 +39,17 @@ export default class AuthRequestBuilder {
38
39
  url: string;
39
40
  stateId: string;
40
41
  }>;
42
+ /**
43
+ * Build a logout URL for RP-initiated logout flow.
44
+ * See: https://youtrack.jetbrains.com/projects/HUB/articles/HUB-A-43#rp-initiated-logout
45
+ *
46
+ * @param {object=} extraParams additional query parameters for logout request
47
+ * @return {Promise.<{url: string, stateId: string}>} logout URL with required parameters
48
+ */
49
+ prepareLogoutRequest(extraParams?: Record<string, unknown> | null | undefined): Promise<{
50
+ url: string;
51
+ stateId: string;
52
+ }>;
41
53
  /**
42
54
  * @param {string} id
43
55
  * @param {StoredState} storedState
@@ -52,6 +52,33 @@ class AuthRequestBuilder {
52
52
  stateId
53
53
  };
54
54
  }
55
+ /**
56
+ * Build a logout URL for RP-initiated logout flow.
57
+ * See: https://youtrack.jetbrains.com/projects/HUB/articles/HUB-A-43#rp-initiated-logout
58
+ *
59
+ * @param {object=} extraParams additional query parameters for logout request
60
+ * @return {Promise.<{url: string, stateId: string}>} logout URL with required parameters
61
+ */
62
+ async prepareLogoutRequest(extraParams) {
63
+ if (!this.config.logout) {
64
+ throw new Error('Logout URL is not configured');
65
+ }
66
+ // eslint-disable-next-line no-underscore-dangle
67
+ const stateId = AuthRequestBuilder._uuid();
68
+ const logoutParams = {
69
+ client_id: this.config.clientId,
70
+ state: stateId,
71
+ ...extraParams
72
+ };
73
+ await this._saveState(stateId, {
74
+ restoreLocation: window.location.href,
75
+ scopes: [...this.config.scopes]
76
+ });
77
+ return {
78
+ url: encodeURL(this.config.logout, logoutParams),
79
+ stateId
80
+ };
81
+ }
55
82
  /**
56
83
  * @param {string} id
57
84
  * @param {StoredState} storedState
@@ -109,7 +109,7 @@ export default class List<T = unknown> extends Component<ListProps<T>, ListState
109
109
  };
110
110
  componentDidMount(): void;
111
111
  shouldComponentUpdate(nextProps: ListProps<T>, nextState: ListState<T>): boolean;
112
- componentDidUpdate(prevProps: ListProps<T>): void;
112
+ componentDidUpdate(prevProps: ListProps<T>, prevState: ListState<T>): void;
113
113
  componentWillUnmount(): void;
114
114
  scheduleScrollListener: (cb: () => void) => void;
115
115
  static isItemType: typeof isItemType;
@@ -155,13 +155,24 @@ class List extends Component {
155
155
  shouldComponentUpdate(nextProps, nextState) {
156
156
  return Object.keys(nextProps).some(key => !Object.is(nextProps[key], this.props[key])) || Object.keys(nextState).some(key => nextState[key] !== this.state[key]);
157
157
  }
158
- componentDidUpdate(prevProps) {
158
+ componentDidUpdate(prevProps, prevState) {
159
159
  if (this.virtualizedList && prevProps.data !== this.props.data) {
160
160
  this.virtualizedList.recomputeRowHeights();
161
161
  }
162
162
  const {
163
163
  activeIndex
164
164
  } = this.state;
165
+ if (!this.virtualizedList && !this.props.disableScrollToActive && this.state.needScrollToActive && activeIndex != null && activeIndex !== prevState.activeIndex) {
166
+ const itemId = this.getId(this.props.data[activeIndex]);
167
+ if (itemId) {
168
+ document.getElementById(itemId)?.scrollIntoView?.({
169
+ block: 'center'
170
+ });
171
+ }
172
+ this.setState({
173
+ needScrollToActive: false
174
+ });
175
+ }
165
176
  const isActiveItemRetainedPosition = activeIndex ? prevProps.data[activeIndex]?.key === this.props.data[activeIndex]?.key : false;
166
177
  if ((this.props.activeIndex === null || this.props.activeIndex === undefined) && getDataHash(this.props.data) !== getDataHash(prevProps.data) && shouldActivateFirstItem(this.props) && !isActiveItemRetainedPosition) {
167
178
  this.activateFirst();
@@ -5,11 +5,11 @@ const MAJOR_VERSION_INDEX = 0;
5
5
  /**
6
6
  * SUPPORTED_BROWSERS are defined by Babel plugin, see babel config
7
7
  */
8
- if (!["and_chr 144", "and_ff 147", "and_qq 14.9", "and_uc 15.5", "android 144", "chrome 144", "chrome 143", "chrome 142", "chrome 141", "chrome 140", "chrome 139", "chrome 138", "chrome 137", "chrome 136", "chrome 135", "chrome 134", "chrome 133", "chrome 132", "chrome 131", "chrome 130", "chrome 129", "chrome 128", "chrome 127", "chrome 126", "chrome 125", "chrome 124", "chrome 123", "chrome 122", "chrome 121", "chrome 120", "chrome 119", "chrome 118", "chrome 117", "chrome 116", "chrome 115", "chrome 112", "chrome 109", "edge 144", "edge 143", "edge 142", "edge 141", "edge 140", "edge 139", "edge 138", "edge 137", "edge 136", "edge 135", "edge 134", "edge 133", "edge 132", "edge 131", "edge 130", "edge 129", "edge 128", "edge 127", "edge 126", "edge 125", "edge 124", "edge 123", "edge 122", "edge 121", "edge 120", "edge 119", "edge 118", "edge 117", "edge 116", "edge 115", "firefox 147", "firefox 146", "firefox 145", "firefox 144", "firefox 143", "firefox 142", "firefox 141", "firefox 140", "firefox 139", "firefox 138", "firefox 137", "firefox 136", "firefox 135", "firefox 134", "firefox 133", "firefox 132", "firefox 131", "firefox 130", "firefox 129", "firefox 128", "firefox 127", "firefox 126", "firefox 125", "firefox 124", "firefox 123", "firefox 122", "firefox 121", "firefox 120", "firefox 119", "firefox 118", "firefox 117", "firefox 116", "ios_saf 26.2", "ios_saf 26.1", "ios_saf 26.0", "ios_saf 18.5-18.7", "ios_saf 18.4", "ios_saf 18.3", "ios_saf 18.2", "ios_saf 18.1", "ios_saf 18.0", "ios_saf 17.6-17.7", "ios_saf 17.5", "ios_saf 17.4", "ios_saf 17.3", "ios_saf 17.2", "ios_saf 17.1", "ios_saf 17.0", "ios_saf 16.6-16.7", "ios_saf 16.5", "ios_saf 16.4", "kaios 3.0-3.1", "kaios 2.5", "op_mini all", "op_mob 80", "opera 125", "opera 124", "safari 26.2", "safari 26.1", "safari 26.0", "safari 18.5-18.6", "safari 18.4", "safari 18.3", "safari 18.2", "safari 18.1", "safari 18.0", "safari 17.6", "safari 17.5", "safari 17.4", "safari 17.3", "safari 17.2", "safari 17.1", "safari 17.0", "safari 16.6", "safari 16.5", "safari 16.4", "samsung 29", "samsung 28"]) {
8
+ if (!["and_chr 144", "and_ff 147", "and_qq 14.9", "and_uc 15.5", "android 144", "chrome 145", "chrome 144", "chrome 143", "chrome 142", "chrome 141", "chrome 140", "chrome 139", "chrome 138", "chrome 137", "chrome 136", "chrome 135", "chrome 134", "chrome 133", "chrome 132", "chrome 131", "chrome 130", "chrome 129", "chrome 128", "chrome 127", "chrome 126", "chrome 125", "chrome 124", "chrome 123", "chrome 122", "chrome 121", "chrome 120", "chrome 119", "chrome 118", "chrome 117", "chrome 116", "chrome 115", "chrome 112", "chrome 109", "edge 144", "edge 143", "edge 142", "edge 141", "edge 140", "edge 139", "edge 138", "edge 137", "edge 136", "edge 135", "edge 134", "edge 133", "edge 132", "edge 131", "edge 130", "edge 129", "edge 128", "edge 127", "edge 126", "edge 125", "edge 124", "edge 123", "edge 122", "edge 121", "edge 120", "edge 119", "edge 118", "edge 117", "edge 116", "edge 115", "firefox 147", "firefox 146", "firefox 145", "firefox 144", "firefox 143", "firefox 142", "firefox 141", "firefox 140", "firefox 139", "firefox 138", "firefox 137", "firefox 136", "firefox 135", "firefox 134", "firefox 133", "firefox 132", "firefox 131", "firefox 130", "firefox 129", "firefox 128", "firefox 127", "firefox 126", "firefox 125", "firefox 124", "firefox 123", "firefox 122", "firefox 121", "firefox 120", "firefox 119", "firefox 118", "firefox 117", "firefox 116", "ios_saf 26.3", "ios_saf 26.2", "ios_saf 26.1", "ios_saf 26.0", "ios_saf 18.5-18.7", "ios_saf 18.4", "ios_saf 18.3", "ios_saf 18.2", "ios_saf 18.1", "ios_saf 18.0", "ios_saf 17.6-17.7", "ios_saf 17.5", "ios_saf 17.4", "ios_saf 17.3", "ios_saf 17.2", "ios_saf 17.1", "ios_saf 17.0", "ios_saf 16.6-16.7", "ios_saf 16.5", "ios_saf 16.4", "kaios 3.0-3.1", "kaios 2.5", "op_mini all", "op_mob 80", "opera 125", "opera 124", "safari 26.3", "safari 26.2", "safari 26.1", "safari 26.0", "safari 18.5-18.6", "safari 18.4", "safari 18.3", "safari 18.2", "safari 18.1", "safari 18.0", "safari 17.6", "safari 17.5", "safari 17.4", "safari 17.3", "safari 17.2", "safari 17.1", "safari 17.0", "safari 16.6", "safari 16.5", "safari 16.4", "samsung 29", "samsung 28"]) {
9
9
  // eslint-disable-next-line no-console
10
10
  console.warn('Ring UI: no SUPPORTED_BROWSERS passed. Please check babel config.');
11
11
  }
12
- const SUPPORTED = ["and_chr 144", "and_ff 147", "and_qq 14.9", "and_uc 15.5", "android 144", "chrome 144", "chrome 143", "chrome 142", "chrome 141", "chrome 140", "chrome 139", "chrome 138", "chrome 137", "chrome 136", "chrome 135", "chrome 134", "chrome 133", "chrome 132", "chrome 131", "chrome 130", "chrome 129", "chrome 128", "chrome 127", "chrome 126", "chrome 125", "chrome 124", "chrome 123", "chrome 122", "chrome 121", "chrome 120", "chrome 119", "chrome 118", "chrome 117", "chrome 116", "chrome 115", "chrome 112", "chrome 109", "edge 144", "edge 143", "edge 142", "edge 141", "edge 140", "edge 139", "edge 138", "edge 137", "edge 136", "edge 135", "edge 134", "edge 133", "edge 132", "edge 131", "edge 130", "edge 129", "edge 128", "edge 127", "edge 126", "edge 125", "edge 124", "edge 123", "edge 122", "edge 121", "edge 120", "edge 119", "edge 118", "edge 117", "edge 116", "edge 115", "firefox 147", "firefox 146", "firefox 145", "firefox 144", "firefox 143", "firefox 142", "firefox 141", "firefox 140", "firefox 139", "firefox 138", "firefox 137", "firefox 136", "firefox 135", "firefox 134", "firefox 133", "firefox 132", "firefox 131", "firefox 130", "firefox 129", "firefox 128", "firefox 127", "firefox 126", "firefox 125", "firefox 124", "firefox 123", "firefox 122", "firefox 121", "firefox 120", "firefox 119", "firefox 118", "firefox 117", "firefox 116", "ios_saf 26.2", "ios_saf 26.1", "ios_saf 26.0", "ios_saf 18.5-18.7", "ios_saf 18.4", "ios_saf 18.3", "ios_saf 18.2", "ios_saf 18.1", "ios_saf 18.0", "ios_saf 17.6-17.7", "ios_saf 17.5", "ios_saf 17.4", "ios_saf 17.3", "ios_saf 17.2", "ios_saf 17.1", "ios_saf 17.0", "ios_saf 16.6-16.7", "ios_saf 16.5", "ios_saf 16.4", "kaios 3.0-3.1", "kaios 2.5", "op_mini all", "op_mob 80", "opera 125", "opera 124", "safari 26.2", "safari 26.1", "safari 26.0", "safari 18.5-18.6", "safari 18.4", "safari 18.3", "safari 18.2", "safari 18.1", "safari 18.0", "safari 17.6", "safari 17.5", "safari 17.4", "safari 17.3", "safari 17.2", "safari 17.1", "safari 17.0", "safari 16.6", "safari 16.5", "safari 16.4", "samsung 29", "samsung 28"] || [];
12
+ const SUPPORTED = ["and_chr 144", "and_ff 147", "and_qq 14.9", "and_uc 15.5", "android 144", "chrome 145", "chrome 144", "chrome 143", "chrome 142", "chrome 141", "chrome 140", "chrome 139", "chrome 138", "chrome 137", "chrome 136", "chrome 135", "chrome 134", "chrome 133", "chrome 132", "chrome 131", "chrome 130", "chrome 129", "chrome 128", "chrome 127", "chrome 126", "chrome 125", "chrome 124", "chrome 123", "chrome 122", "chrome 121", "chrome 120", "chrome 119", "chrome 118", "chrome 117", "chrome 116", "chrome 115", "chrome 112", "chrome 109", "edge 144", "edge 143", "edge 142", "edge 141", "edge 140", "edge 139", "edge 138", "edge 137", "edge 136", "edge 135", "edge 134", "edge 133", "edge 132", "edge 131", "edge 130", "edge 129", "edge 128", "edge 127", "edge 126", "edge 125", "edge 124", "edge 123", "edge 122", "edge 121", "edge 120", "edge 119", "edge 118", "edge 117", "edge 116", "edge 115", "firefox 147", "firefox 146", "firefox 145", "firefox 144", "firefox 143", "firefox 142", "firefox 141", "firefox 140", "firefox 139", "firefox 138", "firefox 137", "firefox 136", "firefox 135", "firefox 134", "firefox 133", "firefox 132", "firefox 131", "firefox 130", "firefox 129", "firefox 128", "firefox 127", "firefox 126", "firefox 125", "firefox 124", "firefox 123", "firefox 122", "firefox 121", "firefox 120", "firefox 119", "firefox 118", "firefox 117", "firefox 116", "ios_saf 26.3", "ios_saf 26.2", "ios_saf 26.1", "ios_saf 26.0", "ios_saf 18.5-18.7", "ios_saf 18.4", "ios_saf 18.3", "ios_saf 18.2", "ios_saf 18.1", "ios_saf 18.0", "ios_saf 17.6-17.7", "ios_saf 17.5", "ios_saf 17.4", "ios_saf 17.3", "ios_saf 17.2", "ios_saf 17.1", "ios_saf 17.0", "ios_saf 16.6-16.7", "ios_saf 16.5", "ios_saf 16.4", "kaios 3.0-3.1", "kaios 2.5", "op_mini all", "op_mob 80", "opera 125", "opera 124", "safari 26.3", "safari 26.2", "safari 26.1", "safari 26.0", "safari 18.5-18.6", "safari 18.4", "safari 18.3", "safari 18.2", "safari 18.1", "safari 18.0", "safari 17.6", "safari 17.5", "safari 17.4", "safari 17.3", "safari 17.2", "safari 17.1", "safari 17.0", "safari 16.6", "safari 16.5", "safari 16.4", "samsung 29", "samsung 28"] || [];
13
13
  const WHITE_LISTED_BROWSERS = ['chrome', 'firefox', 'safari', 'edge'];
14
14
  const WHITE_LIST = SUPPORTED.reduce((acc, item) => {
15
15
  var _item$match;