@krainovsd/js-helpers 0.8.1 → 0.10.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
@@ -20,6 +20,10 @@ const DATE_TYPES = {
20
20
 
21
21
  const API_MIDDLEWARES = {
22
22
  Auth: "auth",
23
+ AuthNoRefresh: "authNoRefresh",
24
+ Logger: "logger",
25
+ };
26
+ const POST_API_MIDDLEWARES = {
23
27
  Logger: "logger",
24
28
  };
25
29
 
@@ -1317,6 +1321,76 @@ function transformData(data, pathToToken, pathToTokenExpires) {
1317
1321
  token,
1318
1322
  };
1319
1323
  }
1324
+ async function getAuthTokenNoRefresh(options) {
1325
+ let waiting = true;
1326
+ const url = new URL(window.origin);
1327
+ url.searchParams.append(options.queryTokenExpiresName, "true");
1328
+ let windowInstance = window.open(url.toString(), "_blank", "width=800,height=600,left=100,top=100");
1329
+ if (!windowInstance) {
1330
+ windowInstance = window.open(url.toString());
1331
+ }
1332
+ if (!windowInstance) {
1333
+ if (options.onWindowOpenError)
1334
+ options.onWindowOpenError();
1335
+ return;
1336
+ }
1337
+ const channel = new BroadcastChannel(options.queryIsRefreshTokenName);
1338
+ channel.onmessage = () => {
1339
+ if (waiting) {
1340
+ waiting = false;
1341
+ channel.close();
1342
+ }
1343
+ };
1344
+ setTimeout(() => {
1345
+ if (waiting) {
1346
+ waiting = false;
1347
+ channel.close();
1348
+ }
1349
+ if (windowInstance && !windowInstance.closed) {
1350
+ windowInstance.close();
1351
+ }
1352
+ }, 15000);
1353
+ await waitUntil(() => waiting);
1354
+ }
1355
+ async function updateAuthTokenNoRefresh(options) {
1356
+ let expires = localStorage.getItem(options.storageTokenExpiresName);
1357
+ if (expires && !Number.isNaN(+expires) && Date.now() > +expires)
1358
+ expires = null;
1359
+ let hasExpiresQuery = false;
1360
+ if (!expires) {
1361
+ const queries = window.location.search.substring(1).split("&");
1362
+ for (const query of queries) {
1363
+ const [key, value] = query.split("=");
1364
+ if (key === options.queryTokenExpiresName && value) {
1365
+ expires = value;
1366
+ hasExpiresQuery = true;
1367
+ break;
1368
+ }
1369
+ }
1370
+ if (expires && !Number.isNaN(+expires) && Date.now() > +expires)
1371
+ expires = null;
1372
+ }
1373
+ if (!expires) {
1374
+ return void window.location.replace(options.authUrl());
1375
+ }
1376
+ localStorage.setItem(options.storageTokenExpiresName, expires);
1377
+ const queries = window.location.search.substring(1).split("&");
1378
+ for (const query of queries) {
1379
+ const [key, value] = query.split("=");
1380
+ if (key === options.queryIsRefreshTokenName && value === "true") {
1381
+ const channel = new BroadcastChannel(options.queryIsRefreshTokenName);
1382
+ channel.postMessage(true);
1383
+ channel.close();
1384
+ window.close();
1385
+ }
1386
+ }
1387
+ if (hasExpiresQuery) {
1388
+ const url = new URL(window.location.href);
1389
+ url.searchParams.delete(options.queryTokenExpiresName);
1390
+ window.location.replace(url.toString());
1391
+ await wait(300);
1392
+ }
1393
+ }
1320
1394
 
1321
1395
  async function updateAuthUser(options) {
1322
1396
  const userInfo = await (options.userRequest ? options.userRequest() : getAuthUser(options));
@@ -1348,7 +1422,7 @@ async function getAuthUser(options) {
1348
1422
  }
1349
1423
  }
1350
1424
 
1351
- let isFetchingAccessToken = false;
1425
+ let isFetchingAccessToken$1 = false;
1352
1426
  const generateAuthMiddleWare = (options) => async (request) => {
1353
1427
  if (!options.authTokenUrl ||
1354
1428
  !options.authUrl ||
@@ -1368,14 +1442,14 @@ const generateAuthMiddleWare = (options) => async (request) => {
1368
1442
  };
1369
1443
  return;
1370
1444
  }
1371
- if (isFetchingAccessToken)
1372
- await waitUntil(() => isFetchingAccessToken);
1445
+ if (isFetchingAccessToken$1)
1446
+ await waitUntil(() => isFetchingAccessToken$1);
1373
1447
  const expires = localStorage.getItem(options.storageTokenExpiresName);
1374
1448
  let token = localStorage.getItem(options.storageTokenName);
1375
1449
  if (!expires || Date.now() > +expires || !token) {
1376
- isFetchingAccessToken = true;
1450
+ isFetchingAccessToken$1 = true;
1377
1451
  token = await (options.tokenRequest ? options.tokenRequest() : getAuthToken(options));
1378
- isFetchingAccessToken = false;
1452
+ isFetchingAccessToken$1 = false;
1379
1453
  if (isNull(token)) {
1380
1454
  return void window.location.replace(options.authUrl());
1381
1455
  }
@@ -1390,14 +1464,100 @@ const generateAuthMiddleWare = (options) => async (request) => {
1390
1464
  };
1391
1465
  };
1392
1466
 
1393
- const consoleMiddleware = (response) => {
1394
- return new Promise((resolve) => {
1395
- // eslint-disable-next-line no-console
1396
- console.log(response);
1397
- resolve(true);
1398
- });
1467
+ let isFetchingAccessToken = false;
1468
+ const generateAuthNoRefreshMiddleWare = (options) => async (request) => {
1469
+ if (!options.authUrl || !options.storageTokenExpiresName || !options.errorUrl) {
1470
+ throw new Error("Auth middleware hasn't required options");
1471
+ }
1472
+ const isSameOrigin = !startWith(request.path, "http");
1473
+ if (request.token) {
1474
+ if (!isSameOrigin)
1475
+ request.headers = {
1476
+ ...request.headers,
1477
+ Authorization: `Bearer ${request.token}`,
1478
+ };
1479
+ return;
1480
+ }
1481
+ if (isFetchingAccessToken)
1482
+ await waitUntil(() => isFetchingAccessToken);
1483
+ const expires = localStorage.getItem(options.storageTokenExpiresName);
1484
+ if (!expires) {
1485
+ isFetchingAccessToken = true;
1486
+ await (options.tokenRequest ? options.tokenRequest() : getAuthTokenNoRefresh(options));
1487
+ isFetchingAccessToken = false;
1488
+ }
1489
+ const token = options.storageTokenName ? localStorage.getItem(options.storageTokenName) : null;
1490
+ if (!isSameOrigin && token)
1491
+ request.headers = {
1492
+ ...request.headers,
1493
+ Authorization: `Bearer ${token}`,
1494
+ };
1399
1495
  };
1400
1496
 
1497
+ function generateConsoleMiddleware(options = {}) {
1498
+ return (request) => {
1499
+ return new Promise((resolve) => {
1500
+ if ((options.filter &&
1501
+ !options.filter(request)) ||
1502
+ (options.filterHeaders && !options.filterHeaders(request.headers)) ||
1503
+ (options.filterMethod && !options.filterMethod(request.method)) ||
1504
+ (options.filterParams && !options.filterParams(request.params)) ||
1505
+ (options.filterPath && !options.filterPath(request.path))) {
1506
+ resolve(true);
1507
+ return;
1508
+ }
1509
+ // eslint-disable-next-line no-console
1510
+ console.log(request);
1511
+ resolve(true);
1512
+ });
1513
+ };
1514
+ }
1515
+
1516
+ function generateConsolePostMiddleware(options = {}) {
1517
+ return (response) => {
1518
+ return new Promise((resolve) => {
1519
+ void (async function logger() {
1520
+ try {
1521
+ if (!response ||
1522
+ (options.filter && !options.filter(response)) ||
1523
+ (options.filterStatus && !options.filterStatus(response.status)) ||
1524
+ (options.filterUrl && !options.filterUrl(response.url)) ||
1525
+ (options.filterHeaders && !options.filterHeaders(response.headers))) {
1526
+ resolve(true);
1527
+ return;
1528
+ }
1529
+ const contentType = response.headers.get("content-type");
1530
+ let result;
1531
+ if (contentType?.includes?.("text")) {
1532
+ result = await response.text();
1533
+ }
1534
+ else if (contentType?.includes?.("json")) {
1535
+ result = await response.json();
1536
+ }
1537
+ else {
1538
+ result = await response.blob();
1539
+ }
1540
+ console.log({
1541
+ url: response.url,
1542
+ status: response.status,
1543
+ headers: response.headers,
1544
+ body: result,
1545
+ });
1546
+ resolve(true);
1547
+ }
1548
+ catch {
1549
+ if (response) {
1550
+ console.log({ url: response.url, status: response.status, headers: response.headers });
1551
+ }
1552
+ resolve(true);
1553
+ }
1554
+ })().finally(() => {
1555
+ resolve(true);
1556
+ });
1557
+ });
1558
+ };
1559
+ }
1560
+
1401
1561
  function generateMiddlewares(activeMiddlewares, middlewareOptions, customMiddlewares) {
1402
1562
  const selectedMiddlewares = customMiddlewares;
1403
1563
  for (const key of activeMiddlewares) {
@@ -1407,8 +1567,13 @@ function generateMiddlewares(activeMiddlewares, middlewareOptions, customMiddlew
1407
1567
  selectedMiddlewares.push(generateAuthMiddleWare(middlewareOptions.auth));
1408
1568
  continue;
1409
1569
  }
1570
+ case API_MIDDLEWARES.AuthNoRefresh: {
1571
+ if (middlewareOptions.authNoRefresh && (IS_BROWSER || IS_JEST))
1572
+ selectedMiddlewares.push(generateAuthNoRefreshMiddleWare(middlewareOptions.authNoRefresh));
1573
+ continue;
1574
+ }
1410
1575
  case API_MIDDLEWARES.Logger: {
1411
- selectedMiddlewares.push(consoleMiddleware);
1576
+ selectedMiddlewares.push(generateConsoleMiddleware(middlewareOptions.logger));
1412
1577
  continue;
1413
1578
  }
1414
1579
  default: {
@@ -1428,6 +1593,31 @@ function generateMiddlewares(activeMiddlewares, middlewareOptions, customMiddlew
1428
1593
  });
1429
1594
  };
1430
1595
  }
1596
+ function generatePostMiddlewares(activePostMiddlewares, postMiddlewaresOptions, customPostMiddlewares) {
1597
+ const selectedMiddlewares = customPostMiddlewares;
1598
+ for (const key of activePostMiddlewares) {
1599
+ switch (key) {
1600
+ case POST_API_MIDDLEWARES.Logger: {
1601
+ selectedMiddlewares.push(generateConsolePostMiddleware(postMiddlewaresOptions.logger));
1602
+ continue;
1603
+ }
1604
+ default: {
1605
+ continue;
1606
+ }
1607
+ }
1608
+ }
1609
+ return function executeMiddlewares(response) {
1610
+ return new Promise((resolve) => {
1611
+ void (async () => {
1612
+ for (const middleware of selectedMiddlewares) {
1613
+ // eslint-disable-next-line no-await-in-loop
1614
+ await middleware(response);
1615
+ }
1616
+ resolve(1);
1617
+ })();
1618
+ });
1619
+ };
1620
+ }
1431
1621
 
1432
1622
  class ResponseError extends Error {
1433
1623
  status;
@@ -1438,8 +1628,14 @@ class ResponseError extends Error {
1438
1628
  this.description = description;
1439
1629
  }
1440
1630
  }
1441
- function createRequestClientInstance({ activeMiddlewares, middlewareOptions, customMiddlewares, } = {}) {
1442
- const executeMiddlewares = generateMiddlewares(activeMiddlewares || [], middlewareOptions || {}, customMiddlewares || []);
1631
+ function createRequestClientInstance(options = {}) {
1632
+ let executeMiddlewares;
1633
+ let executePostMiddlewares;
1634
+ function setMiddlewares({ activeMiddlewares = [], middlewareOptions = {}, customMiddlewares = [], activePostMiddlewares = [], postMiddlewaresOptions = {}, customPostMiddlewares = [], } = {}) {
1635
+ executeMiddlewares = generateMiddlewares(activeMiddlewares, middlewareOptions, customMiddlewares);
1636
+ executePostMiddlewares = generatePostMiddlewares(activePostMiddlewares, postMiddlewaresOptions, customPostMiddlewares);
1637
+ }
1638
+ setMiddlewares(options);
1443
1639
  async function handleRequest(request, responseWithStatus) {
1444
1640
  if (request.delay) {
1445
1641
  await wait(request.delay);
@@ -1491,13 +1687,29 @@ function createRequestClientInstance({ activeMiddlewares, middlewareOptions, cus
1491
1687
  signal: request.signal,
1492
1688
  });
1493
1689
  }
1690
+ await executePostMiddlewares(response);
1494
1691
  if (!response) {
1495
1692
  throw new Error("hasn't response");
1496
1693
  }
1497
1694
  if (!response.ok) {
1695
+ let result;
1696
+ try {
1697
+ const contentType = response.headers.get("content-type");
1698
+ if (contentType?.includes?.("text")) {
1699
+ result = await response.text();
1700
+ }
1701
+ else if (contentType?.includes?.("json")) {
1702
+ result = await response.json();
1703
+ }
1704
+ else {
1705
+ result = await response.blob();
1706
+ }
1707
+ }
1708
+ catch { }
1498
1709
  throw new ResponseError({
1499
1710
  status: response.status,
1500
1711
  message: `HTTP error! Status: ${response.status}`,
1712
+ description: result,
1501
1713
  });
1502
1714
  }
1503
1715
  if (request.downloadFile) {
@@ -1559,6 +1771,7 @@ function createRequestClientInstance({ activeMiddlewares, middlewareOptions, cus
1559
1771
  return {
1560
1772
  requestApi,
1561
1773
  requestApiWithMeta,
1774
+ setMiddlewares,
1562
1775
  };
1563
1776
  }
1564
1777
 
@@ -1654,6 +1867,7 @@ exports.IS_DENO = IS_DENO;
1654
1867
  exports.IS_JEST = IS_JEST;
1655
1868
  exports.IS_NODE = IS_NODE;
1656
1869
  exports.IS_WEB_WORKER = IS_WEB_WORKER;
1870
+ exports.POST_API_MIDDLEWARES = POST_API_MIDDLEWARES;
1657
1871
  exports.ResponseError = ResponseError;
1658
1872
  exports.arrayToMapByKey = arrayToMapByKey;
1659
1873
  exports.buildQueryString = buildQueryString;
@@ -1666,6 +1880,7 @@ exports.downloadFile = downloadFile;
1666
1880
  exports.downloadJson = downloadJson;
1667
1881
  exports.fieldViewFormat = fieldViewFormat;
1668
1882
  exports.getAuthToken = getAuthToken;
1883
+ exports.getAuthTokenNoRefresh = getAuthTokenNoRefresh;
1669
1884
  exports.getAuthUser = getAuthUser;
1670
1885
  exports.getByPath = getByPath;
1671
1886
  exports.getCallerFunctionName = getCallerFunctionName;
@@ -1708,6 +1923,7 @@ exports.transformToNumber = transformToNumber;
1708
1923
  exports.translit = translit;
1709
1924
  exports.trimUrl = trimUrl;
1710
1925
  exports.updateAuthToken = updateAuthToken;
1926
+ exports.updateAuthTokenNoRefresh = updateAuthTokenNoRefresh;
1711
1927
  exports.updateAuthUser = updateAuthUser;
1712
1928
  exports.wait = wait;
1713
1929
  exports.waitUntil = waitUntil;