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

@dappfence/next

v0.1.2

Published

Next.js integration for DappFence — webpack plugin, manifest generation, script injection

Readme

@dappfence/next

Next.js integration for DappFence — automatically copies the security script, hashes static assets, and generates a signed integrity manifest at build time.

Installation

npm install @dappfence/next @dappfence/core

@dappfence/core provides the dappfence.js runtime copied into your output.

Setup

SSR / hybrid apps (default Next.js mode)

Wrap your Next.js config with withDappfence:

// next.config.js
import { withDappfence } from '@dappfence/next';

export default withDappfence({
    secretKey: process.env.DAPPFENCE_SECRET_KEY,
})(nextConfig);

Then add the script tag to your root layout. Use Next.js's built-in <Script> component with strategy="beforeInteractive" so DappFence loads before any other scripts on the page. getDappfenceScriptAttrs supplies all required attributes from the build-time config — no options or secrets are needed in the layout:

// app/layout.js
import Script from 'next/script';
import { getDappfenceScriptAttrs } from '@dappfence/next';

const { src, ...attrs } = getDappfenceScriptAttrs();

export default function RootLayout({ children }) {
    return (
        <html>
            <head>
                <Script src={src} strategy="beforeInteractive" {...attrs} />
            </head>
            <body>{children}</body>
        </html>
    );
}

strategy="beforeInteractive" ensures DappFence is executed before any other JavaScript, which is required for the service worker registration and monkey-patching to take effect. The private key never appears here — getDappfenceScriptAttrs reads only the public signer address and URLs baked into the build by withDappfence.

Runtime instrumentation (App Router with RSC)

App Router pages emit per-request inline scripts of the form <script>self.__next_f.push(...)</script> for React Server Components hydration. The payload varies per request, so these scripts cannot be hashed into DappFence's build-time manifest. Runtime instrumentation rewrites them to inert <script type="application/json"> payloads plus one static reader/init script, making the flight machinery hash-stable across every page.

Create instrumentation.ts at your project root (or src/instrumentation.ts if your app router lives under src/):

export { register } from '@dappfence/next/instrumentation';

If you already have an instrumentation.ts, forward the register call:

import { register as dappfenceRegister } from '@dappfence/next/instrumentation';
import { register as yourRegister } from './your-existing-code';

export async function register() {
    await dappfenceRegister();
    await yourRegister();
}

Deploy matrix: works on Vercel, Netlify, Docker, and self-hosted Node. Not applicable to Edge-runtime routes (which do not emit __next_f.push inline scripts).

Disabling: set patchRSC: false on withDappfence({...}), or set the environment variable DAPPFENCE_PATCH_RSC=false. The env var takes precedence over the config option.

What it does not touch: node_modules on disk, user-authored scripts, non-HTML responses, RSC prefetch responses, Edge-runtime routes.

Static export (output: 'export')

Add a postbuild script — npm runs it automatically after next build:

// package.json
{
    "scripts": {
        "build": "next build",
        "postbuild": "dappfence-next",
    },
}

The dappfence-next CLI reads the config written by the webpack plugin during next build, then injects the script tag into every HTML file in out/, hashes all tracked files, and writes a signed manifest. See Key Management below for how to generate and provide the signing key.

Key resolution order

  1. secretKey option passed to withDappfence({ secretKey: '…' }) — highest priority
  2. DAPPFENCE_SECRET_KEY environment variable

Key Management

DappFence signs the integrity manifest with a secp256k1 private key. The signer's Ethereum address is derived from this key and embedded in the manifest; the service worker uses it to verify the signature at runtime. Anyone with the private key can produce a valid manifest, so treat it like a deploy secret.

Generating a key

Run this once and save the output somewhere safe:

node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"
# → f0570667f495...

Local development

Add the key to a .env.local file (never commit this):

# .env.local
DAPPFENCE_SECRET_KEY=f0570667f495...

Next.js automatically loads .env.local, so process.env.DAPPFENCE_SECRET_KEY will be set when you run next build.

CI / production

Store the key as a repository secret (GitHub Actions, GitLab CI, etc.) and expose it as an environment variable in your build step:

# .github/workflows/deploy.yml
- name: Build
  run: npm run build
  env:
      DAPPFENCE_SECRET_KEY: ${{ secrets.DAPPFENCE_SECRET_KEY }}

Because withDappfence falls back to process.env.DAPPFENCE_SECRET_KEY automatically, no change to next.config.js is needed between local and CI environments.

Where the key is used

The private key is needed in one place only: the environment where next build runs.

  • withDappfence in next.config.js reads the key, derives the public signer address, signs the manifest, then discards the key.
  • getDappfenceScriptAttrs() in your layout reads only the derived public address from .next/dappfence-attrs.json — a file written by the webpack plugin that contains no secrets. The key itself is never written to disk.

For static exports the dappfence-next CLI also reads DAPPFENCE_SECRET_KEY directly from the environment at postbuild time — it is not stored in the build config file.

Key is never on disk

DappFence intentionally avoids persisting the private key anywhere:

  • .next/dappfence-attrs.json — public signer address and URLs only; safe if accidentally committed
  • .next/dappfence-config.json — build options for the static export CLI; no secret key
  • out/ / public/ — served files; no secrets
# .gitignore — still good practice to exclude the .next directory
.next/

Options

| Option | Type | Default | Description | | --------------------------- | ---------- | ----------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | secretKey | string | DAPPFENCE_SECRET_KEY env var | Hex secret key (with or without 0x prefix) used to sign the manifest. Falls back to the DAPPFENCE_SECRET_KEY environment variable. Manifest is unsigned if neither is provided. | | scriptSrc | string | '/dappfence.js' | URL path where dappfence.js will be served. | | manifestUrl | string | '/integrity-manifest.json' | URL path where the manifest will be served. | | manifestPath | string | 'integrity-manifest.json' | Output filename for the manifest relative to the build output dir. | | manifestSignatureType | string | 'noble-secp256k1-recovered-eth' | Signature algorithm written into the manifest. | | manifestSignatureIdentity | string | derived from secretKey | Expected signer Ethereum address. Auto-derived if secretKey is set. | | mode | string | 'protected' | Enforcement mode: 'protected' blocks requests that fail verification; 'reporting' logs violations without blocking. | | appSW | string | null | Path to your app's own service worker, loaded by DappFence via importScripts(). | | warningUrl | string | null | URL shown on the security warning page for tamper alerts. | | extensions | string[] | ['.js','.mjs','.css','.html','.htm','.json','.svg'] | File extensions included in the manifest. | | exclude | string[] | [] | Web paths to exclude from the manifest (e.g. ['/admin']). | | patchRSC | boolean | true | Rewrite Next's RSC __next_f.push inline scripts to inert JSON. See Runtime instrumentation. Env DAPPFENCE_PATCH_RSC overrides. |

What Happens at Build Time

SSR mode

After the client webpack compilation completes:

  1. dappfence.js is copied from @dappfence/core into public/ so Next.js serves it at the root (default public/dappfence.js → /dappfence.js).

  2. integrity-manifest.json is generated — SHA-256 hashes for all static assets under .next/static/, signed with your secretKey, written to public/. HTML is excluded because it is rendered server-side and changes per request.

Static export mode (output: 'export')

After next build completes, dappfence-next (postbuild):

  1. dappfence.js is copied into out/.
  2. Script tag is injected into every HTML file in out/.
  3. integrity-manifest.json is generated — SHA-256 hashes for every tracked file in out/, signed, written to out/.

Current Limitations

  • SSR pages are not hashed. HTML generated on demand cannot be hashed at build time. Only static assets (JS, CSS, etc.) under /_next/static/ are included in the manifest for SSR apps. Script tag injection into HTML must be done manually via your root layout. SSR page verification support is planned for a future version.

  • Dev server is unprotected. The webpack plugin is a no-op during next dev. Security testing must be done against the production build output.

  • Initial load is trusted. DappFence follows a bootstrap trust model: the initial HTML and dappfence.js itself are fetched before the service worker is active, so they are not verified on the very first page load. All later navigations and asset fetches are verified.