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.

Note IHE profiles are complex interoperability specifications. Review the IHE Technical Framework documentation for your chosen profile to understand the full set of requirements and message formats.

Configuration

yaml
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

profile string required
The IHE integration profile to implement. Supported values: XDS.b, PIX, PDQ.
port int required
The TCP port to listen on for incoming IHE transactions.
tls object optional
TLS configuration for encrypted transport. Required by the IHE Audit Trail and Node Authentication (ATNA) profile. Contains cert_file and key_file.
auth object optional
Authentication configuration. Supports 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.

yaml
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.

typescript
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)}`;
}