Comparing version 1.0.0-alpha.17 to 1.0.0-alpha.18
@@ -103,2 +103,3 @@ import { ArcjetBotType, ArcjetEmailType, ArcjetMode, ArcjetDecision, ArcjetRule, ArcjetLogger } from "@arcjet/protocol"; | ||
type PropsForCharacteristic<T> = IsStringLiteral<T> extends true ? T extends "ip.src" | "http.host" | "http.method" | "http.request.uri.path" | `http.request.headers["${string}"]` | `http.request.cookie["${string}"]` | `http.request.uri.args["${string}"]` ? {} : T extends string ? Record<T, string | number | boolean> : never : {}; | ||
export type CharacteristicProps<Characteristics extends readonly string[]> = UnionToIntersection<PropsForCharacteristic<Characteristics[number]>>; | ||
type PropsForRule<R> = R extends ArcjetRule<infer Props> ? Props : {}; | ||
@@ -138,5 +139,5 @@ export type ExtraProps<Rules> = Rules extends [] ? {} : Rules extends ArcjetRule[][] ? UnionToIntersection<PropsForRule<Rules[number][number]>> : Rules extends ArcjetRule[] ? UnionToIntersection<PropsForRule<Rules[number]>> : never; | ||
requested: number; | ||
} | PropsForCharacteristic<Characteristics[number]>>>>; | ||
export declare function fixedWindow<const Characteristics extends readonly string[] = []>(options?: FixedWindowRateLimitOptions<Characteristics>, ...additionalOptions: FixedWindowRateLimitOptions<Characteristics>[]): Primitive<Simplify<UnionToIntersection<PropsForCharacteristic<Characteristics[number]>>>>; | ||
export declare function slidingWindow<const Characteristics extends readonly string[] = []>(options?: SlidingWindowRateLimitOptions<Characteristics>, ...additionalOptions: SlidingWindowRateLimitOptions<Characteristics>[]): Primitive<Simplify<UnionToIntersection<PropsForCharacteristic<Characteristics[number]>>>>; | ||
} | CharacteristicProps<Characteristics>>>>; | ||
export declare function fixedWindow<const Characteristics extends readonly string[] = []>(options?: FixedWindowRateLimitOptions<Characteristics>, ...additionalOptions: FixedWindowRateLimitOptions<Characteristics>[]): Primitive<Simplify<CharacteristicProps<Characteristics>>>; | ||
export declare function slidingWindow<const Characteristics extends readonly string[] = []>(options?: SlidingWindowRateLimitOptions<Characteristics>, ...additionalOptions: SlidingWindowRateLimitOptions<Characteristics>[]): Primitive<Simplify<CharacteristicProps<Characteristics>>>; | ||
export declare function validateEmail(options?: EmailOptions, ...additionalOptions: EmailOptions[]): Primitive<{ | ||
@@ -157,4 +158,4 @@ email: string; | ||
email: string; | ||
} | PropsForCharacteristic<Characteristics[number]>>>>; | ||
export interface ArcjetOptions<Rules extends [...(Primitive | Product)[]]> { | ||
} | CharacteristicProps<Characteristics>>>>; | ||
export interface ArcjetOptions<Rules extends [...(Primitive | Product)[]], Characteristics extends readonly string[]> { | ||
/** | ||
@@ -169,2 +170,6 @@ * The API key to identify the site in Arcjet. | ||
/** | ||
* Characteristics to be used to uniquely identify clients. | ||
*/ | ||
characteristics?: Characteristics; | ||
/** | ||
* The client used to make requests to the Arcjet API. This must be set | ||
@@ -207,2 +212,2 @@ * when creating the SDK, such as inside @arcjet/next or mocked in tests. | ||
*/ | ||
export default function arcjet<const Rules extends [...(Primitive | Product)[]] = []>(options: ArcjetOptions<Rules>): Arcjet<Simplify<ExtraProps<Rules>>>; | ||
export default function arcjet<const Rules extends [...(Primitive | Product)[]] = [], const Characteristics extends readonly string[] = []>(options: ArcjetOptions<Rules, Characteristics>): Arcjet<Simplify<ExtraProps<Rules> & CharacteristicProps<Characteristics>>>; |
26
index.js
import { ArcjetRuleResult, ArcjetEmailReason, ArcjetBotType, ArcjetErrorReason, ArcjetBotReason, ArcjetErrorDecision, ArcjetReason, ArcjetDenyDecision } from '@arcjet/protocol'; | ||
export * from '@arcjet/protocol'; | ||
import { ArcjetBotTypeToProtocol } from '@arcjet/protocol/convert.js'; | ||
import { ArcjetBotTypeToProtocol, isRateLimitRule } from '@arcjet/protocol/convert.js'; | ||
import * as analyze from '@arcjet/analyze'; | ||
@@ -424,15 +424,12 @@ import * as duration from '@arcjet/duration'; | ||
log.time?.("fingerprint"); | ||
let ip = ""; | ||
if (typeof details.ip === "string") { | ||
ip = details.ip; | ||
} | ||
if (details.ip === "") { | ||
log.warn("generateFingerprint: ip is empty"); | ||
} | ||
const characteristics = options.characteristics | ||
? [...options.characteristics] | ||
: []; | ||
const baseContext = { | ||
key, | ||
log, | ||
characteristics, | ||
...ctx, | ||
}; | ||
const fingerprint = await analyze.generateFingerprint(baseContext, ip); | ||
const fingerprint = await analyze.generateFingerprint(baseContext, details); | ||
log.debug("fingerprint (%s): %s", rt, fingerprint); | ||
@@ -465,4 +462,4 @@ log.timeEnd?.("fingerprint"); | ||
const results = []; | ||
// Default all rules to NOT_RUN/ALLOW before doing anything | ||
for (let idx = 0; idx < rules.length; idx++) { | ||
// Default all rules to NOT_RUN/ALLOW before doing anything | ||
results[idx] = new ArcjetRuleResult({ | ||
@@ -474,2 +471,11 @@ ttl: 0, | ||
}); | ||
// Add top-level characteristics to all Rate Limit rules that don't already have | ||
// their own set of characteristics. | ||
const candidate_rule = rules[idx]; | ||
if (isRateLimitRule(candidate_rule)) { | ||
if (typeof candidate_rule.characteristics === "undefined") { | ||
candidate_rule.characteristics = characteristics; | ||
rules[idx] = candidate_rule; | ||
} | ||
} | ||
} | ||
@@ -476,0 +482,0 @@ // We have our own local cache which we check first. This doesn't work in |
60
index.ts
@@ -24,4 +24,8 @@ import { | ||
ArcjetLogger, | ||
ArcjetRateLimitRule, | ||
} from "@arcjet/protocol"; | ||
import { ArcjetBotTypeToProtocol } from "@arcjet/protocol/convert.js"; | ||
import { | ||
ArcjetBotTypeToProtocol, | ||
isRateLimitRule, | ||
} from "@arcjet/protocol/convert.js"; | ||
import { Client } from "@arcjet/protocol/client.js"; | ||
@@ -333,2 +337,4 @@ import * as analyze from "@arcjet/analyze"; | ||
: {}; | ||
export type CharacteristicProps<Characteristics extends readonly string[]> = | ||
UnionToIntersection<PropsForCharacteristic<Characteristics[number]>>; | ||
// Rules can specify they require specific props on an ArcjetRequest | ||
@@ -401,3 +407,3 @@ type PropsForRule<R> = R extends ArcjetRule<infer Props> ? Props : {}; | ||
UnionToIntersection< | ||
{ requested: number } | PropsForCharacteristic<Characteristics[number]> | ||
{ requested: number } | CharacteristicProps<Characteristics> | ||
> | ||
@@ -444,5 +450,3 @@ > | ||
...additionalOptions: FixedWindowRateLimitOptions<Characteristics>[] | ||
): Primitive< | ||
Simplify<UnionToIntersection<PropsForCharacteristic<Characteristics[number]>>> | ||
> { | ||
): Primitive<Simplify<CharacteristicProps<Characteristics>>> { | ||
const rules: ArcjetFixedWindowRateLimitRule<{}>[] = []; | ||
@@ -484,5 +488,3 @@ | ||
...additionalOptions: SlidingWindowRateLimitOptions<Characteristics>[] | ||
): Primitive< | ||
Simplify<UnionToIntersection<PropsForCharacteristic<Characteristics[number]>>> | ||
> { | ||
): Primitive<Simplify<CharacteristicProps<Characteristics>>> { | ||
const rules: ArcjetSlidingWindowRateLimitRule<{}>[] = []; | ||
@@ -755,3 +757,3 @@ | ||
UnionToIntersection< | ||
{ email: string } | PropsForCharacteristic<Characteristics[number]> | ||
{ email: string } | CharacteristicProps<Characteristics> | ||
> | ||
@@ -784,3 +786,6 @@ > | ||
export interface ArcjetOptions<Rules extends [...(Primitive | Product)[]]> { | ||
export interface ArcjetOptions< | ||
Rules extends [...(Primitive | Product)[]], | ||
Characteristics extends readonly string[], | ||
> { | ||
/** | ||
@@ -795,2 +800,6 @@ * The API key to identify the site in Arcjet. | ||
/** | ||
* Characteristics to be used to uniquely identify clients. | ||
*/ | ||
characteristics?: Characteristics; | ||
/** | ||
* The client used to make requests to the Arcjet API. This must be set | ||
@@ -843,3 +852,6 @@ * when creating the SDK, such as inside @arcjet/next or mocked in tests. | ||
const Rules extends [...(Primitive | Product)[]] = [], | ||
>(options: ArcjetOptions<Rules>): Arcjet<Simplify<ExtraProps<Rules>>> { | ||
const Characteristics extends readonly string[] = [], | ||
>( | ||
options: ArcjetOptions<Rules, Characteristics>, | ||
): Arcjet<Simplify<ExtraProps<Rules> & CharacteristicProps<Characteristics>>> { | ||
// We destructure here to make the function signature neat when viewed by consumers | ||
@@ -902,17 +914,15 @@ const { key, rules } = options; | ||
log.time?.("fingerprint"); | ||
let ip = ""; | ||
if (typeof details.ip === "string") { | ||
ip = details.ip; | ||
} | ||
if (details.ip === "") { | ||
log.warn("generateFingerprint: ip is empty"); | ||
} | ||
const characteristics = options.characteristics | ||
? [...options.characteristics] | ||
: []; | ||
const baseContext = { | ||
key, | ||
log, | ||
characteristics, | ||
...ctx, | ||
}; | ||
const fingerprint = await analyze.generateFingerprint(baseContext, ip); | ||
const fingerprint = await analyze.generateFingerprint(baseContext, details); | ||
log.debug("fingerprint (%s): %s", rt, fingerprint); | ||
@@ -958,4 +968,4 @@ log.timeEnd?.("fingerprint"); | ||
const results: ArcjetRuleResult[] = []; | ||
// Default all rules to NOT_RUN/ALLOW before doing anything | ||
for (let idx = 0; idx < rules.length; idx++) { | ||
// Default all rules to NOT_RUN/ALLOW before doing anything | ||
results[idx] = new ArcjetRuleResult({ | ||
@@ -967,2 +977,12 @@ ttl: 0, | ||
}); | ||
// Add top-level characteristics to all Rate Limit rules that don't already have | ||
// their own set of characteristics. | ||
const candidate_rule = rules[idx]; | ||
if (isRateLimitRule(candidate_rule)) { | ||
if (typeof candidate_rule.characteristics === "undefined") { | ||
candidate_rule.characteristics = characteristics; | ||
rules[idx] = candidate_rule; | ||
} | ||
} | ||
} | ||
@@ -969,0 +989,0 @@ |
{ | ||
"name": "arcjet", | ||
"version": "1.0.0-alpha.17", | ||
"version": "1.0.0-alpha.18", | ||
"description": "Arcjet TypeScript and JavaScript SDK core", | ||
@@ -43,12 +43,12 @@ "license": "Apache-2.0", | ||
"dependencies": { | ||
"@arcjet/analyze": "1.0.0-alpha.17", | ||
"@arcjet/duration": "1.0.0-alpha.17", | ||
"@arcjet/headers": "1.0.0-alpha.17", | ||
"@arcjet/protocol": "1.0.0-alpha.17", | ||
"@arcjet/runtime": "1.0.0-alpha.17" | ||
"@arcjet/analyze": "1.0.0-alpha.18", | ||
"@arcjet/duration": "1.0.0-alpha.18", | ||
"@arcjet/headers": "1.0.0-alpha.18", | ||
"@arcjet/protocol": "1.0.0-alpha.18", | ||
"@arcjet/runtime": "1.0.0-alpha.18" | ||
}, | ||
"devDependencies": { | ||
"@arcjet/eslint-config": "1.0.0-alpha.17", | ||
"@arcjet/rollup-config": "1.0.0-alpha.17", | ||
"@arcjet/tsconfig": "1.0.0-alpha.17", | ||
"@arcjet/eslint-config": "1.0.0-alpha.18", | ||
"@arcjet/rollup-config": "1.0.0-alpha.18", | ||
"@arcjet/tsconfig": "1.0.0-alpha.18", | ||
"@edge-runtime/jest-environment": "2.3.10", | ||
@@ -59,3 +59,3 @@ "@jest/globals": "29.7.0", | ||
"jest": "29.7.0", | ||
"typescript": "5.4.5" | ||
"typescript": "5.5.2" | ||
}, | ||
@@ -62,0 +62,0 @@ "publishConfig": { |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
83215
1892
+ Added@arcjet/analyze@1.0.0-alpha.18(transitive)
+ Added@arcjet/duration@1.0.0-alpha.18(transitive)
+ Added@arcjet/headers@1.0.0-alpha.18(transitive)
+ Added@arcjet/protocol@1.0.0-alpha.18(transitive)
+ Added@arcjet/runtime@1.0.0-alpha.18(transitive)
- Removed@arcjet/analyze@1.0.0-alpha.17(transitive)
- Removed@arcjet/headers@1.0.0-alpha.17(transitive)
- Removed@arcjet/protocol@1.0.0-alpha.17(transitive)
- Removed@arcjet/runtime@1.0.0-alpha.17(transitive)