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

@cosyte/synth

v0.0.7

Published

Deterministic, seedable synthetic healthcare-fixture generator for Node.js and TypeScript — spec-clean by construction, never real PHI.

Downloads

767

Readme

@cosyte/synth

Deterministic, seedable synthetic healthcare-fixture generator for Node.js and TypeScript — spec-clean by construction, and never real PHI.

@cosyte/synth generates reproducible synthetic test corpora across the six cosyte formats (HL7 v2, FHIR R4 / US Core, C-CDA, X12, NCPDP, and ASTM). It is a consumer of the cosyte parsers, not a parser: it builds each artifact through the parser's own builder/serializer (so the output is spec-clean by the same mechanism the parser proves) and draws every identifier, name, date, phone, and address from a guaranteed-non-colliding synthetic source. It is a format/conformance generator, not a clinical simulator — it does not model disease progression (that is Synthea).

Status: pre-alpha (0.0.x), published to npm. The version shown on the npm package page is the one that is live; this page never repeats it. The generator is feature-complete: the seeded-PRNG core, the synthetic-safety providers, and the round-trip harness; spec-clean generation across all six formats — HL7 v2 (ADT/ORU/ORM/SIU/VXU), FHIR R4 / US Core (the full clinical set + collection/transaction/document Bundles), C-CDA R2.1 (CCD + Referral Note), X12 005010 (837P/I/D, 835, 271), NCPDP (SCRIPT NewRx / RxRenewal / RxChange + Telecom B1/B2/B3), and ASTM (E1394 record reports + E1381 framing), each built through its parser's own builder/serializer; vendor-quirk mode — profile-driven off-spec fixtures for the three richest profile systems (HL7 v2, C-CDA, ASTM), each round-tripping to exactly the intended parser warning (the intended-warning contract); and the @cosyte/deid pairing loop — a closed-loop co-validation harness that de-identifies generated output and proves every planted synthetic PHI sentinel is removed.

Deferred (honestly out of scope for now): quirk recipes for FHIR / X12 / NCPDP (and any quirk needing a private vendor corpus); the X12 270 eligibility request and NCPDP SCRIPT lifecycle responses (both track the parsers' builder surfaces); NCPDP SCRIPT / ASTM / DICOM de-identify pairing (no @cosyte/deid adapter, or not generated); and optional Synthea clinical-content ingestion.

Install

npm install @cosyte/synth @cosyte/hl7 @cosyte/fhir @cosyte/ccda @cosyte/x12 @cosyte/ncpdp @cosyte/astm

@cosyte/hl7, @cosyte/fhir, @cosyte/ccda, @cosyte/x12, @cosyte/ncpdp, @cosyte/astm, and @cosyte/deid are optional peer dependencies, each needed only for its subpath (@cosyte/synth/hl7, @cosyte/synth/fhir, @cosyte/synth/ccda, @cosyte/synth/x12, @cosyte/synth/ncpdp, @cosyte/synth/astm, and @cosyte/synth/deid — the last needs @cosyte/deid plus the parsers for the formats it pairs) — install only the packages whose fixtures you generate. The package core has zero third-party runtime dependencies.

Generate a spec-clean HL7 v2 message

The HL7 v2 set covers ADT (A01/A04/A08), ORU^R01, ORM^O01, SIU^S12, and VXU^V04 — each built through @cosyte/hl7's buildMessage, so it is spec-clean by construction.

import { generateAdt, generateOru, generateHl7, hl7Corpus, roundTrip } from "@cosyte/synth/hl7";

// Same seed → byte-identical message, on any machine, any run.
const adt = generateAdt({ seed: 12345, trigger: "A01" });
const oru = generateOru({ seed: 12345 });

// Spec-clean by construction: it round-trips through @cosyte/hl7 with zero warnings.
roundTrip(adt).specClean; // true
roundTrip(oru).specClean; // true

// Or generate a reproducible mixed corpus across every family:
const corpus = hl7Corpus({ seed: 42, count: 7 }); // one of each family, cycled
corpus.artifacts.every((a) => a.warnings.length === 0); // true — all spec-clean

// Dispatch by kind when the message type is data:
generateHl7("VXU^V04", 12345);

Generate a spec-clean FHIR R4 / US Core resource

The @cosyte/synth/fhir subpath builds resources through @cosyte/fhir's model constructors, so they are spec-clean by construction — validating under validateResource and, against the real US Core 6.1.0 profiles (bring your own StructureDefinitions — none is bundled), conformant to US Core. The clinical set covers Patient (base + US Core), Condition, Observation (US Core Laboratory Result + Vital Signs), MedicationRequest, Encounter, DiagnosticReport, Immunization, AllergyIntolerance, and Procedure, assembled into a collection, transaction, or document Bundle.

import { generatePatient, generateBundle, fhirCorpus, roundTrip } from "@cosyte/synth/fhir";

// A US Core Patient — same seed → byte-identical resource, anywhere.
const patient = generatePatient({ seed: 12345, profile: "us-core" });

// Spec-clean by construction: it round-trips through @cosyte/fhir with zero errors, byte-stable.
roundTrip(patient).specClean; // true

// A self-contained Bundle assembling a patient + its clinical spine, wired by urn:uuid references:
const bundle = generateBundle({ seed: 42, type: "transaction" });

// Or a reproducible mixed corpus across the whole spine:
const corpus = fhirCorpus({ seed: 2026, count: 6 });
corpus.artifacts.every((a) => a.warnings.length === 0); // true — all spec-clean

@cosyte/fhir is an optional peer dependency, needed only for the @cosyte/synth/fhir subpath.

Generate a spec-clean C-CDA document

The @cosyte/synth/ccda subpath builds Consolidated CDA R2.1 documents through @cosyte/ccda's buildCcda, so template IDs, LOINC section codes, and structured/narrative agreement are the builder's own — the document round-trips through parseCcda with zero warnings. It emits a CCD (generateCcd) or a Referral Note (generateReferralNote), each with the CCD sections (Problems, Allergies, Medications, Results, Vital Signs, Immunizations, Procedures, Social History) populated from the reused, license-clean example-code pools.

import { serializeCcda } from "@cosyte/ccda";
import { generateCcd, generateReferralNote, ccdaCorpus, roundTrip } from "@cosyte/synth/ccda";

// Same seed → byte-identical document. The patient name is from the shipped fake-name pool, the MRN
// lives under a synthetic assigning-authority OID, and every date comes from the seeded generator.
const ccd = generateCcd({ seed: 12345 });
serializeCcda(ccd); // spec-clean C-CDA R2.1 XML

// Spec-clean by construction: it round-trips through @cosyte/ccda with zero warnings.
roundTrip(ccd).specClean; // true
roundTrip(generateReferralNote({ seed: 12345 })).specClean; // true

// Or a reproducible mixed corpus (CCD + Referral Note, cycled):
const corpus = ccdaCorpus({ seed: 42, count: 4 });
corpus.artifacts.every((a) => a.warnings.length === 0); // true — all spec-clean

@cosyte/ccda is an optional peer dependency, needed only for the @cosyte/synth/ccda subpath.

Generate a spec-clean X12 transaction

The @cosyte/synth/x12 subpath builds HIPAA 005010 transactions through @cosyte/x12's domain builders (build837P/I/D, build835, build271), so the ISA/GS/ST…SE/GE/IEA envelope, the computed HL spine, the control numbers, and every segment are the builder's own — each transaction round-trips through @cosyte/x12 with zero warnings. It emits 837 professional / institutional / dental claims, the 835 remittance (balance-checked by construction), and the 271 eligibility response.

import { generate837P, generate835, generate271, x12Corpus, roundTrip } from "@cosyte/synth/x12";

// Same seed → byte-identical EDI. Every subscriber/patient/provider identifier is
// synthetic-by-construction: the provider NPI has a deliberately-INVALID Luhn check digit (so it can
// never be a NPPES-issued NPI), the provider tax id is an SSA never-issued 900-range SSN, member ids
// live under a synthetic assigning authority, and names come from the shipped fake-name pool.
const claim = generate837P({ seed: 12345 });
roundTrip(claim).specClean; // true — re-parses through @cosyte/x12 with zero warnings, byte-stable
roundTrip(generate835({ seed: 7 })).specClean; // true
roundTrip(generate271({ seed: 3 })).specClean; // true

// Or a reproducible mixed corpus (837P/I/D + 835 + 271):
const corpus = x12Corpus({ seed: 42 });
corpus.artifacts.every((a) => a.warnings.length === 0); // true — all spec-clean

@cosyte/x12 is an optional peer dependency, needed only for the @cosyte/synth/x12 subpath.

Deferred: the 270 eligibility request (@cosyte/x12 ships a build271 but no build270, and synth never hand-writes bytes around a missing builder) and vendor-quirk mode.

Generate a spec-clean NCPDP message

The @cosyte/synth/ncpdp subpath builds both NCPDP standards through @cosyte/ncpdp's own emit surface, so each message round-trips through the parser with zero warnings. It emits SCRIPT ePrescribing (generateNewRx via buildNewRx; generateRxRenewalRequest / generateRxChangeRequest via the parser's typed ScriptMessage model + serializeScript) and Telecom pharmacy claims (generateB1 billing / generateB2 reversal / generateB3 rebill via buildTelecomRequest).

import {
  generateNewRx,
  generateB1,
  ncpdpCorpus,
  scriptRoundTrip,
  telecomRoundTrip,
} from "@cosyte/synth/ncpdp";

// Same seed → byte-identical output. NCPDP carries patient AND prescriber identity: the prescriber NPI
// has a deliberately-INVALID Luhn check digit and the prescriber DEA a deliberately-INVALID checksum
// (so neither can denote a real provider); patient/cardholder ids live under a synthetic assigning
// authority, phones are reserved 555-01xx, and names come from the shipped fake-name pool.
scriptRoundTrip(generateNewRx({ seed: 12345 })).specClean; // true — zero warnings, byte-stable
telecomRoundTrip(generateB1({ seed: 777 })).specClean; // true

// Or a reproducible mixed corpus (NewRx + RxRenewal + RxChange + B1 + B2 + B3):
const corpus = ncpdpCorpus({ seed: 42 });
corpus.artifacts.every((a) => a.warnings.length === 0); // true — all spec-clean

@cosyte/ncpdp is an optional peer dependency, needed only for the @cosyte/synth/ncpdp subpath.

Deferred: vendor-quirk mode. SCRIPT coverage tracks the parser's builder surface: the renewal/change responses land as @cosyte/ncpdp grows builders.

Generate a spec-clean ASTM message

The @cosyte/synth/astm subpath builds ASTM laboratory messages through @cosyte/astm's own emit surfacebuildAstmMessage for the E1394 record layer, composeAstmFrames for the E1381 frame layer — so each message round-trips through the parser with zero warnings. It emits the H/P/O/R…/C/L result report (generateAstmResult), the H/P/O/L order (generateAstmOrder), and the framed twin (generateAstmResultFramed).

import {
  generateAstmResult,
  generateAstmResultFramed,
  astmRoundTrip,
  astmFramedRoundTrip,
  astmCorpus,
} from "@cosyte/synth/astm";

// Same seed → byte-identical output. The P (patient) record carries the name, birthdate, and the
// practice- and laboratory-assigned patient ids — all synthetic-by-construction: names from the shipped
// fake-name pool, DOB seeded, and the two ids minted independently under a synthetic assigning authority
// (so they stay DISTINCT, exactly as @cosyte/astm keeps them on parse).
astmRoundTrip(generateAstmResult({ seed: 12345 })).specClean; // true — zero warnings, byte-stable

// The E1381-framed twin: the modulo-256 checksum and 0–7 frame numbers are computed by @cosyte/astm.
astmFramedRoundTrip(generateAstmResultFramed({ seed: 12345 })).specClean; // true

// Or a reproducible mixed corpus (a result report + an order):
const corpus = astmCorpus({ seed: 42 });
corpus.artifacts.every((a) => a.warnings.length === 0); // true — all spec-clean

@cosyte/astm is an optional peer dependency, needed only for the @cosyte/synth/astm subpath.

Generate a vendor-quirk fixture

Spec-clean fixtures test that a parser reads a correct message; quirk mode tests that it tolerates the realistic vendor deviations real traffic carries — and surfaces exactly the right diagnostic. The quirk vocabulary is the parsers' own profile systems: a quirk deviates the message structure so it round-trips to exactly one intended, stable warning code (the intended-warning contract), and where a built-in public parser profile claims the deviation, it round-trips cleanly under it (suppressed, or re-badged to PROFILE_QUIRK_APPLIED). A quirk never introduces a real-looking value — it changes shape, never provenance, so the synthetic-safety gate still passes.

Quirks ship for the three richest profile systems — HL7 v2, C-CDA, and ASTM:

import { generateHl7Quirk, hl7QuirkRoundTrip } from "@cosyte/synth/hl7";
import { generateCcdaQuirk, ccdaQuirkRoundTrip } from "@cosyte/synth/ccda";
import { generateAstmQuirk, astmQuirkRoundTrip } from "@cosyte/synth/astm";

// A site-defined HL7 v2 Z-segment → exactly UNKNOWN_SEGMENT; the `visage` profile suppresses it.
hl7QuirkRoundTrip(generateHl7Quirk({ seed: 1, quirk: "unknown-zsegment" })).warnings; // ["UNKNOWN_SEGMENT"]

// A deprecated C-CDA LOINC → exactly DEPRECATED_LOINC; `smartScorecard` re-badges it.
ccdaQuirkRoundTrip(generateCcdaQuirk({ seed: 1, quirk: "deprecated-loinc" })).withProfile
  ?.tolerated; // true

// A non-standard ASTM &Z& escape → exactly ASTM_UNKNOWN_ESCAPE_SEQUENCE; `referenceCorpus` re-badges it.
astmQuirkRoundTrip(generateAstmQuirk({ seed: 1, quirk: "unknown-escape" })).intendedWarningHeld; // true

A quirk a format's profile system does not support fails closed with a stable SYNTH_UNSUPPORTED_QUIRK diagnostic — never a silently-wrong fixture — and so do the other selectors: a message kind, a document type, a corpus mix entry, an 837 variant, a Bundle type. Each is checked against its own set before anything is generated, so an unrecognised one is a fatal SYNTH_UNSUPPORTED_KIND rather than a mislabelled corpus. Every refusal carries a code and a fixed message from a frozen table, and quotes nothing you passed. Every quirk is grounded in a publicly-documented deviation or a parser's public profile, never a private vendor corpus.

Deferred: quirk recipes for FHIR, X12, and NCPDP, and any quirk that would need a private, vendor-attributed corpus to ground.

Co-validate with @cosyte/deid (the pairing loop)

The @cosyte/synth/deid subpath is a deterministic closed-loop co-validation harness for the synthdeid pair: it generates a spec-clean artifact, plants distinctive synthetic PHI sentinels at the patient loci, de-identifies it through @cosyte/deid, and verifies every sentinel is gone from the output (a surviving sentinel is a hard failure) while the clinical payload survives (the over-scrub guard).

import {
  hl7DeidLoop,
  fhirDeidLoop,
  x12DeidLoop,
  ncpdpTelecomDeidLoop,
  ccdaDeidLoop,
  summarizeDeidCoverage,
} from "@cosyte/synth/deid";

const r = hl7DeidLoop({ seed: 42, kind: "ORU^R01" });
r.pass; // true
r.survivors; // []  — every planted synthetic PHI sentinel was removed
r.clinicalScrubbed; // []  — no clinical value was over-scrubbed

const summary = summarizeDeidCoverage([
  hl7DeidLoop({ seed: 1 }),
  fhirDeidLoop({ seed: 1 }),
  x12DeidLoop({ seed: 1, variant: "837P" }),
  ncpdpTelecomDeidLoop({ seed: 1, transaction: "B1" }),
  ccdaDeidLoop({ seed: 1 }),
]);
summary.allPass; // true — zero survivors, zero over-scrub, per format

This is a co-validation harness, not an independent audit of @cosyte/deid against real-world data — it proves the pair works on synth's own output. The removal check is locus-scoped: it sweeps only the de-identified values remaining at the former PHI loci, so provider/organization identity a de-identifier legitimately retains never reads as a false survivor. @cosyte/deid is an optional peer dependency, needed only for this subpath. Skipped and named (DEID_LOOP_SKIPPED): NCPDP SCRIPT and ASTM (no @cosyte/deid adapter) and DICOM (not generated by synth).

Draw a synthetic value

import { createRng, safe, isSyntheticSsn, isSyntheticNpi } from "@cosyte/synth";

const rng = createRng(42);
isSyntheticSsn(safe.ssn(rng)); // true — always an SSA never-issued SSN
isSyntheticNpi(safe.npi(rng)); // true — always a deliberately-invalid-Luhn NPI (never a real NPI)

What makes it trustworthy

  • Synthetic-by-construction — no code path emits a value not drawn from a reserved range or the shipped fake-name pool (SSA never-issued SSNs, NANP 555-01xx phones, RFC 2606/6761 example.* domains, RFC 5737/3849 TEST-NET IPs, a synthetic assigning authority for MRNs). A CI gate proves it. No generated value can be real or plausibly-real PHI.
  • Spec-clean by the parser's own judgment — built through the parser's conservative serializer, and checked by feeding the artifact straight back in: a spec-clean artifact re-parses with zero warnings.
  • Deterministic — a hand-rolled seeded PRNG (sfc32/splitmix32); Math.random is lint-banned. A seed, and only the seed, determines the output — byte-for-byte, anywhere.
  • Immutable — generated artifacts and the Corpus result are deep-frozen.
  • Zero third-party runtime dependencies — the parser peers are first-party cosyte packages, vendored for dev/test; dual ESM + CJS, validated with attw.

License

MIT © Cosyte