gaato/discord/app does not have a README file
type Spawner = async (async () -> Unit) -> Unitpub(all) suberror AppConfigError {
EmptyToken
DuplicateCommand(name~ : String)
DuplicateCommandPath(command~ : String, path~ : String)
NestedSubcommandGroup(command~ : String, path~ : String)
ChoicesWithAutocomplete(command~ : String, path~ : String)
RequiredOptionAfterOptional(command~ : String, path~ : String)
DuplicateComponentRoute(custom_id~ : String)
DuplicateModalRoute(custom_id~ : String)
EmptyComponentRoute
EmptyModalRoute
InvalidRouteId(custom_id~ : String, reason~ : String)
InvalidModalFieldCount(custom_id~ : String, count~ : Int)
DuplicateModalTextInput(custom_id~ : String, field~ : String)
ModalOutsideLimits(custom_id~ : String, violation~ : LimitViolation)
InvalidFileTypes(owner~ : String, reason~ : String)
InvalidCooldown(command~ : String, seconds~ : Int)
InvalidMaxInFlight(value~ : Int)
} derive(Debug)pub(all) suberror CustomIdError {
TooLong(custom_id~ : String, length~ : Int)
SeparatorInSegment(segment~ : String)
} derive(Debug)pub(all) suberror HandlerError {
UserMessage(message~ : String, ephemeral~ : Bool)
GuildOnly
DmOnly
CheckFailed
MissingPermission(Permissions)
OnCooldown(retry_after_ms~ : Int64)
InvalidArgument(String)
} derive(Debug)test "guard a handler with a permission requirement" {
fn require_send_messages(permissions : @model.Permissions) -> Unit raise {
let required = @model.Permissions::send_messages()
if !permissions.contains(required) {
raise @app.HandlerError::MissingPermission(required)
}
}
try require_send_messages(@model.Permissions::none()) catch {
@app.HandlerError::MissingPermission(_) => ()
other => raise other
} noraise {
_ => fail("expected MissingPermission")
}
}pub(all) suberror ModalPrefillError {
UnknownCustomId(custom_id~ : String)
NonTextInput(custom_id~ : String)
ValueTooLong(custom_id~ : String, length~ : Int)
} derive(Debug)pub struct App {
// private fields
}fn App::attach(self : App, framework : Framework, client~ : Client, application_id~ : Id[ApplicationMarker], waiter? : async (String, Id[UserMarker]?, Int?) -> ComponentCtx?, latency_ms? : () -> Int64?) -> AppCtxfn App::middleware(self : App, middleware : async (InteractionCtx, async () -> Unit) -> Unit) -> Unitfn[A] App::on_component(self : App, route : ComponentRoute[A], handler : ComponentHandler[A]) -> Unitfn App::on_component_raw(self : App, prefix~ : String, handler : async (ComponentCtx) -> Unit) -> Unitasync fn App::serve(self : App, group : TaskGroup[Unit], client? : Client, token? : String, application_id? : Id[ApplicationMarker]) -> InteractionEndpointasync fn App::sync_commands(self : App, client : Client, application_id : Id[ApplicationMarker], scope~ : CommandScope, unowned? : UnownedCommands) -> SyncReportpub struct AppCtx {
// private fields
}pub struct CheckCtx {
// private fields
}pub struct Command[A] {
// private fields
}fn CommandReply::message(content? : String, embeds? : Array[Embed], components? : Array[Component], files? : Array[FileUpload], allowed_mentions? : AllowedMentions, ephemeral? : Bool) -> CommandReplypub(all) enum CommandScope {
Global
Guild(Id[GuildMarker])
Guilds(Array[Id[GuildMarker]])
} derive(Debug)pub struct ComponentDeferredCtx {
// private fields
}async fn ComponentDeferredCtx::edit_original(self : ComponentDeferredCtx, content? : String, clear_content? : Bool, embeds? : Array[Embed], components? : Array[Component], allowed_mentions? : AllowedMentions, files? : Array[FileUpload]) -> Messageasync fn ComponentDeferredCtx::followup(self : ComponentDeferredCtx, content? : String, embeds? : Array[Embed], components? : Array[Component], files? : Array[FileUpload], allowed_mentions? : AllowedMentions, ephemeral? : Bool) -> Messagefn ComponentDeferredCtx::guild_scope(self : ComponentDeferredCtx) -> GuildInvocation raise HandlerErrorasync fn ComponentDeferredCtx::wait_for_component(self : ComponentDeferredCtx, custom_id~ : String, from? : WaitFrom, timeout_ms? : Int) -> ComponentCtx?pub(all) enum ComponentHandler[A] {
Immediate(async (ComponentImmediateCtx, A) -> ComponentReply)
DeferredUpdate(async (ComponentDeferredCtx, A) -> Unit)
DeferredMessage(ephemeral~ : Bool, async (ComponentDeferredCtx, A) -> Unit)
Raw(async (ComponentCtx) -> Unit)
}pub struct ComponentImmediateCtx {
// private fields
}fn ComponentImmediateCtx::guild_scope(self : ComponentImmediateCtx) -> GuildInvocation raise HandlerErrorpub(all) enum ComponentReply {
UpdateMessage(content~ : String?, embeds~ : Array[Embed]?, components~ : Array[Component]?, allowed_mentions~ : AllowedMentions?)
Message(InitialResponse)
ShowModal(ModalHandle)
}fn ComponentReply::message(content? : String, embeds? : Array[Embed], components? : Array[Component], files? : Array[FileUpload], allowed_mentions? : AllowedMentions, ephemeral? : Bool) -> ComponentReplyfn ComponentReply::update_message(content? : String, embeds? : Array[Embed], components? : Array[Component], allowed_mentions? : AllowedMentions) -> ComponentReplypub struct ComponentRoute[A] {
// private fields
}test {
let route = @app.component_route(
id="ticket-close",
state=@app.CustomIdCodec::int(),
)
assert_eq(route.decode(route.custom_id(42)), 42)
}pub struct CustomIdCodec[A] {
// private fields
}fn[A] CustomIdCodec::custom(encode~ : (A) -> String, decode~ : (String) -> A raise HandlerError) -> CustomIdCodec[A]fn[A, B] CustomIdCodec::imap(self : CustomIdCodec[A], to~ : (A) -> B raise HandlerError, from~ : (B) -> A) -> CustomIdCodec[B]fn[A, B] CustomIdCodec::zip(self : CustomIdCodec[A], other : CustomIdCodec[B]) -> CustomIdCodec[(A, B)]pub struct DeferredCtx {
// private fields
}async fn DeferredCtx::edit_original(self : DeferredCtx, content? : String, clear_content? : Bool, embeds? : Array[Embed], components? : Array[Component], allowed_mentions? : AllowedMentions, files? : Array[FileUpload]) -> Messageasync fn DeferredCtx::followup(self : DeferredCtx, content? : String, embeds? : Array[Embed], components? : Array[Component], files? : Array[FileUpload], allowed_mentions? : AllowedMentions, ephemeral? : Bool) -> Messageasync fn DeferredCtx::wait_for_component(self : DeferredCtx, custom_id~ : String, from? : WaitFrom, timeout_ms? : Int) -> ComponentCtx?pub struct FailureCtx {
// private fields
}async fn FailureCtx::respond_error(self : FailureCtx, content? : String, embeds? : Array[Embed], components? : Array[Component], files? : Array[FileUpload], allowed_mentions? : AllowedMentions, ephemeral? : Bool) -> Unitpub struct ImmediateCtx {
// private fields
}pub struct InitialResponse {
// private fields
}fn InitialResponse::message(content? : String, embeds? : Array[Embed], components? : Array[Component], files? : Array[FileUpload], allowed_mentions? : AllowedMentions, ephemeral? : Bool) -> InitialResponsepub struct InteractionCtx {
// private fields
}async fn InteractionCtx::respond(self : InteractionCtx, message : String, ephemeral? : Bool) -> Unitpub struct InteractionEndpoint {
// private fields
}async fn InteractionEndpoint::handle(self : InteractionEndpoint, body : Json, deadline_ms? : Int) -> Json?async fn InteractionEndpoint::handle_interaction(self : InteractionEndpoint, interaction : Interaction, deadline_ms? : Int) -> InteractionOutcomeasync fn InteractionEndpoint::handle_signed_http(self : InteractionEndpoint, request : InteractionHttpRequest, verifier : InteractionVerifier, deadline_ms? : Int) -> InteractionHttpResponsepub(all) enum InteractionHandler[A] {
Immediate(async (ImmediateCtx, A) -> CommandReply)
Deferred(ephemeral~ : Bool, async (DeferredCtx, A) -> Unit)
Raw(async (CommandCtx) -> Unit)
}pub(all) struct InteractionHttpRequest {
http_method : String
signature : String?
timestamp : String?
body : Bytes
}pub(all) struct InteractionHttpResponse {
status : Int
content_type : String?
body : InteractionHttpBody
}pub(all) enum InteractionOutcome {
Reply(response~ : InteractionResponse, files~ : Array[FileUpload]?)
NoRoute
NoResponse
TimedOut
} derive(Debug)pub(all) enum InteractionTarget {
Command(name~ : String)
Component(custom_id~ : String)
Modal(custom_id~ : String)
} derive(Debug)pub struct Modal[A] {
// private fields
}fn[A] Modal::show(self : Modal[A], state? : String, values? : Map[String, String]) -> ModalHandle raisepub struct ModalDeferredCtx {
// private fields
}async fn ModalDeferredCtx::edit_original(self : ModalDeferredCtx, content? : String, clear_content? : Bool, embeds? : Array[Embed], components? : Array[Component], allowed_mentions? : AllowedMentions, files? : Array[FileUpload]) -> Messageasync fn ModalDeferredCtx::followup(self : ModalDeferredCtx, content? : String, embeds? : Array[Embed], components? : Array[Component], files? : Array[FileUpload], allowed_mentions? : AllowedMentions, ephemeral? : Bool) -> Messagepub struct ModalField[A] {
// private fields
}pub struct ModalFields[A] {
// private fields
}fn[A, B, Z] ModalFields::map2(a : ModalField[A], b : ModalField[B], f : (A, B) -> Z) -> ModalFields[Z]fn[A, B, C, Z] ModalFields::map3(a : ModalField[A], b : ModalField[B], c : ModalField[C], f : (A, B, C) -> Z) -> ModalFields[Z]fn[A, B, C, D, Z] ModalFields::map4(a : ModalField[A], b : ModalField[B], c : ModalField[C], d : ModalField[D], f : (A, B, C, D) -> Z) -> ModalFields[Z]fn[A, B, C, D, E, Z] ModalFields::map5(a : ModalField[A], b : ModalField[B], c : ModalField[C], d : ModalField[D], e : ModalField[E], f : (A, B, C, D, E) -> Z) -> ModalFields[Z]pub struct ModalHandle {
// private fields
}pub struct ModalImmediateCtx {
// private fields
}pub(all) enum ModalSubmitHandler[A] {
Immediate(async (ModalImmediateCtx, A) -> InitialResponse)
Deferred(ephemeral~ : Bool, async (ModalDeferredCtx, A) -> Unit)
Raw(async (ModalCtx) -> Unit)
}pub struct RegisteredCommand {
// private fields
}pub struct SlashChild {
// private fields
}test "build a component from its route" {
let route = @app.component_route(id="page", state=@app.CustomIdCodec::int())
let app = @app.App()
app.on_component(
route,
Immediate((_, page) => @app.ComponentReply::message(content="Page \{page}")),
)
let _ = @interaction.button(custom_id=route.custom_id(2), label="Next")
assert_eq(route.custom_id(2), "page:2")
app.validate()
}fn file_field(custom_id~ : String, label~ : String, description? : String, min_values? : Int, max_values? : Int, file_types? : Array[FileTypeFilter]) -> ModalField[Array[Attachment]]fn message_command(name~ : String, handler~ : InteractionHandler[Message], default_member_permissions? : Permissions, nsfw? : Bool, integration_types? : Array[ApplicationIntegrationType], contexts? : Array[InteractionContextType], name_localizations? : Map[String, String]) -> Command[Message]test "construct and validate a typed modal" {
let feedback = @app.modal(
custom_id="feedback",
title="Feedback",
fields=@app.ModalFields::of(
@app.text_field(custom_id="details", label="Details").optional(),
),
)
let app = @app.App()
app.on_modal(feedback, Raw(_ => ()))
app.validate()
let _ : @app.ModalHandle = feedback.show(state="draft")
}fn select_field(custom_id~ : String, label~ : String, options~ : Array[SelectOption], description? : String, placeholder? : String, min_values? : Int, max_values? : Int) -> ModalField[Array[String]]fn[A] slash(name~ : String, description~ : String, args~ : Args[A], handler~ : InteractionHandler[A], default_member_permissions? : Permissions, nsfw? : Bool, integration_types? : Array[ApplicationIntegrationType], contexts? : Array[InteractionContextType], name_localizations? : Map[String, String], description_localizations? : Map[String, String]) -> Command[A]test "inspect a slash-command registration spec" {
let command = @app.slash(
name="echo",
description="Echo text",
args=@interaction.Args::of(
@interaction.arg_string(name="text", description="Text to echo"),
),
handler=Raw(_ => ()),
)
json_inspect(command.spec().to_json(), content={
"name": "echo",
"description": "Echo text",
"options": [
{
"type": 3,
"name": "text",
"description": "Text to echo",
"required": true,
},
],
})
}fn slash_group(name~ : String, description~ : String, children~ : Array[SlashChild], default_member_permissions? : Permissions, nsfw? : Bool, integration_types? : Array[ApplicationIntegrationType], contexts? : Array[InteractionContextType], name_localizations? : Map[String, String], description_localizations? : Map[String, String]) -> Command[Unit]fn[A] subcommand(name~ : String, description~ : String, args~ : Args[A], handler~ : InteractionHandler[A], name_localizations? : Map[String, String], description_localizations? : Map[String, String]) -> SlashChildfn subcommand_group(name~ : String, description~ : String, children~ : Array[SlashChild], name_localizations? : Map[String, String], description_localizations? : Map[String, String]) -> SlashChildfn text_field(custom_id~ : String, label~ : String, style? : TextInputStyle, description? : String, placeholder? : String, min_length? : Int, max_length? : Int, value? : String) -> ModalField[String]fn user_command(name~ : String, handler~ : InteractionHandler[TargetUser], default_member_permissions? : Permissions, nsfw? : Bool, integration_types? : Array[ApplicationIntegrationType], contexts? : Array[InteractionContextType], name_localizations? : Map[String, String]) -> Command[TargetUser]test "inspect context-menu command kinds" {
let user = @app.user_command(name="Inspect user", handler=Raw(_ => ()))
let message = @app.message_command(
name="Inspect message",
handler=Raw(_ => ()),
)
json_inspect(user.spec().to_json(), content={
"name": "Inspect user",
"description": "",
"type": 2,
})
json_inspect(message.spec().to_json(), content={
"name": "Inspect message",
"description": "",
"type": 3,
})
}Install
Download zipAn experimental Discord library for MoonBit: native/JS/Wasm REST, interactions, and gateway bots; native voice with DAVE E2EE.
Dependencies