npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@simplefhir/cda

v0.1.1

Published

CDA and C-CDA XML clinical document parser and FHIR R4 transformer for SimpleFHIR

Readme

SimpleFHIR

Add FHIR R4 to a Node.js backend without running a separate FHIR server stack.

License TypeScript Node.js FHIR

SimpleFHIR is a TypeScript-first FHIR R4 runtime for Node.js. It lets backend developers add FHIR routes, resource validation, search, persistence, versioning, CapabilityStatement generation, OperationOutcome errors, and interoperability features to an existing application with minimal configuration.


Quick Start

NestJS

npm install @simplefhir/nestjs
// src/app.module.ts
import { Module } from '@nestjs/common';
import { FhirModule } from '@simplefhir/nestjs';

@Module({
  imports: [
    FhirModule.forRoot({
      version: 'R4',
      basePath: '/fhir',
    }),
  ],
})
export class AppModule {}

Start your application and SimpleFHIR exposes a FHIR endpoint alongside your existing API:

GET    /fhir/metadata

GET    /fhir/Patient
POST   /fhir/Patient
GET    /fhir/Patient/:id
PUT    /fhir/Patient/:id
DELETE /fhir/Patient/:id

GET    /fhir/Observation
POST   /fhir/Observation

GET    /fhir/Encounter
POST   /fhir/Encounter

Test it:

curl http://localhost:3000/fhir/metadata \
  -H "Accept: application/fhir+json"

Create a patient:

curl -X POST http://localhost:3000/fhir/Patient \
  -H "Content-Type: application/fhir+json" \
  -d '{
    "resourceType": "Patient",
    "name": [
      {
        "family": "Smith",
        "given": ["Alice"]
      }
    ],
    "gender": "female",
    "birthDate": "1990-04-12"
  }'

Search:

curl "http://localhost:3000/fhir/Patient?name=Smith&gender=female" \
  -H "Accept: application/fhir+json"

Why SimpleFHIR?

FHIR is a powerful interoperability standard, but adding a FHIR server surface to a Node.js application can require a large amount of infrastructure and specification-specific code.

Backend teams often end up choosing between:

  • deploying a separate Java/JVM-based FHIR server;
  • implementing FHIR REST behavior manually;
  • building search, validation, versioning, Bundles, and OperationOutcome handling themselves;
  • coupling application code to a specific database or framework.

SimpleFHIR is designed to make that integration feel native to Node.js.

Existing Node.js Application
        │
        ├── /api/users
        ├── /api/billing
        ├── /api/dashboard
        │
        └── SimpleFHIR
              │
              ├── /fhir/metadata
              ├── /fhir/Patient
              ├── /fhir/Observation
              └── /fhir/Encounter

The goal is simple:

Install a package, configure the resources you need, and add a real FHIR R4 API to your existing backend.

SimpleFHIR does not replace FHIR with a proprietary healthcare data model. The API surface remains FHIR.


What SimpleFHIR Handles

SimpleFHIR centralizes the FHIR-specific work that application developers should not have to rebuild for every project:

  • FHIR R4 resource routing
  • CRUD interactions
  • FHIR search parsing
  • SearchSet Bundles
  • CapabilityStatement generation
  • OperationOutcome errors
  • resource validation
  • resource versioning and history
  • lifecycle hooks
  • framework-independent authorization
  • PostgreSQL persistence
  • Prisma persistence
  • SMART on FHIR helpers
  • terminology operations
  • HL7 v2 conversion
  • C-CDA conversion
  • Bulk Data export
  • developer CLI tooling

Architecture

SimpleFHIR keeps FHIR logic separate from framework and database integrations.

┌───────────────────────────────────────────────┐
│            Existing Application               │
│        NestJS / Express / Fastify             │
└──────────────────────┬────────────────────────┘
                       │
                       ▼
┌───────────────────────────────────────────────┐
│            Framework Adapter                  │
│  @simplefhir/nestjs                           │
│  @simplefhir/express                          │
│  @simplefhir/fastify                          │
└──────────────────────┬────────────────────────┘
                       │
                       ▼
┌───────────────────────────────────────────────┐
│              @simplefhir/core                 │
│                                               │
│  Router           Request Engine              │
│  Resource Registry                            │
│  Search Parser + Search AST                   │
│  Validator                                    │
│  Bundle Builder                               │
│  CapabilityStatement Builder                  │
│  OperationOutcome Builder                     │
│  Hooks + Authorization                        │
└──────────────────────┬────────────────────────┘
                       │
                       ▼
┌───────────────────────────────────────────────┐
│             Storage Interface                 │
└──────────────────────┬────────────────────────┘
                       │
            ┌──────────┴──────────┐
            ▼                     ▼
   @simplefhir/prisma    @simplefhir/postgres
            │                     │
            └──────────┬──────────┘
                       ▼
                  PostgreSQL

Architectural rule

@simplefhir/core contains FHIR knowledge.

It should not contain NestJS, Express, Fastify, Prisma, or PostgreSQL-specific logic.

Framework and storage integrations are implemented as adapters around the core runtime.


Packages

| Package | Purpose | |---|---| | @simplefhir/core | Framework-independent FHIR R4 runtime | | @simplefhir/nestjs | NestJS integration | | @simplefhir/express | Express router and middleware | | @simplefhir/fastify | Fastify plugin | | @simplefhir/prisma | Prisma + PostgreSQL storage adapter | | @simplefhir/postgres | Direct PostgreSQL storage adapter | | @simplefhir/terminology | Terminology lookup, expansion, and validation | | @simplefhir/smart | SMART on FHIR discovery and scope enforcement | | @simplefhir/hl7v2 | HL7 v2 parsing and FHIR conversion | | @simplefhir/cda | C-CDA parsing and FHIR conversion | | @simplefhir/bulk-data | FHIR Bulk Data export | | @simplefhir/cli | Validation, scaffolding, and inspection CLI |


Supported FHIR Resources

SimpleFHIR can be configured to expose only the resources your application needs.

Example:

FhirModule.forRoot({
  version: 'R4',

  resources: [
    'Patient',
    'Practitioner',
    'Organization',
    'Encounter',
    'Observation',
    'Condition',
    'AllergyIntolerance',
    'MedicationRequest',
    'DiagnosticReport',
    'DocumentReference',
    'Appointment',
    'CarePlan',
  ],
});

Or configure interactions per resource:

FhirModule.forRoot({
  resources: {
    Patient: {
      interactions: {
        read: true,
        create: true,
        update: true,
        delete: false,
        search: true,
      },

      search: [
        'name',
        'identifier',
        'birthdate',
        'gender',
      ],
    },

    Observation: {
      interactions: {
        read: true,
        create: true,
        update: true,
        delete: false,
        search: true,
      },

      search: [
        'patient',
        'subject',
        'code',
        'date',
        'category',
      ],
    },
  },
});

The same configuration is used to generate the server's CapabilityStatement.


Framework Integrations

NestJS

npm install @simplefhir/nestjs
import { Module } from '@nestjs/common';
import { FhirModule } from '@simplefhir/nestjs';

@Module({
  imports: [
    FhirModule.forRoot({
      version: 'R4',
      basePath: '/fhir',
    }),
  ],
})
export class AppModule {}

Async configuration is also supported:

FhirModule.forRootAsync({
  inject: [ConfigService],

  useFactory: (config: ConfigService) => ({
    version: 'R4',
    basePath: config.get('FHIR_BASE_PATH') ?? '/fhir',
  }),
});

Express

npm install @simplefhir/express express
import express from 'express';
import { fhir } from '@simplefhir/express';

const app = express();

app.use(
  '/fhir',
  fhir({
    version: 'R4',
    resources: [
      'Patient',
      'Observation',
      'Encounter',
      'Condition',
    ],
  }),
);

app.listen(3000, () => {
  console.log('SimpleFHIR running at http://localhost:3000/fhir/metadata');
});

Fastify

npm install @simplefhir/fastify fastify
import Fastify from 'fastify';
import { fhirPlugin } from '@simplefhir/fastify';

async function start() {
  const fastify = Fastify({
    logger: true,
  });

  await fastify.register(fhirPlugin, {
    prefix: '/fhir',
    version: 'R4',
    resources: [
      'Patient',
      'Observation',
      'Encounter',
    ],
  });

  await fastify.listen({
    port: 3000,
    host: '0.0.0.0',
  });
}

void start();

Development Storage

The default/in-memory storage adapter is intended for:

  • quick starts;
  • examples;
  • local development;
  • unit and integration tests.
FhirModule.forRoot()

No external database is required for the simplest local setup.

Do not use in-memory storage for production healthcare data.


Production Persistence

PostgreSQL + Prisma

npm install @simplefhir/nestjs @simplefhir/prisma @prisma/client
npm install -D prisma
import { Module } from '@nestjs/common';
import { PrismaClient } from '@prisma/client';
import { FhirModule } from '@simplefhir/nestjs';
import { prismaAdapter } from '@simplefhir/prisma';

const prisma = new PrismaClient();

@Module({
  imports: [
    FhirModule.forRoot({
      version: 'R4',
      basePath: '/fhir',
      storage: prismaAdapter(prisma),
    }),
  ],
})
export class AppModule {}

The Prisma adapter uses a hybrid persistence model:

FHIR Resource
     │
     ├── Canonical resource JSON → PostgreSQL JSONB
     │
     └── Search parameter extraction
              │
              ├── string indexes
              ├── token indexes
              ├── date indexes
              └── reference indexes

This keeps the complete FHIR resource intact while allowing searchable fields to use database indexes.

Typical resource storage contains:

id
resource_type
version_id
resource_json
created_at
updated_at
deleted_at
tenant_id

Search indexes are maintained separately for FHIR search parameter types.

Direct PostgreSQL

If you prefer pg without Prisma:

npm install @simplefhir/postgres pg
npm install -D @types/pg
import { Pool } from 'pg';
import { postgresAdapter } from '@simplefhir/postgres';

const pool = new Pool({
  connectionString: process.env.DATABASE_URL,
});

const storage = postgresAdapter(pool);

await storage.initSchema();

FhirModule.forRoot({
  storage,
});

FHIR Search

SimpleFHIR parses FHIR search syntax into a database-independent Search AST.

Example request:

GET /fhir/Observation?patient=123&date=gt2026-01-01&_count=20

Conceptually becomes:

{
  resourceType: 'Observation',

  filters: [
    {
      parameter: 'patient',
      type: 'reference',
      operator: 'eq',
      value: '123',
    },
    {
      parameter: 'date',
      type: 'date',
      operator: 'gt',
      value: '2026-01-01',
    },
  ],

  pagination: {
    count: 20,
  },
}

The storage adapter translates this representation into database-specific queries.

This prevents @simplefhir/core from being coupled to Prisma or PostgreSQL.

Search parameter types

SimpleFHIR's search architecture supports FHIR search types such as:

  • string
  • token
  • reference
  • date
  • number
  • quantity
  • URI

Search responses are returned as FHIR Bundle resources with:

{
  "resourceType": "Bundle",
  "type": "searchset",
  "total": 1,
  "entry": []
}

Validation

SimpleFHIR validates resources before persistence and returns FHIR OperationOutcome resources for validation errors.

Example:

{
  "resourceType": "OperationOutcome",
  "issue": [
    {
      "severity": "error",
      "code": "invalid",
      "diagnostics": "Patient.gender contains an invalid value"
    }
  ]
}

Validation is designed as a replaceable subsystem so applications can use progressively stronger validation, including profiles, FHIRPath-based invariants, and terminology validation.


Versioning and History

FHIR resources can carry:

{
  "meta": {
    "versionId": "3",
    "lastUpdated": "2026-09-02T12:00:00Z"
  }
}

Updates increment meta.versionId.

History support is designed around immutable resource versions so previous resource states can be retained rather than overwritten.

Typical history routes include:

GET /fhir/Patient/:id/_history
GET /fhir/Patient/:id/_history/:version

Transactions and Batch Bundles

SimpleFHIR supports FHIR Bundle-based operations such as transactions and batches.

Example transaction:

curl -X POST http://localhost:3000/fhir \
  -H "Content-Type: application/fhir+json" \
  -d '{
    "resourceType": "Bundle",
    "type": "transaction",
    "entry": [
      {
        "request": {
          "method": "POST",
          "url": "Patient"
        },
        "resource": {
          "resourceType": "Patient",
          "name": [
            {
              "family": "Doe"
            }
          ]
        }
      }
    ]
  }'

For transactional storage adapters, transaction entries are executed atomically.


Lifecycle Hooks

SimpleFHIR exposes hooks for application-specific behavior without putting business logic into the FHIR core.

import { defineConfig } from '@simplefhir/core';

export default defineConfig({
  version: 'R4',
  basePath: '/fhir',

  hooks: {
    beforeCreate: async (resource, context) => {
      console.log(`Creating ${resource.resourceType}`);
    },

    afterCreate: async (resource, context) => {
      await eventBus.publish(
        'fhir.resource.created',
        resource,
      );
    },

    beforeDelete: async (resourceType, id, context) => {
      console.log(`Deleting ${resourceType}/${id}`);
    },
  },
});

Supported lifecycle stages include:

beforeRequest / afterRequest

beforeCreate / afterCreate
beforeRead / afterRead
beforeUpdate / afterUpdate
beforeDelete / afterDelete
beforeSearch / afterSearch
beforeValidate / afterValidate

Authorization

SimpleFHIR does not force your application to adopt a specific authentication provider.

Your application can continue using:

  • Passport
  • JWT
  • Auth0
  • Keycloak
  • Clerk
  • Firebase
  • Microsoft Entra ID / Azure AD
  • custom authentication

SimpleFHIR receives the authenticated user/context and performs authorization through a framework-independent hook:

FhirModule.forRoot({
  authorization: async ({
    user,
    resourceType,
    interaction,
  }) => {
    if (!user) {
      return {
        allowed: false,
      };
    }

    if (
      resourceType === 'Patient' &&
      interaction === 'delete'
    ) {
      return {
        allowed: false,
      };
    }

    return {
      allowed: true,
    };
  },
});

Denied FHIR requests are returned as OperationOutcome responses.


SMART on FHIR

Install:

npm install @simplefhir/smart

The SMART package provides helpers for:

  • SMART discovery;
  • OAuth2 / OIDC integration;
  • SMART scopes;
  • patient context;
  • encounter context;
  • patient-compartment enforcement;
  • EHR and standalone launch workflows.

Example:

import {
  createSmartAuthorization,
  SmartConfigBuilder,
} from '@simplefhir/smart';

const smartConfiguration = SmartConfigBuilder.build({
  issuer: 'https://auth.hospital.org',
  authorizationUrl: 'https://auth.hospital.org/oauth/authorize',
  tokenUrl: 'https://auth.hospital.org/oauth/token',
});

const authorization = createSmartAuthorization({
  enforcePatientCompartment: true,
});

SimpleFHIR should integrate with an existing identity provider rather than encouraging applications to build an insecure custom OAuth server.


Terminology

Install:

npm install @simplefhir/terminology
import {
  createTerminologyService,
} from '@simplefhir/terminology';

const terminology = createTerminologyService();

const lookup = await terminology.lookup(
  'http://loinc.org',
  '883-9',
);

const expansion = await terminology.expand(
  'http://hl7.org/fhir/ValueSet/administrative-gender',
);

const result = await terminology.validateCode({
  valueSetUrl:
    'http://hl7.org/fhir/ValueSet/administrative-gender',
  code: 'female',
});

Supported terminology capabilities include:

$lookup
$expand
$validate-code

Terminology providers are designed to be replaceable so applications can use local terminology data or an external terminology service.


HL7 v2 → FHIR

Install:

npm install @simplefhir/hl7v2
import {
  convertHL7v2ToFhir,
} from '@simplefhir/hl7v2';

const message = `MSH|^~\\&|HOSPITAL|ADT|RECEIVER|DEST|20260902120000||ADT^A01|MSG001|P|2.5
PID|1||MRN98765^^^HOSPITAL||DOE^JOHN^A||19800515|M
PV1|1|I|ROOM101^^BED1||||12345^SMITH^ALICE^MD`;

const resources = convertHL7v2ToFhir(message);

The HL7 v2 package focuses on parsing and transformation, while persistence remains the responsibility of the configured FHIR runtime/storage adapter.


C-CDA → FHIR

Install:

npm install @simplefhir/cda
import fs from 'node:fs';
import {
  convertCdaToFhir,
} from '@simplefhir/cda';

const xml = fs.readFileSync(
  'continuity-of-care-document.xml',
  'utf8',
);

const resources = convertCdaToFhir(xml);

The CDA package is intended for importing clinical document content into FHIR resources such as Patient, DocumentReference, Condition, AllergyIntolerance, and Observation, depending on the source document.


FHIR Bulk Data Export

Install:

npm install @simplefhir/bulk-data
import {
  BulkExportJobManager,
} from '@simplefhir/bulk-data';

const manager = new BulkExportJobManager({
  storage: yourStorageAdapter,
  baseUrl: 'https://api.hospital.org/fhir',
});

const exportJob = await manager.startExport({
  requestUrl: '/fhir/$export',
  resourceTypes: [
    'Patient',
    'Observation',
  ],
});

The Bulk Data package is designed around asynchronous export jobs and NDJSON output.


CLI

Install or run through npx:

npx simplefhir init

Useful commands:

# Create a SimpleFHIR configuration file
npx simplefhir init

# Validate a FHIR R4 JSON resource
npx simplefhir validate patient.json

# Inspect extracted search indexes
npx simplefhir inspect observation.json

Configuration

A fuller configuration can look like this:

import {
  defineConfig,
} from '@simplefhir/core';

export default defineConfig({
  version: 'R4',

  basePath: '/fhir',

  resources: {
    Patient: {
      interactions: {
        read: true,
        create: true,
        update: true,
        delete: false,
        search: true,
      },

      search: [
        'name',
        'gender',
        'birthdate',
        'identifier',
      ],
    },
  },

  hooks: {
    beforeCreate: async (resource) => {
      console.log(
        `Creating ${resource.resourceType}`,
      );
    },
  },

  defaultPageCount: 20,
  maxPageCount: 100,

  strictValidation: true,
});

The configuration acts as a shared source of truth for:

  • enabled resources;
  • resource interactions;
  • supported search parameters;
  • validation behavior;
  • routing;
  • authorization;
  • lifecycle hooks;
  • generated CapabilityStatement.

Example Applications

| Example | Stack | |---|---| | examples/nestjs-basic | NestJS + in-memory storage | | examples/nestjs-prisma | NestJS + PostgreSQL + Prisma | | examples/express-basic | Express + SimpleFHIR | | examples/fastify-basic | Fastify + SimpleFHIR | | examples/smart-on-fhir | SMART on FHIR authorization |

Typical usage:

cd examples/nestjs-basic
pnpm install
pnpm start

Development

Install dependencies:

pnpm install

Build all packages:

pnpm build

Run tests:

pnpm test:unit

Design Principles

1. FHIR stays FHIR

SimpleFHIR simplifies configuration and infrastructure. It does not replace FHIR resources with a proprietary data model.

2. Simple defaults, advanced escape hatches

The simplest setup should remain:

FhirModule.forRoot()

Advanced applications can configure storage, validation, resources, authorization, hooks, terminology, and interoperability modules.

3. Framework-independent core

@simplefhir/core must not import NestJS, Express, Fastify, Prisma, or PostgreSQL.

4. Database-independent search

FHIR search is parsed into a Search AST before storage-specific adapters translate it into database queries.

5. Existing authentication stays in place

SimpleFHIR integrates with the application's identity and authentication system rather than replacing it.

6. Production boundaries are explicit

A development server can be started with minimal configuration. Production deployments still require deliberate decisions around persistence, identity, authorization, audit, terminology, backups, observability, and infrastructure security.


Security and Compliance

SimpleFHIR provides infrastructure for implementing secure FHIR APIs, but using SimpleFHIR does not automatically make an application compliant with HIPAA, GDPR, MDR, or any other regulatory framework.

Production healthcare deployments should consider, at minimum:

  • TLS;
  • strong authentication;
  • resource-level authorization;
  • SMART scopes where applicable;
  • tenant isolation;
  • audit logging;
  • encrypted secrets;
  • secure database access;
  • backup and recovery;
  • data retention requirements;
  • protected health information in application logs;
  • deployment-region and data-residency requirements.

Resource bodies should not be written to ordinary application logs by default.


Project Direction

SimpleFHIR is designed to grow in three layers:

Phase 1
Simple FHIR Server
    ↓
CRUD + Search + Validation
CapabilityStatement
OperationOutcome
Persistence

Phase 2
Reusable FHIR Runtime
    ↓
History + Transactions
Advanced Search
Profiles + FHIRPath
Terminology
Subscriptions
Multi-tenancy

Phase 3
Interoperability Platform
    ↓
SMART on FHIR
Bulk Data
HL7 v2
C-CDA
Developer tooling
Observability

The product philosophy remains the same at every layer:

Simple on the outside. FHIR on the wire. Extensible underneath.


Contributing

Contributions are welcome.

Before opening a large pull request:

  1. open an issue describing the change;
  2. keep FHIR-specific logic inside @simplefhir/core;
  3. keep framework/database-specific behavior inside adapters;
  4. include tests for public behavior;
  5. avoid introducing breaking public APIs without discussion.