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

@jbrowse/mobx-state-tree

v5.11.1

Published

Fork of mobx-state-tree starting from v5.4.2 for use in jbrowse 2

Readme

@jbrowse/mobx-state-tree

Fork of mobx-state-tree v5.4.2 maintained for use in JBrowse 2. All upstream types and APIs are available — this page documents only the additions and changes made in this fork.

Infrastructure changes

  • Updated TypeScript and import paths to use explicit file extensions
  • Replaced process.env.NODE_ENV with an exported setDevMode() function
  • Converted tests from Jest to Vitest
  • Replaced tslint with eslint + typescript-eslint
  • Dual CJS/ESM build (avoids issues when both are imported in the same Vite build)
  • Removed unused dependencies and the NonEmptyObject annotation
  • Replaced unique symbol phantom properties ($emptyObject, $stateTreeNodeType) with exported string-keyed brand interfaces ($EmptyObjectBrand, $__mstStateTreeNodeType__), fixing tsgo TS4058/TS4023 errors when MST types appear in exported function return types

Added APIs

types.resilient

Wraps a type so that if instantiation fails (e.g. because the snapshot is from an unknown plugin that is not installed), the error is caught and a fallback type is used instead of crashing the entire state tree.

const PluginWidget = types.resilient(
  KnownWidget,
  UnknownWidget,
  (error, originalSnapshot) => ({ kind: "unknown", raw: originalSnapshot }),
)

// Arrays of plugins stay alive even if one entry is unrecognized
const Store = types.model({
  widgets: types.array(PluginWidget),
})

types.resilient takes three arguments:

  • type — the primary type to try first
  • fallbackType — the type to use when the primary fails
  • createFallbackSnapshot(error, originalSnapshot) — a callback that receives the caught error and the original snapshot, and returns a valid snapshot for the fallback type

Important caveat: isValidSnapshot always returns success for a resilient type. Any value is considered a valid snapshot — validation is deferred to instantiation time, where failures are caught and routed to the fallback.


types.stripDefault

Like types.optional, but omits the property key from the parent model's snapshot entirely when the value equals the default.

Background: snapshots and types.optional

In MST, a snapshot is the plain JSON representation of your model — what you'd get from getSnapshot(model) and what you'd pass to Model.create(...). Snapshots are used for serialization, persistence, and undo/redo.

types.optional lets you define a property with a default value so it can be omitted when creating a model:

const Settings = types.model({
  theme: types.optional(types.string, "light"),
})

const s = Settings.create()   // theme is "light"
getSnapshot(s)                // { theme: "light" }

Even though "light" is just the default, it always appears in the snapshot. If you store or diff these snapshots, every instance carries that redundant data.

What types.stripDefault does

types.stripDefault works exactly like types.optional at runtime — the property gets its default when missing — but the key is left out of the snapshot entirely when the value equals the default:

const Settings = types.model({
  theme: types.stripDefault(types.string, "light"),
})

const s = Settings.create()
getSnapshot(s)                // {}  ← key omitted because value equals default

s.theme = "dark"
getSnapshot(s)                // { theme: "dark" }

s.theme = "light"
getSnapshot(s)                // {}  ← omitted again

Why this matters

Without stripDefault, keeping defaults out of snapshots requires a manual postProcessSnapshot on every model. stripDefault handles this automatically per-property.

This is especially useful when:

  • Snapshots are stored or synced and you want to minimize their size
  • You diff snapshots (e.g. for undo/redo or change detection) and want default values to appear as "no change" rather than an explicit write
  • You have many optional fields and don't want boilerplate postProcessSnapshot

How the default comparison works

The comparison is done against the normalized default snapshot, not the raw value you passed in. MST instantiates the subtype with the default once, reads back its snapshot (which applies any nested model defaults and post-processing), and caches that as the reference. This means a complex nested default that gains extra fields at instantiation time will still compare correctly.


Reflection API additions

These utilities expose type metadata that is useful for building generic tooling (e.g. editors, inspectors, plugin systems) that need to introspect an MST type at runtime.

getChildType(node, propertyName?) — returns the declared MST type of a child property on a model, array, or map instance. For arrays and maps the property name is ignored (all children share one element type).

const Box = types.model({ x: types.number, y: types.number })
const box = Box.create({ x: 1, y: 2 })

getChildType(box, "x").name  // "number"

getUnionSubtypes(type) — given a types.union type, returns the array of its member types. Useful when you need to enumerate what a union can hold.

const Shape = types.union(Circle, Square, Triangle)

getUnionSubtypes(Shape)  // [Circle, Square, Triangle]

getDefaultInstanceOrSnapshot(optionalType) — returns the default value (or snapshot) declared on a types.optional or types.stripDefault type. Lets generic tooling read the default without having to create a model instance.

const t = types.optional(types.string, "hello")

t.getDefaultInstanceOrSnapshot()  // "hello"