npm package: @feelai/fetch-client
Description: A type-safe HTTP/WebSocket client that consumes contracts defined with `@feelai/contract`. It provides fully-inferred TypeScript types for API calls, streaming, and socket connections — no manual type annotations required.
Latest version: 1.1.0

# @feelai/fetch-client

A type-safe HTTP/WebSocket client that consumes contracts defined with `@feelai/contract`. It provides fully-inferred TypeScript types for API calls, streaming, and socket connections — no manual type annotations required.

## Features

- **Type-Safe API Calls**: Input and output types are automatically inferred from your contract.
- **Input Validation**: Validates request input against the contract schema at runtime using `typebox` before sending.
- **Streaming Support**: Connect to stream endpoints over WebSocket with typed event emitters.
- **Socket Support**: Real-time bidirectional communication with typed client/server events.
- **Configurable Headers & Query**: Hook into request lifecycle to inject auth tokens or custom query params.
- **Large Payload Chunking**: Automatically splits large WebSocket messages into 1MB chunks.

## Installation

```bash
bun add @feelai/fetch-client
```

## Usage

### 1. Create a Client

Pass your contract and a base URL to `createClient` (or instantiate `FetchClient` directly).

```typescript
import { createClient } from "@feelai/fetch-client";
import { todoListContract } from "./todoListContract";

const client = createClient(todoListContract, "https://api.example.com");
```

### 2. Call API Endpoints

Use `client.fetch()` to call HTTP endpoints defined in the contract's `apiMap`. The method, input shape, and response type are all inferred automatically.

```typescript
// No input required
const tasks = await client.fetch("getTasks");
//    ^? Task[]

// With typed input
const newTask = await client.fetch("createTask", { title: "Buy groceries" });
//    ^? Task
```

> All requests are sent as `POST` with a JSON body and `credentials: "include"` by default.

### 3. Connect to a Stream

Use `client.stream()` to open a WebSocket connection to a stream endpoint. Returns a typed `Stream` object with typed event handlers.

```typescript
const stream = await client.stream("generateTask", { content: "Write a summary" });

stream.on("chunk", (data) => {
  console.log("Partial:", data);
});

stream.on("end", (data) => {
  console.log("Done:", data);
});

stream.on("error", (err) => {
  console.error("Error:", err);
});
```

### 4. Connect to a Socket

Use `client.socket()` to open a typed bidirectional WebSocket connection for real-time communication.

```typescript
const socket = await client.socket("taskUpdates");

// Listen for server events
socket.on("taskCreated", (task) => {
  console.log("New task:", task);
});

// Send client events
socket.emit("subscribe", {});
```

### 5. Inject Headers & Query Params

Customize outgoing requests by assigning to `initHeaders` and `initStreamQuery` on the client instance.

```typescript
client.initHeaders = () => ({
  Authorization: `Bearer ${getToken()}`,
});

client.initStreamQuery = () => ({
  token: getToken(),
});
```

### 6. Advanced Options

The `fetch()` method accepts standard `RequestInit` options plus extras:

| Option           | Type                     | Description                                      |
| ---------------- | ------------------------ | ------------------------------------------------ |
| `query`          | `Record<string, string>` | Appends query parameters to the URL.             |
| `skipValidation` | `boolean`                | Skips runtime input validation (default: false). |

```typescript
const tasks = await client.fetch("getTasks", undefined, {
  query: { page: "1" },
  skipValidation: true,
});
```

## API Reference

### `createClient(contract, baseUrl)`

Factory function. Returns a `FetchClient` instance bound to the given contract and base URL.

### `FetchClient<TContract>`

| Member                           | Type                                   | Description                                                   |
| -------------------------------- | -------------------------------------- | ------------------------------------------------------------- |
| `initHeaders`                    | `() => Record<string, string> \| void` | Called before every HTTP request to inject headers.           |
| `initStreamQuery`                | `() => Record<string, string> \| void` | Called before every stream connection to inject query params. |
| `fetch(path, input?, options?)`  | `Promise<Output>`                      | Calls an HTTP API endpoint from the contract.                 |
| `stream(path, input?, options?)` | `Promise<Stream<Events>>`              | Opens a WebSocket stream connection.                          |
| `socket(path, query?)`           | `Promise<SocketClient<...>>`           | Opens a bidirectional WebSocket socket connection.            |

## Related Packages

- [`@feelai/contract`](../contract/README.md) — Define API, stream, and socket contracts.
- [`@feelai/stream`](../stream/) — The `Stream` type used by streaming responses.