11import type { APIApplicationCommand , APIApplicationCommandOption , ChatInputCommandInteraction , RESTGetAPIApplicationCommandsResult , RESTPatchAPIApplicationCommandResult , RESTPutAPIApplicationCommandsResult } from 'discord.js'
2+ import type { EffectScope } from 'vue'
23import type { NuxtDiscordOptions , SlashCommandOption , SlashCommandOptionType , SlashCommandReturnType , SlashCommandRuntime } from '../../../types'
34import process from 'node:process'
45import { ApplicationCommandOptionType , Events , Client as InternalClient , REST , Routes , SlashCommandBuilder } from 'discord.js'
56import { useNitroApp } from 'nitropack/runtime'
7+ import { effectScope , isRef } from 'vue'
68import { logger } from '../../logger'
9+ import { reply } from './reply'
710
811export interface DiscordClientErrorBase {
912 type : string
@@ -87,6 +90,8 @@ export class DiscordClient {
8790 this . #handleSlashCommand( interaction )
8891 } )
8992
93+ this . startScope ( )
94+
9095 const { resolve, promise } = Promise . withResolvers < undefined > ( )
9196
9297 this . #client. once ( Events . ClientReady , ( readyClient ) => {
@@ -105,6 +110,21 @@ export class DiscordClient {
105110 await this . #client. destroy ( )
106111 this . #client = null
107112 }
113+ this . stopScope ( )
114+ }
115+
116+ #scope?: EffectScope
117+ public startScope ( ) {
118+ if ( this . #scope)
119+ return
120+ this . #scope = effectScope ( /* detached */ true )
121+ }
122+
123+ public stopScope ( ) {
124+ if ( ! this . #scope)
125+ return
126+ this . #scope. stop ( )
127+ this . #scope = undefined
108128 }
109129
110130 public isReady ( ) : boolean {
@@ -147,6 +167,8 @@ export class DiscordClient {
147167 return this . #slashCommands. find ( cmd => cmd . name === name )
148168 }
149169
170+ #interactionScopes: WeakMap < ChatInputCommandInteraction , EffectScope > = new WeakMap ( )
171+ #commandFinalizationRegistry = new FinalizationRegistry ( ( scope : EffectScope ) => scope . stop ( ) )
150172 async #handleSlashCommand( interaction : ChatInputCommandInteraction ) : Promise < void > {
151173 const name = interaction . commandName
152174 const command = this . #slashCommands. find ( cmd => cmd . name === name )
@@ -205,10 +227,26 @@ export class DiscordClient {
205227 }
206228 }
207229
230+ let scope ! : EffectScope
231+ if ( this . #scope) {
232+ // this scope should be a child of the client scope
233+ this . #scope. run ( ( ) => ( scope = effectScope ( ) ) )
234+ }
235+ else {
236+ scope = effectScope ( )
237+ }
238+
239+ this . #interactionScopes. set ( interaction , scope )
240+ if ( import . meta. dev )
241+ this . #commandFinalizationRegistry. register ( command , scope )
242+
208243 try {
209- currentInteraction = interaction
210- const result = command . execute ! ( ...args )
211- currentInteraction = null
244+ let result ! : SlashCommandReturnType
245+ scope . run ( ( ) => {
246+ currentInteraction = interaction
247+ result = command . execute ! ( ...args )
248+ currentInteraction = null
249+ } )
212250
213251 if ( this . #clientOptions?. deferOnPromise && isPromise ( result ) ) {
214252 await interaction . deferReply ( )
@@ -242,18 +280,18 @@ export class DiscordClient {
242280 }
243281
244282 try {
245- if ( typeof result === 'string' ) {
246- if ( interaction . deferred || interaction . replied ) {
247- return interaction . editReply ( { content : result } )
283+ if ( typeof result === 'string' || isRef ( result ) ) {
284+ return this . #handleSlashCommandReturn( reply ( result ) , interaction , command )
285+ }
286+ else if ( typeof result === 'function' ) {
287+ const scope = this . #interactionScopes. get ( interaction )
288+ if ( ! scope ) {
289+ return result . call ( this , interaction , this )
248290 }
249291 else {
250- return interaction . reply ( { content : result } )
292+ return scope . run ( ( ) => result . call ( this , interaction , this ) )
251293 }
252294 }
253- else if ( typeof result === 'function' ) {
254- const newResult = result . call ( this , interaction , this )
255- return this . #handleSlashCommandReturn( newResult , interaction , command )
256- }
257295 else if ( Symbol . iterator in result && typeof result [ Symbol . iterator ] === 'function' ) {
258296 const gen = result [ Symbol . iterator ] ( )
259297 let next = gen . next ( )
0 commit comments