emr-api-client
Version:
Api client for accessing openmrs service
829 lines (814 loc) • 24.9 kB
JavaScript
"use strict";
var __defProp = Object.defineProperty;
var __defProps = Object.defineProperties;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __propIsEnum = Object.prototype.propertyIsEnumerable;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __spreadValues = (a, b) => {
for (var prop in b || (b = {}))
if (__hasOwnProp.call(b, prop))
__defNormalProp(a, prop, b[prop]);
if (__getOwnPropSymbols)
for (var prop of __getOwnPropSymbols(b)) {
if (__propIsEnum.call(b, prop))
__defNormalProp(a, prop, b[prop]);
}
return a;
};
var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var __async = (__this, __arguments, generator) => {
return new Promise((resolve, reject) => {
var fulfilled = (value) => {
try {
step(generator.next(value));
} catch (e) {
reject(e);
}
};
var rejected = (value) => {
try {
step(generator.throw(value));
} catch (e) {
reject(e);
}
};
var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
step((generator = generator.apply(__this, __arguments)).next());
});
};
// src/index.ts
var src_exports = {};
__export(src_exports, {
ApiCore: () => api_core_default,
ClientError: () => ClientError,
DemographicExchange: () => demographic_exchange_default,
Drug: () => drug_default,
Encounter: () => encounter_default,
GlobalProperty: () => global_property_default,
Lab: () => lab_default,
Location: () => location_default,
Obs: () => obs_default,
Patient: () => patient_default,
Person: () => person_default,
User: () => user_default,
UserProperty: () => user_property_default
});
module.exports = __toCommonJS(src_exports);
// src/types.ts
var ClientError = /* @__PURE__ */ ((ClientError2) => {
ClientError2["INVALID_API_VERSION"] = "Invalid API version";
ClientError2["NOT_FOUND"] = "Request not found";
ClientError2["ENTITY_ERROR"] = "Entity error";
ClientError2["BAD_REQUEST"] = "Bad request";
ClientError2["REQUEST_FAILED"] = "Request Failed";
ClientError2["NO_CONNECTION"] = "No connection";
ClientError2["SERVER_ERROR"] = "Server Error";
ClientError2["INTERNAL_ERROR"] = "Internal error";
ClientError2["GENERAL_ERROR"] = "General Error";
ClientError2["GENERAL_REQUEST_ERROR"] = "General request error";
ClientError2["AUTHENTICATION_ERROR"] = "Authentication Error";
ClientError2["GATE_WAY_ERROR"] = "Gate way error";
ClientError2["RECORD_CONFLICT"] = "Record conflict";
return ClientError2;
})(ClientError || {});
// package.json
var package_default = {
name: "emr-api-client",
version: "1.1.1",
apiConfig: {
host: "http://127.0.0.1:9000"
},
description: "Api client for accessing openmrs service",
main: "./dist/index.js",
module: "./dist/index.mjs",
types: "./dist/index.d.ts",
files: [
"dist"
],
scripts: {
build: "tsup",
test: 'echo "Error: no test specified" && exit 1',
prepublishOnly: "npm run build"
},
author: "Andrew Mfune",
license: "ISC",
devDependencies: {
"ts-node": "^10.9.1",
tsup: "^7.2.0",
typescript: "^5.2.2"
},
keywords: [
"BHT-EMR-API Client",
"BHT-EMR-API",
"H.I.S",
"EMR",
"EMR Client",
"POC",
"POC Client",
"Emastercard"
]
};
// src/api_core.ts
var api_core_default = new class {
constructor() {
this.AUTH = "_auth_";
this.HOST = "_host_";
this.KEEP_USER_LOGGED_IN_FLAG = "_keep_user_logged_in_";
this.userRoles = [];
this.host = "";
this.token = "";
this.username = "";
this.userID = -1;
this.personID = -1;
this.tokenExpiryDate = "";
this.sessionAvailable = false;
this.canPersistLogin = false;
this.loadState();
this.interceptRequest = (req) => req;
this.interceptResponse = (_, res) => res;
}
/**
* This will return the current logged in user's name
* @returns
*/
getUsername() {
return this.username;
}
/**
* Get the logged in user's person id
* @returns
*/
getProviderID() {
return this.personID;
}
/**
* Returns userID of currently logged in user
* @returns
*/
getUserID() {
return this.userID;
}
/**
* Returns URL of API host
* @returns
*/
getHost() {
return this.host;
}
/**
* Configure API host URL i.e. http://localhost:3000 or https://emr.malawi.com
* @param host
*/
setHost(host) {
this.host = host;
localStorage.setItem(this.HOST, this.host);
}
/**
* Generic function for running API endpoints.
* @param relativeUrl
* @param data
* @param baseUrl
* @returns
*/
restRequest(relativeUrl, data, baseUrl = "api/v1") {
return __async(this, null, function* () {
var _a, _b;
let requestData = {
url: `${this.host}/${baseUrl}/${relativeUrl}`,
config: __spreadProps(__spreadValues({}, data), {
mode: "cors",
headers: {
"Authorization": this.token,
"Content-Type": "application/json"
}
})
};
const res = { ok: false };
requestData = this.interceptRequest(requestData);
try {
const req = yield fetch(requestData.url, requestData.config);
const statusResponse = req.status;
res.httpStatusResponse = statusResponse;
if (statusResponse === 204) {
return this.interceptResponse(requestData, res);
}
res.data = yield req.json();
if ([200, 201, 202].includes(statusResponse)) {
res.ok = true;
return this.interceptResponse(requestData, res);
}
switch (statusResponse) {
case 400:
res.clientErrorType = "Bad request" /* BAD_REQUEST */;
break;
case 401:
res.clientErrorType = "Authentication Error" /* AUTHENTICATION_ERROR */;
break;
case 404:
res.clientErrorType = "Request not found" /* NOT_FOUND */;
break;
case 409:
res.clientErrorType = "Record conflict" /* RECORD_CONFLICT */;
break;
case 422:
res.clientErrorType = "Entity error" /* ENTITY_ERROR */;
break;
case 500:
res.clientErrorType = "Server Error" /* SERVER_ERROR */;
break;
case 502:
res.clientErrorType = "Gate way error" /* GATE_WAY_ERROR */;
break;
default:
res.clientErrorType = "General request error" /* GENERAL_REQUEST_ERROR */;
break;
}
res.errorMessage = Array.isArray((_a = res.data) == null ? void 0 : _a.errors) ? (_b = res.data) == null ? void 0 : _b.errors.join(",") : res.clientErrorType || `Error code ${res.httpStatusResponse}`;
} catch (e) {
if (/NetworkError|Failed to fetch/i.test(`${e}`)) {
res.clientErrorType = "No connection" /* NO_CONNECTION */;
res.errorMessage = "Unable to connect to server/network";
} else {
res.clientErrorType = "Internal error" /* INTERNAL_ERROR */;
res.errorMessage = `${e}`;
}
}
return this.interceptResponse(requestData, res);
});
}
/**
* Authentication methord that creates a temporary session on the client side after a successful login
* @param username
* @param password
* @returns
*/
login(_0, _1) {
return __async(this, arguments, function* (username, password, canPersistLogin = this.canPersistLogin) {
this.sessionAvailable = false;
const res = yield this.postJson("auth/login", { username, password });
if (res.ok) {
this.canPersistLogin = canPersistLogin;
this.username = username;
this.startSession(res.data.authorization);
return res;
}
this.clearState();
return res;
});
}
/**
* Starts a new session by saving authentication data and updating the session state.
* @param data - The authorization data containing token, expiry time, user details, and roles.
*/
startSession(data) {
this.tokenExpiryDate = data.expiry_time;
this.personID = data.user.person_id;
this.userID = data.user.user_id;
this.userRoles = data.user.roles;
this.token = data.token;
this.sessionAvailable = true;
this.saveState();
}
/**
* Verifies a password reset token by making a POST request to the API.
* If the token is valid, starts a new session with the returned authorization data.
* @param token - The reset token to verify.
* @returns A boolean indicating whether the token verification was successful.
*/
verifyResetToken(token) {
return __async(this, null, function* () {
const res = yield this.postJson(`auth/reset_password?code=${token}`, {});
if (res.ok && res.data) {
this.startSession(res.data.authorization);
return true;
}
this.clearState();
return false;
});
}
/**
* Clears login session information on the client side
*/
logout() {
this.token = "";
this.userID = -1;
this.personID = -1;
this.username = "";
this.userRoles = [];
this.tokenExpiryDate = "";
this.sessionAvailable = false;
this.clearState();
}
/**Simple check to verify login session */
isLoggedIn() {
return this.sessionAvailable;
}
/**
* Validates provided roles against roles assigned to the current login user
* @param roles
* @returns
*/
userHasRoles(roles) {
const sanitize = (txt) => txt.toLowerCase().trim();
const sanitizedRoles = roles.map((r) => sanitize(r));
return this.userRoles.some((role) => sanitizedRoles.includes(sanitize(role.role)));
}
/**
* Perfoms GET http requests with optional parameters
* @param url
* @param params
* @returns
*/
getJson(url, params = {}) {
const urlParams = Object.keys(params).map((k) => `${k}=${params[k]}`).join("&");
const fullUrl = urlParams.length ? `${url}?${urlParams}` : url;
return this.restRequest(fullUrl, { method: "GET" });
}
/**
* Perfoms POST http requests with provided data
* @param url
* @param data
* @returns
*/
postJson(url, data) {
return this.restRequest(url, {
method: "POST",
body: JSON.stringify(data)
});
}
/**
* Perfoms PUT http requests with provided data
* @param url
* @param data
* @returns
*/
putJson(url, data) {
return this.restRequest(url, {
method: "PUT",
body: JSON.stringify(data)
});
}
/**
* Perfoms DELETE http requests with provided data
* @param url
* @param data
* @returns
*/
void(url, params = {}) {
return this.restRequest(url, {
method: "DELETE",
body: JSON.stringify(params)
});
}
/**
* Method for validating expiration status of a token
* @returns
*/
tokenHasExpired() {
return this.tokenExpiryDate ? /* @__PURE__ */ new Date() > new Date(this.tokenExpiryDate) : true;
}
/**
* Perfoms a healthcheck operation to verify if the API is up
* @returns
*/
apiOk() {
return __async(this, null, function* () {
var _a;
const req = yield this.getJson("_health");
return req.ok && `${(_a = req == null ? void 0 : req.data) == null ? void 0 : _a.status}`.toLowerCase() === "up";
});
}
/**
* Gets current date from the API
* @returns
*/
getDate() {
return __async(this, null, function* () {
const req = yield this.getJson("current_time");
if (req.ok)
return req.data;
});
}
/**
* Gets current API version
* @returns
*/
getVersion() {
return __async(this, null, function* () {
const req = yield this.getJson("version");
if (req.ok && req.data)
return req == null ? void 0 : req.data["System version"];
});
}
/**
* Caches authentication data
*/
saveState() {
const data = JSON.stringify({
token: this.token,
userID: this.userID,
personID: this.personID,
username: this.username,
userRoles: this.userRoles,
tokenExpiryDate: this.tokenExpiryDate
});
this.canPersistLogin ? localStorage.setItem(this.AUTH, data) : sessionStorage.setItem(this.AUTH, data);
localStorage.setItem(this.KEEP_USER_LOGGED_IN_FLAG, `${this.canPersistLogin}`);
}
/**
* Reads saved authentication state
*/
loadState() {
var _a, _b;
this.canPersistLogin = JSON.parse(localStorage.getItem(this.KEEP_USER_LOGGED_IN_FLAG) || `${this.canPersistLogin}`);
const strData = this.canPersistLogin ? localStorage.getItem(this.AUTH) : sessionStorage.getItem(this.AUTH);
const state = JSON.parse(strData || "{}");
this.host = localStorage.getItem(this.HOST) || ((_b = (_a = package_default) == null ? void 0 : _a.apiConfig) == null ? void 0 : _b.host);
this.token = state == null ? void 0 : state.token;
this.username = state == null ? void 0 : state.username;
this.personID = parseInt(`${state == null ? void 0 : state.personID}`);
this.userID = parseInt(`${state == null ? void 0 : state.userID}`);
this.tokenExpiryDate = state == null ? void 0 : state.tokenExpiryDate;
this.userRoles = (state == null ? void 0 : state.userRoles) || [];
this.sessionAvailable = Object.keys(state).length > 0 && !this.tokenHasExpired();
}
clearState() {
localStorage.removeItem(this.AUTH);
sessionStorage.removeItem(this.AUTH);
}
}();
// src/global_property.ts
var global_property_default = new class {
get(property) {
return api_core_default.getJson("global_properties", { property });
}
set(property, propertyValue) {
return api_core_default.postJson("global_properties", {
property,
property_value: propertyValue
});
}
isProp(property) {
return __async(this, null, function* () {
try {
const [prop, val] = property.split("=");
const curVal = yield this.get(prop);
if (curVal == null ? void 0 : curVal.data)
return val === curVal.data[prop];
} catch (e) {
console.error(e);
}
return false;
});
}
}();
// src/demographic_exchange.ts
var demographic_exchange_default = class {
constructor(programID) {
this.NATIONAL_ID_TYPE = 3;
this.programID = programID;
}
isDDeEnabled() {
return __async(this, null, function* () {
return global_property_default.isProp("dde_enabled=true");
});
}
enableDDe() {
return __async(this, null, function* () {
return global_property_default.set("dde_enabled", `true`);
});
}
disableDDe() {
return __async(this, null, function* () {
return global_property_default.set("dde_enabled", `false`);
});
}
findByNpid(npid) {
return api_core_default.getJson("dde/patients/find_by_npid", {
npid,
program_id: this.programID
});
}
findByDemographics(demographics) {
return api_core_default.getJson(`dde/patients/find_by_name_and_gender`, __spreadValues({
program_id: this.programID
}, demographics));
}
findVoidedNpid(npid) {
return api_core_default.getJson(`search/patients/by_identifier`, {
voided: true,
identifier: npid,
type_id: this.NATIONAL_ID_TYPE
});
}
getRemainingNpids() {
return api_core_default.getJson("dde/patients/remaining_npids", {
program_id: this.programID
});
}
reassignNpid(docID, patientID) {
return api_core_default.postJson("dde/patients/reassign_npid", {
program_id: this.programID,
patient_id: patientID,
doc_id: docID
});
}
createNpID(npid, patientID) {
return api_core_default.postJson("patient_identifiers", {
identifier: npid,
patient_id: patientID,
identifier_type: this.NATIONAL_ID_TYPE
});
}
getLocalAndRemoteDiffs(patientID) {
return api_core_default.getJson("dde/patients/diff", {
patient_id: patientID,
program_id: this.programID
});
}
updateLocalDiffs(diffs, patientID) {
return api_core_default.putJson(`people/${patientID}`, __spreadValues({
program_id: this.programID
}, diffs));
}
refreshDemographics(patientID) {
return api_core_default.getJson("dde/patients/refresh", {
program_id: this.programID,
patient_id: patientID
});
}
importPatient(docID) {
return api_core_default.getJson("dde/patients/import_by_doc_id", {
program_id: this.programID,
doc_id: docID
});
}
mergePatients(primary, secondary) {
return api_core_default.postJson("dde/patients/merge", {
program_id: this.programID,
primary,
secondary
});
}
checkPotentialDuplicates(demographics) {
return api_core_default.getJson(`dde/patients/match_by_demographics`, __spreadProps(__spreadValues({}, demographics), {
program_id: this.programID
}));
}
};
// src/user.ts
var user_default = new class {
all(params = {}) {
return api_core_default.getJson("users", params);
}
get(id) {
return api_core_default.getJson(`users/${id}`);
}
create(user) {
return api_core_default.postJson("users", user);
}
update(id, user) {
return api_core_default.putJson(`users/${id}`, user);
}
activate(id) {
return api_core_default.postJson(`users/${id}/activate`, {});
}
deactivate(id) {
return api_core_default.postJson(`users/${id}/deactivate`, {});
}
}();
// src/user_property.ts
var user_property_default = new class {
get(property) {
return api_core_default.getJson("user_properties", { property });
}
set(property, propertyValue) {
return api_core_default.postJson("user_properties", {
property,
property_value: propertyValue
});
}
}();
// src/obs.ts
var obs_default = new class {
all(params = {}) {
return api_core_default.getJson("observations", params);
}
create(encounterID, observations) {
return api_core_default.postJson("observations", {
encounter_id: encounterID,
observations
});
}
update(id, params) {
return api_core_default.putJson(`observations/${id}`, params);
}
void(id, reason) {
return api_core_default.void(`observations/${id}`, { reason });
}
}();
// src/location.ts
var location_default = new class {
getCurrentFacility() {
return api_core_default.getJson("locations/current_facility");
}
getFacilities(params = {}) {
return api_core_default.getJson("locations", params);
}
getFacility(locationID) {
return api_core_default.getJson(`locations/${locationID}`);
}
getRegions() {
return api_core_default.getJson("regions");
}
getDistricts(regionID) {
return api_core_default.getJson("districts", { region_id: regionID, page_size: 1e3 });
}
getTraditionalAuthorities(districtID, name = "") {
return api_core_default.getJson("traditional_authorities", { district_id: districtID, name });
}
getVillages(traditionalAuthorityID, name = "") {
return api_core_default.getJson("villages", { traditional_authority_id: traditionalAuthorityID, name });
}
createAddress(locationName, type, parentLocationID) {
return api_core_default.postJson("addresses", {
address_type: type,
addresses_name: locationName,
parent_location: parentLocationID
});
}
getDistrictByID(id) {
return __async(this, null, function* () {
const res = yield api_core_default.getJson("/districts", { "district_id": id });
if (res.ok && res.data)
return res.data;
throw new Error(res.errorMessage);
});
}
getTraditionalAuthorityById(id) {
return __async(this, null, function* () {
const res = yield api_core_default.getJson("/traditional_authorities", { "traditional_authority_id": id });
if (res.ok && res.data)
return res.data[0];
throw new Error(res.errorMessage);
});
}
}();
// src/patient.ts
var patient_default = new class {
create(personId, programID) {
return api_core_default.postJson("patients", {
program_id: programID,
person_id: personId
});
}
searchBy(searchParams) {
return api_core_default.getJson("search/patients", searchParams);
}
searchByNpid(npid) {
return api_core_default.getJson("search/patients/by_npid", { npid });
}
searchByOtherID(idType, identifier) {
return api_core_default.getJson("search/patients/by_identifier", {
type_id: idType,
identifier
});
}
getVisitDates(patientId, programID, params = {}) {
return api_core_default.getJson(`patients/${patientId}/visits`, __spreadValues({
program_id: programID
}, params));
}
get(patientId) {
return api_core_default.getJson(`patients/${patientId}`);
}
getAll(patientIds) {
return api_core_default.getJson("clients", {
person_ids: patientIds.join(",")
});
}
void(patientId, reason) {
return api_core_default.void(`patients/${patientId}`, { reason });
}
}();
// src/person.ts
var person_default = new class {
all() {
return api_core_default.getJson("people");
}
get(personId) {
return api_core_default.getJson(`people/${personId}`);
}
create(person) {
return api_core_default.postJson("people", person);
}
update(personId, programID, person) {
return api_core_default.putJson(`people/${personId}`, __spreadProps(__spreadValues({}, person), { program_id: programID }));
}
getSimilarFamilyNames(name) {
return api_core_default.getJson("search/family_name", { search_string: name });
}
getSimilarMiddleNames(name) {
return api_core_default.getJson("search/middle_name", { search_string: name });
}
getSimilarGivenNames(name) {
return api_core_default.getJson("search/given_name", { search_string: name });
}
getNames(personId) {
return api_core_default.getJson(`people/${personId}/names`);
}
void(personId, reason) {
return api_core_default.void("people/" + personId, { reason });
}
}();
// src/lab.ts
var lab_default = new class {
createOrder(order) {
return api_core_default.postJson("lab/orders", order);
}
getTestTypes() {
return api_core_default.getJson("lab/test_types");
}
getTestTypesBySpecimen(specimenType = "") {
return api_core_default.getJson("lab/test_types", { specimen_type: specimenType });
}
getSpecimens(testName) {
return api_core_default.getJson("lab/specimen_types", { "test_type": testName });
}
verifyAccessionNumber(accessionNumber) {
return api_core_default.getJson("lab/accession_number", { accession_number: accessionNumber });
}
}();
// src/drug.ts
var drug_default = new class {
createOrder(orders) {
return api_core_default.postJson("drug_orders", orders);
}
getDrugs(params = {}) {
return api_core_default.getJson("drugs", params);
}
getOPDDrugs(params = {}) {
return api_core_default.getJson("OPD_drugslist", params);
}
}();
// src/encounter.ts
var encounter_default = new class {
all(params = {}) {
return api_core_default.getJson("encounters", params);
}
get(id) {
return api_core_default.getJson(`encounters/${id}`);
}
/**
Generate a report on counts of various encounters
POST /reports/encounters
Optional parameters:
all - Retrieves all encounters not just those created by current user
*/
count(params) {
return api_core_default.postJson("reports/encounters", params);
}
create(encounter) {
return api_core_default.postJson("encounters", encounter);
}
update(id, encounter) {
return api_core_default.putJson(`encounters/${id}`, encounter);
}
void(id, reason) {
return api_core_default.void(`encounters/${id}`, { reason });
}
}();
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
ApiCore,
ClientError,
DemographicExchange,
Drug,
Encounter,
GlobalProperty,
Lab,
Location,
Obs,
Patient,
Person,
User,
UserProperty
});
//# sourceMappingURL=index.js.map