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

lever-fetch

v0.1.2

Published

API testing from the command line. Define endpoints as TypeScript, commit them to your repo, run them against any environment.

Readme

lever-fetch

API testing from the command line. Define endpoints as TypeScript, commit them to your repo, run them against any environment.

npm install lever-fetch
npx lever-fetch init
npx lever-fetch list
npx lever-fetch run example/demo.get

Why

API collections shouldn't live in a desktop app. They should be versioned, reviewed, and shared like the rest of your code. lever-fetch stores endpoints as typed TypeScript files in your repo. No accounts, no sync, no GUI.

Project Structure

your-project/
├── endpoints/
│   └── my-api/
│       ├── vars.ts                # Shared test fixtures
│       ├── users.ts               # Endpoint definitions
│       ├── posts.ts
│       └── tests/
│           └── user-flow.ts       # Integration test suites
├── envs/
│   ├── local.ts                   # Base URL + token per environment
│   └── staging.ts
├── .env                           # Secrets (gitignored)
└── package.json

Endpoints

Each named export is a runnable target.

// endpoints/my-api/users.ts
import type { Endpoint } from "lever-fetch";

export const list: Endpoint = {
  method: "GET",
  path: "/users",
  description: "List all users",
};

export const create: Endpoint = {
  method: "POST",
  path: "/users",
  body: { name: "Jane Doe", email: "[email protected]" },
};
npx lever-fetch run my-api/users.list
npx lever-fetch run my-api/users      # all endpoints in file
npx lever-fetch run my-api            # all endpoints in collection
npx lever-fetch run                   # everything

Dynamic Bodies

Return an object from a function when you need fresh values per request.

export const createPost: Endpoint = {
  method: "POST",
  path: "/posts",
  body: () => ({
    title: "New post",
    createdAt: new Date().toISOString(),
  }),
};

Runtime Input

For values you can't hardcode — OTP codes, confirmation tokens, anything that changes every time.

export const verify: Endpoint = {
  method: "POST",
  path: "/auth/verify",
  body: { email: "[email protected]" },
  input: { code: "Enter OTP code" },
};

lever-fetch pauses, asks for the value, and merges it into the body before sending.

$ lever-fetch run my-api/auth.verify --env local
  → Enter OTP code: 123456

[PASS] my-api/auth.verify 200 342ms

Requires an interactive terminal. In CI, use env vars with a dynamic body instead.

Endpoint Fields

| Field | Required | Description | |---------------|----------|------------------------------------------| | method | yes | HTTP method | | path | yes | URL path, supports {var} placeholders | | body | no | Object or () => object | | headers | no | Additional headers | | description | no | Shown in lever-fetch list | | input | no | Body field name → prompt message |

Variables

Shared test fixtures go in vars.ts inside the collection. These get committed.

// endpoints/my-api/vars.ts
export default {
  orgId: "org_01H8MZXK",
  teamId: "team_9F3A2B",
} as Record<string, string>;

Reference them with {varName} in endpoint paths:

export const members: Endpoint = {
  method: "GET",
  path: "/orgs/{orgId}/teams/{teamId}/members",
};

Environment-level vars override collection defaults.

Environments

// envs/local.ts
import type { Env } from "lever-fetch";

export default {
  baseUrl: "http://localhost:3000",
  token: process.env.API_LOCAL_TOKEN ?? "",
} satisfies Env;
// envs/staging.ts
import type { Env } from "lever-fetch";

export default {
  baseUrl: "https://api-staging.example.com",
  token: process.env.API_STAGING_TOKEN ?? "",
  vars: { orgId: "org_STAGING_01" },
} satisfies Env;

| Field | Required | Description | |-----------|----------|--------------------------------------| | baseUrl | yes | Prepended to all endpoint paths | | token | yes | Sent as Authorization: Bearer | | headers | no | Default headers for all requests | | vars | no | Override collection variables |

Secrets go in .env (gitignored) and are auto-loaded at startup. Run lever-fetch init to scaffold a .env.example template.

Secrets Providers

For teams that store credentials in cloud secret stores, environment files can export an async function that fetches secrets at runtime.

npm install @aws-sdk/client-secrets-manager
// envs/staging.ts
import type { Env } from "lever-fetch";
import { secret } from "lever-fetch/secrets";

export default async (): Promise<Env> => ({
  baseUrl: "https://api-staging.example.com",
  token: await secret("aws-secrets-manager", "my-api/staging", { field: "token" }),
});

The secret() function fetches the value from the provider, caches it for the duration of the run, and extracts a JSON field if field is specified. Without field, the raw string is returned.

Multiple fields from one secret are supported — the secret is only fetched once:

export default async (): Promise<Env> => ({
  baseUrl: "https://api.example.com",
  token: await secret("aws-secrets-manager", "my-api/creds", { field: "token" }),
  headers: {
    "X-Api-Key": await secret("aws-secrets-manager", "my-api/creds", { field: "apiKey" }),
  },
});

Static environment files (export default { ... } satisfies Env) continue to work with no changes.

Custom Providers

Register your own provider for any secret store:

import { registerProvider, secret } from "lever-fetch/secrets";

registerProvider({
  name: "my-vault",
  async getSecret(secretId) {
    const response = await fetch(`https://vault.internal/v1/secret/${secretId}`);
    const data = await response.json();
    return data.value;
  },
});

export default async (): Promise<Env> => ({
  baseUrl: "https://api.internal.com",
  token: await secret("my-vault", "api-token"),
});

Secret Options

| Field | Description | |-----------|-----------------------------------------------------| | field | Extract a key from a JSON secret | | region | Provider-specific region override (e.g., AWS region)| | version | Secret version or stage identifier |

Integration Tests

Chain requests together. Extract values from one response and use them in the next.

// endpoints/my-api/tests/user-flow.ts
import type { TestSuite } from "lever-fetch/test";

export default {
  description: "Create a user, then verify they appear in the list",
  steps: [
    {
      name: "create user",
      endpoint: "my-api/users.create",
      assert: { status: 201 },
      extract: { userId: "body.id" },
    },
    {
      name: "list users",
      endpoint: "my-api/users.list",
      assert: { status: 200 },
    },
  ],
} satisfies TestSuite;
npx lever-fetch test my-api/user-flow --env local
[PASS] create user — 201 15ms
  userId = usr_8f3a2b...
[PASS] list users — 200 11ms

--- my-api/user-flow: 2 passed (26ms) ---

Extracted variables are injected into {varName} placeholders for subsequent steps. If a step fails, the rest are skipped.

| Field | Required | Description | |------------|----------|----------------------------------------------------------| | name | yes | Step label | | endpoint | yes | Target (e.g., my-api/users.list) | | assert | no | { status?, body? } — expected values | | extract | no | Variable name → dot-path (e.g., body.id) | | input | no | Body field → prompt message (overrides endpoint-level) |

Load Testing

Ramp up concurrent users to find breaking points.

npx lever-fetch load my-api/users.list --users 100 --duration 30s --ramp-up 10s
────────────────────────────────────────────────
  Load Test Results
────────────────────────────────────────────────
  Total requests:  9,364
  Throughput:      1,865.7 req/s
  Error rate:      0.0%

  Latency (ms):
    p50    4
    p95    7
    p99    10
    max    724

  Status codes:
    200    9,364
────────────────────────────────────────────────

| Option | Default | Max | Description | |------------------|---------|-------|--------------------------| | --users, -u | 10 | 1,000 | Peak concurrent users | | --duration, -d | 30s | 300s | Total test duration | | --ramp-up, -r | 5s | — | Linear ramp-up period |

CLI Reference

lever-fetch init                Scaffold a starter project
lever-fetch run <target>        Run endpoint(s)
lever-fetch test [target]       Run integration test suite(s)
lever-fetch load <target>       Load test a single endpoint
lever-fetch list                List all endpoints

Targets:
  my-api/users.list             Single endpoint
  my-api/users                  All endpoints in a file
  my-api                        Entire collection
  (omit)                        Everything

Options:
  --env, -e <name>              Environment (default: local)
  --token, -t <token>           Override auth token
  --help, -h                    Show help

Types

import type { Endpoint, Env, EnvFactory, InputFields } from "lever-fetch";
import type { TestSuite, TestStep } from "lever-fetch/test";
import { secret, registerProvider } from "lever-fetch/secrets";
import type { SecretsProvider, SecretOptions } from "lever-fetch/secrets";

License

MIT