///|
/// Proof that an interaction was invoked in a guild: the guild id and the
/// invoking member, both validated when the context was built.
pub(all) struct GuildInvocation {
guild_id : @model.GuildId
member : @model.GuildMember
} derive(Debug)
///|
/// The user who invoked this interaction.
pub fn GuildInvocation::user(self : GuildInvocation) -> @model.User {
match self.member.user {
Some(user) => user
None => abort("validated guild invocation has no member user")
}
}
///|
/// The context in which an interaction was invoked.
pub(all) enum InvocationScope {
Guild(GuildInvocation)
Dm(@model.User)
} derive(Debug)
///|
/// The interaction that opened a submitted modal.
pub(all) enum ModalOrigin {
FromComponent(@model.Message)
FromCommand
} derive(Debug)
///|
/// A malformed interaction that cannot satisfy the guarantees exposed by a
/// typed handler context.
pub(all) suberror InteractionContextError {
MissingInvoker
MissingGuildMemberUser
MissingGuildId
MissingComponentMessage
} derive(Debug)
///|
/// The resolved target of a USER context-menu command.
pub(all) struct TargetUser {
user : @model.User
member : @model.GuildMember?
}
///|
/// Prefer the guild member when both `member` and `user` are present: the
/// documented contract is exactly-one, but an interpretable payload should
/// never make the interaction unanswerable.
fn interaction_scope(
interaction : @model.Interaction,
) -> InvocationScope raise InteractionContextError {
match (interaction.guild_member, interaction.user) {
(Some(guild_member), _) => {
guard guild_member.user is Some(_) else { raise MissingGuildMemberUser }
guard interaction.guild_id is Some(guild_id) else { raise MissingGuildId }
Guild({ guild_id, member: guild_member, })
}
(None, Some(user)) => Dm(user)
(None, None) => raise MissingInvoker
}
}
///|
fn InvocationScope::invoking_user(self : InvocationScope) -> @model.User {
match self {
Guild(guild) => guild.user()
Dm(user) => user
}
}
///|
fn component_message(
interaction : @model.Interaction,
) -> @model.Message raise InteractionContextError {
match interaction.message {
Some(message) => message
None => raise MissingComponentMessage
}
}
///|
fn modal_origin(interaction : @model.Interaction) -> ModalOrigin {
match interaction.message {
Some(message) => FromComponent(message)
None => FromCommand
}
}
///|
/// Context handed to a slash / context-menu command handler.
pub(all) struct CommandCtx {
client : @dhttp.Client
application_id : @model.ApplicationId
interaction : @model.Interaction
data : @model.CommandData
options : @interaction.CommandOptions
priv scope_ : InvocationScope
priv gate : ResponseGate
}
///|
/// Whether the command was invoked in a guild or a DM.
pub fn CommandCtx::scope(self : CommandCtx) -> InvocationScope {
self.scope_
}
///|
/// Milliseconds left before the initial-response window closes, or `None`
/// when the executor set no deadline.
pub fn CommandCtx::remaining_ms(self : CommandCtx) -> Int32? {
self.gate.remaining_ms()
}
///|
/// Milliseconds left before this interaction's token expires (15 minutes after
/// the executor received it). Followups and edits fail after that.
pub fn CommandCtx::token_remaining_ms(self : CommandCtx) -> Int32 {
self.gate.token_remaining_ms()
}
///|
/// The current state of this interaction's initial callback.
pub fn CommandCtx::response_state(self : CommandCtx) -> ResponseState {
self.gate.state()
}
///|
/// The validated guild invocation, or `None` when invoked in a DM.
pub fn CommandCtx::guild_scope(self : CommandCtx) -> GuildInvocation? {
match self.scope_ {
Guild(guild) => Some(guild)
Dm(_) => None
}
}
///|
/// The invoking user.
pub fn CommandCtx::user(self : CommandCtx) -> @model.User {
self.scope_.invoking_user()
}
///|
/// The resolved target of a MESSAGE context-menu command, or `None` when this
/// is not a message command or its target is unavailable.
pub fn CommandCtx::target_message(self : CommandCtx) -> @model.Message? {
guard self.data.typ is Message &&
self.data.target_id is Some(target_id) &&
self.data.resolved is Some(resolved) &&
resolved.messages is Some(messages) else {
return None
}
messages.get(target_id.to_string())
}
///|
/// The resolved target of a USER context-menu command, or `None` when this is
/// not a user command or its target is unavailable.
pub fn CommandCtx::target_user(self : CommandCtx) -> TargetUser? {
guard self.data.typ is User &&
self.data.target_id is Some(target_id) &&
self.data.resolved is Some(resolved) &&
resolved.users is Some(users) &&
users.get(target_id.to_string()) is Some(user) else {
return None
}
let target_member = match resolved.members {
Some(members) => members.get(target_id.to_string())
None => None
}
Some({ user, member: target_member, })
}
///|
/// Decode the submitted options into a typed `CommandModel`.
pub fn[T : @interaction.CommandModel] CommandCtx::model(
self : CommandCtx,
) -> T raise {
T::from_options(self.options)
}
///|
/// The operations this interaction's token allows.
fn CommandCtx::responder(self : CommandCtx) -> Responder {
{
gate: self.gate,
client: self.client,
application_id: self.application_id,
token: self.interaction.token,
}
}
///|
/// Send a message through whichever path the response state allows: the
/// initial response while pending, an edit of a still-loading deferred
/// placeholder, or a followup after any other callback. `ephemeral` cannot
/// change an existing message, so an edited placeholder keeps the
/// visibility chosen when deferring. Raises `ResponseGateError::Expired`
/// once the callback window has closed unused. Concurrent replies to one
/// interaction run one at a time, so only the first replaces the placeholder.
pub async fn CommandCtx::reply(
self : CommandCtx,
content? : String,
embeds? : Array[@model.Embed],
components? : Array[@model.Component],
files? : Array[@dhttp.FileUpload],
allowed_mentions? : @model.AllowedMentions,
poll? : @model.PollCreateRequest,
ephemeral~ : Bool = false,
) -> Unit {
self
.responder()
.reply(content, embeds, components, files, allowed_mentions, poll, ephemeral)
}
///|
/// Send the initial "channel message with source" response.
pub async fn CommandCtx::respond(
self : CommandCtx,
content? : String,
embeds? : Array[@model.Embed],
components? : Array[@model.Component],
files? : Array[@dhttp.FileUpload],
allowed_mentions? : @model.AllowedMentions,
poll? : @model.PollCreateRequest,
ephemeral~ : Bool = false,
) -> Unit {
self
.responder()
.respond(
ChannelMessageWithSource,
content?,
embeds?,
components?,
files?,
allowed_mentions?,
poll?,
ephemeral~,
)
}
///|
/// Display a modal as the initial command response.
pub async fn CommandCtx::show_modal(
self : CommandCtx,
custom_id~ : String,
title~ : String,
components~ : Array[@model.Component],
) -> Unit {
self.responder().show_modal(custom_id, title, components)
}
///|
/// Acknowledge now and reply later via `edit_response` / `followup`.
pub async fn CommandCtx::defer_response(
self : CommandCtx,
ephemeral~ : Bool = false,
) -> Unit {
self.responder().defer_message(ephemeral)
}
///|
/// Fetch the original response to this command interaction.
pub async fn CommandCtx::original_response(self : CommandCtx) -> @model.Message {
self.responder().original()
}
///|
/// Delete the original response to this command interaction.
pub async fn CommandCtx::delete_response(self : CommandCtx) -> Unit {
self.responder().delete_original()
}
///|
/// Edit the original response to this command interaction. `poll` may only
/// be added while editing a deferred response.
pub async fn CommandCtx::edit_response(
self : CommandCtx,
content? : String,
clear_content~ : Bool = false,
embeds? : Array[@model.Embed],
components? : Array[@model.Component],
allowed_mentions? : @model.AllowedMentions,
files? : Array[@dhttp.FileUpload],
keep_attachments? : Array[@model.AttachmentRequest],
poll? : @model.PollCreateRequest,
) -> @model.Message {
self
.responder()
.edit_original(
content, clear_content, embeds, components, allowed_mentions, files, keep_attachments,
poll,
)
}
///|
/// Send a followup message for this command interaction.
pub async fn CommandCtx::followup(
self : CommandCtx,
content? : String,
embeds? : Array[@model.Embed],
components? : Array[@model.Component],
files? : Array[@dhttp.FileUpload],
allowed_mentions? : @model.AllowedMentions,
poll? : @model.PollCreateRequest,
ephemeral~ : Bool = false,
) -> @model.Message {
self
.responder()
.followup(
content, embeds, components, files, allowed_mentions, poll, ephemeral,
)
}
///|
/// Fetch a followup message for this command interaction.
pub async fn CommandCtx::get_followup(
self : CommandCtx,
message_id : @model.MessageId,
) -> @model.Message {
self.responder().get_followup(message_id)
}
///|
/// Edit a followup message for this command interaction.
pub async fn CommandCtx::edit_followup(
self : CommandCtx,
message_id : @model.MessageId,
content? : String,
clear_content~ : Bool = false,
embeds? : Array[@model.Embed],
components? : Array[@model.Component],
allowed_mentions? : @model.AllowedMentions,
files? : Array[@dhttp.FileUpload],
keep_attachments? : Array[@model.AttachmentRequest],
) -> @model.Message {
self
.responder()
.edit_followup(
message_id, content, clear_content, embeds, components, allowed_mentions, files,
keep_attachments,
)
}
///|
/// Delete a followup message for this command interaction.
pub async fn CommandCtx::delete_followup(
self : CommandCtx,
message_id : @model.MessageId,
) -> Unit {
self.responder().delete_followup(message_id)
}
///|
/// Context handed to a message-component (button / select) handler.
pub(all) struct ComponentCtx {
client : @dhttp.Client
application_id : @model.ApplicationId
interaction : @model.Interaction
data : @model.ComponentData
priv scope_ : InvocationScope
priv message_ : @model.Message
priv gate : ResponseGate
}
///|
/// Whether the component was invoked in a guild or a DM.
pub fn ComponentCtx::scope(self : ComponentCtx) -> InvocationScope {
self.scope_
}
///|
/// Milliseconds left before the initial-response window closes, or `None`
/// when the executor set no deadline.
pub fn ComponentCtx::remaining_ms(self : ComponentCtx) -> Int32? {
self.gate.remaining_ms()
}
///|
/// Milliseconds left before this interaction's token expires (15 minutes after
/// the executor received it). Followups and edits fail after that.
pub fn ComponentCtx::token_remaining_ms(self : ComponentCtx) -> Int32 {
self.gate.token_remaining_ms()
}
///|
/// The current state of this interaction's initial callback.
pub fn ComponentCtx::response_state(self : ComponentCtx) -> ResponseState {
self.gate.state()
}
///|
/// The validated guild invocation, or `None` when invoked in a DM.
pub fn ComponentCtx::guild_scope(self : ComponentCtx) -> GuildInvocation? {
match self.scope_ {
Guild(guild) => Some(guild)
Dm(_) => None
}
}
///|
/// The invoking user.
pub fn ComponentCtx::user(self : ComponentCtx) -> @model.User {
self.scope_.invoking_user()
}
///|
/// The message to which the component was attached.
pub fn ComponentCtx::message(self : ComponentCtx) -> @model.Message {
self.message_
}
///|
/// The operations this interaction's token allows.
fn ComponentCtx::responder(self : ComponentCtx) -> Responder {
{
gate: self.gate,
client: self.client,
application_id: self.application_id,
token: self.interaction.token,
}
}
///|
/// Send a message through whichever path the response state allows: the
/// initial response while pending, an edit of a still-loading deferred
/// placeholder, or a followup after any other callback. `ephemeral` cannot
/// change an existing message, so an edited placeholder keeps the
/// visibility chosen when deferring. Raises `ResponseGateError::Expired`
/// once the callback window has closed unused. Concurrent replies to one
/// interaction run one at a time, so only the first replaces the placeholder.
pub async fn ComponentCtx::reply(
self : ComponentCtx,
content? : String,
embeds? : Array[@model.Embed],
components? : Array[@model.Component],
files? : Array[@dhttp.FileUpload],
allowed_mentions? : @model.AllowedMentions,
poll? : @model.PollCreateRequest,
ephemeral~ : Bool = false,
) -> Unit {
self
.responder()
.reply(content, embeds, components, files, allowed_mentions, poll, ephemeral)
}
///|
/// Send a new "channel message with source" response.
pub async fn ComponentCtx::respond(
self : ComponentCtx,
content? : String,
embeds? : Array[@model.Embed],
components? : Array[@model.Component],
files? : Array[@dhttp.FileUpload],
allowed_mentions? : @model.AllowedMentions,
poll? : @model.PollCreateRequest,
ephemeral~ : Bool = false,
) -> Unit {
self
.responder()
.respond(
ChannelMessageWithSource,
content?,
embeds?,
components?,
files?,
allowed_mentions?,
poll?,
ephemeral~,
)
}
///|
/// Edit the message the component is attached to.
pub async fn ComponentCtx::update_message(
self : ComponentCtx,
content? : String,
clear_content~ : Bool = false,
embeds? : Array[@model.Embed],
components? : Array[@model.Component],
allowed_mentions? : @model.AllowedMentions,
files? : Array[@dhttp.FileUpload],
keep_attachments? : Array[@model.AttachmentRequest],
poll? : @model.PollCreateRequest,
) -> Unit {
self
.responder()
.respond(
UpdateMessage,
content?,
clear_content~,
embeds?,
components?,
allowed_mentions?,
files?,
keep_attachments?,
poll?,
)
}
///|
/// Display a modal as the initial component response.
pub async fn ComponentCtx::show_modal(
self : ComponentCtx,
custom_id~ : String,
title~ : String,
components~ : Array[@model.Component],
) -> Unit {
self.responder().show_modal(custom_id, title, components)
}
///|
/// Acknowledge now and send a message later through webhook methods.
pub async fn ComponentCtx::defer_response(
self : ComponentCtx,
ephemeral~ : Bool = false,
) -> Unit {
self.responder().defer_message(ephemeral)
}
///|
/// Acknowledge without any visible change (edit later if needed).
pub async fn ComponentCtx::defer_update(self : ComponentCtx) -> Unit {
self.responder().defer_update()
}
///|
/// Fetch the original response to this component interaction.
pub async fn ComponentCtx::original_response(
self : ComponentCtx,
) -> @model.Message {
self.responder().original()
}
///|
/// Delete the original response to this component interaction.
pub async fn ComponentCtx::delete_response(self : ComponentCtx) -> Unit {
self.responder().delete_original()
}
///|
/// Edit the original response to this component interaction. `poll` may only
/// be added while editing a deferred response.
pub async fn ComponentCtx::edit_response(
self : ComponentCtx,
content? : String,
clear_content~ : Bool = false,
embeds? : Array[@model.Embed],
components? : Array[@model.Component],
allowed_mentions? : @model.AllowedMentions,
files? : Array[@dhttp.FileUpload],
keep_attachments? : Array[@model.AttachmentRequest],
poll? : @model.PollCreateRequest,
) -> @model.Message {
self
.responder()
.edit_original(
content, clear_content, embeds, components, allowed_mentions, files, keep_attachments,
poll,
)
}
///|
/// Send a followup message for this component interaction.
pub async fn ComponentCtx::followup(
self : ComponentCtx,
content? : String,
embeds? : Array[@model.Embed],
components? : Array[@model.Component],
files? : Array[@dhttp.FileUpload],
allowed_mentions? : @model.AllowedMentions,
poll? : @model.PollCreateRequest,
ephemeral~ : Bool = false,
) -> @model.Message {
self
.responder()
.followup(
content, embeds, components, files, allowed_mentions, poll, ephemeral,
)
}
///|
/// Fetch a followup message for this component interaction.
pub async fn ComponentCtx::get_followup(
self : ComponentCtx,
message_id : @model.MessageId,
) -> @model.Message {
self.responder().get_followup(message_id)
}
///|
/// Edit a followup message for this component interaction.
pub async fn ComponentCtx::edit_followup(
self : ComponentCtx,
message_id : @model.MessageId,
content? : String,
clear_content~ : Bool = false,
embeds? : Array[@model.Embed],
components? : Array[@model.Component],
allowed_mentions? : @model.AllowedMentions,
files? : Array[@dhttp.FileUpload],
keep_attachments? : Array[@model.AttachmentRequest],
) -> @model.Message {
self
.responder()
.edit_followup(
message_id, content, clear_content, embeds, components, allowed_mentions, files,
keep_attachments,
)
}
///|
/// Delete a followup message for this component interaction.
pub async fn ComponentCtx::delete_followup(
self : ComponentCtx,
message_id : @model.MessageId,
) -> Unit {
self.responder().delete_followup(message_id)
}
///|
/// Context handed to a modal-submit handler.
pub(all) struct ModalCtx {
client : @dhttp.Client
application_id : @model.ApplicationId
interaction : @model.Interaction
data : @model.ModalData
priv scope_ : InvocationScope
priv origin_ : ModalOrigin
priv gate : ResponseGate
}
///|
/// Whether the modal was submitted in a guild or a DM.
pub fn ModalCtx::scope(self : ModalCtx) -> InvocationScope {
self.scope_
}
///|
/// Milliseconds left before the initial-response window closes, or `None`
/// when the executor set no deadline.
pub fn ModalCtx::remaining_ms(self : ModalCtx) -> Int32? {
self.gate.remaining_ms()
}
///|
/// Milliseconds left before this interaction's token expires (15 minutes after
/// the executor received it). Followups and edits fail after that.
pub fn ModalCtx::token_remaining_ms(self : ModalCtx) -> Int32 {
self.gate.token_remaining_ms()
}
///|
/// The current state of this interaction's initial callback.
pub fn ModalCtx::response_state(self : ModalCtx) -> ResponseState {
self.gate.state()
}
///|
/// The validated guild invocation, or `None` when invoked in a DM.
pub fn ModalCtx::guild_scope(self : ModalCtx) -> GuildInvocation? {
match self.scope_ {
Guild(guild) => Some(guild)
Dm(_) => None
}
}
///|
/// The invoking user.
pub fn ModalCtx::user(self : ModalCtx) -> @model.User {
self.scope_.invoking_user()
}
///|
/// Whether the modal was opened from a component or from a command.
pub fn ModalCtx::origin(self : ModalCtx) -> ModalOrigin {
self.origin_
}
///|
/// The submitted value of the text input with the given custom id.
pub fn ModalCtx::text_value(self : ModalCtx, custom_id : String) -> String? {
fn walk(components : Array[@model.Component]) -> String? {
for component in components {
match component {
ActionRow(row) =>
if walk(row.components) is Some(value) {
return Some(value)
}
Label(label) =>
if walk([label.component]) is Some(value) {
return Some(value)
}
TextInput(input) =>
if input.custom_id == custom_id {
return input.value
}
_ => ()
}
}
None
}
walk(self.data.components)
}
///|
/// The operations this interaction's token allows.
fn ModalCtx::responder(self : ModalCtx) -> Responder {
{
gate: self.gate,
client: self.client,
application_id: self.application_id,
token: self.interaction.token,
}
}
///|
/// Send a message through whichever path the response state allows: the
/// initial response while pending, an edit of a still-loading deferred
/// placeholder, or a followup after any other callback. `ephemeral` cannot
/// change an existing message, so an edited placeholder keeps the
/// visibility chosen when deferring. Raises `ResponseGateError::Expired`
/// once the callback window has closed unused. Concurrent replies to one
/// interaction run one at a time, so only the first replaces the placeholder.
pub async fn ModalCtx::reply(
self : ModalCtx,
content? : String,
embeds? : Array[@model.Embed],
components? : Array[@model.Component],
files? : Array[@dhttp.FileUpload],
allowed_mentions? : @model.AllowedMentions,
poll? : @model.PollCreateRequest,
ephemeral~ : Bool = false,
) -> Unit {
self
.responder()
.reply(content, embeds, components, files, allowed_mentions, poll, ephemeral)
}
///|
/// Send a "channel message with source" response to the modal.
pub async fn ModalCtx::respond(
self : ModalCtx,
content? : String,
embeds? : Array[@model.Embed],
components? : Array[@model.Component],
files? : Array[@dhttp.FileUpload],
allowed_mentions? : @model.AllowedMentions,
poll? : @model.PollCreateRequest,
ephemeral~ : Bool = false,
) -> Unit {
self
.responder()
.respond(
ChannelMessageWithSource,
content?,
embeds?,
components?,
files?,
allowed_mentions?,
poll?,
ephemeral~,
)
}
///|
/// Edit the message whose component opened this modal. A modal opened by
/// a command has no such message, so this raises
/// `ResponseGateError::InvalidCallback` without sending anything.
pub async fn ModalCtx::update_message(
self : ModalCtx,
content? : String,
clear_content~ : Bool = false,
embeds? : Array[@model.Embed],
components? : Array[@model.Component],
allowed_mentions? : @model.AllowedMentions,
files? : Array[@dhttp.FileUpload],
keep_attachments? : Array[@model.AttachmentRequest],
poll? : @model.PollCreateRequest,
) -> Unit {
guard self.origin() is FromComponent(_) else {
raise ResponseGateError::InvalidCallback(
kind=ModalSubmit,
typ=UpdateMessage,
)
}
self
.responder()
.respond(
UpdateMessage,
content?,
clear_content~,
embeds?,
components?,
allowed_mentions?,
files?,
keep_attachments?,
poll?,
)
}
///|
/// Acknowledge now and reply later via a followup.
pub async fn ModalCtx::defer_response(
self : ModalCtx,
ephemeral~ : Bool = false,
) -> Unit {
self.responder().defer_message(ephemeral)
}
///|
/// Acknowledge without changing the message whose component opened this
/// modal (edit it later with `edit_response`). A modal opened by a command
/// has no such message, so this raises `ResponseGateError::InvalidCallback`.
pub async fn ModalCtx::defer_update(self : ModalCtx) -> Unit {
guard self.origin() is FromComponent(_) else {
raise ResponseGateError::InvalidCallback(
kind=ModalSubmit,
typ=DeferredUpdateMessage,
)
}
self.responder().defer_update()
}
///|
/// Fetch the original response to this modal interaction.
pub async fn ModalCtx::original_response(self : ModalCtx) -> @model.Message {
self.responder().original()
}
///|
/// Delete the original response to this modal interaction.
pub async fn ModalCtx::delete_response(self : ModalCtx) -> Unit {
self.responder().delete_original()
}
///|
/// Edit the original response to this modal interaction. `poll` may only
/// be added while editing a deferred response.
pub async fn ModalCtx::edit_response(
self : ModalCtx,
content? : String,
clear_content~ : Bool = false,
embeds? : Array[@model.Embed],
components? : Array[@model.Component],
allowed_mentions? : @model.AllowedMentions,
files? : Array[@dhttp.FileUpload],
keep_attachments? : Array[@model.AttachmentRequest],
poll? : @model.PollCreateRequest,
) -> @model.Message {
self
.responder()
.edit_original(
content, clear_content, embeds, components, allowed_mentions, files, keep_attachments,
poll,
)
}
///|
/// Send a followup message for this modal interaction.
pub async fn ModalCtx::followup(
self : ModalCtx,
content? : String,
embeds? : Array[@model.Embed],
components? : Array[@model.Component],
files? : Array[@dhttp.FileUpload],
allowed_mentions? : @model.AllowedMentions,
poll? : @model.PollCreateRequest,
ephemeral~ : Bool = false,
) -> @model.Message {
self
.responder()
.followup(
content, embeds, components, files, allowed_mentions, poll, ephemeral,
)
}
///|
/// Fetch a followup message for this modal interaction.
pub async fn ModalCtx::get_followup(
self : ModalCtx,
message_id : @model.MessageId,
) -> @model.Message {
self.responder().get_followup(message_id)
}
///|
/// Edit a followup message for this modal interaction.
pub async fn ModalCtx::edit_followup(
self : ModalCtx,
message_id : @model.MessageId,
content? : String,
clear_content~ : Bool = false,
embeds? : Array[@model.Embed],
components? : Array[@model.Component],
allowed_mentions? : @model.AllowedMentions,
files? : Array[@dhttp.FileUpload],
keep_attachments? : Array[@model.AttachmentRequest],
) -> @model.Message {
self
.responder()
.edit_followup(
message_id, content, clear_content, embeds, components, allowed_mentions, files,
keep_attachments,
)
}
///|
/// Delete a followup message for this modal interaction.
pub async fn ModalCtx::delete_followup(
self : ModalCtx,
message_id : @model.MessageId,
) -> Unit {
self.responder().delete_followup(message_id)
}
///|
/// Context handed to an autocomplete handler.
pub(all) struct AutocompleteCtx {
client : @dhttp.Client
application_id : @model.ApplicationId
interaction : @model.Interaction
data : @model.CommandData
options : @interaction.CommandOptions
priv gate : ResponseGate
}
///|
/// Milliseconds left before the autocomplete response window closes, or
/// `None` when the executor set no deadline.
pub fn AutocompleteCtx::remaining_ms(self : AutocompleteCtx) -> Int32? {
self.gate.remaining_ms()
}
///|
/// Milliseconds left before this interaction's token expires (15 minutes after
/// the executor received it). Followups and edits fail after that.
pub fn AutocompleteCtx::token_remaining_ms(self : AutocompleteCtx) -> Int32 {
self.gate.token_remaining_ms()
}
///|
/// Send autocomplete suggestions. Choices beyond the first 25 are truncated.
pub async fn AutocompleteCtx::suggest(
self : AutocompleteCtx,
choices : Array[@model.CommandOptionChoice],
) -> Unit {
let choices = if choices.length() > 25 {
choices[:25].to_owned()
} else {
choices
}
self.gate.send({
typ: Autocomplete,
data: Some(@sdkjson.ObjBuilder::new().field("choices", choices).build()),
})
}