From 149ee051def5b74af708d49ac0ae3ffc79545557 Mon Sep 17 00:00:00 2001 From: DustinTurska <135719141+DustinTurska@users.noreply.github.com> Date: Mon, 2 Dec 2024 18:08:07 +0000 Subject: [PATCH] Dustin/engine playground (#5507) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Problem solved FIxes [DASH-495](https://linear.app/thirdweb/issue/DASH-495/engine-playground) Short description of the bug fixed or feature added Added Engine Section to playground -Airdrop -Mint -Webhooks Updated AppSidebar `expanded: false` to show `otherLinks` section - previously this was unseen by users and there was no scroll option Create EngineAPIHeader for Engine CTA and utm link updates Slack [thread](https://thirdwebdev.slack.com/archives/C07U1LM6S2W/p1731687004602369) for initiative --- ## PR-Codex overview This PR introduces new features and updates to the `playground-web` application, including new API routes for minting and airdropping tokens, enhancements to the UI components, and the addition of new environment variables for build processes. ### Detailed summary - Added environment variables for `ENGINE_ACCESS_TOKEN`, `ENGINE_BACKEND_WALLET`, and `ENGINE_URL`. - Introduced new dependencies: `@thirdweb-dev/engine` and `timeago.js`. - Updated `navLinks.ts` to collapse sections and added a new `Engine` section. - Created new pages for `Webhooks`, `Airdrop`, and `Minting` with respective UI components. - Implemented API routes for transaction status, minting, and airdropping. - Enhanced the `EngineAPIHeader` component to display dynamic content. - Added polling functionality for transaction status updates in the `Sponsorship` and `AirdropERC20` components. - Introduced pagination for transaction results in `ClaimTransactionResults` components. > The following files were skipped due to too many changes: `pnpm-lock.yaml` > ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}` --- apps/playground-web/package.json | 2 + apps/playground-web/public/BaseSep.png | Bin 0 -> 22203 bytes apps/playground-web/public/Ethereum.png | Bin 0 -> 14058 bytes apps/playground-web/public/airdrop.avif | Bin 0 -> 21496 bytes apps/playground-web/public/minting.avif | Bin 0 -> 24290 bytes apps/playground-web/public/webhooks.avif | Bin 0 -> 33695 bytes .../src/app/api/airdrop/route.ts | 155 +++++++++ .../src/app/api/claimTo/route.ts | 226 +++++++++++++ .../src/app/api/erc20BatchMintTo/route.ts | 125 ++++++++ .../src/app/api/mintTo/route.ts | 105 ++++++ .../src/app/api/transaction-status/route.ts | 41 +++ .../src/app/engine/airdrop/page.tsx | 45 +++ .../src/app/engine/minting/page.tsx | 44 +++ .../src/app/engine/webhooks/page.tsx | 44 +++ apps/playground-web/src/app/navLinks.ts | 32 +- .../src/components/blocks/EngineAPIHeader.tsx | 64 ++++ .../engine/airdrop/TransactionResults.tsx | 278 ++++++++++++++++ .../engine/airdrop/airdrop-erc20.tsx | 223 +++++++++++++ .../components/engine/gasless/Sponsorship.tsx | 181 +++++++++++ .../src/components/engine/gasless/Webhook.tsx | 77 +++++ .../engine/minting/TransactionResults.tsx | 276 ++++++++++++++++ .../engine/minting/erc1155-mint-to.tsx | 301 ++++++++++++++++++ .../playground-web/src/components/ui/card.tsx | 86 +++++ .../src/components/ui/table.tsx | 117 +++++++ pnpm-lock.yaml | 272 +++++++--------- turbo.json | 1 + 26 files changed, 2539 insertions(+), 156 deletions(-) create mode 100644 apps/playground-web/public/BaseSep.png create mode 100644 apps/playground-web/public/Ethereum.png create mode 100644 apps/playground-web/public/airdrop.avif create mode 100644 apps/playground-web/public/minting.avif create mode 100644 apps/playground-web/public/webhooks.avif create mode 100644 apps/playground-web/src/app/api/airdrop/route.ts create mode 100644 apps/playground-web/src/app/api/claimTo/route.ts create mode 100644 apps/playground-web/src/app/api/erc20BatchMintTo/route.ts create mode 100644 apps/playground-web/src/app/api/mintTo/route.ts create mode 100644 apps/playground-web/src/app/api/transaction-status/route.ts create mode 100644 apps/playground-web/src/app/engine/airdrop/page.tsx create mode 100644 apps/playground-web/src/app/engine/minting/page.tsx create mode 100644 apps/playground-web/src/app/engine/webhooks/page.tsx create mode 100644 apps/playground-web/src/components/blocks/EngineAPIHeader.tsx create mode 100644 apps/playground-web/src/components/engine/airdrop/TransactionResults.tsx create mode 100644 apps/playground-web/src/components/engine/airdrop/airdrop-erc20.tsx create mode 100644 apps/playground-web/src/components/engine/gasless/Sponsorship.tsx create mode 100644 apps/playground-web/src/components/engine/gasless/Webhook.tsx create mode 100644 apps/playground-web/src/components/engine/minting/TransactionResults.tsx create mode 100644 apps/playground-web/src/components/engine/minting/erc1155-mint-to.tsx create mode 100644 apps/playground-web/src/components/ui/card.tsx create mode 100644 apps/playground-web/src/components/ui/table.tsx diff --git a/apps/playground-web/package.json b/apps/playground-web/package.json index 932e46c168c..ddd23b9b550 100644 --- a/apps/playground-web/package.json +++ b/apps/playground-web/package.json @@ -28,6 +28,7 @@ "@radix-ui/react-tabs": "^1.1.1", "@radix-ui/react-tooltip": "1.1.4", "@tanstack/react-query": "5.61.4", + "@thirdweb-dev/engine": "^0.0.16", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", "lucide-react": "0.461.0", @@ -41,6 +42,7 @@ "shiki": "1.22.2", "tailwind-merge": "^2.5.5", "thirdweb": "workspace:*", + "timeago.js": "^4.0.2", "use-debounce": "^10.0.4" }, "devDependencies": { diff --git a/apps/playground-web/public/BaseSep.png b/apps/playground-web/public/BaseSep.png new file mode 100644 index 0000000000000000000000000000000000000000..2b3765ad5c666920d5a085181811d33180fcfcf7 GIT binary patch literal 22203 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 literal 0 HcmV?d00001 diff --git a/apps/playground-web/public/airdrop.avif b/apps/playground-web/public/airdrop.avif new file mode 100644 index 0000000000000000000000000000000000000000..51492b89e12a98edd7bc6a3a46454bffa6397953 GIT binary patch literal 21496 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

niHB>fafd+Cc^~tX- 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 PnV!?~mIB)+K{Vcg^o-ss literal 0 HcmV?d00001 diff --git a/apps/playground-web/public/webhooks.avif b/apps/playground-web/public/webhooks.avif new file mode 100644 index 0000000000000000000000000000000000000000..ec7a214452204cf285611d386e3d19df5416d3b9 GIT binary patch literal 33695 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 literal 0 HcmV?d00001 diff --git a/apps/playground-web/src/app/api/airdrop/route.ts b/apps/playground-web/src/app/api/airdrop/route.ts new file mode 100644 index 00000000000..6fca6a8e9c2 --- /dev/null +++ b/apps/playground-web/src/app/api/airdrop/route.ts @@ -0,0 +1,155 @@ +import { Engine } from "@thirdweb-dev/engine"; +import * as dotenv from "dotenv"; +import type { NextRequest } from "next/server"; +import { NextResponse } from "next/server"; + +dotenv.config(); + +const CHAIN_ID = "84532"; +const BACKEND_WALLET_ADDRESS = process.env.ENGINE_BACKEND_WALLET as string; + +console.log("Environment Variables:"); +console.log("CHAIN_ID:", CHAIN_ID); +console.log("BACKEND_WALLET_ADDRESS:", BACKEND_WALLET_ADDRESS); +console.log("ENGINE_URL:", process.env.ENGINE_URL); +console.log( + "ACCESS_TOKEN:", + process.env.ENGINE_ACCESS_TOKEN ? "Set" : "Not Set", +); + +const engine = new Engine({ + url: process.env.ENGINE_URL as string, + accessToken: process.env.ENGINE_ACCESS_TOKEN as string, +}); + +interface MintResult { + queueId: string; + status: "Queued" | "Sent" | "Mined" | "error"; + transactionHash?: string; + blockExplorerUrl?: string; + errorMessage?: string; + toAddress: string; + amount: string; + chainId: number; + network: "Base Sep"; +} + +export async function POST(req: NextRequest) { + try { + const body = await req.json(); + console.log("Request body:", body); + + const { contractAddress, data } = body; + if (!Array.isArray(data)) { + return NextResponse.json( + { error: "Invalid data format" }, + { status: 400 }, + ); + } + + if (data.length === 0) { + return NextResponse.json({ error: "Empty data array" }, { status: 400 }); + } + + console.log(`Attempting to mint batch to ${data.length} receivers`); + console.log("Using CONTRACT_ADDRESS:", contractAddress); + + const res = await engine.erc20.mintBatchTo( + CHAIN_ID, + contractAddress, + BACKEND_WALLET_ADDRESS, + { + data: data.map((item) => ({ + toAddress: item.toAddress, + amount: item.amount, + })), + }, + ); + + console.log("Mint batch initiated, queue ID:", res.result.queueId); + const result = await pollToMine(res.result.queueId, data[0]); + return NextResponse.json([result]); + } catch (error: unknown) { + console.error("Error minting ERC20 tokens", error); + return NextResponse.json( + [ + { + queueId: "", + status: "error", + errorMessage: + error instanceof Error + ? error.message + : "An unknown error occurred", + toAddress: "", + amount: "", + chainId: Number.parseInt(CHAIN_ID), + network: "Base Sep", + }, + ], + { status: 500 }, + ); + } +} + +async function pollToMine( + queueId: string, + firstItem: { toAddress: string; amount: string }, +): Promise { + let attempts = 0; + const maxAttempts = 10; + + while (attempts < maxAttempts) { + try { + const status = await engine.transaction.status(queueId); + + if (status.result.status === "mined") { + console.log( + "Transaction mined! 🥳 ERC20 tokens have been minted", + queueId, + ); + const transactionHash = status.result.transactionHash; + const blockExplorerUrl = `https://base-sepolia.blockscout.com/tx/${transactionHash}`; + console.log("View transaction on the blockexplorer:", blockExplorerUrl); + return { + queueId, + status: "Mined", + transactionHash: transactionHash ?? undefined, + blockExplorerUrl: blockExplorerUrl, + toAddress: firstItem.toAddress, + amount: firstItem.amount, + chainId: Number.parseInt(CHAIN_ID), + network: "Base Sep", + }; + } + + if (status.result.status === "errored") { + console.error("Mint failed", queueId); + console.error(status.result.errorMessage); + return { + queueId, + status: "error", + errorMessage: status.result.errorMessage ?? "Unknown error occurred", + toAddress: firstItem.toAddress, + amount: firstItem.amount, + chainId: Number.parseInt(CHAIN_ID), + network: "Base Sep", + }; + } + } catch (error) { + console.error("Error checking transaction status:", error); + } + + attempts++; + await new Promise((resolve) => setTimeout(resolve, 5000)); + } + + return { + queueId, + status: "error", + errorMessage: "Transaction did not mine within the expected time", + toAddress: firstItem.toAddress, + amount: firstItem.amount, + chainId: Number.parseInt(CHAIN_ID), + network: "Base Sep", + }; +} diff --git a/apps/playground-web/src/app/api/claimTo/route.ts b/apps/playground-web/src/app/api/claimTo/route.ts new file mode 100644 index 00000000000..3bfe7476a3f --- /dev/null +++ b/apps/playground-web/src/app/api/claimTo/route.ts @@ -0,0 +1,226 @@ +import { Engine } from "@thirdweb-dev/engine"; +import * as dotenv from "dotenv"; +import type { NextRequest } from "next/server"; +import { NextResponse } from "next/server"; + +dotenv.config(); + +const BASESEP_CHAIN_ID = "84532"; +const BACKEND_WALLET_ADDRESS = process.env.ENGINE_BACKEND_WALLET as string; + +console.log("Environment Variables:"); +console.log("CHAIN_ID:", BASESEP_CHAIN_ID); +console.log("BACKEND_WALLET_ADDRESS:", BACKEND_WALLET_ADDRESS); +console.log("ENGINE_URL:", process.env.ENGINE_URL); +console.log( + "ACCESS_TOKEN:", + process.env.ENGINE_ACCESS_TOKEN ? "Set" : "Not Set", +); + +const engine = new Engine({ + url: process.env.ENGINE_URL as string, + accessToken: process.env.ENGINE_ACCESS_TOKEN as string, +}); + +type TransactionStatus = "Queued" | "Sent" | "Mined" | "error"; + +interface ClaimResult { + queueId: string; + status: TransactionStatus; + transactionHash?: string | undefined | null; + blockExplorerUrl?: string | undefined | null; + errorMessage?: string; + toAddress?: string; + amount?: string; + chainId?: string; + timestamp?: number; +} + +// Store ongoing polling processes +const pollingProcesses = new Map(); + +// Helper function to make a single claim +async function makeClaimRequest( + chainId: string, + contractAddress: string, + data: { + recipient: string; + quantity: number; + }, +): Promise { + try { + // Validate the recipient address format + if (!data.recipient.match(/^0x[a-fA-F0-9]{40}$/)) { + throw new Error("Invalid wallet address format"); + } + + const res = await engine.erc721.claimTo( + chainId, + contractAddress, + BACKEND_WALLET_ADDRESS, + { + receiver: data.recipient.toString(), + quantity: data.quantity.toString(), + txOverrides: { + gas: "530000", + maxFeePerGas: "1000000000", + maxPriorityFeePerGas: "1000000000", + }, + }, + ); + + const initialResponse: ClaimResult = { + queueId: res.result.queueId, + status: "Queued", + toAddress: data.recipient, + amount: data.quantity.toString(), + chainId, + timestamp: Date.now(), + }; + + startPolling(res.result.queueId); + return initialResponse; + } catch (error) { + console.error("Claim request error:", error); + throw error; + } +} + +export async function POST(req: NextRequest) { + try { + const body = await req.json(); + + if (!body.receiver || !body.quantity || !body.contractAddress) { + return NextResponse.json( + { error: "Missing receiver, quantity, or contract address" }, + { status: 400 }, + ); + } + + // Validate contract address format + if (!body.contractAddress.match(/^0x[a-fA-F0-9]{40}$/)) { + return NextResponse.json( + { error: "Invalid contract address format" }, + { status: 400 }, + ); + } + + const result = await makeClaimRequest( + BASESEP_CHAIN_ID, + body.contractAddress, + { + recipient: body.receiver, + quantity: Number.parseInt(body.quantity), + }, + ); + + return NextResponse.json({ result }); + } catch (error) { + console.error("API Error:", error); + return NextResponse.json( + { + error: + error instanceof Error ? error.message : "Unknown error occurred", + details: error instanceof Error ? error.stack : undefined, + }, + { status: 400 }, + ); + } +} + +function startPolling(queueId: string) { + const maxPollingTime = 5 * 60 * 1000; // 5 minutes timeout + const startTime = Date.now(); + + const pollingInterval = setInterval(async () => { + try { + // Check if we've exceeded the maximum polling time + if (Date.now() - startTime > maxPollingTime) { + clearInterval(pollingInterval); + pollingProcesses.delete(queueId); + console.log(`Polling timeout for queue ID: ${queueId}`); + return; + } + + const result = await pollToMine(queueId); + if (result.status === "Mined" || result.status === "error") { + clearInterval(pollingInterval); + pollingProcesses.delete(queueId); + console.log("Final result:", result); + } + } catch (error) { + console.error("Error in polling process:", error); + clearInterval(pollingInterval); + pollingProcesses.delete(queueId); + } + }, 1500); + + pollingProcesses.set(queueId, pollingInterval); +} + +async function pollToMine(queueId: string): Promise { + console.log(`Polling for queue ID: ${queueId}`); + const status = await engine.transaction.status(queueId); + console.log(`Current status: ${status.result.status}`); + + switch (status.result.status) { + case "queued": + console.log("Transaction is queued"); + return { queueId, status: "Queued" }; + case "sent": + console.log("Transaction is submitted to the network"); + return { queueId, status: "Sent" }; + case "mined": { + console.log( + "Transaction mined! 🥳 ERC721 token has been claimed", + queueId, + ); + const transactionHash = status.result.transactionHash; + const blockExplorerUrl = + status.result.chainId === BASESEP_CHAIN_ID + ? `https://base-sepolia.blockscout.com/tx/${transactionHash}` + : ""; + console.log("View transaction on the blockexplorer:", blockExplorerUrl); + return { + queueId, + status: "Mined", + transactionHash: transactionHash ?? undefined, + blockExplorerUrl: blockExplorerUrl, + }; + } + case "errored": + console.error("Claim failed", queueId); + console.error(status.result.errorMessage); + return { + queueId, + status: "error", + errorMessage: status.result.errorMessage || "Transaction failed", + }; + default: + return { queueId, status: "Queued" }; + } +} + +// Add a new endpoint to check the status +export async function GET(req: NextRequest) { + const { searchParams } = new URL(req.url); + const queueId = searchParams.get("queueId"); + + if (!queueId) { + return NextResponse.json({ error: "Missing queueId" }, { status: 400 }); + } + + try { + const result = await pollToMine(queueId); + return NextResponse.json(result); + } catch (error) { + console.error("Error checking transaction status:", error); + return NextResponse.json( + { + status: "error" as TransactionStatus, + error: "Failed to check transaction status", + }, + { status: 500 }, + ); + } +} diff --git a/apps/playground-web/src/app/api/erc20BatchMintTo/route.ts b/apps/playground-web/src/app/api/erc20BatchMintTo/route.ts new file mode 100644 index 00000000000..276bf896759 --- /dev/null +++ b/apps/playground-web/src/app/api/erc20BatchMintTo/route.ts @@ -0,0 +1,125 @@ +import { Engine } from "@thirdweb-dev/engine"; +import * as dotenv from "dotenv"; +import type { NextRequest } from "next/server"; +import { NextResponse } from "next/server"; +import type { Address } from "thirdweb"; + +dotenv.config(); + +const BASESEP_CHAIN_ID = "84532"; +const BACKEND_WALLET_ADDRESS = process.env.ENGINE_BACKEND_WALLET as string; + +console.log("Environment Variables:"); +console.log("CHAIN_ID:", BASESEP_CHAIN_ID); +console.log("BACKEND_WALLET_ADDRESS:", BACKEND_WALLET_ADDRESS); +console.log("ENGINE_URL:", process.env.ENGINE_URL); +console.log( + "ACCESS_TOKEN:", + process.env.ENGINE_ACCESS_TOKEN ? "Set" : "Not Set", +); + +const engine = new Engine({ + url: process.env.ENGINE_URL as string, + accessToken: process.env.ENGINE_ACCESS_TOKEN as string, +}); + +const chain = "84532"; + +type Receiver = { + toAddress: Address; + amount: string; +}; + +type DataEntry = { + toAddress: string; + amount: string; +}; + +export async function POST(req: NextRequest) { + try { + const { data, contractAddress } = await req.json(); + + console.log("Received request with:", { + contractAddress, + dataLength: data.length, + sampleData: data[0], + }); + + const receivers: Receiver[] = data.map((entry: DataEntry) => ({ + toAddress: entry.toAddress as Address, + amount: entry.amount, + })); + + const chunks: Receiver[][] = []; + const chunkSize = 10; + for (let i = 0; i < receivers.length; i += chunkSize) { + chunks.push(receivers.slice(i, i + chunkSize)); + } + + // Process first chunk and return immediately with queued status + const firstChunk = chunks[0]; + const res = await engine.erc20.mintBatchTo( + chain, + contractAddress, + BACKEND_WALLET_ADDRESS, + { + data: firstChunk, + }, + ); + + // Return initial queued status + const initialResult = { + queueId: res.result.queueId, + status: "queued" as const, + addresses: firstChunk.map((r) => r.toAddress), + amounts: firstChunk.map((r) => r.amount), + timestamp: Date.now(), + chainId: Number.parseInt(chain), + network: "Base Sep" as const, + }; + + // Start polling in the background + pollToMine(res.result.queueId).then((pollResult) => { + console.log("Transaction completed:", pollResult); + }); + + return NextResponse.json([initialResult]); + } catch (error: unknown) { + console.error("Detailed error:", error); + const errorMessage = + error instanceof Error ? error.message : "Unknown error occurred"; + return NextResponse.json( + { + error: "Transfer failed", + details: errorMessage, + }, + { status: 500 }, + ); + } +} + +async function pollToMine(queueId: string) { + try { + const status = await engine.transaction.status(queueId); + + if (status.result.status === "mined") { + const transactionHash = status.result.transactionHash; + const blockExplorerUrl = `https://base-sepolia.blockscout.com/tx/${transactionHash}`; + return { status: "Mined", queueId, transactionHash, blockExplorerUrl }; + } + + return { + status: + status.result.status.charAt(0).toUpperCase() + + status.result.status.slice(1), + queueId, + }; + } catch (error) { + console.error("Error checking transaction status:", error); + return { + status: "error", + queueId, + errorMessage: "Failed to check transaction status", + }; + } +} diff --git a/apps/playground-web/src/app/api/mintTo/route.ts b/apps/playground-web/src/app/api/mintTo/route.ts new file mode 100644 index 00000000000..b3f4767ac2b --- /dev/null +++ b/apps/playground-web/src/app/api/mintTo/route.ts @@ -0,0 +1,105 @@ +import { Engine } from "@thirdweb-dev/engine"; +import * as dotenv from "dotenv"; +import { type NextRequest, NextResponse } from "next/server"; + +dotenv.config(); + +const CHAIN_ID = "84532"; +const CONTRACT_ADDRESS = "0x8CD193648f5D4E8CD9fD0f8d3865052790A680f6"; +const BACKEND_WALLET_ADDRESS = process.env.ENGINE_BACKEND_WALLET as string; + +// Add logging for environment variables +console.log("Environment Variables:"); +console.log("CHAIN_ID:", CHAIN_ID); +console.log("BACKEND_WALLET_ADDRESS:", BACKEND_WALLET_ADDRESS); +console.log("CONTRACT_ADDRESS:", CONTRACT_ADDRESS); +console.log("ENGINE_URL:", process.env.ENGINE_URL); +console.log( + "ACCESS_TOKEN:", + process.env.ENGINE_ACCESS_TOKEN ? "Set" : "Not Set", +); + +const engine = new Engine({ + url: process.env.ENGINE_URL as string, + accessToken: process.env.ENGINE_ACCESS_TOKEN as string, +}); + +export async function POST(req: NextRequest) { + try { + const body = await req.json(); + console.log("Request body:", body); + + const receiver = body.receiver || body.toAddress; + const metadataWithSupply = body.metadataWithSupply; + + if (!receiver || !metadataWithSupply) { + return NextResponse.json( + { error: "Missing receiver or metadataWithSupply" }, + { status: 400 }, + ); + } + + console.log( + `Attempting to mint for receiver: ${receiver}, metadataWithSupply:`, + metadataWithSupply, + ); + console.log("Using CONTRACT_ADDRESS:", CONTRACT_ADDRESS); + + const res = await engine.erc1155.mintTo( + CHAIN_ID, + CONTRACT_ADDRESS, + BACKEND_WALLET_ADDRESS, + { + receiver, + metadataWithSupply, + }, + ); + + // Return immediately with queued status + const initialResult = { + queueId: res.result.queueId, + status: "Queued" as const, + toAddress: receiver, + amount: metadataWithSupply.supply || "1", + timestamp: Date.now(), + chainId: Number.parseInt(CHAIN_ID), + network: "Base Sep" as const, + }; + + // Start polling in the background + pollToMine(res.result.queueId).then((pollResult) => { + // This will be handled by the frontend polling + console.log("Transaction completed:", pollResult); + }); + + return NextResponse.json(initialResult); + } catch (error: unknown) { + console.error("Error minting ERC1155 tokens", error); + if (error instanceof Error) { + return NextResponse.json( + { error: "Error minting ERC1155 tokens", details: error.message }, + { status: 500 }, + ); + } + } +} + +async function pollToMine(queueId: string) { + try { + const status = await engine.transaction.status(queueId); + + if (status.result.status === "mined") { + const transactionHash = status.result.transactionHash; + const blockExplorerUrl = `https://base-sepolia.blockscout.com/tx/${transactionHash}`; + return { status: "Mined", transactionHash, blockExplorerUrl }; + } + + return { status: status.result.status }; + } catch (error) { + console.error("Error checking transaction status:", error); + return { + status: "error", + errorMessage: "Failed to check transaction status", + }; + } +} diff --git a/apps/playground-web/src/app/api/transaction-status/route.ts b/apps/playground-web/src/app/api/transaction-status/route.ts new file mode 100644 index 00000000000..b52823f4bf2 --- /dev/null +++ b/apps/playground-web/src/app/api/transaction-status/route.ts @@ -0,0 +1,41 @@ +import { Engine } from "@thirdweb-dev/engine"; +import { type NextRequest, NextResponse } from "next/server"; + +const engine = new Engine({ + url: process.env.ENGINE_URL as string, + accessToken: process.env.ACCESS_TOKEN as string, +}); + +export async function GET(req: NextRequest) { + const searchParams = req.nextUrl.searchParams; + const queueId = searchParams.get("queueId"); + + if (!queueId) { + return NextResponse.json({ error: "Missing queueId" }, { status: 400 }); + } + + try { + const status = await engine.transaction.status(queueId); + + if (status.result.status === "mined") { + const transactionHash = status.result.transactionHash; + const blockExplorerUrl = `https://base-sepolia.blockscout.com/tx/${transactionHash}`; + return NextResponse.json({ + status: "Mined", + transactionHash, + blockExplorerUrl, + }); + } + + return NextResponse.json({ + status: status.result.status, + errorMessage: status.result.errorMessage, + }); + } catch (error) { + console.error("Error checking transaction status:", error); + return NextResponse.json( + { error: "Failed to check transaction status" }, + { status: 500 }, + ); + } +} diff --git a/apps/playground-web/src/app/engine/airdrop/page.tsx b/apps/playground-web/src/app/engine/airdrop/page.tsx new file mode 100644 index 00000000000..3fb8d20433a --- /dev/null +++ b/apps/playground-web/src/app/engine/airdrop/page.tsx @@ -0,0 +1,45 @@ +import { AirdropERC20 } from "@/components/engine/airdrop/airdrop-erc20"; +import ThirdwebProvider from "@/components/thirdweb-provider"; +import { EngineAPIHeader } from "../../../components/blocks/EngineAPIHeader"; +// TODO: Get updated banner image and description. +export default function Page() { + return ( + +

+ + Engine makes it effortless for any developer to airdrop tokens at + scale. You sponsor the gas so your users only need a wallet + address! + + } + docsLink="https://thirdweb-engine.apidocumentation.com/reference#tag/erc20/POST/contract/{chain}/{contractAddress}/erc20/mint-batch-to?utm_source=playground" + heroLink="/airdrop.avif" + /> + +
+ +
+
+ + ); +} + +function InGameCurrency() { + return ( + <> +
+

+ Airdrop +

+

+ Use Engine to Airdrop in-game currency to a list of players in one + transaction. +

+
+ + + ); +} diff --git a/apps/playground-web/src/app/engine/minting/page.tsx b/apps/playground-web/src/app/engine/minting/page.tsx new file mode 100644 index 00000000000..3c8a9930fba --- /dev/null +++ b/apps/playground-web/src/app/engine/minting/page.tsx @@ -0,0 +1,44 @@ +import { ERC1155MintTo } from "@/components/engine/minting/erc1155-mint-to"; +import ThirdwebProvider from "@/components/thirdweb-provider"; +import { EngineAPIHeader } from "../../../components/blocks/EngineAPIHeader"; +// TODO: Get updated banner image and description. +export default function Page() { + return ( + +
+ + Allow your users to mint new tokens into any given contract. You + sponsor the gas so your users only need a wallet address! + + } + docsLink="https://thirdweb-engine.apidocumentation.com/reference#tag/erc1155/POST/contract/{chain}/{contractAddress}/erc1155/mint-to?utm_source=playground" + heroLink="/minting.avif" + /> + +
+ +
+
+
+ ); +} + +function Minting() { + return ( + <> +
+

+ Minting +

+

+ Allow your users to mint new tokens into any given contract. You + sponsor the gas so your users only need a wallet address! +

+
+ + + ); +} diff --git a/apps/playground-web/src/app/engine/webhooks/page.tsx b/apps/playground-web/src/app/engine/webhooks/page.tsx new file mode 100644 index 00000000000..af146ca17b6 --- /dev/null +++ b/apps/playground-web/src/app/engine/webhooks/page.tsx @@ -0,0 +1,44 @@ +import { Sponsorship } from "@/components/engine/gasless/Sponsorship"; +import ThirdwebProvider from "@/components/thirdweb-provider"; +import { EngineAPIHeader } from "../../../components/blocks/EngineAPIHeader"; +// TODO: Get updated banner image and description. +export default function Page() { + return ( + +
+ + Configure webhooks in Engine to notify your backend server of + transaction or backend wallet events. + + } + docsLink="https://portal.thirdweb.com/engine/features/webhooks?utm_source=playground" + heroLink="/webhooks.avif" + /> + +
+ +
+
+
+ ); +} + +function Webhooks() { + return ( + <> +
+

+ Webhooks +

+

+ Configure webhooks in Engine to notify your backend server of + transaction or backend wallet events. +

+
+ + + ); +} diff --git a/apps/playground-web/src/app/navLinks.ts b/apps/playground-web/src/app/navLinks.ts index d870b0e4707..8b42463b616 100644 --- a/apps/playground-web/src/app/navLinks.ts +++ b/apps/playground-web/src/app/navLinks.ts @@ -21,7 +21,7 @@ export const navLinks: SidebarLink[] = [ }, { name: "Account Abstraction", - expanded: true, + expanded: false, links: [ { name: "Connect", @@ -39,7 +39,7 @@ export const navLinks: SidebarLink[] = [ }, { name: "In-App Wallet", - expanded: true, + expanded: false, links: [ { name: "Any Auth", @@ -57,7 +57,7 @@ export const navLinks: SidebarLink[] = [ }, { name: "Pay", - expanded: true, + expanded: false, links: [ { name: "Top up", @@ -73,6 +73,32 @@ export const navLinks: SidebarLink[] = [ }, ], }, + { + name: "Engine", + expanded: false, + links: [ + { + name: "Airdrop", + href: "/engine/airdrop", + }, + { + name: "Minting", + href: "/engine/minting", + }, + { + name: "Webhooks", + href: "/engine/webhooks", + }, + // { + // name: "Session Keys", + // href: "/engine/account-abstraction/session-keys", + // }, + // { + // name: "Smart Backend Wallets", + // href: "/engine/account-abstraction/smart-backend-wallets", + // }, + ], + }, { name: "Auth", href: "/connect/auth", diff --git a/apps/playground-web/src/components/blocks/EngineAPIHeader.tsx b/apps/playground-web/src/components/blocks/EngineAPIHeader.tsx new file mode 100644 index 00000000000..16b20f4eda9 --- /dev/null +++ b/apps/playground-web/src/components/blocks/EngineAPIHeader.tsx @@ -0,0 +1,64 @@ +import Image from "next/image"; +import Link from "next/link"; +import { Button } from "../ui/button"; + +export function EngineAPIHeader(props: { + title: string; + description: React.ReactNode; + docsLink: string; + heroLink: string; +}) { + return ( +
+ {/* Left */} +
+

+ {props.title} +

+

+ {props.description} +

+ +
+ + + +
+
+ + {/* Right */} + +
+ ); +} diff --git a/apps/playground-web/src/components/engine/airdrop/TransactionResults.tsx b/apps/playground-web/src/components/engine/airdrop/TransactionResults.tsx new file mode 100644 index 00000000000..a6bc3acef77 --- /dev/null +++ b/apps/playground-web/src/components/engine/airdrop/TransactionResults.tsx @@ -0,0 +1,278 @@ +"use client"; + +import { Button } from "@/components/ui/button"; +import { + Card, + CardContent, + CardFooter, + CardHeader, +} from "@/components/ui/card"; +import { + Table, + TableBody, + TableCell, + TableHead, + TableHeader, + TableRow, +} from "@/components/ui/table"; +import type React from "react"; +import { useState } from "react"; +import { format } from "timeago.js"; + +interface ClaimTransactionResults { + queueId: string; + status: "Queued" | "Sent" | "Mined" | "error"; + transactionHash?: string; + blockExplorerUrl?: string; + errorMessage: "Error" | undefined; + toAddress: string; + amount: string; + timestamp?: number; + chainId: number; + network: "Ethereum" | "Base Sep" | "OP Sep"; +} + +interface ClaimTransactionResultsProps { + results: ClaimTransactionResults[]; +} +// I did have one component of this, but it was causing weird queuing issues when shared among multiple components. So just created one for each instead. +export function ClaimTransactionResults({ + results, +}: ClaimTransactionResultsProps) { + const [currentPage, setCurrentPage] = useState(1); + const [showLeftGradient, setShowLeftGradient] = useState(false); + const [showRightGradient, setShowRightGradient] = useState(true); + const itemsPerPage = 2; + // Added dummy transactions so the table doesn't look empty. + const dummyTransaction1: ClaimTransactionResults = { + queueId: "0x1234567890abcdef", + status: "Mined", + transactionHash: "0xabcdef1234567890", + blockExplorerUrl: "https://etherscan.io/tx/0xabcdef1234567890", + toAddress: "0x1234567890abcdef", + amount: "1.0", + timestamp: Date.now() - 15 * 60 * 1000, + chainId: 1, + network: "Ethereum", + errorMessage: undefined, + }; + + const dummyTransaction2: ClaimTransactionResults = { + queueId: "0x9876543210fedcba", + status: "Mined", + transactionHash: "0x1234567890abcdef", + blockExplorerUrl: "https://etherscan.io/tx/0x1234567890abcdef", + toAddress: "0xabcdef1234567890", + amount: "0.5", + timestamp: Date.now() - 30 * 60 * 1000, + chainId: 1, + network: "Base Sep", + errorMessage: undefined, + }; + + const sortedResults = [...results].reverse(); + const sortedResultsWithDummy = [ + ...sortedResults, + dummyTransaction1, + dummyTransaction2, + ]; + + const indexOfLastItem = currentPage * itemsPerPage; + const indexOfFirstItem = indexOfLastItem - itemsPerPage; + const currentItems = sortedResultsWithDummy.slice( + indexOfFirstItem, + indexOfLastItem, + ); + const totalPages = Math.ceil(sortedResultsWithDummy.length / itemsPerPage); + + const handleNextPage = () => { + setCurrentPage((prev) => Math.min(prev + 1, totalPages)); + }; + + const handlePrevPage = () => { + setCurrentPage((prev) => Math.max(prev - 1, 1)); + }; + + const getDisplayStatus = (result: ClaimTransactionResults) => { + if (result.status === "Mined" && !result.transactionHash) { + return "Pending"; + } + return result.status; + }; + + const getStatusColor = (status: string) => { + switch (status) { + case "Mined": + return "bg-green-500/20 text-green-400"; + case "Queued": + case "Pending": + return "bg-yellow-500/20 text-yellow-400"; + case "Sent": + return "bg-blue-500/20 text-blue-400"; + default: + return "bg-red-500/20 text-red-400"; + } + }; + + const handleScroll = (e: React.UIEvent) => { + const target = e.currentTarget; + const isAtStart = target.scrollLeft === 0; + const isAtEnd = + target.scrollLeft + target.clientWidth >= target.scrollWidth - 1; // -1 for rounding errors + + setShowLeftGradient(!isAtStart); + setShowRightGradient(!isAtEnd); + }; + + return ( + + +

+ Transaction Results +

+ + Last 24 hours • {sortedResultsWithDummy.length} transactions + +
+ +
+ + + + Queue ID + Network + From + Queued + Status + Tx Hash + + + + {currentItems.map((result, index) => ( + + + {result.queueId + ? `${result.queueId.substring(0, 6)}...${result.queueId.substring( + result.queueId.length - 4, + )}` + : "----"} + + + + {result.network === "Base Sep" && ( + Base + )} + {result.network === "OP Sep" && ( + Optimism Sep + )} + {result.network === "Ethereum" && ( + Ethereum + )} + {result.network} + + + + {(() => { + if (!result.toAddress) return "----"; + + const addressDisplay = `${result.toAddress.substring(0, 6)}...${result.toAddress.substring( + result.toAddress.length - 4, + )}`; + // Keeping OP here for consistency. Will be adding a component for Optimism soon. + const getExplorerUrl = () => { + switch (result.network) { + case "Base Sep": + return `https://base-sepolia.blockscout.com/address/${result.toAddress}?tab=tokens`; + case "OP Sep": + return `https://optimism-sepolia.blockscout.com/address/${result.toAddress}?tab=tokens`; + case "Ethereum": + return `https://etherscan.io/address/${result.toAddress}?tab=tokens`; + default: + return null; + } + }; + + const explorerUrl = getExplorerUrl(); + + return explorerUrl ? ( + + {addressDisplay} + + ) : ( + addressDisplay + ); + })()} + + + {result.timestamp ? format(result.timestamp) : "Just now"} + + + + {getDisplayStatus(result)} + + + + {result.transactionHash && result.blockExplorerUrl ? ( + + {`${result.transactionHash.substring(0, 6)}...${result.transactionHash.substring( + result.transactionHash.length - 4, + )}`} + + ) : result.errorMessage ? ( + + {result.errorMessage} + + ) : ( + "----" + )} + + + ))} + +
+
+ {showLeftGradient && ( +
+ )} + {showRightGradient && ( +
+ )} + + + + + Page {currentPage} of {totalPages} + + + + + ); +} diff --git a/apps/playground-web/src/components/engine/airdrop/airdrop-erc20.tsx b/apps/playground-web/src/components/engine/airdrop/airdrop-erc20.tsx new file mode 100644 index 00000000000..93a2556fa2f --- /dev/null +++ b/apps/playground-web/src/components/engine/airdrop/airdrop-erc20.tsx @@ -0,0 +1,223 @@ +"use client"; + +import { Button } from "@/components/ui/button"; +import { Card } from "@/components/ui/card"; +import { + Table, + TableBody, + TableCell, + TableHead, + TableHeader, + TableRow, +} from "@/components/ui/table"; +import { useState } from "react"; +import { ClaimTransactionResults as ClaimTransactionResultsComponent } from "./TransactionResults"; + +interface ClaimTransactionResults { + queueId: string; + status: "Queued" | "Sent" | "Mined" | "error"; + transactionHash?: string; + blockExplorerUrl?: string; + errorMessage: "Error" | undefined; + toAddress: string; + amount: string; + timestamp?: number; + chainId: number; + network: "Ethereum" | "Base Sep" | "OP Sep"; +} + +interface CsvRow { + toAddress: string; + amount: string; +} + +interface BatchResult { + queueId: string; + addresses: string[]; + amounts: string[]; + status: "Queued" | "Sent" | "Mined" | "error"; + timestamp: number; + chainId: number; + network: "Ethereum" | "Base Sep" | "OP Sep"; +} + +// Setting dummy addresses so no one gets spammed. +export function AirdropERC20() { + const [csvData] = useState([ + { toAddress: "0x1f91EB653116A43413930c1df0CF5794fCc2D611", amount: "1" }, + { toAddress: "0xA707E9650631800a635c629e9C8E5937b7277a08", amount: "1" }, + { toAddress: "0xF1f466c973C197e5D9318F6241C2da31742d3d03", amount: "1" }, + { toAddress: "0x56671F2cb5d401f989Df5d3B4f8C814E6A022bf7", amount: "1" }, + { toAddress: "0x5F0633eD9c359C84F9A7B4A898DA6864893fe943", amount: "1" }, + { toAddress: "0x626522375a0F448fc7B87055f83a0402b89D06Eb", amount: "1" }, + { toAddress: "0x4D9c3Ae6ce7751616cB29E2bcF972357f28924E0", amount: "1" }, + { toAddress: "0xc4757A402F4c5a447B2b20670ADd10A042f1142D", amount: "1" }, + { toAddress: "0x9244B15679F4d4e1CEE0Ef6401A59b3d302c8Fca", amount: "1" }, + { toAddress: "0xF7DB7C0205f5Bf2E32F55A633703da1d075036A7", amount: "1" }, + ]); + + const [currentPage, setCurrentPage] = useState(0); + const rowsPerPage = 5; + + const paginatedData = csvData.slice( + currentPage * rowsPerPage, + (currentPage + 1) * rowsPerPage, + ); + + const totalPages = Math.ceil(csvData.length / rowsPerPage); + + const [isSubmitting, setIsSubmitting] = useState(false); + const [results, setResults] = useState([]); + + const pollTransactionStatus = async (queueId: string) => { + const pollInterval = setInterval(async () => { + try { + const response = await fetch( + `/api/transaction-status?queueId=${queueId}`, + ); + const status = await response.json(); + + setResults((prevResults) => + prevResults.map((result) => { + if (result.queueId === queueId) { + return { + ...result, + ...status, + status: status.status === "mined" ? "Mined" : status.status, + }; + } + return result; + }), + ); + + if (status.status === "Mined" || status.status === "error") { + clearInterval(pollInterval); + } + } catch (error) { + console.error("Error polling status:", error); + clearInterval(pollInterval); + } + }, 2000); + + setTimeout(() => clearInterval(pollInterval), 5 * 60 * 1000); + }; + + const handleSubmit = async (e: React.FormEvent) => { + e.preventDefault(); + setIsSubmitting(true); + setResults([]); + + try { + const response = await fetch("/api/erc20BatchMintTo", { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ + contractAddress: "0xcB30dB8FB977e8b27ae34c86aF16C4F5E428c0bE", + data: csvData.map((row) => ({ + toAddress: row.toAddress, + amount: row.amount, + })), + }), + }); + + if (!response.ok) { + throw new Error(`HTTP error! status: ${response.status}`); + } + + const result = await response.json(); + + // Transform the initial queued results + const transformedResults = result.flatMap((batch: BatchResult) => + batch.addresses.map((address: string, index: number) => ({ + queueId: batch.queueId, + status: batch.status, + toAddress: address, + amount: batch.amounts[index], + timestamp: batch.timestamp, + chainId: batch.chainId, + network: batch.network, + })), + ); + + setResults(transformedResults); + + // Start polling for each batch + for (const batch of result) { + pollTransactionStatus(batch.queueId); + } + } catch (error) { + console.error("Error:", error); + setResults([ + { + queueId: "", + status: "error", + errorMessage: "Error", + toAddress: "", + amount: "", + chainId: 84532, + network: "Base Sep", + }, + ]); + } finally { + setIsSubmitting(false); + } + }; + + return ( +
+
+ +
+
+ + + + Address + Amount + + + + {paginatedData.map((row) => ( + + {row.toAddress} + {row.amount} + + ))} + +
+
+ + + Page {currentPage + 1} of {totalPages} + + +
+
+
+
+
+ + +
+ ); +} diff --git a/apps/playground-web/src/components/engine/gasless/Sponsorship.tsx b/apps/playground-web/src/components/engine/gasless/Sponsorship.tsx new file mode 100644 index 00000000000..decd575a5ae --- /dev/null +++ b/apps/playground-web/src/components/engine/gasless/Sponsorship.tsx @@ -0,0 +1,181 @@ +"use client"; + +import { Button } from "@/components/ui/button"; +import { Input } from "@/components/ui/input"; +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from "@/components/ui/select"; +import { THIRDWEB_CLIENT } from "@/lib/client"; +import { useState } from "react"; +import { baseSepolia } from "thirdweb/chains"; +import { ConnectButton, useActiveAccount } from "thirdweb/react"; +import { Webhook } from "./Webhook"; + +interface ClaimTransactionResults { + queueId: string; + status: string; + toAddress: string; + amount: string; + timestamp?: number; + chainId: number; + network: string; + errorMessage?: string; +} + +// This says Sponsorship, but it's actually just displaying a dummy webhook + +export function Sponsorship() { + const [contractAddress, setContractAddress] = useState(""); + const [quantity, setQuantity] = useState("1"); + const [isLoading, setIsLoading] = useState(false); + const [queueId, setQueueId] = useState(null); + const [transactions, setTransactions] = useState( + [], + ); + const [selectedContract, setSelectedContract] = useState(""); + const account = useActiveAccount(); + + const handleSubmit = async (e: React.FormEvent) => { + e.preventDefault(); + setIsLoading(true); + + try { + if (!contractAddress.match(/^0x[a-fA-F0-9]{40}$/)) { + throw new Error("Invalid contract address format"); + } + + const response = await fetch("/api/claimTo", { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ + receiver: account?.address, + quantity: quantity, + contractAddress, + }), + }); + + const data = await response.json(); + const { result } = data; + setQueueId(result.queueId); + + const newTransaction: ClaimTransactionResults = { + queueId: result.queueId, + status: "Queued", + toAddress: account?.address || "", + amount: quantity, + chainId: 84532, + network: "Base Sep", + }; + setTransactions((prev) => [...prev, newTransaction]); + + if (result.queueId) { + const pollInterval = setInterval(async () => { + const statusResponse = await fetch( + `/api/claimTo?queueId=${result.queueId}`, + ); + const statusData = await statusResponse.json(); + + setTransactions((prev) => + prev.map((tx) => + tx.queueId === result.queueId + ? { + ...tx, + status: statusData.status, + errorMessage: statusData.errorMessage, + } + : tx, + ), + ); + + if (statusData.status === "Mined") { + clearInterval(pollInterval); + setIsLoading(false); + } else if (statusData.status === "error") { + clearInterval(pollInterval); + setIsLoading(false); + throw new Error(statusData.errorMessage || "Failed to mint NFT"); + } + }, 2000); + } + } catch (error) { + console.error("Error details:", error); + setIsLoading(false); + } + }; + + // 2 contracts here to show engine claim good, and engine claim bad. One has tokens, and the other doesnt so itll fail + return ( +
+
+
+
+ +
+
    Select an NFT Contract to mint
+
+ +
+
    Select the quantity of NFTs to mint
+
+ setQuantity(e.target.value)} + required + className="text-sm sm:text-base" + /> + +
+
+ + +
+ {transactions.map((tx) => ( +
+ Status: {tx.status} - Amount: {tx.amount} +
+ ))} +
+
+ ); +} diff --git a/apps/playground-web/src/components/engine/gasless/Webhook.tsx b/apps/playground-web/src/components/engine/gasless/Webhook.tsx new file mode 100644 index 00000000000..dbd3340678a --- /dev/null +++ b/apps/playground-web/src/components/engine/gasless/Webhook.tsx @@ -0,0 +1,77 @@ +import { + Card, + CardContent, + CardDescription, + CardHeader, + CardTitle, +} from "@/components/ui/card"; +import { useEffect, useState } from "react"; + +// This says Webhook, but it's actually just displaying a dummy webhook + +interface WebhookData { + queueId?: string; + status?: string; +} + +export function Webhook({ queueId }: { queueId: string }) { + const [data, setData] = useState(null); + const [loading, setLoading] = useState(false); + + useEffect(() => { + if (!queueId) return; + + const fetchData = async () => { + try { + const response = await fetch(`/api/claimTo?queueId=${queueId}`); + const jsonData = await response.json(); + setData(jsonData); + + // Continue polling if not in a final state + if (jsonData.status !== "Mined" && jsonData.status !== "error") { + setTimeout(fetchData, 1500); // Match the backend polling interval + } + } catch (error) { + console.error("Error fetching data:", error); + } + }; + + setLoading(true); + fetchData(); + + // Cleanup polling on unmount or queueId change + return () => { + setData(null); + setLoading(false); + }; + }, [queueId]); + + return ( + + + Webhook Response + {data?.status || "Initializing..."} + + +
+ {loading && !data ? ( +

Loading...

+ ) : ( +
+              
+                {JSON.stringify(
+                  {
+                    queueId: data?.queueId,
+                    status: data?.status,
+                  },
+                  null,
+                  2,
+                )}
+              
+            
+ )} +
+
+
+ ); +} diff --git a/apps/playground-web/src/components/engine/minting/TransactionResults.tsx b/apps/playground-web/src/components/engine/minting/TransactionResults.tsx new file mode 100644 index 00000000000..4576c300481 --- /dev/null +++ b/apps/playground-web/src/components/engine/minting/TransactionResults.tsx @@ -0,0 +1,276 @@ +"use client"; + +import { Button } from "@/components/ui/button"; +import { + Card, + CardContent, + CardFooter, + CardHeader, +} from "@/components/ui/card"; +import { + Table, + TableBody, + TableCell, + TableHead, + TableHeader, + TableRow, +} from "@/components/ui/table"; +import type React from "react"; +import { useState } from "react"; +import { format } from "timeago.js"; + +interface ClaimTransactionResults { + queueId: string; + status: "Queued" | "Sent" | "Mined" | "error"; + transactionHash?: string; + blockExplorerUrl?: string; + errorMessage: "Error" | undefined; + toAddress: string; + amount: string; + timestamp?: number; + chainId: number; + network: "Ethereum" | "Base Sep" | "OP Sep"; +} + +interface ClaimTransactionResultsProps { + results: ClaimTransactionResults[]; +} +// I did have one component of this, but it was causing weird queuing issues when shared among multiple components. So just created one for each instead. +export function ClaimTransactionResults({ + results, +}: ClaimTransactionResultsProps) { + const [currentPage, setCurrentPage] = useState(1); + const [showLeftGradient, setShowLeftGradient] = useState(false); + const [showRightGradient, setShowRightGradient] = useState(true); + const itemsPerPage = 2; + // Added dummy transactions so the table doesn't look empty. + const dummyTransaction1: ClaimTransactionResults = { + queueId: "0x1234567890abcdef", + status: "Mined", + transactionHash: "0xabcdef1234567890", + blockExplorerUrl: "https://etherscan.io/tx/0xabcdef1234567890", + toAddress: "0x1234567890abcdef", + amount: "1.0", + timestamp: Date.now() - 15 * 60 * 1000, + chainId: 1, + network: "Ethereum", + errorMessage: undefined, + }; + + const dummyTransaction2: ClaimTransactionResults = { + queueId: "0x9876543210fedcba", + status: "Mined", + transactionHash: "0x1234567890abcdef", + blockExplorerUrl: "https://etherscan.io/tx/0x1234567890abcdef", + toAddress: "0xabcdef1234567890", + amount: "0.5", + timestamp: Date.now() - 30 * 60 * 1000, + chainId: 1, + network: "Base Sep", + errorMessage: undefined, + }; + + const sortedResults = [...results].reverse(); + const sortedResultsWithDummy = [ + ...sortedResults, + dummyTransaction1, + dummyTransaction2, + ]; + + const indexOfLastItem = currentPage * itemsPerPage; + const indexOfFirstItem = indexOfLastItem - itemsPerPage; + const currentItems = sortedResultsWithDummy.slice( + indexOfFirstItem, + indexOfLastItem, + ); + const totalPages = Math.ceil(sortedResultsWithDummy.length / itemsPerPage); + + const handleNextPage = () => { + setCurrentPage((prev) => Math.min(prev + 1, totalPages)); + }; + + const handlePrevPage = () => { + setCurrentPage((prev) => Math.max(prev - 1, 1)); + }; + + const getDisplayStatus = (result: ClaimTransactionResults) => { + if (result.status === "Mined" && !result.transactionHash) { + return "Pending"; + } + return result.status; + }; + + const getStatusColor = (status: string) => { + switch (status) { + case "Mined": + return "bg-green-500/20 text-green-400"; + case "Queued": + case "Pending": + return "bg-yellow-500/20 text-yellow-400"; + default: + return "bg-red-500/20 text-red-400"; + } + }; + + const handleScroll = (e: React.UIEvent) => { + const target = e.currentTarget; + const isAtStart = target.scrollLeft === 0; + const isAtEnd = + target.scrollLeft + target.clientWidth >= target.scrollWidth - 1; // -1 for rounding errors + + setShowLeftGradient(!isAtStart); + setShowRightGradient(!isAtEnd); + }; + + return ( + + +

+ Transaction Results +

+ + Last 24 hours • {sortedResultsWithDummy.length} transactions + +
+ +
+ + + + Queue ID + Network + From + Queued + Status + Tx Hash + + + + {currentItems.map((result, index) => ( + + + {result.queueId + ? `${result.queueId.substring(0, 6)}...${result.queueId.substring( + result.queueId.length - 4, + )}` + : "----"} + + + + {result.network === "Base Sep" && ( + Base + )} + {result.network === "OP Sep" && ( + Optimism Sep + )} + {result.network === "Ethereum" && ( + Ethereum + )} + {result.network} + + + + {(() => { + if (!result.toAddress) return "----"; + + const addressDisplay = `${result.toAddress.substring(0, 6)}...${result.toAddress.substring( + result.toAddress.length - 4, + )}`; + // Keeping OP here for consistency. Will be adding a component for Optimism soon. + const getExplorerUrl = () => { + switch (result.network) { + case "Base Sep": + return `https://base-sepolia.blockscout.com/address/${result.toAddress}?tab=tokens`; + case "OP Sep": + return `https://optimism-sepolia.blockscout.com/address/${result.toAddress}?tab=tokens`; + case "Ethereum": + return `https://etherscan.io/address/${result.toAddress}?tab=tokens`; + default: + return null; + } + }; + + const explorerUrl = getExplorerUrl(); + + return explorerUrl ? ( + + {addressDisplay} + + ) : ( + addressDisplay + ); + })()} + + + {result.timestamp ? format(result.timestamp) : "Just now"} + + + + {getDisplayStatus(result)} + + + + {result.transactionHash && result.blockExplorerUrl ? ( + + {`${result.transactionHash.substring(0, 6)}...${result.transactionHash.substring( + result.transactionHash.length - 4, + )}`} + + ) : result.errorMessage ? ( + + {result.errorMessage} + + ) : ( + "----" + )} + + + ))} + +
+
+ {showLeftGradient && ( +
+ )} + {showRightGradient && ( +
+ )} + + + + + Page {currentPage} of {totalPages} + + + + + ); +} diff --git a/apps/playground-web/src/components/engine/minting/erc1155-mint-to.tsx b/apps/playground-web/src/components/engine/minting/erc1155-mint-to.tsx new file mode 100644 index 00000000000..92d33956fac --- /dev/null +++ b/apps/playground-web/src/components/engine/minting/erc1155-mint-to.tsx @@ -0,0 +1,301 @@ +"use client"; + +import { Button } from "@/components/ui/button"; +import { Input } from "@/components/ui/input"; +import { Label } from "@/components/ui/label"; +import { THIRDWEB_CLIENT } from "@/lib/client"; +import { useState } from "react"; +import { baseSepolia } from "thirdweb/chains"; +import { ConnectButton, useActiveAccount } from "thirdweb/react"; +import { upload } from "thirdweb/storage"; +import { ClaimTransactionResults as ClaimTransactionResultsComponent } from "./TransactionResults"; + +interface ClaimTransactionResults { + queueId: string; + status: "Queued" | "Sent" | "Mined" | "error"; + transactionHash?: string; + blockExplorerUrl?: string; + errorMessage: "Error" | undefined; + toAddress: string; + amount: string; + timestamp?: number; + chainId: number; + network: "Ethereum" | "Base Sep" | "OP Sep"; +} +// Wasn't sure if this was needed, but added just in case. +const resolveIpfsUrl = (ipfsUrl: string) => { + if (!ipfsUrl) return ""; + if (ipfsUrl.startsWith("ipfs://")) { + return ipfsUrl.replace("ipfs://", "https://ipfs.io/ipfs/"); + } + return ipfsUrl; +}; + +export function ERC1155MintTo() { + const [isSubmitting, setIsSubmitting] = useState(false); + const [results, setResults] = useState([]); + + const [name, setName] = useState(""); + const [description, setDescription] = useState(""); + const [image, setImage] = useState(""); + const [supply, setSupply] = useState("1"); + const [imageFile, setImageFile] = useState(null); + const [isUploading, setIsUploading] = useState(false); + + const account = useActiveAccount(); + + const pollTransactionStatus = async (queueId: string) => { + const pollInterval = setInterval(async () => { + try { + const response = await fetch( + `/api/transaction-status?queueId=${queueId}`, + ); + const status = await response.json(); + + setResults((prevResults) => + prevResults.map((result) => + result.queueId === queueId + ? { + ...result, + ...status, + status: status.status === "mined" ? "Mined" : status.status, + } + : result, + ), + ); + + if (status.status === "Mined" || status.status === "error") { + clearInterval(pollInterval); + } + } catch (error) { + console.error("Error polling status:", error); + clearInterval(pollInterval); + } + }, 2000); + + setTimeout(() => clearInterval(pollInterval), 5 * 60 * 1000); + }; + + const handleSubmit = async (e: React.FormEvent) => { + e.preventDefault(); + if (!account || !name || !description || !image || !supply) { + alert("Please fill in all fields."); + return; + } + + const supplyNum = Number.parseInt(supply); + if (Number.isNaN(supplyNum) || supplyNum < 1) { + alert("Supply must be a positive number."); + return; + } + + setIsSubmitting(true); + + try { + const response = await fetch("/api/mintTo", { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ + receiver: account.address, + metadataWithSupply: { + metadata: { + name, + description, + image, + }, + supply, + }, + }), + }); + + if (!response.ok) { + throw new Error("Network response was not ok"); + } + + const result = await response.json(); + + // Add the initial queued transaction to results + setResults((prevResults) => [...prevResults, result]); + + // Start polling for status updates + pollTransactionStatus(result.queueId); + } catch (error) { + console.error("Error:", error); + setResults([ + { + queueId: "", + status: "error", + errorMessage: "Error", + toAddress: "", + amount: "", + chainId: 84532, + network: "Base Sep", + }, + ]); + } finally { + setIsSubmitting(false); + } + }; + + const handleImageUpload = async (e: React.ChangeEvent) => { + const file = e.target.files?.[0]; + if (!file) return; + + setIsUploading(true); + try { + const uploadResult = await upload({ + client: THIRDWEB_CLIENT, + files: [file], + }); + setImage(uploadResult); + setImageFile(file); + } catch (error) { + console.error("Error uploading file:", error); + alert("Error uploading file"); + } finally { + setIsUploading(false); + } + }; + + return ( +
+
+ {/* Form Section */} +
+ + {account && ( +
+
+
+ + +
+
+
+ + setName(e.target.value)} + required + /> +
+
+ + setDescription(e.target.value)} + required + /> +
+
+
+
+ +
+ + {imageFile && ( +
+ Selected: {imageFile.name} +
+ )} + {isUploading && ( +
+ Uploading... +
+ )} +
+
+
+ + setSupply(e.target.value)} + required + /> +
+
+
+ +

+ thirdweb Engine Playground{" "} + + Minting Contract + +

+
+ )} +
+ + {/* Image Preview Section */} + {account && ( +
+ {image ? ( + NFT Preview { + console.error("Error loading image:", image); + const target = e.target as HTMLImageElement; + target.src = + 'data:image/svg+xml,'; + }} + /> + ) : ( +
+

+ Upload an image to see preview +

+
+ )} + {name && ( +
+

{name}

+ {description && ( +

+ {description} +

+ )} +
+ )} +
+ )} +
+ +
+ ); +} diff --git a/apps/playground-web/src/components/ui/card.tsx b/apps/playground-web/src/components/ui/card.tsx new file mode 100644 index 00000000000..5a90768a118 --- /dev/null +++ b/apps/playground-web/src/components/ui/card.tsx @@ -0,0 +1,86 @@ +import * as React from "react"; + +import { cn } from "@/lib/utils"; + +const Card = React.forwardRef< + HTMLDivElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +
+)); +Card.displayName = "Card"; + +const CardHeader = React.forwardRef< + HTMLDivElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +
+)); +CardHeader.displayName = "CardHeader"; + +const CardTitle = React.forwardRef< + HTMLDivElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +
+)); +CardTitle.displayName = "CardTitle"; + +const CardDescription = React.forwardRef< + HTMLDivElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +
+)); +CardDescription.displayName = "CardDescription"; + +const CardContent = React.forwardRef< + HTMLDivElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +
+)); +CardContent.displayName = "CardContent"; + +const CardFooter = React.forwardRef< + HTMLDivElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +
+)); +CardFooter.displayName = "CardFooter"; + +export { + Card, + CardHeader, + CardFooter, + CardTitle, + CardDescription, + CardContent, +}; diff --git a/apps/playground-web/src/components/ui/table.tsx b/apps/playground-web/src/components/ui/table.tsx new file mode 100644 index 00000000000..14567a0d653 --- /dev/null +++ b/apps/playground-web/src/components/ui/table.tsx @@ -0,0 +1,117 @@ +import * as React from "react"; + +import { cn } from "@/lib/utils"; + +const Table = React.forwardRef< + HTMLTableElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +
+ + +)); +Table.displayName = "Table"; + +const TableHeader = React.forwardRef< + HTMLTableSectionElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( + +)); +TableHeader.displayName = "TableHeader"; + +const TableBody = React.forwardRef< + HTMLTableSectionElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( + +)); +TableBody.displayName = "TableBody"; + +const TableFooter = React.forwardRef< + HTMLTableSectionElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( + tr]:last:border-b-0", + className, + )} + {...props} + /> +)); +TableFooter.displayName = "TableFooter"; + +const TableRow = React.forwardRef< + HTMLTableRowElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( + +)); +TableRow.displayName = "TableRow"; + +const TableHead = React.forwardRef< + HTMLTableCellElement, + React.ThHTMLAttributes +>(({ className, ...props }, ref) => ( +
+)); +TableHead.displayName = "TableHead"; + +const TableCell = React.forwardRef< + HTMLTableCellElement, + React.TdHTMLAttributes +>(({ className, ...props }, ref) => ( + +)); +TableCell.displayName = "TableCell"; + +const TableCaption = React.forwardRef< + HTMLTableCaptionElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +
+)); +TableCaption.displayName = "TableCaption"; + +export { + Table, + TableHeader, + TableBody, + TableFooter, + TableHead, + TableRow, + TableCell, + TableCaption, +}; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ed231dd906f..314f7aef501 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -139,7 +139,7 @@ importers: version: 1.1.4(react-dom@19.0.0-rc-69d4b800-20241021(react@19.0.0-rc-69d4b800-20241021))(react@19.0.0-rc-69d4b800-20241021)(types-react-dom@19.0.0-rc.1)(types-react@19.0.0-rc.1) '@sentry/nextjs': specifier: 8.40.0 - version: 8.40.0(@opentelemetry/core@1.28.0(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.54.2(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.28.0(@opentelemetry/api@1.9.0))(next@15.0.3(@babel/core@7.26.0)(@opentelemetry/api@1.9.0)(@playwright/test@1.49.0)(react-dom@19.0.0-rc-69d4b800-20241021(react@19.0.0-rc-69d4b800-20241021))(react@19.0.0-rc-69d4b800-20241021))(react@19.0.0-rc-69d4b800-20241021)(webpack@5.96.1(@swc/core@1.9.3(@swc/helpers@0.5.15))(esbuild@0.24.0)) + version: 8.40.0(@opentelemetry/core@1.28.0(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.54.2(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.28.0(@opentelemetry/api@1.9.0))(next@15.0.3(@babel/core@7.26.0)(@opentelemetry/api@1.9.0)(@playwright/test@1.49.0)(react-dom@19.0.0-rc-69d4b800-20241021(react@19.0.0-rc-69d4b800-20241021))(react@19.0.0-rc-69d4b800-20241021))(react@19.0.0-rc-69d4b800-20241021)(webpack@5.96.1(@swc/core@1.9.3)(esbuild@0.24.0)) '@shazow/whatsabi': specifier: ^0.17.0 version: 0.17.0(@noble/hashes@1.6.1)(typescript@5.7.2)(zod@3.23.8) @@ -154,7 +154,7 @@ importers: version: link:../../packages/service-utils '@vercel/functions': specifier: ^1.4.2 - version: 1.5.0(@aws-sdk/credential-provider-web-identity@3.696.0(@aws-sdk/client-sts@3.699.0)) + version: 1.5.0(@aws-sdk/credential-provider-web-identity@3.696.0) '@vercel/og': specifier: ^0.6.4 version: 0.6.4 @@ -283,7 +283,7 @@ importers: version: 2.5.5 tailwindcss-animate: specifier: ^1.0.7 - version: 1.0.7(tailwindcss@3.4.15(ts-node@10.9.2(@swc/core@1.9.3(@swc/helpers@0.5.15))(@types/node@22.10.0)(typescript@5.7.2))) + version: 1.0.7(tailwindcss@3.4.15(ts-node@10.9.2(@types/node@22.10.0)(typescript@5.7.2))) thirdweb: specifier: workspace:* version: link:../../packages/thirdweb @@ -332,7 +332,7 @@ importers: version: 8.4.5(react-dom@19.0.0-rc-69d4b800-20241021(react@19.0.0-rc-69d4b800-20241021))(react@19.0.0-rc-69d4b800-20241021)(storybook@8.4.5(bufferutil@4.0.8)(prettier@3.4.1)(utf-8-validate@5.0.10)) '@storybook/nextjs': specifier: 8.4.5 - version: 8.4.5(@swc/core@1.9.3(@swc/helpers@0.5.15))(esbuild@0.24.0)(next@15.0.3(@babel/core@7.26.0)(@opentelemetry/api@1.9.0)(@playwright/test@1.49.0)(react-dom@19.0.0-rc-69d4b800-20241021(react@19.0.0-rc-69d4b800-20241021))(react@19.0.0-rc-69d4b800-20241021))(react-dom@19.0.0-rc-69d4b800-20241021(react@19.0.0-rc-69d4b800-20241021))(react@19.0.0-rc-69d4b800-20241021)(storybook@8.4.5(bufferutil@4.0.8)(prettier@3.4.1)(utf-8-validate@5.0.10))(type-fest@4.28.1)(typescript@5.7.2)(webpack-hot-middleware@2.26.1)(webpack@5.96.1(@swc/core@1.9.3(@swc/helpers@0.5.15))(esbuild@0.24.0)) + version: 8.4.5(@swc/core@1.9.3)(esbuild@0.24.0)(next@15.0.3(@babel/core@7.26.0)(@opentelemetry/api@1.9.0)(@playwright/test@1.49.0)(react-dom@19.0.0-rc-69d4b800-20241021(react@19.0.0-rc-69d4b800-20241021))(react@19.0.0-rc-69d4b800-20241021))(react-dom@19.0.0-rc-69d4b800-20241021(react@19.0.0-rc-69d4b800-20241021))(react@19.0.0-rc-69d4b800-20241021)(storybook@8.4.5(bufferutil@4.0.8)(prettier@3.4.1)(utf-8-validate@5.0.10))(type-fest@4.28.1)(typescript@5.7.2)(webpack-hot-middleware@2.26.1)(webpack@5.96.1(@swc/core@1.9.3)(esbuild@0.24.0)) '@storybook/react': specifier: 8.4.5 version: 8.4.5(@storybook/test@8.4.5(storybook@8.4.5(bufferutil@4.0.8)(prettier@3.4.1)(utf-8-validate@5.0.10)))(react-dom@19.0.0-rc-69d4b800-20241021(react@19.0.0-rc-69d4b800-20241021))(react@19.0.0-rc-69d4b800-20241021)(storybook@8.4.5(bufferutil@4.0.8)(prettier@3.4.1)(utf-8-validate@5.0.10))(typescript@5.7.2) @@ -380,7 +380,7 @@ importers: version: 10.4.20(postcss@8.4.49) checkly: specifier: ^4.11.0 - version: 4.11.0(@swc/core@1.9.3(@swc/helpers@0.5.15))(@types/node@22.10.0)(bufferutil@4.0.8)(typescript@5.7.2)(utf-8-validate@5.0.10) + version: 4.11.0(@swc/core@1.9.3)(@types/node@22.10.0)(bufferutil@4.0.8)(typescript@5.7.2)(utf-8-validate@5.0.10) eslint: specifier: 8.57.0 version: 8.57.0 @@ -407,7 +407,7 @@ importers: version: 8.4.5(bufferutil@4.0.8)(prettier@3.4.1)(utf-8-validate@5.0.10) tailwindcss: specifier: 3.4.15 - version: 3.4.15(ts-node@10.9.2(@swc/core@1.9.3(@swc/helpers@0.5.15))(@types/node@22.10.0)(typescript@5.7.2)) + version: 3.4.15(ts-node@10.9.2(@types/node@22.10.0)(typescript@5.7.2)) typescript: specifier: 5.7.2 version: 5.7.2 @@ -459,6 +459,9 @@ importers: '@tanstack/react-query': specifier: 5.61.4 version: 5.61.4(react@19.0.0-rc-69d4b800-20241021) + '@thirdweb-dev/engine': + specifier: ^0.0.16 + version: 0.0.16 class-variance-authority: specifier: ^0.7.1 version: 0.7.1 @@ -498,6 +501,9 @@ importers: thirdweb: specifier: workspace:* version: link:../../packages/thirdweb + timeago.js: + specifier: ^4.0.2 + version: 4.0.2 use-debounce: specifier: ^10.0.4 version: 10.0.4(react@19.0.0-rc-69d4b800-20241021) @@ -525,10 +531,10 @@ importers: version: 8.4.49 tailwindcss: specifier: 3.4.15 - version: 3.4.15(ts-node@10.9.2(@swc/core@1.9.3(@swc/helpers@0.5.15))(@types/node@22.10.0)(typescript@5.7.2)) + version: 3.4.15(ts-node@10.9.2(@types/node@22.10.0)(typescript@5.7.2)) tailwindcss-animate: specifier: ^1.0.7 - version: 1.0.7(tailwindcss@3.4.15(ts-node@10.9.2(@swc/core@1.9.3(@swc/helpers@0.5.15))(@types/node@22.10.0)(typescript@5.7.2))) + version: 1.0.7(tailwindcss@3.4.15(ts-node@10.9.2(@types/node@22.10.0)(typescript@5.7.2))) typescript: specifier: 5.7.2 version: 5.7.2 @@ -540,13 +546,13 @@ importers: version: 1.0.5(react@19.0.0-rc-69d4b800-20241021) '@mdx-js/loader': specifier: ^2.3.0 - version: 2.3.0(webpack@5.96.1(@swc/core@1.9.3(@swc/helpers@0.5.15))) + version: 2.3.0(webpack@5.96.1) '@mdx-js/react': specifier: ^2.3.0 version: 2.3.0(react@19.0.0-rc-69d4b800-20241021) '@next/mdx': specifier: 15.0.3 - version: 15.0.3(@mdx-js/loader@2.3.0(webpack@5.96.1(@swc/core@1.9.3(@swc/helpers@0.5.15))))(@mdx-js/react@2.3.0(react@19.0.0-rc-69d4b800-20241021)) + version: 15.0.3(@mdx-js/loader@2.3.0(webpack@5.96.1))(@mdx-js/react@2.3.0(react@19.0.0-rc-69d4b800-20241021)) '@radix-ui/react-dialog': specifier: 1.1.2 version: 1.1.2(react-dom@19.0.0-rc-69d4b800-20241021(react@19.0.0-rc-69d4b800-20241021))(react@19.0.0-rc-69d4b800-20241021)(types-react-dom@19.0.0-rc.1)(types-react@19.0.0-rc.1) @@ -627,7 +633,7 @@ importers: version: 2.5.5 tailwindcss-animate: specifier: ^1.0.7 - version: 1.0.7(tailwindcss@3.4.15(ts-node@10.9.2(@swc/core@1.9.3(@swc/helpers@0.5.15))(@types/node@22.10.0)(typescript@5.7.2))) + version: 1.0.7(tailwindcss@3.4.15(ts-node@10.9.2(@types/node@22.10.0)(typescript@5.7.2))) thirdweb: specifier: workspace:* version: link:../../packages/thirdweb @@ -685,7 +691,7 @@ importers: version: 1.2.4 eslint-plugin-tailwindcss: specifier: ^3.17.5 - version: 3.17.5(tailwindcss@3.4.15(ts-node@10.9.2(@swc/core@1.9.3(@swc/helpers@0.5.15))(@types/node@22.10.0)(typescript@5.7.2))) + version: 3.17.5(tailwindcss@3.4.15(ts-node@10.9.2(@types/node@22.10.0)(typescript@5.7.2))) next-sitemap: specifier: ^4.2.3 version: 4.2.3(next@15.0.3(@opentelemetry/api@1.9.0)(@playwright/test@1.49.0)(react-dom@19.0.0-rc-69d4b800-20241021(react@19.0.0-rc-69d4b800-20241021))(react@19.0.0-rc-69d4b800-20241021)) @@ -694,7 +700,7 @@ importers: version: 8.4.49 tailwindcss: specifier: 3.4.15 - version: 3.4.15(ts-node@10.9.2(@swc/core@1.9.3(@swc/helpers@0.5.15))(@types/node@22.10.0)(typescript@5.7.2)) + version: 3.4.15(ts-node@10.9.2(@types/node@22.10.0)(typescript@5.7.2)) tsx: specifier: 4.19.2 version: 4.19.2 @@ -763,7 +769,7 @@ importers: version: 2.5.5 tailwindcss-animate: specifier: ^1.0.7 - version: 1.0.7(tailwindcss@3.4.15(ts-node@10.9.2(@swc/core@1.9.3(@swc/helpers@0.5.15))(@types/node@22.10.0)(typescript@5.7.2))) + version: 1.0.7(tailwindcss@3.4.15(ts-node@10.9.2(@types/node@22.10.0)(typescript@5.7.2))) thirdweb: specifier: workspace:* version: link:../../packages/thirdweb @@ -812,7 +818,7 @@ importers: version: 6.0.1(jiti@2.4.0)(postcss@8.4.49)(tsx@4.19.2)(yaml@2.6.1) tailwindcss: specifier: 3.4.15 - version: 3.4.15(ts-node@10.9.2(@swc/core@1.9.3(@swc/helpers@0.5.15))(@types/node@22.10.0)(typescript@5.7.2)) + version: 3.4.15(ts-node@10.9.2(@types/node@22.10.0)(typescript@5.7.2)) typescript: specifier: 5.7.2 version: 5.7.2 @@ -5367,9 +5373,6 @@ packages: '@swc/helpers@0.5.13': resolution: {integrity: sha512-UoKGxQ3r5kYI9dALKJapMmuK+1zWM/H17Z1+iwnNmzcJRnfFuevZs375TA5rW31pu4BS4NoSy1fRsexDXfWn5w==} - '@swc/helpers@0.5.15': - resolution: {integrity: sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==} - '@swc/types@0.1.17': resolution: {integrity: sha512-V5gRru+aD8YVyCOMAjMpWR1Ui577DD5KSJsHP8RAxopAH22jFz6GZd/qxqjO6MJHQhcsjvjOFXyDhyLQUnMveQ==} @@ -5429,6 +5432,9 @@ packages: peerDependencies: '@testing-library/dom': '>=7.21.4' + '@thirdweb-dev/engine@0.0.16': + resolution: {integrity: sha512-UJ+MIdKYGBhUUEOkbYJy3T7AAkdIRh3xJ7dtilqgnqP6IvIloTZ23jctBWQ3e5kuQFuK88DmwhMhzZSGbXjJTg==} + '@tootallnate/quickjs-emscripten@0.23.0': resolution: {integrity: sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA==} @@ -12815,6 +12821,9 @@ packages: through@2.3.8: resolution: {integrity: sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==} + timeago.js@4.0.2: + resolution: {integrity: sha512-a7wPxPdVlQL7lqvitHGGRsofhdwtkoSXPGATFuSOA2i1ZNQEPLrGnj68vOp2sOJTCFAQVXPeNMX/GctBaO9L2w==} + timers-browserify@2.0.12: resolution: {integrity: sha512-9phl76Cqm6FhSX9Xe1ZUAMLtm1BLkKj2Qd5ApyWkXzsMRaA7dgr81kf4wJmQf/hAvg8EEyJxDo3du/0KlhPiKQ==} engines: {node: '>=0.6.0'} @@ -16977,11 +16986,11 @@ snapshots: react: 19.0.0-rc-69d4b800-20241021 react-dom: 19.0.0-rc-69d4b800-20241021(react@19.0.0-rc-69d4b800-20241021) - '@mdx-js/loader@2.3.0(webpack@5.96.1(@swc/core@1.9.3(@swc/helpers@0.5.15)))': + '@mdx-js/loader@2.3.0(webpack@5.96.1)': dependencies: '@mdx-js/mdx': 2.3.0 source-map: 0.7.4 - webpack: 5.96.1(@swc/core@1.9.3(@swc/helpers@0.5.15)) + webpack: 5.96.1 transitivePeerDependencies: - supports-color @@ -17121,11 +17130,11 @@ snapshots: dependencies: fast-glob: 3.3.1 - '@next/mdx@15.0.3(@mdx-js/loader@2.3.0(webpack@5.96.1(@swc/core@1.9.3(@swc/helpers@0.5.15))))(@mdx-js/react@2.3.0(react@19.0.0-rc-69d4b800-20241021))': + '@next/mdx@15.0.3(@mdx-js/loader@2.3.0(webpack@5.96.1))(@mdx-js/react@2.3.0(react@19.0.0-rc-69d4b800-20241021))': dependencies: source-map: 0.7.4 optionalDependencies: - '@mdx-js/loader': 2.3.0(webpack@5.96.1(@swc/core@1.9.3(@swc/helpers@0.5.15))) + '@mdx-js/loader': 2.3.0(webpack@5.96.1) '@mdx-js/react': 2.3.0(react@19.0.0-rc-69d4b800-20241021) '@next/swc-darwin-arm64@15.0.3': @@ -17283,7 +17292,7 @@ snapshots: widest-line: 3.1.0 wrap-ansi: 7.0.0 - '@oclif/core@2.8.11(@swc/core@1.9.3(@swc/helpers@0.5.15))(@types/node@22.10.0)(typescript@5.7.2)': + '@oclif/core@2.8.11(@swc/core@1.9.3)(@types/node@22.10.0)(typescript@5.7.2)': dependencies: '@types/cli-progress': 3.11.6 ansi-escapes: 4.3.2 @@ -17309,7 +17318,7 @@ snapshots: strip-ansi: 6.0.1 supports-color: 8.1.1 supports-hyperlinks: 2.3.0 - ts-node: 10.9.2(@swc/core@1.9.3(@swc/helpers@0.5.15))(@types/node@22.10.0)(typescript@5.7.2) + ts-node: 10.9.2(@swc/core@1.9.3)(@types/node@22.10.0)(typescript@5.7.2) tslib: 2.8.1 widest-line: 3.1.0 wordwrap: 1.0.0 @@ -17347,10 +17356,10 @@ snapshots: dependencies: '@oclif/core': 1.26.2 - '@oclif/plugin-not-found@2.3.23(@swc/core@1.9.3(@swc/helpers@0.5.15))(@types/node@22.10.0)(typescript@5.7.2)': + '@oclif/plugin-not-found@2.3.23(@swc/core@1.9.3)(@types/node@22.10.0)(typescript@5.7.2)': dependencies: '@oclif/color': 1.0.13 - '@oclif/core': 2.8.11(@swc/core@1.9.3(@swc/helpers@0.5.15))(@types/node@22.10.0)(typescript@5.7.2) + '@oclif/core': 2.8.11(@swc/core@1.9.3)(@types/node@22.10.0)(typescript@5.7.2) fast-levenshtein: 3.0.0 lodash: 4.17.21 transitivePeerDependencies: @@ -17375,9 +17384,9 @@ snapshots: transitivePeerDependencies: - supports-color - '@oclif/plugin-warn-if-update-available@2.0.24(@swc/core@1.9.3(@swc/helpers@0.5.15))(@types/node@22.10.0)(typescript@5.7.2)': + '@oclif/plugin-warn-if-update-available@2.0.24(@swc/core@1.9.3)(@types/node@22.10.0)(typescript@5.7.2)': dependencies: - '@oclif/core': 2.8.11(@swc/core@1.9.3(@swc/helpers@0.5.15))(@types/node@22.10.0)(typescript@5.7.2) + '@oclif/core': 2.8.11(@swc/core@1.9.3)(@types/node@22.10.0)(typescript@5.7.2) chalk: 4.1.2 debug: 4.3.7(supports-color@8.1.1) fs-extra: 9.1.0 @@ -17768,7 +17777,7 @@ snapshots: dependencies: playwright: 1.49.0 - '@pmmmwh/react-refresh-webpack-plugin@0.5.15(react-refresh@0.14.2)(type-fest@4.28.1)(webpack-hot-middleware@2.26.1)(webpack@5.96.1(@swc/core@1.9.3(@swc/helpers@0.5.15))(esbuild@0.24.0))': + '@pmmmwh/react-refresh-webpack-plugin@0.5.15(react-refresh@0.14.2)(type-fest@4.28.1)(webpack-hot-middleware@2.26.1)(webpack@5.96.1(@swc/core@1.9.3)(esbuild@0.24.0))': dependencies: ansi-html: 0.0.9 core-js-pure: 3.39.0 @@ -17778,7 +17787,7 @@ snapshots: react-refresh: 0.14.2 schema-utils: 4.2.0 source-map: 0.7.4 - webpack: 5.96.1(@swc/core@1.9.3(@swc/helpers@0.5.15))(esbuild@0.24.0) + webpack: 5.96.1(@swc/core@1.9.3)(esbuild@0.24.0) optionalDependencies: type-fest: 4.28.1 webpack-hot-middleware: 2.26.1 @@ -18786,7 +18795,7 @@ snapshots: dependencies: '@sentry/types': 8.40.0 - '@sentry/nextjs@8.40.0(@opentelemetry/core@1.28.0(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.54.2(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.28.0(@opentelemetry/api@1.9.0))(next@15.0.3(@babel/core@7.26.0)(@opentelemetry/api@1.9.0)(@playwright/test@1.49.0)(react-dom@19.0.0-rc-69d4b800-20241021(react@19.0.0-rc-69d4b800-20241021))(react@19.0.0-rc-69d4b800-20241021))(react@19.0.0-rc-69d4b800-20241021)(webpack@5.96.1(@swc/core@1.9.3(@swc/helpers@0.5.15))(esbuild@0.24.0))': + '@sentry/nextjs@8.40.0(@opentelemetry/core@1.28.0(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.54.2(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.28.0(@opentelemetry/api@1.9.0))(next@15.0.3(@babel/core@7.26.0)(@opentelemetry/api@1.9.0)(@playwright/test@1.49.0)(react-dom@19.0.0-rc-69d4b800-20241021(react@19.0.0-rc-69d4b800-20241021))(react@19.0.0-rc-69d4b800-20241021))(react@19.0.0-rc-69d4b800-20241021)(webpack@5.96.1(@swc/core@1.9.3)(esbuild@0.24.0))': dependencies: '@opentelemetry/api': 1.9.0 '@opentelemetry/instrumentation-http': 0.53.0(@opentelemetry/api@1.9.0) @@ -18799,7 +18808,7 @@ snapshots: '@sentry/react': 8.40.0(react@19.0.0-rc-69d4b800-20241021) '@sentry/types': 8.40.0 '@sentry/vercel-edge': 8.40.0 - '@sentry/webpack-plugin': 2.22.6(webpack@5.96.1(@swc/core@1.9.3(@swc/helpers@0.5.15))(esbuild@0.24.0)) + '@sentry/webpack-plugin': 2.22.6(webpack@5.96.1(@swc/core@1.9.3)(esbuild@0.24.0)) chalk: 3.0.0 next: 15.0.3(@babel/core@7.26.0)(@opentelemetry/api@1.9.0)(@playwright/test@1.49.0)(react-dom@19.0.0-rc-69d4b800-20241021(react@19.0.0-rc-69d4b800-20241021))(react@19.0.0-rc-69d4b800-20241021) resolve: 1.22.8 @@ -18881,12 +18890,12 @@ snapshots: '@sentry/core': 8.40.0 '@sentry/types': 8.40.0 - '@sentry/webpack-plugin@2.22.6(webpack@5.96.1(@swc/core@1.9.3(@swc/helpers@0.5.15))(esbuild@0.24.0))': + '@sentry/webpack-plugin@2.22.6(webpack@5.96.1(@swc/core@1.9.3)(esbuild@0.24.0))': dependencies: '@sentry/bundler-plugin-core': 2.22.6 unplugin: 1.0.1 uuid: 9.0.1 - webpack: 5.96.1(@swc/core@1.9.3(@swc/helpers@0.5.15))(esbuild@0.24.0) + webpack: 5.96.1(@swc/core@1.9.3)(esbuild@0.24.0) transitivePeerDependencies: - encoding - supports-color @@ -19621,7 +19630,7 @@ snapshots: ts-dedent: 2.2.0 vite: 6.0.0(@types/node@22.10.0)(jiti@2.4.0)(lightningcss@1.28.2)(terser@5.36.0)(tsx@4.19.2)(yaml@2.6.1) - '@storybook/builder-webpack5@8.4.5(@swc/core@1.9.3(@swc/helpers@0.5.15))(esbuild@0.24.0)(storybook@8.4.5(bufferutil@4.0.8)(prettier@3.4.1)(utf-8-validate@5.0.10))(typescript@5.7.2)': + '@storybook/builder-webpack5@8.4.5(@swc/core@1.9.3)(esbuild@0.24.0)(storybook@8.4.5(bufferutil@4.0.8)(prettier@3.4.1)(utf-8-validate@5.0.10))(typescript@5.7.2)': dependencies: '@storybook/core-webpack': 8.4.5(storybook@8.4.5(bufferutil@4.0.8)(prettier@3.4.1)(utf-8-validate@5.0.10)) '@types/node': 22.10.0 @@ -19630,23 +19639,23 @@ snapshots: case-sensitive-paths-webpack-plugin: 2.4.0 cjs-module-lexer: 1.4.1 constants-browserify: 1.0.0 - css-loader: 6.11.0(webpack@5.96.1(@swc/core@1.9.3(@swc/helpers@0.5.15))(esbuild@0.24.0)) + css-loader: 6.11.0(webpack@5.96.1(@swc/core@1.9.3)(esbuild@0.24.0)) es-module-lexer: 1.5.4 - fork-ts-checker-webpack-plugin: 8.0.0(typescript@5.7.2)(webpack@5.96.1(@swc/core@1.9.3(@swc/helpers@0.5.15))(esbuild@0.24.0)) - html-webpack-plugin: 5.6.3(webpack@5.96.1(@swc/core@1.9.3(@swc/helpers@0.5.15))(esbuild@0.24.0)) + fork-ts-checker-webpack-plugin: 8.0.0(typescript@5.7.2)(webpack@5.96.1(@swc/core@1.9.3)(esbuild@0.24.0)) + html-webpack-plugin: 5.6.3(webpack@5.96.1(@swc/core@1.9.3)(esbuild@0.24.0)) magic-string: 0.30.14 path-browserify: 1.0.1 process: 0.11.10 semver: 7.6.3 storybook: 8.4.5(bufferutil@4.0.8)(prettier@3.4.1)(utf-8-validate@5.0.10) - style-loader: 3.3.4(webpack@5.96.1(@swc/core@1.9.3(@swc/helpers@0.5.15))(esbuild@0.24.0)) - terser-webpack-plugin: 5.3.10(@swc/core@1.9.3(@swc/helpers@0.5.15))(esbuild@0.24.0)(webpack@5.96.1(@swc/core@1.9.3(@swc/helpers@0.5.15))(esbuild@0.24.0)) + style-loader: 3.3.4(webpack@5.96.1(@swc/core@1.9.3)(esbuild@0.24.0)) + terser-webpack-plugin: 5.3.10(@swc/core@1.9.3)(esbuild@0.24.0)(webpack@5.96.1(@swc/core@1.9.3)(esbuild@0.24.0)) ts-dedent: 2.2.0 url: 0.11.4 util: 0.12.5 util-deprecate: 1.0.2 - webpack: 5.96.1(@swc/core@1.9.3(@swc/helpers@0.5.15))(esbuild@0.24.0) - webpack-dev-middleware: 6.1.3(webpack@5.96.1(@swc/core@1.9.3(@swc/helpers@0.5.15))(esbuild@0.24.0)) + webpack: 5.96.1(@swc/core@1.9.3)(esbuild@0.24.0) + webpack-dev-middleware: 6.1.3(webpack@5.96.1(@swc/core@1.9.3)(esbuild@0.24.0)) webpack-hot-middleware: 2.26.1 webpack-virtual-modules: 0.6.2 optionalDependencies: @@ -19758,7 +19767,7 @@ snapshots: dependencies: storybook: 8.4.5(bufferutil@4.0.8)(prettier@3.4.1)(utf-8-validate@5.0.10) - '@storybook/nextjs@8.4.5(@swc/core@1.9.3(@swc/helpers@0.5.15))(esbuild@0.24.0)(next@15.0.3(@babel/core@7.26.0)(@opentelemetry/api@1.9.0)(@playwright/test@1.49.0)(react-dom@19.0.0-rc-69d4b800-20241021(react@19.0.0-rc-69d4b800-20241021))(react@19.0.0-rc-69d4b800-20241021))(react-dom@19.0.0-rc-69d4b800-20241021(react@19.0.0-rc-69d4b800-20241021))(react@19.0.0-rc-69d4b800-20241021)(storybook@8.4.5(bufferutil@4.0.8)(prettier@3.4.1)(utf-8-validate@5.0.10))(type-fest@4.28.1)(typescript@5.7.2)(webpack-hot-middleware@2.26.1)(webpack@5.96.1(@swc/core@1.9.3(@swc/helpers@0.5.15))(esbuild@0.24.0))': + '@storybook/nextjs@8.4.5(@swc/core@1.9.3)(esbuild@0.24.0)(next@15.0.3(@babel/core@7.26.0)(@opentelemetry/api@1.9.0)(@playwright/test@1.49.0)(react-dom@19.0.0-rc-69d4b800-20241021(react@19.0.0-rc-69d4b800-20241021))(react@19.0.0-rc-69d4b800-20241021))(react-dom@19.0.0-rc-69d4b800-20241021(react@19.0.0-rc-69d4b800-20241021))(react@19.0.0-rc-69d4b800-20241021)(storybook@8.4.5(bufferutil@4.0.8)(prettier@3.4.1)(utf-8-validate@5.0.10))(type-fest@4.28.1)(typescript@5.7.2)(webpack-hot-middleware@2.26.1)(webpack@5.96.1(@swc/core@1.9.3)(esbuild@0.24.0))': dependencies: '@babel/core': 7.26.0 '@babel/plugin-syntax-bigint': 7.8.3(@babel/core@7.26.0) @@ -19773,31 +19782,31 @@ snapshots: '@babel/preset-react': 7.25.9(@babel/core@7.26.0) '@babel/preset-typescript': 7.26.0(@babel/core@7.26.0) '@babel/runtime': 7.26.0 - '@pmmmwh/react-refresh-webpack-plugin': 0.5.15(react-refresh@0.14.2)(type-fest@4.28.1)(webpack-hot-middleware@2.26.1)(webpack@5.96.1(@swc/core@1.9.3(@swc/helpers@0.5.15))(esbuild@0.24.0)) - '@storybook/builder-webpack5': 8.4.5(@swc/core@1.9.3(@swc/helpers@0.5.15))(esbuild@0.24.0)(storybook@8.4.5(bufferutil@4.0.8)(prettier@3.4.1)(utf-8-validate@5.0.10))(typescript@5.7.2) - '@storybook/preset-react-webpack': 8.4.5(@storybook/test@8.4.5(storybook@8.4.5(bufferutil@4.0.8)(prettier@3.4.1)(utf-8-validate@5.0.10)))(@swc/core@1.9.3(@swc/helpers@0.5.15))(esbuild@0.24.0)(react-dom@19.0.0-rc-69d4b800-20241021(react@19.0.0-rc-69d4b800-20241021))(react@19.0.0-rc-69d4b800-20241021)(storybook@8.4.5(bufferutil@4.0.8)(prettier@3.4.1)(utf-8-validate@5.0.10))(typescript@5.7.2) + '@pmmmwh/react-refresh-webpack-plugin': 0.5.15(react-refresh@0.14.2)(type-fest@4.28.1)(webpack-hot-middleware@2.26.1)(webpack@5.96.1(@swc/core@1.9.3)(esbuild@0.24.0)) + '@storybook/builder-webpack5': 8.4.5(@swc/core@1.9.3)(esbuild@0.24.0)(storybook@8.4.5(bufferutil@4.0.8)(prettier@3.4.1)(utf-8-validate@5.0.10))(typescript@5.7.2) + '@storybook/preset-react-webpack': 8.4.5(@storybook/test@8.4.5(storybook@8.4.5(bufferutil@4.0.8)(prettier@3.4.1)(utf-8-validate@5.0.10)))(@swc/core@1.9.3)(esbuild@0.24.0)(react-dom@19.0.0-rc-69d4b800-20241021(react@19.0.0-rc-69d4b800-20241021))(react@19.0.0-rc-69d4b800-20241021)(storybook@8.4.5(bufferutil@4.0.8)(prettier@3.4.1)(utf-8-validate@5.0.10))(typescript@5.7.2) '@storybook/react': 8.4.5(@storybook/test@8.4.5(storybook@8.4.5(bufferutil@4.0.8)(prettier@3.4.1)(utf-8-validate@5.0.10)))(react-dom@19.0.0-rc-69d4b800-20241021(react@19.0.0-rc-69d4b800-20241021))(react@19.0.0-rc-69d4b800-20241021)(storybook@8.4.5(bufferutil@4.0.8)(prettier@3.4.1)(utf-8-validate@5.0.10))(typescript@5.7.2) '@storybook/test': 8.4.5(storybook@8.4.5(bufferutil@4.0.8)(prettier@3.4.1)(utf-8-validate@5.0.10)) '@types/node': 22.10.0 '@types/semver': 7.5.8 - babel-loader: 9.2.1(@babel/core@7.26.0)(webpack@5.96.1(@swc/core@1.9.3(@swc/helpers@0.5.15))(esbuild@0.24.0)) - css-loader: 6.11.0(webpack@5.96.1(@swc/core@1.9.3(@swc/helpers@0.5.15))(esbuild@0.24.0)) + babel-loader: 9.2.1(@babel/core@7.26.0)(webpack@5.96.1(@swc/core@1.9.3)(esbuild@0.24.0)) + css-loader: 6.11.0(webpack@5.96.1(@swc/core@1.9.3)(esbuild@0.24.0)) find-up: 5.0.0 image-size: 1.1.1 loader-utils: 3.3.1 next: 15.0.3(@babel/core@7.26.0)(@opentelemetry/api@1.9.0)(@playwright/test@1.49.0)(react-dom@19.0.0-rc-69d4b800-20241021(react@19.0.0-rc-69d4b800-20241021))(react@19.0.0-rc-69d4b800-20241021) - node-polyfill-webpack-plugin: 2.0.1(webpack@5.96.1(@swc/core@1.9.3(@swc/helpers@0.5.15))(esbuild@0.24.0)) + node-polyfill-webpack-plugin: 2.0.1(webpack@5.96.1(@swc/core@1.9.3)(esbuild@0.24.0)) pnp-webpack-plugin: 1.7.0(typescript@5.7.2) postcss: 8.4.49 - postcss-loader: 8.1.1(postcss@8.4.49)(typescript@5.7.2)(webpack@5.96.1(@swc/core@1.9.3(@swc/helpers@0.5.15))(esbuild@0.24.0)) + postcss-loader: 8.1.1(postcss@8.4.49)(typescript@5.7.2)(webpack@5.96.1(@swc/core@1.9.3)(esbuild@0.24.0)) react: 19.0.0-rc-69d4b800-20241021 react-dom: 19.0.0-rc-69d4b800-20241021(react@19.0.0-rc-69d4b800-20241021) react-refresh: 0.14.2 resolve-url-loader: 5.0.0 - sass-loader: 13.3.3(webpack@5.96.1(@swc/core@1.9.3(@swc/helpers@0.5.15))(esbuild@0.24.0)) + sass-loader: 13.3.3(webpack@5.96.1(@swc/core@1.9.3)(esbuild@0.24.0)) semver: 7.6.3 storybook: 8.4.5(bufferutil@4.0.8)(prettier@3.4.1)(utf-8-validate@5.0.10) - style-loader: 3.3.4(webpack@5.96.1(@swc/core@1.9.3(@swc/helpers@0.5.15))(esbuild@0.24.0)) + style-loader: 3.3.4(webpack@5.96.1(@swc/core@1.9.3)(esbuild@0.24.0)) styled-jsx: 5.1.6(@babel/core@7.26.0)(react@19.0.0-rc-69d4b800-20241021) ts-dedent: 2.2.0 tsconfig-paths: 4.2.0 @@ -19805,7 +19814,7 @@ snapshots: optionalDependencies: sharp: 0.33.5 typescript: 5.7.2 - webpack: 5.96.1(@swc/core@1.9.3(@swc/helpers@0.5.15))(esbuild@0.24.0) + webpack: 5.96.1(@swc/core@1.9.3)(esbuild@0.24.0) transitivePeerDependencies: - '@rspack/core' - '@swc/core' @@ -19825,11 +19834,11 @@ snapshots: - webpack-hot-middleware - webpack-plugin-serve - '@storybook/preset-react-webpack@8.4.5(@storybook/test@8.4.5(storybook@8.4.5(bufferutil@4.0.8)(prettier@3.4.1)(utf-8-validate@5.0.10)))(@swc/core@1.9.3(@swc/helpers@0.5.15))(esbuild@0.24.0)(react-dom@19.0.0-rc-69d4b800-20241021(react@19.0.0-rc-69d4b800-20241021))(react@19.0.0-rc-69d4b800-20241021)(storybook@8.4.5(bufferutil@4.0.8)(prettier@3.4.1)(utf-8-validate@5.0.10))(typescript@5.7.2)': + '@storybook/preset-react-webpack@8.4.5(@storybook/test@8.4.5(storybook@8.4.5(bufferutil@4.0.8)(prettier@3.4.1)(utf-8-validate@5.0.10)))(@swc/core@1.9.3)(esbuild@0.24.0)(react-dom@19.0.0-rc-69d4b800-20241021(react@19.0.0-rc-69d4b800-20241021))(react@19.0.0-rc-69d4b800-20241021)(storybook@8.4.5(bufferutil@4.0.8)(prettier@3.4.1)(utf-8-validate@5.0.10))(typescript@5.7.2)': dependencies: '@storybook/core-webpack': 8.4.5(storybook@8.4.5(bufferutil@4.0.8)(prettier@3.4.1)(utf-8-validate@5.0.10)) '@storybook/react': 8.4.5(@storybook/test@8.4.5(storybook@8.4.5(bufferutil@4.0.8)(prettier@3.4.1)(utf-8-validate@5.0.10)))(react-dom@19.0.0-rc-69d4b800-20241021(react@19.0.0-rc-69d4b800-20241021))(react@19.0.0-rc-69d4b800-20241021)(storybook@8.4.5(bufferutil@4.0.8)(prettier@3.4.1)(utf-8-validate@5.0.10))(typescript@5.7.2) - '@storybook/react-docgen-typescript-plugin': 1.0.6--canary.9.0c3f3b7.0(typescript@5.7.2)(webpack@5.96.1(@swc/core@1.9.3(@swc/helpers@0.5.15))(esbuild@0.24.0)) + '@storybook/react-docgen-typescript-plugin': 1.0.6--canary.9.0c3f3b7.0(typescript@5.7.2)(webpack@5.96.1(@swc/core@1.9.3)(esbuild@0.24.0)) '@types/node': 22.10.0 '@types/semver': 7.5.8 find-up: 5.0.0 @@ -19841,7 +19850,7 @@ snapshots: semver: 7.6.3 storybook: 8.4.5(bufferutil@4.0.8)(prettier@3.4.1)(utf-8-validate@5.0.10) tsconfig-paths: 4.2.0 - webpack: 5.96.1(@swc/core@1.9.3(@swc/helpers@0.5.15))(esbuild@0.24.0) + webpack: 5.96.1(@swc/core@1.9.3)(esbuild@0.24.0) optionalDependencies: typescript: 5.7.2 transitivePeerDependencies: @@ -19860,7 +19869,7 @@ snapshots: dependencies: storybook: 8.4.5(bufferutil@4.0.8)(prettier@3.4.1)(utf-8-validate@5.0.10) - '@storybook/react-docgen-typescript-plugin@1.0.6--canary.9.0c3f3b7.0(typescript@5.7.2)(webpack@5.96.1(@swc/core@1.9.3(@swc/helpers@0.5.15))(esbuild@0.24.0))': + '@storybook/react-docgen-typescript-plugin@1.0.6--canary.9.0c3f3b7.0(typescript@5.7.2)(webpack@5.96.1(@swc/core@1.9.3)(esbuild@0.24.0))': dependencies: debug: 4.3.7(supports-color@8.1.1) endent: 2.1.0 @@ -19870,7 +19879,7 @@ snapshots: react-docgen-typescript: 2.2.2(typescript@5.7.2) tslib: 2.8.1 typescript: 5.7.2 - webpack: 5.96.1(@swc/core@1.9.3(@swc/helpers@0.5.15))(esbuild@0.24.0) + webpack: 5.96.1(@swc/core@1.9.3)(esbuild@0.24.0) transitivePeerDependencies: - supports-color @@ -20358,7 +20367,7 @@ snapshots: '@swc/core-win32-x64-msvc@1.9.3': optional: true - '@swc/core@1.9.3(@swc/helpers@0.5.15)': + '@swc/core@1.9.3': dependencies: '@swc/counter': 0.1.3 '@swc/types': 0.1.17 @@ -20373,7 +20382,6 @@ snapshots: '@swc/core-win32-arm64-msvc': 1.9.3 '@swc/core-win32-ia32-msvc': 1.9.3 '@swc/core-win32-x64-msvc': 1.9.3 - '@swc/helpers': 0.5.15 optional: true '@swc/counter@0.1.3': {} @@ -20382,11 +20390,6 @@ snapshots: dependencies: tslib: 2.8.1 - '@swc/helpers@0.5.15': - dependencies: - tslib: 2.8.1 - optional: true - '@swc/types@0.1.17': dependencies: '@swc/counter': 0.1.3 @@ -20455,6 +20458,8 @@ snapshots: dependencies: '@testing-library/dom': 10.4.0 + '@thirdweb-dev/engine@0.0.16': {} + '@tootallnate/quickjs-emscripten@0.23.0': {} '@tree-sitter-grammars/tree-sitter-yaml@0.6.1(tree-sitter@0.21.1)': @@ -20899,7 +20904,7 @@ snapshots: '@urql/core': 5.0.8(graphql@16.9.0) wonka: 6.3.4 - '@vercel/functions@1.5.0(@aws-sdk/credential-provider-web-identity@3.696.0(@aws-sdk/client-sts@3.699.0))': + '@vercel/functions@1.5.0(@aws-sdk/credential-provider-web-identity@3.696.0)': optionalDependencies: '@aws-sdk/credential-provider-web-identity': 3.696.0(@aws-sdk/client-sts@3.699.0) @@ -21783,12 +21788,12 @@ snapshots: transitivePeerDependencies: - supports-color - babel-loader@9.2.1(@babel/core@7.26.0)(webpack@5.96.1(@swc/core@1.9.3(@swc/helpers@0.5.15))(esbuild@0.24.0)): + babel-loader@9.2.1(@babel/core@7.26.0)(webpack@5.96.1(@swc/core@1.9.3)(esbuild@0.24.0)): dependencies: '@babel/core': 7.26.0 find-cache-dir: 4.0.0 schema-utils: 4.2.0 - webpack: 5.96.1(@swc/core@1.9.3(@swc/helpers@0.5.15))(esbuild@0.24.0) + webpack: 5.96.1(@swc/core@1.9.3)(esbuild@0.24.0) babel-plugin-istanbul@6.1.1: dependencies: @@ -22249,13 +22254,13 @@ snapshots: check-error@2.1.1: {} - checkly@4.11.0(@swc/core@1.9.3(@swc/helpers@0.5.15))(@types/node@22.10.0)(bufferutil@4.0.8)(typescript@5.7.2)(utf-8-validate@5.0.10): + checkly@4.11.0(@swc/core@1.9.3)(@types/node@22.10.0)(bufferutil@4.0.8)(typescript@5.7.2)(utf-8-validate@5.0.10): dependencies: - '@oclif/core': 2.8.11(@swc/core@1.9.3(@swc/helpers@0.5.15))(@types/node@22.10.0)(typescript@5.7.2) + '@oclif/core': 2.8.11(@swc/core@1.9.3)(@types/node@22.10.0)(typescript@5.7.2) '@oclif/plugin-help': 5.1.20 - '@oclif/plugin-not-found': 2.3.23(@swc/core@1.9.3(@swc/helpers@0.5.15))(@types/node@22.10.0)(typescript@5.7.2) + '@oclif/plugin-not-found': 2.3.23(@swc/core@1.9.3)(@types/node@22.10.0)(typescript@5.7.2) '@oclif/plugin-plugins': 5.4.4 - '@oclif/plugin-warn-if-update-available': 2.0.24(@swc/core@1.9.3(@swc/helpers@0.5.15))(@types/node@22.10.0)(typescript@5.7.2) + '@oclif/plugin-warn-if-update-available': 2.0.24(@swc/core@1.9.3)(@types/node@22.10.0)(typescript@5.7.2) '@typescript-eslint/typescript-estree': 7.18.0(typescript@5.7.2) acorn: 8.8.1 acorn-walk: 8.2.0 @@ -22701,7 +22706,7 @@ snapshots: css-gradient-parser@0.0.16: {} - css-loader@6.11.0(webpack@5.96.1(@swc/core@1.9.3(@swc/helpers@0.5.15))(esbuild@0.24.0)): + css-loader@6.11.0(webpack@5.96.1(@swc/core@1.9.3)(esbuild@0.24.0)): dependencies: icss-utils: 5.1.0(postcss@8.4.49) postcss: 8.4.49 @@ -22712,7 +22717,7 @@ snapshots: postcss-value-parser: 4.2.0 semver: 7.6.3 optionalDependencies: - webpack: 5.96.1(@swc/core@1.9.3(@swc/helpers@0.5.15))(esbuild@0.24.0) + webpack: 5.96.1(@swc/core@1.9.3)(esbuild@0.24.0) css-select@4.3.0: dependencies: @@ -23382,8 +23387,8 @@ snapshots: '@typescript-eslint/parser': 7.14.1(eslint@8.57.0)(typescript@5.7.2) eslint: 8.57.0 eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.6.3(@typescript-eslint/parser@7.14.1(eslint@8.57.0)(typescript@5.7.2))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0)(eslint@8.57.0) - eslint-plugin-import: 2.31.0(@typescript-eslint/parser@7.14.1(eslint@8.57.0)(typescript@5.7.2))(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.0) + eslint-import-resolver-typescript: 3.6.3(@typescript-eslint/parser@7.14.1(eslint@8.57.0)(typescript@5.7.2))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0(@typescript-eslint/parser@7.14.1(eslint@8.57.0)(typescript@5.7.2))(eslint@8.57.0))(eslint@8.57.0) + eslint-plugin-import: 2.31.0(@typescript-eslint/parser@7.14.1(eslint@8.57.0)(typescript@5.7.2))(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@7.14.1(eslint@8.57.0)(typescript@5.7.2))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0(@typescript-eslint/parser@7.14.1(eslint@8.57.0)(typescript@5.7.2))(eslint@8.57.0))(eslint@8.57.0))(eslint@8.57.0) eslint-plugin-jsx-a11y: 6.10.2(eslint@8.57.0) eslint-plugin-react: 7.37.2(eslint@8.57.0) eslint-plugin-react-hooks: 5.0.0(eslint@8.57.0) @@ -23402,19 +23407,19 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@7.14.1(eslint@8.57.0)(typescript@5.7.2))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0)(eslint@8.57.0): + eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@7.14.1(eslint@8.57.0)(typescript@5.7.2))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0(@typescript-eslint/parser@7.14.1(eslint@8.57.0)(typescript@5.7.2))(eslint@8.57.0))(eslint@8.57.0): dependencies: '@nolyfill/is-core-module': 1.0.39 debug: 4.3.7(supports-color@8.1.1) enhanced-resolve: 5.17.1 eslint: 8.57.0 - eslint-module-utils: 2.12.0(@typescript-eslint/parser@7.14.1(eslint@8.57.0)(typescript@5.7.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@7.14.1(eslint@8.57.0)(typescript@5.7.2))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0)(eslint@8.57.0))(eslint@8.57.0) + eslint-module-utils: 2.12.0(@typescript-eslint/parser@7.14.1(eslint@8.57.0)(typescript@5.7.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@7.14.1(eslint@8.57.0)(typescript@5.7.2))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0(@typescript-eslint/parser@7.14.1(eslint@8.57.0)(typescript@5.7.2))(eslint@8.57.0))(eslint@8.57.0))(eslint@8.57.0) fast-glob: 3.3.2 get-tsconfig: 4.8.1 is-bun-module: 1.2.1 is-glob: 4.0.3 optionalDependencies: - eslint-plugin-import: 2.31.0(@typescript-eslint/parser@7.14.1(eslint@8.57.0)(typescript@5.7.2))(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.0) + eslint-plugin-import: 2.31.0(@typescript-eslint/parser@7.14.1(eslint@8.57.0)(typescript@5.7.2))(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@7.14.1(eslint@8.57.0)(typescript@5.7.2))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0(@typescript-eslint/parser@7.14.1(eslint@8.57.0)(typescript@5.7.2))(eslint@8.57.0))(eslint@8.57.0))(eslint@8.57.0) transitivePeerDependencies: - '@typescript-eslint/parser' - eslint-import-resolver-node @@ -23442,18 +23447,18 @@ snapshots: - bluebird - supports-color - eslint-module-utils@2.12.0(@typescript-eslint/parser@7.14.1(eslint@8.57.0)(typescript@5.7.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@7.14.1(eslint@8.57.0)(typescript@5.7.2))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0)(eslint@8.57.0))(eslint@8.57.0): + eslint-module-utils@2.12.0(@typescript-eslint/parser@7.14.1(eslint@8.57.0)(typescript@5.7.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@7.14.1(eslint@8.57.0)(typescript@5.7.2))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0(@typescript-eslint/parser@7.14.1(eslint@8.57.0)(typescript@5.7.2))(eslint@8.57.0))(eslint@8.57.0))(eslint@8.57.0): dependencies: debug: 3.2.7 optionalDependencies: '@typescript-eslint/parser': 7.14.1(eslint@8.57.0)(typescript@5.7.2) eslint: 8.57.0 eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.6.3(@typescript-eslint/parser@7.14.1(eslint@8.57.0)(typescript@5.7.2))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0)(eslint@8.57.0) + eslint-import-resolver-typescript: 3.6.3(@typescript-eslint/parser@7.14.1(eslint@8.57.0)(typescript@5.7.2))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0(@typescript-eslint/parser@7.14.1(eslint@8.57.0)(typescript@5.7.2))(eslint@8.57.0))(eslint@8.57.0) transitivePeerDependencies: - supports-color - eslint-plugin-import@2.31.0(@typescript-eslint/parser@7.14.1(eslint@8.57.0)(typescript@5.7.2))(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.0): + eslint-plugin-import@2.31.0(@typescript-eslint/parser@7.14.1(eslint@8.57.0)(typescript@5.7.2))(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@7.14.1(eslint@8.57.0)(typescript@5.7.2))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0(@typescript-eslint/parser@7.14.1(eslint@8.57.0)(typescript@5.7.2))(eslint@8.57.0))(eslint@8.57.0))(eslint@8.57.0): dependencies: '@rtsao/scc': 1.1.0 array-includes: 3.1.8 @@ -23464,7 +23469,7 @@ snapshots: doctrine: 2.1.0 eslint: 8.57.0 eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.12.0(@typescript-eslint/parser@7.14.1(eslint@8.57.0)(typescript@5.7.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@7.14.1(eslint@8.57.0)(typescript@5.7.2))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0)(eslint@8.57.0))(eslint@8.57.0) + eslint-module-utils: 2.12.0(@typescript-eslint/parser@7.14.1(eslint@8.57.0)(typescript@5.7.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@7.14.1(eslint@8.57.0)(typescript@5.7.2))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0(@typescript-eslint/parser@7.14.1(eslint@8.57.0)(typescript@5.7.2))(eslint@8.57.0))(eslint@8.57.0))(eslint@8.57.0) hasown: 2.0.2 is-core-module: 2.15.1 is-glob: 4.0.3 @@ -23573,11 +23578,11 @@ snapshots: eslint-plugin-svg-jsx@1.2.4: {} - eslint-plugin-tailwindcss@3.17.5(tailwindcss@3.4.15(ts-node@10.9.2(@swc/core@1.9.3(@swc/helpers@0.5.15))(@types/node@22.10.0)(typescript@5.7.2))): + eslint-plugin-tailwindcss@3.17.5(tailwindcss@3.4.15(ts-node@10.9.2(@types/node@22.10.0)(typescript@5.7.2))): dependencies: fast-glob: 3.3.2 postcss: 8.4.49 - tailwindcss: 3.4.15(ts-node@10.9.2(@swc/core@1.9.3(@swc/helpers@0.5.15))(@types/node@22.10.0)(typescript@5.7.2)) + tailwindcss: 3.4.15(ts-node@10.9.2(@types/node@22.10.0)(typescript@5.7.2)) eslint-scope@5.1.1: dependencies: @@ -24255,7 +24260,7 @@ snapshots: cross-spawn: 7.0.6 signal-exit: 4.1.0 - fork-ts-checker-webpack-plugin@8.0.0(typescript@5.7.2)(webpack@5.96.1(@swc/core@1.9.3(@swc/helpers@0.5.15))(esbuild@0.24.0)): + fork-ts-checker-webpack-plugin@8.0.0(typescript@5.7.2)(webpack@5.96.1(@swc/core@1.9.3)(esbuild@0.24.0)): dependencies: '@babel/code-frame': 7.26.2 chalk: 4.1.2 @@ -24270,7 +24275,7 @@ snapshots: semver: 7.6.3 tapable: 2.2.1 typescript: 5.7.2 - webpack: 5.96.1(@swc/core@1.9.3(@swc/helpers@0.5.15))(esbuild@0.24.0) + webpack: 5.96.1(@swc/core@1.9.3)(esbuild@0.24.0) form-data-encoder@2.1.4: {} @@ -24741,7 +24746,7 @@ snapshots: html-void-elements@3.0.0: {} - html-webpack-plugin@5.6.3(webpack@5.96.1(@swc/core@1.9.3(@swc/helpers@0.5.15))(esbuild@0.24.0)): + html-webpack-plugin@5.6.3(webpack@5.96.1(@swc/core@1.9.3)(esbuild@0.24.0)): dependencies: '@types/html-minifier-terser': 6.1.0 html-minifier-terser: 6.1.0 @@ -24749,7 +24754,7 @@ snapshots: pretty-error: 4.0.0 tapable: 2.2.1 optionalDependencies: - webpack: 5.96.1(@swc/core@1.9.3(@swc/helpers@0.5.15))(esbuild@0.24.0) + webpack: 5.96.1(@swc/core@1.9.3)(esbuild@0.24.0) htmlparser2@3.10.1: dependencies: @@ -27233,7 +27238,7 @@ snapshots: node-int64@0.4.0: {} - node-polyfill-webpack-plugin@2.0.1(webpack@5.96.1(@swc/core@1.9.3(@swc/helpers@0.5.15))(esbuild@0.24.0)): + node-polyfill-webpack-plugin@2.0.1(webpack@5.96.1(@swc/core@1.9.3)(esbuild@0.24.0)): dependencies: assert: 2.1.0 browserify-zlib: 0.2.0 @@ -27260,7 +27265,7 @@ snapshots: url: 0.11.4 util: 0.12.5 vm-browserify: 1.1.2 - webpack: 5.96.1(@swc/core@1.9.3(@swc/helpers@0.5.15))(esbuild@0.24.0) + webpack: 5.96.1(@swc/core@1.9.3)(esbuild@0.24.0) node-releases@2.0.18: {} @@ -27883,13 +27888,13 @@ snapshots: camelcase-css: 2.0.1 postcss: 8.4.49 - postcss-load-config@4.0.2(postcss@8.4.49)(ts-node@10.9.2(@swc/core@1.9.3(@swc/helpers@0.5.15))(@types/node@22.10.0)(typescript@5.7.2)): + postcss-load-config@4.0.2(postcss@8.4.49)(ts-node@10.9.2(@types/node@22.10.0)(typescript@5.7.2)): dependencies: lilconfig: 3.1.2 yaml: 2.6.1 optionalDependencies: postcss: 8.4.49 - ts-node: 10.9.2(@swc/core@1.9.3(@swc/helpers@0.5.15))(@types/node@22.10.0)(typescript@5.7.2) + ts-node: 10.9.2(@swc/core@1.9.3)(@types/node@22.10.0)(typescript@5.7.2) postcss-load-config@6.0.1(jiti@2.4.0)(postcss@8.4.49)(tsx@4.19.2)(yaml@2.6.1): dependencies: @@ -27900,14 +27905,14 @@ snapshots: tsx: 4.19.2 yaml: 2.6.1 - postcss-loader@8.1.1(postcss@8.4.49)(typescript@5.7.2)(webpack@5.96.1(@swc/core@1.9.3(@swc/helpers@0.5.15))(esbuild@0.24.0)): + postcss-loader@8.1.1(postcss@8.4.49)(typescript@5.7.2)(webpack@5.96.1(@swc/core@1.9.3)(esbuild@0.24.0)): dependencies: cosmiconfig: 9.0.0(typescript@5.7.2) jiti: 1.21.6 postcss: 8.4.49 semver: 7.6.3 optionalDependencies: - webpack: 5.96.1(@swc/core@1.9.3(@swc/helpers@0.5.15))(esbuild@0.24.0) + webpack: 5.96.1(@swc/core@1.9.3)(esbuild@0.24.0) transitivePeerDependencies: - typescript @@ -29064,10 +29069,10 @@ snapshots: safer-buffer@2.1.2: {} - sass-loader@13.3.3(webpack@5.96.1(@swc/core@1.9.3(@swc/helpers@0.5.15))(esbuild@0.24.0)): + sass-loader@13.3.3(webpack@5.96.1(@swc/core@1.9.3)(esbuild@0.24.0)): dependencies: neo-async: 2.6.2 - webpack: 5.96.1(@swc/core@1.9.3(@swc/helpers@0.5.15))(esbuild@0.24.0) + webpack: 5.96.1(@swc/core@1.9.3)(esbuild@0.24.0) satori@0.12.0: dependencies: @@ -29592,9 +29597,9 @@ snapshots: structured-headers@0.4.1: {} - style-loader@3.3.4(webpack@5.96.1(@swc/core@1.9.3(@swc/helpers@0.5.15))(esbuild@0.24.0)): + style-loader@3.3.4(webpack@5.96.1(@swc/core@1.9.3)(esbuild@0.24.0)): dependencies: - webpack: 5.96.1(@swc/core@1.9.3(@swc/helpers@0.5.15))(esbuild@0.24.0) + webpack: 5.96.1(@swc/core@1.9.3)(esbuild@0.24.0) style-to-object@0.4.4: dependencies: @@ -29739,11 +29744,11 @@ snapshots: tailwind-merge@2.5.5: {} - tailwindcss-animate@1.0.7(tailwindcss@3.4.15(ts-node@10.9.2(@swc/core@1.9.3(@swc/helpers@0.5.15))(@types/node@22.10.0)(typescript@5.7.2))): + tailwindcss-animate@1.0.7(tailwindcss@3.4.15(ts-node@10.9.2(@types/node@22.10.0)(typescript@5.7.2))): dependencies: - tailwindcss: 3.4.15(ts-node@10.9.2(@swc/core@1.9.3(@swc/helpers@0.5.15))(@types/node@22.10.0)(typescript@5.7.2)) + tailwindcss: 3.4.15(ts-node@10.9.2(@types/node@22.10.0)(typescript@5.7.2)) - tailwindcss@3.4.15(ts-node@10.9.2(@swc/core@1.9.3(@swc/helpers@0.5.15))(@types/node@22.10.0)(typescript@5.7.2)): + tailwindcss@3.4.15(ts-node@10.9.2(@types/node@22.10.0)(typescript@5.7.2)): dependencies: '@alloc/quick-lru': 5.2.0 arg: 5.0.2 @@ -29762,7 +29767,7 @@ snapshots: postcss: 8.4.49 postcss-import: 15.1.0(postcss@8.4.49) postcss-js: 4.0.1(postcss@8.4.49) - postcss-load-config: 4.0.2(postcss@8.4.49)(ts-node@10.9.2(@swc/core@1.9.3(@swc/helpers@0.5.15))(@types/node@22.10.0)(typescript@5.7.2)) + postcss-load-config: 4.0.2(postcss@8.4.49)(ts-node@10.9.2(@types/node@22.10.0)(typescript@5.7.2)) postcss-nested: 6.2.0(postcss@8.4.49) postcss-selector-parser: 6.1.2 resolve: 1.22.8 @@ -29824,29 +29829,18 @@ snapshots: ansi-escapes: 4.3.2 supports-hyperlinks: 2.3.0 - terser-webpack-plugin@5.3.10(@swc/core@1.9.3(@swc/helpers@0.5.15))(esbuild@0.24.0)(webpack@5.96.1(@swc/core@1.9.3(@swc/helpers@0.5.15))(esbuild@0.24.0)): + terser-webpack-plugin@5.3.10(@swc/core@1.9.3)(esbuild@0.24.0)(webpack@5.96.1(@swc/core@1.9.3)(esbuild@0.24.0)): dependencies: '@jridgewell/trace-mapping': 0.3.25 jest-worker: 27.5.1 schema-utils: 3.3.0 serialize-javascript: 6.0.2 terser: 5.36.0 - webpack: 5.96.1(@swc/core@1.9.3(@swc/helpers@0.5.15))(esbuild@0.24.0) + webpack: 5.96.1(@swc/core@1.9.3)(esbuild@0.24.0) optionalDependencies: - '@swc/core': 1.9.3(@swc/helpers@0.5.15) + '@swc/core': 1.9.3 esbuild: 0.24.0 - terser-webpack-plugin@5.3.10(@swc/core@1.9.3(@swc/helpers@0.5.15))(webpack@5.96.1(@swc/core@1.9.3(@swc/helpers@0.5.15))): - dependencies: - '@jridgewell/trace-mapping': 0.3.25 - jest-worker: 27.5.1 - schema-utils: 3.3.0 - serialize-javascript: 6.0.2 - terser: 5.36.0 - webpack: 5.96.1(@swc/core@1.9.3(@swc/helpers@0.5.15)) - optionalDependencies: - '@swc/core': 1.9.3(@swc/helpers@0.5.15) - terser-webpack-plugin@5.3.10(webpack@5.96.1): dependencies: '@jridgewell/trace-mapping': 0.3.25 @@ -29904,6 +29898,8 @@ snapshots: through@2.3.8: {} + timeago.js@4.0.2: {} + timers-browserify@2.0.12: dependencies: setimmediate: 1.0.5 @@ -29982,7 +29978,7 @@ snapshots: ts-mixer@6.0.4: {} - ts-node@10.9.2(@swc/core@1.9.3(@swc/helpers@0.5.15))(@types/node@22.10.0)(typescript@5.7.2): + ts-node@10.9.2(@swc/core@1.9.3)(@types/node@22.10.0)(typescript@5.7.2): dependencies: '@cspotcode/source-map-support': 0.8.1 '@tsconfig/node10': 1.0.11 @@ -30000,7 +29996,7 @@ snapshots: v8-compile-cache-lib: 3.0.1 yn: 3.1.1 optionalDependencies: - '@swc/core': 1.9.3(@swc/helpers@0.5.15) + '@swc/core': 1.9.3 ts-pnp@1.2.0(typescript@5.7.2): optionalDependencies: @@ -30754,7 +30750,7 @@ snapshots: - bufferutil - utf-8-validate - webpack-dev-middleware@6.1.3(webpack@5.96.1(@swc/core@1.9.3(@swc/helpers@0.5.15))(esbuild@0.24.0)): + webpack-dev-middleware@6.1.3(webpack@5.96.1(@swc/core@1.9.3)(esbuild@0.24.0)): dependencies: colorette: 2.0.20 memfs: 3.5.3 @@ -30762,7 +30758,7 @@ snapshots: range-parser: 1.2.1 schema-utils: 4.2.0 optionalDependencies: - webpack: 5.96.1(@swc/core@1.9.3(@swc/helpers@0.5.15))(esbuild@0.24.0) + webpack: 5.96.1(@swc/core@1.9.3)(esbuild@0.24.0) webpack-hot-middleware@2.26.1: dependencies: @@ -30806,37 +30802,7 @@ snapshots: - esbuild - uglify-js - webpack@5.96.1(@swc/core@1.9.3(@swc/helpers@0.5.15)): - dependencies: - '@types/eslint-scope': 3.7.7 - '@types/estree': 1.0.6 - '@webassemblyjs/ast': 1.14.1 - '@webassemblyjs/wasm-edit': 1.14.1 - '@webassemblyjs/wasm-parser': 1.14.1 - acorn: 8.14.0 - browserslist: 4.24.2 - chrome-trace-event: 1.0.4 - enhanced-resolve: 5.17.1 - es-module-lexer: 1.5.4 - eslint-scope: 5.1.1 - events: 3.3.0 - glob-to-regexp: 0.4.1 - graceful-fs: 4.2.11 - json-parse-even-better-errors: 2.3.1 - loader-runner: 4.3.0 - mime-types: 2.1.35 - neo-async: 2.6.2 - schema-utils: 3.3.0 - tapable: 2.2.1 - terser-webpack-plugin: 5.3.10(@swc/core@1.9.3(@swc/helpers@0.5.15))(webpack@5.96.1(@swc/core@1.9.3(@swc/helpers@0.5.15))) - watchpack: 2.4.2 - webpack-sources: 3.2.3 - transitivePeerDependencies: - - '@swc/core' - - esbuild - - uglify-js - - webpack@5.96.1(@swc/core@1.9.3(@swc/helpers@0.5.15))(esbuild@0.24.0): + webpack@5.96.1(@swc/core@1.9.3)(esbuild@0.24.0): dependencies: '@types/eslint-scope': 3.7.7 '@types/estree': 1.0.6 @@ -30858,7 +30824,7 @@ snapshots: neo-async: 2.6.2 schema-utils: 3.3.0 tapable: 2.2.1 - terser-webpack-plugin: 5.3.10(@swc/core@1.9.3(@swc/helpers@0.5.15))(esbuild@0.24.0)(webpack@5.96.1(@swc/core@1.9.3(@swc/helpers@0.5.15))(esbuild@0.24.0)) + terser-webpack-plugin: 5.3.10(@swc/core@1.9.3)(esbuild@0.24.0)(webpack@5.96.1(@swc/core@1.9.3)(esbuild@0.24.0)) watchpack: 2.4.2 webpack-sources: 3.2.3 transitivePeerDependencies: diff --git a/turbo.json b/turbo.json index 310bbbd1796..735b2de5d6a 100644 --- a/turbo.json +++ b/turbo.json @@ -70,6 +70,7 @@ "dependsOn": ["^build", "thirdweb#typedoc"] }, "playground-web#build": { + "env": ["ENGINE_ACCESS_TOKEN", "ENGINE_BACKEND_WALLET", "ENGINE_URL"], "outputs": [".next/**", "!.next/cache/**"], "dependsOn": ["^build"] },