Tipos, validators y resolver
Tipos FHIR R4
Sección titulada «Tipos FHIR R4»35 recursos R4 hand-crafted (no autogenerados). Distribución por dominio:
| Dominio | Recursos |
|---|---|
| Clínico | Patient, Encounter, Condition, Observation, Procedure, AllergyIntolerance, MedicationRequest, Medication, DiagnosticReport, Specimen |
| Documentos | DocumentReference, Communication |
| Planificación | CarePlan, Task, ServiceRequest, PlanDefinition, ActivityDefinition |
| Administrativo | Coverage, Flag, RelatedPerson |
| Facturación | Invoice, ChargeItem, PaymentNotice |
| Agendamiento | Appointment, Schedule, Slot |
| Organizacional | Organization, Location, Device, Practitioner, PractitionerRole, HealthcareService |
| Cuestionarios | Questionnaire, QuestionnaireResponse |
| Infraestructura | Bundle |
ResourceTypeMap
Sección titulada «ResourceTypeMap»Record<ResourceType, Type> permite que el cliente infiera el tipo de
retorno automáticamente sin pasar genéricos:
const patient = await fhir.read('Patient', id);// ^ Patient (inferido)
const obs = await fhir.read('Observation', id);// ^ Observation (inferido)Esto reemplaza el patrón fhir.read<Patient>('Patient', id) que era
verbose y propenso a errores.
Helpers exportados
Sección titulada «Helpers exportados»ref(resourceType, id, display?)
Sección titulada «ref(resourceType, id, display?)»Construye un Reference FHIR canonical:
import { ref } from 'emafhir';
const r = ref('Patient', 'abc123', 'Ana Pérez');// → { reference: "Patient/abc123", display: "Ana Pérez" }transaction() builder
Sección titulada «transaction() builder»Construye un Bundle de tipo transaction o batch:
import { transaction } from 'emafhir';
const bundle = transaction() .create(patient) .create(observation) .update(encounter) .delete('Task', 'task-123') .build();
await fhir.transaction(bundle);search() builder
Sección titulada «search() builder»Fluent API para construir SearchParameters:
import { search } from 'emafhir';
const params = search() .where('name', 'García') .whereToken('gender', 'http://hl7.org/fhir/administrative-gender', 'female') .whereDate('birthdate', 'ge', '1990-01-01') .include('Patient:general-practitioner') .sort('-_lastUpdated') .count(20) .build();
const result = await fhir.searchResources('Patient', params);Validators (subpath emafhir/validators)
Sección titulada «Validators (subpath emafhir/validators)»Cuatro validadores de identificadores nacionales, todos puros (estructura + checksum, sin lookups externos a SII / RENAPO / SAT / RENIEC):
| País | Función | Verifica |
|---|---|---|
| Chile | validateRun | RUN módulo 11. Acepta 12.345.678-K y 123456785 |
| México | validateCurp | CURP estructura (18 chars, H/M, 32 estados RENAPO) |
| México | validateRfc | RFC estructura — persona física (13 chars), moral (12), permite Ñ y & (spec SAT) |
| Perú | validateDni | DNI estructura (8 dígitos numéricos) |
Todas devuelven { valid: boolean, normalized: string }:
import { validateRun, validateCurp } from 'emafhir/validators';
validateRun('12.345.678-5'); // { valid: true, normalized: '12345678-5' }validateRun('12.345.678-K'); // { valid: false, normalized: null }validateCurp('garc850315hdfllr03'); // { valid: true, normalized: 'GARC850315HDFLLR03' }ProfileResolver
Sección titulada «ProfileResolver»Clase que resuelve el canonical URL de un perfil FHIR para un país y un
recurso, leyendo runtime desde emashared.countries.
Fórmula
Sección titulada «Fórmula»profile_url = `${ig_canonical_base}/StructureDefinition/${resourceType}`Sin sufijo de versión. Aidbox FAR resuelve la versión activa al momento del write/read (ver ADR-0002).
const resolver = new ProfileResolver(supabaseClient);
// Resolver perfil para un país y recursoconst url = await resolver.getProfileUrl('CL', 'Patient');// → 'https://emahealth.io/fhir/cl/StructureDefinition/Patient'
// Listar países activosconst countries = await resolver.getSupportedCountries();// → ['CL', 'MX', 'PE', 'CO', 'BR', 'AR', 'CR']
// Forzar refresh del cache (Vault llama a esto on CRUD de país)resolver.invalidate();Comportamiento del cache
Sección titulada «Comportamiento del cache»Por qué importa el dedup: si 100 writes simultáneos llegan al worker y el cache está vacío, sólo una query a Supabase se ejecuta. Las demás esperan la misma promesa.
Meta auto-inject (injectMeta)
Sección titulada «Meta auto-inject (injectMeta)»Función async idempotente que agrega/actualiza:
meta.profile— canonical resuelto viaProfileResolver, sin versión.meta.tag = [{ system: 'urn:ema:tenant', code: tenant.id }]meta.tag = [{ system: 'urn:ema:ig-version', code: tenant.igVersion }]
import { injectMeta } from 'emafhir';
const enriched = await injectMeta(resource, tenant, profileResolver);Idempotente: llamarla dos veces sobre el mismo recurso no duplica tags ni profiles. Inmutable: el input no se mutea, devuelve un nuevo objeto. Preserva tags externos que no estén en los namespaces que controla.