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

@orkify/next

v1.0.0-beta.13

Published

Next.js integration for orkify — cache handlers and browser error tracking

Readme

Beta CI npm Node License TypeScript

Next.js integration for orkify — cache handlers and browser error tracking.

Table of Contents

Installation

npm install @orkify/next

@orkify/cache is installed automatically as a dependency.

Cache Handlers

orkify replaces Next.js's default cache with a shared in-memory cache that works across cluster workers. Both handlers use @orkify/cache under the hood — tag invalidation (revalidateTag()) propagates across all workers automatically.

Setup

// next.config.ts
import type { NextConfig } from 'next';

const nextConfig: NextConfig = {
  // Enable 'use cache' directives (required for Next.js 16)
  cacheComponents: true,

  // Next.js 16 'use cache' directives — backed by @orkify/cache
  cacheHandlers: {
    default: require.resolve('@orkify/next/use-cache'),
  },

  // ISR / route cache — backed by @orkify/cache
  cacheHandler: require.resolve('@orkify/next/isr-cache'),

  // Disable Next.js's built-in in-memory cache (orkify handles it)
  cacheMaxMemorySize: 0,

  // Version skew protection — auto-set by `orkify deploy`, optional for `orkify up/run`
  deploymentId: process.env.NEXT_DEPLOYMENT_ID || undefined,
};

export default nextConfig;

Build & Deploy

orkify deploys require output: 'standalone' in your Next.js config — this produces a self-contained build with all dependencies traced and bundled:

// next.config.ts
const nextConfig: NextConfig = {
  output: 'standalone',
  // ... rest of config
};

The standalone output doesn't include public/ or .next/static/, so copy them after building. In your orkify.yml:

deploy:
  install: npm ci
  build: >
    npm run build &&
    cp -r .next/static .next/standalone/.next/static &&
    cp -r public/. .next/standalone/public
processes:
  - name: app
    script: .next/standalone/server.js
    execMode: cluster

The entry point is .next/standalone/server.js — a minimal Node.js server that Next.js generates from the traced dependencies.

Handler Details

  • @orkify/next/use-cache — handles 'use cache' directives. Converts between Next.js's stream-based interface and orkify's synchronous cache. Implements staleness checks (hard expiry, revalidation window, soft tags).
  • @orkify/next/isr-cache — handles ISR / route cache. Simpler adapter: get, set, tag-based revalidation.

Both work standalone (npm run dev) and in cluster mode — the cache detects the mode automatically.

revalidateTag() calls in your Next.js app flow through orkify's cache, which broadcasts tag invalidations to all cluster workers via IPC:

// app/actions.ts
'use server';
import { revalidateTag } from 'next/cache';

export async function refreshPosts() {
  revalidateTag('posts'); // invalidates across all workers
}

ISR Request Coalescing

In cluster mode, multiple workers may detect the same stale cache entry simultaneously. Without coalescing, N workers trigger N parallel revalidations for the same page.

orkify uses the shared cache as a distributed lock. When a worker detects staleness, it sets a short-lived __revalidating:{key} flag. Other workers seeing this flag serve stale content instead of triggering their own revalidation. The lock auto-expires after 30 seconds and is cleared when the fresh entry is stored.

  • Hard expiration: not coalesced (entry is genuinely expired, must be regenerated)
  • Soft tag invalidation: not coalesced (explicit invalidation should always miss)
  • Revalidation window: coalesced (stale-while-revalidate semantics)

Browser Error Tracking

Capture browser errors and route them through orkify's error pipeline. Errors appear on the dashboard alongside server errors — no additional services needed. Errors bundle with the regular telemetry flush — zero additional API calls.

Setup

1. Add the capture component to your root layout:

// app/layout.tsx
import { OrkifyErrorCapture } from '@orkify/next/error-capture';

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html>
      <body>
        {children}
        <OrkifyErrorCapture />
      </body>
    </html>
  );
}

2. Create the API route at app/orkify/errors/route.ts:

export { POST } from '@orkify/next/error-handler';

3. Enable source maps for source-mapped stacks on the dashboard:

// next.config.ts — add to the config above
const nextConfig: NextConfig = {
  // ... cache handler config from above

  experimental: {
    serverSourceMaps: true,
  },
  webpack: (config, { isServer }) => {
    if (!isServer) {
      config.devtool = 'hidden-source-map';
    }
    return config;
  },
  // Turbopack is default in Next.js 16; empty config silences the
  // "webpack config without turbopack config" error during builds.
  turbopack: {},
};

hidden-source-map produces .map files on disk without exposing them to browsers. orkify reads these files server-side to resolve minified stacks.

Error Boundaries

Errors caught by React Error Boundaries (including Next.js error.tsx) don't bubble to window.onerror. Use reportError() to capture them:

// app/error.tsx
'use client';
import { reportError } from '@orkify/next/error-capture';
import { useEffect } from 'react';

export default function ErrorPage({ error }: { error: Error }) {
  useEffect(() => {
    reportError(error);
  }, [error]);

  return <p>Something went wrong.</p>;
}

What's Captured

  • window.onerror — uncaught exceptions
  • unhandledrejection — unhandled promise rejections
  • Manual reportError() calls from error boundaries

Each error includes: name, message, stack trace, page URL, and browser info.

Security

  • Origin validation: Rejects cross-origin requests. Supports X-Forwarded-Host for reverse proxy setups.
  • Rate limiting: Max 10 errors per 10 seconds per IP
  • Payload validation: Zod schema, 64 KB body limit, 100 stack line cap
  • No data reflection: Response is always { ok: true } — never echoes input

Stack Normalization

Firefox and Safari stacks are automatically normalized to V8 format (at fn (file:line:col)) before sending, so the entire downstream pipeline handles one format.

How It Works

Browser → POST /orkify/errors → API route handler → process.send() → orkify daemon → dashboard

Errors flow through the same IPC path as server errors and bundle with the regular telemetry flush. Zero additional API calls.

Server Actions Encryption Key

Next.js encrypts Server Action payloads. If the key differs between cluster workers or across rolling reloads, Server Actions fail with cryptic decryption errors. orkify auto-generates a stable NEXT_SERVER_ACTIONS_ENCRYPTION_KEY when it detects a Next.js app:

  • Generated once at process creation and stored in config
  • Consistent across all cluster workers (shared via config.env)
  • Survives reloads and daemon restarts (persisted in the snapshot file)
  • Skipped if you provide your own key via --env or shell environment

Security Header Stripping

orkify strips dangerous headers from external requests before they reach your app:

| Header | CVE | Risk | | ------------------------- | ------------------------- | ------------------------------------------ | | x-middleware-subrequest | CVE-2025-29927 (CVSS 9.1) | Bypasses Next.js middleware authentication | | x-now-route-matches | CVE-2024-46982 | Cache poisoning via Vercel routing |

Headers are preserved on loopback requests (127.0.0.1, ::1, ::ffff:127.0.0.1) since Next.js uses them internally. Active in fork mode, cluster mode, and run mode with no configuration needed.

Version Skew Protection

During orkify deploy, old and new workers coexist briefly. If client-side bundle hashes changed, a user who loaded a page from an old worker may request assets that only exist in the new version.

orkify auto-sets NEXT_DEPLOYMENT_ID during deploy (format: v{version}-{artifactSlice}). Next.js uses this to tag asset URLs and handle version mismatches gracefully. If you set NEXT_DEPLOYMENT_ID in your secrets, orkify won't overwrite it.

Requirements

  • Node.js 22+
  • Next.js 15+ (16+ for use cache)
  • Must run under @orkify/cli (GitHub) for error tracking to reach the dashboard

License

Apache-2.0