### Installing Cap.js Server Library
Source: https://github.com/tiagorangel1/cap/blob/main/docs/guide/index.md
Instructions for installing the @cap.js/server package using different JavaScript package managers. This library is essential for setting up the server-side API for Cap.
```bun
bun add @cap.js/server
```
```npm
npm i @cap.js/server
```
```pnpm
pnpm i @cap.js/server
```
--------------------------------
### Installing Project Dependencies with Bun
Source: https://github.com/tiagorangel1/cap/blob/main/demo/solver/README.md
This command uses Bun's package manager to install all required project dependencies, similar to `npm install` or `yarn install`.
```Bash
bun install
```
--------------------------------
### Installing @cap.js/server with Bun
Source: https://github.com/tiagorangel1/cap/blob/main/docs/guide/server.md
Instructions to install the `@cap.js/server` library using the Bun package manager.
```bash
bun add @cap.js/server
```
--------------------------------
### Installing @cap.js/server with pnpm
Source: https://github.com/tiagorangel1/cap/blob/main/docs/guide/server.md
Instructions to install the `@cap.js/server` library using the pnpm package manager.
```bash
pnpm i @cap.js/server
```
--------------------------------
### Installing @cap.js/server with npm
Source: https://github.com/tiagorangel1/cap/blob/main/docs/guide/server.md
Instructions to install the `@cap.js/server` library using the npm package manager.
```bash
npm i @cap.js/server
```
--------------------------------
### Configuring Cap.js API Routes
Source: https://github.com/tiagorangel1/cap/blob/main/docs/guide/index.md
Examples demonstrating how to integrate Cap.js into various JavaScript server frameworks (Elysia, Fastify, Bun, Hono, Express) to expose the /api/challenge and /api/redeem endpoints. These routes handle challenge creation and redemption, respectively, and require a tokens_store_path for persistent token storage.
```elysia
import { Elysia } from "elysia";
import Cap from "@cap.js/server";
const cap = new Cap({
tokens_store_path: ".data/tokensList.json"
});
new Elysia()
.post("/api/challenge", () => {
return cap.createChallenge();
})
.post("/api/redeem", async ({ body, set }) => {
const { token, solutions } = body;
if (!token || !solutions) {
set.status = 400;
return { success: false };
}
return await cap.redeemChallenge({ token, solutions });
})
.listen(3000);
console.log(`🦊 Elysia is running at http://localhost:3000`);
```
```fastify
import Fastify from "fastify";
import Cap from "@cap.js/server";
const fastify = Fastify();
const cap = new Cap({
tokens_store_path: ".data/tokensList.json"
});
fastify.post("/api/challenge", (req, res) => {
res.send(cap.createChallenge());
});
fastify.post("/api/redeem", async (req, res) => {
const { token, solutions } = req.body;
if (!token || !solutions) {
return res.code(400).send({ success: false });
}
res.send(await cap.redeemChallenge({ token, solutions }));
});
fastify.listen({ port: 3000, host: "0.0.0.0" }).then(() => {
console.log("Server is running on http://localhost:3000");
});
```
```bun.serve
import Cap from "@cap.js/server";
const cap = new Cap({
tokens_store_path: ".data/tokensList.json"
});
Bun.serve({
port: 3000,
routes: {
"/api/challenge": {
POST: () => {
return Response.json(cap.createChallenge());
}
},
"/api/redeem": {
POST: async (req) => {
const body = await req.json();
const { token, solutions } = body;
if (!token || !solutions) {
return Response.json({ success: false }, { status: 400 });
}
return Response.json(await cap.redeemChallenge({ token, solutions }));
}
}
}
});
console.log(`Server running at http://localhost:3000`);
```
```hono
import { Hono } from "hono";
import Cap from "@cap.js/server";
const app = new Hono();
const cap = new Cap({
tokens_store_path: ".data/tokensList.json"
});
app.post("/api/challenge", (c) => {
return c.json(cap.createChallenge());
});
app.post("/api/redeem", async (c) => {
const { token, solutions } = await c.req.json();
if (!token || !solutions) {
return c.json({ success: false }, 400);
}
return c.json(await cap.redeemChallenge({ token, solutions }));
});
export default {
port: 3000,
fetch: app.fetch
};
```
```express
import express from "express";
import Cap from "@cap.js/server";
const app = express();
app.use(express.json());
const cap = new Cap({
tokens_store_path: ".data/tokensList.json"
});
app.post("/api/challenge", (req, res) => {
res.json(cap.createChallenge());
});
app.post("/api/redeem", async (req, res) => {
const { token, solutions } = req.body;
if (!token || !solutions) {
return res.status(400).json({ success: false });
}
res.json(await cap.redeemChallenge({ token, solutions }));
});
app.listen(3000, () => {
console.log("Listening on port 3000");
});
```
--------------------------------
### Running the Project with Bun
Source: https://github.com/tiagorangel1/cap/blob/main/demo/solver/README.md
This command executes the main project file, `index.js`, using the Bun runtime. It's equivalent to `node index.js` but leverages Bun's performance.
```Bash
bun run index.js
```
--------------------------------
### Installing @cap.js/solver with Bun
Source: https://github.com/tiagorangel1/cap/blob/main/docs/guide/solver.md
This snippet provides the command to install the `@cap.js/solver` library using the Bun package manager. It's a prerequisite for using the library in your project.
```bash
bun add @cap.js/solver
```
--------------------------------
### Installing Hono Checkpoint Middleware (Bun)
Source: https://github.com/tiagorangel1/cap/blob/main/docs/guide/middleware/hono.md
This command installs the Hono framework and the @cap.js/checkpoint-hono middleware using the Bun package manager, which are prerequisites for setting up the checkpoint functionality.
```bash
bun add hono @cap.js/checkpoint-hono
```
--------------------------------
### Installing CAP.js Elysia Middleware - Bash
Source: https://github.com/tiagorangel1/cap/blob/main/docs/guide/middleware/elysia.md
This command installs the necessary packages, `elysia` and `@cap.js/middleware-elysia`, using the Bun package manager, which are required to integrate CAP.js checkpointing into an Elysia application.
```bash
bun add elysia @cap.js/middleware-elysia
```
--------------------------------
### Solving Multiple Cap Challenges (CLI)
Source: https://github.com/tiagorangel1/cap/blob/main/docs/guide/cli.md
This example shows how to pass multiple `salt:target` challenges to the `@cap.js/cli` tool, separated by spaces, for batch solving. The CLI will process each challenge and return its solution.
```bash
bunx '@cap.js/cli' e455cea65e98b:dceb fb8d25f6abac:93f1 ...
```
--------------------------------
### Handling Start Button Click Event (JavaScript)
Source: https://github.com/tiagorangel1/cap/blob/main/standalone/public/test.html
This event listener handles the click event on the 'Start' button. It retrieves the key ID and secret key, performs basic validation, clears previous logs, initializes challenge timing, disables the button, and then initiates a new challenge using the `Cap` widget. It also sets up event listeners for progress and error events from the `Cap` widget, and handles the successful completion or failure of the challenge, including token validation and chart rendering.
```JavaScript
startButton.addEventListener("click", () => {
const KEY_ID = keyIdInput.value.trim();
const SECRET_KEY = secretKeyInput.value.trim();
if (!SECRET_KEY || !KEY_ID) {
clearLogs();
log("Missing secret key or key ID.");
return;
}
clearLogs();
progressTimings = {};
startTime = Date.now();
progressTimings[0] = 0;
startButton.disabled = true;
log(
`Requesting challenge for key ${KEY_ID}...\nSecret key: ${SECRET_KEY.substring(
0,
5
)}...\n\n${"*".repeat(60)}\n\n`
);
if (cap && cap.widget && cap.widget.parentNode) {
cap.widget.parentNode.removeChild(cap.widget);
}
cap = new Cap({
apiEndpoint: `/${KEY_ID}/api/`,
});
cap.addEventListener("progress", (e) => {
const currentTime = Date.now();
const elapsed = currentTime - startTime;
const progress = e.detail.progress;
log(`Solving... ${progress}% [${elapsed}ms]`);
if (progressTimings[progress] === undefined) {
progressTimings[progress] = elapsed;
}
});
cap.addEventListener("error", (e) => {
log(`Error: ${e.detail.error}`);
startButton.disabled = false;
if (cap.widget) {
cap.widget.style.display = "none";
}
});
cap.widget.style.display = "block";
cap
.solve()
.then(async (token) => {
const solveEndTime = Date.now();
const totalSolveTime = solveEndTime - startTime;
log(`Challenge solved in ${totalSolveTime}ms`);
progressTimings[100] = totalSolveTime;
renderProgressChart();
await validateToken(KEY_ID, SECRET_KEY, token.token);
})
.catch((err) => {
log(`Error during solve: ${err}`);
})
.finally(() => {
startButton.disabled = false;
});
});
```
--------------------------------
### Importing Cap Widget Library from CDN - HTML
Source: https://github.com/tiagorangel1/cap/blob/main/docs/guide/index.md
This snippet demonstrates how to include the Cap widget library in your HTML using popular Content Delivery Networks (CDNs) like jsdelivr or unpkg. It's recommended to pin a specific version of the library to avoid potential breaking changes in future updates.
```HTML
```
```HTML
```
--------------------------------
### Running Cap Standalone Server with Docker
Source: https://github.com/tiagorangel1/cap/blob/main/docs/guide/standalone.md
This command starts the Cap Standalone server as a detached Docker container, mapping port 3000, mounting a data volume, and setting an administrative key. It initializes the server for use, allowing access to the dashboard and API endpoints.
```bash
docker run -d \
-p 3000:3000 \
-v cap-data:/usr/src/app/.data \
-e ADMIN_KEY=your_secret_key \
--name cap-standalone \
tiago2/cap:latest
```
--------------------------------
### Example Parsed CLI Output (JSON)
Source: https://github.com/tiagorangel1/cap/blob/main/docs/guide/cli.md
This JSON snippet represents the structured data format that results from parsing the `@cap.js/cli` output using the provided JavaScript example. It shows each challenge as an array containing its salt, target, and solved nonce.
```json
[
["e455cea65e98b", "dceb", "9100"],
["fb8d25f6abac", "93f1", "76570"]
]
```
--------------------------------
### Configuring and Starting an Express Server with CAP.js Checkpoint
Source: https://github.com/tiagorangel1/cap/blob/main/docs/guide/middleware/express.md
This JavaScript code sets up an Express server, configures it to use JSON body parsing and cookie parsing, and integrates the `capCheckpoint` middleware. It also defines a root route and starts the server, demonstrating how to protect routes with the middleware.
```javascript
import express from "express";
import cookieParser from "cookie-parser";
import path from "path";
import { dirname } from "path";
import { fileURLToPath } from "url";
import { capCheckpoint } from "@cap.js/checkpoint-express";
const app = express();
const __dirname = dirname(fileURLToPath(import.meta.url));
app.use(express.json());
app.use(cookieParser());
app.use(
capCheckpoint({
/*
token_validity_hours: 32,
tokens_store_path: ".data/tokensList.json",
token_size: 16,
verification_template_path: join(__dirname, "./index.html"),
*/
})
);
app.get("/", (req, res) => {
res.sendFile(path.join(__dirname, "success.html"));
});
app.listen(3000, () => {
console.log(`Server running on http://localhost:3000`);
});
```
--------------------------------
### Installing Express Checkpoint Middleware with Bun
Source: https://github.com/tiagorangel1/cap/blob/main/docs/guide/middleware/express.md
This command installs the necessary npm packages for an Express application using Bun, including Express itself, `cookie-parser` for handling cookies, and `@cap.js/checkpoint-express` for the checkpoint functionality.
```bash
bun add express cookie-parser @cap.js/middleware-express
```
--------------------------------
### Handling Cap Widget Solve Event - JavaScript
Source: https://github.com/tiagorangel1/cap/blob/main/docs/guide/index.md
This JavaScript code demonstrates how to listen for the `solve` event emitted by the Cap widget. When the widget successfully solves the proof-of-work, this event fires, providing the generated token in `e.detail.token`, which can then be handled as needed by your application. Alternative methods for token retrieval include using the `onsolve` attribute directly on the widget or wrapping the widget in a form.
```JavaScript
const widget = document.querySelector("#cap");
widget.addEventListener("solve", function (e) {
const token = e.detail.token;
// Handle the token as needed
});
```
--------------------------------
### Example Output from @cap.js/solver
Source: https://github.com/tiagorangel1/cap/blob/main/docs/guide/solver.md
This JSON snippet illustrates the structure of the output returned by the `@cap.js/solver` function. Each inner array represents a solved challenge, containing the original challenge ID, the solution, and the calculated proof-of-work value.
```json
[
["a5b6fda4aaed97cf61d7dd9259f733b5", "d455", 67302],
["286bcc39249f9ee698314b600c32e40f", "f0ff", 64511],
["501350aa7c46573cb604284554045703", "4971", 40440],
["a55c02f3b9b4cd088a5a7ee3d4941c14", "eab7", 27959],
["5f3362c12e2779f56f4ef75b4494f5e6", "999f", 71259],
...
]
```
--------------------------------
### Adding Cap Widget Component to HTML
Source: https://github.com/tiagorangel1/cap/blob/main/docs/guide/index.md
This HTML snippet shows how to embed the `` component into your webpage. The `id` attribute is used for easy selection in JavaScript, and the `data-cap-api-endpoint` attribute specifies the URL where the Cap API server is running, which is crucial for the widget's operation.
```HTML
```
--------------------------------
### Configuring CAP.js Elysia Middleware - JavaScript
Source: https://github.com/tiagorangel1/cap/blob/main/docs/guide/middleware/elysia.md
This JavaScript code demonstrates how to initialize and use the `capMiddleware` with an Elysia application. It configures token validity, storage path, token size, and the path to the verification template, setting the scoping to 'scoped' before starting the server.
```javascript
import { Elysia, file } from "elysia";
import { capMiddleware } from "@cap.js/middleware-elysia";
new Elysia()
.use(
capMiddleware({
token_validity_hours: 32, // how long the token is valid for
tokens_store_path: ".data/tokensList.json",
token_size: 16, // token size in bytes
verification_template_path: join(
dirname(fileURLToPath(import.meta.url)),
"./index.html"
),
scoping: "scoped", // 'global' | 'scoped'
})
)
.get("/", () => "Hello Elysia!")
.listen(3000);
```
--------------------------------
### Verifying CAPTCHA Token with Curl
Source: https://github.com/tiagorangel1/cap/blob/main/docs/guide/standalone.md
This `curl` command provides an example of how to send a POST request to the Cap Standalone server's `/siteverify` endpoint. It demonstrates the required JSON payload containing the secret key and the CAPTCHA token for server-side validation.
```bash
curl "https:////siteverify" \
-X POST \
-H "Content-Type: application/json" \
-d '{ "secret": "", "response": "" }'
```
--------------------------------
### Solving Cap Challenges with @cap.js/solver in JavaScript
Source: https://github.com/tiagorangel1/cap/blob/main/docs/guide/solver.md
This JavaScript example demonstrates how to import the `solver` function from `@cap.js/solver` and use it to process a list of Cap challenges. The `CHALLENGES` array holds pairs of challenge IDs and their corresponding data, and the `solver` function returns the solved challenges with their proof-of-work values.
```javascript
import solver from "@cap.js/solver";
const CHALLENGES = [
["a5b6fda4aaed97cf61d7dd9259f733b5", "d455"],
["286bcc39249f9ee698314b600c32e40f", "f0ff"],
["501350aa7c46573cb604284554045703", "4971"],
["a55c02f3b9b4cd088a5a7ee3d4941c14", "eab7"],
["5f3362c12e2779f56f4ef75b4494f5e6", "999f"],
/* ... */
];
console.log(await solver(CHALLENGES));
```
--------------------------------
### Adding Event Listener for Cap Progress - JavaScript
Source: https://github.com/tiagorangel1/cap/blob/main/docs/guide/invisible.md
This example shows how to attach an event listener to a Cap instance to monitor the progress of a challenge solution. It initializes Cap with an API endpoint and then adds a 'progress' event listener. The callback function logs the current solving progress, providing real-time feedback on the challenge resolution.
```js
const cap = new Cap({
apiEndpoint: "/api/"
});
cap.addEventListener("progress", (event) => {
console.log(`Solving... ${event.detail.progress}% done`);
});
```
--------------------------------
### Cap Class Constructor Arguments (JSON)
Source: https://github.com/tiagorangel1/cap/blob/main/docs/guide/server.md
Defines the configuration options for initializing a new `Cap` instance, including the token store path, whether to use file system state, and initial state objects.
```json
{
"tokens_store_path": ".data/tokensList.json",
"noFSState": false,
"state": {
"challengesList": {},
"tokensList": {}
}
}
```
--------------------------------
### Invoking @cap.js/cli (Basic)
Source: https://github.com/tiagorangel1/cap/blob/main/docs/guide/cli.md
This snippet demonstrates the most basic way to invoke the `@cap.js/cli` tool using `bunx`. It's typically used to display help or confirm the tool's availability.
```bash
bunx '@cap.js/cli'
```
--------------------------------
### Validating Cap.js Tokens
Source: https://github.com/tiagorangel1/cap/blob/main/docs/guide/index.md
Demonstrates how to validate a Cap.js token using cap.validateToken. This method returns a success boolean and by default deletes the token after validation. The keepToken: true option can be used to prevent token deletion.
```javascript
await cap.validateToken("..."); // returns { success: Boolean }
await cap.validateToken("...", { keepToken: true });
```
--------------------------------
### Understanding @cap.js/cli Output Format
Source: https://github.com/tiagorangel1/cap/blob/main/docs/guide/cli.md
This snippet illustrates the standard output format of the `@cap.js/cli` tool after successfully solving challenges. Each line represents a solved challenge, providing the original `salt`, `target`, and the computed `nonce`.
```bash
@cap.js/cli 2 challenges
e455cea65e98b:dceb:9100
fb8d25f6abac:93f1:76570
...
```
--------------------------------
### Implementing CAP.js with Bun.serve in JavaScript
Source: https://github.com/tiagorangel1/cap/blob/main/docs/guide/server.md
Demonstrates how to integrate `@cap.js/server` with Bun's native HTTP server (`Bun.serve`) to create `/api/challenge` and `/api/redeem` endpoints for CAPTCHA challenge generation and redemption.
```javascript
import Cap from "@cap.js/server";
const cap = new Cap({
tokens_store_path: ".data/tokensList.json",
});
Bun.serve({
port: 3000,
routes: {
"/api/challenge": {
POST: () => {
return Response.json(cap.createChallenge());
},
},
"/api/redeem": {
POST: async (req) => {
const body = await req.json();
const { token, solutions } = body;
if (!token || !solutions) {
return Response.json({ success: false }, { status: 400 });
}
return Response.json(await cap.redeemChallenge({ token, solutions }));
},
},
},
});
console.log(`Server running at http://localhost:3000`);
```
--------------------------------
### Importing @cap.js/widget Library
Source: https://github.com/tiagorangel1/cap/blob/main/docs/guide/widget.md
These snippets demonstrate various methods to include the `@cap.js/widget` client-side library in your HTML. Options include using popular CDNs like jsDelivr and unpkg, or serving the library from a standalone server. It's recommended to pin a specific version for stability.
```HTML
```
```HTML
```
```HTML
```
--------------------------------
### Displaying @cap.js/cli Usage
Source: https://github.com/tiagorangel1/cap/blob/main/docs/guide/cli.md
This output details the command-line usage for the `@cap.js/cli` tool, specifying the required `` argument in `salt:target` format and general options.
```bash
@cap.js/cli cli solver for cap challenges
Usage:
$ bunx '@cap.js/cli'
Options:
The challenges to solve in
format `salt:target`
```
--------------------------------
### Loading Cap Widget Script from Self-Hosted Server
Source: https://github.com/tiagorangel1/cap/blob/main/docs/guide/standalone.md
This HTML snippet shows how to include the Cap widget's JavaScript file by setting the `src` attribute of a `
```
--------------------------------
### Initializing UI Elements and Challenge Data in JavaScript
Source: https://github.com/tiagorangel1/cap/blob/main/wasm/test/browser.html
This snippet initializes references to key HTML DOM elements and defines a static array of Proof-of-Work challenges. It also determines the number of Web Workers to use based on the system's hardware concurrency, defaulting to 8.
```JavaScript
const solveButton = document.getElementById("solveButton");
const progressDiv = document.getElementById("progress");
const resultsDiv = document.getElementById("results");
const challenges = [ [
"083655eebec28dd11449f082b026e856", "4b00"],
["bd2e454fbe4efaad38c44ecd72cc4a7b", "f3ef"],
["739d2c3ae32e9d726b27231394a2db89", "bcfe"],
["724e8cf75e11586f881f4c5840204378", "3d20"],
["32b76ba7ee19b3db3f6e7de21124f3b0", "fba4"],
["59337d81ae468b50e3b45f19f96b816d", "a27a"],
["2b3194fd3f26be5671945578e32eff39", "4f3c"],
["a6050041bff37f9a31653dd0e8b884a9", "4520"],
["471162e18f09d41e3281b188edefd8de", "7861"],
["3f6d41cdc04e2d0e7784c1a839133df0", "26b5"],
["a4bb413d6e1c2e992a66cb56bd341a08", "cd05"],
["405910a8488466b7fe6067eb92a59232", "f693"],
["1c7d565e1b65df2bf8b26bcf9a6cfbbd", "a75b"],
["93b6cd8025737d92a0b60266dcf5c612", "c0d2"],
["0a799a1d82fd10979661eff665599cc2", "4997"],
["7f0c392563b1694c8066af2f397b8b82", "0d13"],
["b4c7ba684cb9b0c64da82560c3e6b4bc", "5de6"],
["2dd07a35171ed76878746f386d6d6df3", "4bea"],
];
const numWorkers = navigator.hardwareConcurrency || 8;
```
--------------------------------
### Implementing CAP.js with Elysia in JavaScript
Source: https://github.com/tiagorangel1/cap/blob/main/docs/guide/server.md
Demonstrates how to integrate `@cap.js/server` with the Elysia framework to create `/api/challenge` and `/api/redeem` endpoints for CAPTCHA challenge generation and redemption.
```javascript
import { Elysia } from "elysia";
import Cap from "@cap.js/server";
const cap = new Cap({
tokens_store_path: ".data/tokensList.json",
});
new Elysia()
.post("/api/challenge", () => {
return cap.createChallenge();
})
.post("/api/redeem", async ({ body, set }) => {
const { token, solutions } = body;
if (!token || !solutions) {
set.status = 400;
return { success: false };
}
return await cap.redeemChallenge({ token, solutions });
})
.listen(3000);
console.log(`🦊 Elysia is running at http://localhost:3000`);
```
--------------------------------
### Customizing Cap Widget Labels with i18n
Source: https://github.com/tiagorangel1/cap/blob/main/docs/guide/widget.md
This HTML example illustrates how to customize the text labels displayed on the Cap widget for internationalization (i18n). By setting `data-cap-i18n-*` attributes, you can override default labels such as 'Verifying...', 'I'm a human', and 'Error' to match your application's language or branding.
```HTML
```
--------------------------------
### Implementing CAP.js with Fastify in JavaScript
Source: https://github.com/tiagorangel1/cap/blob/main/docs/guide/server.md
Demonstrates how to integrate `@cap.js/server` with the Fastify framework to create `/api/challenge` and `/api/redeem` endpoints for CAPTCHA challenge generation and redemption.
```javascript
import Fastify from "fastify";
import Cap from "@cap.js/server";
const fastify = Fastify();
const cap = new Cap({
tokens_store_path: ".data/tokensList.json",
});
fastify.post("/api/challenge", (req, res) => {
res.send(cap.createChallenge());
});
fastify.post("/api/redeem", async (req, res) => {
const { token, solutions } = req.body;
if (!token || !solutions) {
return res.code(400).send({ success: false });
}
res.send(await cap.redeemChallenge({ token, solutions }));
});
fastify.listen({ port: 3000, host: "0.0.0.0" }).then(() => {
console.log("Server is running on http://localhost:3000");
});
```
--------------------------------
### Initializing Cap and Solving Challenge (Invisible Mode) - JavaScript
Source: https://github.com/tiagorangel1/cap/blob/main/docs/guide/invisible.md
This snippet demonstrates how to initialize a new Cap instance in invisible mode and solve a challenge. It creates a Cap object with a specified API endpoint, then asynchronously calls `solve()` to obtain a solution. The resulting token is then logged to the console, useful for scenarios requiring background security without a visible widget.
```js
const cap = new Cap({
apiEndpoint: "/api/"
});
const solution = await cap.solve();
console.log(solution.token);
```
--------------------------------
### Implementing CAP.js with Hono in JavaScript
Source: https://github.com/tiagorangel1/cap/blob/main/docs/guide/server.md
Demonstrates how to integrate `@cap.js/server` with the Hono framework to create `/api/challenge` and `/api/redeem` endpoints for CAPTCHA challenge generation and redemption.
```javascript
import { Hono } from "hono";
import Cap from "@cap.js/server";
const app = new Hono();
const cap = new Cap({
tokens_store_path: ".data/tokensList.json",
});
app.post("/api/challenge", (c) => {
return c.json(cap.createChallenge());
});
app.post("/api/redeem", async (c) => {
const { token, solutions } = await c.req.json();
if (!token || !solutions) {
return c.json({ success: false }, 400);
}
return c.json(await cap.redeemChallenge({ token, solutions }));
});
export default {
port: 3000,
fetch: app.fetch,
};
```
--------------------------------
### Loading Cap Floating Mode Script from Self-Hosted Server
Source: https://github.com/tiagorangel1/cap/blob/main/docs/guide/standalone.md
This HTML snippet demonstrates how to load the Cap widget's floating mode JavaScript file from your self-hosted Cap Standalone server. It uses a `
```
--------------------------------
### Generating @cap.js/cli Command from Response (JavaScript)
Source: https://github.com/tiagorangel1/cap/blob/main/docs/guide/cli.md
This JavaScript code illustrates how to dynamically construct the `bunx '@cap.js/cli'` command string from a structured challenge response object. It maps challenge arrays into `salt:target` strings and joins them to form the command-line argument.
```javascript
const response = {
"challenge": [
[ "e455cea65e98b", "dceb" ],
[ "fb8d25f6abac", "93f1" ],
...
],
"token": "...",
"expires": 1745343553913
};
const challenges = response.challenge.map((c) => c.join(":")).join(" ");
const command = `bunx '@cap.js/cli' ${challenges}`;
console.log(command); // bunx '@cap.js/cli' e455cea65e98b:dceb fb8d25f6abac:93f1 ...
```
--------------------------------
### Pulling Cap Standalone Docker Image
Source: https://github.com/tiagorangel1/cap/blob/main/docs/guide/standalone.md
This command pulls the latest Cap Standalone Docker image from the `tiago2/cap` repository. It's the first step to setting up the self-hosted Cap backend, ensuring you have the necessary image to run the server.
```bash
docker pull tiago2/cap:latest
```
--------------------------------
### Initializing and Managing Web Workers for Concurrent Challenge Processing - JavaScript
Source: https://github.com/tiagorangel1/cap/blob/main/wasm/test/browser.html
This JavaScript code initializes a pool of web workers to concurrently solve a set of challenges. It dynamically creates worker blobs from a template, manages worker lifecycle including message handling for results and errors, updates UI progress, and cleans up resources upon completion or failure. It ensures robust error handling and proper resource management for parallel computations.
```JavaScript
ngeIndex = 0; allResults = new Array(challenges.length); progressDiv.textContent = `Status: Initializing ${numWorkers} workers...`; progressDiv.classList.remove("text-danger", "fw-bold"); solveButton.disabled = true; solveButton.textContent = "Solving..."; startTime = performance.now(); try { let baseURL; const currentPath = window.location.pathname; const directoryPath = currentPath.substring( 0, currentPath.lastIndexOf("/") + 1 ); baseURL = window.location.origin + directoryPath; if (!baseURL.endsWith("/")) { baseURL += "/"; } const finalWorkerCode = workerCodeTemplate.replace( /\\$\\{baseURL\\}/g, baseURL ); const blob = new Blob([finalWorkerCode], { type: "application/javascript", }); workerBlobUrl = URL.createObjectURL(blob); for (let i = 0; i < numWorkers; i++) { const worker = new Worker(workerBlobUrl, { type: "module" }); worker.onmessage = (event) => { if ( event.data && typeof event.data.challengeIndex !== "undefined" ) { challengesProcessed++; allResults[event.data.challengeIndex] = event.data; displayResult(event.data); updateProgress(); if (challengesProcessed === challenges.length) { const totalTime = ( (performance.now() - startTime) / 1000 ).toFixed(2); progressDiv.textContent = `Status: All ${challenges.length} challenges processed in ${totalTime} seconds.`; progressDiv.classList.remove("text-danger", "fw-bold"); cleanupWorkers(); solveButton.disabled = false; solveButton.textContent = "Solve challenges"; } else { startNextTask(worker); } return; } console.error( `Main: Initialization/Setup error from Worker ${i + 1}:`, event.data.error ); displayResult({ challengeIndex: -1, error: `Worker ${i + 1} setup failed: ${event.data.error}`, }); progressDiv.textContent = `Status: Worker error`; progressDiv.classList.add("text-danger", "fw-bold"); cleanupWorkers(); solveButton.disabled = false; solveButton.textContent = "Solve challenges"; }; worker.onerror = (error) => { console.error( `Main: Error reported from Worker ${i + 1}:`, error ); displayResult({ challengeIndex: -1, error: `Worker ${i + 1} ${error.message || "Unknown error"}`, }); progressDiv.textContent = `Status: Error in Worker ${ i + 1 }. Stopping.`; progressDiv.classList.add("text-danger", "fw-bold"); cleanupWorkers(); solveButton.disabled = false; solveButton.textContent = "Solve challenges"; }; workerPool.push(worker); } workerPool.forEach(startNextTask); updateProgress(); } catch (error) { progressDiv.textContent = `Status: Failed to create workers: ${error.message}`; progressDiv.classList.add("text-danger", "fw-bold"); solveButton.disabled = false; solveButton.textContent = "Solve challenges"; cleanupWorkers(); } });
```
--------------------------------
### Simulating CAP API Responses with Custom Fetch in JavaScript
Source: https://github.com/tiagorangel1/cap/blob/main/widget/test.html
This function intercepts fetch requests to `/api/challenge` and `/api/redeem`, providing mock responses. For `/api/challenge`, it generates a random challenge using `window.crypto.getRandomValues`. For `/api/redeem`, it returns a success token. All other requests are passed to the native `window.fetch`.
```JavaScript
window.CAP_CUSTOM_FETCH = async (url, options) => {\n if (url === "/api/challenge") {\n const browserCrypto = window.crypto;\n return new Response(\n JSON.stringify({\n challenge: Array.from({ length: 5 }, () => [\n Array.from(\n browserCrypto.getRandomValues(new Uint8Array(Math.ceil(32 / 2)))\n )\n .map((byte) => byte.toString(16).padStart(2, "0"))\n .join("")\n .slice(0, 32),\n Array.from(\n browserCrypto.getRandomValues(new Uint8Array(Math.ceil(2 / 2)))\n )\n .map((byte) => byte.toString(16).padStart(2, "0"))\n .join("")\n .slice(0, 4),\n ]),\n token: "",\n expires: new Date().getTime() + 6000 * 100,\n }),\n {\n status: 200,\n headers: { "Content-Type": "application/json" },\n }\n );\n }\n if (url === "/api/redeem") {\n return new Response(\n JSON.stringify({\n success: true,\n token: "ok",\n expires: new Date().getTime() + 1000 * 60,\n }),\n {\n status: 200,\n headers: { "Content-Type": "application/json" },\n }\n );\n }\n return await window.fetch(url, options);\n};
```
--------------------------------
### redeemChallenge Method Arguments (JSON)
Source: https://github.com/tiagorangel1/cap/blob/main/docs/guide/server.md
Outlines the required arguments for the `cap.redeemChallenge` method, which are the `token` to be redeemed and its corresponding `solutions`.
```json
{
"token": "",
"solutions": []
}
```
--------------------------------
### Implementing CAP.js with Express in JavaScript
Source: https://github.com/tiagorangel1/cap/blob/main/docs/guide/server.md
Demonstrates how to integrate `@cap.js/server` with the Express framework to create `/api/challenge` and `/api/redeem` endpoints for CAPTCHA challenge generation and redemption.
```javascript
import express from "express";
import Cap from "@cap.js/server";
const app = express();
app.use(express.json());
const cap = new Cap({
tokens_store_path: ".data/tokensList.json",
});
app.post("/api/challenge", (req, res) => {
res.json(cap.createChallenge());
});
app.post("/api/redeem", async (req, res) => {
const { token, solutions } = req.body;
if (!token || !solutions) {
return res.status(400).json({ success: false });
}
res.json(await cap.redeemChallenge({ token, solutions }));
});
app.listen(3000, () => {
console.log("Listening on port 3000");
});
```
--------------------------------
### Configuring Cap Widget API Endpoint
Source: https://github.com/tiagorangel1/cap/blob/main/docs/guide/standalone.md
This template shows the required API endpoint format for configuring the Cap widget to use a self-hosted Cap Standalone server. It specifies the instance URL and the key ID, enabling the widget to communicate with your custom backend.
```text
https:////api/
```
--------------------------------
### Managing UI State and Worker Pool in JavaScript
Source: https://github.com/tiagorangel1/cap/blob/main/wasm/test/browser.html
This collection of functions handles the dynamic updates of the user interface, manages the lifecycle of Web Workers, and assigns new challenges. It includes functions to update progress text, display individual challenge results (success or error), terminate and clean up workers, and reset the UI to its initial state.
```JavaScript
let workerPool = [];
let workerBlobUrl = null;
let nextChallengeIndex = 0;
let challengesProcessed = 0;
let allResults = [];
let startTime = 0;
function updateProgress() {
const elapsed = ((performance.now() - startTime) / 1000).toFixed(2);
progressDiv.textContent = `Status: Processing... ${challengesProcessed}/${challenges.length} challenges complete. Elapsed: ${elapsed}s`;
progressDiv.classList.remove("text-danger", "fw-bold");
}
function displayResult(data) {
const item = document.createElement("li");
item.classList.add("list-group-item");
if (data.error) {
item.classList.add("list-group-item-danger");
item.innerHTML = `Challenge #${
data.challengeIndex === -1 ? "??" : data.challengeIndex + 1
} errored ${
data.salt ? `${data.salt}:${data.target}` : ""
}
${
data.error
}`;
} else {
item.classList.add("list-group-item-success");
item.innerHTML = `Challenge #${
data.challengeIndex + 1
} solved with nonce ${
data.nonce
}<
```
--------------------------------
### Interacting with CAP Widget in JavaScript
Source: https://github.com/tiagorangel1/cap/blob/main/widget/test.html
This code selects a `cap-widget` element from the DOM, initiates its `solve` method, and adds an event listener for the `solve` event. Upon successful or failed solving, it makes a fetch request to `/solved` or `/failed` respectively, based on the returned token.
```JavaScript
const widget = document.querySelector("cap-widget");\nwidget.solve();\nwidget.addEventListener("solve", function (e) {\n fetch(e.detail.token === "ok" ? "/solved" : "/failed");\n});
```
--------------------------------
### Initializing DOM Elements and Global Variables (JavaScript)
Source: https://github.com/tiagorangel1/cap/blob/main/standalone/public/test.html
This snippet selects various DOM elements by their classes and IDs, and initializes global variables used throughout the application. These variables store references to UI components, chart data, challenge state, and timing information, preparing the application for user interaction and challenge processing.
```JavaScript
const logsElement = document.querySelector(".logs");
const keyIdInput = document.getElementById("keyIdInput");
const secretKeyInput = document.getElementById("secretKeyInput");
const startButton = document.getElementById("startButton");
const ctx = document.querySelector("#progressChart").getContext("2d");
let progressTimings = {};
let chartInstance = null;
let cap = null;
let startTime = 0;
```
--------------------------------
### Configuring Hono Checkpoint Middleware
Source: https://github.com/tiagorangel1/cap/blob/main/docs/guide/middleware/hono.md
This JavaScript code demonstrates how to initialize and configure the @cap.js/checkpoint-hono middleware within a Hono application. It sets parameters like token validity, storage path, token size, and the path to the verification template, then applies it to all routes.
```javascript
import { Hono } from "hono";
import { serveStatic } from "hono/bun";
import { capCheckpoint } from "@cap.js/checkpoint-hono";
const app = new Hono();
app.use(
"*",
capCheckpoint({
token_validity_hours: 32, // how long the token is valid for
tokens_store_path: ".data/tokensList.json",
token_size: 16, // token size in bytes
verification_template_path: join(
dirname(fileURLToPath(import.meta.url)),
"./index.html"
),
})
);
app.get("/", (c) => c.text("Hello Hono!"));
export default app;
```
--------------------------------
### Defining Web Worker Logic for PoW Solving in JavaScript
Source: https://github.com/tiagorangel1/cap/blob/main/wasm/test/browser.html
This snippet defines a self-contained JavaScript function that serves as the template for Web Workers. It imports a WebAssembly module for Proof-of-Work computation, sets up message handlers to receive challenge data, and sends back results or errors to the main thread. The function is converted to a string to be used as a Blob URL for worker creation.
```JavaScript
const workerCodeTemplate = (() => {
const baseURL = "${baseURL}";
// const relativeWasmWrapperPath = "https://cdn.jsdelivr.net/npm/@cap.js/wasm@0.0.4/browser/cap_wasm.min.js";
const relativeWasmWrapperPath = "../src/browser/cap_wasm.js";
let solve_pow_function = null;
let initError = null;
let initPromise = null;
const absoluteWasmWrapperUrl = new URL(relativeWasmWrapperPath, baseURL)
.href;
initPromise = import(absoluteWasmWrapperUrl)
.then((wasmModule) => {
return wasmModule.default().then((instance) => {
solve_pow_function = (
instance && instance.exports ? instance.exports : wasmModule
).solve_pow;
});
})
.catch((error) => {
console.error("[worker] setup failed", error);
self.postMessage({
error: `Worker setup failed: ${error.message || error}`,
});
});
self.onmessage = async (event) => {
const { salt, target, challengeIndex } = event.data;
try {
if (initPromise) {
await initPromise;
}
const startTime = performance.now();
const nonce = solve_pow_function(salt, target);
const endTime = performance.now();
const duration = (endTime - startTime).toFixed(2);
self.postMessage({
challengeIndex: challengeIndex,
salt: salt,
target: target,
nonce: Number(nonce),
durationMs: duration,
});
} catch (error) {
console.error(`[worker] (job #${challengeIndex})`, error);
self.postMessage({
challengeIndex: challengeIndex,
salt: salt,
target: target,
error: `Execution failed: ${error.message || error}`,
});
}
};
self.onerror = (error) => {
self.postMessage({
error: `Error: ${error.message || error}`,
});
};
})
.toString()
.replace("() => {", "")
.slice(0, -1);
```
--------------------------------
### Cap System Interaction Flow - Mermaid Diagram
Source: https://github.com/tiagorangel1/cap/blob/main/docs/guide/workings.md
This Mermaid sequence diagram illustrates the technical flow of how the Cap system works, from user interaction to token redemption. It details the communication between the User, Widget, WASM Solver, and Server, showing the steps for requesting a challenge, distributing work, solving Proof-of-Work (PoW) challenges, submitting solutions, and validating tokens for later requests.
```Mermaid
sequenceDiagram
participant User
participant W as Widget
participant WW as WASM Solver
participant S as Server
User->>W: Interaction
W->>S: Request challenge
activate S
S->>S: Generate challenge
S-->>W: Return challenge
deactivate S
W->>WW: Distribute work
Note over WW: for each challenge
activate WW
WW->>WW: Solve SHA-256 PoW
WW-->>W: Return solutions
deactivate WW
W->>S: Submit solutions
activate S
S->>S: Verify solutions
S-->>W: Return token
deactivate S
W-->>User: Send token
Note over User,S: Later requests
# Assuming user interaction triggers the widget for later requests
# User->>W: (Initiate later request)
W->>S: Send token with request
activate S
S->>S: Validate token
Note over S: Success!
deactivate S
```
--------------------------------
### Implementing Cap Widget Verification Logic (JavaScript)
Source: https://github.com/tiagorangel1/cap/blob/main/checkpoints/express/index.html
This JavaScript code integrates the 'Cap' widget for human verification. It defines a custom fetch function (`CAP_CUSTOM_FETCH`) to intercept requests to `/challenge` and provides a mock response. It also listens for the 'solve' event from the `cap-widget`, updates the page status, sets a clearance cookie with a specified validity, and reloads the page upon successful verification.
```JavaScript
window.CAP_CUSTOM_FETCH = function (url, options) { console.log(url); if (url.endsWith("/challenge")) { return { json: () => { return window.CAP_CHALLENGE; }, }; } return fetch(url, options); }; const widget = document.querySelector("cap-widget"); widget.addEventListener("solve", (event) => { document.querySelector("h2").innerText = "Continuing to your destination..."; document.cookie = `__cap_clearance=${ event.detail.token }; path=/; max-age=${ window.TOKEN_VALIDITY_HOURS * 3_600 }; SameSite=Strict`; setTimeout(() => { location.reload(); }, 300); }); widget.solve();
```
--------------------------------
### Parsing @cap.js/cli Output (JavaScript)
Source: https://github.com/tiagorangel1/cap/blob/main/docs/guide/cli.md
This JavaScript code demonstrates how to parse the newline-separated `salt:target:nonce` string output from the `@cap.js/cli` tool into a structured array of arrays, making it easier to process programmatically.
```javascript
const input = "e455cea65e98b:dceb:9100\nfb8d25f6abac:93f1:76570";
console.log(input.split("\n").map((l) => l.split(":")));
```
--------------------------------
### Cap Constructor Arguments - JSON
Source: https://github.com/tiagorangel1/cap/blob/main/docs/guide/invisible.md
This JSON snippet defines the configuration arguments for the `new Cap()` constructor. It includes `apiEndpoint` for specifying the API endpoint, similar to the `data-cap-api-endpoint` attribute, and `workers` to set the number of worker threads, defaulting to `navigator.hardwareConcurrency` or 8. These arguments customize the Cap instance's behavior upon creation.
```json
{
apiEndpoint: ..., // api endpoint, similar to the widget `data-cap-api-endpoint` attribute
workers: navigator.hardwareConcurrency || 8 // number of worker threads to use
}
```
--------------------------------
### createChallenge Method Arguments (JSON)
Source: https://github.com/tiagorangel1/cap/blob/main/docs/guide/server.md
Specifies the arguments for the `cap.createChallenge` method, controlling challenge properties like the number of challenges, size, difficulty, and expiration time in milliseconds.
```json
{
"challengeCount": 18,
"challengeSize": 32,
"challengeDifficulty": 4,
"expiresMs": 600000
}
```
--------------------------------
### Handling Cap Widget Solve Event in JavaScript
Source: https://github.com/tiagorangel1/cap/blob/main/docs/guide/widget.md
This JavaScript code demonstrates how to listen for the `solve` event triggered by the ``. When the widget successfully generates a token, this event fires, allowing you to capture the token from `e.detail.token` and process it as needed.
```JavaScript
const widget = document.querySelector("#cap");
widget.addEventListener("solve", function (e) {
const token = e.detail.token;
// Handle the token as needed
});
```
--------------------------------
### Styling Basic Page Layout with CSS
Source: https://github.com/tiagorangel1/cap/blob/main/demo/checkpoint/elysia/success.html
This CSS snippet defines the foundational styling for a web page, ensuring content is centered both vertically and horizontally. It sets global font properties, specific styles for headings (h1), paragraphs (p), and buttons, providing a consistent visual theme for the success page.
```CSS
body { margin: 0px; padding: 0px; display: flex; align-items: center; justify-content: center; flex-direction: column; height: 100vh; font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Open Sans", "Helvetica Neue", sans-serif; text-align: center; } h1 { font-size: 4em; margin-bottom: 0px; } p { max-width: 250px; line-height: 1.4; } button { background-color: transparent; font-weight: 500; border: none; cursor: pointer; font-family: inherit; font-size: 16px; }
```
--------------------------------
### Importing Cap Floating Mode Script from Standalone Server (HTML)
Source: https://github.com/tiagorangel1/cap/blob/main/docs/guide/floating.md
This snippet provides an alternative method for importing the Cap widget and floating mode scripts, specifically when they are hosted on a standalone server. This is useful for environments where CDN access might be restricted or a custom hosting solution is preferred.
```HTML
```