@arcjet/analyze 1.0.0-alpha.9 → 1.0.0-beta.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,7 +1,7 @@
1
1
  <a href="https://arcjet.com" target="_arcjet-home">
2
2
  <picture>
3
- <source media="(prefers-color-scheme: dark)" srcset="https://arcjet.com/arcjet-logo-dark-planet-arrival.svg">
4
- <img src="https://arcjet.com/arcjet-logo-light-planet-arrival.svg" alt="Arcjet Logo" height="144" width="auto">
3
+ <source media="(prefers-color-scheme: dark)" srcset="https://arcjet.com/logo/arcjet-dark-lockup-voyage-horizontal.svg">
4
+ <img src="https://arcjet.com/logo/arcjet-light-lockup-voyage-horizontal.svg" alt="Arcjet Logo" height="128" width="auto">
5
5
  </picture>
6
6
  </a>
7
7
 
@@ -17,62 +17,76 @@
17
17
  </p>
18
18
 
19
19
  [Arcjet][arcjet] helps developers protect their apps in just a few lines of
20
- code. Implement rate limiting, bot protection, email verification & defend
20
+ code. Implement rate limiting, bot protection, email verification, and defense
21
21
  against common attacks.
22
22
 
23
23
  This is the [Arcjet][arcjet] local analysis engine.
24
24
 
25
- ## Installation
25
+ - [npm package (`@arcjet/analyze`)](https://www.npmjs.com/package/@arcjet/analyze)
26
+ - [GitHub source code (`analyze/` in `arcjet/arcjet-js`)](https://github.com/arcjet/arcjet-js/tree/main/analyze)
26
27
 
27
- ```shell
28
- npm install -S @arcjet/analyze
29
- ```
30
-
31
- ## Example
32
-
33
- ```ts
34
- import { generateFingerprint, isValidEmail } from "@arcjet/analyze";
28
+ ## What is this?
35
29
 
36
- const fingerprint = generateFingerprint("127.0.0.1");
37
- console.log("fingerprint: ", fingerprint);
30
+ This package provides functionality to analyze requests.
31
+ The work is done in WebAssembly but is called here from JavaScript.
32
+ The functionality is wrapped up into rules in our core package
33
+ ([`arcjet`][github-arcjet-arcjet]),
34
+ in turn exposed from our adapters (such as `@arcjet/next`).
38
35
 
39
- const valid = isValidEmail("hello@example.com");
40
- console.log("is email valid?", valid);
41
- ```
36
+ <!-- TODO(@wooorm-arcjet): link `adapters` above when the main repo is up to date. -->
42
37
 
43
- ## Implementation
38
+ The WebAssembly files are in
39
+ [`@arcjet/analyze-wasm`][github-arcjet-analyze-wasm].
40
+ They are separate because we need to change the import structure for each
41
+ runtime that we support in the bindings.
42
+ Separate packages lets us not duplicate code while providing a combined
43
+ higher-level API for calling our core functionality.
44
44
 
45
- This package provides analyze logic implemented as a WebAssembly module which
46
- will run local analysis on request details before calling the Arcjet API.
45
+ ## When should I use this?
47
46
 
48
- The [arcjet.wasm.js](./wasm/arcjet.wasm.js) file contains the binary inlined as
49
- a base64 [Data URL][mdn-data-url] with the `application/wasm` MIME type.
47
+ This is an internal Arcjet package not designed for public use.
48
+ See our [_Get started_ guide][arcjet-get-started] for how to use Arcjet in your
49
+ application.
50
50
 
51
- This was chosen to save on storage space over inlining the file directly as a
52
- Uint8Array, which would take up ~3x the space of the Wasm file. See
53
- [Better Binary Batter: Mixing Base64 and Uint8Array][wasm-base64-blog] for more
54
- details.
51
+ ## Install
55
52
 
56
- It is then decoded into an ArrayBuffer to be used directly via WebAssembly's
57
- `compile()` function in our entry point file.
53
+ This package is ESM only.
54
+ Install with npm in Node.js:
58
55
 
59
- This is all done to avoid trying to read or bundle the Wasm asset in various
60
- ways based on the platform or bundler a user is targeting. One example being
61
- that Next.js requires special `asyncWebAssembly` webpack config to load our
62
- Wasm file if we don't do this.
56
+ ```sh
57
+ npm install @arcjet/analyze
58
+ ```
63
59
 
64
- In the future, we hope to do away with this workaround when all bundlers
65
- properly support consistent asset bundling techniques.
60
+ ## Use
66
61
 
67
- ## API
62
+ ```js
63
+ import { generateFingerprint, isValidEmail } from "@arcjet/analyze";
68
64
 
69
- In progress.
65
+ const fingerprint = await generateFingerprint(
66
+ { characteristics: [] },
67
+ { ip: "127.0.0.1" },
68
+ );
69
+ console.log(fingerprint);
70
+ // => "fp::2::0d219da6100b99f95cf639b77e088c6df3c096aa5fd61dec5287c5cf94d5e545"
71
+
72
+ const result = await isValidEmail({}, "hello@example.com", {
73
+ tag: "allow-email-validation-config",
74
+ val: {
75
+ allowDomainLiteral: false,
76
+ allow: [],
77
+ requireTopLevelDomain: true,
78
+ },
79
+ });
80
+ console.log(result);
81
+ // => { blocked: [], validity: "valid" }
82
+ ```
70
83
 
71
84
  ## License
72
85
 
73
- Licensed under the [Apache License, Version 2.0][apache-license].
86
+ [Apache License, Version 2.0][apache-license] © [Arcjet Labs, Inc.][arcjet]
74
87
 
75
88
  [arcjet]: https://arcjet.com
76
- [mdn-data-url]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URLs
77
- [wasm-base64-blog]: https://blobfolio.com/2019/better-binary-batter-mixing-base64-and-uint8array/
89
+ [arcjet-get-started]: https://docs.arcjet.com/get-started
78
90
  [apache-license]: http://www.apache.org/licenses/LICENSE-2.0
91
+ [github-arcjet-analyze-wasm]: https://github.com/arcjet/arcjet-js/tree/main/analyze-wasm
92
+ [github-arcjet-arcjet]: https://github.com/arcjet/arcjet-js/tree/main/arcjet
package/index.d.ts CHANGED
@@ -1,27 +1,29 @@
1
- import { type EmailValidationConfig } from "./wasm/arcjet_analyze_js_req.js";
2
- export { type EmailValidationConfig };
1
+ import type { BotConfig, BotResult, DetectedSensitiveInfoEntity, DetectSensitiveInfoFunction, EmailValidationConfig, EmailValidationResult, SensitiveInfoEntities, SensitiveInfoEntity, SensitiveInfoResult } from "@arcjet/analyze-wasm";
2
+ import type { ArcjetLogger } from "@arcjet/protocol";
3
+ interface AnalyzeContext {
4
+ log: ArcjetLogger;
5
+ characteristics: string[];
6
+ }
7
+ type AnalyzeRequest = {
8
+ ip?: string;
9
+ method?: string;
10
+ protocol?: string;
11
+ host?: string;
12
+ path?: string;
13
+ headers?: Record<string, string>;
14
+ cookies?: string;
15
+ query?: string;
16
+ extra?: Record<string, string>;
17
+ };
18
+ export { type EmailValidationConfig, type BotConfig, type SensitiveInfoEntity, type DetectedSensitiveInfoEntity, };
3
19
  /**
4
20
  * Generate a fingerprint for the client. This is used to identify the client
5
21
  * across multiple requests.
6
- * @param ip - The IP address of the client.
22
+ * @param context - The Arcjet Analyze context.
23
+ * @param request - The request to fingerprint.
7
24
  * @returns A SHA-256 string fingerprint.
8
25
  */
9
- export declare function generateFingerprint(ip: string): Promise<string>;
10
- export declare function isValidEmail(candidate: string, options?: EmailValidationConfig): Promise<boolean>;
11
- /**
12
- * Represents the result of the bot detection.
13
- *
14
- * @property `bot_type` - What type of bot this is. This will be one of `BotType`.
15
- * @property `bot_score` - A score ranging from 0 to 99 representing the degree of
16
- * certainty. The higher the number within the type category, the greater the
17
- * degree of certainty. E.g. `BotType.Automated` with a score of 1 means we are
18
- * sure the request was made by an automated bot. `BotType.LikelyNotABot` with a
19
- * score of 30 means we don't think this request was a bot, but it's lowest
20
- * confidence level. `BotType.LikelyNotABot` with a score of 99 means we are
21
- * almost certain this request was not a bot.
22
- */
23
- export interface BotResult {
24
- bot_type: number;
25
- bot_score: number;
26
- }
27
- export declare function detectBot(headers: string, patterns_add: string, patterns_remove: string): Promise<BotResult>;
26
+ export declare function generateFingerprint(context: AnalyzeContext, request: AnalyzeRequest): Promise<string>;
27
+ export declare function isValidEmail(context: AnalyzeContext, candidate: string, options: EmailValidationConfig): Promise<EmailValidationResult>;
28
+ export declare function detectBot(context: AnalyzeContext, request: AnalyzeRequest, options: BotConfig): Promise<BotResult>;
29
+ export declare function detectSensitiveInfo(context: AnalyzeContext, candidate: string, entities: SensitiveInfoEntities, contextWindowSize: number, detect?: DetectSensitiveInfoFunction): Promise<SensitiveInfoResult>;
package/index.js CHANGED
@@ -1,109 +1,118 @@
1
- import initWasm, { detect_bot, generate_fingerprint, is_valid_email } from './wasm/arcjet_analyze_js_req.js';
1
+ import { initializeWasm } from '@arcjet/analyze-wasm';
2
2
 
3
- let state = "uninitialized";
4
- /**
5
- * Initialize the WASM module. This can be explicitly called after creating
6
- * the client, but it will be called automatically if it has not been called
7
- * when the first request is made. This uses a factory-style pattern because
8
- * the call must be async and the constructor cannot be async.
9
- */
10
- async function init() {
11
- if (state === "errored" || state === "unsupported")
12
- return;
13
- if (typeof WebAssembly === "undefined") {
14
- state = "unsupported";
15
- return;
16
- }
17
- if (state === "uninitialized") {
18
- try {
19
- let wasmModule;
20
- // We use `NEXT_RUNTIME` env var to DCE the Node/Browser code in the `else` block
21
- // possible values: "edge" | "nodejs" | undefined
22
- if (process.env["NEXT_RUNTIME"] === "edge") {
23
- const mod = await import(
24
- // @ts-expect-error
25
- './wasm/arcjet_analyze_js_req_bg.wasm?module');
26
- wasmModule = mod.default;
27
- }
28
- else {
29
- const { wasm } = await import('./wasm/arcjet.wasm.js');
30
- wasmModule = await WebAssembly.compile(await wasm());
31
- }
32
- await initWasm(wasmModule);
33
- state = "initialized";
34
- }
35
- catch (err) {
36
- state = "errored";
37
- return;
38
- }
3
+ const FREE_EMAIL_PROVIDERS = [
4
+ "gmail.com",
5
+ "yahoo.com",
6
+ "hotmail.com",
7
+ "aol.com",
8
+ "hotmail.co.uk",
9
+ ];
10
+ function noOpSensitiveInfoDetect() {
11
+ return [];
12
+ }
13
+ function noOpBotsDetect() {
14
+ return [];
15
+ }
16
+ function createCoreImports(detect) {
17
+ if (typeof detect !== "function") {
18
+ detect = noOpSensitiveInfoDetect;
39
19
  }
40
20
  return {
41
- detectBot: detect_bot,
42
- fingerprint: generate_fingerprint,
43
- isValidEmail: is_valid_email,
21
+ "arcjet:js-req/bot-identifier": {
22
+ detect: noOpBotsDetect,
23
+ },
24
+ "arcjet:js-req/email-validator-overrides": {
25
+ isFreeEmail(domain) {
26
+ if (FREE_EMAIL_PROVIDERS.includes(domain)) {
27
+ return "yes";
28
+ }
29
+ return "unknown";
30
+ },
31
+ isDisposableEmail() {
32
+ return "unknown";
33
+ },
34
+ hasMxRecords() {
35
+ return "unknown";
36
+ },
37
+ hasGravatar() {
38
+ return "unknown";
39
+ },
40
+ },
41
+ // TODO(@wooorm-arcjet): figure out a test case for this with the default `detect`.
42
+ "arcjet:js-req/sensitive-information-identifier": {
43
+ detect,
44
+ },
45
+ // TODO(@wooorm-arcjet): figure out a test case for this that calls `verify`.
46
+ "arcjet:js-req/verify-bot": {
47
+ verify() {
48
+ return "unverifiable";
49
+ },
50
+ },
44
51
  };
45
52
  }
53
+ // TODO(@wooorm-arcjet): document what is used to fingerprint.
46
54
  /**
47
55
  * Generate a fingerprint for the client. This is used to identify the client
48
56
  * across multiple requests.
49
- * @param ip - The IP address of the client.
57
+ * @param context - The Arcjet Analyze context.
58
+ * @param request - The request to fingerprint.
50
59
  * @returns A SHA-256 string fingerprint.
51
60
  */
52
- async function generateFingerprint(ip) {
53
- if (ip == "") {
54
- return "";
55
- }
56
- // We use `NEXT_RUNTIME` env var to DCE the JS fallback code in the `else` block
57
- // possible values: "edge" | "nodejs" | undefined
58
- if (process.env["NEXT_RUNTIME"] === "edge") {
59
- const analyze = await init();
60
- // We HAVE to have the WasmAPI in Edge
61
- const fingerprint = analyze.fingerprint(ip);
62
- return fingerprint;
63
- }
64
- else {
65
- const analyze = await init();
66
- if (typeof analyze !== "undefined") {
67
- const fingerprint = analyze.fingerprint(ip);
68
- return fingerprint;
69
- }
70
- else {
71
- // Conditional import because it's not available in some runtimes, we know
72
- // it is when running on Vercel serverless functions.
73
- // TODO(#180): Avoid nodejs-specific import
74
- const createHash = await import('crypto');
75
- // Fingerprint v1 is just the IP address
76
- const fingerprintRaw = `fp_1_${ip}`;
77
- const fingerprint = createHash
78
- .createHash("sha256")
79
- .update(fingerprintRaw)
80
- .digest("hex");
81
- return fingerprint;
82
- }
61
+ async function generateFingerprint(context, request) {
62
+ const { log } = context;
63
+ const coreImports = createCoreImports();
64
+ const analyze = await initializeWasm(coreImports);
65
+ if (typeof analyze !== "undefined") {
66
+ return analyze.generateFingerprint(JSON.stringify(request), context.characteristics);
67
+ // Ignore the `else` branch as we test in places that have WebAssembly.
68
+ /* node:coverage ignore next 4 */
83
69
  }
70
+ log.debug("WebAssembly is not supported in this runtime");
71
+ return "";
84
72
  }
85
- async function isValidEmail(candidate, options) {
86
- const analyze = await init();
73
+ // TODO(@wooorm-arcjet): docs.
74
+ async function isValidEmail(context, candidate, options) {
75
+ const { log } = context;
76
+ const coreImports = createCoreImports();
77
+ const analyze = await initializeWasm(coreImports);
87
78
  if (typeof analyze !== "undefined") {
88
79
  return analyze.isValidEmail(candidate, options);
80
+ // Ignore the `else` branch as we test in places that have WebAssembly.
81
+ /* node:coverage ignore next 4 */
89
82
  }
90
- else {
91
- // TODO: Fallback to JS if we don't have WASM?
92
- return true;
93
- }
83
+ log.debug("WebAssembly is not supported in this runtime");
84
+ return { blocked: [], validity: "valid" };
94
85
  }
95
- async function detectBot(headers, patterns_add, patterns_remove) {
96
- const analyze = await init();
86
+ // TODO(@wooorm-arcjet): docs.
87
+ async function detectBot(context, request, options) {
88
+ const { log } = context;
89
+ const coreImports = createCoreImports();
90
+ const analyze = await initializeWasm(coreImports);
97
91
  if (typeof analyze !== "undefined") {
98
- return analyze.detectBot(headers, patterns_add, patterns_remove);
92
+ return analyze.detectBot(JSON.stringify(request), options);
93
+ // Ignore the `else` branch as we test in places that have WebAssembly.
94
+ /* node:coverage ignore next 4 */
99
95
  }
100
- else {
101
- // TODO: Fallback to JS if we don't have WASM?
102
- return {
103
- bot_type: 1, // NOT_ANALYZED
104
- bot_score: 0,
105
- };
96
+ log.debug("WebAssembly is not supported in this runtime");
97
+ return { allowed: [], denied: [], spoofed: false, verified: false };
98
+ }
99
+ // TODO(@wooorm-arcjet): docs.
100
+ async function detectSensitiveInfo(context, candidate, entities, contextWindowSize, detect) {
101
+ const { log } = context;
102
+ const coreImports = createCoreImports(detect);
103
+ const analyze = await initializeWasm(coreImports);
104
+ if (typeof analyze !== "undefined") {
105
+ const skipCustomDetect = typeof detect !== "function";
106
+ return analyze.detectSensitiveInfo(candidate, {
107
+ entities,
108
+ contextWindowSize,
109
+ skipCustomDetect,
110
+ });
111
+ // Ignore the `else` branch as we test in places that have WebAssembly.
112
+ /* node:coverage ignore next 4 */
106
113
  }
114
+ log.debug("WebAssembly is not supported in this runtime");
115
+ throw new Error("SENSITIVE_INFO rule failed to run because Wasm is not supported in this environment.");
107
116
  }
108
117
 
109
- export { detectBot, generateFingerprint, isValidEmail };
118
+ export { detectBot, detectSensitiveInfo, generateFingerprint, isValidEmail };
package/package.json CHANGED
@@ -1,7 +1,15 @@
1
1
  {
2
2
  "name": "@arcjet/analyze",
3
- "version": "1.0.0-alpha.9",
3
+ "version": "1.0.0-beta.10",
4
4
  "description": "Arcjet local analysis engine",
5
+ "keywords": [
6
+ "analyze",
7
+ "arcjet",
8
+ "attack",
9
+ "limit",
10
+ "protect",
11
+ "verify"
12
+ ],
5
13
  "license": "Apache-2.0",
6
14
  "homepage": "https://arcjet.com",
7
15
  "repository": {
@@ -25,36 +33,30 @@
25
33
  "main": "./index.js",
26
34
  "types": "./index.d.ts",
27
35
  "files": [
28
- "LICENSE",
29
- "README.md",
30
- "wasm/",
31
- "*.js",
32
- "*.d.ts",
33
- "*.ts",
34
- "!*.config.js"
36
+ "index.d.ts",
37
+ "index.js"
35
38
  ],
36
39
  "scripts": {
37
- "prepublishOnly": "npm run build",
38
40
  "build": "rollup --config rollup.config.js",
39
41
  "lint": "eslint .",
40
- "pretest": "npm run build",
41
- "test": "NODE_OPTIONS=--experimental-vm-modules jest --passWithNoTests"
42
+ "prepublishOnly": "npm run build",
43
+ "test-api": "node --test",
44
+ "test-coverage": "node --experimental-test-coverage --test",
45
+ "test": "npm run build && npm run lint && npm run test-coverage"
42
46
  },
43
- "sideEffects": [
44
- "./wasm/arcjet_analyze_js_req_bg.js"
45
- ],
46
47
  "dependencies": {
47
- "@arcjet/logger": "1.0.0-alpha.9"
48
+ "@arcjet/analyze-wasm": "1.0.0-beta.10",
49
+ "@arcjet/protocol": "1.0.0-beta.10"
48
50
  },
49
51
  "devDependencies": {
50
- "@arcjet/eslint-config": "1.0.0-alpha.9",
51
- "@arcjet/rollup-config": "1.0.0-alpha.9",
52
- "@arcjet/tsconfig": "1.0.0-alpha.9",
53
- "@jest/globals": "29.7.0",
54
- "@rollup/wasm-node": "4.12.0",
52
+ "@arcjet/eslint-config": "1.0.0-beta.10",
53
+ "@arcjet/rollup-config": "1.0.0-beta.10",
54
+ "@arcjet/tsconfig": "1.0.0-beta.10",
55
+ "@bytecodealliance/jco": "1.5.0",
56
+ "@rollup/wasm-node": "4.46.2",
55
57
  "@types/node": "18.18.0",
56
- "jest": "29.7.0",
57
- "typescript": "5.3.3"
58
+ "eslint": "9.32.0",
59
+ "typescript": "5.9.2"
58
60
  },
59
61
  "publishConfig": {
60
62
  "access": "public",
package/index.ts DELETED
@@ -1,165 +0,0 @@
1
- import initWasm, {
2
- detect_bot,
3
- generate_fingerprint,
4
- is_valid_email,
5
- type EmailValidationConfig,
6
- } from "./wasm/arcjet_analyze_js_req.js";
7
-
8
- export { type EmailValidationConfig };
9
-
10
- type WasmAPI = {
11
- /**
12
- * The WASM detect_bot function. Initialized by calling `init()`. Defined at a
13
- * class level to avoid having to load the WASM module multiple times.
14
- */
15
- detectBot: typeof detect_bot;
16
- /**
17
- * The WASM fingerprint function. Initialized by calling `init()`. Defined at
18
- * a class level to avoid having to load the WASM module multiple times.
19
- */
20
- fingerprint: typeof generate_fingerprint;
21
- /**
22
- * The WASM email validation function. Initialized by calling `init()`. Defined at
23
- * a class level to avoid having to load the WASM module multiple times.
24
- */
25
- isValidEmail: typeof is_valid_email;
26
- };
27
-
28
- type WasmState = "initialized" | "uninitialized" | "unsupported" | "errored";
29
-
30
- let state: WasmState = "uninitialized";
31
-
32
- /**
33
- * Initialize the WASM module. This can be explicitly called after creating
34
- * the client, but it will be called automatically if it has not been called
35
- * when the first request is made. This uses a factory-style pattern because
36
- * the call must be async and the constructor cannot be async.
37
- */
38
- async function init(): Promise<WasmAPI | undefined> {
39
- if (state === "errored" || state === "unsupported") return;
40
-
41
- if (typeof WebAssembly === "undefined") {
42
- state = "unsupported";
43
- return;
44
- }
45
-
46
- if (state === "uninitialized") {
47
- try {
48
- let wasmModule: WebAssembly.Module;
49
- // We use `NEXT_RUNTIME` env var to DCE the Node/Browser code in the `else` block
50
- // possible values: "edge" | "nodejs" | undefined
51
- if (process.env["NEXT_RUNTIME"] === "edge") {
52
- const mod = await import(
53
- // @ts-expect-error
54
- "./wasm/arcjet_analyze_js_req_bg.wasm?module"
55
- );
56
- wasmModule = mod.default;
57
- } else {
58
- const { wasm } = await import("./wasm/arcjet.wasm.js");
59
- wasmModule = await WebAssembly.compile(await wasm());
60
- }
61
-
62
- await initWasm(wasmModule);
63
- state = "initialized";
64
- } catch (err) {
65
- state = "errored";
66
- return;
67
- }
68
- }
69
-
70
- return {
71
- detectBot: detect_bot,
72
- fingerprint: generate_fingerprint,
73
- isValidEmail: is_valid_email,
74
- };
75
- }
76
-
77
- /**
78
- * Generate a fingerprint for the client. This is used to identify the client
79
- * across multiple requests.
80
- * @param ip - The IP address of the client.
81
- * @returns A SHA-256 string fingerprint.
82
- */
83
- export async function generateFingerprint(ip: string): Promise<string> {
84
- if (ip == "") {
85
- return "";
86
- }
87
-
88
- // We use `NEXT_RUNTIME` env var to DCE the JS fallback code in the `else` block
89
- // possible values: "edge" | "nodejs" | undefined
90
- if (process.env["NEXT_RUNTIME"] === "edge") {
91
- const analyze = await init();
92
- // We HAVE to have the WasmAPI in Edge
93
- const fingerprint = analyze!.fingerprint(ip);
94
- return fingerprint;
95
- } else {
96
- const analyze = await init();
97
- if (typeof analyze !== "undefined") {
98
- const fingerprint = analyze.fingerprint(ip);
99
- return fingerprint;
100
- } else {
101
- // Conditional import because it's not available in some runtimes, we know
102
- // it is when running on Vercel serverless functions.
103
- // TODO(#180): Avoid nodejs-specific import
104
- const createHash = await import("crypto");
105
-
106
- // Fingerprint v1 is just the IP address
107
- const fingerprintRaw = `fp_1_${ip}`;
108
-
109
- const fingerprint = createHash
110
- .createHash("sha256")
111
- .update(fingerprintRaw)
112
- .digest("hex");
113
- return fingerprint;
114
- }
115
- }
116
- }
117
-
118
- export async function isValidEmail(
119
- candidate: string,
120
- options?: EmailValidationConfig,
121
- ) {
122
- const analyze = await init();
123
-
124
- if (typeof analyze !== "undefined") {
125
- return analyze.isValidEmail(candidate, options);
126
- } else {
127
- // TODO: Fallback to JS if we don't have WASM?
128
- return true;
129
- }
130
- }
131
-
132
- /**
133
- * Represents the result of the bot detection.
134
- *
135
- * @property `bot_type` - What type of bot this is. This will be one of `BotType`.
136
- * @property `bot_score` - A score ranging from 0 to 99 representing the degree of
137
- * certainty. The higher the number within the type category, the greater the
138
- * degree of certainty. E.g. `BotType.Automated` with a score of 1 means we are
139
- * sure the request was made by an automated bot. `BotType.LikelyNotABot` with a
140
- * score of 30 means we don't think this request was a bot, but it's lowest
141
- * confidence level. `BotType.LikelyNotABot` with a score of 99 means we are
142
- * almost certain this request was not a bot.
143
- */
144
- export interface BotResult {
145
- bot_type: number;
146
- bot_score: number;
147
- }
148
-
149
- export async function detectBot(
150
- headers: string,
151
- patterns_add: string,
152
- patterns_remove: string,
153
- ): Promise<BotResult> {
154
- const analyze = await init();
155
-
156
- if (typeof analyze !== "undefined") {
157
- return analyze.detectBot(headers, patterns_add, patterns_remove);
158
- } else {
159
- // TODO: Fallback to JS if we don't have WASM?
160
- return {
161
- bot_type: 1, // NOT_ANALYZED
162
- bot_score: 0,
163
- };
164
- }
165
- }
@@ -1,31 +0,0 @@
1
- // @generated by wasm2module - DO NOT EDIT
2
- /* tslint:disable */
3
- /* eslint-disable */
4
-
5
- /**
6
- * This file contains the Arcjet Wasm binary inlined as a base64
7
- * [Data URL](https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URLs)
8
- * with the application/wasm MIME type.
9
- *
10
- * This was chosen to save on storage space over inlining the file directly as
11
- * a Uint8Array, which would take up ~3x the space of the Wasm file. See
12
- * https://blobfolio.com/2019/better-binary-batter-mixing-base64-and-uint8array/
13
- * for more details.
14
- *
15
- * It is then decoded into an ArrayBuffer to be used directly via WebAssembly's
16
- * `compile()` function in our entry point file.
17
- *
18
- * This is all done to avoid trying to read or bundle the Wasm asset in various
19
- * ways based on the platform or bundler a user is targeting. One example being
20
- * that Next.js requires special `asyncWebAssembly` webpack config to load our
21
- * Wasm file if we don't do this.
22
- *
23
- * In the future, we hope to do away with this workaround when all bundlers
24
- * properly support consistent asset bundling techniques.
25
- */
26
-
27
- /**
28
- * Returns an ArrayBuffer for the Arcjet Wasm binary, decoded from a base64 Data
29
- * URL.
30
- */
31
- export function wasm(): Promise<ArrayBuffer>;