@deflectbot/deflect-sdk 1.2.3 → 1.3.1

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,50 +1,78 @@
1
- # Deflect -
1
+ # Deflect SDK (Client-side)
2
2
 
3
3
  ![npm](https://img.shields.io/npm/v/@deflectbot/deflect-sdk)
4
4
  ![downloads](https://img.shields.io/npm/dm/@deflectbot/deflect-sdk)
5
5
 
6
- Deflect is an antibot solution that works with Vue, React, NextJS, and other JavaScript frameworks.
6
+ [Deflect](https://deflect.bot) is an advanced antibot engine that protects your site from bots on any scale.
7
7
 
8
- ---
8
+ ## Usage
9
9
 
10
- ## CDN Install (Auto-Updates)
10
+ See the [documentation](https://docs.deflect.bot/) for how to use this SDK with the Deflect APIs.
11
+
12
+ ## Installation
13
+
14
+ #### yarn
11
15
 
12
16
  ```bash
13
- Include in your project:
14
- <script src="https://cdn.jsdelivr.net/npm/@deflectbot/deflect-sdk/dist/index.min.js"></script>
17
+ yarn add @castleio/sdk
15
18
  ```
16
19
 
17
- ---
18
-
19
- ## NPM Install (Requires Manual Updates)
20
+ #### npm
20
21
 
21
22
  ```bash
22
- npm install deflect
23
+ npm install --save @castleio/sdk
23
24
  ```
24
25
 
25
- ---
26
+ #### CDN
26
27
 
27
- ## Setup
28
+ Use `@deflect-sdk@latest` to always use the latest version, or specify a version with `@deflect-sdk@x.x.x`.
28
29
 
29
- ```ts
30
- import Deflect from '@deflectbot/deflect-sdk';
30
+ ```html
31
+ <script src="https://cdn.jsdelivr.net/npm/@deflectbot/deflect-sdk@latest/dist/index.min.js" />
32
+ ```
31
33
 
34
+ ## Configuration
35
+
36
+ Deflect works through Defense Actions™, which allows you to either setup a global configuration one-time to work across your entire application, or individual and more customized Defense Actions™ for each protected endpoint.
37
+
38
+ #### One-time global initialization.
39
+
40
+ ```ts
32
41
  Deflect.configure({
33
- actionId: 'YOUR_ACTION_ID',
34
- extraArgs: { mode: 'strict' }, // Optional
35
- forceRefresh: true, // Optional
42
+ actionId: "<ACTION_ID>",
36
43
  });
37
44
  ```
38
45
 
39
- ---
40
-
41
- ## Solve Challenge
46
+ #### To get a token to pass to a protected endpoint
42
47
 
43
48
  ```ts
44
- try {
45
- const token = await Deflect.solveChallenge();
46
- console.log('✅ Token received:', token);
47
- } catch (error) {
48
- console.error('❌ Failed to solve challenge:', error);
49
- }
49
+ const token = await Deflect.getToken(); // returns token as string
50
+ ```
51
+
52
+ #### Helper for form submit
53
+
54
+ If you're using forms like this:
55
+
56
+ ```html
57
+ <form action="/login" method="POST">
58
+ <input name="username" />
59
+ <input name="password" type="password" />
60
+ <button type="submit">Login</button>
61
+ </form>
50
62
  ```
63
+
64
+ You can use the helper as shown:
65
+
66
+ ```html
67
+ <form
68
+ action="/login"
69
+ method="POST"
70
+ onsubmit="return Deflect.injectToken(event)"
71
+ >
72
+ <input name="username" />
73
+ <input name="password" type="password" />
74
+ <button type="submit">Login</button>
75
+ </form>
76
+ ```
77
+
78
+ `injectToken()` will fetch a token and insert it as a hidden input named `deflect_token` into your form. Use it directly in your form's onsubmit attribute:
package/dist/index.js CHANGED
@@ -1,126 +1,222 @@
1
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
- return new (P || (P = Promise))(function (resolve, reject) {
4
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
- step((generator = generator.apply(thisArg, _arguments || [])).next());
8
- });
9
- };
10
- class Deflect {
1
+ "use strict";
2
+ var Deflect = (() => {
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
21
+
22
+ // src/global.ts
23
+ var global_exports = {};
24
+ __export(global_exports, {
25
+ default: () => global_default
26
+ });
27
+
28
+ // src/index.ts
29
+ var Deflect = class {
11
30
  constructor() {
12
- this._prefetchedScriptText = null;
13
- this._hasUsedPrefetch = false;
14
- this._customScriptUrl = null;
15
- window.Deflect = window.Deflect || {};
16
- window.Deflect.extraArgs = window.Deflect.extraArgs || {};
31
+ this.config = null;
32
+ this.scriptCache = null;
33
+ this.isWarmupInProgress = false;
34
+ this.initializeGlobalState();
35
+ this.setupAutomaticWarmup();
36
+ }
37
+ static {
38
+ __name(this, "Deflect");
39
+ }
40
+ initializeGlobalState() {
41
+ if (typeof window === "undefined") return;
42
+ window.Deflect = window.Deflect || {};
43
+ }
44
+ setupAutomaticWarmup() {
45
+ if (typeof window === "undefined") return;
46
+ if (document.readyState === "loading") {
47
+ document.addEventListener("DOMContentLoaded", () => this.tryWarmup());
48
+ } else {
49
+ setTimeout(() => this.tryWarmup(), 100);
50
+ }
51
+ }
52
+ async tryWarmup() {
53
+ if (!this.config?.actionId || this.isWarmupInProgress || this.scriptCache) {
54
+ return;
55
+ }
56
+ this.isWarmupInProgress = true;
57
+ try {
58
+ this.scriptCache = await this.fetchScript();
59
+ } catch {
60
+ } finally {
61
+ this.isWarmupInProgress = false;
62
+ }
63
+ }
64
+ buildScriptUrl(actionId) {
65
+ const baseUrl = this.config?.scriptUrl || "https://js.deflect.bot/main.js";
66
+ if (this.config?.scriptUrl) {
67
+ return baseUrl;
68
+ }
69
+ const nonce = Date.now().toString();
70
+ return `${baseUrl}?action_id=${actionId}&_=${nonce}`;
71
+ }
72
+ async fetchScript() {
73
+ if (!this.config?.actionId) {
74
+ throw new Error("actionId is required");
75
+ }
76
+ const url = this.buildScriptUrl(this.config.actionId);
77
+ const response = await fetch(url, { cache: "no-store" });
78
+ if (!response.ok) {
79
+ throw new Error(`Failed to fetch script: ${response.status}`);
80
+ }
81
+ return {
82
+ content: await response.text(),
83
+ sessionId: response.headers.get("session_id") || void 0
84
+ };
85
+ }
86
+ async executeScript(script) {
87
+ if (script.sessionId && typeof window !== "undefined") {
88
+ window.Deflect.sessionId = script.sessionId;
89
+ }
90
+ const readyPromise = this.createReadyPromise();
91
+ const blobUrl = this.createScriptBlob(script.content);
92
+ const scriptElement = await this.loadScriptElement(blobUrl);
93
+ try {
94
+ await readyPromise;
95
+ const token = await this.getTokenFromScript();
96
+ this.prefetchNextScript();
97
+ return token;
98
+ } finally {
99
+ this.cleanup(blobUrl, scriptElement);
100
+ }
101
+ }
102
+ prefetchNextScript() {
103
+ this.tryWarmup().catch(() => {
104
+ });
105
+ }
106
+ createReadyPromise() {
107
+ return new Promise((resolve) => {
17
108
  if (typeof window !== "undefined") {
18
- window.addEventListener("load", () => {
19
- setTimeout(() => {
20
- this._warmupScript();
21
- }, 500);
22
- });
109
+ window.Deflect.ready = {
110
+ promise: new Promise((innerResolve) => {
111
+ window.Deflect.ready.resolve = innerResolve;
112
+ }),
113
+ resolve: /* @__PURE__ */ __name(() => resolve(), "resolve")
114
+ };
23
115
  }
116
+ });
24
117
  }
25
- _getScriptUrl() {
26
- const nonce = Date.now().toString();
27
- if (this._customScriptUrl) {
28
- const separator = this._customScriptUrl.includes("?") ? "&" : "?";
29
- return `${this._customScriptUrl}${separator}action_id=${window.Deflect.actionId}&_=${nonce}`;
30
- }
31
- return `https://js.deflect.bot/main.js?action_id=${window.Deflect.actionId}&_=${nonce}`;
32
- }
33
- _warmupScript() {
34
- if (!window.Deflect.actionId)
35
- return;
36
- const scriptUrl = this._getScriptUrl();
37
- fetch(scriptUrl, { cache: "no-store" })
38
- .then((res) => __awaiter(this, void 0, void 0, function* () {
39
- if (!res.ok)
40
- return;
41
- this._prefetchedScriptText = yield res.text();
42
- }))
43
- .catch(() => { });
44
- }
45
- _refetchScript() {
46
- this._hasUsedPrefetch = false;
47
- this._prefetchedScriptText = null;
48
- setTimeout(() => {
49
- this._warmupScript();
50
- }, 100);
51
- }
52
- setupReady() {
53
- let resolveFn;
54
- const promise = new Promise((resolve) => {
55
- resolveFn = resolve;
56
- });
57
- window.Deflect.ready = {
58
- promise,
59
- resolve: () => resolveFn(),
60
- };
118
+ createScriptBlob(content) {
119
+ const blob = new Blob([content], { type: "text/javascript" });
120
+ return URL.createObjectURL(blob);
121
+ }
122
+ async loadScriptElement(blobUrl) {
123
+ return new Promise((resolve, reject) => {
124
+ const script = document.createElement("script");
125
+ script.type = "module";
126
+ script.src = blobUrl;
127
+ script.onload = () => resolve(script);
128
+ script.onerror = () => reject(new Error("Script failed to load"));
129
+ document.head.appendChild(script);
130
+ });
131
+ }
132
+ async getTokenFromScript() {
133
+ if (typeof window === "undefined" || typeof window.Deflect?.getToken !== "function") {
134
+ throw new Error("Script did not load properly - getToken not available");
135
+ }
136
+ try {
137
+ return await window.Deflect.getToken();
138
+ } catch (error) {
139
+ throw new Error(`Script execution failed: ${error}`);
140
+ }
141
+ }
142
+ cleanup(blobUrl, scriptElement) {
143
+ URL.revokeObjectURL(blobUrl);
144
+ scriptElement.remove();
145
+ if (typeof window !== "undefined" && window.Deflect?.getToken) {
146
+ delete window.Deflect.getToken;
147
+ }
61
148
  }
62
149
  configure(params) {
63
- if (!params.actionId) {
64
- throw new Error("actionId is required in configuration");
65
- }
150
+ if (!params.actionId?.trim()) {
151
+ throw new Error("actionId is required and cannot be empty");
152
+ }
153
+ this.config = { ...params };
154
+ if (typeof window !== "undefined") {
66
155
  window.Deflect.actionId = params.actionId;
67
- if (params.scriptUrl) {
68
- this._customScriptUrl = params.scriptUrl;
69
- }
156
+ }
157
+ this.tryWarmup();
158
+ }
159
+ // Deprecated name kept for backward compatibility
160
+ async solveChallenge() {
161
+ return this.getToken();
162
+ }
163
+ async getToken() {
164
+ if (!this.config?.actionId) {
165
+ throw new Error("Must call configure() before solveChallenge()");
166
+ }
167
+ let script;
168
+ if (this.scriptCache && !this.isWarmupInProgress) {
169
+ script = this.scriptCache;
170
+ this.scriptCache = null;
171
+ } else {
172
+ script = await this.fetchScript();
173
+ }
174
+ return this.executeScript(script);
175
+ }
176
+ async warmup() {
177
+ if (!this.config?.actionId) {
178
+ return false;
179
+ }
180
+ try {
181
+ await this.tryWarmup();
182
+ return this.scriptCache !== null;
183
+ } catch {
184
+ return false;
185
+ }
186
+ }
187
+ clearCache() {
188
+ this.scriptCache = null;
189
+ }
190
+ /**
191
+ * Inject a fresh token as a hidden input into a form. Only accepts a submit event from onsubmit.
192
+ * Usage: <form ... onsubmit="return Deflect.injectToken(event)">
193
+ * Returns false to prevent double submit.
194
+ */
195
+ async injectToken(event) {
196
+ if (!event || !event.target || !(event.target instanceof HTMLFormElement)) {
197
+ throw new Error("injectToken: must be called from a form submit event");
198
+ }
199
+ event.preventDefault();
200
+ const form = event.target;
201
+ const token = await this.getToken();
202
+ Array.from(form.querySelectorAll('input[name="deflect_token"]')).forEach(
203
+ (el) => el.remove()
204
+ );
205
+ const hidden = document.createElement("input");
206
+ hidden.type = "hidden";
207
+ hidden.name = "deflect_token";
208
+ hidden.value = token;
209
+ form.appendChild(hidden);
210
+ form.submit();
211
+ return false;
70
212
  }
71
- solveChallenge() {
72
- return __awaiter(this, void 0, void 0, function* () {
73
- var _a;
74
- if (!window.Deflect.actionId) {
75
- throw new Error("actionId is missing in configuration");
76
- }
77
- this.setupReady();
78
- let scriptText;
79
- let sessionId = null;
80
- if (this._prefetchedScriptText && !this._hasUsedPrefetch) {
81
- scriptText = this._prefetchedScriptText;
82
- this._hasUsedPrefetch = true;
83
- }
84
- else {
85
- const scriptUrl = this._getScriptUrl();
86
- const response = yield fetch(scriptUrl, { cache: "no-store" });
87
- if (!response.ok) {
88
- throw new Error("Failed to fetch the Deflect script");
89
- }
90
- sessionId = response.headers.get("session_id");
91
- scriptText = yield response.text();
92
- }
93
- if (sessionId) {
94
- window.Deflect.sessionId = sessionId;
95
- }
96
- const blob = new Blob([scriptText], { type: "text/javascript" });
97
- const blobUrl = URL.createObjectURL(blob);
98
- const scriptEl = document.createElement("script");
99
- scriptEl.type = "module";
100
- scriptEl.src = blobUrl;
101
- document.head.appendChild(scriptEl);
102
- yield new Promise((resolve, reject) => {
103
- scriptEl.onload = () => resolve();
104
- scriptEl.onerror = () => reject("Failed to load the Deflect script");
105
- });
106
- yield ((_a = window.Deflect.ready) === null || _a === void 0 ? void 0 : _a.promise);
107
- if (typeof window.Deflect === "undefined" ||
108
- typeof window.Deflect.getToken !== "function") {
109
- throw new Error("Deflect script did not load properly");
110
- }
111
- let token;
112
- try {
113
- token = yield window.Deflect.getToken();
114
- }
115
- catch (error) {
116
- throw new Error(`Deflect script execution failed: ${error}`);
117
- }
118
- this._refetchScript();
119
- URL.revokeObjectURL(blobUrl);
120
- scriptEl.remove();
121
- delete window.Deflect.getToken;
122
- return token;
123
- });
124
- }
125
- }
126
- export default new Deflect();
213
+ };
214
+ var src_default = new Deflect();
215
+
216
+ // src/global.ts
217
+ if (typeof window !== "undefined") {
218
+ window.Deflect = src_default;
219
+ }
220
+ var global_default = src_default;
221
+ return __toCommonJS(global_exports);
222
+ })();
@@ -0,0 +1 @@
1
+ "use strict";var Deflect=(()=>{var c=Object.defineProperty;var l=Object.getOwnPropertyDescriptor;var d=Object.getOwnPropertyNames;var p=Object.prototype.hasOwnProperty;var f=(n,e)=>{for(var t in e)c(n,t,{get:e[t],enumerable:!0})},u=(n,e,t,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let i of d(e))!p.call(n,i)&&i!==t&&c(n,i,{get:()=>e[i],enumerable:!(r=l(e,i))||r.enumerable});return n};var h=n=>u(c({},"__esModule",{value:!0}),n);var m={};f(m,{default:()=>w});var s=class{constructor(){this.config=null;this.scriptCache=null;this.isWarmupInProgress=!1;this.initializeGlobalState(),this.setupAutomaticWarmup()}initializeGlobalState(){typeof window>"u"||(window.Deflect=window.Deflect||{})}setupAutomaticWarmup(){typeof window>"u"||(document.readyState==="loading"?document.addEventListener("DOMContentLoaded",()=>this.tryWarmup()):setTimeout(()=>this.tryWarmup(),100))}async tryWarmup(){if(!(!this.config?.actionId||this.isWarmupInProgress||this.scriptCache)){this.isWarmupInProgress=!0;try{this.scriptCache=await this.fetchScript()}catch{}finally{this.isWarmupInProgress=!1}}}buildScriptUrl(e){let t=this.config?.scriptUrl||"https://js.deflect.bot/main.js";if(this.config?.scriptUrl)return t;let r=Date.now().toString();return`${t}?action_id=${e}&_=${r}`}async fetchScript(){if(!this.config?.actionId)throw new Error("actionId is required");let e=this.buildScriptUrl(this.config.actionId),t=await fetch(e,{cache:"no-store"});if(!t.ok)throw new Error(`Failed to fetch script: ${t.status}`);return{content:await t.text(),sessionId:t.headers.get("session_id")||void 0}}async executeScript(e){e.sessionId&&typeof window<"u"&&(window.Deflect.sessionId=e.sessionId);let t=this.createReadyPromise(),r=this.createScriptBlob(e.content),i=await this.loadScriptElement(r);try{await t;let o=await this.getTokenFromScript();return this.prefetchNextScript(),o}finally{this.cleanup(r,i)}}prefetchNextScript(){this.tryWarmup().catch(()=>{})}createReadyPromise(){return new Promise(e=>{typeof window<"u"&&(window.Deflect.ready={promise:new Promise(t=>{window.Deflect.ready.resolve=t}),resolve:()=>e()})})}createScriptBlob(e){let t=new Blob([e],{type:"text/javascript"});return URL.createObjectURL(t)}async loadScriptElement(e){return new Promise((t,r)=>{let i=document.createElement("script");i.type="module",i.src=e,i.onload=()=>t(i),i.onerror=()=>r(new Error("Script failed to load")),document.head.appendChild(i)})}async getTokenFromScript(){if(typeof window>"u"||typeof window.Deflect?.getToken!="function")throw new Error("Script did not load properly - getToken not available");try{return await window.Deflect.getToken()}catch(e){throw new Error(`Script execution failed: ${e}`)}}cleanup(e,t){URL.revokeObjectURL(e),t.remove(),typeof window<"u"&&window.Deflect?.getToken&&delete window.Deflect.getToken}configure(e){if(!e.actionId?.trim())throw new Error("actionId is required and cannot be empty");this.config={...e},typeof window<"u"&&(window.Deflect.actionId=e.actionId),this.tryWarmup()}async solveChallenge(){return this.getToken()}async getToken(){if(!this.config?.actionId)throw new Error("Must call configure() before solveChallenge()");let e;return this.scriptCache&&!this.isWarmupInProgress?(e=this.scriptCache,this.scriptCache=null):e=await this.fetchScript(),this.executeScript(e)}async warmup(){if(!this.config?.actionId)return!1;try{return await this.tryWarmup(),this.scriptCache!==null}catch{return!1}}clearCache(){this.scriptCache=null}async injectToken(e){if(!e||!e.target||!(e.target instanceof HTMLFormElement))throw new Error("injectToken: must be called from a form submit event");e.preventDefault();let t=e.target,r=await this.getToken();Array.from(t.querySelectorAll('input[name="deflect_token"]')).forEach(o=>o.remove());let i=document.createElement("input");return i.type="hidden",i.name="deflect_token",i.value=r,t.appendChild(i),t.submit(),!1}},a=new s;typeof window<"u"&&(window.Deflect=a);var w=a;return h(m);})();
package/package.json CHANGED
@@ -1,11 +1,19 @@
1
1
  {
2
2
  "name": "@deflectbot/deflect-sdk",
3
- "version": "1.2.3",
3
+ "version": "1.3.1",
4
4
  "description": "SDK for deflect.bot - Use it for seamless captcha integration on any website.",
5
- "main": "dist/index.js",
6
- "types": "dist/types/index.d.ts",
5
+ "main": "dist/index.min.js",
6
+ "browser": "dist/index.min.js",
7
+ "unpkg": "dist/index.min.js",
8
+ "jsdelivr": "dist/index.min.js",
9
+ "files": [
10
+ "dist/**/*"
11
+ ],
7
12
  "scripts": {
8
- "build": "tsc"
13
+ "build": "npm run build:global",
14
+ "build:global": "npm run build:global:dev && npm run build:global:min",
15
+ "build:global:dev": "esbuild src/global.ts --bundle --format=iife --global-name=Deflect --outfile=dist/index.js --keep-names",
16
+ "build:global:min": "esbuild src/global.ts --bundle --format=iife --global-name=Deflect --minify --outfile=dist/index.min.js"
9
17
  },
10
18
  "author": "Deflect",
11
19
  "license": "MIT",
@@ -14,12 +22,11 @@
14
22
  "eslint": "^9.22.0",
15
23
  "globals": "^16.0.0",
16
24
  "typescript": "^5.7.3",
17
- "typescript-eslint": "^8.27.0"
25
+ "typescript-eslint": "^8.27.0",
26
+ "esbuild": "^0.23.0"
18
27
  },
19
28
  "publishConfig": {
20
29
  "access": "public"
21
30
  },
22
- "dependencies": {
23
- "@deflectbot/deflect-sdk": "file:"
24
- }
31
+ "dependencies": {}
25
32
  }
package/.gitattributes DELETED
@@ -1,2 +0,0 @@
1
- # Auto detect text files and perform LF normalization
2
- * text=auto
@@ -1,21 +0,0 @@
1
- interface DeflectConfig {
2
- actionId: string;
3
- scriptUrl?: string;
4
- extraArgs?: {
5
- [key: string]: string;
6
- };
7
- }
8
- declare class Deflect {
9
- private _prefetchedScriptText;
10
- private _hasUsedPrefetch;
11
- private _customScriptUrl;
12
- constructor();
13
- private _getScriptUrl;
14
- private _warmupScript;
15
- private _refetchScript;
16
- private setupReady;
17
- configure(params: DeflectConfig): void;
18
- solveChallenge(): Promise<string>;
19
- }
20
- declare const _default: Deflect;
21
- export default _default;
package/eslint.config.mjs DELETED
@@ -1,12 +0,0 @@
1
- import globals from "globals";
2
- import pluginJs from "@eslint/js";
3
- import tseslint from "typescript-eslint";
4
-
5
-
6
- /** @type {import('eslint').Linter.Config[]} */
7
- export default [
8
- {files: ["**/*.{js,mjs,cjs,ts}"]},
9
- {languageOptions: { globals: globals.browser }},
10
- pluginJs.configs.recommended,
11
- ...tseslint.configs.recommended,
12
- ];
package/src/index.ts DELETED
@@ -1,148 +0,0 @@
1
- interface DeflectConfig {
2
- actionId: string;
3
- scriptUrl?: string;
4
- extraArgs?: { [key: string]: string };
5
- }
6
-
7
- class Deflect {
8
- private _prefetchedScriptText: string | null = null;
9
- private _hasUsedPrefetch = false;
10
- private _customScriptUrl: string | null = null;
11
-
12
- constructor() {
13
- window.Deflect = window.Deflect || {};
14
- window.Deflect.extraArgs = window.Deflect.extraArgs || {};
15
-
16
- if (typeof window !== "undefined") {
17
- window.addEventListener("load", () => {
18
- setTimeout(() => {
19
- this._warmupScript();
20
- }, 500);
21
- });
22
- }
23
- }
24
-
25
- private _getScriptUrl(): string {
26
- const nonce = Date.now().toString();
27
- if (this._customScriptUrl) {
28
- const separator = this._customScriptUrl.includes("?") ? "&" : "?";
29
- return `${this._customScriptUrl}${separator}action_id=${window.Deflect.actionId}&_=${nonce}`;
30
- }
31
- return `https://js.deflect.bot/main.js?action_id=${window.Deflect.actionId}&_=${nonce}`;
32
- }
33
-
34
- private _warmupScript(): void {
35
- if (!window.Deflect.actionId) return;
36
-
37
- const scriptUrl = this._getScriptUrl();
38
- fetch(scriptUrl, { cache: "no-store" })
39
- .then(async (res) => {
40
- if (!res.ok) return;
41
- this._prefetchedScriptText = await res.text();
42
- })
43
- .catch(() => {});
44
- }
45
-
46
- private _refetchScript(): void {
47
- this._hasUsedPrefetch = false;
48
- this._prefetchedScriptText = null;
49
-
50
- setTimeout(() => {
51
- this._warmupScript();
52
- }, 100);
53
- }
54
-
55
- private setupReady(): void {
56
- let resolveFn: () => void;
57
- const promise = new Promise<void>((resolve) => {
58
- resolveFn = resolve;
59
- });
60
- window.Deflect.ready = {
61
- promise,
62
- resolve: () => resolveFn(),
63
- };
64
- }
65
-
66
- configure(params: DeflectConfig): void {
67
- if (!params.actionId) {
68
- throw new Error("actionId is required in configuration");
69
- }
70
- window.Deflect.actionId = params.actionId;
71
-
72
- if (params.scriptUrl) {
73
- this._customScriptUrl = params.scriptUrl;
74
- }
75
- }
76
-
77
- async solveChallenge(): Promise<string> {
78
- if (!window.Deflect.actionId) {
79
- throw new Error("actionId is missing in configuration");
80
- }
81
-
82
- this.setupReady();
83
-
84
- let scriptText: string;
85
- let sessionId: string | null = null;
86
-
87
- if (this._prefetchedScriptText && !this._hasUsedPrefetch) {
88
- scriptText = this._prefetchedScriptText;
89
- this._hasUsedPrefetch = true;
90
- } else {
91
- const scriptUrl = this._getScriptUrl();
92
- const response = await fetch(scriptUrl, { cache: "no-store" });
93
-
94
- if (!response.ok) {
95
- throw new Error("Failed to fetch the Deflect script");
96
- }
97
-
98
- sessionId = response.headers.get("session_id");
99
- scriptText = await response.text();
100
- }
101
-
102
- if (sessionId) {
103
- window.Deflect.sessionId = sessionId;
104
- }
105
-
106
- const blob = new Blob([scriptText], { type: "text/javascript" });
107
- const blobUrl = URL.createObjectURL(blob);
108
-
109
- const scriptEl = document.createElement("script");
110
- scriptEl.type = "module";
111
- scriptEl.src = blobUrl;
112
-
113
- document.head.appendChild(scriptEl);
114
-
115
- await new Promise<void>((resolve, reject) => {
116
- scriptEl.onload = () => resolve();
117
- scriptEl.onerror = () => reject("Failed to load the Deflect script");
118
- });
119
-
120
- await window.Deflect.ready?.promise;
121
-
122
- if (
123
- typeof window.Deflect === "undefined" ||
124
- typeof window.Deflect.getToken !== "function"
125
- ) {
126
- throw new Error("Deflect script did not load properly");
127
- }
128
-
129
- let token: string;
130
-
131
- try {
132
- token = await window.Deflect.getToken();
133
- } catch (error) {
134
- throw new Error(`Deflect script execution failed: ${error}`);
135
- }
136
-
137
- this._refetchScript();
138
-
139
- URL.revokeObjectURL(blobUrl);
140
- scriptEl.remove();
141
-
142
- delete window.Deflect.getToken;
143
-
144
- return token;
145
- }
146
- }
147
-
148
- export default new Deflect();
@@ -1,3 +0,0 @@
1
- interface Window {
2
- Deflect: any;
3
- }
package/tsconfig.json DELETED
@@ -1,22 +0,0 @@
1
- {
2
- "compilerOptions": {
3
- "target": "ES2015", // Set target to ES2015 or later
4
- "module": "ESNext", // Use ES module syntax
5
- "moduleResolution": "node", // Resolve modules like Node.js
6
- "strict": true, // Enable strict type-checking
7
- "declaration": true, // Enable generation of .d.ts files
8
- "declarationDir": "./dist/types", // Directory for .d.ts files
9
- "esModuleInterop": true, // Allow importing non-ESM modules
10
- "skipLibCheck": true, // Skip type checking of declaration files
11
- "outDir": "./dist", // Output directory for JavaScript files
12
- "lib": ["ES2015", "DOM"], // Add ES2015 and DOM libraries
13
- "jsx": "preserve" // For JSX compatibility in Vue
14
- },
15
- "include": [
16
- "src/**/*"
17
- ],
18
- "exclude": [
19
- "node_modules",
20
- "dist"
21
- ]
22
- }