XCRAP.CC

Клиент для Node

Тонкая типизированная обёртка над теми же HTTP-эндпоинтами. Ничего невозможного без fetch она не делает — просто избавляет от того, чтобы заново писать классы ошибок, повторы и согласование формата.

Установка

npm install @xcrapcc/sdk

Или тем, чем вы на самом деле пользуетесь:

  • pnpm add @xcrapcc/sdk
  • yarn add @xcrapcc/sdk
  • bun add @xcrapcc/sdk

Требуется · Node 18 или новее. Никаких зависимостей во время выполнения — используется встроенный fetch.

  • Ключа не будет никогда

    Не на что регистрироваться, нечего класть в переменную окружения и нечего менять, когда это случайно закоммитят.

  • Типы на всю глубину

    Полные объявления для каждого метода и каждой структуры ответа: опечатка в имени поля — красное подчёркивание, а не сюрприз во время работы.

  • Markdown встроен

    Один флаг превращает любой ответ в готовый для промпта markdown и говорит, во сколько это обойдётся контекстному окну.

Две строки до поста

Ключ передавать не нужно, настраивать клиент — тоже. Создали и вызвали.

import { Xcrap } from '@xcrapcc/sdk';

const xcrap = new Xcrap();

const tweet = await xcrap.tweet('https://x.com/jack/status/20');
console.log(tweet.text);               // just setting up my twttr
console.log(tweet.metrics.likes);      // 308067

Markdown вместе с ценой в токенах

Каждый метод чтения принимает флаг markdown. Ответ приходит строкой, готовой для промпта, а клиент запоминает, во сколько токенов эта строка, скорее всего, обойдётся, — чтобы сверить бюджет до того, как его потратить.

// Markdown, ready to drop into a prompt.
const md = await xcrap.tweet('https://x.com/jack/status/20', { markdown: true });

// How many tokens that will cost, before you spend them.
console.log(xcrap.lastMeta.markdownTokens);

Треды и ленты

Тред возвращается развёрнутым и по порядку, начиная с первого поста, а не с последнего. Лента листается по курсорам, так что хранить их не нужно.

const thread = await xcrap.thread(
  'https://x.com/naval/status/1002103360646823936',
);

console.log(thread.count);                      // 31
for (const post of thread.tweets) console.log(post.text);

Ошибки — это типы, а не коды

Каждый сбой — класс, который ловится по имени. 404 — удалённый или закрытый пост, 429 несёт число секунд до сброса окна, а сетевой сбой отличим от отказа.

import { Xcrap, XcrapNotFound, XcrapRateLimited } from '@xcrapcc/sdk';

try {
  await xcrap.tweet('https://x.com/jack/status/1');
} catch (error) {
  if (error instanceof XcrapNotFound) return null;
  if (error instanceof XcrapRateLimited) {
    // The client already knows when the window resets.
    await sleep(error.retryAfter * 1000);
  }
  throw error;
}

Все методы

Все принимают формат и флаг markdown и возвращают те же структуры, что и HTTP API.

tweet(url, opts?)
Один пост целиком: текст, автор, метрики, медиа, опрос и цитируемый пост.
thread(url, opts?)
Весь тред от любого поста в нём, развёрнутый в порядке публикации.
search(query, opts?)
Посты по запросу — новые, популярные, с фото или видео — в необязательном диапазоне дат.
replies(url, opts?)
Страница прямых ответов на пост: сначала самые популярные или самые новые.
user(handle, opts?)
Профиль: описание, счётчики, дата регистрации, верификация, город и сайт.
userTweets(handle, opts?)
Одна страница постов аккаунта и курсор на следующую.
userHistory(handle, opts?)
До тысячи постов аккаунта за один вызов, от новых к старым, в необязательном диапазоне дат.
followers(handle, opts?)
Страница аккаунтов, которые подписаны на аккаунт.
following(handle, opts?)
Страница аккаунтов, на которые подписан аккаунт.
trends(opts?)
Что в трендах, с числом постов там, где X его отдаёт.
media(url, opts?)
Все вложения во всех битрейтах, которые закодировал X, прямыми ссылками.
downloadMedia(url, opts?)
Отдаёт один из этих файлов байтами, а не ссылкой.
bulk(urls, opts?)
До пятидесяти постов за один запрос. Битая ссылка роняет только свою запись.

Все параметры — в справочнике API Есть ещё клиент для Python.