@ovok/core 0.3.22 → 0.3.24

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.
Files changed (24) hide show
  1. package/dist/client/observation/methods/generateObservationBodiesByMeasurement.js +3 -2
  2. package/dist/client/observation/methods/observationsToMeasurements.d.ts +2 -2
  3. package/dist/client/observation/methods/observationsToMeasurements.js +95 -1
  4. package/dist/client/observation/services/baby-sleep.d.ts +28 -0
  5. package/dist/client/observation/services/baby-sleep.js +69 -0
  6. package/dist/client/observation/services/creator.js +6 -0
  7. package/dist/client/observation/services/lipid-panel.d.ts +28 -0
  8. package/dist/client/observation/services/lipid-panel.js +134 -0
  9. package/dist/client/observation/services/respiratory-therapy.d.ts +28 -0
  10. package/dist/client/observation/services/respiratory-therapy.js +69 -0
  11. package/dist/client/observation/types/MeasurementTypeKey.d.ts +4 -1
  12. package/dist/client/observation/types/MeasurementTypeKey.js +3 -0
  13. package/dist/client/observation/types/ObservationCode.d.ts +13 -1
  14. package/dist/client/observation/types/ObservationCode.js +12 -0
  15. package/dist/client/observation/types/measurement/BabySleepMeasurement.d.ts +12 -0
  16. package/dist/client/observation/types/measurement/BabySleepMeasurement.js +2 -0
  17. package/dist/client/observation/types/measurement/LipidPanelMeasurement.d.ts +11 -0
  18. package/dist/client/observation/types/measurement/LipidPanelMeasurement.js +2 -0
  19. package/dist/client/observation/types/measurement/RespiratoryTherapyMeasurement.d.ts +12 -0
  20. package/dist/client/observation/types/measurement/RespiratoryTherapyMeasurement.js +2 -0
  21. package/dist/client/observation/types/measurement/index.d.ts +3 -0
  22. package/dist/client/observation/types/measurement/index.js +3 -0
  23. package/dist/conformance/capability-requirements.js +1 -1
  24. package/package.json +1 -1
@@ -58,8 +58,9 @@ async function generateObservationBodiesByMeasurement(params) {
58
58
  return observationBodies.filter(hasObservationValue).map(applyEffectiveDateTime);
59
59
  }
60
60
  const hasObservationValue = (observation) => {
61
- var _a, _b, _c, _d, _e;
61
+ var _a, _b, _c, _d, _e, _f;
62
62
  return ((_a = observation.valueQuantity) === null || _a === void 0 ? void 0 : _a.value) !== undefined ||
63
63
  Boolean((_b = observation.valueSampledData) === null || _b === void 0 ? void 0 : _b.data) ||
64
- Boolean((_e = (_d = (_c = observation.valueCodeableConcept) === null || _c === void 0 ? void 0 : _c.coding) === null || _d === void 0 ? void 0 : _d[0]) === null || _e === void 0 ? void 0 : _e.code);
64
+ Boolean((_e = (_d = (_c = observation.valueCodeableConcept) === null || _c === void 0 ? void 0 : _c.coding) === null || _d === void 0 ? void 0 : _d[0]) === null || _e === void 0 ? void 0 : _e.code) ||
65
+ Boolean((_f = observation.component) === null || _f === void 0 ? void 0 : _f.length);
65
66
  };
@@ -1,6 +1,6 @@
1
1
  import { Observation } from "@medplum/fhirtypes";
2
- import { BloodGlucoseMeasurement, BloodPressureMeasurement, BodyTemperatureMeasurement, BodyWeightMeasurement, EcgMeasurement, HeartRateMeasurement, HeartRateVariabilityMeasurement, Measurement, MeasurementTypeKey, PulseOximeterMeasurement, RespiratoryRateMeasurement, RestingHeartRateMeasurement, StepCountMeasurement, UrineAnalyzeMeasurement, Vo2MaxMeasurement, WalkingHeartRateAverageMeasurement } from "../../../types";
3
- export type SupportedMeasurement = BloodGlucoseMeasurement | BloodPressureMeasurement | BodyTemperatureMeasurement | BodyWeightMeasurement | EcgMeasurement | HeartRateMeasurement | HeartRateVariabilityMeasurement | PulseOximeterMeasurement | RespiratoryRateMeasurement | RestingHeartRateMeasurement | StepCountMeasurement | UrineAnalyzeMeasurement | Vo2MaxMeasurement | WalkingHeartRateAverageMeasurement | Measurement;
2
+ import { BabySleepMeasurement, BloodGlucoseMeasurement, BloodPressureMeasurement, BodyTemperatureMeasurement, BodyWeightMeasurement, EcgMeasurement, HeartRateMeasurement, HeartRateVariabilityMeasurement, LipidPanelMeasurement, Measurement, MeasurementTypeKey, PulseOximeterMeasurement, RespiratoryRateMeasurement, RespiratoryTherapyMeasurement, RestingHeartRateMeasurement, StepCountMeasurement, UrineAnalyzeMeasurement, Vo2MaxMeasurement, WalkingHeartRateAverageMeasurement } from "../../../types";
3
+ export type SupportedMeasurement = BloodGlucoseMeasurement | BabySleepMeasurement | BloodPressureMeasurement | BodyTemperatureMeasurement | BodyWeightMeasurement | EcgMeasurement | HeartRateMeasurement | HeartRateVariabilityMeasurement | LipidPanelMeasurement | PulseOximeterMeasurement | RespiratoryRateMeasurement | RespiratoryTherapyMeasurement | RestingHeartRateMeasurement | StepCountMeasurement | UrineAnalyzeMeasurement | Vo2MaxMeasurement | WalkingHeartRateAverageMeasurement | Measurement;
4
4
  type SupportedType = Exclude<MeasurementTypeKey, MeasurementTypeKey.symptomQuestionnaire>;
5
5
  export type ObservationGrouping = "hasMember" | "time" | ((observation: Observation, index: number, observations: readonly Observation[]) => string);
6
6
  export interface ObservationsToMeasurementsOptions {
@@ -187,6 +187,58 @@ const groupObservations = (observations, options, legacyKey) => {
187
187
  const firstValue = (observations, code) => observations.find((observation) => codeOf(observation) === code)
188
188
  ? valueOf(observations.find((observation) => codeOf(observation) === code))
189
189
  : undefined;
190
+ const LIPID_FIELDS = [
191
+ { key: "totalCholesterol", codes: [types_1.ObservationCode.TOTAL_CHOLESTEROL_MASS, types_1.ObservationCode.TOTAL_CHOLESTEROL_MOLAR] },
192
+ { key: "hdlCholesterol", codes: [types_1.ObservationCode.HDL_CHOLESTEROL_MASS, types_1.ObservationCode.HDL_CHOLESTEROL_MOLAR] },
193
+ { key: "ldlCholesterol", codes: [types_1.ObservationCode.LDL_CHOLESTEROL_MASS, types_1.ObservationCode.LDL_CHOLESTEROL_MOLAR] },
194
+ { key: "triglycerides", codes: [types_1.ObservationCode.TRIGLYCERIDES_MASS, types_1.ObservationCode.TRIGLYCERIDES_MOLAR] },
195
+ { key: "totalCholesterolHdlRatio", codes: [types_1.ObservationCode.TOTAL_CHOLESTEROL_HDL_RATIO] },
196
+ ];
197
+ const lipidValue = (observations, field) => {
198
+ var _a, _b, _c;
199
+ for (const observation of observations) {
200
+ const component = (_a = observation.component) === null || _a === void 0 ? void 0 : _a.find((candidate) => { var _a; return (_a = candidate.code.coding) === null || _a === void 0 ? void 0 : _a.some((coding) => field.codes.includes(coding.code)); });
201
+ const value = (_c = (_b = component === null || component === void 0 ? void 0 : component.valueQuantity) === null || _b === void 0 ? void 0 : _b.value) !== null && _c !== void 0 ? _c : (field.codes.includes(codeOf(observation)) ? valueOf(observation) : undefined);
202
+ if (typeof value === "number") {
203
+ return value;
204
+ }
205
+ }
206
+ return undefined;
207
+ };
208
+ const lipidUnit = (observations) => {
209
+ var _a, _b, _c, _d, _e, _f;
210
+ for (const observation of observations) {
211
+ for (const component of (_a = observation.component) !== null && _a !== void 0 ? _a : []) {
212
+ const code = (_c = (_b = component.code.coding) === null || _b === void 0 ? void 0 : _b[0]) === null || _c === void 0 ? void 0 : _c.code;
213
+ if ([types_1.ObservationCode.TOTAL_CHOLESTEROL_MOLAR, types_1.ObservationCode.HDL_CHOLESTEROL_MOLAR,
214
+ types_1.ObservationCode.LDL_CHOLESTEROL_MOLAR, types_1.ObservationCode.TRIGLYCERIDES_MOLAR].includes(code)) {
215
+ return "mmol/L";
216
+ }
217
+ if ([types_1.ObservationCode.TOTAL_CHOLESTEROL_MASS, types_1.ObservationCode.HDL_CHOLESTEROL_MASS,
218
+ types_1.ObservationCode.LDL_CHOLESTEROL_MASS, types_1.ObservationCode.TRIGLYCERIDES_MASS].includes(code)) {
219
+ return "mg/dL";
220
+ }
221
+ if (((_d = component.valueQuantity) === null || _d === void 0 ? void 0 : _d.unit) === "mmol/L" || ((_e = component.valueQuantity) === null || _e === void 0 ? void 0 : _e.unit) === "mg/dL") {
222
+ return component.valueQuantity.unit;
223
+ }
224
+ }
225
+ const code = codeOf(observation);
226
+ const unit = (_f = observation.valueQuantity) === null || _f === void 0 ? void 0 : _f.unit;
227
+ if (code && [types_1.ObservationCode.TOTAL_CHOLESTEROL_MOLAR, types_1.ObservationCode.HDL_CHOLESTEROL_MOLAR,
228
+ types_1.ObservationCode.LDL_CHOLESTEROL_MOLAR, types_1.ObservationCode.TRIGLYCERIDES_MOLAR].includes(code)) {
229
+ return "mmol/L";
230
+ }
231
+ if (code && [types_1.ObservationCode.TOTAL_CHOLESTEROL_MASS, types_1.ObservationCode.HDL_CHOLESTEROL_MASS,
232
+ types_1.ObservationCode.LDL_CHOLESTEROL_MASS, types_1.ObservationCode.TRIGLYCERIDES_MASS].includes(code)) {
233
+ return "mg/dL";
234
+ }
235
+ if (unit === "mmol/L" || unit === "mg/dL") {
236
+ return unit;
237
+ }
238
+ }
239
+ return "mg/dL";
240
+ };
241
+ const respiratoryComponents = (observations) => observations.flatMap((observation) => { var _a; return (_a = observation.component) !== null && _a !== void 0 ? _a : []; });
190
242
  const baseMeasurement = (measurementTypeKey, observation) => ({
191
243
  measurementTypeKey,
192
244
  ...(observation.id ? { id: observation.id } : {}),
@@ -316,6 +368,28 @@ const inverseGroup = (type, observations) => {
316
368
  }
317
369
  return result;
318
370
  }
371
+ case types_1.MeasurementTypeKey.lipidPanel:
372
+ return {
373
+ ...measurement,
374
+ measurementTypeKey: type,
375
+ unit: lipidUnit(observations),
376
+ ...Object.fromEntries(LIPID_FIELDS.flatMap(({ key, codes }) => {
377
+ const value = lipidValue(observations, { key, codes });
378
+ return value === undefined ? [] : [[key, value]];
379
+ })),
380
+ };
381
+ case types_1.MeasurementTypeKey.respiratoryTherapy:
382
+ return {
383
+ ...measurement,
384
+ measurementTypeKey: type,
385
+ components: respiratoryComponents(observations),
386
+ };
387
+ case types_1.MeasurementTypeKey.babySleep:
388
+ return {
389
+ ...measurement,
390
+ measurementTypeKey: type,
391
+ components: respiratoryComponents(observations),
392
+ };
319
393
  default:
320
394
  return measurement;
321
395
  }
@@ -342,6 +416,12 @@ const codesForType = {
342
416
  types_1.ObservationCode.URIC_ACID,
343
417
  ...types_1.URINE_ANALYTE_DEFINITIONS.map((analyte) => analyte.code),
344
418
  ],
419
+ [types_1.MeasurementTypeKey.lipidPanel]: [
420
+ types_1.ObservationCode.LIPID_PANEL,
421
+ ...LIPID_FIELDS.flatMap(({ codes }) => codes),
422
+ ],
423
+ [types_1.MeasurementTypeKey.respiratoryTherapy]: [types_1.ObservationCode.RESPIRATORY_THERAPY],
424
+ [types_1.MeasurementTypeKey.babySleep]: [types_1.ObservationCode.BABY_SLEEP],
345
425
  };
346
426
  const observationCodesForTypes = (types) => [...new Set(types.flatMap((type) => { var _a; return (_a = codesForType[type]) !== null && _a !== void 0 ? _a : []; }))].join(",");
347
427
  exports.observationCodesForTypes = observationCodesForTypes;
@@ -355,7 +435,21 @@ const observationsToMeasurements = (observations, types, options = {}) => {
355
435
  const groups = groupObservations(matching, options, type === types_1.MeasurementTypeKey.ecg
356
436
  ? (observation, index) => ecgGroupKey(observation, matching) || `ecg:${index}`
357
437
  : undefined);
358
- groups.forEach((group) => output.push(inverseGroup(type, group.observations)));
438
+ groups.forEach((group) => {
439
+ if (type === types_1.MeasurementTypeKey.lipidPanel &&
440
+ !LIPID_FIELDS.some((field) => lipidValue(group.observations, field) !== undefined)) {
441
+ return;
442
+ }
443
+ if (type === types_1.MeasurementTypeKey.respiratoryTherapy &&
444
+ respiratoryComponents(group.observations).length === 0) {
445
+ return;
446
+ }
447
+ if (type === types_1.MeasurementTypeKey.babySleep &&
448
+ respiratoryComponents(group.observations).length === 0) {
449
+ return;
450
+ }
451
+ output.push(inverseGroup(type, group.observations));
452
+ });
359
453
  });
360
454
  return output;
361
455
  };
@@ -0,0 +1,28 @@
1
+ import { Observation } from "@medplum/fhirtypes";
2
+ import { BabySleepMeasurement, Measurement, MeasurementTypeKey, ObservationCode } from "../../../types";
3
+ import { RecordResult, RecordType } from "../types/generate-measurement/HealthConnectTypes";
4
+ import { Sample } from "../types/generate-measurement/Sample";
5
+ import { ObservationFragment } from "../types/generate-observation-body/ObservationFragment";
6
+ import { ObservationValue } from "../types/generate-observation-body/ObservationValue";
7
+ import { ObservationMetadata } from "../types/service/ObservationMetadata";
8
+ import { BaseObservationService } from "./base-observation-service";
9
+ export declare class BabySleepService extends BaseObservationService<BabySleepMeasurement> {
10
+ protected measurementTypeKey: MeasurementTypeKey;
11
+ protected measurementTypeName: string;
12
+ protected observationMetadata: ObservationMetadata<BabySleepMeasurement>[];
13
+ generateObservationFragments(measurement: Measurement): ObservationFragment[];
14
+ getObservationCodes(): {
15
+ coding: {
16
+ code: ObservationCode;
17
+ display: string;
18
+ system: string;
19
+ }[];
20
+ }[];
21
+ getAdditionalProperties(measurement: Measurement): Partial<Observation>[];
22
+ generateValues(_measurement: Measurement): ObservationValue[];
23
+ getUnits(): string[];
24
+ getMeasurementDisplay(measurement: Measurement): string;
25
+ getObservationDisplay(observations: Observation[]): string | undefined;
26
+ convertSamplesToMeasurement(_samples: Sample[]): BabySleepMeasurement;
27
+ convertRecordToMeasurement(_record: RecordResult<RecordType>): BabySleepMeasurement;
28
+ }
@@ -0,0 +1,69 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.BabySleepService = void 0;
4
+ const types_1 = require("../../../types");
5
+ const base_observation_service_1 = require("./base-observation-service");
6
+ const BABY_SLEEP_SYSTEM = "https://sdk.ovok.com/fhir/CodeSystem/measurement-type";
7
+ const recordedAt = (measurement) => measurement.recordedAt instanceof Date &&
8
+ !Number.isNaN(measurement.recordedAt.getTime())
9
+ ? measurement.recordedAt.toISOString()
10
+ : new Date().toISOString();
11
+ class BabySleepService extends base_observation_service_1.BaseObservationService {
12
+ constructor() {
13
+ super(...arguments);
14
+ this.measurementTypeKey = types_1.MeasurementTypeKey.babySleep;
15
+ this.measurementTypeName = "baby sleep";
16
+ this.observationMetadata = [];
17
+ }
18
+ generateObservationFragments(measurement) {
19
+ const babySleep = this.getCastedMeasurement(measurement);
20
+ if (babySleep.components.length === 0) {
21
+ return [];
22
+ }
23
+ return [{
24
+ code: {
25
+ coding: [{
26
+ code: types_1.ObservationCode.BABY_SLEEP,
27
+ display: "Baby sleep observation",
28
+ system: BABY_SLEEP_SYSTEM,
29
+ }],
30
+ },
31
+ additionalProperties: {
32
+ effectiveDateTime: recordedAt(babySleep),
33
+ component: babySleep.components,
34
+ },
35
+ }];
36
+ }
37
+ getObservationCodes() {
38
+ return [{
39
+ coding: [{
40
+ code: types_1.ObservationCode.BABY_SLEEP,
41
+ display: "Baby sleep observation",
42
+ system: BABY_SLEEP_SYSTEM,
43
+ }],
44
+ }];
45
+ }
46
+ getAdditionalProperties(measurement) {
47
+ return [{ effectiveDateTime: recordedAt(this.getCastedMeasurement(measurement)) }];
48
+ }
49
+ generateValues(_measurement) {
50
+ return [];
51
+ }
52
+ getUnits() {
53
+ return [];
54
+ }
55
+ getMeasurementDisplay(measurement) {
56
+ return `${this.getCastedMeasurement(measurement).components.length} baby sleep metrics`;
57
+ }
58
+ getObservationDisplay(observations) {
59
+ const count = observations.reduce((total, observation) => { var _a, _b; return total + ((_b = (_a = observation.component) === null || _a === void 0 ? void 0 : _a.length) !== null && _b !== void 0 ? _b : 0); }, 0);
60
+ return count ? `${count} baby sleep metrics` : undefined;
61
+ }
62
+ convertSamplesToMeasurement(_samples) {
63
+ throw new Error("Baby sleep samples are not supported.");
64
+ }
65
+ convertRecordToMeasurement(_record) {
66
+ throw new Error("Baby sleep Health Connect records are not supported.");
67
+ }
68
+ }
69
+ exports.BabySleepService = BabySleepService;
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.ObservationServiceCreator = void 0;
4
4
  const types_1 = require("../../../types");
5
+ const baby_sleep_1 = require("./baby-sleep");
5
6
  const blood_glucose_1 = require("./blood-glucose");
6
7
  const blood_oxygen_1 = require("./blood-oxygen");
7
8
  const blood_pressure_1 = require("./blood-pressure");
@@ -10,7 +11,9 @@ const body_weight_1 = require("./body-weight");
10
11
  const ecg_1 = require("./ecg");
11
12
  const heart_rate_1 = require("./heart-rate");
12
13
  const heart_rate_variability_1 = require("./heart-rate-variability");
14
+ const lipid_panel_1 = require("./lipid-panel");
13
15
  const respiratory_rate_1 = require("./respiratory-rate");
16
+ const respiratory_therapy_1 = require("./respiratory-therapy");
14
17
  const resting_heart_rate_1 = require("./resting-heart-rate");
15
18
  const step_count_1 = require("./step-count");
16
19
  const uric_acid_service_1 = require("./uric-acid-service");
@@ -43,6 +46,9 @@ class ObservationServiceCreator {
43
46
  this.services.set(types_1.MeasurementTypeKey.vo2Max, new vo2_max_1.Vo2MaxService());
44
47
  this.services.set(types_1.MeasurementTypeKey.urineAnalysis, new uric_acid_service_1.UricAcidService());
45
48
  this.services.set(types_1.MeasurementTypeKey.uricAcid, new uric_acid_service_1.UricAcidService());
49
+ this.services.set(types_1.MeasurementTypeKey.lipidPanel, new lipid_panel_1.LipidPanelService());
50
+ this.services.set(types_1.MeasurementTypeKey.respiratoryTherapy, new respiratory_therapy_1.RespiratoryTherapyService());
51
+ this.services.set(types_1.MeasurementTypeKey.babySleep, new baby_sleep_1.BabySleepService());
46
52
  }
47
53
  getService(type) {
48
54
  const service = this.services.get(type);
@@ -0,0 +1,28 @@
1
+ import { Observation } from "@medplum/fhirtypes";
2
+ import { LipidPanelMeasurement, Measurement, MeasurementTypeKey, ObservationCode } from "../../../types";
3
+ import { RecordResult, RecordType } from "../types/generate-measurement/HealthConnectTypes";
4
+ import { Sample } from "../types/generate-measurement/Sample";
5
+ import { ObservationFragment } from "../types/generate-observation-body/ObservationFragment";
6
+ import { ObservationValue } from "../types/generate-observation-body/ObservationValue";
7
+ import { ObservationMetadata } from "../types/service/ObservationMetadata";
8
+ import { BaseObservationService } from "./base-observation-service";
9
+ export declare class LipidPanelService extends BaseObservationService<LipidPanelMeasurement> {
10
+ protected measurementTypeKey: MeasurementTypeKey;
11
+ protected measurementTypeName: string;
12
+ protected observationMetadata: ObservationMetadata<LipidPanelMeasurement>[];
13
+ generateObservationFragments(measurement: Measurement): ObservationFragment[];
14
+ getObservationCodes(): {
15
+ coding: {
16
+ code: ObservationCode;
17
+ display: string;
18
+ system: string;
19
+ }[];
20
+ }[];
21
+ getAdditionalProperties(measurement: Measurement): Partial<Observation>[];
22
+ generateValues(_measurement: Measurement): ObservationValue[];
23
+ getUnits(): string[];
24
+ getMeasurementDisplay(measurement: Measurement): string;
25
+ getObservationDisplay(observations: Observation[]): string | undefined;
26
+ convertSamplesToMeasurement(_samples: Sample[]): LipidPanelMeasurement;
27
+ convertRecordToMeasurement(_record: RecordResult<RecordType>): LipidPanelMeasurement;
28
+ }
@@ -0,0 +1,134 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.LipidPanelService = void 0;
4
+ const types_1 = require("../../../types");
5
+ const base_observation_service_1 = require("./base-observation-service");
6
+ const UCUM_SYSTEM = "http://unitsofmeasure.org";
7
+ const LOINC_SYSTEM = "http://loinc.org";
8
+ const COMPONENTS = [
9
+ {
10
+ key: "totalCholesterol",
11
+ display: "Total cholesterol",
12
+ massCode: types_1.ObservationCode.TOTAL_CHOLESTEROL_MASS,
13
+ molarCode: types_1.ObservationCode.TOTAL_CHOLESTEROL_MOLAR,
14
+ },
15
+ {
16
+ key: "hdlCholesterol",
17
+ display: "HDL cholesterol",
18
+ massCode: types_1.ObservationCode.HDL_CHOLESTEROL_MASS,
19
+ molarCode: types_1.ObservationCode.HDL_CHOLESTEROL_MOLAR,
20
+ },
21
+ {
22
+ key: "ldlCholesterol",
23
+ display: "LDL cholesterol",
24
+ massCode: types_1.ObservationCode.LDL_CHOLESTEROL_MASS,
25
+ molarCode: types_1.ObservationCode.LDL_CHOLESTEROL_MOLAR,
26
+ },
27
+ {
28
+ key: "triglycerides",
29
+ display: "Triglycerides",
30
+ massCode: types_1.ObservationCode.TRIGLYCERIDES_MASS,
31
+ molarCode: types_1.ObservationCode.TRIGLYCERIDES_MOLAR,
32
+ },
33
+ {
34
+ key: "totalCholesterolHdlRatio",
35
+ display: "Total cholesterol/HDL ratio",
36
+ massCode: types_1.ObservationCode.TOTAL_CHOLESTEROL_HDL_RATIO,
37
+ },
38
+ ];
39
+ const recordedAt = (measurement) => measurement.recordedAt instanceof Date &&
40
+ !Number.isNaN(measurement.recordedAt.getTime())
41
+ ? measurement.recordedAt.toISOString()
42
+ : new Date().toISOString();
43
+ class LipidPanelService extends base_observation_service_1.BaseObservationService {
44
+ constructor() {
45
+ super(...arguments);
46
+ this.measurementTypeKey = types_1.MeasurementTypeKey.lipidPanel;
47
+ this.measurementTypeName = "lipid panel";
48
+ this.observationMetadata = [];
49
+ }
50
+ generateObservationFragments(measurement) {
51
+ const lipidPanel = this.getCastedMeasurement(measurement);
52
+ const components = COMPONENTS.flatMap((item) => {
53
+ const value = lipidPanel[item.key];
54
+ if (typeof value !== "number" || !Number.isFinite(value)) {
55
+ return [];
56
+ }
57
+ const code = lipidPanel.unit === "mmol/L" ? item.molarCode : item.massCode;
58
+ if (!code) {
59
+ return [];
60
+ }
61
+ const unit = item.key === "totalCholesterolHdlRatio" ? "{ratio}" : lipidPanel.unit;
62
+ return [{
63
+ code: {
64
+ coding: [{ code, display: item.display, system: LOINC_SYSTEM }],
65
+ text: item.display,
66
+ },
67
+ valueQuantity: {
68
+ value,
69
+ unit,
70
+ code: unit,
71
+ system: UCUM_SYSTEM,
72
+ },
73
+ }];
74
+ });
75
+ if (components.length === 0) {
76
+ return [];
77
+ }
78
+ return [{
79
+ code: {
80
+ coding: [{
81
+ code: types_1.ObservationCode.LIPID_PANEL,
82
+ display: "Lipid panel - Serum or Plasma",
83
+ system: LOINC_SYSTEM,
84
+ }],
85
+ },
86
+ additionalProperties: {
87
+ effectiveDateTime: recordedAt(lipidPanel),
88
+ component: components,
89
+ },
90
+ }];
91
+ }
92
+ getObservationCodes() {
93
+ return [{
94
+ coding: [{
95
+ code: types_1.ObservationCode.LIPID_PANEL,
96
+ display: "Lipid panel - Serum or Plasma",
97
+ system: LOINC_SYSTEM,
98
+ }],
99
+ }];
100
+ }
101
+ getAdditionalProperties(measurement) {
102
+ return [{ effectiveDateTime: recordedAt(this.getCastedMeasurement(measurement)) }];
103
+ }
104
+ generateValues(_measurement) {
105
+ return [];
106
+ }
107
+ getUnits() {
108
+ return ["mg/dL", "mmol/L", "{ratio}"];
109
+ }
110
+ getMeasurementDisplay(measurement) {
111
+ const lipidPanel = this.getCastedMeasurement(measurement);
112
+ return COMPONENTS.flatMap(({ key, display }) => {
113
+ const value = lipidPanel[key];
114
+ return value === undefined ? [] : [`${display}: ${value}`];
115
+ }).join(", ");
116
+ }
117
+ getObservationDisplay(observations) {
118
+ const components = observations.flatMap((observation) => { var _a; return (_a = observation.component) !== null && _a !== void 0 ? _a : []; });
119
+ const values = components.flatMap((component) => {
120
+ var _a, _b, _c, _d;
121
+ const display = (_a = component.code.text) !== null && _a !== void 0 ? _a : (_c = (_b = component.code.coding) === null || _b === void 0 ? void 0 : _b[0]) === null || _c === void 0 ? void 0 : _c.display;
122
+ const value = (_d = component.valueQuantity) === null || _d === void 0 ? void 0 : _d.value;
123
+ return display && typeof value === "number" ? [`${display}: ${value}`] : [];
124
+ });
125
+ return values.length ? values.join(", ") : undefined;
126
+ }
127
+ convertSamplesToMeasurement(_samples) {
128
+ throw new Error("Lipid panel samples are not supported.");
129
+ }
130
+ convertRecordToMeasurement(_record) {
131
+ throw new Error("Lipid panel Health Connect records are not supported.");
132
+ }
133
+ }
134
+ exports.LipidPanelService = LipidPanelService;
@@ -0,0 +1,28 @@
1
+ import { Observation } from "@medplum/fhirtypes";
2
+ import { Measurement, MeasurementTypeKey, ObservationCode, RespiratoryTherapyMeasurement } from "../../../types";
3
+ import { RecordResult, RecordType } from "../types/generate-measurement/HealthConnectTypes";
4
+ import { Sample } from "../types/generate-measurement/Sample";
5
+ import { ObservationFragment } from "../types/generate-observation-body/ObservationFragment";
6
+ import { ObservationValue } from "../types/generate-observation-body/ObservationValue";
7
+ import { ObservationMetadata } from "../types/service/ObservationMetadata";
8
+ import { BaseObservationService } from "./base-observation-service";
9
+ export declare class RespiratoryTherapyService extends BaseObservationService<RespiratoryTherapyMeasurement> {
10
+ protected measurementTypeKey: MeasurementTypeKey;
11
+ protected measurementTypeName: string;
12
+ protected observationMetadata: ObservationMetadata<RespiratoryTherapyMeasurement>[];
13
+ generateObservationFragments(measurement: Measurement): ObservationFragment[];
14
+ getObservationCodes(): {
15
+ coding: {
16
+ code: ObservationCode;
17
+ display: string;
18
+ system: string;
19
+ }[];
20
+ }[];
21
+ getAdditionalProperties(measurement: Measurement): Partial<Observation>[];
22
+ generateValues(_measurement: Measurement): ObservationValue[];
23
+ getUnits(): string[];
24
+ getMeasurementDisplay(measurement: Measurement): string;
25
+ getObservationDisplay(observations: Observation[]): string | undefined;
26
+ convertSamplesToMeasurement(_samples: Sample[]): RespiratoryTherapyMeasurement;
27
+ convertRecordToMeasurement(_record: RecordResult<RecordType>): RespiratoryTherapyMeasurement;
28
+ }
@@ -0,0 +1,69 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.RespiratoryTherapyService = void 0;
4
+ const types_1 = require("../../../types");
5
+ const base_observation_service_1 = require("./base-observation-service");
6
+ const RESPIRATORY_THERAPY_SYSTEM = "https://sdk.ovok.com/fhir/CodeSystem/measurement-type";
7
+ const recordedAt = (measurement) => measurement.recordedAt instanceof Date &&
8
+ !Number.isNaN(measurement.recordedAt.getTime())
9
+ ? measurement.recordedAt.toISOString()
10
+ : new Date().toISOString();
11
+ class RespiratoryTherapyService extends base_observation_service_1.BaseObservationService {
12
+ constructor() {
13
+ super(...arguments);
14
+ this.measurementTypeKey = types_1.MeasurementTypeKey.respiratoryTherapy;
15
+ this.measurementTypeName = "respiratory therapy";
16
+ this.observationMetadata = [];
17
+ }
18
+ generateObservationFragments(measurement) {
19
+ const respiratoryTherapy = this.getCastedMeasurement(measurement);
20
+ if (respiratoryTherapy.components.length === 0) {
21
+ return [];
22
+ }
23
+ return [{
24
+ code: {
25
+ coding: [{
26
+ code: types_1.ObservationCode.RESPIRATORY_THERAPY,
27
+ display: "Respiratory therapy observation",
28
+ system: RESPIRATORY_THERAPY_SYSTEM,
29
+ }],
30
+ },
31
+ additionalProperties: {
32
+ effectiveDateTime: recordedAt(respiratoryTherapy),
33
+ component: respiratoryTherapy.components,
34
+ },
35
+ }];
36
+ }
37
+ getObservationCodes() {
38
+ return [{
39
+ coding: [{
40
+ code: types_1.ObservationCode.RESPIRATORY_THERAPY,
41
+ display: "Respiratory therapy observation",
42
+ system: RESPIRATORY_THERAPY_SYSTEM,
43
+ }],
44
+ }];
45
+ }
46
+ getAdditionalProperties(measurement) {
47
+ return [{ effectiveDateTime: recordedAt(this.getCastedMeasurement(measurement)) }];
48
+ }
49
+ generateValues(_measurement) {
50
+ return [];
51
+ }
52
+ getUnits() {
53
+ return [];
54
+ }
55
+ getMeasurementDisplay(measurement) {
56
+ return `${this.getCastedMeasurement(measurement).components.length} respiratory therapy metrics`;
57
+ }
58
+ getObservationDisplay(observations) {
59
+ const count = observations.reduce((total, observation) => { var _a, _b; return total + ((_b = (_a = observation.component) === null || _a === void 0 ? void 0 : _a.length) !== null && _b !== void 0 ? _b : 0); }, 0);
60
+ return count ? `${count} respiratory therapy metrics` : undefined;
61
+ }
62
+ convertSamplesToMeasurement(_samples) {
63
+ throw new Error("Respiratory therapy samples are not supported.");
64
+ }
65
+ convertRecordToMeasurement(_record) {
66
+ throw new Error("Respiratory therapy Health Connect records are not supported.");
67
+ }
68
+ }
69
+ exports.RespiratoryTherapyService = RespiratoryTherapyService;
@@ -18,5 +18,8 @@ export declare enum MeasurementTypeKey {
18
18
  spirometryPanel = "spirometry-panel",
19
19
  stepCount = "step-count",
20
20
  restingHeartRate = "resting-heart-rate",
21
- walkingHeartRateAverage = "walking-heart-rate-average"
21
+ walkingHeartRateAverage = "walking-heart-rate-average",
22
+ lipidPanel = "lipid-panel",
23
+ respiratoryTherapy = "respiratory-therapy",
24
+ babySleep = "baby-sleep"
22
25
  }
@@ -23,4 +23,7 @@ var MeasurementTypeKey;
23
23
  MeasurementTypeKey["stepCount"] = "step-count";
24
24
  MeasurementTypeKey["restingHeartRate"] = "resting-heart-rate";
25
25
  MeasurementTypeKey["walkingHeartRateAverage"] = "walking-heart-rate-average";
26
+ MeasurementTypeKey["lipidPanel"] = "lipid-panel";
27
+ MeasurementTypeKey["respiratoryTherapy"] = "respiratory-therapy";
28
+ MeasurementTypeKey["babySleep"] = "baby-sleep";
26
29
  })(MeasurementTypeKey || (exports.MeasurementTypeKey = MeasurementTypeKey = {}));
@@ -34,5 +34,17 @@ export declare enum ObservationCode {
34
34
  PHOTOGRAPHIC_IMAGE = "72170-4",
35
35
  PHENX_RESPIRATORY = "62628-3",
36
36
  RESTING_HEART_RATE = "40443-4",
37
- WALKING_HEART_RATE_AVERAGE = "40442-6"
37
+ WALKING_HEART_RATE_AVERAGE = "40442-6",
38
+ LIPID_PANEL = "100898-6",
39
+ TOTAL_CHOLESTEROL_MASS = "2093-3",
40
+ TOTAL_CHOLESTEROL_MOLAR = "14647-2",
41
+ HDL_CHOLESTEROL_MASS = "2085-9",
42
+ HDL_CHOLESTEROL_MOLAR = "14646-4",
43
+ LDL_CHOLESTEROL_MASS = "13457-7",
44
+ LDL_CHOLESTEROL_MOLAR = "39469-2",
45
+ TRIGLYCERIDES_MASS = "2571-8",
46
+ TRIGLYCERIDES_MOLAR = "14927-8",
47
+ TOTAL_CHOLESTEROL_HDL_RATIO = "9830-1",
48
+ RESPIRATORY_THERAPY = "respiratory-therapy",
49
+ BABY_SLEEP = "baby-sleep"
38
50
  }
@@ -39,4 +39,16 @@ var ObservationCode;
39
39
  ObservationCode["PHENX_RESPIRATORY"] = "62628-3";
40
40
  ObservationCode["RESTING_HEART_RATE"] = "40443-4";
41
41
  ObservationCode["WALKING_HEART_RATE_AVERAGE"] = "40442-6";
42
+ ObservationCode["LIPID_PANEL"] = "100898-6";
43
+ ObservationCode["TOTAL_CHOLESTEROL_MASS"] = "2093-3";
44
+ ObservationCode["TOTAL_CHOLESTEROL_MOLAR"] = "14647-2";
45
+ ObservationCode["HDL_CHOLESTEROL_MASS"] = "2085-9";
46
+ ObservationCode["HDL_CHOLESTEROL_MOLAR"] = "14646-4";
47
+ ObservationCode["LDL_CHOLESTEROL_MASS"] = "13457-7";
48
+ ObservationCode["LDL_CHOLESTEROL_MOLAR"] = "39469-2";
49
+ ObservationCode["TRIGLYCERIDES_MASS"] = "2571-8";
50
+ ObservationCode["TRIGLYCERIDES_MOLAR"] = "14927-8";
51
+ ObservationCode["TOTAL_CHOLESTEROL_HDL_RATIO"] = "9830-1";
52
+ ObservationCode["RESPIRATORY_THERAPY"] = "respiratory-therapy";
53
+ ObservationCode["BABY_SLEEP"] = "baby-sleep";
42
54
  })(ObservationCode || (exports.ObservationCode = ObservationCode = {}));
@@ -0,0 +1,12 @@
1
+ import { ObservationComponent } from "@medplum/fhirtypes";
2
+ import { MeasurementTypeKey } from "../MeasurementTypeKey";
3
+ import { Measurement } from "./Measurement";
4
+ /**
5
+ * One BabySleep observation, such as a clip sample or a session summary.
6
+ * Core preserves the coded components supplied by the device adapter rather than
7
+ * assigning vendor-specific meaning to sleep states, posture, or device status.
8
+ */
9
+ export type BabySleepMeasurement = Measurement & {
10
+ measurementTypeKey: MeasurementTypeKey.babySleep;
11
+ components: ObservationComponent[];
12
+ };
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,11 @@
1
+ import { MeasurementTypeKey } from "../MeasurementTypeKey";
2
+ import { Measurement } from "./Measurement";
3
+ export type LipidPanelMeasurement = Measurement & {
4
+ measurementTypeKey: MeasurementTypeKey.lipidPanel;
5
+ totalCholesterol?: number;
6
+ hdlCholesterol?: number;
7
+ ldlCholesterol?: number;
8
+ triglycerides?: number;
9
+ totalCholesterolHdlRatio?: number;
10
+ unit: "mg/dL" | "mmol/L";
11
+ };
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,12 @@
1
+ import { ObservationComponent } from "@medplum/fhirtypes";
2
+ import { MeasurementTypeKey } from "../MeasurementTypeKey";
3
+ import { Measurement } from "./Measurement";
4
+ /**
5
+ * A coded set of respiratory-therapy observations. Keeping the values as FHIR components
6
+ * lets devices and consuming applications add their own metrics without Core assigning
7
+ * device-specific meaning to them.
8
+ */
9
+ export type RespiratoryTherapyMeasurement = Measurement & {
10
+ measurementTypeKey: MeasurementTypeKey.respiratoryTherapy;
11
+ components: ObservationComponent[];
12
+ };
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -15,3 +15,6 @@ export * from "./RespiratoryRateMeasurement";
15
15
  export * from "./RestingHeartRateMeasurement";
16
16
  export * from "./Vo2MaxMeasurement";
17
17
  export * from "./WalkingHeartRateAverageMeasurement";
18
+ export * from "./LipidPanelMeasurement";
19
+ export * from "./RespiratoryTherapyMeasurement";
20
+ export * from "./BabySleepMeasurement";
@@ -31,3 +31,6 @@ __exportStar(require("./RespiratoryRateMeasurement"), exports);
31
31
  __exportStar(require("./RestingHeartRateMeasurement"), exports);
32
32
  __exportStar(require("./Vo2MaxMeasurement"), exports);
33
33
  __exportStar(require("./WalkingHeartRateAverageMeasurement"), exports);
34
+ __exportStar(require("./LipidPanelMeasurement"), exports);
35
+ __exportStar(require("./RespiratoryTherapyMeasurement"), exports);
36
+ __exportStar(require("./BabySleepMeasurement"), exports);
@@ -48,7 +48,7 @@ exports.OVOK_CORE_REQUIREMENTS = {
48
48
  description: "The FHIR surface a server must provide for the @ovok/core client library's own methods to function.",
49
49
  software: {
50
50
  name: "@ovok/core",
51
- version: "0.3.22",
51
+ version: "0.3.24",
52
52
  },
53
53
  fhirVersion: "4.0.1",
54
54
  format: ["json"],
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ovok/core",
3
- "version": "0.3.22",
3
+ "version": "0.3.24",
4
4
  "private": false,
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",