Arcjet - JS SDK
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/next | npm i @arcjet/next |
| Node.js | @arcjet/node | npm i @arcjet/node |
| Bun | @arcjet/bun | bun add @arcjet/bun |
| Deno | @arcjet/deno | deno add npm:@arcjet/deno |
| Express | @arcjet/node | npm i @arcjet/node |
| Fastify | @arcjet/fastify | npm i @arcjet/fastify |
| Hono | @arcjet/node 或 @arcjet/bun | npm i @arcjet/node |
| NestJS | @arcjet/nest | npm i @arcjet/nest |
| Nuxt | @arcjet/nuxt | npm i @arcjet/nuxt |
| Remix | @arcjet/remix | npm i @arcjet/remix |
| React Router | @arcjet/react-router | npm i @arcjet/react-router |
| SvelteKit | @arcjet/sveltekit | npm i @arcjet/sveltekit |
| Astro | @arcjet/astro | npm i @arcjet/astro |
用于 guard 保护:
npm i @arcjet/guard
步骤 4:告诉你的代理要保护什么
让你的编码代理实施保护。你在 步骤 2 中安装的技能提供了它所需的一切。例如:
“在我的 /api/chat 路由中添加 Arcjet 机器人保护和速率限制”
“在我的 MCP 工具处理器中添加带有提示注入检测的 Arcjet 防护”
代理将安装正确的包,配置规则,并接入
protect() 或 guard() 调用 — 或者查看 完整保护列表
如下。
获取帮助
功能
| 功能 | 请求 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 请求的场景。
示例应用
- Astro
- Deno
- Express
- FastAPI
- Fastify
- NestJS
- Next.js(在线试用)
- Nuxt
- React Router
- Remix
- SvelteKit
- Tanstack Start
蓝图
用法
在 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:ACADEMIC、CATEGORY:ADVERTISING、
CATEGORY:AI、CATEGORY:AMAZON、CATEGORY:APPLE、CATEGORY:ARCHIVE、
CATEGORY:BOTNET、CATEGORY:FEEDFETCHER、CATEGORY:GOOGLE、
CATEGORY:META、CATEGORY:MICROSOFT、CATEGORY:MONITOR、
CATEGORY:OPTIMIZER、CATEGORY:PREVIEW、CATEGORY:PROGRAMMATIC、
CATEGORY:SEARCH_ENGINE、CATEGORY:SLACK、CATEGORY:SOCIAL、
CATEGORY:TOOL、CATEGORY:UNKNOWN、CATEGORY:VERCEL、
CATEGORY:WEBHOOK、CATEGORY: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_NUMBER、EMAIL、PHONE_NUMBER、IP_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}`);
}
RuleWithConfig 和 RuleWithInput 上可用的方法:
| 方法 | 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() 参数参考
| 参数 | 类型 | 描述 |
|---|---|---|
rules | RuleWithInput[] | 绑定的规则输入(必填) |
label | string | 标识此守卫调用的标签(必填) |
metadata | Record<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
@arcjet/astro: Astro 的 SDK。@arcjet/bun: Bun 的 SDK。@arcjet/deno: Deno 的 SDK。@arcjet/fastify: Fastify 的 SDK。@arcjet/guard: 用于 AI 智能体工具调用和后台任务的 Guards SDK。@arcjet/nest: NestJS 的 SDK。@arcjet/next: Next.js 的 SDK。@arcjet/node: Node.js 的 SDK。@arcjet/nuxt: Nuxt 的 SDK。@arcjet/react-router: React Router 的 SDK。@arcjet/remix: Remix 的 SDK。@arcjet/sveltekit: SvelteKit 的 SDK。
Nosecone
有关详细信息,请参阅 文档。
@nosecone/next: 使用安全标头保护您的 Next.js 应用程序。@nosecone/sveltekit: 使用安全标头保护您的 SvelteKit 应用程序。nosecone: 使用安全标头保护您的Response。
实用工具
@arcjet/analyze: 本地分析引擎。@arcjet/body: 从流中提取主体。@arcjet/cache: 基础缓存接口及 实现。@arcjet/decorate: 使用信息装饰响应。@arcjet/duration: 解析持续时间字符串。@arcjet/env: 环境检测。@arcjet/headers: Headers 类的扩展。@arcjet/inspect: 检查 SDK 做出的决策。@arcjet/ip: 查找请求的源 IP。@arcjet/logger: 镜像 Pino 结构化日志器接口的轻量级日志记录器。@arcjet/protocol: 协议的 JS 接口。@arcjet/redact: 从字符串中编辑和还原敏感信息。@arcjet/runtime: 运行时检测。@arcjet/sprintf:util.format的平台无关替代方案。@arcjet/stable-hash: 稳定哈希。@arcjet/transport: Arcjet 协议的传输机制。arcjet: JS SDK 核心。
内部开发
@arcjet/eslint-config: 我们项目的自定义 eslint 配置。@arcjet/rollup-config: 我们项目的自定义 rollup 配置。
支持
本仓库遵循 Arcjet 支持政策。
安全
本仓库遵循 Arcjet 安全政策。
开发
这是一个使用 npm workspaces 和
Turborepo 管理的 monorepo。每个包都位于仓库根目录下的独立目录中
(例如 arcjet-next/、analyze/)。
如果你想使用 Arcjet,你应该为你的运行时安装特定的包
(例如,Next.js 使用 @arcjet/next)。如果你想为 SDK 的开发做出贡献,请参阅 CONTRIBUTING.md。
兼容性
本仓库中维护的包与 Node.js 的 LTS 版本以及 TypeScript 的当前次要版本兼容。
许可证
根据 Apache License, Version 2.0 授权。