nurseitaly-components 0.0.13 → 0.0.14
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/dist/configs/api/apiHandledError.d.ts +15 -0
- package/dist/configs/api/apiHandledError.js +21 -0
- package/dist/configs/api/applyAuthErrorHandling.d.ts +13 -0
- package/dist/configs/api/applyAuthErrorHandling.js +70 -0
- package/dist/configs/api/createApiClient.d.ts +9 -0
- package/dist/configs/api/createApiClient.js +51 -0
- package/dist/configs/api/dispatchApiError.d.ts +10 -0
- package/dist/configs/api/dispatchApiError.js +16 -0
- package/dist/configs/api/index.d.ts +16 -0
- package/dist/configs/api/index.js +16 -0
- package/dist/configs/api.d.ts +2 -10
- package/dist/configs/api.js +2 -52
- package/dist/configs/index.d.ts +1 -0
- package/dist/configs/index.js +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { AxiosError } from 'axios';
|
|
2
|
+
export type ApiErrorHandled = AxiosError & {
|
|
3
|
+
apiErrorHandled?: boolean;
|
|
4
|
+
/** @deprecated use apiErrorHandled */
|
|
5
|
+
authErrorHandled?: boolean;
|
|
6
|
+
};
|
|
7
|
+
export declare function isServerError(status: number | undefined): boolean;
|
|
8
|
+
export declare function markApiErrorHandled(error: AxiosError): void;
|
|
9
|
+
export declare function isHandledApiError(reason: unknown): boolean;
|
|
10
|
+
/** @deprecated use markApiErrorHandled */
|
|
11
|
+
export declare const markAuthErrorHandled: typeof markApiErrorHandled;
|
|
12
|
+
/** @deprecated use isHandledApiError */
|
|
13
|
+
export declare const isHandledAuthError: typeof isHandledApiError;
|
|
14
|
+
/** @deprecated use ApiErrorHandled */
|
|
15
|
+
export type AuthErrorHandled = ApiErrorHandled;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export function isServerError(status) {
|
|
2
|
+
return status !== undefined && status >= 500 && status < 600;
|
|
3
|
+
}
|
|
4
|
+
export function markApiErrorHandled(error) {
|
|
5
|
+
error.apiErrorHandled = true;
|
|
6
|
+
}
|
|
7
|
+
export function isHandledApiError(reason) {
|
|
8
|
+
if (!reason || typeof reason !== 'object')
|
|
9
|
+
return false;
|
|
10
|
+
const error = reason;
|
|
11
|
+
if (error.apiErrorHandled || error.authErrorHandled)
|
|
12
|
+
return true;
|
|
13
|
+
const status = error.response?.status;
|
|
14
|
+
if (!error.config || status === undefined)
|
|
15
|
+
return false;
|
|
16
|
+
return isServerError(status);
|
|
17
|
+
}
|
|
18
|
+
/** @deprecated use markApiErrorHandled */
|
|
19
|
+
export const markAuthErrorHandled = markApiErrorHandled;
|
|
20
|
+
/** @deprecated use isHandledApiError */
|
|
21
|
+
export const isHandledAuthError = isHandledApiError;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { AxiosInstance } from 'axios';
|
|
2
|
+
export type AuthErrorHandling = 'toast' | 'redirect' | 'none';
|
|
3
|
+
export type ApplyAuthErrorHandlingOptions = {
|
|
4
|
+
authErrorHandling?: AuthErrorHandling;
|
|
5
|
+
authStatuses?: Array<401 | 403>;
|
|
6
|
+
redirect?: {
|
|
7
|
+
on401?: string;
|
|
8
|
+
on403?: string;
|
|
9
|
+
};
|
|
10
|
+
onBeforeRedirect?: (status: 401 | 403) => void;
|
|
11
|
+
skipAuthHandlingInStorybook?: boolean;
|
|
12
|
+
};
|
|
13
|
+
export declare function applyAuthErrorHandling(api: AxiosInstance, options: ApplyAuthErrorHandlingOptions): AxiosInstance;
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { markApiErrorHandled } from './apiHandledError';
|
|
2
|
+
import CookieStorage from '../CookieStorage';
|
|
3
|
+
import { messageAction, loggedAction } from '../sessionTypes';
|
|
4
|
+
import { getCommonDispatch } from '../commonDispatch';
|
|
5
|
+
import { getErrorMessageValue } from '../useMessageUtils';
|
|
6
|
+
import i18n from 'i18next';
|
|
7
|
+
function isStorybook() {
|
|
8
|
+
return (typeof window !== 'undefined' &&
|
|
9
|
+
(window.location.port === '6006' ||
|
|
10
|
+
Boolean(window.__STORYBOOK__)));
|
|
11
|
+
}
|
|
12
|
+
function defaultRedirectUrls() {
|
|
13
|
+
const publicUrl = import.meta.env.VITE_APP_PUBLIC_URL;
|
|
14
|
+
return {
|
|
15
|
+
on401: import.meta.env.VITE_APP_AUTH_URL,
|
|
16
|
+
on403: import.meta.env.VITE_APP_UNAUTHORIZED_URL ??
|
|
17
|
+
(publicUrl ? `${publicUrl}/unauthorized` : undefined),
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
function clearAuthStorage() {
|
|
21
|
+
CookieStorage.removeJwtToken();
|
|
22
|
+
sessionStorage.clear();
|
|
23
|
+
localStorage.clear();
|
|
24
|
+
}
|
|
25
|
+
function handleToastAuthError(status) {
|
|
26
|
+
if (status === 401) {
|
|
27
|
+
clearAuthStorage();
|
|
28
|
+
getCommonDispatch()?.(loggedAction(undefined));
|
|
29
|
+
}
|
|
30
|
+
const value = getErrorMessageValue({
|
|
31
|
+
err: { response: { status } },
|
|
32
|
+
t: i18n.t.bind(i18n),
|
|
33
|
+
});
|
|
34
|
+
getCommonDispatch()?.(messageAction({ value, type: 'error' }));
|
|
35
|
+
}
|
|
36
|
+
function handleRedirectAuthError(status, redirect, onBeforeRedirect, skipAuthHandlingInStorybook = true) {
|
|
37
|
+
if (skipAuthHandlingInStorybook && isStorybook())
|
|
38
|
+
return;
|
|
39
|
+
onBeforeRedirect?.(status);
|
|
40
|
+
if (status === 401) {
|
|
41
|
+
clearAuthStorage();
|
|
42
|
+
if (redirect.on401)
|
|
43
|
+
window.location.replace(redirect.on401);
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
if (redirect.on403)
|
|
47
|
+
window.location.href = redirect.on403;
|
|
48
|
+
}
|
|
49
|
+
export function applyAuthErrorHandling(api, options) {
|
|
50
|
+
const { authErrorHandling = 'none', authStatuses = [401, 403], redirect: redirectOverrides, onBeforeRedirect, skipAuthHandlingInStorybook = true, } = options;
|
|
51
|
+
if (authErrorHandling === 'none')
|
|
52
|
+
return api;
|
|
53
|
+
const redirect = { ...defaultRedirectUrls(), ...redirectOverrides };
|
|
54
|
+
api.interceptors.response.use((response) => response, async (error) => {
|
|
55
|
+
const status = error.response?.status;
|
|
56
|
+
if (status === 401 || status === 403) {
|
|
57
|
+
if (!authStatuses.includes(status))
|
|
58
|
+
return Promise.reject(error);
|
|
59
|
+
if (authErrorHandling === 'toast') {
|
|
60
|
+
handleToastAuthError(status);
|
|
61
|
+
}
|
|
62
|
+
else if (authErrorHandling === 'redirect') {
|
|
63
|
+
handleRedirectAuthError(status, redirect, onBeforeRedirect, skipAuthHandlingInStorybook);
|
|
64
|
+
}
|
|
65
|
+
markApiErrorHandled(error);
|
|
66
|
+
}
|
|
67
|
+
return Promise.reject(error);
|
|
68
|
+
});
|
|
69
|
+
return api;
|
|
70
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { AxiosInstance, InternalAxiosRequestConfig } from 'axios';
|
|
2
|
+
export type ServerErrorHandling = 'toast' | 'none';
|
|
3
|
+
export type CreateApiClientOptions = {
|
|
4
|
+
baseURL: string;
|
|
5
|
+
attachJwt?: boolean;
|
|
6
|
+
serverErrorHandling?: ServerErrorHandling;
|
|
7
|
+
augmentRequest?: (config: InternalAxiosRequestConfig) => InternalAxiosRequestConfig;
|
|
8
|
+
};
|
|
9
|
+
export declare function createApiClient(options: CreateApiClientOptions): AxiosInstance;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import axios from 'axios';
|
|
2
|
+
import CookieStorage from '../CookieStorage';
|
|
3
|
+
import { dispatchServerApiError } from './dispatchApiError';
|
|
4
|
+
import { isServerError, markApiErrorHandled } from './apiHandledError';
|
|
5
|
+
const DEFAULT_HEADERS = {
|
|
6
|
+
'Cache-Control': 'no-cache, no-store, must-revalidate',
|
|
7
|
+
Pragma: 'no-cache',
|
|
8
|
+
'Content-Type': 'application/json',
|
|
9
|
+
Accept: 'application/json',
|
|
10
|
+
};
|
|
11
|
+
function toHandledServerErrorResponse(error) {
|
|
12
|
+
return {
|
|
13
|
+
data: null,
|
|
14
|
+
status: error.response?.status ?? 500,
|
|
15
|
+
statusText: error.response?.statusText ?? 'Internal Server Error',
|
|
16
|
+
headers: error.response?.headers ?? {},
|
|
17
|
+
config: error.config,
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
export function createApiClient(options) {
|
|
21
|
+
const { baseURL, attachJwt = true, serverErrorHandling = 'toast', augmentRequest, } = options;
|
|
22
|
+
const api = axios.create({
|
|
23
|
+
headers: DEFAULT_HEADERS,
|
|
24
|
+
baseURL,
|
|
25
|
+
});
|
|
26
|
+
api.interceptors.response.use((response) => response, async (error) => {
|
|
27
|
+
const status = error.response?.status;
|
|
28
|
+
if (isServerError(status) && serverErrorHandling === 'toast') {
|
|
29
|
+
dispatchServerApiError({ err: error });
|
|
30
|
+
markApiErrorHandled(error);
|
|
31
|
+
return toHandledServerErrorResponse(error);
|
|
32
|
+
}
|
|
33
|
+
if (error.status === null) {
|
|
34
|
+
console.log(JSON.stringify(error));
|
|
35
|
+
}
|
|
36
|
+
return Promise.reject(error);
|
|
37
|
+
});
|
|
38
|
+
api.interceptors.request.use((config) => {
|
|
39
|
+
if (!config?.headers) {
|
|
40
|
+
throw new Error('no header available');
|
|
41
|
+
}
|
|
42
|
+
if (attachJwt) {
|
|
43
|
+
const token = CookieStorage.getJwtToken();
|
|
44
|
+
if (token) {
|
|
45
|
+
config.headers.Authorization = `Bearer ${token}`;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return augmentRequest ? augmentRequest(config) : config;
|
|
49
|
+
});
|
|
50
|
+
return api;
|
|
51
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { TFunction } from 'i18next';
|
|
2
|
+
export declare function dispatchApiError({ err, t, key, }: {
|
|
3
|
+
err: unknown;
|
|
4
|
+
t?: TFunction;
|
|
5
|
+
key?: string;
|
|
6
|
+
}): void;
|
|
7
|
+
export declare function dispatchServerApiError({ err, t, }: {
|
|
8
|
+
err: unknown;
|
|
9
|
+
t?: TFunction;
|
|
10
|
+
}): void;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import i18n from 'i18next';
|
|
2
|
+
import { getErrorMessageValue } from '../useMessageUtils';
|
|
3
|
+
import { messageAction } from '../sessionTypes';
|
|
4
|
+
import { getCommonDispatch } from '../commonDispatch';
|
|
5
|
+
export function dispatchApiError({ err, t, key, }) {
|
|
6
|
+
const translate = t ?? i18n.t.bind(i18n);
|
|
7
|
+
const value = getErrorMessageValue({ err, t: translate, key });
|
|
8
|
+
getCommonDispatch()?.(messageAction({ value, type: 'error' }));
|
|
9
|
+
}
|
|
10
|
+
export function dispatchServerApiError({ err, t, }) {
|
|
11
|
+
dispatchApiError({
|
|
12
|
+
err,
|
|
13
|
+
t,
|
|
14
|
+
key: 'common',
|
|
15
|
+
});
|
|
16
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export declare const platformApi: {
|
|
2
|
+
base: string;
|
|
3
|
+
revision: string;
|
|
4
|
+
catalog: string;
|
|
5
|
+
editor: string;
|
|
6
|
+
};
|
|
7
|
+
export declare const parserApiBase: string;
|
|
8
|
+
declare const api: import("axios").AxiosInstance;
|
|
9
|
+
export { createApiClient } from './createApiClient';
|
|
10
|
+
export type { CreateApiClientOptions, ServerErrorHandling, } from './createApiClient';
|
|
11
|
+
export { applyAuthErrorHandling } from './applyAuthErrorHandling';
|
|
12
|
+
export type { ApplyAuthErrorHandlingOptions, AuthErrorHandling, } from './applyAuthErrorHandling';
|
|
13
|
+
export { isHandledApiError, isHandledAuthError, markApiErrorHandled, markAuthErrorHandled, } from './apiHandledError';
|
|
14
|
+
export type { ApiErrorHandled, AuthErrorHandled } from './apiHandledError';
|
|
15
|
+
export { dispatchApiError, dispatchServerApiError } from './dispatchApiError';
|
|
16
|
+
export default api;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { applyAuthErrorHandling } from './applyAuthErrorHandling';
|
|
2
|
+
import { createApiClient } from './createApiClient';
|
|
3
|
+
const platformApiBase = import.meta.env.VITE_APP_PLATFORM_API;
|
|
4
|
+
export const platformApi = {
|
|
5
|
+
base: platformApiBase,
|
|
6
|
+
revision: `${platformApiBase}/revision`,
|
|
7
|
+
catalog: `${platformApiBase}/catalog`,
|
|
8
|
+
editor: `${platformApiBase}/editor`,
|
|
9
|
+
};
|
|
10
|
+
export const parserApiBase = import.meta.env.VITE_APP_PARSER_API;
|
|
11
|
+
const api = applyAuthErrorHandling(createApiClient({ baseURL: platformApiBase }), { authErrorHandling: 'redirect' });
|
|
12
|
+
export { createApiClient } from './createApiClient';
|
|
13
|
+
export { applyAuthErrorHandling } from './applyAuthErrorHandling';
|
|
14
|
+
export { isHandledApiError, isHandledAuthError, markApiErrorHandled, markAuthErrorHandled, } from './apiHandledError';
|
|
15
|
+
export { dispatchApiError, dispatchServerApiError } from './dispatchApiError';
|
|
16
|
+
export default api;
|
package/dist/configs/api.d.ts
CHANGED
|
@@ -1,10 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
export
|
|
3
|
-
base: string;
|
|
4
|
-
revision: string;
|
|
5
|
-
catalog: string;
|
|
6
|
-
editor: string;
|
|
7
|
-
};
|
|
8
|
-
export declare const parserApiBase: string;
|
|
9
|
-
declare const api: import("axios").AxiosInstance;
|
|
10
|
-
export default api;
|
|
1
|
+
export * from './api/index';
|
|
2
|
+
export { default } from './api/index';
|
package/dist/configs/api.js
CHANGED
|
@@ -1,52 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
const platformApiBase = import.meta.env.VITE_APP_PLATFORM_API;
|
|
4
|
-
/** Platform API roots (formerly separate env vars per service). */
|
|
5
|
-
export const platformApi = {
|
|
6
|
-
base: platformApiBase,
|
|
7
|
-
revision: `${platformApiBase}/revision`,
|
|
8
|
-
catalog: `${platformApiBase}/catalog`,
|
|
9
|
-
editor: `${platformApiBase}/editor`,
|
|
10
|
-
};
|
|
11
|
-
export const parserApiBase = import.meta.env.VITE_APP_PARSER_API;
|
|
12
|
-
const api = axios.create({
|
|
13
|
-
headers: {
|
|
14
|
-
'Cache-Control': 'no-cache, no-store, must-revalidate',
|
|
15
|
-
Pragma: 'no-cache',
|
|
16
|
-
'Content-Type': 'application/json',
|
|
17
|
-
Accept: 'application/json',
|
|
18
|
-
},
|
|
19
|
-
baseURL: platformApiBase,
|
|
20
|
-
});
|
|
21
|
-
const isStorybook = () => typeof window !== 'undefined' &&
|
|
22
|
-
(window.location.port === '6006' ||
|
|
23
|
-
window.__STORYBOOK__);
|
|
24
|
-
api.interceptors.response.use((response) => response, async (error) => {
|
|
25
|
-
if (error.response?.status === 401) {
|
|
26
|
-
CookieStorage.removeJwtToken();
|
|
27
|
-
sessionStorage.clear();
|
|
28
|
-
localStorage.clear();
|
|
29
|
-
if (!isStorybook()) {
|
|
30
|
-
window.location.replace(import.meta.env.VITE_APP_AUTH_URL);
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
else if (error.response?.status === 403 && !isStorybook()) {
|
|
34
|
-
window.location.href = import.meta.env.VITE_APP_UNAUTHORIZED_URL;
|
|
35
|
-
}
|
|
36
|
-
else if (error.status === null) {
|
|
37
|
-
console.log(JSON.stringify(error));
|
|
38
|
-
}
|
|
39
|
-
return Promise.reject(error);
|
|
40
|
-
});
|
|
41
|
-
api.interceptors.request.use((config) => {
|
|
42
|
-
if (!config?.headers) {
|
|
43
|
-
throw new Error('no header available');
|
|
44
|
-
}
|
|
45
|
-
const token = CookieStorage.getJwtToken();
|
|
46
|
-
if (!token)
|
|
47
|
-
return config;
|
|
48
|
-
// eslint-disable-next-line no-param-reassign
|
|
49
|
-
config.headers.Authorization = `Bearer ${token}`;
|
|
50
|
-
return config;
|
|
51
|
-
});
|
|
52
|
-
export default api;
|
|
1
|
+
export * from './api/index';
|
|
2
|
+
export { default } from './api/index';
|
package/dist/configs/index.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export { default as CommonContext, CommonProvider } from './CommonContext';
|
|
2
2
|
export { default as CommonDispatchBridge } from './CommonDispatchBridge';
|
|
3
|
+
export * from './api/index';
|
|
3
4
|
export { getCommonDispatch, registerCommonDispatch, } from './commonDispatch';
|
|
4
5
|
export { default as CookieStorage } from './CookieStorage';
|
|
5
6
|
export { commonLocalization, commonResources, featureResources, mergeResources, } from './Localization';
|
package/dist/configs/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export { default as CommonContext, CommonProvider } from './CommonContext';
|
|
2
2
|
export { default as CommonDispatchBridge } from './CommonDispatchBridge';
|
|
3
|
+
export * from './api/index';
|
|
3
4
|
export { getCommonDispatch, registerCommonDispatch, } from './commonDispatch';
|
|
4
5
|
export { default as CookieStorage } from './CookieStorage';
|
|
5
6
|
export { commonLocalization, commonResources, featureResources, mergeResources, } from './Localization';
|