mirror of
https://github.com/tiramisulabs/seyfert.git
synced 2025-07-02 21:16:09 +00:00
feat: proxy cdn
Co-authored-by: MARCROCK22 <MARCROCK22@users.noreply.github.com>
This commit is contained in:
parent
d83330a6e0
commit
7929c9ac9a
325
src/api/CDN.ts
325
src/api/CDN.ts
@ -1,325 +0,0 @@
|
|||||||
/* eslint-disable jsdoc/check-param-names */
|
|
||||||
import { CDN_URL } from '../common/index.js';
|
|
||||||
import {
|
|
||||||
ALLOWED_EXTENSIONS,
|
|
||||||
ALLOWED_SIZES,
|
|
||||||
ALLOWED_STICKER_EXTENSIONS,
|
|
||||||
type ImageExtension,
|
|
||||||
type ImageSize,
|
|
||||||
type StickerExtension,
|
|
||||||
} from './utils/constants.js';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The options used for image URLs
|
|
||||||
*/
|
|
||||||
export interface BaseImageURLOptions {
|
|
||||||
/**
|
|
||||||
* The extension to use for the image URL
|
|
||||||
*
|
|
||||||
* @defaultValue `'webp'`
|
|
||||||
*/
|
|
||||||
extension?: ImageExtension;
|
|
||||||
/**
|
|
||||||
* The size specified in the image URL
|
|
||||||
*/
|
|
||||||
size?: ImageSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The options used for image URLs with animated content
|
|
||||||
*/
|
|
||||||
export interface ImageURLOptions extends BaseImageURLOptions {
|
|
||||||
/**
|
|
||||||
* Whether or not to prefer the static version of an image asset.
|
|
||||||
*/
|
|
||||||
forceStatic?: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The options to use when making a CDN URL
|
|
||||||
*/
|
|
||||||
export interface MakeURLOptions {
|
|
||||||
/**
|
|
||||||
* The allowed extensions that can be used
|
|
||||||
*/
|
|
||||||
allowedExtensions?: readonly string[];
|
|
||||||
/**
|
|
||||||
* The extension to use for the image URL
|
|
||||||
*
|
|
||||||
* @defaultValue `'webp'`
|
|
||||||
*/
|
|
||||||
extension?: ImageExtension | StickerExtension | undefined;
|
|
||||||
/**
|
|
||||||
* The size specified in the image URL
|
|
||||||
*/
|
|
||||||
size?: ImageSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The CDN link builder
|
|
||||||
*/
|
|
||||||
export class CDN {
|
|
||||||
public constructor(private readonly base: string = CDN_URL) {}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Generates an app asset URL for a client's asset.
|
|
||||||
*
|
|
||||||
* @param clientId - The client id that has the asset
|
|
||||||
* @param assetHash - The hash provided by Discord for this asset
|
|
||||||
* @param options - Optional options for the asset
|
|
||||||
*/
|
|
||||||
public appAsset(clientId: string, assetHash: string, options?: Readonly<BaseImageURLOptions>): string {
|
|
||||||
return this.makeURL(`/app-assets/${clientId}/${assetHash}`, options);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Generates an app icon URL for a client's icon.
|
|
||||||
*
|
|
||||||
* @param clientId - The client id that has the icon
|
|
||||||
* @param iconHash - The hash provided by Discord for this icon
|
|
||||||
* @param options - Optional options for the icon
|
|
||||||
*/
|
|
||||||
public appIcon(clientId: string, iconHash: string, options?: Readonly<BaseImageURLOptions>): string {
|
|
||||||
return this.makeURL(`/app-icons/${clientId}/${iconHash}`, options);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Generates an avatar URL, e.g. for a user or a webhook.
|
|
||||||
*
|
|
||||||
* @param id - The id that has the icon
|
|
||||||
* @param avatarHash - The hash provided by Discord for this avatar
|
|
||||||
* @param options - Optional options for the avatar
|
|
||||||
*/
|
|
||||||
public avatar(id: string, avatarHash: string, options?: Readonly<ImageURLOptions>): string {
|
|
||||||
return this.dynamicMakeURL(`/avatars/${id}/${avatarHash}`, avatarHash, options);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Generates a user avatar decoration URL.
|
|
||||||
*
|
|
||||||
* @param userId - The id of the user
|
|
||||||
* @param userAvatarDecoration - The hash provided by Discord for this avatar decoration
|
|
||||||
* @param options - Optional options for the avatar decoration
|
|
||||||
*/
|
|
||||||
public avatarDecoration(
|
|
||||||
userId: string,
|
|
||||||
userAvatarDecoration: string,
|
|
||||||
options?: Readonly<BaseImageURLOptions>,
|
|
||||||
): string {
|
|
||||||
return this.makeURL(`/avatar-decorations/${userId}/${userAvatarDecoration}`, options);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Generates a banner URL, e.g. for a user or a guild.
|
|
||||||
*
|
|
||||||
* @param id - The id that has the banner splash
|
|
||||||
* @param bannerHash - The hash provided by Discord for this banner
|
|
||||||
* @param options - Optional options for the banner
|
|
||||||
*/
|
|
||||||
public banner(id: string, bannerHash: string, options?: Readonly<ImageURLOptions>): string {
|
|
||||||
return this.dynamicMakeURL(`/banners/${id}/${bannerHash}`, bannerHash, options);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Generates an icon URL for a channel, e.g. a group DM.
|
|
||||||
*
|
|
||||||
* @param channelId - The channel id that has the icon
|
|
||||||
* @param iconHash - The hash provided by Discord for this channel
|
|
||||||
* @param options - Optional options for the icon
|
|
||||||
*/
|
|
||||||
public channelIcon(channelId: string, iconHash: string, options?: Readonly<BaseImageURLOptions>): string {
|
|
||||||
return this.makeURL(`/channel-icons/${channelId}/${iconHash}`, options);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Generates a default avatar URL
|
|
||||||
*
|
|
||||||
* @param index - The default avatar index
|
|
||||||
* @remarks
|
|
||||||
* To calculate the index for a user do `(userId >> 22) % 6`,
|
|
||||||
* or `discriminator % 5` if they're using the legacy username system.
|
|
||||||
*/
|
|
||||||
public defaultAvatar(index: number): string {
|
|
||||||
return this.makeURL(`/embed/avatars/${index}`, { extension: 'png' });
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Generates a discovery splash URL for a guild's discovery splash.
|
|
||||||
*
|
|
||||||
* @param guildId - The guild id that has the discovery splash
|
|
||||||
* @param splashHash - The hash provided by Discord for this splash
|
|
||||||
* @param options - Optional options for the splash
|
|
||||||
*/
|
|
||||||
public discoverySplash(guildId: string, splashHash: string, options?: Readonly<BaseImageURLOptions>): string {
|
|
||||||
return this.makeURL(`/discovery-splashes/${guildId}/${splashHash}`, options);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Generates an emoji's URL for an emoji.
|
|
||||||
*
|
|
||||||
* @param emojiId - The emoji id
|
|
||||||
* @param options - Optional options for the emoji
|
|
||||||
*/
|
|
||||||
public emoji(emojiId: string, options?: Readonly<BaseImageURLOptions>): string {
|
|
||||||
const resolvedOptions = options;
|
|
||||||
|
|
||||||
return this.makeURL(`/emojis/${emojiId}`, resolvedOptions);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Generates a guild member avatar URL.
|
|
||||||
*
|
|
||||||
* @param guildId - The id of the guild
|
|
||||||
* @param userId - The id of the user
|
|
||||||
* @param avatarHash - The hash provided by Discord for this avatar
|
|
||||||
* @param options - Optional options for the avatar
|
|
||||||
*/
|
|
||||||
public guildMemberAvatar(
|
|
||||||
guildId: string,
|
|
||||||
userId: string,
|
|
||||||
avatarHash: string,
|
|
||||||
options?: Readonly<ImageURLOptions>,
|
|
||||||
): string {
|
|
||||||
return this.dynamicMakeURL(`/guilds/${guildId}/users/${userId}/avatars/${avatarHash}`, avatarHash, options);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Generates a guild member banner URL.
|
|
||||||
*
|
|
||||||
* @param guildId - The id of the guild
|
|
||||||
* @param userId - The id of the user
|
|
||||||
* @param bannerHash - The hash provided by Discord for this banner
|
|
||||||
* @param options - Optional options for the banner
|
|
||||||
*/
|
|
||||||
public guildMemberBanner(
|
|
||||||
guildId: string,
|
|
||||||
userId: string,
|
|
||||||
bannerHash: string,
|
|
||||||
options?: Readonly<ImageURLOptions>,
|
|
||||||
): string {
|
|
||||||
return this.dynamicMakeURL(`/guilds/${guildId}/users/${userId}/banner`, bannerHash, options);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Generates an icon URL, e.g. for a guild.
|
|
||||||
*
|
|
||||||
* @param id - The id that has the icon splash
|
|
||||||
* @param iconHash - The hash provided by Discord for this icon
|
|
||||||
* @param options - Optional options for the icon
|
|
||||||
*/
|
|
||||||
public icon(id: string, iconHash: string, options?: Readonly<ImageURLOptions>): string {
|
|
||||||
return this.dynamicMakeURL(`/icons/${id}/${iconHash}`, iconHash, options);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Generates a URL for the icon of a role
|
|
||||||
*
|
|
||||||
* @param roleId - The id of the role that has the icon
|
|
||||||
* @param roleIconHash - The hash provided by Discord for this role icon
|
|
||||||
* @param options - Optional options for the role icon
|
|
||||||
*/
|
|
||||||
public roleIcon(roleId: string, roleIconHash: string, options?: Readonly<BaseImageURLOptions>): string {
|
|
||||||
return this.makeURL(`/role-icons/${roleId}/${roleIconHash}`, options);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Generates a guild invite splash URL for a guild's invite splash.
|
|
||||||
*
|
|
||||||
* @param guildId - The guild id that has the invite splash
|
|
||||||
* @param splashHash - The hash provided by Discord for this splash
|
|
||||||
* @param options - Optional options for the splash
|
|
||||||
*/
|
|
||||||
public splash(guildId: string, splashHash: string, options?: Readonly<BaseImageURLOptions>): string {
|
|
||||||
return this.makeURL(`/splashes/${guildId}/${splashHash}`, options);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Generates a sticker URL.
|
|
||||||
*
|
|
||||||
* @param stickerId - The sticker id
|
|
||||||
* @param extension - The extension of the sticker
|
|
||||||
* @privateRemarks
|
|
||||||
* Stickers cannot have a `.webp` extension, so we default to a `.png`
|
|
||||||
*/
|
|
||||||
public sticker(stickerId: string, extension: StickerExtension = 'png'): string {
|
|
||||||
return this.makeURL(`/stickers/${stickerId}`, { allowedExtensions: ALLOWED_STICKER_EXTENSIONS, extension });
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Generates a sticker pack banner URL.
|
|
||||||
*
|
|
||||||
* @param bannerId - The banner id
|
|
||||||
* @param options - Optional options for the banner
|
|
||||||
*/
|
|
||||||
public stickerPackBanner(bannerId: string, options?: Readonly<BaseImageURLOptions>): string {
|
|
||||||
return this.makeURL(`/app-assets/710982414301790216/store/${bannerId}`, options);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Generates a team icon URL for a team's icon.
|
|
||||||
*
|
|
||||||
* @param teamId - The team id that has the icon
|
|
||||||
* @param iconHash - The hash provided by Discord for this icon
|
|
||||||
* @param options - Optional options for the icon
|
|
||||||
*/
|
|
||||||
public teamIcon(teamId: string, iconHash: string, options?: Readonly<BaseImageURLOptions>): string {
|
|
||||||
return this.makeURL(`/team-icons/${teamId}/${iconHash}`, options);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Generates a cover image for a guild scheduled event.
|
|
||||||
*
|
|
||||||
* @param scheduledEventId - The scheduled event id
|
|
||||||
* @param coverHash - The hash provided by discord for this cover image
|
|
||||||
* @param options - Optional options for the cover image
|
|
||||||
*/
|
|
||||||
public guildScheduledEventCover(
|
|
||||||
scheduledEventId: string,
|
|
||||||
coverHash: string,
|
|
||||||
options?: Readonly<BaseImageURLOptions>,
|
|
||||||
): string {
|
|
||||||
return this.makeURL(`/guild-events/${scheduledEventId}/${coverHash}`, options);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructs the URL for the resource, checking whether or not `hash` starts with `a_` if `dynamic` is set to `true`.
|
|
||||||
*
|
|
||||||
* @param route - The base cdn route
|
|
||||||
* @param hash - The hash provided by Discord for this icon
|
|
||||||
* @param options - Optional options for the link
|
|
||||||
*/
|
|
||||||
private dynamicMakeURL(
|
|
||||||
route: string,
|
|
||||||
hash: string,
|
|
||||||
{ forceStatic = false, ...options }: Readonly<ImageURLOptions> = {},
|
|
||||||
): string {
|
|
||||||
return this.makeURL(route, !forceStatic && hash.startsWith('a_') ? { ...options, extension: 'gif' } : options);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructs the URL for the resource
|
|
||||||
*
|
|
||||||
* @param route - The base cdn route
|
|
||||||
* @param options - The extension/size options for the link
|
|
||||||
*/
|
|
||||||
private makeURL(
|
|
||||||
route: string,
|
|
||||||
{ allowedExtensions = ALLOWED_EXTENSIONS, extension = 'webp', size }: Readonly<MakeURLOptions> = {},
|
|
||||||
): string {
|
|
||||||
if (!allowedExtensions.includes(extension)) {
|
|
||||||
throw new RangeError(`Invalid extension provided: ${extension}\nMust be one of: ${allowedExtensions.join(', ')}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (size && !ALLOWED_SIZES.includes(size)) {
|
|
||||||
throw new RangeError(`Invalid size provided: ${size}\nMust be one of: ${ALLOWED_SIZES.join(', ')}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
const url = new URL(`${this.base}${route}.${extension}`);
|
|
||||||
|
|
||||||
if (size) {
|
|
||||||
url.searchParams.set('size', String(size));
|
|
||||||
}
|
|
||||||
|
|
||||||
return url.toString();
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,6 +1,6 @@
|
|||||||
import { CDN_URL } from '../common';
|
import { CDN_URL } from '../common';
|
||||||
import type { APIRoutes, ApiHandler, CDNRoute } from './index';
|
import type { APIRoutes, ApiHandler, CDNRoute } from './index';
|
||||||
import type { HttpMethods } from './shared';
|
import type { HttpMethods, ImageExtension, ImageSize, StickerExtension } from './shared';
|
||||||
|
|
||||||
export enum ProxyRequestMethod {
|
export enum ProxyRequestMethod {
|
||||||
Delete = 'delete',
|
Delete = 'delete',
|
||||||
@ -43,15 +43,15 @@ export const CDNRouter = {
|
|||||||
return new Proxy(noop, {
|
return new Proxy(noop, {
|
||||||
get: (_, key: string) => {
|
get: (_, key: string) => {
|
||||||
if (key === 'get') {
|
if (key === 'get') {
|
||||||
return (value?: string) => {
|
return (value: string | undefined, options?: CDNUrlOptions) => {
|
||||||
const lastRoute = `${CDN_URL}/${route.join('/')}`;
|
const lastRoute = `${CDN_URL}/${route.join('/')}`;
|
||||||
if (value) {
|
let routeResult = lastRoute;
|
||||||
if (typeof value !== 'string') {
|
if (value && typeof value === 'string') {
|
||||||
value = String(value);
|
routeResult = `${lastRoute}/${value}`;
|
||||||
|
return parseCDNURL(routeResult, options);
|
||||||
}
|
}
|
||||||
return `${lastRoute}/${value}`;
|
// @ts-expect-error
|
||||||
}
|
return parseCDNURL(routeResult, value);
|
||||||
return lastRoute;
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
return this.createProxy([...route, key]);
|
return this.createProxy([...route, key]);
|
||||||
@ -62,3 +62,22 @@ export const CDNRouter = {
|
|||||||
}) as unknown as CDNRoute;
|
}) as unknown as CDNRoute;
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export interface BaseCDNUrlOptions {
|
||||||
|
extension?: ImageExtension | StickerExtension | undefined;
|
||||||
|
size?: ImageSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CDNUrlOptions extends BaseCDNUrlOptions {
|
||||||
|
forceStatic?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function parseCDNURL(route: string, options: CDNUrlOptions = { forceStatic: false }) {
|
||||||
|
if (options.forceStatic && route.includes('a_')) options.extension = 'png';
|
||||||
|
|
||||||
|
const url = new URL(`${route}.${options.extension}`);
|
||||||
|
|
||||||
|
if (options.size) url.searchParams.set('size', `${options.size}`);
|
||||||
|
|
||||||
|
return url.toString();
|
||||||
|
}
|
||||||
|
@ -1,3 +1,6 @@
|
|||||||
|
import type { BaseCDNUrlOptions, CDNUrlOptions } from '../..';
|
||||||
|
import type { StickerExtension } from '../shared';
|
||||||
|
|
||||||
export interface CDNRoute {
|
export interface CDNRoute {
|
||||||
embed: {
|
embed: {
|
||||||
avatars: {
|
avatars: {
|
||||||
@ -5,62 +8,71 @@ export interface CDNRoute {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
avatars(id: string): {
|
avatars(id: string): {
|
||||||
get(hash: string): string;
|
get(hash: string, options?: CDNUrlOptions): string;
|
||||||
|
};
|
||||||
|
'avatar-decorations'(userId: string): {
|
||||||
|
get(hash: string, options?: BaseCDNUrlOptions): string;
|
||||||
|
};
|
||||||
|
'channel-icons'(channelId: string): {
|
||||||
|
get(hash: string, options?: BaseCDNUrlOptions): string;
|
||||||
};
|
};
|
||||||
icons(guildId: string): {
|
icons(guildId: string): {
|
||||||
get(hash: string): string;
|
get(hash: string, options?: CDNUrlOptions): string;
|
||||||
};
|
};
|
||||||
splashes(guildId: string): {
|
splashes(guildId: string): {
|
||||||
get(hash: string): string;
|
get(hash: string, options?: BaseCDNUrlOptions): string;
|
||||||
};
|
};
|
||||||
'discovery-splashes'(guidId: string): {
|
'discovery-splashes'(guidId: string): {
|
||||||
get(hash: string): string;
|
get(hash: string, options?: BaseCDNUrlOptions): string;
|
||||||
};
|
};
|
||||||
banners(id: string): {
|
banners(id: string): {
|
||||||
get(hash: string): string;
|
get(hash: string, options?: CDNUrlOptions): string;
|
||||||
};
|
};
|
||||||
guilds(id: string): {
|
guilds(id: string): {
|
||||||
users(id: string): {
|
users(id: string): {
|
||||||
avatars(hash: string): {
|
avatars(hash: string): {
|
||||||
get(): string;
|
get(options?: CDNUrlOptions): string;
|
||||||
};
|
};
|
||||||
banners(hash: string): {
|
banners(hash: string): {
|
||||||
get(): string;
|
get(options?: CDNUrlOptions): string;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
'guild-events'(eventId: string): {
|
||||||
|
get(hash: string, options?: BaseCDNUrlOptions): string;
|
||||||
|
};
|
||||||
emojis(id: string): {
|
emojis(id: string): {
|
||||||
get(): string;
|
get(options?: BaseCDNUrlOptions): string;
|
||||||
};
|
};
|
||||||
appIcons(appId: string): {
|
appIcons(appId: string): {
|
||||||
get(iconOrCover: string): string;
|
get(iconOrCover: string, options?: BaseCDNUrlOptions): string;
|
||||||
};
|
};
|
||||||
'app-assets'(appId: string): {
|
'app-assets'(appId: string): {
|
||||||
get(asset: string): string;
|
get(asset: string): string;
|
||||||
achievements(id: string): {
|
achievements(id: string): {
|
||||||
icons(hash: string): {
|
icons(hash: string): {
|
||||||
get(): string;
|
get(options?: BaseCDNUrlOptions): string;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
'team-icons'(teamId: string): {
|
'team-icons'(teamId: string): {
|
||||||
get(hash: string): string;
|
get(hash: string, options?: BaseCDNUrlOptions): string;
|
||||||
};
|
};
|
||||||
stickers(id: string): {
|
stickers(id: string): {
|
||||||
get(): string;
|
get(extension: StickerExtension): string;
|
||||||
};
|
};
|
||||||
'role-icons'(roleId: string): {
|
'role-icons'(roleId: string): {
|
||||||
get(icon: string): string;
|
get(icon: string, options?: BaseCDNUrlOptions): string;
|
||||||
};
|
};
|
||||||
'guild-events'(id: string): {
|
'guild-events'(id: string): {
|
||||||
get(cover: string): string;
|
get(cover: string, options?: BaseCDNUrlOptions): string;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CDNRoute {
|
export interface CDNRoute {
|
||||||
'app-assets'(id: '710982414301790216'): {
|
'app-assets'(id: '710982414301790216'): {
|
||||||
store(packBannerId: string): {
|
store(packBannerId: string): {
|
||||||
get(): string;
|
get(options?: BaseCDNUrlOptions): string;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -6,8 +6,7 @@ import { Logger } from '../common';
|
|||||||
import { snowflakeToTimestamp } from '../structures/extra/functions';
|
import { snowflakeToTimestamp } from '../structures/extra/functions';
|
||||||
import type { WorkerData } from '../websocket';
|
import type { WorkerData } from '../websocket';
|
||||||
import type { WorkerSendApiRequest } from '../websocket/discord/worker';
|
import type { WorkerSendApiRequest } from '../websocket/discord/worker';
|
||||||
import { CDN } from './CDN';
|
import { CDNRouter, type ProxyRequestMethod } from './Router';
|
||||||
import type { ProxyRequestMethod } from './Router';
|
|
||||||
import { Bucket } from './bucket';
|
import { Bucket } from './bucket';
|
||||||
import {
|
import {
|
||||||
DefaultUserAgent,
|
DefaultUserAgent,
|
||||||
@ -26,7 +25,7 @@ export class ApiHandler {
|
|||||||
globalBlock = false;
|
globalBlock = false;
|
||||||
ratelimits = new Map<string, Bucket>();
|
ratelimits = new Map<string, Bucket>();
|
||||||
readyQueue: (() => void)[] = [];
|
readyQueue: (() => void)[] = [];
|
||||||
cdn = new CDN();
|
cdn = CDNRouter.createProxy();
|
||||||
debugger?: Logger;
|
debugger?: Logger;
|
||||||
workerPromises?: Map<string, { resolve: (value: any) => any; reject: (error: any) => any }>;
|
workerPromises?: Map<string, { resolve: (value: any) => any; reject: (error: any) => any }>;
|
||||||
|
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
export * from './CDN';
|
|
||||||
export * from './Router';
|
export * from './Router';
|
||||||
export * from './Routes';
|
export * from './Routes';
|
||||||
export * from './api';
|
export * from './api';
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
export const DefaultUserAgent = 'DiscordBot (https://seyfert.dev)';
|
export const DefaultUserAgent = 'DiscordBot (https://seyfert.dev)';
|
||||||
export const ALLOWED_EXTENSIONS = ['webp', 'png', 'jpg', 'jpeg', 'gif'] as const satisfies readonly string[];
|
export const ALLOWED_EXTENSIONS = ['webp', 'png', 'jpg', 'jpeg', 'gif'] as const;
|
||||||
export const ALLOWED_STICKER_EXTENSIONS = ['png', 'json', 'gif'] as const satisfies readonly string[];
|
export const ALLOWED_STICKER_EXTENSIONS = ['png', 'json', 'gif'] as const;
|
||||||
export const ALLOWED_SIZES = [16, 32, 64, 128, 256, 512, 1_024, 2_048, 4_096] as const satisfies readonly number[];
|
export const ALLOWED_SIZES = [16, 32, 64, 128, 256, 512, 1_024, 2_048, 4_096] as const;
|
||||||
|
|
||||||
export type ImageExtension = (typeof ALLOWED_EXTENSIONS)[number];
|
export type ImageExtension = (typeof ALLOWED_EXTENSIONS)[number];
|
||||||
export type StickerExtension = (typeof ALLOWED_STICKER_EXTENSIONS)[number];
|
export type StickerExtension = (typeof ALLOWED_STICKER_EXTENSIONS)[number];
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
import type { Identify } from '..';
|
import type { Identify } from '..';
|
||||||
import type { ImageURLOptions } from '../../api';
|
import type { CDNUrlOptions } from '../../api';
|
||||||
import type { UsingClient } from '../../commands';
|
import type { UsingClient } from '../../commands';
|
||||||
|
|
||||||
export type ImageOptions = ImageURLOptions;
|
export type ImageOptions = CDNUrlOptions;
|
||||||
|
|
||||||
export type MethodContext<T = {}> = Identify<{ client: UsingClient } & T>;
|
export type MethodContext<T = {}> = Identify<{ client: UsingClient } & T>;
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import type { APIEmoji, RESTPatchAPIChannelJSONBody, RESTPatchAPIGuildEmojiJSONBody } from 'discord-api-types/v10';
|
import type { APIEmoji, RESTPatchAPIChannelJSONBody, RESTPatchAPIGuildEmojiJSONBody } from 'discord-api-types/v10';
|
||||||
import type { BaseImageURLOptions } from '../api';
|
import type { BaseCDNUrlOptions } from '../api';
|
||||||
import type { UsingClient } from '../commands';
|
import type { UsingClient } from '../commands';
|
||||||
import type { EmojiShorter, MethodContext, ObjectToLower } from '../common';
|
import type { EmojiShorter, MethodContext, ObjectToLower } from '../common';
|
||||||
import { DiscordBase } from './extra/DiscordBase';
|
import { DiscordBase } from './extra/DiscordBase';
|
||||||
@ -32,8 +32,8 @@ export class GuildEmoji extends DiscordBase {
|
|||||||
return this.client.emojis.fetch(this.guildId, this.id, force);
|
return this.client.emojis.fetch(this.guildId, this.id, force);
|
||||||
}
|
}
|
||||||
|
|
||||||
url(options?: BaseImageURLOptions) {
|
url(options?: BaseCDNUrlOptions) {
|
||||||
return this.rest.cdn.emoji(this.id, options);
|
return this.rest.cdn.emojis(this.id).get(options);
|
||||||
}
|
}
|
||||||
|
|
||||||
toString() {
|
toString() {
|
||||||
|
@ -185,7 +185,7 @@ export class GuildMember extends BaseGuildMember {
|
|||||||
return this.user.avatarURL(options);
|
return this.user.avatarURL(options);
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.rest.cdn.guildMemberAvatar(this.guildId, this.id, this.avatar, options);
|
return this.rest.cdn.guilds(this.guildId).users(this.id).avatars(this.avatar).get(options);
|
||||||
}
|
}
|
||||||
|
|
||||||
bannerURL(options?: ImageOptions) {
|
bannerURL(options?: ImageOptions) {
|
||||||
|
@ -36,14 +36,19 @@ export class User extends DiscordBase<APIUser> {
|
|||||||
if (!this.avatar) {
|
if (!this.avatar) {
|
||||||
const avatarIndex =
|
const avatarIndex =
|
||||||
this.discriminator === '0' ? Number(BigInt(this.id) >> 22n) % 6 : Number.parseInt(this.discriminator) % 5;
|
this.discriminator === '0' ? Number(BigInt(this.id) >> 22n) % 6 : Number.parseInt(this.discriminator) % 5;
|
||||||
return this.rest.cdn.defaultAvatar(avatarIndex);
|
return this.rest.cdn.embed.avatars.get(avatarIndex);
|
||||||
}
|
}
|
||||||
return this.rest.cdn.avatar(this.id, this.avatar, options);
|
return this.rest.cdn.avatars(this.id).get(this.avatar, options);
|
||||||
|
}
|
||||||
|
|
||||||
|
avatarDecorationURL(options?: ImageOptions) {
|
||||||
|
if (!this.avatarDecoration) return;
|
||||||
|
return this.rest.cdn['avatar-decorations'](this.id).get(this.avatarDecoration, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
bannerURL(options?: ImageOptions) {
|
bannerURL(options?: ImageOptions) {
|
||||||
if (!this.banner) return;
|
if (!this.banner) return;
|
||||||
return this.rest.cdn.banner(this.id, this.banner, options);
|
return this.rest.cdn.banners(this.id).get(this.banner, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
presence() {
|
presence() {
|
||||||
|
@ -84,7 +84,7 @@ export class Webhook extends DiscordBase {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.rest.cdn.avatar(this.id, this.avatar, options);
|
return this.rest.cdn.avatars(this.id).get(this.avatar, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -42,7 +42,7 @@ export class BaseGuild extends DiscordBase<APIPartialGuild> {
|
|||||||
if (!this.icon) {
|
if (!this.icon) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
return this.rest.cdn.icon(this.id, this.icon, options);
|
return this.rest.cdn.icons(this.id).get(this.icon, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -55,7 +55,7 @@ export class BaseGuild extends DiscordBase<APIPartialGuild> {
|
|||||||
if (!this.splash) {
|
if (!this.splash) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
return this.rest.cdn.discoverySplash(this.id, this.splash, options);
|
return this.rest.cdn['discovery-splashes'](this.id).get(this.splash, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -68,7 +68,7 @@ export class BaseGuild extends DiscordBase<APIPartialGuild> {
|
|||||||
if (!this.banner) {
|
if (!this.banner) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
return this.rest.cdn.banner(this.id, this.banner, options);
|
return this.rest.cdn.banners(this.id).get(this.banner, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
toString(): string {
|
toString(): string {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user