DEV Community

uratmangun
uratmangun

Posted on

8 5 3 2 4

Make Cursor Composer Smarter with Bright Web Scraping Capabilities

This is a submission for the Bright Data Web Scraping Challenge: Most Creative Use of Web Data for AI Models

What I Built

IDE nowadays like cursor has an AI agent to help us coding faster and easier but the cons of ai agent in this case composer, it has limited capabilities, for example chat in cursor has capabilities of searching web, and if we put url into it, it will automatically scrape that web and answer based on the scraped web, the ai agent in cursor named composer doesnt have that capabilities. This is chat feature in cursor below, as you can see there are web search

Image description

But if you go to cursor composer it doesnt have that, especially the agent one,

Image description

So my goal here is creating a web scraper and web searcher using bright and gemini openai compatible model to make cursor composer more smarter with functionality like web search and web scrape

Demo

Web Scraper

A powerful web scraping utility built with Playwright that can extract content and links from websites.

Prerequisites

  • Node.js 18+
  • pnpm (recommended) or bun

Installation & Usage

You can use this tool in two ways:

1. Using npx (Recommended)

Run directly without installation using npx:

npx @uratmangun/scraper-tool show-content <url>
# or
npx @uratmangun/scraper-tool search "<query>"
Enter fullscreen mode Exit fullscreen mode

2. Local Installation

  1. Install dependencies:
pnpm install
# or
bun install
Enter fullscreen mode Exit fullscreen mode
  1. Set up environment variables:
cp .env.example .env.local
Enter fullscreen mode Exit fullscreen mode

Then edit .env.local and set your BRIGHT_PLAYWRIGHT_URL for the Playwright CDP connection.

Commands

View Content

# Using npx
npx @uratmangun/scraper-tool show-content <html|text> <url>

# Using local installation
pnpm run scrape show-content <html|text> <url>
Enter fullscreen mode Exit fullscreen mode

Example:

npx @uratmangun/scraper-tool show-content html https://example.com
# or
npx @uratmangun/scraper-tool show-content text https://example.com
Enter fullscreen mode Exit fullscreen mode

This will display either the HTML or plain text content of the specified URL…

How I Used Bright Data

So in order to do that i'm gonna make a script first to use bright api web scraper:

Bright Data - Web Data Platform

World's largest proxy service with a residential proxy network of 72M IPs worldwide and proxy management interface for zero coding. Start a 7-day free trial »

favicon brightdata.com

Let's create script called scrape.mjs with script below:

import { chromium } from 'playwright';
import { fileURLToPath } from 'url';
import dotenv from 'dotenv';
dotenv.config({ path: '.env.local' });
/**
* Scrapes content from a given URL using Playwright with CDP connection
* @param {string} url - The URL to scrape
* @returns {Promise<string>} - The scraped content
*/
export async function scrapeUrl(url) {
if (!process.env.BRIGHT_PLAYWRIGHT_URL) {
throw new Error('BRIGHT_PLAYWRIGHT_URL environment variable is not set');
}
const browser = await chromium.connectOverCDP(process.env.BRIGHT_PLAYWRIGHT_URL);
try {
const context = await browser.newContext();
const page = await context.newPage();
await page.goto(url, { timeout: 60000 });
await page.waitForLoadState('networkidle');
// Get HTML content
const html = await page.content();
return { html };
} catch (error) {
console.error('Error during scraping:', error);
throw error;
} finally {
await browser.close();
}
}
/**
* Shows the HTML content of a given URL
* @param {string} url - The URL to show content from
* @returns {Promise<void>}
*/
async function showContent(url) {
try {
const { html } = await scrapeUrl(url);
console.log(html);
} catch (error) {
console.error('Error showing content:', error);
throw error;
}
}
// Main function to handle command line usage
async function main() {
const [command, ...args] = process.argv.slice(2);
if (!command || !args.length) {
console.error('Please provide a URL to scrape.');
console.error('Usage: pnpm run scrape show-content <url>');
process.exit(1);
}
try {
if (command !== 'show-content') {
console.error('Invalid command. Only "show-content" is supported.');
console.error('Usage: pnpm run scrape show-content <url>');
process.exit(1);
}
await showContent(args[0]);
} catch (error) {
console.error('Operation failed:', error);
process.exit(1);
}
}
// Run main function if this file is run directly
if (process.argv[1] === fileURLToPath(import.meta.url)) {
main();
}
view raw scrape.mjs hosted with ❤ by GitHub

You can use it like this:

pnpm run scrape show-content <url>
Enter fullscreen mode Exit fullscreen mode

It will show the HTML content of a URL like this:

...
  <div id="js-global-screen-reader-notice" class="sr-only mt-n1" aria-live="polite" aria-atomic="true"></div>
    <div id="js-global-screen-reader-notice-assertive" class="sr-only mt-n1" aria-live="assertive" aria-atomic="true"></div>

Enter fullscreen mode Exit fullscreen mode

So this is good, but it is still unstructured , before we make it structured data that can be understood by both machine and human, we gonna make a search using web scraper of bright as well so create this script for search.mjs:

import { chromium } from 'playwright';
import dotenv from 'dotenv';
// Load environment variables
dotenv.config({ path: '.env.local' });
async function getGoogleHtml(query = '', baseUrl = 'https://www.google.com/search?q=') {
const browser = await chromium.connectOverCDP(process.env.BRIGHT_PLAYWRIGHT_URL);
const searchUrl = baseUrl + encodeURIComponent(query);
try {
const context = await browser.newContext();
const page = await context.newPage();
// Navigate to the URL
await page.goto(searchUrl);
// Get the page content
const content = await page.content();
return content;
} catch (error) {
console.error('Error fetching page:', error);
throw error;
} finally {
await browser.close();
}
}
// Example usage
async function main() {
try {
const query = process.argv[2];
if (!query) {
console.error('Please provide a search query. Usage: pnpm run search <query>');
process.exit(1);
}
const html = await getGoogleHtml(query);
console.log(html);
} catch (error) {
console.error('Main error:', error);
}
}
// Run the main function if this file is run directly
if (process.argv[1] === new URL(import.meta.url).pathname) {
main();
}
export { getGoogleHtml };
view raw search.mjs hosted with ❤ by GitHub

You can run this using pnpm run search <your query> and will show something like this:

...
AAAAAEAACgIQAAAAAACgAAAAAAAAAAAAAABIAAAAAAAAECAABEJCAAAEAAAAAMACAAAILAABAgAEAAAAAAAEAAgAIEAEYL__OAAAAAAAAAAAAAQCABEAAAAAAHABABAE0d4AAQAAAAgAAAAMAAAAQAAAAAAAAAUAAAAAAAAAAAQAAAAAAAAAAAAAAAABAPoBAAAAAAAAAAAAAAACAAAAAABggAIAAvgBAAAAAACAAwAAAAABAQAAOAIGIAAAAAAAAAD3AcDjAeGQwgIAAAAAAAAAAAAAAAABSBDMgfQXBCAAAAAAAAAAAAAAAAAAAJAiaOJyAwAC/d=0/dg=0/br=1/rs=ACT90oEbXjTDEsqDs2o3NzHTmzVZxjp5ng/m=sy27z,sy28k,sy27w,sy29c,sy28x,sy28v,sy288,sy280,M0O4le?xjs=s4" nonce=""></script></body></html>
Enter fullscreen mode Exit fullscreen mode

Again this is still unstructured now we need to parse all of this using AI, i'm using gemini to parse this content to more parseable format like JSON, we gonna extract the link out of the search unstructured data first, to do that let's make some script to consume that unstructured data and convert it to JSON using AI.

import OpenAI from "openai"
import dotenv from 'dotenv';
import { zodResponseFormat } from "openai/helpers/zod";
import { z } from "zod";
dotenv.config({ path: '.env.local' });
const openai = new OpenAI({
baseURL: "https://generativelanguage.googleapis.com/v1beta/openai/",
apiKey: process.env.GEMINI_API_KEY
})
const SearchResult = z.array(
z.object({
title: z.string(),
url: z.string(),
description: z.string(),
})
);
export async function searchParser(content) {
const completion = await openai.chat.completions.create({
model: "gemini-2.0-flash-exp",
response_format: zodResponseFormat(SearchResult, "search_result"),
messages: [
{
role: "system",
content: "You're search results parser. You're given a search results HTML page and you're tasked with parsing the results and returning a json array of objects with the following fields: title, url, description."
},
{role: "user", content}
]
})
return completion
}

Now when you run this you will get something like this:

{
  content: '[\n' +
    '    {\n' +
    '        "description": "Order Panda Express | A Fast Casual Chinese Restaurant ...",\n' +
    '        "title": "Order Panda Express | A Fast Casual Chinese Restaurant ...",\n' +
    '        "url": "https://www.pandaexpress.com/"\n' +
    '    },\n' +
    '    {\n' +
    `        "description": "The only natural habitat for giant pandas in the world is located in southwestern China. Combined with the requirement that all cubs must return to China this creates the sense that pandas belong in and to China, and a country can only receive them if they have good relations with the People's Republic.",\n` +
    `        "title": "The Giant Pandas Have Left the National Zoo. What's Next for U.S. ...",\n` +
    `         "url": "https://www.georgetown.edu/news/the-giant-pandas-have-left-the-national-zoo-whats-next-for-u-s-china-relations/#:~:text=The%20only%20natural%20habitat%20for,relations%20with%20the%20People's%20Republic."\n` +
    '    },\n' +
    '    {\n' +
    '        "description": "Red pandas are the only living members of their taxonomic family, Ailuridae, while giant pandas are in the bear family, Ursidae.",\n' +
    '        "title": "Is a Red Panda a Bear? And More Red Panda Facts ...",\n' +
    '        "url": "https://nationalzoo.si.edu/animals/news/red-panda-bear-and-more-red-panda-facts"\n' +
    '    },\n' +
    '  {\n' +
    '        "description": "Giant pandas live in a few mountain ranges in south central China, in Sichuan, Shaanxi and Gansu provinces. They once lived in lowland areas, but farming, forest clearing and other development now restrict giant pandas to the mountains.",\n' +
    '        "title": "Giant panda",\n' +
    '        "url": "https://nationalzoo.si.edu/animals/giant-panda#:~:text=Giant%20pandas%20live%20in%20a,giant%20pandas%20to%20the%20mountains."\n' +
    '    },\n' +
    '     {\n' +
    `        "description": "Pandas have excellent camouflage for their habitat. The giant panda's distinct black-and-white markings have two functions: camouflage and communication. Most of the panda - its face, neck, belly, rump - is white to help it hide in snowy habitats. The arms and legs are black, helping it to hide in shade.",\n` +
    '        "title": "Top 10 facts about Pandas - WWF",\n' +
    '        "url": "https://www.wwf.org.uk/learn/fascinating-facts/pandas#:~:text=Pandas%20have%20excellent%20camouflage%20for,it%20to%20hide%20in%20shade."\n' +
    '    },\n' +
    '     {\n' +
    '        "description": "The giant panda (Ailuropoda melanoleuca), also known as the panda bear or simply panda, is a bear species endemic to China. It is characterised by its white coat with black patches around the eyes, ears, legs and shoulders. Its body is rotund; adult individuals weigh 100 to 115 kg and are typically 1.2 to 1.9 m long.",\n' +
    '        "title": "Giant panda",\n' +
    '        "url": "https://en.wikipedia.org/wiki/Giant_panda"\n' +
    '    },\n' +
    '   {\n' +
    `        "description": "The giant panda is the rarest member of the bear family and among the world's most threatened animals. Learn about WWF's giant panda conservation efforts.",\n` +
    '        "title": "Giant Panda | Species | WWF",\n' +
    '        "url": "https://www.worldwildlife.org/species/giant-panda"\n' +
    '    },\n' +
    '      {\n' +
    '        "description": "Panda Security antivirus: tailor-made computer security solutions. All our expertise to protect and simplify your life online.",\n' +
    '          "title": "Panda Security | Official Website",\n' +
    '        "url": "https://www.pandasecurity.com/"\n' +
    '    }\n' +
    ']',
  role: 'assistant'
}
Enter fullscreen mode Exit fullscreen mode

The parsed html result. Now we need to put this all into one file so that we can run this globally so composer can use it to gain more knowledge using search engine. I create scrape-or-search.mjs file which contain merged version of search.mjs and scrape.mjs that look like below:

import { chromium } from 'playwright';
import { fileURLToPath } from 'url';
import dotenv from 'dotenv';
import { searchParser } from './convert-search.mjs';
dotenv.config({ path: '.env.local' });
/**
* Scrapes content from a given URL using Playwright with CDP connection
* @param {string} url - The URL to scrape
* @param {string} format - The output format ('html' or 'text')
* @returns {Promise<Object>} - The scraped content
*/
async function scrapeUrl(url, format = 'html') {
if (!process.env.BRIGHT_PLAYWRIGHT_URL) {
throw new Error('BRIGHT_PLAYWRIGHT_URL environment variable is not set');
}
const browser = await chromium.connectOverCDP(process.env.BRIGHT_PLAYWRIGHT_URL);
try {
const context = await browser.newContext();
const page = await context.newPage();
await page.goto(url, { timeout: 60000 });
await page.waitForLoadState('networkidle');
if (format === 'text') {
const text = await page.textContent('body');
return { text };
} else {
const html = await page.content();
return { html };
}
} catch (error) {
console.error('Error during scraping:', error);
throw error;
} finally {
await browser.close();
}
}
/**
* Gets Google search results HTML
* @param {string} query - Search query
* @param {string} baseUrl - Base URL for Google search
* @returns {Promise<string>} - HTML content
*/
async function getGoogleHtml(query = '', baseUrl = 'https://www.google.com/search?q=') {
const browser = await chromium.connectOverCDP(process.env.BRIGHT_PLAYWRIGHT_URL);
const searchUrl = baseUrl + encodeURIComponent(query);
try {
const context = await browser.newContext();
const page = await context.newPage();
await page.goto(searchUrl);
const bodyContent = await page.evaluate(() => {
const body = document.body;
if (!body) return '';
// Remove all script tags
const scripts = body.getElementsByTagName('script');
while (scripts.length > 0) {
scripts[0].parentNode.removeChild(scripts[0]);
}
// Remove all style tags
const styles = body.getElementsByTagName('style');
while (styles.length > 0) {
styles[0].parentNode.removeChild(styles[0]);
}
// Remove all noscript tags
const noscripts = body.getElementsByTagName('noscript');
while (noscripts.length > 0) {
noscripts[0].parentNode.removeChild(noscripts[0]);
}
return body.innerHTML;
});
return bodyContent;
} catch (error) {
console.error('Error fetching page:', error);
throw error;
} finally {
await browser.close();
}
}
/**
* Shows the content of a given URL in specified format
* @param {string} format - The output format ('html' or 'text')
* @param {string} url - The URL to show content from
* @returns {Promise<void>}
*/
async function showContent(format, url) {
try {
const result = await scrapeUrl(url, format);
console.log(result[format]);
} catch (error) {
console.error('Error showing content:', error);
throw error;
}
}
/**
* Performs a Google search and shows the results
* @param {string} query - Search query
* @returns {Promise<void>}
*/
async function search(query) {
try {
console.log('Getting google html');
const html = await getGoogleHtml(query);
console.log("parsing html");
const parsed = await searchParser(html);
console.log(parsed.choices[0].message.content);
} catch (error) {
console.error('Search error:', error);
throw error;
}
}
// Main function to handle command line usage
async function main() {
const [command, ...args] = process.argv.slice(2);
if (!command) {
console.error('Please provide a command.');
console.error('Usage:');
console.error(' pnpm run tool scrape <html|text> <url>');
console.error(' pnpm run tool search <query>');
process.exit(1);
}
try {
switch (command.toLowerCase()) {
case 'scrape':
if (args.length < 2) {
console.error('Please provide the format and URL to scrape.');
console.error('Usage: pnpm run tool scrape <html|text> <url>');
process.exit(1);
}
const format = args[0].toLowerCase();
if (format !== 'html' && format !== 'text') {
console.error('Invalid format. Use either "html" or "text".');
process.exit(1);
}
await showContent(format, args[1]);
break;
case 'search':
if (args.length < 1) {
console.error('Please provide a search query.');
console.error('Usage: pnpm run tool search <query>');
process.exit(1);
}
await search(args.join(' '));
break;
default:
console.error('Invalid command. Use either "scrape" or "search".');
console.error('Usage:');
console.error(' pnpm run tool scrape <html|text> <url>');
console.error(' pnpm run tool search <query>');
process.exit(1);
}
} catch (error) {
console.error('Operation failed:', error);
process.exit(1);
}
}
// Run main function if this file is run directly
if (process.argv[1] === fileURLToPath(import.meta.url)) {
main();
}
export { scrapeUrl, getGoogleHtml };

And we also create bin/cli.js to run command line globally later like this npx @uratmangun/scraper-tool search <query> or npx @uratmangun/scraper-tool scrape <text|html> <url>:

#!/usr/bin/env node
import { fileURLToPath } from 'url';
import { dirname, join } from 'path';
import { spawn } from 'child_process';
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
const scriptPath = join(__dirname, '..', 'scripts', 'scrape-or-search.mjs');
const args = process.argv.slice(2);
const child = spawn('node', [scriptPath, ...args], { stdio: 'inherit' });
child.on('error', (error) => {
console.error('Failed to start subprocess:', error);
process.exit(1);
});
child.on('close', (code) => {
process.exit(code);
});
view raw cli.js hosted with ❤ by GitHub

We then need to publish this change our package.json accordingly:

{
"name": "@uratmangun/scraper-tool",
"version": "1.0.0",
"description": "A CLI tool for web scraping and Google search",
"type": "module",
"bin": {
"@uratmangun/scraper-tool": "./bin/cli.js"
},
"files": [
"bin",
"scripts"
],
"scripts": {
"scrape": "node scripts/scrape.mjs",
"search": "node scripts/search.mjs",
"tool": "node scripts/scrape-or-search.mjs"
},
"keywords": [
"scraper",
"cli",
"google-search",
"web-scraping",
"playwright"
],
"author": "uratmangun",
"license": "MIT",
"dependencies": {
"dotenv": "^16.4.7",
"https-proxy-agent": "^7.0.6",
"ky": "^1.7.4",
"openai": "^4.77.0",
"playwright": "^1.49.1",
"request-promise": "^4.2.6",
"zod": "^3.24.1"
}
}
view raw package.json hosted with ❤ by GitHub

To publish this to npm you need to run both of this command respectively:

npm login
npm publish --access public
Enter fullscreen mode Exit fullscreen mode

This way you can use it using npx, now we need to set our global environment variable inside config.fish because i use fish shell, you can ask chatgpt for any other shell, so to set that vi ~/.config/fish/config.fish then we put both of this:

set -gx BRIGHT_PLAYWRIGHT_URL <your url>
set -gx GEMINI_API_KEY <your api key>

Enter fullscreen mode Exit fullscreen mode

Run source ~/.config/fish/config.fish to apply changes immediately, we can then use this globally which mean our cursor composer agent can use that to search the web as well when you run this command npx @uratmangun/scraper-tool search "web scraping tutorials", ok now to test whether or not it's working let's create some project first we will use something called .cursorrules so cursorrules is basically kinda like system message in AI so before the AI do anything he will read the cursorrules, so let's try without cursorrules first, we gonna make an ethereum project with scaffold-eth and frog, so frog is a https://frog.fm/ a framework to create farcaster frame, farcaster frame is relatively new framework so it may not know what it is, i also will add https://docs.airstack.xyz/airstack-docs-and-faqs/farcaster/farcaster-frames/frames-validator , let's create new folder called testing-composer

Image description

So there is nothing in this folder let's ask the cursor composer agent if he understand what is scaffold-eth and build project out of that, this is the page of scaffold-eth https://scaffoldeth.io/ a framework to create ethereum project easily we will just ask agent this one:

Image description

After running it it hallucinates a lot like for example:

Image description

To install frog.fm basically you just need

pnpm add frog
Enter fullscreen mode Exit fullscreen mode

thats it, not package frog.fm, now let's try using web search, let's add .cursorrules:

if you don't know the answer, try to search it on the internet. You can do so by running the following command:
```
npx @uratmangun/scraper-tool search "<query>"
```
Let's say the query is "how to install frog.fm".
```
npx @uratmangun/scraper-tool search "how to install frog.fm"
```
You will get the result in the following format:
```
[
{
"description": "Oct 28, 2024 — Install Frog via your package manager or build from source. Package Manager. Install the required packages. pnpm",
"title": "Installation",
"url": "https://frog.fm/installation"
},
{
"description": "Nov 5, 2024 — Manual Installation. You can install Frog in an existing project, or start from scratch, by installing Frog as a dependency.",
"title": "Getting started",
"url": "https://frog.fm/getting-started"
},
{
"description": "In this video we're going to take a look at frog. FM which is a new framework for building forecaster frames.",
"title": "Frog.fm Tutorial - Easy Framework For Farcaster Frames",
"url": "https://www.youtube.com/watch?v=zz_q_YkeWIk"
},
{
"description": "Oct 28, 2024 — Manual Installation · Install Next.js · Build your Frame · Add Handlers · Setup Devtools · Add Scripts to package.json · Navigate to Frame · Bonus: ...",
"title": "Next.js",
"url": "https://frog.fm/platforms/next"
},
{
"description": "Nov 5, 2024 — Global Install. First, install frog globally with your package manager: npm pnpm yarn bun. npm. npm i -g frog. Then, run the frog command to...",
"title": "Devtools",
"url": "https://frog.fm/concepts/devtools"
},
{
"description": "Oct 28, 2024 — Manual Installation · Install Vercel · Build your Frame · Add Vercel Handlers · Setup Devtools · Add Scripts to package.json · Navigate to Frame.",
"title": "Vercel Serverless",
"url": "https://frog.fm/platforms/vercel"
},
{
"description": "Nov 5, 2024 — Setup Devtools. Add Frog Devtools after all frames are defined. This way the devtools can automatically discover all your frames.",
"title": "Node.js",
"url": "https://frog.fm/platforms/node"
},
{
"description": "Nov 5, 2024 — Frog is built on top of Hono (a fast & lightweight Web Framework), extended with a first-class API for Farcaster Frames.",
"title": "Overview",
"url": "https://frog.fm/concepts/overview"
},
{
"description": "In this article, you will learn how to create a gasless Farcaster NFT mint frame with Frog.fm and Kriptonio. ... After that, let's install the Kriptonio SDK.",
"title": "How to Create a Gasless Farcaster NFT Mint Frame with Frog ...",
"url": "https://docs.kriptonio.com/blog/farcaster-gasless-nft-frame/"
},
{
"description": "Request for the instructions to include the proper snippet for Vercel integration in Hono. Docs: https://frog.fm/platforms/vercel#setup-devtools",
"title": "Manual Vercel Installation Instructions for Hono Support #252",
"url": "https://github.com/wevm/frog/discussions/252"
}
]
```
Pick one of the results you think is the most relevant to the user's query. for example you pick the first one.
```
https://frog.fm/installation
```
If you want to open the link, you can do so by running the following command:
```
npx @uratmangun/scraper-tool scrape <html|text> <url>
```
For example, if you want to get the content of `https://frog.fm/installation` as a html, you can do so by running the following command:
```
npx @uratmangun/scraper-tool scrape html "https://frog.fm/installation"
```
You will get the content in the following format:
```
<!DOCTYPE html><html lang="en"><head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="/initializeTheme.iife.js"></script>
<title>Installation – Frog</title>
<meta data-react-helmet="true" property="og:type" content="website"><meta data-react-helmet="true" property="og:title" content="Installation"><meta data-react-helmet="true" property="og:image" content="/og.png"><meta data-react-helmet="true" name="twitter:card" content="summary_large_image"><meta data-react-helmet="true" property="twitter:image" content="/og.png">
<link data-react-helmet="true" rel="icon" href="/icon.png" type="image/png">
<script src="https://cdn.usefathom.com/script.js" data-site="MYUAWCWK" defer=""></script>
<script type="module" crossorigin="" src="/assets/index-Bn7ose9h.js"></script>
<link rel="stylesheet" crossorigin="" href="/assets/style-0l4RcWdq.css">
</head>
<body>
<div id="app"><div class="vocs_DocsLayout" data-layout="docs" style="--vocs_Banner_bannerHeight: 32px;"><a class="vocs_SkipLink vocs_utils_visuallyHidden" href="/installation#vocs-content">Skip to content</a><div class="vocs_Banner"><div class="vocs_Banner_inner"><div class="vocs_Banner_content"><p>Introducing <a href="/concepts/signatures">✍️ Signatures</a> and <a href="/concepts/composer-actions">🖥️ Composer Actions</a></p></div><button class="vocs_Banner_closeButton" type="button"><svg width="14" height="14" viewBox="0 0 15 15" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M12.8536 2.85355C13.0488 2.65829 13.0488 2.34171 12.8536 2.14645C12.6583 1.95118 12.3417 1.95118 12.1464 2.14645L7.5 6.79289L2.85355 2.14645C2.65829 1.95118 2.34171 1.95118 2.14645 2.14645C1.95118 2.34171 1.95118 2.65829 2.14645 2.85355L6.79289 7.5L2.14645 12.1464C1.95118 12.3417 1.95118 12.6583 2.14645 12.8536C2.34171 13.0488 2.65829 13.0488 2.85355 12.8536L7.5 8.20711L12.1464 12.8536C12.3417 13.0488 12.6583 13.0488 12.8536 12.8536C13.0488 12.6583 13.0488 12.3417 12.8536 12.1464L8.20711 7.5L12.8536 2.85355Z" fill="currentColor" fill-rule="evenodd" clip-rule="evenodd"></path></svg></button></div></div><div class="vocs_DocsLayout_gutterLeft"><aside class="vocs_Sidebar vocs_DocsLayout_sidebar"><div class="vocs_Sidebar_logoWrapper"><div class="vocs_Sidebar_logo"><a style="align-items:center;display:flex;height:100%" href="/"><img alt="Logo" class="vocs_NavLogo_logoImage vocs_Logo vocs_Logo_logoDark" src="/logo-dark.svg"><img alt="Logo" class="vocs_NavLogo_logoImage vocs_Logo vocs_Logo_logoLight" src="/logo-light.svg"></a></div><div class="vocs_Sidebar_divider"></div></div><nav class="vocs_Sidebar_navigation"><div class="vocs_Sidebar_group"><section class="vocs_Sidebar_section"><div class="vocs_Sidebar_items"><a data-active="true" class="vocs_Sidebar_item" href="/installation">Installation</a><a data-active="false" class="vocs_Sidebar_item" href="/getting-started">Getting Started</a><a data-active="false" class="vocs_Sidebar_item" href="/ui">FrogUI</a></div></section><section class="vocs_Sidebar_section vocs_Sidebar_level"><div class="vocs_Sidebar_sectionHeader"><div class="vocs_Sidebar_sectionTitle">Concepts</div></div><div class="vocs_Sidebar_items"><a data-active="false" class="vocs_Sidebar_item" href="/concepts/overview">Overview</a><a data-active="false" class="vocs_Sidebar_item" href="/concepts/routing">Routing</a><a data-active="false" class="vocs_Sidebar_item" href="/concepts/images-intents">Images &amp; Intents</a><a data-active="false" class="vocs_Sidebar_item" href="/concepts/image-handler">Image Handler</a><a data-active="false" class="vocs_Sidebar_item" href="/concepts/actions">Connecting Frames (Actions)</a><a data-active="false" class="vocs_Sidebar_item" href="/concepts/browser-redirects">Browser Redirects</a><a data-active="false" class="vocs_Sidebar_item" href="/concepts/state-management">State Management</a><a data-active="false" class="vocs_Sidebar_item" href="/concepts/securing-frames">Securing Frames</a><a data-active="false" class="vocs_Sidebar_item" href="/concepts/deployment">Deployment</a><a data-active="false" class="vocs_Sidebar_item" href="/concepts/devtools">Devtools</a><a data-active="false" class="vocs_Sidebar_item" href="/concepts/middleware">Middleware</a><a data-active="false" class="vocs_Sidebar_item" href="/concepts/transactions">Transactions</a><a data-active="false" class="vocs_Sidebar_item" href="/concepts/signatures">Signatures</a><a data-active="false" class="vocs_Sidebar_item" href="/concepts/cast-actions">Cast Actions</a><a data-active="false" class="vocs_Sidebar_item" href="/concepts/client-side-helpers">Client-Side Helpers</a><a data-active="false" class="vocs_Sidebar_item" href="/concepts/composer-actions">Composer Actions</a><a data-active="false" class="vocs_Sidebar_item" href="/concepts/multi-step-cast-actions">Multi-step Cast Actions</a><a data-active="false" class="vocs_Sidebar_item" href="/concepts/mini-apps">Mini-Apps</a><a data-active="false" class="vocs_Sidebar_item" href="/concepts/error-handling">Error Handling</a></div></section><section class="vocs_Sidebar_section vocs_Sidebar_level"><div class="vocs_Sidebar_sectionHeader"><div class="vocs_Sidebar_sectionTitle">Platforms</div></div><div class="vocs_Sidebar_items"><a data-active="false" class="vocs_Sidebar_item" href="/platforms/bun">Bun</a><a data-active="false" class="vocs_Sidebar_item" href="/platforms/cloudflare-workers">Cloudflare Workers</a><a data-active="false" class="vocs_Sidebar_item" href="/platforms/next">Next.js</a><a data-active="false" class="vocs_Sidebar_item" href="/platforms/node">Node.js</a><a data-active="false" class="vocs_Sidebar_item" href="/platforms/vercel">Vercel</a></div></section><section class="vocs_Sidebar_section vocs_Sidebar_level"><div class="vocs_Sidebar_sectionHeader"><div class="vocs_Sidebar_sectionTitle">Hubs</div></div><div class="vocs_Sidebar_items"><a data-active="false" class="vocs_Sidebar_item" href="/hubs/neynar">Neynar</a><a data-active="false" class="vocs_Sidebar_item" href="/hubs/pinata">Pinata</a></div></section><section class="vocs_Sidebar_section vocs_Sidebar_level"><div class="vocs_Sidebar_sectionHeader"><div class="vocs_Sidebar_sectionTitle">Intent Reference</div></div><div class="vocs_Sidebar_items"><a data-active="false" class="vocs_Sidebar_item" href="/intents/button">Button</a><a data-active="false" class="vocs_Sidebar_item" href="/intents/button-link">Button.Link</a><a data-active="false" class="vocs_Sidebar_item" href="/intents/button-mint">Button.Mint</a><a data-active="false" class="vocs_Sidebar_item" href="/intents/button-redirect">Button.Redirect</a><a data-active="false" class="vocs_Sidebar_item" href="/intents/button-reset">Button.Reset</a><a data-active="false" class="vocs_Sidebar_item" href="/intents/button-transaction">Button.Transaction</a><a data-active="false" class="vocs_Sidebar_item" href="/intents/textinput">TextInput</a></div></section><section class="vocs_Sidebar_section vocs_Sidebar_level"><div class="vocs_Sidebar_sectionHeader"><div class="vocs_Sidebar_sectionTitle">Frog Reference</div></div><div class="vocs_Sidebar_items"><a data-active="false" class="vocs_Sidebar_item" href="/reference/frog">Frog</a><section class="vocs_Sidebar_section"><div class="vocs_Sidebar_sectionHeader"><a data-active="false" class="vocs_Sidebar_item" href="/reference/frog-cast-action">Frog.castAction</a></div><div class="vocs_Sidebar_items vocs_Sidebar_levelInset"><a data-active="false" class="vocs_Sidebar_item" href="/reference/frog-cast-action-context">Context</a><a data-active="false" class="vocs_Sidebar_item" href="/reference/frog-cast-action-response">Response</a></div></section><section class="vocs_Sidebar_section"><div class="vocs_Sidebar_sectionHeader"><a data-active="false" class="vocs_Sidebar_item" href="/reference/frog-composer-action">Frog.composerAction</a></div><div class="vocs_Sidebar_items vocs_Sidebar_levelInset"><a data-active="false" class="vocs_Sidebar_item" href="/reference/frog-composer-action-context">Context</a><a data-active="false" class="vocs_Sidebar_item" href="/reference/frog-composer-action-response">Response</a></div></section><section class="vocs_Sidebar_section"><div class="vocs_Sidebar_sectionHeader"><a data-active="false" class="vocs_Sidebar_item" href="/reference/frog-frame">Frog.frame</a></div><div class="vocs_Sidebar_items vocs_Sidebar_levelInset"><a data-active="false" class="vocs_Sidebar_item" href="/reference/frog-frame-context">Context</a><a data-active="false" class="vocs_Sidebar_item" href="/reference/frog-frame-response">Response</a></div></section><section class="vocs_Sidebar_section"><div class="vocs_Sidebar_sectionHeader"><a data-active="false" class="vocs_Sidebar_item" href="/reference/frog-image">Frog.image</a></div><div class="vocs_Sidebar_items vocs_Sidebar_levelInset"><a data-active="false" class="vocs_Sidebar_item" href="/reference/frog-image-context">Context</a><a data-active="false" class="vocs_Sidebar_item" href="/reference/frog-image-response">Response</a></div></section><section class="vocs_Sidebar_section"><div class="vocs_Sidebar_sectionHeader"><a data-active="false" class="vocs_Sidebar_item" href="/reference/frog-transaction">Frog.transaction</a></div><div class="vocs_Sidebar_items vocs_Sidebar_levelInset"><a data-active="false" class="vocs_Sidebar_item" href="/reference/frog-transaction-context">Context</a><a data-active="false" class="vocs_Sidebar_item" href="/reference/frog-transaction-response">Response</a></div></section><section class="vocs_Sidebar_section"><div class="vocs_Sidebar_sectionHeader"><a data-active="false" class="vocs_Sidebar_item" href="/reference/frog-signature">Frog.signature</a></div><div class="vocs_Sidebar_items vocs_Sidebar_levelInset"><a data-active="false" class="vocs_Sidebar_item" href="/reference/frog-signature-context">Context</a><a data-active="false" class="vocs_Sidebar_item" href="/reference/frog-signature-response">Response</a></div></section><a data-active="false" class="vocs_Sidebar_item" href="/reference/frog-hono">Frog.hono</a></div></section><section class="vocs_Sidebar_section vocs_Sidebar_level"><div class="vocs_Sidebar_sectionHeader"><div class="vocs_Sidebar_sectionTitle">Middlewares</div></div><div class="vocs_Sidebar_items"><a data-active="false" class="vocs_Sidebar_item" href="/middlewares/neynar">Neynar</a></div></section><section class="vocs_Sidebar_section vocs_Sidebar_level"><div class="vocs_Sidebar_sectionHeader"><div class="vocs_Sidebar_sectionTitle">Dev Reference</div></div><div class="vocs_Sidebar_items"><a data-active="false" class="vocs_Sidebar_item" href="/dev/devtools">devtools</a></div></section><section class="vocs_Sidebar_section vocs_Sidebar_level"><div class="vocs_Sidebar_sectionHeader"><div class="vocs_Sidebar_sectionTitle">CLI Reference</div></div><div class="vocs_Sidebar_items"><a data-active="false" class="vocs_Sidebar_item" href="/commands/dev">dev</a><a data-active="false" class="vocs_Sidebar_item" href="/commands/vercel-build">vercel-build</a></div></section></div></nav></aside></div><div class="vocs_DocsLayout_gutterTop vocs_DocsLayout_gutterTop_offsetLeftGutter"><div class="vocs_DesktopTopNav"><button class="vocs_DesktopSearch_search" type="button" aria-haspopup="dialog" aria-expanded="false" aria-controls="radix-:Rlj:" data-state="closed"><svg width="15" height="15" viewBox="0 0 15 15" fill="none" xmlns="http://www.w3.org/2000/svg" style="margin-top:2px"><path d="M10 6.5C10 8.433 8.433 10 6.5 10C4.567 10 3 8.433 3 6.5C3 4.567 4.567 3 6.5 3C8.433 3 10 4.567 10 6.5ZM9.30884 10.0159C8.53901 10.6318 7.56251 11 6.5 11C4.01472 11 2 8.98528 2 6.5C2 4.01472 4.01472 2 6.5 2C8.98528 2 11 4.01472 11 6.5C11 7.56251 10.6318 8.53901 10.0159 9.30884L12.8536 12.1464C13.0488 12.3417 13.0488 12.6583 12.8536 12.8536C12.6583 13.0488 12.3417 13.0488 12.1464 12.8536L9.30884 10.0159Z" fill="currentColor" fill-rule="evenodd" clip-rule="evenodd"></path></svg>Search<div class="vocs_DesktopSearch_searchCommand"><div style="background:currentColor;transform:rotate(45deg);width:1.5px;border-radius:2px;height:100%"></div></div></button><div class="vocs_DesktopTopNav_logoWrapper"><div class="vocs_DesktopTopNav_logo"><a style="align-items:center;display:flex;height:56px;margin-top:4px" href="/"><img alt="Logo" class="vocs_NavLogo_logoImage vocs_Logo vocs_Logo_logoDark" src="/logo-dark.svg"><img alt="Logo" class="vocs_NavLogo_logoImage vocs_Logo vocs_Logo_logoLight" src="/logo-light.svg"></a></div></div><div class="vocs_DesktopTopNav_section"></div><div class="vocs_DesktopTopNav_section"><div class="vocs_DesktopTopNav_group"><nav aria-label="Main" data-orientation="horizontal" dir="ltr" class="vocs_NavigationMenu"><div style="position:relative"><ul data-orientation="horizontal" class="vocs_NavigationMenu_list" dir="ltr"><a data-active="false" class="vocs_DesktopTopNav_item vocs_NavigationMenu_link vocs_Link vocs_Link_styleless" href="/ui" variant="styleless" data-radix-collection-item="">FrogUI</a><li class="vocs_DesktopTopNav_item vocs_NavigationMenu_item"><button id="radix-:Rm5j:-trigger-radix-:Ram5j:" data-state="closed" aria-expanded="false" aria-controls="radix-:Rm5j:-content-radix-:Ram5j:" data-active="false" class="vocs_NavigationMenu_trigger vocs_NavigationMenu_link" style="--vocs_NavigationMenu_chevronDownIcon:url(/.vocs/icons/chevron-down.svg)" data-radix-collection-item="">0.18.3</button></li></ul></div></nav></div><div class="vocs_DesktopTopNav_divider vocs_DesktopTopNav_hideCompact"></div><div class="vocs_DesktopTopNav_group vocs_DesktopTopNav_hideCompact" style="margin-left:-8px;margin-right:-8px"><div class="vocs_DesktopTopNav_item"><a class="vocs_DesktopTopNav_button" href="https://discord.gg/JUrRkGweXV" target="_blank" rel="noopener noreferrer"><div aria-label="Discord" class="vocs_Icon vocs_DesktopTopNav_icon" role="img" style="--vocs_Icon_size:23px"><svg width="100%" height="100%" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 127.14 96.36"><title>Discord</title><g id="图层_2" data-name="图层 2"><g id="Discord_Logos" data-name="Discord Logos"><g id="Discord_Logo_-_Large_-_White" data-name="Discord Logo - Large - White"><path d="M107.7,8.07A105.15,105.15,0,0,0,81.47,0a72.06,72.06,0,0,0-3.36,6.83A97.68,97.68,0,0,0,49,6.83,72.37,72.37,0,0,0,45.64,0,105.89,105.89,0,0,0,19.39,8.09C2.79,32.65-1.71,56.6.54,80.21h0A105.73,105.73,0,0,0,32.71,96.36,77.7,77.7,0,0,0,39.6,85.25a68.42,68.42,0,0,1-10.85-5.18c.91-.66,1.8-1.34,2.66-2a75.57,75.57,0,0,0,64.32,0c.87.71,1.76,1.39,2.66,2a68.68,68.68,0,0,1-10.87,5.19,77,77,0,0,0,6.89,11.1A105.25,105.25,0,0,0,126.6,80.22h0C129.24,52.84,122.09,29.11,107.7,8.07ZM42.45,65.69C36.18,65.69,31,60,31,53s5-12.74,11.43-12.74S54,46,53.89,53,48.84,65.69,42.45,65.69Zm42.24,0C78.41,65.69,73.25,60,73.25,53s5-12.74,11.44-12.74S96.23,46,96.12,53,91.08,65.69,84.69,65.69Z" fill="currentColor"></path></g></g></g></svg></div></a></div><div class="vocs_DesktopTopNav_item"><a class="vocs_DesktopTopNav_button" href="https://github.com/wevm/frog" target="_blank" rel="noopener noreferrer"><div aria-label="GitHub" class="vocs_Icon vocs_DesktopTopNav_icon" role="img" style="--vocs_Icon_size:20px"><svg width="100%" height="100%" viewBox="0 0 98 96" xmlns="http://www.w3.org/2000/svg"><title>GitHub</title><path fill-rule="evenodd" clip-rule="evenodd" d="M48.854 0C21.839 0 0 22 0 49.217c0 21.756 13.993 40.172 33.405 46.69 2.427.49 3.316-1.059 3.316-2.362 0-1.141-.08-5.052-.08-9.127-13.59 2.934-16.42-5.867-16.42-5.867-2.184-5.704-5.42-7.17-5.42-7.17-4.448-3.015.324-3.015.324-3.015 4.934.326 7.523 5.052 7.523 5.052 4.367 7.496 11.404 5.378 14.235 4.074.404-3.178 1.699-5.378 3.074-6.6-10.839-1.141-22.243-5.378-22.243-24.283 0-5.378 1.94-9.778 5.014-13.2-.485-1.222-2.184-6.275.486-13.038 0 0 4.125-1.304 13.426 5.052a46.97 46.97 0 0 1 12.214-1.63c4.125 0 8.33.571 12.213 1.63 9.302-6.356 13.427-5.052 13.427-5.052 2.67 6.763.97 11.816.485 13.038 3.155 3.422 5.015 7.822 5.015 13.2 0 18.905-11.404 23.06-22.324 24.283 1.78 1.548 3.316 4.481 3.316 9.126 0 6.6-.08 11.897-.08 13.526 0 1.304.89 2.853 3.316 2.364 19.412-6.52 33.405-24.935 33.405-46.691C97.707 22 75.788 0 48.854 0z" fill="currentColor"></path></svg></div></a></div><div class="vocs_DesktopTopNav_item"><a class="vocs_DesktopTopNav_button" href="https://warpcast.com/wevm" target="_blank" rel="noopener noreferrer"><div aria-label="Warpcast" class="vocs_Icon vocs_DesktopTopNav_icon" role="img" style="--vocs_Icon_size:20px"><svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg"><title>Warpcast</title><path fill-rule="evenodd" clip-rule="evenodd" d="M7.92028 31.9901H24.0698C28.4371 31.9901 31.9901 28.4373 31.9901 24.0699V7.92053C31.9901 3.55319 28.4371 0.000137329 24.0698 0.000137329H7.92028C3.55304 0.000137329 0 3.55319 0 7.92053V24.0699C0 28.4373 3.55304 31.9901 7.92028 31.9901ZM19.4134 16.048L20.9908 10.124H25.1383L21.2924 23.2218H17.7062L15.9951 17.1397L14.284 23.2218H10.7055L6.85115 10.124H10.999L12.5915 16.0916L14.1891 10.124H17.8309L19.4134 16.048Z" fill="currentColor"></path></svg></div></a></div></div><div class="vocs_DesktopTopNav_divider vocs_DesktopTopNav_hideCompact"></div><div class="vocs_DesktopTopNav_group vocs_DesktopTopNav_hideCompact" style="margin-left:-8px;margin-right:-8px"><div class="vocs_DesktopTopNav_item"><button class="vocs_DesktopTopNav_button" type="button"><div aria-label="Light" class="vocs_Icon vocs_DesktopTopNav_icon vocs_utils_visibleDark" role="img" style="--vocs_Icon_size:20px"><svg width="100%" height="100%" viewBox="0 0 84 84" fill="none" xmlns="http://www.w3.org/2000/svg"><title>Sun</title><path d="M41.8675 15.5254C43.9183 15.5254 45.6273 13.7676 45.6273 11.7168V3.80658C45.6273 1.75588 43.9183 0.046875 41.8675 0.046875C39.7679 0.046875 38.0589 1.75588 38.0589 3.80658V11.7168C38.0589 13.7676 39.7679 15.5254 41.8675 15.5254ZM60.3246 23.2402C61.7895 24.7051 64.2309 24.7539 65.7446 23.2402L71.3598 17.6738C72.7758 16.209 72.7758 13.7188 71.3598 12.2539C69.8949 10.7891 67.4535 10.7891 65.9887 12.2539L60.3246 17.918C58.9086 19.3828 58.9086 21.7754 60.3246 23.2402ZM67.9906 41.7461C67.9906 43.7969 69.7485 45.5547 71.7992 45.5547H79.6117C81.7113 45.5547 83.4202 43.7969 83.4202 41.7461C83.4202 39.6953 81.7113 37.9375 79.6117 37.9375H71.7992C69.7485 37.9375 67.9906 39.6953 67.9906 41.7461ZM60.3246 60.3008C58.9086 61.7656 58.9086 64.1582 60.3246 65.623L65.9887 71.2871C67.4535 72.7519 69.8949 72.7031 71.3598 71.2383C72.7758 69.7734 72.7758 67.332 71.3598 65.8672L65.6957 60.3008C64.2309 58.8359 61.7895 58.8359 60.3246 60.3008ZM41.8675 67.9668C39.7679 67.9668 38.0589 69.7246 38.0589 71.7754V79.6855C38.0589 81.7363 39.7679 83.4453 41.8675 83.4453C43.9183 83.4453 45.6273 81.7363 45.6273 79.6855V71.7754C45.6273 69.7246 43.9183 67.9668 41.8675 67.9668ZM23.3617 60.3008C21.8969 58.8359 19.4067 58.8359 17.9418 60.3008L12.3754 65.8184C10.9106 67.2832 10.9106 69.7246 12.3266 71.1894C13.7914 72.6543 16.2328 72.7031 17.6977 71.2383L23.3129 65.623C24.7778 64.1582 24.7778 61.7656 23.3617 60.3008ZM15.6957 41.7461C15.6957 39.6953 13.9867 37.9375 11.8871 37.9375H4.07455C1.97497 37.9375 0.265991 39.6953 0.265991 41.7461C0.265991 43.7969 1.97497 45.5547 4.07455 45.5547H11.8871C13.9867 45.5547 15.6957 43.7969 15.6957 41.7461ZM23.3129 23.2402C24.7778 21.8242 24.7778 19.334 23.3617 17.918L17.7465 12.2539C16.3305 10.8379 13.8403 10.7891 12.4242 12.2539C10.9594 13.7188 10.9594 16.209 12.3754 17.625L17.9418 23.2402C19.4067 24.7051 21.8481 24.7051 23.3129 23.2402Z" fill="currentColor"></path><path d="M41.8675 61.668C52.7073 61.668 61.7405 52.6836 61.7405 41.7461C61.7405 30.8086 52.7073 21.8242 41.8675 21.8242C30.9788 21.8242 21.9456 30.8086 21.9456 41.7461C21.9456 52.6836 30.9788 61.668 41.8675 61.668ZM41.8675 55.0273C34.5921 55.0273 28.5862 48.9727 28.5862 41.7461C28.5862 34.5195 34.5921 28.4648 41.8675 28.4648C49.0941 28.4648 55.0999 34.5195 55.0999 41.7461C55.0999 48.9727 49.0941 55.0273 41.8675 55.0273Z" fill="currentColor"></path></svg></div><div aria-label="Dark" class="vocs_Icon vocs_DesktopTopNav_icon vocs_utils_visibleLight" role="img" style="margin-top:-2px;--vocs_Icon_size:20px"><svg width="100%" height="100%" viewBox="0 0 78 82" fill="none" xmlns="http://www.w3.org/2000/svg"><title>Moon</title><path d="M62.8455 45.9668C63.6268 45.9668 64.2127 45.3809 64.3104 44.5508C65.4334 34.3457 66.0682 33.9551 76.4197 32.3438C77.3963 32.1973 77.9334 31.7578 77.9334 30.8789C77.9334 30.0977 77.3963 29.5605 76.6151 29.4629C66.1658 27.4609 65.4334 27.4609 64.3104 17.2559C64.2127 16.377 63.6268 15.8398 62.8455 15.8398C62.0154 15.8398 61.4783 16.377 61.3807 17.207C60.1111 27.6074 59.6229 28.0957 49.0272 29.4629C48.2947 29.5117 47.7088 30.0977 47.7088 30.8789C47.7088 31.709 48.2947 32.1973 49.0272 32.3438C59.6229 34.3457 60.0623 34.4434 61.3807 44.6484C61.4783 45.3809 62.0154 45.9668 62.8455 45.9668ZM44.535 19.5508C45.0233 19.5508 45.3162 19.2578 45.4139 18.7695C46.6834 12.4707 46.5369 12.373 53.1287 11.0547C53.5682 10.957 53.91 10.7129 53.91 10.1758C53.91 9.63868 53.5682 9.39448 53.1287 9.29688C46.5369 7.97848 46.6834 7.88089 45.4139 1.58199C45.3162 1.09379 45.0233 0.800781 44.535 0.800781C43.9979 0.800781 43.7049 1.09379 43.6072 1.58199C42.3377 7.88089 42.4842 7.97848 35.9412 9.29688C35.4529 9.39448 35.1111 9.63868 35.1111 10.1758C35.1111 10.7129 35.4529 10.957 35.9412 11.0547C42.4842 12.373 42.3865 12.4707 43.6072 18.7695C43.7049 19.2578 43.9979 19.5508 44.535 19.5508Z" fill="currentColor"></path><path d="M34.3298 81.2696C48.49 81.2696 59.9157 74.043 65.0915 61.7872C65.8239 59.9806 65.5798 58.6134 64.7497 57.7833C64.0173 57.0509 62.7478 56.9044 61.3318 57.4903C58.4509 58.6134 54.9353 59.2481 50.6384 59.2481C33.695 59.2481 22.7575 48.6036 22.7575 32.2462C22.7575 27.4122 23.6853 22.6759 24.7595 20.5763C25.5407 18.9161 25.4919 17.5001 24.8083 16.67C24.0271 15.7423 22.6599 15.4005 20.7068 16.1329C8.64624 20.7716 0.345459 33.4181 0.345459 47.8712C0.345459 66.8165 14.5056 81.2696 34.3298 81.2696ZM34.4275 74.5801C18.4607 74.5801 7.03494 62.9591 7.03494 47.3341C7.03494 38.2521 10.9411 30.0489 17.6306 24.629C16.8005 27.0704 16.361 30.6837 16.361 34.1505C16.361 52.8517 29.5446 65.6935 48.8806 65.6935C52.0544 65.6935 54.9841 65.3517 56.4001 64.9122C51.615 70.918 43.4607 74.5801 34.4275 74.5801Z" fill="currentColor"></path></svg></div></button></div></div></div></div><div class="vocs_MobileTopNav"><div class="vocs_MobileTopNav_section"><div class="vocs_MobileTopNav_group"><div class="vocs_MobileTopNav_logo"><a style="align-items:center;display:flex;height:100%" href="/"><img alt="Logo" class="vocs_NavLogo_logoImage vocs_Logo vocs_Logo_logoDark" src="/logo-dark.svg"><img alt="Logo" class="vocs_NavLogo_logoImage vocs_Logo vocs_Logo_logoLight" src="/logo-light.svg"></a></div></div><div class="vocs_MobileTopNav_group"><nav aria-label="Main" data-orientation="horizontal" dir="ltr" class="vocs_MobileTopNav_navigation vocs_NavigationMenu"><div style="position:relative"><ul data-orientation="horizontal" class="vocs_NavigationMenu_list" dir="ltr"><a data-active="false" class="vocs_NavigationMenu_link vocs_Link vocs_Link_styleless" href="/ui" variant="styleless" data-radix-collection-item="">FrogUI</a><li class="vocs_MobileTopNav_item vocs_NavigationMenu_item"><button id="radix-:Rcpj:-trigger-radix-:R5cpj:" data-state="closed" aria-expanded="false" aria-controls="radix-:Rcpj:-content-radix-:R5cpj:" data-active="false" class="vocs_NavigationMenu_trigger vocs_NavigationMenu_link" style="--vocs_NavigationMenu_chevronDownIcon:url(/.vocs/icons/chevron-down.svg)" data-radix-collection-item="">0.18.3</button></li></ul></div></nav><div class="vocs_MobileTopNav_navigation vocs_MobileTopNav_navigation_compact"><a class="vocs_MobileTopNav_navigationItem vocs_Link vocs_Link_styleless" href="/ui" variant="styleless">FrogUI</a></div></div></div><div class="vocs_MobileTopNav_section"><div class="vocs_MobileTopNav_group" style="margin-right:-8px"><button class="vocs_MobileSearch_searchButton" type="button" aria-label="Search" aria-haspopup="dialog" aria-expanded="false" aria-controls="radix-:R39j:" data-state="closed"><svg width="21" height="21" viewBox="0 0 15 15" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M10 6.5C10 8.433 8.433 10 6.5 10C4.567 10 3 8.433 3 6.5C3 4.567 4.567 3 6.5 3C8.433 3 10 4.567 10 6.5ZM9.30884 10.0159C8.53901 10.6318 7.56251 11 6.5 11C4.01472 11 2 8.98528 2 6.5C2 4.01472 4.01472 2 6.5 2C8.98528 2 11 4.01472 11 6.5C11 7.56251 10.6318 8.53901 10.0159 9.30884L12.8536 12.1464C13.0488 12.3417 13.0488 12.6583 12.8536 12.8536C12.6583 13.0488 12.3417 13.0488 12.1464 12.8536L9.30884 10.0159Z" fill="currentColor" fill-rule="evenodd" clip-rule="evenodd"></path></svg></button></div><div class="vocs_MobileTopNav_divider"></div><div class="vocs_MobileTopNav_group" style="margin-left:-8px"><a class="vocs_MobileTopNav_button" href="https://discord.gg/JUrRkGweXV" target="_blank" rel="noopener noreferrer"><div aria-label="Discord" class="vocs_Icon vocs_MobileTopNav_icon" role="img" style="--vocs_Icon_size:21px"><svg width="100%" height="100%" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 127.14 96.36"><title>Discord</title><g id="图层_2" data-name="图层 2"><g id="Discord_Logos" data-name="Discord Logos"><g id="Discord_Logo_-_Large_-_White" data-name="Discord Logo - Large - White"><path d="M107.7,8.07A105.15,105.15,0,0,0,81.47,0a72.06,72.06,0,0,0-3.36,6.83A97.68,97.68,0,0,0,49,6.83,72.37,72.37,0,0,0,45.64,0,105.89,105.89,0,0,0,19.39,8.09C2.79,32.65-1.71,56.6.54,80.21h0A105.73,105.73,0,0,0,32.71,96.36,77.7,77.7,0,0,0,39.6,85.25a68.42,68.42,0,0,1-10.85-5.18c.91-.66,1.8-1.34,2.66-2a75.57,75.57,0,0,0,64.32,0c.87.71,1.76,1.39,2.66,2a68.68,68.68,0,0,1-10.87,5.19,77,77,0,0,0,6.89,11.1A105.25,105.25,0,0,0,126.6,80.22h0C129.24,52.84,122.09,29.11,107.7,8.07ZM42.45,65.69C36.18,65.69,31,60,31,53s5-12.74,11.43-12.74S54,46,53.89,53,48.84,65.69,42.45,65.69Zm42.24,0C78.41,65.69,73.25,60,73.25,53s5-12.74,11.44-12.74S96.23,46,96.12,53,91.08,65.69,84.69,65.69Z" fill="currentColor"></path></g></g></g></svg></div></a><a class="vocs_MobileTopNav_button" href="https://github.com/wevm/frog" target="_blank" rel="noopener noreferrer"><div aria-label="GitHub" class="vocs_Icon vocs_MobileTopNav_icon" role="img" style="--vocs_Icon_size:18px"><svg width="100%" height="100%" viewBox="0 0 98 96" xmlns="http://www.w3.org/2000/svg"><title>GitHub</title><path fill-rule="evenodd" clip-rule="evenodd" d="M48.854 0C21.839 0 0 22 0 49.217c0 21.756 13.993 40.172 33.405 46.69 2.427.49 3.316-1.059 3.316-2.362 0-1.141-.08-5.052-.08-9.127-13.59 2.934-16.42-5.867-16.42-5.867-2.184-5.704-5.42-7.17-5.42-7.17-4.448-3.015.324-3.015.324-3.015 4.934.326 7.523 5.052 7.523 5.052 4.367 7.496 11.404 5.378 14.235 4.074.404-3.178 1.699-5.378 3.074-6.6-10.839-1.141-22.243-5.378-22.243-24.283 0-5.378 1.94-9.778 5.014-13.2-.485-1.222-2.184-6.275.486-13.038 0 0 4.125-1.304 13.426 5.052a46.97 46.97 0 0 1 12.214-1.63c4.125 0 8.33.571 12.213 1.63 9.302-6.356 13.427-5.052 13.427-5.052 2.67 6.763.97 11.816.485 13.038 3.155 3.422 5.015 7.822 5.015 13.2 0 18.905-11.404 23.06-22.324 24.283 1.78 1.548 3.316 4.481 3.316 9.126 0 6.6-.08 11.897-.08 13.526 0 1.304.89 2.853 3.316 2.364 19.412-6.52 33.405-24.935 33.405-46.691C97.707 22 75.788 0 48.854 0z" fill="currentColor"></path></svg></div></a><a class="vocs_MobileTopNav_button" href="https://warpcast.com/wevm" target="_blank" rel="noopener noreferrer"><div aria-label="Warpcast" class="vocs_Icon vocs_MobileTopNav_icon" role="img" style="--vocs_Icon_size:18px"><svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg"><title>Warpcast</title><path fill-rule="evenodd" clip-rule="evenodd" d="M7.92028 31.9901H24.0698C28.4371 31.9901 31.9901 28.4373 31.9901 24.0699V7.92053C31.9901 3.55319 28.4371 0.000137329 24.0698 0.000137329H7.92028C3.55304 0.000137329 0 3.55319 0 7.92053V24.0699C0 28.4373 3.55304 31.9901 7.92028 31.9901ZM19.4134 16.048L20.9908 10.124H25.1383L21.2924 23.2218H17.7062L15.9951 17.1397L14.284 23.2218H10.7055L6.85115 10.124H10.999L12.5915 16.0916L14.1891 10.124H17.8309L19.4134 16.048Z" fill="currentColor"></path></svg></div></a></div></div></div></div><div class="vocs_DocsLayout_gutterTopCurtain vocs_DocsLayout_gutterTopCurtain_withSidebar"><div class="vocs_DesktopTopNav_curtain"></div><div class="vocs_MobileTopNav_curtain"><div class="vocs_MobileTopNav_curtainGroup"><div class="vocs_MobileTopNav_curtainItem"><button type="button" aria-haspopup="dialog" aria-expanded="false" aria-controls="radix-:Rqj:" data-state="closed" class="vocs_MobileTopNav_menuTrigger"><div aria-label="Menu" class="vocs_Icon" role="img" style="--vocs_Icon_size:13px"><svg width="100%" height="100%" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 79 48" fill="none"><title>Menu</title><path fill="currentColor" d="M19.528 47.232h40.87c1.952 0 3.515-1.562 3.515-3.564a3.5 3.5 0 0 0-3.516-3.516H19.528a3.501 3.501 0 0 0-3.515 3.516c0 2.002 1.562 3.564 3.515 3.564ZM12.057 27.262h55.81a3.501 3.501 0 0 0 3.516-3.516 3.501 3.501 0 0 0-3.515-3.515h-55.81a3.501 3.501 0 0 0-3.516 3.515 3.501 3.501 0 0 0 3.515 3.516ZM4.391 7.34H75.29c2.002 0 3.515-1.563 3.515-3.516 0-2.002-1.513-3.564-3.515-3.564H4.39C2.438.26.876 1.822.876 3.824A3.501 3.501 0 0 0 4.39 7.34Z"></path></svg></div><div class="vocs_MobileTopNav_menuTitle">Installation</div></button></div></div><div class="vocs_MobileTopNav_curtainGroup"><div class="vocs_MobileTopNav_curtainItem"><button type="button" aria-haspopup="dialog" aria-expanded="false" aria-controls="radix-:R5aj:" data-state="closed" class="vocs_MobileTopNav_outlineTrigger">On this page<div aria-label="On this page" class="vocs_Icon" role="img" style="--vocs_Icon_size:10px"><svg width="100%" height="100%" viewBox="0 0 39 69" fill="none" xmlns="http://www.w3.org/2000/svg"><title>Chevron Right</title><path d="M38.8697 34.7461C38.8697 33.6719 38.4791 32.6953 37.649 31.8652L7.47318 1.8848C6.74078 1.1035 5.76418 0.712891 4.64118 0.712891C2.34618 0.712891 0.588379 2.42189 0.588379 4.71679C0.588379 5.79099 1.07668 6.81639 1.76028 7.59769L29.0552 34.7461L1.76028 61.8945C1.07668 62.6758 0.588379 63.6523 0.588379 64.7754C0.588379 67.0703 2.34618 68.7793 4.64118 68.7793C5.76418 68.7793 6.74078 68.3887 7.47318 67.6074L37.649 37.627C38.4791 36.7969 38.8697 35.8203 38.8697 34.7461Z" fill="currentColor"></path></svg></div></button></div></div></div></div><div class="vocs_DocsLayout_gutterRight vocs_DocsLayout_gutterRight_withSidebar"><aside class="vocs_Outline"><nav class="vocs_Outline_nav"><h2 class="vocs_Outline_heading">On this page</h2><ul class="vocs_Outline_items"><li class="vocs_Outline_item"><a data-active="false" href="/installation#package-manager" class="vocs_Outline_link">Package Manager</a></li><li class="vocs_Outline_item"><a data-active="false" href="/installation#using-unreleased-commits" class="vocs_Outline_link">Using Unreleased Commits</a></li><li class="vocs_Outline_item"><a data-active="false" href="/installation#security" class="vocs_Outline_link">Security</a></li><ul class="vocs_Outline_items"></ul></ul></nav><div style="margin-left: 16px; margin-top: 16px;"><a href="https://paradigm.xyz" target="_blank" rel="noreferrer noopener"><img alt="Paradigm x Wevm" class="vocs_Logo_logoLight" src="https://raw.githubusercontent.com/wevm/.github/main/content/paradigm-collab-light.svg" style="width: 200px;"><img alt="Paradigm x Wevm" class="vocs_Logo_logoDark" src="https://raw.githubusercontent.com/wevm/.github/main/content/paradigm-collab-dark.svg" style="width: 200px;"></a></div></aside></div><div id="vocs-content" class="vocs_DocsLayout_content vocs_DocsLayout_content_withSidebar vocs_DocsLayout_content_withTopNav"><article class="vocs_Content"><header class="vocs_Header"><h1 class="vocs_H1 vocs_Heading"><div id="installation" class="vocs_Heading_slugTarget"></div>Installation<a class="vocs_Anchor vocs_Autolink" aria-hidden="true" tabindex="-1" href="/installation#installation"><div data-autolink-icon="true" class="vocs_Div vocs_AutolinkIcon" style="--vocs_AutolinkIcon_iconUrl:url(/.vocs/icons/link.svg)"></div></a></h1></header>
<p class="vocs_Paragraph">Install Frog via your package manager or build from source.</p>
<h2 class="vocs_H2 vocs_Heading"><div id="package-manager" class="vocs_Heading_slugTarget"></div>Package Manager<a class="vocs_Anchor vocs_Autolink" aria-hidden="true" tabindex="-1" href="/installation#package-manager"><div data-autolink-icon="true" class="vocs_Div vocs_AutolinkIcon" style="--vocs_AutolinkIcon_iconUrl:url(/.vocs/icons/link.svg)"></div></a></h2>
<p class="vocs_Paragraph">Install the required packages.</p>
<div dir="ltr" data-orientation="horizontal" class="vocs_CodeGroup vocs_Tabs"><div role="tablist" aria-orientation="horizontal" aria-label="Code group" class="vocs_Tabs_list" tabindex="0" data-orientation="horizontal" style="outline:none"><button type="button" role="tab" aria-selected="true" aria-controls="radix-:R15r:-content-pnpm" data-state="active" id="radix-:R15r:-trigger-pnpm" class="vocs_Tabs_trigger" tabindex="-1" data-orientation="horizontal" data-radix-collection-item="">pnpm</button><button type="button" role="tab" aria-selected="false" aria-controls="radix-:R15r:-content-npm" data-state="inactive" id="radix-:R15r:-trigger-npm" class="vocs_Tabs_trigger" tabindex="-1" data-orientation="horizontal" data-radix-collection-item="">npm</button><button type="button" role="tab" aria-selected="false" aria-controls="radix-:R15r:-content-yarn" data-state="inactive" id="radix-:R15r:-trigger-yarn" class="vocs_Tabs_trigger" tabindex="-1" data-orientation="horizontal" data-radix-collection-item="">yarn</button><button type="button" role="tab" aria-selected="false" aria-controls="radix-:R15r:-content-bun" data-state="inactive" id="radix-:R15r:-trigger-bun" class="vocs_Tabs_trigger" tabindex="-1" data-orientation="horizontal" data-radix-collection-item="">bun</button></div><div data-state="active" data-orientation="horizontal" role="tabpanel" aria-labelledby="radix-:R15r:-trigger-pnpm" id="radix-:R15r:-content-pnpm" tabindex="0" data-shiki="true" class="vocs_Tabs_content" style="animation-duration:0s"><div class="vocs_CodeBlock"><div class="vocs_CodeTitle"><div aria-label="Terminal" class="vocs_Icon" role="img" style="margin-top:3px;--vocs_Icon_size:14px"><svg width="100%" height="100%" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 79 95" fill="none"><title>Terminal</title><path fill="currentColor" d="M38.281 34.033c0-1.074-.39-2.05-1.22-2.88L6.885 1.171C6.152.39 5.175 0 4.053 0 1.758 0 0 1.709 0 4.004c0 1.074.488 2.1 1.172 2.88l27.295 27.15L1.172 61.181C.488 61.962 0 62.939 0 64.062c0 2.295 1.758 4.004 4.053 4.004 1.123 0 2.1-.39 2.832-1.172l30.176-29.98c.83-.83 1.22-1.807 1.22-2.88Z"></path><path stroke="currentColor" stroke-linecap="round" stroke-width="8px" d="M36 75h55"></path></svg></div>pnpm</div><div class="vocs_Pre_wrapper"><pre style="background-color:#ffffff;--shiki-dark-bg:#1b1e28;color:#393a34;--shiki-dark:#a6accd" tabindex="0" data-title="pnpm" data-lang="bash" class="shiki shiki-themes vitesse-light poimandres vocs_Pre"><code class="vocs_Code"><span class="line vocs_Span"><span style="color:#59873A;--shiki-dark:#91B4D5" class="vocs_Span">pnpm</span><span style="color:#B56959;--shiki-dark:#ADD7FF" class="vocs_Span"> add</span><span style="color:#B56959;--shiki-dark:#ADD7FF" class="vocs_Span"> frog</span><span style="color:#B56959;--shiki-dark:#ADD7FF" class="vocs_Span"> hono</span></span></code></pre></div></div></div><div data-state="inactive" data-orientation="horizontal" role="tabpanel" aria-labelledby="radix-:R15r:-trigger-npm" hidden="" id="radix-:R15r:-content-npm" tabindex="0" data-shiki="true" class="vocs_Tabs_content"></div><div data-state="inactive" data-orientation="horizontal" role="tabpanel" aria-labelledby="radix-:R15r:-trigger-yarn" hidden="" id="radix-:R15r:-content-yarn" tabindex="0" data-shiki="true" class="vocs_Tabs_content"></div><div data-state="inactive" data-orientation="horizontal" role="tabpanel" aria-labelledby="radix-:R15r:-trigger-bun" hidden="" id="radix-:R15r:-content-bun" tabindex="0" data-shiki="true" class="vocs_Tabs_content"></div></div>
<ul class="vocs_List vocs_List_unordered">
<li class="vocs_ListItem"><a class="vocs_Anchor vocs_Link vocs_Link_accent_underlined vocs_ExternalLink" href="https://github.com/honojs/hono" target="_blank" rel="noopener noreferrer" style="--vocs_ExternalLink_iconUrl:url(/.vocs/icons/arrow-diagonal.svg)">Hono</a> is a small, simple, and ultrafast web framework for the Edges.</li>
<li class="vocs_ListItem"><a class="vocs_Anchor vocs_Link vocs_Link_accent_underlined vocs_ExternalLink" href="https://github.com/microsoft/TypeScript" target="_blank" rel="noopener noreferrer" style="--vocs_ExternalLink_iconUrl:url(/.vocs/icons/arrow-diagonal.svg)">TypeScript</a> is optional, but highly recommended.</li>
</ul>
<h2 class="vocs_H2 vocs_Heading"><div id="using-unreleased-commits" class="vocs_Heading_slugTarget"></div>Using Unreleased Commits<a class="vocs_Anchor vocs_Autolink" aria-hidden="true" tabindex="-1" href="/installation#using-unreleased-commits"><div data-autolink-icon="true" class="vocs_Div vocs_AutolinkIcon" style="--vocs_AutolinkIcon_iconUrl:url(/.vocs/icons/link.svg)"></div></a></h2>
<p class="vocs_Paragraph">If you can't wait for a new release to test the latest features, you can either install from the <code class="vocs_Code">canary</code> tag (tracks the <a class="vocs_Anchor vocs_Link vocs_Link_accent_underlined" href="https://github.com/wevm/frog/tree/main" target="_blank" rel="noopener noreferrer" style="--vocs_ExternalLink_iconUrl:url(/.vocs/icons/arrow-diagonal.svg)"><code class="vocs_Code">main</code></a> branch).</p>
<div dir="ltr" data-orientation="horizontal" class="vocs_CodeGroup vocs_Tabs"><div role="tablist" aria-orientation="horizontal" aria-label="Code group" class="vocs_Tabs_list" tabindex="0" data-orientation="horizontal" style="outline:none"><button type="button" role="tab" aria-selected="true" aria-controls="radix-:R25r:-content-pnpm" data-state="active" id="radix-:R25r:-trigger-pnpm" class="vocs_Tabs_trigger" tabindex="-1" data-orientation="horizontal" data-radix-collection-item="">pnpm</button><button type="button" role="tab" aria-selected="false" aria-controls="radix-:R25r:-content-npm" data-state="inactive" id="radix-:R25r:-trigger-npm" class="vocs_Tabs_trigger" tabindex="-1" data-orientation="horizontal" data-radix-collection-item="">npm</button><button type="button" role="tab" aria-selected="false" aria-controls="radix-:R25r:-content-yarn" data-state="inactive" id="radix-:R25r:-trigger-yarn" class="vocs_Tabs_trigger" tabindex="-1" data-orientation="horizontal" data-radix-collection-item="">yarn</button><button type="button" role="tab" aria-selected="false" aria-controls="radix-:R25r:-content-bun" data-state="inactive" id="radix-:R25r:-trigger-bun" class="vocs_Tabs_trigger" tabindex="-1" data-orientation="horizontal" data-radix-collection-item="">bun</button></div><div data-state="active" data-orientation="horizontal" role="tabpanel" aria-labelledby="radix-:R25r:-trigger-pnpm" id="radix-:R25r:-content-pnpm" tabindex="0" data-shiki="true" class="vocs_Tabs_content" style="animation-duration:0s"><div class="vocs_CodeBlock"><div class="vocs_CodeTitle"><div aria-label="Terminal" class="vocs_Icon" role="img" style="margin-top:3px;--vocs_Icon_size:14px"><svg width="100%" height="100%" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 79 95" fill="none"><title>Terminal</title><path fill="currentColor" d="M38.281 34.033c0-1.074-.39-2.05-1.22-2.88L6.885 1.171C6.152.39 5.175 0 4.053 0 1.758 0 0 1.709 0 4.004c0 1.074.488 2.1 1.172 2.88l27.295 27.15L1.172 61.181C.488 61.962 0 62.939 0 64.062c0 2.295 1.758 4.004 4.053 4.004 1.123 0 2.1-.39 2.832-1.172l30.176-29.98c.83-.83 1.22-1.807 1.22-2.88Z"></path><path stroke="currentColor" stroke-linecap="round" stroke-width="8px" d="M36 75h55"></path></svg></div>pnpm</div><div class="vocs_Pre_wrapper"><pre style="background-color:#ffffff;--shiki-dark-bg:#1b1e28;color:#393a34;--shiki-dark:#a6accd" tabindex="0" data-title="pnpm" data-lang="bash" class="shiki shiki-themes vitesse-light poimandres vocs_Pre"><code class="vocs_Code"><span class="line vocs_Span"><span style="color:#59873A;--shiki-dark:#91B4D5" class="vocs_Span">pnpm</span><span style="color:#B56959;--shiki-dark:#ADD7FF" class="vocs_Span"> add</span><span style="color:#B56959;--shiki-dark:#ADD7FF" class="vocs_Span"> frog@canary</span></span></code></pre></div></div></div><div data-state="inactive" data-orientation="horizontal" role="tabpanel" aria-labelledby="radix-:R25r:-trigger-npm" hidden="" id="radix-:R25r:-content-npm" tabindex="0" data-shiki="true" class="vocs_Tabs_content"></div><div data-state="inactive" data-orientation="horizontal" role="tabpanel" aria-labelledby="radix-:R25r:-trigger-yarn" hidden="" id="radix-:R25r:-content-yarn" tabindex="0" data-shiki="true" class="vocs_Tabs_content"></div><div data-state="inactive" data-orientation="horizontal" role="tabpanel" aria-labelledby="radix-:R25r:-trigger-bun" hidden="" id="radix-:R25r:-content-bun" tabindex="0" data-shiki="true" class="vocs_Tabs_content"></div></div>
<p class="vocs_Paragraph">Or clone the <a class="vocs_Anchor vocs_Link vocs_Link_accent_underlined vocs_ExternalLink" href="https://github.com/wevm/frog" target="_blank" rel="noopener noreferrer" style="--vocs_ExternalLink_iconUrl:url(/.vocs/icons/arrow-diagonal.svg)">Frog repo</a> to your local machine, build, and link it yourself.</p>
<div class="vocs_CodeBlock"><div class="vocs_Pre_wrapper"><pre style="background-color:#ffffff;--shiki-dark-bg:#1b1e28;color:#393a34;--shiki-dark:#a6accd" tabindex="0" class="shiki shiki-themes vitesse-light poimandres vocs_Pre"><code class="vocs_Code"><span class="line vocs_Span"><span style="color:#59873A;--shiki-dark:#91B4D5" class="vocs_Span">gh</span><span style="color:#B56959;--shiki-dark:#ADD7FF" class="vocs_Span"> repo</span><span style="color:#B56959;--shiki-dark:#ADD7FF" class="vocs_Span"> clone</span><span style="color:#B56959;--shiki-dark:#ADD7FF" class="vocs_Span"> wevm/frog</span></span>
<span class="line vocs_Span"><span style="color:#998418;--shiki-dark:#91B4D5" class="vocs_Span">cd</span><span style="color:#B56959;--shiki-dark:#ADD7FF" class="vocs_Span"> frog</span></span>
<span class="line vocs_Span"><span style="color:#59873A;--shiki-dark:#91B4D5" class="vocs_Span">pnpm</span><span style="color:#B56959;--shiki-dark:#ADD7FF" class="vocs_Span"> install</span></span>
<span class="line vocs_Span"><span style="color:#59873A;--shiki-dark:#91B4D5" class="vocs_Span">pnpm</span><span style="color:#B56959;--shiki-dark:#ADD7FF" class="vocs_Span"> build</span></span>
<span class="line vocs_Span"><span style="color:#998418;--shiki-dark:#91B4D5" class="vocs_Span">cd</span><span style="color:#B56959;--shiki-dark:#ADD7FF" class="vocs_Span"> src</span></span>
<span class="line vocs_Span"><span style="color:#59873A;--shiki-dark:#91B4D5" class="vocs_Span">pnpm</span><span style="color:#B56959;--shiki-dark:#ADD7FF" class="vocs_Span"> link</span><span style="color:#A65E2B;--shiki-dark:#ADD7FF" class="vocs_Span"> --global</span></span></code></pre></div></div>
<p class="vocs_Paragraph">Then go to the project where you are using Frog and run <code class="vocs_Code">pnpm link --global frog</code> (or the package manager that you used to link Frog globally). Make sure you installed the <a class="vocs_Anchor vocs_Link vocs_Link_accent_underlined" href="/installation#package-manager">required peer dependencies</a> and their versions are correct.</p>
<h2 class="vocs_H2 vocs_Heading"><div id="security" class="vocs_Heading_slugTarget"></div>Security<a class="vocs_Anchor vocs_Autolink" aria-hidden="true" tabindex="-1" href="/installation#security"><div data-autolink-icon="true" class="vocs_Div vocs_AutolinkIcon" style="--vocs_AutolinkIcon_iconUrl:url(/.vocs/icons/link.svg)"></div></a></h2>
<p class="vocs_Paragraph">Ethereum-related projects are often targeted in attacks to steal users' assets. Make sure you follow security best-practices for your project. Some quick things to get started.</p>
<ul class="vocs_List vocs_List_unordered">
<li class="vocs_ListItem">Pin package versions, upgrade mindfully, and inspect lockfile changes to minimize the risk of <a class="vocs_Anchor vocs_Link vocs_Link_accent_underlined vocs_ExternalLink" href="https://nodejs.org/en/guides/security/#supply-chain-attacks" target="_blank" rel="noopener noreferrer" style="--vocs_ExternalLink_iconUrl:url(/.vocs/icons/arrow-diagonal.svg)">supply-chain attacks</a>.</li>
<li class="vocs_ListItem">Install the <a class="vocs_Anchor vocs_Link vocs_Link_accent_underlined vocs_ExternalLink" href="https://socket.dev" target="_blank" rel="noopener noreferrer" style="--vocs_ExternalLink_iconUrl:url(/.vocs/icons/arrow-diagonal.svg)">Socket Security</a> <a class="vocs_Anchor vocs_Link vocs_Link_accent_underlined vocs_ExternalLink" href="https://github.com/apps/socket-security" target="_blank" rel="noopener noreferrer" style="--vocs_ExternalLink_iconUrl:url(/.vocs/icons/arrow-diagonal.svg)">GitHub App</a> to help detect and block supply-chain attacks.</li>
<li class="vocs_ListItem">Add a <a class="vocs_Anchor vocs_Link vocs_Link_accent_underlined vocs_ExternalLink" href="https://cheatsheetseries.owasp.org/cheatsheets/Content_Security_Policy_Cheat_Sheet.html" target="_blank" rel="noopener noreferrer" style="--vocs_ExternalLink_iconUrl:url(/.vocs/icons/arrow-diagonal.svg)">Content Security Policy</a> to defend against external scripts running in your app.</li>
</ul></article><footer class="vocs_Footer"><div class="vocs_Footer_container"><div class="vocs_Footer_lastUpdated">Last updated: <time datetime="2024-11-06T00:54:44.000Z">11/5/24, 6:54 PM</time></div></div><div class="vocs_Footer_navigation"><div></div><a class="vocs_Footer_navigationItem vocs_Footer_navigationItem_right vocs_Link vocs_Link_styleless" href="/getting-started" variant="styleless"><div class="vocs_Footer_navigationText"><div class="vocs_Footer_navigationTextInner" style="text-align: right;">Getting Started</div><div class="vocs_Footer_navigationIcon vocs_Footer_navigationIcon_right" style="--vocs_Icon_size: 0.75em;"><div aria-label="Next" class="vocs_Icon" role="img"><svg width="100%" height="100%" viewBox="0 0 72 60" fill="none" xmlns="http://www.w3.org/2000/svg"><title>Arrow Right</title><path d="M71.3706 29.7461C71.3706 28.6719 70.8824 27.6465 70.0035 26.8164L44.8081 1.66991C43.9292 0.839814 42.9527 0.449219 41.9273 0.449219C39.7789 0.449219 38.1187 2.06052 38.1187 4.25782C38.1187 5.28322 38.4605 6.30861 39.1929 6.99221L45.9312 13.9746L62.4351 28.8672L63.314 26.7188L50.3257 25.791H4.23196C1.93706 25.791 0.325684 27.4512 0.325684 29.7461C0.325684 32.041 1.93706 33.7012 4.23196 33.7012H50.3257L63.314 32.7734L62.4351 30.6738L45.9312 45.5176L39.1929 52.5C38.4605 53.1836 38.1187 54.209 38.1187 55.2344C38.1187 57.4317 39.7789 59.043 41.9273 59.043C42.9527 59.043 43.9292 58.6524 44.8081 57.8223L70.0035 32.6758C70.8824 31.8457 71.3706 30.8203 71.3706 29.7461Z" fill="currentColor"></path></svg></div></div></div><span class="vocs_KeyboardShortcut">Next<span class="vocs_KeyboardShortcut_kbdGroup"><kbd class="vocs_Kbd">shift</kbd><kbd class="vocs_Kbd">→</kbd></span></span></a></div></footer></div><div data-bottom-observer="true"></div></div></div>
</body></html>
```
Parse the html content and extract the text and use it to answer the question. If you stuck just say you don't know.
view raw .cursorrules hosted with ❤ by GitHub

I'm trying to fix the scaffold-eth project that can't run frog using this prompt let's see if he can search the web now:

Image description

It started to understand now:

Image description

Sometimes whats not good about composer is that it stuck and doesnt respond anymore like this:

Image description

So we need to close the IDE and turn it back on again and prompt agent again in a new tab:

Image description

It's looking good it's using our tools to search the web

Image description

He also trying to see the content of the web using our tool

Image description

He also use the correct tool

Image description

There's still some error but overall the fact that they use our tool means that he now got superpower to search the web its still not as perfect but, it kinda help composer agent to see the world in different way. so instead of just use his hallucinated mind he can see it in another perspective which is great

Postmark Image

Speedy emails, satisfied customers

Are delayed transactional emails costing you user satisfaction? Postmark delivers your emails almost instantly, keeping your customers happy and connected.

Sign up

Top comments (0)

A Workflow Copilot. Tailored to You.

Pieces.app image

Our desktop app, with its intelligent copilot, streamlines coding by generating snippets, extracting code from screenshots, and accelerating problem-solving.

Read the docs

👋 Kindness is contagious

Dive into an ocean of knowledge with this thought-provoking post, revered deeply within the supportive DEV Community. Developers of all levels are welcome to join and enhance our collective intelligence.

Saying a simple "thank you" can brighten someone's day. Share your gratitude in the comments below!

On DEV, sharing ideas eases our path and fortifies our community connections. Found this helpful? Sending a quick thanks to the author can be profoundly valued.

Okay