@cap.js/widget 0.0.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 ADDED
File without changes
@@ -0,0 +1,104 @@
1
+ (() => {
2
+ const handleClick = (evt, element, capWidget, handlers) => {
3
+ const trigger = () => {
4
+ handlers.forEach((h) => {
5
+ element.addEventListener("click", h);
6
+ h.call(element, evt);
7
+ });
8
+
9
+ setTimeout(() => {
10
+ element.onclick = null;
11
+ handlers.forEach((h) => element.removeEventListener("click", h));
12
+ element.onclick = (e) => handleClick(e, element, capWidget, handlers);
13
+ }, 50);
14
+ };
15
+
16
+ element.onclick = null;
17
+
18
+ const offset = parseInt(element.getAttribute("data-cap-floating-offset")) || 8;
19
+ const position =
20
+ element.getAttribute("data-cap-floating-position") || "top";
21
+ const rect = element.getBoundingClientRect();
22
+
23
+ Object.assign(capWidget.style, {
24
+ display: "block",
25
+ position: "fixed",
26
+ zIndex: "99999"
27
+ });
28
+
29
+ const centerX = rect.left + (rect.width - capWidget.offsetWidth) / 2;
30
+ const safeX = Math.min(centerX, window.innerWidth - capWidget.offsetWidth);
31
+
32
+ if (position === "top") {
33
+ capWidget.style.top = `${Math.max(
34
+ 0,
35
+ rect.top - capWidget.offsetHeight - offset
36
+ )}px`;
37
+ } else {
38
+ capWidget.style.top = `${Math.min(
39
+ rect.bottom + offset,
40
+ window.innerHeight - capWidget.offsetHeight
41
+ )}px`;
42
+ }
43
+
44
+ capWidget.style.left = `${Math.max(safeX, 2)}px`;
45
+ capWidget.solve();
46
+
47
+ capWidget.addEventListener("solve", ({ detail }) => {
48
+ element.setAttribute("data-cap-token", detail.token);
49
+ element.setAttribute("data-cap-progress", "done");
50
+ setTimeout(() => {
51
+ trigger();
52
+ }, 500);
53
+
54
+ setTimeout(() => {
55
+ capWidget.style.display = "none";
56
+ }, 700);
57
+ });
58
+ };
59
+
60
+ const setupElement = (element) => {
61
+ const capWidgetSelector = element.getAttribute("data-cap-floating");
62
+ if (!capWidgetSelector) return;
63
+
64
+ const capWidget = document.querySelector(capWidgetSelector);
65
+ if (!document.contains(capWidget) && !capWidget.solve) {
66
+ throw new Error(`[Cap floating] Element "${capWidgetSelector}" doesn't exist or isn't a Cap widget`);
67
+ }
68
+
69
+ capWidget.style.display = "none";
70
+ const handlers = [element.onclick].filter(Boolean);
71
+
72
+ if (typeof getEventListeners === "function") {
73
+ handlers.push(
74
+ ...(getEventListeners(element).click || []).map((l) => l.listener)
75
+ );
76
+ }
77
+
78
+ if (handlers.length) {
79
+ element.onclick = null;
80
+ handlers.forEach((h) => element.removeEventListener("click", h));
81
+ }
82
+
83
+ element.addEventListener("click", (e) => {
84
+ e.stopImmediatePropagation();
85
+ e.preventDefault();
86
+ handleClick(e, element, capWidget, handlers);
87
+ });
88
+ };
89
+
90
+ const init = (root) => {
91
+ setupElement(root);
92
+ root.querySelectorAll("[data-cap-floating]").forEach(setupElement);
93
+ };
94
+
95
+ init(document.body);
96
+
97
+ new MutationObserver((mutations) =>
98
+ mutations.forEach((mutation) =>
99
+ mutation.addedNodes.forEach((node) => {
100
+ if (node.nodeType === Node.ELEMENT_NODE) init(node);
101
+ })
102
+ )
103
+ ).observe(document.body, { childList: true, subtree: true });
104
+ })();
package/cap.js ADDED
@@ -0,0 +1,525 @@
1
+ (function () {
2
+ let workerScript;
3
+
4
+ class CapBase {
5
+ #workerUrl = "";
6
+ #el = null;
7
+ #resetTimer = null;
8
+ #workersCount = navigator.hardwareConcurrency || 8;
9
+ #token = null;
10
+
11
+ async initialize() {
12
+ const until = (predFn, timeout = 10000) => {
13
+ return new Promise((resolve, reject) => {
14
+ const timeoutId = setTimeout(() => {
15
+ reject(new Error("Initialize timeout"));
16
+ }, timeout);
17
+
18
+ const poll = () => {
19
+ if (predFn()) {
20
+ clearTimeout(timeoutId);
21
+ resolve();
22
+ } else {
23
+ setTimeout(poll, 500);
24
+ }
25
+ };
26
+ poll();
27
+ });
28
+ };
29
+
30
+ if (this.#workerUrl) {
31
+ URL.revokeObjectURL(this.#workerUrl);
32
+ }
33
+
34
+ try {
35
+ await until(() => !!workerScript);
36
+ this.#workerUrl = URL.createObjectURL(
37
+ new Blob([workerScript], {
38
+ type: "application/javascript",
39
+ })
40
+ );
41
+ } catch (err) {
42
+ this.error("Failed to initialize worker");
43
+ throw err;
44
+ }
45
+ }
46
+
47
+ async solve() {
48
+ this.dispatchEvent("progress", { progress: 0 });
49
+
50
+ try {
51
+ // MARK: Todo
52
+ const apiEndpoint =
53
+ location.hostname === "localhost"
54
+ ? "/api/"
55
+ : this.#el.getAttribute("cap-api-endpoint");
56
+
57
+ const { challenge, target, token } = await (
58
+ await fetch(
59
+ `${apiEndpoint || "https://trycap.glitch.me/api/"}challenge`,
60
+ {
61
+ method: "POST",
62
+ }
63
+ )
64
+ ).json();
65
+ const solutions = await this.solveChallenges({
66
+ challenge,
67
+ target,
68
+ token,
69
+ });
70
+
71
+ const resp = await (
72
+ await fetch(
73
+ `${apiEndpoint || "https://trycap.glitch.me/api/"}redeem`,
74
+ {
75
+ method: "POST",
76
+ body: JSON.stringify({ token, solutions }),
77
+ headers: { "Content-Type": "application/json" },
78
+ }
79
+ )
80
+ ).json();
81
+
82
+ if (!resp.success) throw new Error("Invalid solution");
83
+
84
+ this.dispatchEvent("progress", { progress: 100 });
85
+ this.dispatchEvent("solve", { token: resp.token });
86
+ this.#token = resp.token;
87
+ if (this.#el.querySelector("input[name='cap-token']")) {
88
+ this.#el.querySelector("input[name='cap-token']").value = resp.token;
89
+ }
90
+
91
+ if (this.#resetTimer) clearTimeout(this.#resetTimer);
92
+ const expiresIn = new Date(resp.expires).getTime() - Date.now();
93
+ if (expiresIn > 0 && expiresIn < 24 * 60 * 60 * 1000) {
94
+ this.#resetTimer = setTimeout(() => this.reset(), expiresIn); // 24h
95
+ } else {
96
+ this.error("Invalid expiration time");
97
+ }
98
+
99
+ return { success: true, token: this.#token };
100
+ } catch (err) {
101
+ this.error(err.message);
102
+ throw err;
103
+ }
104
+ }
105
+
106
+ async solveChallenges({ challenge, target }) {
107
+ const total = challenge.length;
108
+ let completed = 0;
109
+
110
+ const workers = Array(this.#workersCount)
111
+ .fill(null)
112
+ .map(() => new Worker(this.#workerUrl));
113
+
114
+ const solveSingleChallenge = ([salt, target], workerId) =>
115
+ new Promise((resolve, reject) => {
116
+ const worker = workers[workerId];
117
+ const timeout = setTimeout(() => {
118
+ worker.terminate();
119
+ workers[workerId] = new Worker(this.#workerUrl);
120
+ reject(new Error("Worker timeout"));
121
+ }, 30000);
122
+
123
+ worker.onmessage = ({ data }) => {
124
+ if (!data.found) return;
125
+ clearTimeout(timeout);
126
+ completed++;
127
+ this.dispatchEvent("progress", {
128
+ progress: Math.round((completed / total) * 100),
129
+ });
130
+ resolve([salt, target, data.nonce]);
131
+ };
132
+
133
+ worker.onerror = (err) => {
134
+ clearTimeout(timeout);
135
+ this.error(`Error in worker: ${err}`);
136
+ reject(err);
137
+ };
138
+
139
+ worker.postMessage({ salt, target });
140
+ });
141
+
142
+ const results = [];
143
+ try {
144
+ for (let i = 0; i < challenge.length; i += this.#workersCount) {
145
+ const chunk = challenge.slice(
146
+ i,
147
+ Math.min(i + this.#workersCount, challenge.length)
148
+ );
149
+ const chunkResults = await Promise.all(
150
+ chunk.map((c, idx) => solveSingleChallenge(c, idx))
151
+ );
152
+ results.push(...chunkResults);
153
+ }
154
+ } finally {
155
+ workers.forEach((w) => w.terminate());
156
+ }
157
+
158
+ return results;
159
+ }
160
+
161
+ reset() {
162
+ if (this.#resetTimer) {
163
+ clearTimeout(this.#resetTimer);
164
+ this.#resetTimer = null;
165
+ }
166
+ this.dispatchEvent("reset");
167
+ this.#token = null;
168
+ if (this.#el.querySelector("input[name='cap-token']")) {
169
+ this.#el.querySelector("input[name='cap-token']").value = "";
170
+ }
171
+ }
172
+
173
+ error(message = "Unknown error") {
174
+ console.error("[Cap] Error:", message);
175
+ this.dispatchEvent("error", { isCap: true, message });
176
+ }
177
+
178
+ dispatchEvent(eventName, detail = {}) {
179
+ const event = new CustomEvent(eventName, {
180
+ bubbles: true,
181
+ composed: true,
182
+ detail,
183
+ });
184
+ this.#el.dispatchEvent(event);
185
+ }
186
+
187
+ setElement(el) {
188
+ this.#el = el;
189
+ }
190
+
191
+ setWorkersCount(workers) {
192
+ const parsedWorkers = parseInt(workers, 10);
193
+ const maxWorkers = Math.min(navigator.hardwareConcurrency || 8, 16);
194
+ this.#workersCount =
195
+ !isNaN(parsedWorkers) &&
196
+ parsedWorkers > 0 &&
197
+ parsedWorkers <= maxWorkers
198
+ ? parsedWorkers
199
+ : navigator.hardwareConcurrency || 8;
200
+ }
201
+
202
+ getToken() {
203
+ return this.#token;
204
+ }
205
+
206
+ cleanup() {
207
+ if (this.#resetTimer) {
208
+ clearTimeout(this.#resetTimer);
209
+ this.#resetTimer = null;
210
+ }
211
+
212
+ if (this.#workerUrl) {
213
+ URL.revokeObjectURL(this.#workerUrl);
214
+ this.#workerUrl = "";
215
+ }
216
+ }
217
+ }
218
+
219
+ class CapWidget extends HTMLElement {
220
+ #capBase = new CapBase();
221
+ #shadow;
222
+ #div;
223
+ #host;
224
+ #solving = false;
225
+ eventHandlers;
226
+
227
+ static get observedAttributes() {
228
+ return ["onsolve", "onprogress", "onreset", "onerror", "workers"];
229
+ }
230
+
231
+ constructor() {
232
+ super();
233
+ if (this.eventHandlers) {
234
+ this.eventHandlers.forEach((handler, eventName) => {
235
+ this.removeEventListener(eventName.slice(2), handler);
236
+ });
237
+ }
238
+ this.eventHandlers = new Map();
239
+ this.boundHandleProgress = this.handleProgress.bind(this);
240
+ this.boundHandleSolve = this.handleSolve.bind(this);
241
+ this.boundHandleError = this.handleError.bind(this);
242
+ this.boundHandleReset = this.handleReset.bind(this);
243
+ }
244
+
245
+ attributeChangedCallback(name, oldValue, newValue) {
246
+ if (name.startsWith("on")) {
247
+ const eventName = name.slice(2);
248
+ const oldHandler = this.eventHandlers.get(name);
249
+ if (oldHandler) {
250
+ this.removeEventListener(eventName, oldHandler);
251
+ }
252
+
253
+ if (newValue) {
254
+ const handler = (event) => {
255
+ const callback = this.getAttribute(name);
256
+ if (typeof window[callback] === "function") {
257
+ window[callback].call(this, event);
258
+ }
259
+ };
260
+ this.eventHandlers.set(name, handler);
261
+ this.addEventListener(eventName, handler);
262
+ }
263
+ }
264
+ }
265
+
266
+ async connectedCallback() {
267
+ this.#host = this;
268
+ this.#shadow = this.attachShadow({ mode: "open" });
269
+ this.#capBase.setElement(this);
270
+ this.#div = document.createElement("div");
271
+ this.createUI();
272
+ this.addEventListeners();
273
+ await this.#capBase.initialize();
274
+ this.#div.removeAttribute("disabled");
275
+ const workers = this.getAttribute("cap-worker-count");
276
+ this.#capBase.setWorkersCount(
277
+ parseInt(workers)
278
+ ? parseInt(workers, 10)
279
+ : navigator.hardwareConcurrency || 8
280
+ );
281
+ this.#host.innerHTML = `<input type="hidden" name="cap-token">`;
282
+ }
283
+
284
+ createUI() {
285
+ this.#div.classList.add("captcha");
286
+ this.#div.setAttribute("role", "button");
287
+ this.#div.setAttribute("tabindex", "0");
288
+ this.#div.setAttribute("disabled", "true");
289
+ this.#div.innerHTML = `<div class="checkbox"></div><p>I'm a human</p><a href="#" class="credits" target="_blank"><span>Secured by&nbsp;</span>Cap</a>`;
290
+ this.#shadow.innerHTML = `<style>.captcha{background-color:var(--cap-background);border:1px solid var(--cap-border-color);border-radius:var(--cap-border-radius);width:var(--cap-widget-width);display:flex;align-items:center;padding:var(--cap-widget-padding);gap:var(--cap-gap);cursor:pointer;transition:filter var(--cap-transition-duration),transform var(--cap-transition-duration);position:relative;-webkit-tap-highlight-color:rgba(255,255,255,0);overflow:hidden;color:var(--cap-color)}.captcha:hover{filter:var(--cap-hover-filter)}.captcha:not([disabled]):active{transform:scale(var(--cap-active-scale))}.checkbox{width:var(--cap-checkbox-size);height:var(--cap-checkbox-size);border:var(--cap-checkbox-border);border-radius:var(--cap-checkbox-border-radius);background-color:var(--cap-checkbox-background);transition:opacity var(--cap-transition-duration);margin-top:var(--cap-checkbox-margin);margin-bottom:var(--cap-checkbox-margin)}.captcha *{font-family:var(--cap-font)}.captcha p{margin:0;font-weight:500;font-size:15px;user-select:none;transition:opacity var(--cap-transition-duration)}.captcha[data-state=verifying] .checkbox{background: none;display:flex;align-items:center;justify-content:center;transform: scale(1.1);border: none;border-radius: 50%;background: conic-gradient(var(--cap-spinner-color) 0%, var(--cap-spinner-color) var(--progress, 0%), var(--cap-spinner-background-color) var(--progress, 0%), var(--cap-spinner-background-color) 100%);position: relative;}.captcha[data-state=verifying] .checkbox::after {content: "";background-color: var(--cap-background);width: calc(100% - var(--cap-spinner-thickness));height: calc(100% - var(--cap-spinner-thickness));border-radius: 50%;margin:calc(var(--cap-spinner-thickness) / 2)}.captcha[data-state=done] .checkbox{border:1px solid transparent;background-image:var(--cap-checkmark);background-size:cover}.captcha[data-state=error] .checkbox{border:1px solid transparent;background-image:var(--cap-error-cross);background-size:cover}.captcha[disabled]{
291
+ cursor:not-allowed}.captcha[disabled][data-state=verifying]{cursor:progress}.captcha[disabled][data-state=done]{cursor:default}.captcha .credits{position:absolute;bottom:10px;right:10px;font-size:var(--cap-credits-font-size);color:var(--cap-color);opacity:var(--cap-opacity-hover)}.captcha .credits span{display:none;text-decoration:underline}.captcha .credits:hover span{display:inline-block}</style>`;
292
+
293
+ this.#shadow.appendChild(this.#div);
294
+ }
295
+
296
+ addEventListeners() {
297
+ this.#div.querySelector("a").addEventListener("click", (e) => {
298
+ e.stopPropagation();
299
+ e.preventDefault();
300
+ window.open("#", "_blank");
301
+ });
302
+
303
+ this.#div.addEventListener("click", () => {
304
+ if (!this.#div.hasAttribute("disabled")) this.solve();
305
+ });
306
+
307
+ this.addEventListener("progress", this.boundHandleProgress);
308
+ this.addEventListener("solve", this.boundHandleSolve);
309
+ this.addEventListener("error", this.boundHandleError);
310
+ this.addEventListener("reset", this.boundHandleReset);
311
+ }
312
+
313
+ async solve() {
314
+ if (this.#solving) {
315
+ return;
316
+ }
317
+
318
+ try {
319
+ this.#solving = true;
320
+ this.updateUI("verifying", "Verifying...", true);
321
+ const result = await this.#capBase.solve();
322
+ return result;
323
+ } finally {
324
+ this.#solving = false;
325
+ }
326
+ }
327
+
328
+ updateUI(state, text, disabled = false) {
329
+ this.#div.setAttribute("data-state", state);
330
+ this.#div.querySelector("p").innerText = text;
331
+ if (disabled) {
332
+ this.#div.setAttribute("disabled", "true");
333
+ } else {
334
+ this.#div.removeAttribute("disabled");
335
+ }
336
+ }
337
+
338
+ handleProgress(event) {
339
+ const progressElement = this.#div.querySelector("p");
340
+ if (progressElement) {
341
+ this.#div
342
+ .querySelector(".checkbox")
343
+ .style.setProperty("--progress", `${event.detail.progress}%`);
344
+ progressElement.innerText = `Verifying... ${event.detail.progress}%`;
345
+ }
346
+ this.executeAttributeCode("onprogress", event);
347
+ }
348
+
349
+ handleSolve(event) {
350
+ this.updateUI("done", "You're a human", true);
351
+ this.executeAttributeCode("onsolve", event);
352
+ }
353
+
354
+ handleError(event) {
355
+ this.updateUI("error", "Error. Try again.");
356
+ this.executeAttributeCode("onerror", event);
357
+ }
358
+
359
+ handleReset(event) {
360
+ this.updateUI("", "I'm a human");
361
+ this.executeAttributeCode("onreset", event);
362
+ }
363
+
364
+ executeAttributeCode(attributeName, event) {
365
+ const code = this.getAttribute(attributeName);
366
+ if (!code) {
367
+ return;
368
+ }
369
+ const func = new Function("event", code);
370
+ func.call(this, event);
371
+ }
372
+
373
+ reset() {
374
+ this.#capBase.reset();
375
+ }
376
+
377
+ get token() {
378
+ return this.#capBase.getToken();
379
+ }
380
+
381
+ disconnectedCallback() {
382
+ this.removeEventListener("progress", this.boundHandleProgress);
383
+ this.removeEventListener("solve", this.boundHandleSolve);
384
+ this.removeEventListener("error", this.boundHandleError);
385
+ this.removeEventListener("reset", this.boundHandleReset);
386
+
387
+ this.eventHandlers.forEach((handler, eventName) => {
388
+ this.removeEventListener(eventName.slice(2), handler);
389
+ });
390
+ this.eventHandlers.clear();
391
+
392
+ if (this.#shadow) {
393
+ this.#shadow.innerHTML = "";
394
+ }
395
+
396
+ this.#capBase.reset();
397
+ this.#capBase.cleanup();
398
+ }
399
+ }
400
+
401
+ class Cap {
402
+ constructor(el, config = {}) {
403
+ let capBase = new CapBase();
404
+ let element = el || document.createElement("div");
405
+
406
+ if (!el) element.style.display = "none";
407
+ Object.entries(config).forEach(([a, b]) => {
408
+ element.setAttribute(a, b);
409
+ });
410
+
411
+ if (config.apiEndpoint) {
412
+ element.setAttribute("cap-api-endpoint", config.apiEndpoint);
413
+ }
414
+
415
+ capBase.setElement(element);
416
+ capBase.setWorkersCount(
417
+ config.workers || navigator.hardwareConcurrency || 8
418
+ );
419
+ capBase.initialize();
420
+
421
+ this.solve = async function () {
422
+ return await capBase.solve();
423
+ };
424
+
425
+ this.reset = function () {
426
+ capBase.reset();
427
+ };
428
+
429
+ this.addEventListener = function (event, callback) {
430
+ element.addEventListener(event, callback);
431
+ };
432
+
433
+ Object.defineProperty(this, "token", {
434
+ get: () => capBase.getToken(),
435
+ configurable: true,
436
+ enumerable: true,
437
+ });
438
+ }
439
+ }
440
+
441
+ const sheet = new CSSStyleSheet();
442
+ sheet.replaceSync(
443
+ `html{--cap-font:system,-apple-system,"BlinkMacSystemFont",".SFNSText-Regular","San Francisco","Roboto","Segoe UI","Helvetica Neue","Lucida Grande","Ubuntu","arial",sans-serif;--cap-color:#212121;--cap-background:#fdfdfd;--cap-border-color:#dddddd8f;--cap-border-radius:14px;--cap-checkbox-border:1px solid #aaaaaad1;--cap-checkbox-border-radius:6px;--cap-checkbox-background:#fafafa91;--cap-widget-width:240px;--cap-widget-padding:14px;--cap-checkbox-size:24px;--cap-checkbox-margin:2px;--cap-transition-duration:0.2s;--cap-gap:15px;--cap-opacity-hover:0.8;--cap-hover-filter:brightness(97%);--cap-active-scale:0.98;--cap-credits-font-size:12px;--cap-spinner-color:black;--cap-spinner-background-color:#eee;--cap-error-cross:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='96' height='96' viewBox='0 0 24 24'%3E%3Cpath fill='%23f55b50' d='M11 15h2v2h-2zm0-8h2v6h-2zm1-5C6.47 2 2 6.5 2 12a10 10 0 0 0 10 10a10 10 0 0 0 10-10A10 10 0 0 0 12 2m0 18a8 8 0 0 1-8-8a8 8 0 0 1 8-8a8 8 0 0 1 8 8a8 8 0 0 1-8 8'/%3E%3C/svg%3E");--cap-checkmark:url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2224%22%20height%3D%2224%22%20viewBox%3D%220%200%2024%2024%22%3E%3Cstyle%3E%40keyframes%20anim%7B0%25%7Bstroke-dashoffset%3A23.21320343017578px%7Dto%7Bstroke-dashoffset%3A0%7D%7D%3C%2Fstyle%3E%3Cpath%20fill%3D%22none%22%20stroke%3D%22%2300a67d%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%20stroke-width%3D%222%22%20d%3D%22m5%2012%205%205L20%207%22%20style%3D%22stroke-dashoffset%3A0%3Bstroke-dasharray%3A23.21320343017578px%3Banimation%3Aanim%20.5s%20ease%22%2F%3E%3C%2Fsvg%3E");--cap-spinner-thickness:5px;}`
444
+ );
445
+ document.adoptedStyleSheets.push(sheet);
446
+
447
+ const workerFunct = function () {
448
+ let hasher;
449
+
450
+ self.onmessage = async ({ data: { salt, target } }) => {
451
+ if (!hasher) {
452
+ hasher = await hashwasm.createSHA256();
453
+ }
454
+
455
+ let nonce = 0;
456
+ const batchSize = 50000;
457
+ const reportInterval = 500000;
458
+ let processed = 0;
459
+
460
+ const buffer = new Uint8Array(128);
461
+ const encoder = new TextEncoder();
462
+
463
+ while (true) {
464
+ try {
465
+ for (let i = 0; i < batchSize; i++) {
466
+ const input = salt + nonce.toString();
467
+ const inputBytes = encoder.encode(input);
468
+ buffer.set(inputBytes);
469
+
470
+ hasher.init();
471
+ hasher.update(buffer.subarray(0, inputBytes.length));
472
+ const hash = hasher.digest("hex");
473
+
474
+ if (hash.startsWith(target)) {
475
+ self.postMessage({ nonce, found: true });
476
+ return;
477
+ }
478
+
479
+ nonce++;
480
+ }
481
+
482
+ processed += batchSize;
483
+ if (processed >= reportInterval) {
484
+ self.postMessage({ nonce, found: false });
485
+ processed = 0;
486
+ }
487
+ } catch (error) {
488
+ self.postMessage({ found: false, error: error.message });
489
+ return;
490
+ }
491
+ }
492
+ };
493
+ };
494
+
495
+ setTimeout(async function () {
496
+ workerScript =
497
+ (await (await fetch("https://cdn.jsdelivr.net/gh/tiagorangel1/cap/lib/wasm-hashes.min.js")).text()) +
498
+ workerFunct
499
+ .toString()
500
+ .replace(/^function\s*\([^\)]*\)\s*{|\}$/g, "")
501
+ .trim();
502
+ }, 1);
503
+
504
+ window.Cap = Cap;
505
+
506
+ if (!customElements.get("cap-widget")) {
507
+ customElements.define("cap-widget", CapWidget);
508
+ } else {
509
+ console.warn(
510
+ "The cap-widget element has already been defined. Skipping re-defining it."
511
+ );
512
+ }
513
+
514
+ if (typeof exports === "object" && typeof module !== "undefined") {
515
+ module.exports = Cap;
516
+ } else if (typeof define === "function" && define.amd) {
517
+ define([], function () {
518
+ return Cap;
519
+ });
520
+ }
521
+
522
+ if (typeof exports !== "undefined") {
523
+ exports.default = Cap;
524
+ }
525
+ })();
package/package.json ADDED
@@ -0,0 +1,32 @@
1
+ {
2
+ "name": "@cap.js/widget",
3
+ "version": "0.0.1",
4
+ "description": "Cap widget",
5
+ "keywords": [
6
+ "captcha",
7
+ "pow",
8
+ "crypto",
9
+ "encryption",
10
+ "recaptcha",
11
+ "bun",
12
+ "js",
13
+ "node",
14
+ "hcaptcha"
15
+ ],
16
+ "homepage": "https://github.com/tiagorangel1/cap#readme",
17
+ "bugs": {
18
+ "url": "https://github.com/tiagorangel1/cap/issues"
19
+ },
20
+ "repository": {
21
+ "type": "git",
22
+ "url": "git+https://github.com/tiagorangel1/cap.git"
23
+ },
24
+ "license": "AGPL-3.0",
25
+ "author": "Tiago Rangel",
26
+ "type": "commonjs",
27
+ "main": "cap.js",
28
+ "scripts": {
29
+ "test": "echo \"Error: no test specified\" && exit 1",
30
+ "npm:publish": "sudo npm publish --access public"
31
+ }
32
+ }