🔒 VhyxSeal
GitHub

Next.js Adapter

@vhyxseal/nextjs provides a Next.js config plugin, manifest and dashboard route handlers, and server component utilities. It auto-injects the /__agent__/manifest.json and /__agent__/dashboard.json rewrites — no manual routing configuration required.

What the Adapter Provides

  • vhyxsealPlugin() — wraps next.config.ts to auto-inject rewrites and cache headers
  • handleManifestRoute() — route handler for app/api/vhyxseal-manifest/route.ts
  • handleDashboardRoute() — route handler for app/api/vhyxseal-dashboard/route.ts
  • getSealManifest() — fetch manifest in React Server Components

Installation

npm install @vhyxseal/nextjs @vhyxseal/react @vhyxseal/core

Next.js ≥ 14 supported. App Router and Pages Router both covered.

Full Setup

next.config.ts
// next.config.ts
import { vhyxsealPlugin } from '@vhyxseal/nextjs'
import type { NextConfig } from 'next'

const nextConfig: NextConfig = {
  // your existing config
}

export default vhyxsealPlugin({})(nextConfig)

// vhyxsealPlugin() automatically:
//   1. Injects headers for /__agent__/manifest.json (cache, ETag, version)
//   2. Injects rewrite: /__agent__/manifest.json → /api/vhyxseal-manifest
//   3. Injects headers for /__agent__/dashboard.json (no-cache)
//   4. Injects rewrite: /__agent__/dashboard.json → /api/vhyxseal-dashboard
app/api/vhyxseal-manifest/route.ts
// app/api/vhyxseal-manifest/route.ts
import { handleManifestRoute } from '@vhyxseal/nextjs'
import type { ManifestConfig } from '@vhyxseal/core'

const config: ManifestConfig = {
  domain: process.env['VHYXSEAL_DOMAIN'] ?? "example.com",
  domainVerified: process.env['VHYXSEAL_DOMAIN_VERIFIED'] === "true",
  verificationToken: process.env['VHYXSEAL_VERIFICATION_TOKEN'] ?? "",
  agentPolicy: {
    allowedAgents: ["*"],
    requiresConfirmation: ["place-order", "delete-account"],
    rateLimits: {
      actionsPerMinute: 60,
      actionsPerHour: 500,
      manifestRequestsPerMinute: 10,
      perAgentSession: true,
    },
  },
  cacheDurationSeconds: 3600,
}

export async function GET(request: Request) {
  return handleManifestRoute({ request, config })
}
app/api/vhyxseal-dashboard/route.ts
// app/api/vhyxseal-dashboard/route.ts
import { handleDashboardRoute } from '@vhyxseal/nextjs'

export async function GET(request: Request) {
  return handleDashboardRoute({ request })
}

// Dashboard served at /__agent__/dashboard.json
// Contains: action token stats, domain verification, audit log, agent policy
// Cache-Control: no-cache, no-store (always fresh)

SealProvider in Next.js

SealProvider uses React Context and must be in a Client Component. Wrap it in a ClientProviders component and import it from a Server Component layout.

// app/layout.tsx — SealProvider in App Router
"use client"
import { SealProvider } from '@vhyxseal/react'

export function ClientProviders({ children }: { children: React.ReactNode }) {
  return (
    <SealProvider
      config={{
        domain: "example.com",
        domainVerified: false,
        verificationToken: "",
      }}
    >
      {children}
    </SealProvider>
  )
}

// Then in layout.tsx (Server Component):
// import { ClientProviders } from './ClientProviders'
// <ClientProviders>{children}</ClientProviders>

vhyxsealPlugin() Options

Currently accepts an empty options object. Future versions will add customization for the rewrite destination and header values. Plugin auto-injects both manifest and dashboard rewrites with independent duplicate guards — if you already have a rewrite for the canonical URL, the plugin leaves it unchanged.

// Version negotiation — agent sends version headers
// Request:
//   vhyxseal-version: 1.0.0
//   vhyxseal-fallback: 0.9.0

// handleManifestRoute reads these headers and:
//   1. Tries to serve manifest compatible with vhyxseal-version
//   2. Falls back to vhyxseal-fallback if exact match not possible
//   3. Adds X-VhyxSeal-Degraded: true when serving fallback version

// Response headers:
//   X-VhyxSeal-Version: 1.0.0
//   X-VhyxSeal-Domain: example.com
//   X-VhyxSeal-Degraded: true (only when degraded)
//   X-VhyxSeal-Degraded-Reason: "..." (only when degraded)

Server Component Utilities

// Server component — read the manifest server-side
import { getSealManifest } from '@vhyxseal/nextjs'

export default async function ManifestDebugPage() {
  // Fetches from /__agent__/manifest.json at request time
  const manifest = await getSealManifest({
    domain: process.env['VHYXSEAL_DOMAIN'] ?? "localhost:3000",
    domainVerified: false,
    verificationToken: "",
  })

  return (
    <pre>
      {JSON.stringify(
        { fingerprint: manifest?.fingerprint, components: manifest?.components.length },
        null, 2
      )}
    </pre>
  )
}

TypeScript Types

// TypeScript types from @vhyxseal/nextjs
import type {
  ManifestRouteConfig,     // Config for handleManifestRoute
  ManifestRouteRequest,    // Request shape for handleManifestRoute
  ManifestRouteResponse,   // Response shape (status, headers, body)
  DashboardRouteRequest,   // Request shape for handleDashboardRoute
  DashboardRouteResponse,  // Response shape for dashboard
} from '@vhyxseal/nextjs'

Common Patterns

App Router — complete setup

// App Router — full example
// 1. next.config.ts
import { vhyxsealPlugin } from '@vhyxseal/nextjs'
export default vhyxsealPlugin({})({})

// 2. app/api/vhyxseal-manifest/route.ts
import { handleManifestRoute } from '@vhyxseal/nextjs'
export const GET = (req: Request) =>
  handleManifestRoute({ request: req, config: { domain: "example.com", domainVerified: false, verificationToken: "" } })

// 3. app/api/vhyxseal-dashboard/route.ts
import { handleDashboardRoute } from '@vhyxseal/nextjs'
export const GET = (req: Request) => handleDashboardRoute({ request: req })

// 4. app/layout.tsx (client wrapper)
"use client"
import { SealProvider } from '@vhyxseal/react'
export function Providers({ children }) {
  return <SealProvider config={{ domain: "example.com", domainVerified: false, verificationToken: "" }}>{children}</SealProvider>
}

// Manifest live at: /__agent__/manifest.json
// Dashboard live at: /__agent__/dashboard.json

Pages Router setup

// Pages Router — SealProvider in _app.tsx
import type { AppProps } from 'next/app'
import { SealProvider } from '@vhyxseal/react'

export default function App({ Component, pageProps }: AppProps) {
  return (
    <SealProvider
      config={{
        domain: "example.com",
        domainVerified: false,
        verificationToken: "",
      }}
    >
      <Component {...pageProps} />
    </SealProvider>
  )
}

// pages/api/vhyxseal-manifest.ts
import type { NextApiRequest, NextApiResponse } from 'next'
import { handleManifestRoute } from '@vhyxseal/nextjs'

export default async function handler(req: NextApiRequest, res: NextApiResponse) {
  const result = await handleManifestRoute({
    request: req as unknown as Request,
    config: { domain: "example.com", domainVerified: false, verificationToken: "" },
  })
  res.status(result.status).json(result.body)
}

Known Limitations

  • Underscore route constraint (DECISION-028): Next.js ignores route segments starting with underscore. The __agent__ directory cannot be used as a direct Next.js route. The plugin auto-injects a rewrite to solve this — the canonical URL /__agent__/manifest.json works correctly for agents
  • getSealManifest() fetches over HTTP — not available during static export (next export). Use in dynamic routes only
  • SealProvider must be in a Client Component — use a ClientProviders wrapper pattern in App Router
  • The nextjs package exports dual CJS/ESM (DECISION-027) — it is consumed inside next.config.ts which is compiled to CommonJS by Next.js