diff --git a/.github/workflows/rest-proxy.yml b/.github/workflows/rest-proxy.yml index b7fdea47e..22681baaa 100644 --- a/.github/workflows/rest-proxy.yml +++ b/.github/workflows/rest-proxy.yml @@ -3,16 +3,16 @@ name: Rest proxy on: push: branches: - - "main" + - 'main' paths: - - ".github/workflows/rest-proxy.yml" - - "proxies/rest/**" + - '.github/workflows/rest-proxy.yml' + - 'proxies/rest/**' pull_request: paths: - - ".github/workflows/rest-proxy.yml" - - "proxies/rest/**" + - '.github/workflows/rest-proxy.yml' + - 'proxies/rest/**' schedule: - - cron: "0 0 * * *" + - cron: '0 0 * * *' jobs: build: @@ -59,6 +59,7 @@ jobs: runs-on: ubuntu-latest needs: build steps: + - uses: actions/checkout@v3 - name: Set up Docker Buildx uses: docker/setup-buildx-action@v2 - name: Download artifact @@ -71,27 +72,42 @@ jobs: - name: Run Trivy vulnerability scanner uses: aquasecurity/trivy-action@master with: - image-ref: "discordeno/rest-proxy:latest" - format: "table" - exit-code: "0" + image-ref: 'discordeno/rest-proxy:latest' + format: 'table' + exit-code: '0' ignore-unfixed: true - vuln-type: "os,library" - severity: "UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL" + vuln-type: 'os,library' + severity: 'UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL' - name: Run Trivy vulnerability scanner uses: aquasecurity/trivy-action@master - if: ${{ github.event_name == 'schedule' }} + if: ${{ github.event_name == 'schedule' || github.event_name == 'push' }} with: - image-ref: "discordeno/rest-proxy:latest" - exit-code: "0" - vuln-type: "os,library" - severity: "UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL" - format: "sarif" - output: "trivy-results.sarif" + image-ref: 'discordeno/rest-proxy:latest' + exit-code: '0' + vuln-type: 'os,library' + severity: 'UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL' + format: 'sarif' + output: 'trivy-results.sarif' - name: Upload Trivy scan results to GitHub Security tab uses: github/codeql-action/upload-sarif@v2 - if: ${{ github.event_name == 'schedule' }} + if: ${{ github.event_name == 'schedule' || github.event_name == 'push' }} with: - sarif_file: "trivy-results.sarif" + sarif_file: 'trivy-results.sarif' + + - name: Run Snyk to check Docker image for vulnerabilities + if: ${{ github.event_name == 'schedule' || github.event_name == 'push' }} + continue-on-error: true + uses: snyk/actions/docker@master + env: + SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }} + with: + image: 'discordeno/rest-proxy:latest' + args: --file=proxies/rest/Dockerfile + - name: Upload result to GitHub Code Scanning + if: ${{ github.event_name == 'schedule' || github.event_name == 'push' }} + uses: github/codeql-action/upload-sarif@v2 + with: + sarif_file: snyk.sarif build-all-arch: name: Build image for all architectures @@ -117,7 +133,7 @@ jobs: with: context: proxies/rest push: false - tags: "discordeno/rest-proxy:latest" + tags: 'discordeno/rest-proxy:latest' # linux/s390x stuck at yarn install, remove it for now platforms: linux/amd64,linux/arm/v6,linux/arm/v7,linux/arm64/v8,linux/ppc64le target: runner @@ -157,7 +173,7 @@ jobs: with: context: proxies/rest push: true - tags: "ghcr.io/discordeno/rest-proxy:latest" + tags: 'ghcr.io/discordeno/rest-proxy:latest' # linux/s390x stuck at yarn install, remove it for now platforms: linux/amd64,linux/arm/v6,linux/arm/v7,linux/arm64/v8,linux/ppc64le target: runner diff --git a/examples/README.md b/examples/README.md index 78ae3cc13..d13167d7c 100644 --- a/examples/README.md +++ b/examples/README.md @@ -5,6 +5,6 @@ This repo is meant as a template which you can use to create a Discord bot very easily using the [Discordeno library](https://github.com/discordeno/discordeno). -[Website/Guide](https://discordeno.js.org//) +[Website/Guide](https://discordeno.js.org/) [Discord Server](https://discord.com/invite/5vBgXk3UcZ) diff --git a/packages/bot/src/bot.ts b/packages/bot/src/bot.ts index 971e07631..6b1c9dd90 100644 --- a/packages/bot/src/bot.ts +++ b/packages/bot/src/bot.ts @@ -67,18 +67,21 @@ export function createBot(options: CreateBotOptions): Bot { // Set up helpers below. helpers: {} as BotHelpers, async start() { - // @ts-expect-error should this work - if (typeof Deno !== 'undefined') { - // @ts-expect-error should this work - const katsura = await import('https://x.nest.land/katsura@1.3.9/src/discordenoFixes/gatewaySocket.ts') - - await katsura(bot.gateway) - } - if (!options.gateway?.connection) { bot.gateway.connection = await bot.rest.getSessionInfo() + + // Check for overrides in the configuration + if (!options.gateway?.url) + bot.gateway.url = bot.gateway.connection.url; + + if (!options.gateway?.totalShards) + bot.gateway.totalShards = bot.gateway.connection.shards; + + if (!options.gateway?.lastShardId) + bot.gateway.lastShardId = bot.gateway.connection.shards - 1; } - return await bot.gateway.spawnShards() + + await bot.gateway.spawnShards() }, async shutdown() { @@ -184,7 +187,8 @@ export interface EventHandlers { guildId?: bigint member?: Member user?: User - emoji: Emoji + emoji: Emoji, + messageAuthorId?: bigint }) => unknown reactionRemove: (payload: { userId: bigint; channelId: bigint; messageId: bigint; guildId?: bigint; emoji: Emoji }) => unknown reactionRemoveEmoji: (payload: { channelId: bigint; messageId: bigint; guildId?: bigint; emoji: Emoji }) => unknown @@ -205,6 +209,7 @@ export interface EventHandlers { guildBanRemove: (user: User, guildId: bigint) => unknown guildCreate: (guild: Guild) => unknown guildDelete: (id: bigint, shardId: number) => unknown + guildUnavailable: (id: bigint, shardId: number) => unknown guildUpdate: (guild: Guild) => unknown raw: (data: DiscordGatewayPayload, shardId: number) => unknown roleCreate: (role: Role) => unknown diff --git a/packages/bot/src/handlers.ts b/packages/bot/src/handlers.ts index e560250f2..d2c0f8642 100644 --- a/packages/bot/src/handlers.ts +++ b/packages/bot/src/handlers.ts @@ -41,7 +41,7 @@ export function createBotGatewayHandlers( INTEGRATION_UPDATE: options.INTEGRATION_UPDATE ?? handlers.handleIntegrationUpdate, INTEGRATION_DELETE: options.INTEGRATION_DELETE ?? handlers.handleIntegrationDelete, INVITE_CREATE: options.INVITE_CREATE ?? handlers.handleInviteCreate, - INVITE_DELETE: options.INVITE_DELETE ?? handlers.handleInviteCreate, + INVITE_DELETE: options.INVITE_DELETE ?? handlers.handleInviteDelete, MESSAGE_CREATE: options.MESSAGE_CREATE ?? handlers.handleMessageCreate, MESSAGE_DELETE_BULK: options.MESSAGE_DELETE_BULK ?? handlers.handleMessageDeleteBulk, MESSAGE_DELETE: options.MESSAGE_DELETE ?? handlers.handleMessageDelete, diff --git a/packages/bot/src/handlers/guilds/GUILD_DELETE.ts b/packages/bot/src/handlers/guilds/GUILD_DELETE.ts index 3db895c0a..20d636995 100644 --- a/packages/bot/src/handlers/guilds/GUILD_DELETE.ts +++ b/packages/bot/src/handlers/guilds/GUILD_DELETE.ts @@ -3,5 +3,11 @@ import type { Bot } from '../../bot.js' export async function handleGuildDelete(bot: Bot, data: DiscordGatewayPayload, shardId: number): Promise { const payload = data.d as DiscordUnavailableGuild + + if (payload.unavailable) { + bot.events.guildUnavailable?.(bot.transformers.snowflake(payload.id), shardId) + return + } + bot.events.guildDelete?.(bot.transformers.snowflake(payload.id), shardId) } diff --git a/packages/bot/src/handlers/messages/MESSAGE_REACTION_ADD.ts b/packages/bot/src/handlers/messages/MESSAGE_REACTION_ADD.ts index 871cad09f..2b0f1bb88 100644 --- a/packages/bot/src/handlers/messages/MESSAGE_REACTION_ADD.ts +++ b/packages/bot/src/handlers/messages/MESSAGE_REACTION_ADD.ts @@ -14,5 +14,6 @@ export async function handleMessageReactionAdd(bot: Bot, data: DiscordGatewayPay member: payload.member && guildId ? bot.transformers.member(bot, payload.member, guildId, userId) : undefined, user: payload.member ? bot.transformers.user(bot, payload.member.user) : undefined, emoji: bot.transformers.emoji(bot, payload.emoji), + messageAuthorId: payload.message_author_id ? bot.transformers.snowflake(payload.message_author_id) : undefined, }) } diff --git a/packages/bot/src/transformers.ts b/packages/bot/src/transformers.ts index e1ba9c588..15d7d0112 100644 --- a/packages/bot/src/transformers.ts +++ b/packages/bot/src/transformers.ts @@ -334,6 +334,7 @@ export interface Transformers { } user: { username: boolean + globalName: boolean locale: boolean flags: boolean premiumType: boolean @@ -672,6 +673,7 @@ export function createTransformers(options: Partial): Transformers }, user: { username: false, + globalName: false, locale: false, flags: false, premiumType: false, diff --git a/packages/bot/src/transformers/auditLogEntry.ts b/packages/bot/src/transformers/auditLogEntry.ts index 7473f961e..496005ada 100644 --- a/packages/bot/src/transformers/auditLogEntry.ts +++ b/packages/bot/src/transformers/auditLogEntry.ts @@ -1,5 +1,5 @@ import type { DiscordAuditLogEntry } from '@discordeno/types' -import type { Bot } from '../index.js' +import { iconHashToBigInt, type Bot } from '../index.js' import type { Optionalize } from '../optionalize.js' // eslint-disable-next-line @typescript-eslint/explicit-function-return-type @@ -21,13 +21,8 @@ export function transformAuditLogEntry(bot: Bot, payload: DiscordAuditLogEntry) name: val?.name, })), } - case 'discovery_splash_hash': - case 'banner_hash': case 'rules_channel_id': case 'public_updates_channel_id': - case 'icon_hash': - case 'image_hash': - case 'splash_hash': case 'owner_id': case 'widget_channel_id': case 'system_channel_id': @@ -37,13 +32,23 @@ export function transformAuditLogEntry(bot: Bot, payload: DiscordAuditLogEntry) case 'deny': case 'channel_id': case 'inviter_id': - case 'avatar_hash': case 'id': return { key: change.key, old: change.old_value ? bot.transformers.snowflake(change.old_value) : undefined, new: change.new_value ? bot.transformers.snowflake(change.new_value) : undefined, } + case 'discovery_splash_hash': + case 'banner_hash': + case 'icon_hash': + case 'image_hash': + case 'splash_hash': + case 'avatar_hash': + return { + key: change.key, + old: change.old_value ? iconHashToBigInt(change.old_value) : undefined, + new: change.new_value ? iconHashToBigInt(change.new_value) : undefined, + } case 'name': case 'description': case 'preferred_locale': diff --git a/packages/bot/src/transformers/channel.ts b/packages/bot/src/transformers/channel.ts index b4f3414d4..dd18b45c5 100644 --- a/packages/bot/src/transformers/channel.ts +++ b/packages/bot/src/transformers/channel.ts @@ -73,7 +73,7 @@ export function transformChannel(bot: Bot, payload: { channel: DiscordChannel } if (payload.channel.name && props.name) channel.name = payload.channel.name if (payload.channel.topic && props.topic) channel.topic = payload.channel.topic if (payload.channel.last_message_id && props.lastMessageId) channel.lastMessageId = bot.transformers.snowflake(payload.channel.last_message_id) - if (payload.channel.bitrate && props.bitrate) channel.bitrate = props.bitrate + if (payload.channel.bitrate && props.bitrate) channel.bitrate = payload.channel.bitrate if (props.userLimit) channel.userLimit = payload.channel.user_limit if (props.rateLimitPerUser) channel.rateLimitPerUser = payload.channel.rate_limit_per_user if (payload.channel.owner_id && props.ownerId) channel.ownerId = bot.transformers.snowflake(payload.channel.owner_id) diff --git a/packages/bot/src/transformers/message.ts b/packages/bot/src/transformers/message.ts index bf9a3fd88..f54b2b63e 100644 --- a/packages/bot/src/transformers/message.ts +++ b/packages/bot/src/transformers/message.ts @@ -16,7 +16,6 @@ const baseMessage: Partial & MessageBase = { return this.flags?.contains(MessageFlags.Crossposted) ?? false }, set crossposted(value: boolean) { - if (!this.flags) return if (!this.flags) return if (value) this.flags.add(MessageFlags.Crossposted) else this.flags.remove(MessageFlags.Crossposted) diff --git a/packages/bot/src/transformers/reverse/auditLogEntry.ts b/packages/bot/src/transformers/reverse/auditLogEntry.ts index 01e7ec7d8..d28d2b7d5 100644 --- a/packages/bot/src/transformers/reverse/auditLogEntry.ts +++ b/packages/bot/src/transformers/reverse/auditLogEntry.ts @@ -1,5 +1,5 @@ import type { DiscordAuditLogEntry } from '@discordeno/types' -import type { Bot } from '../../index.js' +import { iconBigintToHash, type Bot } from '../../index.js' import type { AuditLogEntry } from '../auditLogEntry.js' export function transformAuditLogEntryToDiscordAuditLogEntry(bot: Bot, payload: AuditLogEntry): DiscordAuditLogEntry { @@ -33,13 +33,8 @@ export function transformAuditLogEntryToDiscordAuditLogEntry(bot: Bot, payload: name: val?.name, })), } - case 'discovery_splash_hash': - case 'banner_hash': case 'rules_channel_id': case 'public_updates_channel_id': - case 'icon_hash': - case 'image_hash': - case 'splash_hash': case 'owner_id': case 'widget_channel_id': case 'system_channel_id': @@ -49,13 +44,23 @@ export function transformAuditLogEntryToDiscordAuditLogEntry(bot: Bot, payload: case 'deny': case 'channel_id': case 'inviter_id': - case 'avatar_hash': case 'id': return { key: change.key, old_value: change.old ? bot.transformers.reverse.snowflake(change.old as bigint) : '', new_value: change.new ? bot.transformers.reverse.snowflake(change.new as bigint) : '', } + case 'discovery_splash_hash': + case 'banner_hash': + case 'icon_hash': + case 'image_hash': + case 'splash_hash': + case 'avatar_hash': + return { + key: change.key, + old_value: change.old ? iconBigintToHash(change.old as bigint) : '', + new_value: change.new ? iconBigintToHash(change.new as bigint) : '', + } case 'name': case 'description': case 'preferred_locale': diff --git a/packages/bot/src/transformers/reverse/member.ts b/packages/bot/src/transformers/reverse/member.ts index 9c4b38e71..947bc5de0 100644 --- a/packages/bot/src/transformers/reverse/member.ts +++ b/packages/bot/src/transformers/reverse/member.ts @@ -8,6 +8,7 @@ export function transformUserToDiscordUser(bot: Bot, payload: User): DiscordUser return { id: payload.id.toString(), username: payload.username, + global_name: payload.globalName ?? null, discriminator: payload.discriminator, avatar: payload.avatar ? iconBigintToHash(payload.avatar) : null, locale: payload.locale, diff --git a/packages/bot/src/transformers/user.ts b/packages/bot/src/transformers/user.ts index 182194919..c2dd56695 100644 --- a/packages/bot/src/transformers/user.ts +++ b/packages/bot/src/transformers/user.ts @@ -32,6 +32,7 @@ export function transformUser(bot: Bot, payload: DiscordUser): User { if (props.publicFlags) user.publicFlags = new ToggleBitfield(payload.public_flags) if (payload.id && props.id) user.id = bot.transformers.snowflake(payload.id) if (payload.username && props.username) user.username = payload.username + if (payload.global_name && props.globalName) user.globalName = payload.global_name if (payload.discriminator && props.discriminator) user.discriminator = payload.discriminator if (payload.locale && props.locale) user.locale = payload.locale if (payload.email && props.email) user.email = payload.email @@ -61,6 +62,8 @@ export interface User extends BaseUser { toggles?: UserToggles /** The user's username, not unique across the platform */ username: string + /** The user's display name, if it is set. For bots, this is the application name */ + globalName?: string /** The user's chosen language option */ locale?: string /** The flags on a user's account */ @@ -73,7 +76,7 @@ export interface User extends BaseUser { accentColor?: number /** The user's id */ id: bigint - /** The user's 4-digit discord-tag */ + /** The user's discord-tag */ discriminator: string /** The user's avatar hash */ avatar?: bigint diff --git a/packages/gateway/src/Shard.ts b/packages/gateway/src/Shard.ts index 3fb47e0bd..8f066eb03 100644 --- a/packages/gateway/src/Shard.ts +++ b/packages/gateway/src/Shard.ts @@ -12,11 +12,13 @@ import type { import { GatewayCloseEventCodes, GatewayIntents, GatewayOpcodes } from '@discordeno/types' import { Collection, LeakyBucket, camelize, delay, logger } from '@discordeno/utils' import { inflateSync } from 'node:zlib' -import WebSocket from 'ws' +import NodeWebSocket from 'ws' import type { RequestMemberRequest } from './manager.js' import type { BotStatusUpdate, ShardEvents, ShardGatewayConfig, ShardHeart, ShardSocketRequest, StatusUpdate, UpdateVoiceState } from './types.js' import { ShardSocketCloseCodes, ShardState } from './types.js' +declare let WebSocket: any + export class DiscordenoShard { /** The id of the shard */ id: number @@ -33,7 +35,7 @@ export class DiscordenoShard { /** Current session id of the shard if present. */ sessionId?: string /** This contains the WebSocket connection to Discord, if currently connected. */ - socket?: WebSocket + socket?: NodeWebSocket /** Current internal state of the this. */ state = ShardState.Offline /** The url provided by discord to use when resuming a connection for this this. */ @@ -111,7 +113,7 @@ export class DiscordenoShard { /** Close the socket connection to discord if present. */ close(code: number, reason: string): void { - if (this.socket?.readyState !== WebSocket.OPEN) return + if (this.socket?.readyState !== NodeWebSocket.OPEN) return this.socket?.close(code, reason) } @@ -129,13 +131,15 @@ export class DiscordenoShard { url.searchParams.set('v', this.gatewayConfig.version.toString()) url.searchParams.set('encoding', 'json') - const socket = new WebSocket(url.toString()) + const socket: NodeWebSocket = + // @ts-expect-error Deno + globalThis.Deno !== undefined && Reflect.has(globalThis, 'Deno') ? new WebSocket(url.toString()) : new NodeWebSocket(url.toString()) this.socket = socket // TODO: proper event handling - socket.onerror = (event) => console.log({ error: event, shardId: this.id }) - socket.onclose = async (event) => await this.handleClose(event) - socket.onmessage = async (message) => await this.handleMessage(message) + socket.onerror = (event: NodeWebSocket.ErrorEvent) => console.log({ error: event, shardId: this.id }) + socket.onclose = async (event: NodeWebSocket.CloseEvent) => await this.handleClose(event) + socket.onmessage = async (message: NodeWebSocket.MessageEvent) => await this.handleMessage(message) return await new Promise((resolve) => { socket.onopen = () => { @@ -204,7 +208,7 @@ export class DiscordenoShard { /** Check whether the connection to Discord is currently open. */ isOpen(): boolean { - return this.socket?.readyState === WebSocket.OPEN + return this.socket?.readyState === NodeWebSocket.OPEN } /** Attempt to resume the previous shards session with the gateway. */ @@ -282,7 +286,7 @@ export class DiscordenoShard { } /** Handle a gateway connection close. */ - async handleClose(close: WebSocket.CloseEvent): Promise { + async handleClose(close: NodeWebSocket.CloseEvent): Promise { // gateway.debug("GW CLOSED", { shardId, payload: event }); this.stopHeartbeating() @@ -485,7 +489,7 @@ export class DiscordenoShard { } /** Handle an incoming gateway message. */ - async handleMessage(message: WebSocket.MessageEvent): Promise { + async handleMessage(message: NodeWebSocket.MessageEvent): Promise { let preProcessMessage = message.data // If message compression is enabled, diff --git a/packages/gateway/src/manager.ts b/packages/gateway/src/manager.ts index edaf9d132..81d5db3cc 100644 --- a/packages/gateway/src/manager.ts +++ b/packages/gateway/src/manager.ts @@ -5,17 +5,15 @@ import Shard from './Shard.js' import type { ShardEvents, StatusUpdate, UpdateVoiceState } from './types.js' export function createGatewayManager(options: CreateGatewayManagerOptions): GatewayManager { - if (!options.connection) { - options.connection = { - url: 'wss://gateway.discord.gg', - shards: 1, - sessionStartLimit: { - maxConcurrency: 1, - remaining: 1000, - total: 1000, - resetAfter: 1000 * 60 * 60 * 24, - }, - } + const connectionOptions = options.connection ?? { + url: 'wss://gateway.discord.gg', + shards: 1, + sessionStartLimit: { + maxConcurrency: 1, + remaining: 1000, + total: 1000, + resetAfter: 1000 * 60 * 60 * 24, + }, } const gateway: GatewayManager = { @@ -28,11 +26,11 @@ export function createGatewayManager(options: CreateGatewayManagerOptions): Gate device: options.properties?.device ?? 'Discordeno', }, token: options.token, - url: options.url ?? options.connection.url ?? 'wss://gateway.discord.gg', + url: options.url ?? connectionOptions.url ?? 'wss://gateway.discord.gg', version: options.version ?? 10, - connection: options.connection, - totalShards: options.totalShards ?? options.connection.shards ?? 1, - lastShardId: options.lastShardId ?? (options.totalShards ? options.totalShards - 1 : (options.connection ? options.connection.shards - 1 : 0)), + connection: connectionOptions, + totalShards: options.totalShards ?? connectionOptions.shards ?? 1, + lastShardId: options.lastShardId ?? (options.totalShards ? options.totalShards - 1 : (connectionOptions ? connectionOptions.shards - 1 : 0)), firstShardId: options.firstShardId ?? 0, totalWorkers: options.totalWorkers ?? 4, shardsPerWorker: options.shardsPerWorker ?? 25, diff --git a/packages/rest/src/manager.ts b/packages/rest/src/manager.ts index b519a449d..6156f6d47 100644 --- a/packages/rest/src/manager.ts +++ b/packages/rest/src/manager.ts @@ -1,6 +1,6 @@ /* eslint-disable @typescript-eslint/restrict-template-expressions */ /* eslint-disable no-const-assign */ -import { calculateBits, camelToSnakeCase, camelize, delay, getBotIdFromToken, logger, processReactionString, urlToBase64 } from '@discordeno/utils' +import { calculateBits, camelToSnakeCase, camelize, delay, getBotIdFromToken, logger, processReactionString, urlToBase64, snakelize } from '@discordeno/utils' import { createInvalidRequestBucket } from './invalidBucket.js' import { Queue } from './queue.js' @@ -126,10 +126,10 @@ export function createRestManager(options: CreateRestManagerOptions): RestManage case 'permissions': case 'allow': case 'deny': - newObj[key] = calculateBits(value) + newObj[key] = typeof value === 'string' ? value : calculateBits(value) continue case 'defaultMemberPermissions': - newObj.default_member_permissions = calculateBits(value) + newObj.default_member_permissions = typeof value === 'string' ? value : calculateBits(value) continue case 'nameLocalizations': newObj.name_localizations = value @@ -175,7 +175,7 @@ export function createRestManager(options: CreateRestManagerOptions): RestManage form.append(`file${i}`, options.files[i].blob, options.files[i].name) } - form.append('payload_json', JSON.stringify({ ...options.body, files: undefined })) + form.append('payload_json', JSON.stringify(snakelize({ ...options.body, files: undefined }))) body = form @@ -777,7 +777,7 @@ export function createRestManager(options: CreateRestManagerOptions): RestManage }, async editMessage(channelId, messageId, body) { - return await rest.patch(rest.routes.channels.message(channelId, messageId), { body }) + return await rest.patch(rest.routes.channels.message(channelId, messageId), { body, files: body.files }) }, async editOriginalInteractionResponse(token, body) { @@ -1226,6 +1226,32 @@ export function createRestManager(options: CreateRestManagerOptions): RestManage async upsertGuildApplicationCommands(guildId, body) { return await rest.put(rest.routes.interactions.commands.guilds.all(rest.applicationId, guildId), { body }) }, + + preferSnakeCase(enabled: boolean) { + const camelizer = enabled ? (x: any) => x : camelize + + rest.get = async (url, options) => { + return camelizer(await rest.makeRequest('GET', url, options)) + } + + rest.post = async (url: string, options?: Omit) => { + return camelizer(await rest.makeRequest('POST', url, options)) + } + + rest.delete = async (url: string, options?: Omit) => { + camelizer(await rest.makeRequest('DELETE', url, options)) + } + + rest.patch = async (url: string, options?: Omit) => { + return camelizer(await rest.makeRequest('PATCH', url, options)) + } + + rest.put = async (url: string, options?: Omit) => { + return camelizer(await rest.makeRequest('PUT', url, options)) + } + + return rest + }, } return rest diff --git a/packages/rest/src/types.ts b/packages/rest/src/types.ts index 895b013e7..b66cb484a 100644 --- a/packages/rest/src/types.ts +++ b/packages/rest/src/types.ts @@ -160,6 +160,8 @@ export interface RestManager { invalidBucket: InvalidRequestBucket /** The routes that are available for this manager. */ routes: RestRoutes + /** Whether or not the rest manager should keep objects in raw snake case from discord. */ + preferSnakeCase: (enabled: boolean) => RestManager; /** Check the rate limits for a url or a bucket. */ checkRateLimits: (url: string) => number | false /** Reshapes and modifies the obj as needed to make it ready for discords api. */ diff --git a/packages/rest/tests/e2e/message.spec.ts b/packages/rest/tests/e2e/message.spec.ts index b2019e720..fdc7959f0 100644 --- a/packages/rest/tests/e2e/message.spec.ts +++ b/packages/rest/tests/e2e/message.spec.ts @@ -59,6 +59,26 @@ describe('Send a message', () => { expect(fileMsg.id).not.equals(undefined); expect(fileMsg.content).equals('222'); expect(fileMsg.attachments.length).equals(1); + expect(fileMsg.attachments.at(0)?.filename).equals('application.txt'); + expect(fileMsg.attachments.at(0)?.size).equals(11); + + const txtFile2 = new Blob(['hello world edit'], { type: 'text/plain' }); + + const edited = await rest.editMessage(e2ecache.channel.id, fileMsg.id, { + content: '222 edit', + files: [ + { + name: 'application_edit.txt', + blob: txtFile2, + }, + ], + }); + + expect(edited.id).not.equals(undefined); + expect(edited.content).equals('222 edit'); + expect(edited.attachments.length).equals(1); + expect(edited.attachments.at(0)?.filename).equals('application_edit.txt'); + expect(edited.attachments.at(0)?.size).equals(16); }) }) diff --git a/packages/rest/tests/e2e/misc.spec.ts b/packages/rest/tests/e2e/misc.spec.ts index 378659961..c76c10c59 100644 --- a/packages/rest/tests/e2e/misc.spec.ts +++ b/packages/rest/tests/e2e/misc.spec.ts @@ -1,4 +1,3 @@ -import { expect } from 'chai' import { describe } from 'mocha' import { e2ecache, rest } from './utils.js' @@ -9,6 +8,7 @@ describe('Typings', () => { }) }) +/* TODO: Add this back when bot's name is changed (https://discord.com/channels/785384884197392384/785384884197392387/1142474846811459776) describe('Commands', () => { it('Upsert global commands', async () => { await rest.upsertGlobalApplicationCommands([ @@ -37,3 +37,4 @@ describe('Commands', () => { expect(rest.getGlobalApplicationCommand(created!.id)).to.throw }) }) +*/ diff --git a/packages/rest/tests/e2e/user.spec.ts b/packages/rest/tests/e2e/user.spec.ts index b388ae165..2ec8b3b36 100644 --- a/packages/rest/tests/e2e/user.spec.ts +++ b/packages/rest/tests/e2e/user.spec.ts @@ -32,7 +32,7 @@ describe('Get a user from the api', () => { }) it('Has a valid discriminator', () => { - expect(user.discriminator.length).to.be.equal(4) + expect(user.discriminator.length).to.be.oneOf([1,4]) }) it('Has been camelized', () => { diff --git a/packages/types/src/discord.ts b/packages/types/src/discord.ts index ca613ea98..3aa2d6ee8 100644 --- a/packages/types/src/discord.ts +++ b/packages/types/src/discord.ts @@ -46,6 +46,8 @@ import type { export interface DiscordUser { /** The user's username, not unique across the platform */ username: string + /** The user's display name, if it is set. For bots, this is the application name */ + global_name: string | null /** The user's chosen language option */ locale?: string /** The flags on a user's account */ @@ -58,7 +60,7 @@ export interface DiscordUser { accent_color?: number /** The user's id */ id: string - /** The user's 4-digit discord-tag */ + /** The user's discord-tag */ discriminator: string /** The user's avatar hash */ avatar: string | null @@ -264,8 +266,8 @@ export interface DiscordTeamMember { permissions: Array<'*'> /** The id of the parent team of which they are a member */ team_id: string - /** The avatar, discriminator, id, and username of the user */ - user: Partial & Pick + /** The avatar, discriminator, id, username, and global_name of the user */ + user: Partial & Pick } /** https://discord.com/developers/docs/topics/gateway#webhooks-update-webhook-update-event-fields */ @@ -2020,6 +2022,8 @@ export interface DiscordMessageReactionAdd { member?: DiscordMemberWithUser /** The emoji used to react */ emoji: Partial + /** The id of the author of this message */ + message_author_id?: string } /** https://discord.com/developers/docs/topics/gateway#voice-server-update */ diff --git a/packages/types/src/discordeno.ts b/packages/types/src/discordeno.ts index 8c88d9e2b..3a8501174 100644 --- a/packages/types/src/discordeno.ts +++ b/packages/types/src/discordeno.ts @@ -348,7 +348,7 @@ export interface GetBans { /** https://discord.com/developers/docs/resources/guild#list-guild-members */ export interface ListGuildMembers { - /** Max number of members to return (1-1000). Default: 1000 */ + /** Max number of members to return (1-1000). Default: 1 */ limit?: number /** The highest user id in the previous page. Default: 0 */ after?: string @@ -853,7 +853,7 @@ export interface EditMessage { /** Edit the flags of the message (only `SUPPRESS_EMBEDS` can currently be set/unset) */ flags?: 4 | null /** The contents of the files being sent/edited */ - files?: FileContent[] | null + files?: FileContent[] /** Allowed mentions for the message */ allowedMentions?: AllowedMentions /** When specified (adding new attachments), attachments which are not provided in this list will be removed. */ diff --git a/packages/utils/src/bucket.ts b/packages/utils/src/bucket.ts index d633c5378..c23a61e75 100644 --- a/packages/utils/src/bucket.ts +++ b/packages/utils/src/bucket.ts @@ -35,9 +35,11 @@ export class LeakyBucket implements LeakyBucketOptions { this.used = this.refillAmount > this.used ? 0 : this.used - this.refillAmount // Reset the refillsAt timestamp since it just got refilled this.refillsAt = undefined + // Reset the timeoutId + clearTimeout(this.timeoutId) + this.timeoutId = undefined; if (this.used > 0) { - if (this.timeoutId) clearTimeout(this.timeoutId) this.timeoutId = setTimeout(() => { this.refillBucket() }, this.refillInterval) diff --git a/packages/utils/src/images.ts b/packages/utils/src/images.ts index 18fec0e7d..aca913851 100644 --- a/packages/utils/src/images.ts +++ b/packages/utils/src/images.ts @@ -41,7 +41,7 @@ export function avatarUrl( options?.size ?? 128, options?.format, ) - : `https://cdn.discordapp.com/embed/avatars/${Number(discriminator) % 5}.png` + : `https://cdn.discordapp.com/embed/avatars/${discriminator === '0' ? (BigInt(userId) >> BigInt(22)) % BigInt(6) : Number(discriminator) % 5}.png` } /** diff --git a/packages/utils/tests/interactions.spec.ts b/packages/utils/tests/interactions.spec.ts index 74bee08a0..94d40cce1 100644 --- a/packages/utils/tests/interactions.spec.ts +++ b/packages/utils/tests/interactions.spec.ts @@ -25,8 +25,8 @@ describe('Convert interaction to args', () => { version: 1, app_permissions: '', data: { - id: "", - name: "", + id: '', + name: '', type: ApplicationCommandTypes.ChatInput, }, }) @@ -91,12 +91,14 @@ describe('Convert interaction to args', () => { '123': { id: '123', username: '123', + global_name: '123', discriminator: '1234', avatar: null, }, '456': { id: '456', username: '456', + global_name: '456', discriminator: '4567', avatar: null, }, diff --git a/proxies/rest/Dockerfile b/proxies/rest/Dockerfile index a24811149..1d1b44ee2 100644 --- a/proxies/rest/Dockerfile +++ b/proxies/rest/Dockerfile @@ -1,4 +1,4 @@ -# we node 18 alpine 3.17 as base image +# we node 18 alpine 3.18 as base image # we use multi stage build in this file # deps: contain all dependencies including dev dependencies # builder: contains all compiled files @@ -6,7 +6,7 @@ # runner: the final image, with only the dependencies and compiled files # build only with the platform of the host machine, since it only uses for dev purposes -FROM --platform=$BUILDPLATFORM node:18.15.0-alpine3.17 AS deps +FROM --platform=$BUILDPLATFORM node:18.16.0-alpine3.18 AS deps WORKDIR /app # copy necessary for install dependencies COPY package.json yarn.lock ./ @@ -14,7 +14,7 @@ COPY package.json yarn.lock ./ RUN yarn install # build only with the platform of the host machine, since we just need its files -FROM --platform=$BUILDPLATFORM node:18.15.0-alpine3.17 AS builder +FROM --platform=$BUILDPLATFORM node:18.16.0-alpine3.18 AS builder # copy the dependencies (node_modules) from the deps image COPY --from=deps /app /app WORKDIR /app @@ -25,7 +25,7 @@ COPY .swcrc ./ # compile the files RUN yarn build -FROM node:18.15.0-alpine3.17 AS prod-deps +FROM node:18.16.0-alpine3.18 AS prod-deps WORKDIR /app # copy necessary files for install dependencies COPY package.json yarn.lock .yarnrc.yml ./ @@ -35,7 +35,7 @@ RUN yarn plugin import workspace-tools # install prod dependencies RUN yarn workspaces focus --all --production -FROM node:18.15.0-alpine3.17 AS runner +FROM node:18.16.0-alpine3.18 AS runner # copy the compiled files from the builder image COPY --from=builder /app/dist /app/dist # copy the prod dependencies (node_modules) from the prod-deps image diff --git a/proxies/rest/yarn.lock b/proxies/rest/yarn.lock index 400d62810..9a195053a 100644 --- a/proxies/rest/yarn.lock +++ b/proxies/rest/yarn.lock @@ -1527,11 +1527,11 @@ __metadata: linkType: hard "semver@npm:^6.0.0": - version: 6.3.0 - resolution: "semver@npm:6.3.0" + version: 6.3.1 + resolution: "semver@npm:6.3.1" bin: - semver: ./bin/semver.js - checksum: 1b26ecf6db9e8292dd90df4e781d91875c0dcc1b1909e70f5d12959a23c7eebb8f01ea581c00783bbee72ceeaad9505797c381756326073850dc36ed284b21b9 + semver: bin/semver.js + checksum: ae47d06de28836adb9d3e25f22a92943477371292d9b665fb023fae278d345d508ca1958232af086d85e0155aee22e313e100971898bbb8d5d89b8b1d4054ca2 languageName: node linkType: hard diff --git a/website/package-lock.json b/website/package-lock.json index 92a0e4cdf..d24c741fd 100644 --- a/website/package-lock.json +++ b/website/package-lock.json @@ -2102,9 +2102,9 @@ } }, "node_modules/@docusaurus/core/node_modules/semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "dependencies": { "lru-cache": "^6.0.0" }, @@ -3033,9 +3033,9 @@ } }, "node_modules/@docusaurus/theme-common/node_modules/semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "peer": true, "dependencies": { "lru-cache": "^6.0.0" @@ -3645,9 +3645,9 @@ } }, "node_modules/@mdx-js/mdx/node_modules/semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", "bin": { "semver": "bin/semver" } @@ -4633,9 +4633,9 @@ } }, "node_modules/@typescript-eslint/eslint-plugin/node_modules/semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "dev": true, "dependencies": { "lru-cache": "^6.0.0" @@ -4777,9 +4777,9 @@ } }, "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "dev": true, "dependencies": { "lru-cache": "^6.0.0" @@ -4836,9 +4836,9 @@ } }, "node_modules/@typescript-eslint/utils/node_modules/semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "dev": true, "dependencies": { "lru-cache": "^6.0.0" @@ -5808,9 +5808,9 @@ } }, "node_modules/builtins/node_modules/semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "dev": true, "dependencies": { "lru-cache": "^6.0.0" @@ -6680,9 +6680,9 @@ } }, "node_modules/css-loader/node_modules/semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "dependencies": { "lru-cache": "^6.0.0" }, @@ -7786,9 +7786,9 @@ } }, "node_modules/eslint-plugin-n/node_modules/semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "dev": true, "dependencies": { "lru-cache": "^6.0.0" @@ -8818,9 +8818,9 @@ } }, "node_modules/fork-ts-checker-webpack-plugin/node_modules/semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "dependencies": { "lru-cache": "^6.0.0" }, @@ -11917,9 +11917,9 @@ } }, "node_modules/postcss-loader/node_modules/semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "dependencies": { "lru-cache": "^6.0.0" }, @@ -13237,9 +13237,9 @@ } }, "node_modules/remark-mdx/node_modules/semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", "bin": { "semver": "bin/semver" } @@ -13702,9 +13702,9 @@ } }, "node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "bin": { "semver": "bin/semver.js" } @@ -15246,9 +15246,9 @@ } }, "node_modules/update-notifier/node_modules/semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "dependencies": { "lru-cache": "^6.0.0" }, @@ -16205,9 +16205,9 @@ "integrity": "sha512-JcKqAHLPxcdb9KM49dufGXn2x3ssnfjbcaQdLlfZsL9rH9wgDQjUtDxbo8NE0F6SFvydeu1VhZe7hZuHsB2/pw==" }, "node_modules/word-wrap": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", - "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.4.tgz", + "integrity": "sha512-2V81OA4ugVo5pRo46hAoD2ivUJx8jXmWXfUkY4KFNw0hEptvN0QfH3K4nHiwzGeKl5rFKedV48QVoqYavy4YpA==", "devOptional": true, "engines": { "node": ">=0.10.0" diff --git a/website/src/components/home/reviews/index.tsx b/website/src/components/home/reviews/index.tsx index 706da1603..fa4cd1c08 100644 --- a/website/src/components/home/reviews/index.tsx +++ b/website/src/components/home/reviews/index.tsx @@ -44,7 +44,7 @@ const reviewList: IReview[] = [ 'https://cdn.discordapp.com/avatars/1032699319368814652/8abbc5911333d3df288ff962a2120d75.png', invite_url: 'https://discord.com/oauth2/authorize?client_id=1032699319368814652&permissions=274877959232&scope=bot%20applications.commands', - guild_count: 50000, + guild_count: 64000, }, developer: { username: '8au', @@ -66,7 +66,7 @@ const reviewList: IReview[] = [ 'https://cdn.discordapp.com/avatars/853327905357561948/a394518e742643f05cc201249d3ae75e.png', invite_url: 'https://discord.com/oauth2/authorize?client_id=853327905357561948&scope=bot&permissions=534925798592', - guild_count: 82000, + guild_count: 100000, }, developer: { username: '8au', diff --git a/website/yarn.lock b/website/yarn.lock index 8c5e7aa14..07326075b 100644 --- a/website/yarn.lock +++ b/website/yarn.lock @@ -10737,11 +10737,11 @@ __metadata: linkType: hard "semver@npm:^5.4.1": - version: 5.7.1 - resolution: "semver@npm:5.7.1" + version: 5.7.2 + resolution: "semver@npm:5.7.2" bin: - semver: ./bin/semver - checksum: 57fd0acfd0bac382ee87cd52cd0aaa5af086a7dc8d60379dfe65fea491fb2489b6016400813930ecd61fd0952dae75c115287a1b16c234b1550887117744dfaf + semver: bin/semver + checksum: fb4ab5e0dd1c22ce0c937ea390b4a822147a9c53dbd2a9a0132f12fe382902beef4fbf12cf51bb955248d8d15874ce8cd89532569756384f994309825f10b686 languageName: node linkType: hard @@ -10754,18 +10754,7 @@ __metadata: languageName: node linkType: hard -"semver@npm:^7.0.0, semver@npm:^7.3.2, semver@npm:^7.3.4, semver@npm:^7.3.7, semver@npm:^7.3.8": - version: 7.3.8 - resolution: "semver@npm:7.3.8" - dependencies: - lru-cache: ^6.0.0 - bin: - semver: bin/semver.js - checksum: ba9c7cbbf2b7884696523450a61fee1a09930d888b7a8d7579025ad93d459b2d1949ee5bbfeb188b2be5f4ac163544c5e98491ad6152df34154feebc2cc337c1 - languageName: node - linkType: hard - -"semver@npm:^7.3.5": +"semver@npm:^7.0.0, semver@npm:^7.3.2, semver@npm:^7.3.4, semver@npm:^7.3.5, semver@npm:^7.3.7, semver@npm:^7.3.8": version: 7.4.0 resolution: "semver@npm:7.4.0" dependencies: @@ -12419,9 +12408,9 @@ __metadata: linkType: hard "word-wrap@npm:^1.2.3": - version: 1.2.3 - resolution: "word-wrap@npm:1.2.3" - checksum: 30b48f91fcf12106ed3186ae4fa86a6a1842416df425be7b60485de14bec665a54a68e4b5156647dec3a70f25e84d270ca8bc8cd23182ed095f5c7206a938c1f + version: 1.2.4 + resolution: "word-wrap@npm:1.2.4" + checksum: 8f1f2e0a397c0e074ca225ba9f67baa23f99293bc064e31355d426ae91b8b3f6b5f6c1fc9ae5e9141178bb362d563f55e62fd8d5c31f2a77e3ade56cb3e35bd1 languageName: node linkType: hard diff --git a/yarn.lock b/yarn.lock index 55c1a4ff7..427811e33 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4489,11 +4489,11 @@ __metadata: linkType: hard "semver@npm:^6.0.0, semver@npm:^6.3.0": - version: 6.3.0 - resolution: "semver@npm:6.3.0" + version: 6.3.1 + resolution: "semver@npm:6.3.1" bin: - semver: ./bin/semver.js - checksum: 1b26ecf6db9e8292dd90df4e781d91875c0dcc1b1909e70f5d12959a23c7eebb8f01ea581c00783bbee72ceeaad9505797c381756326073850dc36ed284b21b9 + semver: bin/semver.js + checksum: ae47d06de28836adb9d3e25f22a92943477371292d9b665fb023fae278d345d508ca1958232af086d85e0155aee22e313e100971898bbb8d5d89b8b1d4054ca2 languageName: node linkType: hard @@ -5383,9 +5383,9 @@ __metadata: linkType: hard "word-wrap@npm:^1.2.3": - version: 1.2.3 - resolution: "word-wrap@npm:1.2.3" - checksum: 30b48f91fcf12106ed3186ae4fa86a6a1842416df425be7b60485de14bec665a54a68e4b5156647dec3a70f25e84d270ca8bc8cd23182ed095f5c7206a938c1f + version: 1.2.4 + resolution: "word-wrap@npm:1.2.4" + checksum: 8f1f2e0a397c0e074ca225ba9f67baa23f99293bc064e31355d426ae91b8b3f6b5f6c1fc9ae5e9141178bb362d563f55e62fd8d5c31f2a77e3ade56cb3e35bd1 languageName: node linkType: hard