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

@beastjs/devtools

v0.1.21

Published

In-page devtools for Beast (BTSX) and Octane apps on Vite, Rspack and Rsbuild: live component state, BTSX → TSRX inspection, and automatic component extraction for deeply nested templates.

Readme

Beast Devtools | @beastjs/devtools

In-page devtools for Beast (BTSX) and Octane apps.

npm Version Node.js Dependencies Bundlers License: ISC

See the live tree. Read the compiled output. Flatten deep templates in one click.

Install · Quick start · Using the overlay · Automatic refactors · Configuration · Security · Troubleshooting


Beast DevTools adds a panel to your app while it runs on the Vite, Rspack or Rsbuild dev server. It shows the live Octane component tree with hook and context values, puts every .btsx file next to the TSRX it compiles to, and finds templates nested too deeply. It can then extract those sections into components for you, with typed props, after showing you the diff.

Production builds are untouched. The plugin runs on the dev server only.

At a glance

| Capability | What it does | Why it matters | | --- | --- | --- | | Components | Live component tree with hooks, context and effects | Debug state without logging | | Element Picker | Hover HTML or SVG elements to see spacing, size, ID and type | Inspect layout without source tags | | Component Finder | Hover the page to see a component and its .btsx line | Go from pixels to source | | BTSX → TSRX | Source and compiled output, linked line by line | See what Beast generates | | Refactor | Finds deep nesting, repeated markup and sibling runs | Keeps templates readable | | Auto-refactor | Writes the component, props interface and imports | Refactors in one reviewed step | | Undo | Restores the files a refactor touched | Makes changes low-risk |

Requirements

| Dependency | Version | | --- | --- | | beast-tsrx | ^0.4.3 | | octane | ^0.4.3 | | Node.js | >=22.22.2 | | typescript (optional) | >=5.0.0, for typed props in refactors |

Plus one bundler:

| Bundler | Packages | Version | | --- | --- | --- | | Vite | vite | ^8.0.16 | | Rspack | @rspack/core and @rspack/dev-server | ^2.0.0 | | Rsbuild | @rsbuild/core | ^2.0.0 |

Installation

bun add -d @beastjs/devtools
npm install -D @beastjs/devtools

Quick start

Add the plugin next to beastOctane(), importing it from your bundler's entry point. Octane's profile option compiles in the runtime inspection hook that the Components panel reads. Enable it for development only.

Vite

// vite.config.ts
import { beastOctane } from 'beast-tsrx/vite'
import { beastDevtools } from '@beastjs/devtools/vite'
import { defineConfig } from 'vite'

export default defineConfig({
  plugins: [
    // `profile: 'auto'` enables the inspection hook in dev builds only.
    beastOctane({ octane: { profile: 'auto' } }),
    beastDevtools(),
  ],
})

@beastjs/devtools without a subpath is also the Vite plugin.

Rspack

// rspack.config.ts
import { beastOctane } from 'beast-tsrx/rspack'
import { beastDevtools } from '@beastjs/devtools/rspack'

export default {
  module: { rules: [{ test: /\.css$/, type: 'css' }] },
  plugins: [
    // Rspack's `profile` is a boolean; the CLI sets NODE_ENV before loading this file.
    beastOctane({ octane: { profile: process.env.NODE_ENV !== 'production' } }),
    beastDevtools(),
  ],
}

[!IMPORTANT] The overlay imports a stylesheet, so an Rspack config needs a rule for .css files.

The plugin hooks into devServer.setupMiddlewares, so it runs under rspack serve. If you start RspackDevServer yourself, pass it compiler.options.devServer. In a multi-compiler config, add the plugin to the browser config that has devServer.

Rsbuild

// rsbuild.config.ts
import { defineConfig } from '@rsbuild/core'
import { beastOctane } from 'beast-tsrx/rsbuild'
import { beastDevtools } from '@beastjs/devtools/rsbuild'

export default defineConfig({
  plugins: [
    ...beastOctane({ octane: { profile: process.env.NODE_ENV !== 'production' } }),
    beastDevtools(),
  ],
})

The overlay loads in every web environment. Server environments are left alone.

Start the dev server and press Alt+Shift+D, or click the Beast button in the bottom-right corner.

Using the overlay

Keyboard and mouse

| Action | How | | --- | --- | | Open or close the panel | Alt+Shift+D, or the Beast button | | Start or stop the Component Finder | Alt+Shift+C, or the crosshair button | | Start or stop Element Picker | Alt+Shift+E, or the ruler button | | Exit Component Finder or Element Picker | Esc | | Resize the panel | Drag its top edge | | Resize a pane | Drag the edge between two panes | | Reset a pane's width | Double-click that edge |

The panel remembers its height, pane widths, open tab and analyzer settings per browser. It slides in and out, and all motion becomes near-instant when the system asks for reduced motion.

Component Finder

Turn on Component Finder and hover any element of your app. An outline follows the pointer, labeled with the component that renders the element and its .btsx file and line. Click to open that line in your editor. That also ends Component Finder.

While Component Finder is on, app clicks select a component to open in the editor. The overlay's own controls keep working.

Element Picker

Click the ruler button in the launcher or toolbar, or press Alt+Shift+E. Hover an element for a compact preview of its tag, ID and dimensions. Click it to open Elements in DevTools.

  • Styles shows common layout and appearance properties. Enable All computed styles or search to inspect the full computed list. Editing a value creates an inline override; remove it to return to the stylesheet value.
  • Attributes shows every attribute and lets you edit, add or remove values.
  • DOM properties includes inherited properties and runtime values such as value, checked and disabled. Editable primitive values can be changed; browser-owned objects and methods are displayed as read-only summaries.

Press Enter or leave a value field to apply it. Undo reverses each edit and remains available when switching panels or reselecting the same element. These are live page edits only: they do not modify BTSX files, and reloading or an app rerender can replace them. Removed elements are marked as disconnected; use Pick another to select their replacement.

The preview appears after 200 ms without pointer movement and sits outside the element. Element Picker works on HTML and SVG without source tags or a runtime connection. Escape cancels picking. Only one tool is active at a time, and selection clicks are consumed so they do not activate the underlying app. Elements inside iframes and closed shadow roots are inspected at their container.

Components

The live Octane component tree, including the each and if scopes that Beast templates create, in one of two views:

  • Blocks (the default) stacks each component as a one-line card. Shades alternate by layer and a colored stripe marks each depth. Indentation stops growing after six levels, and deeper blocks show their depth instead, so large apps stay readable. The view starts at your app's entry component (the .btsx component that main.ts imports), and folds the providers above it into a single wrappers hidden bar you can expand. Anything else those providers render, such as a toaster, stays visible.
  • Tree is the classic indented tree.

Click a caret, or double-click a block, to collapse or expand it. A collapsed block shows how many children it holds. Selecting a component shows:

  • its hook values, named after the setup bindings that declare them, for example activeId: "language";
  • its context values and number of effect slots;
  • the .btsx line that declares it, with buttons to open it in your editor or view its compiled TSRX.

BTSX → TSRX

Any .btsx file beside the TSRX that Beast generates for it. Hovering a line highlights its counterpart through Beast's source map, and clicking pins it. A file that fails to compile shows its BEAST#### diagnostic and the failing line. Both panes update when you save.

Refactor

The nesting depth of every template line, with totals and a per-depth chart, plus three kinds of suggestions:

| Suggestion | Finds | Becomes | | --- | --- | --- | | Extract | A section whose descendants exceed the depth limit measured from its starting line | A component, with props inferred from the bindings it uses | | Shared shape | Blocks with the same markup | One component. Differing attribute values, text and conditions become props | | Repeated | Three or more same-shape siblings, or two larger ones | An each over an array, keyed by a unique field or the index |

For example, two copy buttons that differ only in their handler become calls to one component:

CopyNote(onClick={() => copyNote('left', note)} text='Copy')

A suggestion's name is editable on its card before you apply it. That's the component name (which also names its NameProps interface and file), or the array or loop variable for a repeated run. Names are checked as you type and again on the dev server, which refuses names already used in the file.

The toolbar sets the depth limit, the smallest section worth extracting, and the size at which a section defaults to its own file.

Manual extraction

In Refactor, click the first source line (or its line number) of the block you want to extract. The overlay highlights the entire parsed block and adds a manual card with an inferred component name and props. This also works for shallow blocks that do not meet the automatic suggestion thresholds.

Rename the component on the card, choose hoist or create, review the diff, and apply. Undo works the same as for automatic refactors. Selecting an if, each, or switch includes the complete block and its branches; continuation lines, declarations, and existing component calls are not starting points. Editing the source clears the selection.

Automatic refactors

Every suggestion card can apply itself in one of two ways:

  • Hoist in file adds a local component above the host component's props and setup, and replaces the section with a call.
  • Move to Name.btsx writes the section to a new file beside the source. The new file gets the imports it needs. Module-level types and values the section uses are exported from the source and imported back (type-only where possible), and the source imports the new component.
flowchart LR
    A[Pick a suggestion] --> B[Choose hoist or move]
    B --> C[Dev server builds the change<br/>from the file on disk]
    C --> D{Every file compiles<br/>through Beast and Octane?}
    D -->|No| E[Refused, with the reason]
    D -->|Yes| F[Review the diff]
    F -->|Apply| G[Files written]
    G --> H[Undo available]

Typed props

The extracted component declares its props as a NameProps interface, exported when the section moves to its own file. Each prop's type comes from your project's TypeScript, read at the section itself, so loop variables and narrowing from if and switch branches are accounted for:

| The type is… | It is written as… | | --- | --- | | Already nameable in the file (globals, local types, existing imports) | That name | | A named type exported from another module | That name, with an import type added | | Not exported anywhere, such as Octane's internal setter type | The full type, for example (next: PanelId \| ((prev: PanelId) => PanelId)) => void |

If TypeScript can't be loaded from your project, types are estimated from the source and the card is marked estimated types.

Review and undo

Sections of at least New file at lines (30 by default) default to their own file. Clicking a target first shows a diff of every file it will touch, and nothing is written until you confirm. After applying, Undo restores the files unless they've been edited since.

[!NOTE] Undo history lives in the dev server's memory, so it's lost when the server restarts.

When a refactor is refused

A card offers no automatic refactor when it can't be done safely. The card says why, and you can still copy the code by hand. That happens for:

  • copies that differ in more than values (tags, selectors, loop headers), whose differing values use a variable bound inside the block, or that live in different components;
  • components with scoped style blocks;
  • moving a section that uses a file-local component into a new file.

Open another project folder

Use the Open project folder icon beside the pickers and enter an absolute folder path on the machine running the dev server, or click Browse… to use its native folder chooser (macOS, Windows, or Linux with Zenity/KDialog). The source inspector and refactor panel scan that folder for .btsx files, skipping generated and dependency directories. Changes in the opened folder refresh the overlay automatically. Empty folders can be opened too; they show an empty file list.

The selection belongs to the current browser tab and resets on reload. Use Back to running app to return to the configured project. Live components and Component Finder always inspect the running app; following a component's source link switches back to that project. Opening a folder does not start its dev server.

Configuration

beastDevtools({
  include: ['src'],
  analyzer: { depthLimit: 5, minLines: 8, fileLines: 30 },
  componentFinder: true,
})

| Option | Default | Description | | --- | --- | --- | | include | ['src'] | Directories, relative to the project root, scanned for .btsx files | | analyzer.depthLimit | 5 | Nesting depth (0 = component root) above which a line counts as deep | | analyzer.minLines | 8 | Smallest section, in lines, worth extracting | | analyzer.fileLines | 30 | Sections at least this long move to their own file by default | | componentFinder | true | Tag elements with their component and source line for Component Finder |

elementPicker remains a deprecated alias for componentFinder. When both are provided, componentFinder takes precedence. Element Picker works without source tags.

The project root is Vite's root, Rspack's context, or Rsbuild's root path. Analyzer settings changed in the panel override these defaults for that browser.

How it works

flowchart LR
    subgraph Server[Dev server]
        T[Source tagger] --> B[Beast and Octane compile]
        API[JSON API] --> X[Analyze, refactor, undo]
        W[File watcher] --> S[Server-sent events]
    end
    subgraph Page[Browser]
        O[Overlay] --> H[Octane inspection hook]
        O --> API
        S --> O
        P[Component Finder] --> E[Editor endpoint]
    end
    B --> Page
  • Injection. Vite gets a script tag in index.html, Rspack a global entry, and Rsbuild a source.preEntry.
  • API. A small JSON API under /__beast-devtools/api compiles, source-maps, analyzes and refactors .btsx files with beast-tsrx. Changes reach the overlay as server-sent events, so every dev server behaves the same. Vite's watcher feeds them; under Rspack and Rsbuild the plugin watches the include directories itself.
  • Overlay. The overlay is written in BTSX and ships as source, so your app's own Beast and Octane compile it. It reads the component tree from Octane's __OCTANE_DEVTOOLS__ hook, which profile enables. The app and the overlay share one Octane runtime.
  • Component Finder. Before Beast compiles a project .btsx file, the plugin adds data-beast-src="path:line:column" and data-beast-component to each of its HTML elements. The attributes are static, so Octane builds them into its templates at no runtime cost. Component calls and files in node_modules are not tagged.
  • Editor. Opening a file goes through the dev server's own launch-editor endpoint, which honors the LAUNCH_EDITOR environment variable.

Security model

The devtools can write to your source files, so their API only trusts requests from your own page.

  • The plugin runs only on the dev server. vite build, rspack build and rsbuild build never include the overlay, its API or the source tags.
  • Write endpoints accept only same-origin application/json requests. Requests that a browser marks as cross-site, or whose Origin is a different host, are refused.
  • The browser only names a suggestion. The dev server rebuilds the change from the file on disk, and refuses it if the file changed since it was analyzed.
  • Refactors only touch .btsx files inside the configured include directories, or inside a folder explicitly opened through Open project…. Every resulting file must compile before anything is written.
  • Request bodies are capped at 64 KiB, and component names at 80 characters.

[!WARNING] Like any dev server, it is meant for your machine. Don't expose a dev server running Beast DevTools to an untrusted network.

Troubleshooting

| Symptom | Cause and fix | | --- | --- | | Components shows Runtime off | Octane's inspection hook is missing. Enable profile in beastOctane() for dev builds, as in Quick start. | | The overlay is unstyled under Rspack | Add a rule for .css files: { test: /\.css$/, type: 'css' }. | | Component Finder outlines nothing | componentFinder is false, or the element comes from a package in node_modules, which isn't tagged. | | Open in editor does nothing | Set LAUNCH_EDITOR to your editor's command (for example code or cursor) and restart the dev server. | | A file is missing from the file list | It sits outside the include directories. Add its directory to include. | | Panel sizes or settings look wrong | Clear the beast-devtools:preferences and beast-devtools:layout keys from the page's local storage. |

Limitations

  • Hook values are matched to setup bindings by position and kind. When they don't line up (with custom hooks, for example), the panel shows positions such as #0 instead of guessing.
  • A prop is only as well typed as its binding. A host prop declared as any stays any, because types come from declarations, not from call sites.
  • Moving a section that uses module-level values makes the two files import each other. That's safe, because the values are read at render time, but the import cycle is worth knowing about.
  • Imports that only the moved section used are left in the source file.
  • Component Finder attributes are inserted into tagged lines, so dev-server error columns on those lines can point slightly past the real position. Line numbers are exact.
  • Component Finder names the component whose template holds an element. Markup passed in as children belongs to the file that wrote it.

Repository structure

@beastjs/devtools/
├── vite.ts, rspack.ts, rsbuild.ts   # Bundler plugins
├── server/                          # Node side, built to dist/
│   ├── devtools.ts                  # JSON API, change events, editor redirect
│   ├── project.ts                   # Project scan, compile cache, apply and undo
│   ├── analyze.ts                   # Nesting depth and refactor suggestions
│   ├── refactor.ts                  # Plans the edits for a suggestion
│   ├── types.ts                     # Prop types from the project's TypeScript
│   ├── slots.ts, source-scan.ts     # BTSX and TypeScript source scanning
│   ├── diff.ts, line-map.ts         # Diff previews and source-map line links
│   └── source-tags*.ts              # Component Finder tagging and Rspack loader
├── client/                          # The overlay, shipped as BTSX source
│   ├── BeastDevtools.btsx           # Shell: dock, launcher, panel switching
│   ├── Topbar.btsx, Icons.btsx      # Top bar with tabs and tool buttons; shared icons
│   ├── *Panel.btsx                  # Components, BTSX → TSRX, Refactor
│   ├── element-tools.ts, layout.ts  # Component Finder, Element Picker and resizable panes
│   ├── runtime.ts, api.ts           # Octane hook store and API client
│   └── devtools.css                 # Scoped styles (every class is bdt-*)
├── shared/types.ts                  # Wire types shared by both sides
└── test/                            # End-to-end dev-server harness and fixture

Development

Requirements: Bun and Node.js 22.22.2 or newer.

bun install
bun run check        # type check, tests, and plugin build
bun run pack:check   # list the files npm would publish

vite.test.ts, rspack.test.ts and rsbuild.test.ts start each real dev server on a throwaway app. They check the overlay bundle, the source tags, the API, change events and the editor redirect.

To try changes in an app, link the package and add it to the app's bundler config:

bun link                              # in this repository
bun add -d link:@beastjs/devtools     # in the app

Edits under client/ hot-reload in the linked app. Changes to the plugins or server/ need bun run build and a dev-server restart.

Contributions should keep production builds untouched, refactors conservative, and write endpoints same-origin only.

Releases

Releases are automated through a Release Please PR on main. Merging the PR creates the version tag and GitHub release, then publishes to npm with trusted publishing. See release setup, commit conventions, and retries.

License

Released under the ISC License.


Built for Beast and Octane.

Continue inline props

In BTSX → TSRX, click a component or element header with inline props, then click Continue props with ~. Each prop moves onto its own continuation line, preserving expressions, inline text and children:

Button(
  ~ label="Save"
  ~ onClick={save}
  ~ )

The change is saved after Beast and Octane validate it. Undo restores the previous source unless the file has since been edited.

The Refactor panel automatically suggests continuation for components and elements with 5 or more inline props. Adjust Continue at props to change that minimum; it is saved with your browser preferences. Select Continue props with ~ on a suggestion to review its diff, then Apply changes to save it. Already continued headers are excluded from automatic suggestions.

--automode