@deflectbot/deflect-sdk 1.1.16 → 1.2.0
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 +2 -2
- package/README.md +50 -50
- package/dist/index.js +161 -73
- package/dist/types/index.d.ts +18 -7
- package/eslint.config.mjs +11 -11
- package/package.json +25 -25
- package/src/index.ts +211 -124
- package/src/types/window.d.ts +3 -3
- package/tsconfig.json +22 -22
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
|
-

|
|
4
|
-

|
|
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
|
+

|
|
4
|
+

|
|
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.
|
|
13
|
-
this.
|
|
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
|
-
|
|
25
|
-
if (
|
|
24
|
+
setupAutomaticWarmup() {
|
|
25
|
+
if (typeof window === "undefined")
|
|
26
26
|
return;
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
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
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
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
|
-
|
|
48
|
-
|
|
49
|
-
|
|
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
|
-
|
|
57
|
+
const nonce = Date.now().toString();
|
|
58
|
+
return `${baseUrl}?action_id=${actionId}&_=${nonce}`;
|
|
52
59
|
}
|
|
53
|
-
|
|
60
|
+
fetchScript() {
|
|
54
61
|
return __awaiter(this, void 0, void 0, function* () {
|
|
55
62
|
var _a;
|
|
56
|
-
if (!
|
|
57
|
-
throw new Error("actionId is
|
|
63
|
+
if (!((_a = this.config) === null || _a === void 0 ? void 0 : _a.actionId)) {
|
|
64
|
+
throw new Error("actionId is required");
|
|
58
65
|
}
|
|
59
|
-
this.
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
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
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
const
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
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
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
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
|
-
|
|
131
|
+
return yield window.Deflect.getToken();
|
|
97
132
|
}
|
|
98
133
|
catch (error) {
|
|
99
|
-
throw new Error(`
|
|
134
|
+
throw new Error(`Script execution failed: ${error}`);
|
|
100
135
|
}
|
|
101
|
-
|
|
102
|
-
|
|
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
|
-
|
|
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();
|
package/dist/types/index.d.ts
CHANGED
|
@@ -1,17 +1,28 @@
|
|
|
1
1
|
interface DeflectConfig {
|
|
2
2
|
actionId: string;
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
};
|
|
3
|
+
scriptUrl?: string;
|
|
4
|
+
extraArgs?: Record<string, string>;
|
|
6
5
|
}
|
|
7
6
|
declare class Deflect {
|
|
8
|
-
private
|
|
9
|
-
private
|
|
7
|
+
private config;
|
|
8
|
+
private scriptCache;
|
|
9
|
+
private isWarmupInProgress;
|
|
10
10
|
constructor();
|
|
11
|
-
private
|
|
12
|
-
private
|
|
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.
|
|
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.0",
|
|
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,211 @@
|
|
|
1
|
-
interface DeflectConfig {
|
|
2
|
-
actionId: string;
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
.
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
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
|
+
} finally {
|
|
50
|
+
this.isWarmupInProgress = false;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
private buildScriptUrl(actionId: string): string {
|
|
55
|
+
const baseUrl = this.config?.scriptUrl || "https://js.deflect.bot/main.js";
|
|
56
|
+
|
|
57
|
+
if (this.config?.scriptUrl) {
|
|
58
|
+
return baseUrl;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const nonce = Date.now().toString();
|
|
62
|
+
return `${baseUrl}?action_id=${actionId}&_=${nonce}`;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
private async fetchScript(): Promise<DeflectScript> {
|
|
66
|
+
if (!this.config?.actionId) {
|
|
67
|
+
throw new Error("actionId is required");
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const url = this.buildScriptUrl(this.config.actionId);
|
|
71
|
+
const response = await fetch(url, { cache: "no-store" });
|
|
72
|
+
|
|
73
|
+
if (!response.ok) {
|
|
74
|
+
throw new Error(`Failed to fetch script: ${response.status}`);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
return {
|
|
78
|
+
content: await response.text(),
|
|
79
|
+
sessionId: response.headers.get("session_id") || undefined,
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
private async executeScript(script: DeflectScript): Promise<string> {
|
|
84
|
+
if (script.sessionId && typeof window !== "undefined") {
|
|
85
|
+
window.Deflect.sessionId = script.sessionId;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const readyPromise = this.createReadyPromise();
|
|
89
|
+
|
|
90
|
+
const blobUrl = this.createScriptBlob(script.content);
|
|
91
|
+
const scriptElement = await this.loadScriptElement(blobUrl);
|
|
92
|
+
|
|
93
|
+
try {
|
|
94
|
+
await readyPromise;
|
|
95
|
+
|
|
96
|
+
const token = await this.getTokenFromScript();
|
|
97
|
+
|
|
98
|
+
return token;
|
|
99
|
+
} finally {
|
|
100
|
+
this.cleanup(blobUrl, scriptElement);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
private createReadyPromise(): Promise<void> {
|
|
105
|
+
return new Promise<void>((resolve) => {
|
|
106
|
+
if (typeof window !== "undefined") {
|
|
107
|
+
window.Deflect.ready = {
|
|
108
|
+
promise: new Promise<void>((innerResolve) => {
|
|
109
|
+
window.Deflect.ready.resolve = innerResolve;
|
|
110
|
+
}),
|
|
111
|
+
resolve: () => resolve(),
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
private createScriptBlob(content: string): string {
|
|
118
|
+
const blob = new Blob([content], { type: "text/javascript" });
|
|
119
|
+
return URL.createObjectURL(blob);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
private async loadScriptElement(blobUrl: string): Promise<HTMLScriptElement> {
|
|
123
|
+
return new Promise((resolve, reject) => {
|
|
124
|
+
const script = document.createElement("script");
|
|
125
|
+
script.type = "module";
|
|
126
|
+
script.src = blobUrl;
|
|
127
|
+
|
|
128
|
+
script.onload = () => resolve(script);
|
|
129
|
+
script.onerror = () => reject(new Error("Script failed to load"));
|
|
130
|
+
|
|
131
|
+
document.head.appendChild(script);
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
private async getTokenFromScript(): Promise<string> {
|
|
136
|
+
if (
|
|
137
|
+
typeof window === "undefined" ||
|
|
138
|
+
typeof window.Deflect?.getToken !== "function"
|
|
139
|
+
) {
|
|
140
|
+
throw new Error("Script did not load properly - getToken not available");
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
try {
|
|
144
|
+
return await window.Deflect.getToken();
|
|
145
|
+
} catch (error) {
|
|
146
|
+
throw new Error(`Script execution failed: ${error}`);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
private cleanup(blobUrl: string, scriptElement: HTMLScriptElement): void {
|
|
151
|
+
URL.revokeObjectURL(blobUrl);
|
|
152
|
+
scriptElement.remove();
|
|
153
|
+
|
|
154
|
+
if (typeof window !== "undefined" && window.Deflect?.getToken) {
|
|
155
|
+
delete window.Deflect.getToken;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
public configure(params: DeflectConfig): void {
|
|
160
|
+
if (!params.actionId?.trim()) {
|
|
161
|
+
throw new Error("actionId is required and cannot be empty");
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
this.config = { ...params };
|
|
165
|
+
|
|
166
|
+
if (typeof window !== "undefined") {
|
|
167
|
+
window.Deflect.actionId = params.actionId;
|
|
168
|
+
if (params.extraArgs) {
|
|
169
|
+
window.Deflect.extraArgs = { ...params.extraArgs };
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
this.tryWarmup();
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
public async solveChallenge(): Promise<string> {
|
|
177
|
+
if (!this.config?.actionId) {
|
|
178
|
+
throw new Error("Must call configure() before solveChallenge()");
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
let script: DeflectScript;
|
|
182
|
+
|
|
183
|
+
if (this.scriptCache && !this.isWarmupInProgress) {
|
|
184
|
+
script = this.scriptCache;
|
|
185
|
+
this.scriptCache = null;
|
|
186
|
+
} else {
|
|
187
|
+
script = await this.fetchScript();
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
return this.executeScript(script);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
public async warmup(): Promise<boolean> {
|
|
194
|
+
if (!this.config?.actionId) {
|
|
195
|
+
return false;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
try {
|
|
199
|
+
await this.tryWarmup();
|
|
200
|
+
return this.scriptCache !== null;
|
|
201
|
+
} catch {
|
|
202
|
+
return false;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
public clearCache(): void {
|
|
207
|
+
this.scriptCache = null;
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
export default new Deflect();
|
package/src/types/window.d.ts
CHANGED
|
@@ -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
|
+
}
|