mirror of
https://github.com/discordeno/discordeno.git
synced 2026-09-17 08:47:22 +00:00
Merge branch 'main' of https://github.com/discordeno/discordeno into main
This commit is contained in:
@@ -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
|
||||
|
||||
+1
-1
@@ -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)
|
||||
|
||||
+15
-10
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -3,5 +3,11 @@ import type { Bot } from '../../bot.js'
|
||||
|
||||
export async function handleGuildDelete(bot: Bot, data: DiscordGatewayPayload, shardId: number): Promise<void> {
|
||||
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)
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -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>): Transformers
|
||||
},
|
||||
user: {
|
||||
username: false,
|
||||
globalName: false,
|
||||
locale: false,
|
||||
flags: false,
|
||||
premiumType: false,
|
||||
|
||||
@@ -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':
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -16,7 +16,6 @@ const baseMessage: Partial<Message> & 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)
|
||||
|
||||
@@ -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':
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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<void> {
|
||||
async handleClose(close: NodeWebSocket.CloseEvent): Promise<void> {
|
||||
// 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<void> {
|
||||
async handleMessage(message: NodeWebSocket.MessageEvent): Promise<void> {
|
||||
let preProcessMessage = message.data
|
||||
|
||||
// If message compression is enabled,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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<DiscordMessage>(rest.routes.channels.message(channelId, messageId), { body })
|
||||
return await rest.patch<DiscordMessage>(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<DiscordApplicationCommand[]>(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<CreateRequestBodyOptions, 'body' | 'method'>) => {
|
||||
return camelizer(await rest.makeRequest('POST', url, options))
|
||||
}
|
||||
|
||||
rest.delete = async (url: string, options?: Omit<CreateRequestBodyOptions, 'body' | 'method'>) => {
|
||||
camelizer(await rest.makeRequest('DELETE', url, options))
|
||||
}
|
||||
|
||||
rest.patch = async (url: string, options?: Omit<CreateRequestBodyOptions, 'body' | 'method'>) => {
|
||||
return camelizer(await rest.makeRequest('PATCH', url, options))
|
||||
}
|
||||
|
||||
rest.put = async (url: string, options?: Omit<CreateRequestBodyOptions, 'body' | 'method'>) => {
|
||||
return camelizer(await rest.makeRequest('PUT', url, options))
|
||||
}
|
||||
|
||||
return rest
|
||||
},
|
||||
}
|
||||
|
||||
return rest
|
||||
|
||||
@@ -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. */
|
||||
|
||||
@@ -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);
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
@@ -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
|
||||
})
|
||||
})
|
||||
*/
|
||||
|
||||
@@ -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', () => {
|
||||
|
||||
@@ -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<DiscordUser> & Pick<DiscordUser, 'avatar' | 'discriminator' | 'id' | 'username'>
|
||||
/** The avatar, discriminator, id, username, and global_name of the user */
|
||||
user: Partial<DiscordUser> & Pick<DiscordUser, 'avatar' | 'discriminator' | 'id' | 'username' | 'global_name'>
|
||||
}
|
||||
|
||||
/** 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<DiscordEmoji>
|
||||
/** The id of the author of this message */
|
||||
message_author_id?: string
|
||||
}
|
||||
|
||||
/** https://discord.com/developers/docs/topics/gateway#voice-server-update */
|
||||
|
||||
@@ -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. */
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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`
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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,
|
||||
},
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
Generated
+45
-45
@@ -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"
|
||||
|
||||
@@ -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',
|
||||
|
||||
+8
-19
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user