@mochabug/adapt-web 1.0.0-rc34 → 1.0.0-rc37
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/esm/AdaptCapWidget.js +286 -0
- package/dist/esm/AdaptCapWidget.js.map +1 -0
- package/dist/esm/cap-adapter.js +147 -0
- package/dist/esm/cap-adapter.js.map +1 -0
- package/dist/esm/index.js +175 -5
- package/dist/esm/index.js.map +1 -1
- package/dist/types/AdaptCapWidget.d.ts +89 -0
- package/dist/types/cap-adapter.d.ts +34 -0
- package/dist/types/index.d.ts +20 -1
- package/dist/types/types.d.ts +88 -0
- package/dist/umd/adapt-web.js +773 -13
- package/dist/umd/adapt-web.min.js +210 -4
- package/dist/umd/cap_wasm.js +1 -0
- package/dist/umd/cap_wasm_bg.wasm +0 -0
- package/package.json +6 -5
|
@@ -0,0 +1,286 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Standalone Cap.js widget component for proof-of-work challenges.
|
|
3
|
+
* Can be used independently of AdaptWebClient and iframes.
|
|
4
|
+
*
|
|
5
|
+
* @example
|
|
6
|
+
* ```typescript
|
|
7
|
+
* import { AdaptCapWidget } from "@mochabug/adapt-web";
|
|
8
|
+
* import { createConnectClient } from "@mochabug/adapt-core/connect";
|
|
9
|
+
*
|
|
10
|
+
* const rawClient = createConnectClient({ id: "my-automation" });
|
|
11
|
+
* const widget = new AdaptCapWidget({
|
|
12
|
+
* container: "cap-container",
|
|
13
|
+
* automationId: "my-automation",
|
|
14
|
+
* client: rawClient,
|
|
15
|
+
* onSolve: async (challengeToken, expires) => {
|
|
16
|
+
* const client = createAdaptClient(rawClient, "my-automation");
|
|
17
|
+
* const session = await client.run({ challengeToken });
|
|
18
|
+
* }
|
|
19
|
+
* });
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
import { setupCapAdapter, cleanupCapAdapter } from "./cap-adapter.js";
|
|
23
|
+
// Import Cap.js widget (registers <cap-widget> custom element)
|
|
24
|
+
import "@cap.js/widget";
|
|
25
|
+
/**
|
|
26
|
+
* Standalone Cap.js widget for proof-of-work challenges.
|
|
27
|
+
*
|
|
28
|
+
* This component can be used independently of AdaptWebClient to handle
|
|
29
|
+
* PoW challenges. After solving, the token can be used with any session
|
|
30
|
+
* starting method in @mochabug/adapt-core.
|
|
31
|
+
*/
|
|
32
|
+
export class AdaptCapWidget {
|
|
33
|
+
constructor(options) {
|
|
34
|
+
this.widgetContainer = null;
|
|
35
|
+
this.widgetElement = null;
|
|
36
|
+
this.destroyed = false;
|
|
37
|
+
this.options = options;
|
|
38
|
+
// Resolve container
|
|
39
|
+
const container = typeof options.container === "string"
|
|
40
|
+
? document.getElementById(options.container)
|
|
41
|
+
: options.container;
|
|
42
|
+
if (!container) {
|
|
43
|
+
throw new Error(`Container ${typeof options.container === "string"
|
|
44
|
+
? `with id '${options.container}'`
|
|
45
|
+
: ""} not found`);
|
|
46
|
+
}
|
|
47
|
+
this.containerElement = container;
|
|
48
|
+
// Inject default styles if not already present
|
|
49
|
+
this.injectStyles();
|
|
50
|
+
// Set up Cap.js adapter to intercept fetch calls using the provided client
|
|
51
|
+
setupCapAdapter(options.client, options.automationId);
|
|
52
|
+
// Create and mount widget
|
|
53
|
+
this.mountWidget();
|
|
54
|
+
}
|
|
55
|
+
injectStyles() {
|
|
56
|
+
if (document.getElementById("mb-adapt-cap-styles"))
|
|
57
|
+
return;
|
|
58
|
+
const style = document.createElement("style");
|
|
59
|
+
style.id = "mb-adapt-cap-styles";
|
|
60
|
+
style.textContent = `
|
|
61
|
+
/* ============================================
|
|
62
|
+
Mochabug Adapt Cap Widget - Premium Design
|
|
63
|
+
============================================ */
|
|
64
|
+
|
|
65
|
+
.mb-adapt-cap {
|
|
66
|
+
/* Sizing */
|
|
67
|
+
--mb-cap-border-radius: 16px;
|
|
68
|
+
--mb-cap-height: 72px;
|
|
69
|
+
--mb-cap-width: 320px;
|
|
70
|
+
--mb-cap-padding: 18px 22px;
|
|
71
|
+
--mb-cap-gap: 16px;
|
|
72
|
+
|
|
73
|
+
/* Light Mode Colors */
|
|
74
|
+
--mb-cap-bg: #ffffff;
|
|
75
|
+
--mb-cap-border-color: #e5e7eb;
|
|
76
|
+
--mb-cap-text-color: #111827;
|
|
77
|
+
|
|
78
|
+
/* Checkbox */
|
|
79
|
+
--mb-cap-checkbox-size: 30px;
|
|
80
|
+
--mb-cap-checkbox-radius: 8px;
|
|
81
|
+
--mb-cap-checkbox-border-color: #d1d5db;
|
|
82
|
+
--mb-cap-checkbox-bg: #f9fafb;
|
|
83
|
+
|
|
84
|
+
/* Spinner */
|
|
85
|
+
--mb-cap-spinner-color: #6366f1;
|
|
86
|
+
--mb-cap-spinner-bg: #e5e7eb;
|
|
87
|
+
|
|
88
|
+
/* Typography */
|
|
89
|
+
--mb-cap-font: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
|
|
90
|
+
--mb-cap-font-size: 15px;
|
|
91
|
+
--mb-cap-font-weight: 500;
|
|
92
|
+
|
|
93
|
+
/* Shadows */
|
|
94
|
+
--mb-cap-shadow:
|
|
95
|
+
0 1px 3px rgba(0, 0, 0, 0.08),
|
|
96
|
+
0 4px 12px rgba(0, 0, 0, 0.05);
|
|
97
|
+
--mb-cap-shadow-hover:
|
|
98
|
+
0 4px 12px rgba(0, 0, 0, 0.1),
|
|
99
|
+
0 8px 24px rgba(0, 0, 0, 0.08);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/* Dark Mode */
|
|
103
|
+
.mb-adapt-cap--dark {
|
|
104
|
+
--mb-cap-bg: #1f2937;
|
|
105
|
+
--mb-cap-border-color: #374151;
|
|
106
|
+
--mb-cap-text-color: #f9fafb;
|
|
107
|
+
--mb-cap-checkbox-border-color: #4b5563;
|
|
108
|
+
--mb-cap-checkbox-bg: #374151;
|
|
109
|
+
--mb-cap-spinner-color: #818cf8;
|
|
110
|
+
--mb-cap-spinner-bg: #4b5563;
|
|
111
|
+
--mb-cap-shadow:
|
|
112
|
+
0 1px 3px rgba(0, 0, 0, 0.3),
|
|
113
|
+
0 4px 12px rgba(0, 0, 0, 0.2);
|
|
114
|
+
--mb-cap-shadow-hover:
|
|
115
|
+
0 4px 12px rgba(0, 0, 0, 0.4),
|
|
116
|
+
0 8px 24px rgba(0, 0, 0, 0.3);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/* Container */
|
|
120
|
+
.mb-adapt-cap__container {
|
|
121
|
+
display: flex;
|
|
122
|
+
align-items: center;
|
|
123
|
+
justify-content: center;
|
|
124
|
+
padding: 16px;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/* Cap Widget */
|
|
128
|
+
.mb-adapt-cap cap-widget {
|
|
129
|
+
--cap-background: var(--mb-cap-bg);
|
|
130
|
+
--cap-border-color: var(--mb-cap-border-color);
|
|
131
|
+
--cap-border-radius: var(--mb-cap-border-radius);
|
|
132
|
+
--cap-widget-height: var(--mb-cap-height);
|
|
133
|
+
--cap-widget-width: var(--mb-cap-width);
|
|
134
|
+
--cap-widget-padding: var(--mb-cap-padding);
|
|
135
|
+
--cap-gap: var(--mb-cap-gap);
|
|
136
|
+
--cap-color: var(--mb-cap-text-color);
|
|
137
|
+
--cap-checkbox-size: var(--mb-cap-checkbox-size);
|
|
138
|
+
--cap-checkbox-border: 2px solid var(--mb-cap-checkbox-border-color);
|
|
139
|
+
--cap-checkbox-border-radius: var(--mb-cap-checkbox-radius);
|
|
140
|
+
--cap-checkbox-background: var(--mb-cap-checkbox-bg);
|
|
141
|
+
--cap-checkbox-margin: 0;
|
|
142
|
+
--cap-font: var(--mb-cap-font);
|
|
143
|
+
--cap-spinner-color: var(--mb-cap-spinner-color);
|
|
144
|
+
--cap-spinner-background-color: var(--mb-cap-spinner-bg);
|
|
145
|
+
--cap-spinner-thickness: 3px;
|
|
146
|
+
|
|
147
|
+
display: block;
|
|
148
|
+
box-shadow: var(--mb-cap-shadow);
|
|
149
|
+
border-radius: var(--mb-cap-border-radius);
|
|
150
|
+
transition:
|
|
151
|
+
transform 0.2s ease,
|
|
152
|
+
box-shadow 0.2s ease;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
.mb-adapt-cap cap-widget:hover {
|
|
156
|
+
transform: translateY(-2px);
|
|
157
|
+
box-shadow: var(--mb-cap-shadow-hover);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
.mb-adapt-cap cap-widget:active {
|
|
161
|
+
transform: translateY(0);
|
|
162
|
+
transition-duration: 0.1s;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/* Checkbox styling */
|
|
166
|
+
.mb-adapt-cap cap-widget::part(checkbox) {
|
|
167
|
+
transition: transform 0.15s ease;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
.mb-adapt-cap cap-widget:hover::part(checkbox) {
|
|
171
|
+
transform: scale(1.05);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/* Label styling */
|
|
175
|
+
.mb-adapt-cap cap-widget::part(label) {
|
|
176
|
+
font-size: var(--mb-cap-font-size);
|
|
177
|
+
font-weight: var(--mb-cap-font-weight);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/* Hide attribution */
|
|
181
|
+
.mb-adapt-cap cap-widget::part(attribution) {
|
|
182
|
+
display: none;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/* Responsive */
|
|
186
|
+
@media (max-width: 380px) {
|
|
187
|
+
.mb-adapt-cap {
|
|
188
|
+
--mb-cap-width: 280px;
|
|
189
|
+
--mb-cap-height: 64px;
|
|
190
|
+
--mb-cap-padding: 14px 18px;
|
|
191
|
+
--mb-cap-checkbox-size: 26px;
|
|
192
|
+
--mb-cap-font-size: 14px;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
`;
|
|
196
|
+
document.head.appendChild(style);
|
|
197
|
+
}
|
|
198
|
+
mountWidget() {
|
|
199
|
+
// Create container wrapper with styling class
|
|
200
|
+
this.widgetContainer = document.createElement("div");
|
|
201
|
+
this.widgetContainer.className = "mb-adapt-cap";
|
|
202
|
+
const innerContainer = document.createElement("div");
|
|
203
|
+
innerContainer.className = "mb-adapt-cap__container";
|
|
204
|
+
// Create the Cap widget element
|
|
205
|
+
this.widgetElement = document.createElement("cap-widget");
|
|
206
|
+
this.widgetElement.setAttribute("data-cap-api-endpoint", `/adapt-cap-${this.options.automationId}/`);
|
|
207
|
+
// Apply widget options
|
|
208
|
+
if (this.options.workerCount) {
|
|
209
|
+
this.widgetElement.setAttribute("data-cap-worker-count", String(this.options.workerCount));
|
|
210
|
+
}
|
|
211
|
+
if (this.options.i18n) {
|
|
212
|
+
const { i18n } = this.options;
|
|
213
|
+
if (i18n.verifyingLabel) {
|
|
214
|
+
this.widgetElement.setAttribute("data-cap-i18n-verifying-label", i18n.verifyingLabel);
|
|
215
|
+
}
|
|
216
|
+
if (i18n.initialState) {
|
|
217
|
+
this.widgetElement.setAttribute("data-cap-i18n-initial-state", i18n.initialState);
|
|
218
|
+
}
|
|
219
|
+
if (i18n.solvedLabel) {
|
|
220
|
+
this.widgetElement.setAttribute("data-cap-i18n-solved-label", i18n.solvedLabel);
|
|
221
|
+
}
|
|
222
|
+
if (i18n.errorLabel) {
|
|
223
|
+
this.widgetElement.setAttribute("data-cap-i18n-error-label", i18n.errorLabel);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
// Listen for solve event
|
|
227
|
+
this.widgetElement.addEventListener("solve", ((e) => {
|
|
228
|
+
if (this.destroyed)
|
|
229
|
+
return;
|
|
230
|
+
const token = e.detail?.token;
|
|
231
|
+
const expiresStr = e.detail?.expires;
|
|
232
|
+
const expires = expiresStr ? new Date(expiresStr) : new Date();
|
|
233
|
+
// Auto-destroy after successful solve
|
|
234
|
+
this.destroy();
|
|
235
|
+
if (token) {
|
|
236
|
+
this.options.onSolve(token, expires);
|
|
237
|
+
}
|
|
238
|
+
else {
|
|
239
|
+
this.options.onError?.(new Error("No token received from Cap.js"));
|
|
240
|
+
}
|
|
241
|
+
}));
|
|
242
|
+
// Listen for error event
|
|
243
|
+
this.widgetElement.addEventListener("error", ((e) => {
|
|
244
|
+
if (this.destroyed)
|
|
245
|
+
return;
|
|
246
|
+
console.error("[AdaptCapWidget] Cap.js error:", e.detail);
|
|
247
|
+
this.destroy();
|
|
248
|
+
this.options.onError?.(new Error(e.detail?.message || "Cap.js error"));
|
|
249
|
+
}));
|
|
250
|
+
// Mount to DOM
|
|
251
|
+
innerContainer.appendChild(this.widgetElement);
|
|
252
|
+
this.widgetContainer.appendChild(innerContainer);
|
|
253
|
+
this.containerElement.appendChild(this.widgetContainer);
|
|
254
|
+
}
|
|
255
|
+
/**
|
|
256
|
+
* Enable or disable dark mode styling.
|
|
257
|
+
*/
|
|
258
|
+
setDarkMode(dark) {
|
|
259
|
+
if (!this.widgetContainer)
|
|
260
|
+
return;
|
|
261
|
+
if (dark) {
|
|
262
|
+
this.widgetContainer.classList.add("mb-adapt-cap--dark");
|
|
263
|
+
}
|
|
264
|
+
else {
|
|
265
|
+
this.widgetContainer.classList.remove("mb-adapt-cap--dark");
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
/**
|
|
269
|
+
* Clean up and remove the widget from DOM.
|
|
270
|
+
* Called automatically after successful solve.
|
|
271
|
+
*/
|
|
272
|
+
destroy() {
|
|
273
|
+
if (this.destroyed)
|
|
274
|
+
return;
|
|
275
|
+
this.destroyed = true;
|
|
276
|
+
// Cleanup Cap adapter
|
|
277
|
+
cleanupCapAdapter();
|
|
278
|
+
// Remove from DOM
|
|
279
|
+
if (this.widgetContainer && this.widgetContainer.parentNode) {
|
|
280
|
+
this.widgetContainer.parentNode.removeChild(this.widgetContainer);
|
|
281
|
+
}
|
|
282
|
+
this.widgetContainer = null;
|
|
283
|
+
this.widgetElement = null;
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
//# sourceMappingURL=AdaptCapWidget.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AdaptCapWidget.js","sourceRoot":"","sources":["../../src/AdaptCapWidget.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import { timestampDate } from "@bufbuild/protobuf/wkt";
|
|
2
|
+
// Module-level state for the Cap.js adapter
|
|
3
|
+
let currentClient = null;
|
|
4
|
+
let currentAutomationId = null;
|
|
5
|
+
// Store verification tokens per automation for the redeem step
|
|
6
|
+
const verificationTokens = new Map();
|
|
7
|
+
/**
|
|
8
|
+
* Create a challenge for an automation that requires proof-of-work.
|
|
9
|
+
*
|
|
10
|
+
* @param client - The automation client
|
|
11
|
+
* @param id - The automation ID
|
|
12
|
+
* @returns Challenge information including the token to solve
|
|
13
|
+
*/
|
|
14
|
+
export async function createChallenge(client, id) {
|
|
15
|
+
const response = await client.createChallenge({ id });
|
|
16
|
+
return {
|
|
17
|
+
count: response.count,
|
|
18
|
+
size: response.size,
|
|
19
|
+
difficulty: response.difficulty,
|
|
20
|
+
expires: response.expires ? timestampDate(response.expires) : new Date(),
|
|
21
|
+
token: response.token,
|
|
22
|
+
verificationToken: response.verificationToken,
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Redeem solved challenge solutions for a token that can be used to start a session.
|
|
27
|
+
*
|
|
28
|
+
* @param client - The automation client
|
|
29
|
+
* @param id - The automation ID
|
|
30
|
+
* @param verificationToken - The encrypted verification token from createChallenge
|
|
31
|
+
* @param solutions - Array of nonce solutions found by Cap.js solver
|
|
32
|
+
* @returns Redeemed challenge with token to use for session start
|
|
33
|
+
*/
|
|
34
|
+
export async function redeemChallenge(client, id, verificationToken, solutions) {
|
|
35
|
+
const response = await client.redeemChallenge({
|
|
36
|
+
id,
|
|
37
|
+
verificationToken,
|
|
38
|
+
solutions,
|
|
39
|
+
});
|
|
40
|
+
return {
|
|
41
|
+
token: response.token,
|
|
42
|
+
expires: response.expires ? timestampDate(response.expires) : new Date(),
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
// Set up CAP_CUSTOM_FETCH immediately at module load time.
|
|
46
|
+
// Cap.js checks for this global when its module loads, so we must set it
|
|
47
|
+
// BEFORE @cap.js/widget is imported. The actual client/id are set later
|
|
48
|
+
// via setupCapAdapter().
|
|
49
|
+
if (typeof window !== "undefined") {
|
|
50
|
+
window.CAP_CUSTOM_FETCH = async (url, options) => {
|
|
51
|
+
const urlStr = url.toString();
|
|
52
|
+
// Check if this is a challenge endpoint call from Cap.js
|
|
53
|
+
if (urlStr.endsWith("/challenge")) {
|
|
54
|
+
if (!currentClient || !currentAutomationId) {
|
|
55
|
+
return new Response(JSON.stringify({ error: "Cap adapter not initialized" }), { status: 500, headers: { "Content-Type": "application/json" } });
|
|
56
|
+
}
|
|
57
|
+
try {
|
|
58
|
+
const challengeInfo = await createChallenge(currentClient, currentAutomationId);
|
|
59
|
+
// Store verification token for the redeem step
|
|
60
|
+
verificationTokens.set(currentAutomationId, challengeInfo.verificationToken);
|
|
61
|
+
// Transform response to Cap.js expected format
|
|
62
|
+
// Cap.js expects: { challenge: { c, s, d }, token } where it generates
|
|
63
|
+
// challenges using prng(token + index, size) for salt and prng(token + index + 'd', difficulty) for target
|
|
64
|
+
// We pass the hex seed as 'token' for Cap.js PRNG derivation
|
|
65
|
+
return new Response(JSON.stringify({
|
|
66
|
+
challenge: {
|
|
67
|
+
c: challengeInfo.count,
|
|
68
|
+
s: challengeInfo.size,
|
|
69
|
+
d: challengeInfo.difficulty,
|
|
70
|
+
},
|
|
71
|
+
token: challengeInfo.token, // hex seed for Cap.js PRNG
|
|
72
|
+
expires: challengeInfo.expires.toISOString(),
|
|
73
|
+
}), {
|
|
74
|
+
status: 200,
|
|
75
|
+
headers: { "Content-Type": "application/json" },
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
catch (error) {
|
|
79
|
+
return new Response(JSON.stringify({ error: String(error) }), {
|
|
80
|
+
status: 500,
|
|
81
|
+
headers: { "Content-Type": "application/json" },
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
if (urlStr.endsWith("/redeem")) {
|
|
86
|
+
if (!currentClient || !currentAutomationId) {
|
|
87
|
+
return new Response(JSON.stringify({ error: "Cap adapter not initialized" }), { status: 500, headers: { "Content-Type": "application/json" } });
|
|
88
|
+
}
|
|
89
|
+
// Get the stored verification token
|
|
90
|
+
const verificationToken = verificationTokens.get(currentAutomationId);
|
|
91
|
+
if (!verificationToken) {
|
|
92
|
+
return new Response(JSON.stringify({ error: "No verification token found - challenge must be created first" }), { status: 400, headers: { "Content-Type": "application/json" } });
|
|
93
|
+
}
|
|
94
|
+
try {
|
|
95
|
+
const body = options?.body ? JSON.parse(options.body) : {};
|
|
96
|
+
// Cap.js sends solutions as numbers or strings, convert to bigint
|
|
97
|
+
const solutions = (body.solutions || []).map((s) => BigInt(s));
|
|
98
|
+
const redeemed = await redeemChallenge(currentClient, currentAutomationId, verificationToken, // Use stored verification token, not Cap.js token
|
|
99
|
+
solutions);
|
|
100
|
+
// Clean up stored verification token after successful redeem
|
|
101
|
+
verificationTokens.delete(currentAutomationId);
|
|
102
|
+
// Transform response to Cap.js expected format
|
|
103
|
+
// Cap.js expects: { success: true, token, expires }
|
|
104
|
+
return new Response(JSON.stringify({
|
|
105
|
+
success: true,
|
|
106
|
+
token: redeemed.token,
|
|
107
|
+
expires: redeemed.expires.toISOString(),
|
|
108
|
+
}), {
|
|
109
|
+
status: 200,
|
|
110
|
+
headers: { "Content-Type": "application/json" },
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
catch (error) {
|
|
114
|
+
return new Response(JSON.stringify({ error: String(error) }), {
|
|
115
|
+
status: 500,
|
|
116
|
+
headers: { "Content-Type": "application/json" },
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
// Fall through to regular fetch for any other requests
|
|
121
|
+
return fetch(url, options);
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Set up the Cap.js adapter with the client and automation ID.
|
|
126
|
+
* Must be called before the Cap.js widget is activated.
|
|
127
|
+
*
|
|
128
|
+
* @param client - The automation client to use for API calls
|
|
129
|
+
* @param automationId - The automation ID to use for challenge endpoints
|
|
130
|
+
*/
|
|
131
|
+
export function setupCapAdapter(client, automationId) {
|
|
132
|
+
currentClient = client;
|
|
133
|
+
currentAutomationId = automationId;
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Clean up the Cap.js adapter state.
|
|
137
|
+
* The CAP_CUSTOM_FETCH handler remains in place but will error if called
|
|
138
|
+
* without being set up again via setupCapAdapter().
|
|
139
|
+
*/
|
|
140
|
+
export function cleanupCapAdapter() {
|
|
141
|
+
if (currentAutomationId) {
|
|
142
|
+
verificationTokens.delete(currentAutomationId);
|
|
143
|
+
}
|
|
144
|
+
currentClient = null;
|
|
145
|
+
currentAutomationId = null;
|
|
146
|
+
}
|
|
147
|
+
//# sourceMappingURL=cap-adapter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cap-adapter.js","sourceRoot":"","sources":["../../src/cap-adapter.ts"],"names":[],"mappings":"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"}
|