Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ An official module for interacting with the Top.<span>gg API

# Introduction

The base client is Topgg.Api, and it takes your Top.<span>gg token and provides you with plenty of methods to interact with the API.
The base client is Topgg.Api, and it takes your Top.gg token and provides you with plenty of methods to interact with the API.

Your Top.<span>gg token can be found at `top.gg/bot/(BOT_ID)/webhooks` and copying the token.
See [this tutorial](https://github.com/top-gg/rust-sdk/assets/60427892/d2df5bd3-bc48-464c-b878-a04121727bff) on how to retrieve your API token.

You can also setup webhooks via Topgg.Webhook, look down below at the examples for how to do so!

Expand Down Expand Up @@ -58,5 +58,5 @@ app.post(
app.listen(3000); // your port
```

With this example, your webhook dashboard should look like this:
![](https://i.imgur.com/wFlp4Hg.png)
With this example, your webhook dashboard (`https://top.gg/bot/{your bot's id}/webhooks`) should look like this:
![](https://i.imgur.com/cZfZgK5.png)
80 changes: 49 additions & 31 deletions src/structs/Api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import {
*/
export class Api extends EventEmitter {
private options: APIOptions;

/**
* Create Top.gg API instance
*
Expand All @@ -38,8 +39,25 @@ export class Api extends EventEmitter {
*/
constructor(token: string, options: APIOptions = {}) {
super();

const tokenSegments = token.split(".");

if (tokenSegments.length !== 3) {
throw new Error("Got a malformed API token.");
}

const tokenData = atob(tokenSegments[1]);

try {
JSON.parse(tokenData).id;
} catch {
throw new Error(
"Invalid API token state, this should not happen! Please report!"
);
}

this.options = {
token: token,
token,
...options,
};
}
Expand All @@ -64,6 +82,7 @@ export class Api extends EventEmitter {
});

let responseBody;

if (
(response.headers["content-type"] as string)?.startsWith(
"application/json"
Expand Down Expand Up @@ -92,54 +111,51 @@ export class Api extends EventEmitter {
* ```js
* await api.postStats({
* serverCount: 28199,
* shardCount: 1,
* });
* ```
*
* @param {object} stats Stats object
* @param {number} stats.serverCount Server count
* @param {number} [stats.shardCount] Shard count
* @param {number} [stats.shardId] Posting shard (useful for process sharding)
* @returns {BotStats} Passed object
*/
public async postStats(stats: BotStats): Promise<BotStats> {
if (!stats?.serverCount) throw new Error("Missing Server Count");
if ((stats?.serverCount ?? 0) <= 0) throw new Error("Missing server count");

/* eslint-disable camelcase */
await this._request("POST", "/bots/stats", {
server_count: stats.serverCount,
shard_id: stats.shardId,
shard_count: stats.shardCount,
});
/* eslint-enable camelcase */

return stats;
}

/**
* Get a bots stats
* Get your bot's stats
*
* @example
* ```js
* await api.getStats("461521980492087297");
* await api.getStats();
Comment thread
null8626 marked this conversation as resolved.
* // =>
* {
* serverCount: 28199,
* shardCount 1,
* shardCount: null,
* shards: []
* }
* ```
*
* @param {Snowflake} id Bot ID
* @returns {BotStats} Stats of bot requested
* @returns {BotStats} Your bot's stats
*/
public async getStats(id: Snowflake): Promise<BotStats> {
if (!id) throw new Error("ID missing");
const result = await this._request("GET", `/bots/${id}/stats`);
public async getStats(_id?: Snowflake): Promise<BotStats> {
Comment thread
jpbberry marked this conversation as resolved.
if (_id)
console.warn(
"[DeprecationWarning] getStats() no longer needs an ID argument"
);
const result = await this._request("GET", "/bots/stats");
return {
serverCount: result.server_count,
shardCount: result.shard_count,
shards: result.shards,
shardCount: null,
shards: [],
};
}

Expand All @@ -160,6 +176,8 @@ export class Api extends EventEmitter {
}

/**
* @deprecated No longer supported by Top.gg API v0.
*
* Get user info
*
* @example
Expand All @@ -173,7 +191,10 @@ export class Api extends EventEmitter {
* @returns {UserInfo} Info for user
*/
public async getUser(id: Snowflake): Promise<UserInfo> {
if (!id) throw new Error("ID Missing");
console.warn(
"[DeprecationWarning] getUser is no longer supported by Top.gg API v0."
);

return this._request("GET", `/users/${id}`);
}

Expand All @@ -185,18 +206,15 @@ export class Api extends EventEmitter {
* // Finding by properties
* await api.getBots({
* search: {
* username: "shiro",
* certifiedBot: true,
* username: "shiro"
* },
* });
* // =>
* {
* results: [
* {
* id: '461521980492087297',
* username: 'Shiro',
* discriminator: '8764',
* lib: 'discord.js',
* id: "461521980492087297",
* username: "Shiro",
* ...rest of bot object
* }
* ...other shiro knockoffs B)
Expand Down Expand Up @@ -243,7 +261,7 @@ export class Api extends EventEmitter {
}

/**
* Get users who've voted
* Get recent unique users who've voted
*
* @example
* ```js
Expand All @@ -253,22 +271,22 @@ export class Api extends EventEmitter {
* {
* username: 'Xignotic',
* id: '205680187394752512',
* avatar: '3b9335670c7213b3a2d4e990081900c7'
* avatar: 'https://cdn.discordapp.com/avatars/1026525568344264724/cd70e62e41f691f1c05c8455d8c31e23.png'
* },
* {
* username: 'iara',
* id: '395526710101278721',
* avatar: '3d1477390b8d7c3cec717ac5c778f5f4'
* avatar: 'https://cdn.discordapp.com/avatars/1026525568344264724/cd70e62e41f691f1c05c8455d8c31e23.png'
* }
* ...more
* ]
* ```
*
* @returns {ShortUser[]} Array of users who've voted
* @param {number} [page] The page number. Each page can only have at most 100 voters.
* @returns {ShortUser[]} Array of unique users who've voted
*/
public async getVotes(): Promise<ShortUser[]> {
if (!this.options.token) throw new Error("Missing token");
return this._request("GET", "/bots/votes");
public async getVotes(page?: number): Promise<ShortUser[]> {
return this._request("GET", "/bots/votes", { page: page ?? 1 });
}

/**
Expand Down
96 changes: 72 additions & 24 deletions src/typings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,56 +7,91 @@ export interface APIOptions {
export type Snowflake = string;

export interface BotInfo {
/** The id of the bot */
/** The Top.gg ID of the bot */
id: Snowflake;
/** The Discord ID of the bot */
clientid: Snowflake;
/** The username of the bot */
username: string;
/** The discriminator of the bot */
/**
* The discriminator of the bot
*
* @deprecated No longer supported by Top.gg API v0.
*/
discriminator: string;
/** The avatar hash of the bot's avatar */
avatar?: string;
/** The cdn hash of the bot's avatar if the bot has none */
/** The bot's avatar */
avatar: string;
/**
* The cdn hash of the bot's avatar if the bot has none
*
* @deprecated No longer supported by Top.gg API v0.
*/
defAvatar: string;
/** The URL for the banner image */
/**
* The URL for the banner image
*
* @deprecated No longer supported by Top.gg API v0.
*/
bannerUrl?: string;
/**
* The library of the bot
*
* @deprecated
* @deprecated No longer supported by Top.gg API v0.
*/
lib: string;
/** The prefix of the bot */
prefix: string;
/** The short description of the bot */
shortdesc: string;
/** The long description of the bot. Can contain HTML and/or Markdown */
longdesc: string;
longdesc?: string;
/** The tags of the bot */
tags: string[];
/** The website url of the bot */
website?: string;
/** The support server invite code of the bot */
/** The support url of the bot */
support?: string;
/** The link to the github repo of the bot */
github?: string;
/** The owners of the bot. First one in the array is the main owner */
owners: Snowflake[];
/** The guilds featured on the bot page */
/**
* The guilds featured on the bot page
*
* @deprecated No longer supported by Top.gg API v0.
*/
guilds: Snowflake[];
/** The custom bot invite url of the bot */
invite?: string;
/** The date when the bot was approved (in ISO 8601) */
/** The date when the bot was submitted (in ISO 8601) */
date: string;
/** The certified status of the bot */
/**
* The certified status of the bot
*
* @deprecated No longer supported by Top.gg API v0.
*/
certifiedBot: boolean;
/** The vanity url of the bot */
vanity?: string;
/** The amount of upvotes the bot has */
/** The amount of votes the bot has */
points: number;
/** The amount of upvotes the bot has this month */
/** The amount of votes the bot has this month */
monthlyPoints: number;
/** The guild id for the donatebot setup */
/**
* The guild id for the donatebot setup
*
* @deprecated No longer supported by Top.gg API v0.
*/
donatebotguildid: Snowflake;
/** The amount of servers the bot is in based on posted stats */
server_count?: number;
/** The bot's reviews on Top.gg */
reviews: {
/** This bot's average review score out of 5 */
averageScore: number;
/** This bot's review count */
count: number;
};
}

export interface BotStats {
Expand All @@ -65,23 +100,36 @@ export interface BotStats {
/**
* The amount of servers the bot is in per shard. Always present but can be
* empty. (Only when receiving stats)
*
* @deprecated No longer supported by Top.gg API v0.
*/
shards?: number[];
/** The shard ID to post as (only when posting) */
/**
* The shard ID to post as (only when posting)
*
* @deprecated No longer supported by Top.gg API v0.
*/
shardId?: number;
/** The amount of shards a bot has */
shardCount?: number;
/**
* The amount of shards a bot has
*
* @deprecated No longer supported by Top.gg API v0.
*/
shardCount?: number | null;
}

/**
* @deprecated No longer supported by Top.gg API v0.
*/
export interface UserInfo {
/** The id of the user */
id: Snowflake;
/** The username of the user */
username: string;
/** The discriminator of the user */
discriminator: string;
/** The avatar hash of the user's avatar */
avatar?: string;
/** The user's avatar url */
avatar: string;
/** The cdn hash of the user's avatar if the user has none */
defAvatar: string;
/** The bio of the user */
Expand Down Expand Up @@ -126,8 +174,8 @@ export interface BotsQuery {
[key in keyof BotInfo]: string;
}
| string;
/** The field to sort by. Prefix with "-"" to reverse the order */
sort?: string;
/** Sorts results from a specific criteria. Results will always be descending. */
sort?: "monthlyPoints" | "id" | "date";
/** A list of fields to show. */
fields?: string[] | string;
}
Expand All @@ -153,10 +201,10 @@ export interface ShortUser {
/**
* User's discriminator
*
* @deprecated
* @deprecated No longer supported by Top.gg API v0.
*/
discriminator: string;
/** User's avatar hash */
/** User's avatar url */
avatar: string;
}

Expand Down
Loading