@elliemae/pui-app-sdk 4.14.1 → 4.14.2
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/cjs/api/auth/index.js +3 -1
- package/dist/cjs/utils/app-config/index.js +27 -13
- package/dist/cjs/utils/app-config/tests/app.config.json +147 -0
- package/dist/cjs/utils/auth/index.js +2 -1
- package/dist/cjs/utils/testing/render-with-router-redux.js +14 -15
- package/dist/cjs/utils/window.js +7 -1
- package/dist/cjs/view/micro-app/resources/manifest.js +20 -13
- package/dist/cjs/view/wait-message/index.js +14 -5
- package/dist/esm/api/auth/index.js +3 -1
- package/dist/esm/utils/app-config/index.js +27 -13
- package/dist/esm/utils/app-config/tests/app.config.json +147 -0
- package/dist/esm/utils/auth/index.js +2 -1
- package/dist/esm/utils/testing/render-with-router-redux.js +14 -15
- package/dist/esm/utils/window.js +7 -1
- package/dist/esm/view/micro-app/resources/manifest.js +20 -13
- package/dist/esm/view/wait-message/index.js +15 -6
- package/dist/types/lib/api/auth/index.d.ts +2 -1
- package/dist/types/lib/data/store.d.ts +2 -2
- package/dist/types/lib/utils/app-config/tests/index.test.d.ts +1 -0
- package/dist/types/lib/utils/testing/render-with-redux.d.ts +2 -2
- package/dist/types/lib/utils/testing/render-with-router-redux.d.ts +7 -6
- package/dist/types/lib/view/breakpoint/index.stories.d.ts +0 -1
- package/dist/types/lib/view/error-boundary/default-error-template.d.ts +0 -1
- package/dist/types/lib/view/error-toast/index.stories.d.ts +0 -1
- package/dist/types/lib/view/fields/check-box/index.d.ts +0 -1
- package/dist/types/lib/view/fields/combo-box/index.d.ts +0 -1
- package/dist/types/lib/view/fields/connect-form.d.ts +0 -1
- package/dist/types/lib/view/fields/date-input/index.d.ts +0 -1
- package/dist/types/lib/view/fields/date-picker/index.d.ts +0 -1
- package/dist/types/lib/view/fields/date-range-picker/index.d.ts +0 -1
- package/dist/types/lib/view/fields/large-text-box/index.d.ts +0 -1
- package/dist/types/lib/view/fields/radio/index.d.ts +0 -1
- package/dist/types/lib/view/fields/radio-group/index.d.ts +0 -1
- package/dist/types/lib/view/fields/text-box/index.d.ts +0 -1
- package/dist/types/lib/view/fields/watch-value.d.ts +0 -1
- package/dist/types/lib/view/form/personal-info-section.d.ts +0 -1
- package/dist/types/lib/view/live-message/index.d.ts +0 -1
- package/dist/types/lib/view/live-message/index.stories.d.ts +0 -1
- package/dist/types/lib/view/session-timeout/index.d.ts +0 -1
- package/dist/types/lib/view/session-timeout/index.stories.d.ts +0 -1
- package/package.json +2 -2
|
@@ -27,13 +27,15 @@ var import_http_client = require("../../communication/http-client/index.js");
|
|
|
27
27
|
const getToken = async ({
|
|
28
28
|
clientId,
|
|
29
29
|
redirectUri,
|
|
30
|
-
idpCode
|
|
30
|
+
idpCode,
|
|
31
|
+
scope
|
|
31
32
|
}) => {
|
|
32
33
|
const params = new URLSearchParams();
|
|
33
34
|
params.append("grant_type", "authorization_code");
|
|
34
35
|
params.append("client_id", clientId);
|
|
35
36
|
params.append("redirect_uri", redirectUri);
|
|
36
37
|
params.append("code", idpCode);
|
|
38
|
+
params.append("scope", scope);
|
|
37
39
|
const { data } = await (0, import_http_client.getHTTPClient)().post(
|
|
38
40
|
"/oauth2/v1/token",
|
|
39
41
|
params
|
|
@@ -32,7 +32,6 @@ __export(app_config_exports, {
|
|
|
32
32
|
});
|
|
33
33
|
module.exports = __toCommonJS(app_config_exports);
|
|
34
34
|
var import_lodash = __toESM(require("lodash"));
|
|
35
|
-
var import_http_client = require("../../communication/http-client/index.js");
|
|
36
35
|
var import_config = require("./config.js");
|
|
37
36
|
var import_appdynamics = require("../../analytics/appdynamics.js");
|
|
38
37
|
var import_web_analytics = require("../../analytics/web-analytics.js");
|
|
@@ -47,15 +46,30 @@ const parseAppConfig = (data) => {
|
|
|
47
46
|
(0, import_appdynamics.setAppDynamicsUserData)({ envName: activeEnv });
|
|
48
47
|
(0, import_web_analytics.updateBAEventParameters)({ envName: activeEnv });
|
|
49
48
|
};
|
|
50
|
-
const
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
}
|
|
49
|
+
const getUnVersionedPath = (path) => path.replace(/\d+\.\d+/, "latest");
|
|
50
|
+
const loadAppConfig = async (configPath = (0, import_window.getAssetPath)()) => {
|
|
51
|
+
const appConfigUrl = `${configPath.replace(/\/?$/, "/")}app.config.json`;
|
|
52
|
+
const unversionedConfigPath = getUnVersionedPath(configPath);
|
|
53
|
+
try {
|
|
54
|
+
const response = await fetch(appConfigUrl);
|
|
55
|
+
if (!response.ok) {
|
|
56
|
+
if (configPath !== unversionedConfigPath) {
|
|
57
|
+
await loadAppConfig(unversionedConfigPath);
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
const message = `App Config is not found at ${appConfigUrl}`;
|
|
61
|
+
throw new Error(message);
|
|
62
|
+
}
|
|
63
|
+
const appConfig = await response.json();
|
|
64
|
+
parseAppConfig(appConfig);
|
|
65
|
+
} catch (ex) {
|
|
66
|
+
if (configPath !== unversionedConfigPath) {
|
|
67
|
+
await loadAppConfig(unversionedConfigPath);
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
if (ex?.message?.includes(`Unexpected token`)) {
|
|
71
|
+
throw new Error(`App config file at ${appConfigUrl} is not a valid JSON`);
|
|
72
|
+
}
|
|
73
|
+
throw ex;
|
|
74
|
+
}
|
|
75
|
+
};
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
{
|
|
2
|
+
"appId": "loanapp",
|
|
3
|
+
"activeEnv": "localhost",
|
|
4
|
+
"googleTagManager": true,
|
|
5
|
+
"sessionTimeoutWarnInterval": "7200000",
|
|
6
|
+
"sessionTimeoutInterval": "9000000",
|
|
7
|
+
"serviceEndpoints": {
|
|
8
|
+
"api": "",
|
|
9
|
+
"idp": "https://int.idp.ellielabs.com",
|
|
10
|
+
"logger": "https://int.api.puidiagnostics.rd.elliemae.io/v1/logging"
|
|
11
|
+
},
|
|
12
|
+
"env": {
|
|
13
|
+
"localhost": {
|
|
14
|
+
"serviceEndpoints": {
|
|
15
|
+
"api": "",
|
|
16
|
+
"idp": "https://int.idp.ellielabs.com",
|
|
17
|
+
"logger": "https://int.api.puidiagnostics.rd.elliemae.io/v1/logging"
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
"dev": {
|
|
21
|
+
"serviceEndpoints": {
|
|
22
|
+
"api": "https://dev.api.puiservice.rd.elliemae.io",
|
|
23
|
+
"idp": "https://int.idp.ellielabs.com",
|
|
24
|
+
"logger": "https://int.api.puidiagnostics.rd.elliemae.io/v1/logging"
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
"dev2": {
|
|
28
|
+
"serviceEndpoints": {
|
|
29
|
+
"api": "https://int.api.ellielabs.com",
|
|
30
|
+
"idp": "https://int.idp.ellielabs.com",
|
|
31
|
+
"logger": "https://int.api.puidiagnostics.rd.elliemae.io/v1/logging"
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
"qa": {
|
|
35
|
+
"serviceEndpoints": {
|
|
36
|
+
"api": "https://dev.api.puiservice.rd.elliemae.io",
|
|
37
|
+
"idp": "https://int.idp.ellielabs.com",
|
|
38
|
+
"logger": "https://int.api.puidiagnostics.rd.elliemae.io/v1/logging"
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
"qa2": {
|
|
42
|
+
"serviceEndpoints": {
|
|
43
|
+
"api": "https://int.api.ellielabs.com",
|
|
44
|
+
"idp": "https://int.idp.ellielabs.com",
|
|
45
|
+
"logger": "https://int.api.puidiagnostics.rd.elliemae.io/v1/logging"
|
|
46
|
+
}
|
|
47
|
+
},
|
|
48
|
+
"qa3": {
|
|
49
|
+
"serviceEndpoints": {
|
|
50
|
+
"api": "https://int.api.ellielabs.com",
|
|
51
|
+
"idp": "https://int.idp.ellielabs.com",
|
|
52
|
+
"logger": "https://int.api.puidiagnostics.rd.elliemae.io/v1/logging"
|
|
53
|
+
}
|
|
54
|
+
},
|
|
55
|
+
"int": {
|
|
56
|
+
"serviceEndpoints": {
|
|
57
|
+
"api": "https://dev.api.puiservice.rd.elliemae.io",
|
|
58
|
+
"idp": "https://int.idp.ellielabs.com",
|
|
59
|
+
"logger": "https://int.api.puidiagnostics.rd.elliemae.io/v1/logging"
|
|
60
|
+
}
|
|
61
|
+
},
|
|
62
|
+
"peg-osb1": {
|
|
63
|
+
"serviceEndpoints": {
|
|
64
|
+
"api": "https://encompass-peg-api.elliemae.com",
|
|
65
|
+
"idp": "https://peg.idp.ellielabs.com/authorize",
|
|
66
|
+
"logger": "https://int.api.puidiagnostics.rd.elliemae.io/v1/logging"
|
|
67
|
+
}
|
|
68
|
+
},
|
|
69
|
+
"peg-osb2": {
|
|
70
|
+
"serviceEndpoints": {
|
|
71
|
+
"api": "https://encompass-peg2-api.elliemae.com",
|
|
72
|
+
"idp": "https://peg.idp.ellielabs.com/authorize",
|
|
73
|
+
"logger": "https://int.api.puidiagnostics.rd.elliemae.io/v1/logging"
|
|
74
|
+
}
|
|
75
|
+
},
|
|
76
|
+
"peg": {
|
|
77
|
+
"serviceEndpoints": {
|
|
78
|
+
"api": "https://peg2-west.api.ellielabs.com",
|
|
79
|
+
"idp": "https://peg.idp.ellielabs.com/authorize",
|
|
80
|
+
"logger": "https://int.api.puidiagnostics.rd.elliemae.io/v1/logging"
|
|
81
|
+
}
|
|
82
|
+
},
|
|
83
|
+
"peg-oapi-west": {
|
|
84
|
+
"serviceEndpoints": {
|
|
85
|
+
"api": "https://peg2-west.api.ellielabs.com",
|
|
86
|
+
"idp": "https://peg.idp.ellielabs.com/authorize",
|
|
87
|
+
"logger": "https://int.api.puidiagnostics.rd.elliemae.io/v1/logging"
|
|
88
|
+
}
|
|
89
|
+
},
|
|
90
|
+
"peg-oapi-east": {
|
|
91
|
+
"serviceEndpoints": {
|
|
92
|
+
"api": "https://peg2-east.api.ellielabs.com",
|
|
93
|
+
"idp": "https://peg.idp.ellielabs.com/authorize",
|
|
94
|
+
"logger": "https://int.api.puidiagnostics.rd.elliemae.io/v1/logging"
|
|
95
|
+
}
|
|
96
|
+
},
|
|
97
|
+
"peg2-oapi-east": {
|
|
98
|
+
"serviceEndpoints": {
|
|
99
|
+
"api": "https://peg2-east.api.ellielabs.com",
|
|
100
|
+
"idp": "https://peg.idp.ellielabs.com/authorize",
|
|
101
|
+
"logger": "https://int.api.puidiagnostics.rd.elliemae.io/v1/logging"
|
|
102
|
+
}
|
|
103
|
+
},
|
|
104
|
+
"peg3": {
|
|
105
|
+
"serviceEndpoints": {
|
|
106
|
+
"api": "https://pel1.api.ellielabs.com",
|
|
107
|
+
"idp": "https://peg3.idp.ellielabs.com/authorize",
|
|
108
|
+
"logger": "https://int.api.puidiagnostics.rd.elliemae.io/v1/logging"
|
|
109
|
+
}
|
|
110
|
+
},
|
|
111
|
+
"stage": {
|
|
112
|
+
"serviceEndpoints": {
|
|
113
|
+
"api": "https://stg.api.elliemae.com",
|
|
114
|
+
"idp": "https://stg.idp.elliemae.com/authorize",
|
|
115
|
+
"logger": "https://stg.api.puidiagnostics.ellielabs.com/v1/logging"
|
|
116
|
+
}
|
|
117
|
+
},
|
|
118
|
+
"beta": {
|
|
119
|
+
"serviceEndpoints": {
|
|
120
|
+
"api": "https://concept.api.elliemae.com",
|
|
121
|
+
"idp": "https://concept.idp.elliemae.com/authorize",
|
|
122
|
+
"logger": "https://concept.api.puidiagnostics.elliemae.com/v1/logging"
|
|
123
|
+
}
|
|
124
|
+
},
|
|
125
|
+
"demo": {
|
|
126
|
+
"serviceEndpoints": {
|
|
127
|
+
"api": "https://concept.api.elliemae.com",
|
|
128
|
+
"idp": "https://concept.idp.elliemae.com/authorize",
|
|
129
|
+
"logger": "https://concept.api.puidiagnostics.elliemae.com/v1/logging"
|
|
130
|
+
}
|
|
131
|
+
},
|
|
132
|
+
"epc": {
|
|
133
|
+
"serviceEndpoints": {
|
|
134
|
+
"api": "https://concept.api.elliemae.com",
|
|
135
|
+
"idp": "https://concept.idp.elliemae.com/authorize",
|
|
136
|
+
"logger": "https://concept.api.puidiagnostics.elliemae.com/v1/logging"
|
|
137
|
+
}
|
|
138
|
+
},
|
|
139
|
+
"prod": {
|
|
140
|
+
"serviceEndpoints": {
|
|
141
|
+
"api": "https://api.elliemae.com",
|
|
142
|
+
"idp": "https://idp.elliemae.com/authorize",
|
|
143
|
+
"logger": "https://api.puidiagnostics.ellieservices.com/v1/logging"
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
@@ -113,7 +113,8 @@ const authorize = async ({
|
|
|
113
113
|
const { tokenType, accessToken } = await (0, import_auth.getToken)({
|
|
114
114
|
idpCode,
|
|
115
115
|
redirectUri,
|
|
116
|
-
clientId
|
|
116
|
+
clientId,
|
|
117
|
+
scope
|
|
117
118
|
});
|
|
118
119
|
const authorizationToken = `${tokenType} ${accessToken}`;
|
|
119
120
|
(0, import_helper.setAuthorizationHeader)(authorizationToken);
|
|
@@ -26,19 +26,18 @@ var import_react = require("@testing-library/react");
|
|
|
26
26
|
var import_react_redux = require("react-redux");
|
|
27
27
|
var import_history = require("history");
|
|
28
28
|
var import_store = require("../../data/store.js");
|
|
29
|
-
var import_history2 = require("../history.js");
|
|
30
29
|
var import_app_router = require("../../view/app-router.js");
|
|
31
|
-
const renderWithRouterRedux = (ui, {
|
|
32
|
-
route = "/",
|
|
33
|
-
history = (0, import_history.createMemoryHistory)({ initialEntries: [route] })
|
|
34
|
-
initialState,
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
}
|
|
30
|
+
const renderWithRouterRedux = (ui, options) => {
|
|
31
|
+
const { route = "/", basename = "/", initialState } = options || {};
|
|
32
|
+
const { history = (0, import_history.createMemoryHistory)({ initialEntries: [route] }) } = options || {};
|
|
33
|
+
const { store = (0, import_store.createAppStore)(initialState, history) } = options || {};
|
|
34
|
+
return {
|
|
35
|
+
...(0, import_react.render)(
|
|
36
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_redux.Provider, { store, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_app_router.AppRouter, { basename, history, children: ui }) })
|
|
37
|
+
),
|
|
38
|
+
// adding `store` to the returned utilities to allow us
|
|
39
|
+
// to reference it in our tests (just try to avoid using
|
|
40
|
+
// this to test implementation details).
|
|
41
|
+
store
|
|
42
|
+
};
|
|
43
|
+
};
|
package/dist/cjs/utils/window.js
CHANGED
|
@@ -53,4 +53,10 @@ const getCurrentBreakpoint = () => {
|
|
|
53
53
|
return "medium";
|
|
54
54
|
return "large";
|
|
55
55
|
};
|
|
56
|
-
const getAssetPath = () =>
|
|
56
|
+
const getAssetPath = () => {
|
|
57
|
+
const assetPath = window?.emui?._ASSET_PATH || "latest/";
|
|
58
|
+
if (!window.emui?.version)
|
|
59
|
+
return assetPath;
|
|
60
|
+
const majorMinorVersion = window.emui?.version.match(/^(?:\d+\.\d+)*/g);
|
|
61
|
+
return majorMinorVersion && majorMinorVersion[0] ? assetPath.replace("latest/", `${majorMinorVersion[0]}/`) : assetPath;
|
|
62
|
+
};
|
|
@@ -39,20 +39,27 @@ const getAppManifest = async ({
|
|
|
39
39
|
`${manifestPath.replace(/\/?$/, "/")}manifest.json`,
|
|
40
40
|
hostUrl
|
|
41
41
|
);
|
|
42
|
-
const
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
42
|
+
const getUnVersionedManifestJson = () => {
|
|
43
|
+
const unVersionedManifestPath = getUnVersionedManifestPath(manifestPath);
|
|
44
|
+
if (manifestPath !== unVersionedManifestPath) {
|
|
45
|
+
return getAppManifest({
|
|
46
|
+
hostUrl,
|
|
47
|
+
manifestPath: getUnVersionedManifestPath(manifestPath)
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
throw new Error("manifest.json is not available for the application");
|
|
51
|
+
};
|
|
52
|
+
try {
|
|
53
|
+
const response = await (0, import_http_client.getHTTPClient)().get(
|
|
54
|
+
(0, import_url.removeDoubleSlash)(url.href)
|
|
55
|
+
);
|
|
56
|
+
const { headers } = response;
|
|
57
|
+
if (headers["content-type"]?.includes?.("application/json"))
|
|
58
|
+
return response.data;
|
|
59
|
+
return await getUnVersionedManifestJson();
|
|
60
|
+
} catch (err) {
|
|
61
|
+
return getUnVersionedManifestJson();
|
|
54
62
|
}
|
|
55
|
-
throw new Error("manifest.json is not available for the application");
|
|
56
63
|
};
|
|
57
64
|
const getFullFileNameofAssetsFromManifest = (manifest, assetNames = []) => assetNames.reduce((assets, assetName) => {
|
|
58
65
|
const fullFileName = manifest[assetName];
|
|
@@ -33,16 +33,25 @@ const WaitMessage = (0, import_react.memo)(
|
|
|
33
33
|
style = { color: "white", fontSize: "1.25rem" },
|
|
34
34
|
...rest
|
|
35
35
|
}) => {
|
|
36
|
+
const ref = (0, import_react.useRef)(false);
|
|
37
|
+
const [show, setShow] = (0, import_react.useState)(false);
|
|
36
38
|
const isOpen = (0, import_react2.useAppSelector)((state) => state.waitMessage?.isOpen);
|
|
39
|
+
ref.current = isOpen ?? false;
|
|
37
40
|
const message = (0, import_react2.useAppSelector)((state) => state.waitMessage?.message);
|
|
38
41
|
(0, import_react.useEffect)(() => {
|
|
39
|
-
|
|
40
|
-
(
|
|
41
|
-
|
|
42
|
+
setTimeout(() => {
|
|
43
|
+
if (isOpen && ref.current) {
|
|
44
|
+
setShow(true);
|
|
45
|
+
(0, import_user_wait_event.waitStartEvent)();
|
|
46
|
+
}
|
|
47
|
+
}, 1e3);
|
|
48
|
+
if (!isOpen) {
|
|
49
|
+
setShow(false);
|
|
42
50
|
(0, import_user_wait_event.waitEndEvent)();
|
|
51
|
+
}
|
|
43
52
|
}, [isOpen]);
|
|
44
53
|
(0, import_use_html_wait_message.useHTMLWaitMessage)(isOpen !== null);
|
|
45
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
54
|
+
return show ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
46
55
|
import_ds_loading_indicator.DSLoadingIndicator,
|
|
47
56
|
{
|
|
48
57
|
id: "em-loading",
|
|
@@ -52,6 +61,6 @@ const WaitMessage = (0, import_react.memo)(
|
|
|
52
61
|
loading: isOpen,
|
|
53
62
|
message
|
|
54
63
|
}
|
|
55
|
-
);
|
|
64
|
+
) : null;
|
|
56
65
|
}
|
|
57
66
|
);
|
|
@@ -2,13 +2,15 @@ import { getHTTPClient } from "../../communication/http-client/index.js";
|
|
|
2
2
|
const getToken = async ({
|
|
3
3
|
clientId,
|
|
4
4
|
redirectUri,
|
|
5
|
-
idpCode
|
|
5
|
+
idpCode,
|
|
6
|
+
scope
|
|
6
7
|
}) => {
|
|
7
8
|
const params = new URLSearchParams();
|
|
8
9
|
params.append("grant_type", "authorization_code");
|
|
9
10
|
params.append("client_id", clientId);
|
|
10
11
|
params.append("redirect_uri", redirectUri);
|
|
11
12
|
params.append("code", idpCode);
|
|
13
|
+
params.append("scope", scope);
|
|
12
14
|
const { data } = await getHTTPClient().post(
|
|
13
15
|
"/oauth2/v1/token",
|
|
14
16
|
params
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import _ from "lodash";
|
|
2
|
-
import { getHTTPClient } from "../../communication/http-client/index.js";
|
|
3
2
|
import { setAppConfig } from "./config.js";
|
|
4
3
|
import { setAppDynamicsUserData } from "../../analytics/appdynamics.js";
|
|
5
4
|
import { updateBAEventParameters } from "../../analytics/web-analytics.js";
|
|
@@ -14,18 +13,33 @@ const parseAppConfig = (data) => {
|
|
|
14
13
|
setAppDynamicsUserData({ envName: activeEnv });
|
|
15
14
|
updateBAEventParameters({ envName: activeEnv });
|
|
16
15
|
};
|
|
17
|
-
const
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
}
|
|
16
|
+
const getUnVersionedPath = (path) => path.replace(/\d+\.\d+/, "latest");
|
|
17
|
+
const loadAppConfig = async (configPath = getAssetPath()) => {
|
|
18
|
+
const appConfigUrl = `${configPath.replace(/\/?$/, "/")}app.config.json`;
|
|
19
|
+
const unversionedConfigPath = getUnVersionedPath(configPath);
|
|
20
|
+
try {
|
|
21
|
+
const response = await fetch(appConfigUrl);
|
|
22
|
+
if (!response.ok) {
|
|
23
|
+
if (configPath !== unversionedConfigPath) {
|
|
24
|
+
await loadAppConfig(unversionedConfigPath);
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
const message = `App Config is not found at ${appConfigUrl}`;
|
|
28
|
+
throw new Error(message);
|
|
29
|
+
}
|
|
30
|
+
const appConfig = await response.json();
|
|
31
|
+
parseAppConfig(appConfig);
|
|
32
|
+
} catch (ex) {
|
|
33
|
+
if (configPath !== unversionedConfigPath) {
|
|
34
|
+
await loadAppConfig(unversionedConfigPath);
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
if (ex?.message?.includes(`Unexpected token`)) {
|
|
38
|
+
throw new Error(`App config file at ${appConfigUrl} is not a valid JSON`);
|
|
39
|
+
}
|
|
40
|
+
throw ex;
|
|
41
|
+
}
|
|
42
|
+
};
|
|
29
43
|
export {
|
|
30
44
|
loadAppConfig
|
|
31
45
|
};
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
{
|
|
2
|
+
"appId": "loanapp",
|
|
3
|
+
"activeEnv": "localhost",
|
|
4
|
+
"googleTagManager": true,
|
|
5
|
+
"sessionTimeoutWarnInterval": "7200000",
|
|
6
|
+
"sessionTimeoutInterval": "9000000",
|
|
7
|
+
"serviceEndpoints": {
|
|
8
|
+
"api": "",
|
|
9
|
+
"idp": "https://int.idp.ellielabs.com",
|
|
10
|
+
"logger": "https://int.api.puidiagnostics.rd.elliemae.io/v1/logging"
|
|
11
|
+
},
|
|
12
|
+
"env": {
|
|
13
|
+
"localhost": {
|
|
14
|
+
"serviceEndpoints": {
|
|
15
|
+
"api": "",
|
|
16
|
+
"idp": "https://int.idp.ellielabs.com",
|
|
17
|
+
"logger": "https://int.api.puidiagnostics.rd.elliemae.io/v1/logging"
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
"dev": {
|
|
21
|
+
"serviceEndpoints": {
|
|
22
|
+
"api": "https://dev.api.puiservice.rd.elliemae.io",
|
|
23
|
+
"idp": "https://int.idp.ellielabs.com",
|
|
24
|
+
"logger": "https://int.api.puidiagnostics.rd.elliemae.io/v1/logging"
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
"dev2": {
|
|
28
|
+
"serviceEndpoints": {
|
|
29
|
+
"api": "https://int.api.ellielabs.com",
|
|
30
|
+
"idp": "https://int.idp.ellielabs.com",
|
|
31
|
+
"logger": "https://int.api.puidiagnostics.rd.elliemae.io/v1/logging"
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
"qa": {
|
|
35
|
+
"serviceEndpoints": {
|
|
36
|
+
"api": "https://dev.api.puiservice.rd.elliemae.io",
|
|
37
|
+
"idp": "https://int.idp.ellielabs.com",
|
|
38
|
+
"logger": "https://int.api.puidiagnostics.rd.elliemae.io/v1/logging"
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
"qa2": {
|
|
42
|
+
"serviceEndpoints": {
|
|
43
|
+
"api": "https://int.api.ellielabs.com",
|
|
44
|
+
"idp": "https://int.idp.ellielabs.com",
|
|
45
|
+
"logger": "https://int.api.puidiagnostics.rd.elliemae.io/v1/logging"
|
|
46
|
+
}
|
|
47
|
+
},
|
|
48
|
+
"qa3": {
|
|
49
|
+
"serviceEndpoints": {
|
|
50
|
+
"api": "https://int.api.ellielabs.com",
|
|
51
|
+
"idp": "https://int.idp.ellielabs.com",
|
|
52
|
+
"logger": "https://int.api.puidiagnostics.rd.elliemae.io/v1/logging"
|
|
53
|
+
}
|
|
54
|
+
},
|
|
55
|
+
"int": {
|
|
56
|
+
"serviceEndpoints": {
|
|
57
|
+
"api": "https://dev.api.puiservice.rd.elliemae.io",
|
|
58
|
+
"idp": "https://int.idp.ellielabs.com",
|
|
59
|
+
"logger": "https://int.api.puidiagnostics.rd.elliemae.io/v1/logging"
|
|
60
|
+
}
|
|
61
|
+
},
|
|
62
|
+
"peg-osb1": {
|
|
63
|
+
"serviceEndpoints": {
|
|
64
|
+
"api": "https://encompass-peg-api.elliemae.com",
|
|
65
|
+
"idp": "https://peg.idp.ellielabs.com/authorize",
|
|
66
|
+
"logger": "https://int.api.puidiagnostics.rd.elliemae.io/v1/logging"
|
|
67
|
+
}
|
|
68
|
+
},
|
|
69
|
+
"peg-osb2": {
|
|
70
|
+
"serviceEndpoints": {
|
|
71
|
+
"api": "https://encompass-peg2-api.elliemae.com",
|
|
72
|
+
"idp": "https://peg.idp.ellielabs.com/authorize",
|
|
73
|
+
"logger": "https://int.api.puidiagnostics.rd.elliemae.io/v1/logging"
|
|
74
|
+
}
|
|
75
|
+
},
|
|
76
|
+
"peg": {
|
|
77
|
+
"serviceEndpoints": {
|
|
78
|
+
"api": "https://peg2-west.api.ellielabs.com",
|
|
79
|
+
"idp": "https://peg.idp.ellielabs.com/authorize",
|
|
80
|
+
"logger": "https://int.api.puidiagnostics.rd.elliemae.io/v1/logging"
|
|
81
|
+
}
|
|
82
|
+
},
|
|
83
|
+
"peg-oapi-west": {
|
|
84
|
+
"serviceEndpoints": {
|
|
85
|
+
"api": "https://peg2-west.api.ellielabs.com",
|
|
86
|
+
"idp": "https://peg.idp.ellielabs.com/authorize",
|
|
87
|
+
"logger": "https://int.api.puidiagnostics.rd.elliemae.io/v1/logging"
|
|
88
|
+
}
|
|
89
|
+
},
|
|
90
|
+
"peg-oapi-east": {
|
|
91
|
+
"serviceEndpoints": {
|
|
92
|
+
"api": "https://peg2-east.api.ellielabs.com",
|
|
93
|
+
"idp": "https://peg.idp.ellielabs.com/authorize",
|
|
94
|
+
"logger": "https://int.api.puidiagnostics.rd.elliemae.io/v1/logging"
|
|
95
|
+
}
|
|
96
|
+
},
|
|
97
|
+
"peg2-oapi-east": {
|
|
98
|
+
"serviceEndpoints": {
|
|
99
|
+
"api": "https://peg2-east.api.ellielabs.com",
|
|
100
|
+
"idp": "https://peg.idp.ellielabs.com/authorize",
|
|
101
|
+
"logger": "https://int.api.puidiagnostics.rd.elliemae.io/v1/logging"
|
|
102
|
+
}
|
|
103
|
+
},
|
|
104
|
+
"peg3": {
|
|
105
|
+
"serviceEndpoints": {
|
|
106
|
+
"api": "https://pel1.api.ellielabs.com",
|
|
107
|
+
"idp": "https://peg3.idp.ellielabs.com/authorize",
|
|
108
|
+
"logger": "https://int.api.puidiagnostics.rd.elliemae.io/v1/logging"
|
|
109
|
+
}
|
|
110
|
+
},
|
|
111
|
+
"stage": {
|
|
112
|
+
"serviceEndpoints": {
|
|
113
|
+
"api": "https://stg.api.elliemae.com",
|
|
114
|
+
"idp": "https://stg.idp.elliemae.com/authorize",
|
|
115
|
+
"logger": "https://stg.api.puidiagnostics.ellielabs.com/v1/logging"
|
|
116
|
+
}
|
|
117
|
+
},
|
|
118
|
+
"beta": {
|
|
119
|
+
"serviceEndpoints": {
|
|
120
|
+
"api": "https://concept.api.elliemae.com",
|
|
121
|
+
"idp": "https://concept.idp.elliemae.com/authorize",
|
|
122
|
+
"logger": "https://concept.api.puidiagnostics.elliemae.com/v1/logging"
|
|
123
|
+
}
|
|
124
|
+
},
|
|
125
|
+
"demo": {
|
|
126
|
+
"serviceEndpoints": {
|
|
127
|
+
"api": "https://concept.api.elliemae.com",
|
|
128
|
+
"idp": "https://concept.idp.elliemae.com/authorize",
|
|
129
|
+
"logger": "https://concept.api.puidiagnostics.elliemae.com/v1/logging"
|
|
130
|
+
}
|
|
131
|
+
},
|
|
132
|
+
"epc": {
|
|
133
|
+
"serviceEndpoints": {
|
|
134
|
+
"api": "https://concept.api.elliemae.com",
|
|
135
|
+
"idp": "https://concept.idp.elliemae.com/authorize",
|
|
136
|
+
"logger": "https://concept.api.puidiagnostics.elliemae.com/v1/logging"
|
|
137
|
+
}
|
|
138
|
+
},
|
|
139
|
+
"prod": {
|
|
140
|
+
"serviceEndpoints": {
|
|
141
|
+
"api": "https://api.elliemae.com",
|
|
142
|
+
"idp": "https://idp.elliemae.com/authorize",
|
|
143
|
+
"logger": "https://api.puidiagnostics.ellieservices.com/v1/logging"
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
@@ -89,7 +89,8 @@ const authorize = async ({
|
|
|
89
89
|
const { tokenType, accessToken } = await getToken({
|
|
90
90
|
idpCode,
|
|
91
91
|
redirectUri,
|
|
92
|
-
clientId
|
|
92
|
+
clientId,
|
|
93
|
+
scope
|
|
93
94
|
});
|
|
94
95
|
const authorizationToken = `${tokenType} ${accessToken}`;
|
|
95
96
|
setAuthorizationHeader(authorizationToken);
|
|
@@ -3,22 +3,21 @@ import { render } from "@testing-library/react";
|
|
|
3
3
|
import { Provider } from "react-redux";
|
|
4
4
|
import { createMemoryHistory } from "history";
|
|
5
5
|
import { createAppStore } from "../../data/store.js";
|
|
6
|
-
import { browserHistory } from "../history.js";
|
|
7
6
|
import { AppRouter } from "../../view/app-router.js";
|
|
8
|
-
const renderWithRouterRedux = (ui, {
|
|
9
|
-
route = "/",
|
|
10
|
-
history = createMemoryHistory({ initialEntries: [route] })
|
|
11
|
-
initialState,
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
}
|
|
7
|
+
const renderWithRouterRedux = (ui, options) => {
|
|
8
|
+
const { route = "/", basename = "/", initialState } = options || {};
|
|
9
|
+
const { history = createMemoryHistory({ initialEntries: [route] }) } = options || {};
|
|
10
|
+
const { store = createAppStore(initialState, history) } = options || {};
|
|
11
|
+
return {
|
|
12
|
+
...render(
|
|
13
|
+
/* @__PURE__ */ jsx(Provider, { store, children: /* @__PURE__ */ jsx(AppRouter, { basename, history, children: ui }) })
|
|
14
|
+
),
|
|
15
|
+
// adding `store` to the returned utilities to allow us
|
|
16
|
+
// to reference it in our tests (just try to avoid using
|
|
17
|
+
// this to test implementation details).
|
|
18
|
+
store
|
|
19
|
+
};
|
|
20
|
+
};
|
|
22
21
|
export {
|
|
23
22
|
renderWithRouterRedux
|
|
24
23
|
};
|
package/dist/esm/utils/window.js
CHANGED
|
@@ -27,7 +27,13 @@ const getCurrentBreakpoint = () => {
|
|
|
27
27
|
return "medium";
|
|
28
28
|
return "large";
|
|
29
29
|
};
|
|
30
|
-
const getAssetPath = () =>
|
|
30
|
+
const getAssetPath = () => {
|
|
31
|
+
const assetPath = window?.emui?._ASSET_PATH || "latest/";
|
|
32
|
+
if (!window.emui?.version)
|
|
33
|
+
return assetPath;
|
|
34
|
+
const majorMinorVersion = window.emui?.version.match(/^(?:\d+\.\d+)*/g);
|
|
35
|
+
return majorMinorVersion && majorMinorVersion[0] ? assetPath.replace("latest/", `${majorMinorVersion[0]}/`) : assetPath;
|
|
36
|
+
};
|
|
31
37
|
export {
|
|
32
38
|
getAssetPath,
|
|
33
39
|
getCurrentBreakpoint,
|
|
@@ -15,20 +15,27 @@ const getAppManifest = async ({
|
|
|
15
15
|
`${manifestPath.replace(/\/?$/, "/")}manifest.json`,
|
|
16
16
|
hostUrl
|
|
17
17
|
);
|
|
18
|
-
const
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
18
|
+
const getUnVersionedManifestJson = () => {
|
|
19
|
+
const unVersionedManifestPath = getUnVersionedManifestPath(manifestPath);
|
|
20
|
+
if (manifestPath !== unVersionedManifestPath) {
|
|
21
|
+
return getAppManifest({
|
|
22
|
+
hostUrl,
|
|
23
|
+
manifestPath: getUnVersionedManifestPath(manifestPath)
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
throw new Error("manifest.json is not available for the application");
|
|
27
|
+
};
|
|
28
|
+
try {
|
|
29
|
+
const response = await getHTTPClient().get(
|
|
30
|
+
removeDoubleSlash(url.href)
|
|
31
|
+
);
|
|
32
|
+
const { headers } = response;
|
|
33
|
+
if (headers["content-type"]?.includes?.("application/json"))
|
|
34
|
+
return response.data;
|
|
35
|
+
return await getUnVersionedManifestJson();
|
|
36
|
+
} catch (err) {
|
|
37
|
+
return getUnVersionedManifestJson();
|
|
30
38
|
}
|
|
31
|
-
throw new Error("manifest.json is not available for the application");
|
|
32
39
|
};
|
|
33
40
|
const getFullFileNameofAssetsFromManifest = (manifest, assetNames = []) => assetNames.reduce((assets, assetName) => {
|
|
34
41
|
const fullFileName = manifest[assetName];
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { jsx } from "react/jsx-runtime";
|
|
2
|
-
import { memo, useEffect } from "react";
|
|
2
|
+
import { memo, useEffect, useRef, useState } from "react";
|
|
3
3
|
import { DSLoadingIndicator } from "@elliemae/ds-loading-indicator";
|
|
4
4
|
import { useAppSelector } from "../../data/react.js";
|
|
5
5
|
import { useHTMLWaitMessage } from "./use-html-wait-message.js";
|
|
@@ -13,16 +13,25 @@ const WaitMessage = memo(
|
|
|
13
13
|
style = { color: "white", fontSize: "1.25rem" },
|
|
14
14
|
...rest
|
|
15
15
|
}) => {
|
|
16
|
+
const ref = useRef(false);
|
|
17
|
+
const [show, setShow] = useState(false);
|
|
16
18
|
const isOpen = useAppSelector((state) => state.waitMessage?.isOpen);
|
|
19
|
+
ref.current = isOpen ?? false;
|
|
17
20
|
const message = useAppSelector((state) => state.waitMessage?.message);
|
|
18
21
|
useEffect(() => {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
+
setTimeout(() => {
|
|
23
|
+
if (isOpen && ref.current) {
|
|
24
|
+
setShow(true);
|
|
25
|
+
waitStartEvent();
|
|
26
|
+
}
|
|
27
|
+
}, 1e3);
|
|
28
|
+
if (!isOpen) {
|
|
29
|
+
setShow(false);
|
|
22
30
|
waitEndEvent();
|
|
31
|
+
}
|
|
23
32
|
}, [isOpen]);
|
|
24
33
|
useHTMLWaitMessage(isOpen !== null);
|
|
25
|
-
return /* @__PURE__ */ jsx(
|
|
34
|
+
return show ? /* @__PURE__ */ jsx(
|
|
26
35
|
DSLoadingIndicator,
|
|
27
36
|
{
|
|
28
37
|
id: "em-loading",
|
|
@@ -32,7 +41,7 @@ const WaitMessage = memo(
|
|
|
32
41
|
loading: isOpen,
|
|
33
42
|
message
|
|
34
43
|
}
|
|
35
|
-
);
|
|
44
|
+
) : null;
|
|
36
45
|
}
|
|
37
46
|
);
|
|
38
47
|
export {
|
|
@@ -3,6 +3,7 @@ interface GetTokenRequestParams {
|
|
|
3
3
|
clientId: string;
|
|
4
4
|
redirectUri: string;
|
|
5
5
|
idpCode: string;
|
|
6
|
+
scope: string;
|
|
6
7
|
}
|
|
7
8
|
export interface GetTokenResponse {
|
|
8
9
|
token_type: string;
|
|
@@ -14,7 +15,7 @@ interface GetTokenError {
|
|
|
14
15
|
export interface GetTokenErrorResponse extends AxiosError {
|
|
15
16
|
response: AxiosResponse<GetTokenError>;
|
|
16
17
|
}
|
|
17
|
-
export declare const getToken: ({ clientId, redirectUri, idpCode, }: GetTokenRequestParams) => Promise<{
|
|
18
|
+
export declare const getToken: ({ clientId, redirectUri, idpCode, scope, }: GetTokenRequestParams) => Promise<{
|
|
18
19
|
tokenType: string;
|
|
19
20
|
accessToken: string;
|
|
20
21
|
}>;
|
|
@@ -23,12 +23,12 @@ export declare const createAppStore: (initialState: import("redux").CombinedStat
|
|
|
23
23
|
error: import("./error/index.js").ErrorState;
|
|
24
24
|
breakpoint: import("./breakpoint/index.js").BreakpointState;
|
|
25
25
|
liveMessage: import("./live-message/index.js").LiveMessageState;
|
|
26
|
-
}> | undefined, history: History, middlewareConfig?: MiddlewareConfig) => import("@reduxjs/toolkit/dist/configureStore.js").ToolkitStore<import("redux").
|
|
26
|
+
}> | undefined, history: History, middlewareConfig?: MiddlewareConfig) => import("@reduxjs/toolkit/dist/configureStore.js").ToolkitStore<import("redux").EmptyObject & {
|
|
27
27
|
waitMessage: import("./wait-message/reducer.js").WaitMessageState;
|
|
28
28
|
error: import("./error/index.js").ErrorState;
|
|
29
29
|
breakpoint: import("./breakpoint/index.js").BreakpointState;
|
|
30
30
|
liveMessage: import("./live-message/index.js").LiveMessageState;
|
|
31
|
-
}
|
|
31
|
+
}, {
|
|
32
32
|
payload: import("./wait-message/reducer.js").WaitMessageState;
|
|
33
33
|
type: string;
|
|
34
34
|
} | import("redux").AnyAction | {
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -5,12 +5,12 @@ interface Args {
|
|
|
5
5
|
store: AppStore;
|
|
6
6
|
}
|
|
7
7
|
export declare const renderWithRedux: (ui: React.ReactElement, { initialState, store, }?: Args) => {
|
|
8
|
-
store: import("@reduxjs/toolkit/dist/configureStore.js").ToolkitStore<import("redux").
|
|
8
|
+
store: import("@reduxjs/toolkit/dist/configureStore.js").ToolkitStore<import("redux").EmptyObject & {
|
|
9
9
|
waitMessage: import("../../data/wait-message/reducer.js").WaitMessageState;
|
|
10
10
|
error: import("../../data/error/index.js").ErrorState;
|
|
11
11
|
breakpoint: import("../../data/breakpoint/index.js").BreakpointState;
|
|
12
12
|
liveMessage: import("../../data/live-message/index.js").LiveMessageState;
|
|
13
|
-
}
|
|
13
|
+
}, {
|
|
14
14
|
payload: import("../../data/wait-message/reducer.js").WaitMessageState;
|
|
15
15
|
type: string;
|
|
16
16
|
} | import("redux").AnyAction | {
|
|
@@ -3,17 +3,18 @@ import { History } from 'history';
|
|
|
3
3
|
import { AppStore, RootState } from '../../data/store.js';
|
|
4
4
|
interface Args {
|
|
5
5
|
initialState: RootState;
|
|
6
|
-
store
|
|
7
|
-
route
|
|
8
|
-
|
|
6
|
+
store?: AppStore;
|
|
7
|
+
route?: string;
|
|
8
|
+
basename?: string;
|
|
9
|
+
history?: History;
|
|
9
10
|
}
|
|
10
|
-
export declare const renderWithRouterRedux: (ui: React.ReactElement,
|
|
11
|
-
store: import("@reduxjs/toolkit/dist/configureStore.js").ToolkitStore<import("redux").
|
|
11
|
+
export declare const renderWithRouterRedux: (ui: React.ReactElement, options?: Args) => {
|
|
12
|
+
store: import("@reduxjs/toolkit/dist/configureStore.js").ToolkitStore<import("redux").EmptyObject & {
|
|
12
13
|
waitMessage: import("../../data/wait-message/reducer.js").WaitMessageState;
|
|
13
14
|
error: import("../../data/error/index.js").ErrorState;
|
|
14
15
|
breakpoint: import("../../data/breakpoint/index.js").BreakpointState;
|
|
15
16
|
liveMessage: import("../../data/live-message/index.js").LiveMessageState;
|
|
16
|
-
}
|
|
17
|
+
}, {
|
|
17
18
|
payload: import("../../data/wait-message/reducer.js").WaitMessageState;
|
|
18
19
|
type: string;
|
|
19
20
|
} | import("redux").AnyAction | {
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
/// <reference types="react" />
|
|
2
1
|
import { RegisterOptions, FieldValues, FieldPath } from 'react-hook-form';
|
|
3
2
|
export type DateRangePickerProps<TFieldValues extends FieldValues = FieldValues, TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>> = {
|
|
4
3
|
name: string;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@elliemae/pui-app-sdk",
|
|
3
|
-
"version": "4.14.
|
|
3
|
+
"version": "4.14.2",
|
|
4
4
|
"description": "ICE MT UI Platform Application SDK ",
|
|
5
5
|
"sideEffects": [
|
|
6
6
|
"*.css",
|
|
@@ -64,7 +64,7 @@
|
|
|
64
64
|
},
|
|
65
65
|
"engines": {
|
|
66
66
|
"pnpm": ">=6",
|
|
67
|
-
"node": ">=
|
|
67
|
+
"node": ">=18"
|
|
68
68
|
},
|
|
69
69
|
"author": "ICE MT",
|
|
70
70
|
"license": "MIT",
|