@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 +17 -5
- package/index.d.ts +6 -3
- package/index.js +43 -20
- package/index.ts +54 -27
- package/package.json +12 -8
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-
|
|
4
|
-
<img src="https://arcjet.com/arcjet-
|
|
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
|
|
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.
|
|
79
|
-
|
|
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,
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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 =
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
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.
|
|
20
|
-
return
|
|
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
|
-
|
|
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 ??
|
|
86
|
-
const
|
|
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 {
|
|
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
|
|
62
|
-
|
|
63
|
-
|
|
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
|
|
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
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
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
|
|
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
|
-
|
|
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 ??
|
|
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.
|
|
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/
|
|
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.
|
|
47
|
+
"arcjet": "1.0.0-alpha.15"
|
|
44
48
|
},
|
|
45
49
|
"devDependencies": {
|
|
46
|
-
"@arcjet/eslint-config": "1.0.0-alpha.
|
|
47
|
-
"@arcjet/rollup-config": "1.0.0-alpha.
|
|
48
|
-
"@arcjet/tsconfig": "1.0.0-alpha.
|
|
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.
|
|
52
|
-
"bun-types": "1.1.
|
|
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
|
},
|