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

@demlik/tea

v0.20.0

Published

TEA-faithful state machine substrate — one package, every host adapter. Core + subs + testing, plus React, Durable Object, Chrome extension, Node, in-memory, devtools, and property-testing modules as subpaths.

Readme

@demlik/tea

A TEA / Elm-Architecture TypeScript library for durable, replayable state machines — one pure reducer, every host adapter.

Install

pnpm add @demlik/tea

The one runtime dependency is @standard-schema/spec, a types-only package installed for you. Cmd.define takes any Standard Schema, so bring the schema library you already use (zod, or Effect Schema through Schema.toStandardSchemaV1). The host and testing adapters ride on optional peers you add only for the surface you use: react / react-dom (the ./react hooks), ws (Node WebSocket subs), fast-check (the ./pbt property-testing helpers), vitest (the testing utilities), effect (the ./effect engine), and @opentelemetry/api (the ./otel spans).

Quickstart

A machine is plain data: an init and an update map keyed by Msg type. run drives it, and when it has effects you hand run the interpret map that performs them; dispatch folds a Msg; getState reads the current Model. You name the Model and the Msg union once, under types; everything else is inferred from the machine itself. Each of these words has an entry in the glossary.

import { defineMachine } from "@demlik/tea";
import { run } from "@demlik/tea/promise";

type State = { readonly count: number };
type Msg = { readonly type: "increment" } | { readonly type: "reset" };

const counter = defineMachine({
  types: { model: {} as State, msg: {} as Msg },
  init: (loaded) => (loaded !== null ? [loaded, []] : [{ count: 0 }, []]),
  update: {
    increment: (s) => [{ count: s.count + 1 }, []],
    reset: () => [{ count: 0 }, []],
  },
});

const runtime = await run(counter, {}).ready;
await runtime.dispatch({ type: "increment" });
runtime.getState(); // { count: 1 }

Two engines, one machine

The core is @demlik/tea, and each engine has its own entry point. A machine file imports only the core, so it runs unchanged on either engine.

  • @demlik/tea — the core: defineMachine, Cmd, replay and the types. It imports no engine.
  • @demlik/tea/promise — the Promise engine. Handlers return Promises.
  • @demlik/tea/effect — the Effect engine (stable, Effect v4). Handlers return Effects, services come from your Layers, the handle's verbs return Effects with typed errors, and closing the scope interrupts whatever is in flight.

Run a machine on the Promise engine and on the Effect engine build on the same machine file. Run many machines under one parent starts child machines on the Effect engine with spawn, tell and stop. Coming from 0.15? The migration guide shows every removed or reshaped API, before and after.

Documentation

The four Diátaxis quadrants live in docs/:

  • Tutorials — learning-oriented lessons that take you through the library by building a real machine.
  • How-to guides — goal-oriented directions for getting a specific job done.
  • Reference — information-oriented API description, generated per public module.
  • Explanation — understanding-oriented discussion of how it works and why it is shaped this way.

The glossary defines each word those pages use: Model, Msg, Cmd, Sub, Store and the rest.

Two more surfaces sit behind those, for people working on the library rather than using it: .patterns/ is how the code is shaped, and .decisions/ is why it was shaped that way.