followup.ts
@file Deferring, and the edit that finishes a deferred command.
Overview
@file Deferring, and the edit that finishes a deferred command. Discord gives an interaction 3 seconds. Anything touching D1 defers unconditionally rather than racing that clock, because a command that usually answers in 200 ms and occasionally does not is a command that occasionally fails for no reason a user can see. The interaction token authenticates the follow-up edit, so no bot token is involved here. It expires 15 minutes after the interaction.
depends on command.ts discord.ts · used by build.ts context.ts forget.ts help-me.ts ihave.ts matrix.ts test-request.ts test-result.ts twin.ts verify.ts who-has.ts
flowchart TD defer --> deferredMessage defer --> finish
API
Fexport function defer(c: CommandContext, work: (c: CommandContext) => Promise<string>, opts: { ephemeral?: boolean } = {}): Response
Answer now, work after. work returns the message body to put in place
of the "thinking" placeholder; if it throws, the placeholder is replaced
by an error naming the correlation ID rather than left spinning.
handleApproach, handler, handler, handler, handler, handler, handler, handler · calls deferredMessage, finishFexport function deferRich(c: CommandContext, work: (c: CommandContext) => Promise<DeferredResult>, opts: { ephemeral?: boolean } = {}): Response
Like defer, but work may also attach a file (an image, so far) to
the follow-up edit. A separate entry point rather than widening defer
itself, since every other command only ever needs text.
handler · calls deferredMessage, finishRichFexport async function editOriginal(c: CommandContext, content: string, file?: { bytes: Uint8Array; filename: string }): Promise<void>
Replace the deferred placeholder, optionally attaching a file. Mentions stay off either way.
finish, finishRichFexport function deferUpdate(c: CommandContext, work: (c: CommandContext) => Promise<UpdateOutcome>): Response
Like defer, but for a MESSAGE_COMPONENT interaction: answers with
DEFERRED_UPDATE_MESSAGE (no "thinking…" placeholder shown) and finishes
by either editing the component's own message or sending a private note.
componentHandler · calls deferredUpdate, finishUpdateFexport async function editOriginalComponents(c: CommandContext, body: Record<string, unknown>): Promise<void>
PATCHes @original with an arbitrary components-shaped body, for messages
where content is disabled (IS_COMPONENTS_V2) and editOriginal's
content-only shape does not apply.
finishUpdateFasync function sendEphemeralFollowup(c: CommandContext, content: string): Promise<void>
POSTs a new ephemeral follow-up message without touching the message the component is attached to.
finishUpdateUndocumented (3)
finish, finishRich, finishUpdate