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

@wolfstar/plugin-api

v1.1.3

Published

Plugin for @wolfstar/http-framework exposing a standalone REST API server (routes, middlewares, router)

Downloads

913

Readme

@wolfstar/plugin-api

A plugin for @wolfstar/http-framework, ported from @sapphire/plugin-api. It exposes a standalone REST API server — for health checks, dashboards, or webhooks from other services — built on the same @sapphire/pieces Route/Middleware conventions.

It is intentionally independent from Client#server (the interactions webhook): that server already claims every path on its port and 404s anything that doesn't match, so this plugin binds its own ApiServer on a separate port instead of trying to share the same listener.

Installation

pnpm add @wolfstar/plugin-api

Usage

Import the side-effecting register entrypoint before you create your Client:

import "@wolfstar/plugin-api/register";
import { Client } from "@wolfstar/http-framework";

const client = new Client({
  api: {
    listenOptions: { port: 4000 },
    origin: "*",
  },
});

await client.load();
await client.listen({ port: 8080 }); // interactions webhook; the API server starts right after

Writing a route

Routes are Route pieces loaded from a routes directory, exactly like commands/listeners:

// src/routes/health.get.ts
import { HttpCodes } from "@wolfstar/http-framework";
import { Route } from "@wolfstar/plugin-api";

export class HealthRoute extends Route {
  public run(_request: Route.Request, response: Route.Response) {
    response.json({ status: "ok" }, HttpCodes.OK);
  }
}

The route's path and method are inferred from its location: src/routes/health.get.ts registers GET /health. A folder named [id] becomes a dynamic segment (request.params.id), and a (group)-style folder is skipped when building the path. Both can be overridden explicitly:

export class HealthRoute extends Route {
  public constructor(context: Route.LoaderContext) {
    super(context, { route: "/status", methods: ["GET", "HEAD"] });
  }

  public run(request: Route.Request, response: Route.Response) {
    response.json({ status: "ok", method: request.method });
  }
}

Writing a middleware

Middlewares are Middleware pieces loaded from a middlewares directory, run in ascending position order before route dispatch; a middleware stops the chain by ending the response:

// src/middlewares/requestId.ts
import { Middleware } from "@wolfstar/plugin-api";
import { randomUUID } from "node:crypto";

export class RequestIdMiddleware extends Middleware {
  public constructor(context: Middleware.LoaderContext) {
    super(context, { position: 15 });
  }

  public run(request: Middleware.Request, response: Middleware.Response) {
    response.setHeader("X-Request-Id", randomUUID());
  }
}

Built-in middlewares: headers (position 10, sets CORS headers and short-circuits OPTIONS pre-flight requests) and body (position 20, rejects requests whose Content-Length exceeds maximumBodyLength).

ApiServerOptions

| Option | Default | Description | | ---------------------- | ------------------ | -------------------------------------------------------- | | prefix | undefined | Path segment prefix applied to every route. | | origin | '*' | Access-Control-Allow-Origin header value. | | maximumBodyLength | 1024 * 1024 * 50 | Maximum accepted Content-Length, in bytes. | | server | undefined | Raw options forwarded to node:http's createServer. | | listenOptions | { port: 4000 } | Raw options forwarded to server.listen(). | | automaticallyConnect | true | Whether to start listening during the postListen hook. |

Scope

Ported faithfully: the Route/RouteStore piece conventions, the filesystem-routing/dynamic-segment trie router (RouterRoot/RouterBranch/RouterNode), the position-ordered Middleware/MiddlewareStore chain, and the listener-driven request dispatch pipeline (request → middlewares → routerFound / routerBranchNotFound / routerBranchMethodNotAllowed → route run).

Not ported (out of scope for this webhook-only framework, kept for a future release): cookies, OAuth2/session auth, and the built-in oauth/callback, oauth/logout routes from the original @sapphire/plugin-api. Add your own auth middleware/routes as needed.