@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 +54 -26
- package/dist/index.js +214 -118
- package/dist/index.min.js +1 -0
- package/package.json +15 -8
- package/.gitattributes +0 -2
- package/dist/types/index.d.ts +0 -21
- package/eslint.config.mjs +0 -12
- package/src/index.ts +0 -148
- package/src/types/window.d.ts +0 -3
- package/tsconfig.json +0 -22
package/README.md
CHANGED
|
@@ -1,50 +1,78 @@
|
|
|
1
|
-
# Deflect -
|
|
1
|
+
# Deflect SDK (Client-side)
|
|
2
2
|
|
|
3
3
|

|
|
4
4
|

|
|
5
5
|
|
|
6
|
-
Deflect is an antibot
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
23
|
+
npm install --save @castleio/sdk
|
|
23
24
|
```
|
|
24
25
|
|
|
25
|
-
|
|
26
|
+
#### CDN
|
|
26
27
|
|
|
27
|
-
|
|
28
|
+
Use `@deflect-sdk@latest` to always use the latest version, or specify a version with `@deflect-sdk@x.x.x`.
|
|
28
29
|
|
|
29
|
-
```
|
|
30
|
-
|
|
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:
|
|
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
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
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
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
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
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
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
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
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
|
-
|
|
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
|
-
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
|
-
|
|
64
|
-
|
|
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
|
-
|
|
68
|
-
|
|
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
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
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.
|
|
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
|
-
"
|
|
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": "
|
|
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
package/dist/types/index.d.ts
DELETED
|
@@ -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();
|
package/src/types/window.d.ts
DELETED
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
|
-
}
|