@arcjet/astro 1.0.0-beta.10 → 1.0.0-beta.12

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 (5) hide show
  1. package/index.d.ts +284 -29
  2. package/index.js +314 -51
  3. package/internal.d.ts +68 -20
  4. package/internal.js +21 -13
  5. package/package.json +16 -15
package/index.d.ts CHANGED
@@ -1,75 +1,330 @@
1
- import type { BotOptions, EmailOptions, FixedWindowRateLimitOptions, ProtectSignupOptions, SensitiveInfoOptions, ShieldOptions, SlidingWindowRateLimitOptions, TokenBucketRateLimitOptions } from "arcjet";
1
+ import type { BotOptions, EmailOptions, FilterOptions, FixedWindowRateLimitOptions, ProtectSignupOptions, SensitiveInfoOptions, ShieldOptions, SlidingWindowRateLimitOptions, TokenBucketRateLimitOptions } from "arcjet";
2
2
  import type { AstroIntegration } from "astro";
3
3
  type IntegrationRule<Characteristics extends readonly string[]> = {
4
4
  type: "shield";
5
- options?: ShieldOptions;
5
+ options: ShieldOptions;
6
6
  } | {
7
7
  type: "bot";
8
- options?: BotOptions;
8
+ options: BotOptions;
9
9
  } | {
10
10
  type: "email";
11
- options?: EmailOptions;
11
+ options: EmailOptions;
12
+ } | {
13
+ type: "filter";
14
+ options: FilterOptions;
12
15
  } | {
13
16
  type: "sensitiveInfo";
14
- options?: SensitiveInfoOptions<never>;
17
+ options: SensitiveInfoOptions<never>;
15
18
  } | {
16
19
  type: "fixedWindow";
17
- options?: FixedWindowRateLimitOptions<Characteristics>;
20
+ options: FixedWindowRateLimitOptions<Characteristics>;
18
21
  } | {
19
22
  type: "slidingWindow";
20
- options?: SlidingWindowRateLimitOptions<Characteristics>;
23
+ options: SlidingWindowRateLimitOptions<Characteristics>;
21
24
  } | {
22
25
  type: "tokenBucket";
23
- options?: TokenBucketRateLimitOptions<Characteristics>;
26
+ options: TokenBucketRateLimitOptions<Characteristics>;
24
27
  } | {
25
28
  type: "protectSignup";
26
- options?: ProtectSignupOptions<Characteristics>;
29
+ options: ProtectSignupOptions<Characteristics>;
27
30
  };
31
+ /**
32
+ * Configuration for the Astro integration of Arcjet.
33
+ *
34
+ * @template Characteristics
35
+ * Characteristics to track a user by.
36
+ */
28
37
  type ArcjetIntegrationOptions<Characteristics extends readonly string[]> = {
38
+ /**
39
+ * Integration rules to apply when protecting a request (required).
40
+ *
41
+ * These rules are *different* from those exposed from `arcjet` core.
42
+ * You have to import them from this integration (`@arcjet/astro`) instead.
43
+ */
29
44
  rules: IntegrationRule<Characteristics>[];
45
+ /**
46
+ * Characteristics to track a user by (default: `["src.ip"]`).
47
+ *
48
+ * Can also be passed to rules.
49
+ */
30
50
  characteristics?: Characteristics;
51
+ /**
52
+ * Configuration for the default client (optional).
53
+ */
31
54
  client?: RemoteClientOptions;
55
+ /**
56
+ * IP addresses and CIDR ranges of trusted load balancers and proxies
57
+ * (optional, example: `["100.100.100.100", "100.100.100.0/24"]`).
58
+ */
32
59
  proxies?: string[];
33
60
  };
34
- export declare function shield(options?: ShieldOptions): {
61
+ /**
62
+ * Arcjet Shield WAF rule.
63
+ *
64
+ * Applying this rule protects your application against common attacks,
65
+ * including the OWASP Top 10.
66
+ *
67
+ * The Arcjet Shield WAF analyzes every request to your application to detect
68
+ * suspicious activity.
69
+ * Once a certain suspicion threshold is reached,
70
+ * subsequent requests from that client are blocked for a period of time.
71
+ *
72
+ * @param options
73
+ * Configuration for the Shield rule.
74
+ * @returns
75
+ * Astro integration Shield rule to provide to the SDK in the `rules` field.
76
+ */
77
+ export declare function shield(options: ShieldOptions): {
35
78
  readonly type: "shield";
36
- readonly options: ShieldOptions | undefined;
79
+ readonly options: ShieldOptions;
37
80
  };
38
- export declare function detectBot(options?: BotOptions): {
81
+ /**
82
+ * Arcjet bot detection rule.
83
+ *
84
+ * Applying this rule allows you to manage traffic by automated clients and
85
+ * bots.
86
+ *
87
+ * Bots can be good (such as search engine crawlers or monitoring agents) or bad
88
+ * (such as scrapers or automated scripts).
89
+ * Arcjet allows you to configure which bots you want to allow or deny by
90
+ * specific bot names such as curl, as well as by category such as search
91
+ * engine bots.
92
+ *
93
+ * Bots are detected based on various signals such as the user agent, IP
94
+ * address, DNS records, and more.
95
+ *
96
+ * @param options
97
+ * Configuration for the bot rule (required).
98
+ * @returns
99
+ * Astro integration Bot rule to provide to the SDK in the `rules` field.
100
+ */
101
+ export declare function detectBot(options: BotOptions): {
39
102
  readonly type: "bot";
40
- readonly options: BotOptions | undefined;
103
+ readonly options: BotOptions;
41
104
  };
42
- export declare function validateEmail(options?: EmailOptions): {
105
+ /**
106
+ * Arcjet email validation rule.
107
+ *
108
+ * Applying this rule allows you to validate and verify an email address.
109
+ *
110
+ * The first step of the analysis is to validate the email address syntax.
111
+ * This runs locally within the SDK and validates the email address is in the
112
+ * correct format.
113
+ * If the email syntax is valid, the SDK will pass the email address to the
114
+ * Arcjet cloud API to verify the email address.
115
+ * This performs several checks, depending on the rule configuration.
116
+ *
117
+ * @param options
118
+ * Configuration for the email validation rule (required).
119
+ * @returns
120
+ * Astro integration Email rule to provide to the SDK in the `rules` field.
121
+ */
122
+ export declare function validateEmail(options: EmailOptions): {
43
123
  readonly type: "email";
44
- readonly options: EmailOptions | undefined;
124
+ readonly options: EmailOptions;
125
+ };
126
+ /**
127
+ * Arcjet filter rule.
128
+ *
129
+ * Applying this rule lets you block requests using Wireshark-like display
130
+ * filter expressions over HTTP headers, IP addresses, and other request
131
+ * fields.
132
+ * You can quickly enforce rules like allow/deny by country, network, or
133
+ * `user-agent` pattern.
134
+ *
135
+ * See the [reference guide](https://docs.arcjet.com/filters/reference) for
136
+ * more info on the expression language fields, functions, and values.
137
+ *
138
+ * @param options
139
+ * Configuration (required).
140
+ * @returns
141
+ * Astro integration Filter rule to provide to the SDK in the `rules` field.
142
+ *
143
+ * @example
144
+ * In this example, the expression matches non-VPN GET requests from the US.
145
+ * Requests matching the expression are allowed, all others are denied.
146
+ *
147
+ * ```ts
148
+ * filter({
149
+ * allow: [
150
+ * 'http.request.method eq "GET" and ip.src.country eq "US" and not ip.src.vpn',
151
+ * ],
152
+ * mode: "LIVE",
153
+ * })
154
+ * ```
155
+ *
156
+ * @link https://docs.arcjet.com/filters/reference
157
+ */
158
+ export declare function filter(options: FilterOptions): {
159
+ readonly type: "filter";
160
+ readonly options: FilterOptions;
45
161
  };
46
- export declare function sensitiveInfo(options?: SensitiveInfoOptions<never>): {
162
+ /**
163
+ * Arcjet sensitive information detection rule.
164
+ *
165
+ * Applying this rule protects against clients sending you sensitive information
166
+ * such as personally identifiable information (PII) that you do not wish to
167
+ * handle.
168
+ * The rule runs entirely locally so no data ever leaves your environment.
169
+ *
170
+ * This rule includes built-in detections for email addresses, credit/debit card
171
+ * numbers, IP addresses, and phone numbers.
172
+ * You can also provide a custom detection function to identify additional
173
+ * sensitive information.
174
+ *
175
+ * @param options
176
+ * Configuration for the sensitive information detection rule (required).
177
+ * @returns
178
+ * Astro integration Sensitive information rule to provide to the SDK in the `rules` field.
179
+ */
180
+ export declare function sensitiveInfo(options: SensitiveInfoOptions<never>): {
47
181
  readonly type: "sensitiveInfo";
48
- readonly options: SensitiveInfoOptions<never> | undefined;
182
+ readonly options: SensitiveInfoOptions<never>;
49
183
  };
50
- export declare function fixedWindow<Characteristics extends readonly string[]>(options?: FixedWindowRateLimitOptions<Characteristics>): {
184
+ /**
185
+ * Arcjet fixed window rate limiting rule.
186
+ *
187
+ * Applying this rule sets a fixed window rate limit which tracks the number of
188
+ * requests made by a client over a fixed time window.
189
+ *
190
+ * This is the simplest algorithm.
191
+ * It tracks the number of requests made by a client over a fixed time window
192
+ * such as 60 seconds.
193
+ * If the client exceeds the limit, they are blocked until the window expires.
194
+ *
195
+ * This algorithm is useful when you want to apply a simple fixed limit in a
196
+ * fixed time window.
197
+ * For example, a simple limit on the total number of requests a client can make.
198
+ * However, it can be susceptible to the stampede problem where a client makes
199
+ * a burst of requests at the start of a window and then is blocked for the rest
200
+ * of the window.
201
+ * The sliding window algorithm can be used to avoid this.
202
+ *
203
+ * @template Characteristics
204
+ * Characteristics to track a user by.
205
+ * @param options
206
+ * Configuration for the fixed window rate limiting rule (required).
207
+ * @returns
208
+ * Astro integration Fixed window rule to provide to the SDK in the `rules` field.
209
+ */
210
+ export declare function fixedWindow<Characteristics extends readonly string[]>(options: FixedWindowRateLimitOptions<Characteristics>): {
51
211
  readonly type: "fixedWindow";
52
- readonly options: FixedWindowRateLimitOptions<Characteristics> | undefined;
212
+ readonly options: FixedWindowRateLimitOptions<Characteristics>;
53
213
  };
54
- export declare function slidingWindow<Characteristics extends readonly string[]>(options?: SlidingWindowRateLimitOptions<Characteristics>): {
214
+ /**
215
+ * Arcjet sliding window rate limiting rule.
216
+ *
217
+ * Applying this rule sets a sliding window rate limit which tracks the number
218
+ * of requests made by a client over a sliding window so that the window moves
219
+ * with time.
220
+ *
221
+ * This algorithm is useful to avoid the stampede problem of the fixed window.
222
+ * It provides smoother rate limiting over time and can prevent a client from
223
+ * making a burst of requests at the start of a window and then being blocked
224
+ * for the rest of the window.
225
+ *
226
+ * @template Characteristics
227
+ * Characteristics to track a user by.
228
+ * @param options
229
+ * Configuration for the sliding window rate limiting rule (required).
230
+ * @returns
231
+ * Astro integration Sliding window rule to provide to the SDK in the `rules` field.
232
+ */
233
+ export declare function slidingWindow<Characteristics extends readonly string[]>(options: SlidingWindowRateLimitOptions<Characteristics>): {
55
234
  readonly type: "slidingWindow";
56
- readonly options: SlidingWindowRateLimitOptions<Characteristics> | undefined;
235
+ readonly options: SlidingWindowRateLimitOptions<Characteristics>;
57
236
  };
58
- export declare function tokenBucket<Characteristics extends readonly string[]>(options?: TokenBucketRateLimitOptions<Characteristics>): {
237
+ /**
238
+ * Arcjet token bucket rate limiting rule.
239
+ *
240
+ * Applying this rule sets a token bucket rate limit.
241
+ *
242
+ * This algorithm is based on a bucket filled with a specific number of tokens.
243
+ * Each request withdraws some amount of tokens from the bucket and the bucket
244
+ * is refilled at a fixed rate.
245
+ * Once the bucket is empty, the client is blocked until the bucket refills.
246
+ *
247
+ * This algorithm is useful when you want to allow clients to make a burst of
248
+ * requests and then still be able to make requests at a slower rate.
249
+ *
250
+ * @template Characteristics
251
+ * Characteristics to track a user by.
252
+ * @param options
253
+ * Configuration for the token bucket rate limiting rule (required).
254
+ * @returns
255
+ * Astro integration Token bucket rule to provide to the SDK in the `rules` field.
256
+ */
257
+ export declare function tokenBucket<Characteristics extends readonly string[]>(options: TokenBucketRateLimitOptions<Characteristics>): {
59
258
  readonly type: "tokenBucket";
60
- readonly options: TokenBucketRateLimitOptions<Characteristics> | undefined;
259
+ readonly options: TokenBucketRateLimitOptions<Characteristics>;
61
260
  };
62
- export declare function protectSignup<Characteristics extends readonly string[]>(options?: ProtectSignupOptions<Characteristics>): {
261
+ /**
262
+ * Arcjet signup form protection rule.
263
+ *
264
+ * Applying this rule combines rate limiting, bot protection, and email
265
+ * validation to protect your signup forms from abuse.
266
+ * Using this rule will configure the following:
267
+ *
268
+ * - Rate limiting - signup forms are a common target for bots. Arcjet’s rate
269
+ * limiting helps to prevent bots and other automated or malicious clients
270
+ * from submitting your signup form too many times in a short period of time.
271
+ * - Bot protection - signup forms are usually exclusively used by humans, which
272
+ * means that any automated submissions to the form are likely to be
273
+ * fraudulent.
274
+ * - Email validation - email addresses should be validated to ensure the signup
275
+ * is coming from a legitimate user with a real email address that can
276
+ * actually receive messages.
277
+ *
278
+ * @template Characteristics
279
+ * Characteristics to track a user by.
280
+ * @param options
281
+ * Configuration for the signup form protection rule.
282
+ * @returns
283
+ * Astro integration Signup form protection rule to provide to the SDK in the `rules` field.
284
+ */
285
+ export declare function protectSignup<Characteristics extends readonly string[]>(options: ProtectSignupOptions<Characteristics>): {
63
286
  readonly type: "protectSignup";
64
- readonly options: ProtectSignupOptions<Characteristics> | undefined;
287
+ readonly options: ProtectSignupOptions<Characteristics>;
65
288
  };
289
+ /**
290
+ * Configuration for {@linkcode createRemoteClient}.
291
+ */
66
292
  export type RemoteClientOptions = {
67
- baseUrl?: string;
68
- timeout?: number;
293
+ /**
294
+ * Base URI for HTTP requests to Decide API (optional).
295
+ *
296
+ * Defaults to the environment variable `ARCJET_BASE_URL` (if that value
297
+ * is known and allowed) and the standard production API otherwise.
298
+ */
299
+ baseUrl?: string | undefined;
300
+ /**
301
+ * Timeout in milliseconds for the Decide API (optional).
302
+ *
303
+ * Defaults to `500` in production and `1000` in development.
304
+ */
305
+ timeout?: number | undefined;
69
306
  };
70
- export declare function createRemoteClient({ baseUrl, timeout }: RemoteClientOptions): {
307
+ /**
308
+ * Create a remote client.
309
+ *
310
+ * @param options
311
+ * Configuration (optional).
312
+ * @returns
313
+ * Client.
314
+ */
315
+ export declare function createRemoteClient(options?: RemoteClientOptions | undefined): {
71
316
  readonly baseUrl: string | undefined;
72
317
  readonly timeout: number | undefined;
73
318
  };
74
- export default function arcjet<Characteristics extends readonly string[]>({ rules, characteristics, client, proxies, }?: ArcjetIntegrationOptions<Characteristics>): AstroIntegration;
319
+ /**
320
+ * Create a new Astro integration of Arcjet.
321
+ *
322
+ * @template Characteristics
323
+ * Characteristics to track a user by.
324
+ * @param options
325
+ * Configuration.
326
+ * @returns
327
+ * Astro integration of Arcjet.
328
+ */
329
+ export default function arcjet<Characteristics extends readonly string[]>(options?: ArcjetIntegrationOptions<Characteristics>): AstroIntegration;
75
330
  export {};
package/index.js CHANGED
@@ -7,107 +7,112 @@ const validateProxies = z.array(z.string());
7
7
  const validateCharacteristics = z.array(z.string());
8
8
  const validateClientOptions = z
9
9
  .object({
10
- baseUrl: z.string(),
11
- timeout: z.number(),
10
+ baseUrl: z.string().optional(),
11
+ timeout: z.number().optional(),
12
12
  })
13
13
  .strict()
14
14
  .optional();
15
+ // TODO: once `arcjet` core has `exactOptionalProperties` we can use
16
+ // `satisfies z.ZodType<ShieldOptions>` and such here.
15
17
  const validateShieldOptions = z
16
18
  .object({
17
- mode: validateMode,
19
+ mode: validateMode.optional(),
18
20
  })
19
- .strict()
20
- .optional();
21
- const validateBotOptions = z
22
- .union([
21
+ .strict();
22
+ const validateBotOptions = z.union([
23
23
  z
24
24
  .object({
25
- mode: validateMode,
25
+ mode: validateMode.optional(),
26
26
  allow: z.array(z.string()),
27
27
  })
28
28
  .strict(),
29
29
  z
30
30
  .object({
31
- mode: validateMode,
31
+ mode: validateMode.optional(),
32
32
  deny: z.array(z.string()),
33
33
  })
34
34
  .strict(),
35
- ])
36
- .optional();
37
- const validateEmailOptions = z
38
- .union([
35
+ ]);
36
+ const validateEmailOptions = z.union([
39
37
  z
40
38
  .object({
41
- mode: validateMode,
39
+ mode: validateMode.optional(),
42
40
  allow: z.array(z.string()),
43
- requireTopLevelDomain: z.boolean(),
44
- allowDomainLiteral: z.boolean(),
41
+ requireTopLevelDomain: z.boolean().optional(),
42
+ allowDomainLiteral: z.boolean().optional(),
45
43
  })
46
44
  .strict(),
47
45
  z
48
46
  .object({
49
- mode: validateMode,
47
+ mode: validateMode.optional(),
50
48
  deny: z.array(z.string()),
51
- requireTopLevelDomain: z.boolean(),
52
- allowDomainLiteral: z.boolean(),
49
+ requireTopLevelDomain: z.boolean().optional(),
50
+ allowDomainLiteral: z.boolean().optional(),
53
51
  })
54
52
  .strict(),
55
- ])
56
- .optional();
57
- const validateSensitiveInfoOptions = z
58
- .union([
53
+ ]);
54
+ const validateFilterOptions = z.union([
59
55
  z
60
56
  .object({
61
- mode: validateMode,
57
+ mode: validateMode.optional(),
62
58
  allow: z.array(z.string()),
63
- contextWindowSize: z.number(),
64
59
  })
65
60
  .strict(),
66
61
  z
67
62
  .object({
68
- mode: validateMode,
63
+ mode: validateMode.optional(),
69
64
  deny: z.array(z.string()),
70
- contextWindowSize: z.number(),
71
65
  })
72
66
  .strict(),
73
- ])
74
- .optional();
67
+ ]);
68
+ const validateSensitiveInfoOptions = z.union([
69
+ z
70
+ .object({
71
+ mode: validateMode.optional(),
72
+ allow: z.array(z.string()),
73
+ contextWindowSize: z.number().optional(),
74
+ })
75
+ .strict(),
76
+ z
77
+ .object({
78
+ mode: validateMode.optional(),
79
+ deny: z.array(z.string()),
80
+ contextWindowSize: z.number().optional(),
81
+ })
82
+ .strict(),
83
+ ]);
75
84
  const validateFixedWindowOptions = z
76
85
  .object({
77
- mode: validateMode,
78
- characteristics: validateCharacteristics,
86
+ mode: validateMode.optional(),
87
+ characteristics: validateCharacteristics.optional(),
79
88
  window: z.union([z.string(), z.number()]),
80
89
  max: z.number(),
81
90
  })
82
- .strict()
83
- .optional();
91
+ .strict();
84
92
  const validateSlidingWindowOptions = z
85
93
  .object({
86
- mode: validateMode,
87
- characteristics: validateCharacteristics,
94
+ mode: validateMode.optional(),
95
+ characteristics: validateCharacteristics.optional(),
88
96
  interval: z.union([z.string(), z.number()]),
89
97
  max: z.number(),
90
98
  })
91
- .strict()
92
- .optional();
99
+ .strict();
93
100
  const validateTokenBucketOptions = z
94
101
  .object({
95
- mode: validateMode,
96
- characteristics: validateCharacteristics,
102
+ mode: validateMode.optional(),
103
+ characteristics: validateCharacteristics.optional(),
97
104
  refillRate: z.number(),
98
105
  interval: z.union([z.string(), z.number()]),
99
106
  capacity: z.number(),
100
107
  })
101
- .strict()
102
- .optional();
108
+ .strict();
103
109
  const validateProtectSignupOptions = z
104
110
  .object({
105
111
  rateLimit: validateSlidingWindowOptions,
106
112
  bots: validateBotOptions,
107
113
  email: validateEmailOptions,
108
114
  })
109
- .strict()
110
- .optional();
115
+ .strict();
111
116
  function validateAndSerialize(schema, value) {
112
117
  const v = schema.parse(value);
113
118
  return v ? JSON.stringify(v) : "";
@@ -135,6 +140,13 @@ function integrationRuleToClientRule(rule) {
135
140
  code: `validateEmail(${serializedOpts})`,
136
141
  };
137
142
  }
143
+ case "filter": {
144
+ const serializedOpts = validateAndSerialize(validateFilterOptions, rule.options);
145
+ return {
146
+ importName: `filter`,
147
+ code: `filter(${serializedOpts})`,
148
+ };
149
+ }
138
150
  case "sensitiveInfo": {
139
151
  const serializedOpts = validateAndSerialize(validateSensitiveInfoOptions, rule.options);
140
152
  return {
@@ -176,34 +188,270 @@ function integrationRuleToClientRule(rule) {
176
188
  }
177
189
  }
178
190
  // Mirror the rule functions in the SDK but produce serializable rules
191
+ // Note: please keep JSDocs in sync with `arcjet` core.
192
+ /**
193
+ * Arcjet Shield WAF rule.
194
+ *
195
+ * Applying this rule protects your application against common attacks,
196
+ * including the OWASP Top 10.
197
+ *
198
+ * The Arcjet Shield WAF analyzes every request to your application to detect
199
+ * suspicious activity.
200
+ * Once a certain suspicion threshold is reached,
201
+ * subsequent requests from that client are blocked for a period of time.
202
+ *
203
+ * @param options
204
+ * Configuration for the Shield rule.
205
+ * @returns
206
+ * Astro integration Shield rule to provide to the SDK in the `rules` field.
207
+ */
179
208
  function shield(options) {
180
209
  return { type: "shield", options };
181
210
  }
211
+ // Note: please keep JSDocs in sync with `arcjet` core.
212
+ /**
213
+ * Arcjet bot detection rule.
214
+ *
215
+ * Applying this rule allows you to manage traffic by automated clients and
216
+ * bots.
217
+ *
218
+ * Bots can be good (such as search engine crawlers or monitoring agents) or bad
219
+ * (such as scrapers or automated scripts).
220
+ * Arcjet allows you to configure which bots you want to allow or deny by
221
+ * specific bot names such as curl, as well as by category such as search
222
+ * engine bots.
223
+ *
224
+ * Bots are detected based on various signals such as the user agent, IP
225
+ * address, DNS records, and more.
226
+ *
227
+ * @param options
228
+ * Configuration for the bot rule (required).
229
+ * @returns
230
+ * Astro integration Bot rule to provide to the SDK in the `rules` field.
231
+ */
182
232
  function detectBot(options) {
183
233
  return { type: "bot", options };
184
234
  }
235
+ // Note: please keep JSDocs in sync with `arcjet` core.
236
+ /**
237
+ * Arcjet email validation rule.
238
+ *
239
+ * Applying this rule allows you to validate and verify an email address.
240
+ *
241
+ * The first step of the analysis is to validate the email address syntax.
242
+ * This runs locally within the SDK and validates the email address is in the
243
+ * correct format.
244
+ * If the email syntax is valid, the SDK will pass the email address to the
245
+ * Arcjet cloud API to verify the email address.
246
+ * This performs several checks, depending on the rule configuration.
247
+ *
248
+ * @param options
249
+ * Configuration for the email validation rule (required).
250
+ * @returns
251
+ * Astro integration Email rule to provide to the SDK in the `rules` field.
252
+ */
185
253
  function validateEmail(options) {
186
254
  return { type: "email", options };
187
255
  }
256
+ // Note: please keep JSDocs in sync with `arcjet` core.
257
+ /**
258
+ * Arcjet filter rule.
259
+ *
260
+ * Applying this rule lets you block requests using Wireshark-like display
261
+ * filter expressions over HTTP headers, IP addresses, and other request
262
+ * fields.
263
+ * You can quickly enforce rules like allow/deny by country, network, or
264
+ * `user-agent` pattern.
265
+ *
266
+ * See the [reference guide](https://docs.arcjet.com/filters/reference) for
267
+ * more info on the expression language fields, functions, and values.
268
+ *
269
+ * @param options
270
+ * Configuration (required).
271
+ * @returns
272
+ * Astro integration Filter rule to provide to the SDK in the `rules` field.
273
+ *
274
+ * @example
275
+ * In this example, the expression matches non-VPN GET requests from the US.
276
+ * Requests matching the expression are allowed, all others are denied.
277
+ *
278
+ * ```ts
279
+ * filter({
280
+ * allow: [
281
+ * 'http.request.method eq "GET" and ip.src.country eq "US" and not ip.src.vpn',
282
+ * ],
283
+ * mode: "LIVE",
284
+ * })
285
+ * ```
286
+ *
287
+ * @link https://docs.arcjet.com/filters/reference
288
+ */
289
+ function filter(options) {
290
+ return { type: "filter", options };
291
+ }
292
+ // Note: please keep JSDocs in sync with `arcjet` core.
293
+ /**
294
+ * Arcjet sensitive information detection rule.
295
+ *
296
+ * Applying this rule protects against clients sending you sensitive information
297
+ * such as personally identifiable information (PII) that you do not wish to
298
+ * handle.
299
+ * The rule runs entirely locally so no data ever leaves your environment.
300
+ *
301
+ * This rule includes built-in detections for email addresses, credit/debit card
302
+ * numbers, IP addresses, and phone numbers.
303
+ * You can also provide a custom detection function to identify additional
304
+ * sensitive information.
305
+ *
306
+ * @param options
307
+ * Configuration for the sensitive information detection rule (required).
308
+ * @returns
309
+ * Astro integration Sensitive information rule to provide to the SDK in the `rules` field.
310
+ */
188
311
  function sensitiveInfo(options) {
189
312
  return { type: "sensitiveInfo", options };
190
313
  }
314
+ // Note: please keep JSDocs in sync with `arcjet` core.
315
+ /**
316
+ * Arcjet fixed window rate limiting rule.
317
+ *
318
+ * Applying this rule sets a fixed window rate limit which tracks the number of
319
+ * requests made by a client over a fixed time window.
320
+ *
321
+ * This is the simplest algorithm.
322
+ * It tracks the number of requests made by a client over a fixed time window
323
+ * such as 60 seconds.
324
+ * If the client exceeds the limit, they are blocked until the window expires.
325
+ *
326
+ * This algorithm is useful when you want to apply a simple fixed limit in a
327
+ * fixed time window.
328
+ * For example, a simple limit on the total number of requests a client can make.
329
+ * However, it can be susceptible to the stampede problem where a client makes
330
+ * a burst of requests at the start of a window and then is blocked for the rest
331
+ * of the window.
332
+ * The sliding window algorithm can be used to avoid this.
333
+ *
334
+ * @template Characteristics
335
+ * Characteristics to track a user by.
336
+ * @param options
337
+ * Configuration for the fixed window rate limiting rule (required).
338
+ * @returns
339
+ * Astro integration Fixed window rule to provide to the SDK in the `rules` field.
340
+ */
191
341
  function fixedWindow(options) {
192
- return { type: "fixedWindow", options };
342
+ return {
343
+ type: "fixedWindow",
344
+ options,
345
+ };
193
346
  }
347
+ // Note: please keep JSDocs in sync with `arcjet` core.
348
+ /**
349
+ * Arcjet sliding window rate limiting rule.
350
+ *
351
+ * Applying this rule sets a sliding window rate limit which tracks the number
352
+ * of requests made by a client over a sliding window so that the window moves
353
+ * with time.
354
+ *
355
+ * This algorithm is useful to avoid the stampede problem of the fixed window.
356
+ * It provides smoother rate limiting over time and can prevent a client from
357
+ * making a burst of requests at the start of a window and then being blocked
358
+ * for the rest of the window.
359
+ *
360
+ * @template Characteristics
361
+ * Characteristics to track a user by.
362
+ * @param options
363
+ * Configuration for the sliding window rate limiting rule (required).
364
+ * @returns
365
+ * Astro integration Sliding window rule to provide to the SDK in the `rules` field.
366
+ */
194
367
  function slidingWindow(options) {
195
- return { type: "slidingWindow", options };
368
+ return {
369
+ type: "slidingWindow",
370
+ options,
371
+ };
196
372
  }
373
+ // Note: please keep JSDocs in sync with `arcjet` core.
374
+ /**
375
+ * Arcjet token bucket rate limiting rule.
376
+ *
377
+ * Applying this rule sets a token bucket rate limit.
378
+ *
379
+ * This algorithm is based on a bucket filled with a specific number of tokens.
380
+ * Each request withdraws some amount of tokens from the bucket and the bucket
381
+ * is refilled at a fixed rate.
382
+ * Once the bucket is empty, the client is blocked until the bucket refills.
383
+ *
384
+ * This algorithm is useful when you want to allow clients to make a burst of
385
+ * requests and then still be able to make requests at a slower rate.
386
+ *
387
+ * @template Characteristics
388
+ * Characteristics to track a user by.
389
+ * @param options
390
+ * Configuration for the token bucket rate limiting rule (required).
391
+ * @returns
392
+ * Astro integration Token bucket rule to provide to the SDK in the `rules` field.
393
+ */
197
394
  function tokenBucket(options) {
198
- return { type: "tokenBucket", options };
395
+ return {
396
+ type: "tokenBucket",
397
+ options,
398
+ };
199
399
  }
400
+ // Note: please keep JSDocs in sync with `arcjet` core.
401
+ /**
402
+ * Arcjet signup form protection rule.
403
+ *
404
+ * Applying this rule combines rate limiting, bot protection, and email
405
+ * validation to protect your signup forms from abuse.
406
+ * Using this rule will configure the following:
407
+ *
408
+ * - Rate limiting - signup forms are a common target for bots. Arcjet’s rate
409
+ * limiting helps to prevent bots and other automated or malicious clients
410
+ * from submitting your signup form too many times in a short period of time.
411
+ * - Bot protection - signup forms are usually exclusively used by humans, which
412
+ * means that any automated submissions to the form are likely to be
413
+ * fraudulent.
414
+ * - Email validation - email addresses should be validated to ensure the signup
415
+ * is coming from a legitimate user with a real email address that can
416
+ * actually receive messages.
417
+ *
418
+ * @template Characteristics
419
+ * Characteristics to track a user by.
420
+ * @param options
421
+ * Configuration for the signup form protection rule.
422
+ * @returns
423
+ * Astro integration Signup form protection rule to provide to the SDK in the `rules` field.
424
+ */
200
425
  function protectSignup(options) {
201
- return { type: "protectSignup", options };
426
+ return {
427
+ type: "protectSignup",
428
+ options,
429
+ };
202
430
  }
203
- function createRemoteClient({ baseUrl, timeout }) {
204
- return { baseUrl, timeout };
431
+ /**
432
+ * Create a remote client.
433
+ *
434
+ * @param options
435
+ * Configuration (optional).
436
+ * @returns
437
+ * Client.
438
+ */
439
+ function createRemoteClient(options) {
440
+ const settings = options ?? {};
441
+ return { baseUrl: settings.baseUrl, timeout: settings.timeout };
205
442
  }
206
- function arcjet({ rules, characteristics, client, proxies, } = { rules: [] }) {
443
+ /**
444
+ * Create a new Astro integration of Arcjet.
445
+ *
446
+ * @template Characteristics
447
+ * Characteristics to track a user by.
448
+ * @param options
449
+ * Configuration.
450
+ * @returns
451
+ * Astro integration of Arcjet.
452
+ */
453
+ function arcjet(options = { rules: [] }) {
454
+ const { rules, characteristics, client, proxies } = options;
207
455
  const arcjetImports = new Set();
208
456
  const arcjetRules = [];
209
457
  for (const rule of rules) {
@@ -331,6 +579,21 @@ function arcjet({ rules, characteristics, client, proxies, } = { rules: [] }) {
331
579
  ${Array.from(arcjetImports).join(",\n")}
332
580
  } from "arcjet"
333
581
 
582
+ /**
583
+ * Instance of the Astro integration of Arcjet.
584
+ *
585
+ * Primarily has a \`protect()\` method to make a decision about how a request
586
+ * should be handled.
587
+ *
588
+ * > 👉 **Note**: this is generated by \`@arcjet/astro\` based on how you configure
589
+ * > Arcjet in your \`astro.config.mjs\` file.
590
+ * > In that configuration file, you can pass the (serializable) options that apply
591
+ * > to all requests.
592
+ * > You can call \`aj.withRule\` *on* this default client to extend its behavior.
593
+ *
594
+ * @template Props
595
+ * Configuration.
596
+ */
334
597
  const client = createArcjetClient({
335
598
  rules: [
336
599
  ${arcjetRules.join(",\n")}
@@ -348,4 +611,4 @@ function arcjet({ rules, characteristics, client, proxies, } = { rules: [] }) {
348
611
  };
349
612
  }
350
613
 
351
- export { createRemoteClient, arcjet as default, detectBot, fixedWindow, protectSignup, sensitiveInfo, shield, slidingWindow, tokenBucket, validateEmail };
614
+ export { createRemoteClient, arcjet as default, detectBot, filter, fixedWindow, protectSignup, sensitiveInfo, shield, slidingWindow, tokenBucket, validateEmail };
package/internal.d.ts CHANGED
@@ -10,51 +10,99 @@ type WithoutCustomProps = {
10
10
  type PlainObject = {
11
11
  [key: string]: unknown;
12
12
  };
13
+ /**
14
+ * Configuration for {@linkcode createRemoteClient}.
15
+ */
13
16
  export type RemoteClientOptions = {
17
+ /**
18
+ * Base URI for HTTP requests to Decide API (optional).
19
+ *
20
+ * Defaults to the environment variable `ARCJET_BASE_URL` (if that value
21
+ * is known and allowed) and the standard production API otherwise.
22
+ */
14
23
  baseUrl?: string;
24
+ /**
25
+ * Timeout in milliseconds for the Decide API (optional).
26
+ *
27
+ * Defaults to `500` in production and `1000` in development.
28
+ */
15
29
  timeout?: number;
16
30
  };
31
+ /**
32
+ * Create a remote client.
33
+ *
34
+ * @param options
35
+ * Configuration (optional).
36
+ * @returns
37
+ * Client.
38
+ */
17
39
  export declare function createRemoteClient(options?: RemoteClientOptions): import("@arcjet/protocol/client.js").Client;
18
40
  /**
19
- * The options used to configure an {@link ArcjetAstro} client.
41
+ * Configuration for the Astro integration of Arcjet.
42
+ *
43
+ * @template Rules
44
+ * List of rules.
45
+ * @template Characteristics
46
+ * Characteristics to track a user by.
20
47
  */
21
48
  export type ArcjetOptions<Rules extends [...Array<Primitive | Product>], Characteristics extends readonly string[]> = Simplify<CoreOptions<Rules, Characteristics> & {
22
49
  /**
23
- * One or more IP Address of trusted proxies in front of the application.
24
- * These addresses will be excluded when Arcjet detects a public IP address.
50
+ * IP addresses and CIDR ranges of trusted load balancers and proxies
51
+ * (optional, example: `["100.100.100.100", "100.100.100.0/24"]`).
25
52
  */
26
53
  proxies?: Array<string>;
27
54
  }>;
28
55
  /**
29
- * The ArcjetAstro client provides a public `protect()` method to
30
- * make a decision about how an Astro request should be handled.
56
+ * Instance of the Astro integration of Arcjet.
57
+ *
58
+ * Primarily has a `protect()` method to make a decision about how a request
59
+ * should be handled.
60
+ *
61
+ * @template Props
62
+ * Configuration.
31
63
  */
32
64
  export interface ArcjetAstro<Props extends PlainObject> {
33
65
  /**
34
- * Runs a request through the configured protections. The request is
35
- * analyzed and then a decision made on whether to allow, deny, or challenge
36
- * the request.
66
+ * Make a decision about how to handle a request.
37
67
  *
38
- * @param request - A `Request` provided to the fetch handler.
39
- * @param props - Additonal properties required for running rules against a request.
40
- * @returns An {@link ArcjetDecision} indicating Arcjet's decision about the request.
68
+ * This will analyze the request locally where possible and otherwise call
69
+ * the Arcjet decision API.
70
+ *
71
+ * @param ctx
72
+ * Additional context for this function call.
73
+ * @param request
74
+ * Details about the {@linkcode ArcjetRequest} that Arcjet needs to make a
75
+ * decision.
76
+ * @returns
77
+ * Promise that resolves to an {@linkcode ArcjetDecision} indicating
78
+ * Arcjet’s decision about the request.
41
79
  */
42
80
  protect(request: Request, ...props: Props extends WithoutCustomProps ? [] : [Props]): Promise<ArcjetDecision>;
43
81
  /**
44
- * Augments the client with another rule. Useful for varying rules based on
45
- * criteria in your handler—e.g. different rate limit for logged in users.
82
+ * Augment the client with another rule.
83
+ *
84
+ * Useful for varying rules based on criteria in your handler such as
85
+ * different rate limit for logged in users.
46
86
  *
47
- * @param rule The rule to add to this execution.
48
- * @returns An augmented {@link ArcjetAstro} client.
87
+ * @template Rule
88
+ * Type of rule.
89
+ * @param rule
90
+ * Rule to add to Arcjet.
91
+ * @returns
92
+ * Arcjet instance augmented with the given rule.
49
93
  */
50
94
  withRule<Rule extends Primitive | Product>(rule: Rule): ArcjetAstro<Simplify<Props & ExtraProps<Rule>>>;
51
95
  }
52
96
  /**
53
- * Create a new {@link ArcjetAstro} client. Always build your initial client
54
- * outside of a request handler so it persists across requests. If you need to
55
- * augment a client inside a handler, call the `withRule()` function on the base
56
- * client.
97
+ * Create a new Astro integration of Arcjet.
57
98
  *
58
- * @param options - Arcjet configuration options to apply to all requests.
99
+ * @template Rules
100
+ * List of rules.
101
+ * @template Characteristics
102
+ * Characteristics to track a user by.
103
+ * @param options
104
+ * Configuration.
105
+ * @returns
106
+ * Astro integration of Arcjet.
59
107
  */
60
108
  export declare function createArcjetClient<const Rules extends (Primitive | Product)[], const Characteristics extends readonly string[]>(options: ArcjetOptions<Rules, Characteristics>): ArcjetAstro<Simplify<ExtraProps<Rules> & CharacteristicProps<Characteristics>>>;
package/internal.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import core__default from 'arcjet';
2
2
  export * from 'arcjet';
3
- import findIP, { parseProxy } from '@arcjet/ip';
4
- import ArcjetHeaders from '@arcjet/headers';
3
+ import findIp, { parseProxy } from '@arcjet/ip';
4
+ import { ArcjetHeaders } from '@arcjet/headers';
5
5
  import { baseUrl, isDevelopment, logLevel, platform } from '@arcjet/env';
6
6
  import { Logger } from '@arcjet/logger';
7
7
  import { createClient } from '@arcjet/protocol/client.js';
@@ -36,17 +36,21 @@ function errorMessage(err) {
36
36
  }
37
37
  return "Unknown problem";
38
38
  }
39
+ /**
40
+ * Create a remote client.
41
+ *
42
+ * @param options
43
+ * Configuration (optional).
44
+ * @returns
45
+ * Client.
46
+ */
39
47
  function createRemoteClient(options) {
40
- // The base URL for the Arcjet API. Will default to the standard production
41
- // API unless environment variable `ARCJET_BASE_URL` is set.
42
48
  const url = options?.baseUrl ?? baseUrl(env);
43
- // The timeout for the Arcjet API in milliseconds. This is set to a low value
44
- // in production so calls fail open.
45
49
  const timeout = options?.timeout ?? (isDevelopment(env) ? 1000 : 500);
46
50
  // Transport is the HTTP client that the client uses to make requests.
47
51
  const transport = createTransport(url);
48
52
  const sdkStack = "ASTRO";
49
- const sdkVersion = "1.0.0-beta.10";
53
+ const sdkVersion = "1.0.0-beta.12";
50
54
  return createClient({
51
55
  transport,
52
56
  baseUrl: url,
@@ -56,12 +60,16 @@ function createRemoteClient(options) {
56
60
  });
57
61
  }
58
62
  /**
59
- * Create a new {@link ArcjetAstro} client. Always build your initial client
60
- * outside of a request handler so it persists across requests. If you need to
61
- * augment a client inside a handler, call the `withRule()` function on the base
62
- * client.
63
+ * Create a new Astro integration of Arcjet.
63
64
  *
64
- * @param options - Arcjet configuration options to apply to all requests.
65
+ * @template Rules
66
+ * List of rules.
67
+ * @template Characteristics
68
+ * Characteristics to track a user by.
69
+ * @param options
70
+ * Configuration.
71
+ * @returns
72
+ * Astro integration of Arcjet.
65
73
  */
66
74
  function createArcjetClient(options) {
67
75
  const client = options.client ?? createRemoteClient();
@@ -85,7 +93,7 @@ function createArcjetClient(options) {
85
93
  // We construct an ArcjetHeaders to normalize over Headers
86
94
  const headers = new ArcjetHeaders(request.headers);
87
95
  const url = new URL(request.url);
88
- let ip = findIP({
96
+ let ip = findIp({
89
97
  ip: clientAddress,
90
98
  headers,
91
99
  }, { platform: platform(env), proxies });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@arcjet/astro",
3
- "version": "1.0.0-beta.10",
3
+ "version": "1.0.0-beta.12",
4
4
  "description": "Arcjet helps developers protect their Astro sites in just a few lines of code. Bot detection. Rate limiting. Email validation. Attack protection. Data redaction. A developer-first approach to security.",
5
5
  "keywords": [
6
6
  "analyze",
@@ -47,27 +47,28 @@
47
47
  "build": "rollup --config rollup.config.js",
48
48
  "lint": "eslint .",
49
49
  "prepublishOnly": "npm run build",
50
- "test": "npm run build && npm run lint"
50
+ "test-api": "node --test",
51
+ "test-coverage": "node --experimental-test-coverage --test",
52
+ "test": "npm run build && npm run lint && npm run test-coverage"
51
53
  },
52
54
  "dependencies": {
53
- "@arcjet/env": "1.0.0-beta.10",
54
- "@arcjet/headers": "1.0.0-beta.10",
55
- "@arcjet/ip": "1.0.0-beta.10",
56
- "@arcjet/logger": "1.0.0-beta.10",
57
- "@arcjet/protocol": "1.0.0-beta.10",
58
- "@arcjet/transport": "1.0.0-beta.10",
59
- "arcjet": "1.0.0-beta.10"
55
+ "@arcjet/env": "1.0.0-beta.12",
56
+ "@arcjet/headers": "1.0.0-beta.12",
57
+ "@arcjet/ip": "1.0.0-beta.12",
58
+ "@arcjet/logger": "1.0.0-beta.12",
59
+ "@arcjet/protocol": "1.0.0-beta.12",
60
+ "@arcjet/transport": "1.0.0-beta.12",
61
+ "arcjet": "1.0.0-beta.12"
60
62
  },
61
63
  "peerDependencies": {
62
64
  "astro": "^5.9.3"
63
65
  },
64
66
  "devDependencies": {
65
- "@arcjet/eslint-config": "1.0.0-beta.10",
66
- "@arcjet/rollup-config": "1.0.0-beta.10",
67
- "@arcjet/tsconfig": "1.0.0-beta.10",
68
- "@rollup/wasm-node": "4.46.2",
69
- "astro": "5.12.8",
70
- "eslint": "9.32.0",
67
+ "@arcjet/eslint-config": "1.0.0-beta.12",
68
+ "@arcjet/rollup-config": "1.0.0-beta.12",
69
+ "@rollup/wasm-node": "4.50.0",
70
+ "astro": "5.13.5",
71
+ "eslint": "9.34.0",
71
72
  "typescript": "5.9.2"
72
73
  },
73
74
  "publishConfig": {