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

@blumintinc/microdiff

v1.1.0

Published

Small, fast, zero-dependency deep diff with pluggable atomic-type recognition. Fork of AsyncBanana/microdiff.

Downloads

720

Readme

@blumintinc/microdiff

Small, fast, zero-dependency deep diff with pluggable atomic-type recognition. Fork of AsyncBanana/microdiff at v1.5.0.

What this fork adds

Two options on the diff() API let callers configure which values are treated as atomic leaves (compared by value, never recursed into):

interface MicrodiffOptions {
  cyclesFix: boolean;
  isAtomic: (value: object) => boolean;
  isEqualAtomic: (a: unknown, b: unknown) => boolean;
}
  • isAtomic(value) — return true to treat value as a leaf.
  • isEqualAtomic(a, b) — equality test for two atomic values. Object.is reference/NaN equality is checked separately by diff(), so this only handles value-equal-but-distinct-reference cases.

When omitted, both options fall back to the published defaults (defaultIsAtomic, defaultEqualAtomic). Defaults treat the following as atomic:

  • Date, RegExp, String, Number (upstream microdiff parity)
  • Temporal.* family (upstream microdiff parity)
  • Firestore Timestamp shapes (real firebase-admin/firestore instances and plain {_seconds, _nanoseconds} maps left by structuredClone / deepmerge) — added in 1.1.0

Firestore Timestamp recognition is structural (no firebase-admin dependency) and on by default because BluMint's primary consumer is Firestore-based. Override isAtomic (return false) to disable.

Why this fork exists

Upstream microdiff hardcodes its atomic-type list at module scope. There is no extension hook. For our use case (Firestore Timestamp instances embedded in documents), upstream descends into the Timestamp's _seconds / _nanoseconds private fields and emits per-property CHANGE diffs — which materialize as malformed Firestore writes. The fork exposes the existing recursion gate as a caller-provided predicate so consumers can teach diff() about their own atomic types — and additionally builds Firestore Timestamp recognition into the defaults.

Calls with no options are a strict superset of upstream: identical for everything upstream handles, plus correct treatment of Firestore Timestamps.

Install

npm install @blumintinc/microdiff

Usage

Firestore Timestamps are atomic by default (no options needed):

import diff from "@blumintinc/microdiff";
import { Timestamp } from "firebase-admin/firestore";

const before = { lastUpdated: Timestamp.fromMillis(1000) };
const after = { lastUpdated: Timestamp.fromMillis(2000) };

diff(before, after);
// → [{ type: "CHANGE", path: ["lastUpdated"], value: <Timestamp 2000>, oldValue: <Timestamp 1000> }]
//   No `_seconds`/`_nanoseconds` descent. Timestamp identity preserved in `value` and `oldValue`.

Treat additional custom classes as atomic by extending defaultIsAtomic:

import diff, { defaultIsAtomic, defaultEqualAtomic } from "@blumintinc/microdiff";
import { GeoPoint } from "firebase-admin/firestore";

const isGeoPoint = (v: object) => v instanceof GeoPoint;

diff(before, after, {
  isAtomic: (v) => isGeoPoint(v) || defaultIsAtomic(v),
  isEqualAtomic: (a, b) => {
    if (isGeoPoint(a as object) && isGeoPoint(b as object)) {
      return (a as GeoPoint).isEqual(b as GeoPoint);
    }
    return defaultEqualAtomic(a, b);
  },
});

Note the composition pattern: extend defaultIsAtomic instead of replacing it, otherwise Date / RegExp / Temporal.* / Firestore Timestamps lose their atomic status.

API

| Export | Description | |---|---| | diff (default) | The deep-diff function. Drop-in API-compatible with upstream microdiff. | | defaultIsAtomic | Default predicate. Matches Date, RegExp, String, Number, Temporal.*, and Firestore Timestamp shapes. | | defaultEqualAtomic | Default equality. Timestamps compare via defaultTimestampToMillis; Temporal via String(); rich types via NaN-aware numeric/string coerce. | | defaultIsTimestampShape | Structural duck-type predicate for Firestore Timestamps (real instances + plain-map shapes). | | defaultTimestampToMillis | Extracts epoch ms from any Firestore Timestamp shape. | | defaultRichTypes | Frozen readonly string[] of the four rich-type constructor names. | | defaultTemporalTypes | Frozen readonly string[] of the Temporal API constructor names available on globalThis.Temporal. | | Difference<TData> | Discriminated union of DifferenceCreate / DifferenceRemove / DifferenceChange. Generic over TData for typed paths and values. | | MicrodiffOptions | Options shape. All fields optional via Partial<MicrodiffOptions> at the call site. |

License

MIT, preserved from upstream. See LICENSE for the full text including the BluMint modification notice.