@erosolaraijs/cure 1.0.0

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 (46) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +120 -0
  3. package/dist/bin/cure.d.ts +10 -0
  4. package/dist/bin/cure.d.ts.map +1 -0
  5. package/dist/bin/cure.js +169 -0
  6. package/dist/bin/cure.js.map +1 -0
  7. package/dist/capabilities/cancerTreatmentCapability.d.ts +167 -0
  8. package/dist/capabilities/cancerTreatmentCapability.d.ts.map +1 -0
  9. package/dist/capabilities/cancerTreatmentCapability.js +912 -0
  10. package/dist/capabilities/cancerTreatmentCapability.js.map +1 -0
  11. package/dist/capabilities/index.d.ts +2 -0
  12. package/dist/capabilities/index.d.ts.map +1 -0
  13. package/dist/capabilities/index.js +3 -0
  14. package/dist/capabilities/index.js.map +1 -0
  15. package/dist/compliance/hipaa.d.ts +337 -0
  16. package/dist/compliance/hipaa.d.ts.map +1 -0
  17. package/dist/compliance/hipaa.js +929 -0
  18. package/dist/compliance/hipaa.js.map +1 -0
  19. package/dist/examples/cancerTreatmentDemo.d.ts +21 -0
  20. package/dist/examples/cancerTreatmentDemo.d.ts.map +1 -0
  21. package/dist/examples/cancerTreatmentDemo.js +216 -0
  22. package/dist/examples/cancerTreatmentDemo.js.map +1 -0
  23. package/dist/integrations/clinicalTrials/clinicalTrialsGov.d.ts +265 -0
  24. package/dist/integrations/clinicalTrials/clinicalTrialsGov.d.ts.map +1 -0
  25. package/dist/integrations/clinicalTrials/clinicalTrialsGov.js +808 -0
  26. package/dist/integrations/clinicalTrials/clinicalTrialsGov.js.map +1 -0
  27. package/dist/integrations/ehr/fhir.d.ts +455 -0
  28. package/dist/integrations/ehr/fhir.d.ts.map +1 -0
  29. package/dist/integrations/ehr/fhir.js +859 -0
  30. package/dist/integrations/ehr/fhir.js.map +1 -0
  31. package/dist/integrations/genomics/genomicPlatforms.d.ts +362 -0
  32. package/dist/integrations/genomics/genomicPlatforms.d.ts.map +1 -0
  33. package/dist/integrations/genomics/genomicPlatforms.js +1079 -0
  34. package/dist/integrations/genomics/genomicPlatforms.js.map +1 -0
  35. package/package.json +52 -0
  36. package/src/bin/cure.ts +182 -0
  37. package/src/capabilities/cancerTreatmentCapability.ts +1161 -0
  38. package/src/capabilities/index.ts +2 -0
  39. package/src/compliance/hipaa.ts +1365 -0
  40. package/src/examples/cancerTreatmentDemo.ts +241 -0
  41. package/src/integrations/clinicalTrials/clinicalTrialsGov.ts +1143 -0
  42. package/src/integrations/ehr/fhir.ts +1304 -0
  43. package/src/integrations/genomics/genomicPlatforms.ts +1480 -0
  44. package/src/ml/outcomePredictor.ts +1301 -0
  45. package/src/safety/drugInteractions.ts +942 -0
  46. package/src/validation/retrospectiveValidator.ts +887 -0
@@ -0,0 +1,942 @@
1
+ /**
2
+ * Drug Interaction and Safety Checking System
3
+ *
4
+ * Provides comprehensive drug safety checks:
5
+ * - Drug-drug interactions
6
+ * - Contraindication checking
7
+ * - Dosing validation
8
+ * - Allergy cross-reactivity
9
+ * - Organ function-based adjustments
10
+ * - Pregnancy/lactation safety
11
+ * - QT prolongation risk assessment
12
+ * - CYP450 interaction analysis
13
+ *
14
+ * Data sources would include:
15
+ * - FDA drug labels
16
+ * - DrugBank
17
+ * - PharmGKB
18
+ * - Clinical Pharmacology databases
19
+ */
20
+
21
+ import { EventEmitter } from 'events';
22
+
23
+ // ═══════════════════════════════════════════════════════════════════════════════
24
+ // DRUG INTERACTION TYPES
25
+ // ═══════════════════════════════════════════════════════════════════════════════
26
+
27
+ export interface Drug {
28
+ name: string;
29
+ genericName: string;
30
+ brandNames?: string[];
31
+ drugClass: string;
32
+ rxNormId?: string;
33
+ ndc?: string;
34
+ atcCode?: string;
35
+ mechanism?: string;
36
+ metabolism?: {
37
+ cyp450?: CYP450Profile;
38
+ renalExcretion?: number; // percentage
39
+ hepaticMetabolism?: number;
40
+ };
41
+ }
42
+
43
+ export interface CYP450Profile {
44
+ substrates?: string[]; // CYP enzymes this drug is metabolized by
45
+ inhibitors?: string[]; // CYP enzymes this drug inhibits
46
+ inducers?: string[]; // CYP enzymes this drug induces
47
+ }
48
+
49
+ export interface DrugInteraction {
50
+ drug1: string;
51
+ drug2: string;
52
+ severity: 'contraindicated' | 'major' | 'moderate' | 'minor';
53
+ type: 'pharmacokinetic' | 'pharmacodynamic' | 'additive' | 'synergistic' | 'antagonistic';
54
+ mechanism: string;
55
+ clinicalEffect: string;
56
+ management: string;
57
+ documentation: 'established' | 'theoretical' | 'case-report';
58
+ references?: string[];
59
+ }
60
+
61
+ export interface Contraindication {
62
+ drug: string;
63
+ condition: string;
64
+ severity: 'absolute' | 'relative';
65
+ reason: string;
66
+ alternatives?: string[];
67
+ }
68
+
69
+ export interface DosingGuideline {
70
+ drug: string;
71
+ indication: string;
72
+ standardDose: string;
73
+ renalAdjustment?: {
74
+ gfrThreshold: number;
75
+ adjustment: string;
76
+ }[];
77
+ hepaticAdjustment?: {
78
+ childPughClass: 'A' | 'B' | 'C';
79
+ adjustment: string;
80
+ }[];
81
+ ageAdjustment?: {
82
+ ageThreshold: number;
83
+ adjustment: string;
84
+ }[];
85
+ weightBasedDosing?: {
86
+ formula: string;
87
+ maxDose?: string;
88
+ };
89
+ }
90
+
91
+ export interface AllergyCheck {
92
+ reportedAllergy: string;
93
+ drugToCheck: string;
94
+ crossReactivity: boolean;
95
+ riskLevel: 'high' | 'moderate' | 'low' | 'none';
96
+ relatedAllergens: string[];
97
+ recommendation: string;
98
+ }
99
+
100
+ export interface SafetyAlert {
101
+ id: string;
102
+ type: 'interaction' | 'contraindication' | 'allergy' | 'dosing' | 'organ-function' | 'pregnancy' | 'qt-prolongation' | 'black-box';
103
+ severity: 'critical' | 'high' | 'moderate' | 'low';
104
+ title: string;
105
+ description: string;
106
+ affectedDrugs: string[];
107
+ recommendation: string;
108
+ overridable: boolean;
109
+ requiresDocumentation: boolean;
110
+ references?: string[];
111
+ }
112
+
113
+ export interface PatientSafetyProfile {
114
+ patientId: string;
115
+ allergies: {
116
+ allergen: string;
117
+ reactionType: 'anaphylaxis' | 'rash' | 'angioedema' | 'gi' | 'other';
118
+ severity: 'severe' | 'moderate' | 'mild';
119
+ }[];
120
+ renalFunction: {
121
+ gfr: number;
122
+ creatinine: number;
123
+ dialysis: boolean;
124
+ };
125
+ hepaticFunction: {
126
+ childPughClass?: 'A' | 'B' | 'C';
127
+ bilirubin?: number;
128
+ albumin?: number;
129
+ inr?: number;
130
+ ascites?: 'none' | 'mild' | 'moderate-severe';
131
+ encephalopathy?: 'none' | 'grade-1-2' | 'grade-3-4';
132
+ };
133
+ cardiacStatus: {
134
+ qtcInterval?: number;
135
+ lvef?: number;
136
+ arrhythmiaHistory?: boolean;
137
+ pacemakerIcd?: boolean;
138
+ };
139
+ currentMedications: {
140
+ drug: string;
141
+ dose: string;
142
+ frequency: string;
143
+ startDate?: Date;
144
+ }[];
145
+ demographics: {
146
+ age: number;
147
+ weight: number;
148
+ gender: 'male' | 'female';
149
+ pregnant?: boolean;
150
+ breastfeeding?: boolean;
151
+ };
152
+ geneticFactors?: {
153
+ cyp2d6?: 'poor' | 'intermediate' | 'normal' | 'rapid' | 'ultra-rapid';
154
+ cyp2c19?: 'poor' | 'intermediate' | 'normal' | 'rapid' | 'ultra-rapid';
155
+ dpyd?: 'deficient' | 'intermediate' | 'normal';
156
+ ugt1a1?: '*28/*28' | '*28/*1' | '*1/*1';
157
+ tpmt?: 'poor' | 'intermediate' | 'normal';
158
+ };
159
+ }
160
+
161
+ // ═══════════════════════════════════════════════════════════════════════════════
162
+ // DRUG SAFETY SERVICE
163
+ // ═══════════════════════════════════════════════════════════════════════════════
164
+
165
+ export class DrugSafetyService extends EventEmitter {
166
+ private interactionDatabase: Map<string, DrugInteraction[]> = new Map();
167
+ private contraindicationDatabase: Map<string, Contraindication[]> = new Map();
168
+ private dosingGuidelines: Map<string, DosingGuideline[]> = new Map();
169
+ private allergenCrossReactivity: Map<string, string[]> = new Map();
170
+ private qtProlongingDrugs: Set<string> = new Set();
171
+ private blackBoxWarnings: Map<string, string[]> = new Map();
172
+
173
+ constructor() {
174
+ super();
175
+ this.initializeDatabases();
176
+ }
177
+
178
+ /**
179
+ * Perform comprehensive safety check
180
+ */
181
+ async performSafetyCheck(
182
+ patient: PatientSafetyProfile,
183
+ proposedDrugs: { drug: string; dose: string; route: string }[]
184
+ ): Promise<{
185
+ safe: boolean;
186
+ alerts: SafetyAlert[];
187
+ summary: {
188
+ criticalAlerts: number;
189
+ highAlerts: number;
190
+ moderateAlerts: number;
191
+ lowAlerts: number;
192
+ overallRisk: 'critical' | 'high' | 'moderate' | 'low' | 'minimal';
193
+ };
194
+ recommendations: string[];
195
+ }> {
196
+ const alerts: SafetyAlert[] = [];
197
+ const recommendations: string[] = [];
198
+
199
+ // Get all drugs (current + proposed)
200
+ const allDrugs = [
201
+ ...patient.currentMedications.map(m => m.drug),
202
+ ...proposedDrugs.map(d => d.drug)
203
+ ];
204
+
205
+ // 1. Check drug-drug interactions
206
+ const interactionAlerts = await this.checkDrugInteractions(allDrugs);
207
+ alerts.push(...interactionAlerts);
208
+
209
+ // 2. Check contraindications based on patient conditions
210
+ const contraindicationAlerts = await this.checkContraindications(proposedDrugs.map(d => d.drug), patient);
211
+ alerts.push(...contraindicationAlerts);
212
+
213
+ // 3. Check allergies and cross-reactivity
214
+ const allergyAlerts = await this.checkAllergies(proposedDrugs.map(d => d.drug), patient.allergies);
215
+ alerts.push(...allergyAlerts);
216
+
217
+ // 4. Check dosing based on organ function
218
+ const dosingAlerts = await this.checkDosing(proposedDrugs, patient);
219
+ alerts.push(...dosingAlerts);
220
+
221
+ // 5. Check QT prolongation risk
222
+ const qtAlerts = await this.checkQTProlongation(allDrugs, patient);
223
+ alerts.push(...qtAlerts);
224
+
225
+ // 6. Check pregnancy/lactation
226
+ if (patient.demographics.pregnant || patient.demographics.breastfeeding) {
227
+ const pregnancyAlerts = await this.checkPregnancySafety(proposedDrugs.map(d => d.drug), patient);
228
+ alerts.push(...pregnancyAlerts);
229
+ }
230
+
231
+ // 7. Check black box warnings
232
+ const blackBoxAlerts = await this.checkBlackBoxWarnings(proposedDrugs.map(d => d.drug));
233
+ alerts.push(...blackBoxAlerts);
234
+
235
+ // 8. Check pharmacogenomic considerations
236
+ if (patient.geneticFactors) {
237
+ const pgxAlerts = await this.checkPharmacogenomics(proposedDrugs.map(d => d.drug), patient.geneticFactors);
238
+ alerts.push(...pgxAlerts);
239
+ }
240
+
241
+ // Count alerts by severity
242
+ const criticalAlerts = alerts.filter(a => a.severity === 'critical').length;
243
+ const highAlerts = alerts.filter(a => a.severity === 'high').length;
244
+ const moderateAlerts = alerts.filter(a => a.severity === 'moderate').length;
245
+ const lowAlerts = alerts.filter(a => a.severity === 'low').length;
246
+
247
+ // Determine overall risk
248
+ let overallRisk: 'critical' | 'high' | 'moderate' | 'low' | 'minimal';
249
+ if (criticalAlerts > 0) overallRisk = 'critical';
250
+ else if (highAlerts > 0) overallRisk = 'high';
251
+ else if (moderateAlerts > 0) overallRisk = 'moderate';
252
+ else if (lowAlerts > 0) overallRisk = 'low';
253
+ else overallRisk = 'minimal';
254
+
255
+ // Generate recommendations
256
+ for (const alert of alerts.filter(a => a.severity === 'critical' || a.severity === 'high')) {
257
+ recommendations.push(alert.recommendation);
258
+ }
259
+
260
+ // Determine if safe to proceed
261
+ const safe = criticalAlerts === 0 && !alerts.some(a => !a.overridable);
262
+
263
+ // Emit event
264
+ this.emit('safety-check-completed', { patientId: patient.patientId, safe, alertCount: alerts.length });
265
+
266
+ return {
267
+ safe,
268
+ alerts: alerts.sort((a, b) => {
269
+ const severityOrder = { critical: 0, high: 1, moderate: 2, low: 3 };
270
+ return severityOrder[a.severity] - severityOrder[b.severity];
271
+ }),
272
+ summary: {
273
+ criticalAlerts,
274
+ highAlerts,
275
+ moderateAlerts,
276
+ lowAlerts,
277
+ overallRisk
278
+ },
279
+ recommendations
280
+ };
281
+ }
282
+
283
+ /**
284
+ * Check drug-drug interactions
285
+ */
286
+ async checkDrugInteractions(drugs: string[]): Promise<SafetyAlert[]> {
287
+ const alerts: SafetyAlert[] = [];
288
+ const checkedPairs = new Set<string>();
289
+
290
+ for (let i = 0; i < drugs.length; i++) {
291
+ for (let j = i + 1; j < drugs.length; j++) {
292
+ const drug1 = drugs[i].toLowerCase();
293
+ const drug2 = drugs[j].toLowerCase();
294
+ const pairKey = [drug1, drug2].sort().join('|');
295
+
296
+ if (checkedPairs.has(pairKey)) continue;
297
+ checkedPairs.add(pairKey);
298
+
299
+ const interaction = this.findInteraction(drug1, drug2);
300
+ if (interaction) {
301
+ alerts.push({
302
+ id: `DDI-${Date.now()}-${i}-${j}`,
303
+ type: 'interaction',
304
+ severity: this.mapInteractionSeverity(interaction.severity),
305
+ title: `Drug Interaction: ${drugs[i]} + ${drugs[j]}`,
306
+ description: interaction.clinicalEffect,
307
+ affectedDrugs: [drugs[i], drugs[j]],
308
+ recommendation: interaction.management,
309
+ overridable: interaction.severity !== 'contraindicated',
310
+ requiresDocumentation: interaction.severity === 'major' || interaction.severity === 'contraindicated',
311
+ references: interaction.references
312
+ });
313
+ }
314
+ }
315
+ }
316
+
317
+ return alerts;
318
+ }
319
+
320
+ /**
321
+ * Check contraindications
322
+ */
323
+ async checkContraindications(drugs: string[], patient: PatientSafetyProfile): Promise<SafetyAlert[]> {
324
+ const alerts: SafetyAlert[] = [];
325
+
326
+ // Check renal contraindications
327
+ if (patient.renalFunction.gfr < 30) {
328
+ const renalContraindicated = ['metformin', 'nsaids', 'lithium', 'gadolinium'];
329
+ for (const drug of drugs) {
330
+ if (renalContraindicated.some(c => drug.toLowerCase().includes(c))) {
331
+ alerts.push({
332
+ id: `CI-RENAL-${Date.now()}`,
333
+ type: 'contraindication',
334
+ severity: patient.renalFunction.gfr < 15 ? 'critical' : 'high',
335
+ title: `Renal Contraindication: ${drug}`,
336
+ description: `${drug} is contraindicated or requires significant dose adjustment with GFR ${patient.renalFunction.gfr} mL/min`,
337
+ affectedDrugs: [drug],
338
+ recommendation: `Consider alternative therapy or significant dose reduction. Consult nephrology if essential.`,
339
+ overridable: patient.renalFunction.gfr >= 15,
340
+ requiresDocumentation: true
341
+ });
342
+ }
343
+ }
344
+ }
345
+
346
+ // Check hepatic contraindications
347
+ if (patient.hepaticFunction.childPughClass === 'C') {
348
+ const hepaticContraindicated = ['methotrexate', 'valproic-acid', 'isoniazid', 'ketoconazole'];
349
+ for (const drug of drugs) {
350
+ if (hepaticContraindicated.some(c => drug.toLowerCase().includes(c))) {
351
+ alerts.push({
352
+ id: `CI-HEPATIC-${Date.now()}`,
353
+ type: 'contraindication',
354
+ severity: 'critical',
355
+ title: `Hepatic Contraindication: ${drug}`,
356
+ description: `${drug} is contraindicated in Child-Pugh Class C liver disease`,
357
+ affectedDrugs: [drug],
358
+ recommendation: `Avoid use. Consider alternative therapy.`,
359
+ overridable: false,
360
+ requiresDocumentation: true
361
+ });
362
+ }
363
+ }
364
+ }
365
+
366
+ // Check cardiac contraindications
367
+ if (patient.cardiacStatus.lvef && patient.cardiacStatus.lvef < 40) {
368
+ const cardiacCaution = ['anthracycline', 'trastuzumab', 'sunitinib', 'sorafenib'];
369
+ for (const drug of drugs) {
370
+ if (cardiacCaution.some(c => drug.toLowerCase().includes(c))) {
371
+ alerts.push({
372
+ id: `CI-CARDIAC-${Date.now()}`,
373
+ type: 'contraindication',
374
+ severity: 'high',
375
+ title: `Cardiac Caution: ${drug}`,
376
+ description: `${drug} has cardiotoxicity risk. Patient LVEF is ${patient.cardiacStatus.lvef}%`,
377
+ affectedDrugs: [drug],
378
+ recommendation: `Baseline and serial cardiac monitoring required. Consider cardiology consultation.`,
379
+ overridable: true,
380
+ requiresDocumentation: true
381
+ });
382
+ }
383
+ }
384
+ }
385
+
386
+ return alerts;
387
+ }
388
+
389
+ /**
390
+ * Check allergy cross-reactivity
391
+ */
392
+ async checkAllergies(drugs: string[], allergies: PatientSafetyProfile['allergies']): Promise<SafetyAlert[]> {
393
+ const alerts: SafetyAlert[] = [];
394
+
395
+ for (const allergy of allergies) {
396
+ for (const drug of drugs) {
397
+ const crossReactivity = this.checkCrossReactivity(allergy.allergen, drug);
398
+
399
+ if (crossReactivity.crossReactivity) {
400
+ const severity = allergy.severity === 'severe' && crossReactivity.riskLevel === 'high'
401
+ ? 'critical'
402
+ : allergy.severity === 'severe' || crossReactivity.riskLevel === 'high'
403
+ ? 'high'
404
+ : 'moderate';
405
+
406
+ alerts.push({
407
+ id: `ALLERGY-${Date.now()}`,
408
+ type: 'allergy',
409
+ severity,
410
+ title: `Allergy Alert: ${drug}`,
411
+ description: `Patient allergic to ${allergy.allergen}. ${drug} has ${crossReactivity.riskLevel} cross-reactivity risk.`,
412
+ affectedDrugs: [drug],
413
+ recommendation: crossReactivity.recommendation,
414
+ overridable: allergy.severity !== 'severe' || crossReactivity.riskLevel !== 'high',
415
+ requiresDocumentation: true
416
+ });
417
+ }
418
+ }
419
+ }
420
+
421
+ return alerts;
422
+ }
423
+
424
+ /**
425
+ * Check dosing based on organ function
426
+ */
427
+ async checkDosing(
428
+ drugs: { drug: string; dose: string; route: string }[],
429
+ patient: PatientSafetyProfile
430
+ ): Promise<SafetyAlert[]> {
431
+ const alerts: SafetyAlert[] = [];
432
+
433
+ for (const drugOrder of drugs) {
434
+ const guidelines = this.dosingGuidelines.get(drugOrder.drug.toLowerCase());
435
+ if (!guidelines) continue;
436
+
437
+ for (const guideline of guidelines) {
438
+ // Check renal adjustment
439
+ if (guideline.renalAdjustment) {
440
+ for (const adj of guideline.renalAdjustment) {
441
+ if (patient.renalFunction.gfr < adj.gfrThreshold) {
442
+ alerts.push({
443
+ id: `DOSE-RENAL-${Date.now()}`,
444
+ type: 'dosing',
445
+ severity: 'moderate',
446
+ title: `Dose Adjustment Required: ${drugOrder.drug}`,
447
+ description: `Patient GFR ${patient.renalFunction.gfr} requires dose adjustment`,
448
+ affectedDrugs: [drugOrder.drug],
449
+ recommendation: adj.adjustment,
450
+ overridable: true,
451
+ requiresDocumentation: true
452
+ });
453
+ break;
454
+ }
455
+ }
456
+ }
457
+
458
+ // Check hepatic adjustment
459
+ if (guideline.hepaticAdjustment && patient.hepaticFunction.childPughClass) {
460
+ const adj = guideline.hepaticAdjustment.find(a => a.childPughClass === patient.hepaticFunction.childPughClass);
461
+ if (adj) {
462
+ alerts.push({
463
+ id: `DOSE-HEPATIC-${Date.now()}`,
464
+ type: 'dosing',
465
+ severity: patient.hepaticFunction.childPughClass === 'C' ? 'high' : 'moderate',
466
+ title: `Hepatic Dose Adjustment: ${drugOrder.drug}`,
467
+ description: `Child-Pugh Class ${patient.hepaticFunction.childPughClass} requires dose adjustment`,
468
+ affectedDrugs: [drugOrder.drug],
469
+ recommendation: adj.adjustment,
470
+ overridable: patient.hepaticFunction.childPughClass !== 'C',
471
+ requiresDocumentation: true
472
+ });
473
+ }
474
+ }
475
+
476
+ // Check age-based adjustment
477
+ if (guideline.ageAdjustment) {
478
+ for (const adj of guideline.ageAdjustment) {
479
+ if (patient.demographics.age >= adj.ageThreshold) {
480
+ alerts.push({
481
+ id: `DOSE-AGE-${Date.now()}`,
482
+ type: 'dosing',
483
+ severity: 'low',
484
+ title: `Age-Based Consideration: ${drugOrder.drug}`,
485
+ description: `Patient age ${patient.demographics.age} may require adjustment`,
486
+ affectedDrugs: [drugOrder.drug],
487
+ recommendation: adj.adjustment,
488
+ overridable: true,
489
+ requiresDocumentation: false
490
+ });
491
+ break;
492
+ }
493
+ }
494
+ }
495
+ }
496
+ }
497
+
498
+ return alerts;
499
+ }
500
+
501
+ /**
502
+ * Check QT prolongation risk
503
+ */
504
+ async checkQTProlongation(drugs: string[], patient: PatientSafetyProfile): Promise<SafetyAlert[]> {
505
+ const alerts: SafetyAlert[] = [];
506
+ const qtDrugs = drugs.filter(d => this.qtProlongingDrugs.has(d.toLowerCase()));
507
+
508
+ if (qtDrugs.length > 0) {
509
+ // Check baseline QTc
510
+ const baselineQTc = patient.cardiacStatus.qtcInterval;
511
+ let riskLevel: 'critical' | 'high' | 'moderate' | 'low' = 'moderate';
512
+
513
+ if (baselineQTc && baselineQTc > 500) {
514
+ riskLevel = 'critical';
515
+ } else if (baselineQTc && baselineQTc > 470) {
516
+ riskLevel = 'high';
517
+ } else if (qtDrugs.length >= 2) {
518
+ riskLevel = 'high';
519
+ }
520
+
521
+ // Check for additional risk factors
522
+ const riskFactors: string[] = [];
523
+ if (patient.demographics.gender === 'female') riskFactors.push('Female gender');
524
+ if (patient.demographics.age > 65) riskFactors.push('Age > 65');
525
+ if (patient.cardiacStatus.arrhythmiaHistory) riskFactors.push('Arrhythmia history');
526
+ // Would also check electrolytes (K, Mg) if available
527
+
528
+ if (qtDrugs.length >= 2 || riskLevel === 'critical' || riskLevel === 'high') {
529
+ alerts.push({
530
+ id: `QT-${Date.now()}`,
531
+ type: 'qt-prolongation',
532
+ severity: riskLevel,
533
+ title: `QT Prolongation Risk: ${qtDrugs.join(', ')}`,
534
+ description: `${qtDrugs.length} QT-prolonging drug(s) ordered. ${riskFactors.length > 0 ? 'Risk factors: ' + riskFactors.join(', ') : ''}`,
535
+ affectedDrugs: qtDrugs,
536
+ recommendation: `Monitor QTc. Consider ECG at baseline and after steady state. Avoid if QTc > 500ms.`,
537
+ overridable: riskLevel !== 'critical',
538
+ requiresDocumentation: true
539
+ });
540
+ }
541
+ }
542
+
543
+ return alerts;
544
+ }
545
+
546
+ /**
547
+ * Check pregnancy and lactation safety
548
+ */
549
+ async checkPregnancySafety(
550
+ drugs: string[],
551
+ patient: PatientSafetyProfile
552
+ ): Promise<SafetyAlert[]> {
553
+ const alerts: SafetyAlert[] = [];
554
+
555
+ // Known teratogenic drugs
556
+ const categoryX: string[] = [
557
+ 'methotrexate', 'thalidomide', 'lenalidomide', 'pomalidomide',
558
+ 'isotretinoin', 'warfarin', 'ribavirin', 'leflunomide'
559
+ ];
560
+
561
+ const categoryD: string[] = [
562
+ 'doxorubicin', 'cyclophosphamide', 'imatinib', 'tamoxifen',
563
+ 'carbamazepine', 'phenytoin', 'valproic acid', 'lithium'
564
+ ];
565
+
566
+ for (const drug of drugs) {
567
+ const drugLower = drug.toLowerCase();
568
+
569
+ if (categoryX.some(x => drugLower.includes(x))) {
570
+ alerts.push({
571
+ id: `PREG-X-${Date.now()}`,
572
+ type: 'pregnancy',
573
+ severity: 'critical',
574
+ title: `Pregnancy Contraindication: ${drug}`,
575
+ description: `${drug} is absolutely contraindicated in pregnancy (Category X equivalent)`,
576
+ affectedDrugs: [drug],
577
+ recommendation: `Do not use. Use alternative therapy. Ensure contraception.`,
578
+ overridable: false,
579
+ requiresDocumentation: true
580
+ });
581
+ } else if (categoryD.some(d => drugLower.includes(d))) {
582
+ alerts.push({
583
+ id: `PREG-D-${Date.now()}`,
584
+ type: 'pregnancy',
585
+ severity: 'high',
586
+ title: `Pregnancy Risk: ${drug}`,
587
+ description: `${drug} has evidence of fetal risk but may be used if benefit outweighs risk`,
588
+ affectedDrugs: [drug],
589
+ recommendation: `Document informed consent. Discuss risks with patient. Consider alternatives.`,
590
+ overridable: true,
591
+ requiresDocumentation: true
592
+ });
593
+ }
594
+ }
595
+
596
+ return alerts;
597
+ }
598
+
599
+ /**
600
+ * Check black box warnings
601
+ */
602
+ async checkBlackBoxWarnings(drugs: string[]): Promise<SafetyAlert[]> {
603
+ const alerts: SafetyAlert[] = [];
604
+
605
+ for (const drug of drugs) {
606
+ const warnings = this.blackBoxWarnings.get(drug.toLowerCase());
607
+ if (warnings && warnings.length > 0) {
608
+ alerts.push({
609
+ id: `BBW-${Date.now()}`,
610
+ type: 'black-box',
611
+ severity: 'high',
612
+ title: `Black Box Warning: ${drug}`,
613
+ description: warnings.join('; '),
614
+ affectedDrugs: [drug],
615
+ recommendation: `Ensure appropriate monitoring and patient education. Document informed consent.`,
616
+ overridable: true,
617
+ requiresDocumentation: true
618
+ });
619
+ }
620
+ }
621
+
622
+ return alerts;
623
+ }
624
+
625
+ /**
626
+ * Check pharmacogenomic considerations
627
+ */
628
+ async checkPharmacogenomics(
629
+ drugs: string[],
630
+ genetics: NonNullable<PatientSafetyProfile['geneticFactors']>
631
+ ): Promise<SafetyAlert[]> {
632
+ const alerts: SafetyAlert[] = [];
633
+
634
+ // DPYD and fluoropyrimidines
635
+ if (genetics.dpyd && genetics.dpyd !== 'normal') {
636
+ const fluoropyrimidines = ['5-fu', 'fluorouracil', 'capecitabine'];
637
+ const affected = drugs.filter(d => fluoropyrimidines.some(f => d.toLowerCase().includes(f)));
638
+
639
+ if (affected.length > 0) {
640
+ const severity = genetics.dpyd === 'deficient' ? 'critical' : 'high';
641
+ alerts.push({
642
+ id: `PGX-DPYD-${Date.now()}`,
643
+ type: 'organ-function',
644
+ severity,
645
+ title: `DPYD Deficiency: ${affected.join(', ')}`,
646
+ description: `Patient is DPYD ${genetics.dpyd}. High risk of severe/fatal toxicity with fluoropyrimidines.`,
647
+ affectedDrugs: affected,
648
+ recommendation: genetics.dpyd === 'deficient'
649
+ ? 'Contraindicated. Use alternative therapy.'
650
+ : 'Reduce dose by 50%. Consider alternative.',
651
+ overridable: genetics.dpyd !== 'deficient',
652
+ requiresDocumentation: true
653
+ });
654
+ }
655
+ }
656
+
657
+ // UGT1A1 and irinotecan
658
+ if (genetics.ugt1a1 === '*28/*28') {
659
+ const irinotecan = drugs.filter(d => d.toLowerCase().includes('irinotecan'));
660
+ if (irinotecan.length > 0) {
661
+ alerts.push({
662
+ id: `PGX-UGT1A1-${Date.now()}`,
663
+ type: 'organ-function',
664
+ severity: 'high',
665
+ title: `UGT1A1 Polymorphism: Irinotecan`,
666
+ description: `Patient is UGT1A1*28/*28. Increased risk of severe neutropenia and diarrhea.`,
667
+ affectedDrugs: irinotecan,
668
+ recommendation: `Reduce initial dose by 1 level. Monitor closely.`,
669
+ overridable: true,
670
+ requiresDocumentation: true
671
+ });
672
+ }
673
+ }
674
+
675
+ // TPMT and thiopurines
676
+ if (genetics.tpmt && genetics.tpmt !== 'normal') {
677
+ const thiopurines = ['azathioprine', '6-mercaptopurine', 'thioguanine'];
678
+ const affected = drugs.filter(d => thiopurines.some(t => d.toLowerCase().includes(t)));
679
+
680
+ if (affected.length > 0) {
681
+ const severity = genetics.tpmt === 'poor' ? 'critical' : 'high';
682
+ alerts.push({
683
+ id: `PGX-TPMT-${Date.now()}`,
684
+ type: 'organ-function',
685
+ severity,
686
+ title: `TPMT Deficiency: ${affected.join(', ')}`,
687
+ description: `Patient is TPMT ${genetics.tpmt} metabolizer. Risk of severe myelosuppression.`,
688
+ affectedDrugs: affected,
689
+ recommendation: genetics.tpmt === 'poor'
690
+ ? 'Reduce dose by 90% or use alternative.'
691
+ : 'Reduce dose by 50%. Monitor CBC closely.',
692
+ overridable: genetics.tpmt !== 'poor',
693
+ requiresDocumentation: true
694
+ });
695
+ }
696
+ }
697
+
698
+ return alerts;
699
+ }
700
+
701
+ /**
702
+ * Get recommended alternatives for a contraindicated drug
703
+ */
704
+ getAlternatives(drug: string, reason: string, patientProfile: PatientSafetyProfile): string[] {
705
+ const alternatives: string[] = [];
706
+
707
+ // Drug class-based alternatives
708
+ const alternativeMap: Record<string, string[]> = {
709
+ // Chemotherapy
710
+ 'cisplatin': ['carboplatin', 'oxaliplatin'],
711
+ 'doxorubicin': ['liposomal doxorubicin', 'epirubicin'],
712
+ 'ifosfamide': ['cyclophosphamide'],
713
+
714
+ // Targeted therapy
715
+ 'osimertinib': ['afatinib', 'erlotinib', 'gefitinib'],
716
+ 'alectinib': ['brigatinib', 'lorlatinib', 'crizotinib'],
717
+
718
+ // Immunotherapy (generally fewer direct alternatives)
719
+ 'pembrolizumab': ['nivolumab', 'atezolizumab'],
720
+ 'nivolumab': ['pembrolizumab', 'atezolizumab'],
721
+
722
+ // Supportive care
723
+ 'ondansetron': ['granisetron', 'palonosetron'],
724
+ 'metoclopramide': ['prochlorperazine', 'promethazine']
725
+ };
726
+
727
+ const drugLower = drug.toLowerCase();
728
+ for (const [key, alts] of Object.entries(alternativeMap)) {
729
+ if (drugLower.includes(key)) {
730
+ alternatives.push(...alts);
731
+ break;
732
+ }
733
+ }
734
+
735
+ // Filter alternatives based on patient's contraindications
736
+ return alternatives.filter(alt => {
737
+ const interaction = this.findInteraction(alt, drug);
738
+ if (interaction?.severity === 'contraindicated') return false;
739
+ return true;
740
+ });
741
+ }
742
+
743
+ // ═══════════════════════════════════════════════════════════════════════════════
744
+ // HELPER METHODS
745
+ // ═══════════════════════════════════════════════════════════════════════════════
746
+
747
+ private initializeDatabases(): void {
748
+ // Initialize drug interactions (simplified - production would have comprehensive database)
749
+ this.addInteraction({
750
+ drug1: 'pembrolizumab',
751
+ drug2: 'corticosteroids',
752
+ severity: 'moderate',
753
+ type: 'pharmacodynamic',
754
+ mechanism: 'High-dose corticosteroids may reduce immunotherapy efficacy',
755
+ clinicalEffect: 'Reduced antitumor immune response',
756
+ management: 'Use lowest effective steroid dose. Consider steroid-sparing agents for irAE management.',
757
+ documentation: 'established'
758
+ });
759
+
760
+ this.addInteraction({
761
+ drug1: 'warfarin',
762
+ drug2: 'capecitabine',
763
+ severity: 'major',
764
+ type: 'pharmacokinetic',
765
+ mechanism: 'Capecitabine inhibits CYP2C9, increasing warfarin effect',
766
+ clinicalEffect: 'Increased INR and bleeding risk',
767
+ management: 'Monitor INR closely. Consider LMWH alternative.',
768
+ documentation: 'established'
769
+ });
770
+
771
+ this.addInteraction({
772
+ drug1: 'osimertinib',
773
+ drug2: 'strong cyp3a4 inducers',
774
+ severity: 'major',
775
+ type: 'pharmacokinetic',
776
+ mechanism: 'CYP3A4 inducers decrease osimertinib exposure',
777
+ clinicalEffect: 'Reduced efficacy',
778
+ management: 'Avoid concomitant use with strong CYP3A4 inducers',
779
+ documentation: 'established'
780
+ });
781
+
782
+ // Initialize QT-prolonging drugs
783
+ const qtDrugs = [
784
+ 'ondansetron', 'granisetron', 'haloperidol', 'droperidol',
785
+ 'methadone', 'sotalol', 'amiodarone', 'dofetilide',
786
+ 'ibutilide', 'quinidine', 'procainamide', 'disopyramide',
787
+ 'arsenic trioxide', 'crizotinib', 'lapatinib', 'nilotinib',
788
+ 'pazopanib', 'sunitinib', 'vandetanib', 'vemurafenib'
789
+ ];
790
+ qtDrugs.forEach(d => this.qtProlongingDrugs.add(d.toLowerCase()));
791
+
792
+ // Initialize black box warnings
793
+ this.blackBoxWarnings.set('pembrolizumab', [
794
+ 'Immune-mediated adverse reactions can be severe and fatal',
795
+ 'Monitor for immune-mediated pneumonitis, colitis, hepatitis, endocrinopathies, nephritis, and dermatologic reactions'
796
+ ]);
797
+
798
+ this.blackBoxWarnings.set('trastuzumab', [
799
+ 'Cardiomyopathy: Evaluate LVEF prior to and during treatment',
800
+ 'Infusion reactions including fatal cases'
801
+ ]);
802
+
803
+ this.blackBoxWarnings.set('bevacizumab', [
804
+ 'Gastrointestinal perforation',
805
+ 'Surgery and wound healing complications',
806
+ 'Hemorrhage'
807
+ ]);
808
+
809
+ // Initialize allergy cross-reactivity
810
+ this.allergenCrossReactivity.set('penicillin', ['amoxicillin', 'ampicillin', 'piperacillin', 'cephalosporins']);
811
+ this.allergenCrossReactivity.set('sulfa', ['sulfamethoxazole', 'sulfasalazine', 'celecoxib', 'furosemide']);
812
+ this.allergenCrossReactivity.set('platinum', ['cisplatin', 'carboplatin', 'oxaliplatin']);
813
+
814
+ // Initialize dosing guidelines
815
+ this.dosingGuidelines.set('carboplatin', [{
816
+ drug: 'carboplatin',
817
+ indication: 'solid tumors',
818
+ standardDose: 'AUC 5-6 (Calvert formula)',
819
+ renalAdjustment: [
820
+ { gfrThreshold: 60, adjustment: 'Use Calvert formula with measured or estimated GFR' },
821
+ { gfrThreshold: 30, adjustment: 'Reduce target AUC. Consider nephrology consult' },
822
+ { gfrThreshold: 15, adjustment: 'Avoid or significant dose reduction' }
823
+ ],
824
+ weightBasedDosing: {
825
+ formula: 'Dose (mg) = Target AUC × (GFR + 25)',
826
+ maxDose: 'Cap GFR at 125 mL/min'
827
+ }
828
+ }]);
829
+
830
+ this.dosingGuidelines.set('cisplatin', [{
831
+ drug: 'cisplatin',
832
+ indication: 'solid tumors',
833
+ standardDose: '75-100 mg/m²',
834
+ renalAdjustment: [
835
+ { gfrThreshold: 60, adjustment: 'Standard dose with aggressive hydration' },
836
+ { gfrThreshold: 45, adjustment: 'Reduce dose 25-50%' },
837
+ { gfrThreshold: 30, adjustment: 'Avoid - use carboplatin alternative' }
838
+ ]
839
+ }]);
840
+ }
841
+
842
+ private addInteraction(interaction: DrugInteraction): void {
843
+ const key1 = interaction.drug1.toLowerCase();
844
+ const key2 = interaction.drug2.toLowerCase();
845
+
846
+ if (!this.interactionDatabase.has(key1)) {
847
+ this.interactionDatabase.set(key1, []);
848
+ }
849
+ if (!this.interactionDatabase.has(key2)) {
850
+ this.interactionDatabase.set(key2, []);
851
+ }
852
+
853
+ this.interactionDatabase.get(key1)!.push(interaction);
854
+ this.interactionDatabase.get(key2)!.push(interaction);
855
+ }
856
+
857
+ private findInteraction(drug1: string, drug2: string): DrugInteraction | null {
858
+ const interactions = this.interactionDatabase.get(drug1.toLowerCase());
859
+ if (!interactions) return null;
860
+
861
+ return interactions.find(i =>
862
+ i.drug2.toLowerCase() === drug2.toLowerCase() ||
863
+ i.drug1.toLowerCase() === drug2.toLowerCase()
864
+ ) || null;
865
+ }
866
+
867
+ private mapInteractionSeverity(severity: DrugInteraction['severity']): SafetyAlert['severity'] {
868
+ switch (severity) {
869
+ case 'contraindicated': return 'critical';
870
+ case 'major': return 'high';
871
+ case 'moderate': return 'moderate';
872
+ case 'minor': return 'low';
873
+ }
874
+ }
875
+
876
+ private checkCrossReactivity(allergen: string, drug: string): AllergyCheck {
877
+ const relatedAllergens = this.allergenCrossReactivity.get(allergen.toLowerCase()) || [];
878
+ const crossReacts = relatedAllergens.some(a => drug.toLowerCase().includes(a));
879
+
880
+ let riskLevel: AllergyCheck['riskLevel'] = 'none';
881
+ if (crossReacts) {
882
+ // Platinum cross-reactivity is high
883
+ if (allergen.toLowerCase().includes('platinum')) {
884
+ riskLevel = 'high';
885
+ }
886
+ // Penicillin-cephalosporin is lower risk
887
+ else if (allergen.toLowerCase().includes('penicillin') && drug.toLowerCase().includes('cephalosporin')) {
888
+ riskLevel = 'low'; // ~2% cross-reactivity
889
+ } else {
890
+ riskLevel = 'moderate';
891
+ }
892
+ }
893
+
894
+ return {
895
+ reportedAllergy: allergen,
896
+ drugToCheck: drug,
897
+ crossReactivity: crossReacts,
898
+ riskLevel,
899
+ relatedAllergens,
900
+ recommendation: crossReacts
901
+ ? `Consider alternative. If essential, administer with caution and monitor.`
902
+ : `No known cross-reactivity. Standard precautions.`
903
+ };
904
+ }
905
+
906
+ /**
907
+ * Generate a medication reconciliation report
908
+ */
909
+ async generateMedicationReconciliation(patient: PatientSafetyProfile): Promise<{
910
+ currentMedications: string[];
911
+ interactions: DrugInteraction[];
912
+ recommendations: string[];
913
+ summary: string;
914
+ }> {
915
+ const currentMeds = patient.currentMedications.map(m => m.drug);
916
+ const interactionAlerts = await this.checkDrugInteractions(currentMeds);
917
+
918
+ const interactions: DrugInteraction[] = [];
919
+ for (let i = 0; i < currentMeds.length; i++) {
920
+ for (let j = i + 1; j < currentMeds.length; j++) {
921
+ const int = this.findInteraction(currentMeds[i], currentMeds[j]);
922
+ if (int) interactions.push(int);
923
+ }
924
+ }
925
+
926
+ const recommendations: string[] = [];
927
+ for (const int of interactions.filter(i => i.severity === 'major' || i.severity === 'contraindicated')) {
928
+ recommendations.push(int.management);
929
+ }
930
+
931
+ return {
932
+ currentMedications: currentMeds,
933
+ interactions,
934
+ recommendations,
935
+ summary: interactions.length > 0
936
+ ? `Found ${interactions.length} drug interaction(s), including ${interactions.filter(i => i.severity === 'major' || i.severity === 'contraindicated').length} major interaction(s).`
937
+ : 'No significant drug interactions identified.'
938
+ };
939
+ }
940
+ }
941
+
942
+ export default DrugSafetyService;