npm package: @redonvn/event-ws-cliproxyapi-sdk
Description: TypeScript SDK for CLIProxyAPI WebSocket relay (provider-side).
Latest version: 1.0.6

# @redonvn/event-ws-cliproxyapi-sdk

TypeScript SDK for CLIProxyAPI with two main capabilities:
- HTTP clients for OpenAI/Claude/Gemini-compatible and management endpoints
- Provider-side WebSocket relay for `/v1/ws`

## Why This SDK

- Strong TypeScript types for request/response payloads
- Unified auth model (`accessKey`, `managementKey`, `localPassword`)
- Shared error model (`APIError`) across all HTTP clients
- Explicit client modules by domain: `OpenAIClient`, `ClaudeClient`, `GeminiClient`, `CliproxyClient`, `ManagementClient`, `CliproxyWSProvider`

## Install

```bash
npm i @redonvn/event-ws-cliproxyapi-sdk
```

## Requirements

- Node.js with `fetch` support (Node 18+ recommended)
- TypeScript 5+ (if consuming types in TS)

If your runtime does not provide `fetch`, pass `options.fetch` when creating clients.

## Quick Start

```ts
import {
  CliproxyClient,
  OpenAIClient,
  ClaudeClient,
  GeminiClient,
  ManagementClient,
  APIError
} from '@redonvn/event-ws-cliproxyapi-sdk';

const baseUrl = 'http://127.0.0.1:8317';

const cliproxy = new CliproxyClient({
  baseUrl,
  accessKey: process.env.ACCESS_KEY,
  managementKey: process.env.MANAGEMENT_KEY,
  localPassword: process.env.LOCAL_PASSWORD
});

const openai = new OpenAIClient({ baseUrl, accessKey: process.env.ACCESS_KEY });
const claude = new ClaudeClient({ baseUrl, accessKey: process.env.ACCESS_KEY });
const gemini = new GeminiClient({ baseUrl, accessKey: process.env.ACCESS_KEY });
const management = new ManagementClient({ baseUrl, managementKey: process.env.MANAGEMENT_KEY });

try {
  const models = await openai.getModels();
  console.log(models.data.length);
} catch (err) {
  if (err instanceof APIError) {
    console.error(err.status, err.message, err.payload);
  }
}
```

## Auth Model

- `accessKey`: used for access-protected public inference endpoints
- `managementKey`: used for `/v0/management/*`
- `localPassword`: used for local-protected endpoints such as `/keep-alive`

You can update keys at runtime:
- `setAccessKey(key?)`
- `setManagementKey(key?)`
- `setLocalPassword(value?)`

## Exported Modules

From package root (`src/index.ts`):
- `openai/*`
- `claude/*`
- `gemini/*`
- `cliproxy/*`
- `management/*`
- `ws/*`
- `shared/*`

Core exports:
- Clients: `OpenAIClient`, `ClaudeClient`, `GeminiClient`, `CliproxyClient`, `ManagementClient`
- WS relay: `CliproxyWSProvider`, `CliproxyWSClient`
- WS codec helpers: `decodeRequest`, `encodeResponse`, `decodeResponse`, `encodeChunk`, `decodeChunk`, `encodeError`, `decodeError`
- Errors: `APIError`, `isOpenAIError`, `isStatusError`, `isManagementError`
- Full payload types from `shared/types`

## HTTP Clients

### `OpenAIClient`

Methods:
- `getModels()` -> `GET /v1/models`
- `postChatCompletions(body)` -> `POST /v1/chat/completions`
- `postCompletions(body)` -> `POST /v1/completions`
- `postResponses(body)` -> `POST /v1/responses`
- `postResponsesCompact(body)` -> `POST /v1/responses/compact`

Example:

```ts
const res = await openai.postChatCompletions({
  model: 'gpt-4o-mini',
  messages: [{ role: 'user', content: 'hello' }],
  stream: false
});

const json = await res.json();
console.log(json);
```

### `ClaudeClient`

Methods:
- `getModels()` -> `GET /v1/models` (adds `User-Agent: claude-cli`)
- `postMessages(body)` -> `POST /v1/messages`
- `postMessagesCountTokens(body)` -> `POST /v1/messages/count_tokens`

### `GeminiClient`

Methods:
- `getModels()` -> `GET /v1beta/models`
- `postModelsAction(action, body)` -> `POST /v1beta/models/{action}`
- `getModelsAction(action, query?)` -> `GET /v1beta/models/{action}`
- `postV1Internal(method, body)` -> `POST /v1internal:{method}`

### `CliproxyClient`

Methods:
- `getRoot()` -> `GET /`
- `getManagementHtml()` -> `GET /management.html`
- `keepAlive()` -> `GET /keep-alive`
- OAuth callbacks:
  - `anthropicCallback(query)` -> `GET /anthropic/callback`
  - `codexCallback(query)` -> `GET /codex/callback`
  - `googleCallback(query)` -> `GET /google/callback`
  - `iflowCallback(query)` -> `GET /iflow/callback`
  - `antigravityCallback(query)` -> `GET /antigravity/callback`
- CLIProxy endpoints:
  - `getCliproxyAuths(query?)` -> `GET /v1/cliproxy/auths`
  - `getCliproxyModels(query?)` -> `GET /v1/cliproxy/models`
  - `postCliproxyChat(body)` -> `POST /v1/cliproxy/chat`

### `ManagementClient`

Covers management APIs under `/v0/management/*`, including:
- usage import/export
- runtime config and YAML config
- logging and debug flags
- key/config CRUD (`api-keys`, `claude-api-key`, `gemini-api-key`, `codex-api-key`, `vertex-api-key`, `openai-compatibility`)
- routing/retry/quota flags
- auth files and model definitions
- OAuth helper flows

Also includes:
- `getDesktopKeys()` -> `GET /desktop/keys`
- `getManagementApiKeys()` convenience fallback helper

## Streaming Responses

Many inference methods return raw `Response` for stream compatibility.
- For SSE/event-stream, read `response.body`
- For non-stream mode, parse with `await response.json()` or `await response.text()`

## WebSocket Relay (Provider Side)

Use `CliproxyWSProvider` to handle server forwarded requests over `/v1/ws`.

```ts
import { CliproxyWSProvider } from '@redonvn/event-ws-cliproxyapi-sdk';

const provider = new CliproxyWSProvider({
  baseUrl: 'http://127.0.0.1:8317',
  accessKey: process.env.ACCESS_KEY
});

await provider.connect({
  onEvent: (ev) => {
    if (ev.type === 'ws:open') console.log('connected');
    if (ev.type === 'ws:close') console.log('closed', ev.code, ev.reason);
    if (ev.type === 'error') console.error(ev.error);
  },
  onRequest: async (req, ctx) => {
    if (req.url === '/health') {
      ctx.respond({ status: 200, body: 'ok' });
      return;
    }

    ctx.streamStart(200, { 'Content-Type': 'text/plain' });
    ctx.streamChunk('hello ');
    ctx.streamChunk('world');
    ctx.streamEnd();
  }
});

provider.close();
```

WS message/event types are exported from `ws/types`.

## Error Handling

All non-2xx HTTP responses throw `APIError`.

```ts
import { APIError, isOpenAIError, isManagementError } from '@redonvn/event-ws-cliproxyapi-sdk';

try {
  await management.getConfig();
} catch (err) {
  if (err instanceof APIError) {
    if (isOpenAIError(err.payload)) {
      console.error('openai error:', err.payload.error.message);
    } else if (isManagementError(err.payload)) {
      console.error('management error:', err.payload.error);
    } else {
      console.error(err.status, err.message);
    }
  }
}
```

## Common Types

Selected primary request aliases:
- `PrimaryOpenAIChatRequest`
- `PrimaryOpenAICompletionRequest`
- `PrimaryOpenAIResponsesRequest`
- `PrimaryClaudeRequest`
- `PrimaryGeminiRequest`
- `PrimaryCliproxyRequest`

Protocol and shared types:
- JSON primitives/objects (`JsonValue`, `JsonObject`)
- model/config/auth entities
- OpenAI/Claude/Gemini compatible request/response types

## Development

```bash
npm i
npm run build
```

Build output:
- JS: `dist/*.js`
- Declarations: `dist/*.d.ts`

## Notes

- WebSocket auth: if server has `ws-auth: true`, provide `accessKey`.
- Management endpoints require `managementKey`.
- `keepAlive()` uses local auth (`localPassword`) if server enforces it.
- This SDK is transport-oriented; retries/backoff are intentionally left to the consumer.