TerminalSkills/skills

arcjet

Expert guidance for Arcjet, the developer-first security platform that provides rate limiting, bot protection, email validation, and attack detection as a code-first SDK.

ソースを見る

使い方

  1. インストールコマンドをコピーし、自分の環境へ導入する前にソースを確認します。
  2. 必要なツール、認証情報、対応環境を原文で確認します。
  3. 入力と成果物を指定し、出力を資料と照合します。
npx skills add https://github.com/TerminalSkills/skills --skill arcjet

開始前の確認

  • 導入にはモデル契約、API枠、ファイルへのアクセス許可は含まれません。
  • スター数や導入数は活動の指標であり、独立した品質・安全性試験ではありません。
リポジトリの原文

見出し、例、コード、表、リンク、参照画像を含む原文を表示しています。

Arcjet — Application Security Layer

Overview

Arcjet, the developer-first security platform that provides rate limiting, bot protection, email validation, and attack detection as a code-first SDK. Helps developers add security layers to Next.js, Node.js, and other JavaScript/TypeScript applications without managing infrastructure.

Instructions

Rate Limiting

Protect endpoints from abuse with flexible rate limiting:

typescript
// src/lib/arcjet.ts — Configure Arcjet security rules
import arcjet, { tokenBucket, slidingWindow, fixedWindow } from "@arcjet/next";

// Token bucket — allows bursts, then limits sustained rate
// Good for APIs where occasional spikes are normal
export const aj = arcjet({
  key: process.env.ARCJET_KEY!,
  characteristics: ["ip.src"],      // Rate limit per IP address
  rules: [
    tokenBucket({
      mode: "LIVE",                  // "LIVE" enforces; "DRY_RUN" logs only
      refillRate: 10,                // Add 10 tokens per interval
      interval: 60,                  // Every 60 seconds
      capacity: 20,                  // Max burst of 20 requests
    }),
  ],
});

// Sliding window — smooth rate limiting without burst allowance
// Good for login endpoints where you want strict limits
export const loginLimiter = arcjet({
  key: process.env.ARCJET_KEY!,
  characteristics: ["ip.src"],
  rules: [
    slidingWindow({
      mode: "LIVE",
      max: 5,                        // 5 attempts
      interval: "15m",               // Per 15-minute window
    }),
  ],
});

// Fixed window with multiple tiers (slidingWindow and tokenBucket use `interval`)
export const apiLimiter = arcjet({
  key: process.env.ARCJET_KEY!,
  characteristics: ["http.request.headers[\"x-api-key\"]"],  // Per API key
  rules: [
    fixedWindow({
      mode: "LIVE",
      max: 100,                      // 100 requests
      window: "1h",                  // Per hour (fixedWindow uses `window`, not `interval`)
    }),
    fixedWindow({
      mode: "LIVE",
      max: 1000,                     // 1000 requests
      window: "1d",                  // Per day
    }),
  ],
});

Bot Protection

Detect and block automated traffic:

typescript
// app/api/signup/route.ts — Protect signup from bots
import arcjet, { detectBot, shield } from "@arcjet/next";
import { NextRequest, NextResponse } from "next/server";

const aj = arcjet({
  key: process.env.ARCJET_KEY!,
  rules: [
    // Shield — detects common attack patterns (SQLi, XSS, path traversal)
    shield({ mode: "LIVE" }),

    // Bot detection — blocks automated clients
    detectBot({
      mode: "LIVE",
      allow: [
        "CATEGORY:SEARCH_ENGINE",     // Allow Google, Bing, etc.
        "CATEGORY:MONITOR",           // Allow uptime monitors
      ],
      // Everything else (scrapers, headless browsers, AI crawlers) is blocked
    }),
  ],
});

export async function POST(request: NextRequest) {
  const decision = await aj.protect(request);

  if (decision.isErrored()) {
    // Fail open: Arcjet itself had a problem; log it and let the request through.
    console.error("Arcjet error", decision.reason.message);
  } else if (decision.isDenied()) {
    if (decision.reason.isBot()) {
      return NextResponse.json(
        { error: "Bot traffic is not allowed" }, { status: 403 }
      );
    }
    if (decision.reason.isRateLimit()) {
      return NextResponse.json(
        { error: "Too many requests" },
        { status: 429, headers: { "Retry-After": "60" } }
      );
    }
    if (decision.reason.isShield()) {
      return NextResponse.json(
        { error: "Suspicious request blocked" }, { status: 403 }
      );
    }
  }

  // Request passed all security checks — process normally
  const body = await request.json();
  const user = await createUser(body);
  return NextResponse.json({ user }, { status: 201 });
}

Email Validation

Validate email addresses before accepting them:

typescript
// app/api/subscribe/route.ts — Validate emails at signup
import arcjet, { validateEmail } from "@arcjet/next";
import { NextRequest, NextResponse } from "next/server";

const aj = arcjet({
  key: process.env.ARCJET_KEY!,
  rules: [
    validateEmail({
      mode: "LIVE",
      deny: [
        "DISPOSABLE",                // Block temporary email services
        "INVALID",                    // Block malformed addresses
        "NO_MX_RECORDS",             // Block domains without mail servers
      ],
      // Use either `deny` or `allow`, not both. Free providers (Gmail, Yahoo)
      // stay allowed because "FREE" is not listed.
    }),
  ],
});

export async function POST(request: NextRequest) {
  const { email } = await request.json();

  const decision = await aj.protect(request, { email });

  if (decision.isDenied()) {
    const reason = decision.reason;
    if (reason.isEmail()) {
      // Specific error messages based on email issue
      if (reason.emailTypes.includes("DISPOSABLE")) {
        return NextResponse.json(
          { error: "Please use a permanent email address" },
          { status: 422 }
        );
      }
      if (reason.emailTypes.includes("INVALID")) {
        return NextResponse.json(
          { error: "Please check your email address" },
          { status: 422 }
        );
      }
    }
  }

  // Email is valid — proceed with subscription
  await addToMailingList(email);
  return NextResponse.json({ success: true });
}

Next.js Middleware Integration

Apply security rules globally. createMiddleware wraps the Arcjet client and returns a 403 for denied requests. Next.js 16 renamed the middleware.ts file to proxy.ts (export proxy or a default); the Arcjet code is the same.

typescript
// middleware.ts — Global security middleware for Next.js
import arcjet, { createMiddleware, detectBot, shield } from "@arcjet/next";

const aj = arcjet({
  key: process.env.ARCJET_KEY!,
  rules: [
    shield({ mode: "LIVE" }),
    detectBot({
      mode: "LIVE",
      allow: ["CATEGORY:SEARCH_ENGINE", "CATEGORY:MONITOR", "CATEGORY:PREVIEW"],
    }),
  ],
});

export default createMiddleware(aj);

export const config = {
  // Skip static assets; run on pages and API routes
  matcher: ["/((?!_next/static|_next/image|favicon.ico).*)"],
};

Per-route rate limits belong in the route handler.

Node.js / Express Integration

Use Arcjet with Express or any Node.js framework:

typescript
// src/middleware/security.ts — Arcjet with Express
import arcjet, { tokenBucket, detectBot, shield } from "@arcjet/node";
import { Request, Response, NextFunction } from "express";

const aj = arcjet({
  key: process.env.ARCJET_KEY!,
  characteristics: ["ip.src"],
  rules: [
    shield({ mode: "LIVE" }),
    detectBot({ mode: "LIVE", allow: ["CATEGORY:SEARCH_ENGINE"] }),
    tokenBucket({ mode: "LIVE", refillRate: 30, interval: 60, capacity: 60 }),
  ],
});

export async function arcjetMiddleware(req: Request, res: Response, next: NextFunction) {
  const decision = await aj.protect(req, { requested: 1 });

  if (decision.isDenied()) {
    const status = decision.reason.isRateLimit() ? 429 : 403;
    return res.status(status).json({
      error: decision.reason.isRateLimit() ? "Rate limited" : "Forbidden",
    });
  }

  next();
}

// Usage in Express app
app.use("/api", arcjetMiddleware);

Installation

bash
# Next.js
npm install @arcjet/next

# Node.js / Express
npm install @arcjet/node

# Get a key at https://app.arcjet.com and export it as ARCJET_KEY

protect() for a token bucket takes the cost of the request: await aj.protect(request, { requested: 1 }). Rules default to DRY_RUN when mode is omitted.

Examples

Example 1: Protect a signup endpoint in Next.js

User request: "Stop bots and throwaway emails from hitting /api/signup, and limit each IP to 5 attempts per 15 minutes."

Install @arcjet/next, put ARCJET_KEY in .env.local, and in app/api/signup/route.ts combine shield, detectBot, validateEmail({ deny: ["DISPOSABLE", "INVALID", "NO_MX_RECORDS"] }) and slidingWindow({ max: 5, interval: "15m" }) with characteristics: ["ip.src"]. Call aj.protect(request, { email }). Start every rule in DRY_RUN, read the decisions in the Arcjet dashboard, then switch to LIVE. A blocked request gets 403 (bot, shield), 422 (email) or 429 (rate limit).

Example 2: Rate limit an Express API by API key

User request: "Give each API key 1000 requests a day on our Express server."

Install @arcjet/node, build arcjet({ key, characteristics: ['http.request.headers["x-api-key"]'], rules: [fixedWindow({ mode: "LIVE", window: "1d", max: 1000 })] }), and call aj.protect(req) in a middleware that answers 429 when decision.reason.isRateLimit(). Mount it with app.use("/api", arcjetMiddleware).

Guidelines

  1. Start with DRY_RUN — Use mode: "DRY_RUN" first to monitor traffic patterns before enforcing rules
  2. Layer multiple rules — Combine shield + bot detection + rate limiting; each catches different attack types
  3. Rate limit by the right characteristic — Use IP for public endpoints, API key for authenticated ones, user ID for per-user limits
  4. Allow legitimate bots — Search engines, uptime monitors, and link previews are not attacks; whitelist them
  5. Middleware for global protection — Apply shield and bot detection in middleware; add specific rate limits per route
  6. Graceful degradation — A failed Arcjet call returns an errored decision (decision.isErrored()) rather than denying; decide deliberately whether to fail open (usual) or closed (login, payments)
  7. Client IP — Arcjet reads the IP from the request; behind your own proxy, configure proxies so spoofed X-Forwarded-For values are ignored
同じリポジトリから

関連する Skills

すべての Skills
TerminalSkills
コミュニティ

3dsmax-rendering

Scripts and configures production rendering in Autodesk 3ds Max with the V-Ray and Corona renderers: output size and files, render elements, denoising, light mix, batch and command-line rendering, and network rendering. Use when a user asks to set up a production render, render several cameras in one batch, render from the command line or on a render farm, add render passes for compositing, or cut render time for archviz and product shots.

導入数
0
GitHub Stars
180
更新日
10月25日
TerminalSkills
コミュニティ

3dsmax-scripting

Covers scripting Autodesk 3ds Max, the 3D modeling and rendering application, with MAXScript and Python (pymxs): scene manipulation, object creation, material assignment, camera and light setup, batch operations, and file I/O. Use when tasks involve automating repetitive 3ds Max workflows, batch processing scenes, running scripts headless with 3dsmaxbatch, creating custom tools, or scripting scene setup for archviz, product visualization, or VFX.

導入数
0
GitHub Stars
180
更新日
10月25日
TerminalSkills
コミュニティ

3proxy

3proxy is a small open-source proxy server that runs HTTP/HTTPS, SOCKS4/5, SNI and TCP/UDP port-mapping proxies from one config file. Use when a user asks to set up an HTTP or SOCKS5 proxy, add proxy users and passwords, write 3proxy access rules, chain or rotate upstream (parent) proxies, limit bandwidth, connections or monthly traffic per user, run 3proxy in Docker, or fix a 3proxy.cfg that will not start.

導入数
0
GitHub Stars
180
更新日
10月25日
TerminalSkills
コミュニティ

a2a-protocol

Builds Agent2Agent (A2A) servers and clients, the open protocol (originally from Google, now under the Linux Foundation) that lets AI agents from different frameworks call each other. Use when the user wants to create an A2A-compliant agent, build an Agent Card, implement task management, connect agents across frameworks, set up agent discovery, handle streaming responses, implement push notifications, or orchestrate multi-agent workflows. Trigger words: a2a, agent to agent, agent2agent, a2a pro

導入数
0
GitHub Stars
180
更新日
10月25日