x
This commit is contained in:
		
						commit
						1738204406
					
				
					 3 changed files with 74 additions and 41 deletions
				
			
		|  | @ -1,7 +1,11 @@ | ||||||
| import { Guild } from '../structures/guild.ts' | import { Guild } from '../structures/guild.ts' | ||||||
| import { Interaction } from '../structures/slash.ts' | import { | ||||||
|  |   Interaction, | ||||||
|  |   InteractionApplicationCommandResolved | ||||||
|  | } from '../structures/slash.ts' | ||||||
| import { | import { | ||||||
|   InteractionPayload, |   InteractionPayload, | ||||||
|  |   InteractionResponsePayload, | ||||||
|   InteractionType, |   InteractionType, | ||||||
|   SlashCommandChoice, |   SlashCommandChoice, | ||||||
|   SlashCommandOption, |   SlashCommandOption, | ||||||
|  | @ -14,6 +18,7 @@ import { Client } from './client.ts' | ||||||
| import { RESTManager } from './rest.ts' | import { RESTManager } from './rest.ts' | ||||||
| import { SlashModule } from './slashModule.ts' | import { SlashModule } from './slashModule.ts' | ||||||
| import { verify as edverify } from 'https://deno.land/x/ed25519@1.0.1/mod.ts' | import { verify as edverify } from 'https://deno.land/x/ed25519@1.0.1/mod.ts' | ||||||
|  | import { User } from '../structures/user.ts' | ||||||
| 
 | 
 | ||||||
| export class SlashCommand { | export class SlashCommand { | ||||||
|   slash: SlashCommandsManager |   slash: SlashCommandsManager | ||||||
|  | @ -375,6 +380,7 @@ export interface SlashOptions { | ||||||
| const encoder = new TextEncoder() | const encoder = new TextEncoder() | ||||||
| const decoder = new TextDecoder('utf-8') | const decoder = new TextDecoder('utf-8') | ||||||
| 
 | 
 | ||||||
|  | /** Slash Client represents an Interactions Client which can be used without Harmony Client. */ | ||||||
| export class SlashClient { | export class SlashClient { | ||||||
|   id: string | (() => string) |   id: string | (() => string) | ||||||
|   client?: Client |   client?: Client | ||||||
|  | @ -539,16 +545,17 @@ export class SlashClient { | ||||||
|     return edverify(signature, fullBody, this.publicKey).catch(() => false) |     return edverify(signature, fullBody, this.publicKey).catch(() => false) | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   /** Verify [Deno Std HTTP Server Request](https://deno.land/std/http/server.ts) and return Interaction */ |   /** Verify [Deno Std HTTP Server Request](https://deno.land/std/http/server.ts) and return Interaction. **Data present in Interaction returned by this method is very different from actual typings as there is no real `Client` behind the scenes to cache things.** */ | ||||||
|   async verifyServerRequest(req: { |   async verifyServerRequest(req: { | ||||||
|     headers: Headers |     headers: Headers | ||||||
|     method: string |     method: string | ||||||
|     body: Deno.Reader |     body: Deno.Reader | ||||||
|     respond: (options: { |     respond: (options: { | ||||||
|       status?: number |       status?: number | ||||||
|  |       headers?: Headers | ||||||
|       body?: string | Uint8Array |       body?: string | Uint8Array | ||||||
|     }) => Promise<void> |     }) => Promise<void> | ||||||
|   }): Promise<boolean | Interaction> { |   }): Promise<false | Interaction> { | ||||||
|     if (req.method.toLowerCase() !== 'post') return false |     if (req.method.toLowerCase() !== 'post') return false | ||||||
| 
 | 
 | ||||||
|     const signature = req.headers.get('x-signature-ed25519') |     const signature = req.headers.get('x-signature-ed25519') | ||||||
|  | @ -561,7 +568,31 @@ export class SlashClient { | ||||||
| 
 | 
 | ||||||
|     try { |     try { | ||||||
|       const payload: InteractionPayload = JSON.parse(decoder.decode(rawbody)) |       const payload: InteractionPayload = JSON.parse(decoder.decode(rawbody)) | ||||||
|       const res = new Interaction(this as any, payload, {}) | 
 | ||||||
|  |       // TODO: Maybe fix all this hackery going on here?
 | ||||||
|  |       const res = new Interaction(this as any, payload, { | ||||||
|  |         // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
 | ||||||
|  |         user: new User(this as any, (payload.member?.user ?? payload.user)!), | ||||||
|  |         member: payload.member as any, | ||||||
|  |         guild: payload.guild_id as any, | ||||||
|  |         channel: payload.channel_id as any, | ||||||
|  |         resolved: ((payload.data | ||||||
|  |           ?.resolved as unknown) as InteractionApplicationCommandResolved) ?? { | ||||||
|  |           users: {}, | ||||||
|  |           members: {}, | ||||||
|  |           roles: {}, | ||||||
|  |           channels: {} | ||||||
|  |         } | ||||||
|  |       }) | ||||||
|  |       res._httpRespond = async (d: InteractionResponsePayload) => | ||||||
|  |         await req.respond({ | ||||||
|  |           status: 200, | ||||||
|  |           headers: new Headers({ | ||||||
|  |             'content-type': 'application/json' | ||||||
|  |           }), | ||||||
|  |           body: JSON.stringify(d) | ||||||
|  |         }) | ||||||
|  | 
 | ||||||
|       return res |       return res | ||||||
|     } catch (e) { |     } catch (e) { | ||||||
|       return false |       return false | ||||||
|  |  | ||||||
|  | @ -7,12 +7,14 @@ import { | ||||||
| } from '../types/channel.ts' | } from '../types/channel.ts' | ||||||
| import { INTERACTION_CALLBACK, WEBHOOK_MESSAGE } from '../types/endpoint.ts' | import { INTERACTION_CALLBACK, WEBHOOK_MESSAGE } from '../types/endpoint.ts' | ||||||
| import { | import { | ||||||
|  |   InteractionApplicationCommandData, | ||||||
|   InteractionApplicationCommandOption, |   InteractionApplicationCommandOption, | ||||||
|   InteractionChannelPayload, |   InteractionChannelPayload, | ||||||
|   InteractionPayload, |   InteractionPayload, | ||||||
|   InteractionResponseFlags, |   InteractionResponseFlags, | ||||||
|   InteractionResponsePayload, |   InteractionResponsePayload, | ||||||
|   InteractionResponseType, |   InteractionResponseType, | ||||||
|  |   InteractionType, | ||||||
|   SlashCommandOptionType |   SlashCommandOptionType | ||||||
| } from '../types/slash.ts' | } from '../types/slash.ts' | ||||||
| import { Dict } from '../utils/dict.ts' | import { Dict } from '../utils/dict.ts' | ||||||
|  | @ -26,7 +28,6 @@ import { Message } from './message.ts' | ||||||
| import { Role } from './role.ts' | import { Role } from './role.ts' | ||||||
| import { GuildTextChannel, TextChannel } from './textChannel.ts' | import { GuildTextChannel, TextChannel } from './textChannel.ts' | ||||||
| import { User } from './user.ts' | import { User } from './user.ts' | ||||||
| import { Webhook } from './webhook.ts' |  | ||||||
| 
 | 
 | ||||||
| interface WebhookMessageOptions extends MessageOptions { | interface WebhookMessageOptions extends MessageOptions { | ||||||
|   embeds?: Embed[] |   embeds?: Embed[] | ||||||
|  | @ -86,18 +87,30 @@ export class InteractionUser extends User { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export class Interaction extends SnowflakeBase { | export class Interaction extends SnowflakeBase { | ||||||
|   /** This will be `SlashClient` in case of `SlashClient#verifyServerRequest` */ |   /** Type of Interaction */ | ||||||
|   client!: Client |   type: InteractionType | ||||||
|   type: number |   /** Interaction Token */ | ||||||
|   token: string |   token: string | ||||||
|   /** Interaction ID */ |   /** Interaction ID */ | ||||||
|   id: string |   id: string | ||||||
|   data: InteractionData |   /** Data sent with Interaction. Only applies to Application Command */ | ||||||
|   channel: GuildTextChannel |   data?: InteractionApplicationCommandData | ||||||
|  |   /** Channel in which Interaction was initiated */ | ||||||
|  |   channel?: TextChannel | GuildTextChannel | ||||||
|  |   /** Guild in which Interaction was initiated */ | ||||||
|   guild?: Guild |   guild?: Guild | ||||||
|  |   /** Member object of who initiated the Interaction */ | ||||||
|   member?: Member |   member?: Member | ||||||
|   _savedHook?: Webhook |   /** User object of who invoked Interaction */ | ||||||
|   _respond?: (data: InteractionResponsePayload) => unknown |   user: User | ||||||
|  |   /** Whether we have responded to Interaction or not */ | ||||||
|  |   responded: boolean = false | ||||||
|  |   /** Resolved data for Snowflakes in Slash Command Arguments */ | ||||||
|  |   resolved: InteractionApplicationCommandResolved | ||||||
|  |   /** Whether response was deferred or not */ | ||||||
|  |   deferred: boolean = false | ||||||
|  |   _httpRespond?: (d: InteractionResponsePayload) => unknown | ||||||
|  |   _httpResponded?: boolean | ||||||
| 
 | 
 | ||||||
|   constructor( |   constructor( | ||||||
|     client: Client, |     client: Client, | ||||||
|  | @ -137,7 +150,8 @@ export class Interaction extends SnowflakeBase { | ||||||
|     if (op === undefined || op.value === undefined) return undefined as any |     if (op === undefined || op.value === undefined) return undefined as any | ||||||
|     if (op.type === SlashCommandOptionType.USER) { |     if (op.type === SlashCommandOptionType.USER) { | ||||||
|       const u: InteractionUser = this.resolved.users[op.value] as any |       const u: InteractionUser = this.resolved.users[op.value] as any | ||||||
|       if (this.resolved.members[op.value] !== undefined) u.member = this.resolved.members[op.value] |       if (this.resolved.members[op.value] !== undefined) | ||||||
|  |         u.member = this.resolved.members[op.value] | ||||||
|       return u as any |       return u as any | ||||||
|     } else if (op.type === SlashCommandOptionType.ROLE) |     } else if (op.type === SlashCommandOptionType.ROLE) | ||||||
|       return this.resolved.roles[op.value] as any |       return this.resolved.roles[op.value] as any | ||||||
|  | @ -172,19 +186,24 @@ export class Interaction extends SnowflakeBase { | ||||||
|           : undefined |           : undefined | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     await this.client.rest.post( |     if (this._httpRespond !== undefined && this._httpResponded !== true) { | ||||||
|       INTERACTION_CALLBACK(this.id, this.token), |       this._httpResponded = true | ||||||
|       payload |       await this._httpRespond(payload) | ||||||
|     ) |     } else | ||||||
|  |       await this.client.rest.post( | ||||||
|  |         INTERACTION_CALLBACK(this.id, this.token), | ||||||
|  |         payload | ||||||
|  |       ) | ||||||
|     this.responded = true |     this.responded = true | ||||||
| 
 | 
 | ||||||
|     return this |     return this | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   /** Defer the Interaction i.e. let the user know bot is processing and will respond later. You only have 15 minutes to edit the response! */ |   /** Defer the Interaction i.e. let the user know bot is processing and will respond later. You only have 15 minutes to edit the response! */ | ||||||
|   async defer(): Promise<Interaction> { |   async defer(ephemeral = false): Promise<Interaction> { | ||||||
|     await this.respond({ |     await this.respond({ | ||||||
|       type: InteractionResponseType.DEFERRED_CHANNEL_MESSAGE |       type: InteractionResponseType.DEFERRED_CHANNEL_MESSAGE, | ||||||
|  |       flags: ephemeral ? 1 << 6 : 0 | ||||||
|     }) |     }) | ||||||
|     this.deferred = true |     this.deferred = true | ||||||
|     return this |     return this | ||||||
|  |  | ||||||
|  | @ -18,27 +18,10 @@ await slash.commands.bulkEdit([ | ||||||
| const options = { port: 8000 } | const options = { port: 8000 } | ||||||
| console.log('Listen on port: ' + options.port.toString()) | console.log('Listen on port: ' + options.port.toString()) | ||||||
| listenAndServe(options, async (req) => { | listenAndServe(options, async (req) => { | ||||||
|   const verify = await slash.verifyServerRequest(req) |   const d = await slash.verifyServerRequest(req) | ||||||
|   if (verify === false) |   if (d === false) return req.respond({ status: 401, body: 'not authorized' }) | ||||||
|     return req.respond({ status: 401, body: 'not authorized' }) |  | ||||||
| 
 | 
 | ||||||
|   const respond = async (d: any): Promise<void> => |   console.log(d) | ||||||
|     req.respond({ |   if (d.type === 1) return d.respond({ type: 1 }) | ||||||
|       status: 200, |   d.reply('Pong!') | ||||||
|       body: JSON.stringify(d), |  | ||||||
|       headers: new Headers({ |  | ||||||
|         'content-type': 'application/json' |  | ||||||
|       }) |  | ||||||
|     }) |  | ||||||
| 
 |  | ||||||
|   const body = JSON.parse( |  | ||||||
|     new TextDecoder('utf-8').decode(await Deno.readAll(req.body)) |  | ||||||
|   ) |  | ||||||
|   if (body.type === 1) return await respond({ type: 1 }) |  | ||||||
|   await respond({ |  | ||||||
|     type: 4, |  | ||||||
|     data: { |  | ||||||
|       content: 'Pong!' |  | ||||||
|     } |  | ||||||
|   }) |  | ||||||
| }) | }) | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue