@krainovsd/js-helpers 0.19.0-beta.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 +123 -57
- package/lib/cjs/index.cjs.map +1 -1
- package/lib/esm/api/api.constants.js +8 -7
- package/lib/esm/api/api.constants.js.map +1 -1
- package/lib/esm/api/api.js +29 -18
- package/lib/esm/api/api.js.map +1 -1
- package/lib/esm/api/oauth.js +87 -32
- package/lib/esm/api/oauth.js.map +1 -1
- package/lib/index.d.ts +27 -14
- package/package.json +1 -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;
|
|
@@ -1789,6 +1790,7 @@ function createFetchClient(options) {
|
|
|
1789
1790
|
let retries = options.retries;
|
|
1790
1791
|
let timeout = options.timeout;
|
|
1791
1792
|
let refetchAfterAuthGlobal = options.refetchAfterAuth;
|
|
1793
|
+
let enabled = options.enabled ?? true;
|
|
1792
1794
|
function recreate(options) {
|
|
1793
1795
|
if ("client" in options) {
|
|
1794
1796
|
client = options.client;
|
|
@@ -1808,8 +1810,18 @@ function createFetchClient(options) {
|
|
|
1808
1810
|
if ("refetchAfterAuth" in options) {
|
|
1809
1811
|
refetchAfterAuthGlobal = options.refetchAfterAuth;
|
|
1810
1812
|
}
|
|
1813
|
+
if ("enabled" in options) {
|
|
1814
|
+
enabled = options.enabled ?? true;
|
|
1815
|
+
}
|
|
1811
1816
|
}
|
|
1812
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
|
+
}
|
|
1813
1825
|
const timeoutController = new AbortController();
|
|
1814
1826
|
const requestController = new AbortController();
|
|
1815
1827
|
const requestTimeout = request.timeout ?? timeout;
|
|
@@ -1918,12 +1930,12 @@ function createFetchClient(options) {
|
|
|
1918
1930
|
if (!response.ok) {
|
|
1919
1931
|
if (response.status === 304) {
|
|
1920
1932
|
const error = new ResponseError({
|
|
1921
|
-
message: REQUEST_ERROR.
|
|
1933
|
+
message: REQUEST_ERROR.Cache,
|
|
1922
1934
|
status: response.status,
|
|
1923
1935
|
headers: Object.fromEntries(response.headers.entries()),
|
|
1924
1936
|
});
|
|
1925
|
-
request.onError?.(REQUEST_ERROR.
|
|
1926
|
-
return { data: error, error: REQUEST_ERROR.
|
|
1937
|
+
request.onError?.(REQUEST_ERROR.Cache, error);
|
|
1938
|
+
return { data: error, error: REQUEST_ERROR.Cache, response };
|
|
1927
1939
|
}
|
|
1928
1940
|
/** if you need observe other than only 401 status, you can override some statuses in after handler middleware to 401 */
|
|
1929
1941
|
if (response.status === 401 && refetchAfterAuth) {
|
|
@@ -1966,14 +1978,14 @@ function createFetchClient(options) {
|
|
|
1966
1978
|
catch { }
|
|
1967
1979
|
const error = new ResponseError({
|
|
1968
1980
|
status: response.status,
|
|
1969
|
-
message: REQUEST_ERROR.
|
|
1981
|
+
message: REQUEST_ERROR.Http,
|
|
1970
1982
|
description: result,
|
|
1971
1983
|
headers: Object.fromEntries(response.headers.entries()),
|
|
1972
1984
|
});
|
|
1973
|
-
request.onError?.(REQUEST_ERROR.
|
|
1985
|
+
request.onError?.(REQUEST_ERROR.Http, error);
|
|
1974
1986
|
return {
|
|
1975
1987
|
data: error,
|
|
1976
|
-
error: REQUEST_ERROR.
|
|
1988
|
+
error: REQUEST_ERROR.Http,
|
|
1977
1989
|
response,
|
|
1978
1990
|
};
|
|
1979
1991
|
}
|
|
@@ -2042,36 +2054,36 @@ function createFetchClient(options) {
|
|
|
2042
2054
|
}
|
|
2043
2055
|
if (err instanceof TypeError) {
|
|
2044
2056
|
const error = new ResponseError({
|
|
2045
|
-
message: REQUEST_ERROR.
|
|
2057
|
+
message: REQUEST_ERROR.Network,
|
|
2046
2058
|
status: 0,
|
|
2047
2059
|
description: String(err.message),
|
|
2048
2060
|
});
|
|
2049
|
-
request.onError?.(REQUEST_ERROR.
|
|
2050
|
-
return { data: error, error: REQUEST_ERROR.
|
|
2061
|
+
request.onError?.(REQUEST_ERROR.Network, error);
|
|
2062
|
+
return { data: error, error: REQUEST_ERROR.Network, response: null };
|
|
2051
2063
|
}
|
|
2052
2064
|
if (err instanceof Error && err.name === "AbortError") {
|
|
2053
2065
|
if (timeoutController.signal.aborted) {
|
|
2054
2066
|
const error = new ResponseError({
|
|
2055
|
-
message: REQUEST_ERROR.
|
|
2067
|
+
message: REQUEST_ERROR.Timeout,
|
|
2056
2068
|
status: 0,
|
|
2057
2069
|
});
|
|
2058
|
-
request.onError?.(REQUEST_ERROR.
|
|
2059
|
-
return { data: error, error: REQUEST_ERROR.
|
|
2070
|
+
request.onError?.(REQUEST_ERROR.Timeout, error);
|
|
2071
|
+
return { data: error, error: REQUEST_ERROR.Timeout, response: null };
|
|
2060
2072
|
}
|
|
2061
2073
|
const error = new ResponseError({
|
|
2062
|
-
message: REQUEST_ERROR.
|
|
2074
|
+
message: REQUEST_ERROR.Abort,
|
|
2063
2075
|
status: 0,
|
|
2064
2076
|
});
|
|
2065
|
-
request.onError?.(REQUEST_ERROR.
|
|
2066
|
-
return { data: error, error: REQUEST_ERROR.
|
|
2077
|
+
request.onError?.(REQUEST_ERROR.Abort, error);
|
|
2078
|
+
return { data: error, error: REQUEST_ERROR.Abort, response: null };
|
|
2067
2079
|
}
|
|
2068
2080
|
const error = new ResponseError({
|
|
2069
|
-
message: REQUEST_ERROR.
|
|
2081
|
+
message: REQUEST_ERROR.Unknown,
|
|
2070
2082
|
status: 0,
|
|
2071
2083
|
description: String(err),
|
|
2072
2084
|
});
|
|
2073
|
-
request.onError?.(REQUEST_ERROR.
|
|
2074
|
-
return { data: error, error: REQUEST_ERROR.
|
|
2085
|
+
request.onError?.(REQUEST_ERROR.Unknown, error);
|
|
2086
|
+
return { data: error, error: REQUEST_ERROR.Unknown, response: null };
|
|
2075
2087
|
}
|
|
2076
2088
|
finally {
|
|
2077
2089
|
requestController.abort();
|
|
@@ -2112,18 +2124,48 @@ function executeAfterHandlers(handlers, request, response) {
|
|
|
2112
2124
|
}
|
|
2113
2125
|
|
|
2114
2126
|
function createOauthProvider(opts = {}) {
|
|
2115
|
-
const { refreshTokenWindowUrl = window.origin, closeObserveSubWindowInterval = 500, waitSubWindow =
|
|
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;
|
|
2116
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
|
+
}
|
|
2117
2135
|
async function refetchAfterRefreshFlow(request) {
|
|
2118
2136
|
if (processing) {
|
|
2119
|
-
await
|
|
2137
|
+
await beforeHandlerSetToken(request);
|
|
2120
2138
|
return request;
|
|
2121
2139
|
}
|
|
2122
|
-
|
|
2123
|
-
|
|
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);
|
|
2124
2166
|
return request;
|
|
2125
2167
|
}
|
|
2126
|
-
async function
|
|
2168
|
+
async function startLoginFlowInSubWindow() {
|
|
2127
2169
|
processing = true;
|
|
2128
2170
|
let waiting = true;
|
|
2129
2171
|
const url = new URL(typeof refreshTokenWindowUrl === "function" ? refreshTokenWindowUrl() : refreshTokenWindowUrl);
|
|
@@ -2165,7 +2207,7 @@ function createOauthProvider(opts = {}) {
|
|
|
2165
2207
|
if ("onSubWindowOpenError" in opts)
|
|
2166
2208
|
opts.onSubWindowOpenError?.();
|
|
2167
2209
|
else {
|
|
2168
|
-
startLoginFlow();
|
|
2210
|
+
await startLoginFlow();
|
|
2169
2211
|
}
|
|
2170
2212
|
waiting = false;
|
|
2171
2213
|
return;
|
|
@@ -2174,21 +2216,34 @@ function createOauthProvider(opts = {}) {
|
|
|
2174
2216
|
processing = false;
|
|
2175
2217
|
}
|
|
2176
2218
|
// Trigger an oauth flow through some proxy server
|
|
2177
|
-
function startLoginFlow(loginUrlArg = loginUrl) {
|
|
2219
|
+
async function startLoginFlow(loginUrlArg = loginUrl, delay = 2000) {
|
|
2178
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)}`;
|
|
2179
2221
|
window.location.replace(typeof loginUrlArg === "function" ? loginUrlArg() : loginUrlArg);
|
|
2222
|
+
await wait(delay);
|
|
2180
2223
|
return null;
|
|
2181
2224
|
}
|
|
2182
2225
|
// Trigger an oauth flow through some proxy server
|
|
2183
|
-
function startLogoutFlow(logoutUrlArg = logoutUrl) {
|
|
2184
|
-
logoutUrlArg ??= `/api/v1/auth/logout?frontend_protocol=${window.location.protocol.replace(":", "")}&frontend_host=${window.location.host}
|
|
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}`;
|
|
2185
2228
|
window.location.replace(typeof logoutUrlArg === "function" ? logoutUrlArg() : logoutUrlArg);
|
|
2229
|
+
await wait(delay);
|
|
2186
2230
|
return null;
|
|
2187
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
|
+
}
|
|
2188
2243
|
// Processing an oauth flow: extract expires, get token, close sub windows, check if logout/clear/error url
|
|
2189
2244
|
async function register() {
|
|
2190
2245
|
if (window.location.pathname === logoutPageUrl) {
|
|
2191
|
-
startLogoutFlow();
|
|
2246
|
+
await startLogoutFlow();
|
|
2192
2247
|
return false;
|
|
2193
2248
|
}
|
|
2194
2249
|
if (window.location.pathname === clearPageUrl) {
|
|
@@ -2212,30 +2267,29 @@ function createOauthProvider(opts = {}) {
|
|
|
2212
2267
|
? refreshQuery[refreshQuery.length - 1] === "true"
|
|
2213
2268
|
: false;
|
|
2214
2269
|
/** Expires token */
|
|
2215
|
-
const
|
|
2270
|
+
const expiresStr = isString(expiresQuery)
|
|
2216
2271
|
? expiresQuery
|
|
2217
2272
|
: isArray(expiresQuery)
|
|
2218
2273
|
? expiresQuery[expiresQuery.length - 1]
|
|
2219
|
-
:
|
|
2220
|
-
|
|
2221
|
-
|
|
2274
|
+
: null;
|
|
2275
|
+
const expires = expiresStr ? getExpiresDate(+expiresStr) : null;
|
|
2276
|
+
if (checkExpires(expires)) {
|
|
2277
|
+
localStorage.setItem(expiresTokenStorageName, String(expires));
|
|
2222
2278
|
if (tokenRequest) {
|
|
2223
|
-
const
|
|
2224
|
-
if (
|
|
2225
|
-
localStorage.setItem(tokenStorageName, token);
|
|
2279
|
+
const tokenInfo = await tokenRequest();
|
|
2280
|
+
if (tokenInfo != undefined) {
|
|
2281
|
+
localStorage.setItem(tokenStorageName, tokenInfo.token);
|
|
2226
2282
|
}
|
|
2227
2283
|
}
|
|
2228
|
-
|
|
2229
|
-
|
|
2230
|
-
|
|
2231
|
-
|
|
2232
|
-
|
|
2233
|
-
|
|
2234
|
-
|
|
2235
|
-
|
|
2236
|
-
|
|
2237
|
-
/** Delete expires query */
|
|
2238
|
-
if (expires) {
|
|
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 */
|
|
2239
2293
|
const url = new URL(window.location.href);
|
|
2240
2294
|
url.searchParams.delete(expiresTokenQueryName);
|
|
2241
2295
|
window.location.replace(url.toString());
|
|
@@ -2243,7 +2297,14 @@ function createOauthProvider(opts = {}) {
|
|
|
2243
2297
|
}
|
|
2244
2298
|
return true;
|
|
2245
2299
|
}
|
|
2246
|
-
async function
|
|
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) {
|
|
2247
2308
|
if (processing)
|
|
2248
2309
|
await waitUntil(() => processing);
|
|
2249
2310
|
const token = request.token ?? localStorage.getItem(tokenStorageName);
|
|
@@ -2255,12 +2316,17 @@ function createOauthProvider(opts = {}) {
|
|
|
2255
2316
|
};
|
|
2256
2317
|
}
|
|
2257
2318
|
return {
|
|
2258
|
-
|
|
2319
|
+
startRefreshFlow,
|
|
2320
|
+
startLoginFlowInSubWindow,
|
|
2259
2321
|
startLoginFlow,
|
|
2260
2322
|
startLogoutFlow,
|
|
2261
|
-
register,
|
|
2262
2323
|
refetchAfterRefreshFlow,
|
|
2263
|
-
|
|
2324
|
+
beforeHandlerSetToken,
|
|
2325
|
+
beforeHandlerCheckExpires,
|
|
2326
|
+
register,
|
|
2327
|
+
get isServicePage() {
|
|
2328
|
+
return [errorPageUrl, clearPageUrl, logoutPageUrl].some((u) => document.location.pathname === u);
|
|
2329
|
+
},
|
|
2264
2330
|
get processing() {
|
|
2265
2331
|
return processing;
|
|
2266
2332
|
},
|