@extrahorizon/javascript-sdk 8.14.2-dev-207-77c1c66 → 8.14.2-dev-211-13941b3

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/CHANGELOG.md CHANGED
@@ -5,6 +5,13 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [8.14.2]
9
+
10
+ ### Fixed
11
+ - OAuth2 token refreshes are now shared between parallel requests, no longer invalidating each other
12
+ - Response transformations are no longer applied twice to retried requests
13
+ - Retry handling no longer masks internally generated errors as `TypeError: Cannot destructure property 'retry' of 'config' as it is undefined`
14
+
8
15
  ## [8.14.1]
9
16
 
10
17
  ### Fixed
@@ -1752,11 +1752,13 @@ function typeReceivedError(error) {
1752
1752
  }
1753
1753
 
1754
1754
  const retryInterceptor = (axios) => async (error) => {
1755
+ if (!error || !error.isAxiosError || !error.config) {
1756
+ throw error;
1757
+ }
1755
1758
  const { config } = error;
1756
1759
  const { retry } = config;
1757
1760
  // tries includes the initial try. So 5 tries equals 4 retries
1758
- if ((error === null || error === void 0 ? void 0 : error.isAxiosError) &&
1759
- (retry === null || retry === void 0 ? void 0 : retry.tries) > (retry === null || retry === void 0 ? void 0 : retry.current) &&
1761
+ if ((retry === null || retry === void 0 ? void 0 : retry.tries) > (retry === null || retry === void 0 ? void 0 : retry.current) &&
1760
1762
  (retry === null || retry === void 0 ? void 0 : retry.retryCondition(error))) {
1761
1763
  await delay(retry.retryTimeInMs);
1762
1764
  return axios({
@@ -2235,11 +2237,11 @@ function createOAuth1HttpClient(http, options) {
2235
2237
  {}),
2236
2238
  },
2237
2239
  }));
2238
- httpWithAuth.interceptors.response.use(null, retryInterceptor(httpWithAuth));
2239
- httpWithAuth.interceptors.response.use(null, typeReceivedErrorsInterceptor);
2240
2240
  httpWithAuth.interceptors.response.use(camelizeResponseData);
2241
2241
  httpWithAuth.interceptors.response.use(transformResponseData);
2242
2242
  httpWithAuth.interceptors.response.use(transformKeysResponseData);
2243
+ httpWithAuth.interceptors.response.use(null, retryInterceptor(httpWithAuth));
2244
+ httpWithAuth.interceptors.response.use(null, typeReceivedErrorsInterceptor);
2243
2245
  async function authenticate(data) {
2244
2246
  // If the user has passed in a token/tokenSecret combination.
2245
2247
  // Validate it against /users/me on the unauthenticated Axios client unless skipTokenCheck is true
@@ -2390,6 +2392,7 @@ function btoa(input) {
2390
2392
  const TOKEN_ENDPOINT = `${AUTH_BASE}/oauth2/tokens`;
2391
2393
  function createOAuth2HttpClient(http, options) {
2392
2394
  let tokenData;
2395
+ let refreshingTokensPromise = null;
2393
2396
  if ('refreshToken' in options && 'accessToken' in options) {
2394
2397
  tokenData = {
2395
2398
  refreshToken: options.refreshToken,
@@ -2443,7 +2446,7 @@ function createOAuth2HttpClient(http, options) {
2443
2446
  // Refresh 10 seconds before the token is about to expire.
2444
2447
  // This is to prevent being just too late with a refresh of the token due to latencies
2445
2448
  if (Date.now() > expireTime - 10 * 1000) {
2446
- await authenticate({ refreshToken: tokenData.refreshToken });
2449
+ await refreshTokens();
2447
2450
  }
2448
2451
  }
2449
2452
  return {
@@ -2454,6 +2457,9 @@ function createOAuth2HttpClient(http, options) {
2454
2457
  },
2455
2458
  };
2456
2459
  });
2460
+ httpWithAuth.interceptors.response.use(camelizeResponseData);
2461
+ httpWithAuth.interceptors.response.use(transformResponseData);
2462
+ httpWithAuth.interceptors.response.use(transformKeysResponseData);
2457
2463
  httpWithAuth.interceptors.response.use(null, retryInterceptor(httpWithAuth));
2458
2464
  // If we receive a expired/unknown access token error, refresh the tokens
2459
2465
  httpWithAuth.interceptors.response.use(null, async (error) => {
@@ -2467,15 +2473,12 @@ function createOAuth2HttpClient(http, options) {
2467
2473
  [118, 117].includes((_b = (_a = error.response) === null || _a === void 0 ? void 0 : _a.data) === null || _b === void 0 ? void 0 : _b.code) &&
2468
2474
  !originalRequest.isRetryWithRefreshedTokens) {
2469
2475
  originalRequest.isRetryWithRefreshedTokens = true;
2470
- await authenticate({ refreshToken: tokenData.refreshToken });
2476
+ await refreshTokens();
2471
2477
  return httpWithAuth(originalRequest);
2472
2478
  }
2473
2479
  throw error;
2474
2480
  });
2475
2481
  httpWithAuth.interceptors.response.use(null, typeReceivedErrorsInterceptor);
2476
- httpWithAuth.interceptors.response.use(camelizeResponseData);
2477
- httpWithAuth.interceptors.response.use(transformResponseData);
2478
- httpWithAuth.interceptors.response.use(transformKeysResponseData);
2479
2482
  /**
2480
2483
  * - Adds a creationTimestamp to the token
2481
2484
  * - Notifies the user
@@ -2508,6 +2511,18 @@ function createOAuth2HttpClient(http, options) {
2508
2511
  {});
2509
2512
  return await dateAndSetTokenData(tokenResult.data);
2510
2513
  }
2514
+ async function refreshTokens() {
2515
+ if (refreshingTokensPromise) {
2516
+ return refreshingTokensPromise;
2517
+ }
2518
+ refreshingTokensPromise = authenticate({ refreshToken: tokenData.refreshToken });
2519
+ try {
2520
+ return await refreshingTokensPromise;
2521
+ }
2522
+ finally {
2523
+ refreshingTokensPromise = null;
2524
+ }
2525
+ }
2511
2526
  async function confirmMfa({ token, methodId, code, }) {
2512
2527
  const tokenResult = await http.post(TOKEN_ENDPOINT, {
2513
2528
  ...clientCredentials,
@@ -2629,11 +2644,11 @@ function createProxyHttpClient(http, options) {
2629
2644
  return Promise.reject(error);
2630
2645
  });
2631
2646
  }
2632
- httpWithAuth.interceptors.response.use(null, retryInterceptor(httpWithAuth));
2633
- httpWithAuth.interceptors.response.use(null, typeReceivedErrorsInterceptor);
2634
2647
  httpWithAuth.interceptors.response.use(camelizeResponseData);
2635
2648
  httpWithAuth.interceptors.response.use(transformResponseData);
2636
2649
  httpWithAuth.interceptors.response.use(transformKeysResponseData);
2650
+ httpWithAuth.interceptors.response.use(null, retryInterceptor(httpWithAuth));
2651
+ httpWithAuth.interceptors.response.use(null, typeReceivedErrorsInterceptor);
2637
2652
  async function logout() {
2638
2653
  try {
2639
2654
  await httpWithAuth.post('/logout');
@@ -2694,11 +2709,11 @@ function createHttpClient({ packageVersion, host, requestLogger, responseLogger,
2694
2709
  return Promise.reject(error);
2695
2710
  });
2696
2711
  }
2697
- http.interceptors.response.use(null, retryInterceptor(http));
2698
- http.interceptors.response.use(null, typeReceivedErrorsInterceptor);
2699
2712
  http.interceptors.response.use(camelizeResponseData);
2700
2713
  http.interceptors.response.use(transformResponseData);
2701
2714
  http.interceptors.response.use(transformKeysResponseData);
2715
+ http.interceptors.response.use(null, retryInterceptor(http));
2716
+ http.interceptors.response.use(null, typeReceivedErrorsInterceptor);
2702
2717
  return http;
2703
2718
  }
2704
2719
 
@@ -5768,7 +5783,7 @@ const templatesV2Service = (httpWithAuth) => {
5768
5783
  };
5769
5784
  };
5770
5785
 
5771
- const version = '8.14.2-dev-207-77c1c66';
5786
+ const version = '8.14.2-dev-211-13941b3';
5772
5787
 
5773
5788
  /**
5774
5789
  * Create ExtraHorizon client.
package/build/index.mjs CHANGED
@@ -1722,11 +1722,13 @@ function typeReceivedError(error) {
1722
1722
  }
1723
1723
 
1724
1724
  const retryInterceptor = (axios) => async (error) => {
1725
+ if (!error || !error.isAxiosError || !error.config) {
1726
+ throw error;
1727
+ }
1725
1728
  const { config } = error;
1726
1729
  const { retry } = config;
1727
1730
  // tries includes the initial try. So 5 tries equals 4 retries
1728
- if ((error === null || error === void 0 ? void 0 : error.isAxiosError) &&
1729
- (retry === null || retry === void 0 ? void 0 : retry.tries) > (retry === null || retry === void 0 ? void 0 : retry.current) &&
1731
+ if ((retry === null || retry === void 0 ? void 0 : retry.tries) > (retry === null || retry === void 0 ? void 0 : retry.current) &&
1730
1732
  (retry === null || retry === void 0 ? void 0 : retry.retryCondition(error))) {
1731
1733
  await delay(retry.retryTimeInMs);
1732
1734
  return axios({
@@ -2205,11 +2207,11 @@ function createOAuth1HttpClient(http, options) {
2205
2207
  {}),
2206
2208
  },
2207
2209
  }));
2208
- httpWithAuth.interceptors.response.use(null, retryInterceptor(httpWithAuth));
2209
- httpWithAuth.interceptors.response.use(null, typeReceivedErrorsInterceptor);
2210
2210
  httpWithAuth.interceptors.response.use(camelizeResponseData);
2211
2211
  httpWithAuth.interceptors.response.use(transformResponseData);
2212
2212
  httpWithAuth.interceptors.response.use(transformKeysResponseData);
2213
+ httpWithAuth.interceptors.response.use(null, retryInterceptor(httpWithAuth));
2214
+ httpWithAuth.interceptors.response.use(null, typeReceivedErrorsInterceptor);
2213
2215
  async function authenticate(data) {
2214
2216
  // If the user has passed in a token/tokenSecret combination.
2215
2217
  // Validate it against /users/me on the unauthenticated Axios client unless skipTokenCheck is true
@@ -2360,6 +2362,7 @@ function btoa(input) {
2360
2362
  const TOKEN_ENDPOINT = `${AUTH_BASE}/oauth2/tokens`;
2361
2363
  function createOAuth2HttpClient(http, options) {
2362
2364
  let tokenData;
2365
+ let refreshingTokensPromise = null;
2363
2366
  if ('refreshToken' in options && 'accessToken' in options) {
2364
2367
  tokenData = {
2365
2368
  refreshToken: options.refreshToken,
@@ -2413,7 +2416,7 @@ function createOAuth2HttpClient(http, options) {
2413
2416
  // Refresh 10 seconds before the token is about to expire.
2414
2417
  // This is to prevent being just too late with a refresh of the token due to latencies
2415
2418
  if (Date.now() > expireTime - 10 * 1000) {
2416
- await authenticate({ refreshToken: tokenData.refreshToken });
2419
+ await refreshTokens();
2417
2420
  }
2418
2421
  }
2419
2422
  return {
@@ -2424,6 +2427,9 @@ function createOAuth2HttpClient(http, options) {
2424
2427
  },
2425
2428
  };
2426
2429
  });
2430
+ httpWithAuth.interceptors.response.use(camelizeResponseData);
2431
+ httpWithAuth.interceptors.response.use(transformResponseData);
2432
+ httpWithAuth.interceptors.response.use(transformKeysResponseData);
2427
2433
  httpWithAuth.interceptors.response.use(null, retryInterceptor(httpWithAuth));
2428
2434
  // If we receive a expired/unknown access token error, refresh the tokens
2429
2435
  httpWithAuth.interceptors.response.use(null, async (error) => {
@@ -2437,15 +2443,12 @@ function createOAuth2HttpClient(http, options) {
2437
2443
  [118, 117].includes((_b = (_a = error.response) === null || _a === void 0 ? void 0 : _a.data) === null || _b === void 0 ? void 0 : _b.code) &&
2438
2444
  !originalRequest.isRetryWithRefreshedTokens) {
2439
2445
  originalRequest.isRetryWithRefreshedTokens = true;
2440
- await authenticate({ refreshToken: tokenData.refreshToken });
2446
+ await refreshTokens();
2441
2447
  return httpWithAuth(originalRequest);
2442
2448
  }
2443
2449
  throw error;
2444
2450
  });
2445
2451
  httpWithAuth.interceptors.response.use(null, typeReceivedErrorsInterceptor);
2446
- httpWithAuth.interceptors.response.use(camelizeResponseData);
2447
- httpWithAuth.interceptors.response.use(transformResponseData);
2448
- httpWithAuth.interceptors.response.use(transformKeysResponseData);
2449
2452
  /**
2450
2453
  * - Adds a creationTimestamp to the token
2451
2454
  * - Notifies the user
@@ -2478,6 +2481,18 @@ function createOAuth2HttpClient(http, options) {
2478
2481
  {});
2479
2482
  return await dateAndSetTokenData(tokenResult.data);
2480
2483
  }
2484
+ async function refreshTokens() {
2485
+ if (refreshingTokensPromise) {
2486
+ return refreshingTokensPromise;
2487
+ }
2488
+ refreshingTokensPromise = authenticate({ refreshToken: tokenData.refreshToken });
2489
+ try {
2490
+ return await refreshingTokensPromise;
2491
+ }
2492
+ finally {
2493
+ refreshingTokensPromise = null;
2494
+ }
2495
+ }
2481
2496
  async function confirmMfa({ token, methodId, code, }) {
2482
2497
  const tokenResult = await http.post(TOKEN_ENDPOINT, {
2483
2498
  ...clientCredentials,
@@ -2599,11 +2614,11 @@ function createProxyHttpClient(http, options) {
2599
2614
  return Promise.reject(error);
2600
2615
  });
2601
2616
  }
2602
- httpWithAuth.interceptors.response.use(null, retryInterceptor(httpWithAuth));
2603
- httpWithAuth.interceptors.response.use(null, typeReceivedErrorsInterceptor);
2604
2617
  httpWithAuth.interceptors.response.use(camelizeResponseData);
2605
2618
  httpWithAuth.interceptors.response.use(transformResponseData);
2606
2619
  httpWithAuth.interceptors.response.use(transformKeysResponseData);
2620
+ httpWithAuth.interceptors.response.use(null, retryInterceptor(httpWithAuth));
2621
+ httpWithAuth.interceptors.response.use(null, typeReceivedErrorsInterceptor);
2607
2622
  async function logout() {
2608
2623
  try {
2609
2624
  await httpWithAuth.post('/logout');
@@ -2664,11 +2679,11 @@ function createHttpClient({ packageVersion, host, requestLogger, responseLogger,
2664
2679
  return Promise.reject(error);
2665
2680
  });
2666
2681
  }
2667
- http.interceptors.response.use(null, retryInterceptor(http));
2668
- http.interceptors.response.use(null, typeReceivedErrorsInterceptor);
2669
2682
  http.interceptors.response.use(camelizeResponseData);
2670
2683
  http.interceptors.response.use(transformResponseData);
2671
2684
  http.interceptors.response.use(transformKeysResponseData);
2685
+ http.interceptors.response.use(null, retryInterceptor(http));
2686
+ http.interceptors.response.use(null, typeReceivedErrorsInterceptor);
2672
2687
  return http;
2673
2688
  }
2674
2689
 
@@ -5738,7 +5753,7 @@ const templatesV2Service = (httpWithAuth) => {
5738
5753
  };
5739
5754
  };
5740
5755
 
5741
- const version = '8.14.2-dev-207-77c1c66';
5756
+ const version = '8.14.2-dev-211-13941b3';
5742
5757
 
5743
5758
  /**
5744
5759
  * Create ExtraHorizon client.
@@ -1 +1 @@
1
- export declare const version = "8.14.2-dev-207-77c1c66";
1
+ export declare const version = "8.14.2-dev-211-13941b3";
@@ -1 +1 @@
1
- export declare const version = "8.14.2-dev-207-77c1c66";
1
+ export declare const version = "8.14.2-dev-211-13941b3";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@extrahorizon/javascript-sdk",
3
- "version": "8.14.2-dev-207-77c1c66",
3
+ "version": "8.14.2-dev-211-13941b3",
4
4
  "description": "This package serves as a JavaScript wrapper around all Extra Horizon cloud services.",
5
5
  "main": "build/index.cjs.js",
6
6
  "types": "build/types/index.d.ts",