chore: close #2619

This commit is contained in:
H01001000
2022-12-02 13:18:03 +08:00
parent 4154a9bbdc
commit 1f89abfa4a
24 changed files with 328 additions and 204 deletions

View File

@@ -4,7 +4,8 @@
"private": true,
"workspaces": [
"packages/*",
"packages/plugins/cache"
"packages/plugins/cache",
"packages/plugins/utils"
],
"scripts": {
"build": "turbo run build",
@@ -31,12 +32,10 @@
"lint-staged": {
"*": "prettier --ignore-unknown --write",
"*.ts": [
"eslint --fix --config ./packages/eslint-config-discordeno/index.js --resolve-plugins-relative-to .",
"git add"
"eslint --fix --config ./packages/eslint-config-discordeno/index.js --resolve-plugins-relative-to ."
],
"*.js": [
"eslint --fix --config ./packages/eslint-config-discordeno/index.js --resolve-plugins-relative-to .",
"git add"
"eslint --fix --config ./packages/eslint-config-discordeno/index.js --resolve-plugins-relative-to ."
]
},
"packageManager": "yarn@3.3.0"

View File

@@ -1,31 +0,0 @@
{
"minify": true,
"jsc": {
"parser": {
"syntax": "typescript",
"decorators": true,
"dynamicImport": true
},
"transform": {
"legacyDecorator": true,
"decoratorMetadata": true
},
"target": "es2022",
"keepClassNames": true,
"loose": true,
"minify": {
"compress": {
"unused": true
},
"mangle": true
}
},
"module": {
"type": "es6",
"strict": false,
"strictMode": true,
"lazy": false,
"noInterop": false
},
"sourceMaps": "inline"
}

View File

@@ -1 +0,0 @@
# helpers-plugin

View File

@@ -1 +0,0 @@
export * from '../../index.js'

View File

@@ -1,104 +0,0 @@
import { BotWithCache } from '../cache/src/addCacheCollections.js'
import {
ApplicationCommandOptionChoice,
BigString,
Bot,
Channel,
Collection,
CreateMessage,
FinalHelpers,
InteractionResponse,
ListGuildMembers,
Member,
Message
} from './deps.js'
import { cloneChannel } from './src/channels.js'
import { disconnectMember } from './src/disconnectMember.js'
import { fetchAndRetrieveMembers } from './src/fetchAndRetrieveMembers.js'
import { getMembersPaginated } from './src/getMembersPaginated.js'
import { moveMember } from './src/moveMember.js'
import { sendAutocompleteChoices } from './src/sendAutoCompleteChoices.js'
import { sendDirectMessage } from './src/sendDirectMessage.js'
import { sendPrivateInteractionResponse } from './src/sendPrivateInteractionResponse.js'
import { sendTextMessage } from './src/sendTextMessage.js'
import { suppressEmbeds } from './src/suppressEmbeds.js'
import { archiveThread, editThread, lockThread, ModifyThread, unarchiveThread, unlockThread } from './src/threads.js'
export type BotWithHelpersPlugin<B extends Bot = Bot> = Omit<B, 'helpers'> & HelperFunctionsFromHelperPlugin
export interface HelperFunctionsFromHelperPlugin {
helpers: FinalHelpers & {
fetchAndRetrieveMembers: (guildId: BigString) => Promise<Collection<bigint, Member>>
sendDirectMessage: (userId: BigString, content: string | CreateMessage) => Promise<Message>
sendTextMessage: (channelId: BigString, content: string | CreateMessage) => Promise<Message>
sendPrivateInteractionResponse: (
id: BigString,
token: string,
options: InteractionResponse,
) => Promise<void>
suppressEmbeds: (channelId: BigString, messageId: BigString) => Promise<Message>
archiveThread: (threadId: BigString) => Promise<Channel>
unarchiveThread: (threadId: BigString) => Promise<Channel>
lockThread: (threadId: BigString) => Promise<Channel>
unlockThread: (threadId: BigString) => Promise<Channel>
editThread: (threadId: BigString, options: ModifyThread, reason?: string) => Promise<Channel>
cloneChannel: (channel: Channel, reason?: string) => Promise<Channel>
sendAutocompleteChoices: (
interactionId: BigString,
interactionToken: string,
choices: ApplicationCommandOptionChoice[],
) => Promise<void>
disconnectMember: (guildId: BigString, memberId: BigString) => Promise<Member>
getMembersPaginated: (guildId: BigString, options: ListGuildMembers) => Promise<Collection<bigint, Member>>
moveMember: (guildId: BigString, memberId: BigString, channelId: BigString) => Promise<Member>
}
}
export function enableHelpersPlugin<B extends Bot = Bot> (rawBot: B): BotWithHelpersPlugin<B> {
// FORCE OVERRIDE THE TYPE SO WE CAN SETUP FUNCTIONS
const bot = rawBot as unknown as BotWithHelpersPlugin
bot.helpers.fetchAndRetrieveMembers = async (guildId: BigString) =>
await fetchAndRetrieveMembers(bot as unknown as BotWithCache, guildId)
bot.helpers.sendDirectMessage = async (userId: BigString, content: string | CreateMessage) =>
await sendDirectMessage(bot, userId, content)
bot.helpers.sendTextMessage = async (channelId: BigString, content: string | CreateMessage) =>
await sendTextMessage(bot, channelId, content)
bot.helpers.sendPrivateInteractionResponse = async (id: BigString, token: string, options: InteractionResponse) =>
await sendPrivateInteractionResponse(bot, id, token, options)
bot.helpers.suppressEmbeds = async (channelId: BigString, messageId: BigString) =>
await suppressEmbeds(bot, channelId, messageId)
bot.helpers.archiveThread = async (threadId: BigString) => await archiveThread(bot, threadId)
bot.helpers.unarchiveThread = async (threadId: BigString) => await unarchiveThread(bot, threadId)
bot.helpers.lockThread = async (threadId: BigString) => await lockThread(bot, threadId)
bot.helpers.unlockThread = async (threadId: BigString) => await unlockThread(bot, threadId)
bot.helpers.editThread = async (threadId: BigString, options: ModifyThread, reason?: string) =>
await editThread(bot, threadId, options, reason)
bot.helpers.cloneChannel = async (channel: Channel, reason?: string) => await cloneChannel(bot, channel, reason)
bot.helpers.sendAutocompleteChoices = async (
interactionId: BigString,
interactionToken: string,
choices: ApplicationCommandOptionChoice[]
) => await sendAutocompleteChoices(bot, interactionId, interactionToken, choices)
bot.helpers.disconnectMember = async (guildId: BigString, memberId: BigString) => await disconnectMember(bot, guildId, memberId)
bot.helpers.getMembersPaginated = async (guildId: BigString, options: ListGuildMembers) =>
await getMembersPaginated(bot, guildId, options)
bot.helpers.moveMember = async (guildId: BigString, memberId: BigString, channelId: BigString) =>
await moveMember(bot, guildId, memberId, channelId)
return bot as BotWithHelpersPlugin<B>
}
// EXPORT EVERYTHING HERE SO USERS CAN OPT TO USE FUNCTIONS DIRECTLY
export * from './src/channels.js'
export * from './src/disconnectMember.js'
export * from './src/fetchAndRetrieveMembers.js'
export * from './src/getMembersPaginated.js'
export * from './src/moveMember.js'
export * from './src/sendAutoCompleteChoices.js'
export * from './src/sendDirectMessage.js'
export * from './src/sendPrivateInteractionResponse.js'
export * from './src/sendTextMessage.js'
export * from './src/suppressEmbeds.js'
export * from './src/threads.js'
export default enableHelpersPlugin

View File

@@ -1,6 +0,0 @@
import { BigString, Bot } from '../deps.js'
/** Kicks a member from a voice channel */
export async function disconnectMember (bot: Bot, guildId: BigString, memberId: BigString) {
return await bot.helpers.editMember(guildId, memberId, { channelId: null })
}

View File

@@ -1,16 +0,0 @@
{
"extends": "tsconfig/base.json",
"compilerOptions": {
"outDir": "./dist",
},
"include": [
"./src/**/*.ts",
"./src/**/*.tsx"
],
"exclude": [
"node_modules",
"dist",
"test",
"tests"
]
}

View File

@@ -0,0 +1,31 @@
{
"minify": true,
"jsc": {
"parser": {
"syntax": "typescript",
"decorators": true,
"dynamicImport": true
},
"transform": {
"legacyDecorator": true,
"decoratorMetadata": true
},
"target": "es2022",
"keepClassNames": true,
"loose": true,
"minify": {
"compress": {
"unused": true
},
"mangle": true
}
},
"module": {
"type": "es6",
"strict": false,
"strictMode": true,
"lazy": false,
"noInterop": false
},
"sourceMaps": "inline"
}

View File

@@ -0,0 +1 @@
# utils-plugin

View File

@@ -0,0 +1,170 @@
import {
ApplicationCommandOptionChoice,
BigString,
Bot,
Channel,
Collection,
CreateMessage,
FinalHelpers,
InteractionResponse,
ListGuildMembers,
Member,
Message
} from '@discordeno/bot'
import { BotWithCache } from '../cache/src/addCacheCollections.js'
import { cloneChannel } from './src/channels.js'
import { disconnectMember } from './src/disconnectMember.js'
import { fetchAndRetrieveMembers } from './src/fetchAndRetrieveMembers.js'
import { getMembersPaginated } from './src/getMembersPaginated.js'
import { moveMember } from './src/moveMember.js'
import { sendAutocompleteChoices } from './src/sendAutoCompleteChoices.js'
import { sendDirectMessage } from './src/sendDirectMessage.js'
import { sendPrivateInteractionResponse } from './src/sendPrivateInteractionResponse.js'
import { sendTextMessage } from './src/sendTextMessage.js'
import { suppressEmbeds } from './src/suppressEmbeds.js'
import {
archiveThread,
editThread,
lockThread,
ModifyThread,
unarchiveThread,
unlockThread
} from './src/threads.js'
export type BotWithUtilsPlugin<B extends Bot = Bot> = Omit<B, 'helpers'> &
HelperFunctionsFromHelperPlugin
export interface HelperFunctionsFromHelperPlugin {
helpers: FinalHelpers & {
fetchAndRetrieveMembers: (
guildId: BigString
) => Promise<Collection<bigint, Member>>
sendDirectMessage: (
userId: BigString,
content: string | CreateMessage
) => Promise<Message>
sendTextMessage: (
channelId: BigString,
content: string | CreateMessage
) => Promise<Message>
sendPrivateInteractionResponse: (
id: BigString,
token: string,
options: InteractionResponse
) => Promise<void>
suppressEmbeds: (
channelId: BigString,
messageId: BigString
) => Promise<Message>
archiveThread: (threadId: BigString) => Promise<Channel>
unarchiveThread: (threadId: BigString) => Promise<Channel>
lockThread: (threadId: BigString) => Promise<Channel>
unlockThread: (threadId: BigString) => Promise<Channel>
editThread: (
threadId: BigString,
options: ModifyThread,
reason?: string
) => Promise<Channel>
cloneChannel: (channel: Channel, reason?: string) => Promise<Channel>
sendAutocompleteChoices: (
interactionId: BigString,
interactionToken: string,
choices: ApplicationCommandOptionChoice[]
) => Promise<void>
disconnectMember: (
guildId: BigString,
memberId: BigString
) => Promise<Member>
getMembersPaginated: (
guildId: BigString,
options: ListGuildMembers
) => Promise<Collection<bigint, Member>>
moveMember: (
guildId: BigString,
memberId: BigString,
channelId: BigString
) => Promise<Member>
}
}
export function enableUtilsPlugin<B extends Bot = Bot> (
rawBot: B
): BotWithUtilsPlugin<B> {
// FORCE OVERRIDE THE TYPE SO WE CAN SETUP FUNCTIONS
const bot = rawBot as unknown as BotWithUtilsPlugin
bot.helpers.fetchAndRetrieveMembers = async (guildId: BigString) =>
await fetchAndRetrieveMembers(bot as unknown as BotWithCache, guildId)
bot.helpers.sendDirectMessage = async (
userId: BigString,
content: string | CreateMessage
) => await sendDirectMessage(bot, userId, content)
bot.helpers.sendTextMessage = async (
channelId: BigString,
content: string | CreateMessage
) => await sendTextMessage(bot, channelId, content)
bot.helpers.sendPrivateInteractionResponse = async (
id: BigString,
token: string,
options: InteractionResponse
) => await sendPrivateInteractionResponse(bot, id, token, options)
bot.helpers.suppressEmbeds = async (
channelId: BigString,
messageId: BigString
) => await suppressEmbeds(bot, channelId, messageId)
bot.helpers.archiveThread = async (threadId: BigString) =>
await archiveThread(bot, threadId)
bot.helpers.unarchiveThread = async (threadId: BigString) =>
await unarchiveThread(bot, threadId)
bot.helpers.lockThread = async (threadId: BigString) =>
await lockThread(bot, threadId)
bot.helpers.unlockThread = async (threadId: BigString) =>
await unlockThread(bot, threadId)
bot.helpers.editThread = async (
threadId: BigString,
options: ModifyThread,
reason?: string
) => await editThread(bot, threadId, options, reason)
bot.helpers.cloneChannel = async (channel: Channel, reason?: string) =>
await cloneChannel(bot, channel, reason)
bot.helpers.sendAutocompleteChoices = async (
interactionId: BigString,
interactionToken: string,
choices: ApplicationCommandOptionChoice[]
) =>
await sendAutocompleteChoices(
bot,
interactionId,
interactionToken,
choices
)
bot.helpers.disconnectMember = async (
guildId: BigString,
memberId: BigString
) => await disconnectMember(bot, guildId, memberId)
bot.helpers.getMembersPaginated = async (
guildId: BigString,
options: ListGuildMembers
) => await getMembersPaginated(bot, guildId, options)
bot.helpers.moveMember = async (
guildId: BigString,
memberId: BigString,
channelId: BigString
) => await moveMember(bot, guildId, memberId, channelId)
return bot as BotWithUtilsPlugin<B>
}
// EXPORT EVERYTHING HERE SO USERS CAN OPT TO USE FUNCTIONS DIRECTLY
export * from './src/channels.js'
export * from './src/disconnectMember.js'
export * from './src/fetchAndRetrieveMembers.js'
export * from './src/getMembersPaginated.js'
export * from './src/moveMember.js'
export * from './src/sendAutoCompleteChoices.js'
export * from './src/sendDirectMessage.js'
export * from './src/sendPrivateInteractionResponse.js'
export * from './src/sendTextMessage.js'
export * from './src/suppressEmbeds.js'
export * from './src/threads.js'
export default enableUtilsPlugin

View File

@@ -1,5 +1,5 @@
{
"name": "@discordeno/helpers-plugin",
"name": "@discordeno/utils-plugin",
"version": "18.0.0-alpha.1",
"main": "./dist/index.js",
"types": "./dist/index.d.ts",
@@ -14,15 +14,15 @@
"test-types": "tsc --noEmit"
},
"devDependencies": {
"@discordeno/bot": "18.0.0-alpha.1",
"@swc/cli": "^0.1.57",
"@swc/core": "^1.3.21",
"eslint": "^8.0.1",
"eslint-config-discordeno": "*",
"tsconfig": "*",
"@discordeno/types": "18.0.0-alpha.1",
"typescript": "^4.9.3"
},
"dependencies": {
"@types/node": "^18.11.9"
}
}
}

View File

@@ -1,7 +1,16 @@
import { Bot, Channel, CreateGuildChannel, separateOverwrites } from '../deps.js'
import {
Bot,
Channel,
CreateGuildChannel,
separateOverwrites
} from '@discordeno/bot'
/** Create a copy of a channel */
export async function cloneChannel (bot: Bot, channel: Channel, reason?: string) {
export async function cloneChannel (
bot: Bot,
channel: Channel,
reason?: string
): Promise<Channel> {
if (!channel.guildId) {
throw new Error('Cannot clone a channel outside a guild')
}
@@ -15,7 +24,7 @@ export async function cloneChannel (bot: Bot, channel: Channel, reason?: string)
parentId: channel.parentId,
nsfw: channel.nsfw,
name: channel.name!,
topic: channel.topic || undefined,
topic: channel.topic,
permissionOverwrites: channel.permissionOverwrites.map((overwrite) => {
const [type, id, allow, deny] = separateOverwrites(overwrite)
@@ -30,5 +39,5 @@ export async function cloneChannel (bot: Bot, channel: Channel, reason?: string)
}
// Create the channel (also handles permissions)
return await bot.helpers.createChannel(channel.guildId!, createChannelOptions)
return await bot.helpers.createChannel(channel.guildId, createChannelOptions)
}

View File

@@ -0,0 +1,10 @@
import { BigString, Bot, Member } from '@discordeno/bot'
/** Kicks a member from a voice channel */
export async function disconnectMember (
bot: Bot,
guildId: BigString,
memberId: BigString
): Promise<Member> {
return await bot.helpers.editMember(guildId, memberId, { channelId: null })
}

View File

@@ -1,15 +1,22 @@
import { BigString, Collection, Member } from '@discordeno/bot'
import { BotWithCache } from '../../cache/src/addCacheCollections.js'
import { BigString } from '../deps.js'
/** Fetch members for an entire guild then return the entire guilds cached members. */
export async function fetchAndRetrieveMembers (bot: BotWithCache, guildId: BigString) {
export async function fetchAndRetrieveMembers (
bot: BotWithCache,
guildId: BigString
): Promise<Collection<bigint, Member>> {
if (!bot.enabledPlugins?.has('CACHE')) {
throw new Error('The fetchAndRetrieveMembers function requires the CACHE plugin first.')
throw new Error(
'The fetchAndRetrieveMembers function requires the CACHE plugin first.'
)
}
const guild = bot.guilds.get(bot.transformers.snowflake(guildId))
if (guild == null) {
throw new Error('The guild was not found in cache. Unable to fetch members for uncached guild.')
throw new Error(
'The guild was not found in cache. Unable to fetch members for uncached guild.'
)
}
await bot.helpers.fetchMembers(guildId, { limit: 0 })

View File

@@ -1,4 +1,11 @@
import { BigString, Bot, Collection, DiscordMemberWithUser, ListGuildMembers, Member } from '../deps.js'
import {
BigString,
Bot,
Collection,
DiscordMemberWithUser,
ListGuildMembers,
Member
} from '@discordeno/bot'
/**
* Highly recommended to **NOT** use this function to get members instead use fetchMembers().
@@ -9,23 +16,19 @@ export async function getMembersPaginated (
bot: Bot,
guildId: BigString,
options: ListGuildMembers
) {
): Promise<any> {
const members = new Collection<bigint, Member>()
let membersLeft = options?.limit ?? 1000
let loops = 1
while (
(options?.limit ?? 1000) > members.size &&
membersLeft > 0
) {
while ((options?.limit ?? 1000) > members.size && membersLeft > 0) {
bot.events.debug('Running while loop in getMembers function.')
if (options?.limit && options.limit > 1000) {
console.log(
`Paginating get members from REST. #${loops} / ${Math.ceil(
(options?.limit ?? 1) / 1000
)
}`
)}`
)
}

View File

@@ -1,4 +1,4 @@
import { BigString, Bot } from '../deps.js'
import { BigString, Bot, Member } from '@discordeno/bot'
/**
* Move a member from a voice channel to another.
@@ -8,6 +8,6 @@ export async function moveMember (
guildId: BigString,
memberId: BigString,
channelId: BigString
) {
): Promise<Member> {
return await bot.helpers.editMember(guildId, memberId, { channelId })
}

View File

@@ -1,4 +1,9 @@
import { ApplicationCommandOptionChoice, BigString, Bot, InteractionResponseTypes } from '../deps.js'
import {
ApplicationCommandOptionChoice,
BigString,
Bot,
InteractionResponseTypes
} from '@discordeno/bot'
export async function sendAutocompleteChoices (
bot: Bot,

View File

@@ -1,4 +1,10 @@
import { BigString, Bot, Collection, CreateMessage } from '../deps.js'
import {
BigString,
Bot,
Collection,
CreateMessage,
Message
} from '@discordeno/bot'
/** Maps the <userId, channelId> for dm channels */
export const dmChannelIds = new Collection<BigString, BigString>()
@@ -8,16 +14,16 @@ export async function sendDirectMessage (
bot: Bot,
userId: BigString,
content: string | CreateMessage
) {
): Promise<Message> {
if (typeof content === 'string') content = { content }
// GET CHANNEL ID FROM CACHE OR CREATE THE CHANNEL FOR THIS USER
const cachedChannelId = dmChannelIds.get(userId)
// IF ID IS CACHED SEND MESSAGE DIRECTLY
if (cachedChannelId) return await bot.helpers.sendMessage(cachedChannelId, content)
if (cachedChannelId) { return await bot.helpers.sendMessage(cachedChannelId, content) }
// CREATE A NEW DM CHANNEL AND PLUCK ITS ID
const channel = (await bot.helpers.getDmChannel(userId))
const channel = await bot.helpers.getDmChannel(userId)
// CACHE IT FOR FUTURE REQUESTS
dmChannelIds.set(userId, channel.id)

View File

@@ -1,4 +1,4 @@
import type { BigString, Bot, InteractionResponse } from '../deps.js'
import type { BigString, Bot, InteractionResponse } from '@discordeno/bot'
/** sendInteractionResponse with ephemeral reply */
export async function sendPrivateInteractionResponse (
@@ -6,7 +6,7 @@ export async function sendPrivateInteractionResponse (
id: BigString,
token: string,
options: InteractionResponse
) {
if ((options.data) && !options.data?.flags) options.data.flags = 64 // private: true
): Promise<void> {
if (options.data && !options.data?.flags) options.data.flags = 64 // private: true
return await bot.helpers.sendInteractionResponse(id, token, options)
}

View File

@@ -1,11 +1,11 @@
import { BigString, Bot, CreateMessage } from '../deps.js'
import { BigString, Bot, CreateMessage, Message } from '@discordeno/bot'
/** Sends a text message. */
export async function sendTextMessage (
bot: Bot,
channelId: BigString,
content: string | CreateMessage
) {
): Promise<Message> {
if (typeof content === 'string') content = { content }
return await bot.helpers.sendMessage(channelId, content)
}

View File

@@ -1,11 +1,11 @@
import { BigString, Bot, DiscordMessage } from '../deps.js'
import { BigString, Bot, DiscordMessage, Message } from '@discordeno/bot'
/** Suppress all the embeds in this message */
export async function suppressEmbeds (
bot: Bot,
channelId: BigString,
messageId: BigString
) {
): Promise<Message> {
const result = await bot.rest.runMethod<DiscordMessage>(
bot.rest,
'PATCH',

View File

@@ -1,27 +1,44 @@
import { BigString, Bot, DiscordChannel } from '../deps.js'
import { BigString, Bot, Channel, DiscordChannel } from '@discordeno/bot'
/** Sets a thread channel to be archived. */
export async function archiveThread (bot: Bot, threadId: BigString) {
export async function archiveThread (
bot: Bot,
threadId: BigString
): Promise<Channel> {
return await editThread(bot, threadId, { archived: true })
}
/** Sets a thread channel to be unarchived. */
export async function unarchiveThread (bot: Bot, threadId: BigString) {
export async function unarchiveThread (
bot: Bot,
threadId: BigString
): Promise<Channel> {
return await editThread(bot, threadId, { archived: false })
}
/** Sets a thread channel to be locked. */
export async function lockThread (bot: Bot, threadId: BigString) {
export async function lockThread (
bot: Bot,
threadId: BigString
): Promise<Channel> {
return await editThread(bot, threadId, { locked: true })
}
/** Sets a thread channel to be unlocked. */
export async function unlockThread (bot: Bot, threadId: BigString) {
export async function unlockThread (
bot: Bot,
threadId: BigString
): Promise<Channel> {
return await editThread(bot, threadId, { locked: false })
}
/** Update a thread's settings. Requires the `MANAGE_CHANNELS` permission for the guild. */
export async function editThread (bot: Bot, threadId: BigString, options: ModifyThread, reason?: string) {
export async function editThread (
bot: Bot,
threadId: BigString,
options: ModifyThread,
reason?: string
): Promise<Channel> {
const result = await bot.rest.runMethod<DiscordChannel>(
bot.rest,
'PATCH',
@@ -38,7 +55,9 @@ export async function editThread (bot: Bot, threadId: BigString, options: Modify
return bot.transformers.channel(bot, {
channel: result,
guildId: result.guild_id ? bot.transformers.snowflake(result.guild_id) : undefined
guildId: result.guild_id
? bot.transformers.snowflake(result.guild_id)
: undefined
})
}

View File

@@ -0,0 +1,8 @@
{
"extends": "tsconfig/base.json",
"compilerOptions": {
"outDir": "./dist"
},
"include": ["./src/**/*.ts", "./src/**/*.tsx"],
"exclude": ["node_modules", "dist", "test", "tests"]
}

View File

@@ -110,6 +110,21 @@ __metadata:
languageName: unknown
linkType: soft
"@discordeno/utils-plugin@workspace:packages/plugins/utils":
version: 0.0.0-use.local
resolution: "@discordeno/utils-plugin@workspace:packages/plugins/utils"
dependencies:
"@discordeno/bot": 18.0.0-alpha.1
"@swc/cli": ^0.1.57
"@swc/core": ^1.3.21
"@types/node": ^18.11.9
eslint: ^8.0.1
eslint-config-discordeno: "*"
tsconfig: "*"
typescript: ^4.9.3
languageName: unknown
linkType: soft
"@discordeno/utils@18.0.0-alpha.1, @discordeno/utils@workspace:packages/utils":
version: 0.0.0-use.local
resolution: "@discordeno/utils@workspace:packages/utils"