@deflectbot/deflect-sdk 1.1.16 → 1.2.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/.gitattributes CHANGED
@@ -1,2 +1,2 @@
1
- # Auto detect text files and perform LF normalization
2
- * text=auto
1
+ # Auto detect text files and perform LF normalization
2
+ * text=auto
package/README.md CHANGED
@@ -1,50 +1,50 @@
1
- # Deflect -
2
-
3
- ![npm](https://img.shields.io/npm/v/@deflectbot/deflect-sdk)
4
- ![downloads](https://img.shields.io/npm/dm/@deflectbot/deflect-sdk)
5
-
6
- Deflect is an antibot solution that works with Vue, React, NextJS, and other JavaScript frameworks.
7
-
8
- ---
9
-
10
- ## CDN Install (Auto-Updates)
11
-
12
- ```bash
13
- Include in your project:
14
- <script src="https://cdn.jsdelivr.net/npm/@deflectbot/deflect-sdk/dist/index.min.js"></script>
15
- ```
16
-
17
- ---
18
-
19
- ## NPM Install (Requires Manual Updates)
20
-
21
- ```bash
22
- npm install deflect
23
- ```
24
-
25
- ---
26
-
27
- ## Setup
28
-
29
- ```ts
30
- import Deflect from '@deflectbot/deflect-sdk';
31
-
32
- Deflect.configure({
33
- actionId: 'YOUR_ACTION_ID',
34
- extraArgs: { mode: 'strict' }, // Optional
35
- forceRefresh: true, // Optional
36
- });
37
- ```
38
-
39
- ---
40
-
41
- ## Solve Challenge
42
-
43
- ```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
- }
50
- ```
1
+ # Deflect -
2
+
3
+ ![npm](https://img.shields.io/npm/v/@deflectbot/deflect-sdk)
4
+ ![downloads](https://img.shields.io/npm/dm/@deflectbot/deflect-sdk)
5
+
6
+ Deflect is an antibot solution that works with Vue, React, NextJS, and other JavaScript frameworks.
7
+
8
+ ---
9
+
10
+ ## CDN Install (Auto-Updates)
11
+
12
+ ```bash
13
+ Include in your project:
14
+ <script src="https://cdn.jsdelivr.net/npm/@deflectbot/deflect-sdk/dist/index.min.js"></script>
15
+ ```
16
+
17
+ ---
18
+
19
+ ## NPM Install (Requires Manual Updates)
20
+
21
+ ```bash
22
+ npm install deflect
23
+ ```
24
+
25
+ ---
26
+
27
+ ## Setup
28
+
29
+ ```ts
30
+ import Deflect from '@deflectbot/deflect-sdk';
31
+
32
+ Deflect.configure({
33
+ actionId: 'YOUR_ACTION_ID',
34
+ extraArgs: { mode: 'strict' }, // Optional
35
+ forceRefresh: true, // Optional
36
+ });
37
+ ```
38
+
39
+ ---
40
+
41
+ ## Solve Challenge
42
+
43
+ ```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
+ }
50
+ ```
package/dist/index.js CHANGED
@@ -9,100 +9,188 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
9
9
  };
10
10
  class Deflect {
11
11
  constructor() {
12
- this._prefetchedScriptText = null;
13
- this._hasUsedPrefetch = false;
12
+ this.config = null;
13
+ this.scriptCache = null;
14
+ this.isWarmupInProgress = false;
15
+ this.initializeGlobalState();
16
+ this.setupAutomaticWarmup();
17
+ }
18
+ initializeGlobalState() {
19
+ if (typeof window === "undefined")
20
+ return;
14
21
  window.Deflect = window.Deflect || {};
15
22
  window.Deflect.extraArgs = window.Deflect.extraArgs || {};
16
- if (typeof window !== "undefined") {
17
- window.addEventListener("load", () => {
18
- setTimeout(() => {
19
- this._warmupScript();
20
- }, 500);
21
- });
22
- }
23
23
  }
24
- _warmupScript() {
25
- if (!window.Deflect.actionId)
24
+ setupAutomaticWarmup() {
25
+ if (typeof window === "undefined")
26
26
  return;
27
- const nonce = Date.now().toString();
28
- const scriptUrl = `https://js.deflect.bot/main.js?action_id=${window.Deflect.actionId}&_=${nonce}`;
29
- fetch(scriptUrl, { cache: "no-store" })
30
- .then((res) => __awaiter(this, void 0, void 0, function* () {
31
- if (!res.ok)
27
+ if (document.readyState === "loading") {
28
+ document.addEventListener("DOMContentLoaded", () => this.tryWarmup());
29
+ }
30
+ else {
31
+ setTimeout(() => this.tryWarmup(), 100);
32
+ }
33
+ }
34
+ tryWarmup() {
35
+ return __awaiter(this, void 0, void 0, function* () {
36
+ var _a;
37
+ if (!((_a = this.config) === null || _a === void 0 ? void 0 : _a.actionId) || this.isWarmupInProgress || this.scriptCache) {
32
38
  return;
33
- this._prefetchedScriptText = yield res.text();
34
- }))
35
- .catch(() => { });
36
- }
37
- setupReady() {
38
- let resolveFn;
39
- const promise = new Promise((resolve) => {
40
- resolveFn = resolve;
39
+ }
40
+ this.isWarmupInProgress = true;
41
+ try {
42
+ this.scriptCache = yield this.fetchScript();
43
+ }
44
+ catch (_b) {
45
+ }
46
+ finally {
47
+ this.isWarmupInProgress = false;
48
+ }
41
49
  });
42
- window.Deflect.ready = {
43
- promise,
44
- resolve: () => resolveFn(),
45
- };
46
50
  }
47
- configure(params) {
48
- if (!params.actionId) {
49
- throw new Error("actionId is required in configuration");
51
+ buildScriptUrl(actionId) {
52
+ var _a, _b;
53
+ const baseUrl = ((_a = this.config) === null || _a === void 0 ? void 0 : _a.scriptUrl) || "https://js.deflect.bot/main.js";
54
+ if ((_b = this.config) === null || _b === void 0 ? void 0 : _b.scriptUrl) {
55
+ return baseUrl;
50
56
  }
51
- window.Deflect.actionId = params.actionId;
57
+ const nonce = Date.now().toString();
58
+ return `${baseUrl}?action_id=${actionId}&_=${nonce}`;
52
59
  }
53
- solveChallenge() {
60
+ fetchScript() {
54
61
  return __awaiter(this, void 0, void 0, function* () {
55
62
  var _a;
56
- if (!window.Deflect.actionId) {
57
- throw new Error("actionId is missing in configuration");
63
+ if (!((_a = this.config) === null || _a === void 0 ? void 0 : _a.actionId)) {
64
+ throw new Error("actionId is required");
58
65
  }
59
- this.setupReady();
60
- let scriptText;
61
- let sessionId = null;
62
- if (this._prefetchedScriptText && !this._hasUsedPrefetch) {
63
- scriptText = this._prefetchedScriptText;
64
- this._hasUsedPrefetch = true;
66
+ const url = this.buildScriptUrl(this.config.actionId);
67
+ const response = yield fetch(url, { cache: "no-store" });
68
+ if (!response.ok) {
69
+ throw new Error(`Failed to fetch script: ${response.status}`);
65
70
  }
66
- else {
67
- const nonce = Date.now().toString();
68
- const scriptUrl = `https://js.deflect.bot/main.js?action_id=${window.Deflect.actionId}&_=${nonce}`;
69
- const response = yield fetch(scriptUrl, { cache: "no-store" });
70
- if (!response.ok) {
71
- throw new Error("Failed to fetch the Deflect script");
72
- }
73
- sessionId = response.headers.get("session_id");
74
- scriptText = yield response.text();
75
- }
76
- if (sessionId) {
77
- window.Deflect.sessionId = sessionId;
78
- }
79
- const blob = new Blob([scriptText], { type: "text/javascript" });
80
- const blobUrl = URL.createObjectURL(blob);
81
- const scriptEl = document.createElement("script");
82
- scriptEl.type = "module";
83
- scriptEl.src = blobUrl;
84
- document.head.appendChild(scriptEl);
85
- yield new Promise((resolve, reject) => {
86
- scriptEl.onload = () => resolve();
87
- scriptEl.onerror = () => reject("Failed to load the Deflect script");
71
+ return {
72
+ content: yield response.text(),
73
+ sessionId: response.headers.get("session_id") || undefined,
74
+ };
75
+ });
76
+ }
77
+ executeScript(script) {
78
+ return __awaiter(this, void 0, void 0, function* () {
79
+ if (script.sessionId && typeof window !== "undefined") {
80
+ window.Deflect.sessionId = script.sessionId;
81
+ }
82
+ const readyPromise = this.createReadyPromise();
83
+ const blobUrl = this.createScriptBlob(script.content);
84
+ const scriptElement = yield this.loadScriptElement(blobUrl);
85
+ try {
86
+ yield readyPromise;
87
+ const token = yield this.getTokenFromScript();
88
+ return token;
89
+ }
90
+ finally {
91
+ this.cleanup(blobUrl, scriptElement);
92
+ }
93
+ });
94
+ }
95
+ createReadyPromise() {
96
+ return new Promise((resolve) => {
97
+ if (typeof window !== "undefined") {
98
+ window.Deflect.ready = {
99
+ promise: new Promise((innerResolve) => {
100
+ window.Deflect.ready.resolve = innerResolve;
101
+ }),
102
+ resolve: () => resolve(),
103
+ };
104
+ }
105
+ });
106
+ }
107
+ createScriptBlob(content) {
108
+ const blob = new Blob([content], { type: "text/javascript" });
109
+ return URL.createObjectURL(blob);
110
+ }
111
+ loadScriptElement(blobUrl) {
112
+ return __awaiter(this, void 0, void 0, function* () {
113
+ return new Promise((resolve, reject) => {
114
+ const script = document.createElement("script");
115
+ script.type = "module";
116
+ script.src = blobUrl;
117
+ script.onload = () => resolve(script);
118
+ script.onerror = () => reject(new Error("Script failed to load"));
119
+ document.head.appendChild(script);
88
120
  });
89
- yield ((_a = window.Deflect.ready) === null || _a === void 0 ? void 0 : _a.promise);
90
- if (typeof window.Deflect === "undefined" ||
91
- typeof window.Deflect.getToken !== "function") {
92
- throw new Error("Deflect script did not load properly");
121
+ });
122
+ }
123
+ getTokenFromScript() {
124
+ return __awaiter(this, void 0, void 0, function* () {
125
+ var _a;
126
+ if (typeof window === "undefined" ||
127
+ typeof ((_a = window.Deflect) === null || _a === void 0 ? void 0 : _a.getToken) !== "function") {
128
+ throw new Error("Script did not load properly - getToken not available");
93
129
  }
94
- let token;
95
130
  try {
96
- token = yield window.Deflect.getToken();
131
+ return yield window.Deflect.getToken();
97
132
  }
98
133
  catch (error) {
99
- throw new Error(`Deflect script execution failed: ${error}`);
134
+ throw new Error(`Script execution failed: ${error}`);
100
135
  }
101
- URL.revokeObjectURL(blobUrl);
102
- scriptEl.remove();
136
+ });
137
+ }
138
+ cleanup(blobUrl, scriptElement) {
139
+ var _a;
140
+ URL.revokeObjectURL(blobUrl);
141
+ scriptElement.remove();
142
+ if (typeof window !== "undefined" && ((_a = window.Deflect) === null || _a === void 0 ? void 0 : _a.getToken)) {
103
143
  delete window.Deflect.getToken;
104
- return token;
144
+ }
145
+ }
146
+ configure(params) {
147
+ var _a;
148
+ if (!((_a = params.actionId) === null || _a === void 0 ? void 0 : _a.trim())) {
149
+ throw new Error("actionId is required and cannot be empty");
150
+ }
151
+ this.config = Object.assign({}, params);
152
+ if (typeof window !== "undefined") {
153
+ window.Deflect.actionId = params.actionId;
154
+ if (params.extraArgs) {
155
+ window.Deflect.extraArgs = Object.assign({}, params.extraArgs);
156
+ }
157
+ }
158
+ this.tryWarmup();
159
+ }
160
+ solveChallenge() {
161
+ return __awaiter(this, void 0, void 0, function* () {
162
+ var _a;
163
+ if (!((_a = this.config) === null || _a === void 0 ? void 0 : _a.actionId)) {
164
+ throw new Error("Must call configure() before solveChallenge()");
165
+ }
166
+ let script;
167
+ if (this.scriptCache && !this.isWarmupInProgress) {
168
+ script = this.scriptCache;
169
+ this.scriptCache = null;
170
+ }
171
+ else {
172
+ script = yield this.fetchScript();
173
+ }
174
+ return this.executeScript(script);
175
+ });
176
+ }
177
+ warmup() {
178
+ return __awaiter(this, void 0, void 0, function* () {
179
+ var _a;
180
+ if (!((_a = this.config) === null || _a === void 0 ? void 0 : _a.actionId)) {
181
+ return false;
182
+ }
183
+ try {
184
+ yield this.tryWarmup();
185
+ return this.scriptCache !== null;
186
+ }
187
+ catch (_b) {
188
+ return false;
189
+ }
105
190
  });
106
191
  }
192
+ clearCache() {
193
+ this.scriptCache = null;
194
+ }
107
195
  }
108
196
  export default new Deflect();
@@ -1,17 +1,28 @@
1
1
  interface DeflectConfig {
2
2
  actionId: string;
3
- extraArgs?: {
4
- [key: string]: string;
5
- };
3
+ scriptUrl?: string;
4
+ extraArgs?: Record<string, string>;
6
5
  }
7
6
  declare class Deflect {
8
- private _prefetchedScriptText;
9
- private _hasUsedPrefetch;
7
+ private config;
8
+ private scriptCache;
9
+ private isWarmupInProgress;
10
10
  constructor();
11
- private _warmupScript;
12
- private setupReady;
11
+ private initializeGlobalState;
12
+ private setupAutomaticWarmup;
13
+ private tryWarmup;
14
+ private buildScriptUrl;
15
+ private fetchScript;
16
+ private executeScript;
17
+ private createReadyPromise;
18
+ private createScriptBlob;
19
+ private loadScriptElement;
20
+ private getTokenFromScript;
21
+ private cleanup;
13
22
  configure(params: DeflectConfig): void;
14
23
  solveChallenge(): Promise<string>;
24
+ warmup(): Promise<boolean>;
25
+ clearCache(): void;
15
26
  }
16
27
  declare const _default: Deflect;
17
28
  export default _default;
package/eslint.config.mjs CHANGED
@@ -1,12 +1,12 @@
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,
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
12
  ];
package/package.json CHANGED
@@ -1,25 +1,25 @@
1
- {
2
- "name": "@deflectbot/deflect-sdk",
3
- "version": "1.1.16",
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",
7
- "scripts": {
8
- "build": "tsc"
9
- },
10
- "author": "Deflect",
11
- "license": "MIT",
12
- "devDependencies": {
13
- "@eslint/js": "^9.22.0",
14
- "eslint": "^9.22.0",
15
- "globals": "^16.0.0",
16
- "typescript": "^5.7.3",
17
- "typescript-eslint": "^8.27.0"
18
- },
19
- "publishConfig": {
20
- "access": "public"
21
- },
22
- "dependencies": {
23
- "@deflectbot/deflect-sdk": "file:"
24
- }
25
- }
1
+ {
2
+ "name": "@deflectbot/deflect-sdk",
3
+ "version": "1.2.1",
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",
7
+ "scripts": {
8
+ "build": "tsc"
9
+ },
10
+ "author": "Deflect",
11
+ "license": "MIT",
12
+ "devDependencies": {
13
+ "@eslint/js": "^9.22.0",
14
+ "eslint": "^9.22.0",
15
+ "globals": "^16.0.0",
16
+ "typescript": "^5.7.3",
17
+ "typescript-eslint": "^8.27.0"
18
+ },
19
+ "publishConfig": {
20
+ "access": "public"
21
+ },
22
+ "dependencies": {
23
+ "@deflectbot/deflect-sdk": "file:"
24
+ }
25
+ }
package/src/index.ts CHANGED
@@ -1,124 +1,218 @@
1
- interface DeflectConfig {
2
- actionId: string;
3
- extraArgs?: { [key: string]: string };
4
- }
5
-
6
- class Deflect {
7
- private _prefetchedScriptText: string | null = null;
8
- private _hasUsedPrefetch = false;
9
-
10
- constructor() {
11
- window.Deflect = window.Deflect || {};
12
- window.Deflect.extraArgs = window.Deflect.extraArgs || {};
13
-
14
- if (typeof window !== "undefined") {
15
- window.addEventListener("load", () => {
16
- setTimeout(() => {
17
- this._warmupScript();
18
- }, 500);
19
- });
20
- }
21
- }
22
-
23
- private _warmupScript(): void {
24
- if (!window.Deflect.actionId) return;
25
-
26
- const nonce = Date.now().toString();
27
- const scriptUrl = `https://js.deflect.bot/main.js?action_id=${window.Deflect.actionId}&_=${nonce}`;
28
- fetch(scriptUrl, { cache: "no-store" })
29
- .then(async (res) => {
30
- if (!res.ok) return;
31
- this._prefetchedScriptText = await res.text();
32
- })
33
- .catch(() => {});
34
- }
35
-
36
- private setupReady(): void {
37
- let resolveFn: () => void;
38
- const promise = new Promise<void>((resolve) => {
39
- resolveFn = resolve;
40
- });
41
- window.Deflect.ready = {
42
- promise,
43
- resolve: () => resolveFn(),
44
- };
45
- }
46
-
47
- configure(params: DeflectConfig): void {
48
- if (!params.actionId) {
49
- throw new Error("actionId is required in configuration");
50
- }
51
- window.Deflect.actionId = params.actionId;
52
- }
53
-
54
- async solveChallenge(): Promise<string> {
55
- if (!window.Deflect.actionId) {
56
- throw new Error("actionId is missing in configuration");
57
- }
58
-
59
- this.setupReady();
60
-
61
- let scriptText: string;
62
- let sessionId: string | null = null;
63
-
64
- if (this._prefetchedScriptText && !this._hasUsedPrefetch) {
65
- scriptText = this._prefetchedScriptText;
66
- this._hasUsedPrefetch = true;
67
- } else {
68
- const nonce = Date.now().toString();
69
- const scriptUrl = `https://js.deflect.bot/main.js?action_id=${window.Deflect.actionId}&_=${nonce}`;
70
- const response = await fetch(scriptUrl, { cache: "no-store" });
71
-
72
- if (!response.ok) {
73
- throw new Error("Failed to fetch the Deflect script");
74
- }
75
-
76
- sessionId = response.headers.get("session_id");
77
- scriptText = await response.text();
78
- }
79
-
80
- if (sessionId) {
81
- window.Deflect.sessionId = sessionId;
82
- }
83
-
84
- const blob = new Blob([scriptText], { type: "text/javascript" });
85
- const blobUrl = URL.createObjectURL(blob);
86
-
87
- const scriptEl = document.createElement("script");
88
- scriptEl.type = "module";
89
- scriptEl.src = blobUrl;
90
-
91
- document.head.appendChild(scriptEl);
92
-
93
- await new Promise<void>((resolve, reject) => {
94
- scriptEl.onload = () => resolve();
95
- scriptEl.onerror = () => reject("Failed to load the Deflect script");
96
- });
97
-
98
- await window.Deflect.ready?.promise;
99
-
100
- if (
101
- typeof window.Deflect === "undefined" ||
102
- typeof window.Deflect.getToken !== "function"
103
- ) {
104
- throw new Error("Deflect script did not load properly");
105
- }
106
-
107
- let token: string;
108
-
109
- try {
110
- token = await window.Deflect.getToken();
111
- } catch (error) {
112
- throw new Error(`Deflect script execution failed: ${error}`);
113
- }
114
-
115
- URL.revokeObjectURL(blobUrl);
116
- scriptEl.remove();
117
-
118
- delete window.Deflect.getToken;
119
-
120
- return token;
121
- }
122
- }
123
-
124
- export default new Deflect();
1
+ interface DeflectConfig {
2
+ actionId: string;
3
+ scriptUrl?: string;
4
+ extraArgs?: Record<string, string>;
5
+ }
6
+
7
+ interface DeflectScript {
8
+ sessionId?: string;
9
+ content: string;
10
+ }
11
+
12
+ class Deflect {
13
+ private config: DeflectConfig | null = null;
14
+ private scriptCache: DeflectScript | null = null;
15
+ private isWarmupInProgress = false;
16
+
17
+ constructor() {
18
+ this.initializeGlobalState();
19
+ this.setupAutomaticWarmup();
20
+ }
21
+
22
+ private initializeGlobalState(): void {
23
+ if (typeof window === "undefined") return;
24
+
25
+ window.Deflect = window.Deflect || {};
26
+ window.Deflect.extraArgs = window.Deflect.extraArgs || {};
27
+ }
28
+
29
+ private setupAutomaticWarmup(): void {
30
+ if (typeof window === "undefined") return;
31
+
32
+ if (document.readyState === "loading") {
33
+ document.addEventListener("DOMContentLoaded", () => this.tryWarmup());
34
+ } else {
35
+ setTimeout(() => this.tryWarmup(), 100);
36
+ }
37
+ }
38
+
39
+ private async tryWarmup(): Promise<void> {
40
+ if (!this.config?.actionId || this.isWarmupInProgress || this.scriptCache) {
41
+ return;
42
+ }
43
+
44
+ this.isWarmupInProgress = true;
45
+
46
+ try {
47
+ this.scriptCache = await this.fetchScript();
48
+ } catch {
49
+ /* empty */
50
+ } finally {
51
+ this.isWarmupInProgress = false;
52
+ }
53
+ }
54
+
55
+ private buildScriptUrl(actionId: string): string {
56
+ const baseUrl = this.config?.scriptUrl || "https://js.deflect.bot/main.js";
57
+
58
+ if (this.config?.scriptUrl) {
59
+ return baseUrl;
60
+ }
61
+
62
+ const nonce = Date.now().toString();
63
+ return `${baseUrl}?action_id=${actionId}&_=${nonce}`;
64
+ }
65
+
66
+ private async fetchScript(): Promise<DeflectScript> {
67
+ if (!this.config?.actionId) {
68
+ throw new Error("actionId is required");
69
+ }
70
+
71
+ const url = this.buildScriptUrl(this.config.actionId);
72
+ const response = await fetch(url, { cache: "no-store" });
73
+
74
+ if (!response.ok) {
75
+ throw new Error(`Failed to fetch script: ${response.status}`);
76
+ }
77
+
78
+ return {
79
+ content: await response.text(),
80
+ sessionId: response.headers.get("session_id") || undefined,
81
+ };
82
+ }
83
+
84
+ private async executeScript(script: DeflectScript): Promise<string> {
85
+ if (script.sessionId && typeof window !== "undefined") {
86
+ window.Deflect.sessionId = script.sessionId;
87
+ }
88
+
89
+ const readyPromise = this.createReadyPromise();
90
+
91
+ const blobUrl = this.createScriptBlob(script.content);
92
+ const scriptElement = await this.loadScriptElement(blobUrl);
93
+
94
+ try {
95
+ await readyPromise;
96
+
97
+ const token = await this.getTokenFromScript();
98
+
99
+ this.prefetchNextScript();
100
+
101
+ return token;
102
+ } finally {
103
+ this.cleanup(blobUrl, scriptElement);
104
+ }
105
+ }
106
+
107
+ private prefetchNextScript(): void {
108
+ this.tryWarmup().catch(() => {});
109
+ }
110
+
111
+ private createReadyPromise(): Promise<void> {
112
+ return new Promise<void>((resolve) => {
113
+ if (typeof window !== "undefined") {
114
+ window.Deflect.ready = {
115
+ promise: new Promise<void>((innerResolve) => {
116
+ window.Deflect.ready.resolve = innerResolve;
117
+ }),
118
+ resolve: () => resolve(),
119
+ };
120
+ }
121
+ });
122
+ }
123
+
124
+ private createScriptBlob(content: string): string {
125
+ const blob = new Blob([content], { type: "text/javascript" });
126
+ return URL.createObjectURL(blob);
127
+ }
128
+
129
+ private async loadScriptElement(blobUrl: string): Promise<HTMLScriptElement> {
130
+ return new Promise((resolve, reject) => {
131
+ const script = document.createElement("script");
132
+ script.type = "module";
133
+ script.src = blobUrl;
134
+
135
+ script.onload = () => resolve(script);
136
+ script.onerror = () => reject(new Error("Script failed to load"));
137
+
138
+ document.head.appendChild(script);
139
+ });
140
+ }
141
+
142
+ private async getTokenFromScript(): Promise<string> {
143
+ if (
144
+ typeof window === "undefined" ||
145
+ typeof window.Deflect?.getToken !== "function"
146
+ ) {
147
+ throw new Error("Script did not load properly - getToken not available");
148
+ }
149
+
150
+ try {
151
+ return await window.Deflect.getToken();
152
+ } catch (error) {
153
+ throw new Error(`Script execution failed: ${error}`);
154
+ }
155
+ }
156
+
157
+ private cleanup(blobUrl: string, scriptElement: HTMLScriptElement): void {
158
+ URL.revokeObjectURL(blobUrl);
159
+ scriptElement.remove();
160
+
161
+ if (typeof window !== "undefined" && window.Deflect?.getToken) {
162
+ delete window.Deflect.getToken;
163
+ }
164
+ }
165
+
166
+ public configure(params: DeflectConfig): void {
167
+ if (!params.actionId?.trim()) {
168
+ throw new Error("actionId is required and cannot be empty");
169
+ }
170
+
171
+ this.config = { ...params };
172
+
173
+ if (typeof window !== "undefined") {
174
+ window.Deflect.actionId = params.actionId;
175
+ if (params.extraArgs) {
176
+ window.Deflect.extraArgs = { ...params.extraArgs };
177
+ }
178
+ }
179
+
180
+ this.tryWarmup();
181
+ }
182
+
183
+ public async solveChallenge(): Promise<string> {
184
+ if (!this.config?.actionId) {
185
+ throw new Error("Must call configure() before solveChallenge()");
186
+ }
187
+
188
+ let script: DeflectScript;
189
+
190
+ if (this.scriptCache && !this.isWarmupInProgress) {
191
+ script = this.scriptCache;
192
+ this.scriptCache = null;
193
+ } else {
194
+ script = await this.fetchScript();
195
+ }
196
+
197
+ return this.executeScript(script);
198
+ }
199
+
200
+ public async warmup(): Promise<boolean> {
201
+ if (!this.config?.actionId) {
202
+ return false;
203
+ }
204
+
205
+ try {
206
+ await this.tryWarmup();
207
+ return this.scriptCache !== null;
208
+ } catch {
209
+ return false;
210
+ }
211
+ }
212
+
213
+ public clearCache(): void {
214
+ this.scriptCache = null;
215
+ }
216
+ }
217
+
218
+ export default new Deflect();
@@ -1,3 +1,3 @@
1
- interface Window {
2
- Deflect: any;
3
- }
1
+ interface Window {
2
+ Deflect: any;
3
+ }
package/tsconfig.json CHANGED
@@ -1,22 +1,22 @@
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
- }
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
+ }