ITADN
arcjet/arcjet-js
arcjet/arcjet-js · 文件 下载 ZIP
文件最后提交记录最后更新时间
README.md
以下内容由 AI 翻译,如有问题请点此提交 issue 反馈
Arcjet Logo

Arcjet - JS SDK

npm badge

Arcjet 是随您的 AI 代码一起交付的运行时安全平台。检测提示注入,授权代理工具调用,编辑敏感数据,并拦截机器人和滥用行为。在操作发生之前,在您的应用内部调用的实时安全构建模块。

这是包含各种 Arcjet JS 开源包的 monorepo。

为什么选择 Arcjet?

您应用的 AI 功能和代理会执行真实操作,调用工具、读取数据、访问 API。Arcjet 运行在该代码内部,允许您实时对每个操作执行安全策略,然后审计发生了什么

我需要哪个包?

Arcjet 保护两种类型的入口点。为您的使用 场景选择正确的路径:

入口点适用场景
请求保护HTTP 路由处理器、API 端点、中间件 — 任何包含传入 Request 对象的情况。@arcjet/next@arcjet/node@arcjet/bun 等。
守卫保护AI 智能体工具调用、MCP 服务器处理器、队列工作进程、后台任务 — 任何 没有 HTTP 请求的情况。@arcjet/guard

不确定?如果你有 HTTP 请求,请使用 框架 SDK。如果 没有,请使用 @arcjet/guard。你可以在 同一个项目中使用两者。

快速入门

最快的入门方式是使用 AI 编码智能体。登录,安装 一个技能,然后让你的智能体处理其余部分。

步骤 1:使用 CLI 登录

npx @arcjet/cli auth login

你也可以在 app.arcjet.com 注册并管理密钥,或者将 Arcjet MCP 服务器 连接到你的 AI 助手。

步骤 2:安装技能

技能为你的代理提供文档,以检测你的框架、安装 SDK,并配置请求或防护规则。

npx skills add arcjet/skills

您还可以使用 Arcjet 的 Claude Code 和 Cursor 插件,其中捆绑了 skills、MCP 和编码规则。

步骤 3:安装软件包

用于请求保护 — 选择适用于您框架的 SDK:

框架软件包安装
Next.js@arcjet/nextnpm i @arcjet/next
Node.js@arcjet/nodenpm i @arcjet/node
Bun@arcjet/bunbun add @arcjet/bun
Deno@arcjet/denodeno add npm:@arcjet/deno
Express@arcjet/nodenpm i @arcjet/node
Fastify@arcjet/fastifynpm i @arcjet/fastify
Hono@arcjet/node@arcjet/bunnpm i @arcjet/node
NestJS@arcjet/nestnpm i @arcjet/nest
Nuxt@arcjet/nuxtnpm i @arcjet/nuxt
Remix@arcjet/remixnpm i @arcjet/remix
React Router@arcjet/react-routernpm i @arcjet/react-router
SvelteKit@arcjet/sveltekitnpm i @arcjet/sveltekit
Astro@arcjet/astronpm i @arcjet/astro

用于 guard 保护:

npm i @arcjet/guard

步骤 4:告诉你的代理要保护什么

让你的编码代理实施保护。你在 步骤 2 中安装的技能提供了它所需的一切。例如:

“在我的 /api/chat 路由中添加 Arcjet 机器人保护和速率限制”

“在我的 MCP 工具处理器中添加带有提示注入检测的 Arcjet 防护”

代理将安装正确的包,配置规则,并接入 protect()guard() 调用 — 或者查看 完整保护列表 如下。

获取帮助

加入我们的 Discord 服务器联系支持

  • 文档 — 完整参考和指南
  • 示例应用 — 适用于每个框架的可用启动项目
  • 蓝图 — 常见安全模式的配方

功能

功能请求 SDK防护
🛑 速率限制 — 令牌桶、固定窗口、滑动窗口
🔒 提示注入检测 — 在攻击到达您的 LLM 之前将其拦截
🕵️ 敏感信息检测 — 拦截 PII、信用卡、自定义模式
🤖 机器人防护 — 阻止爬虫、凭证填充、AI 爬虫
🛡️ Shield WAF — 防御 SQL 注入、XSS、OWASP Top 10
📧 邮箱验证 — 拦截一次性、无效、不可投递的地址
📝 注册表单保护 — 机器人 + 邮箱 + 速率限制组合
🎯 请求过滤器 — 基于 IP、路径、请求头的表达式规则
🌐 IP 分析 — 地理位置、ASN、VPN、代理、Tor、托管检测
🔧 自定义规则 — 定义您自己的本地评估逻辑

请求 SDK = @arcjet/next@arcjet/node@arcjet/bun 等 — 用于 HTTP 路由。 Guard = @arcjet/guard — 用于工具调用、MCP 服务器、队列以及任何没有 HTTP 请求的场景。

示例应用

蓝图

用法

docs.arcjet.com 阅读文档。

注意: 以下示例使用 @arcjet/next 进行说明。请替换为 适用于您运行时的 SDK — @arcjet/node@arcjet/bun@arcjet/sveltekit, 等。所有 SDK 的 API 完全相同。

Vercel AI SDK 示例

本示例使用 Vercel AI SDK 保护 Next.js AI 聊天路由:阻止推高成本的自动化客户端, 执行每用户 token 预算,检测消息中的敏感信息,并在提示注入攻击到达模型之前将其拦截。

// app/api/chat/route.ts
import { openai } from "@ai-sdk/openai";
import arcjet, {
  detectBot,
  detectPromptInjection,
  sensitiveInfo,
  shield,
  tokenBucket,
} from "@arcjet/next";
import type { UIMessage } from "ai";
import { convertToModelMessages, isTextUIPart, streamText } from "ai";

const aj = arcjet({
  key: process.env.ARCJET_KEY!, // Get your key with: npx @arcjet/cli sites get-key
  // Track budgets per user — replace "userId" with any stable identifier
  characteristics: ["userId"],
  rules: [
    // Shield protects against common web attacks e.g. SQL injection
    shield({ mode: "LIVE" }),
    // Block all automated clients — bots inflate AI costs
    detectBot({
      mode: "LIVE", // Blocks requests. Use "DRY_RUN" to log only
      allow: [], // Block all bots. See https://arcjet.com/bot-list
    }),
    // Enforce budgets to control AI costs. Adjust rates and limits as needed.
    tokenBucket({
      mode: "LIVE",
      refillRate: 2_000, // Refill 2,000 tokens per hour
      interval: "1h",
      capacity: 5_000, // Maximum 5,000 tokens in the bucket
    }),
    // Block messages containing sensitive information to prevent data leaks
    sensitiveInfo({
      mode: "LIVE",
      // Block PII types that should never appear in AI prompts.
      // Remove types your app legitimately handles (e.g. EMAIL for a support bot).
      deny: ["CREDIT_CARD_NUMBER", "EMAIL"],
    }),
    // Detect prompt injection attacks before they reach your AI model
    detectPromptInjection({
      mode: "LIVE",
    }),
  ],
});

export async function POST(req: Request) {
  const userId = "user-123"; // Replace with your session/auth lookup
  const { messages }: { messages: UIMessage[] } = await req.json();
  const modelMessages = await convertToModelMessages(messages);

  // Estimate token cost: ~1 token per 4 characters of text (rough heuristic)
  const totalChars = modelMessages.reduce((sum, m) => {
    const content =
      typeof m.content === "string" ? m.content : JSON.stringify(m.content);
    return sum + content.length;
  }, 0);
  const estimate = Math.ceil(totalChars / 4);

  // Extract the most recent user message to scan for injection and PII
  const lastMessage: string = (messages.at(-1)?.parts ?? [])
    .filter(isTextUIPart)
    .map((p) => p.text)
    .join(" ");

  const decision = await aj.protect(req, {
    userId,
    requested: estimate,
    sensitiveInfoValue: lastMessage,
    detectPromptInjectionMessage: lastMessage,
  });

  if (decision.isDenied()) {
    if (decision.reason.isBot()) {
      return new Response("Automated clients are not permitted", {
        status: 403,
      });
    } else if (decision.reason.isRateLimit()) {
      return new Response("AI usage limit exceeded", { status: 429 });
    } else if (decision.reason.isSensitiveInfo()) {
      return new Response("Sensitive information detected", { status: 400 });
    } else if (decision.reason.isPromptInjection()) {
      return new Response(
        "Prompt injection detected — please rephrase your message",
        { status: 400 },
      );
    } else {
      return new Response("Forbidden", { status: 403 });
    }
  }

  const result = await streamText({
    model: openai("gpt-4o"),
    messages: modelMessages,
  });

  return result.toUIMessageStreamResponse();
}

提示注入检测

在提示注入攻击(即试图覆盖你的 AI 模型指令的尝试)到达你的模型之前,检测并阻止它们。在每次 protect() 调用时,通过 detectPromptInjectionMessage 传递用户消息。

import arcjet, { detectPromptInjection } from "@arcjet/next";

const aj = arcjet({
  key: process.env.ARCJET_KEY!,
  rules: [
    detectPromptInjection({
      mode: "LIVE", // Blocks requests. Use "DRY_RUN" to log only
    }),
  ],
});

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

  const decision = await aj.protect(request, {
    detectPromptInjectionMessage: message,
  });

  if (decision.isDenied() && decision.reason.isPromptInjection()) {
    return new Response(
      "Prompt injection detected — please rephrase your message",
      { status: 400 },
    );
  }

  // Forward to your AI model...
}

机器人防护

Arcjet 允许您配置一个允许或拒绝的机器人列表。指定 allow 意味着拒绝所有其他机器人。空的允许列表将阻止所有机器人。

可用类别:CATEGORY:ACADEMICCATEGORY:ADVERTISINGCATEGORY:AICATEGORY:AMAZONCATEGORY:APPLECATEGORY:ARCHIVECATEGORY:BOTNETCATEGORY:FEEDFETCHERCATEGORY:GOOGLECATEGORY:METACATEGORY:MICROSOFTCATEGORY:MONITORCATEGORY:OPTIMIZERCATEGORY:PREVIEWCATEGORY:PROGRAMMATICCATEGORY:SEARCH_ENGINECATEGORY:SLACKCATEGORY:SOCIALCATEGORY:TOOLCATEGORY:UNKNOWNCATEGORY:VERCELCATEGORY:WEBHOOKCATEGORY:YAHOO。您还可以允许或拒绝 特定名称的机器人

import arcjet, { detectBot } from "@arcjet/next";
import { isSpoofedBot } from "@arcjet/inspect";

const aj = arcjet({
  key: process.env.ARCJET_KEY!,
  rules: [
    detectBot({
      mode: "LIVE", // Blocks requests. Use "DRY_RUN" to log only
      allow: [
        "CATEGORY:SEARCH_ENGINE", // Google, Bing, etc
        // Uncomment to allow these other common bot categories:
        // "CATEGORY:MONITOR",  // Uptime monitoring services
        // "CATEGORY:PREVIEW",  // Link previews e.g. Slack, Discord
        // See the full list at https://arcjet.com/bot-list
      ],
    }),
  ],
});

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

  if (decision.isDenied() && decision.reason.isBot()) {
    return new Response("No bots allowed", { status: 403 });
  }

  // Arcjet verifies the authenticity of common bots using IP data.
  // Verification isn't always possible, so check the results separately.
  // https://docs.arcjet.com/bot-protection/reference#bot-verification
  if (decision.results.some(isSpoofedBot)) {
    return new Response("Forbidden", { status: 403 });
  }

  return new Response("Hello world");
}

Bots 可按 类别 和/或按 特定 bot 名称 进行配置。例如,允许搜索引擎和 OpenAI crawler,但拒绝所有其他 bots:

detectBot({
  mode: "LIVE",
  allow: ["CATEGORY:SEARCH_ENGINE", "OPENAI_CRAWLER_SEARCH"],
});

速率限制

Arcjet 支持令牌桶、固定窗口和滑动窗口算法。 令牌桶非常适合控制 AI 令牌预算——将 capacity 设置 为用户可消耗的最大令牌数,将 refillRate 设置为每 interval 恢复的令牌数, 并通过 protect() 中的 requested 按请求扣除令牌。 interval 接受字符串("1s""1m""1h""1d")或表示秒数的数字。 使用 characteristics 按用户而非按 IP 跟踪限制。

import arcjet, { tokenBucket } from "@arcjet/next";

const aj = arcjet({
  key: process.env.ARCJET_KEY!,
  characteristics: ["userId"], // Track per user
  rules: [
    tokenBucket({
      mode: "LIVE",
      refillRate: 2_000, // Refill 2,000 tokens per hour
      interval: "1h",
      capacity: 5_000, // Maximum 5,000 tokens in the bucket
    }),
  ],
});

const decision = await aj.protect(request, {
  userId: "user-123",
  requested: estimate, // Number of tokens to deduct
});

if (decision.isDenied() && decision.reason.isRateLimit()) {
  return new Response("AI usage limit exceeded", { status: 429 });
}

敏感信息检测

检测并拦截请求内容中的 PII。在每次 protect() 调用时,通过 sensitiveInfoValue 传递待扫描的内容。内置实体类型: CREDIT_CARD_NUMBEREMAILPHONE_NUMBERIP_ADDRESS。您还可以 提供自定义的 detect 回调以匹配额外的模式。

import arcjet, { sensitiveInfo } from "@arcjet/next";

const aj = arcjet({
  key: process.env.ARCJET_KEY!,
  rules: [
    sensitiveInfo({
      mode: "LIVE", // Blocks requests. Use "DRY_RUN" to log only
      deny: ["CREDIT_CARD_NUMBER", "EMAIL", "PHONE_NUMBER"],
    }),
  ],
});

const decision = await aj.protect(request, {
  sensitiveInfoValue: userMessage,
});

if (decision.isDenied() && decision.reason.isSensitiveInfo()) {
  return new Response("Sensitive information detected", { status: 400 });
}

Shield WAF

保护您的应用程序免受常见网络攻击,包括 OWASP Top 10。

import arcjet, { shield } from "@arcjet/next";

const aj = arcjet({
  key: process.env.ARCJET_KEY!,
  rules: [
    shield({
      mode: "LIVE", // Blocks requests. Use "DRY_RUN" to log only
    }),
  ],
});

电子邮件验证

验证和核实电子邮件地址。拒绝类型:DISPOSABLE, FREE, NO_MX_RECORDS, NO_GRAVATAR, INVALID

import arcjet, { validateEmail } from "@arcjet/next";

const aj = arcjet({
  key: process.env.ARCJET_KEY!,
  rules: [
    validateEmail({
      mode: "LIVE",
      deny: ["DISPOSABLE", "INVALID", "NO_MX_RECORDS"],
    }),
  ],
});

const decision = await aj.protect(request, {
  email: "user@example.com",
});

if (decision.isDenied() && decision.reason.isEmail()) {
  return new Response("Invalid email address", { status: 400 });
}

请求过滤器

使用基于表达式的规则,针对请求属性(IP、 请求头、路径、方法等)过滤请求。

import arcjet, { filter } from "@arcjet/next";

const aj = arcjet({
  key: process.env.ARCJET_KEY!,
  rules: [
    filter({
      mode: "LIVE",
      deny: ['ip.src == "1.2.3.4"', 'http.request.uri.path contains "/admin"'],
    }),
  ],
});

按国家划分

限制对特定国家的访问——适用于许可、合规或 区域部署。allow 列表拒绝所有未列出的国家:

filter({
  mode: "LIVE",
  // Allow only US traffic — all other countries are denied
  allow: ['ip.src.country == "US"'],
});

阻止 VPN 和代理流量

防止匿名流量访问敏感端点——适用于 欺诈预防、执行地理限制以及减少滥用:

filter({
  mode: "LIVE",
  deny: [
    "ip.src.vpn", // VPN services
    "ip.src.proxy", // Open proxies
    "ip.src.tor", // Tor exit nodes
  ],
});

如需更精细的处理,请在调用 protect() 之后使用 decision.ip 辅助函数:

const decision = await aj.protect(request);

if (decision.ip.isVpn() || decision.ip.isTor()) {
  return new Response("VPN traffic not allowed", { status: 403 });
}

请参阅 Request Filters 文档IP Geolocation 蓝图 以及 VPN/Proxy Detection 蓝图 以获取更多详细信息。

IP 分析

Arcjet 会为每个请求添加 IP 元数据。使用这些辅助函数基于网络信号 做出策略决策:

const decision = await aj.protect(request);

if (decision.ip.isHosting()) {
  // Requests from cloud/hosting providers are often automated.
  // https://docs.arcjet.com/blueprints/vpn-proxy-detection
  return new Response("Forbidden", { status: 403 });
}

if (decision.ip.isVpn() || decision.ip.isProxy() || decision.ip.isTor()) {
  // Handle VPN/proxy traffic according to your policy
}

// Access geolocation and network details
console.log(decision.ip.country, decision.ip.city, decision.ip.asn);

// Threat intelligence is undefined when it is unavailable.
if (decision.ip.threat?.riskLevel === "high") {
  console.log(decision.ip.threat.activities, decision.ip.threat.reputation);
}

自定义特征

通过任意稳定标识符(如用户 ID、API 密钥、会话等)而非仅 IP 地址来跟踪和限制请求。

const aj = arcjet({
  key: process.env.ARCJET_KEY!,
  characteristics: ["userId"], // Declare at the SDK level
  rules: [
    tokenBucket({
      mode: "LIVE",
      refillRate: 2_000,
      interval: "1h",
      capacity: 5_000,
    }),
  ],
});

// Pass the characteristic value at request time
const decision = await aj.protect(request, {
  userId: "user-123",
  requested: estimate,
});

Arcjet Guard

@arcjet/guard 是一个底层 API,专为 AI 智能体工具调用和后台任务设计,在这些场景中不存在 HTTP 请求对象。 它提供了细粒度的、针对每次调用的控制,涵盖速率限制、提示词 注入检测、敏感信息检测以及自定义规则。

它与框架 SDK 的区别

框架 SDK(@arcjet/next 等)@arcjet/guard
设计用途HTTP 请求保护AI 智能体工具调用、后台作业
请求对象必需(protect(request, ...)无需提供
规则绑定规则配置一次,通过 protect() 选项传入输入规则配置为函数,每次调用时传入输入
速率限制键IP 或 characteristics 字典显式的 key 字符串(发送前进行 SHA-256 哈希)
自定义规则不支持支持 defineCustomRule,具有类型化的配置/输入/数据

安装

npm i @arcjet/guard

快速入门

import {
  launchArcjet,
  tokenBucket,
  detectPromptInjection,
} from "@arcjet/guard";

// Create the Arcjet client once at module scope
const arcjet = launchArcjet({ key: process.env.ARCJET_KEY! });

// Configure reusable rules
const limitRule = tokenBucket({
  refillRate: 10,
  intervalSeconds: 60,
  maxTokens: 100,
});
const piRule = detectPromptInjection();

// Per request — create rule inputs each time
async function handleToolCall(
  userId: string,
  userMessage: string,
  tokenCount: number,
) {
  const rl = limitRule({ key: userId, requested: tokenCount });
  const decision = await arcjet.guard({
    label: "tools.weather",
    rules: [rl, piRule(userMessage)],
  });

  if (decision.conclusion === "DENY") {
    throw new Error(`Blocked: ${decision.reason}`);
  }

  // safe to proceed
}

速率限制(Guard)

提供令牌桶、固定窗口和滑动窗口算法。 配置一次规则,然后在每次调用时通过 key(以及可选的 requested 令牌数量)进行调用。

令牌桶(Guard)

import { launchArcjet, tokenBucket } from "@arcjet/guard";

const arcjet = launchArcjet({ key: process.env.ARCJET_KEY! });

const limitRule = tokenBucket({
  refillRate: 2_000, // tokens added per interval
  intervalSeconds: 3600, // seconds between refills
  maxTokens: 5_000, // maximum bucket capacity
});

const decision = await arcjet.guard({
  label: "tools.chat",
  rules: [limitRule({ key: userId, requested: tokenEstimate })],
});

if (decision.conclusion === "DENY" && decision.reason === "RATE_LIMIT") {
  throw new Error("Rate limit exceeded");
}

固定窗口(Guard)

import { launchArcjet, fixedWindow } from "@arcjet/guard";

const arcjet = launchArcjet({ key: process.env.ARCJET_KEY! });

const limitRule = fixedWindow({
  maxRequests: 1000, // maximum requests per window
  windowSeconds: 3600, // 1-hour window
});

const decision = await arcjet.guard({
  label: "api.search",
  rules: [limitRule({ key: teamId })],
});

滑动窗口(Guard)

import { launchArcjet, slidingWindow } from "@arcjet/guard";

const arcjet = launchArcjet({ key: process.env.ARCJET_KEY! });

const limitRule = slidingWindow({
  maxRequests: 500, // maximum requests per interval
  intervalSeconds: 60, // 1-minute rolling window
});

const decision = await arcjet.guard({
  label: "api.events",
  rules: [limitRule({ key: userId })],
});

提示注入检测(Guard)

import { launchArcjet, detectPromptInjection } from "@arcjet/guard";

const arcjet = launchArcjet({ key: process.env.ARCJET_KEY! });

const piRule = detectPromptInjection();

const decision = await arcjet.guard({
  label: "tools.chat",
  rules: [piRule(userMessage)],
});

if (decision.conclusion === "DENY" && decision.reason === "PROMPT_INJECTION") {
  throw new Error("Prompt injection detected — please rephrase your message");
}

敏感信息检测(Guard)

在本地检测 PII — 原始文本永远不会离开 SDK。内置实体 类型:EMAIL, PHONE_NUMBER, IP_ADDRESS, CREDIT_CARD_NUMBER

import { launchArcjet, localDetectSensitiveInfo } from "@arcjet/guard";

const arcjet = launchArcjet({ key: process.env.ARCJET_KEY! });

const si = localDetectSensitiveInfo({
  deny: ["CREDIT_CARD_NUMBER", "PHONE_NUMBER"],
});

const decision = await arcjet.guard({
  label: "tools.summary",
  rules: [si(userMessage)],
});

if (decision.conclusion === "DENY" && decision.reason === "SENSITIVE_INFO") {
  throw new Error("Sensitive information detected");
}

自定义规则(Guard)

使用任意键值数据定义您自己的本地评估逻辑。当 提供 evaluate 时,SDK 会在发送请求前在本地调用它。 该函数接收 (config, input, { signal }) 并必须返回 { conclusion: "ALLOW" | "DENY" }

import { launchArcjet, defineCustomRule } from "@arcjet/guard";

const arcjet = launchArcjet({ key: process.env.ARCJET_KEY! });

const topicBlock = defineCustomRule<
  { blockedTopic: string },
  { topic: string },
  { matched: string }
>({
  evaluate: (config, input) => {
    if (input.topic === config.blockedTopic) {
      return { conclusion: "DENY", data: { matched: input.topic } };
    }
    return { conclusion: "ALLOW" };
  },
});

const rule = topicBlock({ data: { blockedTopic: "politics" } });

const decision = await arcjet.guard({
  label: "tools.chat",
  rules: [rule({ data: { topic: userTopic } })],
});

按规则的结果(Guard)

已配置的规则和绑定的输入均提供带类型的结果访问器:

const limitRule = tokenBucket({
  refillRate: 10,
  intervalSeconds: 60,
  maxTokens: 100,
});
const rl = limitRule({ key: userId, requested: 5 });

const decision = await arcjet.guard({ label: "tools.weather", rules: [rl] });

// From the bound input (matches exact invocation)
const r = rl.result(decision);
if (r) {
  console.log(r.remainingTokens, r.maxTokens);
}

// From the configured rule (matches all invocations of this rule)
const ruleResult = limitRule.result(decision);

// Check only denied results
const denied = rl.deniedResult(decision);
if (denied) {
  console.log(`Rate limited — resets at ${denied.resetAtUnixSeconds}`);
}

RuleWithConfigRuleWithInput 上可用的方法:

方法RuleWithConfig (例如 limitRule)RuleWithInput (例如 rl)
results(decision)此配置的所有结果单元素或空数组
result(decision)第一个结果(任意结论)此提交的结果
deniedResult(decision)第一个被拒绝的结果如果被拒绝,则为此提交的结果

决策 API (Guard)

const decision = await arcjet.guard({ label: "tools.weather", rules: [...] });

// Layer 1: conclusion and reason
decision.conclusion;   // "ALLOW" or "DENY"
decision.reason;       // "RATE_LIMIT", "PROMPT_INJECTION", "SENSITIVE_INFO", "CUSTOM", "ERROR", etc.

// Layer 2: error/warning detection
decision.hasFailedOpen(); // true if ALLOW only because a rule/decision could not be processed (fail-closed gate)
decision.errorResults();  // results that errored (rules or the decision that could not be processed)
decision.warnings;        // decision-level diagnostics (e.g. an invalid metadata key that was stripped)

// Layer 3: per-rule results (see "Per-rule results" above)
for (const result of decision.results) {
  console.log(result.type, result.conclusion);
}

guard() 参数参考

参数类型描述
rulesRuleWithInput[]绑定的规则输入(必填)
labelstring标识此守卫调用的标签(必填)
metadataRecord<string, string> | undefined可选的键值元数据

DRY_RUN 模式(Guard)

所有守卫规则都接受一个 mode 参数。使用 "DRY_RUN" 在不进行阻止的情况下评估规则:

const limitRule = tokenBucket({
  mode: "DRY_RUN",
  refillRate: 10,
  intervalSeconds: 60,
  maxTokens: 100,
});

最佳实践

请参阅 Arcjet 最佳实践 以获取详细指导。关键 建议:

创建单个客户端实例,并在整个应用中使用 withRule() 来附加特定于路由的规则。SDK 会缓存决策和 配置,因此为每个请求创建新实例会浪费这些工作。

// lib/arcjet.ts — create once, import everywhere
import arcjet, { shield } from "@arcjet/next";
// Replace @arcjet/next with @arcjet/node, @arcjet/bun, etc. for your runtime

export default arcjet({
  key: process.env.ARCJET_KEY!,
  rules: [
    shield({ mode: "LIVE" }), // base rules applied to every request
  ],
});
// app/api/chat/route.ts — extend per-route with withRule()
import aj from "@/lib/arcjet";
import { detectBot, tokenBucket } from "@arcjet/next";

const routeAj = aj.withRule(detectBot({ mode: "LIVE", allow: [] })).withRule(
  tokenBucket({
    mode: "LIVE",
    refillRate: 2_000,
    interval: "1h",
    capacity: 5_000,
  }),
);

export async function POST(req: Request) {
  const decision = await routeAj.protect(req, { requested: 500 });
  // ...
}

其他建议:

  • 在路由处理程序中调用 protect(),而不是在中间件中。 中间件缺乏 路由上下文,这使得应用特定于路由的规则或自定义 响应变得困难。
  • 每个请求只调用一次 protect() 在中间件和处理程序中 都调用它会使工作量加倍,并可能产生意外结果。
  • DRY_RUN 模式启动规则,以便在切换到 LIVE 之前观察行为。这允许你调整阈值而不影响真实流量。
  • 配置代理,如果你的应用运行在负载均衡器或反向 代理后面,以便 Arcjet 解析真实的客户端 IP:
    arcjet({
      key: process.env.ARCJET_KEY!,
      rules: [],
      proxies: ["100.100.100.100"],
    });
  • 显式处理错误。 protect() 从不抛出异常——出错时它返回 一个 ERROR 结果。通过记录日志并允许请求来失败开放:
    if (decision.isErrored()) {
      console.error("Arcjet error", decision.reason.message);
      // allow the request to proceed
    }

软件包

我们在此仓库中提供了各种软件包的源代码,因此你可以 通过以下类别和描述找到特定的软件包。

SDK

Nosecone

有关详细信息,请参阅 文档

实用工具

内部开发

支持

本仓库遵循 Arcjet 支持政策

安全

本仓库遵循 Arcjet 安全政策

开发

这是一个使用 npm workspacesTurborepo 管理的 monorepo。每个包都位于仓库根目录下的独立目录中 (例如 arcjet-next/analyze/)。

如果你想使用 Arcjet,你应该为你的运行时安装特定的包 (例如,Next.js 使用 @arcjet/next)。如果你想为 SDK 的开发做出贡献,请参阅 CONTRIBUTING.md

兼容性

本仓库中维护的包与 Node.js 的 LTS 版本以及 TypeScript 的当前次要版本兼容。

许可证

根据 Apache License, Version 2.0 授权。