diff --git a/README.md b/README.md index 62ec448..6f6e890 100644 --- a/README.md +++ b/README.md @@ -28,6 +28,7 @@ This Turborepo includes the following example applications: | Name | Description | Path & Links | | --- | --- | --- | +| `@shelby-protocol/ai-image-generation` | Shelby AI image generation example | [`apps/ai-image-generation`](./apps/ai-image-generation) | | `@shelby-protocol/cross-chain-accounts` | Shelby cross chain accounts example | [`apps/cross-chain-accounts`](./apps/cross-chain-accounts) | | `@shelby-protocol/download-example` | An example app to demonstrate downloading blobs using the Shelby SDK | [`apps/download-blob`](./apps/download-blob) | | `@shelby-protocol/upload-example` | An example app to demonstrate uploading blobs using the Shelby SDK | [`apps/upload-blob`](./apps/upload-blob) | diff --git a/apps/ai-image-generation/.env.example b/apps/ai-image-generation/.env.example new file mode 100644 index 0000000..84faa15 --- /dev/null +++ b/apps/ai-image-generation/.env.example @@ -0,0 +1,15 @@ +# Shelby Protocol Configuration +NEXT_PUBLIC_SHELBY_API_URL=https://api.shelbynet.shelby.xyz + +# AI Service API Keys +OPENAI_API_KEY=your_openai_api_key_here + +# Shelby API Key for enhanced rate limits +NEXT_PUBLIC_SHELBY_API_KEY=your_shelby_api_key_here + +# Aptos API Key for enhanced rate limits +NEXT_PUBLIC_APTOS_API_KEY=your_aptos_api_key_here + + +NEXT_PUBLIC_SPONSOR_ACCOUNT_ADDRESS=0x... +NEXT_PUBLIC_SPONSOR_PRIVATE_KEY=ed25519-priv-0x... diff --git a/apps/ai-image-generation/README.md b/apps/ai-image-generation/README.md new file mode 100644 index 0000000..dcb73f5 --- /dev/null +++ b/apps/ai-image-generation/README.md @@ -0,0 +1,151 @@ +# Shelby AI Image Generation - Decentralized AI Artifact Registry + +This demo demonstrates how **Shelby can serve as the data and provenance layer for AI systems**. Every AI inference run produces verifiable, on-chain artifacts that are immutable, attributable, and accessible via Shelby's decentralized network. + +Unlike traditional cloud storage solutions, this application showcases Shelby as a **"Web3 S3" specifically designed for AI workloads** - where AI-generated content lives permanently on-chain with cryptographic provenance, not trapped in centralized systems. + +## 🧠 What Makes This AI-Focused + +This isn't just file storage - it's an **AI artifact registry** that demonstrates: + +### **AI Provenance & Authenticity** + +- Every generated image is cryptographically tied to your Aptos wallet address +- Immutable storage ensures AI outputs can't be tampered with after creation +- Full traceability from prompt → model → output → storage + +### **Decentralized AI Infrastructure** + +- **Compute Layer**: OpenAI DALL-E 3 (external AI service) +- **Storage Layer**: Shelby protocol (decentralized, incentivized network) +- **Provenance Layer**: Aptos blockchain (immutable ownership records) + +### **AI-Specific Metadata** + +Each generated image includes structured metadata stored alongside: + +```json +{ + "prompt": "A futuristic city at sunset", + "engine": "openai", + "model": "dall-e-3", + "createdAt": 1698765432000, + "creator": "0x1234...abcd", + "image": { + "url": "https://api.shelbynet.shelby.xyz/shelby/v1/blobs/0x745...123/images/...." + }, + "blobName": "images/A futuristic city at sunset_82p.png" +} +``` + +## 🏗️ Architecture: Modular Compute-Storage Separation + +``` +┌─────────────────┐ ┌──────────────────┐ ┌─────────────────────┐ +│ AI Compute │ │ Shelby Storage │ │ Aptos Blockchain │ +│ (DALL-E 3) │───▶│ (Artifacts) │───▶│ (Provenance) │ +│ │ │ │ │ │ +│ • Image Gen │ │ • Immutable │ │ • Ownership │ +│ • Model Runs │ │ • Decentralized │ │ • Commitments │ +│ • Stateless │ │ • Auditable │ │ • Expiration │ +└─────────────────┘ └──────────────────┘ └─────────────────────┘ +``` + +This architecture proves that **AI models can run anywhere, but their data, artifacts, and provenance should live in a decentralized, verifiable layer**. + +## 🔥 Why This Matters for AI + +### **Verifiable AI Outputs** + +- Prove ownership of AI-generated content +- Combat deepfakes with cryptographic authenticity +- Enable model output traceability and reproducibility + +### **Open AI Infrastructure** + +- AI artifacts aren't locked in vendor silos (AWS, Google Cloud) +- Decentralized storage with incentivized uptime guarantees +- Permissionless access to AI-generated data + +### **Future-Ready for Verifiable Compute** + +- Today: External AI + Shelby storage +- Tomorrow: Shelby-native AI compute in TEEs with zero-knowledge proofs +- Same artifact storage pattern scales to fully decentralized AI pipelines + +## Getting Started + +### Prerequisites + +- `node` and `pnpm` +- Shelby and Aptos API keys. For best performance, you are encouraged to generate an API key so your app will not hit the rate limit. + - Head to [Geomi](https://geomi.dev/) + - Generate an API key for `shelbynet` and add it to the `.env` file as `NEXT_PUBLIC_SHELBY_API_KEY=` + - Generate an API key for `devnet` and add it to the `.env` file as `NEXT_PUBLIC_APTOS_API_KEY=` +- OpenAI API Key. Head to [OpenAI Platform](https://platform.openai.com/api-keys) to generate an API Key and add it to the `.env` file as `OPENAI_API_KEY=` + +Create an `.env` file by copying the `.env.example` file and fill out the required variables. + +```bash +cp .env.example .env +``` + +Then install dependencies and run the dapp locally + +```bash +pnpm install +pnpm run dev +``` + +Open [http://localhost:3001](http://localhost:3001) with your browser to see the result. + +## 🛠️ Technical Implementation + +### **AI Generation Pipeline** + +```typescript +// 1. Generate image via OpenAI API +const imageBuffer = await generateImage(prompt); + +// 2. Create cryptographic commitments +const commitments = await generateCommitments(provider, imageBuffer); + +// 3. Register blob on Aptos blockchain +const payload = ShelbyBlobClient.createRegisterBlobPayload({ + account: account.address, + blobName: `images/${blobName}.png`, + blobMerkleRoot: commitments.blob_merkle_root, + // ... other metadata +}); + +// 4. Upload to Shelby's decentralized network +await shelbyClient.rpc.putBlob({ + account: account.address, + blobName: imageName, + blobData: new Uint8Array(imageBuffer), +}); +``` + +### **Key Features** + +- **Cross-chain wallet support** (Aptos native + Solana + EVM wallets via sponsored transactions) +- **Metadata co-location** (JSON metadata stored alongside each image) +- **Gallery view** (All your AI artifacts in one place) +- **Explorer integration** (Direct links to Shelby blob explorer) + +### **What You'll Experience:** + +1. **Connect Wallet** - Your Aptos address becomes your AI identity +2. **Generate Image** - AI creates content using your prompt +3. **Store on Shelby** - Image + metadata uploaded to decentralized storage +4. **Verify Provenance** - View your artifacts in Shelby Explorer with full ownership proof + +## 🔮 What This Proves About Shelby + +| **Capability** | **Demonstrated** | +| ------------------------------ | ------------------------------------------------------ | +| **AI Artifact Storage** | ✅ Images stored & served decentralized | +| **Replaces S3/IPFS for AI** | ✅ Fast reads, permanent storage, verifiable ownership | +| **Compute-Storage Separation** | ✅ Model runs anywhere, results live on Shelby | +| **Provenance & Authenticity** | ✅ Each blob cryptographically tied to creator | +| **Future-Ready Architecture** | ✅ Same pattern works for Shelby-native compute | diff --git a/apps/ai-image-generation/app/api/generate-image/route.ts b/apps/ai-image-generation/app/api/generate-image/route.ts new file mode 100644 index 0000000..0a8e06f --- /dev/null +++ b/apps/ai-image-generation/app/api/generate-image/route.ts @@ -0,0 +1,58 @@ +import { type NextRequest, NextResponse } from "next/server"; +import OpenAI from "openai"; + +const OPENAI_API_KEY = process.env.OPENAI_API_KEY ?? ""; + +const openaiClient = new OpenAI({ + apiKey: OPENAI_API_KEY, +}); + +async function genWithOpenAI(prompt: string): Promise { + if (!OPENAI_API_KEY) throw new Error("Set OPENAI_API_KEY"); + + const response = await openaiClient.images.generate({ + model: "dall-e-3", + prompt: prompt, + size: "1024x1024", + response_format: "b64_json", + n: 1, + }); + + if (!response.data) { + throw new Error("No image data received from OpenAI"); + } + + const imageData = response.data[0]; + + if (!imageData.b64_json) { + throw new Error("No base64 image data received from OpenAI"); + } + + return Buffer.from(imageData.b64_json, "base64"); +} + +export async function POST(request: NextRequest) { + try { + const body = await request.json(); + const prompt = String(body?.prompt || ""); + + if (!prompt) { + return NextResponse.json({ error: "prompt required" }, { status: 400 }); + } + + const imageBuffer = await genWithOpenAI(prompt); + + return new NextResponse(new Uint8Array(imageBuffer), { + headers: { + "Content-Type": "image/png", + "Content-Length": imageBuffer.length.toString(), + }, + }); + } catch (e: unknown) { + console.error(e); + return NextResponse.json( + { error: e instanceof Error ? e.message : "generation failed" }, + { status: 500 }, + ); + } +} diff --git a/apps/ai-image-generation/app/favicon.ico b/apps/ai-image-generation/app/favicon.ico new file mode 100644 index 0000000..718d6fe Binary files /dev/null and b/apps/ai-image-generation/app/favicon.ico differ diff --git a/apps/ai-image-generation/app/fonts/GeistMonoVF.woff b/apps/ai-image-generation/app/fonts/GeistMonoVF.woff new file mode 100644 index 0000000..f2ae185 Binary files /dev/null and b/apps/ai-image-generation/app/fonts/GeistMonoVF.woff differ diff --git a/apps/ai-image-generation/app/fonts/GeistVF.woff b/apps/ai-image-generation/app/fonts/GeistVF.woff new file mode 100644 index 0000000..1b62daa Binary files /dev/null and b/apps/ai-image-generation/app/fonts/GeistVF.woff differ diff --git a/apps/ai-image-generation/app/globals.css b/apps/ai-image-generation/app/globals.css new file mode 100644 index 0000000..200400d --- /dev/null +++ b/apps/ai-image-generation/app/globals.css @@ -0,0 +1 @@ +@import "@shelby-protocol/ui/globals.css"; diff --git a/apps/ai-image-generation/app/layout.tsx b/apps/ai-image-generation/app/layout.tsx new file mode 100644 index 0000000..ccab10f --- /dev/null +++ b/apps/ai-image-generation/app/layout.tsx @@ -0,0 +1,36 @@ +import { Toaster } from "@shelby-protocol/ui/components"; +import localFont from "next/font/local"; +import { WalletProvider } from "@/components/WalletProvider"; +import "./globals.css"; +import type { Metadata } from "next"; + +const geistSans = localFont({ + src: "./fonts/GeistVF.woff", + variable: "--font-geist-sans", +}); +const geistMono = localFont({ + src: "./fonts/GeistMonoVF.woff", + variable: "--font-geist-mono", +}); + +export const metadata: Metadata = { + title: "Shelby AI Image Generation Example", + description: "An AI image generation example using Shelby protocol", +}; + +export default function RootLayout({ + children, +}: Readonly<{ + children: React.ReactNode; +}>) { + return ( + + + + {children} + + + + + ); +} diff --git a/apps/ai-image-generation/app/page.tsx b/apps/ai-image-generation/app/page.tsx new file mode 100644 index 0000000..54828bd --- /dev/null +++ b/apps/ai-image-generation/app/page.tsx @@ -0,0 +1,35 @@ +"use client"; + +import { useState } from "react"; +import { GeneratedImages } from "@/components/GeneratedImages"; +import { Header } from "@/components/Header"; +import { ImageGenerator } from "@/components/ImageGenerator"; + +export default function Home() { + const [refreshTrigger, setRefreshTrigger] = useState(0); + + const handleImageGenerated = () => { + setRefreshTrigger((prev) => prev + 1); + }; + + return ( +
+
+ + {/* Main Content */} +
+
+
+

AI Image Generation

+

+ Generate images using AI and store them on the Shelby protocol +

+
+ + + +
+
+
+ ); +} diff --git a/apps/ai-image-generation/components.json b/apps/ai-image-generation/components.json new file mode 100644 index 0000000..e1847ad --- /dev/null +++ b/apps/ai-image-generation/components.json @@ -0,0 +1,20 @@ +{ + "$schema": "https://ui.shadcn.com/schema.json", + "style": "new-york", + "rsc": true, + "tsx": true, + "tailwind": { + "config": "", + "css": "../../packages/ui/src/styles/globals.css", + "baseColor": "neutral", + "cssVariables": true + }, + "iconLibrary": "lucide", + "aliases": { + "components": "@/components", + "hooks": "@/hooks", + "lib": "@/lib", + "utils": "@shelby-protocol/ui/lib/utils", + "ui": "@shelby-protocol/ui/components" + } +} diff --git a/apps/ai-image-generation/components/GeneratedImages.tsx b/apps/ai-image-generation/components/GeneratedImages.tsx new file mode 100644 index 0000000..810c768 --- /dev/null +++ b/apps/ai-image-generation/components/GeneratedImages.tsx @@ -0,0 +1,138 @@ +"use client"; + +import { useWallet } from "@aptos-labs/wallet-adapter-react"; +import type { BlobMetadata } from "@shelby-protocol/sdk/node"; +import { + Card, + CardContent, + CardHeader, + CardTitle, +} from "@shelby-protocol/ui/components/card"; +import Image from "next/image"; +import { useEffect, useState } from "react"; +import { getShelbyClient } from "@/utils/client"; + +const extractFileName = (blobName: string): string => { + return blobName.substring(66); +}; + +export const GeneratedImages = ({ + refreshTrigger, +}: { + refreshTrigger: number; +}) => { + const { account } = useWallet(); + const [images, setImages] = useState([]); + const [loading, setLoading] = useState(false); + + // biome-ignore lint/correctness/useExhaustiveDependencies: refreshTrigger is intentionally used to trigger re-fetch + useEffect(() => { + if (!account) { + setImages([]); + return; + } + + const fetchBlobs = async () => { + setLoading(true); + try { + const allBlobs = await getShelbyClient().coordination.getAccountBlobs({ + account: account.address, + }); + + // Filter to only show PNG images + const pngBlobs = allBlobs.filter((blob) => + extractFileName(blob.name).endsWith(".png"), + ); + + setImages(pngBlobs); + } catch (error) { + console.error("Failed to fetch blobs:", error); + } finally { + setLoading(false); + } + }; + + fetchBlobs(); + }, [account, refreshTrigger]); + + if (!account) { + return ( + + + + Your Generated Images + + + +

+ Connect your wallet to view your generated images +

+
+
+ ); + } + + return ( + + + + Your Generated Images + + + + {loading ? ( +

+ Loading your images... +

+ ) : images.length === 0 ? ( +

+ No images generated yet. Create your first AI image above! +

+ ) : ( +
+ {images.map((item) => ( +
+
+ {item.name} { + console.error("Image failed to load:", e); + }} + /> +
+ +
+ ))} +
+ )} +
+
+ ); +}; diff --git a/apps/ai-image-generation/components/Header.tsx b/apps/ai-image-generation/components/Header.tsx new file mode 100644 index 0000000..44f964d --- /dev/null +++ b/apps/ai-image-generation/components/Header.tsx @@ -0,0 +1,36 @@ +import { useWallet } from "@aptos-labs/wallet-adapter-react"; +import { Button } from "@shelby-protocol/ui/components/button"; +import { XChainWalletSelector } from "@shelby-protocol/ui/components/x-chain-wallet-selector"; + +export const Header = () => { + const { connected, account } = useWallet(); + + const onMintShelbyUsd = () => { + if (!account) { + return; + } + window.open( + `https://docs.shelby.xyz/apis/faucet/shelbyusd?address=${account.address}`, + "_blank", + ); + }; + + return ( +
+
+

+ Shelby AI Image Generation +

+
+
+ + +
+
+ ); +}; diff --git a/apps/ai-image-generation/components/ImageGenerator.tsx b/apps/ai-image-generation/components/ImageGenerator.tsx new file mode 100644 index 0000000..a259662 --- /dev/null +++ b/apps/ai-image-generation/components/ImageGenerator.tsx @@ -0,0 +1,137 @@ +"use client"; + +import { + type AccountAddress, + useWallet, +} from "@aptos-labs/wallet-adapter-react"; +import { Button } from "@shelby-protocol/ui/components/button"; +import { + Card, + CardContent, + CardHeader, + CardTitle, +} from "@shelby-protocol/ui/components/card"; +import { Input } from "@shelby-protocol/ui/components/input"; +import { toast } from "@shelby-protocol/ui/components/sonner"; +import { useState } from "react"; +import { useGenerateImage } from "@/hooks/useGenerateImage"; +import { useUploadImageToShelby } from "@/hooks/useUploadImageToShelby"; + +interface GeneratedImage { + ok: boolean; + prompt: string; + engine: string; + blob: { + url: string; + account: AccountAddress; + blobName: string; + }; + metadata?: { + url: string; + account: AccountAddress; + blobName: string; + }; +} + +interface ImageGeneratorProps { + onImageGenerated?: (image: GeneratedImage) => void; +} + +export const ImageGenerator = ({ onImageGenerated }: ImageGeneratorProps) => { + const { account, connected } = useWallet(); + const [prompt, setPrompt] = useState(""); + + const { generateImage, isGenerating } = useGenerateImage(); + const { uploadImageToShelby, uploadMetadataToShelby, isUploading } = + useUploadImageToShelby(); + + const isProcessing = isGenerating || isUploading; + + const handleGenerate = async () => { + if (!prompt.trim()) { + toast.error("Please enter a prompt"); + return; + } + + if (!connected || !account) { + toast.error("Please connect your wallet first"); + return; + } + + try { + // Step 1: Generate the image using AI + toast.loading("Generating image..."); + const imageBuffer = await generateImage(prompt); + + const blobName = `${prompt.slice(0, 50)}_${Math.random() + .toString(36) + .slice(2)}`; + + // Step 2: Upload to Shelby using connected wallet + toast.loading("Uploading image to Shelby..."); + const uploadedImage = await uploadImageToShelby(imageBuffer, blobName); + + toast.loading("Uploading metadata to Shelby..."); + const metadata = { + prompt, + engine: "openai", + model: "dall-e-3", + createdAt: new Date().toISOString(), + creator: uploadedImage.account.toString(), + image: uploadedImage, + }; + const uploadedMetadata = await uploadMetadataToShelby(metadata, blobName); + + const result: GeneratedImage = { + ok: true, + prompt, + engine: "openai", + blob: uploadedImage, + metadata: uploadedMetadata, + }; + + onImageGenerated?.(result); + toast.success("Image generated and uploaded successfully!"); + } catch (error) { + console.error("Generation error:", error); + toast.error( + error instanceof Error ? error.message : "Failed to generate image", + ); + } finally { + toast.dismiss(); + } + }; + + return ( + + + + AI Image Generator + + + +
+ setPrompt(e.target.value)} + onKeyDown={(e) => + e.key === "Enter" && !isProcessing && handleGenerate() + } + disabled={isProcessing} + /> + +
+
+
+ ); +}; diff --git a/apps/ai-image-generation/components/WalletProvider.tsx b/apps/ai-image-generation/components/WalletProvider.tsx new file mode 100644 index 0000000..c83f750 --- /dev/null +++ b/apps/ai-image-generation/components/WalletProvider.tsx @@ -0,0 +1,29 @@ +"use client"; + +import { setupAutomaticEthereumWalletDerivation } from "@aptos-labs/derived-wallet-ethereum"; +import { setupAutomaticSolanaWalletDerivation } from "@aptos-labs/derived-wallet-solana"; +import { Network } from "@aptos-labs/ts-sdk"; +import { AptosWalletAdapterProvider } from "@aptos-labs/wallet-adapter-react"; +import type { PropsWithChildren } from "react"; + +setupAutomaticSolanaWalletDerivation({ defaultNetwork: Network.SHELBYNET }); +setupAutomaticEthereumWalletDerivation({ defaultNetwork: Network.SHELBYNET }); + +export const WalletProvider = ({ children }: PropsWithChildren) => { + return ( + { + console.log("error", error); + }} + > + {children} + + ); +}; diff --git a/apps/ai-image-generation/hooks/useGenerateImage.tsx b/apps/ai-image-generation/hooks/useGenerateImage.tsx new file mode 100644 index 0000000..56e2a97 --- /dev/null +++ b/apps/ai-image-generation/hooks/useGenerateImage.tsx @@ -0,0 +1,49 @@ +import { useCallback, useState } from "react"; + +interface UseGenerateImageReturn { + generateImage: (prompt: string) => Promise; + isGenerating: boolean; + error: string | null; +} + +export const useGenerateImage = (): UseGenerateImageReturn => { + const [isGenerating, setIsGenerating] = useState(false); + const [error, setError] = useState(null); + + const generateImage = useCallback(async (prompt: string): Promise => { + setIsGenerating(true); + setError(null); + + try { + const response = await fetch("/api/generate-image", { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ prompt }), + }); + + if (!response.ok) { + const errorData = await response.json(); + throw new Error(errorData.error || "Image generation failed"); + } + + // Get the image as a buffer + const arrayBuffer = await response.arrayBuffer(); + return Buffer.from(arrayBuffer); + } catch (err) { + const errorMessage = + err instanceof Error ? err.message : "Image generation failed"; + setError(errorMessage); + throw err; + } finally { + setIsGenerating(false); + } + }, []); + + return { + generateImage, + isGenerating, + error, + }; +}; diff --git a/apps/ai-image-generation/hooks/useSubmitCommitmentTransaction.tsx b/apps/ai-image-generation/hooks/useSubmitCommitmentTransaction.tsx new file mode 100644 index 0000000..7e33879 --- /dev/null +++ b/apps/ai-image-generation/hooks/useSubmitCommitmentTransaction.tsx @@ -0,0 +1,79 @@ +import { + Account, + Ed25519PrivateKey, + type InputGenerateTransactionPayloadData, + PrivateKey, + PrivateKeyVariants, +} from "@aptos-labs/ts-sdk"; +import { + type InputTransactionData, + useWallet, +} from "@aptos-labs/wallet-adapter-react"; +import { useCallback } from "react"; +import { getAptosClient, getShelbyClient } from "@/utils/client"; + +export const useSubmitCommitmentTransaction = () => { + const { account, wallet, signAndSubmitTransaction, signTransaction } = + useWallet(); + + const submitTransaction = useCallback( + async (payload: InputGenerateTransactionPayloadData) => { + if (!account || !wallet) { + throw new Error("Wallet not connected"); + } + + // Handle Aptos native wallets + if (wallet.isAptosNativeWallet) { + const transaction: InputTransactionData = { + data: payload, + }; + const transactionSubmitted = + await signAndSubmitTransaction(transaction); + + await getAptosClient().waitForTransaction({ + transactionHash: transactionSubmitted.hash, + }); + } else { + // Handle cross-chain wallets with sponsored transactions + const privateKey = new Ed25519PrivateKey( + PrivateKey.formatPrivateKey( + process.env.NEXT_PUBLIC_SPONSOR_PRIVATE_KEY as string, + PrivateKeyVariants.Ed25519, + ), + ); + const sponsorAccount = Account.fromPrivateKey({ privateKey }); + + const rawTransaction = + await getShelbyClient().aptos.transaction.build.simple({ + sender: account.address, + data: payload, + withFeePayer: true, + }); + + const walletSignedTransaction = await signTransaction({ + transactionOrPayload: rawTransaction, + }); + + const sponsorAuthenticator = + getShelbyClient().aptos.transaction.signAsFeePayer({ + signer: sponsorAccount, + transaction: rawTransaction, + }); + + const transactionSubmitted = + await getShelbyClient().aptos.transaction.submit.simple({ + transaction: rawTransaction, + senderAuthenticator: walletSignedTransaction.authenticator, + feePayerAuthenticator: sponsorAuthenticator, + }); + + await getShelbyClient().aptos.waitForTransaction({ + transactionHash: transactionSubmitted.hash, + }); + } + }, + [account, wallet, signAndSubmitTransaction, signTransaction], + ); + + return { submitTransaction }; +}; diff --git a/apps/ai-image-generation/hooks/useUploadImageToShelby.tsx b/apps/ai-image-generation/hooks/useUploadImageToShelby.tsx new file mode 100644 index 0000000..ac611ae --- /dev/null +++ b/apps/ai-image-generation/hooks/useUploadImageToShelby.tsx @@ -0,0 +1,175 @@ +import type { AccountAddress } from "@aptos-labs/ts-sdk"; +import { type AccountInfo, useWallet } from "@aptos-labs/wallet-adapter-react"; +import { + ClayErasureCodingProvider, + expectedTotalChunksets, + generateCommitments, + ShelbyBlobClient, +} from "@shelby-protocol/sdk/browser"; +import { useCallback, useState } from "react"; +import { getShelbyClient } from "@/utils/client"; +import { useSubmitCommitmentTransaction } from "./useSubmitCommitmentTransaction"; + +interface UseUploadImageToShelbyReturn { + uploadImageToShelby: ( + imageBuffer: Buffer, + imageName: string, + ) => Promise<{ + url: string; + account: AccountAddress; + blobName: string; + }>; + uploadMetadataToShelby: ( + metadata: Record, + metadataName: string, + ) => Promise<{ + url: string; + account: AccountAddress; + blobName: string; + }>; + isUploading: boolean; + error: string | null; +} + +export const useUploadImageToShelby = (): UseUploadImageToShelbyReturn => { + const [isUploading, setIsUploading] = useState(false); + const [error, setError] = useState(null); + const { account, wallet } = useWallet(); + const { submitTransaction } = useSubmitCommitmentTransaction(); + + const uploadImageToShelby = useCallback( + async (imageBuffer: Buffer, blobName: string) => { + if (!account || !wallet) { + throw new Error("Wallet not connected"); + } + + setIsUploading(true); + setError(null); + + try { + const blobNameImage = `images/${blobName}.png`; + + // 1. Generate commitments for the image + const payload = await generateCommitment( + imageBuffer, + blobNameImage, + account, + ); + + // 4. Submit transaction to register the blob on chain + await submitTransaction(payload); + + // 5. Upload the actual file data to Shelby RPC + const response = await uploadToShlebyRPC( + new Uint8Array(imageBuffer), + blobNameImage, + account, + ); + + return response; + } catch (err) { + const errorMessage = + err instanceof Error ? err.message : "Upload failed"; + setError(errorMessage); + throw err; + } finally { + setIsUploading(false); + } + }, + [account, wallet, submitTransaction], + ); + + const uploadMetadataToShelby = useCallback( + async (metadata: Record, metadataName: string) => { + if (!account || !wallet) { + throw new Error("Wallet not connected"); + } + + setIsUploading(true); + setError(null); + + try { + const blobNameJson = `metadata/${metadataName}.json`; + + // 1. Generate commitments for the image + const payload = await generateCommitment( + Buffer.from(JSON.stringify(metadata, null, 2)), + blobNameJson, + account, + ); + + // 4. Submit transaction to register the blob on chain + await submitTransaction(payload); + + // 5. Upload the actual file data to Shelby RPC + const response = await uploadToShlebyRPC( + new Uint8Array(Buffer.from(JSON.stringify(metadata, null, 2))), + blobNameJson, + account, + ); + + return response; + } catch (err) { + const errorMessage = + err instanceof Error ? err.message : "Upload failed"; + setError(errorMessage); + throw err; + } finally { + setIsUploading(false); + } + }, + [account, wallet, submitTransaction], + ); + + return { + uploadImageToShelby, + uploadMetadataToShelby, + isUploading, + error, + }; +}; + +const generateCommitment = async ( + data: Buffer, + blobName: string, + account: AccountInfo, +) => { + const provider = await ClayErasureCodingProvider.create(); + // 1. Generate commitments for the image + const commitments = await generateCommitments(provider, data); + + // 3. Create the transaction payload + const payload = ShelbyBlobClient.createRegisterBlobPayload({ + account: account.address, + blobName: blobName, + blobMerkleRoot: commitments.blob_merkle_root, + numChunksets: expectedTotalChunksets(commitments.raw_data_size), + expirationMicros: (1000 * 60 * 60 * 24 * 30 + Date.now()) * 1000, // 30 days from now + blobSize: commitments.raw_data_size, + }); + + return payload; +}; + +const uploadToShlebyRPC = async ( + data: Uint8Array, + blobName: string, + account: AccountInfo, +) => { + await getShelbyClient().rpc.putBlob({ + account: account.address, + blobName, + blobData: new Uint8Array(data), + }); + + // 6. Return the public URL and metadata + const url = `https://api.shelbynet.shelby.xyz/shelby/v1/blobs/${account.address.toString()}/${encodeURIComponent( + blobName, + )}`; + + return { + url, + account: account.address, + blobName, + }; +}; diff --git a/apps/ai-image-generation/next-env.d.ts b/apps/ai-image-generation/next-env.d.ts new file mode 100644 index 0000000..830fb59 --- /dev/null +++ b/apps/ai-image-generation/next-env.d.ts @@ -0,0 +1,6 @@ +/// +/// +/// + +// NOTE: This file should not be edited +// see https://nextjs.org/docs/app/api-reference/config/typescript for more information. diff --git a/apps/ai-image-generation/next.config.ts b/apps/ai-image-generation/next.config.ts new file mode 100644 index 0000000..b549b83 --- /dev/null +++ b/apps/ai-image-generation/next.config.ts @@ -0,0 +1,18 @@ +import type { NextConfig } from "next"; + +const nextConfig: NextConfig = { + transpilePackages: ["@shelby-protocol/ui"], + typedRoutes: true, + images: { + remotePatterns: [ + { + protocol: "https", + hostname: "api.shelbynet.shelby.xyz", + port: "", + pathname: "/**", + }, + ], + }, +}; + +export default nextConfig; diff --git a/apps/ai-image-generation/package.json b/apps/ai-image-generation/package.json new file mode 100644 index 0000000..32d6026 --- /dev/null +++ b/apps/ai-image-generation/package.json @@ -0,0 +1,33 @@ +{ + "name": "@shelby-protocol/ai-image-generation", + "version": "0.0.0", + "description": "Shelby AI image generation example", + "private": true, + "scripts": { + "dev": "next dev --turbopack --port 3001", + "build": "next build", + "start": "next start", + "lint": "biome check .", + "fmt": "biome check . --write" + }, + "dependencies": { + "@aptos-labs/derived-wallet-ethereum": "^0.8.0", + "@aptos-labs/derived-wallet-solana": "^0.8.0", + "@aptos-labs/ts-sdk": "^5.1.1", + "@aptos-labs/wallet-adapter-react": "^7.1.0", + "@shelby-protocol/sdk": "0.0.4", + "@shelby-protocol/ui": "workspace:*", + "dotenv": "^16.6.1", + "form-data": "^4.0.4", + "next": "^15.5.0", + "node-fetch": "^3.3.2", + "openai": "^6.6.0", + "react": "^18.3.1", + "react-dom": "^18.3.1" + }, + "devDependencies": { + "@types/node": "^22.15.3", + "@types/react": "^18.3.12", + "@types/react-dom": "^18.3.1" + } +} diff --git a/apps/ai-image-generation/pnpm-lock.yaml b/apps/ai-image-generation/pnpm-lock.yaml new file mode 100644 index 0000000..5ea224b --- /dev/null +++ b/apps/ai-image-generation/pnpm-lock.yaml @@ -0,0 +1,1496 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: + dependencies: + '@aptos-labs/ts-sdk': + specifier: ^5.1.1 + version: 5.1.1(got@11.8.6) + '@shelby-protocol/sdk': + specifier: ^0.0.4 + version: 0.0.4(@aptos-labs/ts-sdk@5.1.1(got@11.8.6)) + dotenv: + specifier: ^16.4.5 + version: 16.6.1 + express: + specifier: ^4.19.2 + version: 4.21.2 + form-data: + specifier: ^4.0.0 + version: 4.0.4 + node-fetch: + specifier: ^3.3.2 + version: 3.3.2 + devDependencies: + '@types/express': + specifier: ^4.17.21 + version: 4.17.23 + '@types/node': + specifier: ^20.11.25 + version: 20.19.22 + tsx: + specifier: ^4.19.2 + version: 4.20.6 + typescript: + specifier: ^5.6.3 + version: 5.9.3 + +packages: + + '@aptos-labs/aptos-cli@1.0.2': + resolution: {integrity: sha512-PYPsd0Kk3ynkxNfe3S4fanI3DiUICCoh4ibQderbvjPFL5A0oK6F4lPEO2t0MDsQySTk2t4vh99Xjy6Bd9y+aQ==} + hasBin: true + + '@aptos-labs/aptos-client@2.0.0': + resolution: {integrity: sha512-A23T3zTCRXEKURodp00dkadVtIrhWjC9uo08dRDBkh69OhCnBAxkENmUy/rcBarfLoFr60nRWt7cBkc8wxr1mg==} + engines: {node: '>=20.0.0'} + peerDependencies: + got: ^11.8.6 + + '@aptos-labs/ts-sdk@5.1.1': + resolution: {integrity: sha512-2QhQzcbVa9o7uQTIfjAGFkWFgddg+R/Ftbo39ZPbNrs1L2b+oMhdB9/uZ0QStN25/h8HPCvH4h4aaPus2jabXQ==} + engines: {node: '>=20.0.0'} + + '@esbuild/aix-ppc64@0.25.11': + resolution: {integrity: sha512-Xt1dOL13m8u0WE8iplx9Ibbm+hFAO0GsU2P34UNoDGvZYkY8ifSiy6Zuc1lYxfG7svWE2fzqCUmFp5HCn51gJg==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] + + '@esbuild/android-arm64@0.25.11': + resolution: {integrity: sha512-9slpyFBc4FPPz48+f6jyiXOx/Y4v34TUeDDXJpZqAWQn/08lKGeD8aDp9TMn9jDz2CiEuHwfhRmGBvpnd/PWIQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] + + '@esbuild/android-arm@0.25.11': + resolution: {integrity: sha512-uoa7dU+Dt3HYsethkJ1k6Z9YdcHjTrSb5NUy66ZfZaSV8hEYGD5ZHbEMXnqLFlbBflLsl89Zke7CAdDJ4JI+Gg==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] + + '@esbuild/android-x64@0.25.11': + resolution: {integrity: sha512-Sgiab4xBjPU1QoPEIqS3Xx+R2lezu0LKIEcYe6pftr56PqPygbB7+szVnzoShbx64MUupqoE0KyRlN7gezbl8g==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] + + '@esbuild/darwin-arm64@0.25.11': + resolution: {integrity: sha512-VekY0PBCukppoQrycFxUqkCojnTQhdec0vevUL/EDOCnXd9LKWqD/bHwMPzigIJXPhC59Vd1WFIL57SKs2mg4w==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] + + '@esbuild/darwin-x64@0.25.11': + resolution: {integrity: sha512-+hfp3yfBalNEpTGp9loYgbknjR695HkqtY3d3/JjSRUyPg/xd6q+mQqIb5qdywnDxRZykIHs3axEqU6l1+oWEQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] + + '@esbuild/freebsd-arm64@0.25.11': + resolution: {integrity: sha512-CmKjrnayyTJF2eVuO//uSjl/K3KsMIeYeyN7FyDBjsR3lnSJHaXlVoAK8DZa7lXWChbuOk7NjAc7ygAwrnPBhA==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] + + '@esbuild/freebsd-x64@0.25.11': + resolution: {integrity: sha512-Dyq+5oscTJvMaYPvW3x3FLpi2+gSZTCE/1ffdwuM6G1ARang/mb3jvjxs0mw6n3Lsw84ocfo9CrNMqc5lTfGOw==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] + + '@esbuild/linux-arm64@0.25.11': + resolution: {integrity: sha512-Qr8AzcplUhGvdyUF08A1kHU3Vr2O88xxP0Tm8GcdVOUm25XYcMPp2YqSVHbLuXzYQMf9Bh/iKx7YPqECs6ffLA==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] + + '@esbuild/linux-arm@0.25.11': + resolution: {integrity: sha512-TBMv6B4kCfrGJ8cUPo7vd6NECZH/8hPpBHHlYI3qzoYFvWu2AdTvZNuU/7hsbKWqu/COU7NIK12dHAAqBLLXgw==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] + + '@esbuild/linux-ia32@0.25.11': + resolution: {integrity: sha512-TmnJg8BMGPehs5JKrCLqyWTVAvielc615jbkOirATQvWWB1NMXY77oLMzsUjRLa0+ngecEmDGqt5jiDC6bfvOw==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] + + '@esbuild/linux-loong64@0.25.11': + resolution: {integrity: sha512-DIGXL2+gvDaXlaq8xruNXUJdT5tF+SBbJQKbWy/0J7OhU8gOHOzKmGIlfTTl6nHaCOoipxQbuJi7O++ldrxgMw==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] + + '@esbuild/linux-mips64el@0.25.11': + resolution: {integrity: sha512-Osx1nALUJu4pU43o9OyjSCXokFkFbyzjXb6VhGIJZQ5JZi8ylCQ9/LFagolPsHtgw6himDSyb5ETSfmp4rpiKQ==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] + + '@esbuild/linux-ppc64@0.25.11': + resolution: {integrity: sha512-nbLFgsQQEsBa8XSgSTSlrnBSrpoWh7ioFDUmwo158gIm5NNP+17IYmNWzaIzWmgCxq56vfr34xGkOcZ7jX6CPw==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] + + '@esbuild/linux-riscv64@0.25.11': + resolution: {integrity: sha512-HfyAmqZi9uBAbgKYP1yGuI7tSREXwIb438q0nqvlpxAOs3XnZ8RsisRfmVsgV486NdjD7Mw2UrFSw51lzUk1ww==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] + + '@esbuild/linux-s390x@0.25.11': + resolution: {integrity: sha512-HjLqVgSSYnVXRisyfmzsH6mXqyvj0SA7pG5g+9W7ESgwA70AXYNpfKBqh1KbTxmQVaYxpzA/SvlB9oclGPbApw==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] + + '@esbuild/linux-x64@0.25.11': + resolution: {integrity: sha512-HSFAT4+WYjIhrHxKBwGmOOSpphjYkcswF449j6EjsjbinTZbp8PJtjsVK1XFJStdzXdy/jaddAep2FGY+wyFAQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] + + '@esbuild/netbsd-arm64@0.25.11': + resolution: {integrity: sha512-hr9Oxj1Fa4r04dNpWr3P8QKVVsjQhqrMSUzZzf+LZcYjZNqhA3IAfPQdEh1FLVUJSiu6sgAwp3OmwBfbFgG2Xg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [netbsd] + + '@esbuild/netbsd-x64@0.25.11': + resolution: {integrity: sha512-u7tKA+qbzBydyj0vgpu+5h5AeudxOAGncb8N6C9Kh1N4n7wU1Xw1JDApsRjpShRpXRQlJLb9wY28ELpwdPcZ7A==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] + + '@esbuild/openbsd-arm64@0.25.11': + resolution: {integrity: sha512-Qq6YHhayieor3DxFOoYM1q0q1uMFYb7cSpLD2qzDSvK1NAvqFi8Xgivv0cFC6J+hWVw2teCYltyy9/m/14ryHg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + + '@esbuild/openbsd-x64@0.25.11': + resolution: {integrity: sha512-CN+7c++kkbrckTOz5hrehxWN7uIhFFlmS/hqziSFVWpAzpWrQoAG4chH+nN3Be+Kzv/uuo7zhX716x3Sn2Jduw==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] + + '@esbuild/openharmony-arm64@0.25.11': + resolution: {integrity: sha512-rOREuNIQgaiR+9QuNkbkxubbp8MSO9rONmwP5nKncnWJ9v5jQ4JxFnLu4zDSRPf3x4u+2VN4pM4RdyIzDty/wQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openharmony] + + '@esbuild/sunos-x64@0.25.11': + resolution: {integrity: sha512-nq2xdYaWxyg9DcIyXkZhcYulC6pQ2FuCgem3LI92IwMgIZ69KHeY8T4Y88pcwoLIjbed8n36CyKoYRDygNSGhA==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + + '@esbuild/win32-arm64@0.25.11': + resolution: {integrity: sha512-3XxECOWJq1qMZ3MN8srCJ/QfoLpL+VaxD/WfNRm1O3B4+AZ/BnLVgFbUV3eiRYDMXetciH16dwPbbHqwe1uU0Q==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + + '@esbuild/win32-ia32@0.25.11': + resolution: {integrity: sha512-3ukss6gb9XZ8TlRyJlgLn17ecsK4NSQTmdIXRASVsiS2sQ6zPPZklNJT5GR5tE/MUarymmy8kCEf5xPCNCqVOA==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] + + '@esbuild/win32-x64@0.25.11': + resolution: {integrity: sha512-D7Hpz6A2L4hzsRpPaCYkQnGOotdUpDzSGRIv9I+1ITdHROSFUWW95ZPZWQmGka1Fg7W3zFJowyn9WGwMJ0+KPA==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + + '@graphql-typed-document-node/core@3.2.0': + resolution: {integrity: sha512-mB9oAsNCm9aM3/SOv4YtBMqZbYj10R7dkq8byBqxGY/ncFwhf2oQzMV+LCRlWoDSEBJ3COiR1yeDvMtsoOsuFQ==} + peerDependencies: + graphql: ^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 + + '@noble/curves@1.9.7': + resolution: {integrity: sha512-gbKGcRUYIjA3/zCCNaWDciTMFI0dCkvou3TL8Zmy5Nc7sJ47a0jtOeZoTaMxkuqRo9cRhjOdZJXegxYE5FN/xw==} + engines: {node: ^14.21.3 || >=16} + + '@noble/hashes@1.8.0': + resolution: {integrity: sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==} + engines: {node: ^14.21.3 || >=16} + + '@scure/base@1.2.6': + resolution: {integrity: sha512-g/nm5FgUa//MCj1gV09zTJTaM6KBAHqLN907YVQqf7zC49+DcO4B1so4ZX07Ef10Twr6nuqYEH9GEggFXA4Fmg==} + + '@scure/bip32@1.7.0': + resolution: {integrity: sha512-E4FFX/N3f4B80AKWp5dP6ow+flD1LQZo/w8UnLGYZO674jS6YnYeepycOOksv+vLPSpgN35wgKgy+ybfTb2SMw==} + + '@scure/bip39@1.6.0': + resolution: {integrity: sha512-+lF0BbLiJNwVlev4eKelw1WWLaiKXw7sSl8T6FvBlWkdX+94aGJ4o8XjUdlyhTCjd8c+B3KT3JfS8P0bLRNU6A==} + + '@shelby-protocol/clay-codes@0.0.1': + resolution: {integrity: sha512-Y4CC/Dg9yMLehPWeLTbuyFmHVy9rrwrcF/ARRQADBDSVFLz8ITPeT6iscA8Y9D7R5RAvBCWkI7X7qijGg2IDVA==} + + '@shelby-protocol/reed-solomon@0.0.1': + resolution: {integrity: sha512-Li+7Uj2LLe247YppsZDbZdnyhxGAmTBOx14QPvLNJzeq1lCmjeV7X2BtRzlvyElsvymQQI/WWcKIHu21ysCR9g==} + + '@shelby-protocol/sdk@0.0.4': + resolution: {integrity: sha512-qSqwMro7e84DLkqQ3cp/JhMaxQ3mz1SquTV07yVS13bpeY7Yv2CC1R1YLZugR8Z0trctFg6suEcuHsp8olVRtw==} + peerDependencies: + '@aptos-labs/ts-sdk': ^2.0.1 || ^3.0.0 || ^4.0.0 || ^5.0.0 + + '@sindresorhus/is@4.6.0': + resolution: {integrity: sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==} + engines: {node: '>=10'} + + '@szmarczak/http-timer@4.0.6': + resolution: {integrity: sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==} + engines: {node: '>=10'} + + '@types/body-parser@1.19.6': + resolution: {integrity: sha512-HLFeCYgz89uk22N5Qg3dvGvsv46B8GLvKKo1zKG4NybA8U2DiEO3w9lqGg29t/tfLRJpJ6iQxnVw4OnB7MoM9g==} + + '@types/cacheable-request@6.0.3': + resolution: {integrity: sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw==} + + '@types/connect@3.4.38': + resolution: {integrity: sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==} + + '@types/express-serve-static-core@4.19.7': + resolution: {integrity: sha512-FvPtiIf1LfhzsaIXhv/PHan/2FeQBbtBDtfX2QfvPxdUelMDEckK08SM6nqo1MIZY3RUlfA+HV8+hFUSio78qg==} + + '@types/express@4.17.23': + resolution: {integrity: sha512-Crp6WY9aTYP3qPi2wGDo9iUe/rceX01UMhnF1jmwDcKCFM6cx7YhGP/Mpr3y9AASpfHixIG0E6azCcL5OcDHsQ==} + + '@types/http-cache-semantics@4.0.4': + resolution: {integrity: sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA==} + + '@types/http-errors@2.0.5': + resolution: {integrity: sha512-r8Tayk8HJnX0FztbZN7oVqGccWgw98T/0neJphO91KkmOzug1KkofZURD4UaD5uH8AqcFLfdPErnBod0u71/qg==} + + '@types/keyv@3.1.4': + resolution: {integrity: sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==} + + '@types/mime@1.3.5': + resolution: {integrity: sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==} + + '@types/node@20.19.22': + resolution: {integrity: sha512-hRnu+5qggKDSyWHlnmThnUqg62l29Aj/6vcYgUaSFL9oc7DVjeWEQN3PRgdSc6F8d9QRMWkf36CLMch1Do/+RQ==} + + '@types/qs@6.14.0': + resolution: {integrity: sha512-eOunJqu0K1923aExK6y8p6fsihYEn/BYuQ4g0CxAAgFc4b/ZLN4CrsRZ55srTdqoiLzU2B2evC+apEIxprEzkQ==} + + '@types/range-parser@1.2.7': + resolution: {integrity: sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==} + + '@types/responselike@1.0.3': + resolution: {integrity: sha512-H/+L+UkTV33uf49PH5pCAUBVPNj2nDBXTN+qS1dOwyyg24l3CcicicCA7ca+HMvJBZcFgl5r8e+RR6elsb4Lyw==} + + '@types/send@0.17.5': + resolution: {integrity: sha512-z6F2D3cOStZvuk2SaP6YrwkNO65iTZcwA2ZkSABegdkAh/lf+Aa/YQndZVfmEXT5vgAp6zv06VQ3ejSVjAny4w==} + + '@types/send@1.2.0': + resolution: {integrity: sha512-zBF6vZJn1IaMpg3xUF25VK3gd3l8zwE0ZLRX7dsQyQi+jp4E8mMDJNGDYnYse+bQhYwWERTxVwHpi3dMOq7RKQ==} + + '@types/serve-static@1.15.9': + resolution: {integrity: sha512-dOTIuqpWLyl3BBXU3maNQsS4A3zuuoYRNIvYSxxhebPfXg2mzWQEPne/nlJ37yOse6uGgR386uTpdsx4D0QZWA==} + + accepts@1.3.8: + resolution: {integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==} + engines: {node: '>= 0.6'} + + array-flatten@1.1.1: + resolution: {integrity: sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==} + + asynckit@0.4.0: + resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} + + body-parser@1.20.3: + resolution: {integrity: sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==} + engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} + + bytes@3.1.2: + resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} + engines: {node: '>= 0.8'} + + cacheable-lookup@5.0.4: + resolution: {integrity: sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA==} + engines: {node: '>=10.6.0'} + + cacheable-request@7.0.4: + resolution: {integrity: sha512-v+p6ongsrp0yTGbJXjgxPow2+DL93DASP4kXCDKb8/bwRtt9OEF3whggkkDkGNzgcWy2XaF4a8nZglC7uElscg==} + engines: {node: '>=8'} + + call-bind-apply-helpers@1.0.2: + resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} + engines: {node: '>= 0.4'} + + call-bound@1.0.4: + resolution: {integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==} + engines: {node: '>= 0.4'} + + clone-response@1.0.3: + resolution: {integrity: sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==} + + combined-stream@1.0.8: + resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} + engines: {node: '>= 0.8'} + + commander@12.1.0: + resolution: {integrity: sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==} + engines: {node: '>=18'} + + content-disposition@0.5.4: + resolution: {integrity: sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==} + engines: {node: '>= 0.6'} + + content-type@1.0.5: + resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==} + engines: {node: '>= 0.6'} + + cookie-signature@1.0.6: + resolution: {integrity: sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==} + + cookie@0.7.1: + resolution: {integrity: sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==} + engines: {node: '>= 0.6'} + + data-uri-to-buffer@4.0.1: + resolution: {integrity: sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==} + engines: {node: '>= 12'} + + debug@2.6.9: + resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + decompress-response@6.0.0: + resolution: {integrity: sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==} + engines: {node: '>=10'} + + defer-to-connect@2.0.1: + resolution: {integrity: sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==} + engines: {node: '>=10'} + + delayed-stream@1.0.0: + 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'} + + destroy@1.2.0: + resolution: {integrity: sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==} + engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} + + dotenv@16.6.1: + resolution: {integrity: sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==} + engines: {node: '>=12'} + + dunder-proto@1.0.1: + resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} + engines: {node: '>= 0.4'} + + ee-first@1.1.1: + resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} + + encodeurl@1.0.2: + resolution: {integrity: sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==} + engines: {node: '>= 0.8'} + + 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==} + + es-define-property@1.0.1: + resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} + engines: {node: '>= 0.4'} + + es-errors@1.3.0: + resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} + engines: {node: '>= 0.4'} + + es-object-atoms@1.1.1: + resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==} + engines: {node: '>= 0.4'} + + es-set-tostringtag@2.1.0: + resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==} + engines: {node: '>= 0.4'} + + esbuild@0.25.11: + resolution: {integrity: sha512-KohQwyzrKTQmhXDW1PjCv3Tyspn9n5GcY2RTDqeORIdIJY8yKIF7sTSopFmn/wpMPW4rdPXI0UE5LJLuq3bx0Q==} + engines: {node: '>=18'} + hasBin: true + + escape-html@1.0.3: + resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==} + + etag@1.8.1: + resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==} + engines: {node: '>= 0.6'} + + eventemitter3@5.0.1: + resolution: {integrity: sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==} + + express@4.21.2: + resolution: {integrity: sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==} + engines: {node: '>= 0.10.0'} + + fetch-blob@3.2.0: + resolution: {integrity: sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==} + engines: {node: ^12.20 || >= 14.13} + + finalhandler@1.3.1: + resolution: {integrity: sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==} + engines: {node: '>= 0.8'} + + form-data@4.0.4: + resolution: {integrity: sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==} + engines: {node: '>= 6'} + + formdata-polyfill@4.0.10: + resolution: {integrity: sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==} + engines: {node: '>=12.20.0'} + + forwarded@0.2.0: + resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==} + engines: {node: '>= 0.6'} + + fresh@0.5.2: + resolution: {integrity: sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==} + engines: {node: '>= 0.6'} + + fsevents@2.3.3: + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + + function-bind@1.1.2: + resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + + get-intrinsic@1.3.0: + resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} + engines: {node: '>= 0.4'} + + get-proto@1.0.1: + resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} + engines: {node: '>= 0.4'} + + get-stream@5.2.0: + resolution: {integrity: sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==} + engines: {node: '>=8'} + + get-tsconfig@4.12.0: + resolution: {integrity: sha512-LScr2aNr2FbjAjZh2C6X6BxRx1/x+aTDExct/xyq2XKbYOiG5c0aK7pMsSuyc0brz3ibr/lbQiHD9jzt4lccJw==} + + gopd@1.2.0: + resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} + engines: {node: '>= 0.4'} + + got@11.8.6: + resolution: {integrity: sha512-6tfZ91bOr7bOXnK7PRDCGBLa1H4U080YHNaAQ2KsMGlLEzRbk44nsZF2E1IeRc3vtJHPVbKCYgdFbaGO2ljd8g==} + engines: {node: '>=10.19.0'} + + graphql-request@7.3.1: + resolution: {integrity: sha512-GdinBsBVYrWzwEvOlzadrV5j8mdOc9ZT8In9QyRIZaxbhkTL08j35yNbPp96jAacYzjeD/hKKy2E2RGI7c7Yug==} + peerDependencies: + graphql: 14 - 16 + + graphql-tag@2.12.6: + resolution: {integrity: sha512-FdSNcu2QQcWnM2VNvSCCDCVS5PpPqpzgFT8+GXzqJuoDd0CBncxCY278u4mhRO7tMgo2JjgJA5aZ+nWSQ/Z+xg==} + engines: {node: '>=10'} + peerDependencies: + graphql: ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0 + + graphql@16.11.0: + resolution: {integrity: sha512-mS1lbMsxgQj6hge1XZ6p7GPhbrtFwUFYi3wRzXAC/FmYnyXMTvvI3td3rjmQ2u8ewXueaSvRPWaEcgVVOT9Jnw==} + engines: {node: ^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0} + + has-symbols@1.1.0: + resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} + engines: {node: '>= 0.4'} + + has-tostringtag@1.0.2: + resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} + engines: {node: '>= 0.4'} + + hasown@2.0.2: + resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} + engines: {node: '>= 0.4'} + + http-cache-semantics@4.2.0: + resolution: {integrity: sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ==} + + http-errors@2.0.0: + resolution: {integrity: sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==} + engines: {node: '>= 0.8'} + + http2-wrapper@1.0.3: + resolution: {integrity: sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg==} + engines: {node: '>=10.19.0'} + + iconv-lite@0.4.24: + resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==} + engines: {node: '>=0.10.0'} + + inherits@2.0.4: + resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + + ipaddr.js@1.9.1: + resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==} + engines: {node: '>= 0.10'} + + js-base64@3.7.8: + resolution: {integrity: sha512-hNngCeKxIUQiEUN3GPJOkz4wF/YvdUdbNL9hsBcMQTkKzboD7T/q3OYOuuPZLUE6dBxSGpwhk5mwuDud7JVAow==} + + json-buffer@3.0.1: + resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} + + jwt-decode@4.0.0: + resolution: {integrity: sha512-+KJGIyHgkGuIq3IEBNftfhW/LfWhXUIY6OmyVWjliu5KH1y0fw7VQ8YndE2O4qZdMSd9SqbnC8GOcZEy0Om7sA==} + engines: {node: '>=18'} + + keyv@4.5.4: + resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} + + lowercase-keys@2.0.0: + resolution: {integrity: sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==} + engines: {node: '>=8'} + + math-intrinsics@1.1.0: + resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} + engines: {node: '>= 0.4'} + + media-typer@0.3.0: + resolution: {integrity: sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==} + engines: {node: '>= 0.6'} + + merge-descriptors@1.0.3: + resolution: {integrity: sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==} + + methods@1.1.2: + resolution: {integrity: sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==} + engines: {node: '>= 0.6'} + + mime-db@1.52.0: + resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} + engines: {node: '>= 0.6'} + + mime-types@2.1.35: + resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} + engines: {node: '>= 0.6'} + + mime@1.6.0: + resolution: {integrity: sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==} + engines: {node: '>=4'} + hasBin: true + + mimic-response@1.0.1: + resolution: {integrity: sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==} + engines: {node: '>=4'} + + mimic-response@3.1.0: + resolution: {integrity: sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==} + engines: {node: '>=10'} + + ms@2.0.0: + resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==} + + ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + + negotiator@0.6.3: + resolution: {integrity: sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==} + engines: {node: '>= 0.6'} + + node-domexception@1.0.0: + resolution: {integrity: sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==} + engines: {node: '>=10.5.0'} + deprecated: Use your platform's native DOMException instead + + node-fetch@3.3.2: + resolution: {integrity: sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + normalize-url@6.1.0: + resolution: {integrity: sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==} + engines: {node: '>=10'} + + object-inspect@1.13.4: + resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==} + engines: {node: '>= 0.4'} + + 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==} + + p-cancelable@2.1.1: + resolution: {integrity: sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==} + engines: {node: '>=8'} + + parseurl@1.3.3: + resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==} + engines: {node: '>= 0.8'} + + path-to-regexp@0.1.12: + resolution: {integrity: sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==} + + poseidon-lite@0.2.1: + resolution: {integrity: sha512-xIr+G6HeYfOhCuswdqcFpSX47SPhm0EpisWJ6h7fHlWwaVIvH3dLnejpatrtw6Xc6HaLrpq05y7VRfvDmDGIog==} + + proxy-addr@2.0.7: + resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==} + engines: {node: '>= 0.10'} + + pump@3.0.3: + resolution: {integrity: sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA==} + + qs@6.13.0: + resolution: {integrity: sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==} + engines: {node: '>=0.6'} + + quick-lru@5.1.1: + resolution: {integrity: sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==} + engines: {node: '>=10'} + + range-parser@1.2.1: + resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==} + engines: {node: '>= 0.6'} + + raw-body@2.5.2: + resolution: {integrity: sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==} + engines: {node: '>= 0.8'} + + resolve-alpn@1.2.1: + resolution: {integrity: sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==} + + resolve-pkg-maps@1.0.0: + resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} + + responselike@2.0.1: + resolution: {integrity: sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw==} + + safe-buffer@5.2.1: + resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} + + safer-buffer@2.1.2: + resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} + + send@0.19.0: + resolution: {integrity: sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==} + engines: {node: '>= 0.8.0'} + + serve-static@1.16.2: + resolution: {integrity: sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==} + engines: {node: '>= 0.8.0'} + + setprototypeof@1.2.0: + resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} + + side-channel-list@1.0.0: + resolution: {integrity: sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==} + engines: {node: '>= 0.4'} + + side-channel-map@1.0.1: + resolution: {integrity: sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==} + engines: {node: '>= 0.4'} + + side-channel-weakmap@1.0.2: + resolution: {integrity: sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==} + engines: {node: '>= 0.4'} + + side-channel@1.1.0: + resolution: {integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==} + engines: {node: '>= 0.4'} + + statuses@2.0.1: + resolution: {integrity: sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==} + engines: {node: '>= 0.8'} + + toidentifier@1.0.1: + resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} + engines: {node: '>=0.6'} + + tslib@2.8.1: + resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + + tsx@4.20.6: + resolution: {integrity: sha512-ytQKuwgmrrkDTFP4LjR0ToE2nqgy886GpvRSpU0JAnrdBYppuY5rLkRUYPU1yCryb24SsKBTL/hlDQAEFVwtZg==} + engines: {node: '>=18.0.0'} + hasBin: true + + type-is@1.6.18: + resolution: {integrity: sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==} + engines: {node: '>= 0.6'} + + typescript@5.9.3: + resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} + engines: {node: '>=14.17'} + hasBin: true + + undici-types@6.21.0: + resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} + + unpipe@1.0.0: + resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} + engines: {node: '>= 0.8'} + + utils-merge@1.0.1: + resolution: {integrity: sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==} + engines: {node: '>= 0.4.0'} + + vary@1.1.2: + resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} + engines: {node: '>= 0.8'} + + web-streams-polyfill@3.3.3: + resolution: {integrity: sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==} + engines: {node: '>= 8'} + + wrappy@1.0.2: + resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + + zod@3.25.76: + resolution: {integrity: sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==} + +snapshots: + + '@aptos-labs/aptos-cli@1.0.2': + dependencies: + commander: 12.1.0 + + '@aptos-labs/aptos-client@2.0.0(got@11.8.6)': + dependencies: + got: 11.8.6 + + '@aptos-labs/ts-sdk@5.1.1(got@11.8.6)': + dependencies: + '@aptos-labs/aptos-cli': 1.0.2 + '@aptos-labs/aptos-client': 2.0.0(got@11.8.6) + '@noble/curves': 1.9.7 + '@noble/hashes': 1.8.0 + '@scure/bip32': 1.7.0 + '@scure/bip39': 1.6.0 + eventemitter3: 5.0.1 + form-data: 4.0.4 + js-base64: 3.7.8 + jwt-decode: 4.0.0 + poseidon-lite: 0.2.1 + transitivePeerDependencies: + - got + + '@esbuild/aix-ppc64@0.25.11': + optional: true + + '@esbuild/android-arm64@0.25.11': + optional: true + + '@esbuild/android-arm@0.25.11': + optional: true + + '@esbuild/android-x64@0.25.11': + optional: true + + '@esbuild/darwin-arm64@0.25.11': + optional: true + + '@esbuild/darwin-x64@0.25.11': + optional: true + + '@esbuild/freebsd-arm64@0.25.11': + optional: true + + '@esbuild/freebsd-x64@0.25.11': + optional: true + + '@esbuild/linux-arm64@0.25.11': + optional: true + + '@esbuild/linux-arm@0.25.11': + optional: true + + '@esbuild/linux-ia32@0.25.11': + optional: true + + '@esbuild/linux-loong64@0.25.11': + optional: true + + '@esbuild/linux-mips64el@0.25.11': + optional: true + + '@esbuild/linux-ppc64@0.25.11': + optional: true + + '@esbuild/linux-riscv64@0.25.11': + optional: true + + '@esbuild/linux-s390x@0.25.11': + optional: true + + '@esbuild/linux-x64@0.25.11': + optional: true + + '@esbuild/netbsd-arm64@0.25.11': + optional: true + + '@esbuild/netbsd-x64@0.25.11': + optional: true + + '@esbuild/openbsd-arm64@0.25.11': + optional: true + + '@esbuild/openbsd-x64@0.25.11': + optional: true + + '@esbuild/openharmony-arm64@0.25.11': + optional: true + + '@esbuild/sunos-x64@0.25.11': + optional: true + + '@esbuild/win32-arm64@0.25.11': + optional: true + + '@esbuild/win32-ia32@0.25.11': + optional: true + + '@esbuild/win32-x64@0.25.11': + optional: true + + '@graphql-typed-document-node/core@3.2.0(graphql@16.11.0)': + dependencies: + graphql: 16.11.0 + + '@noble/curves@1.9.7': + dependencies: + '@noble/hashes': 1.8.0 + + '@noble/hashes@1.8.0': {} + + '@scure/base@1.2.6': {} + + '@scure/bip32@1.7.0': + dependencies: + '@noble/curves': 1.9.7 + '@noble/hashes': 1.8.0 + '@scure/base': 1.2.6 + + '@scure/bip39@1.6.0': + dependencies: + '@noble/hashes': 1.8.0 + '@scure/base': 1.2.6 + + '@shelby-protocol/clay-codes@0.0.1': {} + + '@shelby-protocol/reed-solomon@0.0.1': {} + + '@shelby-protocol/sdk@0.0.4(@aptos-labs/ts-sdk@5.1.1(got@11.8.6))': + dependencies: + '@aptos-labs/ts-sdk': 5.1.1(got@11.8.6) + '@shelby-protocol/clay-codes': 0.0.1 + '@shelby-protocol/reed-solomon': 0.0.1 + graphql: 16.11.0 + graphql-request: 7.3.1(graphql@16.11.0) + graphql-tag: 2.12.6(graphql@16.11.0) + zod: 3.25.76 + + '@sindresorhus/is@4.6.0': {} + + '@szmarczak/http-timer@4.0.6': + dependencies: + defer-to-connect: 2.0.1 + + '@types/body-parser@1.19.6': + dependencies: + '@types/connect': 3.4.38 + '@types/node': 20.19.22 + + '@types/cacheable-request@6.0.3': + dependencies: + '@types/http-cache-semantics': 4.0.4 + '@types/keyv': 3.1.4 + '@types/node': 20.19.22 + '@types/responselike': 1.0.3 + + '@types/connect@3.4.38': + dependencies: + '@types/node': 20.19.22 + + '@types/express-serve-static-core@4.19.7': + dependencies: + '@types/node': 20.19.22 + '@types/qs': 6.14.0 + '@types/range-parser': 1.2.7 + '@types/send': 1.2.0 + + '@types/express@4.17.23': + dependencies: + '@types/body-parser': 1.19.6 + '@types/express-serve-static-core': 4.19.7 + '@types/qs': 6.14.0 + '@types/serve-static': 1.15.9 + + '@types/http-cache-semantics@4.0.4': {} + + '@types/http-errors@2.0.5': {} + + '@types/keyv@3.1.4': + dependencies: + '@types/node': 20.19.22 + + '@types/mime@1.3.5': {} + + '@types/node@20.19.22': + dependencies: + undici-types: 6.21.0 + + '@types/qs@6.14.0': {} + + '@types/range-parser@1.2.7': {} + + '@types/responselike@1.0.3': + dependencies: + '@types/node': 20.19.22 + + '@types/send@0.17.5': + dependencies: + '@types/mime': 1.3.5 + '@types/node': 20.19.22 + + '@types/send@1.2.0': + dependencies: + '@types/node': 20.19.22 + + '@types/serve-static@1.15.9': + dependencies: + '@types/http-errors': 2.0.5 + '@types/node': 20.19.22 + '@types/send': 0.17.5 + + accepts@1.3.8: + dependencies: + mime-types: 2.1.35 + negotiator: 0.6.3 + + array-flatten@1.1.1: {} + + asynckit@0.4.0: {} + + body-parser@1.20.3: + dependencies: + bytes: 3.1.2 + content-type: 1.0.5 + debug: 2.6.9 + depd: 2.0.0 + destroy: 1.2.0 + http-errors: 2.0.0 + iconv-lite: 0.4.24 + on-finished: 2.4.1 + qs: 6.13.0 + raw-body: 2.5.2 + type-is: 1.6.18 + unpipe: 1.0.0 + transitivePeerDependencies: + - supports-color + + bytes@3.1.2: {} + + cacheable-lookup@5.0.4: {} + + cacheable-request@7.0.4: + dependencies: + clone-response: 1.0.3 + get-stream: 5.2.0 + http-cache-semantics: 4.2.0 + keyv: 4.5.4 + lowercase-keys: 2.0.0 + normalize-url: 6.1.0 + responselike: 2.0.1 + + call-bind-apply-helpers@1.0.2: + dependencies: + es-errors: 1.3.0 + function-bind: 1.1.2 + + call-bound@1.0.4: + dependencies: + call-bind-apply-helpers: 1.0.2 + get-intrinsic: 1.3.0 + + clone-response@1.0.3: + dependencies: + mimic-response: 1.0.1 + + combined-stream@1.0.8: + dependencies: + delayed-stream: 1.0.0 + + commander@12.1.0: {} + + content-disposition@0.5.4: + dependencies: + safe-buffer: 5.2.1 + + content-type@1.0.5: {} + + cookie-signature@1.0.6: {} + + cookie@0.7.1: {} + + data-uri-to-buffer@4.0.1: {} + + debug@2.6.9: + dependencies: + ms: 2.0.0 + + decompress-response@6.0.0: + dependencies: + mimic-response: 3.1.0 + + defer-to-connect@2.0.1: {} + + delayed-stream@1.0.0: {} + + depd@2.0.0: {} + + destroy@1.2.0: {} + + dotenv@16.6.1: {} + + dunder-proto@1.0.1: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-errors: 1.3.0 + gopd: 1.2.0 + + ee-first@1.1.1: {} + + encodeurl@1.0.2: {} + + encodeurl@2.0.0: {} + + end-of-stream@1.4.5: + dependencies: + once: 1.4.0 + + es-define-property@1.0.1: {} + + es-errors@1.3.0: {} + + es-object-atoms@1.1.1: + dependencies: + es-errors: 1.3.0 + + es-set-tostringtag@2.1.0: + dependencies: + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + has-tostringtag: 1.0.2 + hasown: 2.0.2 + + esbuild@0.25.11: + optionalDependencies: + '@esbuild/aix-ppc64': 0.25.11 + '@esbuild/android-arm': 0.25.11 + '@esbuild/android-arm64': 0.25.11 + '@esbuild/android-x64': 0.25.11 + '@esbuild/darwin-arm64': 0.25.11 + '@esbuild/darwin-x64': 0.25.11 + '@esbuild/freebsd-arm64': 0.25.11 + '@esbuild/freebsd-x64': 0.25.11 + '@esbuild/linux-arm': 0.25.11 + '@esbuild/linux-arm64': 0.25.11 + '@esbuild/linux-ia32': 0.25.11 + '@esbuild/linux-loong64': 0.25.11 + '@esbuild/linux-mips64el': 0.25.11 + '@esbuild/linux-ppc64': 0.25.11 + '@esbuild/linux-riscv64': 0.25.11 + '@esbuild/linux-s390x': 0.25.11 + '@esbuild/linux-x64': 0.25.11 + '@esbuild/netbsd-arm64': 0.25.11 + '@esbuild/netbsd-x64': 0.25.11 + '@esbuild/openbsd-arm64': 0.25.11 + '@esbuild/openbsd-x64': 0.25.11 + '@esbuild/openharmony-arm64': 0.25.11 + '@esbuild/sunos-x64': 0.25.11 + '@esbuild/win32-arm64': 0.25.11 + '@esbuild/win32-ia32': 0.25.11 + '@esbuild/win32-x64': 0.25.11 + + escape-html@1.0.3: {} + + etag@1.8.1: {} + + eventemitter3@5.0.1: {} + + express@4.21.2: + dependencies: + accepts: 1.3.8 + array-flatten: 1.1.1 + body-parser: 1.20.3 + content-disposition: 0.5.4 + content-type: 1.0.5 + cookie: 0.7.1 + cookie-signature: 1.0.6 + debug: 2.6.9 + depd: 2.0.0 + encodeurl: 2.0.0 + escape-html: 1.0.3 + etag: 1.8.1 + finalhandler: 1.3.1 + fresh: 0.5.2 + http-errors: 2.0.0 + merge-descriptors: 1.0.3 + methods: 1.1.2 + on-finished: 2.4.1 + parseurl: 1.3.3 + path-to-regexp: 0.1.12 + proxy-addr: 2.0.7 + qs: 6.13.0 + range-parser: 1.2.1 + safe-buffer: 5.2.1 + send: 0.19.0 + serve-static: 1.16.2 + setprototypeof: 1.2.0 + statuses: 2.0.1 + type-is: 1.6.18 + utils-merge: 1.0.1 + vary: 1.1.2 + transitivePeerDependencies: + - supports-color + + fetch-blob@3.2.0: + dependencies: + node-domexception: 1.0.0 + web-streams-polyfill: 3.3.3 + + finalhandler@1.3.1: + dependencies: + debug: 2.6.9 + encodeurl: 2.0.0 + escape-html: 1.0.3 + on-finished: 2.4.1 + parseurl: 1.3.3 + statuses: 2.0.1 + unpipe: 1.0.0 + transitivePeerDependencies: + - supports-color + + form-data@4.0.4: + dependencies: + asynckit: 0.4.0 + combined-stream: 1.0.8 + es-set-tostringtag: 2.1.0 + hasown: 2.0.2 + mime-types: 2.1.35 + + formdata-polyfill@4.0.10: + dependencies: + fetch-blob: 3.2.0 + + forwarded@0.2.0: {} + + fresh@0.5.2: {} + + fsevents@2.3.3: + optional: true + + function-bind@1.1.2: {} + + get-intrinsic@1.3.0: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-define-property: 1.0.1 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + function-bind: 1.1.2 + get-proto: 1.0.1 + gopd: 1.2.0 + has-symbols: 1.1.0 + hasown: 2.0.2 + math-intrinsics: 1.1.0 + + get-proto@1.0.1: + dependencies: + dunder-proto: 1.0.1 + es-object-atoms: 1.1.1 + + get-stream@5.2.0: + dependencies: + pump: 3.0.3 + + get-tsconfig@4.12.0: + dependencies: + resolve-pkg-maps: 1.0.0 + + gopd@1.2.0: {} + + got@11.8.6: + dependencies: + '@sindresorhus/is': 4.6.0 + '@szmarczak/http-timer': 4.0.6 + '@types/cacheable-request': 6.0.3 + '@types/responselike': 1.0.3 + cacheable-lookup: 5.0.4 + cacheable-request: 7.0.4 + decompress-response: 6.0.0 + http2-wrapper: 1.0.3 + lowercase-keys: 2.0.0 + p-cancelable: 2.1.1 + responselike: 2.0.1 + + graphql-request@7.3.1(graphql@16.11.0): + dependencies: + '@graphql-typed-document-node/core': 3.2.0(graphql@16.11.0) + graphql: 16.11.0 + + graphql-tag@2.12.6(graphql@16.11.0): + dependencies: + graphql: 16.11.0 + tslib: 2.8.1 + + graphql@16.11.0: {} + + has-symbols@1.1.0: {} + + has-tostringtag@1.0.2: + dependencies: + has-symbols: 1.1.0 + + hasown@2.0.2: + dependencies: + function-bind: 1.1.2 + + http-cache-semantics@4.2.0: {} + + http-errors@2.0.0: + dependencies: + depd: 2.0.0 + inherits: 2.0.4 + setprototypeof: 1.2.0 + statuses: 2.0.1 + toidentifier: 1.0.1 + + http2-wrapper@1.0.3: + dependencies: + quick-lru: 5.1.1 + resolve-alpn: 1.2.1 + + iconv-lite@0.4.24: + dependencies: + safer-buffer: 2.1.2 + + inherits@2.0.4: {} + + ipaddr.js@1.9.1: {} + + js-base64@3.7.8: {} + + json-buffer@3.0.1: {} + + jwt-decode@4.0.0: {} + + keyv@4.5.4: + dependencies: + json-buffer: 3.0.1 + + lowercase-keys@2.0.0: {} + + math-intrinsics@1.1.0: {} + + media-typer@0.3.0: {} + + merge-descriptors@1.0.3: {} + + methods@1.1.2: {} + + mime-db@1.52.0: {} + + mime-types@2.1.35: + dependencies: + mime-db: 1.52.0 + + mime@1.6.0: {} + + mimic-response@1.0.1: {} + + mimic-response@3.1.0: {} + + ms@2.0.0: {} + + ms@2.1.3: {} + + negotiator@0.6.3: {} + + node-domexception@1.0.0: {} + + node-fetch@3.3.2: + dependencies: + data-uri-to-buffer: 4.0.1 + fetch-blob: 3.2.0 + formdata-polyfill: 4.0.10 + + normalize-url@6.1.0: {} + + object-inspect@1.13.4: {} + + on-finished@2.4.1: + dependencies: + ee-first: 1.1.1 + + once@1.4.0: + dependencies: + wrappy: 1.0.2 + + p-cancelable@2.1.1: {} + + parseurl@1.3.3: {} + + path-to-regexp@0.1.12: {} + + poseidon-lite@0.2.1: {} + + proxy-addr@2.0.7: + dependencies: + forwarded: 0.2.0 + ipaddr.js: 1.9.1 + + pump@3.0.3: + dependencies: + end-of-stream: 1.4.5 + once: 1.4.0 + + qs@6.13.0: + dependencies: + side-channel: 1.1.0 + + quick-lru@5.1.1: {} + + range-parser@1.2.1: {} + + raw-body@2.5.2: + dependencies: + bytes: 3.1.2 + http-errors: 2.0.0 + iconv-lite: 0.4.24 + unpipe: 1.0.0 + + resolve-alpn@1.2.1: {} + + resolve-pkg-maps@1.0.0: {} + + responselike@2.0.1: + dependencies: + lowercase-keys: 2.0.0 + + safe-buffer@5.2.1: {} + + safer-buffer@2.1.2: {} + + send@0.19.0: + dependencies: + debug: 2.6.9 + depd: 2.0.0 + destroy: 1.2.0 + encodeurl: 1.0.2 + escape-html: 1.0.3 + etag: 1.8.1 + fresh: 0.5.2 + http-errors: 2.0.0 + mime: 1.6.0 + ms: 2.1.3 + on-finished: 2.4.1 + range-parser: 1.2.1 + statuses: 2.0.1 + transitivePeerDependencies: + - supports-color + + serve-static@1.16.2: + dependencies: + encodeurl: 2.0.0 + escape-html: 1.0.3 + parseurl: 1.3.3 + send: 0.19.0 + transitivePeerDependencies: + - supports-color + + setprototypeof@1.2.0: {} + + side-channel-list@1.0.0: + dependencies: + es-errors: 1.3.0 + object-inspect: 1.13.4 + + side-channel-map@1.0.1: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + object-inspect: 1.13.4 + + side-channel-weakmap@1.0.2: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + object-inspect: 1.13.4 + side-channel-map: 1.0.1 + + side-channel@1.1.0: + dependencies: + es-errors: 1.3.0 + object-inspect: 1.13.4 + side-channel-list: 1.0.0 + side-channel-map: 1.0.1 + side-channel-weakmap: 1.0.2 + + statuses@2.0.1: {} + + toidentifier@1.0.1: {} + + tslib@2.8.1: {} + + tsx@4.20.6: + dependencies: + esbuild: 0.25.11 + get-tsconfig: 4.12.0 + optionalDependencies: + fsevents: 2.3.3 + + type-is@1.6.18: + dependencies: + media-typer: 0.3.0 + mime-types: 2.1.35 + + typescript@5.9.3: {} + + undici-types@6.21.0: {} + + unpipe@1.0.0: {} + + utils-merge@1.0.1: {} + + vary@1.1.2: {} + + web-streams-polyfill@3.3.3: {} + + wrappy@1.0.2: {} + + zod@3.25.76: {} diff --git a/apps/ai-image-generation/postcss.config.mjs b/apps/ai-image-generation/postcss.config.mjs new file mode 100644 index 0000000..e4b5ceb --- /dev/null +++ b/apps/ai-image-generation/postcss.config.mjs @@ -0,0 +1 @@ +export { default } from "@shelby-protocol/ui/postcss.config"; diff --git a/apps/ai-image-generation/tsconfig.json b/apps/ai-image-generation/tsconfig.json new file mode 100644 index 0000000..1e70252 --- /dev/null +++ b/apps/ai-image-generation/tsconfig.json @@ -0,0 +1,28 @@ +{ + "compilerOptions": { + "target": "ES2017", + "lib": ["dom", "dom.iterable", "esnext"], + "allowJs": true, + "skipLibCheck": true, + "strict": true, + "noEmit": true, + "esModuleInterop": true, + "module": "esnext", + "moduleResolution": "bundler", + "resolveJsonModule": true, + "isolatedModules": true, + "jsx": "preserve", + "incremental": true, + "plugins": [ + { + "name": "next" + } + ], + "paths": { + "@/*": ["./*"], + "@shelby-protocol/ui/*": ["../../packages/ui/src/*"] + } + }, + "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], + "exclude": ["node_modules"] +} diff --git a/apps/ai-image-generation/utils/client.ts b/apps/ai-image-generation/utils/client.ts new file mode 100644 index 0000000..0efdcbb --- /dev/null +++ b/apps/ai-image-generation/utils/client.ts @@ -0,0 +1,24 @@ +import { Aptos, AptosConfig, Network } from "@aptos-labs/ts-sdk"; +import { ShelbyClient } from "@shelby-protocol/sdk/browser"; + +export const aptosClient = new Aptos( + new AptosConfig({ + network: Network.SHELBYNET, + clientConfig: { + API_KEY: process.env.NEXT_PUBLIC_APTOS_API_KEY, + }, + }), +); + +export const getAptosClient = () => { + return aptosClient; +}; + +const shelbyClient = new ShelbyClient({ + network: Network.SHELBYNET, + apiKey: process.env.NEXT_PUBLIC_SHELBY_API_KEY, +}); + +export const getShelbyClient = () => { + return shelbyClient; +}; diff --git a/packages/ui/src/components/badge.tsx b/packages/ui/src/components/badge.tsx new file mode 100644 index 0000000..c811e08 --- /dev/null +++ b/packages/ui/src/components/badge.tsx @@ -0,0 +1,45 @@ +import { Slot } from "@radix-ui/react-slot"; +import { cn } from "@shelby-protocol/ui/lib/utils"; +import { cva, type VariantProps } from "class-variance-authority"; +import type * as React from "react"; + +const badgeVariants = cva( + "inline-flex items-center justify-center rounded-full border px-2 py-0.5 text-xs font-medium w-fit whitespace-nowrap shrink-0 [&>svg]:size-3 gap-1 [&>svg]:pointer-events-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive transition-[color,box-shadow] overflow-hidden", + { + variants: { + variant: { + default: + "border-transparent bg-primary text-primary-foreground [a&]:hover:bg-primary/90", + secondary: + "border-transparent bg-secondary text-secondary-foreground [a&]:hover:bg-secondary/90", + destructive: + "border-transparent bg-destructive text-white [a&]:hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60", + outline: + "text-foreground [a&]:hover:bg-accent [a&]:hover:text-accent-foreground", + }, + }, + defaultVariants: { + variant: "default", + }, + }, +); + +function Badge({ + className, + variant, + asChild = false, + ...props +}: React.ComponentProps<"span"> & + VariantProps & { asChild?: boolean }) { + const Comp = asChild ? Slot : "span"; + + return ( + + ); +} + +export { Badge, badgeVariants }; diff --git a/packages/ui/src/components/card.tsx b/packages/ui/src/components/card.tsx new file mode 100644 index 0000000..7a06cf8 --- /dev/null +++ b/packages/ui/src/components/card.tsx @@ -0,0 +1,91 @@ +import { cn } from "@shelby-protocol/ui/lib/utils"; +import type * as React from "react"; + +function Card({ className, ...props }: React.ComponentProps<"div">) { + return ( +
+ ); +} + +function CardHeader({ className, ...props }: React.ComponentProps<"div">) { + return ( +
+ ); +} + +function CardTitle({ className, ...props }: React.ComponentProps<"div">) { + return ( +
+ ); +} + +function CardDescription({ className, ...props }: React.ComponentProps<"div">) { + return ( +
+ ); +} + +function CardAction({ className, ...props }: React.ComponentProps<"div">) { + return ( +
+ ); +} + +function CardContent({ className, ...props }: React.ComponentProps<"div">) { + return ( +
+ ); +} + +function CardFooter({ className, ...props }: React.ComponentProps<"div">) { + return ( +
+ ); +} + +export { + Card, + CardHeader, + CardFooter, + CardTitle, + CardAction, + CardDescription, + CardContent, +}; diff --git a/packages/ui/src/components/index.ts b/packages/ui/src/components/index.ts index 1d8a569..2804741 100644 --- a/packages/ui/src/components/index.ts +++ b/packages/ui/src/components/index.ts @@ -1,5 +1,8 @@ +export * from "./badge"; export * from "./button"; +export * from "./card"; export * from "./collapsible"; export * from "./dialog"; +export * from "./input"; export * from "./sonner"; export * from "./x-chain-wallet-selector"; diff --git a/packages/ui/src/components/input.tsx b/packages/ui/src/components/input.tsx new file mode 100644 index 0000000..de4b07b --- /dev/null +++ b/packages/ui/src/components/input.tsx @@ -0,0 +1,20 @@ +import { cn } from "@shelby-protocol/ui/lib/utils"; +import type * as React from "react"; + +function Input({ className, type, ...props }: React.ComponentProps<"input">) { + return ( + + ); +} + +export { Input }; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 2759064..f4b115b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -24,6 +24,58 @@ importers: specifier: 5.8.2 version: 5.8.2 + apps/ai-image-generation: + dependencies: + '@aptos-labs/derived-wallet-ethereum': + specifier: ^0.8.0 + version: 0.8.0(@aptos-labs/ts-sdk@5.1.1(got@11.8.6))(@wallet-standard/core@1.1.1)(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@3.25.76) + '@aptos-labs/derived-wallet-solana': + specifier: ^0.8.0 + version: 0.8.0(@aptos-labs/ts-sdk@5.1.1(got@11.8.6))(@wallet-standard/core@1.1.1)(bs58@4.0.1)(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10) + '@aptos-labs/ts-sdk': + specifier: ^5.1.1 + version: 5.1.1(got@11.8.6) + '@aptos-labs/wallet-adapter-react': + specifier: ^7.1.0 + version: 7.1.2(@aptos-labs/ts-sdk@5.1.1(got@11.8.6))(@telegram-apps/bridge@1.9.2)(@types/react@18.3.26)(@wallet-standard/core@1.1.1)(aptos@1.22.1(got@11.8.6))(react@18.3.1) + '@shelby-protocol/sdk': + specifier: 0.0.4 + version: 0.0.4(@aptos-labs/ts-sdk@5.1.1(got@11.8.6)) + '@shelby-protocol/ui': + specifier: workspace:* + version: link:../../packages/ui + dotenv: + specifier: ^16.6.1 + version: 16.6.1 + form-data: + specifier: ^4.0.4 + version: 4.0.4 + next: + specifier: ^15.5.0 + version: 15.5.4(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + node-fetch: + specifier: ^3.3.2 + version: 3.3.2 + openai: + specifier: ^6.6.0 + version: 6.6.0(ws@7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.76) + react: + specifier: ^18.3.1 + version: 18.3.1 + react-dom: + specifier: ^18.3.1 + version: 18.3.1(react@18.3.1) + devDependencies: + '@types/node': + specifier: ^22.15.3 + version: 22.18.9 + '@types/react': + specifier: ^18.3.12 + version: 18.3.26 + '@types/react-dom': + specifier: ^18.3.1 + version: 18.3.7(@types/react@18.3.26) + apps/cross-chain-accounts: dependencies: '@aptos-labs/derived-wallet-ethereum': @@ -1693,6 +1745,10 @@ packages: csstype@3.1.3: resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==} + data-uri-to-buffer@4.0.1: + resolution: {integrity: sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==} + engines: {node: '>= 12'} + debug@4.4.3: resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} engines: {node: '>=6.0'} @@ -1729,6 +1785,10 @@ packages: detect-node-es@1.1.0: resolution: {integrity: sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==} + dotenv@16.6.1: + resolution: {integrity: sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==} + engines: {node: '>=12'} + dunder-proto@1.0.1: resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} engines: {node: '>= 0.4'} @@ -1813,6 +1873,10 @@ packages: picomatch: optional: true + fetch-blob@3.2.0: + resolution: {integrity: sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==} + engines: {node: ^12.20 || >= 14.13} + follow-redirects@1.15.11: resolution: {integrity: sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==} engines: {node: '>=4.0'} @@ -1826,6 +1890,10 @@ packages: resolution: {integrity: sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==} engines: {node: '>= 6'} + formdata-polyfill@4.0.10: + resolution: {integrity: sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==} + engines: {node: '>=12.20.0'} + fraction.js@4.3.7: resolution: {integrity: sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==} @@ -2133,6 +2201,11 @@ packages: sass: optional: true + node-domexception@1.0.0: + resolution: {integrity: sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==} + engines: {node: '>=10.5.0'} + deprecated: Use your platform's native DOMException instead + node-fetch@2.7.0: resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==} engines: {node: 4.x || >=6.0.0} @@ -2142,6 +2215,10 @@ packages: encoding: optional: true + node-fetch@3.3.2: + resolution: {integrity: sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + node-gyp-build@4.8.4: resolution: {integrity: sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==} hasBin: true @@ -2160,6 +2237,18 @@ packages: once@1.4.0: resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + openai@6.6.0: + resolution: {integrity: sha512-1yWk4cBsHF5Bq9TreHYOHY7pbqdlT74COnm8vPx7WKn36StS+Hyk8DdAitnLaw67a5Cudkz5EmlFQjSrNnrA2w==} + hasBin: true + peerDependencies: + ws: ^8.18.0 + zod: ^3.25 || ^4.0 + peerDependenciesMeta: + ws: + optional: true + zod: + optional: true + ox@0.9.6: resolution: {integrity: sha512-8SuCbHPvv2eZLYXrNmC0EC12rdzXQLdhnOMlHDW2wiCPLxBrOOJwX5L5E61by+UjTPOryqQiRSnjIKCI+GykKg==} peerDependencies: @@ -2563,6 +2652,10 @@ packages: jsdom: optional: true + web-streams-polyfill@3.3.3: + resolution: {integrity: sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==} + engines: {node: '>= 8'} + webidl-conversions@3.0.1: resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} @@ -4010,6 +4103,8 @@ snapshots: csstype@3.1.3: {} + data-uri-to-buffer@4.0.1: {} + debug@4.4.3: dependencies: ms: 2.1.3 @@ -4030,6 +4125,8 @@ snapshots: detect-node-es@1.1.0: {} + dotenv@16.6.1: {} + dunder-proto@1.0.1: dependencies: call-bind-apply-helpers: 1.0.2 @@ -4136,6 +4233,11 @@ snapshots: optionalDependencies: picomatch: 4.0.3 + fetch-blob@3.2.0: + dependencies: + node-domexception: 1.0.0 + web-streams-polyfill: 3.3.3 + follow-redirects@1.15.11: {} form-data@4.0.4: @@ -4146,6 +4248,10 @@ snapshots: hasown: 2.0.2 mime-types: 2.1.35 + formdata-polyfill@4.0.10: + dependencies: + fetch-blob: 3.2.0 + fraction.js@4.3.7: {} framer-motion@12.23.24(react-dom@18.3.1(react@18.3.1))(react@18.3.1): @@ -4412,10 +4518,18 @@ snapshots: - '@babel/core' - babel-plugin-macros + node-domexception@1.0.0: {} + node-fetch@2.7.0: dependencies: whatwg-url: 5.0.0 + node-fetch@3.3.2: + dependencies: + data-uri-to-buffer: 4.0.1 + fetch-blob: 3.2.0 + formdata-polyfill: 4.0.10 + node-gyp-build@4.8.4: optional: true @@ -4429,6 +4543,11 @@ snapshots: dependencies: wrappy: 1.0.2 + openai@6.6.0(ws@7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.76): + optionalDependencies: + ws: 7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10) + zod: 3.25.76 + ox@0.9.6(typescript@5.9.3)(zod@3.25.76): dependencies: '@adraffy/ens-normalize': 1.11.1 @@ -4847,6 +4966,8 @@ snapshots: - tsx - yaml + web-streams-polyfill@3.3.3: {} + webidl-conversions@3.0.1: {} whatwg-url@5.0.0: