Skip to main content

Medical Records Web SDK - Implementation

This guide provides everything you need to integrate the Medical Records Web SDK into your application.

Overview

The Medical Records Web SDK (@eka-care/medical-records-ts-sdk) is a TypeScript SDK for the Eka Care Medical Records API. It is offline-first and works in both browser and Electron renderer environments. It provides:
  • Records Management: Upload, list, group, download, edit and delete medical documents.
  • Smart Reports: Fetch AI-extracted structured data from lab reports.
  • Cases: Organise records into cases (folders) — a record can belong to multiple cases.
  • Offline Support: All data is cached in IndexedDB; writes done offline are auto-synced on reconnect.
  • Reactive UI Updates: Subscribe to DB change events so your UI auto-updates on any write.
  • Electron Support: Route API calls through an IPC bridge with a single config switch.

Installation

Prerequisites

  • A modern web browser (or Electron renderer) with IndexedDB support.
  • A valid auth token generated via the Connect Login API.

Setup

npm install @eka-care/medical-records-ts-sdk

Quick Start

import { MedicalRecordsClient } from '@eka-care/medical-records-ts-sdk';

const sdk = new MedicalRecordsClient({
  defaultHeaders: {
    'client-id': 'your-client-id',
    'flavour':   'your-flavour',
  },
  // cache defaults to true — pass cache: false to disable IndexedDB
  onError: (err) => console.error(err),
});

sdk.setAuthToken('eyJhbGciOi...');

const docs = await sdk.listDocuments({ bid: 'your-business-id', patientId: 'oid' });

Configuration

new MedicalRecordsClient(config: SDKConfig)
Parameters:
NameTypeRequiredDescription
environmentSDKEnvironment⚙️ OptionalSDKEnvironment.Prod = api.eka.care (default), SDKEnvironment.Dev = api.dev.eka.care
defaultHeadersRecord<string, string>⚙️ OptionalEka identification headers — see below
cacheboolean⚙️ OptionalDefaults to true — IndexedDB offline cache is on by default. Pass false to disable (e.g. environments without IndexedDB, or when patient data must not persist on disk)
transportTransportMode⚙️ OptionalTransportMode.Native = browser fetch (default). TransportMode.Bridge = Electron IPC
onError(err: unknown) => void⚙️ OptionalCalled on every SDK error
onUnauthorized() => Promise<string | undefined> | string | undefined⚙️ OptionalCalled on 401 — return a fresh token to auto-retry
onLog(log: SDKLog) => void⚙️ OptionalReceives structured CRUD events emitted by the SDK — see Offline & Sync → Logging

Identification headers

defaultHeaders: {
  'client-id': 'doc-web',       // app identifier
  'flavour':   'ekascribe-web', // app variant
}
These headers are merged into every HTTP request automatically.

Full config example

import { MedicalRecordsClient, SDKEnvironment, TransportMode } from '@eka-care/medical-records-ts-sdk';

const sdk = new MedicalRecordsClient({
  environment: SDKEnvironment.Prod,
  defaultHeaders: {
    'client-id': 'doc-web',
    'flavour':   'ekascribe-web',
  },
  cache: true,   // default — omit to get the same effect
  transport: TransportMode.Native,
  onLog: (log) => {
    // log: { eventName, eventType, status, platform, entityType, params, message, patientOid, bid, timestamp }
    console.log(`[${log.eventName}] ${log.status} (${log.platform})`, log.params);
  },
  onError: (err) => console.error('[SDK]', err),
  onUnauthorized: async () => await refreshToken(),
});

Authentication

sdk.setAuthToken('eyJhbGciOi...');  // set after login
sdk.setAuthToken(undefined);         // clear (falls back to cookie auth)
The token is sent as Authorization: Bearer <token> on every request. On a 401 response, onUnauthorized is called — return a fresh token to auto-retry once.

Error Handling

import {
  EkaCareApiError,
  UploadFailedError,
  StorageLimitExceededError,
} from '@eka-care/medical-records-ts-sdk';

try {
  await sdk.addDocument({ ... });
} catch (err) {
  if (err instanceof UploadFailedError) {
    // Auth succeeded but S3 upload failed — record saved as upload_failure
    // sdk.sync() retries automatically
    console.error('Failed IDs:', err.failures.map(f => f.documentId));
  } else if (err instanceof StorageLimitExceededError) {
    // The tenant's storage quota is full — upload rejected by server
    console.error('Storage limit exceeded');
  } else if (err instanceof EkaCareApiError) {
    console.error(err.message, err.statusCode, err.responseBody);
  }
}
editDocument, deleteDocument, createCase, updateCase, deleteCase never throw on network failure — local state is always updated and server sync retries automatically.

Document Types

The document type is supplied by your UI — the SDK just stores the code (passed as documentType on upload/edit). The type codes come from the hub API. Common codes for reference:
CodeLabel
psPrescription
lrLab Report
dcDischarge Summary
vcVaccine Certificate
inInsurance
ivInvoice
scScan
otOther

Troubleshooting

Common Issues

1. APIs Not Being Called

Problem: API requests are not triggered or return errors. Solution:
  • Ensure the auth token is set via sdk.setAuthToken() and has not expired.
  • Verify bid and patientId are passed on every call.

2. 401 Loops

Problem: Requests keep failing with 401. Solution:
  • Implement onUnauthorized and return a fresh token — the SDK auto-retries once.
  • If the refresh itself fails, redirect the user to login.

3. Stale Data in UI

Problem: The UI shows old records after an upload, edit or delete. Solution:
  • Subscribe to documents:changed / cases:changed events and re-query the local DB. See Offline & Sync.