@arcjet/skills 1.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,121 @@
1
+ ---
2
+ name: protect
3
+ description: Add Arcjet request protection to JavaScript and TypeScript HTTP handlers. Use when protecting Next.js, Express, Fastify, SvelteKit, Remix, Astro, Nuxt, Bun, Deno, NestJS, or Node.js routes with rate limiting, bot detection, Shield, email validation, or sensitive info detection.
4
+ license: Apache-2.0
5
+ compatibility: JavaScript and TypeScript HTTP apps using an @arcjet/* framework adapter.
6
+ metadata:
7
+ author: arcjet
8
+ type: core
9
+ library: "@arcjet/skills"
10
+ library_version: "1.12.0" # x-release-please-version
11
+ sources:
12
+ - docs/protect.md
13
+ ---
14
+
15
+ # Protect HTTP routes with Arcjet
16
+
17
+ Use this skill for HTTP route handlers. If there is no request object (tool
18
+ calls, MCP handlers, queue workers), load `@arcjet/skills#guard` instead.
19
+
20
+ Load `@arcjet/skills#choose-protections` when you need to pick rules.
21
+ Load `@arcjet/skills#cli` to get an `ARCJET_KEY` before writing code.
22
+
23
+ ## Checklist
24
+
25
+ - [ ] Language is JS/TS (stop if not)
26
+ - [ ] Runtime is Node `>=22.21.0 <23 || >=24.5.0`, Bun ≥ 1.3.0, or Deno stable
27
+ - [ ] `ARCJET_KEY` is in the env file (CLI first; do not leave a TODO)
28
+ - [ ] Shared `arcjet()` client at module scope, `withRule()` for extras
29
+ - [ ] `protect()` inside each route handler, not middleware
30
+ - [ ] Rules that should block use `mode: "LIVE"`
31
+ - [ ] Client IP comes from trusted ingress, not a copied forwarding header
32
+ - [ ] Decisions verified with a real request plus CLI or Console
33
+
34
+ ## Client
35
+
36
+ ```ts
37
+ import arcjet, { shield, detectBot } from "@arcjet/next";
38
+
39
+ export const aj = arcjet({
40
+ key: process.env.ARCJET_KEY!,
41
+ rules: [
42
+ shield({ mode: "LIVE" }),
43
+ detectBot({ mode: "LIVE", allow: ["CATEGORY:SEARCH_ENGINE"] }),
44
+ ],
45
+ });
46
+ ```
47
+
48
+ Pick the adapter the app already uses (`@arcjet/next`, `@arcjet/node`,
49
+ `@arcjet/fastify`, …). Install it with the project's package manager. Do not
50
+ hand-edit `package.json` and guess a version.
51
+
52
+ Omitted `mode` is `DRY_RUN`. `detectBot` requires exactly one of `allow` or
53
+ `deny`. `detectPromptInjection` takes `mode` only — no `threshold`.
54
+
55
+ One client. `withRule()` clones share the decision cache. A second
56
+ `arcjet()` constructor does not.
57
+
58
+ Astro is an integration (`arcjet:client`), not a shared file. Nuxt is a
59
+ module (`#arcjet`). NestJS is `ArcjetModule` + `@InjectArcjet()`. Bun and
60
+ Deno wrap fetch with `aj.handler()` for IP detection, then still call
61
+ `protect()`. Hono on Node passes `c.env.incoming`.
62
+
63
+ ## Handler
64
+
65
+ ```ts
66
+ export async function GET(request: Request) {
67
+ const decision = await aj.protect(request);
68
+
69
+ if (decision.isDenied()) {
70
+ return Response.json({ error: "Forbidden" }, { status: 403 });
71
+ }
72
+
73
+ return Response.json({ ok: true });
74
+ }
75
+ ```
76
+
77
+ Call `protect()` once per request, in the route handler. Not Express
78
+ middleware. Not Next.js middleware.
79
+
80
+ Branch only when the status differs: rate limit → 429; email / PII /
81
+ prompt injection → 400; everything else → 403. `isErrored()` is fail-open —
82
+ log and allow.
83
+
84
+ Pass a trusted `userId` on the rule that needs it. Pass `correlationId`
85
+ when the decision must join another request or guard call.
86
+
87
+ ## Client IP
88
+
89
+ If the app already has a trusted client IP, pass `ipSrc`. An empty string
90
+ is omitted. A malformed value is rejected. Never copy `X-Forwarded-For` or
91
+ another client-controlled header into `ipSrc` — that relabels attacker
92
+ input as trusted.
93
+
94
+ When no usable public address is available, adapters may fall back to
95
+ forwarding headers and log one `unverified-header` warning per client.
96
+ Configure `proxies` (or `cloudflare()`). Inspect with
97
+ `clientIpDetails()` (`@arcjet/node`) or `findIpDetails()` /
98
+ `resolveClientIp()` (`@arcjet/ip`) before shipping.
99
+
100
+ Nested `metadata` is for the Console — no secrets, no PII.
101
+
102
+ ## Common mistakes
103
+
104
+ - `@arcjet/guard` on an HTTP route (or a request adapter on a tool call)
105
+ - `protect()` in middleware
106
+ - Double `protect()` (double-counts rate limits)
107
+ - Dry-run rules that look like they block
108
+ - Both `allow` and `deny` on `detectBot`
109
+ - `threshold` on `detectPromptInjection`
110
+ - Copying `X-Forwarded-For` into `ipSrc` to hide `unverified-header`
111
+ - Hardcoded `ARCJET_KEY`
112
+
113
+ ## Verify
114
+
115
+ Type-check, then `curl` the route. Confirm with
116
+ `npx @arcjet/cli@latest requests list --site-id <id>` or
117
+ https://console.arcjet.com.
118
+
119
+ Exact signatures live in the installed adapter's types. This skill is about
120
+ where Arcjet goes and how its HTTP API is used — match the project's
121
+ conventions for everything else.