@arcjet/bun 1.0.0-alpha.13 → 1.0.0-alpha.14

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
@@ -1,7 +1,7 @@
1
1
  <a href="https://arcjet.com" target="_arcjet-home">
2
2
  <picture>
3
- <source media="(prefers-color-scheme: dark)" srcset="https://arcjet.com/arcjet-logo-dark-planet-arrival.svg">
4
- <img src="https://arcjet.com/arcjet-logo-light-planet-arrival.svg" alt="Arcjet Logo" height="144" width="auto">
3
+ <source media="(prefers-color-scheme: dark)" srcset="https://arcjet.com/logo/arcjet-dark-lockup-voyage-horizontal.svg">
4
+ <img src="https://arcjet.com/logo/arcjet-light-lockup-voyage-horizontal.svg" alt="Arcjet Logo" height="128" width="auto">
5
5
  </picture>
6
6
  </a>
7
7
 
@@ -17,11 +17,20 @@
17
17
  </p>
18
18
 
19
19
  [Arcjet][arcjet] helps developers protect their apps in just a few lines of
20
- code. Implement rate limiting, bot protection, email verification & defense
20
+ code. Implement rate limiting, bot protection, email verification, and defense
21
21
  against common attacks.
22
22
 
23
23
  This is the [Arcjet][arcjet] SDK for [Bun.sh][bun-sh].
24
24
 
25
+ ## Getting started
26
+
27
+ Visit the [quick start guide][quick-start] to get started.
28
+
29
+ ## Example app
30
+
31
+ Try an Arcjet protected app live at [https://example.arcjet.com][example-url]
32
+ ([source code][example-source]).
33
+
25
34
  ## Installation
26
35
 
27
36
  ```shell
@@ -75,8 +84,8 @@ export default {
75
84
  ## Shield example
76
85
 
77
86
  [Arcjet Shield][shield-concepts-docs] protects your application against common
78
- attacks, including the OWASP Top 10. It’s enabled by default and runs on every
79
- request with negligible performance impact.
87
+ attacks, including the OWASP Top 10. You can run Shield on every request with
88
+ negligible performance impact.
80
89
 
81
90
  ```ts
82
91
  import arcjet, { shield } from "@arcjet/bun";
@@ -110,6 +119,9 @@ Licensed under the [Apache License, Version 2.0][apache-license].
110
119
 
111
120
  [arcjet]: https://arcjet.com
112
121
  [bun-sh]: https://bun.sh/
122
+ [example-url]: https://example.arcjet.com
123
+ [quick-start]: https://docs.arcjet.com/get-started/bun
124
+ [example-source]: https://github.com/arcjet/arcjet-js-example
113
125
  [rate-limit-concepts-docs]: https://docs.arcjet.com/rate-limiting/concepts
114
126
  [shield-concepts-docs]: https://docs.arcjet.com/shield/concepts
115
127
  [apache-license]: http://www.apache.org/licenses/LICENSE-2.0
package/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  /// <reference types="bun-types/bun.d.ts" />
2
- import { ArcjetDecision, ArcjetOptions, Primitive, Product, Runtime, ExtraProps, RemoteClient, RemoteClientOptions } from "arcjet";
2
+ import { ArcjetDecision, ArcjetOptions, Primitive, Product, ExtraProps, RemoteClient, RemoteClientOptions } from "arcjet";
3
3
  import type { Server } from "bun";
4
4
  export * from "arcjet";
5
5
  type Simplify<T> = {
@@ -12,13 +12,12 @@ type WithoutCustomProps = {
12
12
  type PlainObject = {
13
13
  [key: string]: unknown;
14
14
  };
15
- export declare function createBunRemoteClient(options?: RemoteClientOptions): RemoteClient;
15
+ export declare function createBunRemoteClient(options?: Partial<RemoteClientOptions>): RemoteClient;
16
16
  /**
17
17
  * The ArcjetBun client provides a public `protect()` method to
18
18
  * make a decision about how a Bun.sh request should be handled.
19
19
  */
20
20
  export interface ArcjetBun<Props extends PlainObject> {
21
- get runtime(): Runtime;
22
21
  /**
23
22
  * Runs a request through the configured protections. The request is
24
23
  * analyzed and then a decision made on whether to allow, deny, or challenge
package/index.js CHANGED
@@ -1,23 +1,36 @@
1
1
  import { createConnectTransport } from '@connectrpc/connect-node';
2
- import core__default, { defaultBaseUrl, createRemoteClient, ArcjetHeaders } from 'arcjet';
2
+ import core__default, { createRemoteClient } from 'arcjet';
3
3
  export * from 'arcjet';
4
4
  import findIP from '@arcjet/ip';
5
+ import ArcjetHeaders from '@arcjet/headers';
6
+ import { env } from 'bun';
7
+ import { logLevel, baseUrl, isProduction, platform, isDevelopment } from '@arcjet/env';
8
+ import { Logger } from '@arcjet/logger';
5
9
 
6
10
  /// <reference types="bun-types/bun.d.ts" />
7
11
  function createBunRemoteClient(options) {
8
12
  // The base URL for the Arcjet API. Will default to the standard production
9
13
  // API unless environment variable `ARCJET_BASE_URL` is set.
10
- const baseUrl = options?.baseUrl ?? defaultBaseUrl();
14
+ const url = options?.baseUrl ?? baseUrl(env);
15
+ // The timeout for the Arcjet API in milliseconds. This is set to a low value
16
+ // in production so calls fail open.
17
+ const timeout = options?.timeout ?? (isProduction(env) ? 500 : 1000);
11
18
  // Transport is the HTTP client that the client uses to make requests.
12
19
  const transport = options?.transport ??
13
20
  createConnectTransport({
14
- baseUrl,
21
+ baseUrl: url,
15
22
  httpVersion: "1.1",
16
23
  });
17
- // TODO(#223): Do we want to allow overrides to either of these? If not, we should probably define a separate type for `options`
24
+ // TODO(#223): Create separate options type to exclude these
18
25
  const sdkStack = "BUN";
19
- const sdkVersion = "1.0.0-alpha.13";
20
- return createRemoteClient({ ...options, transport, sdkStack, sdkVersion });
26
+ const sdkVersion = "1.0.0-alpha.14";
27
+ return createRemoteClient({
28
+ transport,
29
+ baseUrl: url,
30
+ timeout,
31
+ sdkStack,
32
+ sdkVersion,
33
+ });
21
34
  }
22
35
  // This is provided with an `ipCache` where it attempts to lookup the IP. This
23
36
  // is primarily a workaround to the API design in Bun that requires access to
@@ -27,9 +40,18 @@ function toArcjetRequest(ipCache, request, props) {
27
40
  // We construct an ArcjetHeaders to normalize over Headers
28
41
  const headers = new ArcjetHeaders(request.headers);
29
42
  const url = new URL(request.url);
30
- const ip = findIP({
43
+ let ip = findIP({
31
44
  ip: ipCache.get(request),
32
- }, headers);
45
+ }, headers, { platform: platform(env) });
46
+ if (ip === "") {
47
+ // If the `ip` is empty but we're in development mode, we default the IP
48
+ // so the request doesn't fail.
49
+ if (isDevelopment(env)) {
50
+ // TODO: Log that the fingerprint is being overridden once the adapter
51
+ // constructs the logger
52
+ ip = "127.0.0.1";
53
+ }
54
+ }
33
55
  return {
34
56
  ...props,
35
57
  ip,
@@ -48,9 +70,6 @@ function withClient(aj) {
48
70
  // `server.requestIP()`
49
71
  const ipCache = new WeakMap();
50
72
  return Object.freeze({
51
- get runtime() {
52
- return aj.runtime;
53
- },
54
73
  withRule(rule) {
55
74
  const client = aj.withRule(rule);
56
75
  return withClient(client);
@@ -60,7 +79,7 @@ function withClient(aj) {
60
79
  // Further investigation makes it seem like it has something to do with
61
80
  // the definition of `props` in the signature but it's hard to track down
62
81
  const req = toArcjetRequest(ipCache, request, props ?? {});
63
- return aj.protect(req);
82
+ return aj.protect({}, req);
64
83
  },
65
84
  handler(fetch) {
66
85
  return async function (request, server) {
@@ -83,7 +102,12 @@ function withClient(aj) {
83
102
  */
84
103
  function arcjet(options) {
85
104
  const client = options.client ?? createBunRemoteClient();
86
- const aj = core__default({ ...options, client });
105
+ const log = options.log
106
+ ? options.log
107
+ : new Logger({
108
+ level: logLevel(env),
109
+ });
110
+ const aj = core__default({ ...options, client, log });
87
111
  return withClient(aj);
88
112
  }
89
113
 
package/index.ts CHANGED
@@ -5,18 +5,25 @@ import core, {
5
5
  ArcjetOptions,
6
6
  Primitive,
7
7
  Product,
8
- ArcjetHeaders,
9
- Runtime,
10
8
  ArcjetRequest,
11
9
  ExtraProps,
12
10
  RemoteClient,
13
11
  RemoteClientOptions,
14
- defaultBaseUrl,
15
12
  createRemoteClient,
16
13
  Arcjet,
17
14
  } from "arcjet";
18
15
  import findIP from "@arcjet/ip";
16
+ import ArcjetHeaders from "@arcjet/headers";
19
17
  import type { Server } from "bun";
18
+ import { env } from "bun";
19
+ import {
20
+ baseUrl,
21
+ isDevelopment,
22
+ isProduction,
23
+ logLevel,
24
+ platform,
25
+ } from "@arcjet/env";
26
+ import { Logger } from "@arcjet/logger";
20
27
 
21
28
  // Re-export all named exports from the generic SDK
22
29
  export * from "arcjet";
@@ -59,25 +66,35 @@ type PlainObject = {
59
66
  };
60
67
 
61
68
  export function createBunRemoteClient(
62
- options?: RemoteClientOptions,
69
+ options?: Partial<RemoteClientOptions>,
63
70
  ): RemoteClient {
64
71
  // The base URL for the Arcjet API. Will default to the standard production
65
72
  // API unless environment variable `ARCJET_BASE_URL` is set.
66
- const baseUrl = options?.baseUrl ?? defaultBaseUrl();
73
+ const url = options?.baseUrl ?? baseUrl(env);
74
+
75
+ // The timeout for the Arcjet API in milliseconds. This is set to a low value
76
+ // in production so calls fail open.
77
+ const timeout = options?.timeout ?? (isProduction(env) ? 500 : 1000);
67
78
 
68
79
  // Transport is the HTTP client that the client uses to make requests.
69
80
  const transport =
70
81
  options?.transport ??
71
82
  createConnectTransport({
72
- baseUrl,
83
+ baseUrl: url,
73
84
  httpVersion: "1.1",
74
85
  });
75
86
 
76
- // TODO(#223): Do we want to allow overrides to either of these? If not, we should probably define a separate type for `options`
87
+ // TODO(#223): Create separate options type to exclude these
77
88
  const sdkStack = "BUN";
78
89
  const sdkVersion = "__ARCJET_SDK_VERSION__";
79
90
 
80
- return createRemoteClient({ ...options, transport, sdkStack, sdkVersion });
91
+ return createRemoteClient({
92
+ transport,
93
+ baseUrl: url,
94
+ timeout,
95
+ sdkStack,
96
+ sdkVersion,
97
+ });
81
98
  }
82
99
 
83
100
  /**
@@ -85,7 +102,6 @@ export function createBunRemoteClient(
85
102
  * make a decision about how a Bun.sh request should be handled.
86
103
  */
87
104
  export interface ArcjetBun<Props extends PlainObject> {
88
- get runtime(): Runtime;
89
105
  /**
90
106
  * Runs a request through the configured protections. The request is
91
107
  * analyzed and then a decision made on whether to allow, deny, or challenge
@@ -146,12 +162,22 @@ function toArcjetRequest<Props extends PlainObject>(
146
162
  const headers = new ArcjetHeaders(request.headers);
147
163
 
148
164
  const url = new URL(request.url);
149
- const ip = findIP(
165
+ let ip = findIP(
150
166
  {
151
167
  ip: ipCache.get(request),
152
168
  },
153
169
  headers,
170
+ { platform: platform(env) },
154
171
  );
172
+ if (ip === "") {
173
+ // If the `ip` is empty but we're in development mode, we default the IP
174
+ // so the request doesn't fail.
175
+ if (isDevelopment(env)) {
176
+ // TODO: Log that the fingerprint is being overridden once the adapter
177
+ // constructs the logger
178
+ ip = "127.0.0.1";
179
+ }
180
+ }
155
181
 
156
182
  return {
157
183
  ...props,
@@ -175,9 +201,6 @@ function withClient<const Rules extends (Primitive | Product)[]>(
175
201
  const ipCache = new WeakMap<Request, string>();
176
202
 
177
203
  return Object.freeze({
178
- get runtime() {
179
- return aj.runtime;
180
- },
181
204
  withRule(rule: Primitive | Product) {
182
205
  const client = aj.withRule(rule);
183
206
  return withClient(client);
@@ -197,7 +220,7 @@ function withClient<const Rules extends (Primitive | Product)[]>(
197
220
  props ?? {},
198
221
  ) as ArcjetRequest<ExtraProps<Rules>>;
199
222
 
200
- return aj.protect(req);
223
+ return aj.protect({}, req);
201
224
  },
202
225
  handler(
203
226
  fetch: (
@@ -234,7 +257,13 @@ export default function arcjet<const Rules extends (Primitive | Product)[]>(
234
257
  ): ArcjetBun<Simplify<ExtraProps<Rules>>> {
235
258
  const client = options.client ?? createBunRemoteClient();
236
259
 
237
- const aj = core({ ...options, client });
260
+ const log = options.log
261
+ ? options.log
262
+ : new Logger({
263
+ level: logLevel(env),
264
+ });
265
+
266
+ const aj = core({ ...options, client, log });
238
267
 
239
268
  return withClient(aj);
240
269
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@arcjet/bun",
3
- "version": "1.0.0-alpha.13",
3
+ "version": "1.0.0-alpha.14",
4
4
  "description": "Arcjet SDK for Bun.sh",
5
5
  "license": "Apache-2.0",
6
6
  "homepage": "https://arcjet.com",
@@ -38,18 +38,21 @@
38
38
  "test": "NODE_OPTIONS=--experimental-vm-modules jest --passWithNoTests"
39
39
  },
40
40
  "dependencies": {
41
- "@arcjet/ip": "1.0.0-alpha.13",
41
+ "@arcjet/env": "1.0.0-alpha.14",
42
+ "@arcjet/headers": "1.0.0-alpha.14",
43
+ "@arcjet/ip": "1.0.0-alpha.14",
44
+ "@arcjet/logger": "1.0.0-alpha.14",
42
45
  "@connectrpc/connect-node": "1.4.0",
43
- "arcjet": "1.0.0-alpha.13"
46
+ "arcjet": "1.0.0-alpha.14"
44
47
  },
45
48
  "devDependencies": {
46
- "@arcjet/eslint-config": "1.0.0-alpha.13",
47
- "@arcjet/rollup-config": "1.0.0-alpha.13",
48
- "@arcjet/tsconfig": "1.0.0-alpha.13",
49
+ "@arcjet/eslint-config": "1.0.0-alpha.14",
50
+ "@arcjet/rollup-config": "1.0.0-alpha.14",
51
+ "@arcjet/tsconfig": "1.0.0-alpha.14",
49
52
  "@jest/globals": "29.7.0",
50
53
  "@types/node": "20.12.12",
51
- "@rollup/wasm-node": "4.17.2",
52
- "bun-types": "1.1.8",
54
+ "@rollup/wasm-node": "4.18.0",
55
+ "bun-types": "1.1.12",
53
56
  "jest": "29.7.0",
54
57
  "typescript": "5.4.5"
55
58
  },