Headless TypeScript library for CGM and glucose data. Five packages covering 17 clinical metrics, device connectors, FHIR and Open mHealth interop, SVG rendering, React bindings, and seeded test fixtures.
AGP, TIR, GRI, MAGE, CONGA, MODD and more, from the clinical literature
Headless core with no runtime dependencies, held to 100% coverage
Published to npm as a release candidate, approaching 1.0
Continuous glucose monitors produce a reading every five minutes. Turning that stream into something a person can act on means computing metrics that already exist in the clinical literature, and most teams building diabetes software end up reimplementing them.
Diabetic Utils proved the calculations were worth packaging. GlucoseIQ is what happens when the same work is treated as a product: five packages, a size budget, and total coverage on the core.
It also has a harder constraint. This is health software written by someone who is not a clinician, so the most important thing the library does is refuse to claim more than it can support.
GlucoseIQ is a headless analytics core with optional packages layered on top. The core computes and returns data. Nothing in it renders to a screen or reaches for the network.
The API is shaped so the caller cannot skip the question of whether the data was good enough to analyze:
function summarize(readings: GlucoseReading[]) {
const report = analyzeGlucose(readings, { timeZone: 'America/Detroit' })
// `valid` only means at least one usable reading survived filtering.
if (!report.valid || report.timeInRange === null) {
return { status: 'no-data' } as const
}
// Whether that data is adequate is a separate question,
// and it gets a separate field rather than folding into `valid`.
const { meetsCGMStandard, daysOfData, activePercent } =
report.dataSufficiency
if (!meetsCGMStandard) {
return { status: 'insufficient', daysOfData, activePercent } as const
}
return {
status: 'ok',
timeInRange: report.timeInRange.inRange.percentage,
gmi: report.gmi,
} as const
}Two separate gates, because they answer different questions. Report blocks are nullable, so a caller cannot read a percentage without acknowledging it may not exist. Adequacy is then its own check: a week of patchy data can produce a perfectly real Time in Range number that should not be presented as a clinical summary.
Seventeen metric modules, each named for the published measure it implements rather than an invented abstraction:
Vendor formats normalize into one reading shape, and results can leave in formats other health systems already read:
Renderers return SVG strings for AGP charts, Time in Range bars, and trend tiles. The host decides how to embed, sanitize, or deliver that string, so the same call works in a React app, a server-rendered report, or a PDF pipeline.
A dedicated package ships fixed-seed synthetic CGM data and scenario fixtures, so tests, demos, and documentation run on realistic glucose traces without touching anyone's real readings.
@glucoseiq/core for analytics, connectors, interop, and SVG renderers@glucoseiq/react for hooks and headless components, React 18 and 19@glucoseiq/tokens for the five-zone glucose palette, thresholds, and trend glyphs@glucoseiq/testing for fixed-seed synthetic data and scenario fixtures@glucoseiq/cli for analyzing mapped CSV without writing any application codeThe core has no runtime dependencies and no peer dependencies, and both facts are enforced rather than aspirational:
The CSV parser states its behavior instead of guessing, which is what makes it safe to point at an unfamiliar export:
The docs site is built with Fumadocs, and its code samples are type-checked and executed in CI. A snippet that stops compiling fails the build, so the examples cannot drift away from the API they describe.
GlucoseIQ is for informational, educational, and software development use. It is not medical advice and is not a medical device. That line is in the README, the docs, and this case study for the same reason: a library that computes clinical-looking numbers has an obligation to say what it is not.
The same care applies inside the API, where anything project-defined is labeled as project-defined:
glucoseIQScore is non-diagnostic, a
project-defined score derived from GRI rather than a published measure
buildAGPProfile returns AGP-style bands,
a percentile series rather than a standardized complete AGP report
valid is not sufficient,
which is why data adequacy gets its own field instead of being folded
into a boolean
Embedding policy stays with the host, because a library returning an SVG string cannot know where it is about to be placed
Packages publish under the 1.0.0-next tag. The analytics are
settled and covered; what remains before 1.0 is the public API surface. The
prerelease tag is the honest way to say so.