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

@kontsedal/olas-devtools

v0.0.6

Published

Olas in-app devtools — controller tree inspector, cache timeline, mutation log, signal graph.

Readme

@kontsedal/olas-devtools

In-app devtools UI for an Olas root. Two React components: <DevtoolsLauncher> (floating draggable window with a launcher button) and <DevtoolsPanel> (the panel itself, for embedding in your own chrome). Both read the same root.__debug event stream.

A standalone browser extension reading the same stream is tracked in ../../BACKLOG.md.

Install

pnpm add @kontsedal/olas-devtools @kontsedal/olas-core @kontsedal/olas-react @preact/signals-core react

react >= 18 and the three Olas packages are peer deps.

30-second example

import { OlasProvider } from '@kontsedal/olas-react'
import { DevtoolsLauncher } from '@kontsedal/olas-devtools'
import { createRoot } from '@kontsedal/olas-core'

const root = createRoot(appController, { deps })

function AppShell() {
  return (
    <OlasProvider root={root}>
      <App />
      {import.meta.env.DEV && <DevtoolsLauncher root={root} />}
    </OlasProvider>
  )
}

DevtoolsLauncher renders a small launcher button in the bottom right; clicking it opens a draggable, resizable window with the panel. Position + size + open / minimized state persist to localStorage.

If you'd rather host the panel yourself (e.g., fixed sidebar in a layout), import DevtoolsPanel directly and size it however you like. Styles are scoped to the .olas-devtools-* class prefix; no CSS imports needed.

What you'll see

| Tab | Content | |-----|---------| | Tree | Live controller tree. Each node shows its path segment and lifecycle state (active / suspended / disposed). | | Cache | Chronological log of cache:fetch-start / fetch-success / fetch-error / invalidated / gc events. | | Mutations | Chronological log of mutation:run / success / error / rollback events. | | Fields | Field-level validation outcomes (when emitted — see below). |

The Clear button empties the three event logs (the tree is live state, not a log, and is preserved).

API

function DevtoolsLauncher(props: {
  root: Pick<Root<unknown>, '__debug'>
  defaultTab?: DevtoolsTab
  maxEntries?: number       // per-log cap, oldest drop first; default 100
  urlHashKey?: string       // forwarded to the panel; persists open-tab in the URL
  storageKey?: string       // localStorage key for window position/size; default 'olas-devtools-window'
  initial?: { x?: number; y?: number; w?: number; h?: number }
}): JSX.Element

function DevtoolsPanel(props: {
  root: Pick<Root<unknown>, '__debug'>
  defaultTab?: DevtoolsTab
  maxEntries?: number
  urlHashKey?: string
}): JSX.Element

type DevtoolsTab = 'tree' | 'cache' | 'mutations' | 'fields' | 'events'

// Lower-level store — exported so consumers can build their own UI.
class DevtoolsStore {
  readonly tree$: Signal<ControllerNode>
  readonly cache$: Signal<CacheEntry[]>
  readonly mutations$: Signal<MutationEntry[]>
  readonly fields$: Signal<FieldEntry[]>

  attach(root): () => void   // subscribes; returns unsubscribe
  handle(event): void        // for tests or programmatic feed
  clearLogs(): void
}

Important: the panel sees only post-mount events

The panel subscribes to root.__debug on mount. Events that fired before mount (e.g. the root controller's controller:constructed) are NOT in the tree. Mount the panel as early as possible if you want the full picture. The cache / mutation / field logs are bounded by maxEntries (default 100) anyway.

If you need historical state, build a parallel DevtoolsStore early (next to createRoot) and pass it into a custom UI later.

What's emitted by the runtime

Spec §20.9 lists the full DebugEvent union. Today the runtime emits:

  • controller: constructed / suspended / resumed / disposed
  • cache: fetch-start / fetch-success / fetch-error / invalidated / gc
  • mutation: run / success / error / rollback

cache:subscribed and field:validated are declared in the type but not yet wired in the runtime. The panel renders them when they arrive; you can also feed them via store.handle(event) from your own instrumentation.

Further reading