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

@monrow/sdk

v0.3.7

Published

AI cost protection that runs inside your app. Catch runaway loops before they bankrupt you.

Readme

@monrow/sdk

AI cost protection that runs inside your app. Wraps the Anthropic and/or OpenAI client, catches runaway loops and cost ceilings, throws an error before the next call fires. Optional cloud sync (Pro) streams cost-per-feature data to monrow.io.

  • Zero external runtime dependencies. Optional peer deps: @anthropic-ai/sdk, openai (install whichever you use).
  • TypeScript, Node 18+.
  • Local append-only incident log at .monrow/incidents.jsonl.
  • Local-only mode is free and unchanged. Cloud sync is opt-in via apiKey.

Install

npm install @monrow/sdk
# install the provider SDK(s) you use:
npm install @anthropic-ai/sdk
npm install openai

Wrap your Anthropic client

import Anthropic from '@anthropic-ai/sdk'
import {
  Monrow,
  MonrowAbuseError,
  MonrowBlockedError,
  MonrowCostLimitError,
  MonrowPausedError,
} from '@monrow/sdk'

const monrow = new Monrow({
  // optional: enable cloud sync for cost-per-feature dashboards
  apiKey: process.env.MONROW_KEY,
})
const anthropic = monrow.wrap(
  new Anthropic({ apiKey: process.env.ANTHROPIC_API_KEY })
)

OpenAI support

import { Monrow, MonrowAbuseError } from '@monrow/sdk'
import OpenAI from 'openai'

const monrow = new Monrow()
const openai = monrow.wrapOpenAI(
  new OpenAI({ apiKey: process.env.OPENAI_API_KEY })
)

async function handler() {
  try {
    const response = await openai.chat.completions.create({
      model: 'gpt-4o',
      monrow: { user: 'usr_bf29', feature: 'checkout-flow' },
      messages: [{ role: 'user', content: 'hello' }],
    })
    return response
  } catch (err) {
    if (err instanceof MonrowAbuseError) {
      // e.g. return a cached fallback instead of failing the request
      return null
    }
    throw err
  }
}

Works exactly like the Anthropic wrapper. All detectors, incident logging, cost tracking, and cloud sync apply equally.

Use as normal

The wrapped client behaves identically. The only addition is an optional per-call attribution field:

try {
  const res = await anthropic.messages.create({
    model: 'claude-sonnet-4-5',
    max_tokens: 1024,
    messages: [{ role: 'user', content: 'hello' }],
    // @ts-expect-error — monrow extends the request
    monrow: { user: 'usr_bf29', feature: 'checkout-flow' },
  })
} catch (err) {
  if (err instanceof MonrowAbuseError) {
    // runaway loop detected for this user — fall back gracefully
  } else if (err instanceof MonrowCostLimitError) {
    // this user has hit their per-user spend ceiling
  } else if (err instanceof MonrowPausedError) {
    // your cloud panic surface paused everything — show a soft outage screen
  } else if (err instanceof MonrowBlockedError) {
    // this user is blocked from the panic surface — return 403 to them
  } else {
    throw err
  }
}

The monrow field is stripped from the request before it ever reaches the upstream provider (Anthropic or OpenAI).

feature is an optional string (recommended ≤ 64 chars, hard cap 256) used for per-feature cost attribution.

Detectors

runaway_loop (pre-call, throws)

Counts requests per user inside a sliding window. Defaults: 100 requests in 300 seconds. When the threshold is hit, the next call is blocked with a MonrowAbuseError and a full incident card is printed to stderr.

cost_ceiling (pre-call, throws)

Per-user trailing-30-day spend. Default limit $50.00. If a user's cumulative spend has already reached the limit, the next call throws MonrowCostLimitError.

velocity_spike (post-call, log-only)

After each call, compares the user's last-hour request rate to their trailing 24-hour baseline. Never throws. Writes a severity: "observed" incident.

Cloud sync (Pro)

Pass an apiKey to enable cloud sync:

const monrow = new Monrow({ apiKey: process.env.MONROW_KEY })

Generate keys at https://monrow.io/settings/api-keys. Each completed call emits a CostEvent containing only metadata — event_id, user_key, feature, model, input_tokens, output_tokens, cost_cents, timestamp. No prompts. No responses. No PII.

Behavior:

  • Events buffer in memory and on disk at .monrow/sync-queue.jsonl for crash recovery.
  • Flushes every 30 seconds or when 50 events accumulate, whichever first.
  • On 401 (invalid key) or 402 (no Pro subscription), sync disables itself for the session and logs a single warning to stderr. Local detection continues unchanged.
  • On 5xx or network failure, retries with exponential backoff (10s → 30s → 2m → 10m), then drops the batch after the fourth attempt.
  • On SIGTERM, attempts a final flush for up to 5 seconds.

Sync failures never throw into your code.

Cloud control (Pro)

When apiKey is set, the SDK also polls GET ${apiUrl}/v1/control/state every 15 seconds. The endpoint returns a small JSON payload — paused_until, blocked_user_keys, version — used by the panic surface. Polling is If-None-Match ETag-aware so steady-state traffic is one cheap 304 Not Modified per window.

Before every wrapped messages.create() call, the SDK checks the cached state in memory (no network in the hot path):

  • If paused_until is in the future → throws MonrowPausedError.
  • If monrow.user is in blocked_user_keys → throws MonrowBlockedError.
  • Otherwise the existing detectors run.

Auto-release is the safety mechanism: a pause cannot be left on by accident. When paused_until passes, calls resume on the next poll (≤ 15 s).

The cached state is persisted to .monrow/control-state.json for crash recovery. Polling fails open — a 5xx or network error keeps the last-known state and retries on the next tick. A 401 disables polling for the session and logs one warning.

Monrow Cloud does not push notifications. The panic surface is pull-based. Open https://monrow.io/control when you need to act.

CLI (local-only, free)

npx monrow doctor    # transparency report — always free

Runaway loop detection, cost ceilings, and velocity spike logging work with no account and no API key.

Pro cloud ($29/mo)

Requires an API key in .monrowrc.json (from https://monrow.io/settings/api-keys):

npx monrow report                 # per-user cost summary, last 30 days
npx monrow report --by-feature    # per-feature cost summary, last 30 days
npx monrow incidents              # list recent incidents
npx monrow incidents show <id>    # re-render the full incident card

Pro also includes real-time Slack/webhook alerts, AI margin intelligence dashboard, cross-server protection, and the remote kill switch at https://monrow.io.

Report and incident commands read .monrow/incidents.jsonl and .monrow/state.json in the current directory.

Configuration

All settings are optional and have sane defaults. They can be set via the constructor, a .monrowrc.json file in the working directory, or both (constructor wins).

new Monrow({
  // cloud sync (optional)
  apiKey: process.env.MONROW_KEY,        // default: null (local-only)
  apiUrl: 'https://monrow.io',           // default; override for self-hosted
  sync_batch_size: 50,                   // default
  sync_interval_ms: 30_000,              // default
  control_poll_interval_ms: 15_000,      // default

  // detection
  detectors: {
    runaway_loop: { enabled: true, threshold_count: 100, window_seconds: 300 },
    cost_ceiling: { enabled: true, default_limit_cents: 5000 },
    velocity_spike: { enabled: true, multiplier: 5, baseline_window_hours: 24 },
  },
  impact_floor_cents_per_day: 2000,
  incident_log_path: '.monrow/incidents.jsonl',
  silent_boot: false,
})

Security

Run the transparency check at any time:

npx monrow doctor

Prints exactly what files Monrow has written, what network requests it makes, what SDK hooks are active, and whether cloud sync is enabled. No network call required.

Monrow never:

  • Proxies your AI requests
  • Collects prompt or response content
  • Installs background services or daemons
  • Executes shell commands
  • Writes files outside .monrow/

Full security policy: SECURITY.md

What Monrow doesn't do

Trust matters more than features for an in-process SDK. Things Monrow explicitly does not do:

  • No model swapping. Your model parameter is never mutated.
  • No prompt mutation. Your messages payload is never modified.
  • No prompt or response sync. The cloud ingest endpoint only accepts the event metadata listed above.
  • No silent retries against Anthropic.
  • No telemetry by default. Local-only mode makes zero outbound requests.
  • No browser support. Node only. Throws on import in the browser.
  • No external runtime dependencies.

Links

License

MIT.