@peopl-health/nexus 5.9.0-dev.921 → 6.0.0-dev.611

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 (126) hide show
  1. package/lib/clinical/AssistantProcessor.js +5 -34
  2. package/lib/clinical/config/divergenceConfig.js +1 -18
  3. package/lib/clinical/config/llmConfig.js +1 -9
  4. package/lib/clinical/context/ToolRuntimeContext.js +2 -1
  5. package/lib/clinical/helpers/divergenceHelper.js +0 -12
  6. package/lib/clinical/index.js +0 -2
  7. package/lib/clinical/memory/DefaultMemoryManager.js +9 -19
  8. package/lib/clinical/models/turnTraceModel.js +5 -18
  9. package/lib/clinical/providers/AnthropicProvider.js +29 -291
  10. package/lib/clinical/providers/BaseLLMProvider.js +24 -113
  11. package/lib/clinical/providers/GatewayProvider.js +3 -3
  12. package/lib/clinical/providers/OpenAIResponsesProvider.js +4 -46
  13. package/lib/clinical/services/divergenceService.js +5 -22
  14. package/lib/clinical/services/promptComposerService.js +15 -46
  15. package/lib/clinical/services/shadowMessageService.js +12 -28
  16. package/lib/clinical/services/shadowService.js +3 -12
  17. package/lib/clinical/stores/CtcaeCatalog.js +0 -20
  18. package/lib/config/airtableConfig.js +0 -3
  19. package/lib/core/BatchingManager.js +3 -10
  20. package/lib/core/NexusMessaging.js +13 -31
  21. package/lib/eval/EvalProvider.js +2 -3
  22. package/lib/fhir/config/fhirConfig.js +3 -34
  23. package/lib/fhir/constants/projectionSlugs.js +1 -41
  24. package/lib/fhir/helpers/elementHelper.js +0 -21
  25. package/lib/fhir/helpers/fhirHelper.js +2 -5
  26. package/lib/fhir/index.js +0 -24
  27. package/lib/fhir/models/envelopeModel.js +0 -5
  28. package/lib/fhir/projections/registerProjectors.js +0 -16
  29. package/lib/fhir/resources/Condition.js +2 -107
  30. package/lib/fhir/resources/Observation.js +1 -73
  31. package/lib/fhir/resources/Procedure.js +2 -34
  32. package/lib/fhir/resources/Provenance.js +2 -93
  33. package/lib/fhir/services/fhirService.js +2 -2
  34. package/lib/helpers/twilioHelper.js +1 -9
  35. package/lib/index.d.ts +0 -16
  36. package/lib/index.js +0 -9
  37. package/lib/models/messageModel.js +0 -6
  38. package/lib/routes/index.js +1 -21
  39. package/lib/services/airtableService.js +1 -2
  40. package/lib/shared/dtos/ContingencySafetyNet.js +3 -10
  41. package/lib/shared/dtos/DispatchedEscalation.js +8 -3
  42. package/lib/shared/dtos/Reminder.js +2 -2
  43. package/lib/storage/MongoStorage.js +0 -2
  44. package/package.json +1 -1
  45. package/lib/clinical/config/cohortConfig.js +0 -68
  46. package/lib/clinical/config/composerConfig.js +0 -42
  47. package/lib/clinical/config/subAgentsConfig.js +0 -44
  48. package/lib/clinical/flags/bridgeConfig.js +0 -14
  49. package/lib/clinical/flags/composerFlags.js +0 -14
  50. package/lib/clinical/helpers/clinicalFactsHelper.js +0 -108
  51. package/lib/clinical/helpers/clinicalMentionHelper.js +0 -68
  52. package/lib/clinical/helpers/cohortHelper.js +0 -22
  53. package/lib/clinical/helpers/gradeEstimateHelper.js +0 -29
  54. package/lib/clinical/helpers/resultsHelper.js +0 -34
  55. package/lib/clinical/helpers/safetyFlagsHelper.js +0 -10
  56. package/lib/clinical/services/bridgeService.js +0 -55
  57. package/lib/clinical/services/clinicalAirtableService.js +0 -162
  58. package/lib/clinical/services/clinicalExtractionService.js +0 -112
  59. package/lib/clinical/services/composerService.js +0 -59
  60. package/lib/clinical/services/dispatcherService.js +0 -137
  61. package/lib/clinical/services/reminderDispatchService.js +0 -36
  62. package/lib/clinical/services/skillService.js +0 -44
  63. package/lib/clinical/tools/analyzeSymptomPatternsTool.js +0 -279
  64. package/lib/clinical/tools/deliverPatientMessageTool.js +0 -202
  65. package/lib/clinical/tools/extractClinicalInfoTool.js +0 -167
  66. package/lib/clinical/tools/getActiveSymptomLandscapeTool.js +0 -141
  67. package/lib/clinical/tools/getPatientHistoryTool.js +0 -235
  68. package/lib/clinical/tools/getPatientRiskProfileTool.js +0 -71
  69. package/lib/clinical/tools/getRouterContextBundleTool.js +0 -93
  70. package/lib/clinical/tools/lookupCtcaeEntryTool.js +0 -35
  71. package/lib/clinical/tools/openClusterHypothesisTool.js +0 -160
  72. package/lib/clinical/tools/openConditionTool.js +0 -136
  73. package/lib/clinical/tools/recordClinicalImpressionTool.js +0 -251
  74. package/lib/clinical/tools/recordInterventionTool.js +0 -140
  75. package/lib/clinical/tools/registerClinicalTools.js +0 -39
  76. package/lib/clinical/tools/reportCrisisTool.js +0 -211
  77. package/lib/clinical/tools/reportMedicalEscalationTool.js +0 -187
  78. package/lib/clinical/tools/reportResultsReceivedTool.js +0 -153
  79. package/lib/clinical/tools/reportUnresolvedRequestv2Tool.js +0 -177
  80. package/lib/clinical/tools/schedulePatientReminderTool.js +0 -149
  81. package/lib/clinical/tools/setContingencyPlanTool.js +0 -176
  82. package/lib/clinical/tools/skillTool.js +0 -67
  83. package/lib/clinical/tools/submitRoutingDecisionTool.js +0 -291
  84. package/lib/clinical/tools/updateClusterHypothesisTool.js +0 -159
  85. package/lib/controllers/cohortController.js +0 -16
  86. package/lib/controllers/traceController.js +0 -26
  87. package/lib/core/workflowRunner.js +0 -35
  88. package/lib/fhir/config/fhirTablesConfig.js +0 -9
  89. package/lib/fhir/constants/severityPriority.js +0 -8
  90. package/lib/fhir/helpers/compositeHelper.js +0 -88
  91. package/lib/fhir/helpers/fhirReadHelper.js +0 -42
  92. package/lib/fhir/helpers/terminologyHelper.js +0 -260
  93. package/lib/fhir/projections/clusterProjection.js +0 -24
  94. package/lib/fhir/projections/contingencyProjection.js +0 -36
  95. package/lib/fhir/projections/dispatchedEscalationProjection.js +0 -25
  96. package/lib/fhir/projections/interventionProjection.js +0 -42
  97. package/lib/fhir/projections/proctcaeProjection.js +0 -179
  98. package/lib/fhir/projections/reminderProjection.js +0 -20
  99. package/lib/fhir/projections/riskProjection.js +0 -16
  100. package/lib/fhir/projections/routingProjection.js +0 -48
  101. package/lib/fhir/projections/symptomCaseProjection.js +0 -65
  102. package/lib/fhir/resources/CarePlan.js +0 -93
  103. package/lib/fhir/resources/ClinicalImpression.js +0 -118
  104. package/lib/fhir/resources/Communication.js +0 -65
  105. package/lib/fhir/resources/CommunicationRequest.js +0 -182
  106. package/lib/fhir/resources/Device.js +0 -24
  107. package/lib/fhir/resources/Patient.js +0 -18
  108. package/lib/fhir/resources/Questionnaire.js +0 -23
  109. package/lib/fhir/resources/QuestionnaireResponse.js +0 -29
  110. package/lib/fhir/resources/RequestOrchestration.js +0 -46
  111. package/lib/fhir/resources/RiskAssessment.js +0 -99
  112. package/lib/fhir/resources/Task.js +0 -106
  113. package/lib/fhir/resources/interventionExtensions.js +0 -28
  114. package/lib/fhir/services/clusterService.js +0 -77
  115. package/lib/fhir/services/contingencyService.js +0 -117
  116. package/lib/fhir/services/interventionService.js +0 -149
  117. package/lib/fhir/services/resultObservationService.js +0 -52
  118. package/lib/fhir/services/riskService.js +0 -101
  119. package/lib/fhir/services/routingService.js +0 -147
  120. package/lib/fhir/services/snapshotService.js +0 -28
  121. package/lib/fhir/services/symptomCaseService.js +0 -139
  122. package/lib/fhir/services/terminologyService.js +0 -58
  123. package/lib/fhir/services/triageService.js +0 -57
  124. package/lib/fhir/utils/normalizeUtils.js +0 -33
  125. package/lib/shared/dtos/GradedSymptom.js +0 -23
  126. package/lib/shared/dtos/TriageResponse.js +0 -35
@@ -1,48 +0,0 @@
1
- const { fhirId } = require('../helpers/fhirHelper');
2
- const { ClinicalImpression } = require('../resources/ClinicalImpression');
3
- const { Communication } = require('../resources/Communication');
4
- const { CommunicationRequest } = require('../resources/CommunicationRequest');
5
- const { Task } = require('../resources/Task');
6
- const { RequestOrchestration } = require('../resources/RequestOrchestration');
7
- const { CarePlan } = require('../resources/CarePlan');
8
- const { Provenance } = require('../resources/Provenance');
9
-
10
- const PROJECTOR_NAME = 'routing';
11
- const ACTIVITY_TEXT = 'routing-decision';
12
-
13
- const DISPOSITION_BY_KIND = {
14
- communication: Communication,
15
- communication_request: CommunicationRequest,
16
- task: Task,
17
- orchestration: RequestOrchestration,
18
- care_plan: CarePlan,
19
- };
20
-
21
- function projectRoutingDecision(routingDecision) {
22
- const { decisionId, committedAt, assessment, disposition, provenance } = routingDecision;
23
- const impression = ClinicalImpression.fromRoutingAssessment({
24
- assessment,
25
- decisionId,
26
- committedAt,
27
- deferredItems: disposition.deferredItems,
28
- primaryCaseId: disposition.primaryCaseId,
29
- });
30
- const resourceClass = DISPOSITION_BY_KIND[disposition.kind];
31
- if (!resourceClass) throw new Error(`unknown routing-disposition kind: ${disposition.kind}`);
32
- const dispositionResource = resourceClass.fromRoutingDisposition({ disposition });
33
- const provenanceResource = Provenance.fromRoutingDecision({
34
- provenanceId: `${assessment.assessmentId}-prov`,
35
- targetRefs: [
36
- { reference: `ClinicalImpression/${fhirId(assessment.assessmentId)}` },
37
- { reference: `${dispositionResource.resourceType}/${fhirId(disposition.dispositionId)}` },
38
- ],
39
- provenance,
40
- activityText: ACTIVITY_TEXT,
41
- });
42
- return [impression, dispositionResource, provenanceResource];
43
- }
44
-
45
- module.exports = {
46
- projectRoutingDecision,
47
- PROJECTOR_NAME,
48
- };
@@ -1,65 +0,0 @@
1
- const { fhirId } = require('../helpers/fhirHelper');
2
- const { ClinicalImpression } = require('../resources/ClinicalImpression');
3
- const { Condition } = require('../resources/Condition');
4
- const { Observation } = require('../resources/Observation');
5
- const { Provenance } = require('../resources/Provenance');
6
-
7
- const PROJECTOR_NAME = 'symptomCase';
8
- const ACTIVITY_TEXT = 'symptom-management';
9
- const PLACEHOLDER_DECISION_POSTURE = 'pending_initial_assessment';
10
-
11
- function assessmentResources(assessment, dropPreviousTo) {
12
- const grade = assessment.grade;
13
- const hasGradeSignal = grade.bestEstimate !== null
14
- || grade.possibleRange !== null
15
- || Boolean(grade.confidence)
16
- || Boolean(grade.reasoning)
17
- || Boolean(assessment.gradeThresholdClause);
18
- const out = [ClinicalImpression.fromSymptomAssessment({ assessment, dropPreviousTo, hasGradeSignal })];
19
- if (hasGradeSignal) out.push(Observation.fromSymptomGrade({ assessment }));
20
- return out;
21
- }
22
-
23
- function projectSymptomCase(managedSymptom) {
24
- const { condition, latestAssessment, priorAssessments } = managedSymptom;
25
- const allAssessments = [latestAssessment, ...priorAssessments];
26
- const placeholderIds = new Set(
27
- allAssessments.filter((a) => a.decisionPosture === PLACEHOLDER_DECISION_POSTURE).map((a) => a.assessmentId),
28
- );
29
-
30
- const fhirCondition = Condition.fromSymptomCase({
31
- condition,
32
- verification: latestAssessment.gradeVerification,
33
- headAssessmentId: latestAssessment.assessmentId,
34
- });
35
-
36
- const out = [fhirCondition, ...assessmentResources(latestAssessment, placeholderIds)];
37
- const provenanceTargets = [
38
- { reference: `Condition/${fhirId(condition.conditionId)}` },
39
- { reference: `ClinicalImpression/${fhirId(latestAssessment.assessmentId)}` },
40
- ];
41
- out.push(Provenance.fromSymptomCase({
42
- provenanceId: `${condition.conditionId}-prov`,
43
- targetRefs: provenanceTargets,
44
- recordedAt: latestAssessment.performedAt,
45
- activityText: ACTIVITY_TEXT,
46
- }));
47
-
48
- for (const prior of priorAssessments) {
49
- if (placeholderIds.has(prior.assessmentId)) continue;
50
- out.push(...assessmentResources(prior, placeholderIds));
51
- out.push(Provenance.fromSymptomCase({
52
- provenanceId: `${prior.assessmentId}-prov`,
53
- targetRefs: [{ reference: `ClinicalImpression/${fhirId(prior.assessmentId)}` }],
54
- recordedAt: prior.performedAt,
55
- activityText: ACTIVITY_TEXT,
56
- }));
57
- }
58
-
59
- return out;
60
- }
61
-
62
- module.exports = {
63
- projectSymptomCase,
64
- PROJECTOR_NAME,
65
- };
@@ -1,93 +0,0 @@
1
- const { fhirId } = require('../helpers/fhirHelper');
2
- const {
3
- identifier,
4
- patientReference,
5
- reference,
6
- codeableConcept,
7
- extension,
8
- toIso,
9
- } = require('../helpers/elementHelper');
10
- const { CONTINGENCY_PLAN_SLUG, ROUTING_DISPOSITION_SLUG } = require('../constants/projectionSlugs');
11
-
12
- const CONTINGENCY_STATUS_TO_FHIR = {
13
- armed: 'active',
14
- fired_reminder: 'active',
15
- fired_team: 'active',
16
- auto_resolved: 'completed',
17
- cancelled: 'revoked',
18
- };
19
-
20
- class CarePlan {
21
- constructor(payload) {
22
- Object.assign(this, payload);
23
- }
24
-
25
- static fromContingency({ carePlan }) {
26
- const payload = {
27
- resourceType: 'CarePlan',
28
- id: fhirId(carePlan.planId),
29
- identifier: [identifier(CONTINGENCY_PLAN_SLUG, carePlan.planId)],
30
- status: CONTINGENCY_STATUS_TO_FHIR[carePlan.status],
31
- intent: 'plan',
32
- subject: patientReference(carePlan.patientId),
33
- created: toIso(carePlan.createdAt),
34
- period: contingencyPeriod(carePlan),
35
- };
36
- if (carePlan.concern) payload.description = carePlan.concern;
37
- if (carePlan.relatedCaseId) {
38
- payload.addresses = [{ reference: reference('Condition', carePlan.relatedCaseId) }];
39
- }
40
- if (carePlan.relatedClusterId) {
41
- payload.supportingInfo = [reference('ClinicalImpression', carePlan.relatedClusterId)];
42
- }
43
- const ext = contingencyExtensions(carePlan);
44
- if (ext.length) payload.extension = ext;
45
- return new CarePlan(payload);
46
- }
47
-
48
- static fromRoutingDisposition({ disposition }) {
49
- const payload = {
50
- resourceType: 'CarePlan',
51
- id: fhirId(disposition.dispositionId),
52
- identifier: [identifier(ROUTING_DISPOSITION_SLUG, disposition.dispositionId)],
53
- status: 'active',
54
- intent: 'plan',
55
- category: [codeableConcept(disposition.primaryAction)],
56
- subject: patientReference(disposition.patientId),
57
- created: toIso(disposition.authoredAt),
58
- description: disposition.primaryReason,
59
- };
60
- if (disposition.primaryCaseId) {
61
- payload.addresses = [{ reference: reference('Condition', disposition.primaryCaseId) }];
62
- }
63
- return new CarePlan(payload);
64
- }
65
- }
66
-
67
- function contingencyPeriod(carePlan) {
68
- const period = { start: toIso(carePlan.createdAt) };
69
- if (carePlan.resolvedAt) period.end = toIso(carePlan.resolvedAt);
70
- return period;
71
- }
72
-
73
- function contingencyExtensions(carePlan) {
74
- const out = [extension('contingency-status', { valueString: carePlan.status })];
75
- if (carePlan.awaitingCharacterization) {
76
- out.push(extension('contingency-awaiting-characterization', { valueString: carePlan.awaitingCharacterization }));
77
- }
78
- if (carePlan.whyThisMatters) {
79
- out.push(extension('contingency-why-this-matters', { valueString: carePlan.whyThisMatters }));
80
- }
81
- if (carePlan.creationReasoning) {
82
- out.push(extension('contingency-creation-reasoning', { valueString: carePlan.creationReasoning }));
83
- }
84
- if (carePlan.resolvedReason) {
85
- out.push(extension('contingency-resolved-reason', { valueString: carePlan.resolvedReason }));
86
- }
87
- return out;
88
- }
89
-
90
- module.exports = {
91
- CarePlan,
92
- CONTINGENCY_STATUS_TO_FHIR,
93
- };
@@ -1,118 +0,0 @@
1
- const { fhirId } = require('../helpers/fhirHelper');
2
- const { identifier, reference, patientReference, codeableConcept, extension, toIso } = require('../helpers/elementHelper');
3
- const { SYMPTOM_ASSESSMENT_SLUG, CLUSTER_IMPRESSION_SLUG, CLUSTER_LABEL_SLUG, ROUTING_ASSESSMENT_SLUG } = require('../constants/projectionSlugs');
4
-
5
- const CLUSTER_STATUS_TO_FHIR = { active: 'in-progress', dissolved: 'completed' };
6
- const CLUSTER_LIST_SEPARATOR = '; ';
7
-
8
- class ClinicalImpression {
9
- constructor(payload) {
10
- Object.assign(this, payload);
11
- }
12
-
13
- static fromClusterImpression({ cluster }) {
14
- const epistemicExts = [
15
- extension('clusterHypothesisType', { valueString: cluster.hypothesisType }),
16
- extension('clusterHypothesisConfidence', { valueString: cluster.confidence }),
17
- extension('clusterClinicalSignificance', { valueString: cluster.clinicalSignificance }),
18
- ];
19
- if (cluster.strengthensIf.length) {
20
- epistemicExts.push(extension('clusterStrengthensIf', { valueString: cluster.strengthensIf.join(CLUSTER_LIST_SEPARATOR) }));
21
- }
22
- if (cluster.weakensIf.length) {
23
- epistemicExts.push(extension('clusterWeakensIf', { valueString: cluster.weakensIf.join(CLUSTER_LIST_SEPARATOR) }));
24
- }
25
- const lifecycleExts = [extension('cluster-status', { valueString: cluster.status })];
26
- if (cluster.consultationId) lifecycleExts.push(extension('cluster-consultation-id', { valueString: cluster.consultationId }));
27
- if (cluster.dissolveReason) lifecycleExts.push(extension('cluster-dissolve-reason', { valueString: cluster.dissolveReason }));
28
-
29
- const identifiers = [identifier(CLUSTER_IMPRESSION_SLUG, cluster.clusterId)];
30
- if (cluster.label) identifiers.push(identifier(CLUSTER_LABEL_SLUG, cluster.label));
31
-
32
- const payload = {
33
- resourceType: 'ClinicalImpression',
34
- id: fhirId(cluster.clusterId),
35
- identifier: identifiers,
36
- status: CLUSTER_STATUS_TO_FHIR[cluster.status],
37
- subject: patientReference(cluster.patientId),
38
- problem: cluster.memberCaseIds.map((caseId) => reference('Condition', caseId)),
39
- extension: [...epistemicExts, ...lifecycleExts],
40
- };
41
- if (cluster.relationshipModel) payload.summary = cluster.relationshipModel;
42
- if (cluster.openingReasoning) payload.description = cluster.openingReasoning;
43
- if (cluster.dissolvedAt) {
44
- // toIso normalizes to Z; a non-Z openedAt/dissolvedAt does not byte-for-byte round-trip (known loss).
45
- payload.effectivePeriod = { start: toIso(cluster.openedAt), end: toIso(cluster.dissolvedAt) };
46
- } else {
47
- payload.effectiveDateTime = toIso(cluster.openedAt);
48
- }
49
- if (cluster.dissolveCategory) payload.statusReason = codeableConcept(cluster.dissolveCategory);
50
- return new ClinicalImpression(payload);
51
- }
52
-
53
- static fromSymptomAssessment({ assessment, dropPreviousTo = null, hasGradeSignal = false }) {
54
- const extensions = [];
55
- if (assessment.trajectory) extensions.push(extension('trajectory', { valueString: assessment.trajectory }));
56
- if (assessment.decisionPosture) extensions.push(extension('decision-posture', { valueString: assessment.decisionPosture }));
57
- if (assessment.postureReason) extensions.push(extension('posture-reason', { valueString: assessment.postureReason }));
58
- if (assessment.reasoning) extensions.push(extension('assessment-reasoning', { valueString: assessment.reasoning }));
59
- const payload = {
60
- resourceType: 'ClinicalImpression',
61
- id: fhirId(assessment.assessmentId),
62
- identifier: [identifier(SYMPTOM_ASSESSMENT_SLUG, assessment.assessmentId)],
63
- status: 'completed',
64
- subject: patientReference(assessment.patientId),
65
- effectiveDateTime: toIso(assessment.performedAt),
66
- problem: [reference('Condition', assessment.conditionId)],
67
- extension: extensions,
68
- };
69
- if (hasGradeSignal) {
70
- payload.finding = [{ item: { reference: reference('Observation', `${assessment.assessmentId}-grade`) } }];
71
- }
72
- if (assessment.problemRepresentation) payload.summary = assessment.problemRepresentation;
73
- if (assessment.previousId && !(dropPreviousTo && dropPreviousTo.has(assessment.previousId))) {
74
- payload.previous = reference('ClinicalImpression', assessment.previousId);
75
- }
76
- return new ClinicalImpression(payload);
77
- }
78
-
79
- static fromRoutingAssessment({ assessment, decisionId, committedAt, deferredItems = [], primaryCaseId = null }) {
80
- const extensions = [
81
- extension('routing-turn-id', { valueString: assessment.turnId }),
82
- extension('routing-decision-id', { valueString: decisionId }),
83
- extension('routing-committed-at', { valueDateTime: toIso(committedAt) }),
84
- ];
85
- if (primaryCaseId) extensions.push(extension('routing-primary-case-id', { valueString: primaryCaseId }));
86
- for (const deferred of deferredItems) {
87
- extensions.push(extension('routing-deferred-item', { valueString: deferred.item }));
88
- extensions.push(extension('routing-deferred-reason', { valueString: deferred.deferReason }));
89
- }
90
- const payload = {
91
- resourceType: 'ClinicalImpression',
92
- id: fhirId(assessment.assessmentId),
93
- identifier: [identifier(ROUTING_ASSESSMENT_SLUG, assessment.assessmentId)],
94
- status: 'completed',
95
- subject: patientReference(assessment.patientId),
96
- effectiveDateTime: toIso(assessment.performedAt),
97
- finding: assessment.findings.map((finding) => ({
98
- item: reference('Condition', finding.caseId),
99
- extension: [
100
- extension('routing-finding-case-id', { valueString: finding.caseId }),
101
- extension('routing-finding-reasoning', { valueString: finding.clinicalReasoning }),
102
- extension('routing-finding-action', { valueString: finding.decisionAction }),
103
- ],
104
- })),
105
- extension: extensions,
106
- };
107
- if (assessment.summary) payload.summary = assessment.summary;
108
- if (assessment.previousId) payload.previous = reference('ClinicalImpression', assessment.previousId);
109
- if (assessment.notes.length) payload.note = assessment.notes.map((text) => ({ text }));
110
- return new ClinicalImpression(payload);
111
- }
112
- }
113
-
114
- module.exports = {
115
- ClinicalImpression,
116
- CLUSTER_STATUS_TO_FHIR,
117
- CLUSTER_LIST_SEPARATOR,
118
- };
@@ -1,65 +0,0 @@
1
- const { fhirId, codeSystemUrl } = require('../helpers/fhirHelper');
2
- const {
3
- identifier,
4
- reference,
5
- patientReference,
6
- recipientReference,
7
- codeableConcept,
8
- notes,
9
- toIso,
10
- } = require('../helpers/elementHelper');
11
- const {
12
- INTERVENTION_SLUG,
13
- INTERVENTION_KIND_SLUG,
14
- ROUTING_DISPOSITION_SLUG,
15
- } = require('../constants/projectionSlugs');
16
- const { interventionExtensions } = require('./interventionExtensions');
17
-
18
- class Communication {
19
- constructor(payload) {
20
- Object.assign(this, payload);
21
- }
22
-
23
- static fromIntervention({ intervention }) {
24
- const payload = {
25
- resourceType: 'Communication',
26
- id: fhirId(intervention.interventionId),
27
- identifier: [identifier(INTERVENTION_SLUG, intervention.interventionId)],
28
- status: 'completed',
29
- category: [codeableConcept(intervention.kind, { code: intervention.kind, system: codeSystemUrl(INTERVENTION_KIND_SLUG) })],
30
- subject: patientReference(intervention.patientId),
31
- reason: [{ reference: reference('Condition', intervention.caseId) }],
32
- sent: toIso(intervention.deliveredAt),
33
- payload: [{ contentCodeableConcept: codeableConcept(intervention.interventionLabel) }],
34
- recipient: [recipientReference({
35
- patientId: intervention.patientId,
36
- recipientKind: intervention.recipientKind,
37
- recipientRefId: intervention.recipientRefId,
38
- })],
39
- extension: interventionExtensions(intervention),
40
- };
41
- const note = notes(intervention.rationale, intervention.outcomeNotes);
42
- if (note) payload.note = note;
43
- return new Communication(payload);
44
- }
45
-
46
- static fromRoutingDisposition({ disposition }) {
47
- const payload = {
48
- resourceType: 'Communication',
49
- id: fhirId(disposition.dispositionId),
50
- identifier: [identifier(ROUTING_DISPOSITION_SLUG, disposition.dispositionId)],
51
- status: 'completed',
52
- category: [codeableConcept(disposition.primaryAction)],
53
- subject: patientReference(disposition.patientId),
54
- sent: toIso(disposition.authoredAt),
55
- payload: [{ contentCodeableConcept: codeableConcept(disposition.primaryReason) }],
56
- recipient: [patientReference(disposition.patientId)],
57
- };
58
- if (disposition.primaryCaseId) {
59
- payload.reason = [{ reference: reference('Condition', disposition.primaryCaseId) }];
60
- }
61
- return new Communication(payload);
62
- }
63
- }
64
-
65
- module.exports = { Communication };
@@ -1,182 +0,0 @@
1
- const { getOrganizationId } = require('../config/fhirConfig');
2
- const { fhirId, codeSystemUrl } = require('../helpers/fhirHelper');
3
- const {
4
- identifier,
5
- reference,
6
- patientReference,
7
- recipientReference,
8
- codeableConcept,
9
- extension,
10
- notes,
11
- toIso,
12
- } = require('../helpers/elementHelper');
13
- const {
14
- ESCALATION_SLUG,
15
- ESCALATION_KIND_SLUG,
16
- REMINDER_SLUG,
17
- REMINDER_KIND_SLUG,
18
- COMMUNICATION_CHANNEL_SLUG,
19
- CONTINGENCY_STEP_SLUG,
20
- INTERVENTION_SLUG,
21
- INTERVENTION_KIND_SLUG,
22
- ROUTING_DISPOSITION_SLUG,
23
- } = require('../constants/projectionSlugs');
24
- const { SEVERITY_TO_PRIORITY } = require('../constants/severityPriority');
25
- const { CONTINGENCY_STATUS_TO_FHIR } = require('./CarePlan');
26
-
27
- const CONTINGENCY_PRIORITY_CROSSWALK = {
28
- critical: 'stat',
29
- high: 'urgent',
30
- medium: 'routine',
31
- low: 'routine',
32
- routine: 'routine',
33
- urgent: 'urgent',
34
- asap: 'asap',
35
- stat: 'stat',
36
- };
37
- const { interventionExtensions } = require('./interventionExtensions');
38
-
39
- const NOTIFY_STATUS_TO_CR_STATUS = {
40
- queued: 'active',
41
- sent: 'active',
42
- acknowledged: 'completed',
43
- failed: 'revoked',
44
- };
45
-
46
- const REMINDER_STATUS_TO_CR_STATUS = {
47
- scheduled: 'active',
48
- cancelled: 'revoked',
49
- expired: 'revoked',
50
- };
51
-
52
- class CommunicationRequest {
53
- constructor(payload) {
54
- Object.assign(this, payload);
55
- }
56
-
57
- static fromNotifyEscalation({ notify }) {
58
- const payload = {
59
- resourceType: 'CommunicationRequest',
60
- id: fhirId(notify.eventId),
61
- identifier: [identifier(ESCALATION_SLUG, notify.eventId)],
62
- status: NOTIFY_STATUS_TO_CR_STATUS[notify.status],
63
- intent: 'plan',
64
- priority: SEVERITY_TO_PRIORITY[notify.severity] || 'routine',
65
- category: [codeableConcept(notify.kind, { code: notify.kind, system: codeSystemUrl(ESCALATION_KIND_SLUG) })],
66
- subject: patientReference(notify.patientId),
67
- authoredOn: toIso(notify.createdAt),
68
- };
69
- if (notify.reason) payload.reason = [{ concept: codeableConcept(notify.reason) }];
70
- if (typeof notify.recipient === 'string' && /^[A-Za-z]+\/[A-Za-z0-9._-]+$/.test(notify.recipient)) {
71
- payload.recipient = [{ reference: notify.recipient }];
72
- }
73
- if (notify.requiresAck) {
74
- payload.extension = [extension('requires-ack', { valueBoolean: true })];
75
- }
76
- if (notify.fireAt) payload.occurrenceDateTime = toIso(notify.fireAt);
77
- if (notify.followupPurpose) {
78
- (payload.extension || (payload.extension = [])).push(
79
- extension('followup-purpose', { valueString: notify.followupPurpose }),
80
- );
81
- }
82
- return new CommunicationRequest(payload);
83
- }
84
-
85
- static fromReminder({ reminder }) {
86
- const payload = {
87
- resourceType: 'CommunicationRequest',
88
- id: fhirId(reminder.reminderId),
89
- identifier: [identifier(REMINDER_SLUG, reminder.reminderId)],
90
- status: REMINDER_STATUS_TO_CR_STATUS[reminder.status],
91
- intent: 'plan',
92
- category: [codeableConcept(reminder.kind, { code: reminder.kind, system: codeSystemUrl(REMINDER_KIND_SLUG) })],
93
- medium: [codeableConcept(reminder.channel, { code: reminder.channel, system: codeSystemUrl(COMMUNICATION_CHANNEL_SLUG) })],
94
- subject: patientReference(reminder.patientId),
95
- recipient: [recipientReference({
96
- patientId: reminder.patientId,
97
- recipientKind: reminder.recipientKind,
98
- recipientRefId: reminder.recipientRefId,
99
- })],
100
- payload: [{ contentCodeableConcept: codeableConcept(reminder.message) }],
101
- occurrenceDateTime: toIso(reminder.fireAt),
102
- authoredOn: toIso(reminder.authoredAt),
103
- };
104
- if (reminder.cancelReason) payload.statusReason = codeableConcept(reminder.cancelReason);
105
- return new CommunicationRequest(payload);
106
- }
107
-
108
- static fromContingencyStep({ step, planId, patientId, createdAt, parentStatus }) {
109
- const stepId = `${planId}-${step.recipient}`;
110
- const payload = {
111
- resourceType: 'CommunicationRequest',
112
- id: fhirId(stepId),
113
- identifier: [identifier(CONTINGENCY_STEP_SLUG, stepId)],
114
- status: CONTINGENCY_STATUS_TO_FHIR[parentStatus],
115
- intent: 'plan',
116
- category: [codeableConcept(`contingency-${step.recipient}`)],
117
- subject: patientReference(patientId),
118
- recipient: [step.recipient === 'patient'
119
- ? patientReference(patientId)
120
- : { reference: `Organization/${fhirId(getOrganizationId())}` }],
121
- payload: [{ contentCodeableConcept: codeableConcept(step.message) }],
122
- authoredOn: toIso(createdAt),
123
- basedOn: [{ reference: `CarePlan/${fhirId(planId)}` }],
124
- };
125
- const priority = step.priority ? CONTINGENCY_PRIORITY_CROSSWALK[step.priority] || 'routine' : null;
126
- if (priority) payload.priority = priority;
127
- const ext = [];
128
- if (step.priority) ext.push(extension('contingency-step-priority', { valueString: step.priority }));
129
- if (step.actionRequested) ext.push(extension('contingency-action-requested', { valueString: step.actionRequested }));
130
- if (step.firesAfterSilenceMinutes !== null && step.firesAfterSilenceMinutes !== undefined) {
131
- ext.push(extension('fires-after-silence-minutes', { valueInteger: step.firesAfterSilenceMinutes }));
132
- }
133
- if (ext.length) payload.extension = ext;
134
- return new CommunicationRequest(payload);
135
- }
136
-
137
- static fromIntervention({ intervention }) {
138
- const payload = {
139
- resourceType: 'CommunicationRequest',
140
- id: fhirId(intervention.interventionId),
141
- identifier: [identifier(INTERVENTION_SLUG, intervention.interventionId)],
142
- status: intervention.outcome === 'pending' ? 'active' : 'completed',
143
- intent: 'plan',
144
- category: [codeableConcept(intervention.kind, { code: intervention.kind, system: codeSystemUrl(INTERVENTION_KIND_SLUG) })],
145
- subject: patientReference(intervention.patientId),
146
- reason: [{ reference: reference('Condition', intervention.caseId) }],
147
- payload: [{ contentCodeableConcept: codeableConcept(intervention.interventionLabel) }],
148
- recipient: [recipientReference({
149
- patientId: intervention.patientId,
150
- recipientKind: intervention.recipientKind,
151
- recipientRefId: intervention.recipientRefId,
152
- })],
153
- occurrenceDateTime: toIso(intervention.deliveredAt),
154
- authoredOn: toIso(intervention.deliveredAt),
155
- extension: interventionExtensions(intervention),
156
- };
157
- const note = notes(intervention.rationale, intervention.outcomeNotes);
158
- if (note) payload.note = note;
159
- return new CommunicationRequest(payload);
160
- }
161
-
162
- static fromRoutingDisposition({ disposition }) {
163
- const payload = {
164
- resourceType: 'CommunicationRequest',
165
- id: fhirId(disposition.dispositionId),
166
- identifier: [identifier(ROUTING_DISPOSITION_SLUG, disposition.dispositionId)],
167
- status: 'active',
168
- intent: 'plan',
169
- category: [codeableConcept(disposition.primaryAction)],
170
- subject: patientReference(disposition.patientId),
171
- authoredOn: toIso(disposition.authoredAt),
172
- payload: [{ contentCodeableConcept: codeableConcept(disposition.primaryReason) }],
173
- recipient: [patientReference(disposition.patientId)],
174
- };
175
- if (disposition.primaryCaseId) {
176
- payload.reason = [{ reference: reference('Condition', disposition.primaryCaseId) }];
177
- }
178
- return new CommunicationRequest(payload);
179
- }
180
- }
181
-
182
- module.exports = { CommunicationRequest };
@@ -1,24 +0,0 @@
1
- const { fhirId } = require('../helpers/fhirHelper');
2
- const { identifier, codeableConcept } = require('../helpers/elementHelper');
3
-
4
- class Device {
5
- constructor(payload) {
6
- Object.assign(this, payload);
7
- }
8
-
9
- static fromTriageProjection({ deviceId, compositeTableHash }) {
10
- const version = [{ value: 'pro-ctcae-composite' }];
11
- if (compositeTableHash) version.push({ type: { text: 'composite-table' }, value: `sha256:${compositeTableHash}` });
12
- return new Device({
13
- resourceType: 'Device',
14
- id: fhirId(deviceId),
15
- identifier: [identifier('device', deviceId)],
16
- status: 'active',
17
- name: [{ value: 'PRO-CTCAE composite → CTCAE grade estimator', type: 'user-friendly-name' }],
18
- type: [codeableConcept('Software / clinical algorithm')],
19
- version,
20
- });
21
- }
22
- }
23
-
24
- module.exports = { Device };
@@ -1,18 +0,0 @@
1
- const { fhirId } = require('../helpers/fhirHelper');
2
- const { identifier } = require('../helpers/elementHelper');
3
-
4
- class Patient {
5
- constructor(payload) {
6
- Object.assign(this, payload);
7
- }
8
-
9
- static fromTriageProjection({ patientId }) {
10
- return new Patient({
11
- resourceType: 'Patient',
12
- id: fhirId(String(patientId)),
13
- identifier: [identifier('patient', String(patientId))],
14
- });
15
- }
16
- }
17
-
18
- module.exports = { Patient };
@@ -1,23 +0,0 @@
1
- const { getQuestionnaireCanonicalUrl, getProctcaeVersion } = require('../config/fhirConfig');
2
- const { fhirId } = require('../helpers/fhirHelper');
3
-
4
- class Questionnaire {
5
- constructor(payload) {
6
- Object.assign(this, payload);
7
- }
8
-
9
- static fromProctcaeCatalog({ items }) {
10
- return new Questionnaire({
11
- resourceType: 'Questionnaire',
12
- id: fhirId(`pro-ctcae-${getProctcaeVersion()}`),
13
- url: getQuestionnaireCanonicalUrl(),
14
- version: getProctcaeVersion(),
15
- status: 'active',
16
- name: 'PROCTCAE',
17
- subjectType: ['Patient'],
18
- item: items,
19
- });
20
- }
21
- }
22
-
23
- module.exports = { Questionnaire };
@@ -1,29 +0,0 @@
1
- const { getQuestionnaireCanonicalUrl, getProctcaeVersion } = require('../config/fhirConfig');
2
- const { fhirId } = require('../helpers/fhirHelper');
3
- const { identifier, patientReference, toIso } = require('../helpers/elementHelper');
4
-
5
- class QuestionnaireResponse {
6
- constructor(payload) {
7
- Object.assign(this, payload);
8
- }
9
-
10
- static fromTriageProjection({ qr, items }) {
11
- const tid = String(qr.triageId);
12
- const identifiers = [identifier('triage', tid)];
13
- if (qr.questionnaireId) identifiers.push(identifier('questionnaire-week', String(qr.questionnaireId)));
14
- const payload = {
15
- resourceType: 'QuestionnaireResponse',
16
- id: fhirId(`triage-${tid}`),
17
- identifier: identifiers,
18
- questionnaire: `${getQuestionnaireCanonicalUrl()}|${getProctcaeVersion()}`,
19
- status: (qr.completed ?? true) ? 'completed' : 'in-progress',
20
- subject: patientReference(qr.patientId),
21
- source: patientReference(qr.patientId),
22
- };
23
- if (qr.authored) payload.authored = toIso(qr.authored);
24
- if (items.length) payload.item = items;
25
- return new QuestionnaireResponse(payload);
26
- }
27
- }
28
-
29
- module.exports = { QuestionnaireResponse };