diff --git a/cspell.config.yaml b/cspell.config.yaml index 061432c..9508727 100644 --- a/cspell.config.yaml +++ b/cspell.config.yaml @@ -2,13 +2,18 @@ language: en words: - agentcommercekit - bitstring + - blockhash - caip - dbname + - devnet - healthcheck - keypair + - lamports - multibase + - multicall - multicodec - multikey + - pubkeys - secp256 - skyfire - solana diff --git a/demos/payments/README.md b/demos/payments/README.md index 8e87637..65bbfa5 100644 --- a/demos/payments/README.md +++ b/demos/payments/README.md @@ -6,7 +6,7 @@ This interactive command-line demo showcases a common use case: the **Server-Ini - A **Client Agent** attempting to access a protected resource. - A **Server Agent** requiring payment and issuing a formal Payment Request. -- The Client Agent making a payment using **USDC on the Base Sepolia testnet**. +- The Client Agent making a payment using **USDC on the Base Sepolia testnet** or **USDC on Solana devnet**, or a **Stripe** simulated card payment. - A **Receipt Service** verifying the on-chain payment and issuing a cryptographically **Verifiable Credential (VC)** as a payment receipt. - The Client Agent using this receipt to gain access to the resource. @@ -50,7 +50,9 @@ pnpm run demo The interactive CLI will guide you through the following steps: 1. **Client requests resource**: The Client attempts to fetch data from the Server Agent, who responds with an HTTP `402 Payment Required` status. This response contains a `PaymentRequest` which includes details on how to pay for access to this resource and offers multiple payment options. -2. **Client makes payment**: If the client chooses to pay via Credit Card, they will pay via a sample Payment Service. Alternatively, the Client can use the information from the Payment Request to transfer USDC from its wallet to the Server's wallet on the Base Sepolia testnet. +2. **Client makes payment**: If the client chooses to pay via Credit Card, they will pay via a sample Payment Service. Alternatively, the Client can use the information from the Payment Request to transfer USDC from its wallet to the Server's wallet on: + - Base Sepolia (EVM), or + - Solana devnet (SPL token, USDC mint configurable via env) 3. **Client requests a receipt**: Once the payment transaction is complete, the Client or the Payment Service will request a formal Receipt **Verifiable Credential (VC)**. For on-chain payments, the Client provides the Receipt Service with proof of the on-chain transaction and the original Payment Request. 4. **Receipt Service verifies payment**: The Receipt Service verifies all of the provided data, performs on-chain transaction verification if required, and verifies the integrity of the original payment request. If all is successful, it issues a Receipt Credential (VC). 5. **Client presents receipt to Server**: The Client retries the request to the Server, this time presenting the Verifiable Credential (receipt). The Server verifies the receipt and, if valid, grants access to the protected resource. diff --git a/demos/payments/package.json b/demos/payments/package.json index c457c4e..9c70640 100644 --- a/demos/payments/package.json +++ b/demos/payments/package.json @@ -29,6 +29,9 @@ "@hono/node-server": "catalog:", "@repo/api-utils": "workspace:*", "@repo/cli-tools": "workspace:*", + "@solana-program/system": "^0.9.0", + "@solana-program/token": "^0.6.0", + "@solana/kit": "^4.0.0", "agentcommercekit": "workspace:*", "hono": "catalog:", "valibot": "catalog:", diff --git a/demos/payments/src/constants.ts b/demos/payments/src/constants.ts index 1ec3893..073cdf0 100644 --- a/demos/payments/src/constants.ts +++ b/demos/payments/src/constants.ts @@ -26,3 +26,12 @@ export const publicClient = createPublicClient({ chain, transport: http(), }) + +export const solana = { + chainId: caip2ChainIds.solanaDevnet, + rpcUrl: process.env.SOLANA_RPC_URL ?? "https://api.devnet.solana.com", + usdcMint: + process.env.SOLANA_USDC_MINT ?? + "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", + commitment: "confirmed" as const, +} diff --git a/demos/payments/src/index.ts b/demos/payments/src/index.ts index f0f4ef4..f234847 100644 --- a/demos/payments/src/index.ts +++ b/demos/payments/src/index.ts @@ -12,9 +12,30 @@ import { waitForEnter, wordWrap, } from "@repo/cli-tools" +import { + findAssociatedTokenPda, + getCreateAssociatedTokenInstructionAsync, + getTransferCheckedInstruction, + TOKEN_PROGRAM_ADDRESS, +} from "@solana-program/token" +import { + address, + appendTransactionMessageInstructions, + createKeyPairSignerFromBytes, + createSolanaRpc, + createTransactionMessage, + getBase64EncodedWireTransaction, + pipe, + setTransactionMessageFeePayerSigner, + setTransactionMessageLifetimeUsingBlockhash, + signTransactionMessageWithSigners, +} from "@solana/kit" import { addressFromDidPkhUri, + createDidPkhUri, createJwt, + createJwtSigner, + generateKeypair, getDidResolver, isDidPkhUri, isJwtString, @@ -35,10 +56,14 @@ import { chainId, publicClient, SERVER_URL, + solana, usdcAddress, } from "./constants" -import { ensureNonZeroBalances } from "./utils/ensure-balances" -import { ensurePrivateKey } from "./utils/ensure-private-keys" +import { + ensureNonZeroBalances, + ensureSolanaSolBalance, +} from "./utils/ensure-balances" +import { ensurePrivateKey, ensureSolanaKeys } from "./utils/ensure-private-keys" import { getKeypairInfo, type KeypairInfo } from "./utils/keypair-info" import { transferUsdc } from "./utils/usdc-contract" import "./server" @@ -147,12 +172,19 @@ The Client attempts to access a protected resource on the Server. Since no valid ) const paymentOptions = paymentRequest.paymentOptions + + function networkLabel(network: string | undefined): string { + if (network === "stripe") return "Stripe" + if (network?.startsWith("solana:")) return "Solana" + return "Base Sepolia" + } + const selectedPaymentOptionId = await select({ message: "Select which payment option to use", choices: paymentOptions.map((option) => ({ - name: option.network === "stripe" ? "Stripe" : "Base Sepolia", + name: networkLabel(option.network), value: option.id, - description: `Pay on ${option.network === "stripe" ? "Stripe" : "Base Sepolia"} using ${option.currency}`, + description: `Pay on ${networkLabel(option.network)} using ${option.currency}`, })), }) @@ -164,29 +196,38 @@ The Client attempts to access a protected resource on the Server. Since no valid throw new Error(errorMessage("Invalid payment option")) } - let receipt: string - let details: Verifiable - - if (selectedPaymentOption.network === "stripe") { - const paymentResult = await performStripePayment( - clientKeypairInfo, - selectedPaymentOption, - paymentRequestToken, - ) - receipt = paymentResult.receipt - details = paymentResult.details - } else if (selectedPaymentOption.network === chainId) { - const paymentResult = await performOnChainPayment( - clientKeypairInfo, - selectedPaymentOption, - paymentRequestToken, - ) - receipt = paymentResult.receipt - details = paymentResult.details - } else { + function executePayment( + option: PaymentRequest["paymentOptions"][number], + ): Promise<{ + receipt: string + details: Verifiable + }> { + if (option.network === "stripe") { + return performStripePayment( + clientKeypairInfo, + option, + paymentRequestToken, + ) + } + if (option.network?.startsWith("solana:")) { + return performSolanaPayment( + clientKeypairInfo, + option, + paymentRequestToken, + ) + } + if (option.network === chainId) { + return performOnChainPayment( + clientKeypairInfo, + option, + paymentRequestToken, + ) + } throw new Error(errorMessage("Invalid payment option")) } + const { receipt, details } = await executePayment(selectedPaymentOption) + log( successMessage( "Verifiable Payment Receipt (VC) issued successfully by the Receipt Service! 🎉", @@ -397,6 +438,161 @@ If all checks pass, the Receipt Service issues a Verifiable Credential (VC) serv return { receipt, details } } +async function performSolanaPayment( + client: KeypairInfo, + paymentOption: PaymentRequest["paymentOptions"][number], + paymentRequestToken: JwtString, +) { + const receiptServiceUrl = paymentOption.receiptService + if (!receiptServiceUrl) { + throw new Error(errorMessage("Receipt service URL is required")) + } + + log(sectionHeader("💸 Execute Payment (Client Agent -> Solana / SPL Token)")) + + const rpc = createSolanaRpc(solana.rpcUrl) + const clientSolKeys = await ensureSolanaKeys( + "SOLANA_CLIENT_PUBLIC_KEY", + "SOLANA_CLIENT_SECRET_KEY_JSON", + ) + const keyBytes = new Uint8Array( + JSON.parse(clientSolKeys.secretKeyJson) as number[], + ) + const payerSigner = await createKeyPairSignerFromBytes(keyBytes) + + const mint = address(solana.usdcMint) + + // Ensure payer has SOL for fees + await ensureSolanaSolBalance(clientSolKeys.publicKey) + + const recipient = address(paymentOption.recipient) + + const [senderAta] = await findAssociatedTokenPda({ + mint, + owner: payerSigner.address, + tokenProgram: TOKEN_PROGRAM_ADDRESS, + }) + const [recipientAta] = await findAssociatedTokenPda({ + mint, + owner: recipient, + tokenProgram: TOKEN_PROGRAM_ADDRESS, + }) + + // Ensure sender has USDC balance; if not, prompt Circle faucet + let tokenBal: { amount: string } + try { + ;({ value: tokenBal } = await rpc + .getTokenAccountBalance(senderAta, { commitment: solana.commitment }) + .send()) + } catch { + tokenBal = { amount: "0" } + } + while (tokenBal.amount === "0") { + log( + colors.dim( + "USDC balance is 0. Please request devnet USDC from Circle's faucet, then press Enter to retry.", + ), + ) + log(colors.dim(`Send USDC to your wallet: ${clientSolKeys.publicKey}`)) + log(colors.cyan("https://faucet.circle.com/")) + await waitForEnter("Press Enter after funding USDC...") + try { + ;({ value: tokenBal } = await rpc + .getTokenAccountBalance(senderAta, { commitment: solana.commitment }) + .send()) + } catch { + tokenBal = { amount: "0" } + } + } + const { value: recipientAtaInfo } = await rpc + .getAccountInfo(recipientAta, { + commitment: solana.commitment, + encoding: "base64", + }) + .send() + const maybeCreateRecipientAtaInstruction = !recipientAtaInfo + ? await getCreateAssociatedTokenInstructionAsync({ + payer: payerSigner, + owner: recipient, + mint, + ata: recipientAta, + tokenProgram: TOKEN_PROGRAM_ADDRESS, + }) + : undefined + + const amount = BigInt(paymentOption.amount) + const transferIx = getTransferCheckedInstruction({ + source: senderAta, + destination: recipientAta, + mint, + authority: payerSigner.address, + amount, + decimals: paymentOption.decimals, + }) + + const { value: latestBlockhash } = await rpc.getLatestBlockhash().send() + const txMessage = pipe( + createTransactionMessage({ version: 0 }), + (m) => setTransactionMessageFeePayerSigner(payerSigner, m), + (m) => setTransactionMessageLifetimeUsingBlockhash(latestBlockhash, m), + (m) => + appendTransactionMessageInstructions( + [ + ...(maybeCreateRecipientAtaInstruction + ? [maybeCreateRecipientAtaInstruction] + : []), + transferIx, + ], + m, + ), + ) + const signedTx = await signTransactionMessageWithSigners(txMessage) + const wireTx = getBase64EncodedWireTransaction(signedTx) + const signature = await rpc + .sendTransaction(wireTx, { encoding: "base64" }) + .send() + log(colors.dim("View on Solana Explorer:")) + log(link(`https://explorer.solana.com/tx/${signature}?cluster=devnet`), { + wrap: false, + }) + + // Build an ACK Ed25519 signer from the Solana payer seed to sign the receipt request + const ackEd25519Keypair = await generateKeypair( + "Ed25519", + new Uint8Array(Array.from(keyBytes).slice(0, 32)), + ) + const ackEd25519JwtSigner = createJwtSigner(ackEd25519Keypair) + const payerDid = createDidPkhUri(solana.chainId, clientSolKeys.publicKey) + const payload = { + paymentRequestToken, + paymentOptionId: paymentOption.id, + metadata: { + network: solana.chainId, + txHash: signature, + }, + payerDid, + } + const signedPayload = await createJwt( + payload, + { + issuer: payerDid, + signer: ackEd25519JwtSigner, + }, + { alg: "EdDSA" }, + ) + + const response = await fetch(receiptServiceUrl, { + method: "POST", + body: JSON.stringify({ payload: signedPayload }), + }) + const { receipt, details } = (await response.json()) as { + receipt: string + details: Verifiable + } + + return { receipt, details } +} + async function performStripePayment( _client: KeypairInfo, paymentOption: PaymentRequest["paymentOptions"][number], diff --git a/demos/payments/src/receipt-service.ts b/demos/payments/src/receipt-service.ts index 193be04..caad4fd 100644 --- a/demos/payments/src/receipt-service.ts +++ b/demos/payments/src/receipt-service.ts @@ -7,7 +7,9 @@ import { logJson, successMessage, } from "@repo/cli-tools" +import { createSolanaRpc, signature as toSignature } from "@solana/kit" import { + addressFromDidPkhUri, createPaymentReceipt, getDidResolver, isDidPkhUri, @@ -26,7 +28,7 @@ import { HTTPException } from "hono/http-exception" import * as v from "valibot" import { erc20Abi, isAddressEqual } from "viem" import { parseEventLogs } from "viem/utils" -import { chainId, publicClient, usdcAddress } from "./constants" +import { chainId, publicClient, solana, usdcAddress } from "./constants" import { asAddress } from "./utils/as-address" import { getKeypairInfo } from "./utils/keypair-info" @@ -38,6 +40,7 @@ const bodySchema = v.object({ }) const paymentDetailsSchema = v.object({ + paymentOptionId: v.string(), metadata: v.union([ v.object({ network: caip2ChainIdSchema, @@ -97,10 +100,8 @@ app.post("/", async (c) => { }, ) - // Load the payment option from the payment request matching our - // preferred network. const paymentOption = paymentRequest.paymentOptions.find( - (option) => option.network === paymentDetails.metadata.network, + (option) => option.id === paymentDetails.paymentOptionId, ) if (!paymentOption) { @@ -108,10 +109,17 @@ app.post("/", async (c) => { return c.json({ error: "Payment option not found" }, 400) } + if (paymentOption.network !== paymentDetails.metadata.network) { + log(errorMessage("Payment option network mismatch")) + return c.json({ error: "Payment option network mismatch" }, 400) + } + if (paymentOption.network === "stripe") { await verifyStripePayment(parsed.issuer, paymentDetails, paymentOption) } else if (paymentOption.network === chainId) { await verifyOnChainPayment(parsed.issuer, paymentDetails, paymentOption) + } else if (paymentOption.network === solana.chainId) { + await verifySolanaPayment(parsed.issuer, paymentDetails, paymentOption) } else { log(errorMessage("Invalid network")) throw new HTTPException(400, { @@ -235,6 +243,125 @@ async function verifyOnChainPayment( // Additional checks, like checking txHash block number timestamp occurred after payment_request issued } +async function fetchTransaction( + rpc: ReturnType, + txSignature: string, +) { + return rpc + .getTransaction(toSignature(txSignature), { + commitment: solana.commitment, + encoding: "jsonParsed", + maxSupportedTransactionVersion: 0 as const, + }) + .send() +} + +type SolanaTransaction = Awaited> + +type ParsedAccountKey = Readonly<{ + pubkey: string | { toBase58(): string } + signer?: boolean +}> + +type MessageWithAccountKeys = Readonly<{ + accountKeys?: readonly ParsedAccountKey[] +}> + +function extractSignerPubkeys(tx: NonNullable): Set { + const msg = tx.transaction.message as unknown as MessageWithAccountKeys + const signers = new Set() + for (const key of msg.accountKeys ?? []) { + if (key.signer) { + const pub = + typeof key.pubkey === "string" ? key.pubkey : key.pubkey.toBase58() + if (pub) signers.add(pub) + } + } + return signers +} + +type TokenBalance = { + mint: string + owner: string + uiTokenAmount: { amount: string; decimals: number } +} + +function toBigInt(value: unknown): bigint { + if (typeof value === "string") return BigInt(value) + if (typeof value === "number") return BigInt(value) + if (typeof value === "bigint") return value + return 0n +} + +async function verifySolanaPayment( + issuer: string, + paymentDetails: v.InferOutput, + paymentOption: v.InferOutput, +) { + if (paymentDetails.metadata.network !== solana.chainId) { + log(errorMessage("Invalid network")) + throw new HTTPException(400, { message: "Invalid network" }) + } + const signature = paymentDetails.metadata.txHash + const rpc = createSolanaRpc(solana.rpcUrl) + log(colors.dim("Loading Solana transaction details...")) + + let tx: SolanaTransaction | null = null + const maxAttempts = 20 + const delayMs = 1500 + + for (let i = 0; i < maxAttempts; i++) { + tx = await fetchTransaction(rpc, signature) + if (tx && !tx.meta?.err) break + await new Promise((r) => setTimeout(r, delayMs)) + } + if (!tx || tx.meta?.err) { + log(errorMessage("Solana transaction not found or failed")) + throw new HTTPException(400, { message: "Invalid transaction" }) + } + + let issuerAddress: string + try { + issuerAddress = addressFromDidPkhUri(issuer) + } catch { + throw new HTTPException(400, { message: "Invalid issuer DID" }) + } + + const signerPubkeys = extractSignerPubkeys(tx) + if (!signerPubkeys.has(issuerAddress)) { + log(errorMessage("Issuer DID did not sign the transaction")) + throw new HTTPException(400, { message: "Invalid payer DID" }) + } + + const mint = solana.usdcMint + const recipient = paymentOption.recipient + const expectedDecimals = paymentOption.decimals + const expectedAmount = BigInt(paymentOption.amount) + + const post = (tx.meta?.postTokenBalances ?? []) as unknown as TokenBalance[] + const pre = (tx.meta?.preTokenBalances ?? []) as unknown as TokenBalance[] + + const preBal = pre.find((b) => b.mint === mint && b.owner === recipient) + const postBal = post.find((b) => b.mint === mint && b.owner === recipient) + + if (!postBal) { + log(errorMessage("Recipient post token balance not found")) + throw new HTTPException(400, { message: "Recipient not credited" }) + } + if (postBal.uiTokenAmount.decimals !== expectedDecimals) { + log(errorMessage("Invalid token decimals")) + throw new HTTPException(400, { message: "Invalid token decimals" }) + } + + const preAmount = toBigInt(preBal?.uiTokenAmount.amount ?? "0") + const postAmount = toBigInt(postBal.uiTokenAmount.amount) + const delta = postAmount - preAmount + if (delta !== expectedAmount) { + log(errorMessage("Invalid amount")) + throw new HTTPException(400, { message: "Invalid amount" }) + } +} + serve({ port: 4568, fetch: app.fetch, diff --git a/demos/payments/src/server.ts b/demos/payments/src/server.ts index 13f0a4b..359be59 100644 --- a/demos/payments/src/server.ts +++ b/demos/payments/src/server.ts @@ -11,7 +11,13 @@ import { import { Hono, type Env, type TypedResponse } from "hono" import { env } from "hono/adapter" import { HTTPException } from "hono/http-exception" -import { chainId, PAYMENT_SERVICE_URL, RECEIPT_SERVICE_URL } from "./constants" +import { + chainId, + PAYMENT_SERVICE_URL, + RECEIPT_SERVICE_URL, + solana, +} from "./constants" +import { ensureSolanaKeys } from "./utils/ensure-private-keys" import { getKeypairInfo } from "./utils/keypair-info" const app = new Hono() @@ -36,6 +42,11 @@ app.get("/", async (c): Promise> => { const serverIdentity = await getKeypairInfo(env(c).SERVER_PRIVATE_KEY_HEX) const didResolver = getDidResolver() + const { publicKey: solanaServerPublicKey } = await ensureSolanaKeys( + "SOLANA_SERVER_PUBLIC_KEY", + "SOLANA_SERVER_SECRET_KEY_JSON", + ) + const { did: receiptIssuerDid } = await getKeypairInfo( env(c).RECEIPT_SERVICE_PRIVATE_KEY_HEX, ) @@ -53,7 +64,7 @@ app.get("/", async (c): Promise> => { if (!receipt) { log(colors.yellow("No receipt found, generating payment request...")) - // Build a payment request with a single payment option for USDC on Base Sepolia + // Build a payment request with multiple options: USDC on Base Sepolia, Stripe, and Solana (devnet) const paymentRequestInit: PaymentRequestInit = { id: crypto.randomUUID(), paymentOptions: [ @@ -78,6 +89,16 @@ app.get("/", async (c): Promise> => { paymentService: PAYMENT_SERVICE_URL, receiptService: RECEIPT_SERVICE_URL, }, + // USDC on Solana (devnet) + { + id: "usdc-solana-devnet", + amount: BigInt(50000).toString(), + decimals: 6, + currency: "USDC", + recipient: solanaServerPublicKey, + network: solana.chainId, + receiptService: RECEIPT_SERVICE_URL, + }, ], } diff --git a/demos/payments/src/utils/ensure-balances.ts b/demos/payments/src/utils/ensure-balances.ts index 437aa7e..06bf39e 100644 --- a/demos/payments/src/utils/ensure-balances.ts +++ b/demos/payments/src/utils/ensure-balances.ts @@ -1,4 +1,6 @@ -import { waitForEnter } from "@repo/cli-tools" +import { solana } from "@/constants" +import { colors, log, waitForEnter } from "@repo/cli-tools" +import { createSolanaRpc, address as solAddress } from "@solana/kit" import { createPublicClient, erc20Abi, http, type Chain } from "viem" import { formatUnits } from "viem/utils" @@ -10,38 +12,63 @@ export async function ensureNonZeroBalances( address: `0x${string}`, usdcAddress: `0x${string}`, ) { - // 2. Make sure the client wallet has been funded let balanceUsdc = await getErc20Balance(chain, address, usdcAddress) let balanceEth = await getEthBalance(chain, address) while (balanceUsdc.value === BigInt(0)) { - console.log( + log( "We need to fund this address with testnet USDC and testnet ETH:", address, ) - - console.log( + log( "You can get testnet tokens from the following faucets:", "ETH: https://docs.base.org/chain/network-faucets", "USDC: https://faucet.circle.com/", ) - console.log("Once funded, press enter to check balance again") + log("Once funded, press enter to check balance again") await waitForEnter() - console.log("Attempting to fetch USDC balance...") + log(colors.dim("Fetching balances...")) balanceUsdc = await getErc20Balance(chain, address, usdcAddress) - console.log("USDC balance fetched:", balanceUsdc) - console.log("Attempting to fetch ETH balance...") balanceEth = await getEthBalance(chain, address) - console.log("ETH balance fetched:", balanceEth) } - console.log("Client wallet balances:") - console.log(" USDC: ", formatUnits(balanceUsdc.value, balanceUsdc.decimals)) - console.log(" ETH: ", formatUnits(balanceEth.value, balanceUsdc.decimals)) + log("Client wallet balances:") + log(" USDC: ", formatUnits(balanceUsdc.value, balanceUsdc.decimals)) + log(" ETH: ", formatUnits(balanceEth.value, balanceEth.decimals)) return { balanceUsdc, balanceEth } } +export async function ensureSolanaSolBalance(address: string): Promise { + const rpc = createSolanaRpc(solana.rpcUrl) + const pubkey = solAddress(address) + + async function fetchBalance(): Promise { + try { + const balance = await rpc + .getBalance(pubkey, { commitment: solana.commitment }) + .send() + return balance.value + } catch { + return 0n + } + } + + let lamports = await fetchBalance() + + while (lamports === 0n) { + log("We need to fund this Solana address with devnet SOL:", address) + log("Faucet: https://faucet.solana.com/") + log("Once funded, press enter to check balance again") + await waitForEnter() + log(colors.dim("Fetching SOL balance...")) + lamports = await fetchBalance() + } + + log(colors.dim(`SOL balance (lamports): ${lamports}`)) + return lamports +} + async function getEthBalance(chain: Chain, address: `0x${string}`) { const publicClient = createPublicClient({ chain, @@ -68,7 +95,6 @@ async function getErc20Balance( transport: http(), }) - // eslint-disable-next-line @cspell/spellchecker const [balance, decimals] = await publicClient.multicall({ contracts: [ { diff --git a/demos/payments/src/utils/ensure-private-keys.ts b/demos/payments/src/utils/ensure-private-keys.ts index a3a72ca..9d473c7 100644 --- a/demos/payments/src/utils/ensure-private-keys.ts +++ b/demos/payments/src/utils/ensure-private-keys.ts @@ -1,8 +1,9 @@ import { envFilePath } from "@/constants" import { colors, log, updateEnvFile } from "@repo/cli-tools" +import { bytesToBase58, generateKeypair } from "agentcommercekit" import { generatePrivateKeyHex } from "./keypair-info" -export async function ensurePrivateKey(name: string) { +export async function ensurePrivateKey(name: string): Promise { const privateKeyHex = process.env[name] if (privateKeyHex) { @@ -14,3 +15,31 @@ export async function ensurePrivateKey(name: string) { await updateEnvFile({ [name]: newPrivateKeyHex }, envFilePath) return newPrivateKeyHex } + +export async function ensureSolanaKeys( + pubEnv: string, + secretEnv: string, +): Promise<{ publicKey: string; secretKeyJson: string }> { + const existingPub = process.env[pubEnv] + const existingSecret = process.env[secretEnv] + if (existingPub && existingSecret) { + return { publicKey: existingPub, secretKeyJson: existingSecret } + } + log(colors.dim(`Generating ${pubEnv}/${secretEnv}...`)) + + const kp = await generateKeypair("Ed25519") + + // Solana expects a 64-byte secret key (32-byte private + 32-byte public) + const secretKey64 = new Uint8Array(kp.privateKey.length + kp.publicKey.length) + secretKey64.set(kp.privateKey, 0) + secretKey64.set(kp.publicKey, kp.privateKey.length) + const secretKeyJson = JSON.stringify(Array.from(secretKey64)) + + const publicKey = bytesToBase58(kp.publicKey) + + await updateEnvFile( + { [pubEnv]: publicKey, [secretEnv]: secretKeyJson }, + envFilePath, + ) + return { publicKey, secretKeyJson } +} diff --git a/docs/ack-pay/payment-request-payload.mdx b/docs/ack-pay/payment-request-payload.mdx index 2ee463f..9eebbce 100644 --- a/docs/ack-pay/payment-request-payload.mdx +++ b/docs/ack-pay/payment-request-payload.mdx @@ -46,6 +46,16 @@ Every Payment Request payload contains essential properties: "recipient": "acct_StripeAccountID", "paymentService": "https://payments.example.com/stripe", "receiptService": "https://receipts.example.com/stripe" + }, + { + // Option 3: USDC on Solana devnet + "id": "usdc-solana-devnet", + "currency": "USDC", + "network": "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1", + "amount": 10000000, + "decimals": 6, + "recipient": "ExAmPLeSoLaNaAddReSS111111111111111111111111", + "receiptService": "https://receipts.example.com/solana" } // ... more options ... ] diff --git a/docs/ack-pay/receipt-verification.mdx b/docs/ack-pay/receipt-verification.mdx index 39ac7ff..4437db8 100644 --- a/docs/ack-pay/receipt-verification.mdx +++ b/docs/ack-pay/receipt-verification.mdx @@ -20,7 +20,7 @@ _Example ACK Receipt Verifiable Credential:_ { "@context": [ "https://www.w3.org/2018/credentials/v1", - "https://agentcommerkit.org/contexts/payment/v1" // Example ACK context + "https://agentcommercekit.org/contexts/payment/v1" // Example ACK context ], "id": "urn:uuid:5c358383-1d93-4956-8d0c-6e41e4d29901", // Unique receipt ID "type": ["VerifiableCredential", "ACKPaymentReceipt"], diff --git a/docs/demos/demo-payments.mdx b/docs/demos/demo-payments.mdx index 520de0c..84097d8 100644 --- a/docs/demos/demo-payments.mdx +++ b/docs/demos/demo-payments.mdx @@ -62,9 +62,9 @@ Client requests access to a protected resource. Server responds with an HTTP `40 - Client performs an on-chain stablecoin (USDC) payment to the Server’s wallet - on Base Sepolia testnet. Alternatively, a credit card payment can be handled - via a Payment Service. + Client performs an on-chain stablecoin (USDC) payment to the Server's wallet + on Base Sepolia testnet or Solana devnet. Alternatively, a credit card payment + can be handled via a Payment Service. @@ -87,6 +87,6 @@ Client requests access to a protected resource. Server responds with an HTTP `40 Explore comprehensive ACK-Pay functionalities and integrations in real-world applications involving diverse payment methods and Payment Service integrations: -- [View Payments Demo Source Code](https://github.com/agentcommercekit/ack/tree/main/demos//payments) +- [View Payments Demo Source Code](https://github.com/agentcommercekit/ack/tree/main/demos/payments) - [ACK Documentation](https://agentcommercekit.com) - [ACK-Pay Details](/ack-pay/introduction) diff --git a/docs/demos/demos.mdx b/docs/demos/demos.mdx index 3ef32d2..52e4ec9 100644 --- a/docs/demos/demos.mdx +++ b/docs/demos/demos.mdx @@ -33,7 +33,7 @@ Explore ACK-Pay with a demo of server requesting payment and a client agent comp - [Detailed Payments Demo Walkthrough](./demo-payments) -- [View Payments Demo Source Code](https://github.com/agentcommercekit/ack/tree/main/demos//payments) +- [View Payments Demo Source Code](https://github.com/agentcommercekit/ack/tree/main/demos/payments) ## End-to-End Demo diff --git a/package.json b/package.json index 4dd345c..e17c3ef 100644 --- a/package.json +++ b/package.json @@ -18,7 +18,7 @@ "build": "turbo build", "check": "turbo check", "check:format": "prettier --check .", - "check:packages": "pnpx @manypkg/cli check", + "check:packages": "pnpm dlx @manypkg/cli check", "check:types": "turbo check:types", "clean": "turbo clean && git clean -xdf .turbo node_modules/.cache", "demo:e2e": "pnpm --filter ./demos/e2e demo", @@ -33,7 +33,7 @@ "lint": "turbo lint", "lint:fix": "turbo lint:fix", "nuke": "pnpm run clean && git clean -xdf demos/**/node_modules docs/**/node_modules examples/**/node_modules packages/**/node_modules tools/**/node_modules node_modules", - "outdated": "pnpx npm-check-updates --interactive --format group --workspaces", + "outdated": "pnpm dlx npm-check-updates --interactive --format group --workspaces", "publish:packages": "turbo build && changeset publish", "release": "./bin/release", "setup": "./bin/setup", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 176eb7a..e6be073 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -209,6 +209,15 @@ importers: '@repo/cli-tools': specifier: workspace:* version: link:../../tools/cli-tools + '@solana-program/system': + specifier: ^0.9.0 + version: 0.9.1(@solana/kit@4.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(ws@8.18.3)) + '@solana-program/token': + specifier: ^0.6.0 + version: 0.6.0(@solana/kit@4.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(ws@8.18.3)) + '@solana/kit': + specifier: ^4.0.0 + version: 4.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(ws@8.18.3) agentcommercekit: specifier: workspace:* version: link:../../packages/agentcommercekit @@ -2568,18 +2577,64 @@ packages: '@socket.io/component-emitter@3.1.2': resolution: {integrity: sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==} + '@solana-program/system@0.9.1': + resolution: {integrity: sha512-2N30CgYJw0qX8jKU8vW808yLmx5oRoDSM+FC6tqhsLQiph7agK9eRXJlnrq6OUfTAZd5yCYQHQvGtx0S8I9SAA==} + peerDependencies: + '@solana/kit': ^5.0 + + '@solana-program/token@0.6.0': + resolution: {integrity: sha512-omkZh4Tt9rre4wzWHNOhOEHyenXQku3xyc/UrKvShexA/Qlhza67q7uRwmwEDUs4QqoDBidSZPooOmepnA/jig==} + peerDependencies: + '@solana/kit': ^3.0 + + '@solana/accounts@4.0.0': + resolution: {integrity: sha512-fxTtTk7PCJrigdzqhkc0eZYACVZpONKJZy4MkGvZzx5tCC7rUeDJvzau3IYACUCRaaAGPpkINHwYtp8weKsn8w==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' + + '@solana/addresses@4.0.0': + resolution: {integrity: sha512-1OS4nU0HFZxHRxgUb6A72Qg0QbIz6Vu2AbB0j/YSxN4EI+S2BftA83Y6uXhTFDQjKuA+MtHjxe6edB3cs1Pqxw==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' + + '@solana/assertions@4.0.0': + resolution: {integrity: sha512-QwtImPVM5JLEWOFpvHh+eKdvmxdNP6PW8FkmFFEVYR6VFDaZD/hbmSJlwt5p3L69sVmxJA0ughYgD/kkHM7fbg==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' + '@solana/codecs-core@2.1.1': resolution: {integrity: sha512-iPQW3UZ2Vi7QFBo2r9tw0NubtH8EdrhhmZulx6lC8V5a+qjaxovtM/q/UW2BTNpqqHLfO0tIcLyBLrNH4HTWPg==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5.3.3' + '@solana/codecs-core@4.0.0': + resolution: {integrity: sha512-28kNUsyIlhU3MO3/7ZLDqeJf2YAm32B4tnTjl5A9HrbBqsTZ+upT/RzxZGP1MMm7jnPuIKCMwmTpsyqyR6IUpw==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' + + '@solana/codecs-data-structures@4.0.0': + resolution: {integrity: sha512-pvh+Oxz6UIbWxcgwvVwMJIV4nvZn3EHL5ZvCIPClE5Ep8K5sJ8RoRvOohqLcIv9LYn/EZNoXpCodREX/OYpsGw==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' + '@solana/codecs-numbers@2.1.1': resolution: {integrity: sha512-m20IUPJhPUmPkHSlZ2iMAjJ7PaYUvlMtFhCQYzm9BEBSI6OCvXTG3GAPpAnSGRBfg5y+QNqqmKn4QHU3B6zzCQ==} engines: {node: '>=20.18.0'} peerDependencies: typescript: '>=5.3.3' + '@solana/codecs-numbers@4.0.0': + resolution: {integrity: sha512-z9zpjtcwzqT9rbkKVZpkWB5/0V7+6YRKs6BccHkGJlaDx8Pe/+XOvPi2rEdXPqrPd9QWb5Xp1iBfcgaDMyiOiA==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' + '@solana/codecs-strings@2.1.1': resolution: {integrity: sha512-uhj+A7eT6IJn4nuoX8jDdvZa7pjyZyN+k64EZ8+aUtJGt5Ft4NjRM8Jl5LljwYBWKQCgouVuigZHtTO2yAWExA==} engines: {node: '>=20.18.0'} @@ -2587,6 +2642,19 @@ packages: fastestsmallesttextencoderdecoder: ^1.0.22 typescript: '>=5.3.3' + '@solana/codecs-strings@4.0.0': + resolution: {integrity: sha512-XvyD+sQ1zyA0amfxbpoFZsucLoe+yASQtDiLUGMDg5TZ82IHE3B7n82jE8d8cTAqi0HgqQiwU13snPhvg1O0Ow==} + engines: {node: '>=20.18.0'} + peerDependencies: + fastestsmallesttextencoderdecoder: ^1.0.22 + typescript: '>=5.3.3' + + '@solana/codecs@4.0.0': + resolution: {integrity: sha512-qh+Le1u9QBDPubqUrFU5BGX3Kyj7x0viO6z2SUuM0CSqYUvwE7w724LXwDA9QoEL5JkED1rB3bQg4M0bDrABpA==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' + '@solana/errors@2.1.1': resolution: {integrity: sha512-sj6DaWNbSJFvLzT8UZoabMefQUfSW/8tXK7NTiagsDmh+Q87eyQDDC9L3z+mNmx9b6dEf6z660MOIplDD2nfEw==} engines: {node: '>=20.18.0'} @@ -2594,6 +2662,182 @@ packages: peerDependencies: typescript: '>=5.3.3' + '@solana/errors@4.0.0': + resolution: {integrity: sha512-3YEtvcMvtcnTl4HahqLt0VnaGVf7vVWOnt6/uPky5e0qV6BlxDSbGkbBzttNjxLXHognV0AQi3pjvrtfUnZmbg==} + engines: {node: '>=20.18.0'} + hasBin: true + peerDependencies: + typescript: '>=5.3.3' + + '@solana/fast-stable-stringify@4.0.0': + resolution: {integrity: sha512-sNJRi0RQ93vkGQ9VyFTSGm6mfKLk0FWOFpJLcqyP0BNUK1CugBaUMnxAmGqNaVSCktJagTSLqAMi9k1VSdh+Cg==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' + + '@solana/functional@4.0.0': + resolution: {integrity: sha512-duprxASuT0VXlHj3bLBdy9+ZpqdmCZhzCUmTsXps4UlDKr9PxSCQIQ+NK6OPhtBWOh1sNEcT1f1nY/MVqF/KHg==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' + + '@solana/instruction-plans@4.0.0': + resolution: {integrity: sha512-FcyptPR5XmKoj1EyF9xARiqy2BuF+CfrIxTU0WQn5Tix/y7whKYz5CCFtBlWbwIcGxQftmG5tAlcidgnCb7jVw==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' + + '@solana/instructions@4.0.0': + resolution: {integrity: sha512-/Lf3E+6mhe6EL7a3+9FY020yq71lVNgueplJGr221b4wP6ykwPVtoaAiNf+lIrRRYkW8DC81auhmjd2DYpND1w==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' + + '@solana/keys@4.0.0': + resolution: {integrity: sha512-aPz+LF9QK3EHjuklYBnnalcLVHUNz5s4m4DXNVGAtjJD7Q9zEu2dBUm9mRKwlLbQibNOEGa1m86HCjcboqXdjg==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' + + '@solana/kit@4.0.0': + resolution: {integrity: sha512-5c4qMRL+ciWewEtNZ2gX4wf4VpscZYXbWnU2kBiyQhWiqj8zzFIh6iCHbqMX/Myx3pOHfQs/m/iQCnQHPOag9Q==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' + + '@solana/nominal-types@4.0.0': + resolution: {integrity: sha512-zIjHZY+5uboigbzsNhHmF3AlP/xACYxbB0Cb1VAI9i+eFShMeu/3VIrj7x1vbq9hfQKGSFHNFGFqQTivdzpbLw==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' + + '@solana/options@4.0.0': + resolution: {integrity: sha512-QTjBh24a34At66mGfs0lVF1voug1KnA13IZkvcVPr52zFb90+xYiqYeKiICTaf3HkoeoKG+TC2Q0K64+se0+CQ==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' + + '@solana/programs@4.0.0': + resolution: {integrity: sha512-tJCNoKyDKfipGTsQtUO6R9EXk4l4ai+gYuD2R3NubJgMaLPBqIv3IMSCeDSvhuSCDuN2lQ1mLkQrDnE3lm0/iQ==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' + + '@solana/promises@4.0.0': + resolution: {integrity: sha512-zEh815+n2OrrQunZ6m1iuNcoZRc9YnQaTeivBSgl1SYfPaq/Qj/rRiK5DID25Njo4L44p5quu7aal3Bk/eR+tQ==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' + + '@solana/rpc-api@4.0.0': + resolution: {integrity: sha512-nfQkTJCIW3qzUDRrhvr9MBm9jKQ+dZn4ypK35UDPrV+QB5Gc9UmPJ6prvpPtDq8WoU7wqUzswKeY3k7qtgYjEg==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' + + '@solana/rpc-parsed-types@4.0.0': + resolution: {integrity: sha512-aOjwJwen5D0aDXoSths+ekdBO4mu7nmM+yASqCVW2PLN6v7NZmRBzV1/PgMFjDTiymVQj25ipCUvL395s1wsKg==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' + + '@solana/rpc-spec-types@4.0.0': + resolution: {integrity: sha512-rpFMIaetpubeyDXIlxV08vtmiDt7ME9527kCI61slHj6O2rbj+7fABhmlN6J4YDCcL/kfnMCxZyNna94DovHZA==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' + + '@solana/rpc-spec@4.0.0': + resolution: {integrity: sha512-9PFTFWjdgA/KFG4rgzbgA7gm9+aRDwsRJgI1aP7n3dGsGzYUp8vNgRQBhogWscEOETkgZNlsi/artLxgvHEHEg==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' + + '@solana/rpc-subscriptions-api@4.0.0': + resolution: {integrity: sha512-6/MzQT9VkcD7Rh8ExoGdbERTSEubA5eI+Q0R9FRuujl/SIy2BsWaNxaBMuZS0DFmKbIHM+m1ptUFdjKAVjGQuw==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' + + '@solana/rpc-subscriptions-channel-websocket@4.0.0': + resolution: {integrity: sha512-dc4cGfkQJEdkux/CXpItffuytnSU6wktReHEBL+2xaYmF+yGMBeBLzTvkCJ9BbGGfBMf06c5y5QH8X48W5CJdg==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' + ws: ^8.18.0 + + '@solana/rpc-subscriptions-spec@4.0.0': + resolution: {integrity: sha512-2ROfFymoy/TjDAlEPpsmSQAr6LZwG4l/UIhkW7+/VraRu7QPAycuWfSopJnG8D7F3fksICFSeQNwwgBXTN1TWA==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' + + '@solana/rpc-subscriptions@4.0.0': + resolution: {integrity: sha512-rM+R4Xpsym0tYF3sGAEpdY+D+c6fOMk/fhCEewR+veqdubRfvI5QEhq4kHs8qdKKuRbcpGmedPC306H+PQ6Hmg==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' + + '@solana/rpc-transformers@4.0.0': + resolution: {integrity: sha512-3B3C9zpqN2O76CJV9tethtybMFdT2ViN5b2u8sObftGNFqxPmjt7XmbOmPdn7zwLyRM5S2RuZShzfcVJpBf+yQ==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' + + '@solana/rpc-transport-http@4.0.0': + resolution: {integrity: sha512-RjXcQehF3wHm8eoIala+MrdmS3mDSPRl+xwEWzmA1QmBdQl44/XTNOdPJvNkqWXrzE+bAsZGfn0gVua/oCC+zQ==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' + + '@solana/rpc-types@4.0.0': + resolution: {integrity: sha512-mY4W6DQVaLf3M8hSSzIEtaRsVgLg9zv5qdjjYvxkALw0fzjkLW55h3ctGbJ/k+dNpYm9gcKg7zatA7eBNnNmtQ==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' + + '@solana/rpc@4.0.0': + resolution: {integrity: sha512-KF91ghi7P48aeWd4eSY5Fly/ioYz9ww2loQd/YqV3eLQwo3/2HUWd6r6lpSHsLh/HUoUkm+EsYmVN8r/3mE5fg==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' + + '@solana/signers@4.0.0': + resolution: {integrity: sha512-r3ZrltruadsQXmx3fsGOSqAZ3SsgD7zq/QB8sT6IOVcg11Pgdvx48/CEv7djdy44wF4HVpqNCZLfi12EhoaSXQ==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' + + '@solana/subscribable@4.0.0': + resolution: {integrity: sha512-lDI4HkDuGkmdnX7hSgvJsFFadkQxt0pLHIpZTxOt7/6KBDtNs63NTwJGd3d/EuA7ReXwYg5HDG0QtOm64divXQ==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' + + '@solana/sysvars@4.0.0': + resolution: {integrity: sha512-HUu2B8P7iRYWAt1KL/5a6nNTKp73y04cSxZ9PZf2Ap1/KE0/5D8WnkEfnurUQmU3zBner95d+szNOyWMNBOoTw==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' + + '@solana/transaction-confirmation@4.0.0': + resolution: {integrity: sha512-DTBIMB5/UCOpVyL5E0xwswtxs/PGeSD1VL5+C1UCPlggpZNIOlhZoaQqFO56wrJDFASzPMx+dakda5BUuhQkBg==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' + + '@solana/transaction-messages@4.0.0': + resolution: {integrity: sha512-rQo0rRyvkrROFZHUT0uL3vqeBBtxTsNKDtx8pZo6BC3TgGA7V1MoSC3rVOLwYCK6rK5NJZiYNjmneHz/7hVpwQ==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' + + '@solana/transactions@4.0.0': + resolution: {integrity: sha512-bmHIIVTQq+Wlqg4es91Ew4KSbOrvdfPsKg/pVha8ZR77huwvfqQMxRyYF4zMQ+Fm3QXGFKOU0RPVKKYic15jBw==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' + '@standard-schema/spec@1.0.0': resolution: {integrity: sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA==} @@ -3465,6 +3709,10 @@ packages: resolution: {integrity: sha512-/rFeCpNJQbhSZjGVwO9RFV3xPqbnERS8MmIQzCtD/zl6gpJuV/bMLuN92oG3F7d8oDEHHRrujSXNUr8fpjntKw==} engines: {node: '>=18'} + commander@14.0.1: + resolution: {integrity: sha512-2JkV3gUZUVrbNA+1sjBOYLsMZ5cEEl8GTFP2a4AVz5hvasAMCQ1D2l2le/cX+pV4N6ZU17zjUahLpIXRrnWL8A==} + engines: {node: '>=20'} + commander@4.1.1: resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==} engines: {node: '>= 6'} @@ -9015,17 +9263,71 @@ snapshots: '@socket.io/component-emitter@3.1.2': {} + '@solana-program/system@0.9.1(@solana/kit@4.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(ws@8.18.3))': + dependencies: + '@solana/kit': 4.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(ws@8.18.3) + + '@solana-program/token@0.6.0(@solana/kit@4.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(ws@8.18.3))': + dependencies: + '@solana/kit': 4.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(ws@8.18.3) + + '@solana/accounts@4.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': + dependencies: + '@solana/addresses': 4.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/codecs-core': 4.0.0(typescript@5.9.3) + '@solana/codecs-strings': 4.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/errors': 4.0.0(typescript@5.9.3) + '@solana/rpc-spec': 4.0.0(typescript@5.9.3) + '@solana/rpc-types': 4.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/addresses@4.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': + dependencies: + '@solana/assertions': 4.0.0(typescript@5.9.3) + '@solana/codecs-core': 4.0.0(typescript@5.9.3) + '@solana/codecs-strings': 4.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/errors': 4.0.0(typescript@5.9.3) + '@solana/nominal-types': 4.0.0(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/assertions@4.0.0(typescript@5.9.3)': + dependencies: + '@solana/errors': 4.0.0(typescript@5.9.3) + typescript: 5.9.3 + '@solana/codecs-core@2.1.1(typescript@5.9.3)': dependencies: '@solana/errors': 2.1.1(typescript@5.9.3) typescript: 5.9.3 + '@solana/codecs-core@4.0.0(typescript@5.9.3)': + dependencies: + '@solana/errors': 4.0.0(typescript@5.9.3) + typescript: 5.9.3 + + '@solana/codecs-data-structures@4.0.0(typescript@5.9.3)': + dependencies: + '@solana/codecs-core': 4.0.0(typescript@5.9.3) + '@solana/codecs-numbers': 4.0.0(typescript@5.9.3) + '@solana/errors': 4.0.0(typescript@5.9.3) + typescript: 5.9.3 + '@solana/codecs-numbers@2.1.1(typescript@5.9.3)': dependencies: '@solana/codecs-core': 2.1.1(typescript@5.9.3) '@solana/errors': 2.1.1(typescript@5.9.3) typescript: 5.9.3 + '@solana/codecs-numbers@4.0.0(typescript@5.9.3)': + dependencies: + '@solana/codecs-core': 4.0.0(typescript@5.9.3) + '@solana/errors': 4.0.0(typescript@5.9.3) + typescript: 5.9.3 + '@solana/codecs-strings@2.1.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': dependencies: '@solana/codecs-core': 2.1.1(typescript@5.9.3) @@ -9034,12 +9336,330 @@ snapshots: fastestsmallesttextencoderdecoder: 1.0.22 typescript: 5.9.3 + '@solana/codecs-strings@4.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': + dependencies: + '@solana/codecs-core': 4.0.0(typescript@5.9.3) + '@solana/codecs-numbers': 4.0.0(typescript@5.9.3) + '@solana/errors': 4.0.0(typescript@5.9.3) + fastestsmallesttextencoderdecoder: 1.0.22 + typescript: 5.9.3 + + '@solana/codecs@4.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': + dependencies: + '@solana/codecs-core': 4.0.0(typescript@5.9.3) + '@solana/codecs-data-structures': 4.0.0(typescript@5.9.3) + '@solana/codecs-numbers': 4.0.0(typescript@5.9.3) + '@solana/codecs-strings': 4.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/options': 4.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + '@solana/errors@2.1.1(typescript@5.9.3)': dependencies: chalk: 5.6.2 commander: 13.1.0 typescript: 5.9.3 + '@solana/errors@4.0.0(typescript@5.9.3)': + dependencies: + chalk: 5.6.2 + commander: 14.0.1 + typescript: 5.9.3 + + '@solana/fast-stable-stringify@4.0.0(typescript@5.9.3)': + dependencies: + typescript: 5.9.3 + + '@solana/functional@4.0.0(typescript@5.9.3)': + dependencies: + typescript: 5.9.3 + + '@solana/instruction-plans@4.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': + dependencies: + '@solana/errors': 4.0.0(typescript@5.9.3) + '@solana/instructions': 4.0.0(typescript@5.9.3) + '@solana/promises': 4.0.0(typescript@5.9.3) + '@solana/transaction-messages': 4.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/transactions': 4.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/instructions@4.0.0(typescript@5.9.3)': + dependencies: + '@solana/codecs-core': 4.0.0(typescript@5.9.3) + '@solana/errors': 4.0.0(typescript@5.9.3) + typescript: 5.9.3 + + '@solana/keys@4.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': + dependencies: + '@solana/assertions': 4.0.0(typescript@5.9.3) + '@solana/codecs-core': 4.0.0(typescript@5.9.3) + '@solana/codecs-strings': 4.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/errors': 4.0.0(typescript@5.9.3) + '@solana/nominal-types': 4.0.0(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/kit@4.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(ws@8.18.3)': + dependencies: + '@solana/accounts': 4.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/addresses': 4.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/codecs': 4.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/errors': 4.0.0(typescript@5.9.3) + '@solana/functional': 4.0.0(typescript@5.9.3) + '@solana/instruction-plans': 4.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/instructions': 4.0.0(typescript@5.9.3) + '@solana/keys': 4.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/programs': 4.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/rpc': 4.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/rpc-parsed-types': 4.0.0(typescript@5.9.3) + '@solana/rpc-spec-types': 4.0.0(typescript@5.9.3) + '@solana/rpc-subscriptions': 4.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(ws@8.18.3) + '@solana/rpc-types': 4.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/signers': 4.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/sysvars': 4.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/transaction-confirmation': 4.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(ws@8.18.3) + '@solana/transaction-messages': 4.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/transactions': 4.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + - ws + + '@solana/nominal-types@4.0.0(typescript@5.9.3)': + dependencies: + typescript: 5.9.3 + + '@solana/options@4.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': + dependencies: + '@solana/codecs-core': 4.0.0(typescript@5.9.3) + '@solana/codecs-data-structures': 4.0.0(typescript@5.9.3) + '@solana/codecs-numbers': 4.0.0(typescript@5.9.3) + '@solana/codecs-strings': 4.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/errors': 4.0.0(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/programs@4.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': + dependencies: + '@solana/addresses': 4.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/errors': 4.0.0(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/promises@4.0.0(typescript@5.9.3)': + dependencies: + typescript: 5.9.3 + + '@solana/rpc-api@4.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': + dependencies: + '@solana/addresses': 4.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/codecs-core': 4.0.0(typescript@5.9.3) + '@solana/codecs-strings': 4.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/errors': 4.0.0(typescript@5.9.3) + '@solana/keys': 4.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/rpc-parsed-types': 4.0.0(typescript@5.9.3) + '@solana/rpc-spec': 4.0.0(typescript@5.9.3) + '@solana/rpc-transformers': 4.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/rpc-types': 4.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/transaction-messages': 4.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/transactions': 4.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/rpc-parsed-types@4.0.0(typescript@5.9.3)': + dependencies: + typescript: 5.9.3 + + '@solana/rpc-spec-types@4.0.0(typescript@5.9.3)': + dependencies: + typescript: 5.9.3 + + '@solana/rpc-spec@4.0.0(typescript@5.9.3)': + dependencies: + '@solana/errors': 4.0.0(typescript@5.9.3) + '@solana/rpc-spec-types': 4.0.0(typescript@5.9.3) + typescript: 5.9.3 + + '@solana/rpc-subscriptions-api@4.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': + dependencies: + '@solana/addresses': 4.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/keys': 4.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/rpc-subscriptions-spec': 4.0.0(typescript@5.9.3) + '@solana/rpc-transformers': 4.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/rpc-types': 4.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/transaction-messages': 4.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/transactions': 4.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/rpc-subscriptions-channel-websocket@4.0.0(typescript@5.9.3)(ws@8.18.3)': + dependencies: + '@solana/errors': 4.0.0(typescript@5.9.3) + '@solana/functional': 4.0.0(typescript@5.9.3) + '@solana/rpc-subscriptions-spec': 4.0.0(typescript@5.9.3) + '@solana/subscribable': 4.0.0(typescript@5.9.3) + typescript: 5.9.3 + ws: 8.18.3 + + '@solana/rpc-subscriptions-spec@4.0.0(typescript@5.9.3)': + dependencies: + '@solana/errors': 4.0.0(typescript@5.9.3) + '@solana/promises': 4.0.0(typescript@5.9.3) + '@solana/rpc-spec-types': 4.0.0(typescript@5.9.3) + '@solana/subscribable': 4.0.0(typescript@5.9.3) + typescript: 5.9.3 + + '@solana/rpc-subscriptions@4.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(ws@8.18.3)': + dependencies: + '@solana/errors': 4.0.0(typescript@5.9.3) + '@solana/fast-stable-stringify': 4.0.0(typescript@5.9.3) + '@solana/functional': 4.0.0(typescript@5.9.3) + '@solana/promises': 4.0.0(typescript@5.9.3) + '@solana/rpc-spec-types': 4.0.0(typescript@5.9.3) + '@solana/rpc-subscriptions-api': 4.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/rpc-subscriptions-channel-websocket': 4.0.0(typescript@5.9.3)(ws@8.18.3) + '@solana/rpc-subscriptions-spec': 4.0.0(typescript@5.9.3) + '@solana/rpc-transformers': 4.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/rpc-types': 4.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/subscribable': 4.0.0(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + - ws + + '@solana/rpc-transformers@4.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': + dependencies: + '@solana/errors': 4.0.0(typescript@5.9.3) + '@solana/functional': 4.0.0(typescript@5.9.3) + '@solana/nominal-types': 4.0.0(typescript@5.9.3) + '@solana/rpc-spec-types': 4.0.0(typescript@5.9.3) + '@solana/rpc-types': 4.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/rpc-transport-http@4.0.0(typescript@5.9.3)': + dependencies: + '@solana/errors': 4.0.0(typescript@5.9.3) + '@solana/rpc-spec': 4.0.0(typescript@5.9.3) + '@solana/rpc-spec-types': 4.0.0(typescript@5.9.3) + typescript: 5.9.3 + undici-types: 7.16.0 + + '@solana/rpc-types@4.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': + dependencies: + '@solana/addresses': 4.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/codecs-core': 4.0.0(typescript@5.9.3) + '@solana/codecs-numbers': 4.0.0(typescript@5.9.3) + '@solana/codecs-strings': 4.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/errors': 4.0.0(typescript@5.9.3) + '@solana/nominal-types': 4.0.0(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/rpc@4.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': + dependencies: + '@solana/errors': 4.0.0(typescript@5.9.3) + '@solana/fast-stable-stringify': 4.0.0(typescript@5.9.3) + '@solana/functional': 4.0.0(typescript@5.9.3) + '@solana/rpc-api': 4.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/rpc-spec': 4.0.0(typescript@5.9.3) + '@solana/rpc-spec-types': 4.0.0(typescript@5.9.3) + '@solana/rpc-transformers': 4.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/rpc-transport-http': 4.0.0(typescript@5.9.3) + '@solana/rpc-types': 4.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/signers@4.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': + dependencies: + '@solana/addresses': 4.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/codecs-core': 4.0.0(typescript@5.9.3) + '@solana/errors': 4.0.0(typescript@5.9.3) + '@solana/instructions': 4.0.0(typescript@5.9.3) + '@solana/keys': 4.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/nominal-types': 4.0.0(typescript@5.9.3) + '@solana/transaction-messages': 4.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/transactions': 4.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/subscribable@4.0.0(typescript@5.9.3)': + dependencies: + '@solana/errors': 4.0.0(typescript@5.9.3) + typescript: 5.9.3 + + '@solana/sysvars@4.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': + dependencies: + '@solana/accounts': 4.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/codecs': 4.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/errors': 4.0.0(typescript@5.9.3) + '@solana/rpc-types': 4.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/transaction-confirmation@4.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(ws@8.18.3)': + dependencies: + '@solana/addresses': 4.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/codecs-strings': 4.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/errors': 4.0.0(typescript@5.9.3) + '@solana/keys': 4.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/promises': 4.0.0(typescript@5.9.3) + '@solana/rpc': 4.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/rpc-subscriptions': 4.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(ws@8.18.3) + '@solana/rpc-types': 4.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/transaction-messages': 4.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/transactions': 4.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + - ws + + '@solana/transaction-messages@4.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': + dependencies: + '@solana/addresses': 4.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/codecs-core': 4.0.0(typescript@5.9.3) + '@solana/codecs-data-structures': 4.0.0(typescript@5.9.3) + '@solana/codecs-numbers': 4.0.0(typescript@5.9.3) + '@solana/errors': 4.0.0(typescript@5.9.3) + '@solana/functional': 4.0.0(typescript@5.9.3) + '@solana/instructions': 4.0.0(typescript@5.9.3) + '@solana/nominal-types': 4.0.0(typescript@5.9.3) + '@solana/rpc-types': 4.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/transactions@4.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': + dependencies: + '@solana/addresses': 4.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/codecs-core': 4.0.0(typescript@5.9.3) + '@solana/codecs-data-structures': 4.0.0(typescript@5.9.3) + '@solana/codecs-numbers': 4.0.0(typescript@5.9.3) + '@solana/codecs-strings': 4.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/errors': 4.0.0(typescript@5.9.3) + '@solana/functional': 4.0.0(typescript@5.9.3) + '@solana/instructions': 4.0.0(typescript@5.9.3) + '@solana/keys': 4.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/nominal-types': 4.0.0(typescript@5.9.3) + '@solana/rpc-types': 4.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/transaction-messages': 4.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + '@standard-schema/spec@1.0.0': {} '@stoplight/better-ajv-errors@1.0.3(ajv@8.17.1)': @@ -9989,6 +10609,8 @@ snapshots: commander@13.1.0: {} + commander@14.0.1: {} + commander@4.1.1: {} commander@8.3.0: {}