UNPKG

discord-guildpeek

Version:

Get a public preview of a Discord server from its invite code, without authentication.

184 lines (183 loc) 9.21 kB
"use strict"; 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, }; }