npm package: @pachca/sdk
Description: Типизированный клиент для [Pachca API](https://dev.pachca.com).
Latest version: 1.0.13

# Pachca TypeScript SDK

Типизированный клиент для [Pachca API](https://dev.pachca.com).

## Установка

```bash
npm install @pachca/sdk
```

## Использование

```typescript
import { PachcaClient } from "@pachca/sdk";

const pachca = new PachcaClient("YOUR_TOKEN");

// Отправка сообщения
const message = await pachca.messages.createMessage({
  message: { entity_id: chatId, content: "Привет из TypeScript SDK!" },
});

// Список пользователей
const users = await pachca.users.listUsers();
```

## Конвенции

- **Вход**: path-параметры и body-поля (если ≤2) разворачиваются в аргументы метода. Иначе — один объект-запрос.
- **Выход**: если ответ API содержит единственное поле `data`, SDK возвращает его содержимое напрямую.

```typescript
// ≤2 поля → развёрнуто в аргументы
await pachca.reactions.addReaction(messageId, { code: "👍" });
await pachca.messages.pinMessage(messageId);

// >2 полей → объект-запрос
await pachca.messages.createMessage({ message: { entity_id: 123, content: "..." } });

// Ответ: API возвращает { data: Message }, SDK возвращает Message
const message = await pachca.messages.createMessage(...); // Message, не { data: Message }
```

## Пагинация

Для эндпоинтов с курсорной пагинацией SDK генерирует `*All`-методы, которые автоматически обходят все страницы:

```typescript
// Вручную
let cursor: string | undefined;
const chats: Chat[] = [];
for (;;) {
  const response = await pachca.chats.listChats({ cursor });
  if (response.data.length === 0) break;
  chats.push(...response.data);
  cursor = response.meta.paginate.nextPage;
}

// Автоматически
const allChats = await pachca.chats.listChatsAll();
```

Доступные методы: `listChatsAll`, `listUsersAll`, `listTasksAll`, `listTagsAll`, `listMembersAll`, `listChatMessagesAll`, `listReactionsAll`, `searchChatsAll`, `searchMessagesAll`, `searchUsersAll` и др.

## Повторные запросы

SDK автоматически повторяет запросы при получении ответа `429 Too Many Requests`. Используется заголовок `Retry-After` для определения задержки, с экспоненциальным backoff (до 3 попыток).

## Свой HTTP-клиент

Для настройки заголовков, прокси и других параметров HTTP используйте конструктор с объектом конфигурации:

```typescript
import { PachcaClient } from "@pachca/sdk";

const client = new PachcaClient({
  headers: { Authorization: `Bearer ${token}` },
});
```

Полный пример: [`examples/custom-headers.ts`](examples/custom-headers.ts)

## Загрузка файлов

Загрузка файла — трёхшаговый процесс:

```typescript
// 1. Получить параметры загрузки
const params = await pachca.common.getUploadParams();

// 2. Загрузить файл на S3
const file = fs.readFileSync("photo.png");
await pachca.common.uploadFile(params, file, "photo.png");

// 3. Прикрепить к сообщению (используя key из params)
```

## Обработка ошибок

```typescript
import { PachcaClient, ApiError, OAuthError } from "@pachca/sdk";

try {
  await pachca.messages.getMessage(999999);
} catch (e) {
  if (e instanceof OAuthError) {
    console.log(`Ошибка авторизации: ${e.message}`);
  } else if (e instanceof ApiError) {
    console.log(`Ошибка API: ${e.errors}`);
  }
}
```

## Тестирование

Для unit-тестов используйте `PachcaClient.stub()` — создаёт клиент без HTTP-подключения.

Методы без переопределения выбрасывают `Error("Service.method is not implemented")`:

```typescript
import { PachcaClient, MessagesService, Message } from "@pachca/sdk";

// Мок-сервис
class MockMessagesService extends MessagesService {
  async getMessage(id: number): Promise<Message> {
    return { id, content: "Test message", entityId: 123 } as Message;
  }
}

// Тест
const client = PachcaClient.stub({
  messages: new MockMessagesService(),
});

const message = await client.messages.getMessage(1);
expect(message.content).toBe("Test message");
```

Полный пример: [`examples/stub.ts`](examples/stub.ts)