@krainovsd/js-helpers 0.17.0 → 0.18.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/cjs/index.cjs CHANGED
@@ -1775,17 +1775,22 @@ class OauthState {
1775
1775
  }
1776
1776
  }
1777
1777
  const OAUTH_STATE = new OauthState();
1778
+ const OAUTH_TOKEN_STORAGE_NAME = "session_token";
1779
+ const OAUTH_TOKEN_EXPIRES_STORAGE_NAME = "session_token_expires";
1780
+ const OAUTH_REFRESH_QUERY = "only_session_refresh";
1778
1781
 
1779
1782
  async function getOauthTokenFromOtherWindow(options) {
1780
1783
  let waiting = true;
1781
1784
  const url = new URL(typeof options.refreshTokenWindowUrl === "function"
1782
1785
  ? options.refreshTokenWindowUrl()
1783
1786
  : (options.refreshTokenWindowUrl ?? window.origin));
1784
- url.searchParams.append(options.onlyRefreshTokenWindowQueryName, "true");
1787
+ // added only refresh tag to autoclose window after flow
1788
+ url.searchParams.append(options.onlyRefreshTokenWindowQueryName ?? OAUTH_REFRESH_QUERY, "true");
1789
+ // try open window with both of action
1785
1790
  let windowInstance = window.open(url.toString(), "_blank", "width=800,height=600,left=100,top=100");
1786
1791
  windowInstance ??= window.open(url.toString(), "_blank");
1787
1792
  if (windowInstance) {
1788
- const channel = new BroadcastChannel(options.onlyRefreshTokenWindowQueryName);
1793
+ const channel = new BroadcastChannel(options.onlyRefreshTokenWindowQueryName ?? OAUTH_REFRESH_QUERY);
1789
1794
  const windowCloseObserver = setInterval(() => {
1790
1795
  if (windowInstance.closed) {
1791
1796
  if (waiting) {
@@ -1811,11 +1816,14 @@ async function getOauthTokenFromOtherWindow(options) {
1811
1816
  if (windowInstance && !windowInstance.closed) {
1812
1817
  windowInstance.close();
1813
1818
  }
1814
- }, options.wait ?? 15000);
1819
+ }, options.wait ?? 8000);
1815
1820
  }
1816
1821
  else {
1817
- if (options.onWindowOpenError)
1818
- options.onWindowOpenError();
1822
+ if ("onWindowOpenError" in options)
1823
+ options.onWindowOpenError?.();
1824
+ else {
1825
+ getOauthToken(options.oauthUrl);
1826
+ }
1819
1827
  waiting = false;
1820
1828
  return;
1821
1829
  }
@@ -1828,19 +1836,21 @@ async function refetchAfterOauth(options, refetch) {
1828
1836
  onWindowOpenError: options.onWindowOpenError,
1829
1837
  refreshTokenWindowUrl: options.refreshTokenWindowUrl,
1830
1838
  wait: options.wait,
1831
- expiresTokenStorageName: options.expiresTokenStorageName,
1832
1839
  closeObserveInterval: options.closeObserveInterval,
1833
1840
  });
1834
1841
  OAUTH_STATE.fetching = false;
1835
1842
  return await refetch();
1836
1843
  }
1837
- async function getOauthToken(options) {
1838
- const queries = getQueryValues([
1839
- options.expiresTokenQueryName,
1840
- options.onlyRefreshTokenWindowQueryName,
1841
- ]);
1842
- const refreshQuery = queries?.[options.onlyRefreshTokenWindowQueryName];
1843
- const expiresQuery = queries?.[options.expiresTokenQueryName];
1844
+ function getOauthToken(oauthUrl) {
1845
+ oauthUrl ??= `/api/v1/auth?frontend_protocol=${window.location.protocol.replace(":", "")}&frontend_host=${window.location.host}&comeback_path=${window.location.pathname}${encodeURIComponent(window.location.search)}`;
1846
+ window.location.replace(typeof oauthUrl === "function" ? oauthUrl() : oauthUrl);
1847
+ return null;
1848
+ }
1849
+ async function extractOauthOptions(options = {}) {
1850
+ const { expiresTokenQueryName = OAUTH_TOKEN_EXPIRES_STORAGE_NAME, onlyRefreshTokenWindowQueryName = OAUTH_REFRESH_QUERY, tokenStorageName = OAUTH_TOKEN_STORAGE_NAME, expiresTokenStorageName = OAUTH_TOKEN_EXPIRES_STORAGE_NAME, tokenRequest = undefined, } = options;
1851
+ const queries = getQueryValues([expiresTokenQueryName, onlyRefreshTokenWindowQueryName]);
1852
+ const refreshQuery = queries?.[onlyRefreshTokenWindowQueryName];
1853
+ const expiresQuery = queries?.[expiresTokenQueryName];
1844
1854
  /** Is OnlyRefresh window */
1845
1855
  const isRefresh = isString(refreshQuery)
1846
1856
  ? refreshQuery === "true"
@@ -1853,21 +1863,18 @@ async function getOauthToken(options) {
1853
1863
  : isArray(expiresQuery)
1854
1864
  ? expiresQuery[expiresQuery.length - 1]
1855
1865
  : false;
1856
- /** OAuth flow if not expires */
1857
- if (!expires) {
1858
- window.location.replace(typeof options.oauthUrl === "function" ? options.oauthUrl() : options.oauthUrl);
1859
- return null;
1860
- }
1861
- localStorage.setItem(options.expiresTokenStorageName, expires);
1862
- if (options.tokenRequest) {
1863
- const token = await options.tokenRequest();
1864
- if (token != undefined && options.tokenStorageName) {
1865
- localStorage.setItem(options.tokenStorageName, token);
1866
+ if (expires && !Number.isNaN(+expires) && Date.now() < +expires) {
1867
+ localStorage.setItem(expiresTokenStorageName, expires);
1868
+ if (tokenRequest) {
1869
+ const token = await tokenRequest();
1870
+ if (token != undefined && tokenStorageName) {
1871
+ localStorage.setItem(tokenStorageName, token);
1872
+ }
1866
1873
  }
1867
1874
  }
1868
1875
  /** Close if OnlyRefresh window */
1869
1876
  if (isRefresh) {
1870
- const channel = new BroadcastChannel(options.onlyRefreshTokenWindowQueryName);
1877
+ const channel = new BroadcastChannel(onlyRefreshTokenWindowQueryName);
1871
1878
  channel.postMessage(true);
1872
1879
  channel.close();
1873
1880
  window.close();
@@ -1875,7 +1882,7 @@ async function getOauthToken(options) {
1875
1882
  /** Delete expires query */
1876
1883
  if (expires) {
1877
1884
  const url = new URL(window.location.href);
1878
- url.searchParams.delete(options.expiresTokenQueryName);
1885
+ url.searchParams.delete(expiresTokenQueryName);
1879
1886
  window.location.replace(url.toString());
1880
1887
  return null;
1881
1888
  }
@@ -2029,7 +2036,10 @@ function createFetchClient(options) {
2029
2036
  request.onError?.(REQUEST_ERROR.CACHE_ERROR, error);
2030
2037
  return { data: error, error: REQUEST_ERROR.CACHE_ERROR, response };
2031
2038
  }
2032
- if (response.status === 401 && refetchAfterOauth$1 && oauthOptions) {
2039
+ if ((oauthOptions?.responseStatusesForOauth?.includes(response.status) ||
2040
+ (!oauthOptions?.responseStatusesForOauth && response.status === 401)) &&
2041
+ oauthOptions &&
2042
+ refetchAfterOauth$1) {
2033
2043
  return await refetchAfterOauth(oauthOptions, () => handleRequest({ ...request, refetchAfterOauth: false }));
2034
2044
  }
2035
2045
  if (response.status === 401 && refetchAfterAuth) {
@@ -2200,7 +2210,6 @@ function executeBeforeHandlers(handlers, request) {
2200
2210
  return new Promise((resolve) => {
2201
2211
  void (async () => {
2202
2212
  for (const handler of handlers) {
2203
- // eslint-disable-next-line no-await-in-loop
2204
2213
  await handler(request);
2205
2214
  }
2206
2215
  resolve(1);
@@ -2211,7 +2220,6 @@ function executeAfterHandlers(handlers, request, response) {
2211
2220
  return new Promise((resolve) => {
2212
2221
  void (async () => {
2213
2222
  for (const handler of handlers) {
2214
- // eslint-disable-next-line no-await-in-loop
2215
2223
  await handler(request, response);
2216
2224
  }
2217
2225
  resolve(1);
@@ -2289,39 +2297,13 @@ function loggerBeforeHandler(options = {}) {
2289
2297
  };
2290
2298
  }
2291
2299
 
2292
- const oauthBeforeHandler = (options) => async (request) => {
2293
- if (!options.expiresTokenStorageName) {
2294
- throw new Error("Auth middleware hasn't required options");
2295
- }
2296
- const isSameOrigin = !startWith(request.path, "http");
2297
- if (request.token) {
2298
- if (!isSameOrigin)
2299
- request.headers = {
2300
- ...request.headers,
2301
- Authorization: `Bearer ${request.token}`,
2302
- };
2303
- return;
2304
- }
2300
+ const authBeforeHandler = (options = {}) => async (request) => {
2301
+ const { tokenStorageName = OAUTH_TOKEN_STORAGE_NAME, forceSetToken = false } = options;
2305
2302
  if (OAUTH_STATE.fetching)
2306
2303
  await waitUntil(() => OAUTH_STATE.fetching);
2307
- const expires = localStorage.getItem(options.expiresTokenStorageName);
2308
- let token;
2309
- if (!expires || Number.isNaN(+expires) || Date.now() > +expires) {
2310
- OAUTH_STATE.fetching = true;
2311
- await getOauthTokenFromOtherWindow({
2312
- onlyRefreshTokenWindowQueryName: options.onlyRefreshTokenWindowQueryName,
2313
- onWindowOpenError: options.onWindowOpenError,
2314
- refreshTokenWindowUrl: options.refreshTokenWindowUrl,
2315
- wait: options.wait,
2316
- expiresTokenStorageName: options.expiresTokenStorageName,
2317
- closeObserveInterval: options.closeObserveInterval,
2318
- });
2319
- if (options.tokenStorageName) {
2320
- token = localStorage.getItem(options.tokenStorageName);
2321
- }
2322
- OAUTH_STATE.fetching = false;
2323
- }
2324
- if (!isSameOrigin && token)
2304
+ const token = request.token ?? localStorage.getItem(tokenStorageName);
2305
+ const isSameOrigin = request.path.includes(window.location.origin) || !startWith(request.path, "http");
2306
+ if ((!isSameOrigin || forceSetToken) && token)
2325
2307
  request.headers = {
2326
2308
  ...request.headers,
2327
2309
  Authorization: `Bearer ${token}`,
@@ -2337,12 +2319,16 @@ exports.IS_DENO = IS_DENO;
2337
2319
  exports.IS_JEST = IS_JEST;
2338
2320
  exports.IS_NODE = IS_NODE;
2339
2321
  exports.IS_WEB_WORKER = IS_WEB_WORKER;
2322
+ exports.OAUTH_REFRESH_QUERY = OAUTH_REFRESH_QUERY;
2340
2323
  exports.OAUTH_STATE = OAUTH_STATE;
2324
+ exports.OAUTH_TOKEN_EXPIRES_STORAGE_NAME = OAUTH_TOKEN_EXPIRES_STORAGE_NAME;
2325
+ exports.OAUTH_TOKEN_STORAGE_NAME = OAUTH_TOKEN_STORAGE_NAME;
2341
2326
  exports.REQUEST_ERROR = REQUEST_ERROR;
2342
2327
  exports.RESPONSE_DATA_SYMBOL = RESPONSE_DATA_SYMBOL;
2343
2328
  exports.ResponseError = ResponseError;
2344
2329
  exports.arrayToMapByKey = arrayToMapByKey;
2345
2330
  exports.asyncLoop = asyncLoop;
2331
+ exports.authBeforeHandler = authBeforeHandler;
2346
2332
  exports.buildQueryString = buildQueryString;
2347
2333
  exports.checkType = checkType;
2348
2334
  exports.cloneDeep = cloneDeep;
@@ -2361,6 +2347,7 @@ exports.differenceWith = differenceWith;
2361
2347
  exports.downloadFile = downloadFile;
2362
2348
  exports.downloadJson = downloadJson;
2363
2349
  exports.execAnimation = execAnimation;
2350
+ exports.extractOauthOptions = extractOauthOptions;
2364
2351
  exports.extractQueries = extractQueries;
2365
2352
  exports.fieldViewFormat = fieldViewFormat;
2366
2353
  exports.getByPath = getByPath;
@@ -2392,7 +2379,6 @@ exports.jsonParse = jsonParse;
2392
2379
  exports.limitStreamOfRequests = limitStreamOfRequests;
2393
2380
  exports.loggerAfterHandler = loggerAfterHandler;
2394
2381
  exports.loggerBeforeHandler = loggerBeforeHandler;
2395
- exports.oauthBeforeHandler = oauthBeforeHandler;
2396
2382
  exports.randomBase64 = randomBase64;
2397
2383
  exports.randomHex = randomHex;
2398
2384
  exports.randomNumber = randomNumber;