@krainovsd/js-helpers 0.18.1 → 0.19.0-beta.10
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 +268 -164
- package/lib/cjs/index.cjs.map +1 -1
- package/lib/esm/api/api.constants.js +12 -8
- package/lib/esm/api/api.constants.js.map +1 -1
- package/lib/esm/api/api.js +31 -30
- package/lib/esm/api/api.js.map +1 -1
- package/lib/esm/api/oauth.js +210 -96
- package/lib/esm/api/oauth.js.map +1 -1
- package/lib/esm/index.js +2 -3
- package/lib/esm/index.js.map +1 -1
- package/lib/index.d.ts +73 -56
- package/package.json +2 -1
- package/lib/esm/api/before/oauth-before-handler.js +0 -23
- package/lib/esm/api/before/oauth-before-handler.js.map +0 -1
package/lib/cjs/index.cjs
CHANGED
|
@@ -1757,13 +1757,14 @@ function throttle(func, interval) {
|
|
|
1757
1757
|
|
|
1758
1758
|
const RESPONSE_DATA_SYMBOL = Symbol("response data");
|
|
1759
1759
|
const REQUEST_ERROR = {
|
|
1760
|
-
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
|
|
1760
|
+
Http: "http",
|
|
1761
|
+
Network: "network",
|
|
1762
|
+
Timeout: "timeout",
|
|
1763
|
+
Abort: "abort",
|
|
1764
|
+
Validation: "validation",
|
|
1765
|
+
Cache: "cache",
|
|
1766
|
+
Unknown: "unknown",
|
|
1767
|
+
Disabled: "disabled",
|
|
1767
1768
|
};
|
|
1768
1769
|
class OauthState {
|
|
1769
1770
|
_fetching = false;
|
|
@@ -1778,132 +1779,22 @@ const OAUTH_STATE = new OauthState();
|
|
|
1778
1779
|
const OAUTH_TOKEN_STORAGE_NAME = "session_token";
|
|
1779
1780
|
const OAUTH_TOKEN_EXPIRES_STORAGE_NAME = "session_token_expires";
|
|
1780
1781
|
const OAUTH_REFRESH_QUERY = "only_session_refresh";
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
const url = new URL(typeof options.refreshTokenWindowUrl === "function"
|
|
1785
|
-
? options.refreshTokenWindowUrl()
|
|
1786
|
-
: (options.refreshTokenWindowUrl ?? window.origin));
|
|
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
|
|
1790
|
-
let windowInstance = window.open(url.toString(), "_blank", "width=800,height=600,left=100,top=100");
|
|
1791
|
-
windowInstance ??= window.open(url.toString(), "_blank");
|
|
1792
|
-
if (windowInstance) {
|
|
1793
|
-
const channel = new BroadcastChannel(options.onlyRefreshTokenWindowQueryName ?? OAUTH_REFRESH_QUERY);
|
|
1794
|
-
const windowCloseObserver = setInterval(() => {
|
|
1795
|
-
if (windowInstance.closed) {
|
|
1796
|
-
if (waiting) {
|
|
1797
|
-
waiting = false;
|
|
1798
|
-
channel.close();
|
|
1799
|
-
clearInterval(windowCloseObserver);
|
|
1800
|
-
}
|
|
1801
|
-
}
|
|
1802
|
-
}, options.closeObserveInterval ?? 500);
|
|
1803
|
-
channel.onmessage = () => {
|
|
1804
|
-
if (waiting) {
|
|
1805
|
-
waiting = false;
|
|
1806
|
-
channel.close();
|
|
1807
|
-
clearInterval(windowCloseObserver);
|
|
1808
|
-
}
|
|
1809
|
-
};
|
|
1810
|
-
setTimeout(() => {
|
|
1811
|
-
if (waiting) {
|
|
1812
|
-
waiting = false;
|
|
1813
|
-
channel.close();
|
|
1814
|
-
clearInterval(windowCloseObserver);
|
|
1815
|
-
}
|
|
1816
|
-
if (windowInstance && !windowInstance.closed) {
|
|
1817
|
-
windowInstance.close();
|
|
1818
|
-
}
|
|
1819
|
-
}, options.wait ?? 8000);
|
|
1820
|
-
}
|
|
1821
|
-
else {
|
|
1822
|
-
if ("onWindowOpenError" in options)
|
|
1823
|
-
options.onWindowOpenError?.();
|
|
1824
|
-
else {
|
|
1825
|
-
getOauthToken(options.oauthUrl);
|
|
1826
|
-
}
|
|
1827
|
-
waiting = false;
|
|
1828
|
-
return;
|
|
1829
|
-
}
|
|
1830
|
-
await waitUntil(() => waiting);
|
|
1831
|
-
}
|
|
1832
|
-
async function refetchAfterOauth(options, refetch) {
|
|
1833
|
-
OAUTH_STATE.fetching = true;
|
|
1834
|
-
await getOauthTokenFromOtherWindow({
|
|
1835
|
-
onlyRefreshTokenWindowQueryName: options.onlyRefreshTokenWindowQueryName,
|
|
1836
|
-
onWindowOpenError: options.onWindowOpenError,
|
|
1837
|
-
refreshTokenWindowUrl: options.refreshTokenWindowUrl,
|
|
1838
|
-
wait: options.wait,
|
|
1839
|
-
closeObserveInterval: options.closeObserveInterval,
|
|
1840
|
-
});
|
|
1841
|
-
OAUTH_STATE.fetching = false;
|
|
1842
|
-
return await refetch();
|
|
1843
|
-
}
|
|
1844
|
-
// Trigger an oauth flow through some proxy server
|
|
1845
|
-
function getOauthToken(oauthUrl) {
|
|
1846
|
-
oauthUrl ??= `/api/v1/auth?frontend_protocol=${window.location.protocol.replace(":", "")}&frontend_host=${window.location.host}&comeback_path=${window.location.pathname}${encodeURIComponent(window.location.search)}`;
|
|
1847
|
-
window.location.replace(typeof oauthUrl === "function" ? oauthUrl() : oauthUrl);
|
|
1848
|
-
return null;
|
|
1849
|
-
}
|
|
1850
|
-
// Processing an oauth flow: extract expires, get token, close sub windows
|
|
1851
|
-
async function applyOauthProvider(options = {}) {
|
|
1852
|
-
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;
|
|
1853
|
-
const queries = getQueryValues([expiresTokenQueryName, onlyRefreshTokenWindowQueryName]);
|
|
1854
|
-
const refreshQuery = queries?.[onlyRefreshTokenWindowQueryName];
|
|
1855
|
-
const expiresQuery = queries?.[expiresTokenQueryName];
|
|
1856
|
-
/** Is OnlyRefresh window */
|
|
1857
|
-
const isRefresh = isString(refreshQuery)
|
|
1858
|
-
? refreshQuery === "true"
|
|
1859
|
-
: isArray(refreshQuery)
|
|
1860
|
-
? refreshQuery[refreshQuery.length - 1] === "true"
|
|
1861
|
-
: false;
|
|
1862
|
-
/** Expires token */
|
|
1863
|
-
const expires = isString(expiresQuery)
|
|
1864
|
-
? expiresQuery
|
|
1865
|
-
: isArray(expiresQuery)
|
|
1866
|
-
? expiresQuery[expiresQuery.length - 1]
|
|
1867
|
-
: false;
|
|
1868
|
-
if (expires && !Number.isNaN(+expires) && Date.now() < +expires) {
|
|
1869
|
-
localStorage.setItem(expiresTokenStorageName, expires);
|
|
1870
|
-
if (tokenRequest) {
|
|
1871
|
-
const token = await tokenRequest();
|
|
1872
|
-
if (token != undefined && tokenStorageName) {
|
|
1873
|
-
localStorage.setItem(tokenStorageName, token);
|
|
1874
|
-
}
|
|
1875
|
-
}
|
|
1876
|
-
}
|
|
1877
|
-
/** Close if OnlyRefresh window */
|
|
1878
|
-
if (isRefresh) {
|
|
1879
|
-
const channel = new BroadcastChannel(onlyRefreshTokenWindowQueryName);
|
|
1880
|
-
channel.postMessage(true);
|
|
1881
|
-
channel.close();
|
|
1882
|
-
window.close();
|
|
1883
|
-
}
|
|
1884
|
-
/** Delete expires query */
|
|
1885
|
-
if (expires) {
|
|
1886
|
-
const url = new URL(window.location.href);
|
|
1887
|
-
url.searchParams.delete(expiresTokenQueryName);
|
|
1888
|
-
window.location.replace(url.toString());
|
|
1889
|
-
}
|
|
1890
|
-
}
|
|
1782
|
+
const OAUTH_ERROR_PAGE_URL = "/error";
|
|
1783
|
+
const OAUTH_CLEAR_PAGE_URL = "/clear";
|
|
1784
|
+
const OAUTH_LOGOUT_PAGE_URL = "/logout";
|
|
1891
1785
|
|
|
1892
1786
|
function createFetchClient(options) {
|
|
1893
1787
|
let client = options.client;
|
|
1894
|
-
let oauthOptions = options.oauthOptions;
|
|
1895
1788
|
let beforeHandlers = options.beforeHandlers;
|
|
1896
1789
|
let afterHandlers = options.afterHandlers;
|
|
1897
1790
|
let retries = options.retries;
|
|
1898
1791
|
let timeout = options.timeout;
|
|
1899
1792
|
let refetchAfterAuthGlobal = options.refetchAfterAuth;
|
|
1793
|
+
let enabled = options.enabled ?? true;
|
|
1900
1794
|
function recreate(options) {
|
|
1901
1795
|
if ("client" in options) {
|
|
1902
1796
|
client = options.client;
|
|
1903
1797
|
}
|
|
1904
|
-
if ("oauthOptions" in options) {
|
|
1905
|
-
oauthOptions = options.oauthOptions;
|
|
1906
|
-
}
|
|
1907
1798
|
if ("beforeHandlers" in options) {
|
|
1908
1799
|
beforeHandlers = options.beforeHandlers;
|
|
1909
1800
|
}
|
|
@@ -1919,8 +1810,18 @@ function createFetchClient(options) {
|
|
|
1919
1810
|
if ("refetchAfterAuth" in options) {
|
|
1920
1811
|
refetchAfterAuthGlobal = options.refetchAfterAuth;
|
|
1921
1812
|
}
|
|
1813
|
+
if ("enabled" in options) {
|
|
1814
|
+
enabled = options.enabled ?? true;
|
|
1815
|
+
}
|
|
1922
1816
|
}
|
|
1923
1817
|
async function handleRequest(request) {
|
|
1818
|
+
if (!enabled) {
|
|
1819
|
+
return {
|
|
1820
|
+
response: null,
|
|
1821
|
+
data: new ResponseError({ message: "requests disabled", status: 0 }),
|
|
1822
|
+
error: REQUEST_ERROR.Disabled,
|
|
1823
|
+
};
|
|
1824
|
+
}
|
|
1924
1825
|
const timeoutController = new AbortController();
|
|
1925
1826
|
const requestController = new AbortController();
|
|
1926
1827
|
const requestTimeout = request.timeout ?? timeout;
|
|
@@ -1968,7 +1869,7 @@ function createFetchClient(options) {
|
|
|
1968
1869
|
await executeBeforeHandlers(handlers, request);
|
|
1969
1870
|
}
|
|
1970
1871
|
}
|
|
1971
|
-
const { method, body, path, queries, headers = {}
|
|
1872
|
+
const { method, body, path, queries, headers = {} } = request;
|
|
1972
1873
|
let refetchAfterAuth = refetchAfterAuthGlobal;
|
|
1973
1874
|
if ("refetchAfterAuth" in request) {
|
|
1974
1875
|
refetchAfterAuth = request.refetchAfterAuth;
|
|
@@ -2029,19 +1930,14 @@ function createFetchClient(options) {
|
|
|
2029
1930
|
if (!response.ok) {
|
|
2030
1931
|
if (response.status === 304) {
|
|
2031
1932
|
const error = new ResponseError({
|
|
2032
|
-
message: REQUEST_ERROR.
|
|
1933
|
+
message: REQUEST_ERROR.Cache,
|
|
2033
1934
|
status: response.status,
|
|
2034
1935
|
headers: Object.fromEntries(response.headers.entries()),
|
|
2035
1936
|
});
|
|
2036
|
-
request.onError?.(REQUEST_ERROR.
|
|
2037
|
-
return { data: error, error: REQUEST_ERROR.
|
|
2038
|
-
}
|
|
2039
|
-
if ((oauthOptions?.responseStatusesForOauth?.includes(response.status) ||
|
|
2040
|
-
(!oauthOptions?.responseStatusesForOauth && response.status === 401)) &&
|
|
2041
|
-
oauthOptions &&
|
|
2042
|
-
refetchAfterOauth$1) {
|
|
2043
|
-
return await refetchAfterOauth(oauthOptions, () => handleRequest({ ...request, refetchAfterOauth: false }));
|
|
1937
|
+
request.onError?.(REQUEST_ERROR.Cache, error);
|
|
1938
|
+
return { data: error, error: REQUEST_ERROR.Cache, response };
|
|
2044
1939
|
}
|
|
1940
|
+
/** if you need observe other than only 401 status, you can override some statuses in after handler middleware to 401 */
|
|
2045
1941
|
if (response.status === 401 && refetchAfterAuth) {
|
|
2046
1942
|
const newRequest = await refetchAfterAuth(request);
|
|
2047
1943
|
return await handleRequest({ ...newRequest, refetchAfterAuth: false });
|
|
@@ -2082,14 +1978,14 @@ function createFetchClient(options) {
|
|
|
2082
1978
|
catch { }
|
|
2083
1979
|
const error = new ResponseError({
|
|
2084
1980
|
status: response.status,
|
|
2085
|
-
message: REQUEST_ERROR.
|
|
1981
|
+
message: REQUEST_ERROR.Http,
|
|
2086
1982
|
description: result,
|
|
2087
1983
|
headers: Object.fromEntries(response.headers.entries()),
|
|
2088
1984
|
});
|
|
2089
|
-
request.onError?.(REQUEST_ERROR.
|
|
1985
|
+
request.onError?.(REQUEST_ERROR.Http, error);
|
|
2090
1986
|
return {
|
|
2091
1987
|
data: error,
|
|
2092
|
-
error: REQUEST_ERROR.
|
|
1988
|
+
error: REQUEST_ERROR.Http,
|
|
2093
1989
|
response,
|
|
2094
1990
|
};
|
|
2095
1991
|
}
|
|
@@ -2158,36 +2054,36 @@ function createFetchClient(options) {
|
|
|
2158
2054
|
}
|
|
2159
2055
|
if (err instanceof TypeError) {
|
|
2160
2056
|
const error = new ResponseError({
|
|
2161
|
-
message: REQUEST_ERROR.
|
|
2057
|
+
message: REQUEST_ERROR.Network,
|
|
2162
2058
|
status: 0,
|
|
2163
2059
|
description: String(err.message),
|
|
2164
2060
|
});
|
|
2165
|
-
request.onError?.(REQUEST_ERROR.
|
|
2166
|
-
return { data: error, error: REQUEST_ERROR.
|
|
2061
|
+
request.onError?.(REQUEST_ERROR.Network, error);
|
|
2062
|
+
return { data: error, error: REQUEST_ERROR.Network, response: null };
|
|
2167
2063
|
}
|
|
2168
2064
|
if (err instanceof Error && err.name === "AbortError") {
|
|
2169
2065
|
if (timeoutController.signal.aborted) {
|
|
2170
2066
|
const error = new ResponseError({
|
|
2171
|
-
message: REQUEST_ERROR.
|
|
2067
|
+
message: REQUEST_ERROR.Timeout,
|
|
2172
2068
|
status: 0,
|
|
2173
2069
|
});
|
|
2174
|
-
request.onError?.(REQUEST_ERROR.
|
|
2175
|
-
return { data: error, error: REQUEST_ERROR.
|
|
2070
|
+
request.onError?.(REQUEST_ERROR.Timeout, error);
|
|
2071
|
+
return { data: error, error: REQUEST_ERROR.Timeout, response: null };
|
|
2176
2072
|
}
|
|
2177
2073
|
const error = new ResponseError({
|
|
2178
|
-
message: REQUEST_ERROR.
|
|
2074
|
+
message: REQUEST_ERROR.Abort,
|
|
2179
2075
|
status: 0,
|
|
2180
2076
|
});
|
|
2181
|
-
request.onError?.(REQUEST_ERROR.
|
|
2182
|
-
return { data: error, error: REQUEST_ERROR.
|
|
2077
|
+
request.onError?.(REQUEST_ERROR.Abort, error);
|
|
2078
|
+
return { data: error, error: REQUEST_ERROR.Abort, response: null };
|
|
2183
2079
|
}
|
|
2184
2080
|
const error = new ResponseError({
|
|
2185
|
-
message: REQUEST_ERROR.
|
|
2081
|
+
message: REQUEST_ERROR.Unknown,
|
|
2186
2082
|
status: 0,
|
|
2187
2083
|
description: String(err),
|
|
2188
2084
|
});
|
|
2189
|
-
request.onError?.(REQUEST_ERROR.
|
|
2190
|
-
return { data: error, error: REQUEST_ERROR.
|
|
2085
|
+
request.onError?.(REQUEST_ERROR.Unknown, error);
|
|
2086
|
+
return { data: error, error: REQUEST_ERROR.Unknown, response: null };
|
|
2191
2087
|
}
|
|
2192
2088
|
finally {
|
|
2193
2089
|
requestController.abort();
|
|
@@ -2227,6 +2123,228 @@ function executeAfterHandlers(handlers, request, response) {
|
|
|
2227
2123
|
});
|
|
2228
2124
|
}
|
|
2229
2125
|
|
|
2126
|
+
function createOauthProvider(opts = {}) {
|
|
2127
|
+
const { refreshTokenWindowUrl = window.origin, closeObserveSubWindowInterval = 500, waitSubWindow = 15000, loginUrl = undefined, logoutUrl = undefined, clearPageUrl = OAUTH_CLEAR_PAGE_URL, errorPageUrl = OAUTH_ERROR_PAGE_URL, logoutPageUrl = OAUTH_LOGOUT_PAGE_URL, afterClearPageUrl = "/", expiresTokenQueryName = OAUTH_TOKEN_EXPIRES_STORAGE_NAME, tokenStorageName = OAUTH_TOKEN_STORAGE_NAME, expiresTokenStorageName = OAUTH_TOKEN_EXPIRES_STORAGE_NAME, tokenRequest = undefined, forceSetToken = false, subWindow = true, refreshToken = false, } = opts;
|
|
2128
|
+
let processing = false;
|
|
2129
|
+
function getExpiresDate(expires) {
|
|
2130
|
+
return Date.now() + (expires - 30) * 1000;
|
|
2131
|
+
}
|
|
2132
|
+
function checkExpires(expires) {
|
|
2133
|
+
return expires != undefined && !Number.isNaN(+expires) && Date.now() < +expires;
|
|
2134
|
+
}
|
|
2135
|
+
async function refetchAfterRefreshFlow(request) {
|
|
2136
|
+
if (processing) {
|
|
2137
|
+
await beforeHandlerSetToken(request);
|
|
2138
|
+
return request;
|
|
2139
|
+
}
|
|
2140
|
+
processing = true;
|
|
2141
|
+
if (refreshToken && tokenRequest) {
|
|
2142
|
+
const tokenInfo = await startRefreshFlow();
|
|
2143
|
+
if (tokenInfo == undefined) {
|
|
2144
|
+
if (subWindow) {
|
|
2145
|
+
await startLoginFlowInSubWindow();
|
|
2146
|
+
}
|
|
2147
|
+
else {
|
|
2148
|
+
await startLoginFlow();
|
|
2149
|
+
}
|
|
2150
|
+
processing = false;
|
|
2151
|
+
await beforeHandlerSetToken(request);
|
|
2152
|
+
return request;
|
|
2153
|
+
}
|
|
2154
|
+
processing = false;
|
|
2155
|
+
await beforeHandlerSetToken(request);
|
|
2156
|
+
return request;
|
|
2157
|
+
}
|
|
2158
|
+
if (subWindow) {
|
|
2159
|
+
await startLoginFlowInSubWindow();
|
|
2160
|
+
}
|
|
2161
|
+
else {
|
|
2162
|
+
await startLoginFlow();
|
|
2163
|
+
}
|
|
2164
|
+
processing = false;
|
|
2165
|
+
await beforeHandlerSetToken(request);
|
|
2166
|
+
return request;
|
|
2167
|
+
}
|
|
2168
|
+
async function startLoginFlowInSubWindow() {
|
|
2169
|
+
processing = true;
|
|
2170
|
+
let waiting = true;
|
|
2171
|
+
const url = new URL(typeof refreshTokenWindowUrl === "function" ? refreshTokenWindowUrl() : refreshTokenWindowUrl);
|
|
2172
|
+
// added only refresh tag to autoclose window after flow
|
|
2173
|
+
url.searchParams.append(OAUTH_REFRESH_QUERY, "true");
|
|
2174
|
+
// try open window with both of action
|
|
2175
|
+
let windowInstance = window.open(url.toString(), "_blank", "width=800,height=600,left=100,top=100");
|
|
2176
|
+
windowInstance ??= window.open(url.toString(), "_blank");
|
|
2177
|
+
if (windowInstance) {
|
|
2178
|
+
const channel = new BroadcastChannel(OAUTH_REFRESH_QUERY);
|
|
2179
|
+
const windowCloseObserver = setInterval(() => {
|
|
2180
|
+
if (windowInstance.closed) {
|
|
2181
|
+
if (waiting) {
|
|
2182
|
+
waiting = false;
|
|
2183
|
+
channel.close();
|
|
2184
|
+
clearInterval(windowCloseObserver);
|
|
2185
|
+
}
|
|
2186
|
+
}
|
|
2187
|
+
}, closeObserveSubWindowInterval);
|
|
2188
|
+
channel.onmessage = () => {
|
|
2189
|
+
if (waiting) {
|
|
2190
|
+
waiting = false;
|
|
2191
|
+
channel.close();
|
|
2192
|
+
clearInterval(windowCloseObserver);
|
|
2193
|
+
}
|
|
2194
|
+
};
|
|
2195
|
+
setTimeout(() => {
|
|
2196
|
+
if (waiting) {
|
|
2197
|
+
waiting = false;
|
|
2198
|
+
channel.close();
|
|
2199
|
+
clearInterval(windowCloseObserver);
|
|
2200
|
+
}
|
|
2201
|
+
if (windowInstance && !windowInstance.closed) {
|
|
2202
|
+
windowInstance.close();
|
|
2203
|
+
}
|
|
2204
|
+
}, waitSubWindow);
|
|
2205
|
+
}
|
|
2206
|
+
else {
|
|
2207
|
+
if ("onSubWindowOpenError" in opts)
|
|
2208
|
+
opts.onSubWindowOpenError?.();
|
|
2209
|
+
else {
|
|
2210
|
+
await startLoginFlow();
|
|
2211
|
+
}
|
|
2212
|
+
waiting = false;
|
|
2213
|
+
return;
|
|
2214
|
+
}
|
|
2215
|
+
await waitUntil(() => waiting);
|
|
2216
|
+
processing = false;
|
|
2217
|
+
}
|
|
2218
|
+
// Trigger an oauth flow through some proxy server
|
|
2219
|
+
async function startLoginFlow(loginUrlArg = loginUrl, delay = 2000) {
|
|
2220
|
+
loginUrlArg ??= `/api/v1/auth?frontend_protocol=${window.location.protocol.replace(":", "")}&frontend_host=${window.location.host}&comeback_path=${window.location.pathname}${encodeURIComponent(window.location.search)}`;
|
|
2221
|
+
window.location.replace(typeof loginUrlArg === "function" ? loginUrlArg() : loginUrlArg);
|
|
2222
|
+
await wait(delay);
|
|
2223
|
+
return null;
|
|
2224
|
+
}
|
|
2225
|
+
// Trigger an oauth flow through some proxy server
|
|
2226
|
+
async function startLogoutFlow(logoutUrlArg = logoutUrl, delay = 2000) {
|
|
2227
|
+
logoutUrlArg ??= `/api/v1/auth/logout?frontend_protocol=${window.location.protocol.replace(":", "")}&frontend_host=${window.location.host}`;
|
|
2228
|
+
window.location.replace(typeof logoutUrlArg === "function" ? logoutUrlArg() : logoutUrlArg);
|
|
2229
|
+
await wait(delay);
|
|
2230
|
+
return null;
|
|
2231
|
+
}
|
|
2232
|
+
async function startRefreshFlow() {
|
|
2233
|
+
const tokenInfo = await tokenRequest?.();
|
|
2234
|
+
if (tokenInfo) {
|
|
2235
|
+
localStorage.setItem(tokenStorageName, tokenInfo.token);
|
|
2236
|
+
if (tokenInfo.expires !== 0) {
|
|
2237
|
+
tokenInfo.expires = getExpiresDate(tokenInfo.expires);
|
|
2238
|
+
localStorage.setItem(expiresTokenStorageName, String(tokenInfo.expires));
|
|
2239
|
+
}
|
|
2240
|
+
}
|
|
2241
|
+
return tokenInfo;
|
|
2242
|
+
}
|
|
2243
|
+
// Processing an oauth flow: extract expires, get token, close sub windows, check if logout/clear/error url
|
|
2244
|
+
async function register() {
|
|
2245
|
+
if (window.location.pathname === logoutPageUrl) {
|
|
2246
|
+
await startLogoutFlow();
|
|
2247
|
+
return false;
|
|
2248
|
+
}
|
|
2249
|
+
if (window.location.pathname === clearPageUrl) {
|
|
2250
|
+
localStorage.removeItem(expiresTokenStorageName);
|
|
2251
|
+
localStorage.removeItem(tokenStorageName);
|
|
2252
|
+
window.location.replace(afterClearPageUrl);
|
|
2253
|
+
return false;
|
|
2254
|
+
}
|
|
2255
|
+
if (window.location.pathname === errorPageUrl) {
|
|
2256
|
+
localStorage.removeItem(expiresTokenStorageName);
|
|
2257
|
+
localStorage.removeItem(tokenStorageName);
|
|
2258
|
+
return false;
|
|
2259
|
+
}
|
|
2260
|
+
const queries = getQueryValues([expiresTokenQueryName, OAUTH_REFRESH_QUERY]);
|
|
2261
|
+
const refreshQuery = queries?.[OAUTH_REFRESH_QUERY];
|
|
2262
|
+
const expiresQuery = queries?.[expiresTokenQueryName];
|
|
2263
|
+
/** Is OnlyRefresh window */
|
|
2264
|
+
const isRefresh = isString(refreshQuery)
|
|
2265
|
+
? refreshQuery === "true"
|
|
2266
|
+
: isArray(refreshQuery)
|
|
2267
|
+
? refreshQuery[refreshQuery.length - 1] === "true"
|
|
2268
|
+
: false;
|
|
2269
|
+
/** Expires token */
|
|
2270
|
+
const expiresStr = isString(expiresQuery)
|
|
2271
|
+
? expiresQuery
|
|
2272
|
+
: isArray(expiresQuery)
|
|
2273
|
+
? expiresQuery[expiresQuery.length - 1]
|
|
2274
|
+
: null;
|
|
2275
|
+
const expires = expiresStr ? getExpiresDate(+expiresStr) : null;
|
|
2276
|
+
if (checkExpires(expires)) {
|
|
2277
|
+
localStorage.setItem(expiresTokenStorageName, String(expires));
|
|
2278
|
+
if (tokenRequest) {
|
|
2279
|
+
const tokenInfo = await tokenRequest();
|
|
2280
|
+
if (tokenInfo != undefined) {
|
|
2281
|
+
localStorage.setItem(tokenStorageName, tokenInfo.token);
|
|
2282
|
+
}
|
|
2283
|
+
}
|
|
2284
|
+
/** Close if OnlyRefresh window */
|
|
2285
|
+
if (isRefresh) {
|
|
2286
|
+
const channel = new BroadcastChannel(OAUTH_REFRESH_QUERY);
|
|
2287
|
+
channel.postMessage(true);
|
|
2288
|
+
channel.close();
|
|
2289
|
+
window.close();
|
|
2290
|
+
return false;
|
|
2291
|
+
}
|
|
2292
|
+
/** Delete expires query */
|
|
2293
|
+
const url = new URL(window.location.href);
|
|
2294
|
+
url.searchParams.delete(expiresTokenQueryName);
|
|
2295
|
+
window.location.replace(url.toString());
|
|
2296
|
+
return false;
|
|
2297
|
+
}
|
|
2298
|
+
return true;
|
|
2299
|
+
}
|
|
2300
|
+
async function beforeHandlerCheckExpires(request) {
|
|
2301
|
+
const expires = localStorage.getItem(expiresTokenStorageName);
|
|
2302
|
+
if (checkExpires(expires)) {
|
|
2303
|
+
return;
|
|
2304
|
+
}
|
|
2305
|
+
await refetchAfterRefreshFlow(request);
|
|
2306
|
+
}
|
|
2307
|
+
async function beforeHandlerSetToken(request) {
|
|
2308
|
+
if (processing)
|
|
2309
|
+
await waitUntil(() => processing);
|
|
2310
|
+
const token = request.token ?? localStorage.getItem(tokenStorageName);
|
|
2311
|
+
const isSameOrigin = request.path.includes(window.location.origin) || !startWith(request.path, "http");
|
|
2312
|
+
if ((!isSameOrigin || forceSetToken) && token)
|
|
2313
|
+
request.headers = {
|
|
2314
|
+
...request.headers,
|
|
2315
|
+
Authorization: `Bearer ${token}`,
|
|
2316
|
+
};
|
|
2317
|
+
}
|
|
2318
|
+
return {
|
|
2319
|
+
startRefreshFlow,
|
|
2320
|
+
startLoginFlowInSubWindow,
|
|
2321
|
+
startLoginFlow,
|
|
2322
|
+
startLogoutFlow,
|
|
2323
|
+
refetchAfterRefreshFlow,
|
|
2324
|
+
beforeHandlerSetToken,
|
|
2325
|
+
beforeHandlerCheckExpires,
|
|
2326
|
+
register,
|
|
2327
|
+
get isServicePage() {
|
|
2328
|
+
return [errorPageUrl, clearPageUrl, logoutPageUrl].some((u) => document.location.pathname === u);
|
|
2329
|
+
},
|
|
2330
|
+
get processing() {
|
|
2331
|
+
return processing;
|
|
2332
|
+
},
|
|
2333
|
+
get token() {
|
|
2334
|
+
return localStorage.getItem(tokenStorageName);
|
|
2335
|
+
},
|
|
2336
|
+
get expires() {
|
|
2337
|
+
const expires = localStorage.getItem(expiresTokenStorageName);
|
|
2338
|
+
return expires == undefined ? null : Number.isNaN(+expires) ? null : +expires;
|
|
2339
|
+
},
|
|
2340
|
+
get expired() {
|
|
2341
|
+
const expiresStr = localStorage.getItem(expiresTokenStorageName);
|
|
2342
|
+
const expires = expiresStr == undefined ? null : Number.isNaN(+expiresStr) ? null : +expiresStr;
|
|
2343
|
+
return expires == undefined ? true : Date.now() > expires;
|
|
2344
|
+
},
|
|
2345
|
+
};
|
|
2346
|
+
}
|
|
2347
|
+
|
|
2230
2348
|
function loggerAfterHandler(options = {}) {
|
|
2231
2349
|
return (request, response) => {
|
|
2232
2350
|
return new Promise((resolve) => {
|
|
@@ -2297,19 +2415,6 @@ function loggerBeforeHandler(options = {}) {
|
|
|
2297
2415
|
};
|
|
2298
2416
|
}
|
|
2299
2417
|
|
|
2300
|
-
const authBeforeHandler = (options = {}) => async (request) => {
|
|
2301
|
-
const { tokenStorageName = OAUTH_TOKEN_STORAGE_NAME, forceSetToken = false } = options;
|
|
2302
|
-
if (OAUTH_STATE.fetching)
|
|
2303
|
-
await waitUntil(() => OAUTH_STATE.fetching);
|
|
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)
|
|
2307
|
-
request.headers = {
|
|
2308
|
-
...request.headers,
|
|
2309
|
-
Authorization: `Bearer ${token}`,
|
|
2310
|
-
};
|
|
2311
|
-
};
|
|
2312
|
-
|
|
2313
2418
|
exports.COLOR_FORMATS = COLOR_FORMATS;
|
|
2314
2419
|
exports.DATE_TYPES = DATE_TYPES;
|
|
2315
2420
|
exports.FIELD_TYPES = FIELD_TYPES;
|
|
@@ -2319,6 +2424,9 @@ exports.IS_DENO = IS_DENO;
|
|
|
2319
2424
|
exports.IS_JEST = IS_JEST;
|
|
2320
2425
|
exports.IS_NODE = IS_NODE;
|
|
2321
2426
|
exports.IS_WEB_WORKER = IS_WEB_WORKER;
|
|
2427
|
+
exports.OAUTH_CLEAR_PAGE_URL = OAUTH_CLEAR_PAGE_URL;
|
|
2428
|
+
exports.OAUTH_ERROR_PAGE_URL = OAUTH_ERROR_PAGE_URL;
|
|
2429
|
+
exports.OAUTH_LOGOUT_PAGE_URL = OAUTH_LOGOUT_PAGE_URL;
|
|
2322
2430
|
exports.OAUTH_REFRESH_QUERY = OAUTH_REFRESH_QUERY;
|
|
2323
2431
|
exports.OAUTH_STATE = OAUTH_STATE;
|
|
2324
2432
|
exports.OAUTH_TOKEN_EXPIRES_STORAGE_NAME = OAUTH_TOKEN_EXPIRES_STORAGE_NAME;
|
|
@@ -2326,10 +2434,8 @@ exports.OAUTH_TOKEN_STORAGE_NAME = OAUTH_TOKEN_STORAGE_NAME;
|
|
|
2326
2434
|
exports.REQUEST_ERROR = REQUEST_ERROR;
|
|
2327
2435
|
exports.RESPONSE_DATA_SYMBOL = RESPONSE_DATA_SYMBOL;
|
|
2328
2436
|
exports.ResponseError = ResponseError;
|
|
2329
|
-
exports.applyOauthProvider = applyOauthProvider;
|
|
2330
2437
|
exports.arrayToMapByKey = arrayToMapByKey;
|
|
2331
2438
|
exports.asyncLoop = asyncLoop;
|
|
2332
|
-
exports.authBeforeHandler = authBeforeHandler;
|
|
2333
2439
|
exports.buildQueryString = buildQueryString;
|
|
2334
2440
|
exports.checkType = checkType;
|
|
2335
2441
|
exports.cloneDeep = cloneDeep;
|
|
@@ -2337,6 +2443,7 @@ exports.copyToClipboard = copyToClipboard;
|
|
|
2337
2443
|
exports.createFetchClient = createFetchClient;
|
|
2338
2444
|
exports.createGlobalId = createGlobalId;
|
|
2339
2445
|
exports.createLocalIdGenerator = createLocalIdGenerator;
|
|
2446
|
+
exports.createOauthProvider = createOauthProvider;
|
|
2340
2447
|
exports.createURLWithQueries = createURLWithQueries;
|
|
2341
2448
|
exports.dateDifference = dateDifference;
|
|
2342
2449
|
exports.dateFormat = dateFormat;
|
|
@@ -2355,8 +2462,6 @@ exports.getCallerFunctionName = getCallerFunctionName;
|
|
|
2355
2462
|
exports.getColorFormat = getColorFormat;
|
|
2356
2463
|
exports.getDateByRules = getDateByRules;
|
|
2357
2464
|
exports.getFileNameFromHeader = getFileNameFromHeader;
|
|
2358
|
-
exports.getOauthToken = getOauthToken;
|
|
2359
|
-
exports.getOauthTokenFromOtherWindow = getOauthTokenFromOtherWindow;
|
|
2360
2465
|
exports.getQueryValues = getQueryValues;
|
|
2361
2466
|
exports.getRandomColor = getRandomColor;
|
|
2362
2467
|
exports.getToday = getToday;
|
|
@@ -2384,7 +2489,6 @@ exports.randomHex = randomHex;
|
|
|
2384
2489
|
exports.randomNumber = randomNumber;
|
|
2385
2490
|
exports.randomString = randomString;
|
|
2386
2491
|
exports.readFile = readFile;
|
|
2387
|
-
exports.refetchAfterOauth = refetchAfterOauth;
|
|
2388
2492
|
exports.setByPath = setByPath;
|
|
2389
2493
|
exports.speedTest = speedTest;
|
|
2390
2494
|
exports.startWith = startWith;
|