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

@bazariodev/fsm-delays

v0.1.0

Published

Declarative delays and intervals for @bazariodev/fsm — timeouts, repeating timers, and context-derived backoff that cancel on state leave, built on @bazariodev/fsm-effects.

Readme

@bazariodev/fsm-delays

Declarative delays and intervals for @bazariodev/fsm. Attach time-driven events to states — one-shot after timeouts and repeating every intervals — that arm on entry and cancel on leave. Built on @bazariodev/fsm-effects.

Full design rationale: Delays.md ADR.

Install

pnpm add @bazariodev/fsm-delays @bazariodev/fsm @bazariodev/fsm-effects

@bazariodev/fsm and @bazariodev/fsm-effects are peer dependencies.

Usage

import { FsmDelays } from '@bazariodev/fsm-delays';

const delays = new FsmDelays(callMachine, {
  delays: {
    // ring-no-answer timeout
    ringing: { after: 30_000, send: { type: 'NO_ANSWER' } },

    // heartbeat while connected
    connected: { every: 5_000, send: { type: 'PING' } },

    // exponential reconnect backoff, derived from context
    reconnecting: {
      after: (snapshot) => Math.min(30_000, 1_000 * 2 ** snapshot.context.attempts),
      send: { type: 'RETRY' },
    },
  },
});

delays.stop(); // or `using delays = new FsmDelays(...)`

A spec carries exactly one of after (one-shot) or every (repeating). after/every (ms) and send may be static values or functions of the entry snapshot. Multiple specs per state and wildcard (*) specs are supported.

Composing with hand-written effects

compileDelays returns an effects fragment you can merge into your own FsmEffects, so one subscriber drives both delays and effects:

import { FsmEffects } from '@bazariodev/fsm-effects';
import { compileDelays } from '@bazariodev/fsm-delays';

new FsmEffects(machine, {
  effects: {
    ...compileDelays({ delays: { ringing: { after: 30_000, send: { type: 'NO_ANSWER' } } } }),
    dialing: (snapshot, { signal, send }) => {
      // hand-written effect alongside the compiled delays
    },
  },
});

Merge per state: a delay map and an effect map that share a state key would overwrite on spread — keep their keys distinct unless you intend to override.

Design decisions

  • Built on the effects runner. A delay compiles to an effect that arms a timer on entry and returns () => clearTimeout(handle). Cancellation, re-entrancy safety, and the guarded send all come from @bazariodev/fsm-effects. Because cleanup runs synchronously when the leaving state's controller aborts, a pending timer can never fire for a state the machine has already left.
  • after and every. One-shot timeouts and repeating intervals, modelled as a union so a spec carries exactly one. every covers heartbeat and registration-refresh as first-class.
  • Dynamic resolvers. after/every/send resolve against the entry snapshot — once when an after fires, on each tick for an every. Exponential backoff falls out of a dynamic after plus an attempt counter in context; no separate retry DSL.
  • Injectable scheduler. An optional scheduler ({ setTimeout, clearTimeout, setInterval, clearInterval }) defaults to the global timers. Tests inject a deterministic clock instead of relying on fake timers.
  • Self-transitions don't restart timers (inherited from the effects runner): a heartbeat every keeps ticking across the self-transitions its own events cause.
  • Validation. Construction fails fast on a non-object delays map, a spec that is not an object, a spec without exactly one of after/every, a missing send, or a static after/every that is negative/non-finite (after >= 0, every > 0). A dynamic resolver that yields an invalid duration is logged at warn and skipped for that entry; the rest still arm.
  • Error containment. The timer callback fires after the effect body returns, outside the runner's try/catch, so the module wraps it: a throw from resolving send, or a machine error from the delayed api.send (guard/reducer/hook failure), is caught and logged via logger as fsm-delays: delayed send threw rather than escaping as an uncaught timer exception. No error event is auto-sent.

API

  • FsmDelays — convenience runner that owns an internal FsmEffects; stop() and [Symbol.dispose].
  • compileDelays(config) — pure compiler returning an EffectsConfig['effects'] fragment.
  • Types: AfterSpec, EverySpec, DelaySpec, DelaysConfig, Scheduler, Resolvable.

License

MIT