Using the CORS Proxy
Relevant source files
The following files were used as context for generating this wiki page:
The @mariozechner/pi-proxy package provides a simple, zero-configuration CORS and authentication proxy. Its primary purpose is to enable browser-based clients, such as the pi-web-ui, to communicate with LLM provider APIs that are protected by CORS policies or require OAuth tokens, which cannot be securely handled directly in the browser. It acts as a middleware that forwards requests to a target URL while attaching the necessary CORS headers to the response.
This proxy is an essential development tool within the pi-mono ecosystem, allowing frontend components to seamlessly interact with backend services like Anthropic's API without being blocked by standard browser security policies.
Sources: packages/proxy/README.md, packages/web-ui/src/utils/i18n.ts:121-121
Architecture and Request Flow
The proxy is a lightweight server built using Hono and @hono/node-server. It listens for incoming requests on a specified port and expects a url query parameter containing the target API endpoint.
The core logic is as follows:
- A client sends a request to the proxy server, e.g.,
http://localhost:3001?url=https://api.anthropic.com/v1/messages. - The proxy extracts the target URL from the
urlquery parameter. - It copies all headers from the incoming request, excluding
host,origin, andreferer, to prevent conflicts. - The request, along with its body (for methods like POST), is forwarded to the target URL.
- Upon receiving a response from the target API, the proxy creates a new response.
- It sets permissive CORS headers (e.g.,
Access-Control-Allow-Origin: *) on this new response. - Any CORS-related headers from the original upstream response are stripped to avoid conflicts.
- The final response is sent back to the client, which can now process it without CORS errors.
Sources: packages/proxy/src/cors-proxy.ts:10-53, packages/proxy/README.md:28-33, packages/proxy/package.json:15-16
The following diagram illustrates the request and response flow through the proxy.
Getting Started
The proxy can be run directly from the source using tsx or via an npm script. It can also be installed globally to use the pi-proxy command.
| Command | Description |
|---|---|
npx tsx packages/proxy/src/cors-proxy.ts 3001 | Run the proxy directly on port 3001. |
npm run dev -w @mariozechner/pi-proxy | Starts the proxy using the dev script, which runs tsx src/cors-proxy.ts 3001. |
pi-proxy 3001 | If installed globally, starts the proxy on port 3001 using the CLI. |
Sources: packages/proxy/README.md:7-15, packages/proxy/package.json:10-13
Usage Examples
Basic Fetch Request
To proxy a standard fetch call, prepend the proxy's address to the request and pass the original target URL in the url query parameter.
Original Request:
fetch('https://api.anthropic.com/v1/messages', { /* ... */ });
Proxied Request:
fetch('http://localhost:3001?url=https://api.anthropic.com/v1/messages', { /* ... */ });
Sources: packages/proxy/README.md:17-23
AI SDK Integration
For SDKs like Anthropic's, you can configure the baseURL to automatically route all requests through the proxy. This is particularly useful for handling OAuth tokens.
import Anthropic from '@anthropic-ai/sdk';
const client = new Anthropic({
apiKey: 'oauth_token_here',
baseURL: 'http://localhost:3001?url=https://api.anthropic.com'
});
Sources: packages/proxy/README.md:25-33
Web UI Configuration
The pi-web-ui provides a settings interface to configure the CORS proxy directly from the browser.
| Setting | Description |
|---|---|
| Use CORS Proxy | A toggle to enable or disable proxying for API calls. |
| Proxy URL | The full URL of the running proxy server (e.g., http://localhost:3001). |
The UI provides the following description for the feature: "Allows browser-based apps to bypass CORS restrictions when calling LLM providers. Required for Z-AI and Anthropic with OAuth token." The expected format is also specified: The proxy must accept requests as <proxy-url>/?url=<target-url>.
Sources: packages/web-ui/src/utils/i18n.ts:117-122, packages/web-ui/src/utils/i18n.ts:257-262
Command-Line Interface (CLI)
The package exposes a pi-proxy executable, defined in package.json. The entry point is dist/cli.js.
The CLI script is very simple: it parses the port number from the command-line arguments and starts the proxy server on that port. If no port is provided, it defaults to 3000.
// packages/proxy/src/cli.ts:4-11
#!/usr/bin/env node
import { serve } from "@hono/node-server";
import { app } from "./cors-proxy.js";
const port = process.argv[2] ? parseInt(process.argv[2], 10) : 3000;
serve({
fetch: app.fetch,
port,
});
Sources: packages/proxy/package.json:8-10, packages/proxy/src/cli.ts:4-11
Core Implementation
The proxy server logic is contained entirely within packages/proxy/src/cors-proxy.ts. It uses the Hono web framework to handle all incoming requests with a single route handler.
Request Handler Flow
The app.all('*', ...) handler intercepts every request, regardless of the HTTP method or path.
This diagram shows the logic inside the handler.
Header Manipulation
A key part of the implementation is careful header management.
- Request Headers: Headers from the original client request are copied, but
host,origin, andrefererare deleted to ensure the target API receives the request as if it came from a server-side client. - Response Headers: After fetching from the target, a new
Responseobject is created. This allows the proxy to control the headers sent back to the browser. It explicitly setsAccess-Control-Allow-Origin: *and other CORS headers, while stripping any CORS headers that may have been returned by the upstream API to prevent conflicts.
// packages/proxy/src/cors-proxy.ts:22-26
const fwdHeaders = new Headers(c.req.raw.headers);
fwdHeaders.delete("host");
fwdHeaders.delete("origin");
fwdHeaders.delete("referer");
// packages/proxy/src/cors-proxy.ts:42-45
const responseHeaders = new Headers(res.headers);
corsHeaders.forEach((value, key) => {
responseHeaders.set(key, value);
});
Sources: packages/proxy/src/cors-proxy.ts:22-26, packages/proxy/src/cors-proxy.ts:42-45