mirror of
https://github.com/jaronpate/unicord.git
synced 2026-10-18 21:47:40 +00:00
79 lines
2.9 KiB
TypeScript
79 lines
2.9 KiB
TypeScript
import type { Unicord } from '.';
|
|
import { exists, log } from './utils';
|
|
|
|
export class UnicordDiscordAPI {
|
|
private readonly base_url: string = 'https://discord.com/api';
|
|
private readonly version: number = 10;
|
|
|
|
constructor(private self: Unicord) {}
|
|
|
|
async request<T = any>(method: string, path: string, data?: any): Promise<T> {
|
|
const url = `${this.base_url}/v${this.version.toString()}${path.startsWith('/') ? '' : '/'}${path}`;
|
|
const headers = {
|
|
Authorization: `Bot ${this.self.config.token}`,
|
|
Accept: 'application/json',
|
|
'Content-Type': 'application/json',
|
|
};
|
|
|
|
const response = await fetch(url, {
|
|
method,
|
|
headers,
|
|
body: JSON.stringify(data),
|
|
});
|
|
|
|
if (!response.ok) {
|
|
// console.error(`Failed to fetch: ${response.statusText} ${response.url} ${response.status}`);
|
|
console.log('Failed Request Response: ', await response.text());
|
|
throw new Error(`Failed to fetch: ${response.statusText}`);
|
|
}
|
|
|
|
const body = await response.json();
|
|
|
|
// console.log(`API Request: ${method} ${url}`);
|
|
// console.log(`API Body: ${JSON.stringify(data, null, 4)}`);
|
|
// console.log('API Response:', JSON.stringify(body, null, 4));
|
|
|
|
// Extract rate limit headers
|
|
const remaining = response.headers.get('X-RateLimit-Remaining');
|
|
const limit = response.headers.get('X-RateLimit-Limit');
|
|
const reset = response.headers.get('X-RateLimit-Reset');
|
|
const resetSeconds = response.headers.get('X-RateLimit-Reset-After');
|
|
const limitBucket = response.headers.get('X-RateLimit-Bucket');
|
|
|
|
// Log rate limit info for debugging
|
|
log(`Rate Limit: ${remaining}/${limit} - Reset: ${resetSeconds}s - Bucket: ${limitBucket}`);
|
|
|
|
// If status is 429, we are being rate limited
|
|
if (response.status === 429) {
|
|
// Look for the retry-after header
|
|
const retryAfter = response.headers.get('Retry-After');
|
|
if (exists(retryAfter)) {
|
|
// Wait for the retry-after time
|
|
await new Promise((resolve) => setTimeout(resolve, parseInt(retryAfter) * 1000));
|
|
} else {
|
|
// TODO: Handle this case better
|
|
// Maybe wait some arbitrary time??
|
|
throw new Error('Rate limited without Retry-After header');
|
|
}
|
|
}
|
|
|
|
return body;
|
|
}
|
|
|
|
async get<T = any>(path: string): Promise<T> {
|
|
return this.request('GET', path);
|
|
}
|
|
|
|
async post<T = any>(path: string, data: any): Promise<T> {
|
|
return this.request('POST', path, data);
|
|
}
|
|
|
|
async patch<T = any>(path: string, data: any): Promise<T> {
|
|
return this.request('PATCH', path, data);
|
|
}
|
|
|
|
async delete<T = any>(path: string): Promise<T> {
|
|
return this.request('DELETE', path);
|
|
}
|
|
}
|