discord-guildpeek
Version:
Get a public preview of a Discord server from its invite code, without authentication.
184 lines (183 loc) • 9.21 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __exportStar = (this && this.__exportStar) || function(m, exports) {
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.AllowedExtensionsV9 = void 0;
exports.fetchInviteStatusV9 = fetchInviteStatusV9;
exports.getInviteStatusV9 = getInviteStatusV9;
const v9_schema_1 = require("./v9_schema");
__exportStar(require("./v9_schema"), exports);
/**
* Fetches the status of a Discord invite using the v9 API and validates the response against the provided schema.
*
* @param inviteId - The unique identifier of the Discord invite to fetch.
* @returns A promise that resolves to the validated invite data conforming to `DiscordInviteSchemaV9`.
* @throws Will throw an error if the fetch fails or if the response data does not match the expected schema.
*/
async function fetchInviteStatusV9(inviteId) {
const url = `https://discord.com/api/v9/invites/${inviteId}?with_counts=true&with_expiration=true`;
// Fetch the invite status from Discord API
const response = await fetch(url);
// Check if the response is ok (status code 200-299)
if (!response.ok) {
throw new Error(`Failed to fetch invite status: ${response.statusText}`);
}
// Parse the response JSON and validate it against the schema
const data = await response.json();
// Validate the data structure using the schema
const parsedData = v9_schema_1.DiscordInviteSchemaV9.safeParse(data);
// If validation fails, throw an error with the validation message
if (!parsedData.success) {
throw new Error(`Invalid data structure: ${parsedData.error.message}`);
}
return parsedData.data;
}
/**
* Retrieves the status of a Discord invite using the V9 API.
*
* @param inviteId - The unique identifier of the Discord invite.
* @returns A promise that resolves to the invite status in the V9 format.
*/
async function getInviteStatusV9(inviteId) {
const inviteData = await fetchInviteStatusV9(inviteId);
return convertInviteStatusV9(inviteData);
}
/**
* Enum representing the allowed image file extensions for Discord assets.
*
* These extensions are commonly supported for user avatars, guild icons, and other media.
*
* @remarks The values correspond to the file formats accepted by Discord's API.
*/
var AllowedExtensionsV9;
(function (AllowedExtensionsV9) {
AllowedExtensionsV9["WEBP"] = "webp";
AllowedExtensionsV9["PNG"] = "png";
AllowedExtensionsV9["JPG"] = "jpg";
AllowedExtensionsV9["JPEG"] = "jpeg";
AllowedExtensionsV9["GIF"] = "gif";
})(AllowedExtensionsV9 || (exports.AllowedExtensionsV9 = AllowedExtensionsV9 = {}));
/**
* Represents the types of resources available in the Discord API.
*/
var RessourceTypeV9;
(function (RessourceTypeV9) {
RessourceTypeV9["AVATARS"] = "avatars";
RessourceTypeV9["BANNERS"] = "banners";
RessourceTypeV9["ICONS"] = "icons";
RessourceTypeV9["SPLASHES"] = "splashes";
})(RessourceTypeV9 || (RessourceTypeV9 = {}));
/**
* Returns a function that generates a Discord CDN image URL for a given media type, user ID, and resource ID.
*
* @param mediaType - The type of media resource (e.g., "avatars", "banners").
* @param userId - The ID of the user associated with the resource.
* @param ressourceId - The ID of the specific resource (e.g., avatar hash).
* @returns A function that takes image options (size and extension) and returns the corresponding CDN URL.
*/
function ImageGetter(mediaType, userId, ressourceId) {
return (args) => {
const size = args.size ? `?size=${args.size}` : "";
const extension = args.extension ? args.extension : AllowedExtensionsV9.PNG;
return `https://cdn.discordapp.com/${mediaType}/${userId}/${ressourceId}.${extension}${size}`;
};
}
/**
* Generates an asynchronous function that retrieves the URL for a GIF version of a Discord resource.
* The returned function checks if the GIF exists by making a request to the Discord CDN.
* If the GIF exists, its URL is returned; otherwise, a fallback URL with a specified or default extension is provided.
*
* @param mediatype - The type of Discord resource (e.g., "avatars", "banners").
* @param userId - The ID of the user or entity owning the resource.
* @param ressourceId - The unique identifier for the specific resource.
* @returns An asynchronous function that, given arguments for size and backup extension, returns the appropriate resource URL.
*/
function ImageGifgetter(mediatype, userId, ressourceId) {
// This function generates a URL for a GIF version of a Discord resource, checking if the GIF exists before returning it.
return async (args, checkMethod = "HEAD") => {
const size = args.size ? `?size=${args.size}` : "";
const backUpExtension = args.backupExtension ? args.backupExtension : AllowedExtensionsV9.PNG; // default to PNG if no backup extension is provided
const link = `https://cdn.discordapp.com/${mediatype}/${userId}/${ressourceId}.`;
// Check if the GIF version of the resource exists
const response = await fetch(link + AllowedExtensionsV9.GIF, { method: checkMethod });
// If the response is OK, return the GIF link; otherwise, return the backup extension link
return response.ok
? link + AllowedExtensionsV9.GIF + size
: link + backUpExtension + size;
};
}
/**
* Converts a Discord invite object conforming to the `DiscordInviteSchemaV9` schema
* into a `DiscordInviteStatusV9` object, transforming and formatting fields as needed.
*
* This function handles the conversion of date strings to `Date` objects, constructs
* CDN URLs for guild and inviter assets (icons, banners, avatars), and maps nested
* guild, channel, and inviter information to the output structure.
*
* @param data - The invite data object to convert, validated against `DiscordInviteSchemaV9`.
* @returns The converted invite status object in the `DiscordInviteStatusV9` format.
*/
function convertInviteStatusV9(data) {
return {
code: data.code,
expiresAt: data.expires_at ? new Date(data.expires_at) : null,
guild: {
id: data.guild.id,
name: data.guild.name,
icon: ImageGetter(RessourceTypeV9.ICONS, data.guild.id, data.guild.icon),
banner: data.guild.splash ? ImageGetter(RessourceTypeV9.SPLASHES, data.guild.id, data.guild.splash) : null,
iconGif: ImageGifgetter(RessourceTypeV9.ICONS, data.guild.id, data.guild.icon),
bannerGif: data.guild.banner ? ImageGifgetter(RessourceTypeV9.SPLASHES, data.guild.id, data.guild.banner) : null,
members: data.profile.member_count,
onlines: data.profile.online_count,
description: data.guild.description,
features: data.guild.features,
verificationLevel: data.guild.verification_level,
vanityUrl: data.guild.vanity_url_code,
nsfwLevel: data.guild.nsfw_level,
nsfw: data.guild.nsfw,
premiumSubscription: data.guild.premium_subscription_count,
premiumTier: data.guild.premium_tier,
tag: data.profile.tag,
badge: {
count: data.profile.badge,
colorPrimary: data.profile.badge_color_primary,
colorSecondary: data.profile.badge_color_secondary,
hash: data.profile.badge_hash,
},
traits: data.profile.traits,
visibility: data.profile.visibility
},
channel: {
id: data.channel.id,
type: data.channel.type,
name: data.channel.name,
},
inviter: data.inviter ? {
id: data.inviter.id,
username: data.inviter.username,
globalName: data.inviter.global_name || "",
avatar: ImageGetter(RessourceTypeV9.AVATARS, data.inviter.id, data.inviter.avatar),
banner: data.inviter.banner ? ImageGetter(RessourceTypeV9.BANNERS, data.inviter.id, data.inviter.banner) : null,
avatarGif: ImageGifgetter(RessourceTypeV9.AVATARS, data.inviter.id, data.inviter.avatar),
bannerGif: data.inviter.banner ? ImageGifgetter(RessourceTypeV9.BANNERS, data.inviter.id, data.inviter.banner) : null,
discriminator: data.inviter.discriminator,
flags: data.inviter.flags,
publicFlags: data.inviter.public_flags,
accentColor: data.inviter.accent_color || null,
bannerColor: data.inviter.banner_color ? `${data.inviter.banner_color}` : null
} : null,
};
}