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

@airdraft/next

v0.1.20

Published

Airdraft Next.js App Router integration — route handlers, OpenAPI, revalidation

Readme

@airdraft/next

Next.js adapter for Airdraft. Provides the API route handler, server-side helpers, middleware, and revalidation utilities.

Installation

npm install @airdraft/next

Usage

API Route Handler

Create app/api/cms/[...path]/route.ts:

import { createCmsHandler } from '@airdraft/next'
import { airdraft } from '../../../../airdraft.config'

export const { GET, POST, PATCH, PUT, DELETE } = createCmsHandler(airdraft)

createCmsHandler automatically wraps all routes with audit logging when a plugin with onAuditEvent is registered.

Server Client

import { createCmsClient } from '@airdraft/next'
import { airdraft } from '../airdraft.config'

const cms = createCmsClient(airdraft)
const { entries } = await cms.listEntries('posts')

Middleware

Protect your CMS UI routes in middleware.ts (not the API routes — those are protected by @airdraft/plugin-auth):

import { withCmsProxy } from '@airdraft/next'

export default withCmsProxy({ basePath: '/api/cms' })
export const config = { matcher: ['/cms/:path*'] }

Revalidation

import { revalidateEntry } from '@airdraft/next'

// Call after publishing an entry to trigger ISR
await revalidateEntry({ collection: 'posts', slug: 'hello-world' })

Exports

| Export | Description | |---|---| | createCmsHandler(config) | Returns { GET, POST, PATCH, PUT, DELETE } Next.js route handlers. | | createCmsClient(config) | Returns a direct server-side CMS client (no HTTP). Use in Server Components and generateStaticParams. | | withCmsProxy(options) | Next.js middleware that proxies CMS requests to the configured basePath. | | revalidateEntry(options) | Triggers Next.js ISR revalidation for an entry path. | | createTokenProvider() | Token provider for client-side auth flows. |

Server Client

import { createCmsClient } from '@airdraft/next'
import { airdraft } from '../airdraft.config'

const cms = createCmsClient(airdraft)

// List with pagination
const { entries, total, page, pages, hasNext } = await cms.listEntries('posts', {
  status: 'published',
  limit: 10,
  page: 2,
})

// Single entry with sibling navigation
const post = await cms.getEntry('posts', 'hello-world', { siblings: true })
// post.wordCount, post.readTime, post.prev, post.next

HTTP API

System routes

| Route | Description | |---|---| | GET /health | Health check. Returns { data: { status: 'ok', timestamp: '...' } }. | | GET /schema | Full CmsSchema describing all collections and fields. | | GET /openapi.json | OpenAPI 3.0.0 spec auto-generated from the runtime collection schemas. | | GET /docs | Scalar API reference UI, sourced from /openapi.json. |

Query parameters:

| Param | Description | |---|---| | limit | Max entries per page (capped at 100). | | page | 1-based page number. Converted to offset = (page-1)*limit. Takes precedence over offset. | | offset | Zero-based offset (alternative to page). | | sort[field] | Field name to sort by (e.g. sort[field]=createdAt). | | sort[order] | Sort direction: asc or desc. | | status | published | draft | all (default). | | expand | Comma-separated relation field names to expand inline. | | filter[field] | Equality filter on any field. |

Response shape:

{
  "data": [
    { "slug": "...", "title": "...", "wordCount": 1432, "readTime": "7 min read", "_sha": "..." }
  ],
  "meta": {
    "total": 42,
    "page": 1,
    "pages": 5,
    "hasNext": true,
    "hasPrev": false,
    "offset": 0,
    "limit": 10
  }
}

GET /{collection}/{slug}

Query parameters:

| Param | Description | |---|---| | expand | Comma-separated relation field names to expand inline. | | siblings | Set to true or 1 to include prev/next sibling stubs in meta. | | siblings[sort] | Field name to sort the sibling pool by. | | siblings[order] | asc | desc (default desc). | | siblings[status] | Filter sibling pool by publish status. | | siblings[fields] | Comma-separated fields to include in sibling stubs. | | siblings[filter][field] | Equality filter on the sibling pool. |

Response shape:

{
  "data": { "slug": "...", "title": "...", "body": "..." },
  "meta": {
    "sha": "...",
    "wordCount": 1432,
    "readTime": "7 min read",
    "prev": { "slug": "prev-post", "data": { "title": "Prev Post" }, "wordCount": 980, "readTime": "5 min read" },
    "next": null
  }
}

Audit Logging

When any plugin registers an onAuditEvent hook, createHandler wraps every route with auditWrap. Each request produces an AuditEvent that includes:

  • action, method, path, statusCode, durationMs
  • collection, slug (when applicable)
  • actor — the raw API key / bearer token
  • error.message, error.code, error.details — per-field validation failures are included in details for VALIDATION_ERROR responses

Response Transform

After each successful response, createHandler runs all plugin transformResponse hooks in registration order. This is used by @airdraft/plugin-auth to transparently append refreshed Set-Cookie headers when a server-side silent token rotation occurs (expired access token + valid refresh cookie). Auth errors (401/403) bypass the transform pipeline.

Changelog

Breaking change (v0.1.14): Sort query parameters changed from flat ?sort=field&order=asc to bracket notation ?sort[field]=field&sort[order]=asc to be consistent with the filter[field] convention. Update any API consumers before upgrading.

See CHANGELOG.md.