Skip to content

Instantly share code, notes, and snippets.

@hokage-shuriken
Created December 30, 2025 11:12
Show Gist options
  • Select an option

  • Save hokage-shuriken/c9ce0669b3d09fa7d9873b3e2c60b780 to your computer and use it in GitHub Desktop.

Select an option

Save hokage-shuriken/c9ce0669b3d09fa7d9873b3e2c60b780 to your computer and use it in GitHub Desktop.
const BASE_URL = 'https://memealerts.com/api';
class MemeAlertsClient {
/**
* @param {string} token - Bearer JWT токен
*/
constructor(token) {
if (!token) {
throw new Error('Token is required');
}
this.token = token;
}
/**
* @private
*/
async _request(endpoint, body) {
const response = await fetch(`${BASE_URL}${endpoint}`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${this.token}`,
},
body: JSON.stringify(body),
});
const data = await response.json().catch(() => null);
if (!response.ok) {
const message = data?.message || data?.error || `HTTP ${response.status}`;
throw new Error(message);
}
return data;
}
/**
* Получить список саппортеров с пагинацией
* @param {object} options
* @param {number} [options.limit=20] - количество на страницу
* @param {number} [options.skip=0] - сколько пропустить
* @param {string} [options.query=''] - поисковый запрос
* @returns {Promise<{data: object[], total: number}>}
*/
async getSupporters({ limit = 20, skip = 0, query = '' } = {}) {
return this._request('/supporters', {
limit,
skip,
query,
filters: [],
});
}
/**
* Найти саппортера по имени (точное или частичное совпадение)
* @param {string} username - имя для поиска
* @param {object} options
* @param {boolean} [options.exact=true] - точное совпадение имени
* @returns {Promise<object|null>} - саппортер или null
*/
async findSupporter(username, { exact = true } = {}) {
const normalizedSearch = username.toLowerCase();
let skip = 0;
const limit = 50;
while (true) {
const { data, total } = await this.getSupporters({ limit, skip, query: username });
for (const supporter of data) {
const name = supporter.supporterName?.toLowerCase();
if (exact) {
if (name === normalizedSearch) return supporter;
} else {
if (name?.includes(normalizedSearch)) return supporter;
}
}
skip += limit;
if (skip >= total || data.length === 0) {
return null;
}
}
}
/**
* Начислить мемкоины пользователю
* @param {string} userId - ID получателя
* @param {string} streamerId - ID стримера (владельца канала)
* @param {number} value - количество мемкоинов
* @returns {Promise<object>}
*/
async giveBonus(userId, streamerId, value) {
if (!userId) throw new Error('userId is required');
if (!streamerId) throw new Error('streamerId is required');
if (typeof value !== 'number' || value <= 0) {
throw new Error('value must be a positive number');
}
return this._request('/user/give-bonus', {
userId,
streamerId,
value,
});
}
}
module.exports = { MemeAlertsClient };
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment