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

@tktideai/ai-api-cost-guard

v1.0.0

Published

Hard-stop budget limiter for AI API calls. Prevents runaway charges from OpenAI, Anthropic, Google Gemini and more.

Readme

api-cost-guard

Set a hard stop on your AI API spend — in one line of code.

Your cloud provider's billing limit doesn't stop mid-request spikes, infinite loops, or per-user abuse. This does.

Built with TypeScript and money-safe decimal arithmetic. Zero floating-point surprises.


The problem

Your app has a bug → infinite loop → 1,000 API calls in 60 seconds
Your cloud billing limit? It fires an email. After the fact.
Your credit card? Already charged.

api-cost-guard intercepts every request before it reaches the provider. If the cost would exceed your limit — it never goes out.


Install

npm install @tktideai/ai-api-cost-guard

Quick start

import { ApiCostGuard } from '@tktideai/ai-api-cost-guard';

const guard = new ApiCostGuard({
  hardLimit:       10.00,   // stop all requests at $10
  softLimit:        8.00,   // warn at $8
  perRequestLimit:  0.50,   // no single request over $0.50
});

// Before every API call:
const check = guard.preflightCheck('gpt-4o', 500, 500);
if (!check.allowed) return; // blocked — never reaches OpenAI

const response = await openai.chat.completions.create({ ... });

// After — record real usage so future checks stay accurate:
guard.recordUsage('gpt-4o',
  response.usage.prompt_tokens,
  response.usage.completion_tokens,
);

Simpler: use wrap()

const response = await guard.wrap(
  () => openai.chat.completions.create({ model: 'gpt-4o', messages }),
  {
    model:                 'gpt-4o',
    estimatedInputTokens:   500,
    estimatedOutputTokens:  500,
    extractUsage: (res) => ({
      inputTokens:  res.usage.prompt_tokens,
      outputTokens: res.usage.completion_tokens,
    }),
  },
);
// returns null if blocked, result if allowed

Options

const guard = new ApiCostGuard({
  // ── Limits ───────────────────────────────────────────────────────────
  hardLimit:       10.00,    // $ — block all requests at this cumulative spend
  softLimit:        8.00,    // $ — fire onWarning (does not block)
  perRequestLimit:  0.50,    // $ — block any single request above this cost

  // ── Rolling window ───────────────────────────────────────────────────
  windowMs: 3_600_000,       // only count spend in the last 1 hour (optional)

  // ── Callbacks ────────────────────────────────────────────────────────
  onWarning: (details) => {
    console.log(`⚠️ Approaching limit: $${details.projectedTotal}`);
  },
  onBlock: (error) => {
    console.log(`🛑 Blocked: ${error.message}`);
  },

  // ── Behaviour ────────────────────────────────────────────────────────
  throwOnBlock: true,        // throw BudgetExceededError when blocked (default: true)

  // ── Custom pricing ───────────────────────────────────────────────────
  customPricing: {
    'my-fine-tuned-model': { input: '0.008', output: '0.016', unit: 1000 },
  },
});

Supported models

Pricing is built-in and matched by substring — versioned names like gpt-4o-mini-2024-07-18 work automatically.

OpenAI

| Model | Input / 1k | Output / 1k | |---|---|---| | gpt-4o | $0.0025 | $0.0100 | | gpt-4o-mini | $0.00015 | $0.0006 | | gpt-4-turbo | $0.0100 | $0.0300 | | gpt-4 | $0.0300 | $0.0600 | | gpt-3.5-turbo | $0.0005 | $0.0015 | | o1 | $0.0150 | $0.0600 | | o3 | $0.0100 | $0.0400 | | o4-mini | $0.0011 | $0.0044 | | o1-pro | $0.1500 | $0.6000 |

Anthropic

| Model | Input / 1k | Output / 1k | |---|---|---| | claude-opus-4 | $0.0150 | $0.0750 | | claude-sonnet-4 | $0.0030 | $0.0150 | | claude-3-5-sonnet | $0.0030 | $0.0150 | | claude-3-5-haiku | $0.0008 | $0.0040 | | claude-3-opus | $0.0150 | $0.0750 | | claude-3-haiku | $0.00025 | $0.00125 |

Google Gemini

| Model | Input / 1k | Output / 1k | |---|---|---| | gemini-2.5-pro | $0.00125 | $0.0100 | | gemini-2.0-flash | $0.0001 | $0.0004 | | gemini-1.5-pro | $0.00125 | $0.0050 | | gemini-1.5-flash | $0.000075 | $0.0003 |

Prices may change. Always verify against provider docs and override via customPricing if needed.


Check your spend

const stats = guard.getStats();

console.log(stats.totalSpend.toFixed(4));     // "3.4200"
console.log(stats.remainingBudget.toFixed(4)); // "6.5800"
console.log(stats.percentUsed);               // "34.20"
console.log(stats.requestCount);              // 47

Express middleware

import { ApiCostGuard, createMiddleware } from '@tktideai/ai-api-cost-guard';

const guard = new ApiCostGuard({ hardLimit: 50 });

app.post('/api/chat', createMiddleware(guard), async (req, res) => {
  // If we reach here, budget is OK
  const response = await openai.chat.completions.create(req.body);
  guard.recordUsage(
    req.body.model,
    response.usage.prompt_tokens,
    response.usage.completion_tokens,
  );
  res.json(response);
});
// Returns 429 automatically if budget exceeded

Per-user limits (SaaS)

// One guard per user — isolated budgets
const userGuards = new Map<string, ApiCostGuard>();

function getGuard(userId: string): ApiCostGuard {
  if (!userGuards.has(userId)) {
    userGuards.set(userId, new ApiCostGuard({
      hardLimit: 5.00,           // $5 per user
      windowMs:  30 * 24 * 60 * 60 * 1000, // per month
    }));
  }
  return userGuards.get(userId)!;
}

// In your route:
const guard = getGuard(req.user.id);
const check = guard.preflightCheck('gpt-4o', 500, 500);

Email alerts (optional)

Get real email notifications when limits are hit. Uses Gmail SMTP — no external API key needed.

Setup

1. Get a Gmail app password for your sender address:

Google Account → Security → 2-Step Verification → App Passwords → Generate

2. Add to your .env:

[email protected]
GMAIL_PASS=xxxx xxxx xxxx xxxx

3. Use in your app:

import { ApiCostGuard } from '@tktideai/ai-api-cost-guard';
import { createEmailNotifier } from '@tktideai/ai-api-cost-guard/notifiers';

const notifier = createEmailNotifier({
  from:     process.env.GMAIL_FROM!,      // your Gmail — used as the sender
  password: process.env.GMAIL_PASS!,      // your Gmail app password
  to:       '[email protected]',            // where alerts are delivered
  message:  'Your AI budget needs attention.',  // optional
});

const guard = new ApiCostGuard({
  softLimit: 8,
  hardLimit: 10,
  onWarning: notifier,
  onBlock:   notifier,
});

What the email looks like

Subject: ⚠️ API Cost Alert — Budget Warning | TKTIDE

┌─────────────────────────────────────┐
│  ⚠️  Approaching Budget Limit       │
├─────────────────────────────────────┤
│  Your AI budget needs attention.    │  ← your message
│                                     │
│  Trigger        Soft Limit Warning  │
│  Current Spend  $7.9900             │
│  Projected      $8.0075             │
│  Limit          $8.0000             │
├─────────────────────────────────────┤
│  [TKTIDE logo]                      │
│  TKTIDE is here to help             │
│  https://tktide.com                 │
└─────────────────────────────────────┘

Email failures are non-fatal — they never crash or block your app.


Why TypeScript + Decimal.js?

Plain JavaScript has a well-known problem with money math:

// JavaScript — this is real:
0.1 + 0.2 === 0.30000000000000004  // true

// Your $0.30 hard limit never triggers
// You get charged $0.30000000000000004

api-cost-guard uses Decimal.js for all arithmetic:

new Decimal('0.10').plus('0.20').equals('0.30') // always true

Every cost, limit, and comparison is exact.


Error handling

import { ApiCostGuard, BudgetExceededError } from '@tktideai/ai-api-cost-guard';

try {
  guard.preflightCheck('gpt-4o', 5000, 2000);
} catch (e) {
  if (e instanceof BudgetExceededError) {
    console.log(e.details.type);           // 'hard_limit' | 'per_request_limit'
    console.log(e.details.limit);          // Decimal
    console.log(e.details.projectedTotal); // Decimal
    console.log(e.details.currentSpend);   // Decimal
  }
}

Or opt out of throwing:

const guard = new ApiCostGuard({
  hardLimit:    10,
  throwOnBlock: false,  // returns { allowed: false } instead of throwing
});

const check = guard.preflightCheck('gpt-4o', 5000, 2000);
if (!check.allowed) {
  console.log(check.reason); // 'hard_limit' | 'per_request_limit'
}

Full API reference

new ApiCostGuard(options)

Creates a new guard instance.

guard.preflightCheck(model, inputTokens, outputTokens?)

Check if a request is within budget before sending. Returns PreflightResult{ allowed: true } or { allowed: false, reason }.

guard.recordUsage(model, inputTokens, outputTokens, metadata?)

Record actual token usage after a successful API response. Returns the cost as a Decimal.

guard.wrap(apiFn, options)

Combines preflight + API call + usage recording in one call. Returns the API result or null if blocked (when throwOnBlock: false).

guard.getStats()

Returns a snapshot of current spend, request count, remaining budget, and the full ledger.

guard.reset()

Clears all spend records. Useful between billing periods or test runs.


Scripts

npm test          # run all 62 tests
npm run build     # compile TypeScript to dist/
npm run test:watch # watch mode

License

MIT — built with ❤️ by TKTIDE