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

diabetic-utils

v1.5.0

Published

Zero-bloat TypeScript utilities for diabetes data: glucose, A1C, conversions, time-in-range, and more.

Readme

🩸 Diabetic Utils

Built and maintained by Mark Learst.

A TypeScript toolkit for diabetes analytics and health data.

Diabetic Utils Logo

A modern, strictly-typed utility library for glucose, A1C, insulin, and diabetes metrics. Designed for reliability and transparency—no bloat, no guesswork, just robust utilities with referenced formulas from published guidelines.

Disclaimer: This library is for informational and educational purposes only. It does not constitute medical advice, diagnosis, or treatment. Always consult a qualified healthcare provider for medical decisions.

v1.5.0 adds a full advanced CGM metrics suite, CGM vendor adapters, and health data interoperability (FHIR, Open mHealth).


📊 Status & Quality

Status codecov CI TypeScript Coverage npm npm downloads License


🚀 What's New in v1.5.0

📈 Advanced CGM Metrics Suite

A complete set of published CGM analytics, each with peer-reviewed references:

  • ADRR: Average Daily Risk Range (Kovatchev 2006)
  • GRADE: Glycemic Risk Assessment Diabetes Equation with hypo/eu/hyper partitioning (Hill 2007)
  • J-Index: Composite mean + variability score (Wojcicki 1995)
  • CONGA: Continuous Overall Net Glycemic Action for intra-day variability (McDonnell 2005)
  • Active Percent: CGM wear-time tracking against clinical thresholds (Danne 2017)
  • AGP Aggregate: Single-call calculateAGPMetrics() computes all Tier 1 metrics at once
  • LBGI / HBGI: Low/High Blood Glucose Index (Kovatchev 2006)
  • GRI: Glycemia Risk Index with zone A-E classification (Klonoff 2023)
  • MODD: Mean of Daily Differences for day-to-day variability (Service 1980)

🔌 CGM Connector Adapters

Pure transformation helpers that normalize vendor payloads into a canonical NormalizedCGMReading type:

  • Dexcom Share — normalize Dexcom Share API responses
  • Libre LinkUp — normalize Libre LinkUp API responses
  • Nightscout — normalize Nightscout SGV entries

🏥 Health Data Interoperability

Build standards-compliant payloads for health data exchange:

  • FHIR CGM IG — HL7 FHIR-aligned CGM summary and sensor reading observations
  • Open mHealth — OMH blood-glucose datapoints with full header support

✅ 337 Passing Tests

  • 100% coverage across lines, branches, functions, and statements
  • New edge-case coverage for out-of-order timestamps, mixed units, and cross-module interactions

📦 Installation

npm install diabetic-utils
# or
pnpm add diabetic-utils
# or
yarn add diabetic-utils

Requirements: TypeScript 4.5+ or JavaScript (ES2020+)


⚡ Quick Start

Basic Conversions & Calculations

import {
  mgDlToMmolL,
  mmolLToMgDl,
  estimateGMI,
  estimateA1CFromAverage
} from 'diabetic-utils'

// Glucose unit conversions
mgDlToMmolL(180)  // → 10.0
mmolLToMgDl(5.5)  // → 99

// GMI calculation (multiple input formats)
estimateGMI(100, 'mg/dL')              // → 5.4
estimateGMI('5.5 mmol/L')              // → 5.4
estimateGMI({ value: 100, unit: 'mg/dL' })  // → 5.4

// A1C estimation
estimateA1CFromAverage(154, 'mg/dL')  // → 7.0

Enhanced Time-in-Range

import { calculateEnhancedTIR } from 'diabetic-utils'
import type { GlucoseReading } from 'diabetic-utils'

const readings: GlucoseReading[] = [
  { value: 120, unit: 'mg/dL', timestamp: '2024-01-01T08:00:00Z' },
  { value: 95,  unit: 'mg/dL', timestamp: '2024-01-01T08:05:00Z' },
  { value: 180, unit: 'mg/dL', timestamp: '2024-01-01T08:10:00Z' },
  // ... more readings
]

const result = calculateEnhancedTIR(readings)

console.log(`TIR: ${result.inRange.percentage}%`)
// TIR: 72.5%

console.log(`Very Low: ${result.veryLow.percentage}%`)
// Very Low: 0.5%

console.log(`Assessment: ${result.meetsTargets.overallAssessment}`)
// Assessment: good

console.log(result.meetsTargets.recommendations)
// ['All metrics meet consensus targets.']

Pregnancy TIR

import { calculatePregnancyTIR } from 'diabetic-utils'

const result = calculatePregnancyTIR(readings)

console.log(`TIR (63-140 mg/dL): ${result.inRange.percentage}%`)
// TIR (63-140 mg/dL): 85.2%

console.log(`Meets pregnancy targets: ${result.meetsPregnancyTargets}`)
// Meets pregnancy targets: true

console.log(result.recommendations)
// ['All metrics meet pregnancy consensus targets.', ...]

AGP Metrics (All-in-One)

import { calculateAGPMetrics } from 'diabetic-utils'
import type { GlucoseReading } from 'diabetic-utils'

const readings: GlucoseReading[] = [
  { value: 120, unit: 'mg/dL', timestamp: '2024-01-01T08:00:00Z' },
  { value: 95,  unit: 'mg/dL', timestamp: '2024-01-01T08:05:00Z' },
  { value: 180, unit: 'mg/dL', timestamp: '2024-01-01T08:10:00Z' },
  // ... more readings across multiple days
]

const agp = calculateAGPMetrics(readings)

console.log(`Mean: ${agp.meanGlucose} mg/dL`)
console.log(`SD: ${agp.sd}, CV: ${agp.cv}%`)
console.log(`LBGI: ${agp.lbgi}, HBGI: ${agp.hbgi}`)
console.log(`ADRR: ${agp.adrr}`)
console.log(`GRADE: ${agp.grade.gradeScore}`)
console.log(`GRI: ${agp.gri.gri} (Zone ${agp.gri.zone})`)
console.log(`J-Index: ${agp.jIndex}`)
console.log(`MODD: ${agp.modd} mg/dL`)
console.log(`CONGA: ${agp.conga} mg/dL`)
console.log(`Active: ${agp.activePercent.activePercent}%`)

CGM Connector Adapters

import {
  normalizeDexcomEntries,
  normalizeLibreEntries,
  normalizeNightscoutEntries
} from 'diabetic-utils'

// Normalize vendor data into a canonical format
const dexcomReadings = normalizeDexcomEntries(dexcomShareResponse)
const libreReadings = normalizeLibreEntries(libreLinkUpResponse)
const nightscoutReadings = normalizeNightscoutEntries(nightscoutSGVEntries)

// All return NormalizedCGMReading[] with:
//   { value, unit, timestamp, trend, source }
// Ready to pass into any diabetic-utils analytics function

FHIR & Open mHealth Export

import {
  buildFHIRCGMSummary,
  buildFHIRSensorReading,
  buildOMHDataPoint
} from 'diabetic-utils'

// Build a FHIR CGM summary observation
const fhirSummary = buildFHIRCGMSummary(tirResult, {
  start: '2024-01-01',
  end: '2024-01-14'
})

// Build a FHIR sensor reading observation
const fhirReading = buildFHIRSensorReading({
  value: 120, unit: 'mg/dL', timestamp: '2024-01-01T08:00:00Z'
})

// Build an Open mHealth blood-glucose datapoint
const omhPoint = buildOMHDataPoint(
  { value: 120, unit: 'mg/dL', timestamp: '2024-01-01T08:00:00Z' },
  'reading-001'
)

Glucose Labeling & Validation

import {
  getGlucoseLabel,
  isHypo,
  isHyper,
  isValidGlucoseValue
} from 'diabetic-utils'

// Label glucose values
getGlucoseLabel(60, 'mg/dL')   // → 'low'
getGlucoseLabel(5.5, 'mmol/L') // → 'normal'
getGlucoseLabel(200, 'mg/dL')  // → 'high'

// Threshold checks
isHypo(65, 'mg/dL')   // → true
isHyper(180, 'mg/dL') // → false

// Validation
isValidGlucoseValue(120, 'mg/dL')  // → true
isValidGlucoseValue(-10, 'mg/dL')  // → false

Variability Analytics

import {
  glucoseStandardDeviation,
  glucoseCoefficientOfVariation,
  glucosePercentiles,
  glucoseMAGE
} from 'diabetic-utils'

const data = [90, 100, 110, 120, 130, 140, 150, 160, 170, 180]

// Standard deviation (unbiased sample SD, n-1)
glucoseStandardDeviation(data)  // → 30.28

// Coefficient of variation (CV%)
glucoseCoefficientOfVariation(data)  // → 22.43

// Percentiles (nearest-rank method)
glucosePercentiles(data, [10, 50, 90])
// → { 10: 90, 50: 130, 90: 170 }

// MAGE (Mean Amplitude of Glycemic Excursions)
const mage = glucoseMAGE([100, 120, 80, 160, 90, 140, 70, 180])
console.log(`MAGE: ${mage} mg/dL`)

Custom Thresholds

import { getGlucoseLabel, isHypo, getA1CCategory } from 'diabetic-utils'

// Custom hypoglycemia threshold
isHypo(75, 'mg/dL', { mgdl: 80 })  // → true

// Custom hyperglycemia threshold
isHyper(9.0, 'mmol/L', { mmoll: 8.5 })  // → true

// Custom glucose label thresholds
getGlucoseLabel(75, 'mg/dL', {
  hypo: { mgdl: 80 },
  hyper: { mgdl: 160 }
})  // → 'low'

// Custom A1C category cutoffs
getA1CCategory(6.5, {
  normalMax: 6.0,
  prediabetesMax: 7.0
})  // → 'prediabetes'

🌟 Features

Core Utilities

  • Glucose Conversions: mg/dL ⇄ mmol/L
  • A1C Calculations: GMI, eAG, A1C estimation
  • Time-in-Range: Enhanced TIR (5 ranges), Pregnancy TIR
  • HOMA-IR: Insulin resistance calculation
  • Variability Metrics: SD, CV, MAGE, percentiles
  • Validation: Input guards, string parsing
  • Labeling: Glucose status (low/normal/high)

Advanced CGM Metrics

  • LBGI / HBGI: Low/High Blood Glucose Index (Kovatchev 2006)
  • GRI: Glycemia Risk Index with zone A-E classification (Klonoff 2023)
  • MODD: Mean of Daily Differences for day-to-day variability (Service 1980)
  • ADRR: Average Daily Risk Range (Kovatchev 2006)
  • GRADE: Glycemic Risk Assessment Diabetes Equation with partitioning (Hill 2007)
  • J-Index: Composite mean + variability score (Wojcicki 1995)
  • CONGA: Continuous Overall Net Glycemic Action (McDonnell 2005)
  • Active Percent: CGM wear-time tracking (Danne 2017)
  • AGP Aggregate: All Tier 1 metrics in a single call

CGM Connector Adapters

  • Dexcom Share: Normalize Dexcom Share API responses
  • Libre LinkUp: Normalize Libre LinkUp API responses
  • Nightscout: Normalize Nightscout SGV entries
  • Canonical Type: NormalizedCGMReading with trend + source metadata

Interoperability

  • FHIR CGM IG: Build HL7 FHIR-aligned CGM summary and sensor reading payloads
  • Open mHealth: Build OMH blood-glucose datapoints

Quality & DX

  • TypeScript-First: 100% strict mode, zero any types
  • 100% Test Coverage: 337 tests, all edge cases covered
  • Zero Dependencies: No bloat, tree-shakable
  • Published References: ADA, CDC, ISPAD, PubMed citations
  • TSDoc: Complete API documentation
  • ESM + CJS: Works everywhere
  • Type Predicates: Better type narrowing
  • Named Constants: Self-documenting formulas

🏆 Why Choose Diabetic Utils?

Referenced Formulas

Every formula, threshold, and calculation references published guidelines:

  • International Consensus on Time in Range (2019) - TIR calculations
  • ADA Standards of Care (2024) - Pregnancy targets, A1C guidelines
  • ISPAD Guidelines (2018) - Glucose variability metrics
  • NIH/NIDDK - HOMA-IR, eAG formulas
  • Kovatchev et al. (2006) - LBGI, HBGI, ADRR
  • Hill et al. (2007) - GRADE
  • Klonoff et al. (2023) - GRI
  • Wojcicki (1995) - J-Index
  • McDonnell et al. (2005) - CONGA
  • Danne et al. (2017) - Active Percent

Production-Ready

  • 100% Test Coverage - Every line tested
  • Type-Safe - Catch errors at compile time
  • Zero Dependencies - Small bundle, no supply chain risk
  • Modern ESM - Tree-shakable, works with Vite, Next.js, etc.

Developer-Friendly

  • Clear API - Predictable function signatures
  • Great DX - Autocomplete with literal types
  • Working Examples - Copy-paste ready code
  • Test Helpers - Utilities for your own tests

Unique Features

Only TypeScript/JavaScript library with:

  • Full AGP metrics suite in a single call
  • Enhanced TIR (5-range breakdown) and Pregnancy TIR
  • MAGE calculation (Service 1970)
  • ADRR, GRADE, J-Index, CONGA, and Active Percent
  • CGM vendor adapters (Dexcom, Libre, Nightscout)
  • FHIR CGM IG-aligned export utilities
  • LBGI/HBGI, GRI, and MODD metrics
  • Type predicates for validation

📚 Full API Reference

Glucose Conversions

  • mgDlToMmolL(value) - Convert mg/dL to mmol/L
  • mmolLToMgDl(value) - Convert mmol/L to mg/dL
  • convertGlucoseUnit({ value, unit }) - Generic unit conversion

A1C & GMI

  • estimateA1CFromAverage(glucose, unit) - A1C from average glucose
  • estimateGMI(input, unit?) - GMI from average glucose
  • a1cToGMI(a1c) - Convert A1C to GMI
  • estimateAvgGlucoseFromA1C(a1c) - A1C to estimated average glucose (mg/dL)

Time-in-Range

  • calculateTimeInRange(readings, low, high) - Basic TIR
  • calculateEnhancedTIR(readings, options?) - 5-range TIR
  • calculatePregnancyTIR(readings, options?) - Pregnancy TIR

Glucose Analysis

  • getGlucoseLabel(value, unit, thresholds?) - Label as low/normal/high
  • isHypo(value, unit, threshold?) - Check hypoglycemia
  • isHyper(value, unit, threshold?) - Check hyperglycemia
  • isValidGlucoseValue(value, unit) - Validate glucose value

A1C Analysis

  • getA1CCategory(a1c, cutoffs?) - Categorize A1C
  • isA1CInTarget(a1c, target?) - Check if A1C meets target

Variability Metrics

  • glucoseStandardDeviation(readings) - SD (unbiased)
  • glucoseCoefficientOfVariation(readings) - CV%
  • glucosePercentiles(readings, percentiles) - Percentile ranks
  • glucoseMAGE(readings, options?) - Mean Amplitude of Glycemic Excursions

Insulin Metrics

  • calculateHOMAIR(glucose, insulin, unit) - HOMA-IR
  • isValidInsulin(value) - Validate insulin value

Advanced CGM Metrics

  • calculateAGPMetrics(readings, options?) - All Tier 1 metrics in a single call
  • glucoseLBGI(readings) - Low Blood Glucose Index (Kovatchev 2006)
  • glucoseHBGI(readings) - High Blood Glucose Index (Kovatchev 2006)
  • calculateADRR(readings) - Average Daily Risk Range (Kovatchev 2006)
  • calculateGRADE(readings) - Glycemic Risk Assessment Diabetes Equation (Hill 2007)
  • calculateGRI(input) - Glycemia Risk Index with zone A-E (Klonoff 2023)
  • calculateJIndex(readings) - J-Index composite score (Wojcicki 1995)
  • calculateMODD(readings, options?) - Mean of Daily Differences (Service 1980)
  • calculateCONGA(readings, options?) - Continuous Overall Net Glycemic Action (McDonnell 2005)
  • calculateActivePercent(readings, options?) - CGM wear-time percentage (Danne 2017)

CGM Connector Adapters

  • normalizeDexcomEntries(entries) - Dexcom Share → NormalizedCGMReading[]
  • normalizeLibreEntries(entries) - Libre LinkUp → NormalizedCGMReading[]
  • normalizeNightscoutEntries(entries) - Nightscout SGV → NormalizedCGMReading[]

Interoperability

  • buildFHIRCGMSummary(tir, period, options?) - FHIR CGM summary observation
  • buildFHIRSensorReading(reading) - FHIR sensor reading observation
  • buildFHIRSensorReadings(readings) - FHIR sensor reading observations from a list of readings
  • buildOMHBloodGlucose(reading) - Open mHealth blood-glucose body
  • buildOMHBloodGlucoseList(readings) - Open mHealth blood-glucose bodies from a list of readings
  • buildOMHDataPoint(reading, id) - Full OMH datapoint with header

Utilities

  • parseGlucoseString(str) - Parse "120 mg/dL" → { value, unit }
  • formatGlucose(value, unit) - Format glucose with unit
  • isValidGlucoseString(str) - Validate glucose string

View Complete API Docs →


🧪 Test Helpers

The repository includes test utilities in tests/test-helpers.ts for contributors and downstream developers:

// In your test files (not published to npm — copy as needed)
import {
  createGlucoseReadings,
  COMMON_TEST_VALUES,
  TEST_TIMESTAMP_BASE
} from './tests/test-helpers'

// Create test data easily
const readings = createGlucoseReadings([100, 110, 120], 'mg/dL', 5)
// → 3 readings at 5-minute intervals

// Use common test values
const { NORMAL_GLUCOSE_MGDL, HYPO_GLUCOSE_MGDL } = COMMON_TEST_VALUES

🔬 References

All calculations reference peer-reviewed published sources:


🏗️ Architecture

diabetic-utils/
├── src/
│   ├── index.ts              # Main exports
│   ├── constants.ts          # Clinical thresholds & formulas
│   ├── types.ts              # TypeScript types
│   ├── conversions.ts        # Glucose unit conversions
│   ├── a1c.ts               # A1C & GMI calculations
│   ├── tir.ts               # Basic time-in-range
│   ├── tir-enhanced.ts      # Enhanced & pregnancy TIR
│   ├── glucose.ts           # Glucose utilities
│   ├── alignment.ts         # HOMA-IR
│   ├── variability.ts       # SD, CV, percentiles
│   ├── mage.ts              # MAGE calculation
│   ├── formatters.ts        # String formatting
│   ├── guards.ts            # Type guards
│   ├── validators.ts        # Input validation
│   ├── connectors/          # CGM vendor adapters
│   │   ├── dexcom.ts        # Dexcom Share normalization
│   │   ├── libre.ts         # Libre LinkUp normalization
│   │   ├── nightscout.ts    # Nightscout SGV normalization
│   │   └── types.ts         # Vendor & canonical types
│   ├── interop/             # Health data interoperability
│   │   ├── fhir.ts          # FHIR CGM IG payload builders
│   │   ├── openmhealth.ts   # Open mHealth payload builders
│   │   └── types.ts         # Interop payload types
│   └── metrics/             # Advanced CGM metrics
│       ├── agp.ts           # Aggregate AGP metrics
│       ├── bgi.ts           # LBGI / HBGI
│       ├── adrr.ts          # Average Daily Risk Range
│       ├── grade.ts         # GRADE score
│       ├── gri.ts           # Glycemia Risk Index
│       ├── jindex.ts        # J-Index
│       ├── modd.ts          # Mean of Daily Differences
│       ├── conga.ts         # CONGA
│       └── active-percent.ts # CGM wear time
├── tests/
│   ├── test-helpers.ts      # Shared test utilities
│   └── *.test.ts            # 100% coverage tests (337 tests)
└── dist/                    # Built output (ESM + CJS)

Key Principles:

  • ✅ Zero dependencies
  • ✅ Tree-shakable modules
  • ✅ Strict TypeScript
  • ✅ 100% test coverage
  • ✅ Published references in TSDoc

🤝 Contributing

Contributions are welcome! Please follow these steps:

  1. Fork the repository
  2. Create your feature branch: git checkout -b feat/my-feature
  3. Add tests for any new functionality
  4. Ensure 100% coverage: pnpm test:coverage
  5. Commit with conventional commits: git commit -m "feat: add new feature"
  6. Push to your branch: git push origin feat/my-feature
  7. Open a pull request

Development Commands

# Install dependencies
pnpm install

# Run tests
pnpm test

# Run tests with coverage
pnpm test:coverage

# Build library
pnpm build

📝 Changelog

See CHANGELOG.md for detailed release notes and version history.


📄 License

This project is licensed under the MIT License. See the LICENSE file for details.

© 2024–2026 Mark Learst

Use it, fork it, build something that matters.


🔗 Links


🙋‍♂️ Author

Mark Learst Full-stack developer, diabetes advocate, and open source contributor.

💬 Using diabetic-utils in your project? Let me know—I'd love to feature it! ⭐ Star the repo and help us build the best diabetes toolkit together!


💬 Support


📝 A Personal Note

I built diabetic-utils because I believe in the power of data-driven diabetes management. As someone who's lived with diabetes, I know how hard it can be to make sense of the numbers.

That's why I've poured my heart into creating a library that's both accurate and easy to use. Whether you're building an app, working on research, or just trying to understand your own data, I hope diabetic-utils can help.

Let's work together to make diabetes management better, one data point at a time. 🩸


Built with ❤️ by the diabetes community, for the diabetes community.