UNPKG

emr-api-client

Version:

Api client for accessing openmrs service

829 lines (814 loc) 24.9 kB
"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