@seedcord/http 0.6.0 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,8 +1,8 @@
1
1
  import { t as RouteManifest } from "./RouteManifest-D7qXj8Ts.mjs";
2
2
  import "reflect-metadata";
3
- import { AutocompletableNames, AutocompleteRouteBrand, ChoiceValueOf, ComponentDefsBrand, ComponentKindBrand, ContextMenuKindBrand, ContextMenuNamesBrand, EntryFor, FocusedField, GateFitsWith, HasComponentDefs, MatchArms, NamesFor, PageCursor, SingleParams, SlashOptions, SlashRouteBrand } from "@seedcord/core/internal";
3
+ import { AutocompletableNames, AutocompleteRouteBrand, ChoiceValueOf, ComponentDefsBrand, ComponentKindBrand, ContextMenuKindBrand, ContextMenuNamesBrand, EntryFor, FocusedField, GateFitsWith, HasComponentDefs, MatchArms, MiddlewareKindsBrand, MiddlewareRegistry, NamesFor, PageCursor, SingleParams, SlashOptions, SlashRouteBrand } from "@seedcord/core/internal";
4
4
  import { REST } from "@discordjs/rest";
5
- import { ArraySourceBase, AutocompleteOptions, BaseHandler, BaseReplySender, Bus, CoreBase, CursorSourceBase, DispatchContext, Gate, GateContextBase, GuildPermissionsContext, InteractionKind, ModalLike, PageSourceBase, PaginatorBase, PaginatorConfig, RepliableHandler, RequiredOf, ResolvedEmoji, SlashRegistry, Subscriber, SubscriptionKey, WebhookLog } from "@seedcord/core";
5
+ import { ArraySourceBase, AutocompleteOptions, BaseHandler, BaseReplySender, Bus, CoreBase, CursorSourceBase, DispatchContext, DispatchResult, Gate, GateContextBase, GuildPermissionsContext, InteractionKind, MiddlewareKind, ModalLike, PageSourceBase, PaginatorBase, PaginatorConfig, RepliableHandler, RequiredOf, ResolvedEmoji, SlashRegistry, Subscriber, SubscriptionKey, WebhookLog } from "@seedcord/core";
6
6
  import { APIApplicationCommandAutocompleteInteraction, APIApplicationCommandOptionChoice, APIAttachment, APIChatInputApplicationCommandInteraction, APIContextMenuInteraction, APIInteraction, APIInteractionDataResolvedChannel, APIInteractionDataResolvedChannelBase, APIInteractionDataResolvedGuildMember, APIInteractionGuildMember, APIMessage, APIMessageApplicationCommandInteraction, APIMessageChannelSelectInteractionData, APIMessageComponentButtonInteraction, APIMessageComponentInteraction, APIMessageComponentSelectMenuInteraction, APIMessageMentionableSelectInteractionData, APIMessageRoleSelectInteractionData, APIMessageStringSelectInteractionData, APIMessageUserSelectInteractionData, APIModalInteractionResponseCallbackData, APIModalSubmission, APIModalSubmitInteraction, APIRole, APIThreadChannel, APIUser, APIUserApplicationCommandInteraction, ApplicationCommandType, ChannelType, ModalSubmitComponent, ThreadChannelType } from "discord-api-types/v10";
7
7
  import { API } from "@discordjs/core/http-only";
8
8
  import { AnyCustomId } from "@seedcord/custom-id";
@@ -40,6 +40,7 @@ interface HttpServerConfig extends Config {
40
40
  interface HttpEdgeConfig extends Config {
41
41
  runtime: 'edge';
42
42
  port?: never;
43
+ lifecycle?: never;
43
44
  }
44
45
  /**
45
46
  * The http transport's configuration, discriminated on `runtime`.
@@ -68,6 +69,401 @@ interface Core extends CoreBase {
68
69
  readonly config: HttpConfig;
69
70
  }
70
71
  //#endregion
72
+ //#region src/handlers/interaction/AutocompleteHandler.d.ts
73
+ type FocusedArms<Route extends keyof SlashRegistry, Ret> = { [Name in AutocompletableNames<Route>]: (value: string, respond: (choices: readonly APIApplicationCommandOptionChoice<ChoiceValueOf<EntryFor<Route, Name>>>[]) => Promise<void>) => Promisable<Ret>; };
74
+ /**
75
+ * Base class for an autocomplete handler on the HTTP transport.
76
+ *
77
+ * Pass the command route(s) from the generated registry as the generic. Branch on the focused field with
78
+ * `this.match`, read already-entered sibling options with `this.options`, and find which command fired
79
+ * with `this.route`.
80
+ *
81
+ * @typeParam Route - One or more route keys from {@link SlashRegistry}, e.g. `'search'`.
82
+ */
83
+ declare abstract class AutocompleteHandler<Route extends keyof SlashRegistry> extends BaseHandler<APIApplicationCommandAutocompleteInteraction, Core> {
84
+ constructor(event: APIApplicationCommandAutocompleteInteraction, core: Core, dispatch: DispatchContext);
85
+ /** @internal */
86
+ readonly [AutocompleteRouteBrand]?: Route;
87
+ /**
88
+ * Typed Discord REST API (`@discordjs/core/http-only`) over `core.rest`, one instance per core.
89
+ */
90
+ protected get api(): API;
91
+ private resolver?;
92
+ private get reader();
93
+ /**
94
+ * The focused option for this interaction. `value` is always the raw partial string the user is typing,
95
+ * even for an integer or number option, so coerce it yourself when you need a number.
96
+ */
97
+ protected get focused(): FocusedField<Route>;
98
+ /**
99
+ * Run the arm for the focused field. An autocomplete always dispatches by which field is focused.
100
+ * Match is how you read it.
101
+ *
102
+ * Provide one arm per autocompletable field across the registered commands, keyed by field name. Each
103
+ * arm receives the focused partial value and a `respond` typed to that field's choice value. The
104
+ * arms must cover every autocompletable field, a missing field or an unknown key is a compile error. A
105
+ * focused field with no arm, only reachable from a stale-deployed command, throws at runtime.
106
+ *
107
+ * @param arms - One handler per autocompletable field, keyed by field name.
108
+ * @returns The result of the arm that ran.
109
+ */
110
+ protected match<Ret>(arms: FocusedArms<Route, Ret>): Promise<Ret>;
111
+ /** Send autocomplete suggestions, callback type 8. Prefer {@link match}, which restricts each field's choices to its declared type. */
112
+ protected respond(choices: readonly APIApplicationCommandOptionChoice[]): Promise<void>;
113
+ /** The firing command route, for a field whose completion differs per registered command. */
114
+ protected get route(): Route;
115
+ /**
116
+ * The already-entered options on this command, restricted to the kinds Discord resolves during autocomplete
117
+ * (string, integer, number, boolean) with every read nullable, since a sibling is partial while the user
118
+ * types the focused field. The focused field is on `this.focused`.
119
+ */
120
+ protected get options(): AutocompleteOptions<Route>;
121
+ }
122
+ //#endregion
123
+ //#region src/reply/ReplySender.d.ts
124
+ /** The interaction payload fields the sender writes its wire from. */
125
+ interface InteractionRef {
126
+ readonly application_id: string;
127
+ readonly id: string;
128
+ readonly token: string;
129
+ }
130
+ /** The created message an http reply resolves to (the http `SentMessage` lens). */
131
+ type SentMessage = APIMessage;
132
+ /**
133
+ * Writes interaction responses over the Discord REST callback and webhook endpoints. Construction is
134
+ * internal to the repliable handler bases and the dispatcher.
135
+ */
136
+ declare class ReplySender extends BaseReplySender<SentMessage> {
137
+ private readonly ref;
138
+ private readonly rest;
139
+ constructor(ref: InteractionRef, rest: REST, dispatch: DispatchContext, bus: Bus);
140
+ protected writeReply(response: ReplyResponse | string, opts?: SendOpts): Promise<SentMessage | undefined>;
141
+ protected writeDefer(opts?: DeferOpts): Promise<void>;
142
+ protected writeDeferUpdate(): Promise<void>;
143
+ protected writeUpdate(response: ReplyResponse | string): Promise<SentMessage | undefined>;
144
+ protected writeFollowUp(response: ReplyResponse | string, opts?: SendOpts): Promise<SentMessage>;
145
+ protected writeEditOriginal(response: ReplyResponse | string): Promise<SentMessage>;
146
+ protected writeEditTarget(targetId: string, response: ReplyResponse | string): Promise<SentMessage>;
147
+ protected writeDeleteOriginal(): Promise<void>;
148
+ protected writeDeleteTarget(targetId: string): Promise<void>;
149
+ protected writeModal(data: APIModalInteractionResponseCallbackData): Promise<void>;
150
+ private callback;
151
+ private editMessage;
152
+ private rawFiles;
153
+ private createdMessage;
154
+ }
155
+ //#endregion
156
+ //#region src/handlers/interactionTypes.d.ts
157
+ type ValidInteractionTypes = APIChatInputApplicationCommandInteraction | APIContextMenuInteraction | APIMessageComponentInteraction | APIModalSubmitInteraction | APIApplicationCommandAutocompleteInteraction;
158
+ type Repliables = Exclude<ValidInteractionTypes, APIApplicationCommandAutocompleteInteraction>;
159
+ //#endregion
160
+ //#region src/handlers/RepliableHandler.d.ts
161
+ /**
162
+ * Shared base the repliable HTTP interaction handlers extend.
163
+ *
164
+ * Not a public entry point. Extend {@link SlashHandler}, {@link ButtonHandler}, {@link ModalHandler},
165
+ * {@link ContextMenuHandler}, or one of the select menu bases instead. This class binds the core
166
+ * reply base to the http sender.
167
+ *
168
+ * @typeParam Event - The repliable interaction type this handler processes
169
+ */
170
+ declare abstract class RepliableHandler$1<Event extends Repliables> extends RepliableHandler<Event, Core, SentMessage, never, ReplySender> {
171
+ /** @internal */
172
+ getEvent(): Event;
173
+ protected buildSender(event: Event, core: Core, dispatch: DispatchContext): ReplySender;
174
+ /**
175
+ * Typed Discord REST API (`@discordjs/core/http-only`) over `core.rest`, one instance per core.
176
+ * The interaction callbacks on `api.interactions` bypass the reply surface. The
177
+ * `no-raw-interaction-acks` rule flags them in handler classes.
178
+ */
179
+ protected get api(): API;
180
+ }
181
+ //#endregion
182
+ //#region src/handlers/interaction/InteractionHandler.d.ts
183
+ /**
184
+ * Shared base the repliable interaction handlers extend.
185
+ *
186
+ * Not a public entry point. Extend {@link SlashHandler}, {@link ContextMenuHandler}, {@link ButtonHandler},
187
+ * {@link ModalHandler}, or one of the select menu bases instead. This class adds `showModal` on top
188
+ * of the reply members.
189
+ *
190
+ * @typeParam Event - The repliable interaction type this handler processes
191
+ */
192
+ declare abstract class InteractionHandler<Event extends Repliables> extends RepliableHandler$1<Event> {
193
+ constructor(event: Event, core: Core, dispatch: DispatchContext);
194
+ /**
195
+ * Open a modal. Must be the initial response to this interaction. The modal kind rejects this call at
196
+ * compile time (Discord forbids a modal in response to a modal).
197
+ */
198
+ protected showModal(this: InteractionHandler<Exclude<Repliables, APIModalSubmitInteraction>>, modal: ModalLike): Promise<void>;
199
+ }
200
+ //#endregion
201
+ //#region src/handlers/interaction/components/ComponentHandler.d.ts
202
+ /**
203
+ * Shared base the customId-routed component handlers extend on the HTTP transport.
204
+ *
205
+ * Not a public entry point. Extend {@link ButtonHandler}, {@link ModalHandler}, or one of the select menu
206
+ * bases instead. This class defines the customId decode, the route matching, and the source-message
207
+ * verbs `update` and `deferUpdate`.
208
+ *
209
+ * @typeParam Event - The component or modal interaction type this handler processes
210
+ * @typeParam Defs - The customId route definitions registered on the concrete handler
211
+ */
212
+ declare abstract class ComponentHandler<Event extends APIMessageComponentInteraction | APIModalSubmitInteraction, Defs extends readonly AnyCustomId[]> extends InteractionHandler<Event> implements HasComponentDefs<Defs> {
213
+ /** @internal */
214
+ readonly [ComponentDefsBrand]?: Defs;
215
+ /** Rewrite the source message this component interaction came from. */
216
+ protected update(response: ReplyResponse | string): Promise<SentMessage>;
217
+ /** Acknowledge the component without changing the source message. */
218
+ protected deferUpdate(): Promise<void>;
219
+ private decoded?;
220
+ private get route();
221
+ /**
222
+ * The decoded params of the single route this handler is registered for.
223
+ *
224
+ * Reading this decodes `this.event.data.custom_id` once (cached after the first read) and throws
225
+ * `StaleCustomId` or `InvalidCustomId` when the wire no longer matches the current shape, which the
226
+ * dispatcher boundary turns into a reply. On a handler registered for several routes this is
227
+ * `never`, so use {@link match} instead.
228
+ */
229
+ protected get params(): SingleParams<Defs>;
230
+ /**
231
+ * Run the arm for whichever route the component was minted from. Use this only when the handler is
232
+ * registered for several routes. A single-route handler reads `this.params` directly. On a multi-route
233
+ * handler `this.params` is `never`, so match is the only way to read the decoded params.
234
+ *
235
+ * Provide one arm per registered route, keyed by its prefix, and each arm receives that route's own
236
+ * decoded params. The arms cover every registered route prefix, checked at compile time, and a prefix
237
+ * unmatched at runtime throws `CustomIdMatchArmMissing`. Decoding runs before any arm, so a stale or
238
+ * corrupt wire throws before an arm body executes.
239
+ *
240
+ * @param arms - One callback per registered route, keyed by prefix.
241
+ * @returns The result of the arm that ran.
242
+ *
243
+ * @example
244
+ * ```ts
245
+ * \@ButtonRoute(Approve, Reject)
246
+ * class ReviewButtons extends ButtonHandler<[typeof Approve, typeof Reject]> {
247
+ * async execute() {
248
+ * await this.match({
249
+ * approve: ({ userId }) => this.reply(`approved <@${userId}>`),
250
+ * reject: ({ userId }) => this.reply(`rejected <@${userId}>`)
251
+ * });
252
+ * }
253
+ * }
254
+ * ```
255
+ */
256
+ protected match<Ret>(arms: MatchArms<Defs, Ret>): Promise<Ret>;
257
+ }
258
+ //#endregion
259
+ //#region src/handlers/interaction/components/SelectMenuHandler.d.ts
260
+ /** @internal */
261
+ type SelectInteraction<Data> = APIMessageComponentSelectMenuInteraction & {
262
+ data: Data;
263
+ };
264
+ /**
265
+ * Shared base the select menu handlers extend on the HTTP transport.
266
+ *
267
+ * Not a public entry point. Extend {@link StringMenuHandler}, {@link UserMenuHandler},
268
+ * {@link RoleMenuHandler}, {@link ChannelMenuHandler}, or {@link MentionableMenuHandler} instead. This
269
+ * class defines the `values` getter those bases share.
270
+ *
271
+ * @typeParam Event - The select menu interaction type this handler processes
272
+ * @typeParam Defs - The customId route definitions registered on the concrete handler
273
+ */
274
+ declare abstract class SelectMenuHandler<Event extends APIMessageComponentSelectMenuInteraction, Defs extends readonly AnyCustomId[]> extends ComponentHandler<Event, Defs> {
275
+ /** The values this select picked. On every kind but the string menu they are snowflake ids. */
276
+ protected get values(): string[];
277
+ }
278
+ /**
279
+ * Base class for a string select menu handler on the HTTP transport.
280
+ *
281
+ * Register the customId definitions with `@StringMenuRoute`, list the same ones in the generic, then read
282
+ * the chosen option values from `this.values`. Read `this.params` for a single route or `this.match` for
283
+ * several. Reply through the handler members, or rewrite the source message with `this.update`.
284
+ *
285
+ * @typeParam Defs - The customId definitions this handler decodes, e.g. `[typeof TopicsId]`.
286
+ *
287
+ * @example
288
+ * ```ts
289
+ * \@StringMenuRoute(TopicsId)
290
+ * class Topics extends StringMenuHandler<[typeof TopicsId]> {
291
+ * async execute() {
292
+ * const { userId } = this.params;
293
+ * await this.update(`<@${userId}> now follows ${this.values.join(', ')}`);
294
+ * }
295
+ * }
296
+ * ```
297
+ */
298
+ declare abstract class StringMenuHandler<Defs extends readonly AnyCustomId[]> extends SelectMenuHandler<SelectInteraction<APIMessageStringSelectInteractionData>, Defs> {
299
+ /** @internal */
300
+ readonly [ComponentKindBrand]?: InteractionKind.StringMenu;
301
+ }
302
+ /**
303
+ * Base class for a user select menu handler on the HTTP transport.
304
+ *
305
+ * Beside `this.values` this handler declares `this.users` and `this.members`. Register the customId
306
+ * definitions with `@UserMenuRoute` and list the same ones in the generic.
307
+ *
308
+ * @typeParam Defs - The customId definitions this handler decodes, e.g. `[typeof AssignId]`.
309
+ *
310
+ * @example
311
+ * ```ts
312
+ * \@UserMenuRoute(AssignId)
313
+ * class Assign extends UserMenuHandler<[typeof AssignId]> {
314
+ * async execute() {
315
+ * const { roleId } = this.params;
316
+ * await this.reply(`assigning ${this.users.size} member(s) to <@&${roleId}>`);
317
+ * }
318
+ * }
319
+ * ```
320
+ */
321
+ declare abstract class UserMenuHandler<Defs extends readonly AnyCustomId[]> extends SelectMenuHandler<SelectInteraction<APIMessageUserSelectInteractionData>, Defs> {
322
+ /** @internal */
323
+ readonly [ComponentKindBrand]?: InteractionKind.UserMenu;
324
+ /** The users this select picked. */
325
+ protected get users(): Collection<string, APIUser>;
326
+ /** The guild members behind the picked users. Discord resolves these only inside a guild. */
327
+ protected get members(): Collection<string, APIInteractionDataResolvedGuildMember>;
328
+ }
329
+ /**
330
+ * Base class for a role select menu handler on the HTTP transport.
331
+ *
332
+ * Beside `this.values` this handler declares `this.roles`. Register the customId definitions with
333
+ * `@RoleMenuRoute` and list the same ones in the generic.
334
+ *
335
+ * @typeParam Defs - The customId definitions this handler decodes, e.g. `[typeof GrantId]`.
336
+ *
337
+ * @example
338
+ * ```ts
339
+ * \@RoleMenuRoute(GrantId)
340
+ * class Grant extends RoleMenuHandler<[typeof GrantId]> {
341
+ * async execute() {
342
+ * await this.update(`granting ${this.roles.size} role(s)`);
343
+ * }
344
+ * }
345
+ * ```
346
+ */
347
+ declare abstract class RoleMenuHandler<Defs extends readonly AnyCustomId[]> extends SelectMenuHandler<SelectInteraction<APIMessageRoleSelectInteractionData>, Defs> {
348
+ /** @internal */
349
+ readonly [ComponentKindBrand]?: InteractionKind.RoleMenu;
350
+ /** The roles this select picked. */
351
+ protected get roles(): Collection<string, APIRole>;
352
+ }
353
+ /**
354
+ * Base class for a channel select menu handler on the HTTP transport.
355
+ *
356
+ * Beside `this.values` this handler declares `this.channels`. Register the customId definitions with
357
+ * `@ChannelMenuRoute` and list the same ones in the generic.
358
+ *
359
+ * @typeParam Defs - The customId definitions this handler decodes, e.g. `[typeof LogTargetId]`.
360
+ *
361
+ * @example
362
+ * ```ts
363
+ * \@ChannelMenuRoute(LogTargetId)
364
+ * class LogTarget extends ChannelMenuHandler<[typeof LogTargetId]> {
365
+ * async execute() {
366
+ * await this.update(`logging to ${this.channels.size} channel(s)`);
367
+ * }
368
+ * }
369
+ * ```
370
+ */
371
+ declare abstract class ChannelMenuHandler<Defs extends readonly AnyCustomId[]> extends SelectMenuHandler<SelectInteraction<APIMessageChannelSelectInteractionData>, Defs> {
372
+ /** @internal */
373
+ readonly [ComponentKindBrand]?: InteractionKind.ChannelMenu;
374
+ /** The channels this select picked. */
375
+ protected get channels(): Collection<string, APIInteractionDataResolvedChannel>;
376
+ }
377
+ /**
378
+ * Base class for a mentionable select menu handler on the HTTP transport.
379
+ *
380
+ * A mentionable menu accepts users and roles together. `this.users`, `this.members`, and `this.roles`
381
+ * can each come back empty.
382
+ *
383
+ * @typeParam Defs - The customId definitions this handler decodes, e.g. `[typeof InviteId]`.
384
+ *
385
+ * @example
386
+ * ```ts
387
+ * \@MentionableMenuRoute(InviteId)
388
+ * class Invite extends MentionableMenuHandler<[typeof InviteId]> {
389
+ * async execute() {
390
+ * await this.update(`inviting ${this.users.size} user(s) and ${this.roles.size} role(s)`);
391
+ * }
392
+ * }
393
+ * ```
394
+ */
395
+ declare abstract class MentionableMenuHandler<Defs extends readonly AnyCustomId[]> extends SelectMenuHandler<SelectInteraction<APIMessageMentionableSelectInteractionData>, Defs> {
396
+ /** @internal */
397
+ readonly [ComponentKindBrand]?: InteractionKind.MentionableMenu;
398
+ /** The users this select picked. */
399
+ protected get users(): Collection<string, APIUser>;
400
+ /** The guild members behind the picked users. Discord resolves these only inside a guild. */
401
+ protected get members(): Collection<string, APIInteractionDataResolvedGuildMember>;
402
+ /** The roles this select picked. */
403
+ protected get roles(): Collection<string, APIRole>;
404
+ }
405
+ //#endregion
406
+ //#region src/handlers/interaction/middlewareKinds.d.ts
407
+ interface Payloads {
408
+ [InteractionKind.Slash]: APIChatInputApplicationCommandInteraction;
409
+ [InteractionKind.Button]: APIMessageComponentButtonInteraction;
410
+ [InteractionKind.Modal]: APIModalSubmitInteraction;
411
+ [InteractionKind.StringMenu]: SelectInteraction<APIMessageStringSelectInteractionData>;
412
+ [InteractionKind.UserMenu]: SelectInteraction<APIMessageUserSelectInteractionData>;
413
+ [InteractionKind.RoleMenu]: SelectInteraction<APIMessageRoleSelectInteractionData>;
414
+ [InteractionKind.ChannelMenu]: SelectInteraction<APIMessageChannelSelectInteractionData>;
415
+ [InteractionKind.MentionableMenu]: SelectInteraction<APIMessageMentionableSelectInteractionData>;
416
+ [InteractionKind.MessageContextMenu]: APIMessageApplicationCommandInteraction;
417
+ [InteractionKind.UserContextMenu]: APIUserApplicationCommandInteraction;
418
+ }
419
+ type InteractionForKind = { [Kind in MiddlewareKind]: Payloads[Kind]; };
420
+ /** @internal */
421
+ type InteractionOf<Kind extends MiddlewareKind> = InteractionForKind[Kind];
422
+ //#endregion
423
+ //#region src/handlers/interaction/InteractionMiddleware.d.ts
424
+ /**
425
+ * Base class for interaction middleware on the HTTP transport.
426
+ *
427
+ * Middleware runs after the dispatcher builds the handler and before the gates, over the handler's own
428
+ * reply surface. Name the kinds in the generic and list the same ones in `{ kinds }`. Several kinds give
429
+ * `this.event` a union. Narrow it on `type` and `data.component_type`. A catchall reads every repliable
430
+ * kind.
431
+ *
432
+ * @typeParam Kind - One or more {@link InteractionKind} members. Defaults to every repliable kind.
433
+ *
434
+ * @example
435
+ * ```ts
436
+ * \@RegisterInteractionMiddleware({ kinds: [InteractionKind.Button] })
437
+ * class Audit extends InteractionMiddleware<InteractionKind.Button> {
438
+ * async execute() {
439
+ * this.logger.info(this.event.data.custom_id);
440
+ * }
441
+ * }
442
+ * ```
443
+ */
444
+ declare abstract class InteractionMiddleware<in out Kind extends MiddlewareKind = MiddlewareKind> extends RepliableHandler$1<InteractionOf<Kind>> {
445
+ /** @internal */
446
+ readonly [MiddlewareKindsBrand]?: Kind;
447
+ constructor(event: InteractionOf<Kind>, core: Core, dispatch: DispatchContext, sender: ReplySender);
448
+ /**
449
+ * Runs once the handler settles, newest middleware first. A refusal or a throw still reaches it,
450
+ * since seedcord calls it on every middleware whose `execute()` started. Implement it to release
451
+ * something this middleware took in `execute()`, such as a lock or an open span. A throw in here
452
+ * is logged and goes no further.
453
+ *
454
+ * @param result - How the dispatch ended. Either failure state carries the thrown value on `caught`.
455
+ *
456
+ * @example
457
+ * ```ts
458
+ * // the base declares it. an implementation carries `override`.
459
+ * override async after(result: DispatchResult) {
460
+ * this.lock.release();
461
+ * }
462
+ * ```
463
+ */
464
+ after?(result: DispatchResult): Promise<void>;
465
+ }
466
+ //#endregion
71
467
  //#region src/engine.d.ts
72
468
  /** Structural match for the Workers `ExecutionContext`. Pass it from the edge entry so post-202 work runs under `waitUntil`. */
73
469
  interface EngineContext {
@@ -178,86 +574,8 @@ type InjectedEmojiMap = { [K in keyof EmojiMap]: ResolvedEmoji; };
178
574
  /**
179
575
  * The bot's resolved emojis, keyed by {@link EmojiMap}. Filled by {@link EmojiInjector} during startup.
180
576
  * Throws if you read a key the injector did not fill.
181
- */
182
- declare const Emojis: InjectedEmojiMap;
183
- //#endregion
184
- //#region src/reply/ReplySender.d.ts
185
- /** The interaction payload fields the sender writes its wire from. */
186
- interface InteractionRef {
187
- readonly application_id: string;
188
- readonly id: string;
189
- readonly token: string;
190
- }
191
- /** The created message an http reply resolves to (the http `SentMessage` lens). */
192
- type SentMessage = APIMessage;
193
- /**
194
- * Writes interaction responses over the Discord REST callback and webhook endpoints. Construction is
195
- * internal to the repliable handler bases and the dispatcher.
196
- */
197
- declare class ReplySender extends BaseReplySender<SentMessage> {
198
- private readonly ref;
199
- private readonly rest;
200
- constructor(ref: InteractionRef, rest: REST, routeId: string, bus: Bus);
201
- protected writeReply(response: ReplyResponse | string, opts?: SendOpts): Promise<SentMessage | undefined>;
202
- protected writeDefer(opts?: DeferOpts): Promise<void>;
203
- protected writeDeferUpdate(): Promise<void>;
204
- protected writeUpdate(response: ReplyResponse | string): Promise<SentMessage | undefined>;
205
- protected writeFollowUp(response: ReplyResponse | string, opts?: SendOpts): Promise<SentMessage>;
206
- protected writeEditOriginal(response: ReplyResponse | string): Promise<SentMessage>;
207
- protected writeEditTarget(targetId: string, response: ReplyResponse | string): Promise<SentMessage>;
208
- protected writeDeleteOriginal(): Promise<void>;
209
- protected writeDeleteTarget(targetId: string): Promise<void>;
210
- protected writeModal(data: APIModalInteractionResponseCallbackData): Promise<void>;
211
- private callback;
212
- private editMessage;
213
- private rawFiles;
214
- private createdMessage;
215
- }
216
- //#endregion
217
- //#region src/handlers/interactionTypes.d.ts
218
- type ValidInteractionTypes = APIChatInputApplicationCommandInteraction | APIContextMenuInteraction | APIMessageComponentInteraction | APIModalSubmitInteraction | APIApplicationCommandAutocompleteInteraction;
219
- type Repliables = Exclude<ValidInteractionTypes, APIApplicationCommandAutocompleteInteraction>;
220
- //#endregion
221
- //#region src/handlers/RepliableHandler.d.ts
222
- /**
223
- * Shared base the repliable HTTP interaction handlers extend.
224
- *
225
- * Not a public entry point. Extend {@link SlashHandler}, {@link ButtonHandler}, {@link ModalHandler},
226
- * {@link ContextMenuHandler}, or one of the select menu bases instead. This class binds the core
227
- * reply base to the http sender.
228
- *
229
- * @typeParam Event - The repliable interaction type this handler processes
230
- */
231
- declare abstract class RepliableHandler$1<Event extends Repliables> extends RepliableHandler<Event, Core, SentMessage, never, ReplySender> {
232
- /** @internal */
233
- getEvent(): Event;
234
- protected buildSender(event: Event, core: Core, routeId: string): ReplySender;
235
- /**
236
- * Typed Discord REST API (`@discordjs/core/http-only`) over `core.rest`, one instance per core.
237
- * The interaction callbacks on `api.interactions` bypass the reply surface. The
238
- * `no-raw-interaction-acks` rule flags them in handler classes.
239
- */
240
- protected get api(): API;
241
- }
242
- //#endregion
243
- //#region src/handlers/interaction/InteractionHandler.d.ts
244
- /**
245
- * Shared base the repliable interaction handlers extend.
246
- *
247
- * Not a public entry point. Extend {@link SlashHandler}, {@link ContextMenuHandler}, {@link ButtonHandler},
248
- * {@link ModalHandler}, or one of the select menu bases instead. This class adds `showModal` on top
249
- * of the reply members.
250
- *
251
- * @typeParam Event - The repliable interaction type this handler processes
252
- */
253
- declare abstract class InteractionHandler<Event extends Repliables> extends RepliableHandler$1<Event> {
254
- constructor(event: Event, core: Core, dispatch?: DispatchContext);
255
- /**
256
- * Open a modal. Must be the initial response to this interaction. The modal kind rejects this call at
257
- * compile time (Discord forbids a modal in response to a modal).
258
- */
259
- protected showModal(this: InteractionHandler<Exclude<Repliables, APIModalSubmitInteraction>>, modal: ModalLike): Promise<void>;
260
- }
577
+ */
578
+ declare const Emojis: InjectedEmojiMap;
261
579
  //#endregion
262
580
  //#region src/handlers/interaction/SlashHandler.d.ts
263
581
  type SlashMatchArms<Route extends keyof SlashRegistry, Ret> = { [Key in Route]: (options: SlashOptions$1<Key>) => Promisable<Ret>; };
@@ -389,115 +707,6 @@ declare abstract class MessageContextMenuHandler<Names extends NamesFor<Applicat
389
707
  protected match<Ret>(arms: MessageMenuArms<Names, Ret>): Promise<Ret>;
390
708
  }
391
709
  //#endregion
392
- //#region src/handlers/interaction/AutocompleteHandler.d.ts
393
- type FocusedArms<Route extends keyof SlashRegistry, Ret> = { [Name in AutocompletableNames<Route>]: (value: string, respond: (choices: readonly APIApplicationCommandOptionChoice<ChoiceValueOf<EntryFor<Route, Name>>>[]) => Promise<void>) => Promisable<Ret>; };
394
- /**
395
- * Base class for an autocomplete handler on the HTTP transport.
396
- *
397
- * Pass the command route(s) from the generated registry as the generic. Branch on the focused field with
398
- * `this.match`, read already-entered sibling options with `this.options`, and find which command fired
399
- * with `this.route`.
400
- *
401
- * @typeParam Route - One or more route keys from {@link SlashRegistry}, e.g. `'search'`.
402
- */
403
- declare abstract class AutocompleteHandler<Route extends keyof SlashRegistry> extends BaseHandler<APIApplicationCommandAutocompleteInteraction, Core> {
404
- constructor(event: APIApplicationCommandAutocompleteInteraction, core: Core, dispatch?: DispatchContext);
405
- /** @internal */
406
- readonly [AutocompleteRouteBrand]?: Route;
407
- /**
408
- * Typed Discord REST API (`@discordjs/core/http-only`) over `core.rest`, one instance per core.
409
- */
410
- protected get api(): API;
411
- private resolver?;
412
- private get reader();
413
- /**
414
- * The focused option for this interaction. `value` is always the raw partial string the user is typing,
415
- * even for an integer or number option, so coerce it yourself when you need a number.
416
- */
417
- protected get focused(): FocusedField<Route>;
418
- /**
419
- * Run the arm for the focused field. An autocomplete always dispatches by which field is focused.
420
- * Match is how you read it.
421
- *
422
- * Provide one arm per autocompletable field across the registered commands, keyed by field name. Each
423
- * arm receives the focused partial value and a `respond` typed to that field's choice value. The
424
- * arms must cover every autocompletable field, a missing field or an unknown key is a compile error. A
425
- * focused field with no arm, only reachable from a stale-deployed command, throws at runtime.
426
- *
427
- * @param arms - One handler per autocompletable field, keyed by field name.
428
- * @returns The result of the arm that ran.
429
- */
430
- protected match<Ret>(arms: FocusedArms<Route, Ret>): Promise<Ret>;
431
- /** Send autocomplete suggestions, callback type 8. Prefer {@link match}, which restricts each field's choices to its declared type. */
432
- protected respond(choices: readonly APIApplicationCommandOptionChoice[]): Promise<void>;
433
- /** The firing command route, for a field whose completion differs per registered command. */
434
- protected get route(): Route;
435
- /**
436
- * The already-entered options on this command, restricted to the kinds Discord resolves during autocomplete
437
- * (string, integer, number, boolean) with every read nullable, since a sibling is partial while the user
438
- * types the focused field. The focused field is on `this.focused`.
439
- */
440
- protected get options(): AutocompleteOptions<Route>;
441
- }
442
- //#endregion
443
- //#region src/handlers/interaction/components/ComponentHandler.d.ts
444
- /**
445
- * Shared base the customId-routed component handlers extend on the HTTP transport.
446
- *
447
- * Not a public entry point. Extend {@link ButtonHandler}, {@link ModalHandler}, or one of the select menu
448
- * bases instead. This class defines the customId decode, the route matching, and the source-message
449
- * verbs `update` and `deferUpdate`.
450
- *
451
- * @typeParam Event - The component or modal interaction type this handler processes
452
- * @typeParam Defs - The customId route definitions registered on the concrete handler
453
- */
454
- declare abstract class ComponentHandler<Event extends APIMessageComponentInteraction | APIModalSubmitInteraction, Defs extends readonly AnyCustomId[]> extends InteractionHandler<Event> implements HasComponentDefs<Defs> {
455
- /** @internal */
456
- readonly [ComponentDefsBrand]?: Defs;
457
- /** Rewrite the source message this component interaction came from. */
458
- protected update(response: ReplyResponse | string): Promise<SentMessage>;
459
- /** Acknowledge the component without changing the source message. */
460
- protected deferUpdate(): Promise<void>;
461
- private decoded?;
462
- private get route();
463
- /**
464
- * The decoded params of the single route this handler is registered for.
465
- *
466
- * Reading this decodes `this.event.data.custom_id` once (cached after the first read) and throws
467
- * `StaleCustomId` or `InvalidCustomId` when the wire no longer matches the current shape, which the
468
- * dispatcher boundary turns into a reply. On a handler registered for several routes this is
469
- * `never`, so use {@link match} instead.
470
- */
471
- protected get params(): SingleParams<Defs>;
472
- /**
473
- * Run the arm for whichever route the component was minted from. Use this only when the handler is
474
- * registered for several routes. A single-route handler reads `this.params` directly. On a multi-route
475
- * handler `this.params` is `never`, so match is the only way to read the decoded params.
476
- *
477
- * Provide one arm per registered route, keyed by its prefix, and each arm receives that route's own
478
- * decoded params. The arms cover every registered route prefix, checked at compile time, and a prefix
479
- * unmatched at runtime throws `CustomIdMatchArmMissing`. Decoding runs before any arm, so a stale or
480
- * corrupt wire throws before an arm body executes.
481
- *
482
- * @param arms - One callback per registered route, keyed by prefix.
483
- * @returns The result of the arm that ran.
484
- *
485
- * @example
486
- * ```ts
487
- * \@ButtonRoute(Approve, Reject)
488
- * class ReviewButtons extends ButtonHandler<[typeof Approve, typeof Reject]> {
489
- * async execute() {
490
- * await this.match({
491
- * approve: ({ userId }) => this.reply(`approved <@${userId}>`),
492
- * reject: ({ userId }) => this.reply(`rejected <@${userId}>`)
493
- * });
494
- * }
495
- * }
496
- * ```
497
- */
498
- protected match<Ret>(arms: MatchArms<Defs, Ret>): Promise<Ret>;
499
- }
500
- //#endregion
501
710
  //#region src/handlers/interaction/components/ButtonHandler.d.ts
502
711
  /**
503
712
  * Base class for a button interaction handler on the HTTP transport.
@@ -549,152 +758,6 @@ declare abstract class ModalHandler<Defs extends readonly AnyCustomId[]> extends
549
758
  private ensureSourceMessage;
550
759
  }
551
760
  //#endregion
552
- //#region src/handlers/interaction/components/SelectMenuHandler.d.ts
553
- type SelectInteraction<Data> = APIMessageComponentSelectMenuInteraction & {
554
- data: Data;
555
- };
556
- /**
557
- * Shared base the select menu handlers extend on the HTTP transport.
558
- *
559
- * Not a public entry point. Extend {@link StringMenuHandler}, {@link UserMenuHandler},
560
- * {@link RoleMenuHandler}, {@link ChannelMenuHandler}, or {@link MentionableMenuHandler} instead. This
561
- * class defines the `values` getter those bases share.
562
- *
563
- * @typeParam Event - The select menu interaction type this handler processes
564
- * @typeParam Defs - The customId route definitions registered on the concrete handler
565
- */
566
- declare abstract class SelectMenuHandler<Event extends APIMessageComponentSelectMenuInteraction, Defs extends readonly AnyCustomId[]> extends ComponentHandler<Event, Defs> {
567
- /** The values this select picked. On every kind but the string menu they are snowflake ids. */
568
- protected get values(): string[];
569
- }
570
- /**
571
- * Base class for a string select menu handler on the HTTP transport.
572
- *
573
- * Register the customId definitions with `@StringMenuRoute`, list the same ones in the generic, then read
574
- * the chosen option values from `this.values`. Read `this.params` for a single route or `this.match` for
575
- * several. Reply through the handler members, or rewrite the source message with `this.update`.
576
- *
577
- * @typeParam Defs - The customId definitions this handler decodes, e.g. `[typeof TopicsId]`.
578
- *
579
- * @example
580
- * ```ts
581
- * \@StringMenuRoute(TopicsId)
582
- * class Topics extends StringMenuHandler<[typeof TopicsId]> {
583
- * async execute() {
584
- * const { userId } = this.params;
585
- * await this.update(`<@${userId}> now follows ${this.values.join(', ')}`);
586
- * }
587
- * }
588
- * ```
589
- */
590
- declare abstract class StringMenuHandler<Defs extends readonly AnyCustomId[]> extends SelectMenuHandler<SelectInteraction<APIMessageStringSelectInteractionData>, Defs> {
591
- /** @internal */
592
- readonly [ComponentKindBrand]?: InteractionKind.StringMenu;
593
- }
594
- /**
595
- * Base class for a user select menu handler on the HTTP transport.
596
- *
597
- * Beside `this.values` this handler declares `this.users` and `this.members`. Register the customId
598
- * definitions with `@UserMenuRoute` and list the same ones in the generic.
599
- *
600
- * @typeParam Defs - The customId definitions this handler decodes, e.g. `[typeof AssignId]`.
601
- *
602
- * @example
603
- * ```ts
604
- * \@UserMenuRoute(AssignId)
605
- * class Assign extends UserMenuHandler<[typeof AssignId]> {
606
- * async execute() {
607
- * const { roleId } = this.params;
608
- * await this.reply(`assigning ${this.users.size} member(s) to <@&${roleId}>`);
609
- * }
610
- * }
611
- * ```
612
- */
613
- declare abstract class UserMenuHandler<Defs extends readonly AnyCustomId[]> extends SelectMenuHandler<SelectInteraction<APIMessageUserSelectInteractionData>, Defs> {
614
- /** @internal */
615
- readonly [ComponentKindBrand]?: InteractionKind.UserMenu;
616
- /** The users this select picked. */
617
- protected get users(): Collection<string, APIUser>;
618
- /** The guild members behind the picked users. Discord resolves these only inside a guild. */
619
- protected get members(): Collection<string, APIInteractionDataResolvedGuildMember>;
620
- }
621
- /**
622
- * Base class for a role select menu handler on the HTTP transport.
623
- *
624
- * Beside `this.values` this handler declares `this.roles`. Register the customId definitions with
625
- * `@RoleMenuRoute` and list the same ones in the generic.
626
- *
627
- * @typeParam Defs - The customId definitions this handler decodes, e.g. `[typeof GrantId]`.
628
- *
629
- * @example
630
- * ```ts
631
- * \@RoleMenuRoute(GrantId)
632
- * class Grant extends RoleMenuHandler<[typeof GrantId]> {
633
- * async execute() {
634
- * await this.update(`granting ${this.roles.size} role(s)`);
635
- * }
636
- * }
637
- * ```
638
- */
639
- declare abstract class RoleMenuHandler<Defs extends readonly AnyCustomId[]> extends SelectMenuHandler<SelectInteraction<APIMessageRoleSelectInteractionData>, Defs> {
640
- /** @internal */
641
- readonly [ComponentKindBrand]?: InteractionKind.RoleMenu;
642
- /** The roles this select picked. */
643
- protected get roles(): Collection<string, APIRole>;
644
- }
645
- /**
646
- * Base class for a channel select menu handler on the HTTP transport.
647
- *
648
- * Beside `this.values` this handler declares `this.channels`. Register the customId definitions with
649
- * `@ChannelMenuRoute` and list the same ones in the generic.
650
- *
651
- * @typeParam Defs - The customId definitions this handler decodes, e.g. `[typeof LogTargetId]`.
652
- *
653
- * @example
654
- * ```ts
655
- * \@ChannelMenuRoute(LogTargetId)
656
- * class LogTarget extends ChannelMenuHandler<[typeof LogTargetId]> {
657
- * async execute() {
658
- * await this.update(`logging to ${this.channels.size} channel(s)`);
659
- * }
660
- * }
661
- * ```
662
- */
663
- declare abstract class ChannelMenuHandler<Defs extends readonly AnyCustomId[]> extends SelectMenuHandler<SelectInteraction<APIMessageChannelSelectInteractionData>, Defs> {
664
- /** @internal */
665
- readonly [ComponentKindBrand]?: InteractionKind.ChannelMenu;
666
- /** The channels this select picked. */
667
- protected get channels(): Collection<string, APIInteractionDataResolvedChannel>;
668
- }
669
- /**
670
- * Base class for a mentionable select menu handler on the HTTP transport.
671
- *
672
- * A mentionable menu accepts users and roles together. `this.users`, `this.members`, and `this.roles`
673
- * can each come back empty.
674
- *
675
- * @typeParam Defs - The customId definitions this handler decodes, e.g. `[typeof InviteId]`.
676
- *
677
- * @example
678
- * ```ts
679
- * \@MentionableMenuRoute(InviteId)
680
- * class Invite extends MentionableMenuHandler<[typeof InviteId]> {
681
- * async execute() {
682
- * await this.update(`inviting ${this.users.size} user(s) and ${this.roles.size} role(s)`);
683
- * }
684
- * }
685
- * ```
686
- */
687
- declare abstract class MentionableMenuHandler<Defs extends readonly AnyCustomId[]> extends SelectMenuHandler<SelectInteraction<APIMessageMentionableSelectInteractionData>, Defs> {
688
- /** @internal */
689
- readonly [ComponentKindBrand]?: InteractionKind.MentionableMenu;
690
- /** The users this select picked. */
691
- protected get users(): Collection<string, APIUser>;
692
- /** The guild members behind the picked users. Discord resolves these only inside a guild. */
693
- protected get members(): Collection<string, APIInteractionDataResolvedGuildMember>;
694
- /** The roles this select picked. */
695
- protected get roles(): Collection<string, APIRole>;
696
- }
697
- //#endregion
698
761
  //#region src/subscribers/index.d.ts
699
762
  /**
700
763
  * Base class for an HTTP subscriber, binding `this.core` to the HTTP {@link Core}.
@@ -726,7 +789,7 @@ interface PageContext {
726
789
  }
727
790
  //#endregion
728
791
  //#region src/pagination/Paginator.d.ts
729
- type PaginatorHandlerCtor<Prefix extends string> = new (event: APIMessageComponentButtonInteraction, core: Core) => ButtonHandler<[PageCursor<Prefix>]> & {
792
+ type PaginatorHandlerCtor<Prefix extends string> = new (...args: ConstructorParameters<typeof ButtonHandler>) => ButtonHandler<[PageCursor<Prefix>]> & {
730
793
  execute(): Promise<void>;
731
794
  };
732
795
  /**
@@ -880,5 +943,5 @@ declare function Gated<const Gates extends NonEmptyTuple<Gate<GateContextBase>>>
880
943
  //#region src/version.d.ts
881
944
  declare const version: string;
882
945
  //#endregion
883
- export { InjectedEmojiMap as A, SlashHandler as C, ReplySender as D, InteractionRef as E, EngineContext as F, Core as I, HttpConfig as L, SelectedMentionables as M, SlashOptions$1 as N, SentMessage as O, createSeedcord as P, HttpEdgeConfig as R, UserContextMenuHandler as S, RepliableHandler$1 as T, ModalHandler as _, CursorSource as a, AutocompleteHandler as b, PageContext as c, ChannelMenuHandler as d, MentionableMenuHandler as f, UserMenuHandler as g, StringMenuHandler as h, ArraySource as i, ModalFields as j, Emojis as k, Subscriber$1 as l, SelectMenuHandler as m, Gated as n, PageSource as o, RoleMenuHandler as p, InteractionGateContext as r, Paginator as s, version as t, WebhookLog$1 as u, ButtonHandler as v, InteractionHandler as w, MessageContextMenuHandler as x, ComponentHandler as y, HttpServerConfig as z };
884
- //# sourceMappingURL=edge.index-BW-YQh7m.d.mts.map
946
+ export { ComponentHandler as A, HttpServerConfig as B, InteractionMiddleware as C, SelectMenuHandler as D, RoleMenuHandler as E, SentMessage as F, AutocompleteHandler as I, Core as L, RepliableHandler$1 as M, InteractionRef as N, StringMenuHandler as O, ReplySender as P, HttpConfig as R, EngineContext as S, MentionableMenuHandler as T, InjectedEmojiMap as _, CursorSource as a, SlashOptions$1 as b, PageContext as c, ModalHandler as d, ButtonHandler as f, Emojis as g, SlashHandler as h, ArraySource as i, InteractionHandler as j, UserMenuHandler as k, Subscriber$1 as l, UserContextMenuHandler as m, Gated as n, PageSource as o, MessageContextMenuHandler as p, InteractionGateContext as r, Paginator as s, version as t, WebhookLog$1 as u, ModalFields as v, ChannelMenuHandler as w, createSeedcord as x, SelectedMentionables as y, HttpEdgeConfig as z };
947
+ //# sourceMappingURL=edge.index-CgLU9PiF.d.mts.map