@arcjet/astro 1.6.0 → 1.7.0-rc.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.
- package/{index.d.ts → dist/index.d.ts} +103 -101
- package/dist/index.js +584 -0
- package/dist/internal.d.ts +118 -0
- package/dist/internal.js +118 -0
- package/dist/middleware.d.ts +4 -0
- package/dist/middleware.js +9 -0
- package/package.json +42 -43
- package/index.js +0 -681
- package/internal.d.ts +0 -123
- package/internal.js +0 -148
- package/middleware.d.ts +0 -1
- package/middleware.js +0 -14
package/dist/index.js
ADDED
|
@@ -0,0 +1,584 @@
|
|
|
1
|
+
import fs from "node:fs/promises";
|
|
2
|
+
import { z } from "astro/zod";
|
|
3
|
+
import { cloudflare } from "@arcjet/ip";
|
|
4
|
+
//#region src/index.ts
|
|
5
|
+
const resolvedVirtualClientId = "\0ARCJET_VIRTUAL_CLIENT";
|
|
6
|
+
const validateMode = z.enum(["LIVE", "DRY_RUN"]);
|
|
7
|
+
const validateProxyService = z.object({
|
|
8
|
+
kind: z.literal("service"),
|
|
9
|
+
name: z.string(),
|
|
10
|
+
ranges: z.array(z.string()),
|
|
11
|
+
clientIp: z.array(z.object({
|
|
12
|
+
header: z.string(),
|
|
13
|
+
format: z.enum(["ip", "ips"])
|
|
14
|
+
}))
|
|
15
|
+
});
|
|
16
|
+
const validateProxies = z.array(z.union([z.string(), validateProxyService]));
|
|
17
|
+
const validateCharacteristics = z.array(z.string());
|
|
18
|
+
const validateClientOptions = z.object({
|
|
19
|
+
baseUrl: z.string().optional(),
|
|
20
|
+
timeout: z.number().optional()
|
|
21
|
+
}).strict().optional();
|
|
22
|
+
const validateShieldOptions = z.object({ mode: validateMode.optional() }).strict();
|
|
23
|
+
const validateBotOptions = z.union([z.object({
|
|
24
|
+
mode: validateMode.optional(),
|
|
25
|
+
allow: z.array(z.string())
|
|
26
|
+
}).strict(), z.object({
|
|
27
|
+
mode: validateMode.optional(),
|
|
28
|
+
deny: z.array(z.string())
|
|
29
|
+
}).strict()]);
|
|
30
|
+
const validateEmailOptions = z.union([z.object({
|
|
31
|
+
mode: validateMode.optional(),
|
|
32
|
+
allow: z.array(z.string()),
|
|
33
|
+
requireTopLevelDomain: z.boolean().optional(),
|
|
34
|
+
allowDomainLiteral: z.boolean().optional()
|
|
35
|
+
}).strict(), z.object({
|
|
36
|
+
mode: validateMode.optional(),
|
|
37
|
+
deny: z.array(z.string()),
|
|
38
|
+
requireTopLevelDomain: z.boolean().optional(),
|
|
39
|
+
allowDomainLiteral: z.boolean().optional()
|
|
40
|
+
}).strict()]);
|
|
41
|
+
const validateFilterOptions = z.union([z.object({
|
|
42
|
+
mode: validateMode.optional(),
|
|
43
|
+
allow: z.array(z.string())
|
|
44
|
+
}).strict(), z.object({
|
|
45
|
+
mode: validateMode.optional(),
|
|
46
|
+
deny: z.array(z.string())
|
|
47
|
+
}).strict()]);
|
|
48
|
+
const validateSensitiveInfoOptions = z.union([z.object({
|
|
49
|
+
mode: validateMode.optional(),
|
|
50
|
+
allow: z.array(z.string()),
|
|
51
|
+
contextWindowSize: z.number().optional()
|
|
52
|
+
}).strict(), z.object({
|
|
53
|
+
mode: validateMode.optional(),
|
|
54
|
+
deny: z.array(z.string()),
|
|
55
|
+
contextWindowSize: z.number().optional()
|
|
56
|
+
}).strict()]);
|
|
57
|
+
const validateFixedWindowOptions = z.object({
|
|
58
|
+
mode: validateMode.optional(),
|
|
59
|
+
characteristics: validateCharacteristics.optional(),
|
|
60
|
+
window: z.union([z.string(), z.number()]),
|
|
61
|
+
max: z.number()
|
|
62
|
+
}).strict();
|
|
63
|
+
const validateSlidingWindowOptions = z.object({
|
|
64
|
+
mode: validateMode.optional(),
|
|
65
|
+
characteristics: validateCharacteristics.optional(),
|
|
66
|
+
interval: z.union([z.string(), z.number()]),
|
|
67
|
+
max: z.number()
|
|
68
|
+
}).strict();
|
|
69
|
+
const validateTokenBucketOptions = z.object({
|
|
70
|
+
mode: validateMode.optional(),
|
|
71
|
+
characteristics: validateCharacteristics.optional(),
|
|
72
|
+
refillRate: z.number(),
|
|
73
|
+
interval: z.union([z.string(), z.number()]),
|
|
74
|
+
capacity: z.number()
|
|
75
|
+
}).strict();
|
|
76
|
+
const validateProtectSignupOptions = z.object({
|
|
77
|
+
rateLimit: validateSlidingWindowOptions,
|
|
78
|
+
bots: validateBotOptions,
|
|
79
|
+
email: validateEmailOptions
|
|
80
|
+
}).strict();
|
|
81
|
+
const validateDetectPromptInjectionOptions = z.object({
|
|
82
|
+
mode: validateMode.optional(),
|
|
83
|
+
threshold: z.number().optional()
|
|
84
|
+
}).strict();
|
|
85
|
+
function validateAndSerialize(schema, value) {
|
|
86
|
+
const v = schema.parse(value);
|
|
87
|
+
return v ? JSON.stringify(v) : "";
|
|
88
|
+
}
|
|
89
|
+
function integrationRuleToClientRule(rule) {
|
|
90
|
+
switch (rule.type) {
|
|
91
|
+
case "shield": return {
|
|
92
|
+
importName: `shield`,
|
|
93
|
+
code: `shield(${validateAndSerialize(validateShieldOptions, rule.options)})`
|
|
94
|
+
};
|
|
95
|
+
case "bot": return {
|
|
96
|
+
importName: `detectBot`,
|
|
97
|
+
code: `detectBot(${validateAndSerialize(validateBotOptions, rule.options)})`
|
|
98
|
+
};
|
|
99
|
+
case "email": return {
|
|
100
|
+
importName: `validateEmail`,
|
|
101
|
+
code: `validateEmail(${validateAndSerialize(validateEmailOptions, rule.options)})`
|
|
102
|
+
};
|
|
103
|
+
case "filter": return {
|
|
104
|
+
importName: `filter`,
|
|
105
|
+
code: `filter(${validateAndSerialize(validateFilterOptions, rule.options)})`
|
|
106
|
+
};
|
|
107
|
+
case "sensitiveInfo": return {
|
|
108
|
+
importName: `sensitiveInfo`,
|
|
109
|
+
code: `sensitiveInfo(${validateAndSerialize(validateSensitiveInfoOptions, rule.options)})`
|
|
110
|
+
};
|
|
111
|
+
case "fixedWindow": return {
|
|
112
|
+
importName: `fixedWindow`,
|
|
113
|
+
code: `fixedWindow(${validateAndSerialize(validateFixedWindowOptions, rule.options)})`
|
|
114
|
+
};
|
|
115
|
+
case "slidingWindow": return {
|
|
116
|
+
importName: `slidingWindow`,
|
|
117
|
+
code: `slidingWindow(${validateAndSerialize(validateSlidingWindowOptions, rule.options)})`
|
|
118
|
+
};
|
|
119
|
+
case "tokenBucket": return {
|
|
120
|
+
importName: `tokenBucket`,
|
|
121
|
+
code: `tokenBucket(${validateAndSerialize(validateTokenBucketOptions, rule.options)})`
|
|
122
|
+
};
|
|
123
|
+
case "protectSignup": return {
|
|
124
|
+
importName: `protectSignup`,
|
|
125
|
+
code: `protectSignup(${validateAndSerialize(validateProtectSignupOptions, rule.options)})`
|
|
126
|
+
};
|
|
127
|
+
case "detectPromptInjection": return {
|
|
128
|
+
importName: `detectPromptInjection`,
|
|
129
|
+
code: `detectPromptInjection(${validateAndSerialize(validateDetectPromptInjectionOptions, rule.options)})`
|
|
130
|
+
};
|
|
131
|
+
default: throw new Error("Cannot convert rule via integration");
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Arcjet Shield WAF rule.
|
|
136
|
+
*
|
|
137
|
+
* Applying this rule protects your application against common attacks,
|
|
138
|
+
* including the OWASP Top 10.
|
|
139
|
+
*
|
|
140
|
+
* The Arcjet Shield WAF analyzes every request to your application to detect
|
|
141
|
+
* suspicious activity.
|
|
142
|
+
* Once a certain suspicion threshold is reached,
|
|
143
|
+
* subsequent requests from that client are blocked for a period of time.
|
|
144
|
+
*
|
|
145
|
+
* @param options
|
|
146
|
+
* Configuration for the Shield rule.
|
|
147
|
+
* @returns
|
|
148
|
+
* Astro integration Shield rule to provide to the SDK in the `rules` field.
|
|
149
|
+
*/
|
|
150
|
+
function shield(options) {
|
|
151
|
+
return {
|
|
152
|
+
type: "shield",
|
|
153
|
+
options
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Arcjet bot detection rule.
|
|
158
|
+
*
|
|
159
|
+
* Applying this rule allows you to manage traffic by automated clients and
|
|
160
|
+
* bots.
|
|
161
|
+
*
|
|
162
|
+
* Bots can be good (such as search engine crawlers or monitoring agents) or bad
|
|
163
|
+
* (such as scrapers or automated scripts).
|
|
164
|
+
* Arcjet allows you to configure which bots you want to allow or deny by
|
|
165
|
+
* specific bot names such as curl, as well as by category such as search
|
|
166
|
+
* engine bots.
|
|
167
|
+
*
|
|
168
|
+
* Bots are detected based on various signals such as the user agent, IP
|
|
169
|
+
* address, DNS records, and more.
|
|
170
|
+
*
|
|
171
|
+
* @param options
|
|
172
|
+
* Configuration for the bot rule (required).
|
|
173
|
+
* @returns
|
|
174
|
+
* Astro integration Bot rule to provide to the SDK in the `rules` field.
|
|
175
|
+
*/
|
|
176
|
+
function detectBot(options) {
|
|
177
|
+
return {
|
|
178
|
+
type: "bot",
|
|
179
|
+
options
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* Arcjet email validation rule.
|
|
184
|
+
*
|
|
185
|
+
* Applying this rule allows you to validate and verify an email address.
|
|
186
|
+
*
|
|
187
|
+
* The first step of the analysis is to validate the email address syntax.
|
|
188
|
+
* This runs locally within the SDK and validates the email address is in the
|
|
189
|
+
* correct format.
|
|
190
|
+
* If the email syntax is valid, the SDK will pass the email address to the
|
|
191
|
+
* Arcjet cloud API to verify the email address.
|
|
192
|
+
* This performs several checks, depending on the rule configuration.
|
|
193
|
+
*
|
|
194
|
+
* @param options
|
|
195
|
+
* Configuration for the email validation rule (required).
|
|
196
|
+
* @returns
|
|
197
|
+
* Astro integration Email rule to provide to the SDK in the `rules` field.
|
|
198
|
+
*/
|
|
199
|
+
function validateEmail(options) {
|
|
200
|
+
return {
|
|
201
|
+
type: "email",
|
|
202
|
+
options
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* Arcjet filter rule.
|
|
207
|
+
*
|
|
208
|
+
* Applying this rule lets you block requests using Wireshark-like display
|
|
209
|
+
* filter expressions over HTTP headers, IP addresses, and other request
|
|
210
|
+
* fields.
|
|
211
|
+
* You can quickly enforce rules like allow/deny by country, network, or
|
|
212
|
+
* `user-agent` pattern.
|
|
213
|
+
*
|
|
214
|
+
* See the [reference guide](https://docs.arcjet.com/filters/reference) for
|
|
215
|
+
* more info on the expression language fields, functions, and values.
|
|
216
|
+
*
|
|
217
|
+
* @param options
|
|
218
|
+
* Configuration (required).
|
|
219
|
+
* @returns
|
|
220
|
+
* Astro integration Filter rule to provide to the SDK in the `rules` field.
|
|
221
|
+
*
|
|
222
|
+
* @example
|
|
223
|
+
* In this example, the expression matches non-VPN GET requests from the US.
|
|
224
|
+
* Requests matching the expression are allowed, all others are denied.
|
|
225
|
+
*
|
|
226
|
+
* ```ts
|
|
227
|
+
* filter({
|
|
228
|
+
* allow: [
|
|
229
|
+
* 'http.request.method eq "GET" and ip.src.country eq "US" and not ip.src.vpn',
|
|
230
|
+
* ],
|
|
231
|
+
* mode: "LIVE",
|
|
232
|
+
* })
|
|
233
|
+
* ```
|
|
234
|
+
*
|
|
235
|
+
* @link https://docs.arcjet.com/filters/reference
|
|
236
|
+
*/
|
|
237
|
+
function filter(options) {
|
|
238
|
+
return {
|
|
239
|
+
type: "filter",
|
|
240
|
+
options
|
|
241
|
+
};
|
|
242
|
+
}
|
|
243
|
+
/**
|
|
244
|
+
* Arcjet sensitive information detection rule.
|
|
245
|
+
*
|
|
246
|
+
* Applying this rule protects against clients sending you sensitive information
|
|
247
|
+
* such as personally identifiable information (PII) that you do not wish to
|
|
248
|
+
* handle.
|
|
249
|
+
* The rule runs entirely locally so no data ever leaves your environment.
|
|
250
|
+
*
|
|
251
|
+
* This rule includes built-in detections for email addresses, credit/debit card
|
|
252
|
+
* numbers, IP addresses, and phone numbers.
|
|
253
|
+
* You can also provide a custom detection function to identify additional
|
|
254
|
+
* sensitive information.
|
|
255
|
+
*
|
|
256
|
+
* @param options
|
|
257
|
+
* Configuration for the sensitive information detection rule (required).
|
|
258
|
+
* @returns
|
|
259
|
+
* Astro integration Sensitive information rule to provide to the SDK in the `rules` field.
|
|
260
|
+
*/
|
|
261
|
+
function sensitiveInfo(options) {
|
|
262
|
+
return {
|
|
263
|
+
type: "sensitiveInfo",
|
|
264
|
+
options
|
|
265
|
+
};
|
|
266
|
+
}
|
|
267
|
+
/**
|
|
268
|
+
* Arcjet fixed window rate limiting rule.
|
|
269
|
+
*
|
|
270
|
+
* Applying this rule sets a fixed window rate limit which tracks the number of
|
|
271
|
+
* requests made by a client over a fixed time window.
|
|
272
|
+
*
|
|
273
|
+
* This is the simplest algorithm.
|
|
274
|
+
* It tracks the number of requests made by a client over a fixed time window
|
|
275
|
+
* such as 60 seconds.
|
|
276
|
+
* If the client exceeds the limit, they are blocked until the window expires.
|
|
277
|
+
*
|
|
278
|
+
* This algorithm is useful when you want to apply a simple fixed limit in a
|
|
279
|
+
* fixed time window.
|
|
280
|
+
* For example, a simple limit on the total number of requests a client can make.
|
|
281
|
+
* However, it can be susceptible to the stampede problem where a client makes
|
|
282
|
+
* a burst of requests at the start of a window and then is blocked for the rest
|
|
283
|
+
* of the window.
|
|
284
|
+
* The sliding window algorithm can be used to avoid this.
|
|
285
|
+
*
|
|
286
|
+
* @template Characteristics
|
|
287
|
+
* Characteristics to track a user by.
|
|
288
|
+
* @param options
|
|
289
|
+
* Configuration for the fixed window rate limiting rule (required).
|
|
290
|
+
* @returns
|
|
291
|
+
* Astro integration Fixed window rule to provide to the SDK in the `rules` field.
|
|
292
|
+
*/
|
|
293
|
+
function fixedWindow(options) {
|
|
294
|
+
return {
|
|
295
|
+
type: "fixedWindow",
|
|
296
|
+
options
|
|
297
|
+
};
|
|
298
|
+
}
|
|
299
|
+
/**
|
|
300
|
+
* Arcjet sliding window rate limiting rule.
|
|
301
|
+
*
|
|
302
|
+
* Applying this rule sets a sliding window rate limit which tracks the number
|
|
303
|
+
* of requests made by a client over a sliding window so that the window moves
|
|
304
|
+
* with time.
|
|
305
|
+
*
|
|
306
|
+
* This algorithm is useful to avoid the stampede problem of the fixed window.
|
|
307
|
+
* It provides smoother rate limiting over time and can prevent a client from
|
|
308
|
+
* making a burst of requests at the start of a window and then being blocked
|
|
309
|
+
* for the rest of the window.
|
|
310
|
+
*
|
|
311
|
+
* @template Characteristics
|
|
312
|
+
* Characteristics to track a user by.
|
|
313
|
+
* @param options
|
|
314
|
+
* Configuration for the sliding window rate limiting rule (required).
|
|
315
|
+
* @returns
|
|
316
|
+
* Astro integration Sliding window rule to provide to the SDK in the `rules` field.
|
|
317
|
+
*/
|
|
318
|
+
function slidingWindow(options) {
|
|
319
|
+
return {
|
|
320
|
+
type: "slidingWindow",
|
|
321
|
+
options
|
|
322
|
+
};
|
|
323
|
+
}
|
|
324
|
+
/**
|
|
325
|
+
* Arcjet token bucket rate limiting rule.
|
|
326
|
+
*
|
|
327
|
+
* Applying this rule sets a token bucket rate limit.
|
|
328
|
+
*
|
|
329
|
+
* This algorithm is based on a bucket filled with a specific number of tokens.
|
|
330
|
+
* Each request withdraws some amount of tokens from the bucket and the bucket
|
|
331
|
+
* is refilled at a fixed rate.
|
|
332
|
+
* Once the bucket is empty, the client is blocked until the bucket refills.
|
|
333
|
+
*
|
|
334
|
+
* This algorithm is useful when you want to allow clients to make a burst of
|
|
335
|
+
* requests and then still be able to make requests at a slower rate.
|
|
336
|
+
*
|
|
337
|
+
* @template Characteristics
|
|
338
|
+
* Characteristics to track a user by.
|
|
339
|
+
* @param options
|
|
340
|
+
* Configuration for the token bucket rate limiting rule (required).
|
|
341
|
+
* @returns
|
|
342
|
+
* Astro integration Token bucket rule to provide to the SDK in the `rules` field.
|
|
343
|
+
*/
|
|
344
|
+
function tokenBucket(options) {
|
|
345
|
+
return {
|
|
346
|
+
type: "tokenBucket",
|
|
347
|
+
options
|
|
348
|
+
};
|
|
349
|
+
}
|
|
350
|
+
/**
|
|
351
|
+
* Arcjet signup form protection rule.
|
|
352
|
+
*
|
|
353
|
+
* Applying this rule combines rate limiting, bot protection, and email
|
|
354
|
+
* validation to protect your signup forms from abuse.
|
|
355
|
+
* Using this rule will configure the following:
|
|
356
|
+
*
|
|
357
|
+
* - Rate limiting - signup forms are a common target for bots. Arcjet’s rate
|
|
358
|
+
* limiting helps to prevent bots and other automated or malicious clients
|
|
359
|
+
* from submitting your signup form too many times in a short period of time.
|
|
360
|
+
* - Bot protection - signup forms are usually exclusively used by humans, which
|
|
361
|
+
* means that any automated submissions to the form are likely to be
|
|
362
|
+
* fraudulent.
|
|
363
|
+
* - Email validation - email addresses should be validated to ensure the signup
|
|
364
|
+
* is coming from a legitimate user with a real email address that can
|
|
365
|
+
* actually receive messages.
|
|
366
|
+
*
|
|
367
|
+
* @template Characteristics
|
|
368
|
+
* Characteristics to track a user by.
|
|
369
|
+
* @param options
|
|
370
|
+
* Configuration for the signup form protection rule.
|
|
371
|
+
* @returns
|
|
372
|
+
* Astro integration Signup form protection rule to provide to the SDK in the `rules` field.
|
|
373
|
+
*/
|
|
374
|
+
function protectSignup(options) {
|
|
375
|
+
return {
|
|
376
|
+
type: "protectSignup",
|
|
377
|
+
options
|
|
378
|
+
};
|
|
379
|
+
}
|
|
380
|
+
/**
|
|
381
|
+
* Arcjet prompt injection detection rule.
|
|
382
|
+
*
|
|
383
|
+
* Analyzes LLM prompts to detect prompt injection attempts.
|
|
384
|
+
*
|
|
385
|
+
* The Arcjet prompt injection detection rule analyzes prompts sent to LLM
|
|
386
|
+
* applications to detect jailbreak and injection attempts.
|
|
387
|
+
* The analysis is performed through Arcjet's Cloud API.
|
|
388
|
+
*
|
|
389
|
+
* @param options
|
|
390
|
+
* Configuration for the prompt injection detection rule.
|
|
391
|
+
* @returns
|
|
392
|
+
* Astro integration Prompt injection detection rule to provide to the SDK in the `rules` field.
|
|
393
|
+
*/
|
|
394
|
+
function detectPromptInjection(options = {}) {
|
|
395
|
+
return {
|
|
396
|
+
type: "detectPromptInjection",
|
|
397
|
+
options
|
|
398
|
+
};
|
|
399
|
+
}
|
|
400
|
+
/**
|
|
401
|
+
* Arcjet prompt injection detection rule.
|
|
402
|
+
*
|
|
403
|
+
* @deprecated
|
|
404
|
+
* Use `detectPromptInjection` instead.
|
|
405
|
+
*/
|
|
406
|
+
const experimental_detectPromptInjection = detectPromptInjection;
|
|
407
|
+
/**
|
|
408
|
+
* Create a remote client.
|
|
409
|
+
*
|
|
410
|
+
* @param options
|
|
411
|
+
* Configuration (optional).
|
|
412
|
+
* @returns
|
|
413
|
+
* Client.
|
|
414
|
+
*/
|
|
415
|
+
function createRemoteClient(options) {
|
|
416
|
+
const settings = options ?? {};
|
|
417
|
+
return {
|
|
418
|
+
baseUrl: settings.baseUrl,
|
|
419
|
+
timeout: settings.timeout
|
|
420
|
+
};
|
|
421
|
+
}
|
|
422
|
+
/**
|
|
423
|
+
* Create a new Astro integration of Arcjet.
|
|
424
|
+
*
|
|
425
|
+
* @template Characteristics
|
|
426
|
+
* Characteristics to track a user by.
|
|
427
|
+
* @param options
|
|
428
|
+
* Configuration.
|
|
429
|
+
* @returns
|
|
430
|
+
* Astro integration of Arcjet.
|
|
431
|
+
*/
|
|
432
|
+
function arcjet(options = { rules: [] }) {
|
|
433
|
+
const { rules, characteristics, client, proxies } = options;
|
|
434
|
+
const arcjetImports = /* @__PURE__ */ new Set();
|
|
435
|
+
const arcjetRules = [];
|
|
436
|
+
for (const rule of rules) {
|
|
437
|
+
const { importName, code } = integrationRuleToClientRule(rule);
|
|
438
|
+
arcjetImports.add(importName);
|
|
439
|
+
arcjetRules.push(code);
|
|
440
|
+
}
|
|
441
|
+
const characteristicsInjection = characteristics ? `characteristics: ${validateAndSerialize(validateCharacteristics, characteristics)},` : "";
|
|
442
|
+
const proxiesInjection = proxies ? `proxies: ${validateAndSerialize(validateProxies, proxies)},` : "";
|
|
443
|
+
const clientInjection = client ? `client: createRemoteClient(${validateAndSerialize(validateClientOptions, client)}),` : "";
|
|
444
|
+
return {
|
|
445
|
+
name: "@arcjet/astro",
|
|
446
|
+
hooks: {
|
|
447
|
+
"astro:config:setup"({ updateConfig, addMiddleware }) {
|
|
448
|
+
updateConfig({
|
|
449
|
+
env: { schema: {
|
|
450
|
+
ARCJET_KEY: {
|
|
451
|
+
type: "string",
|
|
452
|
+
context: "server",
|
|
453
|
+
access: "secret",
|
|
454
|
+
startsWith: "ajkey_"
|
|
455
|
+
},
|
|
456
|
+
ARCJET_ENV: {
|
|
457
|
+
type: "enum",
|
|
458
|
+
context: "server",
|
|
459
|
+
access: "public",
|
|
460
|
+
values: ["production", "development"],
|
|
461
|
+
optional: true
|
|
462
|
+
},
|
|
463
|
+
ARCJET_BASE_URL: {
|
|
464
|
+
type: "string",
|
|
465
|
+
context: "server",
|
|
466
|
+
access: "public",
|
|
467
|
+
startsWith: "https://",
|
|
468
|
+
optional: true
|
|
469
|
+
},
|
|
470
|
+
ARCJET_LOG_LEVEL: {
|
|
471
|
+
type: "enum",
|
|
472
|
+
context: "server",
|
|
473
|
+
access: "public",
|
|
474
|
+
values: [
|
|
475
|
+
"debug",
|
|
476
|
+
"info",
|
|
477
|
+
"warn",
|
|
478
|
+
"error"
|
|
479
|
+
],
|
|
480
|
+
optional: true
|
|
481
|
+
},
|
|
482
|
+
FLY_APP_NAME: {
|
|
483
|
+
type: "string",
|
|
484
|
+
context: "server",
|
|
485
|
+
access: "public",
|
|
486
|
+
optional: true
|
|
487
|
+
},
|
|
488
|
+
VERCEL: {
|
|
489
|
+
type: "string",
|
|
490
|
+
context: "server",
|
|
491
|
+
access: "public",
|
|
492
|
+
optional: true
|
|
493
|
+
},
|
|
494
|
+
FIREBASE_CONFIG: {
|
|
495
|
+
access: "public",
|
|
496
|
+
context: "server",
|
|
497
|
+
optional: true,
|
|
498
|
+
type: "string"
|
|
499
|
+
},
|
|
500
|
+
RENDER: {
|
|
501
|
+
access: "public",
|
|
502
|
+
context: "server",
|
|
503
|
+
optional: true,
|
|
504
|
+
type: "string"
|
|
505
|
+
}
|
|
506
|
+
} },
|
|
507
|
+
vite: { plugins: [{
|
|
508
|
+
name: "@arcjet/astro",
|
|
509
|
+
resolveId(id) {
|
|
510
|
+
if (id === "arcjet:client") return resolvedVirtualClientId;
|
|
511
|
+
},
|
|
512
|
+
async load(id) {
|
|
513
|
+
if (id === resolvedVirtualClientId) return { code: `
|
|
514
|
+
${await fs.readFile(new URL("./internal.js", import.meta.url), { encoding: "utf-8" })}
|
|
515
|
+
|
|
516
|
+
import {
|
|
517
|
+
${Array.from(arcjetImports).join(",\n")}
|
|
518
|
+
} from "arcjet"
|
|
519
|
+
|
|
520
|
+
// Construct an Arcjet client for the virtual module
|
|
521
|
+
const aj = createArcjetClient({
|
|
522
|
+
key: ARCJET_KEY,
|
|
523
|
+
rules: [
|
|
524
|
+
${arcjetRules.join(",\n")}
|
|
525
|
+
],
|
|
526
|
+
${characteristicsInjection}
|
|
527
|
+
${proxiesInjection}
|
|
528
|
+
${clientInjection}
|
|
529
|
+
})
|
|
530
|
+
|
|
531
|
+
export default aj;
|
|
532
|
+
` };
|
|
533
|
+
}
|
|
534
|
+
}] }
|
|
535
|
+
});
|
|
536
|
+
addMiddleware({
|
|
537
|
+
entrypoint: new URL("./middleware.js", import.meta.url),
|
|
538
|
+
order: "pre"
|
|
539
|
+
});
|
|
540
|
+
},
|
|
541
|
+
"astro:config:done": async ({ buildOutput, injectTypes, logger }) => {
|
|
542
|
+
if (buildOutput === "static") logger.warn("✦ Arcjet can only protect Dynamic routes.\n\n Configure at least 1 Dynamic route to use the Arcjet integration, see Astro's\n Dynamic routes documentation for configuration details:\n https://docs.astro.build/en/guides/routing/#dynamic-routes\n");
|
|
543
|
+
injectTypes({
|
|
544
|
+
content: `
|
|
545
|
+
declare module "arcjet:client" {
|
|
546
|
+
${await fs.readFile(new URL("./internal.d.ts", import.meta.url), { encoding: "utf-8" })}
|
|
547
|
+
|
|
548
|
+
import {
|
|
549
|
+
${Array.from(arcjetImports).join(",\n")}
|
|
550
|
+
} from "arcjet"
|
|
551
|
+
|
|
552
|
+
/**
|
|
553
|
+
* Instance of the Astro integration of Arcjet.
|
|
554
|
+
*
|
|
555
|
+
* Primarily has a \`protect()\` method to make a decision about how a request
|
|
556
|
+
* should be handled.
|
|
557
|
+
*
|
|
558
|
+
* > 👉 **Note**: this is generated by \`@arcjet/astro\` based on how you configure
|
|
559
|
+
* > Arcjet in your \`astro.config.mjs\` file.
|
|
560
|
+
* > In that configuration file, you can pass the (serializable) options that apply
|
|
561
|
+
* > to all requests.
|
|
562
|
+
* > You can call \`aj.withRule\` *on* this default client to extend its behavior.
|
|
563
|
+
*
|
|
564
|
+
* @template Props
|
|
565
|
+
* Configuration.
|
|
566
|
+
*/
|
|
567
|
+
const client = createArcjetClient({
|
|
568
|
+
rules: [
|
|
569
|
+
${arcjetRules.join(",\n")}
|
|
570
|
+
],
|
|
571
|
+
${characteristicsInjection}
|
|
572
|
+
${proxiesInjection}
|
|
573
|
+
${clientInjection}
|
|
574
|
+
})
|
|
575
|
+
export default client
|
|
576
|
+
}`,
|
|
577
|
+
filename: "client.d.ts"
|
|
578
|
+
});
|
|
579
|
+
}
|
|
580
|
+
}
|
|
581
|
+
};
|
|
582
|
+
}
|
|
583
|
+
//#endregion
|
|
584
|
+
export { cloudflare, createRemoteClient, arcjet as default, detectBot, detectPromptInjection, experimental_detectPromptInjection, filter, fixedWindow, protectSignup, sensitiveInfo, shield, slidingWindow, tokenBucket, validateEmail };
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { ProxyService } from "@arcjet/ip";
|
|
2
|
+
import { ArcjetDecision, ArcjetOptions as ArcjetOptions$1, ArcjetRule, CharacteristicProps, ExtraProps, Primitive, Product } from "arcjet";
|
|
3
|
+
export * from "arcjet";
|
|
4
|
+
|
|
5
|
+
//#region src/internal.d.ts
|
|
6
|
+
type Simplify<T> = { [KeyType in keyof T]: T[KeyType] } & {};
|
|
7
|
+
declare const emptyObjectSymbol: unique symbol;
|
|
8
|
+
type PlainObject = {
|
|
9
|
+
[key: string]: unknown;
|
|
10
|
+
};
|
|
11
|
+
/**
|
|
12
|
+
* Dynamically generate whether zero or one `properties` object must or can be passed.
|
|
13
|
+
*/
|
|
14
|
+
type MaybeProperties<T> = { [P in keyof T]?: T[P] } extends T ? T extends {
|
|
15
|
+
[emptyObjectSymbol]?: never;
|
|
16
|
+
} ? [] : [properties?: T] : [properties: T];
|
|
17
|
+
/**
|
|
18
|
+
* Configuration for {@linkcode createRemoteClient}.
|
|
19
|
+
*/
|
|
20
|
+
type RemoteClientOptions = {
|
|
21
|
+
/**
|
|
22
|
+
* Base URI for HTTP requests to Decide API (optional).
|
|
23
|
+
*
|
|
24
|
+
* Defaults to the environment variable `ARCJET_BASE_URL` (if that value
|
|
25
|
+
* is known and allowed) and the standard production API otherwise.
|
|
26
|
+
*/
|
|
27
|
+
baseUrl?: string;
|
|
28
|
+
/**
|
|
29
|
+
* Timeout in milliseconds for the Decide API (optional).
|
|
30
|
+
*
|
|
31
|
+
* Defaults to `500` in production and `1000` in development.
|
|
32
|
+
*/
|
|
33
|
+
timeout?: number;
|
|
34
|
+
};
|
|
35
|
+
/**
|
|
36
|
+
* Create a remote client.
|
|
37
|
+
*
|
|
38
|
+
* @param options
|
|
39
|
+
* Configuration (optional).
|
|
40
|
+
* @returns
|
|
41
|
+
* Client.
|
|
42
|
+
*/
|
|
43
|
+
declare function createRemoteClient(options?: RemoteClientOptions): import("@arcjet/protocol/client.js").Client;
|
|
44
|
+
/**
|
|
45
|
+
* Configuration for the Astro integration of Arcjet.
|
|
46
|
+
*
|
|
47
|
+
* @template Rules
|
|
48
|
+
* List of rules.
|
|
49
|
+
* @template Characteristics
|
|
50
|
+
* Characteristics to track a user by.
|
|
51
|
+
*/
|
|
52
|
+
type ArcjetOptions<Rules extends [...Array<Primitive | Product>], Characteristics extends readonly string[]> = Simplify<ArcjetOptions$1<Rules, Characteristics> & {
|
|
53
|
+
/**
|
|
54
|
+
* IP addresses and CIDR ranges of trusted load balancers and proxies
|
|
55
|
+
* (optional, example: `["100.100.100.100", "100.100.100.0/24"]`).
|
|
56
|
+
*
|
|
57
|
+
* Proxy services such as {@linkcode cloudflare} can also be included to read
|
|
58
|
+
* the real client IP from a service-specific header when the request comes
|
|
59
|
+
* from that service.
|
|
60
|
+
*/
|
|
61
|
+
proxies?: Array<string | ProxyService>;
|
|
62
|
+
}>;
|
|
63
|
+
/**
|
|
64
|
+
* Instance of the Astro integration of Arcjet.
|
|
65
|
+
*
|
|
66
|
+
* Primarily has a `protect()` method to make a decision about how a request
|
|
67
|
+
* should be handled.
|
|
68
|
+
*
|
|
69
|
+
* @template Props
|
|
70
|
+
* Configuration.
|
|
71
|
+
*/
|
|
72
|
+
interface ArcjetAstro<Props extends PlainObject> {
|
|
73
|
+
/**
|
|
74
|
+
* Make a decision about how to handle a request.
|
|
75
|
+
*
|
|
76
|
+
* This will analyze the request locally where possible and otherwise call
|
|
77
|
+
* the Arcjet decision API.
|
|
78
|
+
*
|
|
79
|
+
* @param ctx
|
|
80
|
+
* Additional context for this function call.
|
|
81
|
+
* @param request
|
|
82
|
+
* Details about the {@linkcode ArcjetRequest} that Arcjet needs to make a
|
|
83
|
+
* decision.
|
|
84
|
+
* @returns
|
|
85
|
+
* Promise that resolves to an {@linkcode ArcjetDecision} indicating
|
|
86
|
+
* Arcjet’s decision about the request.
|
|
87
|
+
*/
|
|
88
|
+
protect(request: Request, ...props: MaybeProperties<Props>): Promise<ArcjetDecision>;
|
|
89
|
+
/**
|
|
90
|
+
* Augment the client with another rule.
|
|
91
|
+
*
|
|
92
|
+
* Useful for varying rules based on criteria in your handler such as
|
|
93
|
+
* different rate limit for logged in users.
|
|
94
|
+
*
|
|
95
|
+
* @template Rule
|
|
96
|
+
* Type of rule.
|
|
97
|
+
* @param rule
|
|
98
|
+
* Rule to add to Arcjet.
|
|
99
|
+
* @returns
|
|
100
|
+
* Arcjet instance augmented with the given rule.
|
|
101
|
+
*/
|
|
102
|
+
withRule<Rule extends ArcjetRule>(rule: Array<Rule>): ArcjetAstro<Props & (Rule extends ArcjetRule<infer P> ? P : {})>;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Create a new Astro integration of Arcjet.
|
|
106
|
+
*
|
|
107
|
+
* @template Rules
|
|
108
|
+
* List of rules.
|
|
109
|
+
* @template Characteristics
|
|
110
|
+
* Characteristics to track a user by.
|
|
111
|
+
* @param options
|
|
112
|
+
* Configuration.
|
|
113
|
+
* @returns
|
|
114
|
+
* Astro integration of Arcjet.
|
|
115
|
+
*/
|
|
116
|
+
declare function createArcjetClient<const Rules extends (Primitive | Product)[], const Characteristics extends readonly string[]>(options: ArcjetOptions<Rules, Characteristics>): ArcjetAstro<ExtraProps<Rules> & CharacteristicProps<Characteristics>>;
|
|
117
|
+
//#endregion
|
|
118
|
+
export { ArcjetAstro, ArcjetOptions, RemoteClientOptions, createArcjetClient, createRemoteClient };
|