bot/src/discord.ts
openaliro/openaliro
Module

discord.ts

@file Wire constants and response builders for the Discord interactions…

bot/src/discord.ts11 documented symbols

Overview

@file Wire constants and response builders for the Discord interactions protocol. Kept dependency-free so test/ can exercise it without a Worker runtime.

used by command.ts build.ts context.ts decode-devid.ts forget.ts help-me.ts ihave.ts matrix.ts ping.ts size.ts spec.ts test-request.ts test-result.ts twin.ts verify.ts who-has.ts why.ts followup.ts index.ts modal.ts testRequestContainer.ts

flowchart TD
  deferredMessage --> jsonResponse

API

Fexport function jsonResponse(body: unknown, status = 200): Response

bot/src/discord.ts:109

Serialises an interaction response body. Discord expects exactly this shape back within the 3 second deadline, or a defer followed by a PATCH to the response webhook.

called by deferredMessage, deferredUpdate, handleApproach, handleExplain, message, modal, modalResponse

Fexport function message(content: string, opts: { ephemeral?: boolean } = {}): Response

bot/src/discord.ts:132

A CHANNEL_MESSAGE_WITH_SOURCE response, **ephemeral unless told otherwise**. The default is deliberate and is the one place the two halves of this bot disagreed: triage replies defaulted to ephemeral, compatibility replies to public. Nothing in the type system can catch that — it is a runtime default behind ~50 call sites — so it resolves in the fail-safe direction. A reply that should have been public and came out private is a visible annoyance somebody reports; a reply that should have been private and came out public has already been read by the channel. Say { ephemeral: false }, or use publicMessage, to opt a reply into being visible to everyone. Mention parsing is suppressed unconditionally: nothing this bot echoes back should ever be able to ping, since some of what it echoes is user-typed. onlyUsers is the single sanctioned exception.

called by componentHandler, handler, handler, handler, handler, handler, handler, handler  ·  calls jsonResponse

Fexport function publicMessage(content: string): Response

bot/src/discord.ts:147

A reply everyone in the channel can see. Exists so that "this is public" is written at the call site rather than inferred from an absent argument, which is what made the two halves' defaults disagree unnoticed.

calls message

Fexport function invokerId(interaction: Interaction): string | null

bot/src/discord.ts:153

The Discord user ID that invoked an interaction: member.user.id in a guild, user.id in a DM. Never a username or display name.

called by componentHandler, handler, handler, handler, handler, handler, handler, modalHandler

Fexport function optionString(interaction: Interaction, name: string, max: number): string | null

bot/src/discord.ts:159

A command option's string value, trimmed and capped. Discord enforces its own limits client-side; this Worker does not trust that.

called by handler, handler, handler, handler, handler, handler, handler, handler

Fexport function deferredMessage(opts: { ephemeral?: boolean } = {}): Response

bot/src/discord.ts:168

A DEFERRED_CHANNEL_MESSAGE_WITH_SOURCE response: the "thinking…" placeholder for work that will not finish inside the 3 second deadline.

called by defer, deferRich  ·  calls jsonResponse

Fexport function modalResponse(modal: { custom_id: string; title: string; components: unknown[]; }): Response

bot/src/discord.ts:177

A MODAL response. Must be the immediate response to the interaction — there is no deferring first and opening one after.

called by handler  ·  calls jsonResponse

Fexport function deferredUpdate(): Response

bot/src/discord.ts:190

A DEFERRED_UPDATE_MESSAGE response: for a MESSAGE_COMPONENT interaction (a button click) whose eventual edit will not finish inside the 3 second deadline. Unlike deferredMessage, this carries no placeholder content — Discord shows no "thinking…" state at all, it just leaves the existing message as-is until the follow-up edit lands.

called by deferUpdate  ·  calls jsonResponse

Fexport function onlyUsers(ids: string[]):

bot/src/discord.ts:213

Suppress everything, then re-allow specific user IDs. The only pings this bot ever sends are to the maintainer, on a no-match or on request, and the ID comes from configuration rather than from a field somebody typed. parse: [] still holds, so nothing inside the user's own text can become a mention.

called by onModalSubmit

Fexport function modal(customId: string, title: string, inputs: ModalInput[]): Response

bot/src/discord.ts:231

Build and return a modal from plain field descriptions. The ergonomic half of modalResponse, which takes an already-assembled payload.

called by handler  ·  calls jsonResponse

Fexport function modalValue(interaction: Interaction, customId: string, max: number): string | null

bot/src/discord.ts:257

One submitted modal field, trimmed and capped. null for absent or empty, matching optionString so callers treat both the same way.

called by onModalSubmit
Undocumented (1)

newCorrelationId