@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.
- package/README.md +112 -0
- package/build/.tsbuildinfo +1 -1
- package/build/index.d.ts +1 -0
- package/build/index.d.ts.map +1 -1
- package/build/index.js +1 -0
- package/build/index.js.map +1 -1
- package/build/webhook/create-webhook-interaction-responder.d.ts +33 -0
- package/build/webhook/create-webhook-interaction-responder.d.ts.map +1 -0
- package/build/webhook/create-webhook-interaction-responder.js +25 -0
- package/build/webhook/create-webhook-interaction-responder.js.map +1 -0
- package/build/webhook/create-webhook-only-client.d.ts +35 -0
- package/build/webhook/create-webhook-only-client.d.ts.map +1 -0
- package/build/webhook/create-webhook-only-client.js +36 -0
- package/build/webhook/create-webhook-only-client.js.map +1 -0
- package/build/webhook/handle-webhook-interaction-request.d.ts +51 -0
- package/build/webhook/handle-webhook-interaction-request.d.ts.map +1 -0
- package/build/webhook/handle-webhook-interaction-request.js +45 -0
- package/build/webhook/handle-webhook-interaction-request.js.map +1 -0
- package/build/webhook/index.d.ts +6 -0
- package/build/webhook/index.d.ts.map +1 -0
- package/build/webhook/index.js +11 -0
- package/build/webhook/index.js.map +1 -0
- package/build/webhook/interaction-from-webhook-payload.d.ts +31 -0
- package/build/webhook/interaction-from-webhook-payload.d.ts.map +1 -0
- package/build/webhook/interaction-from-webhook-payload.js +91 -0
- package/build/webhook/interaction-from-webhook-payload.js.map +1 -0
- package/build/webhook/verify-interaction-request.d.ts +22 -0
- package/build/webhook/verify-interaction-request.d.ts.map +1 -0
- package/build/webhook/verify-interaction-request.js +37 -0
- package/build/webhook/verify-interaction-request.js.map +1 -0
- package/package.json +5 -1
package/README.md
CHANGED
|
@@ -480,6 +480,118 @@ process is never restarted. Fall back to a real restart for those, and for
|
|
|
480
480
|
anything that needs `beforeSpawn`'s one-time setup (e.g. slash command
|
|
481
481
|
registration) to re-run.
|
|
482
482
|
|
|
483
|
+
### `@went.tf/discord-bot-framework/webhook` (experimental)
|
|
484
|
+
|
|
485
|
+
> **Experimental, unvalidated against a real bot.** Unlike every other
|
|
486
|
+
> subpath in this package, `./webhook` hasn't yet been proven against a real
|
|
487
|
+
> migration — see the scope note at the end of this section and CLAUDE.md's
|
|
488
|
+
> `./webhook` design-decision entry. The API may change in a minor/patch
|
|
489
|
+
> release until that validation happens, despite semver-major otherwise being
|
|
490
|
+
> reserved for breaking changes in this package.
|
|
491
|
+
|
|
492
|
+
An alternate, independent transport alongside `./client`'s gateway-based
|
|
493
|
+
`createBotClient`/`createShardManager`, for bots that want to receive
|
|
494
|
+
interactions over an HTTP Interactions Endpoint instead of holding a
|
|
495
|
+
WebSocket open. As with `createBotClient`/`createShardManager`, this doesn't
|
|
496
|
+
unify with the gateway path behind one entry point — pick one transport per
|
|
497
|
+
bot and use its functions directly.
|
|
498
|
+
|
|
499
|
+
`verifyInteractionRequest` checks a request's `X-Signature-Ed25519`/
|
|
500
|
+
`X-Signature-Timestamp` headers against your application's public key, using
|
|
501
|
+
Node's native `crypto` module (no `tweetnacl`/`discord-interactions`
|
|
502
|
+
dependency needed). `handleWebhookInteractionRequest` wraps that plus
|
|
503
|
+
Discord's PING→PONG endpoint-validation handshake around your own handler,
|
|
504
|
+
taking/returning plain data so it can be wired into any HTTP framework (or
|
|
505
|
+
none):
|
|
506
|
+
|
|
507
|
+
```ts
|
|
508
|
+
import { handleWebhookInteractionRequest } from '@went.tf/discord-bot-framework/webhook';
|
|
509
|
+
import { createServer } from 'node:http';
|
|
510
|
+
|
|
511
|
+
createServer(async (req, res) => {
|
|
512
|
+
const chunks: Buffer[] = [];
|
|
513
|
+
for await (const chunk of req) chunks.push(chunk);
|
|
514
|
+
const rawBody = Buffer.concat(chunks);
|
|
515
|
+
|
|
516
|
+
const { status, body } = await handleWebhookInteractionRequest(
|
|
517
|
+
{
|
|
518
|
+
signature: req.headers['x-signature-ed25519'] as string,
|
|
519
|
+
timestamp: req.headers['x-signature-timestamp'] as string,
|
|
520
|
+
rawBody,
|
|
521
|
+
},
|
|
522
|
+
{
|
|
523
|
+
publicKey: env.DISCORD_PUBLIC_KEY,
|
|
524
|
+
logger,
|
|
525
|
+
onInteraction: (interaction) => handleInteraction(interaction), // bot-side: build an APIInteractionResponse
|
|
526
|
+
},
|
|
527
|
+
);
|
|
528
|
+
res.writeHead(status, { 'Content-Type': 'application/json' }).end(JSON.stringify(body));
|
|
529
|
+
}).listen(3000);
|
|
530
|
+
```
|
|
531
|
+
|
|
532
|
+
`createWebhookInteractionResponder` gives you the REST calls needed *after*
|
|
533
|
+
that initial response — editing a deferred reply, sending a follow-up, or
|
|
534
|
+
deleting the reply — built on `@discordjs/rest` (already a peer dependency):
|
|
535
|
+
|
|
536
|
+
```ts
|
|
537
|
+
import { createWebhookInteractionResponder } from '@went.tf/discord-bot-framework/webhook';
|
|
538
|
+
|
|
539
|
+
const responder = createWebhookInteractionResponder({ rest, applicationId, interactionToken: interaction.token });
|
|
540
|
+
await responder.editReply({ content: 'Done!' });
|
|
541
|
+
```
|
|
542
|
+
|
|
543
|
+
**Running existing gateway-shaped command handlers unmodified:**
|
|
544
|
+
`createWebhookOnlyClient` builds a real discord.js `Client` that's fully
|
|
545
|
+
authenticated for REST but never opens a gateway connection (`Client#login()`
|
|
546
|
+
always does, with no way to opt out, so this sets `client.rest`'s token
|
|
547
|
+
directly instead - both fully public API). `interactionFromWebhookPayload`
|
|
548
|
+
then reconstructs a genuine discord.js `Interaction` instance from the raw
|
|
549
|
+
payload, the same way discord.js's own gateway path does internally - so
|
|
550
|
+
`.reply()`/`.deferReply()`/`.editReply()`/`.options.getString()` etc. all work
|
|
551
|
+
exactly as they do today, and your existing `BotChatInputCommand`/
|
|
552
|
+
`dispatchChatInputCommand`/`createInteractionRouter` code needs zero changes:
|
|
553
|
+
|
|
554
|
+
```ts
|
|
555
|
+
import { createWebhookOnlyClient, handleWebhookInteractionRequest, interactionFromWebhookPayload } from '@went.tf/discord-bot-framework/webhook';
|
|
556
|
+
import { dispatchChatInputCommand } from '@went.tf/discord-bot-framework/interactions';
|
|
557
|
+
|
|
558
|
+
const client = createWebhookOnlyClient({ token: env.DISCORD_BOT_TOKEN });
|
|
559
|
+
|
|
560
|
+
// inside your HTTP handler, in place of the plain onInteraction above:
|
|
561
|
+
onInteraction: async (data) => {
|
|
562
|
+
const interaction = interactionFromWebhookPayload(client, data);
|
|
563
|
+
if (interaction.isChatInputCommand()) {
|
|
564
|
+
await dispatchChatInputCommand(interaction, context, { commands: registry.byName, onError });
|
|
565
|
+
return; // .reply()/.deferReply() already sent the real response via REST
|
|
566
|
+
}
|
|
567
|
+
// ...similarly for dispatchComponent/dispatchModal/dispatchAutocomplete/dispatchContextMenu
|
|
568
|
+
},
|
|
569
|
+
```
|
|
570
|
+
|
|
571
|
+
Two real gaps versus a gateway-delivered interaction, both from there being no
|
|
572
|
+
populated gateway cache: `.guild` is always `null`, and `.channel` is `null`
|
|
573
|
+
unless you pre-cache the interaction's inline partial channel data yourself.
|
|
574
|
+
`.member` degrades gracefully instead (falls back to the raw
|
|
575
|
+
`APIInteractionGuildMember` object), so plain property reads keep working.
|
|
576
|
+
See `interactionFromWebhookPayload`'s doc comment for the full detail -
|
|
577
|
+
runtime-verified in `interaction-from-webhook-payload.test.ts` (including the
|
|
578
|
+
two discord.js interaction classes with `private` constructors,
|
|
579
|
+
`ButtonInteraction`/`ModalSubmitInteraction`, which still construct correctly
|
|
580
|
+
through this bridge).
|
|
581
|
+
|
|
582
|
+
**One thing this hasn't verified**, because it needs live Discord traffic,
|
|
583
|
+
not just source-reading: when a handler's `.reply()`/`.deferReply()` call
|
|
584
|
+
already sent the real response via REST mid-handler, what your `onInteraction`
|
|
585
|
+
callback should still return as the literal HTTP response to Discord's
|
|
586
|
+
original webhook POST. `handleWebhookInteractionRequest` sends a bare `{}`
|
|
587
|
+
with a 200 if `onInteraction` returns nothing, on the assumption (backed by
|
|
588
|
+
discord.js's `InteractionResponses` source - every reply method calls the same
|
|
589
|
+
`Routes.interactionCallback()` REST route regardless of gateway vs. webhook
|
|
590
|
+
delivery, so the mechanism is provably delivery-agnostic on Discord's side)
|
|
591
|
+
that this is fine, but that assumption is unconfirmed against a real
|
|
592
|
+
registered endpoint. See CLAUDE.md's `./webhook` design-decision entry before
|
|
593
|
+
relying on this in production.
|
|
594
|
+
|
|
483
595
|
### `@went.tf/discord-bot-framework/dev`
|
|
484
596
|
|
|
485
597
|
Live-reloads compiled command/interaction handler *implementations* during
|