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

nextlove

v4.5.1

Published

Enhanced Next.js API types, OpenAPI generation and utilities.

Readme

nextlove - Enhanced NextJS API Types, OpenAPI and Utilities

Make type-safe routes that automatically generate OpenAPI in NextJS easy!

  • Define endpoints with middleware and have your request objects and responses automatically be typed
  • The same zod schemas used for your types will be in the generated openapi.json file!
  • Throw http exceptions and they'll magically be handled
  • Have well-typed middleware

Installation

npm install nextlove

Create well-typed routes + middleware with nextlove!

nextlove allows you to create well-typed middleware and routes using utility types and functions. The two main functions to know are createWithRouteSpec, which allows you to create a withRouteSpec function that can be used with all your endpoints, and the Middleware utility function which makes middleware type-safe.

Let's take a look at an example project with three files:

  • lib/with-route-spec.ts - This file is used to create the withRouteSpec middleware. This middleware should be used for all your routes.
  • lib/middlewares/with-auth-token.ts - This is an authentication middleware we'll be using to make sure requests are authenticating
  • lib/middlewares/with-db.ts - A common global middleware that attaches a database client to the request object
  • pages/api/health.ts - Just a health endpoint to see if the server is running! It won't have any auth
  • pages/api/todos/add.ts - An endpoint to add a TODO, this will help show how we can use auth!
// pages/api/health.ts
import { withRouteSpec } from "lib/with-route-spec"
import { z } from "zod"

const routeSpec = {
  methods: ["GET"],
  auth: "none",
  jsonResponse: z.object({
    healthy: z.boolean(),
  }),
} as const

export default withRouteSpec(routeSpec)(async (req, res) => {
  /* ... */
  return res.status(200).json({ healthy: true })
})
// lib/with-route-spec.ts
export const withRouteSpec = createWithRouteSpec({
  authMiddlewareMap: { auth_token: withAuthToken },
  globalMiddlewares: [globalMiddleware],

  // For OpenAPI Generation
  apiName: "My API",
  productionServerUrl: "https://example.com",
  globalSchemas: {
    user: z.object({
      user_id: z.string().uuid(),
    }),
  },
} as const)
// lib/middlewares/with-auth-token.ts
import { UnauthorizedException, Middleware } from "nextlove"

export const withAuthToken: Middleware<{
  auth: {
    authorized_by: "auth_token"
  }
}> = (next) => async (req, res) => {
  req.auth = {
    authorized_by: "auth_token",
  }

  return next(req, res)
}

export default withAuthToken
// pages/api/todos/add.ts
import { withRouteSpec, UnauthorizedException } from "lib/with-route-spec"
import { z } from "zod"

const routeSpec = {
  methods: ["POST"],
  auth: "auth_token",
  jsonBody: z.object({
    content: z.string(),
  }),
  jsonResponse: z.object({
    ok: z.boolean(),
  }),
} as const

export default withRouteSpec(routeSpec)(async (req, res) => {
  // req.auth is correctly typed here!
  if (req.auth.authorized_by !== "auth_token") {
    throw new UnauthorizedException({
      type: "unauthorized",
      message: "Authenticate yourself to get the requested response",
    })
  }
  // TODO add todo
  return res.status(200).json({ ok: true })
})

createWithRouteSpec Parameters

| Parameter | Description | | --------------------- | ------------------------------------------------------------ | | authMiddlewareMap | Object that maps different types of auth to their middleware | | globalMiddlewares | Middlewares that should be applied on every route | | apiName | Used as the name of the api in openapi.json | | productionServerUrl | Used as the default server url in openapi.json |

withRouteSpec Parameters

| Parameter | Description | | -------------- | -------------------------------------------------------------------------------------------------------------------------------------- | | methods | HTTP Methods accepted by this route | | auth | none or a key from your authMiddlewareMap, this authentication middleware will be applied | | queryParams | Any GET query parameters on the request as a zod object | | jsonBody | The JSON body this endpoint accepts as a zod object | | formData | The multipart/form-data (todo) or application/x-www-form-urlencoded encoded body | | commonParams | Parameters common to both the query and json body as a zod object, this is sometimes used if a GET route also accepts POST | | jsonResponse | A zod object representing the json resposne |

Generating OpenAPI Types (Command Line)

Just run nextlove generate-openapi in your project root!

Examples:

# Print OpenAPI JSON directly to the command line for the package in the current directory
nextlove generate-openapi --packageDir .

# Write OpenAPI JSON to "openapi.json" file
nextlove generate-openapi . --outputFile openapi.json

# Only generate OpenAPI JSON for public api routes
nextlove generate-openapi . --pathGlob '/pages/api/public/**/*.ts'

| Parameter | Description | | ------------ | ------------------------------------------------------------------------------------------ | | packageDir | Path to directory containing package.json and NextJS project | | outputFile | Path to output openapi.json file | | pathGlob | Paths to consider as valid routes for OpenAPI generation, defaults to /pages/api/**/*.ts |

Generating OpenAPI Types (Script)

import { generateOpenAPI } from "nextlove"

generateOpenAPI({
  packageDir: ".",
  outputFile: "openapi.json",
  pathGlob: "/src/pages/api/**/*.ts",

  // Tags improve the organization of an OpenAPI spec by making "expandable"
  // sections including routes
  tags: ["users", "teams", "workspaces"].map((t) => ({
    name: `/${t}`,
    description: t,
    doesRouteHaveTag: (route) => route.includes(`/${t}`),
  })),
  mapFilePathToHTTPRoute(fp) {
    return fp
      .replace("src/pages/api/public", "")
      .replace(/\.ts$/, "")
      .replace(/\/index$/, "")
  },
})

Extracting route specs (Command Line)

Just run nextlove extract-route-specs in your project root! It will output a ESM file bundled by esbuild.

Caveats:

  • All dependencies and dev dependencies in your package.json are automatically marked as external when bundling. This means that you may want to re-bundle the output file if you plan on publishing it as part of a library.
  • By default, API route files aren't allowed to import anything besides dependencies declared in package.json. This is to avoid accidentally polluting the bundle. To allow specific imports, use the --allowed-import-patterns flag: --allowed-import-patterns '**/lib/**' --allowed-import-patterns '**/models/**'

Wrap middlewares together using wrappers!

import { wrappers } from "nextlove"

wrappers(withDatabase, logger.withContext("somecontext"), async (req, res) => {
  res.status(200).end("...")
})

nextjs-exception-middleware

import { BadRequestException } from "nextlove"

// Inside a route handler
if (bad_soups.includes(soup_param)) {
  throw new BadRequestException({
    type: "cant_make_soup",
    message: "Soup was too difficult, please specify a different soup",
    data: { soup_param },
  })
}

All Modules

This repo bundles NextJS utility modules including...