@arcjet/bun 1.3.0 → 1.4.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.
Files changed (3) hide show
  1. package/README.md +485 -57
  2. package/index.js +1 -1
  3. package/package.json +25 -18
package/README.md CHANGED
@@ -16,95 +16,522 @@
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.
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
+ }),
148
+ ],
149
+ });
62
150
 
63
- This package is ESM only.
64
- Install with Bun:
151
+ export default {
152
+ fetch: aj.handler(async (req) => {
153
+ const { message } = await req.json();
154
+
155
+ const decision = await aj.protect(req, {
156
+ detectPromptInjectionMessage: message,
157
+ });
158
+
159
+ if (decision.isDenied() && decision.reason.isPromptInjection()) {
160
+ return new Response(
161
+ "Prompt injection detected — please rephrase your message",
162
+ { status: 400 },
163
+ );
164
+ }
65
165
 
66
- ```sh
67
- bun add @arcjet/bun
166
+ // Forward to your AI model...
167
+ return new Response("OK");
168
+ }),
169
+ };
68
170
  ```
69
171
 
70
- ## Use
172
+ ## Bot protection
71
173
 
72
- ```ts
73
- import arcjet, { shield } from "@arcjet/bun";
174
+ Arcjet allows you to configure a list of bots to allow or deny. Specifying
175
+ `allow` means all other bots are denied. An empty allow list blocks all bots.
74
176
 
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;
177
+ Available categories: `CATEGORY:ACADEMIC`, `CATEGORY:ADVERTISING`,
178
+ `CATEGORY:AI`, `CATEGORY:AMAZON`, `CATEGORY:APPLE`, `CATEGORY:ARCHIVE`,
179
+ `CATEGORY:BOTNET`, `CATEGORY:FEEDFETCHER`, `CATEGORY:GOOGLE`,
180
+ `CATEGORY:META`, `CATEGORY:MICROSOFT`, `CATEGORY:MONITOR`,
181
+ `CATEGORY:OPTIMIZER`, `CATEGORY:PREVIEW`, `CATEGORY:PROGRAMMATIC`,
182
+ `CATEGORY:SEARCH_ENGINE`, `CATEGORY:SLACK`, `CATEGORY:SOCIAL`,
183
+ `CATEGORY:TOOL`, `CATEGORY:UNKNOWN`, `CATEGORY:VERCEL`,
184
+ `CATEGORY:WEBHOOK`, `CATEGORY:YAHOO`. You can also allow or deny
185
+ [specific bots by name][bot-list].
78
186
 
79
- if (!arcjetKey) {
80
- throw new Error("Cannot find `ARCJET_KEY` environment variable");
81
- }
187
+ ```ts
188
+ import arcjet, { detectBot } from "@arcjet/bun";
189
+ import { isSpoofedBot } from "@arcjet/inspect";
190
+ import { env } from "bun";
82
191
 
83
192
  const aj = arcjet({
84
- key: arcjetKey,
193
+ key: env.ARCJET_KEY!,
85
194
  rules: [
86
- // Shield protects your app from common attacks.
87
- // Use `DRY_RUN` instead of `LIVE` to only log.
88
- shield({ mode: "LIVE" }),
195
+ detectBot({
196
+ mode: "LIVE",
197
+ allow: [
198
+ "CATEGORY:SEARCH_ENGINE",
199
+ // See the full list at https://arcjet.com/bot-list
200
+ ],
201
+ }),
89
202
  ],
90
203
  });
91
204
 
92
205
  export default {
93
- port: 8000,
94
- fetch: aj.handler(async function (request: Request) {
95
- const decision = await aj.protect(request);
206
+ fetch: aj.handler(async (req) => {
207
+ const decision = await aj.protect(req);
96
208
 
97
- if (decision.isDenied()) {
98
- return Response.json({ message: "Forbidden" }, { status: 403 });
209
+ if (decision.isDenied() && decision.reason.isBot()) {
210
+ return new Response("No bots allowed", { status: 403 });
211
+ }
212
+
213
+ // Verifies the authenticity of common bots using IP data.
214
+ if (decision.results.some(isSpoofedBot)) {
215
+ return new Response("Forbidden", { status: 403 });
99
216
  }
100
217
 
101
- return Response.json({ message: "Hello world" });
218
+ return new Response("Hello world");
102
219
  }),
103
220
  };
104
221
  ```
105
222
 
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.
223
+ ### Bot categories
224
+
225
+ Bots can be configured by [category][bot-categories-docs] and/or by [specific
226
+ bot name][bot-list]. For example, to allow search engines and the OpenAI
227
+ crawler, but deny all other bots:
228
+
229
+ ```ts
230
+ detectBot({
231
+ mode: "LIVE",
232
+ allow: ["CATEGORY:SEARCH_ENGINE", "OPENAI_CRAWLER_SEARCH"],
233
+ });
234
+ ```
235
+
236
+ ### Verified vs spoofed bots
237
+
238
+ Bots claiming to be well-known crawlers (e.g. Googlebot) are verified by
239
+ checking their IP address against known IP ranges. If a bot fails verification,
240
+ it is labeled as spoofed. Use `isSpoofedBot` from `@arcjet/inspect` to check:
241
+
242
+ ```ts
243
+ import { isSpoofedBot } from "@arcjet/inspect";
244
+
245
+ if (decision.results.some(isSpoofedBot)) {
246
+ return new Response("Forbidden", { status: 403 });
247
+ }
248
+ ```
249
+
250
+ ## Rate limiting
251
+
252
+ Arcjet supports token bucket, fixed window, and sliding window algorithms.
253
+ Token buckets are ideal for controlling AI token budgets — set `capacity` to
254
+ the max tokens a user can spend, `refillRate` to how many tokens are restored
255
+ per `interval`, and deduct tokens per request via `requested` in `protect()`.
256
+ The `interval` accepts strings (`"1s"`, `"1m"`, `"1h"`, `"1d"`) or seconds as
257
+ a number. Use `characteristics` to track limits per user instead of per IP.
258
+
259
+ ```ts
260
+ import arcjet, { tokenBucket } from "@arcjet/bun";
261
+ import { env } from "bun";
262
+
263
+ const aj = arcjet({
264
+ key: env.ARCJET_KEY!,
265
+ characteristics: ["userId"], // Track per user
266
+ rules: [
267
+ tokenBucket({
268
+ mode: "LIVE",
269
+ refillRate: 2_000, // Refill 2,000 tokens per hour
270
+ interval: "1h",
271
+ capacity: 5_000, // Maximum 5,000 tokens in the bucket
272
+ }),
273
+ ],
274
+ });
275
+
276
+ const decision = await aj.protect(req, {
277
+ userId: "user-123",
278
+ requested: estimate, // Number of tokens to deduct
279
+ });
280
+
281
+ if (decision.isDenied() && decision.reason.isRateLimit()) {
282
+ return new Response("Rate limit exceeded", { status: 429 });
283
+ }
284
+ ```
285
+
286
+ ## Sensitive information detection
287
+
288
+ Detect and block PII in request content. Pass the content to scan via
289
+ `sensitiveInfoValue` on each `protect()` call. Built-in entity types:
290
+ `CREDIT_CARD_NUMBER`, `EMAIL`, `PHONE_NUMBER`, `IP_ADDRESS`. You can also
291
+ provide a custom `detect` callback for additional patterns.
292
+
293
+ ```ts
294
+ import arcjet, { sensitiveInfo } from "@arcjet/bun";
295
+ import { env } from "bun";
296
+
297
+ const aj = arcjet({
298
+ key: env.ARCJET_KEY!,
299
+ rules: [
300
+ sensitiveInfo({
301
+ mode: "LIVE", // Blocks requests. Use "DRY_RUN" to log only
302
+ deny: ["CREDIT_CARD_NUMBER", "EMAIL", "PHONE_NUMBER"],
303
+ }),
304
+ ],
305
+ });
306
+
307
+ const decision = await aj.protect(req, {
308
+ sensitiveInfoValue: userMessage, // The text content to scan
309
+ });
310
+
311
+ if (decision.isDenied() && decision.reason.isSensitiveInfo()) {
312
+ return new Response("Sensitive information detected", { status: 400 });
313
+ }
314
+ ```
315
+
316
+ ## Shield WAF
317
+
318
+ Protect your application against common web attacks, including the OWASP
319
+ Top 10.
320
+
321
+ ```ts
322
+ import arcjet, { shield } from "@arcjet/bun";
323
+ import { env } from "bun";
324
+
325
+ const aj = arcjet({
326
+ key: env.ARCJET_KEY!,
327
+ rules: [
328
+ shield({
329
+ mode: "LIVE", // Blocks requests. Use "DRY_RUN" to log only
330
+ }),
331
+ ],
332
+ });
333
+ ```
334
+
335
+ ## Email validation
336
+
337
+ Validate and verify email addresses. Deny types: `DISPOSABLE`, `FREE`,
338
+ `NO_MX_RECORDS`, `NO_GRAVATAR`, `INVALID`.
339
+
340
+ ```ts
341
+ import arcjet, { validateEmail } from "@arcjet/bun";
342
+ import { env } from "bun";
343
+
344
+ const aj = arcjet({
345
+ key: env.ARCJET_KEY!,
346
+ rules: [
347
+ validateEmail({
348
+ mode: "LIVE",
349
+ deny: ["DISPOSABLE", "INVALID", "NO_MX_RECORDS"],
350
+ }),
351
+ ],
352
+ });
353
+
354
+ const decision = await aj.protect(req, {
355
+ email: "user@example.com",
356
+ });
357
+
358
+ if (decision.isDenied() && decision.reason.isEmail()) {
359
+ return new Response("Invalid email address", { status: 400 });
360
+ }
361
+ ```
362
+
363
+ ## Request filters
364
+
365
+ Filter requests using expression-based rules against request properties (IP,
366
+ headers, path, method, etc.).
367
+
368
+ ```ts
369
+ import arcjet, { filter } from "@arcjet/bun";
370
+ import { env } from "bun";
371
+
372
+ const aj = arcjet({
373
+ key: env.ARCJET_KEY!,
374
+ rules: [
375
+ filter({
376
+ mode: "LIVE",
377
+ deny: ['ip.src == "1.2.3.4"'],
378
+ }),
379
+ ],
380
+ });
381
+ ```
382
+
383
+ ### Block by country
384
+
385
+ Restrict access to specific countries — useful for licensing, compliance, or
386
+ regional rollouts. The `allow` list denies all countries not listed:
387
+
388
+ ```ts
389
+ filter({
390
+ mode: "LIVE",
391
+ // Allow only US traffic — all other countries are denied
392
+ allow: ['ip.src.country == "US"'],
393
+ });
394
+ ```
395
+
396
+ ### Block VPN and proxy traffic
397
+
398
+ Prevent anonymized traffic from accessing sensitive endpoints — useful for
399
+ fraud prevention, enforcing geo-restrictions, and reducing abuse:
400
+
401
+ ```ts
402
+ filter({
403
+ mode: "LIVE",
404
+ deny: [
405
+ "ip.src.vpn", // VPN services
406
+ "ip.src.proxy", // Open proxies
407
+ "ip.src.tor", // Tor exit nodes
408
+ ],
409
+ });
410
+ ```
411
+
412
+ For more nuanced handling, use `decision.ip` helpers after calling `protect()`:
413
+
414
+ ```ts
415
+ const decision = await aj.protect(req);
416
+
417
+ if (decision.ip.isVpn() || decision.ip.isTor()) {
418
+ return new Response("VPN traffic not allowed", { status: 403 });
419
+ }
420
+ ```
421
+
422
+ See the [Request Filters docs][filters-docs],
423
+ [IP Geolocation blueprint](https://docs.arcjet.com/blueprints/ip-geolocation), and
424
+ [VPN/Proxy Detection blueprint](https://docs.arcjet.com/blueprints/vpn-proxy-detection)
425
+ for more details.
426
+
427
+ ## IP analysis
428
+
429
+ Arcjet enriches every request with IP metadata. Use these helpers to make
430
+ policy decisions based on network signals:
431
+
432
+ ```ts
433
+ const decision = await aj.protect(req);
434
+
435
+ if (decision.ip.isHosting()) {
436
+ // Requests from cloud/hosting providers are often automated.
437
+ // https://docs.arcjet.com/blueprints/vpn-proxy-detection
438
+ return new Response("Forbidden", { status: 403 });
439
+ }
440
+
441
+ if (decision.ip.isVpn() || decision.ip.isProxy() || decision.ip.isTor()) {
442
+ // Handle VPN/proxy traffic according to your policy
443
+ }
444
+
445
+ // Access geolocation and network details
446
+ console.log(decision.ip.country, decision.ip.city, decision.ip.asn);
447
+ ```
448
+
449
+ ## Custom characteristics
450
+
451
+ Track and limit requests by any stable identifier — user ID, API key, session,
452
+ etc. — rather than IP address alone.
453
+
454
+ ```ts
455
+ const aj = arcjet({
456
+ key: env.ARCJET_KEY!,
457
+ characteristics: ["userId"], // Declare at the SDK level
458
+ rules: [
459
+ tokenBucket({
460
+ mode: "LIVE",
461
+ refillRate: 2_000,
462
+ interval: "1h",
463
+ capacity: 5_000,
464
+ }),
465
+ ],
466
+ });
467
+
468
+ // Pass the characteristic value at request time
469
+ const decision = await aj.protect(req, {
470
+ userId: "user-123", // Replace with your actual user ID
471
+ requested: estimate,
472
+ });
473
+ ```
474
+
475
+ ## Best practices
476
+
477
+ See the [Arcjet best practices][best-practices] for detailed guidance. Key
478
+ recommendations:
479
+
480
+ **Create a single client instance** and reuse it with `withRule()` for
481
+ route-specific rules. The SDK caches decisions and configuration, so creating a
482
+ new instance per request wastes that work.
483
+
484
+ ```ts
485
+ // lib/arcjet.ts — create once, import everywhere
486
+ import arcjet, { shield } from "@arcjet/bun";
487
+ import { env } from "bun";
488
+
489
+ export default arcjet({
490
+ key: env.ARCJET_KEY!,
491
+ rules: [
492
+ shield({ mode: "LIVE" }), // base rules applied to every request
493
+ ],
494
+ });
495
+ ```
496
+
497
+ ```ts
498
+ // routes/chat.ts — extend per-route with withRule()
499
+ import aj from "./lib/arcjet.js";
500
+ import { detectBot, tokenBucket } from "@arcjet/bun";
501
+
502
+ const routeAj = aj.withRule(detectBot({ mode: "LIVE", allow: [] })).withRule(
503
+ tokenBucket({
504
+ mode: "LIVE",
505
+ refillRate: 2_000,
506
+ interval: "1h",
507
+ capacity: 5_000,
508
+ }),
509
+ );
510
+
511
+ export async function handler(req: Request) {
512
+ const decision = await routeAj.protect(req, { requested: 500 });
513
+ // ...
514
+ }
515
+ ```
516
+
517
+ **Other recommendations:**
518
+
519
+ - **Call `protect()` once per request** in the handler where you need it.
520
+ - **Start rules in `DRY_RUN` mode** to observe behavior before switching to
521
+ `LIVE`. This lets you tune thresholds without affecting real traffic.
522
+ - **Configure proxies** if your app runs behind a load balancer or reverse proxy
523
+ so Arcjet resolves the real client IP:
524
+ ```ts
525
+ arcjet({ key: env.ARCJET_KEY!, rules: [], proxies: ["100.100.100.100"] });
526
+ ```
527
+ - **Handle errors explicitly.** `protect()` never throws — on error it returns
528
+ an `ERROR` result. Fail open by logging and allowing the request:
529
+ ```ts
530
+ if (decision.isErrored()) {
531
+ console.error("Arcjet error", decision.reason.message);
532
+ // allow the request to proceed
533
+ }
534
+ ```
108
535
 
109
536
  ## Test
110
537
 
@@ -119,11 +546,12 @@ bun test
119
546
 
120
547
  [Apache License, Version 2.0][apache-license] © [Arcjet Labs, Inc.][arcjet]
121
548
 
122
- [arcjet-get-started]: https://docs.arcjet.com/get-started
123
- [arcjet-reference-bun]: https://docs.arcjet.com/reference/bun
124
549
  [arcjet]: https://arcjet.com
550
+ [arcjet-reference-bun]: https://docs.arcjet.com/reference/bun
125
551
  [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
552
  [apache-license]: http://www.apache.org/licenses/LICENSE-2.0
553
+ [bot-categories-docs]: https://docs.arcjet.com/bot-protection/identifying-bots
554
+ [bot-list]: https://arcjet.com/bot-list
555
+ [signup-protection-docs]: https://docs.arcjet.com/signup-protection
556
+ [filters-docs]: https://docs.arcjet.com/filters
557
+ [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.3.0";
29
+ const sdkVersion = "1.4.0";
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.3.0",
4
- "description": "Arcjet SDK for Bun",
3
+ "version": "1.4.0",
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.3.0",
48
- "@arcjet/env": "1.3.0",
49
- "@arcjet/headers": "1.3.0",
50
- "@arcjet/ip": "1.3.0",
51
- "@arcjet/logger": "1.3.0",
52
- "@arcjet/protocol": "1.3.0",
53
- "@arcjet/transport": "1.3.0",
54
- "arcjet": "1.3.0"
54
+ "@arcjet/body": "1.4.0",
55
+ "@arcjet/env": "1.4.0",
56
+ "@arcjet/headers": "1.4.0",
57
+ "@arcjet/ip": "1.4.0",
58
+ "@arcjet/logger": "1.4.0",
59
+ "@arcjet/protocol": "1.4.0",
60
+ "@arcjet/transport": "1.4.0",
61
+ "arcjet": "1.4.0"
55
62
  },
56
63
  "devDependencies": {
57
- "@arcjet/eslint-config": "1.3.0",
58
- "@arcjet/rollup-config": "1.3.0",
59
- "@rollup/wasm-node": "4.57.1",
60
- "bun-types": "1.3.8",
61
- "eslint": "9.39.2",
64
+ "@arcjet/eslint-config": "1.4.0",
65
+ "@arcjet/rollup-config": "1.4.0",
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",