@arcjet/astro 1.3.1 → 1.5.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.
package/README.md CHANGED
@@ -18,11 +18,31 @@
18
18
 
19
19
  [Arcjet][arcjet] is the runtime security platform that ships with your AI code. Stop bots and automated attacks from burning your AI budget, leaking data, or misusing tools with Arcjet's AI security building blocks. Every feature works with any Astro application.
20
20
 
21
- This is the [Arcjet][arcjet] SDK for [Astro][astro].
21
+ This is the [Arcjet][arcjet] SDK for [Astro][astro] **request protection** —
22
+ use it to protect HTTP route handlers and API endpoints. If you need to protect
23
+ AI agent tool calls, MCP server handlers, or background jobs (anything without
24
+ an HTTP request), see [`@arcjet/guard`](https://github.com/arcjet/arcjet-js/tree/main/arcjet-guard).
22
25
 
23
26
  ## Getting started
24
27
 
25
- 1. Get your API key at [`app.arcjet.com`](https://app.arcjet.com)
28
+ ### Quick setup with an AI agent
29
+
30
+ 1. Log in with the CLI:
31
+ ```sh
32
+ npx @arcjet/cli auth login
33
+ ```
34
+ 2. Install the request protection skill to give your coding agent the docs it needs:
35
+ ```sh
36
+ npx skills add arcjet/skills --skill add-request-protection
37
+ ```
38
+ 3. Tell your agent what to protect — it handles the rest.
39
+
40
+ ### Manual setup
41
+
42
+ 1. **Log in** with the CLI (or at [`app.arcjet.com`](https://app.arcjet.com?utm_campaign=arcjet-js)):
43
+ ```sh
44
+ npx @arcjet/cli auth login
45
+ ```
26
46
  2. `npm install @arcjet/astro`
27
47
  3. Set `ARCJET_KEY=ajkey_yourkey` in your environment
28
48
  4. Add Arcjet to your app — see the [quick start](#quick-start) below
@@ -34,6 +54,23 @@ This is the [Arcjet][arcjet] SDK for [Astro][astro].
34
54
 
35
55
  ## Features
36
56
 
57
+ All features below are available with `@arcjet/astro` for request protection.
58
+ For guard protection (tool calls, MCP servers, queues) see
59
+ [`@arcjet/guard`](https://github.com/arcjet/arcjet-js/tree/main/arcjet-guard).
60
+
61
+ | Feature | `@arcjet/astro` | `@arcjet/guard` |
62
+ | ------------------------------- | :-------------: | :-------------: |
63
+ | Rate Limiting | ✅ | ✅ |
64
+ | Prompt Injection Detection | ✅ | ✅ |
65
+ | Sensitive Information Detection | ✅ | ✅ |
66
+ | Bot Protection | ✅ | — |
67
+ | Shield WAF | ✅ | — |
68
+ | Email Validation | ✅ | — |
69
+ | Signup Form Protection | ✅ | — |
70
+ | Request Filters | ✅ | — |
71
+ | IP Analysis | ✅ | — |
72
+ | Custom Rules | — | ✅ |
73
+
37
74
  - 🔒 [Prompt Injection Detection](#prompt-injection-detection) — detect and block
38
75
  prompt injection attacks before they reach your LLM.
39
76
  - 🤖 [Bot Protection](#bot-protection) — stop scrapers, credential stuffers,
@@ -142,7 +179,7 @@ For the full reference, see the [Arcjet Astro SDK docs][arcjet-reference-astro].
142
179
 
143
180
  Detect and block prompt injection attacks — attempts to override your AI
144
181
  model's instructions — before they reach your model. Pass the user's message
145
- via `detectPromptInjectionMessage` on each `protect()` call. Tune sensitivity with the `threshold` parameter (0.0–1.0, default 0.5) — higher values are more conservative.
182
+ via `detectPromptInjectionMessage` on each `protect()` call.
146
183
 
147
184
  Configure in `astro.config.mjs`:
148
185
 
@@ -156,7 +193,6 @@ export default defineConfig({
156
193
  rules: [
157
194
  detectPromptInjection({
158
195
  mode: "LIVE", // Blocks requests. Use "DRY_RUN" to log only
159
- threshold: 0.5, // Score above which requests are blocked (default: 0.5)
160
196
  }),
161
197
  ],
162
198
  }),
package/index.d.ts CHANGED
@@ -1,5 +1,8 @@
1
1
  import type { BotOptions, DetectPromptInjectionOptions, EmailOptions, FilterOptions, FixedWindowRateLimitOptions, ProtectSignupOptions, SensitiveInfoOptions, ShieldOptions, SlidingWindowRateLimitOptions, TokenBucketRateLimitOptions } from "arcjet";
2
+ import type { ProxyService } from "@arcjet/ip";
2
3
  import type { AstroIntegration } from "astro";
4
+ export { cloudflare } from "@arcjet/ip";
5
+ export type { ProxyService } from "@arcjet/ip";
3
6
  type IntegrationRule<Characteristics extends readonly string[]> = {
4
7
  type: "shield";
5
8
  options: ShieldOptions;
@@ -58,8 +61,12 @@ export type ArcjetOptions<Characteristics extends readonly string[]> = {
58
61
  /**
59
62
  * IP addresses and CIDR ranges of trusted load balancers and proxies
60
63
  * (optional, example: `["100.100.100.100", "100.100.100.0/24"]`).
64
+ *
65
+ * Proxy services such as {@linkcode cloudflare} can also be included to read
66
+ * the real client IP from a service-specific header when the request comes
67
+ * from that service.
61
68
  */
62
- proxies?: string[];
69
+ proxies?: Array<string | ProxyService>;
63
70
  };
64
71
  /**
65
72
  * Arcjet Shield WAF rule.
@@ -355,4 +362,3 @@ export declare function createRemoteClient(options?: RemoteClientOptions | undef
355
362
  * Astro integration of Arcjet.
356
363
  */
357
364
  export default function arcjet<Characteristics extends readonly string[]>(options?: ArcjetOptions<Characteristics>): AstroIntegration;
358
- export {};
package/index.js CHANGED
@@ -1,9 +1,20 @@
1
1
  import { z } from 'astro/zod';
2
2
  import fs from 'node:fs/promises';
3
+ export { cloudflare } from '@arcjet/ip';
3
4
 
4
5
  const resolvedVirtualClientId = "\0ARCJET_VIRTUAL_CLIENT";
5
6
  const validateMode = z.enum(["LIVE", "DRY_RUN"]);
6
- const validateProxies = z.array(z.string());
7
+ // A proxy service (such as the one created by `cloudflare()`) is a plain,
8
+ // JSON-serializable object, so it survives being injected into the generated
9
+ // client config. Ranges must be strings here because parsed `Cidr` objects
10
+ // would not serialize; `findIp` parses these strings at runtime.
11
+ const validateProxyService = z.object({
12
+ kind: z.literal("service"),
13
+ name: z.string(),
14
+ ranges: z.array(z.string()),
15
+ clientIp: z.array(z.object({ header: z.string(), format: z.enum(["ip", "ips"]) })),
16
+ });
17
+ const validateProxies = z.array(z.union([z.string(), validateProxyService]));
7
18
  const validateCharacteristics = z.array(z.string());
8
19
  const validateClientOptions = z
9
20
  .object({
package/internal.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import type { ArcjetDecision, ArcjetOptions as CoreOptions, ArcjetRule, Primitive, Product, ExtraProps, CharacteristicProps } from "arcjet";
2
+ import { type ProxyService } from "@arcjet/ip";
2
3
  export * from "arcjet";
3
4
  type Simplify<T> = {
4
5
  [KeyType in keyof T]: T[KeyType];
@@ -59,8 +60,12 @@ export type ArcjetOptions<Rules extends [...Array<Primitive | Product>], Charact
59
60
  /**
60
61
  * IP addresses and CIDR ranges of trusted load balancers and proxies
61
62
  * (optional, example: `["100.100.100.100", "100.100.100.0/24"]`).
63
+ *
64
+ * Proxy services such as {@linkcode cloudflare} can also be included to read
65
+ * the real client IP from a service-specific header when the request comes
66
+ * from that service.
62
67
  */
63
- proxies?: Array<string>;
68
+ proxies?: Array<string | ProxyService>;
64
69
  }>;
65
70
  /**
66
71
  * Instance of the Astro integration of Arcjet.
package/internal.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import core__default from 'arcjet';
2
2
  export * from 'arcjet';
3
3
  import { readBodyWeb } from '@arcjet/body';
4
- import { parseProxy, findIp } from '@arcjet/ip';
4
+ import { parseProxies, findIp } from '@arcjet/ip';
5
5
  import { ArcjetHeaders } from '@arcjet/headers';
6
6
  import { logLevel, isDevelopment, baseUrl, platform } from '@arcjet/env';
7
7
  import { Logger } from '@arcjet/logger';
@@ -40,7 +40,7 @@ function createRemoteClient(options) {
40
40
  // Transport is the HTTP client that the client uses to make requests.
41
41
  const transport = createTransport(url);
42
42
  const sdkStack = "ASTRO";
43
- const sdkVersion = "1.3.1";
43
+ const sdkVersion = "1.5.0";
44
44
  return createClient({
45
45
  transport,
46
46
  baseUrl: url,
@@ -69,7 +69,7 @@ function createArcjetClient(options) {
69
69
  level: logLevel(env),
70
70
  });
71
71
  const proxies = Array.isArray(options.proxies)
72
- ? options.proxies.map(parseProxy)
72
+ ? parseProxies(options.proxies)
73
73
  : undefined;
74
74
  if (isDevelopment(process.env)) {
75
75
  log.warn("Arcjet will use 127.0.0.1 when missing public IP address in development mode");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@arcjet/astro",
3
- "version": "1.3.1",
3
+ "version": "1.5.0",
4
4
  "description": "Arcjet runtime security SDK for Astro — bot protection, rate limiting, prompt injection detection, PII blocking, and WAF",
5
5
  "keywords": [
6
6
  "ai",
@@ -58,24 +58,24 @@
58
58
  "test": "npm run build && npm run lint && npm run test-coverage"
59
59
  },
60
60
  "dependencies": {
61
- "@arcjet/body": "1.3.1",
62
- "@arcjet/env": "1.3.1",
63
- "@arcjet/headers": "1.3.1",
64
- "@arcjet/ip": "1.3.1",
65
- "@arcjet/logger": "1.3.1",
66
- "@arcjet/protocol": "1.3.1",
67
- "@arcjet/transport": "1.3.1",
68
- "arcjet": "1.3.1"
61
+ "@arcjet/body": "1.5.0",
62
+ "@arcjet/env": "1.5.0",
63
+ "@arcjet/headers": "1.5.0",
64
+ "@arcjet/ip": "1.5.0",
65
+ "@arcjet/logger": "1.5.0",
66
+ "@arcjet/protocol": "1.5.0",
67
+ "@arcjet/transport": "1.5.0",
68
+ "arcjet": "1.5.0"
69
69
  },
70
70
  "peerDependencies": {
71
71
  "astro": "^5.9.3 || ^6.0.0"
72
72
  },
73
73
  "devDependencies": {
74
- "@arcjet/eslint-config": "1.3.1",
75
- "@arcjet/rollup-config": "1.3.1",
76
- "@rollup/wasm-node": "4.59.0",
77
- "astro": "6.1.2",
78
- "eslint": "9.39.3",
74
+ "@arcjet/eslint-config": "1.5.0",
75
+ "@arcjet/rollup-config": "1.5.0",
76
+ "@rollup/wasm-node": "4.61.0",
77
+ "astro": "6.1.10",
78
+ "eslint": "9.39.4",
79
79
  "typescript": "5.9.3"
80
80
  },
81
81
  "publishConfig": {