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

@unbyte/abar

v0.1.0

Published

Active bars for your terminal. Manage live output lines with handles — update, finish, or let them disappear. Normal `console.*` writes coexist cleanly with the bar area.

Readme

abar

Active bars for your terminal. Manage live output lines with handles — update, finish, or let them disappear. Normal console.* writes coexist cleanly with the bar area.

demo

Installation

npm install @unbyte/abar
# or
pnpm add @unbyte/abar
# or
yarn add @unbyte/abar

Examples

See examples for runnable demos.

Quick Start

import abar from '@unbyte/abar'

abar.start()

const bar = abar.add({ text: 'loading...' })

setTimeout(() => {
  bar.update('still loading...')
}, 500)

setTimeout(() => {
  bar.finish('done!')  // prints "done!" permanently and removes the bar
  abar.stop()
}, 1000)

Multiple bars:

import abar from '@unbyte/abar'

abar.start()

const tasks = ['fetch', 'build', 'deploy'].map(name =>
  abar.add({ text: `[pending] ${name}` })
)

for (const [i, task] of tasks.entries()) {
  await doWork(i)
  task.finish(`[done] ${tasks[i].text?.split(' ')[1]}`)
}

abar.stop()

Core Concepts

Bar and handle

A bar is a live line of text pinned to the bottom of your terminal. abar owns the rendering — it clears and redraws the bar area around normal log output so the two never collide.

Each bar is created with abar.add(), which returns a handle. The handle is your control point: you push new text to it, and when the work is done you call finish() to either print a final line permanently or silently remove the bar.

A handle moves through three states:

  • init — created with no text, hidden until the first update(text) call.
  • active — has text, included in every render frame.
  • finished — after finish(). Permanently removed; all methods become no-ops. If finish(text) is called with a string, that text is written to the stream as a normal log line. Pass null to remove silently.

abar.stop() clears the bar area but does not finish handles — active handles re-appear on the next abar.start().

Transformer pipeline

Before each frame, abar collects all active bars as BarEntry[] and runs them through config.transformers in order. Each transformer receives the current entries and returns the list to actually render — you can filter bars, reorder them, rewrite their text, or inject SyntheticBarEntry rows (separators, headers, summaries) that aren't backed by a real handle.

import abar from '@unbyte/abar'

abar.configure({
  transformers: [
    entries => entries.map(e => ({
      ...e,
      text: `[${new Date().toISOString()}] ${e.text}`,
    })),
  ],
})

Reference

abar.configure(options)

Must be called before start() and while no handles are active.

| Option | Type | Default | Description | |---|---|---|---| | stream | NodeJS.WriteStream | process.stderr | Stream to render bars into | | renderThrottle | number | 16 | Trailing-edge debounce window in ms; rapid updates are collapsed into one render | | enabled | boolean | isInteractive(stream) | When false, all bar operations are no-ops and writes pass through unmodified | | discardStdin | boolean | true | Put stdin into raw mode while active to prevent input corrupting the bar area | | transformers | Transformer[] | [] | Ordered pipeline applied to render entries before each frame |

abar.add(options)BarHandle

| Option | Type | Default | Description | |---|---|---|---| | id | string | crypto.randomUUID() | Unique identifier | | text | string | undefined | Initial text; omit to start in init state |

BarHandle

| Member | Description | |---|---| | .id | The id assigned at add() | | .createdAt | Timestamp at creation | | .updatedAt | Timestamp at last update() | | .update(text) | Set new text and schedule a re-render | | .finish(text?) | Remove from bar area; writes text to the stream permanently if given, writes current text if omitted, or removes silently if null |

License

MIT License