@deflectbot/deflect-sdk 1.3.0 → 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/dist/index.js +195 -199
- package/package.json +12 -5
- package/.gitattributes +0 -2
- package/dist/global.js +0 -7
- package/dist/types/global.d.ts +0 -7
- package/dist/types/index.d.ts +0 -35
- package/eslint.config.mjs +0 -12
- package/src/global.ts +0 -18
- package/src/index.ts +0 -238
- package/src/types/window.d.ts +0 -6
- package/tsconfig.json +0 -22
- /package/dist/{deflect.global.min.js → index.min.js} +0 -0
package/dist/index.js
CHANGED
|
@@ -1,226 +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");
|
|
17
39
|
}
|
|
18
40
|
initializeGlobalState() {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
window.Deflect = window.Deflect || {};
|
|
41
|
+
if (typeof window === "undefined") return;
|
|
42
|
+
window.Deflect = window.Deflect || {};
|
|
22
43
|
}
|
|
23
44
|
setupAutomaticWarmup() {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
}
|
|
43
|
-
catch (_b) {
|
|
44
|
-
/* empty */
|
|
45
|
-
}
|
|
46
|
-
finally {
|
|
47
|
-
this.isWarmupInProgress = false;
|
|
48
|
-
}
|
|
49
|
-
});
|
|
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
|
+
}
|
|
50
63
|
}
|
|
51
64
|
buildScriptUrl(actionId) {
|
|
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
|
-
this.prefetchNextScript();
|
|
89
|
-
return token;
|
|
90
|
-
}
|
|
91
|
-
finally {
|
|
92
|
-
this.cleanup(blobUrl, scriptElement);
|
|
93
|
-
}
|
|
94
|
-
});
|
|
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
|
+
}
|
|
95
101
|
}
|
|
96
102
|
prefetchNextScript() {
|
|
97
|
-
|
|
103
|
+
this.tryWarmup().catch(() => {
|
|
104
|
+
});
|
|
98
105
|
}
|
|
99
106
|
createReadyPromise() {
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
107
|
+
return new Promise((resolve) => {
|
|
108
|
+
if (typeof window !== "undefined") {
|
|
109
|
+
window.Deflect.ready = {
|
|
110
|
+
promise: new Promise((innerResolve) => {
|
|
111
|
+
window.Deflect.ready.resolve = innerResolve;
|
|
112
|
+
}),
|
|
113
|
+
resolve: /* @__PURE__ */ __name(() => resolve(), "resolve")
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
});
|
|
110
117
|
}
|
|
111
118
|
createScriptBlob(content) {
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
}
|
|
115
|
-
loadScriptElement(blobUrl) {
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
try {
|
|
135
|
-
return yield window.Deflect.getToken();
|
|
136
|
-
}
|
|
137
|
-
catch (error) {
|
|
138
|
-
throw new Error(`Script execution failed: ${error}`);
|
|
139
|
-
}
|
|
140
|
-
});
|
|
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
141
|
}
|
|
142
142
|
cleanup(blobUrl, scriptElement) {
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
}
|
|
143
|
+
URL.revokeObjectURL(blobUrl);
|
|
144
|
+
scriptElement.remove();
|
|
145
|
+
if (typeof window !== "undefined" && window.Deflect?.getToken) {
|
|
146
|
+
delete window.Deflect.getToken;
|
|
147
|
+
}
|
|
149
148
|
}
|
|
150
149
|
configure(params) {
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
this.tryWarmup();
|
|
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") {
|
|
155
|
+
window.Deflect.actionId = params.actionId;
|
|
156
|
+
}
|
|
157
|
+
this.tryWarmup();
|
|
160
158
|
}
|
|
161
159
|
// Deprecated name kept for backward compatibility
|
|
162
|
-
solveChallenge() {
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
return false;
|
|
189
|
-
}
|
|
190
|
-
try {
|
|
191
|
-
yield this.tryWarmup();
|
|
192
|
-
return this.scriptCache !== null;
|
|
193
|
-
}
|
|
194
|
-
catch (_b) {
|
|
195
|
-
return false;
|
|
196
|
-
}
|
|
197
|
-
});
|
|
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
|
+
}
|
|
198
186
|
}
|
|
199
187
|
clearCache() {
|
|
200
|
-
|
|
188
|
+
this.scriptCache = null;
|
|
201
189
|
}
|
|
202
190
|
/**
|
|
203
191
|
* Inject a fresh token as a hidden input into a form. Only accepts a submit event from onsubmit.
|
|
204
192
|
* Usage: <form ... onsubmit="return Deflect.injectToken(event)">
|
|
205
193
|
* Returns false to prevent double submit.
|
|
206
194
|
*/
|
|
207
|
-
injectToken(event) {
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
}
|
|
225
|
-
}
|
|
226
|
-
|
|
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;
|
|
212
|
+
}
|
|
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
|
+
})();
|
package/package.json
CHANGED
|
@@ -1,12 +1,19 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@deflectbot/deflect-sdk",
|
|
3
|
-
"version": "1.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
|
-
"
|
|
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": "
|
|
9
|
-
"build:global": "
|
|
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"
|
|
10
17
|
},
|
|
11
18
|
"author": "Deflect",
|
|
12
19
|
"license": "MIT",
|
package/.gitattributes
DELETED
package/dist/global.js
DELETED
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
// Re-export the default instance while also assigning it to window.Deflect for non-module usage.
|
|
2
|
-
import DeflectInstance from "./index";
|
|
3
|
-
if (typeof window !== "undefined") {
|
|
4
|
-
// Avoid overwriting if a user already attached something custom.
|
|
5
|
-
window.Deflect = DeflectInstance;
|
|
6
|
-
}
|
|
7
|
-
export default DeflectInstance;
|
package/dist/types/global.d.ts
DELETED
package/dist/types/index.d.ts
DELETED
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
interface DeflectConfig {
|
|
2
|
-
actionId: string;
|
|
3
|
-
scriptUrl?: string;
|
|
4
|
-
}
|
|
5
|
-
declare class Deflect {
|
|
6
|
-
private config;
|
|
7
|
-
private scriptCache;
|
|
8
|
-
private isWarmupInProgress;
|
|
9
|
-
constructor();
|
|
10
|
-
private initializeGlobalState;
|
|
11
|
-
private setupAutomaticWarmup;
|
|
12
|
-
private tryWarmup;
|
|
13
|
-
private buildScriptUrl;
|
|
14
|
-
private fetchScript;
|
|
15
|
-
private executeScript;
|
|
16
|
-
private prefetchNextScript;
|
|
17
|
-
private createReadyPromise;
|
|
18
|
-
private createScriptBlob;
|
|
19
|
-
private loadScriptElement;
|
|
20
|
-
private getTokenFromScript;
|
|
21
|
-
private cleanup;
|
|
22
|
-
configure(params: DeflectConfig): void;
|
|
23
|
-
solveChallenge(): Promise<string>;
|
|
24
|
-
getToken(): Promise<string>;
|
|
25
|
-
warmup(): Promise<boolean>;
|
|
26
|
-
clearCache(): void;
|
|
27
|
-
/**
|
|
28
|
-
* Inject a fresh token as a hidden input into a form. Only accepts a submit event from onsubmit.
|
|
29
|
-
* Usage: <form ... onsubmit="return Deflect.injectToken(event)">
|
|
30
|
-
* Returns false to prevent double submit.
|
|
31
|
-
*/
|
|
32
|
-
injectToken(event: SubmitEvent): Promise<false>;
|
|
33
|
-
}
|
|
34
|
-
declare const _default: Deflect;
|
|
35
|
-
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/global.ts
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
// Re-export the default instance while also assigning it to window.Deflect for non-module usage.
|
|
2
|
-
import DeflectInstance from "./index";
|
|
3
|
-
|
|
4
|
-
// Ensure side effects (constructor) already ran on import.
|
|
5
|
-
// Attach to window for classic script tag usage.
|
|
6
|
-
declare global {
|
|
7
|
-
interface Window {
|
|
8
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- SDK attaches dynamic shape at runtime
|
|
9
|
-
Deflect: any;
|
|
10
|
-
}
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
if (typeof window !== "undefined") {
|
|
14
|
-
// Avoid overwriting if a user already attached something custom.
|
|
15
|
-
window.Deflect = DeflectInstance;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
export default DeflectInstance;
|
package/src/index.ts
DELETED
|
@@ -1,238 +0,0 @@
|
|
|
1
|
-
interface DeflectConfig {
|
|
2
|
-
actionId: string;
|
|
3
|
-
scriptUrl?: string;
|
|
4
|
-
}
|
|
5
|
-
|
|
6
|
-
interface DeflectScript {
|
|
7
|
-
sessionId?: string;
|
|
8
|
-
content: string;
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
class Deflect {
|
|
12
|
-
private config: DeflectConfig | null = null;
|
|
13
|
-
private scriptCache: DeflectScript | null = null;
|
|
14
|
-
private isWarmupInProgress = false;
|
|
15
|
-
|
|
16
|
-
constructor() {
|
|
17
|
-
this.initializeGlobalState();
|
|
18
|
-
this.setupAutomaticWarmup();
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
private initializeGlobalState(): void {
|
|
22
|
-
if (typeof window === "undefined") return;
|
|
23
|
-
window.Deflect = window.Deflect || {};
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
private setupAutomaticWarmup(): void {
|
|
27
|
-
if (typeof window === "undefined") return;
|
|
28
|
-
|
|
29
|
-
if (document.readyState === "loading") {
|
|
30
|
-
document.addEventListener("DOMContentLoaded", () => this.tryWarmup());
|
|
31
|
-
} else {
|
|
32
|
-
setTimeout(() => this.tryWarmup(), 100);
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
private async tryWarmup(): Promise<void> {
|
|
37
|
-
if (!this.config?.actionId || this.isWarmupInProgress || this.scriptCache) {
|
|
38
|
-
return;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
this.isWarmupInProgress = true;
|
|
42
|
-
|
|
43
|
-
try {
|
|
44
|
-
this.scriptCache = await this.fetchScript();
|
|
45
|
-
} catch {
|
|
46
|
-
/* empty */
|
|
47
|
-
} finally {
|
|
48
|
-
this.isWarmupInProgress = false;
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
private buildScriptUrl(actionId: string): string {
|
|
53
|
-
const baseUrl = this.config?.scriptUrl || "https://js.deflect.bot/main.js";
|
|
54
|
-
|
|
55
|
-
if (this.config?.scriptUrl) {
|
|
56
|
-
return baseUrl;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
const nonce = Date.now().toString();
|
|
60
|
-
return `${baseUrl}?action_id=${actionId}&_=${nonce}`;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
private async fetchScript(): Promise<DeflectScript> {
|
|
64
|
-
if (!this.config?.actionId) {
|
|
65
|
-
throw new Error("actionId is required");
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
const url = this.buildScriptUrl(this.config.actionId);
|
|
69
|
-
const response = await fetch(url, { cache: "no-store" });
|
|
70
|
-
|
|
71
|
-
if (!response.ok) {
|
|
72
|
-
throw new Error(`Failed to fetch script: ${response.status}`);
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
return {
|
|
76
|
-
content: await response.text(),
|
|
77
|
-
sessionId: response.headers.get("session_id") || undefined,
|
|
78
|
-
};
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
private async executeScript(script: DeflectScript): Promise<string> {
|
|
82
|
-
if (script.sessionId && typeof window !== "undefined") {
|
|
83
|
-
window.Deflect.sessionId = script.sessionId;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
const readyPromise = this.createReadyPromise();
|
|
87
|
-
|
|
88
|
-
const blobUrl = this.createScriptBlob(script.content);
|
|
89
|
-
const scriptElement = await this.loadScriptElement(blobUrl);
|
|
90
|
-
|
|
91
|
-
try {
|
|
92
|
-
await readyPromise;
|
|
93
|
-
|
|
94
|
-
const token = await this.getTokenFromScript();
|
|
95
|
-
|
|
96
|
-
this.prefetchNextScript();
|
|
97
|
-
|
|
98
|
-
return token;
|
|
99
|
-
} finally {
|
|
100
|
-
this.cleanup(blobUrl, scriptElement);
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
private prefetchNextScript(): void {
|
|
105
|
-
this.tryWarmup().catch(() => {});
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
private createReadyPromise(): Promise<void> {
|
|
109
|
-
return new Promise<void>((resolve) => {
|
|
110
|
-
if (typeof window !== "undefined") {
|
|
111
|
-
window.Deflect.ready = {
|
|
112
|
-
promise: new Promise<void>((innerResolve) => {
|
|
113
|
-
window.Deflect.ready.resolve = innerResolve;
|
|
114
|
-
}),
|
|
115
|
-
resolve: () => resolve(),
|
|
116
|
-
};
|
|
117
|
-
}
|
|
118
|
-
});
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
private createScriptBlob(content: string): string {
|
|
122
|
-
const blob = new Blob([content], { type: "text/javascript" });
|
|
123
|
-
return URL.createObjectURL(blob);
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
private async loadScriptElement(blobUrl: string): Promise<HTMLScriptElement> {
|
|
127
|
-
return new Promise((resolve, reject) => {
|
|
128
|
-
const script = document.createElement("script");
|
|
129
|
-
script.type = "module";
|
|
130
|
-
script.src = blobUrl;
|
|
131
|
-
|
|
132
|
-
script.onload = () => resolve(script);
|
|
133
|
-
script.onerror = () => reject(new Error("Script failed to load"));
|
|
134
|
-
|
|
135
|
-
document.head.appendChild(script);
|
|
136
|
-
});
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
private async getTokenFromScript(): Promise<string> {
|
|
140
|
-
if (
|
|
141
|
-
typeof window === "undefined" ||
|
|
142
|
-
typeof window.Deflect?.getToken !== "function"
|
|
143
|
-
) {
|
|
144
|
-
throw new Error("Script did not load properly - getToken not available");
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
try {
|
|
148
|
-
return await window.Deflect.getToken();
|
|
149
|
-
} catch (error) {
|
|
150
|
-
throw new Error(`Script execution failed: ${error}`);
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
private cleanup(blobUrl: string, scriptElement: HTMLScriptElement): void {
|
|
155
|
-
URL.revokeObjectURL(blobUrl);
|
|
156
|
-
scriptElement.remove();
|
|
157
|
-
|
|
158
|
-
if (typeof window !== "undefined" && window.Deflect?.getToken) {
|
|
159
|
-
delete window.Deflect.getToken;
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
public configure(params: DeflectConfig): void {
|
|
164
|
-
if (!params.actionId?.trim()) {
|
|
165
|
-
throw new Error("actionId is required and cannot be empty");
|
|
166
|
-
}
|
|
167
|
-
this.config = { ...params };
|
|
168
|
-
if (typeof window !== "undefined") {
|
|
169
|
-
window.Deflect.actionId = params.actionId;
|
|
170
|
-
}
|
|
171
|
-
this.tryWarmup();
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
// Deprecated name kept for backward compatibility
|
|
175
|
-
public async solveChallenge(): Promise<string> {
|
|
176
|
-
return this.getToken();
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
public async getToken(): Promise<string> {
|
|
180
|
-
if (!this.config?.actionId) {
|
|
181
|
-
throw new Error("Must call configure() before solveChallenge()");
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
let script: DeflectScript;
|
|
185
|
-
|
|
186
|
-
if (this.scriptCache && !this.isWarmupInProgress) {
|
|
187
|
-
script = this.scriptCache;
|
|
188
|
-
this.scriptCache = null;
|
|
189
|
-
} else {
|
|
190
|
-
script = await this.fetchScript();
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
return this.executeScript(script);
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
public async warmup(): Promise<boolean> {
|
|
197
|
-
if (!this.config?.actionId) {
|
|
198
|
-
return false;
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
try {
|
|
202
|
-
await this.tryWarmup();
|
|
203
|
-
return this.scriptCache !== null;
|
|
204
|
-
} catch {
|
|
205
|
-
return false;
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
public clearCache(): void {
|
|
210
|
-
this.scriptCache = null;
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
/**
|
|
214
|
-
* Inject a fresh token as a hidden input into a form. Only accepts a submit event from onsubmit.
|
|
215
|
-
* Usage: <form ... onsubmit="return Deflect.injectToken(event)">
|
|
216
|
-
* Returns false to prevent double submit.
|
|
217
|
-
*/
|
|
218
|
-
public async injectToken(event: SubmitEvent): Promise<false> {
|
|
219
|
-
if (!event || !event.target || !(event.target instanceof HTMLFormElement)) {
|
|
220
|
-
throw new Error("injectToken: must be called from a form submit event");
|
|
221
|
-
}
|
|
222
|
-
event.preventDefault();
|
|
223
|
-
const form = event.target;
|
|
224
|
-
const token = await this.getToken();
|
|
225
|
-
Array.from(form.querySelectorAll('input[name="deflect_token"]')).forEach(
|
|
226
|
-
(el) => el.remove()
|
|
227
|
-
);
|
|
228
|
-
const hidden = document.createElement("input");
|
|
229
|
-
hidden.type = "hidden";
|
|
230
|
-
hidden.name = "deflect_token";
|
|
231
|
-
hidden.value = token;
|
|
232
|
-
form.appendChild(hidden);
|
|
233
|
-
form.submit();
|
|
234
|
-
return false;
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
export default new Deflect();
|
package/src/types/window.d.ts
DELETED
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
// Global window augmentation for Deflect SDK.
|
|
2
|
-
// Using 'any' here keeps backward compatibility and avoids circular type issues.
|
|
3
|
-
interface Window {
|
|
4
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- SDK attaches dynamic shape at runtime
|
|
5
|
-
Deflect: any;
|
|
6
|
-
}
|
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
|
-
}
|
|
File without changes
|