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

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 } from "arcjet";
3
3
  import type { Server } from "bun";
4
4
  export * from "arcjet";
5
5
  type Simplify<T> = {
@@ -12,13 +12,16 @@ type WithoutCustomProps = {
12
12
  type PlainObject = {
13
13
  [key: string]: unknown;
14
14
  };
15
- export declare function createBunRemoteClient(options?: RemoteClientOptions): RemoteClient;
15
+ export type RemoteClientOptions = {
16
+ baseUrl?: string;
17
+ timeout?: number;
18
+ };
19
+ export declare function createRemoteClient(options?: RemoteClientOptions): import("@arcjet/protocol/client.js").Client;
16
20
  /**
17
21
  * The ArcjetBun client provides a public `protect()` method to
18
22
  * make a decision about how a Bun.sh request should be handled.
19
23
  */
20
24
  export interface ArcjetBun<Props extends PlainObject> {
21
- get runtime(): Runtime;
22
25
  /**
23
26
  * Runs a request through the configured protections. The request is
24
27
  * analyzed and then a decision made on whether to allow, deny, or challenge
package/index.js CHANGED
@@ -1,23 +1,35 @@
1
1
  import { createConnectTransport } from '@connectrpc/connect-node';
2
- import core__default, { defaultBaseUrl, createRemoteClient, ArcjetHeaders } from 'arcjet';
2
+ import core__default 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';
9
+ import { createClient } from '@arcjet/protocol/client.js';
5
10
 
6
11
  /// <reference types="bun-types/bun.d.ts" />
7
- function createBunRemoteClient(options) {
12
+ function createRemoteClient(options) {
8
13
  // The base URL for the Arcjet API. Will default to the standard production
9
14
  // API unless environment variable `ARCJET_BASE_URL` is set.
10
- const baseUrl = options?.baseUrl ?? defaultBaseUrl();
15
+ const url = options?.baseUrl ?? baseUrl(env);
16
+ // The timeout for the Arcjet API in milliseconds. This is set to a low value
17
+ // in production so calls fail open.
18
+ const timeout = options?.timeout ?? (isProduction(env) ? 500 : 1000);
11
19
  // Transport is the HTTP client that the client uses to make requests.
12
- const transport = options?.transport ??
13
- createConnectTransport({
14
- baseUrl,
15
- httpVersion: "1.1",
16
- });
17
- // TODO(#223): Do we want to allow overrides to either of these? If not, we should probably define a separate type for `options`
20
+ const transport = createConnectTransport({
21
+ baseUrl: url,
22
+ httpVersion: "1.1",
23
+ });
18
24
  const sdkStack = "BUN";
19
- const sdkVersion = "1.0.0-alpha.13";
20
- return createRemoteClient({ ...options, transport, sdkStack, sdkVersion });
25
+ const sdkVersion = "1.0.0-alpha.15";
26
+ return createClient({
27
+ transport,
28
+ baseUrl: url,
29
+ timeout,
30
+ sdkStack,
31
+ sdkVersion,
32
+ });
21
33
  }
22
34
  // This is provided with an `ipCache` where it attempts to lookup the IP. This
23
35
  // is primarily a workaround to the API design in Bun that requires access to
@@ -27,9 +39,18 @@ function toArcjetRequest(ipCache, request, props) {
27
39
  // We construct an ArcjetHeaders to normalize over Headers
28
40
  const headers = new ArcjetHeaders(request.headers);
29
41
  const url = new URL(request.url);
30
- const ip = findIP({
42
+ let ip = findIP({
31
43
  ip: ipCache.get(request),
32
- }, headers);
44
+ }, headers, { platform: platform(env) });
45
+ if (ip === "") {
46
+ // If the `ip` is empty but we're in development mode, we default the IP
47
+ // so the request doesn't fail.
48
+ if (isDevelopment(env)) {
49
+ // TODO: Log that the fingerprint is being overridden once the adapter
50
+ // constructs the logger
51
+ ip = "127.0.0.1";
52
+ }
53
+ }
33
54
  return {
34
55
  ...props,
35
56
  ip,
@@ -48,9 +69,6 @@ function withClient(aj) {
48
69
  // `server.requestIP()`
49
70
  const ipCache = new WeakMap();
50
71
  return Object.freeze({
51
- get runtime() {
52
- return aj.runtime;
53
- },
54
72
  withRule(rule) {
55
73
  const client = aj.withRule(rule);
56
74
  return withClient(client);
@@ -60,7 +78,7 @@ function withClient(aj) {
60
78
  // Further investigation makes it seem like it has something to do with
61
79
  // the definition of `props` in the signature but it's hard to track down
62
80
  const req = toArcjetRequest(ipCache, request, props ?? {});
63
- return aj.protect(req);
81
+ return aj.protect({}, req);
64
82
  },
65
83
  handler(fetch) {
66
84
  return async function (request, server) {
@@ -82,9 +100,14 @@ function withClient(aj) {
82
100
  * @param options - Arcjet configuration options to apply to all requests.
83
101
  */
84
102
  function arcjet(options) {
85
- const client = options.client ?? createBunRemoteClient();
86
- const aj = core__default({ ...options, client });
103
+ const client = options.client ?? createRemoteClient();
104
+ const log = options.log
105
+ ? options.log
106
+ : new Logger({
107
+ level: logLevel(env),
108
+ });
109
+ const aj = core__default({ ...options, client, log });
87
110
  return withClient(aj);
88
111
  }
89
112
 
90
- export { createBunRemoteClient, arcjet as default };
113
+ export { createRemoteClient, arcjet as default };
package/index.ts CHANGED
@@ -5,18 +5,23 @@ import core, {
5
5
  ArcjetOptions,
6
6
  Primitive,
7
7
  Product,
8
- ArcjetHeaders,
9
- Runtime,
10
8
  ArcjetRequest,
11
9
  ExtraProps,
12
- RemoteClient,
13
- RemoteClientOptions,
14
- defaultBaseUrl,
15
- createRemoteClient,
16
10
  Arcjet,
17
11
  } from "arcjet";
18
12
  import findIP from "@arcjet/ip";
13
+ import ArcjetHeaders from "@arcjet/headers";
19
14
  import type { Server } from "bun";
15
+ import { env } from "bun";
16
+ import {
17
+ baseUrl,
18
+ isDevelopment,
19
+ isProduction,
20
+ logLevel,
21
+ platform,
22
+ } from "@arcjet/env";
23
+ import { Logger } from "@arcjet/logger";
24
+ import { createClient } from "@arcjet/protocol/client.js";
20
25
 
21
26
  // Re-export all named exports from the generic SDK
22
27
  export * from "arcjet";
@@ -58,26 +63,36 @@ type PlainObject = {
58
63
  [key: string]: unknown;
59
64
  };
60
65
 
61
- export function createBunRemoteClient(
62
- options?: RemoteClientOptions,
63
- ): RemoteClient {
66
+ export type RemoteClientOptions = {
67
+ baseUrl?: string;
68
+ timeout?: number;
69
+ };
70
+
71
+ export function createRemoteClient(options?: RemoteClientOptions) {
64
72
  // The base URL for the Arcjet API. Will default to the standard production
65
73
  // API unless environment variable `ARCJET_BASE_URL` is set.
66
- const baseUrl = options?.baseUrl ?? defaultBaseUrl();
74
+ const url = options?.baseUrl ?? baseUrl(env);
75
+
76
+ // The timeout for the Arcjet API in milliseconds. This is set to a low value
77
+ // in production so calls fail open.
78
+ const timeout = options?.timeout ?? (isProduction(env) ? 500 : 1000);
67
79
 
68
80
  // Transport is the HTTP client that the client uses to make requests.
69
- const transport =
70
- options?.transport ??
71
- createConnectTransport({
72
- baseUrl,
73
- httpVersion: "1.1",
74
- });
75
-
76
- // TODO(#223): Do we want to allow overrides to either of these? If not, we should probably define a separate type for `options`
81
+ const transport = createConnectTransport({
82
+ baseUrl: url,
83
+ httpVersion: "1.1",
84
+ });
85
+
77
86
  const sdkStack = "BUN";
78
87
  const sdkVersion = "__ARCJET_SDK_VERSION__";
79
88
 
80
- return createRemoteClient({ ...options, transport, sdkStack, sdkVersion });
89
+ return createClient({
90
+ transport,
91
+ baseUrl: url,
92
+ timeout,
93
+ sdkStack,
94
+ sdkVersion,
95
+ });
81
96
  }
82
97
 
83
98
  /**
@@ -85,7 +100,6 @@ export function createBunRemoteClient(
85
100
  * make a decision about how a Bun.sh request should be handled.
86
101
  */
87
102
  export interface ArcjetBun<Props extends PlainObject> {
88
- get runtime(): Runtime;
89
103
  /**
90
104
  * Runs a request through the configured protections. The request is
91
105
  * analyzed and then a decision made on whether to allow, deny, or challenge
@@ -146,12 +160,22 @@ function toArcjetRequest<Props extends PlainObject>(
146
160
  const headers = new ArcjetHeaders(request.headers);
147
161
 
148
162
  const url = new URL(request.url);
149
- const ip = findIP(
163
+ let ip = findIP(
150
164
  {
151
165
  ip: ipCache.get(request),
152
166
  },
153
167
  headers,
168
+ { platform: platform(env) },
154
169
  );
170
+ if (ip === "") {
171
+ // If the `ip` is empty but we're in development mode, we default the IP
172
+ // so the request doesn't fail.
173
+ if (isDevelopment(env)) {
174
+ // TODO: Log that the fingerprint is being overridden once the adapter
175
+ // constructs the logger
176
+ ip = "127.0.0.1";
177
+ }
178
+ }
155
179
 
156
180
  return {
157
181
  ...props,
@@ -175,9 +199,6 @@ function withClient<const Rules extends (Primitive | Product)[]>(
175
199
  const ipCache = new WeakMap<Request, string>();
176
200
 
177
201
  return Object.freeze({
178
- get runtime() {
179
- return aj.runtime;
180
- },
181
202
  withRule(rule: Primitive | Product) {
182
203
  const client = aj.withRule(rule);
183
204
  return withClient(client);
@@ -197,7 +218,7 @@ function withClient<const Rules extends (Primitive | Product)[]>(
197
218
  props ?? {},
198
219
  ) as ArcjetRequest<ExtraProps<Rules>>;
199
220
 
200
- return aj.protect(req);
221
+ return aj.protect({}, req);
201
222
  },
202
223
  handler(
203
224
  fetch: (
@@ -232,9 +253,15 @@ function withClient<const Rules extends (Primitive | Product)[]>(
232
253
  export default function arcjet<const Rules extends (Primitive | Product)[]>(
233
254
  options: ArcjetOptions<Rules>,
234
255
  ): ArcjetBun<Simplify<ExtraProps<Rules>>> {
235
- const client = options.client ?? createBunRemoteClient();
256
+ const client = options.client ?? createRemoteClient();
257
+
258
+ const log = options.log
259
+ ? options.log
260
+ : new Logger({
261
+ level: logLevel(env),
262
+ });
236
263
 
237
- const aj = core({ ...options, client });
264
+ const aj = core({ ...options, client, log });
238
265
 
239
266
  return withClient(aj);
240
267
  }
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.15",
4
4
  "description": "Arcjet SDK for Bun.sh",
5
5
  "license": "Apache-2.0",
6
6
  "homepage": "https://arcjet.com",
@@ -38,18 +38,22 @@
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.15",
42
+ "@arcjet/headers": "1.0.0-alpha.15",
43
+ "@arcjet/ip": "1.0.0-alpha.15",
44
+ "@arcjet/logger": "1.0.0-alpha.15",
45
+ "@arcjet/protocol": "1.0.0-alpha.15",
42
46
  "@connectrpc/connect-node": "1.4.0",
43
- "arcjet": "1.0.0-alpha.13"
47
+ "arcjet": "1.0.0-alpha.15"
44
48
  },
45
49
  "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",
50
+ "@arcjet/eslint-config": "1.0.0-alpha.15",
51
+ "@arcjet/rollup-config": "1.0.0-alpha.15",
52
+ "@arcjet/tsconfig": "1.0.0-alpha.15",
49
53
  "@jest/globals": "29.7.0",
50
54
  "@types/node": "20.12.12",
51
- "@rollup/wasm-node": "4.17.2",
52
- "bun-types": "1.1.8",
55
+ "@rollup/wasm-node": "4.18.0",
56
+ "bun-types": "1.1.13",
53
57
  "jest": "29.7.0",
54
58
  "typescript": "5.4.5"
55
59
  },