npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

loop-client

v0.1.3

Published

"Loop/Mattermost TypeScript client"

Downloads

72

Readme

Loop Client

License: ISC Node.js Version TypeScript

🇺🇸 Read in English

Современный, строго типизированный TypeScript клиент для Loop. Совместим и с Node.js, и с браузерами, предоставляет (почти) полное покрытие Loop API с полной типобезопасностью.

Возможности

Типобезопасность

  • Написан на TypeScript 5.9 со строгой проверкой типов
  • Полные определения типов для (почти) всех методов API

🔄 Надёжность

  • Встроенные механизмы повторных попыток с настраиваемыми политиками
  • Очередь запросов с контролем параллелизма (через breadline-ts)

🌐 Универсальная совместимость

  • Работает как в Node.js (≥20), так и в браузерных окружениях

📊 Обширное покрытие API

  • Каналы: Создание, управление, поиск и модерация каналов
  • Сообщения: Создание, обновление, закрепление, поиск сообщений и тредов
  • Пользователи: Управление пользователями, профили, аутентификация
  • Команды: Создание команд, управление участниками и администрирование
  • Файлы: Загрузка, скачивание и управление вложениями
  • Эмодзи: Управление эмодзи
  • Вебхуки: Управление вебхуками
  • Боты: Управление ботами и автоматизация
  • Плейбуки: Управление плейбуками и запусками
  • Группы: Управление группами
  • Администрирование: Системное администрирование и аналитика
  • И многое другое...

🧪 Надёжность

  • Комплексное покрытие unit-тестами (порог 90%+)
  • Интеграционные тесты с реальным API
  • Fuzz-тестирование для пограничных случаев

Установка

npm install loop-client

Или используя pnpm:

pnpm add loop-client

Или используя yarn:

yarn add loop-client

Или используя bun:

bun add loop-client

Быстрый старт

Базовое использование

import { LoopClient } from 'loop-client';

// Инициализация
const client = new LoopClient('https://your-loop-server.loop.ru', {
  token: 'your-api-token',
  logLevel: 'info'
});

// Получение текущего пользователя
const me = await client.users.profile.get.me();
console.log(`Привет, ${me.data.username}!`);

// Создание сообщения
const post = await client.posts.create({
  channel_id: 'channel-id-here',
  message: 'Привет от loop-client!'
});

// Поиск каналов
const channels = await client.channels.search.all({
  term: 'general'
});

// Не забудьте очистить ресурсы по завершении
client.destroy();

Расширенная конфигурация

import { LoopClient, fiveRetriesInFiveMinutes } from 'loop-client';

const client = new LoopClient('https://your-loop-server.loop.ru', {
  // Аутентификация
  token: 'your-api-token',
  userID: 'me', // Опционально: ID текущего пользователя (вычисляется автоматически, если не передан)
  
  // Автоматическое поведение
  useCurrentUserForDirectChannels: true, // Автоматически подставлять ID текущего пользователя для создания ЛС
  useCurrentUserForPostCreation: true,   // Автоматически определять channel_id или user_id при создании поста
  saveFetchedUserID: false,              // Кешировать полученный ID пользователя для будущих запросов

  // Логирование
  logLevel: 'debug',
  logger: customLogger, // Опционально: свой логгер
  
  // Настройка производительности
  maxRequestConcurrency: 50, // Ограничение параллельных запросов
  retryConfig: fiveRetriesInFiveMinutes, // Политика повторов
  
  // Настройка сети
  timeout: 30000, // Таймаут запроса в мс
  headers: {
    'X-Custom-Header': 'value'
  },
  agent: new https.Agent({ keepAlive: true }), // Пользовательский HTTP агент (например, для прокси)
  requestInterceptor: (config) => config,      // Перехватчик запросов
  adapter: customAdapter,                      // Пользовательский адаптер для Axios
  
  // Параметры TLS/SSL
  tls: {
    rejectUnauthorized: false // Для самоподписанных сертификатов
  },
  
  // Тестирование
  testConnectionOnInit: true // Проверка соединения при инициализации
});

Справочник API

Клиент предоставляет комплексный API, организованный по типам ресурсов. Все методы возвращают Promise с типизированными результатами.

Основные ресурсы

Пользователи

// Получить пользователя по ID
await client.users.profile.get.byId({ user_id: 'user-id' });

// Поиск пользователей
await client.users.search({ term: 'john' });

// Обновить роли пользователя
await client.users.updateRoles({
  user_id: 'user-id',
  roles: 'system_user system_admin'
});

// Установить стандартный статус пользователя
await client.users.status.set({
  user_id: 'me',
  status: 'away'
});

// Установить пользовательский статус
await client.users.status.setCustom({
  emoji: '🚀',
  text: 'Работаю над чем-то крутым'
});

Каналы

// Создать обычный канал
await client.channels.create.regular({
  team_id: 'team-id',
  name: 'my-channel',
  display_name: 'Мой канал',
  type: 'O' // 'O' для открытого, 'P' для приватного
});

// Создать канал личных сообщений
await client.channels.create.direct(['user-id-1', 'user-id-2']);

// Получить канал по имени
await client.channels.get.byName({
  team_id: 'team-id',
  channel_name: 'general'
});

// Добавить участника в канал
await client.channels.members.add({
  channel_id: 'channel-id',
  user_id: 'user-id'
});

// Поиск каналов
await client.channels.search.all({ term: 'маркетинг' });

Сообщения

// Создать сообщение
await client.posts.create({
  channel_id: 'channel-id',
  message: 'Привет, мир!'
});

// Создать сообщение с вложенными файлами
await client.posts.create({
  channel_id: 'channel-id',
  message: 'Посмотрите этот файл',
  file_ids: ['file-id-1', 'file-id-2']
});

// Получить сообщения для канала
await client.posts.getForChannel({
  channel_id: 'channel-id',
  page: 0,
  per_page: 60
});

// Поиск сообщений
await client.posts.search({ terms: 'важная встреча' });

// Закрепить/открепить сообщение
await client.posts.pin({ post_id: 'post-id' });
await client.posts.unpin({ post_id: 'post-id' });

// Получить тред
await client.posts.getThread({ post_id: 'post-id' });

Файлы

// Загрузить файл
const uploadResult = await client.files.upload({
  channel_id: 'channel-id',
  files: fileBuffer, // или Stream
  filename: 'document.pdf'
}); // Примечание: реальная реализация может потребовать FormData или специфической обработки потоков в зависимости от окружения

// Получить метаданные файла
await client.files.get.metadata({ file_id: 'file-id' });

// Скачать файл
const fileData = await client.files.get.file({ file_id: 'file-id' });

// Поиск файлов
await client.files.search({ terms: 'отчёт', team_id: 'team-id' });

Команды

// Создать команду
await client.teams.create({
  name: 'my-team',
  display_name: 'Моя команда',
  type: 'O' // 'O' для открытой, 'I' для приватной
});

// Добавить участника в команду
await client.teams.members.add({
  team_id: 'team-id',
  user_id: 'user-id'
});

// Поиск команд
await client.teams.search({ term: 'разработка' });

Дополнительные ресурсы

Клиент также предоставляет методы для:

  • Эмодзи: Управление пользовательскими эмодзи (client.emojis.*)
  • Реакции: Реакции на сообщения (client.reactions.*)
  • Вебхуки: Входящие и исходящие вебхуки (client.webhooks.*)
  • Боты: Управление ботами (client.bots.*)
  • Настройки: Пользовательские настройки (client.preferences.*)
  • Роли: Управление ролями и правами (client.roles.*)
  • Группы: Синхронизация LDAP групп (client.groups.*)
  • Плейбуки: Управление плейбуками (client.playbooks.*)
  • Задачи: Управление фоновыми задачами (client.jobs.*)
  • Система: Конфигурация системы и аналитика (client.system.*)
  • OAuth: Управление OAuth приложениями (client.oauth.*)
  • Соответствие: Отчёты о соответствии (client.compliance.*)
  • И многое другое...

См. документацию Loop API для полного API.

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

import { WebAPIRequestError, WebAPIServerError } from 'loop-client';

try {
  await client.posts.create({
    channel_id: 'invalid-channel-id',
    message: 'Это не сработает'
  });
} catch (error) {
  if (error instanceof WebAPIRequestError) {
    console.error('Ошибка запроса:', error.message);
    console.error('Код статуса:', error.statusCode);
  } else if (error instanceof WebAPIServerError) {
    console.error('Ошибка сервера:', error.message);
    console.error('ID ошибки сервера:', error.serverErrorId);
  } else {
    console.error('Неожиданная ошибка:', error);
  }
}

Политики повторных попыток

Клиент включает две встроенные политики повторных попыток:

import { 
  tenRetriesInAboutThirtyMinutes, 
  fiveRetriesInFiveMinutes 
} from 'loop-client';

// По умолчанию: 10 попыток за ~30 минут
const client1 = new LoopClient(url, {
  token,
  retryConfig: tenRetriesInAboutThirtyMinutes
});

// Быстрее: 5 попыток за 5 минут
const client2 = new LoopClient(url, {
  token,
  retryConfig: fiveRetriesInFiveMinutes
});

// Своя политика повторов
const client3 = new LoopClient(url, {
  token,
  retryConfig: {
    retries: 3,
    factor: 2,
    minTimeout: 1000,
    maxTimeout: 60000,
    random: true
  }
});

Разработка

Требования

  • Node.js ≥20
  • pnpm (рекомендуется) или npm

Настройка

# Клонировать репозиторий
git clone https://github.com/triple-sun/loop-client.git
cd loop-client

# Установить зависимости
pnpm install

# Собрать проект
pnpm build

Структура проекта

loop-client/
├── src/
│   ├── web-client.ts       # Основной класс LoopClient
│   ├── methods.ts          # Определения методов API (2900+ строк)
│   ├── errors.ts           # Определения ошибок
│   ├── utils.ts            # Вспомогательные функции
│   ├── const.ts            # Константы и политики повторов
│   ├── logger.ts           # Утилиты для логирования
│   ├── instrument.ts       # Инструменты для определения метаданных
│   └── types/              # Типы
│       ├── methods/        # Типы аргументов методов
│       └── responses/      # Типы ответов
├── test/
│   ├── integration/        # Интеграционные тесты
│   ├── fuzzing/            # Fuzz-тесты
│   └── *.test.ts          # Unit-тесты
├── build/                  # Скомпилированный вывод
└── coverage/               # Отчёты о покрытии тестами

Доступные скрипты

# Запустить все тесты
pnpm test

# Запустить тесты с покрытием
pnpm test

# Запустить интеграционные тесты с реальным API (требуется .env.test.local)
pnpm test:real:only

# Собрать проект
pnpm build

# Проверка и форматирование кода
pnpm check

# Только форматирование
pnpm format

# Только проверка lint
pnpm lint

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

Проект имеет комплексное покрытие тестами:

# Запустить unit-тесты
pnpm test

# Запустить интеграционные тесты против реального API
# Создайте .env.test.local с:
# LOOP_URL=https://your-loop-server.com
# LOOP_TOKEN=your-test-token
pnpm test:real:only

Структура тестов:

  • Unit-тесты: Тесты с моками для основной функциональности
  • Интеграционные тесты: Тесты против реального Loop API
  • Fuzz-тесты: Тестирование граничных случаев и случайного ввода
  • Требование покрытия: 90% строк и выражений

Качество кода

В проекте используется:

  • TypeScript 5.9 со строгим режимом
  • Biome для линтинга и форматирования
  • Husky для git-хуков
  • lint-staged для проверок перед коммитом

Конфигурация:

  • Строгие настройки TypeScript в tsconfig.json
  • Конфигурация Biome в biome.json
  • Конфигурация Jest в jest.config.ts

Переменные окружения

Для тестирования против реального Loop сервера создайте файл .env.test.local:

LOOP_URL=https://your-loop-server.com
LOOP_TOKEN=your-personal-access-token

Участие в разработке

Участие в разработке приветствуется! Пожалуйста:

  1. Форкните репозиторий
  2. Создайте ветку для новой функции (git checkout -b feature/amazing-feature)
  3. Внесите изменения, следуя стандартам качества кода
  4. Запустите тесты (pnpm test)
  5. Закоммитьте изменения (git commit -m 'Добавлена крутая функция')
  6. Отправьте в ветку (git push origin feature/amazing-feature)
  7. Откройте Pull Request

Стандарты кодирования

  • Следуйте существующей конфигурации TypeScript и Biome
  • Поддерживайте покрытие тестами выше 90%
  • Добавляйте тесты для новых функций
  • Обновляйте документацию по необходимости
  • Используйте общепринятые сообщения коммитов

Лицензия

ISC License - см. package.json для деталей

Ссылки

Благодарности


Сделано с ❤️ triple-sun