@arcjet/node
Advanced tools
Comparing version 1.0.0-alpha.17 to 1.0.0-alpha.18
@@ -1,2 +0,2 @@ | ||
import { ArcjetDecision, ArcjetOptions, Primitive, Product, ExtraProps } from "arcjet"; | ||
import type { ArcjetDecision, ArcjetOptions, Primitive, Product, ExtraProps, CharacteristicProps } from "arcjet"; | ||
export * from "arcjet"; | ||
@@ -60,2 +60,2 @@ type Simplify<T> = { | ||
*/ | ||
export default function arcjet<const Rules extends (Primitive | Product)[]>(options: ArcjetOptions<Rules>): ArcjetNode<Simplify<ExtraProps<Rules>>>; | ||
export default function arcjet<const Rules extends (Primitive | Product)[], const Characteristics extends readonly string[]>(options: ArcjetOptions<Rules, Characteristics>): ArcjetNode<Simplify<ExtraProps<Rules> & CharacteristicProps<Characteristics>>>; |
152
index.js
@@ -6,3 +6,3 @@ import { createConnectTransport } from '@connectrpc/connect-node'; | ||
import ArcjetHeaders from '@arcjet/headers'; | ||
import { logLevel, baseUrl, isProduction, platform, isDevelopment } from '@arcjet/env'; | ||
import { logLevel, baseUrl, isDevelopment, platform } from '@arcjet/env'; | ||
import { Logger } from '@arcjet/logger'; | ||
@@ -17,3 +17,3 @@ import { createClient } from '@arcjet/protocol/client.js'; | ||
// in production so calls fail open. | ||
const timeout = options?.timeout ?? (isProduction(process.env) ? 500 : 1000); | ||
const timeout = options?.timeout ?? (isDevelopment(process.env) ? 1000 : 500); | ||
// Transport is the HTTP client that the client uses to make requests. | ||
@@ -25,3 +25,3 @@ const transport = createConnectTransport({ | ||
const sdkStack = "NODEJS"; | ||
const sdkVersion = "1.0.0-alpha.17"; | ||
const sdkVersion = "1.0.0-alpha.18"; | ||
return createClient({ | ||
@@ -45,73 +45,2 @@ transport, | ||
} | ||
function toArcjetRequest(request, props) { | ||
// We pull the cookies from the request before wrapping them in ArcjetHeaders | ||
const cookies = cookiesToString(request.headers?.cookie); | ||
// We construct an ArcjetHeaders to normalize over Headers | ||
const headers = new ArcjetHeaders(request.headers); | ||
let ip = findIP(request, headers, { platform: platform(process.env) }); | ||
if (ip === "") { | ||
// If the `ip` is empty but we're in development mode, we default the IP | ||
// so the request doesn't fail. | ||
if (isDevelopment(process.env)) { | ||
// TODO: Log that the fingerprint is being overridden once the adapter | ||
// constructs the logger | ||
ip = "127.0.0.1"; | ||
} | ||
} | ||
const method = request.method ?? ""; | ||
const host = headers.get("host") ?? ""; | ||
let path = ""; | ||
let query = ""; | ||
let protocol = ""; | ||
if (typeof request.socket?.encrypted !== "undefined") { | ||
protocol = request.socket.encrypted ? "https:" : "http:"; | ||
} | ||
else { | ||
protocol = "http:"; | ||
} | ||
// Do some very simple validation, but also try/catch around URL parsing | ||
if (typeof request.url !== "undefined" && request.url !== "" && host !== "") { | ||
try { | ||
const url = new URL(request.url, `${protocol}//${host}`); | ||
path = url.pathname; | ||
query = url.search; | ||
protocol = url.protocol; | ||
} | ||
catch { | ||
// If the parsing above fails, just set the path as whatever url we | ||
// received. | ||
// TODO(#216): Add logging to arcjet-node | ||
path = request.url ?? ""; | ||
} | ||
} | ||
else { | ||
path = request.url ?? ""; | ||
} | ||
return { | ||
...props, | ||
ip, | ||
method, | ||
protocol, | ||
host, | ||
path, | ||
headers, | ||
cookies, | ||
query, | ||
}; | ||
} | ||
function withClient(aj) { | ||
return Object.freeze({ | ||
withRule(rule) { | ||
const client = aj.withRule(rule); | ||
return withClient(client); | ||
}, | ||
async protect(request, ...[props]) { | ||
// TODO(#220): The generic manipulations get really mad here, so we cast | ||
// Further investigation makes it seem like it has something to do with | ||
// the definition of `props` in the signature but it's hard to track down | ||
const req = toArcjetRequest(request, props ?? {}); | ||
return aj.protect({}, req); | ||
}, | ||
}); | ||
} | ||
/** | ||
@@ -132,2 +61,77 @@ * Create a new {@link ArcjetNode} client. Always build your initial client | ||
}); | ||
function toArcjetRequest(request, props) { | ||
// We pull the cookies from the request before wrapping them in ArcjetHeaders | ||
const cookies = cookiesToString(request.headers?.cookie); | ||
// We construct an ArcjetHeaders to normalize over Headers | ||
const headers = new ArcjetHeaders(request.headers); | ||
let ip = findIP(request, headers, { platform: platform(process.env) }); | ||
if (ip === "") { | ||
// If the `ip` is empty but we're in development mode, we default the IP | ||
// so the request doesn't fail. | ||
if (isDevelopment(process.env)) { | ||
log.warn("Using 127.0.0.1 as IP address in development mode"); | ||
ip = "127.0.0.1"; | ||
} | ||
else { | ||
log.warn(`Client IP address is missing. If this is a dev environment set the ARCJET_ENV env var to "development"`); | ||
} | ||
} | ||
const method = request.method ?? ""; | ||
const host = headers.get("host") ?? ""; | ||
let path = ""; | ||
let query = ""; | ||
let protocol = ""; | ||
if (typeof request.socket?.encrypted !== "undefined") { | ||
protocol = request.socket.encrypted ? "https:" : "http:"; | ||
} | ||
else { | ||
protocol = "http:"; | ||
} | ||
// Do some very simple validation, but also try/catch around URL parsing | ||
if (typeof request.url !== "undefined" && | ||
request.url !== "" && | ||
host !== "") { | ||
try { | ||
const url = new URL(request.url, `${protocol}//${host}`); | ||
path = url.pathname; | ||
query = url.search; | ||
protocol = url.protocol; | ||
} | ||
catch { | ||
// If the parsing above fails, just set the path as whatever url we | ||
// received. | ||
path = request.url ?? ""; | ||
log.warn('Unable to parse URL. Using "%s" as `path`.', path); | ||
} | ||
} | ||
else { | ||
path = request.url ?? ""; | ||
} | ||
return { | ||
...props, | ||
ip, | ||
method, | ||
protocol, | ||
host, | ||
path, | ||
headers, | ||
cookies, | ||
query, | ||
}; | ||
} | ||
function withClient(aj) { | ||
return Object.freeze({ | ||
withRule(rule) { | ||
const client = aj.withRule(rule); | ||
return withClient(client); | ||
}, | ||
async protect(request, ...[props]) { | ||
// TODO(#220): The generic manipulations get really mad here, so we cast | ||
// Further investigation makes it seem like it has something to do with | ||
// the definition of `props` in the signature but it's hard to track down | ||
const req = toArcjetRequest(request, props ?? {}); | ||
return aj.protect({}, req); | ||
}, | ||
}); | ||
} | ||
const aj = core__default({ ...options, client, log }); | ||
@@ -134,0 +138,0 @@ return withClient(aj); |
208
index.ts
import { createConnectTransport } from "@connectrpc/connect-node"; | ||
import core, { | ||
import core from "arcjet"; | ||
import type { | ||
ArcjetDecision, | ||
@@ -10,12 +11,7 @@ ArcjetOptions, | ||
Arcjet, | ||
CharacteristicProps, | ||
} from "arcjet"; | ||
import findIP from "@arcjet/ip"; | ||
import ArcjetHeaders from "@arcjet/headers"; | ||
import { | ||
baseUrl, | ||
isDevelopment, | ||
isProduction, | ||
logLevel, | ||
platform, | ||
} from "@arcjet/env"; | ||
import { baseUrl, isDevelopment, logLevel, platform } from "@arcjet/env"; | ||
import { Logger } from "@arcjet/logger"; | ||
@@ -76,3 +72,3 @@ import { createClient } from "@arcjet/protocol/client.js"; | ||
// in production so calls fail open. | ||
const timeout = options?.timeout ?? (isProduction(process.env) ? 500 : 1000); | ||
const timeout = options?.timeout ?? (isDevelopment(process.env) ? 1000 : 500); | ||
@@ -153,90 +149,2 @@ // Transport is the HTTP client that the client uses to make requests. | ||
function toArcjetRequest<Props extends PlainObject>( | ||
request: ArcjetNodeRequest, | ||
props: Props, | ||
): ArcjetRequest<Props> { | ||
// We pull the cookies from the request before wrapping them in ArcjetHeaders | ||
const cookies = cookiesToString(request.headers?.cookie); | ||
// We construct an ArcjetHeaders to normalize over Headers | ||
const headers = new ArcjetHeaders(request.headers); | ||
let ip = findIP(request, headers, { platform: platform(process.env) }); | ||
if (ip === "") { | ||
// If the `ip` is empty but we're in development mode, we default the IP | ||
// so the request doesn't fail. | ||
if (isDevelopment(process.env)) { | ||
// TODO: Log that the fingerprint is being overridden once the adapter | ||
// constructs the logger | ||
ip = "127.0.0.1"; | ||
} | ||
} | ||
const method = request.method ?? ""; | ||
const host = headers.get("host") ?? ""; | ||
let path = ""; | ||
let query = ""; | ||
let protocol = ""; | ||
if (typeof request.socket?.encrypted !== "undefined") { | ||
protocol = request.socket.encrypted ? "https:" : "http:"; | ||
} else { | ||
protocol = "http:"; | ||
} | ||
// Do some very simple validation, but also try/catch around URL parsing | ||
if (typeof request.url !== "undefined" && request.url !== "" && host !== "") { | ||
try { | ||
const url = new URL(request.url, `${protocol}//${host}`); | ||
path = url.pathname; | ||
query = url.search; | ||
protocol = url.protocol; | ||
} catch { | ||
// If the parsing above fails, just set the path as whatever url we | ||
// received. | ||
// TODO(#216): Add logging to arcjet-node | ||
path = request.url ?? ""; | ||
} | ||
} else { | ||
path = request.url ?? ""; | ||
} | ||
return { | ||
...props, | ||
ip, | ||
method, | ||
protocol, | ||
host, | ||
path, | ||
headers, | ||
cookies, | ||
query, | ||
}; | ||
} | ||
function withClient<const Rules extends (Primitive | Product)[]>( | ||
aj: Arcjet<ExtraProps<Rules>>, | ||
): ArcjetNode<ExtraProps<Rules>> { | ||
return Object.freeze({ | ||
withRule(rule: Primitive | Product) { | ||
const client = aj.withRule(rule); | ||
return withClient(client); | ||
}, | ||
async protect( | ||
request: ArcjetNodeRequest, | ||
...[props]: ExtraProps<Rules> extends WithoutCustomProps | ||
? [] | ||
: [ExtraProps<Rules>] | ||
): Promise<ArcjetDecision> { | ||
// TODO(#220): The generic manipulations get really mad here, so we cast | ||
// Further investigation makes it seem like it has something to do with | ||
// the definition of `props` in the signature but it's hard to track down | ||
const req = toArcjetRequest(request, props ?? {}) as ArcjetRequest< | ||
ExtraProps<Rules> | ||
>; | ||
return aj.protect({}, req); | ||
}, | ||
}); | ||
} | ||
/** | ||
@@ -250,5 +158,10 @@ * Create a new {@link ArcjetNode} client. Always build your initial client | ||
*/ | ||
export default function arcjet<const Rules extends (Primitive | Product)[]>( | ||
options: ArcjetOptions<Rules>, | ||
): ArcjetNode<Simplify<ExtraProps<Rules>>> { | ||
export default function arcjet< | ||
const Rules extends (Primitive | Product)[], | ||
const Characteristics extends readonly string[], | ||
>( | ||
options: ArcjetOptions<Rules, Characteristics>, | ||
): ArcjetNode< | ||
Simplify<ExtraProps<Rules> & CharacteristicProps<Characteristics>> | ||
> { | ||
const client = options.client ?? createRemoteClient(); | ||
@@ -262,2 +175,97 @@ | ||
function toArcjetRequest<Props extends PlainObject>( | ||
request: ArcjetNodeRequest, | ||
props: Props, | ||
): ArcjetRequest<Props> { | ||
// We pull the cookies from the request before wrapping them in ArcjetHeaders | ||
const cookies = cookiesToString(request.headers?.cookie); | ||
// We construct an ArcjetHeaders to normalize over Headers | ||
const headers = new ArcjetHeaders(request.headers); | ||
let ip = findIP(request, headers, { platform: platform(process.env) }); | ||
if (ip === "") { | ||
// If the `ip` is empty but we're in development mode, we default the IP | ||
// so the request doesn't fail. | ||
if (isDevelopment(process.env)) { | ||
log.warn("Using 127.0.0.1 as IP address in development mode"); | ||
ip = "127.0.0.1"; | ||
} else { | ||
log.warn( | ||
`Client IP address is missing. If this is a dev environment set the ARCJET_ENV env var to "development"`, | ||
); | ||
} | ||
} | ||
const method = request.method ?? ""; | ||
const host = headers.get("host") ?? ""; | ||
let path = ""; | ||
let query = ""; | ||
let protocol = ""; | ||
if (typeof request.socket?.encrypted !== "undefined") { | ||
protocol = request.socket.encrypted ? "https:" : "http:"; | ||
} else { | ||
protocol = "http:"; | ||
} | ||
// Do some very simple validation, but also try/catch around URL parsing | ||
if ( | ||
typeof request.url !== "undefined" && | ||
request.url !== "" && | ||
host !== "" | ||
) { | ||
try { | ||
const url = new URL(request.url, `${protocol}//${host}`); | ||
path = url.pathname; | ||
query = url.search; | ||
protocol = url.protocol; | ||
} catch { | ||
// If the parsing above fails, just set the path as whatever url we | ||
// received. | ||
path = request.url ?? ""; | ||
log.warn('Unable to parse URL. Using "%s" as `path`.', path); | ||
} | ||
} else { | ||
path = request.url ?? ""; | ||
} | ||
return { | ||
...props, | ||
ip, | ||
method, | ||
protocol, | ||
host, | ||
path, | ||
headers, | ||
cookies, | ||
query, | ||
}; | ||
} | ||
function withClient<const Rules extends (Primitive | Product)[]>( | ||
aj: Arcjet<ExtraProps<Rules>>, | ||
): ArcjetNode<ExtraProps<Rules>> { | ||
return Object.freeze({ | ||
withRule(rule: Primitive | Product) { | ||
const client = aj.withRule(rule); | ||
return withClient(client); | ||
}, | ||
async protect( | ||
request: ArcjetNodeRequest, | ||
...[props]: ExtraProps<Rules> extends WithoutCustomProps | ||
? [] | ||
: [ExtraProps<Rules>] | ||
): Promise<ArcjetDecision> { | ||
// TODO(#220): The generic manipulations get really mad here, so we cast | ||
// Further investigation makes it seem like it has something to do with | ||
// the definition of `props` in the signature but it's hard to track down | ||
const req = toArcjetRequest(request, props ?? {}) as ArcjetRequest< | ||
ExtraProps<Rules> | ||
>; | ||
return aj.protect({}, req); | ||
}, | ||
}); | ||
} | ||
const aj = core({ ...options, client, log }); | ||
@@ -264,0 +272,0 @@ |
{ | ||
"name": "@arcjet/node", | ||
"version": "1.0.0-alpha.17", | ||
"version": "1.0.0-alpha.18", | ||
"description": "Arcjet SDK for Node.js", | ||
@@ -43,14 +43,14 @@ "license": "Apache-2.0", | ||
"dependencies": { | ||
"@arcjet/env": "1.0.0-alpha.17", | ||
"@arcjet/headers": "1.0.0-alpha.17", | ||
"@arcjet/ip": "1.0.0-alpha.17", | ||
"@arcjet/logger": "1.0.0-alpha.17", | ||
"@arcjet/protocol": "1.0.0-alpha.17", | ||
"@arcjet/env": "1.0.0-alpha.18", | ||
"@arcjet/headers": "1.0.0-alpha.18", | ||
"@arcjet/ip": "1.0.0-alpha.18", | ||
"@arcjet/logger": "1.0.0-alpha.18", | ||
"@arcjet/protocol": "1.0.0-alpha.18", | ||
"@connectrpc/connect-node": "1.4.0", | ||
"arcjet": "1.0.0-alpha.17" | ||
"arcjet": "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", | ||
"@jest/globals": "29.7.0", | ||
@@ -60,3 +60,3 @@ "@types/node": "18.18.0", | ||
"jest": "29.7.0", | ||
"typescript": "5.4.5" | ||
"typescript": "5.5.2" | ||
}, | ||
@@ -63,0 +63,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
34195
436
+ Added@arcjet/analyze@1.0.0-alpha.18(transitive)
+ Added@arcjet/duration@1.0.0-alpha.18(transitive)
+ Added@arcjet/env@1.0.0-alpha.18(transitive)
+ Added@arcjet/headers@1.0.0-alpha.18(transitive)
+ Added@arcjet/ip@1.0.0-alpha.18(transitive)
+ Added@arcjet/logger@1.0.0-alpha.18(transitive)
+ Added@arcjet/protocol@1.0.0-alpha.18(transitive)
+ Added@arcjet/runtime@1.0.0-alpha.18(transitive)
+ Added@arcjet/sprintf@1.0.0-alpha.18(transitive)
+ Addedarcjet@1.0.0-alpha.18(transitive)
- Removed@arcjet/analyze@1.0.0-alpha.17(transitive)
- Removed@arcjet/env@1.0.0-alpha.17(transitive)
- Removed@arcjet/headers@1.0.0-alpha.17(transitive)
- Removed@arcjet/ip@1.0.0-alpha.17(transitive)
- Removed@arcjet/logger@1.0.0-alpha.17(transitive)
- Removed@arcjet/protocol@1.0.0-alpha.17(transitive)
- Removed@arcjet/runtime@1.0.0-alpha.17(transitive)
- Removed@arcjet/sprintf@1.0.0-alpha.17(transitive)
- Removedarcjet@1.0.0-alpha.17(transitive)
Updated@arcjet/env@1.0.0-alpha.18
Updated@arcjet/ip@1.0.0-alpha.18
Updatedarcjet@1.0.0-alpha.18