{"id":48878837,"url":"https://github.com/pmbstyle/openrouter-proxy","last_synced_at":"2026-04-16T01:34:48.473Z","repository":{"id":319669047,"uuid":"1079274916","full_name":"pmbstyle/openrouter-proxy","owner":"pmbstyle","description":"Nodejs OpenRouter proxy inference that provides all nessary endpoints for your LLM application.","archived":false,"fork":false,"pushed_at":"2026-01-12T20:53:59.000Z","size":241,"stargazers_count":2,"open_issues_count":0,"forks_count":2,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-01-12T22:58:56.780Z","etag":null,"topics":["llm-inference","llm-proxy","llm-webservice","nodejs","openrouter-api"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/pmbstyle.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-10-19T13:35:24.000Z","updated_at":"2026-01-12T20:54:03.000Z","dependencies_parsed_at":null,"dependency_job_id":"279fb2e5-d22c-4ddd-b46f-28f52fd7c372","html_url":"https://github.com/pmbstyle/openrouter-proxy","commit_stats":null,"previous_names":["pmbstyle/openrouter-proxy"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/pmbstyle/openrouter-proxy","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pmbstyle%2Fopenrouter-proxy","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pmbstyle%2Fopenrouter-proxy/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pmbstyle%2Fopenrouter-proxy/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pmbstyle%2Fopenrouter-proxy/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/pmbstyle","download_url":"https://codeload.github.com/pmbstyle/openrouter-proxy/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pmbstyle%2Fopenrouter-proxy/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31867712,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-15T15:24:51.572Z","status":"ssl_error","status_checked_at":"2026-04-15T15:24:39.138Z","response_time":63,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["llm-inference","llm-proxy","llm-webservice","nodejs","openrouter-api"],"created_at":"2026-04-16T01:34:47.798Z","updated_at":"2026-04-16T01:34:48.460Z","avatar_url":"https://github.com/pmbstyle.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# OpenRouter Proxy Service\n\nA high-performance, stateless OpenRouter proxy service built with Node.js, TypeScript, and Express. Provides REST API and WebSocket streaming capabilities for LLM inference.\n\n## Features\n\n- **Dual Interface**: REST API for standard requests and WebSocket for streaming\n- **Comprehensive Parameter Support**: System prompts, model/provider selection, temperature, tools, etc.\n- **Multi-modal Support**: Text, audio, and image generation capabilities\n- **Robust Error Handling**: Graceful failure recovery and informative error responses\n- **High Performance**: Optimized for speed and low latency\n- **IP-based Rate Limiting**: Protection against abuse while maintaining simplicity\n- **Usage tracking**: Global and per API key tracking requests, tokens, cost, and models\n\n## Quick Start\n\n### Prerequisites\n\n- Node.js 20+\n- npm or yarn\n- OpenRouter API key\n\n### Installation\n\n1. Clone the repository:\n```bash\ngit clone https://github.com/pmbstyle/openrouter-proxy.git\ncd openrouter-proxy\n```\n\n2. Install dependencies:\n```bash\nnpm install\n```\n\n3. Set up environment variables:\n```bash\ncp .env.example .env\n# Edit .env with your OpenRouter API key\n```\n\n4. Build the project:\n```bash\nnpm run build\n```\n\n5. Start the server:\n```bash\nnpm start\n```\n\nFor development:\n```bash\nnpm run dev\n```\n\n## Configuration\n\nThe service uses environment variables for configuration. See `.env.example` for all available options:\n\n### Required Variables\n\n- `OPENROUTER_API_KEY`: Your OpenRouter API key\n\n### Optional Variables\n\n- `PORT`: Server port (default: 3000)\n- `HOST`: Server host (default: 0.0.0.0)\n- `NODE_ENV`: Environment (development/production/test)\n- `LOG_LEVEL`: Logging level (debug/info/warn/error)\n- `RATE_LIMIT_WINDOW_MS`: Rate limit window in milliseconds (default: 900000)\n- `RATE_LIMIT_MAX_REQUESTS`: Max requests per window (default: 100)\n- `WS_MAX_CONNECTIONS`: Max WebSocket connections (default: 1000)\n- `WS_HEARTBEAT_INTERVAL`: WebSocket heartbeat interval (default: 30000)\n- `MAX_CONCURRENT_REQUESTS`: Max concurrent requests (default: 100)\n- `REQUEST_TIMEOUT`: Request timeout in milliseconds (default: 30000)\n- `ALLOWED_ORIGINS`: Comma-separated list of allowed CORS origins (e.g., `http://localhost:3001,https://example.com`). Defaults to `http://localhost:3000,http://localhost:3001` in development mode. Leave empty to block all cross-origin requests in production.\n- `CORS_CREDENTIALS`: Enable CORS credentials (default: true)\n\n## API Endpoints\n\n### Health Check\n\n#### `GET /health`\nCheck service health status.\n\n**Response:**\n```json\n{\n  \"status\": \"healthy\",\n  \"timestamp\": \"2024-01-01T00:00:00.000Z\",\n  \"uptime\": 123.45,\n  \"version\": \"1.0.0\",\n  \"environment\": \"production\"\n}\n```\n\n### Inference Endpoints\n\n#### `POST /api/v1/inference`\nCreate a completion using the specified model.\n\n**Request Body:**\n```json\n{\n  \"model\": \"openai/gpt-4o\",\n  \"messages\": [\n    {\n      \"role\": \"user\",\n      \"content\": \"Hello, world!\"\n    }\n  ],\n  \"temperature\": 0.7,\n  \"max_tokens\": 100,\n  \"stream\": false\n}\n```\n\n**Response:**\n```json\n{\n  \"id\": \"chatcmpl-123\",\n  \"choices\": [\n    {\n      \"finish_reason\": \"stop\",\n      \"message\": {\n        \"content\": \"Hello! How can I help you today?\",\n        \"role\": \"assistant\"\n      }\n    }\n  ],\n  \"usage\": {\n    \"prompt_tokens\": 10,\n    \"completion_tokens\": 15,\n    \"total_tokens\": 25\n  },\n  \"model\": \"openai/gpt-4o\",\n  \"created\": 1704067200,\n  \"object\": \"chat.completion\"\n}\n```\n\n#### `POST /api/v1/inference/stream`\nCreate a streaming completion using the specified model.\n\n**Request Body:**\n```json\n{\n  \"model\": \"openai/gpt-4o\",\n  \"messages\": [\n    {\n      \"role\": \"user\",\n      \"content\": \"Tell me a story\"\n    }\n  ],\n  \"temperature\": 0.7,\n  \"max_tokens\": 500,\n  \"stream\": true\n}\n```\n\n**Response:** Server-Sent Events stream\n```\ndata: {\"id\":\"chatcmpl-123\",\"object\":\"chat.completion.chunk\",\"created\":1704067200,\"model\":\"openai/gpt-4o\",\"choices\":[{\"index\":0,\"delta\":{\"role\":\"assistant\",\"content\":\"\"},\"finish_reason\":null}]}\n\ndata: {\"id\":\"chatcmpl-123\",\"object\":\"chat.completion.chunk\",\"created\":1704067200,\"model\":\"openai/gpt-4o\",\"choices\":[{\"index\":0,\"delta\":{\"content\":\"Once\"},\"finish_reason\":null}]}\n\ndata: {\"id\":\"chatcmpl-123\",\"object\":\"chat.completion.chunk\",\"created\":1704067200,\"model\":\"openai/gpt-4o\",\"choices\":[{\"index\":0,\"delta\":{\"content\":\" upon\"},\"finish_reason\":null}]}\n\ndata: [DONE]\n```\n\n### Model Endpoints\n\n#### `GET /api/v1/models`\nList all available models with optional filtering and pagination.\n\n**Query Parameters:**\n- `provider` (optional): Filter by provider (e.g., \"openai\", \"anthropic\")\n- `search` (optional): Search in model name or description\n- `limit` (optional): Number of models to return (default: 50, max: 100)\n- `offset` (optional): Number of models to skip (default: 0)\n\n**Example:**\n```\nGET /api/v1/models?provider=openai\u0026search=gpt\u0026limit=10\u0026offset=0\n```\n\n**Response:**\n```json\n{\n  \"data\": [\n    {\n      \"id\": \"openai/gpt-4o\",\n      \"name\": \"GPT-4o\",\n      \"description\": \"Most advanced GPT-4 model\",\n      \"context_length\": 128000,\n      \"pricing\": {\n        \"prompt\": \"0.005\",\n        \"completion\": \"0.015\"\n      },\n      \"supported_parameters\": [\"temperature\", \"max_tokens\", \"top_p\"],\n      \"is_moderated\": true,\n      \"max_completion_tokens\": 4096\n    }\n  ],\n  \"pagination\": {\n    \"total\": 150,\n    \"limit\": 10,\n    \"offset\": 0,\n    \"hasMore\": true\n  }\n}\n```\n\n#### `GET /api/v1/models/:id`\nGet detailed information about a specific model.\n\n**Example:**\n```\nGET /api/v1/models/openai/gpt-4o\n```\n\n**Response:**\n```json\n{\n  \"data\": {\n    \"id\": \"openai/gpt-4o\",\n    \"name\": \"GPT-4o\",\n    \"description\": \"Most advanced GPT-4 model\",\n    \"context_length\": 128000,\n    \"pricing\": {\n      \"prompt\": \"0.005\",\n      \"completion\": \"0.015\"\n    },\n    \"supported_parameters\": [\"temperature\", \"max_tokens\", \"top_p\", \"frequency_penalty\", \"presence_penalty\"],\n    \"is_moderated\": true,\n    \"max_completion_tokens\": 4096\n  }\n}\n```\n\n#### `GET /api/v1/models/:id/parameters`\nGet supported parameters for a specific model.\n\n**Example:**\n```\nGET /api/v1/models/openai/gpt-4o/parameters\n```\n\n**Response:**\n```json\n{\n  \"data\": {\n    \"model\": \"openai/gpt-4o\",\n    \"supported_parameters\": [\n      \"temperature\",\n      \"max_tokens\",\n      \"top_p\",\n      \"frequency_penalty\",\n      \"presence_penalty\",\n      \"stop\",\n      \"stream\"\n    ]\n  }\n}\n```\n\n#### `GET /api/v1/models/:id/pricing`\nGet pricing information for a specific model.\n\n**Example:**\n```\nGET /api/v1/models/openai/gpt-4o/pricing\n```\n\n**Response:**\n```json\n{\n  \"data\": {\n    \"model\": \"openai/gpt-4o\",\n    \"pricing\": {\n      \"prompt\": \"0.005\",\n      \"completion\": \"0.015\"\n    }\n  }\n}\n```\n\n#### `GET /api/v1/models/top`\nGet top models by context length.\n\n**Query Parameters:**\n- `limit` (optional): Number of models to return (default: 10)\n\n**Example:**\n```\nGET /api/v1/models/top?limit=5\n```\n\n**Response:**\n```json\n{\n  \"data\": [\n    {\n      \"id\": \"anthropic/claude-3-5-sonnet-20241022\",\n      \"name\": \"Claude 3.5 Sonnet\",\n      \"context_length\": 200000,\n      \"pricing\": {\n        \"prompt\": \"0.003\",\n        \"completion\": \"0.015\"\n      }\n    }\n  ]\n}\n```\n\n#### `GET /api/v1/models/search`\nSearch models by query.\n\n**Query Parameters:**\n- `q` (required): Search query\n- `limit` (optional): Number of results to return (default: 20)\n\n**Example:**\n```\nGET /api/v1/models/search?q=code\u0026limit=5\n```\n\n**Response:**\n```json\n{\n  \"data\": [\n    {\n      \"id\": \"openai/gpt-4o\",\n      \"name\": \"GPT-4o\",\n      \"description\": \"Most advanced GPT-4 model with code capabilities\"\n    }\n  ],\n  \"query\": \"code\",\n  \"total\": 25\n}\n```\n\n#### `GET /api/v1/models/providers`\nGet all available providers.\n\n**Response:**\n```json\n{\n  \"data\": [\n    \"openai\",\n    \"anthropic\",\n    \"google\",\n    \"meta\",\n    \"mistral\"\n  ]\n}\n```\n\n#### `GET /api/v1/models/providers/:provider`\nGet models by provider.\n\n**Example:**\n```\nGET /api/v1/models/providers/openai\n```\n\n**Response:**\n```json\n{\n  \"data\": [\n    {\n      \"id\": \"openai/gpt-4o\",\n      \"name\": \"GPT-4o\",\n      \"context_length\": 128000\n    }\n  ],\n  \"provider\": \"openai\"\n}\n```\n\n## WebSocket API\n\n### Connection\n\nConnect to the WebSocket endpoint:\n```\nws://localhost:3000/ws\n```\n\n### Message Types\n\n#### Inference Request\n```json\n{\n  \"type\": \"inference_request\",\n  \"id\": \"req-123\",\n  \"data\": {\n    \"model\": \"openai/gpt-4o\",\n    \"messages\": [\n      {\n        \"role\": \"user\",\n        \"content\": \"Hello, world!\"\n      }\n    ],\n    \"temperature\": 0.7,\n    \"max_tokens\": 100\n  }\n}\n```\n\n#### Inference Response\n```json\n{\n  \"type\": \"inference_response\",\n  \"id\": \"req-123\",\n  \"data\": {\n    \"content\": \"Hello! How can I help you today?\",\n    \"finish_reason\": \"stop\",\n    \"usage\": {\n      \"prompt_tokens\": 10,\n      \"completion_tokens\": 15,\n      \"total_tokens\": 25\n    },\n    \"model\": \"openai/gpt-4o\",\n    \"created\": 1704067200\n  }\n}\n```\n\n#### Heartbeat\n```json\n{\n  \"type\": \"heartbeat\",\n  \"timestamp\": 1704067200000\n}\n```\n\n#### Error\n```json\n{\n  \"type\": \"error\",\n  \"id\": \"req-123\",\n  \"error\": {\n    \"code\": 400,\n    \"message\": \"Invalid model\",\n    \"type\": \"validation\"\n  }\n}\n```\n\n#### Close\n```json\n{\n  \"type\": \"close\",\n  \"reason\": \"Client requested close\",\n  \"code\": 1000\n}\n```\n\n## Usage Examples\n\n### REST API Example (JavaScript)\n\n```javascript\n// Standard completion\nconst response = await fetch('http://localhost:3000/api/v1/inference', {\n  method: 'POST',\n  headers: {\n    'Content-Type': 'application/json'\n  },\n  body: JSON.stringify({\n    model: 'openai/gpt-4o',\n    messages: [\n      { role: 'user', content: 'Hello, world!' }\n    ],\n    temperature: 0.7,\n    max_tokens: 100\n  })\n});\n\nconst data = await response.json();\nconsole.log(data.choices[0].message.content);\n```\n\n### Streaming Example (JavaScript)\n\n```javascript\n// Streaming completion\nconst response = await fetch('http://localhost:3000/api/v1/inference/stream', {\n  method: 'POST',\n  headers: {\n    'Content-Type': 'application/json'\n  },\n  body: JSON.stringify({\n    model: 'openai/gpt-4o',\n    messages: [\n      { role: 'user', content: 'Tell me a story' }\n    ],\n    temperature: 0.7,\n    max_tokens: 500,\n    stream: true\n  })\n});\n\nconst reader = response.body.getReader();\nconst decoder = new TextDecoder();\n\nwhile (true) {\n  const { done, value } = await reader.read();\n  if (done) break;\n\n  const chunk = decoder.decode(value);\n  const lines = chunk.split('\\n');\n\n  for (const line of lines) {\n    if (line.startsWith('data: ')) {\n      const data = line.slice(6);\n      if (data === '[DONE]') break;\n      \n      try {\n        const parsed = JSON.parse(data);\n        if (parsed.choices?.[0]?.delta?.content) {\n          console.log(parsed.choices[0].delta.content);\n        }\n      } catch (e) {\n        // Ignore invalid JSON\n      }\n    }\n  }\n}\n```\n\n### WebSocket Example (JavaScript)\n\n```javascript\nconst ws = new WebSocket('ws://localhost:3000/ws');\n\nws.onopen = () =\u003e {\n  // Send inference request\n  ws.send(JSON.stringify({\n    type: 'inference_request',\n    id: 'req-123',\n    data: {\n      model: 'openai/gpt-4o',\n      messages: [\n        { role: 'user', content: 'Hello, world!' }\n      ],\n      temperature: 0.7\n    }\n  }));\n};\n\nws.onmessage = (event) =\u003e {\n  const message = JSON.parse(event.data);\n  \n  switch (message.type) {\n    case 'inference_response':\n      if (message.data.content) {\n        console.log(message.data.content);\n      }\n      if (message.data.finish_reason) {\n        console.log('Finished:', message.data.finish_reason);\n      }\n      break;\n      \n    case 'error':\n      console.error('Error:', message.error.message);\n      break;\n      \n    case 'heartbeat':\n      console.log('Heartbeat received');\n      break;\n  }\n};\n\nws.onclose = () =\u003e {\n  console.log('WebSocket connection closed');\n};\n```\n\n### Python Example\n\n```python\nimport requests\nimport json\n\n# Standard completion\nresponse = requests.post('http://localhost:3000/api/v1/inference', \n    json={\n        'model': 'openai/gpt-4o',\n        'messages': [\n            {'role': 'user', 'content': 'Hello, world!'}\n        ],\n        'temperature': 0.7,\n        'max_tokens': 100\n    }\n)\n\ndata = response.json()\nprint(data['choices'][0]['message']['content'])\n```\n\n### cURL Examples\n\n```bash\n# Standard completion\ncurl -X POST http://localhost:3000/api/v1/inference \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n    \"model\": \"openai/gpt-4o\",\n    \"messages\": [\n      {\"role\": \"user\", \"content\": \"Hello, world!\"}\n    ],\n    \"temperature\": 0.7,\n    \"max_tokens\": 100\n  }'\n\n# List models\ncurl http://localhost:3000/api/v1/models\n\n# Get model details\ncurl http://localhost:3000/api/v1/models/openai/gpt-4o\n\n# Search models\ncurl \"http://localhost:3000/api/v1/models/search?q=gpt\u0026limit=5\"\n```\n\n## Error Handling\n\n### Error Response Format\n\nAll errors follow this format:\n\n```json\n{\n  \"error\": {\n    \"code\": 400,\n    \"message\": \"Validation error\",\n    \"type\": \"validation\",\n    \"details\": {\n      \"field\": \"model\",\n      \"message\": \"Model is required\"\n    }\n  }\n}\n```\n\n### Error Types\n\n- `validation`: Request validation failed\n- `rate_limit`: Rate limit exceeded\n- `openrouter`: OpenRouter API error\n- `internal`: Internal server error\n\n### Common Error Codes\n\n- `400`: Bad Request - Invalid request data\n- `404`: Not Found - Model or endpoint not found\n- `429`: Too Many Requests - Rate limit exceeded\n- `500`: Internal Server Error - Server error\n- `502`: Bad Gateway - OpenRouter API error\n- `503`: Service Unavailable - Service temporarily unavailable\n\n## Rate Limiting\n\nThe service implements IP-based rate limiting:\n\n- **Default**: 100 requests per 15 minutes per IP\n- **Inference endpoints**: 50 requests per 15 minutes per IP\n- **WebSocket**: 5 connections per minute per IP\n\nRate limit headers are included in responses:\n- `X-RateLimit-Limit`: Maximum requests allowed\n- `X-RateLimit-Remaining`: Requests remaining in current window\n- `X-RateLimit-Reset`: Time when the rate limit resets\n\n## Development\n\n### Scripts\n\n- `npm run dev` - Start development server with hot reload\n- `npm run build` - Build the project\n- `npm start` - Start production server\n- `npm test` - Run tests\n- `npm run test:watch` - Run tests in watch mode\n- `npm run test:coverage` - Run tests with coverage\n- `npm run lint` - Run ESLint\n- `npm run lint:fix` - Fix ESLint errors\n\n### Project Structure\n\n```\nsrc/\n├── controllers/          # Request handlers\n├── services/            # Business logic\n├── middleware/          # Express middleware\n├── routes/              # API routes\n├── types/               # TypeScript definitions\n├── utils/               # Utility functions\n├── app.ts               # Express app setup\n└── server.ts            # Server entry point\n```\n\n## Testing\n\nThe project includes comprehensive tests:\n\n- **Unit tests**: Test individual functions and classes\n- **Integration tests**: Test complete request/response cycles\n- **Load tests**: Test performance under load\n\nRun tests:\n```bash\nnpm test\n```\n\n## Docker\n\n### Build and Run\n\n```bash\n# Build the image\ndocker build -f docker/Dockerfile -t llm-proxy .\n\n# Run the container\ndocker run -p 3000:3000 -e OPENROUTER_API_KEY=your-key llm-proxy\n```\n\n### Docker Compose\n\n```bash\n# Start all services\ndocker-compose -f docker/docker-compose.yml up -d\n\n# Stop all services\ndocker-compose -f docker/docker-compose.yml down\n```\n\n## Monitoring\n\nThe service provides monitoring endpoints:\n\n- `GET /health` - Health check with uptime and version info\n\n## Security\n\n- IP-based rate limiting\n- Input validation and sanitization\n- CORS protection\n- Security headers (Helmet)\n- No authentication required (stateless design)\n\n### CORS Configuration\n\nThe service uses Cross-Origin Resource Sharing (CORS) to control which domains can access the API. By default:\n\n- **Development mode**: Allows `http://localhost:3000` and `http://localhost:3001`\n- **Production mode**: Blocks all cross-origin requests unless explicitly configured\n\nTo configure allowed origins, set the `ALLOWED_ORIGINS` environment variable:\n\n```bash\n# Single origin\nALLOWED_ORIGINS=http://localhost:3001\n\n# Multiple origins (comma-separated)\nALLOWED_ORIGINS=http://localhost:3001,http://localhost:3000,https://yourdomain.com\n\n# Allow all origins (not recommended for production)\nALLOWED_ORIGINS=*\n```\n\n**Common CORS issues:**\n\nIf you see CORS errors in your browser console:\n\n1. Ensure your client's origin is in `ALLOWED_ORIGINS`\n2. Check that the origin includes the protocol (http/https) and port\n3. For local development, either:\n   - Set `NODE_ENV=development` to use default localhost origins\n   - Or explicitly set `ALLOWED_ORIGINS=http://localhost:YOUR_PORT`\n\n## Performance\n\n- Connection pooling for OpenRouter API\n- Efficient WebSocket handling\n- Memory-optimized streaming\n- Request/response compression\n- Caching for model information\n- Stateless design for horizontal scaling\n\n## Contributing\n\n1. Fork the repository\n2. Create a feature branch\n3. Make your changes\n4. Add tests\n5. Submit a pull request\n\n## License\n\nMIT License - see LICENSE file for details.\n\n## Support\n\nFor issues and questions, please open an issue on GitHub.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpmbstyle%2Fopenrouter-proxy","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpmbstyle%2Fopenrouter-proxy","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpmbstyle%2Fopenrouter-proxy/lists"}