@went.tf/discord-bot-framework 2.4.0 → 2.6.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.
Files changed (31) hide show
  1. package/README.md +112 -0
  2. package/build/.tsbuildinfo +1 -1
  3. package/build/index.d.ts +1 -0
  4. package/build/index.d.ts.map +1 -1
  5. package/build/index.js +1 -0
  6. package/build/index.js.map +1 -1
  7. package/build/webhook/create-webhook-interaction-responder.d.ts +33 -0
  8. package/build/webhook/create-webhook-interaction-responder.d.ts.map +1 -0
  9. package/build/webhook/create-webhook-interaction-responder.js +25 -0
  10. package/build/webhook/create-webhook-interaction-responder.js.map +1 -0
  11. package/build/webhook/create-webhook-only-client.d.ts +35 -0
  12. package/build/webhook/create-webhook-only-client.d.ts.map +1 -0
  13. package/build/webhook/create-webhook-only-client.js +36 -0
  14. package/build/webhook/create-webhook-only-client.js.map +1 -0
  15. package/build/webhook/handle-webhook-interaction-request.d.ts +51 -0
  16. package/build/webhook/handle-webhook-interaction-request.d.ts.map +1 -0
  17. package/build/webhook/handle-webhook-interaction-request.js +45 -0
  18. package/build/webhook/handle-webhook-interaction-request.js.map +1 -0
  19. package/build/webhook/index.d.ts +6 -0
  20. package/build/webhook/index.d.ts.map +1 -0
  21. package/build/webhook/index.js +11 -0
  22. package/build/webhook/index.js.map +1 -0
  23. package/build/webhook/interaction-from-webhook-payload.d.ts +31 -0
  24. package/build/webhook/interaction-from-webhook-payload.d.ts.map +1 -0
  25. package/build/webhook/interaction-from-webhook-payload.js +91 -0
  26. package/build/webhook/interaction-from-webhook-payload.js.map +1 -0
  27. package/build/webhook/verify-interaction-request.d.ts +22 -0
  28. package/build/webhook/verify-interaction-request.d.ts.map +1 -0
  29. package/build/webhook/verify-interaction-request.js +37 -0
  30. package/build/webhook/verify-interaction-request.js.map +1 -0
  31. package/package.json +5 -1
package/build/index.d.ts CHANGED
@@ -4,5 +4,6 @@ export * from './api-client/index.js';
4
4
  export * from './interactions/index.js';
5
5
  export * from './commands/index.js';
6
6
  export * from './client/index.js';
7
+ export * from './webhook/index.js';
7
8
  export * from './utils/index.js';
8
9
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAIA,cAAc,mBAAmB,CAAC;AAClC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,uBAAuB,CAAC;AACtC,cAAc,yBAAyB,CAAC;AACxC,cAAc,qBAAqB,CAAC;AACpC,cAAc,mBAAmB,CAAC;AAClC,cAAc,kBAAkB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAIA,cAAc,mBAAmB,CAAC;AAClC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,uBAAuB,CAAC;AACtC,cAAc,yBAAyB,CAAC;AACxC,cAAc,qBAAqB,CAAC;AACpC,cAAc,mBAAmB,CAAC;AAClC,cAAc,oBAAoB,CAAC;AACnC,cAAc,kBAAkB,CAAC"}
package/build/index.js CHANGED
@@ -8,5 +8,6 @@ export * from './api-client/index.js';
8
8
  export * from './interactions/index.js';
9
9
  export * from './commands/index.js';
10
10
  export * from './client/index.js';
11
+ export * from './webhook/index.js';
11
12
  export * from './utils/index.js';
12
13
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,0EAA0E;AAC1E,6CAA6C;AAC7C,sCAAsC;AACtC,wCAAwC;AACxC,cAAc,mBAAmB,CAAC;AAClC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,uBAAuB,CAAC;AACtC,cAAc,yBAAyB,CAAC;AACxC,cAAc,qBAAqB,CAAC;AACpC,cAAc,mBAAmB,CAAC;AAClC,cAAc,kBAAkB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,0EAA0E;AAC1E,6CAA6C;AAC7C,sCAAsC;AACtC,wCAAwC;AACxC,cAAc,mBAAmB,CAAC;AAClC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,uBAAuB,CAAC;AACtC,cAAc,yBAAyB,CAAC;AACxC,cAAc,qBAAqB,CAAC;AACpC,cAAc,mBAAmB,CAAC;AAClC,cAAc,oBAAoB,CAAC;AACnC,cAAc,kBAAkB,CAAC"}
@@ -0,0 +1,33 @@
1
+ import { REST } from '@discordjs/rest';
2
+ import { RESTPatchAPIWebhookWithTokenMessageJSONBody, RESTPostAPIWebhookWithTokenJSONBody, RESTPostAPIWebhookWithTokenResult } from 'discord-api-types/v10';
3
+ export interface CreateWebhookInteractionResponderOptions {
4
+ rest: REST;
5
+ applicationId: string;
6
+ /** The responding interaction's own token (`APIInteraction.token`), valid for 15 minutes after receipt. */
7
+ interactionToken: string;
8
+ }
9
+ export interface WebhookInteractionResponder {
10
+ /** `PATCH /webhooks/{application.id}/{interaction.token}/messages/@original` - edits the initial response (including a deferred one). */
11
+ editReply(body: RESTPatchAPIWebhookWithTokenMessageJSONBody): Promise<unknown>;
12
+ /** `POST /webhooks/{application.id}/{interaction.token}` - sends an additional message after the initial response. */
13
+ followUp(body: RESTPostAPIWebhookWithTokenJSONBody): Promise<RESTPostAPIWebhookWithTokenResult>;
14
+ /** `DELETE /webhooks/{application.id}/{interaction.token}/messages/@original` - deletes the initial response. */
15
+ deleteReply(): Promise<void>;
16
+ }
17
+ /**
18
+ * REST counterpart to editing/following-up on an interaction once it's
19
+ * already been given its initial response - built on `@discordjs/rest` (an
20
+ * existing peer dependency, same client `createCommandRegistrar` already
21
+ * uses) rather than a live discord.js `Client`, since webhook mode has none.
22
+ *
23
+ * This is *not* a drop-in replacement for discord.js's
24
+ * `Interaction#reply()`/`editReply()`/`options.get*()` surface - it only
25
+ * covers what happens after `handleWebhookInteractionRequest`'s synchronous
26
+ * response (the initial `reply()`/`deferReply()` equivalent is just the
27
+ * `APIInteractionResponse` your `onInteraction` callback returns). Mimicking
28
+ * discord.js's full `Interaction` shape closely enough for existing
29
+ * gateway-based handler code to run unmodified against it is real,
30
+ * unvalidated design work - see CLAUDE.md's `./webhook` design-decision entry.
31
+ */
32
+ export declare function createWebhookInteractionResponder(options: CreateWebhookInteractionResponderOptions): WebhookInteractionResponder;
33
+ //# sourceMappingURL=create-webhook-interaction-responder.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"create-webhook-interaction-responder.d.ts","sourceRoot":"","sources":["../../src/webhook/create-webhook-interaction-responder.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAC;AACvC,OAAO,EAAE,2CAA2C,EAAE,mCAAmC,EAAE,iCAAiC,EAAU,MAAM,uBAAuB,CAAC;AAEpK,MAAM,WAAW,wCAAwC;IACvD,IAAI,EAAE,IAAI,CAAC;IACX,aAAa,EAAE,MAAM,CAAC;IACtB,2GAA2G;IAC3G,gBAAgB,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,2BAA2B;IAC1C,yIAAyI;IACzI,SAAS,CAAC,IAAI,EAAE,2CAA2C,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAC/E,sHAAsH;IACtH,QAAQ,CAAC,IAAI,EAAE,mCAAmC,GAAG,OAAO,CAAC,iCAAiC,CAAC,CAAC;IAChG,iHAAiH;IACjH,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CAC9B;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,iCAAiC,CAAC,OAAO,EAAE,wCAAwC,GAAG,2BAA2B,CAQhI"}
@@ -0,0 +1,25 @@
1
+ import { Routes } from 'discord-api-types/v10';
2
+ /**
3
+ * REST counterpart to editing/following-up on an interaction once it's
4
+ * already been given its initial response - built on `@discordjs/rest` (an
5
+ * existing peer dependency, same client `createCommandRegistrar` already
6
+ * uses) rather than a live discord.js `Client`, since webhook mode has none.
7
+ *
8
+ * This is *not* a drop-in replacement for discord.js's
9
+ * `Interaction#reply()`/`editReply()`/`options.get*()` surface - it only
10
+ * covers what happens after `handleWebhookInteractionRequest`'s synchronous
11
+ * response (the initial `reply()`/`deferReply()` equivalent is just the
12
+ * `APIInteractionResponse` your `onInteraction` callback returns). Mimicking
13
+ * discord.js's full `Interaction` shape closely enough for existing
14
+ * gateway-based handler code to run unmodified against it is real,
15
+ * unvalidated design work - see CLAUDE.md's `./webhook` design-decision entry.
16
+ */
17
+ export function createWebhookInteractionResponder(options) {
18
+ const { rest, applicationId, interactionToken } = options;
19
+ return {
20
+ editReply: (body) => rest.patch(Routes.webhookMessage(applicationId, interactionToken, '@original'), { body }),
21
+ followUp: (body) => rest.post(Routes.webhook(applicationId, interactionToken), { body }),
22
+ deleteReply: () => rest.delete(Routes.webhookMessage(applicationId, interactionToken, '@original')),
23
+ };
24
+ }
25
+ //# sourceMappingURL=create-webhook-interaction-responder.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"create-webhook-interaction-responder.js","sourceRoot":"","sources":["../../src/webhook/create-webhook-interaction-responder.ts"],"names":[],"mappings":"AACA,OAAO,EAAuH,MAAM,EAAE,MAAM,uBAAuB,CAAC;AAkBpK;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,iCAAiC,CAAC,OAAiD;IACjG,MAAM,EAAE,IAAI,EAAE,aAAa,EAAE,gBAAgB,EAAE,GAAG,OAAO,CAAC;IAE1D,OAAO;QACL,SAAS,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,cAAc,CAAC,aAAa,EAAE,gBAAgB,EAAE,WAAW,CAAC,EAAE,EAAE,IAAI,EAAE,CAAC;QAC9G,QAAQ,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,aAAa,EAAE,gBAAgB,CAAC,EAAE,EAAE,IAAI,EAAE,CAA+C;QACtI,WAAW,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,cAAc,CAAC,aAAa,EAAE,gBAAgB,EAAE,WAAW,CAAC,CAAkB;KACrH,CAAC;AACJ,CAAC"}
@@ -0,0 +1,35 @@
1
+ import { Client, ClientOptions } from 'discord.js';
2
+ export interface CreateWebhookOnlyClientOptions extends Omit<ClientOptions, 'intents'> {
3
+ /** No gateway connection is ever opened, so no intents actually apply - defaults to `[]`. */
4
+ intents?: ClientOptions['intents'];
5
+ token: string;
6
+ }
7
+ /**
8
+ * Builds a discord.js `Client` for webhook (HTTP Interactions Endpoint) mode:
9
+ * fully public API (`new Client()` + `Client#rest.setToken()`, both documented),
10
+ * but deliberately **never calls `Client#login()`**, since `login()`
11
+ * unconditionally opens a gateway WebSocket connection
12
+ * (`this.ws.connect()`, no way to opt out) - the entire reason a bot would
13
+ * reach for `./webhook` in the first place.
14
+ *
15
+ * The resulting client's `rest` is fully authenticated (same
16
+ * `rest.setToken()` call `login()` itself makes), so `Interaction#reply()`/
17
+ * `deferReply()`/`editReply()`/etc. work normally - they only ever call
18
+ * `this.client.rest` against `Routes.interactionCallback()`, with no
19
+ * `client.application`/gateway dependency. `client.guilds`/`client.channels`
20
+ * caches stay permanently empty, though - see `interactionFromWebhookPayload`'s
21
+ * doc comment for what that does and doesn't affect.
22
+ *
23
+ * Typed as `Client<true>` (discord.js's "ready" client) rather than the more
24
+ * literally-accurate `Client<false>`, purely so the result can be passed to
25
+ * `interactionFromWebhookPayload`/`dispatch*`/`createInteractionRouter`
26
+ * without a cast at every call site - every discord.js interaction class's
27
+ * own constructor requires `Client<true>` regardless of whether the client
28
+ * actually went through the gateway ready lifecycle. This client never does
29
+ * (there's no gateway connection to become ready on), so anything gated by
30
+ * `Ready` at the type level but genuinely absent at runtime -
31
+ * `client.user`/`client.application` chief among them - will be `null`
32
+ * despite what its type claims; avoid touching those in webhook mode.
33
+ */
34
+ export declare function createWebhookOnlyClient(options: CreateWebhookOnlyClientOptions): Client<true>;
35
+ //# sourceMappingURL=create-webhook-only-client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"create-webhook-only-client.d.ts","sourceRoot":"","sources":["../../src/webhook/create-webhook-only-client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAEnD,MAAM,WAAW,8BAA+B,SAAQ,IAAI,CAAC,aAAa,EAAE,SAAS,CAAC;IACpF,6FAA6F;IAC7F,OAAO,CAAC,EAAE,aAAa,CAAC,SAAS,CAAC,CAAC;IACnC,KAAK,EAAE,MAAM,CAAC;CACf;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,8BAA8B,GAAG,MAAM,CAAC,IAAI,CAAC,CAM7F"}
@@ -0,0 +1,36 @@
1
+ import { Client } from 'discord.js';
2
+ /**
3
+ * Builds a discord.js `Client` for webhook (HTTP Interactions Endpoint) mode:
4
+ * fully public API (`new Client()` + `Client#rest.setToken()`, both documented),
5
+ * but deliberately **never calls `Client#login()`**, since `login()`
6
+ * unconditionally opens a gateway WebSocket connection
7
+ * (`this.ws.connect()`, no way to opt out) - the entire reason a bot would
8
+ * reach for `./webhook` in the first place.
9
+ *
10
+ * The resulting client's `rest` is fully authenticated (same
11
+ * `rest.setToken()` call `login()` itself makes), so `Interaction#reply()`/
12
+ * `deferReply()`/`editReply()`/etc. work normally - they only ever call
13
+ * `this.client.rest` against `Routes.interactionCallback()`, with no
14
+ * `client.application`/gateway dependency. `client.guilds`/`client.channels`
15
+ * caches stay permanently empty, though - see `interactionFromWebhookPayload`'s
16
+ * doc comment for what that does and doesn't affect.
17
+ *
18
+ * Typed as `Client<true>` (discord.js's "ready" client) rather than the more
19
+ * literally-accurate `Client<false>`, purely so the result can be passed to
20
+ * `interactionFromWebhookPayload`/`dispatch*`/`createInteractionRouter`
21
+ * without a cast at every call site - every discord.js interaction class's
22
+ * own constructor requires `Client<true>` regardless of whether the client
23
+ * actually went through the gateway ready lifecycle. This client never does
24
+ * (there's no gateway connection to become ready on), so anything gated by
25
+ * `Ready` at the type level but genuinely absent at runtime -
26
+ * `client.user`/`client.application` chief among them - will be `null`
27
+ * despite what its type claims; avoid touching those in webhook mode.
28
+ */
29
+ export function createWebhookOnlyClient(options) {
30
+ const { token, intents = [], ...clientOptions } = options;
31
+ const client = new Client({ intents, ...clientOptions });
32
+ client.token = token;
33
+ client.rest.setToken(token);
34
+ return client;
35
+ }
36
+ //# sourceMappingURL=create-webhook-only-client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"create-webhook-only-client.js","sourceRoot":"","sources":["../../src/webhook/create-webhook-only-client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAiB,MAAM,YAAY,CAAC;AAQnD;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,MAAM,UAAU,uBAAuB,CAAC,OAAuC;IAC7E,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,EAAE,EAAE,GAAG,aAAa,EAAE,GAAG,OAAO,CAAC;IAC1D,MAAM,MAAM,GAAG,IAAI,MAAM,CAAC,EAAE,OAAO,EAAE,GAAG,aAAa,EAAE,CAAC,CAAC;IACzD,MAAM,CAAC,KAAK,GAAG,KAAK,CAAC;IACrB,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;IAC5B,OAAO,MAAsB,CAAC;AAChC,CAAC"}
@@ -0,0 +1,51 @@
1
+ import { APIInteraction, APIInteractionResponse } from 'discord-api-types/v10';
2
+ import { NestableLogger } from '../logger/types.js';
3
+ export interface WebhookInteractionRequest {
4
+ /** The request's `X-Signature-Ed25519` header. */
5
+ signature: string | undefined;
6
+ /** The request's `X-Signature-Timestamp` header. */
7
+ timestamp: string | undefined;
8
+ /** The raw (unparsed) request body, exactly as received - required for signature verification. */
9
+ rawBody: string | Buffer;
10
+ }
11
+ export interface WebhookInteractionResponse {
12
+ status: number;
13
+ body: APIInteractionResponse | {
14
+ error: string;
15
+ } | Record<string, never>;
16
+ }
17
+ export interface HandleWebhookInteractionRequestOptions {
18
+ /** The bot's Ed25519 application public key, from the Discord developer portal, as a hex string. */
19
+ publicKey: string;
20
+ logger: NestableLogger;
21
+ /**
22
+ * Called for every interaction that isn't Discord's own PING handshake
23
+ * check. Its return value becomes the HTTP response body sent back to
24
+ * Discord as the interaction's initial response (e.g. a `CHANNEL_MESSAGE_WITH_SOURCE`
25
+ * or a `DEFERRED_CHANNEL_MESSAGE_WITH_SOURCE` to be followed up on later via
26
+ * `createWebhookInteractionResponder`).
27
+ *
28
+ * If you instead bridge into a real discord.js interaction via
29
+ * `interactionFromWebhookPayload` and dispatch it through
30
+ * `dispatchChatInputCommand`/`createInteractionRouter`, the handler's own
31
+ * `.reply()`/`.deferReply()` call already sends the actual response via
32
+ * REST before this resolves - return nothing (`void`) in that case, and a
33
+ * generic 200 ack is sent back to Discord's original request instead.
34
+ * **This dual response path (a real REST call already made mid-handler,
35
+ * plus a separate bare HTTP ack to the original webhook POST) is unverified
36
+ * against live Discord traffic** - see this module's CLAUDE.md entry.
37
+ */
38
+ onInteraction: (interaction: APIInteraction) => APIInteractionResponse | void | Promise<APIInteractionResponse | void>;
39
+ }
40
+ /**
41
+ * Framework-agnostic core of an HTTP Interactions endpoint: verifies the
42
+ * request's Ed25519 signature, answers Discord's PING (type 1) validation
43
+ * handshake with PONG directly, and otherwise hands the parsed interaction to
44
+ * `onInteraction`. Deliberately takes/returns plain data (raw body + headers
45
+ * in, `{ status, body }` out) instead of an `http.IncomingMessage`/Express
46
+ * `Request`/etc., so it can be wired into any HTTP layer a bot already uses -
47
+ * this package doesn't otherwise depend on one, and picking one here would be
48
+ * a bigger commitment than this function needs to make.
49
+ */
50
+ export declare function handleWebhookInteractionRequest(request: WebhookInteractionRequest, options: HandleWebhookInteractionRequestOptions): Promise<WebhookInteractionResponse>;
51
+ //# sourceMappingURL=handle-webhook-interaction-request.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"handle-webhook-interaction-request.d.ts","sourceRoot":"","sources":["../../src/webhook/handle-webhook-interaction-request.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,sBAAsB,EAA4C,MAAM,uBAAuB,CAAC;AACzH,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAGpD,MAAM,WAAW,yBAAyB;IACxC,kDAAkD;IAClD,SAAS,EAAE,MAAM,GAAG,SAAS,CAAC;IAC9B,oDAAoD;IACpD,SAAS,EAAE,MAAM,GAAG,SAAS,CAAC;IAC9B,kGAAkG;IAClG,OAAO,EAAE,MAAM,GAAG,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,0BAA0B;IACzC,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,sBAAsB,GAAG;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,GAAG,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;CAC1E;AAED,MAAM,WAAW,sCAAsC;IACrD,oGAAoG;IACpG,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,cAAc,CAAC;IACvB;;;;;;;;;;;;;;;;OAgBG;IACH,aAAa,EAAE,CAAC,WAAW,EAAE,cAAc,KAAK,sBAAsB,GAAG,IAAI,GAAG,OAAO,CAAC,sBAAsB,GAAG,IAAI,CAAC,CAAC;CACxH;AAED;;;;;;;;;GASG;AACH,wBAAsB,+BAA+B,CACnD,OAAO,EAAE,yBAAyB,EAClC,OAAO,EAAE,sCAAsC,GAC9C,OAAO,CAAC,0BAA0B,CAAC,CAiCrC"}
@@ -0,0 +1,45 @@
1
+ import { InteractionResponseType, InteractionType } from 'discord-api-types/v10';
2
+ import { verifyInteractionRequest } from './verify-interaction-request.js';
3
+ /**
4
+ * Framework-agnostic core of an HTTP Interactions endpoint: verifies the
5
+ * request's Ed25519 signature, answers Discord's PING (type 1) validation
6
+ * handshake with PONG directly, and otherwise hands the parsed interaction to
7
+ * `onInteraction`. Deliberately takes/returns plain data (raw body + headers
8
+ * in, `{ status, body }` out) instead of an `http.IncomingMessage`/Express
9
+ * `Request`/etc., so it can be wired into any HTTP layer a bot already uses -
10
+ * this package doesn't otherwise depend on one, and picking one here would be
11
+ * a bigger commitment than this function needs to make.
12
+ */
13
+ export async function handleWebhookInteractionRequest(request, options) {
14
+ const { publicKey, logger, onInteraction } = options;
15
+ const isValid = verifyInteractionRequest({
16
+ publicKey,
17
+ signature: request.signature,
18
+ timestamp: request.timestamp,
19
+ rawBody: request.rawBody,
20
+ });
21
+ if (!isValid) {
22
+ logger.warn('Rejected webhook interaction request with invalid signature');
23
+ return { status: 401, body: { error: 'Invalid request signature' } };
24
+ }
25
+ let interaction;
26
+ try {
27
+ interaction = JSON.parse(request.rawBody.toString());
28
+ }
29
+ catch (e) {
30
+ logger.error('Failed to parse webhook interaction request body as JSON', e);
31
+ return { status: 400, body: { error: 'Invalid JSON body' } };
32
+ }
33
+ if (interaction.type === InteractionType.Ping) {
34
+ return { status: 200, body: { type: InteractionResponseType.Pong } };
35
+ }
36
+ try {
37
+ const body = await onInteraction(interaction);
38
+ return { status: 200, body: body ?? {} };
39
+ }
40
+ catch (e) {
41
+ logger.error('Error while handling webhook interaction', e);
42
+ return { status: 500, body: { error: 'Internal error' } };
43
+ }
44
+ }
45
+ //# sourceMappingURL=handle-webhook-interaction-request.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"handle-webhook-interaction-request.js","sourceRoot":"","sources":["../../src/webhook/handle-webhook-interaction-request.ts"],"names":[],"mappings":"AAAA,OAAO,EAA0C,uBAAuB,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAEzH,OAAO,EAAE,wBAAwB,EAAE,MAAM,iCAAiC,CAAC;AAwC3E;;;;;;;;;GASG;AACH,MAAM,CAAC,KAAK,UAAU,+BAA+B,CACnD,OAAkC,EAClC,OAA+C;IAE/C,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,aAAa,EAAE,GAAG,OAAO,CAAC;IAErD,MAAM,OAAO,GAAG,wBAAwB,CAAC;QACvC,SAAS;QACT,SAAS,EAAE,OAAO,CAAC,SAAS;QAC5B,SAAS,EAAE,OAAO,CAAC,SAAS;QAC5B,OAAO,EAAE,OAAO,CAAC,OAAO;KACzB,CAAC,CAAC;IACH,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,MAAM,CAAC,IAAI,CAAC,6DAA6D,CAAC,CAAC;QAC3E,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE,KAAK,EAAE,2BAA2B,EAAE,EAAE,CAAC;IACvE,CAAC;IAED,IAAI,WAA2B,CAAC;IAChC,IAAI,CAAC;QACH,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAmB,CAAC;IACzE,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,MAAM,CAAC,KAAK,CAAC,0DAA0D,EAAE,CAAC,CAAC,CAAC;QAC5E,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE,KAAK,EAAE,mBAAmB,EAAE,EAAE,CAAC;IAC/D,CAAC;IAED,IAAI,WAAW,CAAC,IAAI,KAAK,eAAe,CAAC,IAAI,EAAE,CAAC;QAC9C,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,uBAAuB,CAAC,IAAI,EAAE,EAAE,CAAC;IACvE,CAAC;IAED,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,MAAM,aAAa,CAAC,WAAW,CAAC,CAAC;QAC9C,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,IAAI,IAAI,EAAE,EAAE,CAAC;IAC3C,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,MAAM,CAAC,KAAK,CAAC,0CAA0C,EAAE,CAAC,CAAC,CAAC;QAC5D,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE,KAAK,EAAE,gBAAgB,EAAE,EAAE,CAAC;IAC5D,CAAC;AACH,CAAC"}
@@ -0,0 +1,6 @@
1
+ export * from './verify-interaction-request.js';
2
+ export * from './handle-webhook-interaction-request.js';
3
+ export * from './create-webhook-interaction-responder.js';
4
+ export * from './create-webhook-only-client.js';
5
+ export * from './interaction-from-webhook-payload.js';
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/webhook/index.ts"],"names":[],"mappings":"AAKA,cAAc,iCAAiC,CAAC;AAChD,cAAc,yCAAyC,CAAC;AACxD,cAAc,2CAA2C,CAAC;AAC1D,cAAc,iCAAiC,CAAC;AAChD,cAAc,uCAAuC,CAAC"}
@@ -0,0 +1,11 @@
1
+ // Experimental: unvalidated against a real bot migration yet. See this
2
+ // module's design-decision entry in CLAUDE.md before relying on it, in
3
+ // particular that the initial-response HTTP semantics documented on
4
+ // `handleWebhookInteractionRequest`/`interactionFromWebhookPayload` are
5
+ // unverified against live Discord traffic.
6
+ export * from './verify-interaction-request.js';
7
+ export * from './handle-webhook-interaction-request.js';
8
+ export * from './create-webhook-interaction-responder.js';
9
+ export * from './create-webhook-only-client.js';
10
+ export * from './interaction-from-webhook-payload.js';
11
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/webhook/index.ts"],"names":[],"mappings":"AAAA,uEAAuE;AACvE,uEAAuE;AACvE,oEAAoE;AACpE,wEAAwE;AACxE,2CAA2C;AAC3C,cAAc,iCAAiC,CAAC;AAChD,cAAc,yCAAyC,CAAC;AACxD,cAAc,2CAA2C,CAAC;AAC1D,cAAc,iCAAiC,CAAC;AAChD,cAAc,uCAAuC,CAAC"}
@@ -0,0 +1,31 @@
1
+ import { APIInteraction } from 'discord-api-types/v10';
2
+ import { Client, Interaction } from 'discord.js';
3
+ /**
4
+ * Reconstructs a genuine discord.js `Interaction` instance from a raw
5
+ * webhook-delivered interaction payload, so existing gateway-shaped handler
6
+ * code (`interaction.reply()`, `interaction.options.getString()`, etc.) can
7
+ * run completely unmodified in webhook mode - built on the same `client`
8
+ * this instance's `.reply()`/`.editReply()`/etc. will make real REST calls
9
+ * through (see `createWebhookOnlyClient`). Mirrors discord.js's own
10
+ * `InteractionCreateAction.handle()` class-picking switch (which does the
11
+ * same thing for gateway-delivered payloads) exactly, one discord-api-types
12
+ * version at a time - if discord.js adds a new interaction/component type,
13
+ * this needs a matching new case.
14
+ *
15
+ * **Two real gaps versus a gateway-delivered interaction, both from having
16
+ * no populated gateway cache:**
17
+ * - `.guild` is always `null` (`client.guilds.cache` is permanently empty in
18
+ * webhook mode, and unlike `.channel`, nothing pre-caches a partial for
19
+ * it).
20
+ * - `.channel` is `null` unless the caller pre-caches the interaction's
21
+ * inline partial channel data into `client.channels` first - this
22
+ * function does not attempt that itself (discord.js's own equivalent step,
23
+ * `Action#getChannel`, is a private internal not exposed for reuse).
24
+ *
25
+ * `.member` degrades gracefully instead of breaking: it falls back to the
26
+ * raw `APIInteractionGuildMember` POJO instead of a real `GuildMember`
27
+ * class instance when `.guild` is `null`, so plain property reads (`.roles`,
28
+ * `.nick`, ...) keep working - only actual `GuildMember` methods would not.
29
+ */
30
+ export declare function interactionFromWebhookPayload(client: Client<true>, data: APIInteraction): Interaction;
31
+ //# sourceMappingURL=interaction-from-webhook-payload.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"interaction-from-webhook-payload.d.ts","sourceRoot":"","sources":["../../src/webhook/interaction-from-webhook-payload.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAA0D,MAAM,uBAAuB,CAAC;AAC/G,OAAO,EAKL,MAAM,EACN,WAAW,EASZ,MAAM,YAAY,CAAC;AAwBpB;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,wBAAgB,6BAA6B,CAAC,MAAM,EAAE,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,cAAc,GAAG,WAAW,CAuCrG"}
@@ -0,0 +1,91 @@
1
+ import { ApplicationCommandType, ComponentType, InteractionType } from 'discord-api-types/v10';
2
+ import { AutocompleteInteraction, ButtonInteraction, ChannelSelectMenuInteraction, ChatInputCommandInteraction, MentionableSelectMenuInteraction, MessageContextMenuCommandInteraction, ModalSubmitInteraction, PrimaryEntryPointCommandInteraction, RoleSelectMenuInteraction, StringSelectMenuInteraction, UserContextMenuCommandInteraction, UserSelectMenuInteraction, } from 'discord.js';
3
+ /**
4
+ * Constructs a discord.js interaction class directly against its own real
5
+ * `(client, data)` constructor - checked against every class this module
6
+ * uses (discord.js@14.26.x), each one's constructor is either `protected`
7
+ * (blocks external construction, but not a subclass's `super()` - not used
8
+ * here since it'd be a second, inconsistent mechanism just for those) or, for
9
+ * `ButtonInteraction`/`ModalSubmitInteraction`/the 5 select-menu classes,
10
+ * fully `private` (blocks even subclassing) with a narrower `data` parameter
11
+ * type (`APIMessageButtonInteractionData`, `APIModalSubmitInteraction`,
12
+ * `APIMessage*SelectInteractionData`) that isn't part of discord.js's public
13
+ * export surface to reference by name anyway. Both are pure TypeScript
14
+ * access-control keywords, erased in the compiled `.js` - this is exactly
15
+ * what discord.js's own `InteractionCreateAction.handle()` does at runtime
16
+ * (`new InteractionClass(client, data)`), just reached through a type cast
17
+ * instead of module-internal privilege, since there's no way to reference a
18
+ * type discord.js itself doesn't export.
19
+ */
20
+ function constructInteraction(InteractionClass, client, data) {
21
+ const Ctor = InteractionClass;
22
+ return new Ctor(client, data);
23
+ }
24
+ /**
25
+ * Reconstructs a genuine discord.js `Interaction` instance from a raw
26
+ * webhook-delivered interaction payload, so existing gateway-shaped handler
27
+ * code (`interaction.reply()`, `interaction.options.getString()`, etc.) can
28
+ * run completely unmodified in webhook mode - built on the same `client`
29
+ * this instance's `.reply()`/`.editReply()`/etc. will make real REST calls
30
+ * through (see `createWebhookOnlyClient`). Mirrors discord.js's own
31
+ * `InteractionCreateAction.handle()` class-picking switch (which does the
32
+ * same thing for gateway-delivered payloads) exactly, one discord-api-types
33
+ * version at a time - if discord.js adds a new interaction/component type,
34
+ * this needs a matching new case.
35
+ *
36
+ * **Two real gaps versus a gateway-delivered interaction, both from having
37
+ * no populated gateway cache:**
38
+ * - `.guild` is always `null` (`client.guilds.cache` is permanently empty in
39
+ * webhook mode, and unlike `.channel`, nothing pre-caches a partial for
40
+ * it).
41
+ * - `.channel` is `null` unless the caller pre-caches the interaction's
42
+ * inline partial channel data into `client.channels` first - this
43
+ * function does not attempt that itself (discord.js's own equivalent step,
44
+ * `Action#getChannel`, is a private internal not exposed for reuse).
45
+ *
46
+ * `.member` degrades gracefully instead of breaking: it falls back to the
47
+ * raw `APIInteractionGuildMember` POJO instead of a real `GuildMember`
48
+ * class instance when `.guild` is `null`, so plain property reads (`.roles`,
49
+ * `.nick`, ...) keep working - only actual `GuildMember` methods would not.
50
+ */
51
+ export function interactionFromWebhookPayload(client, data) {
52
+ switch (data.type) {
53
+ case InteractionType.ApplicationCommand:
54
+ switch (data.data.type) {
55
+ case ApplicationCommandType.ChatInput:
56
+ return constructInteraction(ChatInputCommandInteraction, client, data);
57
+ case ApplicationCommandType.User:
58
+ return constructInteraction(UserContextMenuCommandInteraction, client, data);
59
+ case ApplicationCommandType.Message:
60
+ return constructInteraction(MessageContextMenuCommandInteraction, client, data);
61
+ case ApplicationCommandType.PrimaryEntryPoint:
62
+ return constructInteraction(PrimaryEntryPointCommandInteraction, client, data);
63
+ default:
64
+ throw new Error(`Unknown application command interaction type: ${data.data.type}`);
65
+ }
66
+ case InteractionType.MessageComponent:
67
+ switch (data.data.component_type) {
68
+ case ComponentType.Button:
69
+ return constructInteraction(ButtonInteraction, client, data);
70
+ case ComponentType.StringSelect:
71
+ return constructInteraction(StringSelectMenuInteraction, client, data);
72
+ case ComponentType.UserSelect:
73
+ return constructInteraction(UserSelectMenuInteraction, client, data);
74
+ case ComponentType.RoleSelect:
75
+ return constructInteraction(RoleSelectMenuInteraction, client, data);
76
+ case ComponentType.MentionableSelect:
77
+ return constructInteraction(MentionableSelectMenuInteraction, client, data);
78
+ case ComponentType.ChannelSelect:
79
+ return constructInteraction(ChannelSelectMenuInteraction, client, data);
80
+ default:
81
+ throw new Error(`Unknown message component interaction type: ${data.data.component_type}`);
82
+ }
83
+ case InteractionType.ApplicationCommandAutocomplete:
84
+ return constructInteraction(AutocompleteInteraction, client, data);
85
+ case InteractionType.ModalSubmit:
86
+ return constructInteraction(ModalSubmitInteraction, client, data);
87
+ default:
88
+ throw new Error(`Unknown interaction type: ${data.type}`);
89
+ }
90
+ }
91
+ //# sourceMappingURL=interaction-from-webhook-payload.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"interaction-from-webhook-payload.js","sourceRoot":"","sources":["../../src/webhook/interaction-from-webhook-payload.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,22 @@
1
+ export interface VerifyInteractionRequestOptions {
2
+ /** The bot's Ed25519 application public key, from the Discord developer portal, as a hex string. */
3
+ publicKey: string;
4
+ /** The request's `X-Signature-Ed25519` header. */
5
+ signature: string | undefined;
6
+ /** The request's `X-Signature-Timestamp` header. */
7
+ timestamp: string | undefined;
8
+ /** The raw (unparsed) request body, exactly as received - verification fails against a re-serialized body. */
9
+ rawBody: string | Buffer;
10
+ }
11
+ /**
12
+ * Verifies a Discord Interactions-webhook request's Ed25519 signature, per
13
+ * https://discord.com/developers/docs/interactions/overview#setting-up-an-endpoint.
14
+ *
15
+ * Built on Node's native `crypto` module (`verify`/`createPublicKey`, both
16
+ * Ed25519-capable since Node 12) instead of `tweetnacl` or
17
+ * `discord-interactions` - matching this package's standing preference for a
18
+ * native API over a new dependency when one suffices (see the discord-webhook
19
+ * pino transport, and `createHandlerWatcher`'s use of native `fs.watch`).
20
+ */
21
+ export declare function verifyInteractionRequest(options: VerifyInteractionRequestOptions): boolean;
22
+ //# sourceMappingURL=verify-interaction-request.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verify-interaction-request.d.ts","sourceRoot":"","sources":["../../src/webhook/verify-interaction-request.ts"],"names":[],"mappings":"AASA,MAAM,WAAW,+BAA+B;IAC9C,oGAAoG;IACpG,SAAS,EAAE,MAAM,CAAC;IAClB,kDAAkD;IAClD,SAAS,EAAE,MAAM,GAAG,SAAS,CAAC;IAC9B,oDAAoD;IACpD,SAAS,EAAE,MAAM,GAAG,SAAS,CAAC;IAC9B,8GAA8G;IAC9G,OAAO,EAAE,MAAM,GAAG,MAAM,CAAC;CAC1B;AAED;;;;;;;;;GASG;AACH,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,+BAA+B,GAAG,OAAO,CAkB1F"}
@@ -0,0 +1,37 @@
1
+ import { createPublicKey, verify } from 'node:crypto';
2
+ // DER SPKI wrapper for a raw 32-byte Ed25519 public key
3
+ // (302a300506032b6570032100 = SEQUENCE { SEQUENCE { OID 1.3.101.112 }, BIT STRING (32 bytes) }).
4
+ // Node's `crypto.createPublicKey` has no raw-Ed25519-key input format, only DER/PEM/JWK, and
5
+ // Discord's developer portal only ever gives bots the raw 32-byte hex key - this prefix is the
6
+ // standard, fixed way to wrap one into the DER SPKI shape `createPublicKey` accepts.
7
+ const ed25519SpkiDerPrefix = Buffer.from('302a300506032b6570032100', 'hex');
8
+ /**
9
+ * Verifies a Discord Interactions-webhook request's Ed25519 signature, per
10
+ * https://discord.com/developers/docs/interactions/overview#setting-up-an-endpoint.
11
+ *
12
+ * Built on Node's native `crypto` module (`verify`/`createPublicKey`, both
13
+ * Ed25519-capable since Node 12) instead of `tweetnacl` or
14
+ * `discord-interactions` - matching this package's standing preference for a
15
+ * native API over a new dependency when one suffices (see the discord-webhook
16
+ * pino transport, and `createHandlerWatcher`'s use of native `fs.watch`).
17
+ */
18
+ export function verifyInteractionRequest(options) {
19
+ const { publicKey, signature, timestamp, rawBody } = options;
20
+ if (!signature || !timestamp) {
21
+ return false;
22
+ }
23
+ try {
24
+ const key = createPublicKey({
25
+ key: Buffer.concat([ed25519SpkiDerPrefix, Buffer.from(publicKey, 'hex')]),
26
+ format: 'der',
27
+ type: 'spki',
28
+ });
29
+ const message = Buffer.concat([Buffer.from(timestamp, 'utf8'), Buffer.from(rawBody)]);
30
+ return verify(null, message, key, Buffer.from(signature, 'hex'));
31
+ }
32
+ catch {
33
+ // Malformed hex in publicKey/signature, wrong-length key, etc. - all just "not valid".
34
+ return false;
35
+ }
36
+ }
37
+ //# sourceMappingURL=verify-interaction-request.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verify-interaction-request.js","sourceRoot":"","sources":["../../src/webhook/verify-interaction-request.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAEtD,wDAAwD;AACxD,iGAAiG;AACjG,6FAA6F;AAC7F,+FAA+F;AAC/F,qFAAqF;AACrF,MAAM,oBAAoB,GAAG,MAAM,CAAC,IAAI,CAAC,0BAA0B,EAAE,KAAK,CAAC,CAAC;AAa5E;;;;;;;;;GASG;AACH,MAAM,UAAU,wBAAwB,CAAC,OAAwC;IAC/E,MAAM,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC;IAC7D,IAAI,CAAC,SAAS,IAAI,CAAC,SAAS,EAAE,CAAC;QAC7B,OAAO,KAAK,CAAC;IACf,CAAC;IAED,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,eAAe,CAAC;YAC1B,GAAG,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,oBAAoB,EAAE,MAAM,CAAC,IAAI,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC,CAAC;YACzE,MAAM,EAAE,KAAK;YACb,IAAI,EAAE,MAAM;SACb,CAAC,CAAC;QACH,MAAM,OAAO,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;QACtF,OAAO,MAAM,CAAC,IAAI,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,CAAC,IAAI,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC,CAAC;IACnE,CAAC;IAAC,MAAM,CAAC;QACP,uFAAuF;QACvF,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@went.tf/discord-bot-framework",
3
- "version": "2.4.0",
3
+ "version": "2.6.0",
4
4
  "description": "Shared framework for building Discord bots with discord.js: logging, env validation, interaction dispatch, API client, and optional Postgres/i18next helpers",
5
5
  "author": "WentTheFox <mail@went.tf> (https://github.com/WentTheFox)",
6
6
  "license": "MIT",
@@ -48,6 +48,10 @@
48
48
  "types": "./build/client/index.d.ts",
49
49
  "default": "./build/client/index.js"
50
50
  },
51
+ "./webhook": {
52
+ "types": "./build/webhook/index.d.ts",
53
+ "default": "./build/webhook/index.js"
54
+ },
51
55
  "./dev": {
52
56
  "types": "./build/dev/index.d.ts",
53
57
  "default": "./build/dev/index.js"