@dereekb/nestjs 13.32.0 → 13.34.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,25 +0,0 @@
1
- {
2
- "name": "@dereekb/nestjs/discord",
3
- "version": "13.32.0",
4
- "peerDependencies": {
5
- "@dereekb/nestjs": "13.32.0",
6
- "@dereekb/rxjs": "13.32.0",
7
- "@dereekb/util": "13.32.0",
8
- "@nestjs/common": "^11.1.19",
9
- "@nestjs/config": "^4.0.4",
10
- "discord.js": "^14.26.3",
11
- "express": "^5.2.1"
12
- },
13
- "exports": {
14
- "./package.json": "./package.json",
15
- ".": {
16
- "module": "./index.esm.js",
17
- "types": "./index.d.ts",
18
- "import": "./index.cjs.mjs",
19
- "default": "./index.cjs.js"
20
- }
21
- },
22
- "module": "./index.esm.js",
23
- "main": "./index.cjs.js",
24
- "types": "./index.d.ts"
25
- }
@@ -1 +0,0 @@
1
- export * from './lib';
@@ -1,69 +0,0 @@
1
- import { Client, type Message } from 'discord.js';
2
- import { type OnModuleDestroy, type OnModuleInit } from '@nestjs/common';
3
- import { DiscordServiceConfig } from './discord.config';
4
- import { type DiscordChannelId } from './discord.type';
5
- /**
6
- * Injectable service that wraps the discord.js Client for bot operations.
7
- *
8
- * Automatically logs in on module init and destroys the client on module destroy
9
- * when autoLogin is enabled (default).
10
- */
11
- export declare class DiscordApi implements OnModuleInit, OnModuleDestroy {
12
- readonly config: DiscordServiceConfig;
13
- private readonly logger;
14
- /**
15
- * The underlying discord.js Client instance.
16
- */
17
- readonly client: Client;
18
- constructor(config: DiscordServiceConfig);
19
- onModuleInit(): Promise<void>;
20
- onModuleDestroy(): Promise<void>;
21
- /**
22
- * Sends a text message to a Discord channel.
23
- *
24
- * @param channelId - target channel's snowflake ID
25
- * @param content - message text to send
26
- *
27
- * @throws {Error} When the channel is not found or is not a text channel.
28
- *
29
- * @example
30
- * ```ts
31
- * const message = await discordApi.sendMessage('123456789', 'Hello from the bot!');
32
- * ```
33
- */
34
- /**
35
- * Sends a text message to the specified Discord channel.
36
- *
37
- * @param channelId - Target channel's snowflake ID.
38
- * @param content - Message text to send.
39
- * @returns The sent Discord Message.
40
- * @throws {Error} When the channel is not found or is not a text channel.
41
- */
42
- sendMessage(channelId: DiscordChannelId, content: string): Promise<Message>;
43
- /**
44
- * Registers a handler for the MessageCreate event (incoming messages).
45
- *
46
- * Returns an unsubscribe function to remove the handler.
47
- *
48
- * @param handler - callback invoked for each incoming message
49
- *
50
- * @example
51
- * ```ts
52
- * const unsubscribe = discordApi.onMessage((message) => {
53
- * if (!message.author.bot) {
54
- * console.log(`${message.author.tag}: ${message.content}`);
55
- * }
56
- * });
57
- *
58
- * // Later, to stop listening:
59
- * unsubscribe();
60
- * ```
61
- */
62
- /**
63
- * Registers a handler for incoming Discord messages (MessageCreate event).
64
- *
65
- * @param handler - Callback invoked for each incoming Message.
66
- * @returns An unsubscribe function that removes the registered handler.
67
- */
68
- onMessage(handler: (message: Message) => void): () => void;
69
- }
@@ -1,107 +0,0 @@
1
- import { type Maybe } from '@dereekb/util';
2
- import { type FetchPageFactory, type FetchPageFactoryConfigDefaults } from '@dereekb/util/fetch';
3
- import { type DiscordMessageId } from './discord.type';
4
- /**
5
- * Default number of messages per page when fetching Discord channel messages.
6
- */
7
- export declare const DEFAULT_DISCORD_MESSAGES_PER_PAGE = 100;
8
- /**
9
- * Base pagination parameters for Discord channel message endpoints.
10
- *
11
- * Discord uses cursor-based pagination via snowflake IDs rather than page numbers.
12
- * Only one of `before`, `after`, or `around` should be specified per request.
13
- */
14
- export interface DiscordMessagePageFilter {
15
- /**
16
- * Fetch messages before this message ID.
17
- */
18
- readonly before?: Maybe<DiscordMessageId>;
19
- /**
20
- * Fetch messages after this message ID.
21
- */
22
- readonly after?: Maybe<DiscordMessageId>;
23
- /**
24
- * Fetch messages around this message ID.
25
- */
26
- readonly around?: Maybe<DiscordMessageId>;
27
- /**
28
- * Maximum number of messages to return per page (1-100).
29
- *
30
- * Defaults to {@link DEFAULT_DISCORD_MESSAGES_PER_PAGE}.
31
- */
32
- readonly limit?: Maybe<number>;
33
- }
34
- /**
35
- * Result of a paginated Discord message fetch containing the array of messages.
36
- *
37
- * @typeParam T - The message type (typically discord.js `Message`)
38
- */
39
- export interface DiscordMessagePageResult<T> {
40
- /**
41
- * Array of messages returned.
42
- */
43
- readonly data: T[];
44
- }
45
- /**
46
- * A fetch function that accepts {@link DiscordMessagePageFilter} input and returns a {@link DiscordMessagePageResult}.
47
- * Used as the underlying data source for {@link discordFetchMessagePageFactory}.
48
- */
49
- export type DiscordFetchMessagePageFetchFunction<I extends DiscordMessagePageFilter, T> = (input: I) => Promise<DiscordMessagePageResult<T>>;
50
- /**
51
- * Configuration for {@link discordFetchMessagePageFactory}.
52
- *
53
- * @typeParam T - The message type
54
- */
55
- export interface DiscordFetchMessagePageFactoryConfig<T> {
56
- /**
57
- * Extracts the snowflake ID from a message object. Used to determine the cursor for the next page.
58
- *
59
- * Defaults to reading the `id` property on the message.
60
- */
61
- readonly readMessageId?: (message: T) => DiscordMessageId;
62
- }
63
- /**
64
- * Configuration for {@link discordFetchMessagePageFactory}.
65
- *
66
- * @typeParam I - The input filter type
67
- * @typeParam T - The message type
68
- */
69
- export interface DiscordFetchMessagePageFactoryInput<I extends DiscordMessagePageFilter, T> {
70
- /**
71
- * The Discord fetch function to paginate over.
72
- */
73
- readonly fetch: DiscordFetchMessagePageFetchFunction<I, T>;
74
- /**
75
- * Optional config for reading message IDs.
76
- */
77
- readonly config?: Maybe<DiscordFetchMessagePageFactoryConfig<T>>;
78
- /**
79
- * Optional default configuration for the page factory.
80
- */
81
- readonly defaults?: Maybe<FetchPageFactoryConfigDefaults>;
82
- }
83
- /**
84
- * Creates a page factory that wraps a Discord message fetch function with automatic cursor-based pagination.
85
- *
86
- * Discord paginates via `before`/`after` snowflake IDs. This factory automatically reads the last
87
- * message's ID from each response and sets it as the `before` cursor for the next request.
88
- * When the number of returned messages is less than the requested limit, pagination stops.
89
- *
90
- * @param input - The factory input configuration.
91
- * @returns A page factory that produces iterable page fetchers.
92
- *
93
- * @example
94
- * ```typescript
95
- * const pageFactory = discordFetchMessagePageFactory({ fetch: fetchChannelMessages });
96
- *
97
- * const fetchPage = pageFactory({ limit: 50 });
98
- * const firstPage = await fetchPage.fetchNext();
99
- *
100
- * if (firstPage.hasNext) {
101
- * const secondPage = await firstPage.fetchNext();
102
- * }
103
- * ```
104
- */
105
- export declare function discordFetchMessagePageFactory<I extends DiscordMessagePageFilter, T extends {
106
- id: string;
107
- }>(input: DiscordFetchMessagePageFactoryInput<I, T>): FetchPageFactory<I, DiscordMessagePageResult<T>>;
@@ -1,20 +0,0 @@
1
- import { DiscordApi } from './discord.api';
2
- /**
3
- * Shared, process-singleton Discord test client.
4
- *
5
- * Integration spec files import {@link getSharedDiscordTestClient} so that at most one
6
- * `client.login()` call occurs per vitest worker process, regardless of how many spec
7
- * files participate. This keeps the bot's daily gateway-session quota intact during
8
- * normal development.
9
- */
10
- export interface SharedDiscordTestClient {
11
- readonly discordApi: DiscordApi;
12
- readonly testChannelId: string;
13
- }
14
- /**
15
- * Returns the shared logged-in test client, creating it on first call and reusing it
16
- * on subsequent calls within the same process.
17
- *
18
- * @returns The cached {@link SharedDiscordTestClient}.
19
- */
20
- export declare function getSharedDiscordTestClient(): Promise<SharedDiscordTestClient>;
@@ -1,58 +0,0 @@
1
- import { type Maybe } from '@dereekb/util';
2
- import { type ClientOptions, GatewayIntentBits } from 'discord.js';
3
- import { type DiscordBotToken } from './discord.type';
4
- /**
5
- * Default environment variable for the Discord bot token.
6
- */
7
- export declare const DISCORD_BOT_TOKEN_ENV_VAR = "DISCORD_BOT_TOKEN";
8
- /**
9
- * Placeholder bot token value used in development and CI environments where a real Discord
10
- * login should not be attempted. Mirrors the value used in the workspace's .env file.
11
- */
12
- export declare const DISCORD_BOT_TOKEN_PLACEHOLDER = "placeholder";
13
- /**
14
- * Returns true if the input is a real, usable Discord bot token.
15
- *
16
- * A token is usable when it is non-empty and is not the shared placeholder value, allowing
17
- * non-production environments to skip a real gateway login that would always fail.
18
- *
19
- * @param botToken - The bot token read from configuration, if any.
20
- * @returns True when the token should be used to log in.
21
- *
22
- * @example
23
- * ```ts
24
- * isUsableDiscordBotToken('placeholder'); // false
25
- * isUsableDiscordBotToken('real-token'); // true
26
- * ```
27
- */
28
- export declare function isUsableDiscordBotToken(botToken: Maybe<DiscordBotToken>): boolean;
29
- /**
30
- * Default gateway intents for a bot that reads guild messages.
31
- *
32
- * Includes Guilds, GuildMessages, and MessageContent.
33
- * Note: MessageContent is a privileged intent and must be enabled in the Discord Developer Portal.
34
- */
35
- export declare const DEFAULT_DISCORD_INTENTS: GatewayIntentBits[];
36
- export interface DiscordServiceApiConfig {
37
- /**
38
- * The bot token used to authenticate with the Discord gateway.
39
- */
40
- readonly botToken: DiscordBotToken;
41
- /**
42
- * discord.js Client options. Intents default to DEFAULT_DISCORD_INTENTS if not provided.
43
- */
44
- readonly clientOptions?: Partial<ClientOptions>;
45
- /**
46
- * Whether to automatically call client.login() during module initialization.
47
- *
48
- * Defaults to true.
49
- */
50
- readonly autoLogin?: boolean;
51
- }
52
- /**
53
- * Configuration for the DiscordApi service.
54
- */
55
- export declare abstract class DiscordServiceConfig {
56
- readonly discord: DiscordServiceApiConfig;
57
- static assertValidConfig(config: DiscordServiceConfig): void;
58
- }
@@ -1,20 +0,0 @@
1
- import { ConfigService } from '@nestjs/config';
2
- import { DiscordServiceConfig } from './discord.config';
3
- /**
4
- * Factory that creates a DiscordServiceConfig from environment variables.
5
- *
6
- * autoLogin is enabled only when a real bot token is configured and the process is not running
7
- * under a test environment, so development and CI runs (which use a placeholder token) never
8
- * attempt a real gateway login that would fail.
9
- *
10
- * @param configService - The NestJS config service used to read Discord environment variables.
11
- * @returns A validated DiscordServiceConfig populated from environment variables.
12
- */
13
- export declare function discordServiceConfigFactory(configService: ConfigService): DiscordServiceConfig;
14
- /**
15
- * NestJS module that provides the DiscordApi service.
16
- *
17
- * Reads the bot token from the DISCORD_BOT_TOKEN environment variable.
18
- */
19
- export declare class DiscordModule {
20
- }
@@ -1,26 +0,0 @@
1
- /**
2
- * A Discord snowflake ID string.
3
- */
4
- export type DiscordId = string;
5
- /**
6
- * Bot token used to authenticate the Discord bot with the gateway.
7
- */
8
- export type DiscordBotToken = string;
9
- /**
10
- * A Discord channel ID (snowflake string).
11
- */
12
- export type DiscordChannelId = string;
13
- /**
14
- * A Discord guild (server) ID (snowflake string).
15
- */
16
- export type DiscordGuildId = string;
17
- /**
18
- * A Discord message snowflake ID string.
19
- */
20
- export type DiscordMessageId = string;
21
- /**
22
- * The Ed25519 public key of your Discord application, used to verify interaction webhooks.
23
- *
24
- * Found in the Discord Developer Portal under your application's General Information page.
25
- */
26
- export type DiscordPublicKey = string;
@@ -1,28 +0,0 @@
1
- import { type GatewayIntentBits, type ClientOptions } from 'discord.js';
2
- /**
3
- * Returns default ClientOptions for a bot that reads guild messages.
4
- *
5
- * Includes Guilds, GuildMessages, and MessageContent intents.
6
- *
7
- * @returns Partial ClientOptions with the default bot intents set.
8
- *
9
- * @example
10
- * ```ts
11
- * const options = discordDefaultClientOptions();
12
- * // options.intents === [GatewayIntentBits.Guilds, GatewayIntentBits.GuildMessages, GatewayIntentBits.MessageContent]
13
- * ```
14
- */
15
- export declare function discordDefaultClientOptions(): Partial<ClientOptions>;
16
- /**
17
- * Returns ClientOptions with additional intents merged with the defaults.
18
- *
19
- * @param additionalIntents - Extra intents to include beyond the defaults.
20
- * @returns Partial ClientOptions with the merged intent list.
21
- *
22
- * @example
23
- * ```ts
24
- * const options = discordClientOptionsWithIntents([GatewayIntentBits.DirectMessages]);
25
- * // options.intents includes Guilds, GuildMessages, MessageContent, and DirectMessages
26
- * ```
27
- */
28
- export declare function discordClientOptionsWithIntents(additionalIntents: GatewayIntentBits[]): Partial<ClientOptions>;
@@ -1,7 +0,0 @@
1
- export * from './webhook';
2
- export * from './discord.module';
3
- export * from './discord.api';
4
- export * from './discord.api.page';
5
- export * from './discord.config';
6
- export * from './discord.type';
7
- export * from './discord.util';
@@ -1,6 +0,0 @@
1
- export * from './webhook.discord';
2
- export * from './webhook.discord.config';
3
- export * from './webhook.discord.controller';
4
- export * from './webhook.discord.module';
5
- export * from './webhook.discord.service';
6
- export * from './webhook.discord.verify';
@@ -1,22 +0,0 @@
1
- import { type DiscordPublicKey } from '../discord.type';
2
- /**
3
- * Default environment variable for the Discord application public key.
4
- */
5
- export declare const DISCORD_PUBLIC_KEY_ENV_VAR = "DISCORD_PUBLIC_KEY";
6
- /**
7
- * The byte length of a Discord Ed25519 public key (32 bytes = 64 hex characters).
8
- */
9
- export declare const DISCORD_ED25519_PUBLIC_KEY_BYTE_LENGTH = 32;
10
- export interface DiscordWebhookConfig {
11
- /**
12
- * The Ed25519 public key used to verify incoming interaction webhook signatures.
13
- */
14
- readonly publicKey: DiscordPublicKey;
15
- }
16
- /**
17
- * Configuration for the DiscordWebhookService.
18
- */
19
- export declare abstract class DiscordWebhookServiceConfig {
20
- readonly discordWebhook: DiscordWebhookConfig;
21
- static assertValidConfig(config: DiscordWebhookServiceConfig): void;
22
- }
@@ -1,8 +0,0 @@
1
- import { type RawBodyBuffer } from '@dereekb/nestjs';
2
- import { type Request } from 'express';
3
- import { DiscordWebhookService } from './webhook.discord.service';
4
- export declare class DiscordWebhookController {
5
- private readonly _discordWebhookService;
6
- constructor(discordWebhookService: DiscordWebhookService);
7
- handleDiscordWebhook(req: Request, rawBody: RawBodyBuffer): Promise<void>;
8
- }
@@ -1,59 +0,0 @@
1
- import { type HandlerBindAccessor, type HandlerMappedSetFunction, type Handler } from '@dereekb/util';
2
- import { InteractionType, type Interaction } from 'discord.js';
3
- /**
4
- * Discord interaction type numeric key, used for handler dispatch.
5
- */
6
- export type DiscordInteractionType = InteractionType;
7
- /**
8
- * An untyped Discord interaction received via webhook.
9
- */
10
- export type UntypedDiscordInteraction = Interaction;
11
- /**
12
- * A typed Discord interaction, narrowed from the base Interaction type.
13
- *
14
- * @example
15
- * ```ts
16
- * const interaction: DiscordWebhookInteraction<ChatInputCommandInteraction> = discordWebhookInteraction(rawInteraction);
17
- * ```
18
- */
19
- export type DiscordWebhookInteraction<T extends Interaction = Interaction> = T;
20
- /**
21
- * Casts an untyped Discord interaction to a typed one.
22
- *
23
- * @param interaction - The raw interaction to cast.
24
- * @returns The interaction cast to the specified typed DiscordWebhookInteraction.
25
- */
26
- export declare function discordWebhookInteraction<T extends Interaction = Interaction>(interaction: UntypedDiscordInteraction): DiscordWebhookInteraction<T>;
27
- export type DiscordInteractionHandler = Handler<UntypedDiscordInteraction, DiscordInteractionType>;
28
- export declare const discordInteractionHandlerFactory: import("@dereekb/util").HandlerFactory<UntypedDiscordInteraction, InteractionType, boolean>;
29
- export type DiscordHandlerMappedSetFunction<T extends Interaction = Interaction> = HandlerMappedSetFunction<DiscordWebhookInteraction<T>>;
30
- /**
31
- * Configurer for Discord interaction handlers.
32
- *
33
- * Handlers are keyed on InteractionType. Use discord.js type guards
34
- * (e.g., interaction.isChatInputCommand(), interaction.isButton()) within
35
- * your handler callback for sub-type refinement.
36
- */
37
- export interface DiscordInteractionHandlerConfigurer extends HandlerBindAccessor<UntypedDiscordInteraction, DiscordInteractionType> {
38
- /**
39
- * Handles application commands (slash commands + context menu commands).
40
- *
41
- * Use interaction.isChatInputCommand() or interaction.isContextMenuCommand() to narrow the type within your handler.
42
- */
43
- readonly handleApplicationCommand: DiscordHandlerMappedSetFunction;
44
- /**
45
- * Handles message component interactions (buttons + select menus).
46
- *
47
- * Use interaction.isButton() or interaction.isStringSelectMenu() to narrow the type within your handler.
48
- */
49
- readonly handleMessageComponent: DiscordHandlerMappedSetFunction;
50
- /**
51
- * Handles modal submit interactions.
52
- */
53
- readonly handleModalSubmit: DiscordHandlerMappedSetFunction;
54
- /**
55
- * Handles autocomplete interactions for slash command options.
56
- */
57
- readonly handleAutocomplete: DiscordHandlerMappedSetFunction;
58
- }
59
- export declare const discordInteractionHandlerConfigurerFactory: import("@dereekb/util").HandlerConfigurerFactory<DiscordInteractionHandlerConfigurer, UntypedDiscordInteraction, InteractionType, boolean>;
@@ -1,17 +0,0 @@
1
- import { ConfigService } from '@nestjs/config';
2
- import { DiscordWebhookServiceConfig } from './webhook.discord.config';
3
- /**
4
- * Factory that creates a DiscordWebhookServiceConfig from environment variables.
5
- *
6
- * @param configService - The NestJS config service used to read the Discord public key environment variable.
7
- * @returns A validated DiscordWebhookServiceConfig populated from environment variables.
8
- */
9
- export declare function discordWebhookServiceConfigFactory(configService: ConfigService): DiscordWebhookServiceConfig;
10
- /**
11
- * NestJS module that provides Discord interaction webhook handling.
12
- *
13
- * Standalone — does not depend on DiscordModule (no bot token needed).
14
- * Reads the application public key from the DISCORD_PUBLIC_KEY environment variable.
15
- */
16
- export declare class DiscordWebhookModule {
17
- }
@@ -1,18 +0,0 @@
1
- import { type Request } from 'express';
2
- import { type DiscordInteractionType, type UntypedDiscordInteraction } from './webhook.discord';
3
- import { type Handler } from '@dereekb/util';
4
- import { DiscordWebhookServiceConfig } from './webhook.discord.config';
5
- /**
6
- * Service that handles Discord interaction webhook events.
7
- *
8
- * Verifies incoming webhook signatures and dispatches interactions to registered handlers.
9
- */
10
- export declare class DiscordWebhookService {
11
- private readonly logger;
12
- private readonly _verifier;
13
- readonly handler: Handler<UntypedDiscordInteraction, DiscordInteractionType>;
14
- readonly configure: import("@dereekb/util").HandlerConfigurer<import("./webhook.discord").DiscordInteractionHandlerConfigurer, UntypedDiscordInteraction, import("discord.js").InteractionType, boolean>;
15
- constructor(discordWebhookServiceConfig: DiscordWebhookServiceConfig);
16
- updateForWebhook(req: Request, rawBody: Buffer): Promise<void>;
17
- updateForDiscordInteraction(interaction: UntypedDiscordInteraction): Promise<void>;
18
- }
@@ -1,46 +0,0 @@
1
- import { type Request } from 'express';
2
- import { type DiscordPublicKey } from '../discord.type';
3
- export interface DiscordWebhookEventVerificationConfig {
4
- /**
5
- * The Ed25519 public key from the Discord Developer Portal.
6
- */
7
- readonly publicKey: DiscordPublicKey;
8
- }
9
- export type DiscordWebhookEventVerificationResult = DiscordWebhookEventVerificationSuccessResult | DiscordWebhookEventVerificationErrorResult;
10
- export interface DiscordWebhookEventVerificationSuccessResult {
11
- readonly valid: true;
12
- /**
13
- * The parsed JSON body of the verified interaction.
14
- */
15
- readonly body: unknown;
16
- }
17
- export interface DiscordWebhookEventVerificationErrorResult {
18
- readonly valid: false;
19
- }
20
- /**
21
- * Function that verifies a Discord interaction webhook request using Ed25519 signatures.
22
- */
23
- export type DiscordWebhookEventVerifier = (req: Request, rawBody: Buffer) => Promise<DiscordWebhookEventVerificationResult>;
24
- /**
25
- * Creates a verifier for Discord interaction webhook requests.
26
- *
27
- * Discord signs interaction webhook requests with Ed25519. The signed message is
28
- * the concatenation of the x-signature-timestamp header and the raw request body.
29
- * The signature is provided in the x-signature-ed25519 header as a hex string.
30
- *
31
- * Uses Node.js built-in crypto with JWK key import — no external dependencies required.
32
- *
33
- * @param config - Verification config containing the application's public key.
34
- * @returns A DiscordWebhookEventVerifier function that validates Ed25519-signed requests.
35
- *
36
- * @example
37
- * ```ts
38
- * const verifier = discordWebhookEventVerifier({ publicKey: 'your-hex-public-key' });
39
- * const result = await verifier(req, rawBody);
40
- *
41
- * if (result.valid) {
42
- * // result.body contains the parsed interaction
43
- * }
44
- * ```
45
- */
46
- export declare function discordWebhookEventVerifier(config: DiscordWebhookEventVerificationConfig): DiscordWebhookEventVerifier;