From 43f9209a7e986dc86e7901063e112158061e628c Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Tue, 24 Mar 2026 03:50:23 +0000 Subject: [PATCH 01/11] refactor: rename ogDescription frontmatter field to imageDescription More specific naming: 'imageDescription' clarifies this field controls the text rendered inside OG images, distinct from 'description' which Vocs uses for HTML meta tags. --- scripts/generate-og-descriptions.ts | 2 +- src/pages/_api/api/og.tsx | 4 ++-- src/pages/brand.mdx | 2 +- src/pages/faq.mdx | 2 +- src/pages/guides/building-with-an-llm.mdx | 2 +- src/pages/guides/multiple-payment-methods.mdx | 2 +- src/pages/guides/one-time-payments.mdx | 2 +- src/pages/guides/pay-as-you-go.mdx | 2 +- src/pages/guides/streamed-payments.mdx | 2 +- src/pages/intents/charge.mdx | 2 +- src/pages/overview.mdx | 2 +- src/pages/payment-methods/card/charge.mdx | 2 +- src/pages/payment-methods/card/index.mdx | 2 +- src/pages/payment-methods/custom.mdx | 2 +- src/pages/payment-methods/index.mdx | 2 +- src/pages/payment-methods/lightning/charge.mdx | 2 +- src/pages/payment-methods/lightning/index.mdx | 2 +- src/pages/payment-methods/lightning/session.mdx | 2 +- src/pages/payment-methods/stripe/charge.mdx | 2 +- src/pages/payment-methods/stripe/index.mdx | 2 +- src/pages/payment-methods/tempo/charge.mdx | 2 +- src/pages/payment-methods/tempo/index.mdx | 2 +- src/pages/payment-methods/tempo/session.mdx | 2 +- src/pages/protocol/challenges.mdx | 2 +- src/pages/protocol/credentials.mdx | 2 +- src/pages/protocol/http-402.mdx | 2 +- src/pages/protocol/index.mdx | 2 +- src/pages/protocol/receipts.mdx | 2 +- src/pages/protocol/transports/http.mdx | 2 +- src/pages/protocol/transports/index.mdx | 2 +- src/pages/protocol/transports/mcp.mdx | 2 +- src/pages/quickstart/agent.mdx | 2 +- src/pages/quickstart/client.mdx | 2 +- src/pages/quickstart/index.mdx | 2 +- src/pages/quickstart/server.mdx | 2 +- src/pages/sdk/index.mdx | 2 +- src/pages/sdk/python/client.mdx | 2 +- src/pages/sdk/python/core.mdx | 2 +- src/pages/sdk/python/index.mdx | 2 +- src/pages/sdk/python/server.mdx | 2 +- src/pages/sdk/rust/client.mdx | 2 +- src/pages/sdk/rust/core.mdx | 2 +- src/pages/sdk/rust/index.mdx | 2 +- src/pages/sdk/rust/server.mdx | 2 +- src/pages/sdk/typescript/cli.mdx | 2 +- src/pages/sdk/typescript/core/Expires.mdx | 2 +- src/pages/sdk/typescript/index.mdx | 2 +- src/pages/services.mdx | 2 +- 48 files changed, 49 insertions(+), 49 deletions(-) diff --git a/scripts/generate-og-descriptions.ts b/scripts/generate-og-descriptions.ts index 04e4dc95..ee58407a 100644 --- a/scripts/generate-og-descriptions.ts +++ b/scripts/generate-og-descriptions.ts @@ -11,7 +11,7 @@ function extractOgDescription(content: string): string | null { const match = content.match(/^---\s*\n([\s\S]*?)\n---/); if (!match) return null; const fm = match[1]; - const descMatch = fm.match(/^ogDescription:\s*"(.+)"\s*$/m); + const descMatch = fm.match(/^imageDescription:\s*"(.+)"\s*$/m); return descMatch ? descMatch[1] : null; } diff --git a/src/pages/_api/api/og.tsx b/src/pages/_api/api/og.tsx index d8798f59..e2d67fa6 100644 --- a/src/pages/_api/api/og.tsx +++ b/src/pages/_api/api/og.tsx @@ -1,7 +1,7 @@ // @ts-nocheck – server-only, uses Vite ?raw import and resvg native module import { initWasm, Resvg } from "@resvg/resvg-wasm"; import resvgWasm from "@resvg/resvg-wasm/index_bg.wasm?url"; -import ogDescriptions from "../../../generated/og-descriptions.json"; +import imageDescriptions from "../../../generated/og-descriptions.json"; import templateSvg from "./og-template.svg?raw"; const BLOB = "https://wgfdjv2jfqz2dlpx.public.blob.vercel-storage.com"; @@ -230,7 +230,7 @@ export async function GET(request: Request) { const rawDescription = url.searchParams.get("description") || ""; const path = decodeURIComponent(url.searchParams.get("path") || ""); const description = - (ogDescriptions as Record)[path] || rawDescription; + (imageDescriptions as Record)[path] || rawDescription; const category = getCategoryForPath(path); const subcategory = getSubcategoryForPath(path); diff --git a/src/pages/brand.mdx b/src/pages/brand.mdx index 5179c188..237184a2 100644 --- a/src/pages/brand.mdx +++ b/src/pages/brand.mdx @@ -1,7 +1,7 @@ --- title: "Brand assets and guidelines" description: "Download official MPP logos, wordmarks, and brand assets. Guidelines for using the Machine Payments Protocol brand in your project or integration." -ogDescription: "Download MPP logos, icons, and brand assets for use in your documentation and marketing materials" +imageDescription: "Download MPP logos, icons, and brand assets for use in your documentation and marketing materials" --- # Brand [MPP brand assets and guidelines] diff --git a/src/pages/faq.mdx b/src/pages/faq.mdx index 26cc1c88..455d2fdf 100644 --- a/src/pages/faq.mdx +++ b/src/pages/faq.mdx @@ -1,6 +1,6 @@ --- description: "Answers to common questions about MPP—payment methods, settlement, pricing, security, and how the protocol compares to API keys and subscriptions." -ogDescription: "Common questions about the Machine Payments Protocol, payment methods, wallets, and how MPP compares to other solutions" +imageDescription: "Common questions about the Machine Payments Protocol, payment methods, wallets, and how MPP compares to other solutions" --- # Frequently asked questions [Common questions about the Machine Payments Protocol] diff --git a/src/pages/guides/building-with-an-llm.mdx b/src/pages/guides/building-with-an-llm.mdx index b04bbbce..96dd9189 100644 --- a/src/pages/guides/building-with-an-llm.mdx +++ b/src/pages/guides/building-with-an-llm.mdx @@ -1,7 +1,7 @@ --- title: Build with an LLM description: Use llms-full.txt to give your agent complete MPP context. -ogDescription: "Give your LLM or AI agent the context it needs to build MPP integrations from your codebase" +imageDescription: "Give your LLM or AI agent the context it needs to build MPP integrations from your codebase" --- import { Card, Cards } from 'vocs' diff --git a/src/pages/guides/multiple-payment-methods.mdx b/src/pages/guides/multiple-payment-methods.mdx index 3b1db52c..7fd45acb 100644 --- a/src/pages/guides/multiple-payment-methods.mdx +++ b/src/pages/guides/multiple-payment-methods.mdx @@ -1,6 +1,6 @@ --- description: "Accept Tempo stablecoins, Stripe cards, and Lightning Bitcoin on a single API endpoint. Serve a multi-method 402 Challenge and let clients choose." -ogDescription: "Offer your users a choice of payment methods including stablecoins, cards, and Lightning" +imageDescription: "Offer your users a choice of payment methods including stablecoins, cards, and Lightning" --- import { Cards } from 'vocs' diff --git a/src/pages/guides/one-time-payments.mdx b/src/pages/guides/one-time-payments.mdx index 032db386..44f11127 100644 --- a/src/pages/guides/one-time-payments.mdx +++ b/src/pages/guides/one-time-payments.mdx @@ -1,5 +1,5 @@ --- -ogDescription: "Accept single fixed-price payments for API calls using the charge intent with any payment method" +imageDescription: "Accept single fixed-price payments for API calls using the charge intent with any payment method" --- import { Cards, Tabs, Tab } from 'vocs' diff --git a/src/pages/guides/pay-as-you-go.mdx b/src/pages/guides/pay-as-you-go.mdx index 81ae4b90..960743d9 100644 --- a/src/pages/guides/pay-as-you-go.mdx +++ b/src/pages/guides/pay-as-you-go.mdx @@ -1,6 +1,6 @@ --- description: "Build a payment-gated API with session-based billing using mppx payment channels. Charge per request with near-zero latency overhead." -ogDescription: "Accept metered usage-based payments using sessions that track consumption over time" +imageDescription: "Accept metered usage-based payments using sessions that track consumption over time" --- import { Cards, Tabs, Tab } from 'vocs' diff --git a/src/pages/guides/streamed-payments.mdx b/src/pages/guides/streamed-payments.mdx index cb855262..a2f91d15 100644 --- a/src/pages/guides/streamed-payments.mdx +++ b/src/pages/guides/streamed-payments.mdx @@ -1,6 +1,6 @@ --- description: "Accept streamed payments over Server-Sent Events with mppx. Bill per token in real time using Tempo payment channels for LLM inference APIs." -ogDescription: "Accept continuous real-time payments that stream value as a service is consumed" +imageDescription: "Accept continuous real-time payments that stream value as a service is consumed" --- import { Cards, Tabs, Tab } from "vocs"; diff --git a/src/pages/intents/charge.mdx b/src/pages/intents/charge.mdx index 5a617c60..5a84b593 100644 --- a/src/pages/intents/charge.mdx +++ b/src/pages/intents/charge.mdx @@ -1,6 +1,6 @@ --- title: "Charge intent for one-time payments" -ogDescription: "Immediate one-time payments where the full amount is collected in a single request-response cycle" +imageDescription: "Immediate one-time payments where the full amount is collected in a single request-response cycle" --- import { Cards } from 'vocs' diff --git a/src/pages/overview.mdx b/src/pages/overview.mdx index 082853eb..f39c61ff 100644 --- a/src/pages/overview.mdx +++ b/src/pages/overview.mdx @@ -1,6 +1,6 @@ --- description: "MPP standardizes HTTP 402 for machine-to-machine payments. Learn how agents, apps, and services exchange payments in the same HTTP request." -ogDescription: "The open protocol for machine-to-machine payments, built on an open IETF specification for HTTP 402" +imageDescription: "The open protocol for machine-to-machine payments, built on an open IETF specification for HTTP 402" --- import { Cards } from 'vocs' diff --git a/src/pages/payment-methods/card/charge.mdx b/src/pages/payment-methods/card/charge.mdx index f8440704..08214f67 100755 --- a/src/pages/payment-methods/card/charge.mdx +++ b/src/pages/payment-methods/card/charge.mdx @@ -1,5 +1,5 @@ --- -ogDescription: "One-time payments using encrypted network tokens for secure card-based transactions" +imageDescription: "One-time payments using encrypted network tokens for secure card-based transactions" --- import { Cards } from 'vocs' diff --git a/src/pages/payment-methods/card/index.mdx b/src/pages/payment-methods/card/index.mdx index ef5ad5ac..a53a5475 100755 --- a/src/pages/payment-methods/card/index.mdx +++ b/src/pages/payment-methods/card/index.mdx @@ -1,6 +1,6 @@ --- title: "Card payment method" -ogDescription: "Card payments via encrypted network tokens for direct card-present and card-not-present flows" +imageDescription: "Card payments via encrypted network tokens for direct card-present and card-not-present flows" --- import { Cards } from 'vocs' diff --git a/src/pages/payment-methods/custom.mdx b/src/pages/payment-methods/custom.mdx index 7a7947ba..19eaf362 100644 --- a/src/pages/payment-methods/custom.mdx +++ b/src/pages/payment-methods/custom.mdx @@ -1,6 +1,6 @@ --- title: "Custom payment methods" -ogDescription: "Build your own payment method by implementing the core challenge-credential-receipt control flow" +imageDescription: "Build your own payment method by implementing the core challenge-credential-receipt control flow" --- import { Cards } from 'vocs' diff --git a/src/pages/payment-methods/index.mdx b/src/pages/payment-methods/index.mdx index be71a055..e0c86d9d 100644 --- a/src/pages/payment-methods/index.mdx +++ b/src/pages/payment-methods/index.mdx @@ -1,5 +1,5 @@ --- -ogDescription: "Available payment methods in MPP and how to choose the right one for your use case" +imageDescription: "Available payment methods in MPP and how to choose the right one for your use case" --- import { Cards, Tab, Tabs } from 'vocs' diff --git a/src/pages/payment-methods/lightning/charge.mdx b/src/pages/payment-methods/lightning/charge.mdx index 53c6015f..c9002231 100644 --- a/src/pages/payment-methods/lightning/charge.mdx +++ b/src/pages/payment-methods/lightning/charge.mdx @@ -1,5 +1,5 @@ --- -ogDescription: "One-time payments using BOLT11 invoices settled instantly over the Lightning Network" +imageDescription: "One-time payments using BOLT11 invoices settled instantly over the Lightning Network" --- import { Cards } from 'vocs' diff --git a/src/pages/payment-methods/lightning/index.mdx b/src/pages/payment-methods/lightning/index.mdx index 229c16d4..c3d509b4 100644 --- a/src/pages/payment-methods/lightning/index.mdx +++ b/src/pages/payment-methods/lightning/index.mdx @@ -1,5 +1,5 @@ --- -ogDescription: "Bitcoin payments over the Lightning Network for instant, low-fee global transactions" +imageDescription: "Bitcoin payments over the Lightning Network for instant, low-fee global transactions" --- # Lightning [Bitcoin payments over the Lightning Network] diff --git a/src/pages/payment-methods/lightning/session.mdx b/src/pages/payment-methods/lightning/session.mdx index 23f20907..20cf54e3 100644 --- a/src/pages/payment-methods/lightning/session.mdx +++ b/src/pages/payment-methods/lightning/session.mdx @@ -1,5 +1,5 @@ --- -ogDescription: "Pay-as-you-go streaming payments over Lightning using incrementally settled micropayments" +imageDescription: "Pay-as-you-go streaming payments over Lightning using incrementally settled micropayments" --- import { Cards, Tab, Tabs } from 'vocs' diff --git a/src/pages/payment-methods/stripe/charge.mdx b/src/pages/payment-methods/stripe/charge.mdx index 0a70009f..31218b8c 100644 --- a/src/pages/payment-methods/stripe/charge.mdx +++ b/src/pages/payment-methods/stripe/charge.mdx @@ -1,5 +1,5 @@ --- -ogDescription: "One-time payments using Stripe Shared Payment Tokens for seamless card-based transactions" +imageDescription: "One-time payments using Stripe Shared Payment Tokens for seamless card-based transactions" --- import { Cards } from 'vocs' diff --git a/src/pages/payment-methods/stripe/index.mdx b/src/pages/payment-methods/stripe/index.mdx index ca937c08..97168562 100644 --- a/src/pages/payment-methods/stripe/index.mdx +++ b/src/pages/payment-methods/stripe/index.mdx @@ -1,6 +1,6 @@ --- title: "Stripe payment method" -ogDescription: "Accept card, wallet, and bank transfer payments through Stripe's global payment infrastructure" +imageDescription: "Accept card, wallet, and bank transfer payments through Stripe's global payment infrastructure" --- import { Cards } from 'vocs' diff --git a/src/pages/payment-methods/tempo/charge.mdx b/src/pages/payment-methods/tempo/charge.mdx index b8281eca..a071b3cb 100644 --- a/src/pages/payment-methods/tempo/charge.mdx +++ b/src/pages/payment-methods/tempo/charge.mdx @@ -1,5 +1,5 @@ --- -ogDescription: "One-time TIP-20 stablecoin token transfers settled on-chain with cryptographic receipts" +imageDescription: "One-time TIP-20 stablecoin token transfers settled on-chain with cryptographic receipts" --- import { Cards } from "vocs"; diff --git a/src/pages/payment-methods/tempo/index.mdx b/src/pages/payment-methods/tempo/index.mdx index fe56b102..edfbde31 100644 --- a/src/pages/payment-methods/tempo/index.mdx +++ b/src/pages/payment-methods/tempo/index.mdx @@ -1,6 +1,6 @@ --- title: "Tempo stablecoin payments" -ogDescription: "Stablecoin payments on the Tempo blockchain with near-instant finality and low transaction costs" +imageDescription: "Stablecoin payments on the Tempo blockchain with near-instant finality and low transaction costs" --- import { Badge } from 'vocs' diff --git a/src/pages/payment-methods/tempo/session.mdx b/src/pages/payment-methods/tempo/session.mdx index b251ad05..667771de 100644 --- a/src/pages/payment-methods/tempo/session.mdx +++ b/src/pages/payment-methods/tempo/session.mdx @@ -1,5 +1,5 @@ --- -ogDescription: "Low-cost high-throughput streaming payments using off-chain state channels on Tempo" +imageDescription: "Low-cost high-throughput streaming payments using off-chain state channels on Tempo" --- import { Cards, Tab, Tabs } from 'vocs' diff --git a/src/pages/protocol/challenges.mdx b/src/pages/protocol/challenges.mdx index 3d70174f..af9d0f59 100644 --- a/src/pages/protocol/challenges.mdx +++ b/src/pages/protocol/challenges.mdx @@ -1,5 +1,5 @@ --- -ogDescription: "Server-issued payment requirements that describe the amount, currency, and accepted payment methods" +imageDescription: "Server-issued payment requirements that describe the amount, currency, and accepted payment methods" --- # Challenges [Server-issued payment requirements] diff --git a/src/pages/protocol/credentials.mdx b/src/pages/protocol/credentials.mdx index 2d80b871..7d76bf2b 100644 --- a/src/pages/protocol/credentials.mdx +++ b/src/pages/protocol/credentials.mdx @@ -1,5 +1,5 @@ --- -ogDescription: "Client-submitted payment proofs that demonstrate a valid payment has been made for a request" +imageDescription: "Client-submitted payment proofs that demonstrate a valid payment has been made for a request" --- # Credentials [Client-submitted payment proofs] diff --git a/src/pages/protocol/http-402.mdx b/src/pages/protocol/http-402.mdx index 28254c1d..8b295127 100644 --- a/src/pages/protocol/http-402.mdx +++ b/src/pages/protocol/http-402.mdx @@ -1,6 +1,6 @@ --- description: "HTTP 402 Payment Required signals that a resource requires payment. Learn when and how MPP servers return 402 with a WWW-Authenticate Challenge." -ogDescription: "How MPP uses the HTTP 402 status code to signal that payment is required before accessing a resource" +imageDescription: "How MPP uses the HTTP 402 status code to signal that payment is required before accessing a resource" --- # HTTP 402 payment required [The status code that signals payment is required] diff --git a/src/pages/protocol/index.mdx b/src/pages/protocol/index.mdx index f1f0433a..3eac29af 100644 --- a/src/pages/protocol/index.mdx +++ b/src/pages/protocol/index.mdx @@ -1,6 +1,6 @@ --- description: "The Machine Payments Protocol standardizes HTTP 402 with an extensible challenge–credential–receipt flow that works with any payment network." -ogDescription: "An extensible framework for standardizing HTTP 402 Payment Required for machine-to-machine payments" +imageDescription: "An extensible framework for standardizing HTTP 402 Payment Required for machine-to-machine payments" --- import { Badge } from "vocs"; diff --git a/src/pages/protocol/receipts.mdx b/src/pages/protocol/receipts.mdx index 47adaecf..c755511b 100644 --- a/src/pages/protocol/receipts.mdx +++ b/src/pages/protocol/receipts.mdx @@ -1,7 +1,7 @@ --- title: "Payment receipts and verification" description: "Receipts confirm successful payment in MPP. Return them in the Payment-Receipt header so clients can verify that the server accepted their Credential." -ogDescription: "Server-issued acknowledgments that confirm successful payment and grant access to the resource" +imageDescription: "Server-issued acknowledgments that confirm successful payment and grant access to the resource" --- # Receipts [Server acknowledgment of successful payment] diff --git a/src/pages/protocol/transports/http.mdx b/src/pages/protocol/transports/http.mdx index 34d83cbc..e2a4c4e5 100644 --- a/src/pages/protocol/transports/http.mdx +++ b/src/pages/protocol/transports/http.mdx @@ -1,6 +1,6 @@ --- description: "The HTTP transport maps MPP payment flows to standard HTTP headers—WWW-Authenticate for Challenges, Authorization for Credentials, and Payment-Receipt." -ogDescription: "Payment flows using standard HTTP headers for challenges, credentials, and receipts" +imageDescription: "Payment flows using standard HTTP headers for challenges, credentials, and receipts" --- import { Badge } from 'vocs' diff --git a/src/pages/protocol/transports/index.mdx b/src/pages/protocol/transports/index.mdx index 619facdd..5eb44a42 100644 --- a/src/pages/protocol/transports/index.mdx +++ b/src/pages/protocol/transports/index.mdx @@ -1,6 +1,6 @@ --- description: "MPP defines transport bindings for HTTP and MCP. Learn how Challenges, Credentials, and Receipts map to headers and JSON-RPC messages." -ogDescription: "How MPP payment flows are carried over different transport protocols like HTTP and MCP" +imageDescription: "How MPP payment flows are carried over different transport protocols like HTTP and MCP" --- # Transports [HTTP and MCP bindings for payment flows] diff --git a/src/pages/protocol/transports/mcp.mdx b/src/pages/protocol/transports/mcp.mdx index f38d54fe..d43ab2c0 100644 --- a/src/pages/protocol/transports/mcp.mdx +++ b/src/pages/protocol/transports/mcp.mdx @@ -1,5 +1,5 @@ --- -ogDescription: "Payment flows for AI tool calls using MCP and JSON-RPC as the underlying transport" +imageDescription: "Payment flows for AI tool calls using MCP and JSON-RPC as the underlying transport" --- import { Badge } from 'vocs' diff --git a/src/pages/quickstart/agent.mdx b/src/pages/quickstart/agent.mdx index 9371724a..2b73f5f3 100644 --- a/src/pages/quickstart/agent.mdx +++ b/src/pages/quickstart/agent.mdx @@ -1,6 +1,6 @@ --- description: "Connect your coding agent to MPP-enabled services. Set up Tempo Wallet or the mppx SDK to handle 402 payment flows automatically." -ogDescription: "Connect your AI agent to MPP-enabled services and handle payments automatically" +imageDescription: "Connect your AI agent to MPP-enabled services and handle payments automatically" --- import { Badge, Card, Cards, Tab, Tabs } from 'vocs' diff --git a/src/pages/quickstart/client.mdx b/src/pages/quickstart/client.mdx index 15e6d539..cc3c4ad7 100644 --- a/src/pages/quickstart/client.mdx +++ b/src/pages/quickstart/client.mdx @@ -1,6 +1,6 @@ --- description: "Handle payment-gated resources in your app. Use the mppx client SDK to intercept 402 responses, pay, and retry—all automatically." -ogDescription: "Handle payment-gated resources automatically in your frontend or backend application" +imageDescription: "Handle payment-gated resources automatically in your frontend or backend application" --- import { Cards } from 'vocs' diff --git a/src/pages/quickstart/index.mdx b/src/pages/quickstart/index.mdx index d14f22e2..57721e46 100644 --- a/src/pages/quickstart/index.mdx +++ b/src/pages/quickstart/index.mdx @@ -1,6 +1,6 @@ --- description: "Get started with MPP in minutes. Protect your API with payments, connect your agent, or integrate your app with MPP-enabled services." -ogDescription: "Get started with MPP in minutes using the TypeScript, Python, or Rust SDK" +imageDescription: "Get started with MPP in minutes using the TypeScript, Python, or Rust SDK" --- import { Cards } from 'vocs' diff --git a/src/pages/quickstart/server.mdx b/src/pages/quickstart/server.mdx index e4b030bb..f8748316 100644 --- a/src/pages/quickstart/server.mdx +++ b/src/pages/quickstart/server.mdx @@ -1,6 +1,6 @@ --- description: "Add payment-gated access to your API with mppx. Accept stablecoins, cards, and Bitcoin in a few lines of code using the MPP server SDK." -ogDescription: "Charge for access to protected API resources using challenges, credentials, and receipts" +imageDescription: "Charge for access to protected API resources using challenges, credentials, and receipts" --- import { Badge, Cards } from 'vocs' diff --git a/src/pages/sdk/index.mdx b/src/pages/sdk/index.mdx index 7d619e4a..cc9d7fd9 100644 --- a/src/pages/sdk/index.mdx +++ b/src/pages/sdk/index.mdx @@ -1,7 +1,7 @@ --- title: "SDKs and client libraries" description: "Official MPP SDK implementations in TypeScript, Python, and Rust. Libraries for building MPP clients and servers with full protocol support." -ogDescription: "Official MPP SDK implementations in TypeScript, Python, and Rust for clients, servers, and agents" +imageDescription: "Official MPP SDK implementations in TypeScript, Python, and Rust for clients, servers, and agents" --- import { Cards } from 'vocs' diff --git a/src/pages/sdk/python/client.mdx b/src/pages/sdk/python/client.mdx index 94207965..b0a9cc67 100644 --- a/src/pages/sdk/python/client.mdx +++ b/src/pages/sdk/python/client.mdx @@ -1,6 +1,6 @@ --- title: "Python MPP client" -ogDescription: "Handle HTTP 402 responses automatically and manage payment flows in Python clients" +imageDescription: "Handle HTTP 402 responses automatically and manage payment flows in Python clients" --- # Client [Handle 402 responses automatically] diff --git a/src/pages/sdk/python/core.mdx b/src/pages/sdk/python/core.mdx index 49691ce6..310ad0fb 100644 --- a/src/pages/sdk/python/core.mdx +++ b/src/pages/sdk/python/core.mdx @@ -1,5 +1,5 @@ --- -ogDescription: "Challenge, Credential, and Receipt primitive types for working with the MPP protocol in Python" +imageDescription: "Challenge, Credential, and Receipt primitive types for working with the MPP protocol in Python" --- # Core Types [Challenge, Credential, and Receipt primitives] diff --git a/src/pages/sdk/python/index.mdx b/src/pages/sdk/python/index.mdx index 76143167..b494a1fa 100644 --- a/src/pages/sdk/python/index.mdx +++ b/src/pages/sdk/python/index.mdx @@ -1,5 +1,5 @@ --- -ogDescription: "The pympp Python library for building MPP clients and servers in Python applications" +imageDescription: "The pympp Python library for building MPP clients and servers in Python applications" --- import * as SdkBadge from '../../../components/SdkBadge' diff --git a/src/pages/sdk/python/server.mdx b/src/pages/sdk/python/server.mdx index ba7cfe46..a813f9c7 100644 --- a/src/pages/sdk/python/server.mdx +++ b/src/pages/sdk/python/server.mdx @@ -1,5 +1,5 @@ --- -ogDescription: "Protect API endpoints with payment requirements and verify credentials in Python servers" +imageDescription: "Protect API endpoints with payment requirements and verify credentials in Python servers" --- # Server [Protect endpoints with payment requirements] diff --git a/src/pages/sdk/rust/client.mdx b/src/pages/sdk/rust/client.mdx index 26ac7a2b..94b443f1 100644 --- a/src/pages/sdk/rust/client.mdx +++ b/src/pages/sdk/rust/client.mdx @@ -1,5 +1,5 @@ --- -ogDescription: "Handle HTTP 402 responses automatically and manage payment flows in Rust clients" +imageDescription: "Handle HTTP 402 responses automatically and manage payment flows in Rust clients" --- # Client [Handle 402 responses automatically] diff --git a/src/pages/sdk/rust/core.mdx b/src/pages/sdk/rust/core.mdx index 3c0f2984..a1891c42 100644 --- a/src/pages/sdk/rust/core.mdx +++ b/src/pages/sdk/rust/core.mdx @@ -1,5 +1,5 @@ --- -ogDescription: "Challenge, Credential, and Receipt primitive types for working with the MPP protocol in Rust" +imageDescription: "Challenge, Credential, and Receipt primitive types for working with the MPP protocol in Rust" --- # Core types [Challenge, Credential, and Receipt primitives] diff --git a/src/pages/sdk/rust/index.mdx b/src/pages/sdk/rust/index.mdx index 9b23ba41..1b2fe64d 100644 --- a/src/pages/sdk/rust/index.mdx +++ b/src/pages/sdk/rust/index.mdx @@ -1,6 +1,6 @@ --- title: "Rust SDK for MPP" -ogDescription: "The mpp Rust library for high-performance MPP clients and servers with zero-copy parsing" +imageDescription: "The mpp Rust library for high-performance MPP clients and servers with zero-copy parsing" --- import * as SdkBadge from '../../../components/SdkBadge' diff --git a/src/pages/sdk/rust/server.mdx b/src/pages/sdk/rust/server.mdx index 1384d337..af751a2a 100644 --- a/src/pages/sdk/rust/server.mdx +++ b/src/pages/sdk/rust/server.mdx @@ -1,5 +1,5 @@ --- -ogDescription: "Protect API endpoints with payment requirements and verify credentials in Rust servers" +imageDescription: "Protect API endpoints with payment requirements and verify credentials in Rust servers" --- # Server [Protect endpoints with payment requirements] diff --git a/src/pages/sdk/typescript/cli.mdx b/src/pages/sdk/typescript/cli.mdx index 4d5b370d..07cf815d 100644 --- a/src/pages/sdk/typescript/cli.mdx +++ b/src/pages/sdk/typescript/cli.mdx @@ -1,5 +1,5 @@ --- -ogDescription: "Built-in command-line tool for making paid HTTP requests and managing wallets from the terminal" +imageDescription: "Built-in command-line tool for making paid HTTP requests and managing wallets from the terminal" --- # CLI Reference [Built-in command-line tool for paid HTTP requests] diff --git a/src/pages/sdk/typescript/core/Expires.mdx b/src/pages/sdk/typescript/core/Expires.mdx index 38437bca..a47503e4 100644 --- a/src/pages/sdk/typescript/core/Expires.mdx +++ b/src/pages/sdk/typescript/core/Expires.mdx @@ -1,6 +1,6 @@ --- title: "Expires utility functions" -ogDescription: "Generate relative expiration timestamps for challenges, credentials, and payment requests" +imageDescription: "Generate relative expiration timestamps for challenges, credentials, and payment requests" --- # `Expires` [Generate relative expiration timestamps] diff --git a/src/pages/sdk/typescript/index.mdx b/src/pages/sdk/typescript/index.mdx index 2c06d9c1..98dfb372 100644 --- a/src/pages/sdk/typescript/index.mdx +++ b/src/pages/sdk/typescript/index.mdx @@ -1,5 +1,5 @@ --- -ogDescription: "The mppx TypeScript library for building MPP clients, servers, and middleware integrations" +imageDescription: "The mppx TypeScript library for building MPP clients, servers, and middleware integrations" --- import * as SdkBadge from '../../../components/SdkBadge' diff --git a/src/pages/services.mdx b/src/pages/services.mdx index 60e41c6b..a99381c8 100644 --- a/src/pages/services.mdx +++ b/src/pages/services.mdx @@ -4,7 +4,7 @@ layout: minimal showAskAi: false showOutline: false showSearch: false -ogDescription: "Discover MPP-enabled services your agents and applications can pay for and use" +imageDescription: "Discover MPP-enabled services your agents and applications can pay for and use" --- import { ServicesPage } from "../components/ServicesPage"; From 30724b05487297392660d7a23d5e6d3ebd081dd4 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Tue, 24 Mar 2026 03:54:05 +0000 Subject: [PATCH 02/11] fix: 404 ASCII art compressed vertically on mobile Increase line-height from 1.15 to 1.8 and bump minimum font size from 2.5px to 3px to prevent the ASCII art from being squashed on small screens. --- src/components/NotFoundPage.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/NotFoundPage.tsx b/src/components/NotFoundPage.tsx index ac8c4a13..d15004d3 100644 --- a/src/components/NotFoundPage.tsx +++ b/src/components/NotFoundPage.tsx @@ -161,7 +161,7 @@ export function NotFoundPage() { className="overflow-hidden max-w-full mb-8" style={{ fontFamily: "monospace", - lineHeight: 1.15, + lineHeight: 1.8, whiteSpace: "pre", letterSpacing: "1px", color: "var(--vocs-text-color-heading)", @@ -169,7 +169,7 @@ export function NotFoundPage() { }} >
{mppLines.map((mppLine, lineIdx) => { From 2e74ddd32e24f604d9f6a018d59fe7dba08a7ffd Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Tue, 24 Mar 2026 09:16:44 +0000 Subject: [PATCH 03/11] fix: load VTCDuBois fonts directly from Vercel Blob In SSR/dynamic rendering mode, the Node.js server handles all requests before Vercel's rewrite layer fires. Since VTCDuBois font files are gitignored and not in the deployment, the server returns 404 before the rewrite to Blob can kick in. Fix by pointing @font-face src and preload links directly to the Blob URL. Remove the now-unnecessary vercel.json rewrite. --- public/icons/browser-use.svg | 1 - public/icons/builtwith.svg | 1 - public/icons/clado.svg | 1 - public/icons/diffbot.svg | 1 - public/icons/edgar-search.svg | 1 - public/icons/edgar.svg | 1 - public/icons/hunter.svg | 1 - public/icons/judge0.svg | 1 - public/icons/laso.svg | 1 - public/icons/mapbox.svg | 1 - public/icons/mathpix.svg | 1 - public/icons/openweather.svg | 1 - public/icons/perplexity.svg | 1 - public/icons/rentcast.svg | 1 - public/icons/replicate.svg | 1 - public/icons/stability-ai.svg | 1 - public/icons/suno.svg | 1 - src/pages/_layout.tsx | 4 ++-- src/pages/_root.css | 4 ++-- vercel.json | 6 ------ 20 files changed, 4 insertions(+), 27 deletions(-) delete mode 100644 public/icons/browser-use.svg delete mode 100644 public/icons/builtwith.svg delete mode 100644 public/icons/clado.svg delete mode 100644 public/icons/diffbot.svg delete mode 100644 public/icons/edgar-search.svg delete mode 100644 public/icons/edgar.svg delete mode 100644 public/icons/hunter.svg delete mode 100644 public/icons/judge0.svg delete mode 100644 public/icons/laso.svg delete mode 100644 public/icons/mapbox.svg delete mode 100644 public/icons/mathpix.svg delete mode 100644 public/icons/openweather.svg delete mode 100644 public/icons/perplexity.svg delete mode 100644 public/icons/rentcast.svg delete mode 100644 public/icons/replicate.svg delete mode 100644 public/icons/stability-ai.svg delete mode 100644 public/icons/suno.svg diff --git a/public/icons/browser-use.svg b/public/icons/browser-use.svg deleted file mode 100644 index c5653e9a..00000000 --- a/public/icons/browser-use.svg +++ /dev/null @@ -1 +0,0 @@ -B \ No newline at end of file diff --git a/public/icons/builtwith.svg b/public/icons/builtwith.svg deleted file mode 100644 index c5653e9a..00000000 --- a/public/icons/builtwith.svg +++ /dev/null @@ -1 +0,0 @@ -B \ No newline at end of file diff --git a/public/icons/clado.svg b/public/icons/clado.svg deleted file mode 100644 index 6397c9fe..00000000 --- a/public/icons/clado.svg +++ /dev/null @@ -1 +0,0 @@ -C \ No newline at end of file diff --git a/public/icons/diffbot.svg b/public/icons/diffbot.svg deleted file mode 100644 index 4e7b94c5..00000000 --- a/public/icons/diffbot.svg +++ /dev/null @@ -1 +0,0 @@ -D \ No newline at end of file diff --git a/public/icons/edgar-search.svg b/public/icons/edgar-search.svg deleted file mode 100644 index c3759c30..00000000 --- a/public/icons/edgar-search.svg +++ /dev/null @@ -1 +0,0 @@ -E \ No newline at end of file diff --git a/public/icons/edgar.svg b/public/icons/edgar.svg deleted file mode 100644 index c3759c30..00000000 --- a/public/icons/edgar.svg +++ /dev/null @@ -1 +0,0 @@ -E \ No newline at end of file diff --git a/public/icons/hunter.svg b/public/icons/hunter.svg deleted file mode 100644 index 8c41e70b..00000000 --- a/public/icons/hunter.svg +++ /dev/null @@ -1 +0,0 @@ -H \ No newline at end of file diff --git a/public/icons/judge0.svg b/public/icons/judge0.svg deleted file mode 100644 index 9ae294e1..00000000 --- a/public/icons/judge0.svg +++ /dev/null @@ -1 +0,0 @@ -J \ No newline at end of file diff --git a/public/icons/laso.svg b/public/icons/laso.svg deleted file mode 100644 index cd907823..00000000 --- a/public/icons/laso.svg +++ /dev/null @@ -1 +0,0 @@ -L \ No newline at end of file diff --git a/public/icons/mapbox.svg b/public/icons/mapbox.svg deleted file mode 100644 index 79660ad7..00000000 --- a/public/icons/mapbox.svg +++ /dev/null @@ -1 +0,0 @@ -M \ No newline at end of file diff --git a/public/icons/mathpix.svg b/public/icons/mathpix.svg deleted file mode 100644 index 79660ad7..00000000 --- a/public/icons/mathpix.svg +++ /dev/null @@ -1 +0,0 @@ -M \ No newline at end of file diff --git a/public/icons/openweather.svg b/public/icons/openweather.svg deleted file mode 100644 index f8aae7c1..00000000 --- a/public/icons/openweather.svg +++ /dev/null @@ -1 +0,0 @@ -O \ No newline at end of file diff --git a/public/icons/perplexity.svg b/public/icons/perplexity.svg deleted file mode 100644 index 9ab6ffe6..00000000 --- a/public/icons/perplexity.svg +++ /dev/null @@ -1 +0,0 @@ -P \ No newline at end of file diff --git a/public/icons/rentcast.svg b/public/icons/rentcast.svg deleted file mode 100644 index 71c4d653..00000000 --- a/public/icons/rentcast.svg +++ /dev/null @@ -1 +0,0 @@ -R \ No newline at end of file diff --git a/public/icons/replicate.svg b/public/icons/replicate.svg deleted file mode 100644 index 71c4d653..00000000 --- a/public/icons/replicate.svg +++ /dev/null @@ -1 +0,0 @@ -R \ No newline at end of file diff --git a/public/icons/stability-ai.svg b/public/icons/stability-ai.svg deleted file mode 100644 index cc0f3225..00000000 --- a/public/icons/stability-ai.svg +++ /dev/null @@ -1 +0,0 @@ -S \ No newline at end of file diff --git a/public/icons/suno.svg b/public/icons/suno.svg deleted file mode 100644 index cc0f3225..00000000 --- a/public/icons/suno.svg +++ /dev/null @@ -1 +0,0 @@ -S \ No newline at end of file diff --git a/src/pages/_layout.tsx b/src/pages/_layout.tsx index c05a9e22..ee0dd2b3 100644 --- a/src/pages/_layout.tsx +++ b/src/pages/_layout.tsx @@ -447,14 +447,14 @@ export default function Layout(props: React.PropsWithChildren) { )} Date: Tue, 24 Mar 2026 09:26:48 +0000 Subject: [PATCH 04/11] style: format long Blob URLs in font-face declarations --- src/pages/_root.css | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/pages/_root.css b/src/pages/_root.css index becde9f9..d83459f6 100644 --- a/src/pages/_root.css +++ b/src/pages/_root.css @@ -31,7 +31,8 @@ @font-face { font-family: "VTC Du Bois"; - src: url("https://wgfdjv2jfqz2dlpx.public.blob.vercel-storage.com/fonts/VTCDuBois-Regular.woff2") format("woff2"); + src: url("https://wgfdjv2jfqz2dlpx.public.blob.vercel-storage.com/fonts/VTCDuBois-Regular.woff2") + format("woff2"); font-weight: 400; font-style: normal; font-display: swap; @@ -39,7 +40,8 @@ @font-face { font-family: "VTC Du Bois"; - src: url("https://wgfdjv2jfqz2dlpx.public.blob.vercel-storage.com/fonts/VTCDuBois-Bold.woff2") format("woff2"); + src: url("https://wgfdjv2jfqz2dlpx.public.blob.vercel-storage.com/fonts/VTCDuBois-Bold.woff2") + format("woff2"); font-weight: 700; font-style: normal; font-display: swap; From 67a95f3b8ec9abbc16324077a9a92abac827537a Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Tue, 24 Mar 2026 09:56:21 +0000 Subject: [PATCH 05/11] fix: remove local icon overrides, use Blob + logo.dev fallback only Remove all 77 static SVG icons from public/icons/. The icon API now resolves icons exclusively from Vercel Blob (synced from logo.dev), with a live logo.dev fallback using provider.url domain, and a generated letter SVG as the last resort. This eliminates stale local overrides that were blocking fresh Blob-hosted logos from being served. --- public/icons/abstract-company-enrichment.svg | 1 - public/icons/abstract-email-reputation.svg | 1 - public/icons/abstract-exchange-rates.svg | 1 - public/icons/abstract-holidays.svg | 1 - public/icons/abstract-iban-validation.svg | 1 - public/icons/abstract-ip-intelligence.svg | 1 - public/icons/abstract-phone-intelligence.svg | 1 - public/icons/abstract-timezone.svg | 1 - public/icons/abstract-vat.svg | 1 - public/icons/abstract-web-scraping.svg | 1 - public/icons/agentmail.svg | 1 - public/icons/alchemy.svg | 1 - public/icons/allium.svg | 1 - public/icons/alphavantage.svg | 1 - public/icons/anthropic.svg | 1 - public/icons/apollo.svg | 1 - public/icons/aviationstack.svg | 1 - public/icons/billboard.svg | 1 - public/icons/brave.svg | 1 - public/icons/browserbase.svg | 1 - public/icons/codestorage.svg | 1 - public/icons/codex.svg | 1 - public/icons/coingecko.svg | 1 - public/icons/deepgram.svg | 1 - public/icons/deepl.svg | 1 - public/icons/deepseek.svg | 1 - public/icons/diffbot-kg.svg | 1 - public/icons/diffbot-nl.svg | 1 - public/icons/digitalocean.svg | 1 - public/icons/dune.svg | 1 - public/icons/exa.svg | 1 - public/icons/fal.svg | 1 - public/icons/firecrawl.svg | 1 - public/icons/flightapi.svg | 1 - public/icons/gemini.svg | 1 - public/icons/goflightlabs.svg | 1 - public/icons/googlemaps-aerialview.svg | 1 - public/icons/googlemaps-airquality.svg | 1 - public/icons/googlemaps-geolocation.svg | 1 - public/icons/googlemaps-places-v2.svg | 1 - public/icons/googlemaps-pollen.svg | 1 - public/icons/googlemaps-roads.svg | 1 - public/icons/googlemaps-routes.svg | 1 - public/icons/googlemaps-solar.svg | 1 - public/icons/googlemaps-tiles.svg | 1 - public/icons/googlemaps-validation.svg | 1 - public/icons/googlemaps-weather.svg | 1 - public/icons/googlemaps.svg | 1 - public/icons/grok.svg | 1 - public/icons/groq.svg | 1 - public/icons/ipinfo.svg | 1 - public/icons/kicksdb.svg | 1 - public/icons/mistral.svg | 1 - public/icons/modal.svg | 1 - public/icons/openai.svg | 1 - public/icons/openrouter.svg | 1 - public/icons/oxylabs.svg | 1 - public/icons/parallel.svg | 1 - public/icons/postalform.svg | 1 - public/icons/prospect-butcher.svg | 1 - public/icons/rpc.svg | 1 - public/icons/screenshotone.svg | 1 - public/icons/serpapi.svg | 1 - public/icons/spyfu.svg | 1 - public/icons/stableemail.svg | 1 - public/icons/stableenrich.svg | 1 - public/icons/stablephone.svg | 1 - public/icons/stablesocial.svg | 1 - public/icons/stablestudio.svg | 1 - public/icons/stabletravel.svg | 1 - public/icons/stableupload.svg | 1 - public/icons/storage.svg | 1 - public/icons/stripe-climate.svg | 1 - public/icons/tavily.svg | 1 - public/icons/twitter.svg | 1 - public/icons/twocaptcha.svg | 1 - public/icons/wolframalpha.svg | 1 - src/components/ServiceDiscovery.tsx | 11 +++- src/components/ServicesPage.tsx | 11 +++- src/data/registry.ts | 6 +- src/pages/_api/api/icon.ts | 68 ++++++++++---------- 81 files changed, 57 insertions(+), 116 deletions(-) delete mode 100644 public/icons/abstract-company-enrichment.svg delete mode 100644 public/icons/abstract-email-reputation.svg delete mode 100644 public/icons/abstract-exchange-rates.svg delete mode 100644 public/icons/abstract-holidays.svg delete mode 100644 public/icons/abstract-iban-validation.svg delete mode 100644 public/icons/abstract-ip-intelligence.svg delete mode 100644 public/icons/abstract-phone-intelligence.svg delete mode 100644 public/icons/abstract-timezone.svg delete mode 100644 public/icons/abstract-vat.svg delete mode 100644 public/icons/abstract-web-scraping.svg delete mode 100644 public/icons/agentmail.svg delete mode 100644 public/icons/alchemy.svg delete mode 100644 public/icons/allium.svg delete mode 100644 public/icons/alphavantage.svg delete mode 100644 public/icons/anthropic.svg delete mode 100644 public/icons/apollo.svg delete mode 100644 public/icons/aviationstack.svg delete mode 100644 public/icons/billboard.svg delete mode 100644 public/icons/brave.svg delete mode 100644 public/icons/browserbase.svg delete mode 100644 public/icons/codestorage.svg delete mode 100644 public/icons/codex.svg delete mode 100644 public/icons/coingecko.svg delete mode 100644 public/icons/deepgram.svg delete mode 100644 public/icons/deepl.svg delete mode 100644 public/icons/deepseek.svg delete mode 100644 public/icons/diffbot-kg.svg delete mode 100644 public/icons/diffbot-nl.svg delete mode 100644 public/icons/digitalocean.svg delete mode 100644 public/icons/dune.svg delete mode 100644 public/icons/exa.svg delete mode 100644 public/icons/fal.svg delete mode 100644 public/icons/firecrawl.svg delete mode 100644 public/icons/flightapi.svg delete mode 100644 public/icons/gemini.svg delete mode 100644 public/icons/goflightlabs.svg delete mode 100644 public/icons/googlemaps-aerialview.svg delete mode 100644 public/icons/googlemaps-airquality.svg delete mode 100644 public/icons/googlemaps-geolocation.svg delete mode 100644 public/icons/googlemaps-places-v2.svg delete mode 100644 public/icons/googlemaps-pollen.svg delete mode 100644 public/icons/googlemaps-roads.svg delete mode 100644 public/icons/googlemaps-routes.svg delete mode 100644 public/icons/googlemaps-solar.svg delete mode 100644 public/icons/googlemaps-tiles.svg delete mode 100644 public/icons/googlemaps-validation.svg delete mode 100644 public/icons/googlemaps-weather.svg delete mode 100644 public/icons/googlemaps.svg delete mode 100644 public/icons/grok.svg delete mode 100644 public/icons/groq.svg delete mode 100644 public/icons/ipinfo.svg delete mode 100644 public/icons/kicksdb.svg delete mode 100644 public/icons/mistral.svg delete mode 100644 public/icons/modal.svg delete mode 100644 public/icons/openai.svg delete mode 100644 public/icons/openrouter.svg delete mode 100644 public/icons/oxylabs.svg delete mode 100644 public/icons/parallel.svg delete mode 100644 public/icons/postalform.svg delete mode 100644 public/icons/prospect-butcher.svg delete mode 100644 public/icons/rpc.svg delete mode 100644 public/icons/screenshotone.svg delete mode 100644 public/icons/serpapi.svg delete mode 100644 public/icons/spyfu.svg delete mode 100644 public/icons/stableemail.svg delete mode 100644 public/icons/stableenrich.svg delete mode 100644 public/icons/stablephone.svg delete mode 100644 public/icons/stablesocial.svg delete mode 100644 public/icons/stablestudio.svg delete mode 100644 public/icons/stabletravel.svg delete mode 100644 public/icons/stableupload.svg delete mode 100644 public/icons/storage.svg delete mode 100644 public/icons/stripe-climate.svg delete mode 100644 public/icons/tavily.svg delete mode 100644 public/icons/twitter.svg delete mode 100644 public/icons/twocaptcha.svg delete mode 100644 public/icons/wolframalpha.svg diff --git a/public/icons/abstract-company-enrichment.svg b/public/icons/abstract-company-enrichment.svg deleted file mode 100644 index 9e350650..00000000 --- a/public/icons/abstract-company-enrichment.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/public/icons/abstract-email-reputation.svg b/public/icons/abstract-email-reputation.svg deleted file mode 100644 index 9e350650..00000000 --- a/public/icons/abstract-email-reputation.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/public/icons/abstract-exchange-rates.svg b/public/icons/abstract-exchange-rates.svg deleted file mode 100644 index 9e350650..00000000 --- a/public/icons/abstract-exchange-rates.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/public/icons/abstract-holidays.svg b/public/icons/abstract-holidays.svg deleted file mode 100644 index 9e350650..00000000 --- a/public/icons/abstract-holidays.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/public/icons/abstract-iban-validation.svg b/public/icons/abstract-iban-validation.svg deleted file mode 100644 index 9e350650..00000000 --- a/public/icons/abstract-iban-validation.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/public/icons/abstract-ip-intelligence.svg b/public/icons/abstract-ip-intelligence.svg deleted file mode 100644 index 9e350650..00000000 --- a/public/icons/abstract-ip-intelligence.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/public/icons/abstract-phone-intelligence.svg b/public/icons/abstract-phone-intelligence.svg deleted file mode 100644 index 9e350650..00000000 --- a/public/icons/abstract-phone-intelligence.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/public/icons/abstract-timezone.svg b/public/icons/abstract-timezone.svg deleted file mode 100644 index 9e350650..00000000 --- a/public/icons/abstract-timezone.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/public/icons/abstract-vat.svg b/public/icons/abstract-vat.svg deleted file mode 100644 index 9e350650..00000000 --- a/public/icons/abstract-vat.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/public/icons/abstract-web-scraping.svg b/public/icons/abstract-web-scraping.svg deleted file mode 100644 index 9e350650..00000000 --- a/public/icons/abstract-web-scraping.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/public/icons/agentmail.svg b/public/icons/agentmail.svg deleted file mode 100644 index d00c65f9..00000000 --- a/public/icons/agentmail.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/public/icons/alchemy.svg b/public/icons/alchemy.svg deleted file mode 100644 index a6c357eb..00000000 --- a/public/icons/alchemy.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/public/icons/allium.svg b/public/icons/allium.svg deleted file mode 100644 index 672645eb..00000000 --- a/public/icons/allium.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/public/icons/alphavantage.svg b/public/icons/alphavantage.svg deleted file mode 100644 index eaca4b1c..00000000 --- a/public/icons/alphavantage.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/public/icons/anthropic.svg b/public/icons/anthropic.svg deleted file mode 100644 index 6f481ffc..00000000 --- a/public/icons/anthropic.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/public/icons/apollo.svg b/public/icons/apollo.svg deleted file mode 100644 index c4f70f8e..00000000 --- a/public/icons/apollo.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/public/icons/aviationstack.svg b/public/icons/aviationstack.svg deleted file mode 100644 index 9738be41..00000000 --- a/public/icons/aviationstack.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/public/icons/billboard.svg b/public/icons/billboard.svg deleted file mode 100644 index a64eed46..00000000 --- a/public/icons/billboard.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/public/icons/brave.svg b/public/icons/brave.svg deleted file mode 100644 index 1a44afd7..00000000 --- a/public/icons/brave.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/public/icons/browserbase.svg b/public/icons/browserbase.svg deleted file mode 100644 index d85ebcbc..00000000 --- a/public/icons/browserbase.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/public/icons/codestorage.svg b/public/icons/codestorage.svg deleted file mode 100644 index 76563d7a..00000000 --- a/public/icons/codestorage.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/public/icons/codex.svg b/public/icons/codex.svg deleted file mode 100644 index 82eeef0a..00000000 --- a/public/icons/codex.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/public/icons/coingecko.svg b/public/icons/coingecko.svg deleted file mode 100644 index 266feb4f..00000000 --- a/public/icons/coingecko.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/public/icons/deepgram.svg b/public/icons/deepgram.svg deleted file mode 100644 index 5238f9c9..00000000 --- a/public/icons/deepgram.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/public/icons/deepl.svg b/public/icons/deepl.svg deleted file mode 100644 index 12cbf5ba..00000000 --- a/public/icons/deepl.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/public/icons/deepseek.svg b/public/icons/deepseek.svg deleted file mode 100644 index 316491dd..00000000 --- a/public/icons/deepseek.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/public/icons/diffbot-kg.svg b/public/icons/diffbot-kg.svg deleted file mode 100644 index 4b7c2804..00000000 --- a/public/icons/diffbot-kg.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/public/icons/diffbot-nl.svg b/public/icons/diffbot-nl.svg deleted file mode 100644 index 4b7c2804..00000000 --- a/public/icons/diffbot-nl.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/public/icons/digitalocean.svg b/public/icons/digitalocean.svg deleted file mode 100644 index d881184d..00000000 --- a/public/icons/digitalocean.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/public/icons/dune.svg b/public/icons/dune.svg deleted file mode 100644 index 587d4d77..00000000 --- a/public/icons/dune.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/public/icons/exa.svg b/public/icons/exa.svg deleted file mode 100644 index d04f2bfd..00000000 --- a/public/icons/exa.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/public/icons/fal.svg b/public/icons/fal.svg deleted file mode 100644 index 5c02f15f..00000000 --- a/public/icons/fal.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/public/icons/firecrawl.svg b/public/icons/firecrawl.svg deleted file mode 100644 index 6907d7c5..00000000 --- a/public/icons/firecrawl.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/public/icons/flightapi.svg b/public/icons/flightapi.svg deleted file mode 100644 index 01dc2714..00000000 --- a/public/icons/flightapi.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/public/icons/gemini.svg b/public/icons/gemini.svg deleted file mode 100644 index c3cf32ff..00000000 --- a/public/icons/gemini.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/public/icons/goflightlabs.svg b/public/icons/goflightlabs.svg deleted file mode 100644 index ab1d5e43..00000000 --- a/public/icons/goflightlabs.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/public/icons/googlemaps-aerialview.svg b/public/icons/googlemaps-aerialview.svg deleted file mode 100644 index 3e648350..00000000 --- a/public/icons/googlemaps-aerialview.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/public/icons/googlemaps-airquality.svg b/public/icons/googlemaps-airquality.svg deleted file mode 100644 index 3e648350..00000000 --- a/public/icons/googlemaps-airquality.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/public/icons/googlemaps-geolocation.svg b/public/icons/googlemaps-geolocation.svg deleted file mode 100644 index 3e648350..00000000 --- a/public/icons/googlemaps-geolocation.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/public/icons/googlemaps-places-v2.svg b/public/icons/googlemaps-places-v2.svg deleted file mode 100644 index 3e648350..00000000 --- a/public/icons/googlemaps-places-v2.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/public/icons/googlemaps-pollen.svg b/public/icons/googlemaps-pollen.svg deleted file mode 100644 index 3e648350..00000000 --- a/public/icons/googlemaps-pollen.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/public/icons/googlemaps-roads.svg b/public/icons/googlemaps-roads.svg deleted file mode 100644 index 3e648350..00000000 --- a/public/icons/googlemaps-roads.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/public/icons/googlemaps-routes.svg b/public/icons/googlemaps-routes.svg deleted file mode 100644 index 3e648350..00000000 --- a/public/icons/googlemaps-routes.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/public/icons/googlemaps-solar.svg b/public/icons/googlemaps-solar.svg deleted file mode 100644 index 3e648350..00000000 --- a/public/icons/googlemaps-solar.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/public/icons/googlemaps-tiles.svg b/public/icons/googlemaps-tiles.svg deleted file mode 100644 index 3e648350..00000000 --- a/public/icons/googlemaps-tiles.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/public/icons/googlemaps-validation.svg b/public/icons/googlemaps-validation.svg deleted file mode 100644 index 3e648350..00000000 --- a/public/icons/googlemaps-validation.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/public/icons/googlemaps-weather.svg b/public/icons/googlemaps-weather.svg deleted file mode 100644 index 3e648350..00000000 --- a/public/icons/googlemaps-weather.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/public/icons/googlemaps.svg b/public/icons/googlemaps.svg deleted file mode 100644 index 3e648350..00000000 --- a/public/icons/googlemaps.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/public/icons/grok.svg b/public/icons/grok.svg deleted file mode 100644 index 0c11bd10..00000000 --- a/public/icons/grok.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/public/icons/groq.svg b/public/icons/groq.svg deleted file mode 100644 index a429691e..00000000 --- a/public/icons/groq.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/public/icons/ipinfo.svg b/public/icons/ipinfo.svg deleted file mode 100644 index 7f3aaeb9..00000000 --- a/public/icons/ipinfo.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/public/icons/kicksdb.svg b/public/icons/kicksdb.svg deleted file mode 100644 index 1fa9baef..00000000 --- a/public/icons/kicksdb.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/public/icons/mistral.svg b/public/icons/mistral.svg deleted file mode 100644 index 3499c0b2..00000000 --- a/public/icons/mistral.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/public/icons/modal.svg b/public/icons/modal.svg deleted file mode 100644 index 21a8c394..00000000 --- a/public/icons/modal.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/public/icons/openai.svg b/public/icons/openai.svg deleted file mode 100644 index b4839440..00000000 --- a/public/icons/openai.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/public/icons/openrouter.svg b/public/icons/openrouter.svg deleted file mode 100644 index e54129b5..00000000 --- a/public/icons/openrouter.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/public/icons/oxylabs.svg b/public/icons/oxylabs.svg deleted file mode 100644 index 07b28f27..00000000 --- a/public/icons/oxylabs.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/public/icons/parallel.svg b/public/icons/parallel.svg deleted file mode 100644 index 97fe9a0f..00000000 --- a/public/icons/parallel.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/public/icons/postalform.svg b/public/icons/postalform.svg deleted file mode 100644 index 761d0e3c..00000000 --- a/public/icons/postalform.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/public/icons/prospect-butcher.svg b/public/icons/prospect-butcher.svg deleted file mode 100644 index a3c13bea..00000000 --- a/public/icons/prospect-butcher.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/public/icons/rpc.svg b/public/icons/rpc.svg deleted file mode 100644 index b8f129fc..00000000 --- a/public/icons/rpc.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/public/icons/screenshotone.svg b/public/icons/screenshotone.svg deleted file mode 100644 index b3983bcc..00000000 --- a/public/icons/screenshotone.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/public/icons/serpapi.svg b/public/icons/serpapi.svg deleted file mode 100644 index 9b7df559..00000000 --- a/public/icons/serpapi.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/public/icons/spyfu.svg b/public/icons/spyfu.svg deleted file mode 100644 index 6af3dc90..00000000 --- a/public/icons/spyfu.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/public/icons/stableemail.svg b/public/icons/stableemail.svg deleted file mode 100644 index 5d460b33..00000000 --- a/public/icons/stableemail.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/public/icons/stableenrich.svg b/public/icons/stableenrich.svg deleted file mode 100644 index 93178e6d..00000000 --- a/public/icons/stableenrich.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/public/icons/stablephone.svg b/public/icons/stablephone.svg deleted file mode 100644 index 0cd08f22..00000000 --- a/public/icons/stablephone.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/public/icons/stablesocial.svg b/public/icons/stablesocial.svg deleted file mode 100644 index cce5f112..00000000 --- a/public/icons/stablesocial.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/public/icons/stablestudio.svg b/public/icons/stablestudio.svg deleted file mode 100644 index a3af1f40..00000000 --- a/public/icons/stablestudio.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/public/icons/stabletravel.svg b/public/icons/stabletravel.svg deleted file mode 100644 index 2978ab75..00000000 --- a/public/icons/stabletravel.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/public/icons/stableupload.svg b/public/icons/stableupload.svg deleted file mode 100644 index 4d54842c..00000000 --- a/public/icons/stableupload.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/public/icons/storage.svg b/public/icons/storage.svg deleted file mode 100644 index b8f129fc..00000000 --- a/public/icons/storage.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/public/icons/stripe-climate.svg b/public/icons/stripe-climate.svg deleted file mode 100644 index 54a0fba9..00000000 --- a/public/icons/stripe-climate.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/public/icons/tavily.svg b/public/icons/tavily.svg deleted file mode 100644 index c787c223..00000000 --- a/public/icons/tavily.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/public/icons/twitter.svg b/public/icons/twitter.svg deleted file mode 100644 index 6c9879b1..00000000 --- a/public/icons/twitter.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/public/icons/twocaptcha.svg b/public/icons/twocaptcha.svg deleted file mode 100644 index d637f6b3..00000000 --- a/public/icons/twocaptcha.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/public/icons/wolframalpha.svg b/public/icons/wolframalpha.svg deleted file mode 100644 index 3a9deb1a..00000000 --- a/public/icons/wolframalpha.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/components/ServiceDiscovery.tsx b/src/components/ServiceDiscovery.tsx index 439d19e0..2a1a26f3 100644 --- a/src/components/ServiceDiscovery.tsx +++ b/src/components/ServiceDiscovery.tsx @@ -80,8 +80,17 @@ function getExamplePayload(ep: Endpoint): string { return "'{}'"; } +function domainFrom(s: Service): string | undefined { + if (!s.provider?.url) return undefined; + try { + return new URL(s.provider.url).hostname; + } catch { + return undefined; + } +} + function getIconUrl(service: Service): string { - return getIconUrlForService(service.id); + return getIconUrlForService(service.id, domainFrom(service)); } // --------------------------------------------------------------------------- diff --git a/src/components/ServicesPage.tsx b/src/components/ServicesPage.tsx index c7aaad15..b7857879 100644 --- a/src/components/ServicesPage.tsx +++ b/src/components/ServicesPage.tsx @@ -6,6 +6,15 @@ import type { Category, Endpoint, Service } from "../data/registry"; import { fetchServices, iconUrl } from "../data/registry"; import { ServiceDiscovery } from "./ServiceDiscovery"; +function domainFrom(s: Service): string | undefined { + if (!s.provider?.url) return undefined; + try { + return new URL(s.provider.url).hostname; + } catch { + return undefined; + } +} + export const CATEGORY_LABELS: Record = { ai: "AI", blockchain: "Blockchain", @@ -2988,7 +2997,7 @@ function ServiceIcon({ service: s }: { service: Service }) { > {s.id && !imgError ? ( ${letter}`; @@ -18,7 +14,7 @@ function letterSvg(id: string): string { async function blobGet( id: string, -): Promise<{ body: ReadableStream; contentType: string } | null> { +): Promise<{ data: ArrayBuffer; contentType: string } | null> { if (!BLOB_TOKEN) return null; try { for (const ext of ["png", "svg"]) { @@ -29,11 +25,11 @@ async function blobGet( }); if (blobs.length > 0) { const res = await fetch(blobs[0].url); - if (res.ok && res.body) { + if (res.ok) { const ct = res.headers.get("content-type") ?? (ext === "svg" ? "image/svg+xml" : `image/${ext}`); - return { body: res.body, contentType: ct }; + return { data: await res.arrayBuffer(), contentType: ct }; } } } @@ -43,41 +39,43 @@ async function blobGet( return null; } -async function staticIcon( - request: Request, - id: string, -): Promise { - try { - const origin = new URL(request.url).origin; - const res = await fetch(`${origin}/icons/${id}.svg`); - if (res.ok) { - return new Response(await res.text(), { - headers: { ...FALLBACK_HEADERS, ...CACHE_HEADERS }, - }); - } - } catch { - // static file not available - } - return null; -} - export async function GET(request: Request) { - const id = new URL(request.url).searchParams.get("id"); + const url = new URL(request.url); + const id = url.searchParams.get("id"); if (!id) return new Response("Missing id parameter", { status: 400 }); - // 1. Static override (public/icons/*.svg) — hand-curated icons take priority - const override = await staticIcon(request, id); - if (override) return override; - - // 2. Vercel Blob (logo.dev sync) + // 1. Vercel Blob (synced from logo.dev) const blob = await blobGet(id); if (blob) { - return new Response(blob.body, { + return new Response(blob.data, { headers: { "Content-Type": blob.contentType, ...CACHE_HEADERS }, }); } + // 2. Live logo.dev fallback + if (LOGODEV_PK) { + const domain = url.searchParams.get("domain"); + if (domain) { + try { + const res = await fetch( + `https://img.logo.dev/${domain}?token=${LOGODEV_PK}&format=png&size=256&greyscale=true&theme=dark&retina=true`, + ); + if (res.ok) { + return new Response(await res.arrayBuffer(), { + headers: { "Content-Type": "image/png", ...CACHE_HEADERS }, + }); + } + } catch (e) { + console.error(`[icon] logo.dev fallback error for ${domain}:`, e); + } + } + } + // 3. Letter SVG (guaranteed — never 404) - console.warn(`[icon] no icon found for ${id}, generating letter fallback`); - return new Response(letterSvg(id), { headers: FALLBACK_HEADERS }); + return new Response(letterSvg(id), { + headers: { + "Content-Type": "image/svg+xml", + "Cache-Control": "public, s-maxage=3600, stale-while-revalidate", + }, + }); } From 4e1825ee11310f1aa0e20133f628d63c1c797117 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Tue, 24 Mar 2026 09:58:59 +0000 Subject: [PATCH 06/11] refactor: extract shared logoDevUrl helper Single source of truth for logo.dev URL construction, used by both the icon API endpoint and the sync-logos build script. --- scripts/sync-logos.ts | 3 ++- src/lib/logodev.ts | 24 ++++++++++++++++++++++++ src/pages/_api/api/icon.ts | 3 ++- 3 files changed, 28 insertions(+), 2 deletions(-) create mode 100644 src/lib/logodev.ts diff --git a/scripts/sync-logos.ts b/scripts/sync-logos.ts index 80588fab..3b8fefd9 100644 --- a/scripts/sync-logos.ts +++ b/scripts/sync-logos.ts @@ -7,6 +7,7 @@ import { readFileSync } from "node:fs"; import { resolve } from "node:path"; import { put } from "@vercel/blob"; +import { logoDevUrl } from "../src/lib/logodev"; // --------------------------------------------------------------------------- // Types @@ -184,7 +185,7 @@ function domainForService(svc: ServiceEntry): string | null { } function logoUrl(domain: string): string { - return `https://img.logo.dev/${domain}?token=${LOGODEV_PK}&format=png&size=256&greyscale=true&theme=dark&fallback=monogram&retina=true`; + return logoDevUrl(domain, { token: LOGODEV_PK! }); } // --------------------------------------------------------------------------- diff --git a/src/lib/logodev.ts b/src/lib/logodev.ts new file mode 100644 index 00000000..7b62baa4 --- /dev/null +++ b/src/lib/logodev.ts @@ -0,0 +1,24 @@ +const BASE = "https://img.logo.dev"; + +export interface LogoDevOptions { + token: string; + size?: number; + greyscale?: boolean; + theme?: "dark" | "light"; + retina?: boolean; +} + +export function logoDevUrl( + domain: string, + { token, size = 256, greyscale = true, theme = "dark", retina = true }: LogoDevOptions, +): string { + const params = new URLSearchParams({ + token, + format: "png", + size: String(size), + }); + if (greyscale) params.set("greyscale", "true"); + if (theme) params.set("theme", theme); + if (retina) params.set("retina", "true"); + return `${BASE}/${domain}?${params}`; +} diff --git a/src/pages/_api/api/icon.ts b/src/pages/_api/api/icon.ts index 57262c79..8fd9d94b 100644 --- a/src/pages/_api/api/icon.ts +++ b/src/pages/_api/api/icon.ts @@ -1,4 +1,5 @@ import { list } from "@vercel/blob"; +import { logoDevUrl } from "../../../lib/logodev"; const BLOB_TOKEN = process.env.BLOB_READ_WRITE_TOKEN; const LOGODEV_PK = process.env.LOGODEV_PUBLIC_KEY; @@ -58,7 +59,7 @@ export async function GET(request: Request) { if (domain) { try { const res = await fetch( - `https://img.logo.dev/${domain}?token=${LOGODEV_PK}&format=png&size=256&greyscale=true&theme=dark&retina=true`, + logoDevUrl(domain, { token: LOGODEV_PK }), ); if (res.ok) { return new Response(await res.arrayBuffer(), { From 56d7e3be3374cd2cdecb81595aaae272d60d6fa8 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Tue, 24 Mar 2026 10:05:30 +0000 Subject: [PATCH 07/11] refactor: extract ServiceLogo component, remove duplicate icon rendering Single ServiceLogo component replaces three separate inline icon implementations across ServicesPage and ServiceDiscovery. Handles img loading, error fallback to initials, and domain passthrough for logo.dev in one place. --- src/components/ServiceDiscovery.tsx | 80 +++++---------------------- src/components/ServiceLogo.tsx | 85 +++++++++++++++++++++++++++++ src/components/ServicesPage.tsx | 55 +------------------ src/lib/logodev.ts | 8 ++- src/pages/_api/api/icon.ts | 4 +- 5 files changed, 109 insertions(+), 123 deletions(-) create mode 100644 src/components/ServiceLogo.tsx diff --git a/src/components/ServiceDiscovery.tsx b/src/components/ServiceDiscovery.tsx index 2a1a26f3..7c96ee1e 100644 --- a/src/components/ServiceDiscovery.tsx +++ b/src/components/ServiceDiscovery.tsx @@ -3,10 +3,8 @@ import { useCallback, useEffect, useMemo, useRef, useState } from "react"; import { createPortal } from "react-dom"; import type { Category, Endpoint, Service } from "../data/registry"; -import { - fetchServices, - iconUrl as getIconUrlForService, -} from "../data/registry"; +import { fetchServices } from "../data/registry"; +import { ServiceLogo } from "./ServiceLogo"; import { PINNED_IDS } from "./ServicesPage"; const CATEGORY_LABELS: Record = { @@ -80,18 +78,6 @@ function getExamplePayload(ep: Endpoint): string { return "'{}'"; } -function domainFrom(s: Service): string | undefined { - if (!s.provider?.url) return undefined; - try { - return new URL(s.provider.url).hostname; - } catch { - return undefined; - } -} - -function getIconUrl(service: Service): string { - return getIconUrlForService(service.id, domainFrom(service)); -} // --------------------------------------------------------------------------- // Filter engine — scores services against a query @@ -202,8 +188,6 @@ export function ServiceDiscovery({ const overlayRef = useRef(null); const gridRef = useRef(null); const inputRef = useRef(null); - const brokenIcons = useRef(new Set()); - const [, forceIconUpdate] = useState(0); const [activeIndex, setActiveIndex] = useState(-1); const [isFocused, setIsFocused] = useState(false); @@ -665,7 +649,6 @@ export function ServiceDiscovery({
{stableScored.slice(0, 48).map(({ service, score }) => { const isMatch = (!debouncedQuery && !externalCategory) || score > 0; - const iconUrl = getIconUrl(service); const t = transforms[service.id]; const isAnimating = hasQuery && isMatch && t; @@ -757,21 +740,11 @@ export function ServiceDiscovery({ zIndex: 1, }} > - {iconUrl && !brokenIcons.current.has(service.id) ? ( - { - brokenIcons.current.add(service.id); - forceIconUpdate((n) => n + 1); - }} - /> - ) : ( -
- {service.name[0]} -
- )} + {service.integration !== "third-party" && ( (null); const [copiedJson, setCopiedJson] = useState(false); const [showAgentTip, setShowAgentTip] = useState(false); - const [imgError, setImgError] = useState(false); const [isClosing, setIsClosing] = useState(false); const handleClose = useCallback(() => { @@ -875,8 +847,6 @@ function ServiceDetailModal({ return () => window.removeEventListener("keydown", handleKey); }, [handleClose]); - const iconUrl = getIconUrl(service); - function formatPrice(ep: Endpoint): string { const p = ep.payment; if (!p?.amount) return p?.amountHint ?? "—"; @@ -991,36 +961,12 @@ function ServiceDetailModal({ {/* Header */}
- {iconUrl && !imgError ? ( - setImgError(true)} - className="discovery-card-icon-img" - style={{ - width: 44, - height: 44, - borderRadius: 10, - }} - /> - ) : ( -
- {service.name[0]} -
- )} +
; + } + + return ( + setImgError(true)} + /> + ); +} + +export function ServiceLogoFallback({ + name, + size = 28, +}: { + name: string; + size?: number; +}) { + const initials = name + .split(/[\s-]+/) + .slice(0, 2) + .map((w) => w.charAt(0).toUpperCase()) + .join(""); + + return ( +
1 ? Math.round(size * 0.36) : Math.round(size * 0.46), + fontWeight: 600, + letterSpacing: "-0.02em", + color: "var(--vocs-text-color-secondary)", + border: + "1px solid light-dark(rgba(0,0,0,0.08), rgba(255,255,255,0.08))", + }} + > + {initials || "?"} +
+ ); +} diff --git a/src/components/ServicesPage.tsx b/src/components/ServicesPage.tsx index b7857879..8d3c90ec 100644 --- a/src/components/ServicesPage.tsx +++ b/src/components/ServicesPage.tsx @@ -3,17 +3,9 @@ import { useCallback, useEffect, useMemo, useRef, useState } from "react"; import { Link } from "vocs"; import type { Category, Endpoint, Service } from "../data/registry"; -import { fetchServices, iconUrl } from "../data/registry"; +import { fetchServices } from "../data/registry"; import { ServiceDiscovery } from "./ServiceDiscovery"; - -function domainFrom(s: Service): string | undefined { - if (!s.provider?.url) return undefined; - try { - return new URL(s.provider.url).hostname; - } catch { - return undefined; - } -} +import { ServiceLogo } from "./ServiceLogo"; export const CATEGORY_LABELS: Record = { ai: "AI", @@ -2952,38 +2944,8 @@ function BorderlessBadge({ children }: { children: React.ReactNode }) { // Service icon with optional first-party overlay // --------------------------------------------------------------------------- -function FallbackIcon({ name }: { name: string }) { - const initials = name - .split(/[\s-]+/) - .slice(0, 2) - .map((w) => w.charAt(0).toUpperCase()) - .join(""); - return ( -
1 ? 10 : 13, - fontWeight: 600, - letterSpacing: "-0.02em", - color: "var(--vocs-text-color-secondary)", - border: - "1px solid light-dark(rgba(0,0,0,0.08), rgba(255,255,255,0.08))", - }} - > - {initials || "?"} -
- ); -} - function ServiceIcon({ service: s }: { service: Service }) { const isFirstParty = s.integration !== "third-party"; - const [imgError, setImgError] = useState(false); return (
- {s.id && !imgError ? ( - setImgError(true)} - /> - ) : ( - - )} + {isFirstParty && ( Date: Tue, 24 Mar 2026 10:09:07 +0000 Subject: [PATCH 08/11] style: fix biome formatting in ServiceDiscovery and ServiceLogo --- src/components/ServiceDiscovery.tsx | 1 - src/components/ServiceLogo.tsx | 5 ++++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/components/ServiceDiscovery.tsx b/src/components/ServiceDiscovery.tsx index 7c96ee1e..7b9d07ae 100644 --- a/src/components/ServiceDiscovery.tsx +++ b/src/components/ServiceDiscovery.tsx @@ -78,7 +78,6 @@ function getExamplePayload(ep: Endpoint): string { return "'{}'"; } - // --------------------------------------------------------------------------- // Filter engine — scores services against a query // --------------------------------------------------------------------------- diff --git a/src/components/ServiceLogo.tsx b/src/components/ServiceLogo.tsx index c7155eec..0d455b7d 100644 --- a/src/components/ServiceLogo.tsx +++ b/src/components/ServiceLogo.tsx @@ -71,7 +71,10 @@ export function ServiceLogoFallback({ display: "flex", alignItems: "center", justifyContent: "center", - fontSize: initials.length > 1 ? Math.round(size * 0.36) : Math.round(size * 0.46), + fontSize: + initials.length > 1 + ? Math.round(size * 0.36) + : Math.round(size * 0.46), fontWeight: 600, letterSpacing: "-0.02em", color: "var(--vocs-text-color-secondary)", From 527a91a5f61b7b7142993dc121473e2d17d29df4 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Tue, 24 Mar 2026 10:14:57 +0000 Subject: [PATCH 09/11] fix: restore icon manifest theme logic in ServiceLogo Re-add light background detection and invert filter for icons that need color correction based on the current theme. ServiceLogo now fetches the icon manifest internally and applies filter: invert(1) when an icon has a light background and the user is in dark mode (or vice versa). --- src/components/ServiceLogo.tsx | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/src/components/ServiceLogo.tsx b/src/components/ServiceLogo.tsx index 0d455b7d..d0aa762f 100644 --- a/src/components/ServiceLogo.tsx +++ b/src/components/ServiceLogo.tsx @@ -1,8 +1,8 @@ "use client"; -import { useState } from "react"; -import type { Service } from "../data/registry"; -import { iconUrl } from "../data/registry"; +import { useEffect, useState } from "react"; +import type { IconManifest, Service } from "../data/registry"; +import { fetchIconManifest, iconUrl, useIsDark } from "../data/registry"; function domainFrom(s: Service): string | undefined { if (!s.provider?.url) return undefined; @@ -25,11 +25,15 @@ export function ServiceLogo({ style?: React.CSSProperties; }) { const [imgError, setImgError] = useState(false); + const isDark = useIsDark(); + const manifest = useIconManifest(); if (!service.id || imgError) { return ; } + const needsInvert = isDark === manifest.lightBg.has(service.id); + return ( setImgError(true)} @@ -86,3 +91,16 @@ export function ServiceLogoFallback({
); } + +const EMPTY_MANIFEST: IconManifest = { + transparent: new Set(), + lightBg: new Set(), +}; + +function useIconManifest(): IconManifest { + const [manifest, setManifest] = useState(EMPTY_MANIFEST); + useEffect(() => { + fetchIconManifest().then(setManifest); + }, []); + return manifest; +} From 9037e449b1dfc431afee91f909e1c7d6480af09b Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Tue, 24 Mar 2026 10:21:21 +0000 Subject: [PATCH 10/11] fix: add .ts extension to logodev import for Node ESM compatibility --- scripts/sync-logos.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/sync-logos.ts b/scripts/sync-logos.ts index 3b8fefd9..b0b12a17 100644 --- a/scripts/sync-logos.ts +++ b/scripts/sync-logos.ts @@ -7,7 +7,7 @@ import { readFileSync } from "node:fs"; import { resolve } from "node:path"; import { put } from "@vercel/blob"; -import { logoDevUrl } from "../src/lib/logodev"; +import { logoDevUrl } from "../src/lib/logodev.ts"; // --------------------------------------------------------------------------- // Types From e0f919943b8fde6baf65337908f23dcbe3524e36 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Tue, 24 Mar 2026 10:38:26 +0000 Subject: [PATCH 11/11] fix: use top-level zlib import in sync-logos for ESM compatibility The require('node:zlib') call inside decodePngPixels silently failed in ESM mode, causing all PNG transparency and lightBg detection to return false. Now correctly detects 11 transparent and 27 light-bg icons. --- scripts/sync-logos.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/scripts/sync-logos.ts b/scripts/sync-logos.ts index b0b12a17..d59db780 100644 --- a/scripts/sync-logos.ts +++ b/scripts/sync-logos.ts @@ -6,6 +6,7 @@ import { readFileSync } from "node:fs"; import { resolve } from "node:path"; +import * as zlib from "node:zlib"; import { put } from "@vercel/blob"; import { logoDevUrl } from "../src/lib/logodev.ts"; @@ -59,7 +60,7 @@ const DOMAIN_OVERRIDES: Record = { // --------------------------------------------------------------------------- function decodePngPixels(buf: ArrayBuffer) { - const { inflateSync } = require("node:zlib") as typeof import("node:zlib"); + const { inflateSync } = zlib; const bytes = new Uint8Array(buf); if (bytes.length < 26) return null; const colorType = bytes[25];