mirror of
https://github.com/getcompanion-ai/co-mono.git
synced 2026-04-17 06:04:51 +00:00
Proxy package
This commit is contained in:
parent
aaea0f4600
commit
66f092c0c6
9 changed files with 249 additions and 4 deletions
67
packages/proxy/README.md
Normal file
67
packages/proxy/README.md
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
# @mariozechner/pi-proxy
|
||||
|
||||
CORS and authentication proxy for pi-ai. Enables browser clients to access OAuth-protected endpoints.
|
||||
|
||||
## Usage
|
||||
|
||||
### CORS Proxy
|
||||
|
||||
Zero-config CORS proxy for development:
|
||||
|
||||
```bash
|
||||
# Run directly with tsx
|
||||
npx tsx packages/proxy/src/cors-proxy.ts 3001
|
||||
|
||||
# Or use npm script
|
||||
npm run dev -w @mariozechner/pi-proxy
|
||||
|
||||
# Or install globally and use CLI
|
||||
npm install -g @mariozechner/pi-proxy
|
||||
pi-proxy 3001
|
||||
```
|
||||
|
||||
The proxy will forward requests to any URL:
|
||||
|
||||
```javascript
|
||||
// Instead of:
|
||||
fetch('https://api.anthropic.com/v1/messages', { ... })
|
||||
|
||||
// Use:
|
||||
fetch('http://localhost:3001?url=https://api.anthropic.com/v1/messages', { ... })
|
||||
```
|
||||
|
||||
### OAuth Integration
|
||||
|
||||
For Anthropic OAuth tokens, configure your client to use the proxy:
|
||||
|
||||
```typescript
|
||||
import Anthropic from '@anthropic-ai/sdk';
|
||||
|
||||
const client = new Anthropic({
|
||||
apiKey: 'oauth_token_here',
|
||||
baseURL: 'http://localhost:3001?url=https://api.anthropic.com'
|
||||
});
|
||||
```
|
||||
|
||||
## Future Proxy Types
|
||||
|
||||
- **BunnyCDN Edge Function**: Deploy as edge function
|
||||
- **Managed Proxy**: Self-hosted with provider key management and credential auth
|
||||
- **Cloudflare Worker**: Deploy as CF worker
|
||||
|
||||
## Architecture
|
||||
|
||||
The proxy:
|
||||
1. Accepts requests with `?url=<target>` query parameter
|
||||
2. Forwards all headers (except `host`, `origin`)
|
||||
3. Forwards request body for non-GET/HEAD requests
|
||||
4. Returns response with CORS headers enabled
|
||||
5. Strips CORS headers from upstream response
|
||||
|
||||
## Development
|
||||
|
||||
```bash
|
||||
npm install
|
||||
npm run build
|
||||
npm run check
|
||||
```
|
||||
27
packages/proxy/package.json
Normal file
27
packages/proxy/package.json
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
{
|
||||
"name": "@mariozechner/pi-proxy",
|
||||
"version": "0.5.43",
|
||||
"type": "module",
|
||||
"description": "CORS and authentication proxy for pi-ai",
|
||||
"main": "dist/index.js",
|
||||
"types": "dist/index.d.ts",
|
||||
"bin": {
|
||||
"pi-proxy": "dist/cli.js"
|
||||
},
|
||||
"scripts": {
|
||||
"clean": "rm -rf dist",
|
||||
"build": "tsc",
|
||||
"check": "biome check --write .",
|
||||
"typecheck": "tsc --noEmit",
|
||||
"dev": "tsx src/cors-proxy.ts 3001"
|
||||
},
|
||||
"dependencies": {
|
||||
"@hono/node-server": "^1.14.0",
|
||||
"hono": "^4.6.16"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^22.10.5",
|
||||
"tsx": "^4.19.2",
|
||||
"typescript": "^5.7.3"
|
||||
}
|
||||
}
|
||||
16
packages/proxy/src/cli.ts
Normal file
16
packages/proxy/src/cli.ts
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
#!/usr/bin/env node
|
||||
import { spawn } from "node:child_process";
|
||||
import path from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
|
||||
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
||||
const port = process.argv[2] || "3001";
|
||||
|
||||
// Run the CORS proxy
|
||||
const child = spawn("node", [path.join(__dirname, "cors-proxy.js"), port], {
|
||||
stdio: "inherit",
|
||||
});
|
||||
|
||||
child.on("exit", (code) => {
|
||||
process.exit(code || 0);
|
||||
});
|
||||
73
packages/proxy/src/cors-proxy.ts
Normal file
73
packages/proxy/src/cors-proxy.ts
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
#!/usr/bin/env node
|
||||
import { serve } from "@hono/node-server";
|
||||
import { Hono } from "hono";
|
||||
import { cors } from "hono/cors";
|
||||
|
||||
export function createCorsProxy() {
|
||||
const app = new Hono();
|
||||
|
||||
// Enable CORS for all origins
|
||||
app.use("*", cors());
|
||||
|
||||
// Proxy all requests
|
||||
app.all("*", async (c) => {
|
||||
const url = new URL(c.req.url);
|
||||
const targetUrl = url.searchParams.get("url");
|
||||
|
||||
if (!targetUrl) {
|
||||
return c.json({ error: "Missing 'url' query parameter" }, 400);
|
||||
}
|
||||
|
||||
try {
|
||||
// Forward the request
|
||||
const headers = new Headers();
|
||||
c.req.raw.headers.forEach((value, key) => {
|
||||
// Skip host and origin headers
|
||||
if (key.toLowerCase() !== "host" && key.toLowerCase() !== "origin") {
|
||||
headers.set(key, value);
|
||||
}
|
||||
});
|
||||
|
||||
const response = await fetch(targetUrl, {
|
||||
method: c.req.method,
|
||||
headers,
|
||||
body: c.req.method !== "GET" && c.req.method !== "HEAD" ? await c.req.raw.clone().arrayBuffer() : undefined,
|
||||
});
|
||||
|
||||
// Forward response headers
|
||||
const responseHeaders = new Headers();
|
||||
response.headers.forEach((value, key) => {
|
||||
// Skip CORS headers (we handle them)
|
||||
if (!key.toLowerCase().startsWith("access-control-")) {
|
||||
responseHeaders.set(key, value);
|
||||
}
|
||||
});
|
||||
|
||||
// Return proxied response
|
||||
return new Response(response.body, {
|
||||
status: response.status,
|
||||
statusText: response.statusText,
|
||||
headers: responseHeaders,
|
||||
});
|
||||
} catch (error) {
|
||||
console.error("Proxy error:", error);
|
||||
return c.json({ error: error instanceof Error ? error.message : "Proxy request failed" }, 502);
|
||||
}
|
||||
});
|
||||
|
||||
return app;
|
||||
}
|
||||
|
||||
// CLI entry point
|
||||
if (import.meta.url === `file://${process.argv[1]}`) {
|
||||
const app = createCorsProxy();
|
||||
const port = Number.parseInt(process.argv[2] || "3001", 10);
|
||||
|
||||
console.log(`🔌 CORS proxy running on http://localhost:${port}`);
|
||||
console.log(`Usage: http://localhost:${port}?url=<target-url>`);
|
||||
|
||||
serve({
|
||||
fetch: app.fetch,
|
||||
port,
|
||||
});
|
||||
}
|
||||
1
packages/proxy/src/index.ts
Normal file
1
packages/proxy/src/index.ts
Normal file
|
|
@ -0,0 +1 @@
|
|||
export { createCorsProxy } from "./cors-proxy.js";
|
||||
8
packages/proxy/tsconfig.json
Normal file
8
packages/proxy/tsconfig.json
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"extends": "../../tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "dist",
|
||||
"rootDir": "src"
|
||||
},
|
||||
"include": ["src/**/*"]
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue