npm package: @maaz_khan6266/next-middleware-utils
Description: Edge-ready utilities for Next.js middleware with full TypeScript support.
Latest version: 0.1.0

## next-middleware-utils

Edge-ready utilities for Next.js middleware with full TypeScript support. All helpers are
tree-shakable and rely only on Web Standard APIs, making them safe for the Edge runtime.

### Installation

```bash
npm install next-middleware-utils
# or
yarn add next-middleware-utils
# or
pnpm add next-middleware-utils
```

### Quick Start (Next.js middleware)

```ts
// middleware.ts
import { NextRequest, NextResponse } from "next/server";
import {
  authGuard,
  ipRestriction,
  isBot,
  abTest,
  buildRewriteUrl
} from "next-middleware-utils";

export async function middleware(req: NextRequest) {
  // 1) Auth guard (e.g. protect /dashboard)
  if (req.nextUrl.pathname.startsWith("/dashboard")) {
    const auth = await authGuard(req, {
      cookieName: "auth_token",
      redirectTo: "/login"
    });

    if (!auth.isAuthorized) {
      if (auth.redirectUrl) {
        return NextResponse.redirect(auth.redirectUrl);
      }

      return new NextResponse("Unauthorized", { status: auth.status });
    }
  }

  // 2) IP restriction example
  const ipCheck = ipRestriction(req, {
    mode: "blocklist",
    blockedIps: ["192.168.0.10"]
  });

  if (!ipCheck.isAllowed) {
    return new NextResponse("Forbidden", { status: 403 });
  }

  // 3) Bot detection
  const bot = isBot(req);
  if (bot.isBot) {
    // Optionally short-circuit for bots
    return NextResponse.next();
  }

  // 4) A/B test
  const ab = abTest(req, {
    experimentName: "homepage-layout",
    variants: ["control", "variantA"],
    rolloutPercentage: 50
  });

  const res = NextResponse.next();
  if (ab.cookie) {
    res.headers.append("Set-Cookie", ab.cookie.headerValue);
  }

  // 5) Rewrite helper
  if (req.nextUrl.pathname === "/legacy") {
    const target = buildRewriteUrl(req, "/new-legacy", { preserveQuery: true });
    return NextResponse.rewrite(target);
  }

  return res;
}

export const config = {
  matcher: ["/:path*"]
};
```

### API Overview

#### `authGuard(req, options)`

Small helper to check for a token in cookies or headers and optionally validate it.

- **Options**:
  - `cookieName?: string` – cookie to read token from (default `"auth_token"`).
  - `headerName?: string` – header name if you prefer header-based token (e.g. `"authorization"`).
  - `bearerPrefix?: string` – default `"Bearer "`.
  - `getToken?: (req) => string | null` – custom token extractor.
  - `validateToken?: (token) => boolean | Promise<boolean>` – custom token validation (JWT, etc.).
  - `redirectTo?: string` – URL to redirect on failure (302 instead of 401).

- **Returns**:
  - `{ isAuthorized: true; token?: string | null }` or
  - `{ isAuthorized: false; status: 401 | 302; redirectUrl?: string; reason: string }`.

#### `ipRestriction(req, options)`

Whitelist/blacklist IP helper.

- `mode: "allowlist" | "blocklist"` (default `"blocklist"`).
- `allowedIps?: string[]`, `blockedIps?: string[]`.
- `headerName?: string` for IP (default `"x-forwarded-for"`).
- Returns `{ isAllowed: boolean; ip?: string | null; reason?: string }`.

#### `buildRewriteUrl(req, target, options?)`

Builds a URL for rewrite/redirect, preserving and merging query parameters.

- `target: string` – absolute or relative path.
- `options.preserveQuery?: boolean` (default `true`).
- `options.mergeQuery?: Record<string, string | undefined>` – extra query params.

#### `isBot(req, options?)`

Fast user-agent/header-based bot detection.

- Uses common bot user-agent substrings.
- Options allow extra allowlist/blocklist regexes.
- Returns `{ isBot: boolean; matchedRule?: string; userAgent: string }`.

#### `abTest(req, options)`

Cookie-based A/B test assignment.

- `experimentName: string`.
- `variants: string[]` – e.g. `["control", "variant"]`.
- `rolloutPercentage?: number` (`0–100`, default `100`).
- `cookieName?: string` – default `ab_${experimentName}`.
- `cookieMaxAgeDays?: number` (default `30`).

Returns:

```ts
{
  variant: string;
  isNewAssignment: boolean;
  cookie?: {
    name: string;
    value: string;
    headerValue: string; // ready-to-use Set-Cookie value
  };
}
```

Usage in middleware:

```ts
const res = NextResponse.next();
if (ab.cookie) {
  res.headers.append("Set-Cookie", ab.cookie.headerValue);
}
```

### Development

- **Build**: `npm run build`
- **Test**: `npm test`
- **Lint**: `npm run lint`
- **Typecheck**: `npm run typecheck`
- **Example app**: `npm run example:dev`

See the bottom of this document for linking/publishing instructions.