IHE Source
Implement IHE (Integrating the Healthcare Enterprise) profiles such as XDS.b, PIX, and PDQ for standards-based healthcare data exchange.
Overview
The IHE source implements server-side actors for IHE integration profiles. IHE profiles define specific implementations of healthcare standards (HL7, DICOM, FHIR) for particular use cases such as cross-enterprise document sharing, patient identity management, and patient demographics querying.
Each profile defines a set of transactions between actors. The IHE source acts as the receiving actor (e.g. Document Repository in XDS.b, PIX Manager in PIX, Demographics Supplier in PDQ) and processes incoming transactions through the intu pipeline.
Configuration
listener:
type: ihe
ihe:
profile: PIX
port: 8080
tls:
cert_file: /etc/intu/certs/ihe.crt
key_file: /etc/intu/certs/ihe.key
auth:
type: basic
username: ${IHE_USER}
password: ${IHE_PASS}
Properties
XDS.b, PIX, PDQ.cert_file and key_file.basic, bearer, and saml types depending on the profile.Supported Profiles
| Profile | Full Name | Actor Role | Key Transactions |
|---|---|---|---|
XDS.b |
Cross-Enterprise Document Sharing | Document Repository / Registry | ITI-41 (Provide and Register), ITI-42 (Register), ITI-43 (Retrieve) |
PIX |
Patient Identifier Cross-referencing | PIX Manager | ITI-8 (Patient Identity Feed), ITI-9 (PIX Query) |
PDQ |
Patient Demographics Query | Demographics Supplier | ITI-21 (Patient Demographics Query), ITI-22 (Patient Demographics and Visit Query) |
Complete Example
An IHE PIX Manager that receives patient identity feed transactions (ITI-8) and cross-references patient identifiers across assigning authorities.
id: pix-manager-inbound
enabled: true
listener:
type: ihe
ihe:
profile: PIX
port: 8080
tls:
cert_file: /etc/intu/certs/ihe.crt
key_file: /etc/intu/certs/ihe.key
auth:
type: basic
username: ${IHE_USER}
password: ${IHE_PASS}
validator:
runtime: node
entrypoint: validator.ts
transformer:
runtime: node
entrypoint: transformer.ts
destinations:
- master-patient-index
- audit-repository
TypeScript Transformer Example
This transformer processes a PIX Patient Identity Feed (ITI-8) message, which arrives as an HL7v2 ADT message, and produces a cross-reference record for the master patient index.
import { Message, TransformResult } from "@intu/sdk";
interface PatientIdentifier {
value: string;
assigningAuthority: string;
identifierType: string;
}
interface CrossReferenceRecord {
action: "add" | "update" | "merge";
identifiers: PatientIdentifier[];
demographics: {
familyName: string;
givenName: string;
dateOfBirth: string;
gender: string;
};
mergedFrom?: PatientIdentifier;
sourceSystem: string;
timestamp: string;
}
export default function transform(msg: Message): TransformResult {
const raw = msg.body as string;
const segments = raw.split("\r").filter(Boolean);
const segmentMap = new Map<string, string[]>();
for (const seg of segments) {
const fields = seg.split("|");
segmentMap.set(fields[0], fields);
}
const msh = segmentMap.get("MSH");
const evn = segmentMap.get("EVN");
const pid = segmentMap.get("PID");
const mrg = segmentMap.get("MRG");
if (!msh || !pid) {
return { success: false, error: "Missing required MSH or PID segment" };
}
const eventType = msh[8]?.split("^")[1] || "";
const action = resolveAction(eventType);
const identifiers = parseIdentifiers(pid[3] || "");
const nameParts = (pid[5] || "").split("^");
const record: CrossReferenceRecord = {
action,
identifiers,
demographics: {
familyName: nameParts[0] || "",
givenName: nameParts[1] || "",
dateOfBirth: formatDate(pid[7] || ""),
gender: pid[8] || "",
},
sourceSystem: msh[3] || "",
timestamp: evn?.[2] || msh[6] || new Date().toISOString(),
};
if (action === "merge" && mrg) {
const mergedIds = parseIdentifiers(mrg[1] || "");
if (mergedIds.length > 0) {
record.mergedFrom = mergedIds[0];
}
}
return {
success: true,
body: JSON.stringify(record),
contentType: "application/json",
};
}
function resolveAction(eventType: string): "add" | "update" | "merge" {
switch (eventType) {
case "A01":
case "A04":
case "A28":
return "add";
case "A08":
case "A31":
return "update";
case "A40":
return "merge";
default:
return "update";
}
}
function parseIdentifiers(field: string): PatientIdentifier[] {
return field.split("~").map((id) => {
const parts = id.split("^");
return {
value: parts[0] || "",
assigningAuthority: parts[3]?.split("&")[0] || "",
identifierType: parts[4] || "",
};
});
}
function formatDate(hl7Date: string): string {
if (hl7Date.length < 8) return "";
return `${hl7Date.slice(0, 4)}-${hl7Date.slice(4, 6)}-${hl7Date.slice(6, 8)}`;
}