diff --git a/apps/mcp/.env.example b/apps/mcp/.env.example
index 172367a..a776438 100644
--- a/apps/mcp/.env.example
+++ b/apps/mcp/.env.example
@@ -1,17 +1,44 @@
-# Phase 1 will populate this. Phase 0 just reserves the file.
-# See docs/superpowers/specs/2026-05-05-ghbounty-mcp-server-design.md
-
+# GitHub OAuth App for Device Flow
+# Public; ships in env (production + preview).
GITHUB_OAUTH_CLIENT_ID=
+
+# Secret; production env only. Backed up in 1Password.
GITHUB_OAUTH_CLIENT_SECRET=
-# Same value as the existing frontend service-role key, but kept in a
-# separate Vercel project so it can be rotated independently.
-SUPABASE_SERVICE_ROLE_KEY=
+# Supabase service-role key (separate from the frontend's; rotate independently)
SUPABASE_URL=
+SUPABASE_SERVICE_ROLE_KEY=
-# Solana RPC for tx-building (Helius mainnet or devnet).
+# Solana RPC (Helius mainnet for production, devnet for preview/dev)
SOLANA_RPC_URL=
-# Stake authority keypair (JSON array). Same format as GAS_STATION_KEYPAIR_JSON.
-# Generated per Task 2 of Phase 0.
-STAKE_AUTHORITY_KEYPAIR_JSON=
+# Stake authority keypair (JSON array, 64 bytes). Same format as
+# GAS_STATION_KEYPAIR_JSON. Used by the relayer-side cron jobs (Phase 4),
+# NOT by the MCP server itself. Phase 1 doesn't read this — it's listed
+# here for documentation completeness.
+# STAKE_AUTHORITY_KEYPAIR_JSON=
+
+# Upstash Redis for rate limiting — provisioned via Vercel Marketplace
+# (Project Settings → Storage → Browse Marketplace → Upstash → Connect).
+# Vercel auto-injects these env vars after the connection is created.
+# Do NOT set them manually for production/preview deployments.
+UPSTASH_REDIS_REST_URL=
+UPSTASH_REDIS_REST_TOKEN=
+
+# Frontend's gas-station endpoint (production: https://www.ghbounty.com/api/gas-station/sponsor)
+GAS_STATION_SPONSOR_URL=
+
+# Shared secret with the frontend's gas-station-route-core.ts. Phase 1 PR
+# adds this to the frontend env too. Generate a random 64-char hex string.
+GAS_STATION_SERVICE_TOKEN=
+
+# Public; identifies this service in logs / agent welcome messages.
+NEXT_PUBLIC_MCP_BASE_URL=https://mcp.ghbounty.com
+
+# Public; same value as the frontend's GAS_STATION_PUBKEY env var. Used as
+# the fee_payer in unsigned txs returned by prepare_* tools.
+NEXT_PUBLIC_GAS_STATION_PUBKEY=
+
+# Random 32-byte hex (or any string >= 32 chars). Used to AES-256-GCM
+# encrypt GitHub access tokens at rest in agent_accounts.github_oauth_token_encrypted.
+MCP_TOKEN_ENCRYPTION_KEY=
diff --git a/apps/mcp/.gitignore b/apps/mcp/.gitignore
new file mode 100644
index 0000000..025e7a4
--- /dev/null
+++ b/apps/mcp/.gitignore
@@ -0,0 +1,5 @@
+.next/
+node_modules/
+.env.local
+.env*.local
+next-env.d.ts
diff --git a/apps/mcp/README.md b/apps/mcp/README.md
new file mode 100644
index 0000000..bdeaae9
--- /dev/null
+++ b/apps/mcp/README.md
@@ -0,0 +1,36 @@
+# @ghbounty/mcp
+
+Public MCP server hosted at `https://mcp.ghbounty.com`. Lets any AI agent (Claude Code, Cursor, Codex, custom) sign up and operate the GhBounty marketplace autonomously.
+
+## Architecture
+
+- **Next.js 16** + Turbopack (matches the frontend stack)
+- **`@vercel/mcp-adapter`** for the MCP transport (Streamable HTTP)
+- **Supabase service-role** for DB writes; bypasses RLS, enforces equivalent policies in code
+- **Upstash Redis** for rate limiting (provisioned via Vercel Marketplace, no separate Upstash account)
+- **Helius RPC** for Solana
+- **GitHub Device Flow** for agentic OAuth (no browser redirect needed)
+
+## Local development
+
+```bash
+# 1. Copy the env template and fill in real values from 1Password
+cp apps/mcp/.env.example apps/mcp/.env.local
+# Edit apps/mcp/.env.local
+
+# 2. Run the dev server
+pnpm --filter @ghbounty/mcp dev
+
+# 3. Health check
+curl http://localhost:3001/api/health
+```
+
+## Deploy
+
+The Vercel project is `ghbounty-mcp` in the `weareghbounty-6269` team. DNS for `mcp.ghbounty.com` is configured to point at this project. Pushes to `main` auto-deploy to production; PR branches get preview deployments.
+
+Upstash Redis is provisioned via Vercel Marketplace (Project Settings → Storage → Browse Marketplace → Upstash → Connect). No upstash.com signup needed.
+
+## Tools
+
+See `lib/tools/` for the implementations. Surface and contracts documented in `docs/superpowers/specs/2026-05-05-ghbounty-mcp-server-design.md` section 6.
diff --git a/apps/mcp/app/api/health/route.ts b/apps/mcp/app/api/health/route.ts
new file mode 100644
index 0000000..ee1c513
--- /dev/null
+++ b/apps/mcp/app/api/health/route.ts
@@ -0,0 +1,12 @@
+export const dynamic = "force-dynamic";
+
+export async function GET() {
+ return new Response(
+ JSON.stringify({
+ ok: true,
+ service: "ghbounty-mcp",
+ timestamp: new Date().toISOString(),
+ }),
+ { status: 200, headers: { "Content-Type": "application/json" } }
+ );
+}
diff --git a/apps/mcp/app/api/mcp/[transport]/route.ts b/apps/mcp/app/api/mcp/[transport]/route.ts
new file mode 100644
index 0000000..b5bb131
--- /dev/null
+++ b/apps/mcp/app/api/mcp/[transport]/route.ts
@@ -0,0 +1,25 @@
+// Public MCP endpoint. The dynamic route segment `[transport]` is
+// `sse` for Streamable HTTP transport. Tools are registered by
+// `lib/tools/register.ts`; this file is just the framework shell.
+
+import { createMcpHandler } from "mcp-handler";
+import { registerAllTools } from "@/lib/tools/register";
+
+const handler = createMcpHandler(
+ async (server) => {
+ await registerAllTools(server);
+ },
+ {
+ capabilities: {
+ tools: {},
+ },
+ },
+ {
+ basePath: "/api/mcp",
+ }
+);
+
+export { handler as GET, handler as POST, handler as DELETE };
+
+export const dynamic = "force-dynamic";
+export const maxDuration = 60;
diff --git a/apps/mcp/app/globals.css b/apps/mcp/app/globals.css
new file mode 100644
index 0000000..80ca823
--- /dev/null
+++ b/apps/mcp/app/globals.css
@@ -0,0 +1,28 @@
+:root {
+ color-scheme: dark;
+}
+body {
+ margin: 0;
+ font-family: -apple-system, system-ui, sans-serif;
+ background: #0a0a0a;
+ color: #e5e5e5;
+ min-height: 100vh;
+}
+.container {
+ max-width: 720px;
+ margin: 80px auto;
+ padding: 0 24px;
+}
+code {
+ background: #1a1a1a;
+ padding: 2px 6px;
+ border-radius: 4px;
+ font-family: ui-monospace, monospace;
+}
+pre {
+ background: #1a1a1a;
+ padding: 16px;
+ border-radius: 8px;
+ overflow-x: auto;
+}
+a { color: #00e5d1; }
diff --git a/apps/mcp/app/layout.tsx b/apps/mcp/app/layout.tsx
new file mode 100644
index 0000000..1330a0e
--- /dev/null
+++ b/apps/mcp/app/layout.tsx
@@ -0,0 +1,17 @@
+import type { Metadata } from "next";
+import "./globals.css";
+
+export const metadata: Metadata = {
+ title: "GhBounty MCP",
+ description: "Public MCP server for AI agents to operate the GhBounty marketplace.",
+};
+
+export default function RootLayout({
+ children,
+}: Readonly<{ children: React.ReactNode }>) {
+ return (
+
+
{children}
+
+ );
+}
diff --git a/apps/mcp/app/page.tsx b/apps/mcp/app/page.tsx
new file mode 100644
index 0000000..3b0ce88
--- /dev/null
+++ b/apps/mcp/app/page.tsx
@@ -0,0 +1,18 @@
+export default function Page() {
+ return (
+
+
GhBounty MCP Server
+
+ This is the MCP endpoint for AI agents. Connect with the URL:
+
+
https://mcp.ghbounty.com/api/mcp/sse
+
+ Full docs:{" "}
+ ghbounty.com/agents
+
+
+ Health: /api/health
+
+
+ );
+}
diff --git a/apps/mcp/lib/auth/api-key.ts b/apps/mcp/lib/auth/api-key.ts
new file mode 100644
index 0000000..46f4609
--- /dev/null
+++ b/apps/mcp/lib/auth/api-key.ts
@@ -0,0 +1,42 @@
+// API key generation + verification. Format: `ghbk_live_<32 hex chars>`.
+//
+// Storage:
+// - Plaintext is shown to the agent ONCE (response of create_account.complete).
+// - bcrypt hash + first 12 chars (prefix) are stored in api_keys table.
+// - Lookup is by prefix (indexed); bcrypt verifies on match.
+
+import { randomBytes } from "node:crypto";
+import bcrypt from "bcryptjs";
+
+const PREFIX = "ghbk_live_";
+const SECRET_HEX_LEN = 32; // 16 bytes → 32 hex chars
+const PREFIX_HEX_LEN = 12; // first 12 chars of the hex part used as table lookup index
+const BCRYPT_ROUNDS = 12;
+
+export interface MintedKey {
+ /** Full plaintext key. Show to the agent ONCE; never store. */
+ plaintext: string;
+ /** First 12 hex chars (prefixed). Indexed in DB for O(1) lookup. */
+ prefix: string;
+ /** bcrypt hash. Store this in `api_keys.key_hash`. */
+ hash: string;
+}
+
+export function mintApiKey(): MintedKey {
+ const secret = randomBytes(SECRET_HEX_LEN / 2).toString("hex");
+ const plaintext = `${PREFIX}${secret}`;
+ const prefix = `${PREFIX}${secret.slice(0, PREFIX_HEX_LEN)}`;
+ const hash = bcrypt.hashSync(plaintext, BCRYPT_ROUNDS);
+ return { plaintext, prefix, hash };
+}
+
+export function extractPrefix(plaintext: string): string {
+ if (!plaintext.startsWith(PREFIX)) {
+ throw new Error("Invalid API key format");
+ }
+ return plaintext.slice(0, PREFIX.length + PREFIX_HEX_LEN);
+}
+
+export function verifyApiKey(plaintext: string, hash: string): boolean {
+ return bcrypt.compareSync(plaintext, hash);
+}
diff --git a/apps/mcp/lib/auth/middleware.ts b/apps/mcp/lib/auth/middleware.ts
new file mode 100644
index 0000000..6a62039
--- /dev/null
+++ b/apps/mcp/lib/auth/middleware.ts
@@ -0,0 +1,84 @@
+// Bearer token authentication for MCP tool calls.
+//
+// Flow:
+// 1. Parse `Authorization: Bearer ` header.
+// 2. Extract first 22 chars (prefix) for indexed DB lookup.
+// 3. Fetch api_keys row + joined agent_accounts row.
+// 4. bcrypt-verify the plaintext against key_hash.
+// 5. Reject if revoked OR agent_account.status is not 'active'.
+// 6. Return the agent for the tool to use.
+
+import { extractPrefix, verifyApiKey } from "./api-key";
+import { supabaseAdmin } from "@/lib/supabase/admin";
+import type { AuthResult, AgentAccount } from "@/lib/tools/types";
+
+export async function authenticate(
+ authorizationHeader: string | undefined
+): Promise {
+ if (!authorizationHeader || !authorizationHeader.startsWith("Bearer ")) {
+ return { ok: false, error: { code: "Unauthorized", message: "Missing or malformed Authorization header" } };
+ }
+
+ const plaintext = authorizationHeader.slice("Bearer ".length).trim();
+
+ let prefix: string;
+ try {
+ prefix = extractPrefix(plaintext);
+ } catch {
+ return { ok: false, error: { code: "Unauthorized", message: "Invalid API key format" } };
+ }
+
+ const supabase = supabaseAdmin();
+ const { data, error } = await supabase
+ .from("api_keys")
+ .select("id, key_hash, agent_account_id, agent_accounts(id, role, status, wallet_pubkey, github_handle)")
+ .eq("key_prefix", prefix)
+ .is("revoked_at", null)
+ .maybeSingle();
+
+ if (error) {
+ return { ok: false, error: { code: "Unauthorized", message: "Authentication lookup failed" } };
+ }
+ if (!data) {
+ return { ok: false, error: { code: "Unauthorized", message: "API key not found" } };
+ }
+
+ if (!verifyApiKey(plaintext, (data as any).key_hash)) {
+ return { ok: false, error: { code: "Unauthorized", message: "API key mismatch" } };
+ }
+
+ // The Supabase typed-join syntax returns agent_accounts as either an object
+ // or a single-element array depending on the relationship. Normalize.
+ const rawAgent = (data as any).agent_accounts;
+ const agentRow = Array.isArray(rawAgent) ? rawAgent[0] : rawAgent;
+ if (!agentRow) {
+ return { ok: false, error: { code: "Unauthorized", message: "Agent record missing" } };
+ }
+
+ if (agentRow.status !== "active") {
+ return {
+ ok: false,
+ error: {
+ code: "Forbidden",
+ message: `Agent account is ${agentRow.status}, not active`,
+ },
+ };
+ }
+
+ const agent: AgentAccount = {
+ id: agentRow.id,
+ role: agentRow.role,
+ status: agentRow.status,
+ wallet_pubkey: agentRow.wallet_pubkey,
+ github_handle: agentRow.github_handle,
+ };
+
+ // Async: update last_used_at without blocking the response.
+ supabase
+ .from("api_keys")
+ .update({ last_used_at: new Date().toISOString() })
+ .eq("id", (data as any).id)
+ .then(() => {});
+
+ return { ok: true, agent, apiKeyId: (data as any).id };
+}
diff --git a/apps/mcp/lib/errors.ts b/apps/mcp/lib/errors.ts
new file mode 100644
index 0000000..52b4bff
--- /dev/null
+++ b/apps/mcp/lib/errors.ts
@@ -0,0 +1,28 @@
+// Typed errors matching the spec's error model. Each tool returns these
+// to the MCP transport, which formats them as JSON-RPC errors.
+
+export type McpErrorCode =
+ | "BlockhashExpired"
+ | "WalletInsufficientFunds"
+ | "InvalidSignature"
+ | "WrongSigner"
+ | "TxTampered"
+ | "ProgramError"
+ | "RateLimited"
+ | "Unauthorized"
+ | "Forbidden"
+ | "NotFound"
+ | "Conflict"
+ | "RpcError"
+ | "InternalError"
+ | "InvalidInput";
+
+export interface McpError {
+ code: McpErrorCode;
+ message: string;
+ details?: unknown;
+}
+
+export function mcpError(code: McpErrorCode, message: string, details?: unknown): McpError {
+ return { code, message, details };
+}
diff --git a/apps/mcp/lib/github/device-flow.ts b/apps/mcp/lib/github/device-flow.ts
new file mode 100644
index 0000000..0db00e7
--- /dev/null
+++ b/apps/mcp/lib/github/device-flow.ts
@@ -0,0 +1,134 @@
+// GitHub Device Flow proxy + at-rest token encryption.
+//
+// Calls 3 GitHub endpoints:
+// 1. POST /login/device/code → start
+// 2. POST /login/oauth/access_token → poll
+// 3. GET /user → fetch handle (after auth success)
+//
+// Plus AES-256-GCM helpers for encrypting the access_token before storing
+// it in agent_accounts.github_oauth_token_encrypted.
+//
+// Docs: https://docs.github.com/en/apps/creating-github-apps/authenticating-with-a-github-app/
+
+import { createCipheriv, createDecipheriv, randomBytes, createHash } from "node:crypto";
+
+const GH_DEVICE_CODE_URL = "https://github.com/login/device/code";
+const GH_TOKEN_URL = "https://github.com/login/oauth/access_token";
+const GH_USER_URL = "https://api.github.com/user";
+const SCOPE = "read:user user:email";
+
+// --- Device flow ---------------------------------------------------------
+
+export interface DeviceFlowStart {
+ device_code: string;
+ user_code: string;
+ verification_uri: string;
+ expires_in: number;
+ interval: number;
+}
+
+export type PollResult =
+ | { kind: "ok"; access_token: string }
+ | { kind: "pending" }
+ | { kind: "error"; error: string };
+
+function clientId(): string {
+ const id = process.env.GITHUB_OAUTH_CLIENT_ID;
+ if (!id) throw new Error("GITHUB_OAUTH_CLIENT_ID must be set");
+ return id;
+}
+
+export async function startDeviceFlow(): Promise {
+ const res = await fetch(GH_DEVICE_CODE_URL, {
+ method: "POST",
+ headers: {
+ Accept: "application/json",
+ "Content-Type": "application/json",
+ },
+ body: JSON.stringify({
+ client_id: clientId(),
+ scope: SCOPE,
+ }),
+ });
+ if (!res.ok) {
+ throw new Error(`GitHub /login/device/code returned ${res.status}`);
+ }
+ const json = await res.json();
+ return json as DeviceFlowStart;
+}
+
+export async function pollAccessToken(device_code: string): Promise {
+ const res = await fetch(GH_TOKEN_URL, {
+ method: "POST",
+ headers: {
+ Accept: "application/json",
+ "Content-Type": "application/json",
+ },
+ body: JSON.stringify({
+ client_id: clientId(),
+ device_code,
+ grant_type: "urn:ietf:params:oauth:grant-type:device_code",
+ }),
+ });
+ if (!res.ok) {
+ return { kind: "error", error: `http_${res.status}` };
+ }
+ const json = await res.json();
+ if (typeof json.access_token === "string") {
+ return { kind: "ok", access_token: json.access_token };
+ }
+ if (json.error === "authorization_pending" || json.error === "slow_down") {
+ return { kind: "pending" };
+ }
+ return { kind: "error", error: typeof json.error === "string" ? json.error : "unknown" };
+}
+
+export async function fetchUserHandle(access_token: string): Promise {
+ const res = await fetch(GH_USER_URL, {
+ headers: {
+ Accept: "application/vnd.github+json",
+ Authorization: `Bearer ${access_token}`,
+ "X-GitHub-Api-Version": "2022-11-28",
+ },
+ });
+ if (!res.ok) {
+ throw new Error(`GitHub /user returned ${res.status}`);
+ }
+ const json = await res.json();
+ if (typeof json.login !== "string") {
+ throw new Error("GitHub /user response missing login");
+ }
+ return json.login;
+}
+
+// --- Token encryption (at-rest) ----------------------------------------
+
+const ALGO = "aes-256-gcm";
+const IV_LEN = 12;
+const TAG_LEN = 16;
+
+function encryptionKey(): Buffer {
+ const raw = process.env.MCP_TOKEN_ENCRYPTION_KEY;
+ if (!raw) throw new Error("MCP_TOKEN_ENCRYPTION_KEY must be set (32+ chars)");
+ return createHash("sha256").update(raw).digest();
+}
+
+export function encryptAccessToken(plaintext: string): string {
+ const iv = randomBytes(IV_LEN);
+ const cipher = createCipheriv(ALGO, encryptionKey(), iv);
+ const ct = Buffer.concat([cipher.update(plaintext, "utf8"), cipher.final()]);
+ const tag = cipher.getAuthTag();
+ // Layout: iv | tag | ciphertext, base64 encoded.
+ return Buffer.concat([iv, tag, ct]).toString("base64");
+}
+
+export function decryptAccessToken(encoded: string): string {
+ const buf = Buffer.from(encoded, "base64");
+ if (buf.length < IV_LEN + TAG_LEN) throw new Error("ciphertext too short");
+ const iv = buf.subarray(0, IV_LEN);
+ const tag = buf.subarray(IV_LEN, IV_LEN + TAG_LEN);
+ const ct = buf.subarray(IV_LEN + TAG_LEN);
+ const decipher = createDecipheriv(ALGO, encryptionKey(), iv);
+ decipher.setAuthTag(tag);
+ return Buffer.concat([decipher.update(ct), decipher.final()]).toString("utf8");
+}
diff --git a/apps/mcp/lib/rate-limit/ip.ts b/apps/mcp/lib/rate-limit/ip.ts
new file mode 100644
index 0000000..a81957b
--- /dev/null
+++ b/apps/mcp/lib/rate-limit/ip.ts
@@ -0,0 +1,16 @@
+// Extract the client IP from a request, taking Vercel's headers into
+// account. The MCP adapter passes a standard fetch Request, so we read
+// from headers.
+
+export function getClientIp(request: Request): string {
+ // Vercel sets these in order of preference:
+ const forwarded = request.headers.get("x-forwarded-for");
+ if (forwarded) {
+ // First entry in the comma-separated list is the original client.
+ const first = forwarded.split(",")[0];
+ return first ? first.trim() : "unknown";
+ }
+ const real = request.headers.get("x-real-ip");
+ if (real) return real;
+ return "unknown";
+}
diff --git a/apps/mcp/lib/rate-limit/upstash.ts b/apps/mcp/lib/rate-limit/upstash.ts
new file mode 100644
index 0000000..c7b6470
--- /dev/null
+++ b/apps/mcp/lib/rate-limit/upstash.ts
@@ -0,0 +1,72 @@
+// Sliding-window rate limits for the MCP server.
+//
+// Three tiers (spec section 9 layer 3):
+// - createAccount: 5 req / hour / IP (anonymous)
+// - read: 100 req / minute / agent (authenticated)
+// - prepare: 30 req / minute / agent (authenticated, for prepare_* tools)
+//
+// Each tier is a separate Ratelimit instance so we can monitor / tune
+// independently. Upstash's REST client makes them safe to invoke from
+// any serverless environment.
+//
+// Provisioned via Vercel Marketplace (Project → Storage → Browse Marketplace
+// → Upstash → Connect). Vercel auto-injects KV_REST_API_URL +
+// KV_REST_API_TOKEN (its legacy KV naming) when connected this way; direct
+// Upstash setups use UPSTASH_REDIS_REST_URL + UPSTASH_REDIS_REST_TOKEN.
+// We accept both so the same code runs in either configuration.
+
+import { Ratelimit } from "@upstash/ratelimit";
+import { Redis } from "@upstash/redis";
+
+let _redis: Redis | null = null;
+function redis(): Redis {
+ if (_redis) return _redis;
+ const url =
+ process.env.UPSTASH_REDIS_REST_URL ?? process.env.KV_REST_API_URL;
+ const token =
+ process.env.UPSTASH_REDIS_REST_TOKEN ?? process.env.KV_REST_API_TOKEN;
+ if (!url || !token) {
+ throw new Error(
+ "Upstash Redis credentials must be set: UPSTASH_REDIS_REST_URL/_TOKEN (direct) or KV_REST_API_URL/_TOKEN (Vercel Marketplace)"
+ );
+ }
+ _redis = new Redis({ url, token });
+ return _redis;
+}
+
+let _createAccount: Ratelimit | null = null;
+let _read: Ratelimit | null = null;
+let _prepare: Ratelimit | null = null;
+
+export function createAccountLimiter(): Ratelimit {
+ if (_createAccount) return _createAccount;
+ _createAccount = new Ratelimit({
+ redis: redis(),
+ limiter: Ratelimit.slidingWindow(5, "1 h"),
+ prefix: "mcp:create_account",
+ analytics: true,
+ });
+ return _createAccount;
+}
+
+export function readLimiter(): Ratelimit {
+ if (_read) return _read;
+ _read = new Ratelimit({
+ redis: redis(),
+ limiter: Ratelimit.slidingWindow(100, "1 m"),
+ prefix: "mcp:read",
+ analytics: true,
+ });
+ return _read;
+}
+
+export function prepareLimiter(): Ratelimit {
+ if (_prepare) return _prepare;
+ _prepare = new Ratelimit({
+ redis: redis(),
+ limiter: Ratelimit.slidingWindow(30, "1 m"),
+ prefix: "mcp:prepare",
+ analytics: true,
+ });
+ return _prepare;
+}
diff --git a/apps/mcp/lib/solana/gas-station-client.ts b/apps/mcp/lib/solana/gas-station-client.ts
new file mode 100644
index 0000000..27c8fe3
--- /dev/null
+++ b/apps/mcp/lib/solana/gas-station-client.ts
@@ -0,0 +1,56 @@
+// Calls the frontend's /api/gas-station/sponsor endpoint to submit a
+// gas-station-sponsored transaction. The endpoint is shared with the
+// frontend and has its own auth (Privy bearer for human users; we use
+// a service-to-service shared secret for the MCP).
+//
+// FRONTEND FOLLOW-UP NEEDED: frontend/lib/gas-station-route-core.ts must
+// be extended to accept a new auth path: requests with the
+// `x-mcp-service-token` header where the value matches the
+// GAS_STATION_SERVICE_TOKEN env var. Open a separate PR after this one
+// merges.
+//
+// Returns either { tx_hash } or a structured error.
+
+export interface SponsorResult {
+ ok: boolean;
+ tx_hash?: string;
+ error?: { code: string; message: string };
+}
+
+function endpointUrl(): string {
+ const url = process.env.GAS_STATION_SPONSOR_URL;
+ if (!url) throw new Error("GAS_STATION_SPONSOR_URL must be set");
+ return url;
+}
+
+function serviceToken(): string {
+ const tok = process.env.GAS_STATION_SERVICE_TOKEN;
+ if (!tok) throw new Error("GAS_STATION_SERVICE_TOKEN must be set");
+ return tok;
+}
+
+export async function sponsorAndSubmit(signed_tx_b64: string): Promise {
+ const res = await fetch(endpointUrl(), {
+ method: "POST",
+ headers: {
+ "Content-Type": "application/json",
+ "x-mcp-service-token": serviceToken(),
+ },
+ body: JSON.stringify({ signed_tx_b64, source: "mcp" }),
+ });
+
+ let json: { tx_hash?: string; error?: { code: string; message: string } };
+ try {
+ json = (await res.json()) as { tx_hash?: string; error?: { code: string; message: string } };
+ } catch {
+ return { ok: false, error: { code: "RpcError", message: `Gas station returned ${res.status} (non-JSON body)` } };
+ }
+
+ if (res.status === 200 && json.tx_hash) {
+ return { ok: true, tx_hash: json.tx_hash };
+ }
+ if (json.error) {
+ return { ok: false, error: json.error };
+ }
+ return { ok: false, error: { code: "RpcError", message: `Gas station returned ${res.status}` } };
+}
diff --git a/apps/mcp/lib/solana/rpc.ts b/apps/mcp/lib/solana/rpc.ts
new file mode 100644
index 0000000..e93212f
--- /dev/null
+++ b/apps/mcp/lib/solana/rpc.ts
@@ -0,0 +1,36 @@
+// @solana/kit RPC client. Reads SOLANA_RPC_URL from env (Helius mainnet
+// for production, devnet for dev). Singleton for connection reuse.
+
+import {
+ createSolanaRpc,
+ createSolanaRpcSubscriptions,
+ type Rpc,
+ type SolanaRpcApi,
+ type RpcSubscriptions,
+ type SolanaRpcSubscriptionsApi,
+} from "@solana/kit";
+
+let _rpc: Rpc | null = null;
+let _subs: RpcSubscriptions | null = null;
+
+export function solanaRpc(): Rpc {
+ if (_rpc) return _rpc;
+ const url = process.env.SOLANA_RPC_URL;
+ if (!url) {
+ throw new Error("SOLANA_RPC_URL must be set in apps/mcp env");
+ }
+ _rpc = createSolanaRpc(url);
+ return _rpc;
+}
+
+export function solanaRpcSubscriptions(): RpcSubscriptions {
+ if (_subs) return _subs;
+ const url = process.env.SOLANA_RPC_URL;
+ if (!url) {
+ throw new Error("SOLANA_RPC_URL must be set in apps/mcp env");
+ }
+ // ws:// URL is the http URL with the protocol swapped
+ const wsUrl = url.replace(/^http/, "ws");
+ _subs = createSolanaRpcSubscriptions(wsUrl);
+ return _subs;
+}
diff --git a/apps/mcp/lib/supabase/admin.ts b/apps/mcp/lib/supabase/admin.ts
new file mode 100644
index 0000000..848ea25
--- /dev/null
+++ b/apps/mcp/lib/supabase/admin.ts
@@ -0,0 +1,34 @@
+// Service-role Supabase client. Bypasses RLS. Used ONLY by MCP tool
+// handlers, which must enforce equivalent policies in code (e.g., agent X
+// can only see their own api_keys, not other agents').
+//
+// Singleton because Next.js can re-import per-request in dev; we want
+// connection reuse where possible.
+//
+// TODO Phase 4: import the typed `Database` shape from @ghbounty/db once
+// frontend/lib/db.types.ts is shared via the workspace package. For now
+// the client is untyped — tool handlers cast at call sites.
+
+import { createClient, type SupabaseClient } from "@supabase/supabase-js";
+
+let _client: SupabaseClient | null = null;
+
+export function supabaseAdmin(): SupabaseClient {
+ if (_client) return _client;
+
+ const url = process.env.SUPABASE_URL;
+ const key = process.env.SUPABASE_SERVICE_ROLE_KEY;
+ if (!url || !key) {
+ throw new Error(
+ "SUPABASE_URL and SUPABASE_SERVICE_ROLE_KEY must be set in apps/mcp env"
+ );
+ }
+
+ _client = createClient(url, key, {
+ auth: {
+ persistSession: false,
+ autoRefreshToken: false,
+ },
+ });
+ return _client;
+}
diff --git a/apps/mcp/lib/tools/bounties/get.ts b/apps/mcp/lib/tools/bounties/get.ts
new file mode 100644
index 0000000..9398810
--- /dev/null
+++ b/apps/mcp/lib/tools/bounties/get.ts
@@ -0,0 +1,76 @@
+import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
+import { z } from "zod";
+import { authenticate } from "@/lib/auth/middleware";
+import { supabaseAdmin } from "@/lib/supabase/admin";
+import { mcpError } from "@/lib/errors";
+
+const GetInput = z.object({
+ authorization: z.string().optional(),
+ id: z.string().uuid(),
+});
+
+export async function handleBountiesGet(raw: unknown) {
+ const parsed = GetInput.safeParse(raw);
+ if (!parsed.success) return { error: mcpError("InvalidInput", parsed.error.message) };
+
+ const auth = await authenticate(parsed.data.authorization);
+ if (!auth.ok) return { error: auth.error };
+
+ const supabase = supabaseAdmin();
+
+ const { data, error } = await supabase
+ .from("issues")
+ .select(
+ "id, amount, state, pda, github_issue_url, submission_count, bounty_meta(title, description, release_mode, evaluation_criteria, reject_threshold), created_at, creator"
+ )
+ .eq("id", parsed.data.id)
+ .maybeSingle();
+
+ if (error) return { error: mcpError("InternalError", error.message) };
+ if (!data) return { error: mcpError("NotFound", "Bounty not found") };
+
+ const row = data as any;
+ const meta = Array.isArray(row.bounty_meta) ? row.bounty_meta[0] : row.bounty_meta;
+
+ // If caller is a dev, surface their submission for this bounty (if any).
+ let my_submission: { id: string; status: string } | null = null;
+ if (auth.agent.role === "dev" && row.pda) {
+ const { data: sub } = await supabase
+ .from("submissions")
+ .select("id, state")
+ .eq("issue_pda", row.pda)
+ .eq("solver", auth.agent.wallet_pubkey)
+ .maybeSingle();
+ if (sub) my_submission = { id: (sub as any).id, status: (sub as any).state };
+ }
+
+ return {
+ bounty: {
+ id: row.id,
+ amount_sol: (Number(row.amount) / 1e9).toString(),
+ state: row.state,
+ pda: row.pda,
+ github_issue_url: row.github_issue_url,
+ title: meta?.title ?? null,
+ description: meta?.description ?? null,
+ release_mode: meta?.release_mode ?? null,
+ evaluation_criteria: meta?.evaluation_criteria ?? null,
+ reject_threshold: meta?.reject_threshold ?? null,
+ submission_count: row.submission_count,
+ created_at: row.created_at,
+ },
+ my_submission,
+ };
+}
+
+export function registerBountiesGet(server: McpServer): void {
+ server.tool(
+ "bounties.get",
+ { id: z.string().uuid() },
+ async (input, extra) => {
+ const authorization = (extra as any)?.requestInfo?.headers?.authorization;
+ const result = await handleBountiesGet({ ...input, authorization });
+ return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
+ }
+ );
+}
diff --git a/apps/mcp/lib/tools/bounties/list.ts b/apps/mcp/lib/tools/bounties/list.ts
new file mode 100644
index 0000000..545b800
--- /dev/null
+++ b/apps/mcp/lib/tools/bounties/list.ts
@@ -0,0 +1,75 @@
+import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
+import { z } from "zod";
+import { authenticate } from "@/lib/auth/middleware";
+import { supabaseAdmin } from "@/lib/supabase/admin";
+import { mcpError } from "@/lib/errors";
+
+const ListInput = z.object({
+ authorization: z.string().optional(),
+ filter: z
+ .object({
+ status: z.enum(["open", "resolved", "cancelled"]).optional(),
+ min_sol: z.string().optional(),
+ max_sol: z.string().optional(),
+ })
+ .optional(),
+ cursor: z.string().optional(),
+});
+
+export async function handleBountiesList(raw: unknown) {
+ const parsed = ListInput.safeParse(raw);
+ if (!parsed.success) return { error: mcpError("InvalidInput", parsed.error.message) };
+
+ const auth = await authenticate(parsed.data.authorization);
+ if (!auth.ok) return { error: auth.error };
+
+ const filter = parsed.data.filter ?? {};
+ const supabase = supabaseAdmin();
+
+ let q: any = supabase
+ .from("issues")
+ .select(
+ "id, amount, state, github_issue_url, submission_count, bounty_meta(title, description, release_mode), created_at"
+ );
+
+ if (filter.status) q = q.eq("state", filter.status);
+
+ q = q.order("created_at", { ascending: false }).limit(50);
+
+ const { data, error } = await q;
+ if (error) return { error: mcpError("InternalError", error.message) };
+
+ return {
+ items: (data ?? []).map((row: any) => ({
+ id: row.id,
+ title: Array.isArray(row.bounty_meta) ? row.bounty_meta[0]?.title ?? null : row.bounty_meta?.title ?? null,
+ amount_sol: (Number(row.amount) / 1e9).toString(),
+ github_url: row.github_issue_url,
+ submission_count: row.submission_count,
+ state: row.state,
+ created_at: row.created_at,
+ })),
+ next_cursor: null, // simple paging in v1
+ };
+}
+
+export function registerBountiesList(server: McpServer): void {
+ server.tool(
+ "bounties.list",
+ {
+ filter: z
+ .object({
+ status: z.enum(["open", "resolved", "cancelled"]).optional(),
+ min_sol: z.string().optional(),
+ max_sol: z.string().optional(),
+ })
+ .optional(),
+ cursor: z.string().optional(),
+ },
+ async (input, extra) => {
+ const authorization = (extra as any)?.requestInfo?.headers?.authorization;
+ const result = await handleBountiesList({ ...input, authorization });
+ return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
+ }
+ );
+}
diff --git a/apps/mcp/lib/tools/create-account/complete.ts b/apps/mcp/lib/tools/create-account/complete.ts
new file mode 100644
index 0000000..98a640a
--- /dev/null
+++ b/apps/mcp/lib/tools/create-account/complete.ts
@@ -0,0 +1,211 @@
+// apps/mcp/lib/tools/create-account/complete.ts
+//
+// Tool: create_account.complete
+// Public (no auth). Submits the signed init_stake_deposit tx.
+//
+// Steps (full algorithm in spec section 7):
+// 1. SELECT pending_txs by (agent_account_id, tool_name='create_account.complete').
+// 404 if missing/expired/consumed.
+// 2. Decode signed_tx_b64. Verify the agent's signature is present
+// and the wire-bytes hash matches pending_txs.message_hash (anti-tamper).
+// 3. POST to gas-station endpoint to submit. Wait for confirm.
+// 4. On confirm:
+// - INSERT stake_deposits row.
+// - INSERT profiles, developers OR companies, wallets.
+// - Mint API key, INSERT api_keys.
+// - UPDATE agent_accounts.status = active.
+// - UPDATE pending_txs.consumed_at.
+// 5. Return { api_key, agent_id, profile, github_handle }.
+
+import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
+import { z } from "zod";
+import { createHash } from "node:crypto";
+import { getTransactionDecoder } from "@solana/kit";
+import { supabaseAdmin } from "@/lib/supabase/admin";
+import { sponsorAndSubmit } from "@/lib/solana/gas-station-client";
+import { mintApiKey } from "@/lib/auth/api-key";
+import { mcpError, type McpError } from "@/lib/errors";
+
+const CompleteInput = z.object({
+ account_id: z.string().uuid(),
+ signed_tx_b64: z.string().min(1),
+});
+
+interface CompleteOk {
+ api_key: string;
+ agent_id: string;
+ github_handle: string;
+ profile: {
+ id: string;
+ role: "dev" | "company";
+ wallet_pubkey: string;
+ };
+}
+type CompleteResult = CompleteOk | { error: McpError };
+
+export async function handleCreateAccountComplete(raw: unknown): Promise {
+ const parsed = CompleteInput.safeParse(raw);
+ if (!parsed.success) {
+ return { error: mcpError("InvalidInput", parsed.error.message) };
+ }
+ const { account_id, signed_tx_b64 } = parsed.data;
+
+ const supabase = supabaseAdmin();
+
+ // 1. Find the pending_tx row.
+ const { data: pending } = await supabase
+ .from("pending_txs")
+ .select("id, message_hash, expected_signer, expires_at, consumed_at")
+ .eq("agent_account_id", account_id)
+ .eq("tool_name", "create_account.complete")
+ .order("created_at", { ascending: false })
+ .limit(1)
+ .single();
+
+ if (!pending) {
+ return { error: mcpError("BlockhashExpired", "No pending transaction found for this account") };
+ }
+ const p = pending as any;
+ if (p.consumed_at) {
+ return { error: mcpError("BlockhashExpired", "Pending transaction already consumed") };
+ }
+ if (new Date(p.expires_at) < new Date()) {
+ return { error: mcpError("BlockhashExpired", "Pending transaction expired") };
+ }
+
+ // 2. Decode signed tx, verify signer + wire-bytes hash.
+ let decoded: any;
+ let wireBytes: Buffer;
+ try {
+ wireBytes = Buffer.from(signed_tx_b64, "base64");
+ decoded = getTransactionDecoder().decode(wireBytes);
+ } catch {
+ return { error: mcpError("InvalidSignature", "Could not decode signed transaction") };
+ }
+
+ // Verify the expected signer's signature is present and not null.
+ const sig = decoded.signatures?.[p.expected_signer];
+ if (!sig) {
+ return { error: mcpError("WrongSigner", "Expected signer signature missing") };
+ }
+
+ // Verify hash matches what poll() recorded.
+ const actualHash = createHash("sha256").update(wireBytes).digest("hex");
+ if (actualHash !== p.message_hash) {
+ return { error: mcpError("TxTampered", "Transaction wire bytes do not match prepared hash") };
+ }
+
+ // 3. Submit via gas station (handles fee payer signing + RPC submit + confirm).
+ const sponsorRes = await sponsorAndSubmit(signed_tx_b64);
+ if (!sponsorRes.ok || !sponsorRes.tx_hash) {
+ return {
+ error: mcpError(
+ sponsorRes.error?.code === "WalletInsufficientFunds" ? "WalletInsufficientFunds" : "RpcError",
+ sponsorRes.error?.message ?? "Sponsor failed"
+ ),
+ };
+ }
+
+ // 4. Persist post-confirmation rows.
+ const { data: agent } = await supabase
+ .from("agent_accounts")
+ .select("id, role, wallet_pubkey, github_handle")
+ .eq("id", account_id)
+ .single();
+
+ if (!agent || !(agent as any).github_handle) {
+ return { error: mcpError("InternalError", "Agent missing or has no github_handle") };
+ }
+ const ag = agent as any;
+
+ // INSERT stake_deposits. PDA derivation TODO Phase 2 — for v1, store the
+ // wallet pubkey + tx_hash, derive the actual PDA later from the chain.
+ // The DB row schema requires `pda`; use a placeholder format that includes
+ // the tx_hash so the row is unique and traceable.
+ await supabase.from("stake_deposits").insert({
+ agent_account_id: account_id,
+ pda: `stake-deposit-pda:${ag.wallet_pubkey}`, // TODO: real PDA derivation
+ tx_signature: sponsorRes.tx_hash,
+ amount_lamports: "35000000",
+ locked_until: new Date(Date.now() + 14 * 24 * 60 * 60 * 1000).toISOString(),
+ });
+
+ // INSERT profiles, developers/companies, wallets.
+ const userId = `did:agent:${ag.id}`;
+ await supabase.from("profiles").insert({
+ user_id: userId,
+ role: ag.role,
+ github_handle: ag.github_handle,
+ });
+
+ if (ag.role === "dev") {
+ await supabase.from("developers").insert({
+ user_id: userId,
+ github_handle: ag.github_handle,
+ });
+ } else {
+ await supabase.from("companies").insert({
+ user_id: userId,
+ name: ag.github_handle,
+ slug: ag.github_handle.toLowerCase(),
+ });
+ }
+
+ await supabase.from("wallets").insert({
+ user_id: userId,
+ chain_id: "solana-mainnet",
+ address: ag.wallet_pubkey,
+ });
+
+ // Mint API key.
+ const { plaintext, prefix, hash } = mintApiKey();
+ const { data: keyRow } = await supabase
+ .from("api_keys")
+ .insert({
+ agent_account_id: account_id,
+ key_hash: hash,
+ key_prefix: prefix,
+ })
+ .select("id")
+ .single();
+
+ if (!keyRow) {
+ return { error: mcpError("InternalError", "API key insert failed") };
+ }
+
+ // Mark agent active + consume pending_tx.
+ await supabase
+ .from("agent_accounts")
+ .update({ status: "active" })
+ .eq("id", account_id);
+
+ await supabase
+ .from("pending_txs")
+ .update({ consumed_at: new Date().toISOString() })
+ .eq("id", p.id);
+
+ return {
+ api_key: plaintext,
+ agent_id: ag.id,
+ github_handle: ag.github_handle,
+ profile: {
+ id: userId,
+ role: ag.role,
+ wallet_pubkey: ag.wallet_pubkey,
+ },
+ };
+}
+
+export function registerCreateAccountComplete(server: McpServer): void {
+ server.tool(
+ "create_account.complete",
+ {
+ account_id: z.string().uuid(),
+ signed_tx_b64: z.string(),
+ },
+ async (input) => {
+ const result = await handleCreateAccountComplete(input);
+ return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
+ }
+ );
+}
diff --git a/apps/mcp/lib/tools/create-account/init.ts b/apps/mcp/lib/tools/create-account/init.ts
new file mode 100644
index 0000000..5109316
--- /dev/null
+++ b/apps/mcp/lib/tools/create-account/init.ts
@@ -0,0 +1,119 @@
+// apps/mcp/lib/tools/create-account/init.ts
+//
+// Tool: create_account.init
+// Public (no auth). Rate-limited per IP.
+//
+// Steps:
+// 1. Validate input (role + wallet_pubkey shape).
+// 2. Rate-limit by IP via createAccountLimiter.
+// 3. POST GitHub /login/device/code to get user_code.
+// 4. INSERT agent_accounts row with status=pending_oauth, store device_code in
+// github_oauth_token_encrypted (gets overwritten with the access_token in poll).
+// 5. Return account_id, user_code, verification_uri, expires_at.
+
+import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
+import { z } from "zod";
+import { supabaseAdmin } from "@/lib/supabase/admin";
+import { startDeviceFlow, encryptAccessToken } from "@/lib/github/device-flow";
+import { createAccountLimiter } from "@/lib/rate-limit/upstash";
+import { mcpError, type McpError } from "@/lib/errors";
+
+const InitInput = z.object({
+ role: z.enum(["dev", "company"]),
+ wallet_pubkey: z.string().regex(/^[1-9A-HJ-NP-Za-km-z]{32,44}$/, "Invalid Solana pubkey"),
+ ip: z.string().optional(),
+ company_info: z
+ .object({
+ name: z.string().min(1).max(80),
+ slug: z.string().regex(/^[a-z0-9-]{2,40}$/),
+ website: z.string().url().optional(),
+ github_org: z.string().optional(),
+ })
+ .optional(),
+});
+
+interface InitOk {
+ account_id: string;
+ user_code: string;
+ verification_uri: string;
+ expires_at: string;
+}
+type InitResult = InitOk | { error: McpError };
+
+export async function handleCreateAccountInit(raw: unknown): Promise {
+ const parsed = InitInput.safeParse(raw);
+ if (!parsed.success) {
+ return { error: mcpError("InvalidInput", parsed.error.message) };
+ }
+ const { role, wallet_pubkey, ip = "unknown" } = parsed.data;
+
+ // Rate limit by IP.
+ const rl = await createAccountLimiter().limit(ip);
+ if (!rl.success) {
+ return { error: mcpError("RateLimited", "Too many account creation attempts from this IP") };
+ }
+
+ // Start GitHub Device Flow.
+ let dev: Awaited>;
+ try {
+ dev = await startDeviceFlow();
+ } catch (err) {
+ return { error: mcpError("RpcError", `GitHub Device Flow failed: ${(err as Error).message}`) };
+ }
+
+ // INSERT agent_accounts.
+ const supabase = supabaseAdmin();
+ const { data, error } = await supabase
+ .from("agent_accounts")
+ .insert({
+ role,
+ wallet_pubkey,
+ status: "pending_oauth",
+ github_oauth_token_encrypted: encryptAccessToken(dev.device_code),
+ })
+ .select("id")
+ .single();
+
+ if (error) {
+ if (error.code === "23505") {
+ return { error: mcpError("Conflict", "An agent with this wallet_pubkey already exists") };
+ }
+ return { error: mcpError("InternalError", `agent_accounts insert: ${error.message}`) };
+ }
+
+ return {
+ account_id: (data as any).id,
+ user_code: dev.user_code,
+ verification_uri: dev.verification_uri,
+ expires_at: new Date(Date.now() + dev.expires_in * 1000).toISOString(),
+ };
+}
+
+// Tool registration glue.
+export function registerCreateAccountInit(server: McpServer): void {
+ server.tool(
+ "create_account.init",
+ {
+ role: z.enum(["dev", "company"]),
+ wallet_pubkey: z.string(),
+ company_info: z
+ .object({
+ name: z.string(),
+ slug: z.string(),
+ website: z.string().optional(),
+ github_org: z.string().optional(),
+ })
+ .optional(),
+ },
+ async (input, extra) => {
+ const ip =
+ (extra as any)?.requestInfo?.headers?.["x-forwarded-for"]?.toString().split(",")[0]?.trim() ||
+ (extra as any)?.requestInfo?.headers?.["x-real-ip"] ||
+ "unknown";
+ const result = await handleCreateAccountInit({ ...input, ip });
+ return {
+ content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
+ };
+ }
+ );
+}
diff --git a/apps/mcp/lib/tools/create-account/poll.ts b/apps/mcp/lib/tools/create-account/poll.ts
new file mode 100644
index 0000000..c1e96b5
--- /dev/null
+++ b/apps/mcp/lib/tools/create-account/poll.ts
@@ -0,0 +1,215 @@
+// apps/mcp/lib/tools/create-account/poll.ts
+//
+// Tool: create_account.poll
+// Public (no auth).
+//
+// Steps (full algorithm in spec section 7):
+// 1. SELECT agent_accounts row by id, must be status=pending_oauth.
+// 2. Decrypt the stored device_code.
+// 3. POST GitHub /login/oauth/access_token with device_code.
+// 4. If pending → return { status: "pending" }.
+// 5. If ok:
+// a. GET /user with the access_token to extract login (handle).
+// b. UPDATE agent_accounts: github_handle, status=pending_stake,
+// github_oauth_token_encrypted=encrypted access_token.
+// c. Build unsigned tx: init_stake_deposit(35M lamports), with
+// GAS_STATION_PUBKEY as fee_payer, agent's pubkey as signer.
+// d. Compute message hash; INSERT pending_txs row.
+// e. Return { status: "ready_to_stake", github_handle, tx_to_sign_b64,
+// expected_signers, expected_program_id, stake_amount_sol }.
+
+import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
+import { z } from "zod";
+import {
+ pollAccessToken,
+ fetchUserHandle,
+ decryptAccessToken,
+ encryptAccessToken,
+} from "@/lib/github/device-flow";
+import { supabaseAdmin } from "@/lib/supabase/admin";
+import { solanaRpc } from "@/lib/solana/rpc";
+import { mcpError, type McpError } from "@/lib/errors";
+import {
+ address,
+ appendTransactionMessageInstructions,
+ createTransactionMessage,
+ pipe,
+ setTransactionMessageFeePayer,
+ setTransactionMessageLifetimeUsingBlockhash,
+ compileTransaction,
+ getBase64EncodedWireTransaction,
+} from "@solana/kit";
+import {
+ getInitStakeDepositInstruction,
+ findStakePda,
+} from "@ghbounty/sdk";
+import { createHash } from "node:crypto";
+
+const PollInput = z.object({
+ account_id: z.string().uuid(),
+});
+
+const STAKE_AMOUNT = 35_000_000n; // 0.035 SOL
+const PENDING_TX_TTL_SECONDS = 50;
+
+interface PollPending { status: "pending" }
+interface PollReady {
+ status: "ready_to_stake";
+ github_handle: string;
+ tx_to_sign_b64: string;
+ expected_signers: string[];
+ expected_program_id: string;
+ stake_amount_sol: string;
+}
+type PollResult = PollPending | PollReady | { error: McpError };
+
+function getProgramAddress(): string {
+ // The IDL-generated GHBOUNTY_ESCROW_PROGRAM_ADDRESS is "" (empty).
+ // Read the real address from env; fall back to the devnet address from Anchor.toml.
+ return (
+ process.env.GHBOUNTY_PROGRAM_ADDRESS ??
+ "CPZx26QXs3HjwGobr8cVAZEtF1qGzqnNbBdt7h1EwbBg"
+ );
+}
+
+export async function handleCreateAccountPoll(raw: unknown): Promise {
+ const parsed = PollInput.safeParse(raw);
+ if (!parsed.success) {
+ return { error: mcpError("InvalidInput", parsed.error.message) };
+ }
+ const { account_id } = parsed.data;
+
+ const supabase = supabaseAdmin();
+
+ // Fetch the agent row.
+ const { data: agent, error: agentErr } = await supabase
+ .from("agent_accounts")
+ .select("id, status, role, wallet_pubkey, github_oauth_token_encrypted")
+ .eq("id", account_id)
+ .single();
+
+ if (agentErr || !agent) {
+ return { error: mcpError("NotFound", "Agent account not found") };
+ }
+ const a = agent as any;
+ if (a.status === "active") {
+ return { error: mcpError("Conflict", "Account already active") };
+ }
+ if (a.status !== "pending_oauth") {
+ return { error: mcpError("Forbidden", `Cannot poll account with status ${a.status}`) };
+ }
+ if (!a.github_oauth_token_encrypted) {
+ return { error: mcpError("InternalError", "Device code missing on account") };
+ }
+
+ // Decrypt + poll.
+ let device_code: string;
+ try {
+ device_code = decryptAccessToken(a.github_oauth_token_encrypted);
+ } catch {
+ return { error: mcpError("InternalError", "Failed to decrypt device code") };
+ }
+
+ const pollResult = await pollAccessToken(device_code);
+ if (pollResult.kind === "pending") {
+ return { status: "pending" };
+ }
+ if (pollResult.kind === "error") {
+ return { error: mcpError("Forbidden", `GitHub Device Flow error: ${pollResult.error}`) };
+ }
+
+ // Got access_token — fetch user, update agent, build tx.
+ const handle = await fetchUserHandle(pollResult.access_token);
+
+ const { error: updErr } = await supabase
+ .from("agent_accounts")
+ .update({
+ github_handle: handle,
+ status: "pending_stake",
+ github_oauth_token_encrypted: encryptAccessToken(pollResult.access_token),
+ })
+ .eq("id", account_id);
+
+ if (updErr) {
+ if ((updErr as any).code === "23505") {
+ return { error: mcpError("Conflict", "GitHub handle already used by another agent") };
+ }
+ return { error: mcpError("InternalError", `agent update: ${(updErr as any).message}`) };
+ }
+
+ // Build the init_stake_deposit transaction.
+ // Use the sync builder + explicitly derive the stake PDA ourselves,
+ // passing the real program address (IDL placeholder is "").
+ const programAddr = address(getProgramAddress());
+ const ownerAddr = address(a.wallet_pubkey);
+
+ // Derive stake PDA using the real program address.
+ const [stakePdaAddr] = await findStakePda(
+ { owner: ownerAddr },
+ { programAddress: programAddr },
+ );
+
+ // Build a partial signer shape (address-only); signing happens later in `complete`.
+ const ownerSigner = { address: ownerAddr } as any;
+
+ const ix = getInitStakeDepositInstruction(
+ {
+ owner: ownerSigner,
+ stake: stakePdaAddr,
+ amount: STAKE_AMOUNT,
+ },
+ { programAddress: programAddr },
+ );
+
+ const rpc = solanaRpc();
+ const { value: blockhash } = await rpc.getLatestBlockhash().send();
+
+ const gasStationPubkey = process.env.NEXT_PUBLIC_GAS_STATION_PUBKEY;
+ if (!gasStationPubkey) {
+ return { error: mcpError("InternalError", "NEXT_PUBLIC_GAS_STATION_PUBKEY must be set") };
+ }
+
+ const message = pipe(
+ createTransactionMessage({ version: 0 }),
+ (m) => setTransactionMessageFeePayer(address(gasStationPubkey), m),
+ (m) => setTransactionMessageLifetimeUsingBlockhash(blockhash, m),
+ (m) => appendTransactionMessageInstructions([ix], m),
+ );
+
+ const compiled = compileTransaction(message);
+ const tx_to_sign_b64 = getBase64EncodedWireTransaction(compiled);
+
+ // Compute message hash for anti-tamper validation in `complete`.
+ const wireBytes = Buffer.from(tx_to_sign_b64, "base64");
+ const message_hash = createHash("sha256").update(wireBytes).digest("hex");
+
+ // INSERT pending_txs row.
+ await supabase.from("pending_txs").insert({
+ agent_account_id: account_id,
+ tool_name: "create_account.complete",
+ resource_id: null,
+ message_hash,
+ expected_signer: a.wallet_pubkey,
+ expires_at: new Date(Date.now() + PENDING_TX_TTL_SECONDS * 1000).toISOString(),
+ });
+
+ return {
+ status: "ready_to_stake",
+ github_handle: handle,
+ tx_to_sign_b64,
+ expected_signers: [a.wallet_pubkey],
+ expected_program_id: getProgramAddress(),
+ stake_amount_sol: "0.035",
+ };
+}
+
+export function registerCreateAccountPoll(server: McpServer): void {
+ server.tool(
+ "create_account.poll",
+ { account_id: z.string().uuid() },
+ async (input) => {
+ const result = await handleCreateAccountPoll(input);
+ return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
+ }
+ );
+}
diff --git a/apps/mcp/lib/tools/register.ts b/apps/mcp/lib/tools/register.ts
new file mode 100644
index 0000000..cd38ea7
--- /dev/null
+++ b/apps/mcp/lib/tools/register.ts
@@ -0,0 +1,18 @@
+import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
+import { registerCreateAccountInit } from "./create-account/init";
+import { registerCreateAccountPoll } from "./create-account/poll";
+import { registerCreateAccountComplete } from "./create-account/complete";
+import { registerWhoami } from "./whoami";
+import { registerBountiesList } from "./bounties/list";
+import { registerBountiesGet } from "./bounties/get";
+import { registerSubmissionsGet } from "./submissions/get";
+
+export async function registerAllTools(server: McpServer): Promise {
+ registerCreateAccountInit(server);
+ registerCreateAccountPoll(server);
+ registerCreateAccountComplete(server);
+ registerWhoami(server);
+ registerBountiesList(server);
+ registerBountiesGet(server);
+ registerSubmissionsGet(server);
+}
diff --git a/apps/mcp/lib/tools/submissions/get.ts b/apps/mcp/lib/tools/submissions/get.ts
new file mode 100644
index 0000000..f381fde
--- /dev/null
+++ b/apps/mcp/lib/tools/submissions/get.ts
@@ -0,0 +1,61 @@
+import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
+import { z } from "zod";
+import { authenticate } from "@/lib/auth/middleware";
+import { supabaseAdmin } from "@/lib/supabase/admin";
+import { mcpError } from "@/lib/errors";
+
+const GetInput = z.object({
+ authorization: z.string().optional(),
+ submission_id: z.string().uuid(),
+});
+
+export async function handleSubmissionsGet(raw: unknown) {
+ const parsed = GetInput.safeParse(raw);
+ if (!parsed.success) return { error: mcpError("InvalidInput", parsed.error.message) };
+
+ const auth = await authenticate(parsed.data.authorization);
+ if (!auth.ok) return { error: auth.error };
+
+ const supabase = supabaseAdmin();
+ const { data, error } = await supabase
+ .from("submissions")
+ .select("id, solver, pr_url, score, state, opus_report_hash, bounty:issue_pda(creator)")
+ .eq("id", parsed.data.submission_id)
+ .maybeSingle();
+
+ if (error) return { error: mcpError("InternalError", error.message) };
+ if (!data) return { error: mcpError("NotFound", "Submission not found") };
+
+ const row = data as any;
+ const callerWallet = auth.agent.wallet_pubkey;
+ const isSolver = row.solver === callerWallet;
+ const bountyRel = Array.isArray(row.bounty) ? row.bounty[0] : row.bounty;
+ const isBountyOwner = bountyRel?.creator === callerWallet;
+
+ if (!isSolver && !isBountyOwner) {
+ return { error: mcpError("Forbidden", "Not authorized to view this submission") };
+ }
+
+ return {
+ submission: {
+ id: row.id,
+ solver: row.solver,
+ pr_url: row.pr_url,
+ score: row.score,
+ state: row.state,
+ opus_report_hash: row.opus_report_hash,
+ },
+ };
+}
+
+export function registerSubmissionsGet(server: McpServer): void {
+ server.tool(
+ "submissions.get",
+ { submission_id: z.string().uuid() },
+ async (input, extra) => {
+ const authorization = (extra as any)?.requestInfo?.headers?.authorization;
+ const result = await handleSubmissionsGet({ ...input, authorization });
+ return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
+ }
+ );
+}
diff --git a/apps/mcp/lib/tools/types.ts b/apps/mcp/lib/tools/types.ts
new file mode 100644
index 0000000..7313a35
--- /dev/null
+++ b/apps/mcp/lib/tools/types.ts
@@ -0,0 +1,13 @@
+// Shared types for tool handlers.
+
+export interface AgentAccount {
+ id: string;
+ role: "dev" | "company";
+ status: "pending_oauth" | "pending_stake" | "active" | "suspended" | "revoked";
+ wallet_pubkey: string;
+ github_handle: string | null;
+}
+
+export type AuthResult =
+ | { ok: true; agent: AgentAccount; apiKeyId: string }
+ | { ok: false; error: { code: "Unauthorized" | "Forbidden"; message: string } };
diff --git a/apps/mcp/lib/tools/whoami.ts b/apps/mcp/lib/tools/whoami.ts
new file mode 100644
index 0000000..4c4da4b
--- /dev/null
+++ b/apps/mcp/lib/tools/whoami.ts
@@ -0,0 +1,44 @@
+import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
+import { authenticate } from "@/lib/auth/middleware";
+import { solanaRpc } from "@/lib/solana/rpc";
+import { address } from "@solana/kit";
+
+interface WhoamiInput {
+ authorization?: string;
+}
+
+export async function handleWhoami(input: WhoamiInput) {
+ const auth = await authenticate(input.authorization);
+ if (!auth.ok) {
+ return { error: auth.error };
+ }
+ const { agent } = auth;
+
+ const rpc = solanaRpc();
+ let balanceLamports = 0n;
+ try {
+ const { value } = await rpc.getBalance(address(agent.wallet_pubkey)).send();
+ balanceLamports = value;
+ } catch {
+ // Soft fail — RPC hiccup; return 0 balance instead of erroring.
+ }
+
+ return {
+ agent_id: agent.id,
+ role: agent.role,
+ status: agent.status,
+ github_handle: agent.github_handle,
+ wallet_pubkey: agent.wallet_pubkey,
+ balances: {
+ sol_lamports: balanceLamports.toString(),
+ },
+ };
+}
+
+export function registerWhoami(server: McpServer): void {
+ server.tool("whoami", {}, async (_input, extra) => {
+ const authorization = (extra as any)?.requestInfo?.headers?.authorization;
+ const result = await handleWhoami({ authorization });
+ return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
+ });
+}
diff --git a/apps/mcp/next.config.ts b/apps/mcp/next.config.ts
new file mode 100644
index 0000000..183b22c
--- /dev/null
+++ b/apps/mcp/next.config.ts
@@ -0,0 +1,11 @@
+import type { NextConfig } from "next";
+
+const nextConfig: NextConfig = {
+ // Same reason as frontend: workspace packages with NodeNext-style imports
+ // need transpilation through Next/SWC.
+ transpilePackages: ["@ghbounty/sdk", "@ghbounty/shared", "@ghbounty/db"],
+
+ reactStrictMode: true,
+};
+
+export default nextConfig;
diff --git a/apps/mcp/package.json b/apps/mcp/package.json
new file mode 100644
index 0000000..68036e2
--- /dev/null
+++ b/apps/mcp/package.json
@@ -0,0 +1,37 @@
+{
+ "name": "@ghbounty/mcp",
+ "version": "0.0.0",
+ "private": true,
+ "type": "module",
+ "scripts": {
+ "dev": "next dev --port 3001",
+ "build": "next build",
+ "start": "next start --port 3001",
+ "typecheck": "tsc --noEmit",
+ "test": "vitest run"
+ },
+ "dependencies": {
+ "@ghbounty/db": "workspace:^",
+ "@ghbounty/sdk": "workspace:^",
+ "@ghbounty/shared": "workspace:^",
+ "@modelcontextprotocol/sdk": "^1.0.0",
+ "@solana/kit": "^6.9.0",
+ "@supabase/supabase-js": "^2.104.1",
+ "@upstash/ratelimit": "^2.0.8",
+ "@upstash/redis": "^1.38.0",
+ "mcp-handler": "^1.1.0",
+ "bcryptjs": "^3.0.3",
+ "next": "16.2.4",
+ "react": "19.2.4",
+ "react-dom": "19.2.4",
+ "zod": "^3.23.8"
+ },
+ "devDependencies": {
+ "@types/bcryptjs": "^2.4.6",
+ "@types/node": "^22.0.0",
+ "@types/react": "^19.0.0",
+ "@types/react-dom": "^19.0.0",
+ "typescript": "^5.6.0",
+ "vitest": "^2.1.9"
+ }
+}
diff --git a/apps/mcp/tests/auth/api-key.test.ts b/apps/mcp/tests/auth/api-key.test.ts
new file mode 100644
index 0000000..6aee35b
--- /dev/null
+++ b/apps/mcp/tests/auth/api-key.test.ts
@@ -0,0 +1,42 @@
+import { describe, it, expect } from "vitest";
+import { mintApiKey, verifyApiKey, extractPrefix } from "@/lib/auth/api-key";
+
+describe("mintApiKey", () => {
+ it("produces a key with the correct prefix and length", () => {
+ const { plaintext, prefix, hash } = mintApiKey();
+ expect(plaintext).toMatch(/^ghbk_live_[0-9a-f]{32}$/);
+ expect(prefix).toMatch(/^ghbk_live_[0-9a-f]{12}$/);
+ expect(plaintext.startsWith(prefix)).toBe(true);
+ expect(hash).not.toBe(plaintext);
+ expect(hash.length).toBeGreaterThan(50); // bcrypt hashes are ~60 chars
+ });
+
+ it("produces unique keys on every call", () => {
+ const a = mintApiKey();
+ const b = mintApiKey();
+ expect(a.plaintext).not.toBe(b.plaintext);
+ });
+});
+
+describe("verifyApiKey", () => {
+ it("returns true for the matching plaintext", () => {
+ const { plaintext, hash } = mintApiKey();
+ expect(verifyApiKey(plaintext, hash)).toBe(true);
+ });
+
+ it("returns false for a different plaintext", () => {
+ const { hash } = mintApiKey();
+ expect(verifyApiKey("ghbk_live_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", hash)).toBe(false);
+ });
+});
+
+describe("extractPrefix", () => {
+ it("returns the first 22 chars (prefix + 12 hex)", () => {
+ const { plaintext, prefix } = mintApiKey();
+ expect(extractPrefix(plaintext)).toBe(prefix);
+ });
+
+ it("throws on invalid format", () => {
+ expect(() => extractPrefix("invalid_key")).toThrow();
+ });
+});
diff --git a/apps/mcp/tests/auth/middleware.test.ts b/apps/mcp/tests/auth/middleware.test.ts
new file mode 100644
index 0000000..73d390a
--- /dev/null
+++ b/apps/mcp/tests/auth/middleware.test.ts
@@ -0,0 +1,130 @@
+import { describe, it, expect, vi, beforeEach } from "vitest";
+import { authenticate } from "@/lib/auth/middleware";
+
+// Mock the supabase admin client
+vi.mock("@/lib/supabase/admin", () => ({
+ supabaseAdmin: vi.fn(),
+}));
+
+import { supabaseAdmin } from "@/lib/supabase/admin";
+
+describe("authenticate", () => {
+ beforeEach(() => {
+ vi.resetAllMocks();
+ });
+
+ it("returns Unauthorized when header is missing", async () => {
+ const result = await authenticate(undefined);
+ expect(result.ok).toBe(false);
+ if (!result.ok) {
+ expect(result.error.code).toBe("Unauthorized");
+ }
+ });
+
+ it("returns Unauthorized for malformed Bearer header", async () => {
+ const result = await authenticate("Token abc");
+ expect(result.ok).toBe(false);
+ });
+
+ it("returns Unauthorized when prefix not found in DB", async () => {
+ (supabaseAdmin as any).mockReturnValue({
+ from: () => ({
+ select: () => ({
+ eq: () => ({
+ is: () => ({
+ maybeSingle: () => Promise.resolve({ data: null, error: null }),
+ }),
+ }),
+ }),
+ }),
+ });
+
+ const result = await authenticate("Bearer ghbk_live_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
+ expect(result.ok).toBe(false);
+ if (!result.ok) {
+ expect(result.error.code).toBe("Unauthorized");
+ }
+ });
+
+ it("returns the agent_account when prefix matches and bcrypt verifies", async () => {
+ const { mintApiKey } = await import("@/lib/auth/api-key");
+ const { plaintext, hash } = mintApiKey();
+
+ (supabaseAdmin as any).mockReturnValue({
+ from: () => ({
+ select: () => ({
+ eq: () => ({
+ is: () => ({
+ maybeSingle: () =>
+ Promise.resolve({
+ data: {
+ id: "key-uuid",
+ key_hash: hash,
+ agent_account_id: "agent-uuid",
+ agent_accounts: {
+ id: "agent-uuid",
+ role: "dev",
+ status: "active",
+ wallet_pubkey: "7xK...",
+ github_handle: "claudebot42",
+ },
+ },
+ error: null,
+ }),
+ }),
+ }),
+ }),
+ update: () => ({
+ eq: () => ({
+ then: (cb: any) => cb(),
+ }),
+ }),
+ }),
+ });
+
+ const result = await authenticate(`Bearer ${plaintext}`);
+ expect(result.ok).toBe(true);
+ if (result.ok) {
+ expect(result.agent.role).toBe("dev");
+ expect(result.agent.status).toBe("active");
+ }
+ });
+
+ it("returns Forbidden when agent status is not active", async () => {
+ const { mintApiKey } = await import("@/lib/auth/api-key");
+ const { plaintext, hash } = mintApiKey();
+
+ (supabaseAdmin as any).mockReturnValue({
+ from: () => ({
+ select: () => ({
+ eq: () => ({
+ is: () => ({
+ maybeSingle: () =>
+ Promise.resolve({
+ data: {
+ id: "key-uuid",
+ key_hash: hash,
+ agent_account_id: "agent-uuid",
+ agent_accounts: {
+ id: "agent-uuid",
+ role: "dev",
+ status: "suspended",
+ wallet_pubkey: "7xK...",
+ github_handle: "claudebot42",
+ },
+ },
+ error: null,
+ }),
+ }),
+ }),
+ }),
+ }),
+ });
+
+ const result = await authenticate(`Bearer ${plaintext}`);
+ expect(result.ok).toBe(false);
+ if (!result.ok) {
+ expect(result.error.code).toBe("Forbidden");
+ }
+ });
+});
diff --git a/apps/mcp/tests/e2e/onboarding.test.ts b/apps/mcp/tests/e2e/onboarding.test.ts
new file mode 100644
index 0000000..b1a47c8
--- /dev/null
+++ b/apps/mcp/tests/e2e/onboarding.test.ts
@@ -0,0 +1,66 @@
+import { describe, it, expect, vi, beforeEach } from "vitest";
+
+// Wire mocks for Supabase, GitHub, gas-station, RPC, and rate-limit.
+vi.mock("@/lib/supabase/admin", () => ({ supabaseAdmin: vi.fn() }));
+vi.mock("@/lib/github/device-flow");
+vi.mock("@/lib/solana/gas-station-client", () => ({
+ sponsorAndSubmit: vi.fn().mockResolvedValue({ ok: true, tx_hash: "MOCK_TX_HASH" }),
+}));
+vi.mock("@/lib/rate-limit/upstash", () => ({
+ createAccountLimiter: () => ({ limit: () => Promise.resolve({ success: true }) }),
+}));
+vi.mock("@/lib/solana/rpc", () => ({
+ solanaRpc: () => ({
+ getLatestBlockhash: () => ({
+ send: () =>
+ Promise.resolve({
+ value: { blockhash: "1".repeat(32), lastValidBlockHeight: 1n },
+ }),
+ }),
+ getBalance: () => ({ send: () => Promise.resolve({ value: 100_000_000n }) }),
+ }),
+}));
+
+import { handleCreateAccountInit } from "@/lib/tools/create-account/init";
+import { supabaseAdmin } from "@/lib/supabase/admin";
+import { startDeviceFlow } from "@/lib/github/device-flow";
+
+describe("E2E: onboarding init smoke", () => {
+ beforeEach(() => {
+ vi.resetAllMocks();
+ process.env.MCP_TOKEN_ENCRYPTION_KEY = "x".repeat(32);
+ });
+
+ it("init returns user_code + persists agent row", async () => {
+ (startDeviceFlow as any).mockResolvedValue({
+ device_code: "DEV",
+ user_code: "ABCD-1234",
+ verification_uri: "https://github.com/login/device",
+ expires_in: 900,
+ interval: 5,
+ });
+
+ const insertCall = vi.fn().mockReturnValue({
+ select: () => ({
+ single: () => Promise.resolve({ data: { id: "agent-1" }, error: null }),
+ }),
+ });
+
+ (supabaseAdmin as any).mockReturnValue({
+ from: () => ({ insert: insertCall }),
+ });
+
+ const result = await handleCreateAccountInit({
+ role: "dev",
+ wallet_pubkey: "7xK7gE8FpQrSjVz9mYwGtCkBtNvDtTvPzGjGpZqMxKqp",
+ ip: "192.0.2.1",
+ });
+
+ if ("error" in result) {
+ throw new Error(`Expected success, got: ${result.error.code}`);
+ }
+ expect(result.user_code).toBe("ABCD-1234");
+ expect(result.account_id).toBe("agent-1");
+ expect(insertCall).toHaveBeenCalledOnce();
+ });
+});
diff --git a/apps/mcp/tests/github/device-flow.test.ts b/apps/mcp/tests/github/device-flow.test.ts
new file mode 100644
index 0000000..9127fb4
--- /dev/null
+++ b/apps/mcp/tests/github/device-flow.test.ts
@@ -0,0 +1,122 @@
+import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
+import {
+ startDeviceFlow,
+ pollAccessToken,
+ fetchUserHandle,
+} from "@/lib/github/device-flow";
+
+const realFetch = global.fetch;
+
+describe("GitHub Device Flow client", () => {
+ beforeEach(() => {
+ process.env.GITHUB_OAUTH_CLIENT_ID = "test_client_id";
+ });
+
+ afterEach(() => {
+ global.fetch = realFetch;
+ });
+
+ describe("startDeviceFlow", () => {
+ it("posts client_id + scope and returns the device_code", async () => {
+ global.fetch = vi.fn().mockResolvedValue({
+ ok: true,
+ json: () =>
+ Promise.resolve({
+ device_code: "DEV_CODE",
+ user_code: "ABCD-1234",
+ verification_uri: "https://github.com/login/device",
+ expires_in: 900,
+ interval: 5,
+ }),
+ });
+
+ const result = await startDeviceFlow();
+ expect(result.device_code).toBe("DEV_CODE");
+ expect(result.user_code).toBe("ABCD-1234");
+
+ const calls = (global.fetch as any).mock.calls;
+ expect(calls[0][0]).toBe("https://github.com/login/device/code");
+ expect(calls[0][1].method).toBe("POST");
+ });
+ });
+
+ describe("pollAccessToken", () => {
+ it("returns the access_token when GitHub returns success", async () => {
+ global.fetch = vi.fn().mockResolvedValue({
+ ok: true,
+ json: () => Promise.resolve({ access_token: "TOKEN_123", token_type: "bearer" }),
+ });
+
+ const result = await pollAccessToken("DEV_CODE");
+ expect(result.kind).toBe("ok");
+ if (result.kind === "ok") {
+ expect(result.access_token).toBe("TOKEN_123");
+ }
+ });
+
+ it("returns 'pending' when authorization_pending", async () => {
+ global.fetch = vi.fn().mockResolvedValue({
+ ok: true,
+ json: () => Promise.resolve({ error: "authorization_pending" }),
+ });
+
+ const result = await pollAccessToken("DEV_CODE");
+ expect(result.kind).toBe("pending");
+ });
+
+ it("returns 'error' for any other GitHub error", async () => {
+ global.fetch = vi.fn().mockResolvedValue({
+ ok: true,
+ json: () => Promise.resolve({ error: "expired_token" }),
+ });
+
+ const result = await pollAccessToken("DEV_CODE");
+ expect(result.kind).toBe("error");
+ if (result.kind === "error") {
+ expect(result.error).toBe("expired_token");
+ }
+ });
+ });
+
+ describe("fetchUserHandle", () => {
+ it("returns login for the user authenticated by the access token", async () => {
+ global.fetch = vi.fn().mockResolvedValue({
+ ok: true,
+ json: () =>
+ Promise.resolve({
+ login: "claudebot42",
+ id: 12345,
+ email: "claudebot@example.com",
+ }),
+ });
+
+ const handle = await fetchUserHandle("TOKEN_123");
+ expect(handle).toBe("claudebot42");
+ });
+ });
+});
+
+describe("token encryption", () => {
+ beforeEach(() => {
+ process.env.MCP_TOKEN_ENCRYPTION_KEY = "x".repeat(32);
+ });
+
+ it("encryptAccessToken / decryptAccessToken round-trip", async () => {
+ const { encryptAccessToken, decryptAccessToken } = await import(
+ "@/lib/github/device-flow"
+ );
+ const plaintext = "ghu_1234567890abcdef";
+ const encrypted = encryptAccessToken(plaintext);
+ expect(encrypted).not.toBe(plaintext);
+ expect(decryptAccessToken(encrypted)).toBe(plaintext);
+ });
+
+ it("decrypt fails on tampered ciphertext", async () => {
+ const { encryptAccessToken, decryptAccessToken } = await import(
+ "@/lib/github/device-flow"
+ );
+ const enc = encryptAccessToken("plaintext");
+ const tampered = enc.slice(0, -2) + "AA";
+ expect(() => decryptAccessToken(tampered)).toThrow();
+ });
+});
diff --git a/apps/mcp/tests/rate-limit/upstash.test.ts b/apps/mcp/tests/rate-limit/upstash.test.ts
new file mode 100644
index 0000000..5b8dc6e
--- /dev/null
+++ b/apps/mcp/tests/rate-limit/upstash.test.ts
@@ -0,0 +1,19 @@
+import { describe, it, expect } from "vitest";
+
+const HAS_UPSTASH =
+ !!process.env.UPSTASH_REDIS_REST_URL && !!process.env.UPSTASH_REDIS_REST_TOKEN;
+
+describe.skipIf(!HAS_UPSTASH)("Upstash rate limiter (live)", () => {
+ it("createAccountLimiter rejects on the 6th request from same IP within an hour", async () => {
+ const { createAccountLimiter } = await import("@/lib/rate-limit/upstash");
+ const limiter = createAccountLimiter();
+ const ip = `test:${Date.now()}`;
+
+ for (let i = 0; i < 5; i++) {
+ const r = await limiter.limit(ip);
+ expect(r.success).toBe(true);
+ }
+ const sixth = await limiter.limit(ip);
+ expect(sixth.success).toBe(false);
+ }, 30_000);
+});
diff --git a/apps/mcp/tests/tools/bounties.test.ts b/apps/mcp/tests/tools/bounties.test.ts
new file mode 100644
index 0000000..e465e87
--- /dev/null
+++ b/apps/mcp/tests/tools/bounties.test.ts
@@ -0,0 +1,89 @@
+import { describe, it, expect, vi, beforeEach } from "vitest";
+
+vi.mock("@/lib/supabase/admin", () => ({ supabaseAdmin: vi.fn() }));
+vi.mock("@/lib/auth/middleware");
+
+import { handleBountiesList } from "@/lib/tools/bounties/list";
+import { authenticate } from "@/lib/auth/middleware";
+import { supabaseAdmin } from "@/lib/supabase/admin";
+
+describe("bounties.list", () => {
+ beforeEach(() => vi.resetAllMocks());
+
+ it("returns Unauthorized when not authed", async () => {
+ (authenticate as any).mockResolvedValue({
+ ok: false,
+ error: { code: "Unauthorized", message: "no key" },
+ });
+ const result = await handleBountiesList({ authorization: undefined });
+ expect((result as any).error.code).toBe("Unauthorized");
+ });
+
+ it("returns paginated open bounties", async () => {
+ (authenticate as any).mockResolvedValue({
+ ok: true,
+ agent: { id: "a", role: "dev", status: "active", wallet_pubkey: "7", github_handle: "h" },
+ });
+
+ (supabaseAdmin as any).mockReturnValue({
+ from: () => ({
+ select: () => ({
+ eq: () => ({
+ order: () => ({
+ limit: () =>
+ Promise.resolve({
+ data: [
+ {
+ id: "b1",
+ amount: "1000000000",
+ state: "open",
+ github_issue_url: "x",
+ submission_count: 0,
+ bounty_meta: [{ title: "t" }],
+ created_at: "2026-05-06",
+ },
+ ],
+ error: null,
+ }),
+ }),
+ }),
+ }),
+ }),
+ });
+
+ const result = await handleBountiesList({
+ authorization: "Bearer ghbk_live_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+ filter: { status: "open" },
+ });
+ expect((result as any).items).toHaveLength(1);
+ expect((result as any).items[0].id).toBe("b1");
+ expect((result as any).items[0].amount_sol).toBe("1");
+ });
+});
+
+describe("bounties.get", () => {
+ beforeEach(() => vi.resetAllMocks());
+
+ it("returns 404 for unknown id", async () => {
+ const { handleBountiesGet } = await import("@/lib/tools/bounties/get");
+ (authenticate as any).mockResolvedValue({
+ ok: true,
+ agent: { id: "a", role: "dev", status: "active", wallet_pubkey: "7", github_handle: "h" },
+ });
+ (supabaseAdmin as any).mockReturnValue({
+ from: () => ({
+ select: () => ({
+ eq: () => ({
+ maybeSingle: () => Promise.resolve({ data: null, error: null }),
+ }),
+ }),
+ }),
+ });
+
+ const result = await handleBountiesGet({
+ authorization: "Bearer ghbk_live_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+ id: "00000000-0000-0000-0000-000000000099",
+ });
+ expect((result as any).error.code).toBe("NotFound");
+ });
+});
diff --git a/apps/mcp/tests/tools/create-account.test.ts b/apps/mcp/tests/tools/create-account.test.ts
new file mode 100644
index 0000000..093938f
--- /dev/null
+++ b/apps/mcp/tests/tools/create-account.test.ts
@@ -0,0 +1,362 @@
+import { describe, it, expect, vi, beforeEach } from "vitest";
+
+vi.mock("@/lib/supabase/admin", () => ({
+ supabaseAdmin: vi.fn(),
+}));
+vi.mock("@/lib/github/device-flow");
+vi.mock("@/lib/rate-limit/upstash", () => ({
+ createAccountLimiter: () => ({ limit: () => Promise.resolve({ success: true }) }),
+}));
+
+import { handleCreateAccountInit } from "@/lib/tools/create-account/init";
+import { supabaseAdmin } from "@/lib/supabase/admin";
+import { startDeviceFlow } from "@/lib/github/device-flow";
+
+describe("create_account.init handler", () => {
+ beforeEach(() => {
+ vi.resetAllMocks();
+ process.env.MCP_TOKEN_ENCRYPTION_KEY = "x".repeat(32);
+ });
+
+ it("inserts agent_accounts row + returns user_code", async () => {
+ (startDeviceFlow as any).mockResolvedValue({
+ device_code: "DEV_CODE_AAA",
+ user_code: "ABCD-1234",
+ verification_uri: "https://github.com/login/device",
+ expires_in: 900,
+ interval: 5,
+ });
+
+ const insertChain = {
+ insert: vi.fn().mockReturnValue({
+ select: vi.fn().mockReturnValue({
+ single: vi.fn().mockResolvedValue({
+ data: { id: "agent-uuid-1" },
+ error: null,
+ }),
+ }),
+ }),
+ };
+ (supabaseAdmin as any).mockReturnValue({
+ from: () => insertChain,
+ });
+
+ const result = await handleCreateAccountInit({
+ role: "dev",
+ wallet_pubkey: "7xK7gE8FpQrSjVz9mYwGtCkBtNvDtTvPzGjGpZqMxKqp",
+ ip: "192.0.2.1",
+ });
+
+ if ("error" in result) {
+ throw new Error(`Expected ok, got error: ${result.error.code}`);
+ }
+ expect(result.user_code).toBe("ABCD-1234");
+ expect(result.account_id).toBe("agent-uuid-1");
+ expect(insertChain.insert).toHaveBeenCalledOnce();
+ });
+
+ it("returns Conflict 409 if wallet_pubkey already exists", async () => {
+ (startDeviceFlow as any).mockResolvedValue({
+ device_code: "DEV_CODE_AAA",
+ user_code: "ABCD-1234",
+ verification_uri: "https://github.com/login/device",
+ expires_in: 900,
+ interval: 5,
+ });
+ const insertChain = {
+ insert: () => ({
+ select: () => ({
+ single: () =>
+ Promise.resolve({
+ data: null,
+ error: { code: "23505", message: "duplicate key value violates unique constraint" },
+ }),
+ }),
+ }),
+ };
+ (supabaseAdmin as any).mockReturnValue({
+ from: () => insertChain,
+ });
+
+ const result = await handleCreateAccountInit({
+ role: "dev",
+ wallet_pubkey: "7xK7gE8FpQrSjVz9mYwGtCkBtNvDtTvPzGjGpZqMxKqp",
+ ip: "192.0.2.1",
+ });
+ if (!("error" in result)) throw new Error("expected error");
+ expect(result.error.code).toBe("Conflict");
+ });
+
+ it("returns RateLimited when limiter rejects", async () => {
+ vi.doMock("@/lib/rate-limit/upstash", () => ({
+ createAccountLimiter: () => ({ limit: () => Promise.resolve({ success: false }) }),
+ }));
+ vi.resetModules();
+ const { handleCreateAccountInit } = await import("@/lib/tools/create-account/init");
+
+ const result = await handleCreateAccountInit({
+ role: "dev",
+ wallet_pubkey: "7xK7gE8FpQrSjVz9mYwGtCkBtNvDtTvPzGjGpZqMxKqp",
+ ip: "192.0.2.1",
+ });
+ if (!("error" in result)) throw new Error("expected error");
+ expect(result.error.code).toBe("RateLimited");
+
+ vi.doUnmock("@/lib/rate-limit/upstash");
+ });
+});
+
+describe("create_account.poll handler", () => {
+ beforeEach(() => {
+ vi.resetAllMocks();
+ process.env.MCP_TOKEN_ENCRYPTION_KEY = "x".repeat(32);
+ process.env.NEXT_PUBLIC_GAS_STATION_PUBKEY = "11111111111111111111111111111112";
+ process.env.SOLANA_RPC_URL = "https://api.devnet.solana.com";
+ });
+
+ it("returns 'pending' when GitHub still polling", async () => {
+ const { handleCreateAccountPoll } = await import(
+ "@/lib/tools/create-account/poll"
+ );
+ const { pollAccessToken, decryptAccessToken } = await import("@/lib/github/device-flow");
+ (pollAccessToken as any).mockResolvedValue({ kind: "pending" });
+ (decryptAccessToken as any).mockReturnValue("DEV_CODE_DECRYPTED");
+
+ (supabaseAdmin as any).mockReturnValue({
+ from: () => ({
+ select: () => ({
+ eq: () => ({
+ single: () =>
+ Promise.resolve({
+ data: {
+ id: "agent-uuid-1",
+ status: "pending_oauth",
+ wallet_pubkey: "7xK7gE8FpQrSjVz9mYwGtCkBtNvDtTvPzGjGpZqMxKqp",
+ role: "dev",
+ github_oauth_token_encrypted: "encrypted_device_code_b64",
+ },
+ error: null,
+ }),
+ }),
+ }),
+ }),
+ });
+
+ const result = await handleCreateAccountPoll({ account_id: "00000000-0000-0000-0000-000000000001" });
+ expect((result as any).status).toBe("pending");
+ });
+
+ it("returns NotFound when account_id doesn't exist", async () => {
+ const { handleCreateAccountPoll } = await import(
+ "@/lib/tools/create-account/poll"
+ );
+ (supabaseAdmin as any).mockReturnValue({
+ from: () => ({
+ select: () => ({
+ eq: () => ({
+ single: () => Promise.resolve({ data: null, error: { message: "not found" } }),
+ }),
+ }),
+ }),
+ });
+
+ const result = await handleCreateAccountPoll({ account_id: "00000000-0000-0000-0000-000000000099" });
+ if (!("error" in result)) throw new Error("expected error");
+ expect((result as any).error.code).toBe("NotFound");
+ });
+
+ it("returns Forbidden when account already active", async () => {
+ const { handleCreateAccountPoll } = await import(
+ "@/lib/tools/create-account/poll"
+ );
+ (supabaseAdmin as any).mockReturnValue({
+ from: () => ({
+ select: () => ({
+ eq: () => ({
+ single: () =>
+ Promise.resolve({
+ data: {
+ id: "agent-1",
+ status: "active",
+ wallet_pubkey: "7xK...",
+ role: "dev",
+ github_oauth_token_encrypted: "abc",
+ },
+ error: null,
+ }),
+ }),
+ }),
+ }),
+ });
+
+ const result = await handleCreateAccountPoll({ account_id: "00000000-0000-0000-0000-000000000001" });
+ if (!("error" in result)) throw new Error("expected error");
+ // Conflict because account is already active
+ expect((result as any).error.code).toBe("Conflict");
+ });
+});
+
+describe("create_account.complete handler", () => {
+ beforeEach(() => {
+ vi.resetAllMocks();
+ process.env.MCP_TOKEN_ENCRYPTION_KEY = "x".repeat(32);
+ process.env.GAS_STATION_SPONSOR_URL = "https://example.com/api/gas-station/sponsor";
+ process.env.GAS_STATION_SERVICE_TOKEN = "test-token";
+ });
+
+ it("returns BlockhashExpired when pending_txs row is gone or expired", async () => {
+ const { handleCreateAccountComplete } = await import(
+ "@/lib/tools/create-account/complete"
+ );
+
+ (supabaseAdmin as any).mockReturnValue({
+ from: () => ({
+ select: () => ({
+ eq: () => ({
+ eq: () => ({
+ order: () => ({
+ limit: () => ({
+ single: () =>
+ Promise.resolve({ data: null, error: null }),
+ }),
+ }),
+ }),
+ }),
+ }),
+ }),
+ });
+
+ const result = await handleCreateAccountComplete({
+ account_id: "00000000-0000-0000-0000-000000000001",
+ signed_tx_b64: "AQAB",
+ });
+ if (!("error" in result)) throw new Error("expected error");
+ expect(result.error.code).toBe("BlockhashExpired");
+ });
+
+ it("returns BlockhashExpired when pending_tx already consumed", async () => {
+ const { handleCreateAccountComplete } = await import(
+ "@/lib/tools/create-account/complete"
+ );
+
+ (supabaseAdmin as any).mockReturnValue({
+ from: () => ({
+ select: () => ({
+ eq: () => ({
+ eq: () => ({
+ order: () => ({
+ limit: () => ({
+ single: () =>
+ Promise.resolve({
+ data: {
+ id: "tx-1",
+ message_hash: "abc",
+ expected_signer: "7xK...",
+ expires_at: new Date(Date.now() + 30000).toISOString(),
+ consumed_at: new Date().toISOString(),
+ },
+ error: null,
+ }),
+ }),
+ }),
+ }),
+ }),
+ }),
+ }),
+ });
+
+ const result = await handleCreateAccountComplete({
+ account_id: "00000000-0000-0000-0000-000000000001",
+ signed_tx_b64: "AQAB",
+ });
+ if (!("error" in result)) throw new Error("expected error");
+ expect(result.error.code).toBe("BlockhashExpired");
+ });
+
+ it("returns BlockhashExpired when pending_tx is past expires_at", async () => {
+ const { handleCreateAccountComplete } = await import(
+ "@/lib/tools/create-account/complete"
+ );
+
+ (supabaseAdmin as any).mockReturnValue({
+ from: () => ({
+ select: () => ({
+ eq: () => ({
+ eq: () => ({
+ order: () => ({
+ limit: () => ({
+ single: () =>
+ Promise.resolve({
+ data: {
+ id: "tx-1",
+ message_hash: "abc",
+ expected_signer: "7xK...",
+ expires_at: new Date(Date.now() - 30000).toISOString(),
+ consumed_at: null,
+ },
+ error: null,
+ }),
+ }),
+ }),
+ }),
+ }),
+ }),
+ }),
+ });
+
+ const result = await handleCreateAccountComplete({
+ account_id: "00000000-0000-0000-0000-000000000001",
+ signed_tx_b64: "AQAB",
+ });
+ if (!("error" in result)) throw new Error("expected error");
+ expect(result.error.code).toBe("BlockhashExpired");
+ });
+});
+
+describe("create_account.complete signature validation", () => {
+ beforeEach(() => {
+ vi.resetAllMocks();
+ process.env.MCP_TOKEN_ENCRYPTION_KEY = "x".repeat(32);
+ process.env.GAS_STATION_SPONSOR_URL = "https://example.com/api/gas-station/sponsor";
+ process.env.GAS_STATION_SERVICE_TOKEN = "test-token";
+ });
+
+ it("returns InvalidSignature when signed_tx_b64 is malformed", async () => {
+ const { handleCreateAccountComplete } = await import(
+ "@/lib/tools/create-account/complete"
+ );
+
+ (supabaseAdmin as any).mockReturnValue({
+ from: () => ({
+ select: () => ({
+ eq: () => ({
+ eq: () => ({
+ order: () => ({
+ limit: () => ({
+ single: () =>
+ Promise.resolve({
+ data: {
+ id: "tx-1",
+ message_hash: "abc",
+ expected_signer: "7xK...",
+ expires_at: new Date(Date.now() + 30000).toISOString(),
+ consumed_at: null,
+ },
+ error: null,
+ }),
+ }),
+ }),
+ }),
+ }),
+ }),
+ }),
+ });
+
+ const result = await handleCreateAccountComplete({
+ account_id: "00000000-0000-0000-0000-000000000001",
+ signed_tx_b64: "not-valid-base64-or-tx",
+ });
+ if (!("error" in result)) throw new Error("expected error");
+ expect(["InvalidSignature", "WrongSigner", "TxTampered"]).toContain(result.error.code);
+ });
+});
diff --git a/apps/mcp/tests/tools/submissions.test.ts b/apps/mcp/tests/tools/submissions.test.ts
new file mode 100644
index 0000000..7aaa7a4
--- /dev/null
+++ b/apps/mcp/tests/tools/submissions.test.ts
@@ -0,0 +1,79 @@
+import { describe, it, expect, vi, beforeEach } from "vitest";
+
+vi.mock("@/lib/supabase/admin", () => ({ supabaseAdmin: vi.fn() }));
+vi.mock("@/lib/auth/middleware");
+
+import { handleSubmissionsGet } from "@/lib/tools/submissions/get";
+import { authenticate } from "@/lib/auth/middleware";
+import { supabaseAdmin } from "@/lib/supabase/admin";
+
+describe("submissions.get", () => {
+ beforeEach(() => vi.resetAllMocks());
+
+ it("403 when caller is neither solver nor bounty company", async () => {
+ (authenticate as any).mockResolvedValue({
+ ok: true,
+ agent: { id: "a", role: "dev", status: "active", wallet_pubkey: "OTHER_WALLET", github_handle: "h" },
+ });
+ (supabaseAdmin as any).mockReturnValue({
+ from: () => ({
+ select: () => ({
+ eq: () => ({
+ maybeSingle: () =>
+ Promise.resolve({
+ data: {
+ id: "00000000-0000-0000-0000-000000000001",
+ solver: "DIFFERENT_WALLET",
+ pr_url: "https://github.com/o/r/pull/1",
+ score: null,
+ state: "Pending",
+ bounty: { creator: "COMPANY_WALLET" },
+ },
+ error: null,
+ }),
+ }),
+ }),
+ }),
+ });
+
+ const result = await handleSubmissionsGet({
+ authorization: "Bearer ghbk_live_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+ submission_id: "00000000-0000-0000-0000-000000000001",
+ });
+ expect((result as any).error.code).toBe("Forbidden");
+ });
+
+ it("returns submission when caller is the solver", async () => {
+ (authenticate as any).mockResolvedValue({
+ ok: true,
+ agent: { id: "a", role: "dev", status: "active", wallet_pubkey: "SOLVER_WALLET", github_handle: "h" },
+ });
+ (supabaseAdmin as any).mockReturnValue({
+ from: () => ({
+ select: () => ({
+ eq: () => ({
+ maybeSingle: () =>
+ Promise.resolve({
+ data: {
+ id: "00000000-0000-0000-0000-000000000001",
+ solver: "SOLVER_WALLET",
+ pr_url: "https://github.com/o/r/pull/1",
+ score: 7,
+ state: "Scored",
+ bounty: { creator: "COMPANY_WALLET" },
+ },
+ error: null,
+ }),
+ }),
+ }),
+ }),
+ });
+
+ const result = await handleSubmissionsGet({
+ authorization: "Bearer ghbk_live_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+ submission_id: "00000000-0000-0000-0000-000000000001",
+ });
+ expect((result as any).submission.id).toBe("00000000-0000-0000-0000-000000000001");
+ expect((result as any).submission.score).toBe(7);
+ });
+});
diff --git a/apps/mcp/tests/tools/whoami.test.ts b/apps/mcp/tests/tools/whoami.test.ts
new file mode 100644
index 0000000..0d9b4ec
--- /dev/null
+++ b/apps/mcp/tests/tools/whoami.test.ts
@@ -0,0 +1,44 @@
+import { describe, it, expect, vi, beforeEach } from "vitest";
+
+vi.mock("@/lib/supabase/admin", () => ({ supabaseAdmin: vi.fn() }));
+vi.mock("@/lib/auth/middleware");
+vi.mock("@/lib/solana/rpc", () => ({
+ solanaRpc: () => ({
+ getBalance: () => ({
+ send: () => Promise.resolve({ value: 100_000_000n }),
+ }),
+ }),
+}));
+
+import { handleWhoami } from "@/lib/tools/whoami";
+import { authenticate } from "@/lib/auth/middleware";
+
+describe("whoami handler", () => {
+ beforeEach(() => vi.resetAllMocks());
+
+ it("returns Unauthorized when middleware rejects", async () => {
+ (authenticate as any).mockResolvedValue({
+ ok: false,
+ error: { code: "Unauthorized", message: "no key" },
+ });
+ const result = await handleWhoami({ authorization: undefined });
+ expect((result as any).error.code).toBe("Unauthorized");
+ });
+
+ it("returns agent info + balance when authorized", async () => {
+ (authenticate as any).mockResolvedValue({
+ ok: true,
+ apiKeyId: "key-uuid",
+ agent: {
+ id: "agent-uuid",
+ role: "dev",
+ status: "active",
+ wallet_pubkey: "7xK7gE8FpQrSjVz9mYwGtCkBtNvDtTvPzGjGpZqMxKqp",
+ github_handle: "claudebot",
+ },
+ });
+ const result = await handleWhoami({ authorization: "Bearer ghbk_live_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" });
+ expect((result as any).agent_id).toBe("agent-uuid");
+ expect((result as any).balances.sol_lamports).toBe("100000000");
+ });
+});
diff --git a/apps/mcp/tsconfig.json b/apps/mcp/tsconfig.json
new file mode 100644
index 0000000..a4b11b3
--- /dev/null
+++ b/apps/mcp/tsconfig.json
@@ -0,0 +1,17 @@
+{
+ "extends": "../../tsconfig.base.json",
+ "compilerOptions": {
+ "lib": ["ES2022", "DOM", "DOM.Iterable"],
+ "module": "ESNext",
+ "moduleResolution": "bundler",
+ "jsx": "preserve",
+ "incremental": true,
+ "plugins": [{ "name": "next" }],
+ "noUncheckedIndexedAccess": false,
+ "paths": {
+ "@/*": ["./*"]
+ }
+ },
+ "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"],
+ "exclude": ["node_modules", ".next"]
+}
diff --git a/apps/mcp/vercel.json b/apps/mcp/vercel.json
new file mode 100644
index 0000000..94b6efa
--- /dev/null
+++ b/apps/mcp/vercel.json
@@ -0,0 +1,12 @@
+{
+ "framework": "nextjs",
+ "buildCommand": "cd ../.. && pnpm --filter @ghbounty/mcp build",
+ "installCommand": "cd ../.. && pnpm install --frozen-lockfile",
+ "outputDirectory": ".next",
+ "regions": ["iad1"],
+ "functions": {
+ "app/api/mcp/[transport]/route.ts": {
+ "maxDuration": 60
+ }
+ }
+}
diff --git a/apps/mcp/vitest.config.ts b/apps/mcp/vitest.config.ts
new file mode 100644
index 0000000..dad143e
--- /dev/null
+++ b/apps/mcp/vitest.config.ts
@@ -0,0 +1,13 @@
+import { defineConfig } from "vitest/config";
+import { resolve } from "node:path";
+
+export default defineConfig({
+ resolve: {
+ alias: {
+ "@": resolve(__dirname, "."),
+ },
+ },
+ test: {
+ passWithNoTests: true,
+ },
+});
diff --git a/docs/superpowers/decisions/2026-05-06-mcp-rate-limit-backend.md b/docs/superpowers/decisions/2026-05-06-mcp-rate-limit-backend.md
new file mode 100644
index 0000000..450c8ed
--- /dev/null
+++ b/docs/superpowers/decisions/2026-05-06-mcp-rate-limit-backend.md
@@ -0,0 +1,24 @@
+# Decision — Rate-limit backend (Upstash via Vercel Marketplace)
+
+**Date:** 2026-05-06
+**Status:** Accepted
+**Resolves:** OQ #5 in `docs/superpowers/specs/2026-05-05-ghbounty-mcp-server-design.md`
+
+## Decision
+Use Upstash Redis (`@upstash/redis` + `@upstash/ratelimit`), **provisioned via Vercel Marketplace** (Project → Storage → Browse Marketplace → Upstash → Connect). NO separate Upstash account needed; Vercel manages the integration end-to-end.
+
+## Why Upstash (provisioned via Vercel)
+- `@upstash/ratelimit` is purpose-built for serverless: sliding window, fixed window, token bucket — all atomic, all REST-based (no connection pooling issues).
+- Mature: years in production at thousands of Vercel deployments.
+- Free tier covers our v1 traffic (10K requests/day).
+- REST API works from any JS runtime (Edge, Node, browser); no socket setup.
+- **Vercel Marketplace provisioning means zero new accounts, single billing through Vercel.**
+
+## Why NOT pure Postgres (Supabase) rate limiting
+Considered. Pros: zero new services. Cons: needs an atomic Postgres function (sliding window with row-level locking) — non-trivial SQL, slower (30-50ms p95 vs ~5ms for Redis), risks DB connection saturation under load. Not worth the complexity for v1.
+
+## Setup
+- Production Vercel env: connect Upstash Redis instance via Marketplace (sized "Free" or "Pay-as-you-go").
+- Preview Vercel env: connect a separate Upstash instance (or share with prod for v1 — only adds noise to metrics, doesn't break anything).
+- Vercel auto-injects `UPSTASH_REDIS_REST_URL` + `UPSTASH_REDIS_REST_TOKEN` into the deployment env. No copy-paste of secrets.
+- Configured in Task 13 (code) + Task 32 (provisioning during deploy).
diff --git a/docs/superpowers/decisions/2026-05-06-mcp-vercel-deploy.md b/docs/superpowers/decisions/2026-05-06-mcp-vercel-deploy.md
new file mode 100644
index 0000000..5cf2017
--- /dev/null
+++ b/docs/superpowers/decisions/2026-05-06-mcp-vercel-deploy.md
@@ -0,0 +1,78 @@
+# Decision — Vercel deploy config for ghbounty-mcp
+
+**Date:** 2026-05-06
+**Status:** Accepted (manual provisioning pending user action)
+
+## Project
+- Slug: `ghbounty-mcp`
+- Team: `weareghbounty-6269s-projects` (same as frontend, per OQ #4 decision in `2026-05-06-mcp-vercel-team.md`)
+- Framework: Next.js 16
+- Root directory: `apps/mcp`
+- Region: `iad1`
+- `app/api/mcp/[transport]/route.ts` `maxDuration`: 60s
+- `vercel.json` config inside `apps/mcp/` already wired
+
+## Provisioning steps (USER, one-time)
+
+### 1. Create the Vercel project
+- Open https://vercel.com/new
+- Import `Ghbounty/GhBounty` repo (already connected)
+- Project name: `ghbounty-mcp`
+- Team: `weareghbounty-6269s-projects`
+- Root Directory: `apps/mcp`
+- Framework Preset: Next.js (auto-detected)
+- Build & Output: leave defaults (the repo's `apps/mcp/vercel.json` overrides them)
+- DO NOT deploy yet — set env vars first.
+
+### 2. Set env vars (production + preview, in dashboard)
+
+Required in BOTH `production` and `preview`:
+
+| Var | Value |
+|---|---|
+| `GITHUB_OAUTH_CLIENT_ID` | `Iv23liabu10KaQEjpH9w` (public, from Phase 0 GitHub App) |
+| `GITHUB_OAUTH_CLIENT_SECRET` | from `~/.ghbounty/github-app-credentials.json` (or 1Password) |
+| `SUPABASE_URL` | same value as the frontend's |
+| `SUPABASE_SERVICE_ROLE_KEY` | NEW key — generate in Supabase dashboard, distinct from frontend's. Rotate independently. |
+| `SOLANA_RPC_URL` | Helius mainnet for `production`, devnet for `preview` |
+| `GAS_STATION_SPONSOR_URL` | `https://www.ghbounty.com/api/gas-station/sponsor` (prod) or preview URL |
+| `GAS_STATION_SERVICE_TOKEN` | Generate a random 64-char hex (`openssl rand -hex 32`). Add SAME value to the frontend's env too. |
+| `NEXT_PUBLIC_GAS_STATION_PUBKEY` | same as frontend's `GAS_STATION_PUBKEY` |
+| `MCP_TOKEN_ENCRYPTION_KEY` | random 32-byte hex (`openssl rand -hex 32`). Used for AES-256-GCM at-rest encryption of GitHub tokens. |
+| `GHBOUNTY_PROGRAM_ADDRESS` | `CPZx26QXs3HjwGobr8cVAZEtF1qGzqnNbBdt7h1EwbBg` (Anchor.toml default — replace if program is redeployed) |
+| `NEXT_PUBLIC_MCP_BASE_URL` | `https://mcp.ghbounty.com` |
+
+### 3. Provision Upstash Redis via Vercel Marketplace
+- Vercel dashboard → `ghbounty-mcp` project → **Storage** tab
+- Click **Browse Marketplace** → search **Upstash** → **Redis** → **Connect**
+- Plan: Free
+- Attach to: Production environment
+- Vercel auto-injects `UPSTASH_REDIS_REST_URL` + `UPSTASH_REDIS_REST_TOKEN` (no manual entry)
+- Repeat for Preview environment (separate instance recommended; ok to share with prod for v1)
+
+### 4. Configure DNS for `mcp.ghbounty.com`
+- Vercel dashboard → `ghbounty-mcp` project → **Settings → Domains**
+- Add `mcp.ghbounty.com`
+- Vercel issues an SSL cert automatically once DNS resolves
+- DNS provider (Vercel-managed if the root `ghbounty.com` is also on Vercel): add `CNAME mcp → cname.vercel-dns.com`
+
+### 5. First deploy
+- Push the `feat/mcp-phase-1-onboarding` branch (already done by Phase 1 Task 34 below)
+- Vercel auto-deploys preview from the PR
+- Once PR merges to main, production deploy goes out
+- Smoke test:
+ ```bash
+ curl https://mcp.ghbounty.com/api/health
+ ```
+ Expected: `{ "ok": true, "service": "ghbounty-mcp", ... }`
+
+## Frontend follow-up needed (separate PR)
+
+The MCP server's `gas-station-client.ts` POSTs to the frontend's `/api/gas-station/sponsor` with a new `x-mcp-service-token` header. The frontend's `gas-station-route-core.ts` needs to accept this auth path (in addition to existing Privy bearer auth).
+
+Tasks for that PR:
+- Add `GAS_STATION_SERVICE_TOKEN` to the frontend's prod + preview Vercel env (same value as MCP project)
+- Update `frontend/lib/gas-station-route-core.ts` to accept requests with a matching `x-mcp-service-token` header
+- Test that requests from the MCP project are accepted; requests with wrong/missing token are rejected (401)
+
+Until that lands, the MCP's `create_account.complete` will fail at the gas-station call with 401. The MCP server itself works in dev (mocked) but cannot complete on-chain submissions in production until the frontend update merges.
diff --git a/docs/superpowers/decisions/2026-05-06-mcp-vercel-team.md b/docs/superpowers/decisions/2026-05-06-mcp-vercel-team.md
new file mode 100644
index 0000000..e467dcf
--- /dev/null
+++ b/docs/superpowers/decisions/2026-05-06-mcp-vercel-team.md
@@ -0,0 +1,19 @@
+# Decision — Vercel team for ghbounty-mcp project
+
+**Date:** 2026-05-06
+**Status:** Accepted
+**Resolves:** OQ #4 in `docs/superpowers/specs/2026-05-05-ghbounty-mcp-server-design.md`
+
+## Decision
+Deploy the `ghbounty-mcp` Vercel project under the same team as the frontend: `weareghbounty-6269`.
+
+## Why same team
+- Single billing surface
+- Same DNS root (`ghbounty.com`) — DNS records live with the team
+- Less context-switching for ops
+
+## Why NOT a separate team
+The "isolated team for security" argument is theoretical for v1. The threat model: if the frontend's deploy access is compromised, an attacker would already have access to the customer-facing domain. Putting the MCP server on a separate team doesn't materially reduce blast radius if the same humans have access to both.
+
+## Mitigation
+The MCP server uses a separate Supabase service-role key from the frontend's. Rotate independently. Vercel env vars are scoped per-project, so leaking the frontend's vars does NOT leak the MCP's.
diff --git a/docs/superpowers/plans/2026-05-06-mcp-phase-1-onboarding.md b/docs/superpowers/plans/2026-05-06-mcp-phase-1-onboarding.md
index 01da344..77577d6 100644
--- a/docs/superpowers/plans/2026-05-06-mcp-phase-1-onboarding.md
+++ b/docs/superpowers/plans/2026-05-06-mcp-phase-1-onboarding.md
@@ -22,7 +22,7 @@
2. Solana CLI 3.1.14 + Anchor 0.30.1 + Rust 1.89 (installed during Phase 0).
3. `~/.ghbounty/github-app-credentials.json` exists locally with the GitHub App credentials registered in Phase 0.
4. Device Flow toggle activated in https://github.com/organizations/Ghbounty/settings/apps/ghbounty-mcp (manual one-time step).
-5. Upstash account exists (free tier is fine). Two Redis databases: one for production, one for preview/dev. Both have `UPSTASH_REDIS_REST_URL` + `UPSTASH_REDIS_REST_TOKEN` from the dashboard.
+5. **No external Upstash account needed.** Provisioned via Vercel Marketplace from inside the `ghbounty-mcp` Vercel project (Storage tab → Browse Marketplace → Upstash → Connect). Vercel manages billing through your existing Vercel account; env vars `UPSTASH_REDIS_REST_URL` + `UPSTASH_REDIS_REST_TOKEN` are auto-injected. Configure two instances: one attached to Production env, another attached to Preview env. _The npm package `@upstash/redis` is the same — only the provisioning path is via Vercel UI._
6. Helius Solana RPC key (free tier OK for dev, paid for production).
---
@@ -158,21 +158,23 @@ The MCP server uses a separate Supabase service-role key from the frontend's. Ro
**Resolves:** OQ #5 in `docs/superpowers/specs/2026-05-05-ghbounty-mcp-server-design.md`
## Decision
-Use Upstash Redis (`@upstash/redis` + `@upstash/ratelimit`) for rate limiting.
+Use Upstash Redis (`@upstash/redis` + `@upstash/ratelimit`), **provisioned via Vercel Marketplace** (Project → Storage → Browse Marketplace → Upstash → Connect). NO separate Upstash account needed; Vercel manages the integration end-to-end.
-## Why Upstash
+## Why Upstash (provisioned via Vercel)
- `@upstash/ratelimit` is purpose-built for serverless: sliding window, fixed window, token bucket — all atomic, all REST-based (no connection pooling issues).
- Mature: years in production at thousands of Vercel deployments.
- Free tier covers our v1 traffic (10K requests/day).
- REST API works from any JS runtime (Edge, Node, browser); no socket setup.
+- **Vercel Marketplace provisioning means zero new accounts, single billing through Vercel.**
-## Why NOT Vercel KV
-- Newer (released 2023). Less battle-tested for rate limiting specifically.
-- Would couple our rate-limit infra to Vercel; harder to migrate if we ever leave Vercel.
-- The `@vercel/kv` package wraps Upstash Redis under the hood anyway — using Upstash directly skips a layer.
+## Why NOT pure Postgres (Supabase) rate limiting
+Considered. Pros: zero new services. Cons: needs an atomic Postgres function (sliding window with row-level locking) — non-trivial SQL, slower (30-50ms p95 vs ~5ms for Redis), risks DB connection saturation under load. Not worth the complexity for v1.
## Setup
-Each environment (preview, production) gets its own Upstash Redis instance. Env vars: `UPSTASH_REDIS_REST_URL` + `UPSTASH_REDIS_REST_TOKEN`. Configured in Task 13.
+- Production Vercel env: connect Upstash Redis instance via Marketplace (sized "Free" or "Pay-as-you-go").
+- Preview Vercel env: connect a separate Upstash instance (or share with prod for v1 — only adds noise to metrics, doesn't break anything).
+- Vercel auto-injects `UPSTASH_REDIS_REST_URL` + `UPSTASH_REDIS_REST_TOKEN` into the deployment env. No copy-paste of secrets.
+- Configured in Task 13 (code) + Task 32 (provisioning during deploy).
```
- [ ] **Step 4: Commit**
@@ -3453,9 +3455,13 @@ vercel env add SUPABASE_SERVICE_ROLE_KEY production
# NEW key — generate in Supabase dashboard, distinct from frontend's
vercel env add SOLANA_RPC_URL production
# Helius mainnet URL
-vercel env add UPSTASH_REDIS_REST_URL production
-# from Upstash dashboard (production DB)
-vercel env add UPSTASH_REDIS_REST_TOKEN production
+# UPSTASH_REDIS_REST_URL + UPSTASH_REDIS_REST_TOKEN are auto-injected by
+# Vercel when you connect Upstash via the Marketplace. Skip these CLI
+# commands — instead, in the Vercel dashboard:
+# 1. Go to Project → Storage → Browse Marketplace → Upstash → Connect
+# 2. Pick "Free" plan; attach to Production env
+# 3. Repeat for Preview env (or share with prod for v1)
+# Vercel populates the env vars automatically.
vercel env add GAS_STATION_SPONSOR_URL production
# https://www.ghbounty.com/api/gas-station/sponsor
vercel env add GAS_STATION_SERVICE_TOKEN production
@@ -3488,7 +3494,7 @@ Repeat the entire list for `preview` (use a separate Upstash DB for preview, but
- `GITHUB_OAUTH_CLIENT_ID`, `GITHUB_OAUTH_CLIENT_SECRET`
- `SUPABASE_URL`, `SUPABASE_SERVICE_ROLE_KEY` (NEW key, distinct from frontend's)
- `SOLANA_RPC_URL` (Helius mainnet for prod, devnet for preview)
-- `UPSTASH_REDIS_REST_URL`, `UPSTASH_REDIS_REST_TOKEN` (separate DBs per env)
+- `UPSTASH_REDIS_REST_URL`, `UPSTASH_REDIS_REST_TOKEN` — auto-injected by Vercel after connecting Upstash via Storage Marketplace (no manual entry)
- `GAS_STATION_SPONSOR_URL` (= frontend prod URL)
- `GAS_STATION_SERVICE_TOKEN` (NEW shared secret with frontend; add to frontend env too)
- `NEXT_PUBLIC_GAS_STATION_PUBKEY` (= frontend's value)
@@ -3638,6 +3644,6 @@ After implementation, run through before opening the PR:
## Estimated effort
-5-7 days for one engineer who already has the env set up (Phase 0 done, GitHub App registered, Upstash account ready). Tasks 19-24 (the 3 onboarding tools with their tx-building) are the long stretch.
+5-7 days for one engineer who already has the env set up (Phase 0 done, GitHub App registered). Upstash KV provisioning happens during Task 32 via the Vercel UI — no extra account creation needed. Tasks 19-24 (the 3 onboarding tools with their tx-building) are the long stretch.
If unfamiliar with `@vercel/mcp-adapter` and `@solana/kit` 6.x: pad to 8-10 days. The Codama-generated builders may need adapter calls that the spec didn't anticipate.
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 8267b48..5519217 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -12,6 +12,70 @@ importers:
specifier: ^9.1.7
version: 9.1.7
+ apps/mcp:
+ dependencies:
+ '@ghbounty/db':
+ specifier: workspace:^
+ version: link:../../packages/db
+ '@ghbounty/sdk':
+ specifier: workspace:^
+ version: link:../../packages/sdk
+ '@ghbounty/shared':
+ specifier: workspace:^
+ version: link:../../packages/shared
+ '@modelcontextprotocol/sdk':
+ specifier: ^1.0.0
+ version: 1.29.0(zod@3.25.76)
+ '@solana/kit':
+ specifier: ^6.9.0
+ version: 6.9.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)
+ '@supabase/supabase-js':
+ specifier: ^2.104.1
+ version: 2.104.1(bufferutil@4.1.0)(utf-8-validate@6.0.6)
+ '@upstash/ratelimit':
+ specifier: ^2.0.8
+ version: 2.0.8(@upstash/redis@1.38.0)
+ '@upstash/redis':
+ specifier: ^1.38.0
+ version: 1.38.0
+ bcryptjs:
+ specifier: ^3.0.3
+ version: 3.0.3
+ mcp-handler:
+ specifier: ^1.1.0
+ version: 1.1.0(@modelcontextprotocol/sdk@1.29.0(zod@3.25.76))(next@16.2.4(react-dom@19.2.4(react@19.2.4))(react@19.2.4))
+ next:
+ specifier: 16.2.4
+ version: 16.2.4(@babel/core@7.29.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
+ react:
+ specifier: 19.2.4
+ version: 19.2.4
+ react-dom:
+ specifier: 19.2.4
+ version: 19.2.4(react@19.2.4)
+ zod:
+ specifier: ^3.23.8
+ version: 3.25.76
+ devDependencies:
+ '@types/bcryptjs':
+ specifier: ^2.4.6
+ version: 2.4.6
+ '@types/node':
+ specifier: ^22.0.0
+ version: 22.19.17
+ '@types/react':
+ specifier: ^19.0.0
+ version: 19.2.14
+ '@types/react-dom':
+ specifier: ^19.0.0
+ version: 19.2.3(@types/react@19.2.14)
+ typescript:
+ specifier: ^5.6.0
+ version: 5.9.3
+ vitest:
+ specifier: ^2.1.9
+ version: 2.1.9(@types/node@22.19.17)(happy-dom@20.9.0(bufferutil@4.1.0)(utf-8-validate@6.0.6))
+
frontend:
dependencies:
'@coral-xyz/anchor':
@@ -22,7 +86,7 @@ importers:
version: link:../packages/shared
'@privy-io/react-auth':
specifier: ^3.22.2
- version: 3.22.2(@solana-program/memo@0.11.0(@solana/kit@6.8.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)))(@solana-program/system@0.10.0(@solana/kit@6.8.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)))(@solana-program/token@0.9.0(@solana/kit@6.8.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)))(@solana/kit@6.8.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6))(@solana/sysvars@6.9.0(typescript@5.9.3))(@tanstack/query-core@5.100.6)(@tanstack/react-query@5.100.6(react@19.2.4))(@types/react@19.2.14)(bufferutil@4.1.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@19.2.4))(utf-8-validate@6.0.6)(zod@4.3.6)
+ version: 3.22.2(@solana-program/memo@0.11.0(@solana/kit@6.8.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)))(@solana-program/system@0.10.0(@solana/kit@6.8.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)))(@solana-program/token@0.9.0(@solana/kit@6.8.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)))(@solana/kit@6.8.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6))(@solana/sysvars@6.9.0(typescript@5.9.3))(@tanstack/query-core@5.100.6)(@tanstack/react-query@5.100.6(react@19.2.4))(@types/react@19.2.14)(@upstash/redis@1.38.0)(bufferutil@4.1.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@19.2.4))(utf-8-validate@6.0.6)(zod@4.3.6)
'@solana-program/memo':
specifier: ^0.11.0
version: 0.11.0(@solana/kit@6.8.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6))
@@ -86,7 +150,7 @@ importers:
dependencies:
drizzle-orm:
specifier: ^0.45.2
- version: 0.45.2(@prisma/client@5.22.0(prisma@5.22.0))(postgres@3.4.9)(prisma@5.22.0)
+ version: 0.45.2(@prisma/client@5.22.0(prisma@5.22.0))(@upstash/redis@1.38.0)(postgres@3.4.9)(prisma@5.22.0)
postgres:
specifier: ^3.4.9
version: 3.4.9
@@ -191,7 +255,7 @@ importers:
version: 17.4.2
drizzle-orm:
specifier: ^0.45.2
- version: 0.45.2(@prisma/client@5.22.0(prisma@5.22.0))(postgres@3.4.9)(prisma@5.22.0)
+ version: 0.45.2(@prisma/client@5.22.0(prisma@5.22.0))(@upstash/redis@1.38.0)(postgres@3.4.9)(prisma@5.22.0)
genlayer-js:
specifier: ^1.1.7
version: 1.1.7(bufferutil@4.1.0)(eslint@9.39.4)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.3.6)
@@ -1077,6 +1141,12 @@ packages:
peerDependencies:
react: '>= 16 || ^19.0.0-rc'
+ '@hono/node-server@1.19.14':
+ resolution: {integrity: sha512-GwtvgtXxnWsucXvbQXkRgqksiH2Qed37H9xHZocE5sA3N8O8O8/8FA3uclQXxXVzc9XBZuEOMK7+r02FmSpHtw==}
+ engines: {node: '>=18.14.1'}
+ peerDependencies:
+ hono: ^4
+
'@humanfs/core@0.19.2':
resolution: {integrity: sha512-UhXNm+CFMWcbChXywFwkmhqjs3PRCmcSa/hfBgLIb7oQ5HNb1wS0icWsGtSAUNgefHeI+eBrA8I1fxmbHsGdvA==}
engines: {node: '>=18.18.0'}
@@ -1360,6 +1430,16 @@ packages:
resolution: {integrity: sha512-w8CVbdkDrVXFJbfBSlDfafDR6BAkpDmv1bC1UJVCoVny5tW2RKAdn9i68Xf7asYT4TnUhl/hN4zfUiKQq9II4g==}
engines: {node: '>=16.0.0'}
+ '@modelcontextprotocol/sdk@1.29.0':
+ resolution: {integrity: sha512-zo37mZA9hJWpULgkRpowewez1y6ML5GsXJPY8FI0tBBCd77HEvza4jDqRKOXgHNn867PVGCyTdzqpz0izu5ZjQ==}
+ engines: {node: '>=18'}
+ peerDependencies:
+ '@cfworker/json-schema': ^4.1.1
+ zod: ^3.25 || ^4.0
+ peerDependenciesMeta:
+ '@cfworker/json-schema':
+ optional: true
+
'@msgpack/msgpack@3.1.2':
resolution: {integrity: sha512-JEW4DEtBzfe8HvUYecLU9e6+XJnKDlUAIve8FvPzF3Kzs6Xo/KuZkZJsDH0wJXl/qEZbeeE7edxDNY3kMs39hQ==}
engines: {node: '>= 18'}
@@ -1604,6 +1684,35 @@ packages:
peerDependencies:
react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1
+ '@redis/bloom@1.2.0':
+ resolution: {integrity: sha512-HG2DFjYKbpNmVXsa0keLHp/3leGJz1mjh09f2RLGGLQZzSHpkmZWuwJbAvo3QcRY8p80m5+ZdXZdYOSBLlp7Cg==}
+ peerDependencies:
+ '@redis/client': ^1.0.0
+
+ '@redis/client@1.6.1':
+ resolution: {integrity: sha512-/KCsg3xSlR+nCK8/8ZYSknYxvXHwubJrU82F3Lm1Fp6789VQ0/3RJKfsmRXjqfaTA++23CvC3hqmqe/2GEt6Kw==}
+ engines: {node: '>=14'}
+
+ '@redis/graph@1.1.1':
+ resolution: {integrity: sha512-FEMTcTHZozZciLRl6GiiIB4zGm5z5F3F6a6FZCyrfxdKOhFlGkiAqlexWMBzCi4DcRoyiOsuLfW+cjlGWyExOw==}
+ peerDependencies:
+ '@redis/client': ^1.0.0
+
+ '@redis/json@1.0.7':
+ resolution: {integrity: sha512-6UyXfjVaTBTJtKNG4/9Z8PSpKE6XgSyEb8iwaqDcy+uKrd/DGYHTWkUdnQDyzm727V7p21WUMhsqz5oy65kPcQ==}
+ peerDependencies:
+ '@redis/client': ^1.0.0
+
+ '@redis/search@1.2.0':
+ resolution: {integrity: sha512-tYoDBbtqOVigEDMAcTGsRlMycIIjwMCgD8eR2t0NANeQmgK/lvxNAvYyb6bZDD4frHRhIHkJu2TBRvB0ERkOmw==}
+ peerDependencies:
+ '@redis/client': ^1.0.0
+
+ '@redis/time-series@1.1.0':
+ resolution: {integrity: sha512-c1Q99M5ljsIuc4YdaCwfUEXsofakb9c8+Zse2qxTadu8TalLXuAESzLvFAvNVbkmSlvlzIQOLpBCmWI9wTOt+g==}
+ peerDependencies:
+ '@redis/client': ^1.0.0
+
'@reown/appkit-common@1.7.8':
resolution: {integrity: sha512-ridIhc/x6JOp7KbDdwGKY4zwf8/iK8EYBl+HtWrruutSLwZyVi5P8WaZa+8iajL6LcDcDF7LoyLwMTym7SRuwQ==}
@@ -3054,6 +3163,9 @@ packages:
'@tybys/wasm-util@0.10.1':
resolution: {integrity: sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==}
+ '@types/bcryptjs@2.4.6':
+ resolution: {integrity: sha512-9xlo6R2qDs5uixm0bcIqCeMCE6HiQsIyel9KQySStiyqNl2tnj2mP3DX1Nf56MD6KMenNNlBBsy3LJ7gUEQPXQ==}
+
'@types/bn.js@5.2.0':
resolution: {integrity: sha512-DLbJ1BPqxvQhIGbeu8VbUC1DiAiahHtAYvA0ZEAa4P31F7IaArc8z3C3BRQdWX4mtLQuABG4yzp76ZrS02Ui1Q==}
@@ -3264,6 +3376,18 @@ packages:
cpu: [x64]
os: [win32]
+ '@upstash/core-analytics@0.0.10':
+ resolution: {integrity: sha512-7qJHGxpQgQr9/vmeS1PktEwvNAF7TI4iJDi8Pu2CFZ9YUGHZH4fOP5TfYlZ4aVxfopnELiE4BS4FBjyK7V1/xQ==}
+ engines: {node: '>=16.0.0'}
+
+ '@upstash/ratelimit@2.0.8':
+ resolution: {integrity: sha512-YSTMBJ1YIxsoPkUMX/P4DDks/xV5YYCswWMamU8ZIfK9ly6ppjRnVOyBhMDXBmzjODm4UQKcxsJPvaeFAijp5w==}
+ peerDependencies:
+ '@upstash/redis': ^1.34.3
+
+ '@upstash/redis@1.38.0':
+ resolution: {integrity: sha512-wu+dZBptlLy0+MCUEoHmzrY/TnmgDey3+c7EbIGwrLqAvkP8yi5MWZHYGIFtAygmL4Bkz2TdFu+eU0vFPncIcg==}
+
'@vitest/expect@2.1.9':
resolution: {integrity: sha512-UJCIkTBenHeKT1TTlKMJWy1laZewsRIzYighyYiJKZreqtdxSos/S1t+ktRMQWu2CKqaarrkeszJx1cgC5tGZw==}
@@ -3510,6 +3634,10 @@ packages:
resolution: {integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==}
engines: {node: '>=6.5'}
+ accepts@2.0.0:
+ resolution: {integrity: sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==}
+ engines: {node: '>= 0.6'}
+
acorn-jsx@5.3.2:
resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==}
peerDependencies:
@@ -3524,9 +3652,20 @@ packages:
resolution: {integrity: sha512-kja8j7PjmncONqaTsB8fQ+wE2mSU2DJ9D4XKoJ5PFWIdRMa6SLSN1ff4mOr4jCbfRSsxR4keIiySJU0N9T5hIQ==}
engines: {node: '>= 8.0.0'}
+ ajv-formats@3.0.1:
+ resolution: {integrity: sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==}
+ peerDependencies:
+ ajv: ^8.0.0
+ peerDependenciesMeta:
+ ajv:
+ optional: true
+
ajv@6.15.0:
resolution: {integrity: sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==}
+ ajv@8.20.0:
+ resolution: {integrity: sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==}
+
ansi-regex@5.0.1:
resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==}
engines: {node: '>=8'}
@@ -3644,6 +3783,10 @@ packages:
engines: {node: '>=6.0.0'}
hasBin: true
+ bcryptjs@3.0.3:
+ resolution: {integrity: sha512-GlF5wPWnSa/X5LKM1o0wz0suXIINz1iHRLvTS+sLyi7XPbe5ycmYI3DlZqVGZZtDgl4DmasFg7gOB3JYbphV5g==}
+ hasBin: true
+
big.js@6.2.2:
resolution: {integrity: sha512-y/ie+Faknx7sZA5MfGA2xKlu0GDv8RWrXGsmlteyJQ2lvoKv9GBK/fpRMc2qlSoBAgNxrixICFCBefIq8WCQpQ==}
@@ -3653,6 +3796,10 @@ packages:
bn.js@5.2.3:
resolution: {integrity: sha512-EAcmnPkxpntVL+DS7bO1zhcZNvCkxqtkd0ZY53h06GNQ3DEkkGZ/gKgmDv6DdZQGj9BgfSPKtJJ7Dp1GPP8f7w==}
+ body-parser@2.2.2:
+ resolution: {integrity: sha512-oP5VkATKlNwcgvxi0vM0p/D3n2C3EReYVX+DNYs5TjZFn/oQt2j+4sVJtSMr18pdRr8wjTcBl6LoV+FUwzPmNA==}
+ engines: {node: '>=18'}
+
borsh@0.7.0:
resolution: {integrity: sha512-CLCsZGIBCFnPtkNnieW/a8wmreDmfUtjU2m9yHrzPXIlNbqVs0AQrSatSG6vdNYUqdc83tkQi2eHfF98ubzQLA==}
@@ -3695,6 +3842,10 @@ packages:
resolution: {integrity: sha512-ZMANVnAixE6AWWnPzlW2KpUrxhm9woycYvPOo67jWHyFowASTEd9s+QN1EIMsSDtwhIxN4sWE1jotpuDUIgyIw==}
engines: {node: '>=6.14.2'}
+ bytes@3.1.2:
+ resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==}
+ engines: {node: '>= 0.8'}
+
cac@6.7.14:
resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==}
engines: {node: '>=8'}
@@ -3767,6 +3918,10 @@ packages:
resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==}
engines: {node: '>=6'}
+ cluster-key-slot@1.1.2:
+ resolution: {integrity: sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==}
+ engines: {node: '>=0.10.0'}
+
codama@1.6.0:
resolution: {integrity: sha512-JKydzwNYJkGjkZ98ipehd3hJksLQU6nYS7x0GPjOwD0wih+xP8q7WCKgleN8LM2sRuC75rfpr3uXLXSpQpBYKA==}
hasBin: true
@@ -3785,6 +3940,10 @@ packages:
resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==}
engines: {node: '>= 0.8'}
+ commander@11.1.0:
+ resolution: {integrity: sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==}
+ engines: {node: '>=16'}
+
commander@14.0.2:
resolution: {integrity: sha512-TywoWNNRbhoD0BXs1P3ZEScW8W5iKrnbithIl0YH+uCmBd0QpPOA8yc82DS3BIE5Ma6FnBVUsJ7wVUDz4dvOWQ==}
engines: {node: '>=20'}
@@ -3799,12 +3958,28 @@ packages:
concat-map@0.0.1:
resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==}
+ content-disposition@1.1.0:
+ resolution: {integrity: sha512-5jRCH9Z/+DRP7rkvY83B+yGIGX96OYdJmzngqnw2SBSxqCFPd0w2km3s5iawpGX8krnwSGmF0FW5Nhr0Hfai3g==}
+ engines: {node: '>=18'}
+
+ content-type@1.0.5:
+ resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==}
+ engines: {node: '>= 0.6'}
+
convert-source-map@2.0.0:
resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==}
cookie-es@1.2.3:
resolution: {integrity: sha512-lXVyvUvrNXblMqzIRrxHb57UUVmqsSWlxqt3XIjCkUP0wDAf6uicO6KMbEgYrMNtEvWgWHwe42CKxPu9MYAnWw==}
+ cookie-signature@1.2.2:
+ resolution: {integrity: sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==}
+ engines: {node: '>=6.6.0'}
+
+ cookie@0.7.2:
+ resolution: {integrity: sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==}
+ engines: {node: '>= 0.6'}
+
cookie@1.1.1:
resolution: {integrity: sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==}
engines: {node: '>=18'}
@@ -3812,6 +3987,10 @@ packages:
core-util-is@1.0.3:
resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==}
+ cors@2.8.6:
+ resolution: {integrity: sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw==}
+ engines: {node: '>= 0.10'}
+
crc-32@1.2.2:
resolution: {integrity: sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==}
engines: {node: '>=0.8'}
@@ -3925,6 +4104,10 @@ packages:
resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==}
engines: {node: '>=0.4.0'}
+ depd@2.0.0:
+ resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==}
+ engines: {node: '>= 0.8'}
+
derive-valtio@0.1.0:
resolution: {integrity: sha512-OCg2UsLbXK7GmmpzMXhYkdO64vhJ1ROUUGaTFyHjVwEdMEcTTRj7W1TxLbSBxdY8QLBPCcp66MTyaSy0RpO17A==}
peerDependencies:
@@ -4061,6 +4244,9 @@ packages:
resolution: {integrity: sha512-wG99Zcfcys9fZux7Cft8BAX/YrOJLJSZ3jyYPfhZHqN2E+Ffx+QXBDsv3gubEgPtV6dTzJMSQUwk1H98/t/0wQ==}
engines: {bun: '>=1', deno: '>=2', node: '>=16'}
+ ee-first@1.1.1:
+ resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==}
+
electron-to-chromium@1.5.344:
resolution: {integrity: sha512-4MxfbmNDm+KPh066EZy+eUnkcDPcZ35wNmOWzFuh/ijvHsve6kbLTLURy88uCNK5FbpN+yk2nQY6BYh1GEt+wg==}
@@ -4073,6 +4259,10 @@ packages:
encode-utf8@1.0.3:
resolution: {integrity: sha512-ucAnuBEhUK4boH2HjVYG5Q2mQyPorvv0u/ocS+zhdw0S8AlHYY+GOFhP1Gio5z4icpP2ivFSvhtFjQi8+T9ppw==}
+ encodeurl@2.0.0:
+ resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==}
+ engines: {node: '>= 0.8'}
+
end-of-stream@1.4.5:
resolution: {integrity: sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==}
@@ -4162,6 +4352,9 @@ packages:
resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==}
engines: {node: '>=6'}
+ escape-html@1.0.3:
+ resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==}
+
escape-string-regexp@4.0.0:
resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==}
engines: {node: '>=10'}
@@ -4289,6 +4482,10 @@ packages:
resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==}
engines: {node: '>=0.10.0'}
+ etag@1.8.1:
+ resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==}
+ engines: {node: '>= 0.6'}
+
eth-block-tracker@7.1.0:
resolution: {integrity: sha512-8YdplnuE1IK4xfqpf4iU7oBxnOYAc35934o083G8ao+8WM8QQtt/mVlAY6yIAdY1eMeLqg4Z//PZjJGmWGPMRg==}
engines: {node: '>=14.0.0'}
@@ -4326,10 +4523,28 @@ packages:
resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==}
engines: {node: '>=0.8.x'}
+ eventsource-parser@3.0.8:
+ resolution: {integrity: sha512-70QWGkr4snxr0OXLRWsFLeRBIRPuQOvt4s8QYjmUlmlkyTZkRqS7EDVRZtzU3TiyDbXSzaOeF0XUKy8PchzukQ==}
+ engines: {node: '>=18.0.0'}
+
+ eventsource@3.0.7:
+ resolution: {integrity: sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA==}
+ engines: {node: '>=18.0.0'}
+
expect-type@1.3.0:
resolution: {integrity: sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==}
engines: {node: '>=12.0.0'}
+ express-rate-limit@8.5.1:
+ resolution: {integrity: sha512-5O6KYmyJEpuPJV5hNTXKbAHWRqrzyu+OI3vUnSd2kXFubIVpG7ezpgxQy76Zo5GQZtrQBg86hF+CM/NX+cioiQ==}
+ engines: {node: '>= 16'}
+ peerDependencies:
+ express: '>= 4.11'
+
+ express@5.2.1:
+ resolution: {integrity: sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==}
+ engines: {node: '>= 18'}
+
extension-port-stream@3.0.0:
resolution: {integrity: sha512-an2S5quJMiy5bnZKEf6AkfH/7r8CzHvhchU40gxN+OM6HPhe7Z9T1FUychcf2M9PpPOO0Hf7BAEfJkw2TDIBDw==}
engines: {node: '>=12.0.0'}
@@ -4367,6 +4582,9 @@ packages:
fast-stable-stringify@1.0.0:
resolution: {integrity: sha512-wpYMUmFu5f00Sm0cj2pfivpmawLZ0NKdviQ4w9zJeR8JVtOpOxHmLaJuj0vxvGqMJQWyP/COUkF75/57OKyRag==}
+ fast-uri@3.1.2:
+ resolution: {integrity: sha512-rVjf7ArG3LTk+FS6Yw81V1DLuZl1bRbNrev6Tmd/9RaroeeRRJhAt7jg/6YFxbvAQXUCavSoZhPPj6oOx+5KjQ==}
+
fastq@1.20.1:
resolution: {integrity: sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==}
@@ -4394,6 +4612,10 @@ packages:
resolution: {integrity: sha512-8rXg1ZnX7xzy2NGDVkBVaAy+lSlPNwad13BtgSlLuxfIslyt5Vg64U7tFcCt4WS1R0hvtnQybT/IyCkGZ3DpXQ==}
engines: {node: '>=0.10.0'}
+ finalhandler@2.1.1:
+ resolution: {integrity: sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==}
+ engines: {node: '>= 18.0.0'}
+
find-up@4.1.0:
resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==}
engines: {node: '>=8'}
@@ -4426,6 +4648,14 @@ packages:
resolution: {integrity: sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==}
engines: {node: '>= 6'}
+ forwarded@0.2.0:
+ resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==}
+ engines: {node: '>= 0.6'}
+
+ fresh@2.0.0:
+ resolution: {integrity: sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==}
+ engines: {node: '>= 0.8'}
+
fsevents@2.3.3:
resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==}
engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
@@ -4445,6 +4675,10 @@ packages:
resolution: {integrity: sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g==}
engines: {node: '>= 0.4'}
+ generic-pool@3.9.0:
+ resolution: {integrity: sha512-hymDOu5B53XvN4QT9dBmZxPX4CWhBPPLguTZ9MMFeFa/Kg0xWVfylOVNlJji/E7yTZWFd/q9GO5TxDLq156D7g==}
+ engines: {node: '>= 4'}
+
genlayer-js@1.1.7:
resolution: {integrity: sha512-4X5AAW0k6eqP1x11F39wbfyhn3IBNlqj+gS89PuY9mBwxjaf3c9JrszVzBZ7OoYW6M5nuZ2kvCP9Dm0/rdPRkA==}
@@ -4546,6 +4780,10 @@ packages:
resolution: {integrity: sha512-qM0jDhFEaCBb4TxoW7f53Qrpv9RBiayUHo0S52JudprkhvpjIrGoU1mnnr29Fvd1U335ZFPZQY1wlkqgfGXyLg==}
engines: {node: '>=16.9.0'}
+ http-errors@2.0.1:
+ resolution: {integrity: sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==}
+ engines: {node: '>= 0.8'}
+
humanize-ms@1.2.1:
resolution: {integrity: sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==}
@@ -4558,6 +4796,10 @@ packages:
resolution: {integrity: sha512-1dhVQZXhcHje7798IVM+xoo/1ZdVfzOMIc8/rgVSijRK38EDqOJoGula9N/8ZI5RD8QTxNQtK/Gozpr+qUqRRA==}
engines: {node: '>=20.0.0'}
+ iconv-lite@0.7.2:
+ resolution: {integrity: sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==}
+ engines: {node: '>=0.10.0'}
+
idb-keyval@6.2.1:
resolution: {integrity: sha512-8Sb3veuYCyrZL+VBt9LJfZjLUPWVvqn8tG28VqYNFCo43KHcKuq+b4EiXGeuaLAQWL2YmyDgMp2aSpH9JHsEQg==}
@@ -4590,6 +4832,14 @@ packages:
resolution: {integrity: sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==}
engines: {node: '>= 0.4'}
+ ip-address@10.2.0:
+ resolution: {integrity: sha512-/+S6j4E9AHvW9SWMSEY9Xfy66O5PWvVEJ08O0y5JGyEKQpojb0K0GKpz/v5HJ/G0vi3D2sjGK78119oXZeE0qA==}
+ engines: {node: '>= 12'}
+
+ ipaddr.js@1.9.1:
+ resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==}
+ engines: {node: '>= 0.10'}
+
iron-webcrypto@1.2.1:
resolution: {integrity: sha512-feOM6FaSr6rEABp/eDfVseKyTMDt+KGpeB35SkVn9Tyn0CqvVsY3EwI0v5i8nMHyJnzCIQf7nsy3p41TPkJZhg==}
@@ -4671,6 +4921,9 @@ packages:
resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==}
engines: {node: '>=0.12.0'}
+ is-promise@4.0.0:
+ resolution: {integrity: sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==}
+
is-regex@1.2.1:
resolution: {integrity: sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==}
engines: {node: '>= 0.4'}
@@ -4791,6 +5044,12 @@ packages:
json-schema-traverse@0.4.1:
resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==}
+ json-schema-traverse@1.0.0:
+ resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==}
+
+ json-schema-typed@8.0.2:
+ resolution: {integrity: sha512-fQhoXdcvc3V28x7C7BMs4P5+kNlgUURe2jmUT1T//oBRMDrqy1QPelJimwZGo7Hg9VPV3EQV5Bnq4hbFy2vetA==}
+
json-stable-stringify-without-jsonify@1.0.1:
resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==}
@@ -4897,9 +5156,27 @@ packages:
resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==}
engines: {node: '>= 0.4'}
+ mcp-handler@1.1.0:
+ resolution: {integrity: sha512-MVCES7g18gcoZy+R/3v5nadkUMzMAWdos8jRl6DyljOKvd2/ZKDmwlCjL6zp4vo+7FeCXOYL1uWinHWlkKAAUg==}
+ hasBin: true
+ peerDependencies:
+ '@modelcontextprotocol/sdk': 1.26.0
+ next: '>=13.0.0'
+ peerDependenciesMeta:
+ next:
+ optional: true
+
md5@2.3.0:
resolution: {integrity: sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g==}
+ media-typer@1.1.0:
+ resolution: {integrity: sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==}
+ engines: {node: '>= 0.8'}
+
+ merge-descriptors@2.0.0:
+ resolution: {integrity: sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==}
+ engines: {node: '>=18'}
+
merge2@1.4.1:
resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==}
engines: {node: '>= 8'}
@@ -4915,10 +5192,18 @@ packages:
resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==}
engines: {node: '>= 0.6'}
+ mime-db@1.54.0:
+ resolution: {integrity: sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==}
+ engines: {node: '>= 0.6'}
+
mime-types@2.1.35:
resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==}
engines: {node: '>= 0.6'}
+ mime-types@3.0.2:
+ resolution: {integrity: sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==}
+ engines: {node: '>=18'}
+
minimatch@10.2.5:
resolution: {integrity: sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==}
engines: {node: 18 || 20 || >=22}
@@ -4959,6 +5244,10 @@ packages:
natural-compare@1.4.0:
resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==}
+ negotiator@1.0.0:
+ resolution: {integrity: sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==}
+ engines: {node: '>= 0.6'}
+
next@16.2.4:
resolution: {integrity: sha512-kPvz56wF5frc+FxlHI5qnklCzbq53HTwORaWBGdT0vNoKh1Aya9XC8aPauH4NJxqtzbWsS5mAbctm4cr+EkQ2Q==}
engines: {node: '>=20.9.0'}
@@ -5061,6 +5350,10 @@ packages:
resolution: {integrity: sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA==}
engines: {node: '>=14.0.0'}
+ on-finished@2.4.1:
+ resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==}
+ engines: {node: '>= 0.8'}
+
once@1.4.0:
resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==}
@@ -5153,6 +5446,10 @@ packages:
resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==}
engines: {node: '>=6'}
+ parseurl@1.3.3:
+ resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==}
+ engines: {node: '>= 0.8'}
+
path-exists@4.0.0:
resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==}
engines: {node: '>=8'}
@@ -5164,6 +5461,9 @@ packages:
path-parse@1.0.7:
resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==}
+ path-to-regexp@8.4.2:
+ resolution: {integrity: sha512-qRcuIdP69NPm4qbACK+aDogI5CBDMi1jKe0ry5rSQJz8JVLsC7jV8XpiJjGRLLol3N+R5ihGYcrPLTno6pAdBA==}
+
pathe@1.1.2:
resolution: {integrity: sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==}
@@ -5217,6 +5517,10 @@ packages:
resolution: {integrity: sha512-dMACeu63HtRLmCG8VKdy4cShCPKaYDR4youZqoSWLxl5Gu99HUw8bw75thbPv9Nip+H+QYX8o3ZJbTdVZZ2TVg==}
hasBin: true
+ pkce-challenge@5.0.1:
+ resolution: {integrity: sha512-wQ0b/W4Fr01qtpHlqSqspcj3EhBvimsdh0KlHhH8HRZnMsEa0ea2fTULOXOS9ccQr3om+GcGRk4e+isrZWV8qQ==}
+ engines: {node: '>=16.20.0'}
+
pngjs@5.0.0:
resolution: {integrity: sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw==}
engines: {node: '>=10.13.0'}
@@ -5313,6 +5617,10 @@ packages:
prop-types@15.8.1:
resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==}
+ proxy-addr@2.0.7:
+ resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==}
+ engines: {node: '>= 0.10'}
+
proxy-compare@2.6.0:
resolution: {integrity: sha512-8xuCeM3l8yqdmbPoYeLbrAXCBWu19XEYc5/F28f5qOaoAIMyfmBUkl5axiK+x9olUvRlcekvnm98AP9RDngOIw==}
@@ -5339,6 +5647,10 @@ packages:
engines: {node: '>=10.13.0'}
hasBin: true
+ qs@6.15.1:
+ resolution: {integrity: sha512-6YHEFRL9mfgcAvql/XhwTvf5jKcOiiupt2FiJxHkiX1z4j7WL8J/jRHYLluORvc1XxB5rV20KoeK00gVJamspg==}
+ engines: {node: '>=0.6'}
+
query-string@7.1.3:
resolution: {integrity: sha512-hh2WYhq4fi8+b+/2Kg9CEge4fDPvHS534aOOvOZeQ3+Vf2mCFsaFBYj0i+iXcAq6I9Vzp5fjMFBlONvayDC1qg==}
engines: {node: '>=6'}
@@ -5352,6 +5664,14 @@ packages:
radix3@1.1.2:
resolution: {integrity: sha512-b484I/7b8rDEdSDKckSSBA8knMpcdsXudlE/LNL639wFoHKwLbEkQFZHWEYwDC0wa0FKUcCY+GAF73Z7wxNVFA==}
+ range-parser@1.2.1:
+ resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==}
+ engines: {node: '>= 0.6'}
+
+ raw-body@3.0.2:
+ resolution: {integrity: sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==}
+ engines: {node: '>= 0.10'}
+
react-aria@3.48.0:
resolution: {integrity: sha512-jQjd4rBEIMqecBaAKYJbVGK6EqIHLa5znVQ7jwFyK5vCyljoj6KhgtiahmcIPsG5vG5vEDLw+ba+bEWn6A2P4w==}
peerDependencies:
@@ -5404,6 +5724,9 @@ packages:
resolution: {integrity: sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg==}
engines: {node: '>= 12.13.0'}
+ redis@4.7.1:
+ resolution: {integrity: sha512-S1bJDnqLftzHXHP8JsT5II/CtHWQrASX5K96REjWjlmWKrviSOLWmM7QnRLstAWsu1VBBV1ffV6DzCvxNP0UJQ==}
+
reflect.getprototypeof@1.0.10:
resolution: {integrity: sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==}
engines: {node: '>= 0.4'}
@@ -5416,6 +5739,10 @@ packages:
resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==}
engines: {node: '>=0.10.0'}
+ require-from-string@2.0.2:
+ resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==}
+ engines: {node: '>=0.10.0'}
+
require-main-filename@2.0.0:
resolution: {integrity: sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==}
@@ -5440,6 +5767,10 @@ packages:
engines: {node: '>=18.0.0', npm: '>=8.0.0'}
hasBin: true
+ router@2.2.0:
+ resolution: {integrity: sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==}
+ engines: {node: '>= 18'}
+
rpc-websockets@9.3.8:
resolution: {integrity: sha512-7r+fm4tSJmLf9GvZfL1DJ1SJwpagpp6AazqM0FUaeV7CA+7+NYINSk1syWa4tU/6OF2CyBicLtzENGmXRJH6wQ==}
@@ -5468,6 +5799,9 @@ packages:
resolution: {integrity: sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==}
engines: {node: '>=10'}
+ safer-buffer@2.1.2:
+ resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==}
+
scheduler@0.27.0:
resolution: {integrity: sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==}
@@ -5491,6 +5825,14 @@ packages:
engines: {node: '>=10'}
hasBin: true
+ send@1.2.1:
+ resolution: {integrity: sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==}
+ engines: {node: '>= 18'}
+
+ serve-static@2.2.1:
+ resolution: {integrity: sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==}
+ engines: {node: '>= 18'}
+
set-blocking@2.0.0:
resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==}
@@ -5509,6 +5851,9 @@ packages:
resolution: {integrity: sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==}
engines: {node: '>= 0.4'}
+ setprototypeof@1.2.0:
+ resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==}
+
sha.js@2.4.12:
resolution: {integrity: sha512-8LzC5+bvI45BjpfXU8V5fdU2mfeKiQe1D1gIMn7XUlF3OTUrpdJpPPH4EMAnF0DsHHdSZqCdSss5qCmJKuiO3w==}
engines: {node: '>= 0.10'}
@@ -5596,6 +5941,10 @@ packages:
stackback@0.0.2:
resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==}
+ statuses@2.0.2:
+ resolution: {integrity: sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==}
+ engines: {node: '>= 0.8'}
+
std-env@3.10.0:
resolution: {integrity: sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==}
@@ -5760,6 +6109,10 @@ packages:
resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==}
engines: {node: '>=8.0'}
+ toidentifier@1.0.1:
+ resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==}
+ engines: {node: '>=0.6'}
+
toml@3.0.0:
resolution: {integrity: sha512-y/mWCZinnvxjTKYhJ+pYxwD0mRLVvOtdS2Awbgxln6iEnt4rk0yBxeSBHkGJcPucRiG0e55mwWp+g/05rsrd6w==}
@@ -5793,6 +6146,10 @@ packages:
resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==}
engines: {node: '>= 0.8.0'}
+ type-is@2.0.1:
+ resolution: {integrity: sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==}
+ engines: {node: '>= 0.6'}
+
typed-array-buffer@1.0.3:
resolution: {integrity: sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==}
engines: {node: '>= 0.4'}
@@ -5856,6 +6213,10 @@ packages:
undici-types@8.2.0:
resolution: {integrity: sha512-uciYZ5yCmf+QJb18kJw10HjquzM7K0z992vWcI+84KeBpTfXT4hfgfGJ5DQbf/mCBPACofkrjvqgcjZfuujjFA==}
+ unpipe@1.0.0:
+ resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==}
+ engines: {node: '>= 0.8'}
+
unrs-resolver@1.11.1:
resolution: {integrity: sha512-bSjt9pjaEBnNiGgc9rUiHGKv5l4/TGzDmYw3RhnkJGtLhbnnA/5qJj7x3dNDCRx/PJxu774LlH8lCOlB4hEfKg==}
@@ -5995,6 +6356,10 @@ packages:
react:
optional: true
+ vary@1.1.2:
+ resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==}
+ engines: {node: '>= 0.8'}
+
viem@2.23.2:
resolution: {integrity: sha512-NVmW/E0c5crMOtbEAqMF0e3NmvQykFXhLOc/CkLIXOlzHSA6KXVz3CYVmaKqBF8/xtjsjHAGjdJN3Ru1kFJLaA==}
peerDependencies:
@@ -6213,6 +6578,9 @@ packages:
yallist@3.1.1:
resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==}
+ yallist@4.0.0:
+ resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==}
+
yargs-parser@18.1.3:
resolution: {integrity: sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==}
engines: {node: '>=6'}
@@ -6225,6 +6593,11 @@ packages:
resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==}
engines: {node: '>=10'}
+ zod-to-json-schema@3.25.2:
+ resolution: {integrity: sha512-O/PgfnpT1xKSDeQYSCfRI5Gy3hPf91mKVDuYLUHZJMiDFptvP41MSnWofm8dnCm0256ZNfZIM7DSzuSMAFnjHA==}
+ peerDependencies:
+ zod: ^3.25.28 || ^4
+
zod-validation-error@4.0.2:
resolution: {integrity: sha512-Q6/nZLe6jxuU80qb/4uJ4t5v2VEZ44lzQjPDhYJNztRQ4wyWc6VF3D3Kb/fAuPetZQnhS3hnajCf9CsWesghLQ==}
engines: {node: '>=18.0.0'}
@@ -7091,6 +7464,10 @@ snapshots:
dependencies:
react: 19.2.4
+ '@hono/node-server@1.19.14(hono@4.12.15)':
+ dependencies:
+ hono: 4.12.15
+
'@humanfs/core@0.19.2':
dependencies:
'@humanfs/types': 0.15.0
@@ -7436,6 +7813,28 @@ snapshots:
transitivePeerDependencies:
- supports-color
+ '@modelcontextprotocol/sdk@1.29.0(zod@3.25.76)':
+ dependencies:
+ '@hono/node-server': 1.19.14(hono@4.12.15)
+ ajv: 8.20.0
+ ajv-formats: 3.0.1(ajv@8.20.0)
+ content-type: 1.0.5
+ cors: 2.8.6
+ cross-spawn: 7.0.6
+ eventsource: 3.0.7
+ eventsource-parser: 3.0.8
+ express: 5.2.1
+ express-rate-limit: 8.5.1(express@5.2.1)
+ hono: 4.12.15
+ jose: 6.2.3
+ json-schema-typed: 8.0.2
+ pkce-challenge: 5.0.1
+ raw-body: 3.0.2
+ zod: 3.25.76
+ zod-to-json-schema: 3.25.2(zod@3.25.76)
+ transitivePeerDependencies:
+ - supports-color
+
'@msgpack/msgpack@3.1.2': {}
'@napi-rs/wasm-runtime@0.2.12':
@@ -7610,7 +8009,7 @@ snapshots:
'@privy-io/popup@0.0.4': {}
- '@privy-io/react-auth@3.22.2(@solana-program/memo@0.11.0(@solana/kit@6.8.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)))(@solana-program/system@0.10.0(@solana/kit@6.8.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)))(@solana-program/token@0.9.0(@solana/kit@6.8.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)))(@solana/kit@6.8.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6))(@solana/sysvars@6.9.0(typescript@5.9.3))(@tanstack/query-core@5.100.6)(@tanstack/react-query@5.100.6(react@19.2.4))(@types/react@19.2.14)(bufferutil@4.1.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@19.2.4))(utf-8-validate@6.0.6)(zod@4.3.6)':
+ '@privy-io/react-auth@3.22.2(@solana-program/memo@0.11.0(@solana/kit@6.8.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)))(@solana-program/system@0.10.0(@solana/kit@6.8.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)))(@solana-program/token@0.9.0(@solana/kit@6.8.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)))(@solana/kit@6.8.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6))(@solana/sysvars@6.9.0(typescript@5.9.3))(@tanstack/query-core@5.100.6)(@tanstack/react-query@5.100.6(react@19.2.4))(@types/react@19.2.14)(@upstash/redis@1.38.0)(bufferutil@4.1.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@19.2.4))(utf-8-validate@6.0.6)(zod@4.3.6)':
dependencies:
'@base-org/account': 1.1.1(@types/react@19.2.14)(bufferutil@4.1.0)(react@19.2.4)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@19.2.4))(utf-8-validate@6.0.6)(zod@4.3.6)
'@coinbase/wallet-sdk': 4.3.2
@@ -7633,8 +8032,8 @@ snapshots:
'@simplewebauthn/browser': 13.3.0
'@tanstack/react-virtual': 3.13.24(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
'@wallet-standard/app': 1.1.0
- '@walletconnect/ethereum-provider': 2.22.4(@types/react@19.2.14)(bufferutil@4.1.0)(react@19.2.4)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@4.3.6)
- '@walletconnect/universal-provider': 2.22.4(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@4.3.6)
+ '@walletconnect/ethereum-provider': 2.22.4(@types/react@19.2.14)(@upstash/redis@1.38.0)(bufferutil@4.1.0)(react@19.2.4)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@4.3.6)
+ '@walletconnect/universal-provider': 2.22.4(@upstash/redis@1.38.0)(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@4.3.6)
eventemitter3: 5.0.4
fast-password-entropy: 1.1.1
jose: 4.15.9
@@ -7653,7 +8052,7 @@ snapshots:
tinycolor2: 1.6.0
uuid: 8.3.2
viem: 2.47.12(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@4.3.6)
- x402: 0.7.3(@solana/sysvars@6.9.0(typescript@5.9.3))(@tanstack/query-core@5.100.6)(@tanstack/react-query@5.100.6(react@19.2.4))(@types/react@19.2.14)(bufferutil@4.1.0)(react@19.2.4)(typescript@5.9.3)(utf-8-validate@6.0.6)
+ x402: 0.7.3(@solana/sysvars@6.9.0(typescript@5.9.3))(@tanstack/query-core@5.100.6)(@tanstack/react-query@5.100.6(react@19.2.4))(@types/react@19.2.14)(@upstash/redis@1.38.0)(bufferutil@4.1.0)(react@19.2.4)(typescript@5.9.3)(utf-8-validate@6.0.6)
zustand: 5.0.12(@types/react@19.2.14)(react@19.2.4)(use-sync-external-store@1.4.0(react@19.2.4))
optionalDependencies:
'@solana-program/memo': 0.11.0(@solana/kit@6.8.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6))
@@ -7725,6 +8124,32 @@ snapshots:
dependencies:
react: 19.2.4
+ '@redis/bloom@1.2.0(@redis/client@1.6.1)':
+ dependencies:
+ '@redis/client': 1.6.1
+
+ '@redis/client@1.6.1':
+ dependencies:
+ cluster-key-slot: 1.1.2
+ generic-pool: 3.9.0
+ yallist: 4.0.0
+
+ '@redis/graph@1.1.1(@redis/client@1.6.1)':
+ dependencies:
+ '@redis/client': 1.6.1
+
+ '@redis/json@1.0.7(@redis/client@1.6.1)':
+ dependencies:
+ '@redis/client': 1.6.1
+
+ '@redis/search@1.2.0(@redis/client@1.6.1)':
+ dependencies:
+ '@redis/client': 1.6.1
+
+ '@redis/time-series@1.1.0(@redis/client@1.6.1)':
+ dependencies:
+ '@redis/client': 1.6.1
+
'@reown/appkit-common@1.7.8(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@3.22.4)':
dependencies:
big.js: 6.2.2
@@ -7769,11 +8194,11 @@ snapshots:
- utf-8-validate
- zod
- '@reown/appkit-controllers@1.7.8(@types/react@19.2.14)(bufferutil@4.1.0)(react@19.2.4)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@3.25.76)':
+ '@reown/appkit-controllers@1.7.8(@types/react@19.2.14)(@upstash/redis@1.38.0)(bufferutil@4.1.0)(react@19.2.4)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@3.25.76)':
dependencies:
'@reown/appkit-common': 1.7.8(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@3.25.76)
'@reown/appkit-wallet': 1.7.8(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)
- '@walletconnect/universal-provider': 2.21.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@3.25.76)
+ '@walletconnect/universal-provider': 2.21.0(@upstash/redis@1.38.0)(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@3.25.76)
valtio: 1.13.2(@types/react@19.2.14)(react@19.2.4)
viem: 2.47.12(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@3.25.76)
transitivePeerDependencies:
@@ -7804,11 +8229,11 @@ snapshots:
- utf-8-validate
- zod
- '@reown/appkit-controllers@1.8.9(@types/react@19.2.14)(bufferutil@4.1.0)(react@19.2.4)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@4.3.6)':
+ '@reown/appkit-controllers@1.8.9(@types/react@19.2.14)(@upstash/redis@1.38.0)(bufferutil@4.1.0)(react@19.2.4)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@4.3.6)':
dependencies:
'@reown/appkit-common': 1.8.9(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@4.3.6)
'@reown/appkit-wallet': 1.8.9(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)
- '@walletconnect/universal-provider': 2.21.9(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@4.3.6)
+ '@walletconnect/universal-provider': 2.21.9(@upstash/redis@1.38.0)(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@4.3.6)
valtio: 2.1.7(@types/react@19.2.14)(react@19.2.4)
viem: 2.47.12(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@4.3.6)
transitivePeerDependencies:
@@ -7839,12 +8264,12 @@ snapshots:
- utf-8-validate
- zod
- '@reown/appkit-pay@1.7.8(@types/react@19.2.14)(bufferutil@4.1.0)(react@19.2.4)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@3.25.76)':
+ '@reown/appkit-pay@1.7.8(@types/react@19.2.14)(@upstash/redis@1.38.0)(bufferutil@4.1.0)(react@19.2.4)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@3.25.76)':
dependencies:
'@reown/appkit-common': 1.7.8(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@3.25.76)
- '@reown/appkit-controllers': 1.7.8(@types/react@19.2.14)(bufferutil@4.1.0)(react@19.2.4)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@3.25.76)
- '@reown/appkit-ui': 1.7.8(@types/react@19.2.14)(bufferutil@4.1.0)(react@19.2.4)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@3.25.76)
- '@reown/appkit-utils': 1.7.8(@types/react@19.2.14)(bufferutil@4.1.0)(react@19.2.4)(typescript@5.9.3)(utf-8-validate@6.0.6)(valtio@1.13.2(@types/react@19.2.14)(react@19.2.4))(zod@3.25.76)
+ '@reown/appkit-controllers': 1.7.8(@types/react@19.2.14)(@upstash/redis@1.38.0)(bufferutil@4.1.0)(react@19.2.4)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@3.25.76)
+ '@reown/appkit-ui': 1.7.8(@types/react@19.2.14)(@upstash/redis@1.38.0)(bufferutil@4.1.0)(react@19.2.4)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@3.25.76)
+ '@reown/appkit-utils': 1.7.8(@types/react@19.2.14)(@upstash/redis@1.38.0)(bufferutil@4.1.0)(react@19.2.4)(typescript@5.9.3)(utf-8-validate@6.0.6)(valtio@1.13.2(@types/react@19.2.14)(react@19.2.4))(zod@3.25.76)
lit: 3.3.0
valtio: 1.13.2(@types/react@19.2.14)(react@19.2.4)
transitivePeerDependencies:
@@ -7875,12 +8300,12 @@ snapshots:
- utf-8-validate
- zod
- '@reown/appkit-pay@1.8.9(@types/react@19.2.14)(bufferutil@4.1.0)(react@19.2.4)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@4.3.6)':
+ '@reown/appkit-pay@1.8.9(@types/react@19.2.14)(@upstash/redis@1.38.0)(bufferutil@4.1.0)(react@19.2.4)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@4.3.6)':
dependencies:
'@reown/appkit-common': 1.8.9(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@4.3.6)
- '@reown/appkit-controllers': 1.8.9(@types/react@19.2.14)(bufferutil@4.1.0)(react@19.2.4)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@4.3.6)
- '@reown/appkit-ui': 1.8.9(@types/react@19.2.14)(bufferutil@4.1.0)(react@19.2.4)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@4.3.6)
- '@reown/appkit-utils': 1.8.9(@types/react@19.2.14)(bufferutil@4.1.0)(react@19.2.4)(typescript@5.9.3)(utf-8-validate@6.0.6)(valtio@2.1.7(@types/react@19.2.14)(react@19.2.4))(zod@4.3.6)
+ '@reown/appkit-controllers': 1.8.9(@types/react@19.2.14)(@upstash/redis@1.38.0)(bufferutil@4.1.0)(react@19.2.4)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@4.3.6)
+ '@reown/appkit-ui': 1.8.9(@types/react@19.2.14)(@upstash/redis@1.38.0)(bufferutil@4.1.0)(react@19.2.4)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@4.3.6)
+ '@reown/appkit-utils': 1.8.9(@types/react@19.2.14)(@upstash/redis@1.38.0)(bufferutil@4.1.0)(react@19.2.4)(typescript@5.9.3)(utf-8-validate@6.0.6)(valtio@2.1.7(@types/react@19.2.14)(react@19.2.4))(zod@4.3.6)
lit: 3.3.0
valtio: 2.1.7(@types/react@19.2.14)(react@19.2.4)
transitivePeerDependencies:
@@ -7919,12 +8344,12 @@ snapshots:
dependencies:
buffer: 6.0.3
- '@reown/appkit-scaffold-ui@1.7.8(@types/react@19.2.14)(bufferutil@4.1.0)(react@19.2.4)(typescript@5.9.3)(utf-8-validate@6.0.6)(valtio@1.13.2(@types/react@19.2.14)(react@19.2.4))(zod@3.25.76)':
+ '@reown/appkit-scaffold-ui@1.7.8(@types/react@19.2.14)(@upstash/redis@1.38.0)(bufferutil@4.1.0)(react@19.2.4)(typescript@5.9.3)(utf-8-validate@6.0.6)(valtio@1.13.2(@types/react@19.2.14)(react@19.2.4))(zod@3.25.76)':
dependencies:
'@reown/appkit-common': 1.7.8(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@3.25.76)
- '@reown/appkit-controllers': 1.7.8(@types/react@19.2.14)(bufferutil@4.1.0)(react@19.2.4)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@3.25.76)
- '@reown/appkit-ui': 1.7.8(@types/react@19.2.14)(bufferutil@4.1.0)(react@19.2.4)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@3.25.76)
- '@reown/appkit-utils': 1.7.8(@types/react@19.2.14)(bufferutil@4.1.0)(react@19.2.4)(typescript@5.9.3)(utf-8-validate@6.0.6)(valtio@1.13.2(@types/react@19.2.14)(react@19.2.4))(zod@3.25.76)
+ '@reown/appkit-controllers': 1.7.8(@types/react@19.2.14)(@upstash/redis@1.38.0)(bufferutil@4.1.0)(react@19.2.4)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@3.25.76)
+ '@reown/appkit-ui': 1.7.8(@types/react@19.2.14)(@upstash/redis@1.38.0)(bufferutil@4.1.0)(react@19.2.4)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@3.25.76)
+ '@reown/appkit-utils': 1.7.8(@types/react@19.2.14)(@upstash/redis@1.38.0)(bufferutil@4.1.0)(react@19.2.4)(typescript@5.9.3)(utf-8-validate@6.0.6)(valtio@1.13.2(@types/react@19.2.14)(react@19.2.4))(zod@3.25.76)
'@reown/appkit-wallet': 1.7.8(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)
lit: 3.3.0
transitivePeerDependencies:
@@ -7956,12 +8381,12 @@ snapshots:
- valtio
- zod
- '@reown/appkit-scaffold-ui@1.8.9(@types/react@19.2.14)(bufferutil@4.1.0)(react@19.2.4)(typescript@5.9.3)(utf-8-validate@6.0.6)(valtio@2.1.7(@types/react@19.2.14)(react@19.2.4))(zod@4.3.6)':
+ '@reown/appkit-scaffold-ui@1.8.9(@types/react@19.2.14)(@upstash/redis@1.38.0)(bufferutil@4.1.0)(react@19.2.4)(typescript@5.9.3)(utf-8-validate@6.0.6)(valtio@2.1.7(@types/react@19.2.14)(react@19.2.4))(zod@4.3.6)':
dependencies:
'@reown/appkit-common': 1.8.9(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@4.3.6)
- '@reown/appkit-controllers': 1.8.9(@types/react@19.2.14)(bufferutil@4.1.0)(react@19.2.4)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@4.3.6)
- '@reown/appkit-ui': 1.8.9(@types/react@19.2.14)(bufferutil@4.1.0)(react@19.2.4)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@4.3.6)
- '@reown/appkit-utils': 1.8.9(@types/react@19.2.14)(bufferutil@4.1.0)(react@19.2.4)(typescript@5.9.3)(utf-8-validate@6.0.6)(valtio@2.1.7(@types/react@19.2.14)(react@19.2.4))(zod@4.3.6)
+ '@reown/appkit-controllers': 1.8.9(@types/react@19.2.14)(@upstash/redis@1.38.0)(bufferutil@4.1.0)(react@19.2.4)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@4.3.6)
+ '@reown/appkit-ui': 1.8.9(@types/react@19.2.14)(@upstash/redis@1.38.0)(bufferutil@4.1.0)(react@19.2.4)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@4.3.6)
+ '@reown/appkit-utils': 1.8.9(@types/react@19.2.14)(@upstash/redis@1.38.0)(bufferutil@4.1.0)(react@19.2.4)(typescript@5.9.3)(utf-8-validate@6.0.6)(valtio@2.1.7(@types/react@19.2.14)(react@19.2.4))(zod@4.3.6)
'@reown/appkit-wallet': 1.8.9(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)
lit: 3.3.0
transitivePeerDependencies:
@@ -7993,10 +8418,10 @@ snapshots:
- valtio
- zod
- '@reown/appkit-ui@1.7.8(@types/react@19.2.14)(bufferutil@4.1.0)(react@19.2.4)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@3.25.76)':
+ '@reown/appkit-ui@1.7.8(@types/react@19.2.14)(@upstash/redis@1.38.0)(bufferutil@4.1.0)(react@19.2.4)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@3.25.76)':
dependencies:
'@reown/appkit-common': 1.7.8(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@3.25.76)
- '@reown/appkit-controllers': 1.7.8(@types/react@19.2.14)(bufferutil@4.1.0)(react@19.2.4)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@3.25.76)
+ '@reown/appkit-controllers': 1.7.8(@types/react@19.2.14)(@upstash/redis@1.38.0)(bufferutil@4.1.0)(react@19.2.4)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@3.25.76)
'@reown/appkit-wallet': 1.7.8(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)
lit: 3.3.0
qrcode: 1.5.3
@@ -8028,11 +8453,11 @@ snapshots:
- utf-8-validate
- zod
- '@reown/appkit-ui@1.8.9(@types/react@19.2.14)(bufferutil@4.1.0)(react@19.2.4)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@4.3.6)':
+ '@reown/appkit-ui@1.8.9(@types/react@19.2.14)(@upstash/redis@1.38.0)(bufferutil@4.1.0)(react@19.2.4)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@4.3.6)':
dependencies:
'@phosphor-icons/webcomponents': 2.1.5
'@reown/appkit-common': 1.8.9(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@4.3.6)
- '@reown/appkit-controllers': 1.8.9(@types/react@19.2.14)(bufferutil@4.1.0)(react@19.2.4)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@4.3.6)
+ '@reown/appkit-controllers': 1.8.9(@types/react@19.2.14)(@upstash/redis@1.38.0)(bufferutil@4.1.0)(react@19.2.4)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@4.3.6)
'@reown/appkit-wallet': 1.8.9(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)
lit: 3.3.0
qrcode: 1.5.3
@@ -8064,14 +8489,14 @@ snapshots:
- utf-8-validate
- zod
- '@reown/appkit-utils@1.7.8(@types/react@19.2.14)(bufferutil@4.1.0)(react@19.2.4)(typescript@5.9.3)(utf-8-validate@6.0.6)(valtio@1.13.2(@types/react@19.2.14)(react@19.2.4))(zod@3.25.76)':
+ '@reown/appkit-utils@1.7.8(@types/react@19.2.14)(@upstash/redis@1.38.0)(bufferutil@4.1.0)(react@19.2.4)(typescript@5.9.3)(utf-8-validate@6.0.6)(valtio@1.13.2(@types/react@19.2.14)(react@19.2.4))(zod@3.25.76)':
dependencies:
'@reown/appkit-common': 1.7.8(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@3.25.76)
- '@reown/appkit-controllers': 1.7.8(@types/react@19.2.14)(bufferutil@4.1.0)(react@19.2.4)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@3.25.76)
+ '@reown/appkit-controllers': 1.7.8(@types/react@19.2.14)(@upstash/redis@1.38.0)(bufferutil@4.1.0)(react@19.2.4)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@3.25.76)
'@reown/appkit-polyfills': 1.7.8
'@reown/appkit-wallet': 1.7.8(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)
'@walletconnect/logger': 2.1.2
- '@walletconnect/universal-provider': 2.21.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@3.25.76)
+ '@walletconnect/universal-provider': 2.21.0(@upstash/redis@1.38.0)(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@3.25.76)
valtio: 1.13.2(@types/react@19.2.14)(react@19.2.4)
viem: 2.47.12(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@3.25.76)
transitivePeerDependencies:
@@ -8102,15 +8527,15 @@ snapshots:
- utf-8-validate
- zod
- '@reown/appkit-utils@1.8.9(@types/react@19.2.14)(bufferutil@4.1.0)(react@19.2.4)(typescript@5.9.3)(utf-8-validate@6.0.6)(valtio@2.1.7(@types/react@19.2.14)(react@19.2.4))(zod@4.3.6)':
+ '@reown/appkit-utils@1.8.9(@types/react@19.2.14)(@upstash/redis@1.38.0)(bufferutil@4.1.0)(react@19.2.4)(typescript@5.9.3)(utf-8-validate@6.0.6)(valtio@2.1.7(@types/react@19.2.14)(react@19.2.4))(zod@4.3.6)':
dependencies:
'@reown/appkit-common': 1.8.9(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@4.3.6)
- '@reown/appkit-controllers': 1.8.9(@types/react@19.2.14)(bufferutil@4.1.0)(react@19.2.4)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@4.3.6)
+ '@reown/appkit-controllers': 1.8.9(@types/react@19.2.14)(@upstash/redis@1.38.0)(bufferutil@4.1.0)(react@19.2.4)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@4.3.6)
'@reown/appkit-polyfills': 1.8.9
'@reown/appkit-wallet': 1.8.9(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)
'@wallet-standard/wallet': 1.1.0
'@walletconnect/logger': 2.1.2
- '@walletconnect/universal-provider': 2.21.9(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@4.3.6)
+ '@walletconnect/universal-provider': 2.21.9(@upstash/redis@1.38.0)(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@4.3.6)
valtio: 2.1.7(@types/react@19.2.14)(react@19.2.4)
viem: 2.47.12(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@4.3.6)
transitivePeerDependencies:
@@ -8163,18 +8588,18 @@ snapshots:
- typescript
- utf-8-validate
- '@reown/appkit@1.7.8(@types/react@19.2.14)(bufferutil@4.1.0)(react@19.2.4)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@3.25.76)':
+ '@reown/appkit@1.7.8(@types/react@19.2.14)(@upstash/redis@1.38.0)(bufferutil@4.1.0)(react@19.2.4)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@3.25.76)':
dependencies:
'@reown/appkit-common': 1.7.8(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@3.25.76)
- '@reown/appkit-controllers': 1.7.8(@types/react@19.2.14)(bufferutil@4.1.0)(react@19.2.4)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@3.25.76)
- '@reown/appkit-pay': 1.7.8(@types/react@19.2.14)(bufferutil@4.1.0)(react@19.2.4)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@3.25.76)
+ '@reown/appkit-controllers': 1.7.8(@types/react@19.2.14)(@upstash/redis@1.38.0)(bufferutil@4.1.0)(react@19.2.4)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@3.25.76)
+ '@reown/appkit-pay': 1.7.8(@types/react@19.2.14)(@upstash/redis@1.38.0)(bufferutil@4.1.0)(react@19.2.4)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@3.25.76)
'@reown/appkit-polyfills': 1.7.8
- '@reown/appkit-scaffold-ui': 1.7.8(@types/react@19.2.14)(bufferutil@4.1.0)(react@19.2.4)(typescript@5.9.3)(utf-8-validate@6.0.6)(valtio@1.13.2(@types/react@19.2.14)(react@19.2.4))(zod@3.25.76)
- '@reown/appkit-ui': 1.7.8(@types/react@19.2.14)(bufferutil@4.1.0)(react@19.2.4)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@3.25.76)
- '@reown/appkit-utils': 1.7.8(@types/react@19.2.14)(bufferutil@4.1.0)(react@19.2.4)(typescript@5.9.3)(utf-8-validate@6.0.6)(valtio@1.13.2(@types/react@19.2.14)(react@19.2.4))(zod@3.25.76)
+ '@reown/appkit-scaffold-ui': 1.7.8(@types/react@19.2.14)(@upstash/redis@1.38.0)(bufferutil@4.1.0)(react@19.2.4)(typescript@5.9.3)(utf-8-validate@6.0.6)(valtio@1.13.2(@types/react@19.2.14)(react@19.2.4))(zod@3.25.76)
+ '@reown/appkit-ui': 1.7.8(@types/react@19.2.14)(@upstash/redis@1.38.0)(bufferutil@4.1.0)(react@19.2.4)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@3.25.76)
+ '@reown/appkit-utils': 1.7.8(@types/react@19.2.14)(@upstash/redis@1.38.0)(bufferutil@4.1.0)(react@19.2.4)(typescript@5.9.3)(utf-8-validate@6.0.6)(valtio@1.13.2(@types/react@19.2.14)(react@19.2.4))(zod@3.25.76)
'@reown/appkit-wallet': 1.7.8(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)
- '@walletconnect/types': 2.21.0
- '@walletconnect/universal-provider': 2.21.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@3.25.76)
+ '@walletconnect/types': 2.21.0(@upstash/redis@1.38.0)
+ '@walletconnect/universal-provider': 2.21.0(@upstash/redis@1.38.0)(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@3.25.76)
bs58: 6.0.0
valtio: 1.13.2(@types/react@19.2.14)(react@19.2.4)
viem: 2.47.12(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@3.25.76)
@@ -8206,17 +8631,17 @@ snapshots:
- utf-8-validate
- zod
- '@reown/appkit@1.8.9(@types/react@19.2.14)(bufferutil@4.1.0)(react@19.2.4)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@4.3.6)':
+ '@reown/appkit@1.8.9(@types/react@19.2.14)(@upstash/redis@1.38.0)(bufferutil@4.1.0)(react@19.2.4)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@4.3.6)':
dependencies:
'@reown/appkit-common': 1.8.9(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@4.3.6)
- '@reown/appkit-controllers': 1.8.9(@types/react@19.2.14)(bufferutil@4.1.0)(react@19.2.4)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@4.3.6)
- '@reown/appkit-pay': 1.8.9(@types/react@19.2.14)(bufferutil@4.1.0)(react@19.2.4)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@4.3.6)
+ '@reown/appkit-controllers': 1.8.9(@types/react@19.2.14)(@upstash/redis@1.38.0)(bufferutil@4.1.0)(react@19.2.4)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@4.3.6)
+ '@reown/appkit-pay': 1.8.9(@types/react@19.2.14)(@upstash/redis@1.38.0)(bufferutil@4.1.0)(react@19.2.4)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@4.3.6)
'@reown/appkit-polyfills': 1.8.9
- '@reown/appkit-scaffold-ui': 1.8.9(@types/react@19.2.14)(bufferutil@4.1.0)(react@19.2.4)(typescript@5.9.3)(utf-8-validate@6.0.6)(valtio@2.1.7(@types/react@19.2.14)(react@19.2.4))(zod@4.3.6)
- '@reown/appkit-ui': 1.8.9(@types/react@19.2.14)(bufferutil@4.1.0)(react@19.2.4)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@4.3.6)
- '@reown/appkit-utils': 1.8.9(@types/react@19.2.14)(bufferutil@4.1.0)(react@19.2.4)(typescript@5.9.3)(utf-8-validate@6.0.6)(valtio@2.1.7(@types/react@19.2.14)(react@19.2.4))(zod@4.3.6)
+ '@reown/appkit-scaffold-ui': 1.8.9(@types/react@19.2.14)(@upstash/redis@1.38.0)(bufferutil@4.1.0)(react@19.2.4)(typescript@5.9.3)(utf-8-validate@6.0.6)(valtio@2.1.7(@types/react@19.2.14)(react@19.2.4))(zod@4.3.6)
+ '@reown/appkit-ui': 1.8.9(@types/react@19.2.14)(@upstash/redis@1.38.0)(bufferutil@4.1.0)(react@19.2.4)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@4.3.6)
+ '@reown/appkit-utils': 1.8.9(@types/react@19.2.14)(@upstash/redis@1.38.0)(bufferutil@4.1.0)(react@19.2.4)(typescript@5.9.3)(utf-8-validate@6.0.6)(valtio@2.1.7(@types/react@19.2.14)(react@19.2.4))(zod@4.3.6)
'@reown/appkit-wallet': 1.8.9(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)
- '@walletconnect/universal-provider': 2.21.9(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@4.3.6)
+ '@walletconnect/universal-provider': 2.21.9(@upstash/redis@1.38.0)(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@4.3.6)
bs58: 6.0.0
semver: 7.7.2
valtio: 2.1.7(@types/react@19.2.14)(react@19.2.4)
@@ -9920,6 +10345,8 @@ snapshots:
tslib: 2.8.1
optional: true
+ '@types/bcryptjs@2.4.6': {}
+
'@types/bn.js@5.2.0':
dependencies:
'@types/node': 20.19.39
@@ -10125,6 +10552,19 @@ snapshots:
'@unrs/resolver-binding-win32-x64-msvc@1.11.1':
optional: true
+ '@upstash/core-analytics@0.0.10':
+ dependencies:
+ '@upstash/redis': 1.38.0
+
+ '@upstash/ratelimit@2.0.8(@upstash/redis@1.38.0)':
+ dependencies:
+ '@upstash/core-analytics': 0.0.10
+ '@upstash/redis': 1.38.0
+
+ '@upstash/redis@1.38.0':
+ dependencies:
+ uncrypto: 0.1.3
+
'@vitest/expect@2.1.9':
dependencies:
'@vitest/spy': 2.1.9
@@ -10173,7 +10613,7 @@ snapshots:
loupe: 3.2.1
tinyrainbow: 1.2.0
- '@wagmi/connectors@6.2.0(@tanstack/react-query@5.100.6(react@19.2.4))(@types/react@19.2.14)(@wagmi/core@2.22.1(@tanstack/query-core@5.100.6)(@types/react@19.2.14)(react@19.2.4)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@19.2.4))(viem@2.47.12(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@4.3.6)))(bufferutil@4.1.0)(react@19.2.4)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@19.2.4))(utf-8-validate@6.0.6)(viem@2.47.12(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@4.3.6))(wagmi@2.19.5(@tanstack/query-core@5.100.6)(@tanstack/react-query@5.100.6(react@19.2.4))(@types/react@19.2.14)(bufferutil@4.1.0)(react@19.2.4)(typescript@5.9.3)(utf-8-validate@6.0.6)(viem@2.47.12(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@4.3.6))(zod@3.25.76))(zod@3.25.76)':
+ '@wagmi/connectors@6.2.0(@tanstack/react-query@5.100.6(react@19.2.4))(@types/react@19.2.14)(@upstash/redis@1.38.0)(@wagmi/core@2.22.1(@tanstack/query-core@5.100.6)(@types/react@19.2.14)(react@19.2.4)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@19.2.4))(viem@2.47.12(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@4.3.6)))(bufferutil@4.1.0)(react@19.2.4)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@19.2.4))(utf-8-validate@6.0.6)(viem@2.47.12(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@4.3.6))(wagmi@2.19.5(@tanstack/query-core@5.100.6)(@tanstack/react-query@5.100.6(react@19.2.4))(@types/react@19.2.14)(@upstash/redis@1.38.0)(bufferutil@4.1.0)(react@19.2.4)(typescript@5.9.3)(utf-8-validate@6.0.6)(viem@2.47.12(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@4.3.6))(zod@3.25.76))(zod@3.25.76)':
dependencies:
'@base-org/account': 2.4.0(@types/react@19.2.14)(bufferutil@4.1.0)(react@19.2.4)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@19.2.4))(utf-8-validate@6.0.6)(zod@3.25.76)
'@coinbase/wallet-sdk': 4.3.6(@types/react@19.2.14)(bufferutil@4.1.0)(react@19.2.4)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@19.2.4))(utf-8-validate@6.0.6)(zod@3.25.76)
@@ -10182,9 +10622,9 @@ snapshots:
'@safe-global/safe-apps-provider': 0.18.6(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@3.25.76)
'@safe-global/safe-apps-sdk': 9.1.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@3.25.76)
'@wagmi/core': 2.22.1(@tanstack/query-core@5.100.6)(@types/react@19.2.14)(react@19.2.4)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@19.2.4))(viem@2.47.12(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@4.3.6))
- '@walletconnect/ethereum-provider': 2.21.1(@types/react@19.2.14)(bufferutil@4.1.0)(react@19.2.4)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@3.25.76)
+ '@walletconnect/ethereum-provider': 2.21.1(@types/react@19.2.14)(@upstash/redis@1.38.0)(bufferutil@4.1.0)(react@19.2.4)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@3.25.76)
cbw-sdk: '@coinbase/wallet-sdk@3.9.3'
- porto: 0.2.35(@tanstack/react-query@5.100.6(react@19.2.4))(@types/react@19.2.14)(@wagmi/core@2.22.1(@tanstack/query-core@5.100.6)(@types/react@19.2.14)(react@19.2.4)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@19.2.4))(viem@2.47.12(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@4.3.6)))(react@19.2.4)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@19.2.4))(viem@2.47.12(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@4.3.6))(wagmi@2.19.5(@tanstack/query-core@5.100.6)(@tanstack/react-query@5.100.6(react@19.2.4))(@types/react@19.2.14)(bufferutil@4.1.0)(react@19.2.4)(typescript@5.9.3)(utf-8-validate@6.0.6)(viem@2.47.12(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@4.3.6))(zod@3.25.76))
+ porto: 0.2.35(@tanstack/react-query@5.100.6(react@19.2.4))(@types/react@19.2.14)(@wagmi/core@2.22.1(@tanstack/query-core@5.100.6)(@types/react@19.2.14)(react@19.2.4)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@19.2.4))(viem@2.47.12(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@4.3.6)))(react@19.2.4)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@19.2.4))(viem@2.47.12(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@4.3.6))(wagmi@2.19.5(@tanstack/query-core@5.100.6)(@tanstack/react-query@5.100.6(react@19.2.4))(@types/react@19.2.14)(@upstash/redis@1.38.0)(bufferutil@4.1.0)(react@19.2.4)(typescript@5.9.3)(utf-8-validate@6.0.6)(viem@2.47.12(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@4.3.6))(zod@3.25.76))
viem: 2.47.12(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@4.3.6)
optionalDependencies:
typescript: 5.9.3
@@ -10255,21 +10695,21 @@ snapshots:
dependencies:
'@wallet-standard/base': 1.1.0
- '@walletconnect/core@2.21.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@3.25.76)':
+ '@walletconnect/core@2.21.0(@upstash/redis@1.38.0)(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@3.25.76)':
dependencies:
'@walletconnect/heartbeat': 1.2.2
'@walletconnect/jsonrpc-provider': 1.0.14
'@walletconnect/jsonrpc-types': 1.0.4
'@walletconnect/jsonrpc-utils': 1.0.8
'@walletconnect/jsonrpc-ws-connection': 1.0.16(bufferutil@4.1.0)(utf-8-validate@6.0.6)
- '@walletconnect/keyvaluestorage': 1.1.1
+ '@walletconnect/keyvaluestorage': 1.1.1(@upstash/redis@1.38.0)
'@walletconnect/logger': 2.1.2
'@walletconnect/relay-api': 1.0.11
'@walletconnect/relay-auth': 1.1.0
'@walletconnect/safe-json': 1.0.2
'@walletconnect/time': 1.0.2
- '@walletconnect/types': 2.21.0
- '@walletconnect/utils': 2.21.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@3.25.76)
+ '@walletconnect/types': 2.21.0(@upstash/redis@1.38.0)
+ '@walletconnect/utils': 2.21.0(@upstash/redis@1.38.0)(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@3.25.76)
'@walletconnect/window-getters': 1.0.1
es-toolkit: 1.33.0
events: 3.3.0
@@ -10299,21 +10739,21 @@ snapshots:
- utf-8-validate
- zod
- '@walletconnect/core@2.21.1(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@3.25.76)':
+ '@walletconnect/core@2.21.1(@upstash/redis@1.38.0)(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@3.25.76)':
dependencies:
'@walletconnect/heartbeat': 1.2.2
'@walletconnect/jsonrpc-provider': 1.0.14
'@walletconnect/jsonrpc-types': 1.0.4
'@walletconnect/jsonrpc-utils': 1.0.8
'@walletconnect/jsonrpc-ws-connection': 1.0.16(bufferutil@4.1.0)(utf-8-validate@6.0.6)
- '@walletconnect/keyvaluestorage': 1.1.1
+ '@walletconnect/keyvaluestorage': 1.1.1(@upstash/redis@1.38.0)
'@walletconnect/logger': 2.1.2
'@walletconnect/relay-api': 1.0.11
'@walletconnect/relay-auth': 1.1.0
'@walletconnect/safe-json': 1.0.2
'@walletconnect/time': 1.0.2
- '@walletconnect/types': 2.21.1
- '@walletconnect/utils': 2.21.1(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@3.25.76)
+ '@walletconnect/types': 2.21.1(@upstash/redis@1.38.0)
+ '@walletconnect/utils': 2.21.1(@upstash/redis@1.38.0)(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@3.25.76)
'@walletconnect/window-getters': 1.0.1
es-toolkit: 1.33.0
events: 3.3.0
@@ -10343,21 +10783,21 @@ snapshots:
- utf-8-validate
- zod
- '@walletconnect/core@2.21.9(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@4.3.6)':
+ '@walletconnect/core@2.21.9(@upstash/redis@1.38.0)(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@4.3.6)':
dependencies:
'@walletconnect/heartbeat': 1.2.2
'@walletconnect/jsonrpc-provider': 1.0.14
'@walletconnect/jsonrpc-types': 1.0.4
'@walletconnect/jsonrpc-utils': 1.0.8
'@walletconnect/jsonrpc-ws-connection': 1.0.16(bufferutil@4.1.0)(utf-8-validate@6.0.6)
- '@walletconnect/keyvaluestorage': 1.1.1
+ '@walletconnect/keyvaluestorage': 1.1.1(@upstash/redis@1.38.0)
'@walletconnect/logger': 2.1.2
'@walletconnect/relay-api': 1.0.11
'@walletconnect/relay-auth': 1.1.0
'@walletconnect/safe-json': 1.0.2
'@walletconnect/time': 1.0.2
- '@walletconnect/types': 2.21.9
- '@walletconnect/utils': 2.21.9(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@4.3.6)
+ '@walletconnect/types': 2.21.9(@upstash/redis@1.38.0)
+ '@walletconnect/utils': 2.21.9(@upstash/redis@1.38.0)(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@4.3.6)
'@walletconnect/window-getters': 1.0.1
es-toolkit: 1.39.3
events: 3.3.0
@@ -10387,21 +10827,21 @@ snapshots:
- utf-8-validate
- zod
- '@walletconnect/core@2.22.4(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@4.3.6)':
+ '@walletconnect/core@2.22.4(@upstash/redis@1.38.0)(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@4.3.6)':
dependencies:
'@walletconnect/heartbeat': 1.2.2
'@walletconnect/jsonrpc-provider': 1.0.14
'@walletconnect/jsonrpc-types': 1.0.4
'@walletconnect/jsonrpc-utils': 1.0.8
'@walletconnect/jsonrpc-ws-connection': 1.0.16(bufferutil@4.1.0)(utf-8-validate@6.0.6)
- '@walletconnect/keyvaluestorage': 1.1.1
+ '@walletconnect/keyvaluestorage': 1.1.1(@upstash/redis@1.38.0)
'@walletconnect/logger': 3.0.0
'@walletconnect/relay-api': 1.0.11
'@walletconnect/relay-auth': 1.1.0
'@walletconnect/safe-json': 1.0.2
'@walletconnect/time': 1.0.2
- '@walletconnect/types': 2.22.4
- '@walletconnect/utils': 2.22.4(typescript@5.9.3)(zod@4.3.6)
+ '@walletconnect/types': 2.22.4(@upstash/redis@1.38.0)
+ '@walletconnect/utils': 2.22.4(@upstash/redis@1.38.0)(typescript@5.9.3)(zod@4.3.6)
'@walletconnect/window-getters': 1.0.1
es-toolkit: 1.39.3
events: 3.3.0
@@ -10435,18 +10875,18 @@ snapshots:
dependencies:
tslib: 1.14.1
- '@walletconnect/ethereum-provider@2.21.1(@types/react@19.2.14)(bufferutil@4.1.0)(react@19.2.4)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@3.25.76)':
+ '@walletconnect/ethereum-provider@2.21.1(@types/react@19.2.14)(@upstash/redis@1.38.0)(bufferutil@4.1.0)(react@19.2.4)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@3.25.76)':
dependencies:
- '@reown/appkit': 1.7.8(@types/react@19.2.14)(bufferutil@4.1.0)(react@19.2.4)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@3.25.76)
+ '@reown/appkit': 1.7.8(@types/react@19.2.14)(@upstash/redis@1.38.0)(bufferutil@4.1.0)(react@19.2.4)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@3.25.76)
'@walletconnect/jsonrpc-http-connection': 1.0.8
'@walletconnect/jsonrpc-provider': 1.0.14
'@walletconnect/jsonrpc-types': 1.0.4
'@walletconnect/jsonrpc-utils': 1.0.8
- '@walletconnect/keyvaluestorage': 1.1.1
- '@walletconnect/sign-client': 2.21.1(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@3.25.76)
- '@walletconnect/types': 2.21.1
- '@walletconnect/universal-provider': 2.21.1(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@3.25.76)
- '@walletconnect/utils': 2.21.1(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@3.25.76)
+ '@walletconnect/keyvaluestorage': 1.1.1(@upstash/redis@1.38.0)
+ '@walletconnect/sign-client': 2.21.1(@upstash/redis@1.38.0)(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@3.25.76)
+ '@walletconnect/types': 2.21.1(@upstash/redis@1.38.0)
+ '@walletconnect/universal-provider': 2.21.1(@upstash/redis@1.38.0)(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@3.25.76)
+ '@walletconnect/utils': 2.21.1(@upstash/redis@1.38.0)(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@3.25.76)
events: 3.3.0
transitivePeerDependencies:
- '@azure/app-configuration'
@@ -10476,19 +10916,19 @@ snapshots:
- utf-8-validate
- zod
- '@walletconnect/ethereum-provider@2.22.4(@types/react@19.2.14)(bufferutil@4.1.0)(react@19.2.4)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@4.3.6)':
+ '@walletconnect/ethereum-provider@2.22.4(@types/react@19.2.14)(@upstash/redis@1.38.0)(bufferutil@4.1.0)(react@19.2.4)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@4.3.6)':
dependencies:
- '@reown/appkit': 1.8.9(@types/react@19.2.14)(bufferutil@4.1.0)(react@19.2.4)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@4.3.6)
+ '@reown/appkit': 1.8.9(@types/react@19.2.14)(@upstash/redis@1.38.0)(bufferutil@4.1.0)(react@19.2.4)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@4.3.6)
'@walletconnect/jsonrpc-http-connection': 1.0.8
'@walletconnect/jsonrpc-provider': 1.0.14
'@walletconnect/jsonrpc-types': 1.0.4
'@walletconnect/jsonrpc-utils': 1.0.8
- '@walletconnect/keyvaluestorage': 1.1.1
+ '@walletconnect/keyvaluestorage': 1.1.1(@upstash/redis@1.38.0)
'@walletconnect/logger': 3.0.0
- '@walletconnect/sign-client': 2.22.4(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@4.3.6)
- '@walletconnect/types': 2.22.4
- '@walletconnect/universal-provider': 2.22.4(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@4.3.6)
- '@walletconnect/utils': 2.22.4(typescript@5.9.3)(zod@4.3.6)
+ '@walletconnect/sign-client': 2.22.4(@upstash/redis@1.38.0)(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@4.3.6)
+ '@walletconnect/types': 2.22.4(@upstash/redis@1.38.0)
+ '@walletconnect/universal-provider': 2.22.4(@upstash/redis@1.38.0)(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@4.3.6)
+ '@walletconnect/utils': 2.22.4(@upstash/redis@1.38.0)(typescript@5.9.3)(zod@4.3.6)
events: 3.3.0
transitivePeerDependencies:
- '@azure/app-configuration'
@@ -10565,11 +11005,11 @@ snapshots:
- bufferutil
- utf-8-validate
- '@walletconnect/keyvaluestorage@1.1.1':
+ '@walletconnect/keyvaluestorage@1.1.1(@upstash/redis@1.38.0)':
dependencies:
'@walletconnect/safe-json': 1.0.2
idb-keyval: 6.2.2
- unstorage: 1.17.5(idb-keyval@6.2.2)
+ unstorage: 1.17.5(@upstash/redis@1.38.0)(idb-keyval@6.2.2)
transitivePeerDependencies:
- '@azure/app-configuration'
- '@azure/cosmos'
@@ -10616,16 +11056,16 @@ snapshots:
dependencies:
tslib: 1.14.1
- '@walletconnect/sign-client@2.21.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@3.25.76)':
+ '@walletconnect/sign-client@2.21.0(@upstash/redis@1.38.0)(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@3.25.76)':
dependencies:
- '@walletconnect/core': 2.21.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@3.25.76)
+ '@walletconnect/core': 2.21.0(@upstash/redis@1.38.0)(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@3.25.76)
'@walletconnect/events': 1.0.1
'@walletconnect/heartbeat': 1.2.2
'@walletconnect/jsonrpc-utils': 1.0.8
'@walletconnect/logger': 2.1.2
'@walletconnect/time': 1.0.2
- '@walletconnect/types': 2.21.0
- '@walletconnect/utils': 2.21.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@3.25.76)
+ '@walletconnect/types': 2.21.0(@upstash/redis@1.38.0)
+ '@walletconnect/utils': 2.21.0(@upstash/redis@1.38.0)(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@3.25.76)
events: 3.3.0
transitivePeerDependencies:
- '@azure/app-configuration'
@@ -10652,16 +11092,16 @@ snapshots:
- utf-8-validate
- zod
- '@walletconnect/sign-client@2.21.1(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@3.25.76)':
+ '@walletconnect/sign-client@2.21.1(@upstash/redis@1.38.0)(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@3.25.76)':
dependencies:
- '@walletconnect/core': 2.21.1(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@3.25.76)
+ '@walletconnect/core': 2.21.1(@upstash/redis@1.38.0)(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@3.25.76)
'@walletconnect/events': 1.0.1
'@walletconnect/heartbeat': 1.2.2
'@walletconnect/jsonrpc-utils': 1.0.8
'@walletconnect/logger': 2.1.2
'@walletconnect/time': 1.0.2
- '@walletconnect/types': 2.21.1
- '@walletconnect/utils': 2.21.1(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@3.25.76)
+ '@walletconnect/types': 2.21.1(@upstash/redis@1.38.0)
+ '@walletconnect/utils': 2.21.1(@upstash/redis@1.38.0)(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@3.25.76)
events: 3.3.0
transitivePeerDependencies:
- '@azure/app-configuration'
@@ -10688,16 +11128,16 @@ snapshots:
- utf-8-validate
- zod
- '@walletconnect/sign-client@2.21.9(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@4.3.6)':
+ '@walletconnect/sign-client@2.21.9(@upstash/redis@1.38.0)(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@4.3.6)':
dependencies:
- '@walletconnect/core': 2.21.9(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@4.3.6)
+ '@walletconnect/core': 2.21.9(@upstash/redis@1.38.0)(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@4.3.6)
'@walletconnect/events': 1.0.1
'@walletconnect/heartbeat': 1.2.2
'@walletconnect/jsonrpc-utils': 1.0.8
'@walletconnect/logger': 2.1.2
'@walletconnect/time': 1.0.2
- '@walletconnect/types': 2.21.9
- '@walletconnect/utils': 2.21.9(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@4.3.6)
+ '@walletconnect/types': 2.21.9(@upstash/redis@1.38.0)
+ '@walletconnect/utils': 2.21.9(@upstash/redis@1.38.0)(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@4.3.6)
events: 3.3.0
transitivePeerDependencies:
- '@azure/app-configuration'
@@ -10724,16 +11164,16 @@ snapshots:
- utf-8-validate
- zod
- '@walletconnect/sign-client@2.22.4(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@4.3.6)':
+ '@walletconnect/sign-client@2.22.4(@upstash/redis@1.38.0)(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@4.3.6)':
dependencies:
- '@walletconnect/core': 2.22.4(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@4.3.6)
+ '@walletconnect/core': 2.22.4(@upstash/redis@1.38.0)(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@4.3.6)
'@walletconnect/events': 1.0.1
'@walletconnect/heartbeat': 1.2.2
'@walletconnect/jsonrpc-utils': 1.0.8
'@walletconnect/logger': 3.0.0
'@walletconnect/time': 1.0.2
- '@walletconnect/types': 2.22.4
- '@walletconnect/utils': 2.22.4(typescript@5.9.3)(zod@4.3.6)
+ '@walletconnect/types': 2.22.4(@upstash/redis@1.38.0)
+ '@walletconnect/utils': 2.22.4(@upstash/redis@1.38.0)(typescript@5.9.3)(zod@4.3.6)
events: 3.3.0
transitivePeerDependencies:
- '@azure/app-configuration'
@@ -10764,12 +11204,12 @@ snapshots:
dependencies:
tslib: 1.14.1
- '@walletconnect/types@2.21.0':
+ '@walletconnect/types@2.21.0(@upstash/redis@1.38.0)':
dependencies:
'@walletconnect/events': 1.0.1
'@walletconnect/heartbeat': 1.2.2
'@walletconnect/jsonrpc-types': 1.0.4
- '@walletconnect/keyvaluestorage': 1.1.1
+ '@walletconnect/keyvaluestorage': 1.1.1(@upstash/redis@1.38.0)
'@walletconnect/logger': 2.1.2
events: 3.3.0
transitivePeerDependencies:
@@ -10793,12 +11233,12 @@ snapshots:
- ioredis
- uploadthing
- '@walletconnect/types@2.21.1':
+ '@walletconnect/types@2.21.1(@upstash/redis@1.38.0)':
dependencies:
'@walletconnect/events': 1.0.1
'@walletconnect/heartbeat': 1.2.2
'@walletconnect/jsonrpc-types': 1.0.4
- '@walletconnect/keyvaluestorage': 1.1.1
+ '@walletconnect/keyvaluestorage': 1.1.1(@upstash/redis@1.38.0)
'@walletconnect/logger': 2.1.2
events: 3.3.0
transitivePeerDependencies:
@@ -10822,12 +11262,12 @@ snapshots:
- ioredis
- uploadthing
- '@walletconnect/types@2.21.9':
+ '@walletconnect/types@2.21.9(@upstash/redis@1.38.0)':
dependencies:
'@walletconnect/events': 1.0.1
'@walletconnect/heartbeat': 1.2.2
'@walletconnect/jsonrpc-types': 1.0.4
- '@walletconnect/keyvaluestorage': 1.1.1
+ '@walletconnect/keyvaluestorage': 1.1.1(@upstash/redis@1.38.0)
'@walletconnect/logger': 2.1.2
events: 3.3.0
transitivePeerDependencies:
@@ -10851,12 +11291,12 @@ snapshots:
- ioredis
- uploadthing
- '@walletconnect/types@2.22.4':
+ '@walletconnect/types@2.22.4(@upstash/redis@1.38.0)':
dependencies:
'@walletconnect/events': 1.0.1
'@walletconnect/heartbeat': 1.2.2
'@walletconnect/jsonrpc-types': 1.0.4
- '@walletconnect/keyvaluestorage': 1.1.1
+ '@walletconnect/keyvaluestorage': 1.1.1(@upstash/redis@1.38.0)
'@walletconnect/logger': 3.0.0
events: 3.3.0
transitivePeerDependencies:
@@ -10880,18 +11320,18 @@ snapshots:
- ioredis
- uploadthing
- '@walletconnect/universal-provider@2.21.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@3.25.76)':
+ '@walletconnect/universal-provider@2.21.0(@upstash/redis@1.38.0)(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@3.25.76)':
dependencies:
'@walletconnect/events': 1.0.1
'@walletconnect/jsonrpc-http-connection': 1.0.8
'@walletconnect/jsonrpc-provider': 1.0.14
'@walletconnect/jsonrpc-types': 1.0.4
'@walletconnect/jsonrpc-utils': 1.0.8
- '@walletconnect/keyvaluestorage': 1.1.1
+ '@walletconnect/keyvaluestorage': 1.1.1(@upstash/redis@1.38.0)
'@walletconnect/logger': 2.1.2
- '@walletconnect/sign-client': 2.21.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@3.25.76)
- '@walletconnect/types': 2.21.0
- '@walletconnect/utils': 2.21.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@3.25.76)
+ '@walletconnect/sign-client': 2.21.0(@upstash/redis@1.38.0)(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@3.25.76)
+ '@walletconnect/types': 2.21.0(@upstash/redis@1.38.0)
+ '@walletconnect/utils': 2.21.0(@upstash/redis@1.38.0)(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@3.25.76)
es-toolkit: 1.33.0
events: 3.3.0
transitivePeerDependencies:
@@ -10920,18 +11360,18 @@ snapshots:
- utf-8-validate
- zod
- '@walletconnect/universal-provider@2.21.1(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@3.25.76)':
+ '@walletconnect/universal-provider@2.21.1(@upstash/redis@1.38.0)(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@3.25.76)':
dependencies:
'@walletconnect/events': 1.0.1
'@walletconnect/jsonrpc-http-connection': 1.0.8
'@walletconnect/jsonrpc-provider': 1.0.14
'@walletconnect/jsonrpc-types': 1.0.4
'@walletconnect/jsonrpc-utils': 1.0.8
- '@walletconnect/keyvaluestorage': 1.1.1
+ '@walletconnect/keyvaluestorage': 1.1.1(@upstash/redis@1.38.0)
'@walletconnect/logger': 2.1.2
- '@walletconnect/sign-client': 2.21.1(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@3.25.76)
- '@walletconnect/types': 2.21.1
- '@walletconnect/utils': 2.21.1(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@3.25.76)
+ '@walletconnect/sign-client': 2.21.1(@upstash/redis@1.38.0)(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@3.25.76)
+ '@walletconnect/types': 2.21.1(@upstash/redis@1.38.0)
+ '@walletconnect/utils': 2.21.1(@upstash/redis@1.38.0)(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@3.25.76)
es-toolkit: 1.33.0
events: 3.3.0
transitivePeerDependencies:
@@ -10960,18 +11400,18 @@ snapshots:
- utf-8-validate
- zod
- '@walletconnect/universal-provider@2.21.9(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@4.3.6)':
+ '@walletconnect/universal-provider@2.21.9(@upstash/redis@1.38.0)(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@4.3.6)':
dependencies:
'@walletconnect/events': 1.0.1
'@walletconnect/jsonrpc-http-connection': 1.0.8
'@walletconnect/jsonrpc-provider': 1.0.14
'@walletconnect/jsonrpc-types': 1.0.4
'@walletconnect/jsonrpc-utils': 1.0.8
- '@walletconnect/keyvaluestorage': 1.1.1
+ '@walletconnect/keyvaluestorage': 1.1.1(@upstash/redis@1.38.0)
'@walletconnect/logger': 2.1.2
- '@walletconnect/sign-client': 2.21.9(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@4.3.6)
- '@walletconnect/types': 2.21.9
- '@walletconnect/utils': 2.21.9(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@4.3.6)
+ '@walletconnect/sign-client': 2.21.9(@upstash/redis@1.38.0)(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@4.3.6)
+ '@walletconnect/types': 2.21.9(@upstash/redis@1.38.0)
+ '@walletconnect/utils': 2.21.9(@upstash/redis@1.38.0)(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@4.3.6)
es-toolkit: 1.39.3
events: 3.3.0
transitivePeerDependencies:
@@ -11000,18 +11440,18 @@ snapshots:
- utf-8-validate
- zod
- '@walletconnect/universal-provider@2.22.4(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@4.3.6)':
+ '@walletconnect/universal-provider@2.22.4(@upstash/redis@1.38.0)(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@4.3.6)':
dependencies:
'@walletconnect/events': 1.0.1
'@walletconnect/jsonrpc-http-connection': 1.0.8
'@walletconnect/jsonrpc-provider': 1.0.14
'@walletconnect/jsonrpc-types': 1.0.4
'@walletconnect/jsonrpc-utils': 1.0.8
- '@walletconnect/keyvaluestorage': 1.1.1
+ '@walletconnect/keyvaluestorage': 1.1.1(@upstash/redis@1.38.0)
'@walletconnect/logger': 3.0.0
- '@walletconnect/sign-client': 2.22.4(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@4.3.6)
- '@walletconnect/types': 2.22.4
- '@walletconnect/utils': 2.22.4(typescript@5.9.3)(zod@4.3.6)
+ '@walletconnect/sign-client': 2.22.4(@upstash/redis@1.38.0)(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@4.3.6)
+ '@walletconnect/types': 2.22.4(@upstash/redis@1.38.0)
+ '@walletconnect/utils': 2.22.4(@upstash/redis@1.38.0)(typescript@5.9.3)(zod@4.3.6)
es-toolkit: 1.39.3
events: 3.3.0
transitivePeerDependencies:
@@ -11040,18 +11480,18 @@ snapshots:
- utf-8-validate
- zod
- '@walletconnect/utils@2.21.0(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@3.25.76)':
+ '@walletconnect/utils@2.21.0(@upstash/redis@1.38.0)(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@3.25.76)':
dependencies:
'@noble/ciphers': 1.2.1
'@noble/curves': 1.8.1
'@noble/hashes': 1.7.1
'@walletconnect/jsonrpc-utils': 1.0.8
- '@walletconnect/keyvaluestorage': 1.1.1
+ '@walletconnect/keyvaluestorage': 1.1.1(@upstash/redis@1.38.0)
'@walletconnect/relay-api': 1.0.11
'@walletconnect/relay-auth': 1.1.0
'@walletconnect/safe-json': 1.0.2
'@walletconnect/time': 1.0.2
- '@walletconnect/types': 2.21.0
+ '@walletconnect/types': 2.21.0(@upstash/redis@1.38.0)
'@walletconnect/window-getters': 1.0.1
'@walletconnect/window-metadata': 1.0.1
bs58: 6.0.0
@@ -11084,18 +11524,18 @@ snapshots:
- utf-8-validate
- zod
- '@walletconnect/utils@2.21.1(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@3.25.76)':
+ '@walletconnect/utils@2.21.1(@upstash/redis@1.38.0)(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@3.25.76)':
dependencies:
'@noble/ciphers': 1.2.1
'@noble/curves': 1.8.1
'@noble/hashes': 1.7.1
'@walletconnect/jsonrpc-utils': 1.0.8
- '@walletconnect/keyvaluestorage': 1.1.1
+ '@walletconnect/keyvaluestorage': 1.1.1(@upstash/redis@1.38.0)
'@walletconnect/relay-api': 1.0.11
'@walletconnect/relay-auth': 1.1.0
'@walletconnect/safe-json': 1.0.2
'@walletconnect/time': 1.0.2
- '@walletconnect/types': 2.21.1
+ '@walletconnect/types': 2.21.1(@upstash/redis@1.38.0)
'@walletconnect/window-getters': 1.0.1
'@walletconnect/window-metadata': 1.0.1
bs58: 6.0.0
@@ -11128,7 +11568,7 @@ snapshots:
- utf-8-validate
- zod
- '@walletconnect/utils@2.21.9(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@4.3.6)':
+ '@walletconnect/utils@2.21.9(@upstash/redis@1.38.0)(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@4.3.6)':
dependencies:
'@msgpack/msgpack': 3.1.2
'@noble/ciphers': 1.3.0
@@ -11136,12 +11576,12 @@ snapshots:
'@noble/hashes': 1.8.0
'@scure/base': 1.2.6
'@walletconnect/jsonrpc-utils': 1.0.8
- '@walletconnect/keyvaluestorage': 1.1.1
+ '@walletconnect/keyvaluestorage': 1.1.1(@upstash/redis@1.38.0)
'@walletconnect/relay-api': 1.0.11
'@walletconnect/relay-auth': 1.1.0
'@walletconnect/safe-json': 1.0.2
'@walletconnect/time': 1.0.2
- '@walletconnect/types': 2.21.9
+ '@walletconnect/types': 2.21.9(@upstash/redis@1.38.0)
'@walletconnect/window-getters': 1.0.1
'@walletconnect/window-metadata': 1.0.1
blakejs: 1.2.1
@@ -11174,7 +11614,7 @@ snapshots:
- utf-8-validate
- zod
- '@walletconnect/utils@2.22.4(typescript@5.9.3)(zod@4.3.6)':
+ '@walletconnect/utils@2.22.4(@upstash/redis@1.38.0)(typescript@5.9.3)(zod@4.3.6)':
dependencies:
'@msgpack/msgpack': 3.1.2
'@noble/ciphers': 1.3.0
@@ -11182,13 +11622,13 @@ snapshots:
'@noble/hashes': 1.8.0
'@scure/base': 1.2.6
'@walletconnect/jsonrpc-utils': 1.0.8
- '@walletconnect/keyvaluestorage': 1.1.1
+ '@walletconnect/keyvaluestorage': 1.1.1(@upstash/redis@1.38.0)
'@walletconnect/logger': 3.0.0
'@walletconnect/relay-api': 1.0.11
'@walletconnect/relay-auth': 1.1.0
'@walletconnect/safe-json': 1.0.2
'@walletconnect/time': 1.0.2
- '@walletconnect/types': 2.22.4
+ '@walletconnect/types': 2.22.4(@upstash/redis@1.38.0)
'@walletconnect/window-getters': 1.0.1
'@walletconnect/window-metadata': 1.0.1
blakejs: 1.2.1
@@ -11272,6 +11712,11 @@ snapshots:
dependencies:
event-target-shim: 5.0.1
+ accepts@2.0.0:
+ dependencies:
+ mime-types: 3.0.2
+ negotiator: 1.0.0
+
acorn-jsx@5.3.2(acorn@8.16.0):
dependencies:
acorn: 8.16.0
@@ -11282,6 +11727,10 @@ snapshots:
dependencies:
humanize-ms: 1.2.1
+ ajv-formats@3.0.1(ajv@8.20.0):
+ optionalDependencies:
+ ajv: 8.20.0
+
ajv@6.15.0:
dependencies:
fast-deep-equal: 3.1.3
@@ -11289,6 +11738,13 @@ snapshots:
json-schema-traverse: 0.4.1
uri-js: 4.4.1
+ ajv@8.20.0:
+ dependencies:
+ fast-deep-equal: 3.1.3
+ fast-uri: 3.1.2
+ json-schema-traverse: 1.0.0
+ require-from-string: 2.0.2
+
ansi-regex@5.0.1: {}
ansi-styles@4.3.0:
@@ -11424,12 +11880,28 @@ snapshots:
baseline-browser-mapping@2.10.21: {}
+ bcryptjs@3.0.3: {}
+
big.js@6.2.2: {}
blakejs@1.2.1: {}
bn.js@5.2.3: {}
+ body-parser@2.2.2:
+ dependencies:
+ bytes: 3.1.2
+ content-type: 1.0.5
+ debug: 4.4.3
+ http-errors: 2.0.1
+ iconv-lite: 0.7.2
+ on-finished: 2.4.1
+ qs: 6.15.1
+ raw-body: 3.0.2
+ type-is: 2.0.1
+ transitivePeerDependencies:
+ - supports-color
+
borsh@0.7.0:
dependencies:
bn.js: 5.2.3
@@ -11480,6 +11952,8 @@ snapshots:
dependencies:
node-gyp-build: 4.8.4
+ bytes@3.1.2: {}
+
cac@6.7.14: {}
call-bind-apply-helpers@1.0.2:
@@ -11544,6 +12018,8 @@ snapshots:
clsx@2.1.1: {}
+ cluster-key-slot@1.1.2: {}
+
codama@1.6.0:
dependencies:
'@codama/cli': 1.5.1
@@ -11564,6 +12040,8 @@ snapshots:
dependencies:
delayed-stream: 1.0.0
+ commander@11.1.0: {}
+
commander@14.0.2: {}
commander@14.0.3: {}
@@ -11572,14 +12050,27 @@ snapshots:
concat-map@0.0.1: {}
+ content-disposition@1.1.0: {}
+
+ content-type@1.0.5: {}
+
convert-source-map@2.0.0: {}
cookie-es@1.2.3: {}
+ cookie-signature@1.2.2: {}
+
+ cookie@0.7.2: {}
+
cookie@1.1.1: {}
core-util-is@1.0.3: {}
+ cors@2.8.6:
+ dependencies:
+ object-assign: 4.1.1
+ vary: 1.1.2
+
crc-32@1.2.2: {}
cross-fetch@3.2.0:
@@ -11676,6 +12167,8 @@ snapshots:
delayed-stream@1.0.0: {}
+ depd@2.0.0: {}
+
derive-valtio@0.1.0(valtio@1.13.2(@types/react@19.2.14)(react@19.2.4)):
dependencies:
valtio: 1.13.2(@types/react@19.2.14)(react@19.2.4)
@@ -11707,9 +12200,10 @@ snapshots:
esbuild: 0.25.12
tsx: 4.21.0
- drizzle-orm@0.45.2(@prisma/client@5.22.0(prisma@5.22.0))(postgres@3.4.9)(prisma@5.22.0):
+ drizzle-orm@0.45.2(@prisma/client@5.22.0(prisma@5.22.0))(@upstash/redis@1.38.0)(postgres@3.4.9)(prisma@5.22.0):
optionalDependencies:
'@prisma/client': 5.22.0(prisma@5.22.0)
+ '@upstash/redis': 1.38.0
postgres: 3.4.9
prisma: 5.22.0
@@ -11733,6 +12227,8 @@ snapshots:
'@noble/curves': 1.9.7
'@noble/hashes': 1.8.0
+ ee-first@1.1.1: {}
+
electron-to-chromium@1.5.344: {}
emoji-regex@8.0.0: {}
@@ -11741,6 +12237,8 @@ snapshots:
encode-utf8@1.0.3: {}
+ encodeurl@2.0.0: {}
+
end-of-stream@1.4.5:
dependencies:
once: 1.4.0
@@ -11988,6 +12486,8 @@ snapshots:
escalade@3.2.0: {}
+ escape-html@1.0.3: {}
+
escape-string-regexp@4.0.0: {}
eslint-config-next@16.2.4(@typescript-eslint/parser@8.59.0(eslint@9.39.4)(typescript@5.9.3))(eslint@9.39.4)(typescript@5.9.3):
@@ -12125,8 +12625,8 @@ snapshots:
'@babel/parser': 7.29.2
eslint: 9.39.4
hermes-parser: 0.25.1
- zod: 4.3.6
- zod-validation-error: 4.0.2(zod@4.3.6)
+ zod: 3.25.76
+ zod-validation-error: 4.0.2(zod@3.25.76)
transitivePeerDependencies:
- supports-color
@@ -12224,6 +12724,8 @@ snapshots:
esutils@2.0.3: {}
+ etag@1.8.1: {}
+
eth-block-tracker@7.1.0:
dependencies:
'@metamask/eth-json-rpc-provider': 1.0.1
@@ -12270,8 +12772,52 @@ snapshots:
events@3.3.0: {}
+ eventsource-parser@3.0.8: {}
+
+ eventsource@3.0.7:
+ dependencies:
+ eventsource-parser: 3.0.8
+
expect-type@1.3.0: {}
+ express-rate-limit@8.5.1(express@5.2.1):
+ dependencies:
+ express: 5.2.1
+ ip-address: 10.2.0
+
+ express@5.2.1:
+ dependencies:
+ accepts: 2.0.0
+ body-parser: 2.2.2
+ content-disposition: 1.1.0
+ content-type: 1.0.5
+ cookie: 0.7.2
+ cookie-signature: 1.2.2
+ debug: 4.4.3
+ depd: 2.0.0
+ encodeurl: 2.0.0
+ escape-html: 1.0.3
+ etag: 1.8.1
+ finalhandler: 2.1.1
+ fresh: 2.0.0
+ http-errors: 2.0.1
+ merge-descriptors: 2.0.0
+ mime-types: 3.0.2
+ on-finished: 2.4.1
+ once: 1.4.0
+ parseurl: 1.3.3
+ proxy-addr: 2.0.7
+ qs: 6.15.1
+ range-parser: 1.2.1
+ router: 2.2.0
+ send: 1.2.1
+ serve-static: 2.2.1
+ statuses: 2.0.2
+ type-is: 2.0.1
+ vary: 1.1.2
+ transitivePeerDependencies:
+ - supports-color
+
extension-port-stream@3.0.0:
dependencies:
readable-stream: 4.7.0
@@ -12303,6 +12849,8 @@ snapshots:
fast-stable-stringify@1.0.0: {}
+ fast-uri@3.1.2: {}
+
fastq@1.20.1:
dependencies:
reusify: 1.1.0
@@ -12323,6 +12871,17 @@ snapshots:
filter-obj@1.1.0: {}
+ finalhandler@2.1.1:
+ dependencies:
+ debug: 4.4.3
+ encodeurl: 2.0.0
+ escape-html: 1.0.3
+ on-finished: 2.4.1
+ parseurl: 1.3.3
+ statuses: 2.0.2
+ transitivePeerDependencies:
+ - supports-color
+
find-up@4.1.0:
dependencies:
locate-path: 5.0.0
@@ -12354,6 +12913,10 @@ snapshots:
hasown: 2.0.3
mime-types: 2.1.35
+ forwarded@0.2.0: {}
+
+ fresh@2.0.0: {}
+
fsevents@2.3.3:
optional: true
@@ -12372,6 +12935,8 @@ snapshots:
generator-function@2.0.1: {}
+ generic-pool@3.9.0: {}
+
genlayer-js@1.1.7(bufferutil@4.1.0)(eslint@9.39.4)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.3.6):
dependencies:
eslint-plugin-import: 2.32.0(eslint@9.39.4)
@@ -12515,6 +13080,14 @@ snapshots:
hono@4.12.15: {}
+ http-errors@2.0.1:
+ dependencies:
+ depd: 2.0.0
+ inherits: 2.0.4
+ setprototypeof: 1.2.0
+ statuses: 2.0.2
+ toidentifier: 1.0.1
+
humanize-ms@1.2.1:
dependencies:
ms: 2.1.3
@@ -12523,6 +13096,10 @@ snapshots:
iceberg-js@0.8.1: {}
+ iconv-lite@0.7.2:
+ dependencies:
+ safer-buffer: 2.1.2
+
idb-keyval@6.2.1: {}
idb-keyval@6.2.2: {}
@@ -12548,6 +13125,10 @@ snapshots:
hasown: 2.0.3
side-channel: 1.1.0
+ ip-address@10.2.0: {}
+
+ ipaddr.js@1.9.1: {}
+
iron-webcrypto@1.2.1: {}
is-arguments@1.2.0:
@@ -12632,6 +13213,8 @@ snapshots:
is-number@7.0.0: {}
+ is-promise@4.0.0: {}
+
is-regex@1.2.1:
dependencies:
call-bound: 1.0.4
@@ -12778,6 +13361,10 @@ snapshots:
json-schema-traverse@0.4.1: {}
+ json-schema-traverse@1.0.0: {}
+
+ json-schema-typed@8.0.2: {}
+
json-stable-stringify-without-jsonify@1.0.1: {}
json-stable-stringify@1.3.0:
@@ -12886,12 +13473,25 @@ snapshots:
math-intrinsics@1.1.0: {}
+ mcp-handler@1.1.0(@modelcontextprotocol/sdk@1.29.0(zod@3.25.76))(next@16.2.4(react-dom@19.2.4(react@19.2.4))(react@19.2.4)):
+ dependencies:
+ '@modelcontextprotocol/sdk': 1.29.0(zod@3.25.76)
+ chalk: 5.6.2
+ commander: 11.1.0
+ redis: 4.7.1
+ optionalDependencies:
+ next: 16.2.4(@babel/core@7.29.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
+
md5@2.3.0:
dependencies:
charenc: 0.0.2
crypt: 0.0.2
is-buffer: 1.1.6
+ media-typer@1.1.0: {}
+
+ merge-descriptors@2.0.0: {}
+
merge2@1.4.1: {}
micro-ftch@0.3.1: {}
@@ -12903,10 +13503,16 @@ snapshots:
mime-db@1.52.0: {}
+ mime-db@1.54.0: {}
+
mime-types@2.1.35:
dependencies:
mime-db: 1.52.0
+ mime-types@3.0.2:
+ dependencies:
+ mime-db: 1.54.0
+
minimatch@10.2.5:
dependencies:
brace-expansion: 5.0.5
@@ -12933,6 +13539,8 @@ snapshots:
natural-compare@1.4.0: {}
+ negotiator@1.0.0: {}
+
next@16.2.4(@babel/core@7.29.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4):
dependencies:
'@next/env': 16.2.4
@@ -13043,6 +13651,10 @@ snapshots:
on-exit-leak-free@2.1.2: {}
+ on-finished@2.4.1:
+ dependencies:
+ ee-first: 1.1.1
+
once@1.4.0:
dependencies:
wrappy: 1.0.2
@@ -13210,12 +13822,16 @@ snapshots:
dependencies:
callsites: 3.1.0
+ parseurl@1.3.3: {}
+
path-exists@4.0.0: {}
path-key@3.1.1: {}
path-parse@1.0.7: {}
+ path-to-regexp@8.4.2: {}
+
pathe@1.1.2: {}
pathval@2.0.1: {}
@@ -13293,11 +13909,13 @@ snapshots:
sonic-boom: 2.8.0
thread-stream: 0.15.2
+ pkce-challenge@5.0.1: {}
+
pngjs@5.0.0: {}
pony-cause@2.1.11: {}
- porto@0.2.35(@tanstack/react-query@5.100.6(react@19.2.4))(@types/react@19.2.14)(@wagmi/core@2.22.1(@tanstack/query-core@5.100.6)(@types/react@19.2.14)(react@19.2.4)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@19.2.4))(viem@2.47.12(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@4.3.6)))(react@19.2.4)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@19.2.4))(viem@2.47.12(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@4.3.6))(wagmi@2.19.5(@tanstack/query-core@5.100.6)(@tanstack/react-query@5.100.6(react@19.2.4))(@types/react@19.2.14)(bufferutil@4.1.0)(react@19.2.4)(typescript@5.9.3)(utf-8-validate@6.0.6)(viem@2.47.12(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@4.3.6))(zod@3.25.76)):
+ porto@0.2.35(@tanstack/react-query@5.100.6(react@19.2.4))(@types/react@19.2.14)(@wagmi/core@2.22.1(@tanstack/query-core@5.100.6)(@types/react@19.2.14)(react@19.2.4)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@19.2.4))(viem@2.47.12(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@4.3.6)))(react@19.2.4)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@19.2.4))(viem@2.47.12(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@4.3.6))(wagmi@2.19.5(@tanstack/query-core@5.100.6)(@tanstack/react-query@5.100.6(react@19.2.4))(@types/react@19.2.14)(@upstash/redis@1.38.0)(bufferutil@4.1.0)(react@19.2.4)(typescript@5.9.3)(utf-8-validate@6.0.6)(viem@2.47.12(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@4.3.6))(zod@3.25.76)):
dependencies:
'@wagmi/core': 2.22.1(@tanstack/query-core@5.100.6)(@types/react@19.2.14)(react@19.2.4)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@19.2.4))(viem@2.47.12(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@4.3.6))
hono: 4.12.15
@@ -13311,7 +13929,7 @@ snapshots:
'@tanstack/react-query': 5.100.6(react@19.2.4)
react: 19.2.4
typescript: 5.9.3
- wagmi: 2.19.5(@tanstack/query-core@5.100.6)(@tanstack/react-query@5.100.6(react@19.2.4))(@types/react@19.2.14)(bufferutil@4.1.0)(react@19.2.4)(typescript@5.9.3)(utf-8-validate@6.0.6)(viem@2.47.12(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@4.3.6))(zod@4.3.6)
+ wagmi: 2.19.5(@tanstack/query-core@5.100.6)(@tanstack/react-query@5.100.6(react@19.2.4))(@types/react@19.2.14)(@upstash/redis@1.38.0)(bufferutil@4.1.0)(react@19.2.4)(typescript@5.9.3)(utf-8-validate@6.0.6)(viem@2.47.12(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@4.3.6))(zod@4.3.6)
transitivePeerDependencies:
- '@types/react'
- immer
@@ -13367,6 +13985,11 @@ snapshots:
object-assign: 4.1.1
react-is: 16.13.1
+ proxy-addr@2.0.7:
+ dependencies:
+ forwarded: 0.2.0
+ ipaddr.js: 1.9.1
+
proxy-compare@2.6.0: {}
proxy-compare@3.0.1: {}
@@ -13393,6 +14016,10 @@ snapshots:
pngjs: 5.0.0
yargs: 15.4.1
+ qs@6.15.1:
+ dependencies:
+ side-channel: 1.1.0
+
query-string@7.1.3:
dependencies:
decode-uri-component: 0.2.2
@@ -13406,6 +14033,15 @@ snapshots:
radix3@1.1.2: {}
+ range-parser@1.2.1: {}
+
+ raw-body@3.0.2:
+ dependencies:
+ bytes: 3.1.2
+ http-errors: 2.0.1
+ iconv-lite: 0.7.2
+ unpipe: 1.0.0
+
react-aria@3.48.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4):
dependencies:
'@internationalized/date': 3.12.1
@@ -13475,6 +14111,15 @@ snapshots:
real-require@0.2.0: {}
+ redis@4.7.1:
+ dependencies:
+ '@redis/bloom': 1.2.0(@redis/client@1.6.1)
+ '@redis/client': 1.6.1
+ '@redis/graph': 1.1.1(@redis/client@1.6.1)
+ '@redis/json': 1.0.7(@redis/client@1.6.1)
+ '@redis/search': 1.2.0(@redis/client@1.6.1)
+ '@redis/time-series': 1.1.0(@redis/client@1.6.1)
+
reflect.getprototypeof@1.0.10:
dependencies:
call-bind: 1.0.9
@@ -13497,6 +14142,8 @@ snapshots:
require-directory@2.1.1: {}
+ require-from-string@2.0.2: {}
+
require-main-filename@2.0.0: {}
resolve-from@4.0.0: {}
@@ -13545,6 +14192,16 @@ snapshots:
'@rollup/rollup-win32-x64-msvc': 4.60.2
fsevents: 2.3.3
+ router@2.2.0:
+ dependencies:
+ debug: 4.4.3
+ depd: 2.0.0
+ is-promise: 4.0.0
+ parseurl: 1.3.3
+ path-to-regexp: 8.4.2
+ transitivePeerDependencies:
+ - supports-color
+
rpc-websockets@9.3.8:
dependencies:
'@swc/helpers': 0.5.21
@@ -13587,6 +14244,8 @@ snapshots:
safe-stable-stringify@2.5.0: {}
+ safer-buffer@2.1.2: {}
+
scheduler@0.27.0: {}
secure-json-parse@2.7.0: {}
@@ -13599,6 +14258,31 @@ snapshots:
semver@7.7.4: {}
+ send@1.2.1:
+ dependencies:
+ debug: 4.4.3
+ encodeurl: 2.0.0
+ escape-html: 1.0.3
+ etag: 1.8.1
+ fresh: 2.0.0
+ http-errors: 2.0.1
+ mime-types: 3.0.2
+ ms: 2.1.3
+ on-finished: 2.4.1
+ range-parser: 1.2.1
+ statuses: 2.0.2
+ transitivePeerDependencies:
+ - supports-color
+
+ serve-static@2.2.1:
+ dependencies:
+ encodeurl: 2.0.0
+ escape-html: 1.0.3
+ parseurl: 1.3.3
+ send: 1.2.1
+ transitivePeerDependencies:
+ - supports-color
+
set-blocking@2.0.0: {}
set-cookie-parser@2.7.2: {}
@@ -13625,6 +14309,8 @@ snapshots:
es-errors: 1.3.0
es-object-atoms: 1.1.1
+ setprototypeof@1.2.0: {}
+
sha.js@2.4.12:
dependencies:
inherits: 2.0.4
@@ -13755,6 +14441,8 @@ snapshots:
stackback@0.0.2: {}
+ statuses@2.0.2: {}
+
std-env@3.10.0: {}
stop-iteration-iterator@1.1.0:
@@ -13915,6 +14603,8 @@ snapshots:
dependencies:
is-number: 7.0.0
+ toidentifier@1.0.1: {}
+
toml@3.0.0: {}
tr46@0.0.3: {}
@@ -13947,6 +14637,12 @@ snapshots:
dependencies:
prelude-ls: 1.2.1
+ type-is@2.0.1:
+ dependencies:
+ content-type: 1.0.5
+ media-typer: 1.1.0
+ mime-types: 3.0.2
+
typed-array-buffer@1.0.3:
dependencies:
call-bound: 1.0.4
@@ -14024,6 +14720,8 @@ snapshots:
undici-types@8.2.0: {}
+ unpipe@1.0.0: {}
+
unrs-resolver@1.11.1:
dependencies:
napi-postinstall: 0.3.4
@@ -14048,7 +14746,7 @@ snapshots:
'@unrs/resolver-binding-win32-ia32-msvc': 1.11.1
'@unrs/resolver-binding-win32-x64-msvc': 1.11.1
- unstorage@1.17.5(idb-keyval@6.2.2):
+ unstorage@1.17.5(@upstash/redis@1.38.0)(idb-keyval@6.2.2):
dependencies:
anymatch: 3.1.3
chokidar: 5.0.0
@@ -14059,6 +14757,7 @@ snapshots:
ofetch: 1.5.1
ufo: 1.6.3
optionalDependencies:
+ '@upstash/redis': 1.38.0
idb-keyval: 6.2.2
update-browserslist-db@1.2.3(browserslist@4.28.2):
@@ -14124,6 +14823,8 @@ snapshots:
'@types/react': 19.2.14
react: 19.2.4
+ vary@1.1.2: {}
+
viem@2.23.2(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@3.25.76):
dependencies:
'@noble/curves': 1.8.1
@@ -14424,10 +15125,10 @@ snapshots:
- supports-color
- terser
- wagmi@2.19.5(@tanstack/query-core@5.100.6)(@tanstack/react-query@5.100.6(react@19.2.4))(@types/react@19.2.14)(bufferutil@4.1.0)(react@19.2.4)(typescript@5.9.3)(utf-8-validate@6.0.6)(viem@2.47.12(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@4.3.6))(zod@4.3.6):
+ wagmi@2.19.5(@tanstack/query-core@5.100.6)(@tanstack/react-query@5.100.6(react@19.2.4))(@types/react@19.2.14)(@upstash/redis@1.38.0)(bufferutil@4.1.0)(react@19.2.4)(typescript@5.9.3)(utf-8-validate@6.0.6)(viem@2.47.12(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@4.3.6))(zod@4.3.6):
dependencies:
'@tanstack/react-query': 5.100.6(react@19.2.4)
- '@wagmi/connectors': 6.2.0(@tanstack/react-query@5.100.6(react@19.2.4))(@types/react@19.2.14)(@wagmi/core@2.22.1(@tanstack/query-core@5.100.6)(@types/react@19.2.14)(react@19.2.4)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@19.2.4))(viem@2.47.12(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@4.3.6)))(bufferutil@4.1.0)(react@19.2.4)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@19.2.4))(utf-8-validate@6.0.6)(viem@2.47.12(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@4.3.6))(wagmi@2.19.5(@tanstack/query-core@5.100.6)(@tanstack/react-query@5.100.6(react@19.2.4))(@types/react@19.2.14)(bufferutil@4.1.0)(react@19.2.4)(typescript@5.9.3)(utf-8-validate@6.0.6)(viem@2.47.12(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@4.3.6))(zod@3.25.76))(zod@3.25.76)
+ '@wagmi/connectors': 6.2.0(@tanstack/react-query@5.100.6(react@19.2.4))(@types/react@19.2.14)(@upstash/redis@1.38.0)(@wagmi/core@2.22.1(@tanstack/query-core@5.100.6)(@types/react@19.2.14)(react@19.2.4)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@19.2.4))(viem@2.47.12(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@4.3.6)))(bufferutil@4.1.0)(react@19.2.4)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@19.2.4))(utf-8-validate@6.0.6)(viem@2.47.12(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@4.3.6))(wagmi@2.19.5(@tanstack/query-core@5.100.6)(@tanstack/react-query@5.100.6(react@19.2.4))(@types/react@19.2.14)(@upstash/redis@1.38.0)(bufferutil@4.1.0)(react@19.2.4)(typescript@5.9.3)(utf-8-validate@6.0.6)(viem@2.47.12(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@4.3.6))(zod@3.25.76))(zod@3.25.76)
'@wagmi/core': 2.22.1(@tanstack/query-core@5.100.6)(@types/react@19.2.14)(react@19.2.4)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@19.2.4))(viem@2.47.12(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@4.3.6))
react: 19.2.4
use-sync-external-store: 1.4.0(react@19.2.4)
@@ -14580,7 +15281,7 @@ snapshots:
bufferutil: 4.1.0
utf-8-validate: 6.0.6
- x402@0.7.3(@solana/sysvars@6.9.0(typescript@5.9.3))(@tanstack/query-core@5.100.6)(@tanstack/react-query@5.100.6(react@19.2.4))(@types/react@19.2.14)(bufferutil@4.1.0)(react@19.2.4)(typescript@5.9.3)(utf-8-validate@6.0.6):
+ x402@0.7.3(@solana/sysvars@6.9.0(typescript@5.9.3))(@tanstack/query-core@5.100.6)(@tanstack/react-query@5.100.6(react@19.2.4))(@types/react@19.2.14)(@upstash/redis@1.38.0)(bufferutil@4.1.0)(react@19.2.4)(typescript@5.9.3)(utf-8-validate@6.0.6):
dependencies:
'@scure/base': 1.2.6
'@solana-program/compute-budget': 0.11.0(@solana/kit@5.5.1(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6))
@@ -14593,7 +15294,7 @@ snapshots:
'@wallet-standard/base': 1.1.0
'@wallet-standard/features': 1.1.0
viem: 2.47.12(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@3.25.76)
- wagmi: 2.19.5(@tanstack/query-core@5.100.6)(@tanstack/react-query@5.100.6(react@19.2.4))(@types/react@19.2.14)(bufferutil@4.1.0)(react@19.2.4)(typescript@5.9.3)(utf-8-validate@6.0.6)(viem@2.47.12(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@4.3.6))(zod@4.3.6)
+ wagmi: 2.19.5(@tanstack/query-core@5.100.6)(@tanstack/react-query@5.100.6(react@19.2.4))(@types/react@19.2.14)(@upstash/redis@1.38.0)(bufferutil@4.1.0)(react@19.2.4)(typescript@5.9.3)(utf-8-validate@6.0.6)(viem@2.47.12(bufferutil@4.1.0)(typescript@5.9.3)(utf-8-validate@6.0.6)(zod@4.3.6))(zod@4.3.6)
zod: 3.25.76
transitivePeerDependencies:
- '@azure/app-configuration'
@@ -14641,6 +15342,8 @@ snapshots:
yallist@3.1.1: {}
+ yallist@4.0.0: {}
+
yargs-parser@18.1.3:
dependencies:
camelcase: 5.3.1
@@ -14662,9 +15365,13 @@ snapshots:
yocto-queue@0.1.0: {}
- zod-validation-error@4.0.2(zod@4.3.6):
+ zod-to-json-schema@3.25.2(zod@3.25.76):
dependencies:
- zod: 4.3.6
+ zod: 3.25.76
+
+ zod-validation-error@4.0.2(zod@3.25.76):
+ dependencies:
+ zod: 3.25.76
zod@3.22.4: {}
diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml
index e0a208f..c323ae2 100644
--- a/pnpm-workspace.yaml
+++ b/pnpm-workspace.yaml
@@ -2,3 +2,4 @@ packages:
- "relayer"
- "frontend"
- "packages/*"
+ - "apps/*"