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

@alexanderfortin/pi-usage-lib

v0.2.3

Published

Shared library for Pi usage monitoring extensions

Readme

pi-usage-lib

Shared library for building Pi coding agent usage-monitoring extensions.

It absorbs all the boilerplate that most *-usage extension needs — Pi event registration, provider matching, API fetching with sandbox-aware auth, response caching, error handling, and themed footer rendering — so that each extension reduces to a single config object with two callbacks.

What's Included

| Module | Exports | Purpose | |---|---|---| | pi-usage-lib | createUsageExtension(), UsageCache, UsageError, buildAuthHeaders(), safeFetch(), safeParseJson() | Factory + building blocks | | pi-usage-lib/datetime | formatInstantFromEpochMs(), formatTimeRemainingFromEpochMs() | Temporal date/time helpers |

Install

bun add @alexanderfortin/pi-usage-lib

Quick Start

import { createUsageExtension, buildAuthHeaders, safeFetch, safeParseJson } from "@alexanderfortin/pi-usage-lib"

export default createUsageExtension({
  providerPrefix: "myprovider",
  statusKey: "myprovider-usage",
  label: "MyProvider",

  async fetchUsage(modelRegistry) {
    const headers = await buildAuthHeaders(modelRegistry, "myprovider")
    const response = await safeFetch("https://api.myprovider.com/usage", { headers })
    const data = await safeParseJson(response)
    return { balance: data.balance }
  },

  renderStatus(data, theme) {
    return theme.fg("muted", "MyProvider:") + theme.fg("accent", `$${data.balance.toFixed(2)}`)
  },
})

That's it — one file, no other source files needed. The factory registers all Pi events, manages caching, handles errors, and shows a themed footer automatically.

API Reference

createUsageExtension<TData>(config)

Creates a Pi extension function from a configuration object.

interface UsageExtensionConfig<TData> {
  providerPrefix: string      // e.g. "zai", "deepseek"
  statusKey: string           // e.g. "zai-usage"
  label: string               // e.g. "MyProvider"
  cooldownMs?: number         // cache TTL (default: 30_000)
  fetchUsage: FetchUsageFn<TData>
  renderStatus: RenderStatusFn<TData>
  renderError?: RenderErrorFn // optional, defaults to themed <err:code> display
}

The returned function is a valid Pi extension — pass it as the default export or register it via pi.extensions.

buildAuthHeaders(modelRegistry, providerName, extra?)

Builds authenticated fetch headers using a 3-way sandbox-aware strategy:

  1. Real key → sends Authorization: Bearer <key>
  2. "proxy-managed" sentinel → skips auth header (Docker Sandbox proxy handles it)
  3. No key → skips auth header (API returns 401 → shown as <err:http401>)

Always sets Accept-Encoding: identity to work around Pi v0.75.0's undici gzip decompression issue.

safeFetch(url, init?)

Wraps fetch() with structured error handling:

  • Network errors (DNS, timeout, proxy) → throws UsageError with code "fetch"
  • HTTP errors (4xx, 5xx) → throws UsageError with code "http{status}"

safeParseJson<T>(response)

Parses response.json() with error handling:

  • Empty or malformed body → throws UsageError with code "badjson"

UsageError

class UsageError extends Error {
  readonly name = "UsageError"
  readonly code: string  // e.g. "fetch", "http401", "badjson", custom codes
}

Used by safeFetch, safeParseJson, and the default error renderer. Extensions can throw UsageError from their fetchUsage with custom codes — the default renderError will display them as <err:code> in the footer.

UsageCache<TData>

The generic cache class used internally by createUsageExtension. Available for advanced use cases where you need direct control over the cache lifecycle.

Color Thresholds (Configurable)

The library highlights usage values with color when they approach or exceed limits:

  • Percentage-based (e.g. Z.ai usage): warning above 80%, critical at 90%+
  • Credit-based (e.g. DeepSeek balance): warning below $5, critical at $1 or less

Overriding thresholds via settings file

You can override any or all of the default thresholds by creating a JSON file at ~/.pi/agent/usage-lib.json:

{
  "thresholds": {
    "percentage": { "warning": 70, "critical": 85 },
    "credit": { "warning": 5, "critical": 2 }
  }
}

All keys are optional — only the ones you specify are overridden; the rest keep their defaults. Unknown keys and non-numeric values are silently ignored. The file is read once per session and cached.

Overriding thresholds programmatically

The colorForPercentage() and colorForCredit() helpers accept an optional thresholds parameter:

import { colorForPercentage, type ColorThresholds } from "@alexanderfortin/pi-usage-lib"

const custom: ColorThresholds = {
  percentage: { warning: 60, critical: 75 },
  credit: { warning: 5, critical: 1 },
}

// In your renderStatus callback:
const color = colorForPercentage(data.percentage, theme, custom)

When no thresholds argument is passed, the functions fall back to the values loaded from the settings file (or the built-in defaults).

Color threshold API

| Export | Description | |---|---| | ColorThresholds | Type describing the threshold structure | | DEFAULT_COLOR_THRESHOLDS | Built-in default thresholds | | loadColorThresholds() | Load & cache thresholds from the settings file | | mergeThresholds(defaults, overrides) | Merge partial overrides into defaults | | getSettingsFilePath() | Resolve the path to ~/.pi/agent/usage-lib.json |

Error Display (Default Behavior)

By default, errors are shown in the footer using the following pattern:

MyProvider:<err:http401>
MyProvider:<err:fetch>
MyProvider:<err:badjson>

No console.error is called — the footer is the error channel. To customize, provide a renderError callback. Return undefined to clear the footer instead.

Date/Time Utilities (pi-usage-lib/datetime)

import { formatInstantFromEpochMs, formatTimeRemainingFromEpochMs } from "@alexanderfortin/pi-usage-lib/datetime"

formatInstantFromEpochMs(1705318245000)    // "Mon, 15 Jan 2024, 14:30:45 GMT"
formatTimeRemainingFromEpochMs(Date.now() + 3665000)  // "1h 1m 5s"

License

See LICENSE