@openmrs/esm-api 4.3.2-pre.660 → 4.3.2-pre.662

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/jest.config.js CHANGED
@@ -8,6 +8,7 @@ module.exports = {
8
8
  "<rootDir>/__mocks__/openmrs-esm-error-handling.mock.ts",
9
9
  "@openmrs/esm-config": "<rootDir>/__mocks__/openmrs-esm-config.mock.ts",
10
10
  "single-spa": "<rootDir>/__mocks__/single-spa.mock.ts",
11
+ dexie: require.resolve("dexie"),
11
12
  },
12
13
  testEnvironment: "jsdom",
13
14
  testEnvironmentOptions: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openmrs/esm-api",
3
- "version": "4.3.2-pre.660",
3
+ "version": "4.3.2-pre.662",
4
4
  "license": "MPL-2.0",
5
5
  "description": "The javascript module for interacting with the OpenMRS API",
6
6
  "browser": "dist/openmrs-esm-api.js",
@@ -41,13 +41,14 @@
41
41
  },
42
42
  "peerDependencies": {
43
43
  "@openmrs/esm-config": "4.x",
44
- "@openmrs/esm-error-handling": "4.x"
44
+ "@openmrs/esm-error-handling": "4.x",
45
+ "@openmrs/esm-offline": "4.x"
45
46
  },
46
47
  "devDependencies": {
47
- "@openmrs/esm-config": "^4.3.2-pre.660",
48
- "@openmrs/esm-error-handling": "^4.3.2-pre.660",
49
- "@openmrs/esm-state": "^4.3.2-pre.660",
48
+ "@openmrs/esm-config": "^4.3.2-pre.662",
49
+ "@openmrs/esm-error-handling": "^4.3.2-pre.662",
50
+ "@openmrs/esm-state": "^4.3.2-pre.662",
50
51
  "rxjs": "^6.5.3"
51
52
  },
52
- "gitHead": "7b4eed59da0624b69ea0b86baada3dc111f6407a"
53
+ "gitHead": "1e1ab6761ff3726c7e0eee55373b1bf4a0d97b99"
53
54
  }
package/src/index.ts CHANGED
@@ -1,6 +1,5 @@
1
1
  export * from "./types";
2
2
  export * from "./openmrs-fetch";
3
- export * from "./fhir";
4
3
  export * from "./setup";
5
4
 
6
5
  export * from "./shared-api-objects/current-user";
@@ -4,7 +4,11 @@ import isPlainObject from "lodash-es/isPlainObject";
4
4
  import { getConfig, navigate } from "@openmrs/esm-config";
5
5
  import { FetchResponse } from "./types";
6
6
 
7
- export const sessionEndpoint = "/ws/rest/v1/session";
7
+ export const restBaseUrl = "/ws/rest/v1/";
8
+
9
+ export const fhirBaseUrl = "/ws/fhir2/R4";
10
+
11
+ export const sessionEndpoint = `${restBaseUrl}session`;
8
12
 
9
13
  /**
10
14
  * Append `path` to the OpenMRS SPA base.
@@ -92,9 +96,13 @@ export function openmrsFetch<T = any>(
92
96
  );
93
97
  }
94
98
 
99
+ // ensure path starts with /
100
+ if (path[0] !== "/") {
101
+ path = "/" + path;
102
+ }
103
+
95
104
  // Prefix the url with the openmrs spa base
96
- // @ts-ignore
97
- const url = makeUrl(path);
105
+ let url: string = makeUrl(path);
98
106
 
99
107
  // We're going to need some headers
100
108
  if (!fetchInit.headers) {
@@ -126,10 +134,21 @@ export function openmrsFetch<T = any>(
126
134
  * header. Returning that header is useful when using the API, but
127
135
  * not from a UI.
128
136
  */
129
- if (typeof fetchInit.headers["Disable-WWW-Authenticate"] === "undefined") {
137
+ if (
138
+ path.startsWith(restBaseUrl) &&
139
+ typeof fetchInit.headers["Disable-WWW-Authenticate"] === "undefined"
140
+ ) {
130
141
  fetchInit.headers["Disable-WWW-Authenticate"] = "true";
131
142
  }
132
143
 
144
+ if (path.startsWith(fhirBaseUrl)) {
145
+ const urlUrl = new URL(url, window.location.toString());
146
+ if (!urlUrl.searchParams.has("_summary")) {
147
+ urlUrl.searchParams.set("_summary", "data");
148
+ url = urlUrl.toString();
149
+ }
150
+ }
151
+
133
152
  /* We capture the stacktrace before making the request, so that if an error occurs we can
134
153
  * log a full stacktrace that includes the code that made the request and handled the response
135
154
  * Otherwise, we could run into situations where the stacktrace doesn't even show which code
@@ -303,7 +322,7 @@ export class OpenmrsFetchError extends Error {
303
322
  responseBody: string | FetchResponseJson | null;
304
323
  }
305
324
 
306
- interface FetchConfig extends Omit<Omit<RequestInit, "body">, "headers"> {
325
+ export interface FetchConfig extends Omit<RequestInit, "body" | "headers"> {
307
326
  headers?: FetchHeaders;
308
327
  body?: FetchBody | string;
309
328
  }
package/src/public.ts CHANGED
@@ -1,6 +1,5 @@
1
1
  export * from "./types";
2
2
  export * from "./openmrs-fetch";
3
- export * from "./fhir";
4
3
 
5
4
  export * from "./shared-api-objects/current-user";
6
5
  export * from "./shared-api-objects/current-patient";
@@ -1,59 +1,59 @@
1
+ import { fhirBaseUrl, openmrsFetch } from "../openmrs-fetch";
1
2
  import { fetchCurrentPatient } from "./current-patient";
2
- import { fhir } from "../fhir";
3
3
 
4
- jest.mock("../fhir", () => ({
5
- fhir: {
6
- read: jest.fn(),
7
- },
4
+ jest.mock("../openmrs-fetch", () => ({
5
+ openmrsFetch: jest.fn(),
8
6
  }));
9
7
 
10
8
  describe("current patient", () => {
11
9
  beforeEach(() => {
12
- (fhir.read as jest.MockedFunction<any>).mockReset();
10
+ (openmrsFetch as jest.MockedFunction<any>).mockReset();
13
11
  });
14
12
 
15
13
  it("fetches the correct patient from a patient chart URL", () => {
16
- (fhir.read as jest.MockedFunction<any>).mockReturnValueOnce(
14
+ (openmrsFetch as jest.MockedFunction<any>).mockReturnValueOnce(
17
15
  Promise.resolve({
18
16
  data: {},
19
17
  })
20
18
  );
21
19
 
22
- return fetchCurrentPatient("12").then(() => {
23
- expect(fhir.read as jest.MockedFunction<any>).toHaveBeenCalledWith({
24
- type: "Patient",
25
- patient: "12",
26
- });
20
+ return fetchCurrentPatient("12", undefined, false).then(() => {
21
+ expect(openmrsFetch as jest.MockedFunction<any>).toHaveBeenCalledWith(
22
+ `${fhirBaseUrl}/Patient/12`,
23
+ undefined
24
+ );
27
25
  });
28
26
  });
29
27
 
30
28
  it("fetches the correct patient from the patient home URL", () => {
31
- (fhir.read as jest.MockedFunction<any>).mockReturnValueOnce(
29
+ (openmrsFetch as jest.MockedFunction<any>).mockReturnValueOnce(
32
30
  Promise.resolve({
33
31
  data: {},
34
32
  })
35
33
  );
36
34
 
37
- return fetchCurrentPatient("34").then(() => {
38
- expect(fhir.read as jest.MockedFunction<any>).toHaveBeenCalledWith({
39
- type: "Patient",
40
- patient: "34",
41
- });
35
+ return fetchCurrentPatient("34", undefined, false).then(() => {
36
+ expect(openmrsFetch as jest.MockedFunction<any>).toHaveBeenCalledWith(
37
+ `${fhirBaseUrl}/Patient/34`,
38
+ undefined
39
+ );
42
40
  });
43
41
  });
44
42
 
45
43
  it("can handle dashes and alphanumeric characters in the patient uuid", () => {
46
- (fhir.read as jest.MockedFunction<any>).mockReturnValueOnce(
44
+ (openmrsFetch as jest.MockedFunction<any>).mockReturnValueOnce(
47
45
  Promise.resolve({
48
46
  data: {},
49
47
  })
50
48
  );
51
49
 
52
- return fetchCurrentPatient("34-asdsd-234243h342").then(() => {
53
- expect(fhir.read as jest.MockedFunction<any>).toHaveBeenCalledWith({
54
- type: "Patient",
55
- patient: "34-asdsd-234243h342",
56
- });
57
- });
50
+ return fetchCurrentPatient("34-asdsd-234243h342", undefined, false).then(
51
+ () => {
52
+ expect(openmrsFetch as jest.MockedFunction<any>).toHaveBeenCalledWith(
53
+ `${fhirBaseUrl}/Patient/34-asdsd-234243h342`,
54
+ undefined
55
+ );
56
+ }
57
+ );
58
58
  });
59
59
  });
@@ -1,9 +1,9 @@
1
1
  /** @module @category API */
2
- import { fhir } from "../fhir";
2
+ import { getSynchronizationItems } from "@openmrs/esm-offline";
3
+ import { FetchConfig, fhirBaseUrl, openmrsFetch } from "../openmrs-fetch";
3
4
  import { FetchResponse } from "../types";
4
5
 
5
6
  export type CurrentPatient = fhir.Patient | FetchResponse<fhir.Patient>;
6
-
7
7
  export interface CurrentPatientOptions {
8
8
  includeConfig?: boolean;
9
9
  }
@@ -18,17 +18,48 @@ export interface OnlyThePatient extends CurrentPatientOptions {
18
18
 
19
19
  export type PatientUuid = string | null;
20
20
 
21
- export function fetchCurrentPatient(
21
+ export async function fetchCurrentPatient(
22
22
  patientUuid: PatientUuid,
23
- contentOverrides?: Partial<Parameters<typeof fhir.read>[0]>
24
- ) {
23
+ fetchInit?: FetchConfig,
24
+ includeOfflinePatients: boolean = true
25
+ ): Promise<fhir.Patient | null> {
25
26
  if (patientUuid) {
26
- return fhir.read<fhir.Patient>({
27
- type: "Patient",
28
- patient: patientUuid,
29
- ...contentOverrides,
30
- });
27
+ let err: Error | null = null;
28
+ const [onlinePatient, offlinePatient] = await Promise.all([
29
+ openmrsFetch<fhir.Patient>(
30
+ `${fhirBaseUrl}/Patient/${patientUuid}`,
31
+ fetchInit
32
+ ).catch<FetchResponse<fhir.Patient>>((e) => (err = e)),
33
+ includeOfflinePatients
34
+ ? getOfflineRegisteredPatientAsFhirPatient(patientUuid)
35
+ : Promise.resolve(null),
36
+ ]);
37
+
38
+ if (onlinePatient.ok) {
39
+ return onlinePatient.data;
40
+ }
41
+
42
+ if (offlinePatient) {
43
+ return offlinePatient;
44
+ }
45
+
46
+ if (err) {
47
+ throw err;
48
+ }
31
49
  }
32
50
 
33
- return Promise.resolve(null);
51
+ return null;
52
+ }
53
+
54
+ async function getOfflineRegisteredPatientAsFhirPatient(
55
+ patientUuid: string
56
+ ): Promise<fhir.Patient | null> {
57
+ const patientRegistrationSyncItems = await getSynchronizationItems<{
58
+ fhirPatient: fhir.Patient;
59
+ }>("patient-registration");
60
+ const patientSyncItem = patientRegistrationSyncItems.find(
61
+ (item) => item.fhirPatient.id === patientUuid
62
+ );
63
+
64
+ return patientSyncItem?.fhirPatient ?? null;
34
65
  }
package/src/types/fhir.ts CHANGED
@@ -1,12 +1,9 @@
1
- import { FetchHeaders } from "../openmrs-fetch";
2
-
3
1
  /*
4
2
  Originally taken from https://github.com/FHIR/fhir.js/blob/ec82ccfc125e05dbb645f47c100fe60f2c34bb73/src/fhir.d.ts
5
3
  Has been adapted to be even better - if we can get fhir.js to publish a good version to npm with better typedefs,
6
4
  we can remove this file in favor of the one they maintain
7
5
  */
8
6
 
9
- type ClientFn = (...args: any[]) => Promise<{ data: any }>;
10
7
  export type ResourceName =
11
8
  | "DomainResource"
12
9
  | "Organization"
@@ -103,72 +100,3 @@ export type ResourceName =
103
100
  | "Binary"
104
101
  | "Bundle"
105
102
  | "Parameters";
106
- interface QueryOptions {
107
- $include?: { [key: string]: string | string[] };
108
- [key: string]: any;
109
- }
110
-
111
- declare function Create<T extends fhir.DomainResource>(content: {
112
- resource: T;
113
- }): Promise<{ data: T }>;
114
- declare function Create(content: {
115
- type: "Binary";
116
- data: Buffer;
117
- }): Promise<{ data: fhir.Binary }>;
118
- declare function Create<T extends fhir.DomainResource>(content: {
119
- type: ResourceName;
120
- data: T;
121
- }): Promise<{ data: T }>;
122
-
123
- declare function Read<T extends fhir.DomainResource>(content: {
124
- type: ResourceName;
125
- id?: string;
126
- patient?: string;
127
- headers?: FetchHeaders;
128
- }): Promise<{ data: T }>;
129
-
130
- declare function Patch(content: {
131
- type: ResourceName;
132
- id: string;
133
- data: Array<{
134
- op: "replace" | "add" | "remove";
135
- path: string;
136
- value: string | object;
137
- }>;
138
- }): Promise<{ data: fhir.OperationOutcome }>;
139
-
140
- declare function Update<T extends fhir.DomainResource>(content: {
141
- resource: T;
142
- }): Promise<{ data: T }>;
143
-
144
- declare function Search(content: {
145
- type: ResourceName;
146
- count?: number;
147
- query?: QueryOptions;
148
- }): Promise<{ data: fhir.Bundle }>;
149
-
150
- declare function NextPage(content: {
151
- type: ResourceName;
152
- bundle: fhir.Bundle;
153
- }): Promise<{ data: fhir.Bundle }>;
154
-
155
- export interface FhirClient {
156
- conformance: ClientFn;
157
- document: ClientFn;
158
- profile: ClientFn;
159
- transaction: ClientFn;
160
- history: ClientFn;
161
- typeHistory: ClientFn;
162
- resourceHistory: ClientFn;
163
- read: typeof Read;
164
- vread: ClientFn;
165
- delete: ClientFn;
166
- create: typeof Create;
167
- validate: ClientFn;
168
- search: typeof Search;
169
- update: typeof Update;
170
- nextPage: typeof NextPage;
171
- prevPage: ClientFn;
172
- resolve: ClientFn;
173
- patch: typeof Patch;
174
- }
package/src/fhir.ts DELETED
@@ -1,74 +0,0 @@
1
- /** @module @category API */
2
- import { openmrsFetch, FetchHeaders, OpenmrsFetchError } from "./openmrs-fetch";
3
- import type { ResourceName } from "./types/fhir";
4
-
5
- export const fhirBaseUrl = `/ws/fhir2/R4`;
6
-
7
- const openmrsFhirAdapter = {
8
- http(requestObj: FHIRRequestObj) {
9
- return openmrsFetch(requestObj.url, {
10
- method: requestObj.method,
11
- headers: requestObj.headers,
12
- }).then(
13
- (response) => {
14
- return {
15
- status: response.status,
16
- headers: response.headers,
17
- data: response.data,
18
- config: requestObj,
19
- };
20
- },
21
- (err: OpenmrsFetchError) => {
22
- return {
23
- status: err.response.status,
24
- headers: err.response.headers,
25
- data: err.responseBody as any,
26
- config: requestObj,
27
- };
28
- }
29
- );
30
- },
31
- };
32
-
33
- /**
34
- * The `fhir` object is replicates the API from [fhir.js](https://github.com/FHIR/fhir.js)
35
- * that can be used to call FHIR-compliant OpenMRS APIs. See
36
- * [the docs for fhir.js](https://github.com/FHIR/fhir.js) for more info
37
- * and example usage.
38
- *
39
- * This object should be considered deprecated and may be removed from a future version
40
- * of the framework.
41
- *
42
- * @category API
43
- * @deprecated
44
- */
45
- export const fhir = {
46
- read: <T>(
47
- options: FHIRRequestOptions
48
- ): Promise<{
49
- status: number;
50
- headers: Headers;
51
- data: T;
52
- config: FHIRRequestObj;
53
- }> => {
54
- return openmrsFhirAdapter.http({
55
- url: `${fhirBaseUrl}/${options.type}/${options.patient}`,
56
- method: "GET",
57
- headers: options.headers ?? {},
58
- });
59
- },
60
- };
61
-
62
- /** @deprecated */
63
- export interface FHIRRequestOptions {
64
- type: ResourceName;
65
- patient: string;
66
- headers?: FetchHeaders;
67
- }
68
-
69
- /** @deprecated */
70
- export interface FHIRRequestObj {
71
- url: string;
72
- method: string;
73
- headers: FetchHeaders;
74
- }