@redonvn/event-ws-cliproxyapi-sdk 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. package/README.md +428 -0
  2. package/dist/claude/client.d.ts +8 -0
  3. package/dist/claude/client.js +16 -0
  4. package/dist/claude/index.d.ts +2 -0
  5. package/dist/claude/index.js +1 -0
  6. package/dist/client.d.ts +19 -0
  7. package/dist/client.js +96 -0
  8. package/dist/cliproxy/client.d.ts +41 -0
  9. package/dist/cliproxy/client.js +43 -0
  10. package/dist/cliproxy/index.d.ts +2 -0
  11. package/dist/cliproxy/index.js +1 -0
  12. package/dist/codec.d.ts +8 -0
  13. package/dist/codec.js +79 -0
  14. package/dist/errors/index.d.ts +13 -0
  15. package/dist/errors/index.js +26 -0
  16. package/dist/gemini/client.d.ts +9 -0
  17. package/dist/gemini/client.js +19 -0
  18. package/dist/gemini/index.d.ts +2 -0
  19. package/dist/gemini/index.js +1 -0
  20. package/dist/http/client.d.ts +260 -0
  21. package/dist/http/client.js +591 -0
  22. package/dist/http/index.d.ts +2 -0
  23. package/dist/http/index.js +2 -0
  24. package/dist/http/types.d.ts +783 -0
  25. package/dist/http/types.js +1 -0
  26. package/dist/http-client.d.ts +259 -0
  27. package/dist/http-client.js +557 -0
  28. package/dist/http-types.d.ts +677 -0
  29. package/dist/http-types.js +1 -0
  30. package/dist/index.d.ts +7 -0
  31. package/dist/index.js +7 -0
  32. package/dist/management/client.d.ts +187 -0
  33. package/dist/management/client.js +399 -0
  34. package/dist/management/index.d.ts +2 -0
  35. package/dist/management/index.js +1 -0
  36. package/dist/openai/client.d.ts +10 -0
  37. package/dist/openai/client.js +23 -0
  38. package/dist/openai/index.d.ts +2 -0
  39. package/dist/openai/index.js +1 -0
  40. package/dist/shared/errors.d.ts +13 -0
  41. package/dist/shared/errors.js +26 -0
  42. package/dist/shared/http.d.ts +29 -0
  43. package/dist/shared/http.js +125 -0
  44. package/dist/shared/index.d.ts +2 -0
  45. package/dist/shared/index.js +2 -0
  46. package/dist/shared/types.d.ts +789 -0
  47. package/dist/shared/types.js +1 -0
  48. package/dist/types/index.d.ts +2 -0
  49. package/dist/types/index.js +2 -0
  50. package/dist/types.d.ts +101 -0
  51. package/dist/types.js +1 -0
  52. package/dist/utils/index.d.ts +0 -0
  53. package/dist/utils/index.js +2 -0
  54. package/dist/ws/client.d.ts +20 -0
  55. package/dist/ws/client.js +114 -0
  56. package/dist/ws/codec.d.ts +8 -0
  57. package/dist/ws/codec.js +100 -0
  58. package/dist/ws/index.d.ts +3 -0
  59. package/dist/ws/index.js +3 -0
  60. package/dist/ws/types.d.ts +101 -0
  61. package/dist/ws/types.js +1 -0
  62. package/package.json +29 -0
package/README.md ADDED
@@ -0,0 +1,428 @@
1
+ # event-ws-CLIProxyAPI-sdk
2
+
3
+ TypeScript SDK for CLIProxyAPI covering:
4
+ - WebSocket relay (provider-side) via `/v1/ws`
5
+ - Full HTTP client for public and management APIs
6
+
7
+ ## Endpoints (Full List + Function)
8
+
9
+ WebSocket relay
10
+ - `GET /v1/ws`: WebSocket relay endpoint for provider-side request/response and streaming.
11
+
12
+ Public (no management key)
13
+ - `GET /`: Health/info root. Returns server message + key endpoints list.
14
+ - `GET /management.html`: Management UI HTML (if enabled on server).
15
+ - `GET /keep-alive`: Keep-alive heartbeat (only if server enabled it). Requires local password when set.
16
+ - OAuth callbacks (used by browser auth flows):
17
+ - `GET /anthropic/callback`: Persist Anthropic OAuth callback.
18
+ - `GET /codex/callback`: Persist Codex OAuth callback.
19
+ - `GET /google/callback`: Persist Gemini OAuth callback.
20
+ - `GET /iflow/callback`: Persist iFlow OAuth callback.
21
+ - `GET /antigravity/callback`: Persist Antigravity OAuth callback.
22
+ - `POST /v1internal:method`: Gemini CLI handler (localhost only). For `generateContent` / `streamGenerateContent`.
23
+
24
+ OpenAI-compatible (`/v1`)
25
+ - `GET /v1/models`: List models (OpenAI or Claude depending on User-Agent).
26
+ - `POST /v1/chat/completions`: Chat Completions (OpenAI-compatible, supports stream).
27
+ - `POST /v1/completions`: Completions (OpenAI-compatible, supports stream).
28
+ - `POST /v1/messages`: Claude-style messages (supports stream).
29
+ - `POST /v1/messages/count_tokens`: Claude token counting.
30
+ - `POST /v1/responses`: OpenAI Responses API (supports stream).
31
+ - `POST /v1/responses/compact`: OpenAI Responses Compact (non-stream).
32
+
33
+ CLIProxy simplified (`/v1/cliproxy`)
34
+ - `GET /v1/cliproxy/auths`: List authenticated accounts and supported models.
35
+ - `GET /v1/cliproxy/models`: List available models (format: openai/claude/gemini/generic).
36
+ - `POST /v1/cliproxy/chat`: Simplified chat proxy (maps to OpenAI chat).
37
+
38
+ Gemini-compatible (`/v1beta`)
39
+ - `GET /v1beta/models`: List Gemini models.
40
+ - `POST /v1beta/models/*action`: Gemini generate/stream endpoints (e.g. `:generateContent`, `:streamGenerateContent`).
41
+ - `GET /v1beta/models/*action`: Gemini GET actions.
42
+
43
+ Management (`/v0/management`, requires management key)
44
+ - `GET /v0/management/usage`: Usage snapshot (in-memory stats).
45
+ - `GET /v0/management/usage/export`: Export usage snapshot.
46
+ - `POST /v0/management/usage/import`: Import usage snapshot.
47
+ - `GET /v0/management/config`: Full config JSON.
48
+ - `GET /v0/management/config.yaml`: Config YAML.
49
+ - `PUT /v0/management/config.yaml`: Replace config YAML (validates then saves).
50
+ - `GET /v0/management/latest-version`: Latest release version (from GitHub).
51
+ - `GET /v0/management/debug`: Debug flag.
52
+ - `PUT /v0/management/debug`: Update debug flag.
53
+ - `PATCH /v0/management/debug`: Update debug flag.
54
+ - `GET /v0/management/logging-to-file`: Logging-to-file flag.
55
+ - `PUT /v0/management/logging-to-file`: Update logging-to-file.
56
+ - `PATCH /v0/management/logging-to-file`: Update logging-to-file.
57
+ - `GET /v0/management/logs-max-total-size-mb`: Logs max size.
58
+ - `PUT /v0/management/logs-max-total-size-mb`: Update logs max size.
59
+ - `PATCH /v0/management/logs-max-total-size-mb`: Update logs max size.
60
+ - `GET /v0/management/error-logs-max-files`: Error logs max files.
61
+ - `PUT /v0/management/error-logs-max-files`: Update error logs max files.
62
+ - `PATCH /v0/management/error-logs-max-files`: Update error logs max files.
63
+ - `GET /v0/management/usage-statistics-enabled`: Usage stats enabled.
64
+ - `PUT /v0/management/usage-statistics-enabled`: Update usage stats enabled.
65
+ - `PATCH /v0/management/usage-statistics-enabled`: Update usage stats enabled.
66
+ - `GET /v0/management/proxy-url`: Proxy URL.
67
+ - `PUT /v0/management/proxy-url`: Update proxy URL.
68
+ - `PATCH /v0/management/proxy-url`: Update proxy URL.
69
+ - `DELETE /v0/management/proxy-url`: Clear proxy URL.
70
+ - `POST /v0/management/api-call`: Test outbound API call using an auth entry.
71
+ - `GET /v0/management/quota-exceeded/switch-project`: Switch project flag.
72
+ - `PUT /v0/management/quota-exceeded/switch-project`: Update switch project flag.
73
+ - `PATCH /v0/management/quota-exceeded/switch-project`: Update switch project flag.
74
+ - `GET /v0/management/quota-exceeded/switch-preview-model`: Switch preview model flag.
75
+ - `PUT /v0/management/quota-exceeded/switch-preview-model`: Update switch preview model flag.
76
+ - `PATCH /v0/management/quota-exceeded/switch-preview-model`: Update switch preview model flag.
77
+ - `GET /v0/management/api-keys`: List API keys.
78
+ - `PUT /v0/management/api-keys`: Replace API keys.
79
+ - `PATCH /v0/management/api-keys`: Patch API keys.
80
+ - `DELETE /v0/management/api-keys`: Delete API keys.
81
+ - `GET /v0/management/gemini-api-key`: List Gemini keys.
82
+ - `PUT /v0/management/gemini-api-key`: Replace Gemini keys.
83
+ - `PATCH /v0/management/gemini-api-key`: Patch Gemini keys.
84
+ - `DELETE /v0/management/gemini-api-key`: Delete Gemini keys.
85
+ - `GET /v0/management/logs`: Read log lines.
86
+ - `DELETE /v0/management/logs`: Clear logs.
87
+ - `GET /v0/management/request-error-logs`: List request error logs.
88
+ - `GET /v0/management/request-error-logs/:name`: Download a request error log.
89
+ - `GET /v0/management/request-log-by-id/:id`: Download request log by request ID.
90
+ - `GET /v0/management/request-log`: Request log enabled flag.
91
+ - `PUT /v0/management/request-log`: Update request log enabled flag.
92
+ - `PATCH /v0/management/request-log`: Update request log enabled flag.
93
+ - `GET /v0/management/ws-auth`: WebSocket auth enabled flag.
94
+ - `PUT /v0/management/ws-auth`: Update WebSocket auth enabled flag.
95
+ - `PATCH /v0/management/ws-auth`: Update WebSocket auth enabled flag.
96
+ - `GET /v0/management/ampcode`: Amp CLI config.
97
+ - `GET /v0/management/ampcode/upstream-url`: Amp upstream URL.
98
+ - `PUT /v0/management/ampcode/upstream-url`: Update Amp upstream URL.
99
+ - `PATCH /v0/management/ampcode/upstream-url`: Update Amp upstream URL.
100
+ - `DELETE /v0/management/ampcode/upstream-url`: Clear Amp upstream URL.
101
+ - `GET /v0/management/ampcode/upstream-api-key`: Amp upstream API key.
102
+ - `PUT /v0/management/ampcode/upstream-api-key`: Update Amp upstream API key.
103
+ - `PATCH /v0/management/ampcode/upstream-api-key`: Update Amp upstream API key.
104
+ - `DELETE /v0/management/ampcode/upstream-api-key`: Clear Amp upstream API key.
105
+ - `GET /v0/management/ampcode/restrict-management-to-localhost`: Restrict Amp management to localhost.
106
+ - `PUT /v0/management/ampcode/restrict-management-to-localhost`: Update restriction.
107
+ - `PATCH /v0/management/ampcode/restrict-management-to-localhost`: Update restriction.
108
+ - `GET /v0/management/ampcode/model-mappings`: List Amp model mappings.
109
+ - `PUT /v0/management/ampcode/model-mappings`: Replace Amp model mappings.
110
+ - `PATCH /v0/management/ampcode/model-mappings`: Patch Amp model mappings.
111
+ - `DELETE /v0/management/ampcode/model-mappings`: Delete Amp model mappings.
112
+ - `GET /v0/management/ampcode/force-model-mappings`: Force model mappings flag.
113
+ - `PUT /v0/management/ampcode/force-model-mappings`: Update force model mappings.
114
+ - `PATCH /v0/management/ampcode/force-model-mappings`: Update force model mappings.
115
+ - `GET /v0/management/ampcode/upstream-api-keys`: List Amp upstream API keys.
116
+ - `PUT /v0/management/ampcode/upstream-api-keys`: Replace Amp upstream API keys.
117
+ - `PATCH /v0/management/ampcode/upstream-api-keys`: Patch Amp upstream API keys.
118
+ - `DELETE /v0/management/ampcode/upstream-api-keys`: Delete Amp upstream API keys.
119
+ - `GET /v0/management/request-retry`: Request retry count.
120
+ - `PUT /v0/management/request-retry`: Update request retry count.
121
+ - `PATCH /v0/management/request-retry`: Update request retry count.
122
+ - `GET /v0/management/max-retry-interval`: Max retry interval.
123
+ - `PUT /v0/management/max-retry-interval`: Update max retry interval.
124
+ - `PATCH /v0/management/max-retry-interval`: Update max retry interval.
125
+ - `GET /v0/management/force-model-prefix`: Force model prefix flag.
126
+ - `PUT /v0/management/force-model-prefix`: Update force model prefix.
127
+ - `PATCH /v0/management/force-model-prefix`: Update force model prefix.
128
+ - `GET /v0/management/routing/strategy`: Routing strategy.
129
+ - `PUT /v0/management/routing/strategy`: Update routing strategy.
130
+ - `PATCH /v0/management/routing/strategy`: Update routing strategy.
131
+ - `GET /v0/management/claude-api-key`: List Claude keys.
132
+ - `PUT /v0/management/claude-api-key`: Replace Claude keys.
133
+ - `PATCH /v0/management/claude-api-key`: Patch Claude keys.
134
+ - `DELETE /v0/management/claude-api-key`: Delete Claude keys.
135
+ - `GET /v0/management/codex-api-key`: List Codex keys.
136
+ - `PUT /v0/management/codex-api-key`: Replace Codex keys.
137
+ - `PATCH /v0/management/codex-api-key`: Patch Codex keys.
138
+ - `DELETE /v0/management/codex-api-key`: Delete Codex keys.
139
+ - `GET /v0/management/openai-compatibility`: List OpenAI compatibility configs.
140
+ - `PUT /v0/management/openai-compatibility`: Replace OpenAI compatibility configs.
141
+ - `PATCH /v0/management/openai-compatibility`: Patch OpenAI compatibility configs.
142
+ - `DELETE /v0/management/openai-compatibility`: Delete OpenAI compatibility configs.
143
+ - `GET /v0/management/vertex-api-key`: List Vertex compatibility keys.
144
+ - `PUT /v0/management/vertex-api-key`: Replace Vertex compatibility keys.
145
+ - `PATCH /v0/management/vertex-api-key`: Patch Vertex compatibility keys.
146
+ - `DELETE /v0/management/vertex-api-key`: Delete Vertex compatibility keys.
147
+ - `GET /v0/management/oauth-excluded-models`: List OAuth excluded models.
148
+ - `PUT /v0/management/oauth-excluded-models`: Replace OAuth excluded models.
149
+ - `PATCH /v0/management/oauth-excluded-models`: Patch OAuth excluded models.
150
+ - `DELETE /v0/management/oauth-excluded-models`: Delete OAuth excluded models.
151
+ - `GET /v0/management/oauth-model-alias`: List OAuth model alias.
152
+ - `PUT /v0/management/oauth-model-alias`: Replace OAuth model alias.
153
+ - `PATCH /v0/management/oauth-model-alias`: Patch OAuth model alias.
154
+ - `DELETE /v0/management/oauth-model-alias`: Delete OAuth model alias.
155
+ - `GET /v0/management/auth-files`: List auth files.
156
+ - `GET /v0/management/auth-files/models`: Get models for an auth file.
157
+ - `GET /v0/management/model-definitions/:channel`: Get static model definitions.
158
+ - `GET /v0/management/auth-files/download`: Download auth file.
159
+ - `POST /v0/management/auth-files`: Upload auth file.
160
+ - `DELETE /v0/management/auth-files`: Delete auth file.
161
+ - `PATCH /v0/management/auth-files/status`: Enable/disable auth file.
162
+ - `POST /v0/management/vertex/import`: Import Vertex credentials.
163
+ - OAuth token helpers:
164
+ - `GET /v0/management/anthropic-auth-url`: Start Anthropic OAuth.
165
+ - `GET /v0/management/codex-auth-url`: Start Codex OAuth.
166
+ - `GET /v0/management/gemini-cli-auth-url`: Start Gemini CLI OAuth.
167
+ - `GET /v0/management/antigravity-auth-url`: Start Antigravity OAuth.
168
+ - `GET /v0/management/qwen-auth-url`: Start Qwen OAuth.
169
+ - `GET /v0/management/kimi-auth-url`: Start Kimi OAuth.
170
+ - `GET /v0/management/iflow-auth-url`: Start iFlow OAuth.
171
+ - `POST /v0/management/iflow-auth-url`: Submit iFlow cookie token.
172
+ - `POST /v0/management/oauth-callback`: Post OAuth callback data.
173
+ - `GET /v0/management/get-auth-status`: Poll OAuth status.
174
+
175
+ ## Install
176
+
177
+ ```bash
178
+ npm i
179
+ ```
180
+
181
+ ## Build
182
+
183
+ ```bash
184
+ npm run build
185
+ ```
186
+
187
+ ## Exports
188
+
189
+ ```ts
190
+ import {
191
+ // WS relay
192
+ CliproxyWSProvider,
193
+ CliproxyWSClient,
194
+ decodeRequest,
195
+ encodeResponse,
196
+ encodeChunk,
197
+ encodeError,
198
+ type HTTPRequest,
199
+ type HTTPResponse,
200
+ type ProviderOptions,
201
+ type ProviderEvent,
202
+ type WSRequestContext,
203
+
204
+ // HTTP clients by service
205
+ CliproxyClient,
206
+ OpenAIClient,
207
+ ClaudeClient,
208
+ GeminiClient,
209
+ ManagementClient,
210
+
211
+ // Primary request types
212
+ type PrimaryOpenAIChatRequest,
213
+ type PrimaryClaudeRequest,
214
+ type PrimaryGeminiRequest,
215
+ type PrimaryCliproxyRequest
216
+ } from 'event-ws-cliproxyapi-sdk';
217
+ ```
218
+
219
+ ## Types (Events and Protocol)
220
+
221
+ ### Events (SDK level)
222
+
223
+ - `ProviderEvent`
224
+ - `ws:open` – WebSocket connected
225
+ - `ws:close` – WebSocket closed
226
+ - `request` – server sent an `http_request`
227
+ - `error` – handler error
228
+
229
+ ### Protocol messages (WS level)
230
+
231
+ - `WSMessageType`
232
+ - `http_request` (server → client)
233
+ - `http_response` (client → server)
234
+ - `stream_start` / `stream_chunk` / `stream_end` (client → server)
235
+ - `error` (client → server)
236
+ - `ping` / `pong`
237
+
238
+ ### Request/Response types
239
+
240
+ - `HTTPRequest`
241
+ - `method`, `url`, `headers`, `body`, `sent_at`
242
+ - `HTTPResponse`
243
+ - `status`, `headers`, `body`
244
+
245
+ ### Helper context
246
+
247
+ - `WSRequestContext`
248
+ - `respond(resp)`
249
+ - `streamStart(status?, headers?)`
250
+ - `streamChunk(chunk)`
251
+ - `streamEnd()`
252
+ - `error(message, status?)`
253
+
254
+ ## Usage (Provider Relay)
255
+
256
+ ```ts
257
+ import { CliproxyWSProvider } from 'event-ws-cliproxyapi-sdk';
258
+
259
+ const provider = new CliproxyWSProvider({
260
+ baseUrl: 'http://127.0.0.1:8317',
261
+ accessKey: 'andev'
262
+ });
263
+
264
+ await provider.connect({
265
+ onEvent: (ev) => {
266
+ if (ev.type === 'ws:open') console.log('ws open');
267
+ if (ev.type === 'ws:close') console.log('ws close', ev.code, ev.reason);
268
+ },
269
+ onRequest: async (req, ctx) => {
270
+ if (req.url === '/v1/cliproxy/chat') {
271
+ ctx.streamStart(200, { 'Content-Type': 'text/plain' });
272
+ ctx.streamChunk('hello ');
273
+ ctx.streamChunk('world');
274
+ ctx.streamEnd();
275
+ return;
276
+ }
277
+ ctx.respond({ status: 404, body: 'not found' });
278
+ }
279
+ });
280
+
281
+ provider.close();
282
+ ```
283
+
284
+ ## Usage (HTTP Client)
285
+
286
+ ```ts
287
+ import { CliproxyClient, OpenAIClient, ClaudeClient, GeminiClient, ManagementClient } from 'event-ws-cliproxyapi-sdk';
288
+
289
+ const cliproxy = new CliproxyClient({
290
+ baseUrl: 'http://127.0.0.1:8317',
291
+ accessKey: 'your-access-key',
292
+ managementKey: 'your-management-key'
293
+ });
294
+
295
+ // Public: list auths
296
+ const auths = await cliproxy.getCliproxyAuths();
297
+
298
+ // OpenAI-compatible chat
299
+ const openai = new OpenAIClient({ baseUrl: 'http://127.0.0.1:8317', accessKey: 'your-access-key' });
300
+ await openai.postChatCompletions({
301
+ model: 'gpt-4o-mini',
302
+ messages: [
303
+ { role: 'user', content: [{ type: 'text', text: 'hello' }] }
304
+ ]
305
+ });
306
+ ```
307
+
308
+ ## Response Types
309
+
310
+ OpenAI-compatible
311
+ - `OpenAIChatCompletionResponse` (non-stream)
312
+ - `OpenAIChatCompletionChunk` (stream)
313
+ - `OpenAICompletionResponse` (non-stream)
314
+ - `OpenAICompletionChunk` (stream)
315
+ - `OpenAIResponsesResponse` (non-stream)
316
+ - `OpenAIResponsesChunk` (stream)
317
+
318
+ Claude-compatible
319
+ - `ClaudeMessagesResponse` (non-stream)
320
+ - `ClaudeStreamEvent` (stream)
321
+
322
+ Gemini-compatible
323
+ - `GeminiGenerateContentResponse` (non-stream)
324
+ - `GeminiStreamChunk` (stream)
325
+
326
+ Errors
327
+ - `OpenAIErrorResponse` (OpenAI-style `{ error: { message, type, code? } }`)
328
+ - `ErrorResponse` (management `{ error: string, message?: string }`)
329
+ - `StatusResponse` (status polling `{ status: "ok" | "error" | "wait", error?: string }`)
330
+ - `APIError` (thrown by service clients on non-2xx)
331
+
332
+ ## Response Examples (OK / Failed)
333
+
334
+ OpenAI Chat Completions (OK, non-stream):
335
+ ```json
336
+ {
337
+ "id": "chatcmpl_123",
338
+ "object": "chat.completion",
339
+ "created": 1730000000,
340
+ "model": "gpt-4o-mini",
341
+ "choices": [
342
+ {
343
+ "index": 0,
344
+ "message": { "role": "assistant", "content": "hello" },
345
+ "finish_reason": "stop"
346
+ }
347
+ ],
348
+ "usage": { "total_tokens": 10 }
349
+ }
350
+ ```
351
+
352
+ OpenAI Chat Completions (Failed):
353
+ ```json
354
+ {
355
+ "error": {
356
+ "message": "Invalid request: Missing model",
357
+ "type": "invalid_request_error",
358
+ "code": "invalid_request_error"
359
+ }
360
+ }
361
+ ```
362
+
363
+ Claude Messages (OK, non-stream):
364
+ ```json
365
+ {
366
+ "id": "msg_123",
367
+ "type": "message",
368
+ "role": "assistant",
369
+ "model": "claude-3-5-sonnet",
370
+ "content": [{ "type": "text", "text": "hello" }],
371
+ "stop_reason": "end_turn",
372
+ "usage": { "input_tokens": 5, "output_tokens": 5 }
373
+ }
374
+ ```
375
+
376
+ Claude Messages (Failed):
377
+ ```json
378
+ { "error": "invalid request" }
379
+ ```
380
+
381
+ Gemini GenerateContent (OK, non-stream):
382
+ ```json
383
+ {
384
+ "candidates": [
385
+ {
386
+ "content": {
387
+ "role": "model",
388
+ "parts": [{ "text": "hello" }]
389
+ },
390
+ "finishReason": "STOP",
391
+ "index": 0
392
+ }
393
+ ]
394
+ }
395
+ ```
396
+
397
+ Gemini GenerateContent (Failed):
398
+ ```json
399
+ { "error": "invalid request" }
400
+ ```
401
+
402
+ Management (Failed):
403
+ ```json
404
+ { "error": "invalid management key" }
405
+ ```
406
+
407
+ ## Image + Text in One Message
408
+
409
+ ```ts
410
+ await openai.postChatCompletions({
411
+ model: 'gpt-4o-mini',
412
+ messages: [
413
+ {
414
+ role: 'user',
415
+ content: [
416
+ { type: 'text', text: 'describe this image' },
417
+ { type: 'image_url', image_url: { url: 'https://example.com/cat.jpg' } }
418
+ ]
419
+ }
420
+ ]
421
+ });
422
+ ```
423
+
424
+ ## Notes
425
+
426
+ - For WS relay, if `ws-auth: true`, pass `accessKey` as `Authorization: Bearer ...`.
427
+ - Management APIs require `managementKey` (or local password for `/keep-alive` if enabled).
428
+ - HTTP client returns `Response` for streaming endpoints; parse SSE or chunks based on your client.
@@ -0,0 +1,8 @@
1
+ import type { ClaudeMessagesRequest, ModelListResponse } from '../shared/types.js';
2
+ import type { RequestOptions } from '../shared/http.js';
3
+ import { BaseHttpClient } from '../shared/http.js';
4
+ export declare class ClaudeClient extends BaseHttpClient {
5
+ getModels(options?: RequestOptions): Promise<ModelListResponse>;
6
+ postMessages(body: ClaudeMessagesRequest, options?: RequestOptions): Promise<Response>;
7
+ postMessagesCountTokens(body: ClaudeMessagesRequest, options?: RequestOptions): Promise<Response>;
8
+ }
@@ -0,0 +1,16 @@
1
+ import { BaseHttpClient } from '../shared/http.js';
2
+ export class ClaudeClient extends BaseHttpClient {
3
+ // GET /v1/models (Claude response when User-Agent starts with "claude-cli")
4
+ getModels(options) {
5
+ const headers = { ...(options?.headers ?? {}), 'User-Agent': 'claude-cli' };
6
+ return this.requestJson('GET', '/v1/models', undefined, { ...options, headers }, 'access');
7
+ }
8
+ // POST /v1/messages
9
+ postMessages(body, options) {
10
+ return this.requestRaw('POST', '/v1/messages', JSON.stringify(body), options, 'access');
11
+ }
12
+ // POST /v1/messages/count_tokens
13
+ postMessagesCountTokens(body, options) {
14
+ return this.requestRaw('POST', '/v1/messages/count_tokens', JSON.stringify(body), options, 'access');
15
+ }
16
+ }
@@ -0,0 +1,2 @@
1
+ export { ClaudeClient } from './client.js';
2
+ export type { ClaudeMessageRole, ClaudeContentText, ClaudeContentImage, ClaudeContentBlock, ClaudeMessage, ClaudeMessagesRequest, ClaudeUsage, ClaudeMessagesResponse, ClaudeStreamEventType, ClaudeStreamEvent, ClaudeCompatibleRequest, ClaudeCompatibleResponse } from '../shared/types.js';
@@ -0,0 +1 @@
1
+ export { ClaudeClient } from './client.js';
@@ -0,0 +1,19 @@
1
+ import type { HTTPRequest, ProviderEvent, ProviderOptions, WSRequestContext } from './types.js';
2
+ export interface ProviderHandlers {
3
+ onRequest: (req: HTTPRequest, ctx: WSRequestContext) => void | Promise<void>;
4
+ onEvent?: (ev: ProviderEvent) => void;
5
+ }
6
+ export declare class CliproxyWSProvider {
7
+ private ws?;
8
+ private options;
9
+ private handlers?;
10
+ constructor(options: ProviderOptions);
11
+ connect(handlers: ProviderHandlers): Promise<void>;
12
+ close(): void;
13
+ private handleMessage;
14
+ private handleClose;
15
+ private buildContext;
16
+ private sendMessage;
17
+ }
18
+ export declare class CliproxyWSClient extends CliproxyWSProvider {
19
+ }
package/dist/client.js ADDED
@@ -0,0 +1,96 @@
1
+ import WebSocket from 'ws';
2
+ import { decodeRequest, encodeChunk, encodeError, encodeResponse } from './codec.js';
3
+ export class CliproxyWSProvider {
4
+ constructor(options) {
5
+ this.options = options;
6
+ }
7
+ connect(handlers) {
8
+ this.handlers = handlers;
9
+ if (this.ws && this.ws.readyState === WebSocket.OPEN)
10
+ return Promise.resolve();
11
+ const base = this.options.baseUrl.replace(/\/+$/, '');
12
+ const url = `${base.replace(/^http/, 'ws')}/v1/ws`;
13
+ const headers = {};
14
+ if (this.options.accessKey)
15
+ headers['Authorization'] = `Bearer ${this.options.accessKey}`;
16
+ this.ws = new WebSocket(url, { headers });
17
+ return new Promise((resolve, reject) => {
18
+ const ws = this.ws;
19
+ const onOpen = () => {
20
+ this.handlers?.onEvent?.({ type: 'ws:open' });
21
+ resolve();
22
+ };
23
+ const onErr = (err) => reject(err);
24
+ ws.once('open', onOpen);
25
+ ws.once('error', onErr);
26
+ ws.on('message', (raw) => this.handleMessage(raw.toString()));
27
+ ws.on('close', (code, reason) => this.handleClose(code, reason.toString()));
28
+ });
29
+ }
30
+ close() {
31
+ this.ws?.close();
32
+ }
33
+ handleMessage(raw) {
34
+ let msg;
35
+ try {
36
+ msg = JSON.parse(raw);
37
+ }
38
+ catch {
39
+ return;
40
+ }
41
+ if (!msg || !msg.id || !msg.type)
42
+ return;
43
+ if (msg.type === 'ping') {
44
+ this.sendMessage('pong', msg.id);
45
+ return;
46
+ }
47
+ if (msg.type !== 'http_request')
48
+ return;
49
+ const req = decodeRequest(msg.payload);
50
+ const ctx = this.buildContext(msg.id);
51
+ this.handlers?.onEvent?.({ type: 'request', requestId: msg.id, request: req });
52
+ try {
53
+ const result = this.handlers?.onRequest(req, ctx);
54
+ if (result && typeof result.then === 'function') {
55
+ result.catch((err) => {
56
+ ctx.error(err?.message ?? 'provider error');
57
+ });
58
+ }
59
+ }
60
+ catch (err) {
61
+ ctx.error(err instanceof Error ? err.message : 'provider error');
62
+ }
63
+ }
64
+ handleClose(code, reason) {
65
+ this.handlers?.onEvent?.({ type: 'ws:close', code, reason });
66
+ }
67
+ buildContext(requestId) {
68
+ return {
69
+ requestId,
70
+ respond: (resp) => {
71
+ this.sendMessage('http_response', requestId, encodeResponse(resp));
72
+ },
73
+ streamStart: (status, headers) => {
74
+ const payload = encodeResponse({ status: status ?? 200, headers, body: '' });
75
+ this.sendMessage('stream_start', requestId, payload);
76
+ },
77
+ streamChunk: (chunk) => {
78
+ this.sendMessage('stream_chunk', requestId, encodeChunk(chunk));
79
+ },
80
+ streamEnd: () => {
81
+ this.sendMessage('stream_end', requestId);
82
+ },
83
+ error: (message, status) => {
84
+ this.sendMessage('error', requestId, encodeError(message, status));
85
+ }
86
+ };
87
+ }
88
+ sendMessage(type, id, payload) {
89
+ if (!this.ws || this.ws.readyState !== WebSocket.OPEN)
90
+ return;
91
+ const msg = (payload === undefined ? { id, type } : { id, type, payload });
92
+ this.ws.send(JSON.stringify(msg));
93
+ }
94
+ }
95
+ export class CliproxyWSClient extends CliproxyWSProvider {
96
+ }
@@ -0,0 +1,41 @@
1
+ import type { CliproxyAuthsQuery, CliproxyAuthsResponse, CliproxyChatRequest, CliproxyModelsQuery, CliproxyModelsResponse, KeepAliveResponse, RootResponse } from '../shared/types.js';
2
+ import type { RequestOptions } from '../shared/http.js';
3
+ import { BaseHttpClient } from '../shared/http.js';
4
+ export declare class CliproxyClient extends BaseHttpClient {
5
+ getRoot(): Promise<RootResponse>;
6
+ getManagementHtml(): Promise<Response>;
7
+ keepAlive(): Promise<KeepAliveResponse>;
8
+ anthropicCallback(query: {
9
+ code?: string;
10
+ state?: string;
11
+ error?: string;
12
+ error_description?: string;
13
+ }): Promise<Response>;
14
+ codexCallback(query: {
15
+ code?: string;
16
+ state?: string;
17
+ error?: string;
18
+ error_description?: string;
19
+ }): Promise<Response>;
20
+ googleCallback(query: {
21
+ code?: string;
22
+ state?: string;
23
+ error?: string;
24
+ error_description?: string;
25
+ }): Promise<Response>;
26
+ iflowCallback(query: {
27
+ code?: string;
28
+ state?: string;
29
+ error?: string;
30
+ error_description?: string;
31
+ }): Promise<Response>;
32
+ antigravityCallback(query: {
33
+ code?: string;
34
+ state?: string;
35
+ error?: string;
36
+ error_description?: string;
37
+ }): Promise<Response>;
38
+ getCliproxyAuths(query?: CliproxyAuthsQuery): Promise<CliproxyAuthsResponse>;
39
+ getCliproxyModels(query?: CliproxyModelsQuery): Promise<CliproxyModelsResponse>;
40
+ postCliproxyChat(body: CliproxyChatRequest, options?: RequestOptions): Promise<Response>;
41
+ }
@@ -0,0 +1,43 @@
1
+ import { BaseHttpClient } from '../shared/http.js';
2
+ export class CliproxyClient extends BaseHttpClient {
3
+ // GET /
4
+ getRoot() {
5
+ return this.requestJson('GET', '/');
6
+ }
7
+ // GET /management.html
8
+ getManagementHtml() {
9
+ return this.requestRaw('GET', '/management.html');
10
+ }
11
+ // GET /keep-alive (local password if configured)
12
+ keepAlive() {
13
+ return this.requestJson('GET', '/keep-alive', undefined, undefined, 'local');
14
+ }
15
+ // OAuth callbacks
16
+ anthropicCallback(query) {
17
+ return this.requestRaw('GET', '/anthropic/callback', undefined, { query });
18
+ }
19
+ codexCallback(query) {
20
+ return this.requestRaw('GET', '/codex/callback', undefined, { query });
21
+ }
22
+ googleCallback(query) {
23
+ return this.requestRaw('GET', '/google/callback', undefined, { query });
24
+ }
25
+ iflowCallback(query) {
26
+ return this.requestRaw('GET', '/iflow/callback', undefined, { query });
27
+ }
28
+ antigravityCallback(query) {
29
+ return this.requestRaw('GET', '/antigravity/callback', undefined, { query });
30
+ }
31
+ // GET /v1/cliproxy/auths
32
+ getCliproxyAuths(query) {
33
+ return this.requestJson('GET', '/v1/cliproxy/auths', undefined, { query: query }, 'access');
34
+ }
35
+ // GET /v1/cliproxy/models
36
+ getCliproxyModels(query) {
37
+ return this.requestJson('GET', '/v1/cliproxy/models', undefined, { query: query }, 'access');
38
+ }
39
+ // POST /v1/cliproxy/chat
40
+ postCliproxyChat(body, options) {
41
+ return this.requestRaw('POST', '/v1/cliproxy/chat', JSON.stringify(body), options, 'access');
42
+ }
43
+ }
@@ -0,0 +1,2 @@
1
+ export { CliproxyClient } from './client.js';
2
+ export type { CliproxyChatRequest, CliproxyAuthModelEntry, CliproxyAuthEntry, CliproxyAuthsResponse, CliproxyModelsResponse, CliproxyAuthsQuery, CliproxyModelsQuery } from '../shared/types.js';
@@ -0,0 +1 @@
1
+ export { CliproxyClient } from './client.js';