@arcjet/bun 1.2.0 → 1.3.1

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.
Files changed (3) hide show
  1. package/README.md +486 -57
  2. package/index.js +1 -1
  3. package/package.json +25 -18
package/README.md CHANGED
@@ -16,95 +16,523 @@
16
16
  </a>
17
17
  </p>
18
18
 
19
- [Arcjet][arcjet] helps developers protect their apps in just a few lines of
20
- code. Implement rate limiting, bot protection, email verification, and defense
21
- against common attacks.
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 Bun application.
22
20
 
23
- This is the [Arcjet][arcjet] SDK for [Bun.sh][bun-sh].
24
-
25
- - [npm package (`@arcjet/bun`)](https://www.npmjs.com/package/@arcjet/bun)
26
- - [GitHub source code (`arcjet-bun/` in `arcjet/arcjet-js`)](https://github.com/arcjet/arcjet-js/tree/main/arcjet-bun)
21
+ This is the [Arcjet][arcjet] SDK for [Bun][bun-sh].
27
22
 
28
23
  ## Getting started
29
24
 
30
- Visit the [quick start guide][quick-start] to get started.
25
+ 1. Get your API key at [`app.arcjet.com`](https://app.arcjet.com)
26
+ 2. `bun add @arcjet/bun`
27
+ 3. Set `ARCJET_KEY=ajkey_yourkey` in your environment
28
+ 4. Add Arcjet to your server — see the [quick start](#quick-start) below
29
+
30
+ [npm package](https://www.npmjs.com/package/@arcjet/bun) |
31
+ [GitHub source](https://github.com/arcjet/arcjet-js/tree/main/arcjet-bun) |
32
+ [Full docs][arcjet-reference-bun] |
33
+ [Other SDKs on GitHub](https://github.com/arcjet)
34
+
35
+ ## Features
36
+
37
+ - 🔒 [Prompt Injection Detection](#prompt-injection-detection) — detect and block
38
+ prompt injection attacks before they reach your LLM.
39
+ - 🤖 [Bot Protection](#bot-protection) — stop scrapers, credential stuffers, and
40
+ AI crawlers from abusing your endpoints.
41
+ - 🛑 [Rate Limiting](#rate-limiting) — token bucket, fixed window, and sliding
42
+ window algorithms; model AI token budgets per user.
43
+ - 🕵️ [Sensitive Information Detection](#sensitive-information-detection) — block
44
+ PII, credit cards, and custom patterns from entering your AI pipeline.
45
+ - 🛡️ [Shield WAF](#shield-waf) — protect against SQL injection, XSS, and other
46
+ common web attacks.
47
+ - 📧 [Email Validation](#email-validation) — block disposable, invalid, and
48
+ undeliverable addresses at signup.
49
+ - 📝 [Signup Form Protection][signup-protection-docs] — combines bot protection,
50
+ email validation, and rate limiting to protect your signup forms.
51
+ - 🎯 [Request Filters](#request-filters) — expression-based rules on IP, path,
52
+ headers, and custom fields.
53
+ - 🌐 [IP Analysis](#ip-analysis) — geolocation, ASN, VPN, proxy, Tor, and hosting
54
+ detection included with every request.
55
+
56
+ ## Quick start
57
+
58
+ This example protects a Bun HTTP server with bot detection, Shield WAF, and
59
+ token bucket rate limiting.
31
60
 
32
- ## Example
61
+ ```ts
62
+ // index.ts
63
+ import arcjet, { detectBot, shield, tokenBucket } from "@arcjet/bun";
64
+ import { isSpoofedBot } from "@arcjet/inspect";
65
+ import { env } from "bun";
33
66
 
34
- Try an Arcjet protected Next.js app live at
35
- [`example.arcjet.com`][example-next-url]
36
- ([source code][example-next-source]).
67
+ const aj = arcjet({
68
+ key: env.ARCJET_KEY!, // Get your site key from https://app.arcjet.com
69
+ rules: [
70
+ // Shield protects your app from common attacks e.g. SQL injection
71
+ shield({ mode: "LIVE" }),
72
+ // Create a bot detection rule
73
+ detectBot({
74
+ mode: "LIVE", // Blocks requests. Use "DRY_RUN" to log only
75
+ // Block all bots except the following
76
+ allow: [
77
+ "CATEGORY:SEARCH_ENGINE", // Google, Bing, etc
78
+ // Uncomment to allow these other common bot categories
79
+ // See the full list at https://arcjet.com/bot-list
80
+ //"CATEGORY:MONITOR", // Uptime monitoring services
81
+ //"CATEGORY:PREVIEW", // Link previews e.g. Slack, Discord
82
+ ],
83
+ }),
84
+ // Token bucket rate limit. Other algorithms are supported.
85
+ tokenBucket({
86
+ mode: "LIVE",
87
+ // Tracked by IP address by default, but this can be customized
88
+ // See https://docs.arcjet.com/fingerprints
89
+ refillRate: 5, // Refill 5 tokens per interval
90
+ interval: 10, // Refill every 10 seconds
91
+ capacity: 10, // Bucket capacity of 10 tokens
92
+ }),
93
+ ],
94
+ });
37
95
 
38
- <!--
96
+ export default {
97
+ port: 3000,
98
+ fetch: aj.handler(async (req) => {
99
+ const decision = await aj.protect(req, { requested: 5 }); // Deduct 5 tokens
100
+ console.log("Arcjet decision", decision);
39
101
 
40
- TODO: Bun example.
102
+ if (decision.isDenied()) {
103
+ if (decision.reason.isRateLimit()) {
104
+ return new Response("Too many requests", { status: 429 });
105
+ } else if (decision.reason.isBot()) {
106
+ return new Response("No bots allowed", { status: 403 });
107
+ } else {
108
+ return new Response("Forbidden", { status: 403 });
109
+ }
110
+ }
41
111
 
42
- See [`arcjet/example-bun`][example-astro-source] for a Bun example.
112
+ // Requests from hosting IPs are likely from bots.
113
+ // https://docs.arcjet.com/blueprints/vpn-proxy-detection
114
+ if (decision.ip.isHosting()) {
115
+ return new Response("Forbidden", { status: 403 });
116
+ }
43
117
 
44
- [example-bun-source]: https://github.com/arcjet/example-bun
118
+ // Verifies the authenticity of common bots using IP data.
119
+ // Verification isn't always possible, so check the results separately.
120
+ // https://docs.arcjet.com/bot-protection/reference#bot-verification
121
+ if (decision.results.some(isSpoofedBot)) {
122
+ return new Response("Forbidden", { status: 403 });
123
+ }
45
124
 
46
- -->
125
+ return new Response("Hello world");
126
+ }),
127
+ };
128
+ ```
47
129
 
48
- ## What is this?
130
+ For the full reference, see the [Arcjet Bun SDK docs][arcjet-reference-bun].
49
131
 
50
- This is our adapter to integrate Arcjet into Bun.
51
- Arcjet helps you secure your Bun server.
52
- This package exists so that we can provide the best possible experience to
53
- Bun users.
132
+ ## Prompt injection detection
54
133
 
55
- ## When should I use this?
134
+ Detect and block prompt injection attacks — attempts to override your AI
135
+ model's instructions — before they reach your model. Pass the user's message
136
+ via `detectPromptInjectionMessage` on each `protect()` call. Tune sensitivity with the `threshold` parameter (0.0–1.0, default 0.5) — higher values are more conservative.
56
137
 
57
- You can use this if you are using Bun.
58
- See our [_Get started_ guide][arcjet-get-started] for other supported
59
- runtimes.
138
+ ```ts
139
+ import arcjet, { detectPromptInjection } from "@arcjet/bun";
140
+ import { env } from "bun";
60
141
 
61
- ## Install
142
+ const aj = arcjet({
143
+ key: env.ARCJET_KEY!,
144
+ rules: [
145
+ detectPromptInjection({
146
+ mode: "LIVE", // Blocks requests. Use "DRY_RUN" to log only
147
+ threshold: 0.5, // Score above which requests are blocked (default: 0.5)
148
+ }),
149
+ ],
150
+ });
62
151
 
63
- This package is ESM only.
64
- Install with Bun:
152
+ export default {
153
+ fetch: aj.handler(async (req) => {
154
+ const { message } = await req.json();
155
+
156
+ const decision = await aj.protect(req, {
157
+ detectPromptInjectionMessage: message,
158
+ });
159
+
160
+ if (decision.isDenied() && decision.reason.isPromptInjection()) {
161
+ return new Response(
162
+ "Prompt injection detected — please rephrase your message",
163
+ { status: 400 },
164
+ );
165
+ }
65
166
 
66
- ```sh
67
- bun add @arcjet/bun
167
+ // Forward to your AI model...
168
+ return new Response("OK");
169
+ }),
170
+ };
68
171
  ```
69
172
 
70
- ## Use
173
+ ## Bot protection
71
174
 
72
- ```ts
73
- import arcjet, { shield } from "@arcjet/bun";
175
+ Arcjet allows you to configure a list of bots to allow or deny. Specifying
176
+ `allow` means all other bots are denied. An empty allow list blocks all bots.
74
177
 
75
- // Get your Arcjet key at <https://app.arcjet.com>.
76
- // Set it as an environment variable instead of hard coding it.
77
- const arcjetKey = Bun.env.ARCJET_KEY;
178
+ Available categories: `CATEGORY:ACADEMIC`, `CATEGORY:ADVERTISING`,
179
+ `CATEGORY:AI`, `CATEGORY:AMAZON`, `CATEGORY:APPLE`, `CATEGORY:ARCHIVE`,
180
+ `CATEGORY:BOTNET`, `CATEGORY:FEEDFETCHER`, `CATEGORY:GOOGLE`,
181
+ `CATEGORY:META`, `CATEGORY:MICROSOFT`, `CATEGORY:MONITOR`,
182
+ `CATEGORY:OPTIMIZER`, `CATEGORY:PREVIEW`, `CATEGORY:PROGRAMMATIC`,
183
+ `CATEGORY:SEARCH_ENGINE`, `CATEGORY:SLACK`, `CATEGORY:SOCIAL`,
184
+ `CATEGORY:TOOL`, `CATEGORY:UNKNOWN`, `CATEGORY:VERCEL`,
185
+ `CATEGORY:WEBHOOK`, `CATEGORY:YAHOO`. You can also allow or deny
186
+ [specific bots by name][bot-list].
78
187
 
79
- if (!arcjetKey) {
80
- throw new Error("Cannot find `ARCJET_KEY` environment variable");
81
- }
188
+ ```ts
189
+ import arcjet, { detectBot } from "@arcjet/bun";
190
+ import { isSpoofedBot } from "@arcjet/inspect";
191
+ import { env } from "bun";
82
192
 
83
193
  const aj = arcjet({
84
- key: arcjetKey,
194
+ key: env.ARCJET_KEY!,
85
195
  rules: [
86
- // Shield protects your app from common attacks.
87
- // Use `DRY_RUN` instead of `LIVE` to only log.
88
- shield({ mode: "LIVE" }),
196
+ detectBot({
197
+ mode: "LIVE",
198
+ allow: [
199
+ "CATEGORY:SEARCH_ENGINE",
200
+ // See the full list at https://arcjet.com/bot-list
201
+ ],
202
+ }),
89
203
  ],
90
204
  });
91
205
 
92
206
  export default {
93
- port: 8000,
94
- fetch: aj.handler(async function (request: Request) {
95
- const decision = await aj.protect(request);
207
+ fetch: aj.handler(async (req) => {
208
+ const decision = await aj.protect(req);
96
209
 
97
- if (decision.isDenied()) {
98
- return Response.json({ message: "Forbidden" }, { status: 403 });
210
+ if (decision.isDenied() && decision.reason.isBot()) {
211
+ return new Response("No bots allowed", { status: 403 });
212
+ }
213
+
214
+ // Verifies the authenticity of common bots using IP data.
215
+ if (decision.results.some(isSpoofedBot)) {
216
+ return new Response("Forbidden", { status: 403 });
99
217
  }
100
218
 
101
- return Response.json({ message: "Hello world" });
219
+ return new Response("Hello world");
102
220
  }),
103
221
  };
104
222
  ```
105
223
 
106
- For more on how to configure Arcjet with Bun and how to protect Bun,
107
- see the [Arcjet Bun SDK reference][arcjet-reference-bun] on our website.
224
+ ### Bot categories
225
+
226
+ Bots can be configured by [category][bot-categories-docs] and/or by [specific
227
+ bot name][bot-list]. For example, to allow search engines and the OpenAI
228
+ crawler, but deny all other bots:
229
+
230
+ ```ts
231
+ detectBot({
232
+ mode: "LIVE",
233
+ allow: ["CATEGORY:SEARCH_ENGINE", "OPENAI_CRAWLER_SEARCH"],
234
+ });
235
+ ```
236
+
237
+ ### Verified vs spoofed bots
238
+
239
+ Bots claiming to be well-known crawlers (e.g. Googlebot) are verified by
240
+ checking their IP address against known IP ranges. If a bot fails verification,
241
+ it is labeled as spoofed. Use `isSpoofedBot` from `@arcjet/inspect` to check:
242
+
243
+ ```ts
244
+ import { isSpoofedBot } from "@arcjet/inspect";
245
+
246
+ if (decision.results.some(isSpoofedBot)) {
247
+ return new Response("Forbidden", { status: 403 });
248
+ }
249
+ ```
250
+
251
+ ## Rate limiting
252
+
253
+ Arcjet supports token bucket, fixed window, and sliding window algorithms.
254
+ Token buckets are ideal for controlling AI token budgets — set `capacity` to
255
+ the max tokens a user can spend, `refillRate` to how many tokens are restored
256
+ per `interval`, and deduct tokens per request via `requested` in `protect()`.
257
+ The `interval` accepts strings (`"1s"`, `"1m"`, `"1h"`, `"1d"`) or seconds as
258
+ a number. Use `characteristics` to track limits per user instead of per IP.
259
+
260
+ ```ts
261
+ import arcjet, { tokenBucket } from "@arcjet/bun";
262
+ import { env } from "bun";
263
+
264
+ const aj = arcjet({
265
+ key: env.ARCJET_KEY!,
266
+ characteristics: ["userId"], // Track per user
267
+ rules: [
268
+ tokenBucket({
269
+ mode: "LIVE",
270
+ refillRate: 2_000, // Refill 2,000 tokens per hour
271
+ interval: "1h",
272
+ capacity: 5_000, // Maximum 5,000 tokens in the bucket
273
+ }),
274
+ ],
275
+ });
276
+
277
+ const decision = await aj.protect(req, {
278
+ userId: "user-123",
279
+ requested: estimate, // Number of tokens to deduct
280
+ });
281
+
282
+ if (decision.isDenied() && decision.reason.isRateLimit()) {
283
+ return new Response("Rate limit exceeded", { status: 429 });
284
+ }
285
+ ```
286
+
287
+ ## Sensitive information detection
288
+
289
+ Detect and block PII in request content. Pass the content to scan via
290
+ `sensitiveInfoValue` on each `protect()` call. Built-in entity types:
291
+ `CREDIT_CARD_NUMBER`, `EMAIL`, `PHONE_NUMBER`, `IP_ADDRESS`. You can also
292
+ provide a custom `detect` callback for additional patterns.
293
+
294
+ ```ts
295
+ import arcjet, { sensitiveInfo } from "@arcjet/bun";
296
+ import { env } from "bun";
297
+
298
+ const aj = arcjet({
299
+ key: env.ARCJET_KEY!,
300
+ rules: [
301
+ sensitiveInfo({
302
+ mode: "LIVE", // Blocks requests. Use "DRY_RUN" to log only
303
+ deny: ["CREDIT_CARD_NUMBER", "EMAIL", "PHONE_NUMBER"],
304
+ }),
305
+ ],
306
+ });
307
+
308
+ const decision = await aj.protect(req, {
309
+ sensitiveInfoValue: userMessage, // The text content to scan
310
+ });
311
+
312
+ if (decision.isDenied() && decision.reason.isSensitiveInfo()) {
313
+ return new Response("Sensitive information detected", { status: 400 });
314
+ }
315
+ ```
316
+
317
+ ## Shield WAF
318
+
319
+ Protect your application against common web attacks, including the OWASP
320
+ Top 10.
321
+
322
+ ```ts
323
+ import arcjet, { shield } from "@arcjet/bun";
324
+ import { env } from "bun";
325
+
326
+ const aj = arcjet({
327
+ key: env.ARCJET_KEY!,
328
+ rules: [
329
+ shield({
330
+ mode: "LIVE", // Blocks requests. Use "DRY_RUN" to log only
331
+ }),
332
+ ],
333
+ });
334
+ ```
335
+
336
+ ## Email validation
337
+
338
+ Validate and verify email addresses. Deny types: `DISPOSABLE`, `FREE`,
339
+ `NO_MX_RECORDS`, `NO_GRAVATAR`, `INVALID`.
340
+
341
+ ```ts
342
+ import arcjet, { validateEmail } from "@arcjet/bun";
343
+ import { env } from "bun";
344
+
345
+ const aj = arcjet({
346
+ key: env.ARCJET_KEY!,
347
+ rules: [
348
+ validateEmail({
349
+ mode: "LIVE",
350
+ deny: ["DISPOSABLE", "INVALID", "NO_MX_RECORDS"],
351
+ }),
352
+ ],
353
+ });
354
+
355
+ const decision = await aj.protect(req, {
356
+ email: "user@example.com",
357
+ });
358
+
359
+ if (decision.isDenied() && decision.reason.isEmail()) {
360
+ return new Response("Invalid email address", { status: 400 });
361
+ }
362
+ ```
363
+
364
+ ## Request filters
365
+
366
+ Filter requests using expression-based rules against request properties (IP,
367
+ headers, path, method, etc.).
368
+
369
+ ```ts
370
+ import arcjet, { filter } from "@arcjet/bun";
371
+ import { env } from "bun";
372
+
373
+ const aj = arcjet({
374
+ key: env.ARCJET_KEY!,
375
+ rules: [
376
+ filter({
377
+ mode: "LIVE",
378
+ deny: ['ip.src == "1.2.3.4"'],
379
+ }),
380
+ ],
381
+ });
382
+ ```
383
+
384
+ ### Block by country
385
+
386
+ Restrict access to specific countries — useful for licensing, compliance, or
387
+ regional rollouts. The `allow` list denies all countries not listed:
388
+
389
+ ```ts
390
+ filter({
391
+ mode: "LIVE",
392
+ // Allow only US traffic — all other countries are denied
393
+ allow: ['ip.src.country == "US"'],
394
+ });
395
+ ```
396
+
397
+ ### Block VPN and proxy traffic
398
+
399
+ Prevent anonymized traffic from accessing sensitive endpoints — useful for
400
+ fraud prevention, enforcing geo-restrictions, and reducing abuse:
401
+
402
+ ```ts
403
+ filter({
404
+ mode: "LIVE",
405
+ deny: [
406
+ "ip.src.vpn", // VPN services
407
+ "ip.src.proxy", // Open proxies
408
+ "ip.src.tor", // Tor exit nodes
409
+ ],
410
+ });
411
+ ```
412
+
413
+ For more nuanced handling, use `decision.ip` helpers after calling `protect()`:
414
+
415
+ ```ts
416
+ const decision = await aj.protect(req);
417
+
418
+ if (decision.ip.isVpn() || decision.ip.isTor()) {
419
+ return new Response("VPN traffic not allowed", { status: 403 });
420
+ }
421
+ ```
422
+
423
+ See the [Request Filters docs][filters-docs],
424
+ [IP Geolocation blueprint](https://docs.arcjet.com/blueprints/ip-geolocation), and
425
+ [VPN/Proxy Detection blueprint](https://docs.arcjet.com/blueprints/vpn-proxy-detection)
426
+ for more details.
427
+
428
+ ## IP analysis
429
+
430
+ Arcjet enriches every request with IP metadata. Use these helpers to make
431
+ policy decisions based on network signals:
432
+
433
+ ```ts
434
+ const decision = await aj.protect(req);
435
+
436
+ if (decision.ip.isHosting()) {
437
+ // Requests from cloud/hosting providers are often automated.
438
+ // https://docs.arcjet.com/blueprints/vpn-proxy-detection
439
+ return new Response("Forbidden", { status: 403 });
440
+ }
441
+
442
+ if (decision.ip.isVpn() || decision.ip.isProxy() || decision.ip.isTor()) {
443
+ // Handle VPN/proxy traffic according to your policy
444
+ }
445
+
446
+ // Access geolocation and network details
447
+ console.log(decision.ip.country, decision.ip.city, decision.ip.asn);
448
+ ```
449
+
450
+ ## Custom characteristics
451
+
452
+ Track and limit requests by any stable identifier — user ID, API key, session,
453
+ etc. — rather than IP address alone.
454
+
455
+ ```ts
456
+ const aj = arcjet({
457
+ key: env.ARCJET_KEY!,
458
+ characteristics: ["userId"], // Declare at the SDK level
459
+ rules: [
460
+ tokenBucket({
461
+ mode: "LIVE",
462
+ refillRate: 2_000,
463
+ interval: "1h",
464
+ capacity: 5_000,
465
+ }),
466
+ ],
467
+ });
468
+
469
+ // Pass the characteristic value at request time
470
+ const decision = await aj.protect(req, {
471
+ userId: "user-123", // Replace with your actual user ID
472
+ requested: estimate,
473
+ });
474
+ ```
475
+
476
+ ## Best practices
477
+
478
+ See the [Arcjet best practices][best-practices] for detailed guidance. Key
479
+ recommendations:
480
+
481
+ **Create a single client instance** and reuse it with `withRule()` for
482
+ route-specific rules. The SDK caches decisions and configuration, so creating a
483
+ new instance per request wastes that work.
484
+
485
+ ```ts
486
+ // lib/arcjet.ts — create once, import everywhere
487
+ import arcjet, { shield } from "@arcjet/bun";
488
+ import { env } from "bun";
489
+
490
+ export default arcjet({
491
+ key: env.ARCJET_KEY!,
492
+ rules: [
493
+ shield({ mode: "LIVE" }), // base rules applied to every request
494
+ ],
495
+ });
496
+ ```
497
+
498
+ ```ts
499
+ // routes/chat.ts — extend per-route with withRule()
500
+ import aj from "./lib/arcjet.js";
501
+ import { detectBot, tokenBucket } from "@arcjet/bun";
502
+
503
+ const routeAj = aj.withRule(detectBot({ mode: "LIVE", allow: [] })).withRule(
504
+ tokenBucket({
505
+ mode: "LIVE",
506
+ refillRate: 2_000,
507
+ interval: "1h",
508
+ capacity: 5_000,
509
+ }),
510
+ );
511
+
512
+ export async function handler(req: Request) {
513
+ const decision = await routeAj.protect(req, { requested: 500 });
514
+ // ...
515
+ }
516
+ ```
517
+
518
+ **Other recommendations:**
519
+
520
+ - **Call `protect()` once per request** in the handler where you need it.
521
+ - **Start rules in `DRY_RUN` mode** to observe behavior before switching to
522
+ `LIVE`. This lets you tune thresholds without affecting real traffic.
523
+ - **Configure proxies** if your app runs behind a load balancer or reverse proxy
524
+ so Arcjet resolves the real client IP:
525
+ ```ts
526
+ arcjet({ key: env.ARCJET_KEY!, rules: [], proxies: ["100.100.100.100"] });
527
+ ```
528
+ - **Handle errors explicitly.** `protect()` never throws — on error it returns
529
+ an `ERROR` result. Fail open by logging and allowing the request:
530
+ ```ts
531
+ if (decision.isErrored()) {
532
+ console.error("Arcjet error", decision.reason.message);
533
+ // allow the request to proceed
534
+ }
535
+ ```
108
536
 
109
537
  ## Test
110
538
 
@@ -119,11 +547,12 @@ bun test
119
547
 
120
548
  [Apache License, Version 2.0][apache-license] © [Arcjet Labs, Inc.][arcjet]
121
549
 
122
- [arcjet-get-started]: https://docs.arcjet.com/get-started
123
- [arcjet-reference-bun]: https://docs.arcjet.com/reference/bun
124
550
  [arcjet]: https://arcjet.com
551
+ [arcjet-reference-bun]: https://docs.arcjet.com/reference/bun
125
552
  [bun-sh]: https://bun.sh/
126
- [example-next-source]: https://github.com/arcjet/example-nextjs
127
- [example-next-url]: https://example.arcjet.com
128
- [quick-start]: https://docs.arcjet.com/get-started/bun
129
553
  [apache-license]: http://www.apache.org/licenses/LICENSE-2.0
554
+ [bot-categories-docs]: https://docs.arcjet.com/bot-protection/identifying-bots
555
+ [bot-list]: https://arcjet.com/bot-list
556
+ [signup-protection-docs]: https://docs.arcjet.com/signup-protection
557
+ [filters-docs]: https://docs.arcjet.com/filters
558
+ [best-practices]: https://docs.arcjet.com/best-practices
package/index.js CHANGED
@@ -26,7 +26,7 @@ function createRemoteClient(options) {
26
26
  // Transport is the HTTP client that the client uses to make requests.
27
27
  const transport = createTransport(url);
28
28
  const sdkStack = "BUN";
29
- const sdkVersion = "1.2.0";
29
+ const sdkVersion = "1.3.1";
30
30
  return createClient({
31
31
  transport,
32
32
  baseUrl: url,
package/package.json CHANGED
@@ -1,18 +1,25 @@
1
1
  {
2
2
  "name": "@arcjet/bun",
3
- "version": "1.2.0",
4
- "description": "Arcjet SDK for Bun",
3
+ "version": "1.3.1",
4
+ "description": "Arcjet runtime security SDK for Bun — bot protection, rate limiting, prompt injection detection, PII blocking, and WAF",
5
5
  "keywords": [
6
+ "ai",
6
7
  "analyze",
7
8
  "arcjet",
8
9
  "attack",
9
- "bun.sh",
10
+ "bot-detection",
10
11
  "bun",
12
+ "bun.sh",
11
13
  "limit",
14
+ "llm",
15
+ "pii",
16
+ "prompt-injection",
12
17
  "protect",
18
+ "rate-limiting",
13
19
  "secure",
14
20
  "security",
15
- "verify"
21
+ "verify",
22
+ "waf"
16
23
  ],
17
24
  "license": "Apache-2.0",
18
25
  "homepage": "https://arcjet.com",
@@ -44,23 +51,23 @@
44
51
  "test": "npm run build && npm run lint"
45
52
  },
46
53
  "dependencies": {
47
- "@arcjet/body": "1.2.0",
48
- "@arcjet/env": "1.2.0",
49
- "@arcjet/headers": "1.2.0",
50
- "@arcjet/ip": "1.2.0",
51
- "@arcjet/logger": "1.2.0",
52
- "@arcjet/protocol": "1.2.0",
53
- "@arcjet/transport": "1.2.0",
54
- "arcjet": "1.2.0"
54
+ "@arcjet/body": "1.3.1",
55
+ "@arcjet/env": "1.3.1",
56
+ "@arcjet/headers": "1.3.1",
57
+ "@arcjet/ip": "1.3.1",
58
+ "@arcjet/logger": "1.3.1",
59
+ "@arcjet/protocol": "1.3.1",
60
+ "@arcjet/transport": "1.3.1",
61
+ "arcjet": "1.3.1"
55
62
  },
56
63
  "devDependencies": {
57
- "@arcjet/eslint-config": "1.2.0",
58
- "@arcjet/rollup-config": "1.2.0",
59
- "@rollup/wasm-node": "4.57.1",
60
- "bun-types": "1.3.8",
61
- "eslint": "9.39.2",
64
+ "@arcjet/eslint-config": "1.3.1",
65
+ "@arcjet/rollup-config": "1.3.1",
66
+ "@rollup/wasm-node": "4.59.0",
67
+ "bun-types": "1.3.10",
68
+ "eslint": "9.39.3",
62
69
  "typescript": "5.9.3",
63
- "undici-types": "7.19.2"
70
+ "undici-types": "7.22.0"
64
71
  },
65
72
  "publishConfig": {
66
73
  "access": "public",