@openmrs/esm-api 10.0.1-pre.5607 → 10.0.1-pre.5616
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/.turbo/turbo-build.log +1 -1
- package/dist/current-user.d.ts +65 -3
- package/dist/current-user.d.ts.map +1 -1
- package/dist/current-user.js +146 -23
- package/dist/openmrs-fetch.d.ts +5 -0
- package/dist/openmrs-fetch.d.ts.map +1 -1
- package/dist/openmrs-fetch.js +53 -57
- package/dist/public.d.ts +1 -1
- package/dist/public.d.ts.map +1 -1
- package/dist/public.js +1 -1
- package/mock-jest.ts +3 -0
- package/mock.ts +3 -0
- package/package.json +9 -9
- package/src/current-user.test.ts +230 -25
- package/src/current-user.ts +170 -21
- package/src/openmrs-fetch.test.ts +11 -1
- package/src/openmrs-fetch.ts +62 -70
- package/src/public.ts +12 -1
package/src/openmrs-fetch.ts
CHANGED
|
@@ -109,19 +109,17 @@ export function openmrsFetch<T = any>(path: string, fetchInit: FetchConfig = {})
|
|
|
109
109
|
fetchInit.headers = {};
|
|
110
110
|
}
|
|
111
111
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
*/
|
|
112
|
+
// Automatically stringify javascript objects being sent in the
|
|
113
|
+
// request body.
|
|
115
114
|
if (isPlainObject(fetchInit.body)) {
|
|
116
115
|
fetchInit.body = JSON.stringify(fetchInit.body);
|
|
117
116
|
}
|
|
118
117
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
*/
|
|
118
|
+
// Add a request header to tell the server to respond with json,
|
|
119
|
+
// since frontend code almost always wants json and the OpenMRS
|
|
120
|
+
// server won't give you json unless you explicitly ask for it.
|
|
121
|
+
// If a different Accept header is preferred, pass it into the fetchInit.
|
|
122
|
+
// If no Accept header is desired, pass it in explicitly as null.
|
|
125
123
|
if (typeof fetchInit.headers.Accept === 'undefined') {
|
|
126
124
|
fetchInit.headers.Accept = 'application/json';
|
|
127
125
|
}
|
|
@@ -130,10 +128,9 @@ export function openmrsFetch<T = any>(path: string, fetchInit: FetchConfig = {})
|
|
|
130
128
|
delete fetchInit.headers.Accept;
|
|
131
129
|
}
|
|
132
130
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
*/
|
|
131
|
+
// This tells the OpenMRS REST API not to return a WWW-Authenticate
|
|
132
|
+
// header. Returning that header is useful when using the API, but
|
|
133
|
+
// not from a UI.
|
|
137
134
|
let isRestRequest = false;
|
|
138
135
|
try {
|
|
139
136
|
const requestUrl = new URL(url, window.location.href);
|
|
@@ -173,11 +170,10 @@ export function openmrsFetch<T = any>(path: string, fetchInit: FetchConfig = {})
|
|
|
173
170
|
}
|
|
174
171
|
}
|
|
175
172
|
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
*/
|
|
173
|
+
// We capture the stacktrace before making the request, so that if an error occurs we can
|
|
174
|
+
// log a full stacktrace that includes the code that made the request and handled the response
|
|
175
|
+
// Otherwise, we could run into situations where the stacktrace doesn't even show which code
|
|
176
|
+
// called @openmrs/api.
|
|
181
177
|
const requestStacktrace = Error();
|
|
182
178
|
|
|
183
179
|
return window.fetch(url, fetchInit as RequestInit).then(async (r) => {
|
|
@@ -185,13 +181,11 @@ export function openmrsFetch<T = any>(path: string, fetchInit: FetchConfig = {})
|
|
|
185
181
|
const { redirectAuthFailure, followRedirects } = await getConfig<EsmApiConfigObject>('@openmrs/esm-api');
|
|
186
182
|
|
|
187
183
|
if (response.ok) {
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
* - HTTP 204: Logout redirect URLs (e.g. Keycloak IdP logout). Refer: OA-41 #1231
|
|
194
|
-
*/
|
|
184
|
+
// Backend modules can trigger SPA redirects by returning a `Location` header.
|
|
185
|
+
// This is required because `fetch()` hides HTTP redirects from the application.
|
|
186
|
+
|
|
187
|
+
// Session endpoint (2xx): Authentication challenge URLs (e.g. TOTP,2FA).
|
|
188
|
+
// HTTP 204: Logout redirect URLs (e.g. Keycloak IdP logout). Refer: OA-41 #1231
|
|
195
189
|
const location = response.headers.get('location');
|
|
196
190
|
const shouldRedirect =
|
|
197
191
|
followRedirects && location && (url === makeUrl(sessionEndpoint) || response.status === 204);
|
|
@@ -201,10 +195,9 @@ export function openmrsFetch<T = any>(path: string, fetchInit: FetchConfig = {})
|
|
|
201
195
|
}
|
|
202
196
|
|
|
203
197
|
if (response.status === 204) {
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
*/
|
|
198
|
+
// HTTP 204 - No Content
|
|
199
|
+
// We should not try to download the empty response as json. Instead,
|
|
200
|
+
// we return null since there is no response body.
|
|
208
201
|
response.data = null as unknown as T;
|
|
209
202
|
return response;
|
|
210
203
|
} else {
|
|
@@ -224,15 +217,12 @@ export function openmrsFetch<T = any>(path: string, fetchInit: FetchConfig = {})
|
|
|
224
217
|
});
|
|
225
218
|
}
|
|
226
219
|
} else {
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
*/
|
|
220
|
+
// HTTP response status is not in 200s. Usually this will mean
|
|
221
|
+
// either HTTP 400s (bad request from browser) or HTTP 500s (server error)
|
|
222
|
+
// Our goal is to come up with best possible stacktrace and error message
|
|
223
|
+
// to help developers understand the problem and debug
|
|
232
224
|
|
|
233
|
-
|
|
234
|
-
* Redirect to given url when redirect on auth failure is enabled
|
|
235
|
-
*/
|
|
225
|
+
// Redirect to given url when redirect on auth failure is enabled
|
|
236
226
|
if (
|
|
237
227
|
(url === makeUrl(sessionEndpoint) && response.status === 403) ||
|
|
238
228
|
(redirectAuthFailure.enabled && redirectAuthFailure.errors.includes(response.status))
|
|
@@ -244,40 +234,37 @@ export function openmrsFetch<T = any>(path: string, fetchInit: FetchConfig = {})
|
|
|
244
234
|
const location = redirectAuthFailure.url || response.headers.get('location') || defaultRedirectAuthFailureUrl;
|
|
245
235
|
navigate({ to: location });
|
|
246
236
|
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
: new Promise<FetchResponse>(() => {});
|
|
254
|
-
} else {
|
|
255
|
-
// Attempt to download a response body, if it has one
|
|
256
|
-
return response
|
|
257
|
-
.clone()
|
|
258
|
-
.text()
|
|
259
|
-
.then(
|
|
260
|
-
(responseText) => {
|
|
261
|
-
let responseBody = responseText;
|
|
262
|
-
try {
|
|
263
|
-
responseBody = JSON.parse(responseText);
|
|
264
|
-
} catch (err) {
|
|
265
|
-
// Server didn't respond with json, so just go with the response text string
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
/* Make the fetch promise go into "rejected" status, with the best
|
|
269
|
-
* possible stacktrace and error message.
|
|
270
|
-
*/
|
|
271
|
-
throw new OpenmrsFetchError(url, response, responseBody, requestStacktrace);
|
|
272
|
-
},
|
|
273
|
-
(err) => {
|
|
274
|
-
/* We weren't able to download a response body for this error.
|
|
275
|
-
* Time to just give the best possible stacktrace and error message.
|
|
276
|
-
*/
|
|
277
|
-
throw new OpenmrsFetchError(url, response, null, requestStacktrace);
|
|
278
|
-
},
|
|
279
|
-
);
|
|
237
|
+
const rejectAuthFailures = fetchInit.rejectAuthFailure === true;
|
|
238
|
+
if (!rejectAuthFailures) {
|
|
239
|
+
return redirectAuthFailure.resolvePromise
|
|
240
|
+
? (Promise.resolve() as unknown as Promise<FetchResponse>)
|
|
241
|
+
: new Promise<FetchResponse>(() => {});
|
|
242
|
+
}
|
|
280
243
|
}
|
|
244
|
+
|
|
245
|
+
// Attempt to download a response body, if it has one
|
|
246
|
+
return response
|
|
247
|
+
.clone()
|
|
248
|
+
.text()
|
|
249
|
+
.then(
|
|
250
|
+
(responseText) => {
|
|
251
|
+
let responseBody = responseText;
|
|
252
|
+
try {
|
|
253
|
+
responseBody = JSON.parse(responseText);
|
|
254
|
+
} catch (err) {
|
|
255
|
+
// Server didn't respond with json, so just go with the response text string
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
// Make the fetch promise go into "rejected" status, with the best
|
|
259
|
+
// possible stacktrace and error message.
|
|
260
|
+
throw new OpenmrsFetchError(url, response, responseBody, requestStacktrace);
|
|
261
|
+
},
|
|
262
|
+
() => {
|
|
263
|
+
// We weren't able to download a response body for this error.
|
|
264
|
+
// Time to just give the best possible stacktrace and error message.
|
|
265
|
+
throw new OpenmrsFetchError(url, response, null, requestStacktrace);
|
|
266
|
+
},
|
|
267
|
+
);
|
|
281
268
|
}
|
|
282
269
|
});
|
|
283
270
|
}
|
|
@@ -298,6 +285,11 @@ export class OpenmrsFetchError extends Error implements FetchError {
|
|
|
298
285
|
export interface FetchConfig extends Omit<RequestInit, 'body' | 'headers'> {
|
|
299
286
|
headers?: FetchHeaders;
|
|
300
287
|
body?: FetchBody | string;
|
|
288
|
+
/**
|
|
289
|
+
* When `true`, a response that triggers the auth-failure redirect still navigates, but the
|
|
290
|
+
* returned promise rejects with an `OpenmrsFetchError` instead of staying pending.
|
|
291
|
+
*/
|
|
292
|
+
rejectAuthFailure?: boolean;
|
|
301
293
|
}
|
|
302
294
|
|
|
303
295
|
type ResponseBody = string | FetchResponseJson;
|
package/src/public.ts
CHANGED
|
@@ -15,5 +15,16 @@ export {
|
|
|
15
15
|
} from './current-user';
|
|
16
16
|
export * from './environment';
|
|
17
17
|
export * from './types';
|
|
18
|
-
export
|
|
18
|
+
export {
|
|
19
|
+
fhirBaseUrl,
|
|
20
|
+
makeUrl,
|
|
21
|
+
openmrsFetch,
|
|
22
|
+
OpenmrsFetchError,
|
|
23
|
+
restBaseUrl,
|
|
24
|
+
sessionEndpoint,
|
|
25
|
+
type FetchConfig,
|
|
26
|
+
type FetchError,
|
|
27
|
+
type FetchHeaders,
|
|
28
|
+
type FetchResponseJson,
|
|
29
|
+
} from './openmrs-fetch';
|
|
19
30
|
export * from './openmrs-backend-dependencies';
|