@went.tf/discord-bot-framework 2.0.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/LICENSE +21 -0
- package/README.md +550 -0
- package/build/.tsbuildinfo +1 -0
- package/build/api-client/api-client.d.ts +13 -0
- package/build/api-client/api-client.d.ts.map +1 -0
- package/build/api-client/api-client.js +147 -0
- package/build/api-client/api-client.js.map +1 -0
- package/build/api-client/api-http-exception.d.ts +7 -0
- package/build/api-client/api-http-exception.d.ts.map +1 -0
- package/build/api-client/api-http-exception.js +12 -0
- package/build/api-client/api-http-exception.js.map +1 -0
- package/build/api-client/index.d.ts +4 -0
- package/build/api-client/index.d.ts.map +1 -0
- package/build/api-client/index.js +4 -0
- package/build/api-client/index.js.map +1 -0
- package/build/api-client/types.d.ts +105 -0
- package/build/api-client/types.d.ts.map +1 -0
- package/build/api-client/types.js +8 -0
- package/build/api-client/types.js.map +1 -0
- package/build/client/create-bot-client.d.ts +14 -0
- package/build/client/create-bot-client.d.ts.map +1 -0
- package/build/client/create-bot-client.js +19 -0
- package/build/client/create-bot-client.js.map +1 -0
- package/build/client/create-shard-manager.d.ts +17 -0
- package/build/client/create-shard-manager.d.ts.map +1 -0
- package/build/client/create-shard-manager.js +26 -0
- package/build/client/create-shard-manager.js.map +1 -0
- package/build/client/index.d.ts +3 -0
- package/build/client/index.d.ts.map +1 -0
- package/build/client/index.js +3 -0
- package/build/client/index.js.map +1 -0
- package/build/commands/build-application-commands-body.d.ts +39 -0
- package/build/commands/build-application-commands-body.d.ts.map +1 -0
- package/build/commands/build-application-commands-body.js +127 -0
- package/build/commands/build-application-commands-body.js.map +1 -0
- package/build/commands/fixed-reply-command-factory.d.ts +10 -0
- package/build/commands/fixed-reply-command-factory.d.ts.map +1 -0
- package/build/commands/fixed-reply-command-factory.js +19 -0
- package/build/commands/fixed-reply-command-factory.js.map +1 -0
- package/build/commands/index.d.ts +4 -0
- package/build/commands/index.d.ts.map +1 -0
- package/build/commands/index.js +4 -0
- package/build/commands/index.js.map +1 -0
- package/build/commands/registration.d.ts +24 -0
- package/build/commands/registration.d.ts.map +1 -0
- package/build/commands/registration.js +69 -0
- package/build/commands/registration.js.map +1 -0
- package/build/commands/schema/application-command-leaf-option.schema.d.ts +230 -0
- package/build/commands/schema/application-command-leaf-option.schema.d.ts.map +1 -0
- package/build/commands/schema/application-command-leaf-option.schema.js +129 -0
- package/build/commands/schema/application-command-leaf-option.schema.js.map +1 -0
- package/build/commands/schema/application-command-leaf-option.schema.json +258 -0
- package/build/commands/schema/application-command-option-choice.schema.d.ts +18 -0
- package/build/commands/schema/application-command-option-choice.schema.d.ts.map +1 -0
- package/build/commands/schema/application-command-option-choice.schema.js +12 -0
- package/build/commands/schema/application-command-option-choice.schema.js.map +1 -0
- package/build/commands/schema/application-command-option-choice.schema.json +23 -0
- package/build/commands/schema/application-command-option.schema.d.ts +12 -0
- package/build/commands/schema/application-command-option.schema.d.ts.map +1 -0
- package/build/commands/schema/application-command-option.schema.js +13 -0
- package/build/commands/schema/application-command-option.schema.js.map +1 -0
- package/build/commands/schema/application-command-option.schema.json +14 -0
- package/build/commands/schema/application-command-subcommand-group.schema.d.ts +28 -0
- package/build/commands/schema/application-command-subcommand-group.schema.d.ts.map +1 -0
- package/build/commands/schema/application-command-subcommand-group.schema.js +22 -0
- package/build/commands/schema/application-command-subcommand-group.schema.js.map +1 -0
- package/build/commands/schema/application-command-subcommand-group.schema.json +26 -0
- package/build/commands/schema/application-command-subcommand.schema.d.ts +29 -0
- package/build/commands/schema/application-command-subcommand.schema.d.ts.map +1 -0
- package/build/commands/schema/application-command-subcommand.schema.js +23 -0
- package/build/commands/schema/application-command-subcommand.schema.js.map +1 -0
- package/build/commands/schema/application-command-subcommand.schema.json +26 -0
- package/build/commands/schema/application-command-type.schema.d.ts +6 -0
- package/build/commands/schema/application-command-type.schema.d.ts.map +1 -0
- package/build/commands/schema/application-command-type.schema.js +6 -0
- package/build/commands/schema/application-command-type.schema.js.map +1 -0
- package/build/commands/schema/application-command-type.schema.json +9 -0
- package/build/commands/schema/application-integration-type.schema.d.ts +6 -0
- package/build/commands/schema/application-integration-type.schema.d.ts.map +1 -0
- package/build/commands/schema/application-integration-type.schema.js +6 -0
- package/build/commands/schema/application-integration-type.schema.js.map +1 -0
- package/build/commands/schema/application-integration-type.schema.json +8 -0
- package/build/commands/schema/channel-type.schema.d.ts +6 -0
- package/build/commands/schema/channel-type.schema.d.ts.map +1 -0
- package/build/commands/schema/channel-type.schema.js +6 -0
- package/build/commands/schema/channel-type.schema.js.map +1 -0
- package/build/commands/schema/channel-type.schema.json +16 -0
- package/build/commands/schema/chat-input-command.schema.d.ts +45 -0
- package/build/commands/schema/chat-input-command.schema.d.ts.map +1 -0
- package/build/commands/schema/chat-input-command.schema.js +34 -0
- package/build/commands/schema/chat-input-command.schema.js.map +1 -0
- package/build/commands/schema/chat-input-command.schema.json +46 -0
- package/build/commands/schema/commands-file.schema.d.ts +18 -0
- package/build/commands/schema/commands-file.schema.d.ts.map +1 -0
- package/build/commands/schema/commands-file.schema.js +16 -0
- package/build/commands/schema/commands-file.schema.js.map +1 -0
- package/build/commands/schema/commands-file.schema.json +14 -0
- package/build/commands/schema/context-menu-command.schema.d.ts +40 -0
- package/build/commands/schema/context-menu-command.schema.d.ts.map +1 -0
- package/build/commands/schema/context-menu-command.schema.js +32 -0
- package/build/commands/schema/context-menu-command.schema.js.map +1 -0
- package/build/commands/schema/context-menu-command.schema.json +40 -0
- package/build/commands/schema/context-menu-name.schema.d.ts +7 -0
- package/build/commands/schema/context-menu-name.schema.d.ts.map +1 -0
- package/build/commands/schema/context-menu-name.schema.js +7 -0
- package/build/commands/schema/context-menu-name.schema.js.map +1 -0
- package/build/commands/schema/context-menu-name.schema.json +6 -0
- package/build/commands/schema/default-member-permissions.schema.d.ts +7 -0
- package/build/commands/schema/default-member-permissions.schema.d.ts.map +1 -0
- package/build/commands/schema/default-member-permissions.schema.js +7 -0
- package/build/commands/schema/default-member-permissions.schema.js.map +1 -0
- package/build/commands/schema/default-member-permissions.schema.json +6 -0
- package/build/commands/schema/index.d.ts +77 -0
- package/build/commands/schema/index.d.ts.map +1 -0
- package/build/commands/schema/index.js +48 -0
- package/build/commands/schema/index.js.map +1 -0
- package/build/commands/schema/interaction-context-type.schema.d.ts +6 -0
- package/build/commands/schema/interaction-context-type.schema.d.ts.map +1 -0
- package/build/commands/schema/interaction-context-type.schema.js +6 -0
- package/build/commands/schema/interaction-context-type.schema.js.map +1 -0
- package/build/commands/schema/interaction-context-type.schema.json +9 -0
- package/build/commands/schema/option-name.schema.d.ts +7 -0
- package/build/commands/schema/option-name.schema.d.ts.map +1 -0
- package/build/commands/schema/option-name.schema.js +7 -0
- package/build/commands/schema/option-name.schema.js.map +1 -0
- package/build/commands/schema/option-name.schema.json +6 -0
- package/build/commands/schema/parse-commands-file.d.ts +19 -0
- package/build/commands/schema/parse-commands-file.d.ts.map +1 -0
- package/build/commands/schema/parse-commands-file.js +19 -0
- package/build/commands/schema/parse-commands-file.js.map +1 -0
- package/build/db/create-postgres-prisma-db.d.ts +20 -0
- package/build/db/create-postgres-prisma-db.d.ts.map +1 -0
- package/build/db/create-postgres-prisma-db.js +17 -0
- package/build/db/create-postgres-prisma-db.js.map +1 -0
- package/build/db/index.d.ts +2 -0
- package/build/db/index.d.ts.map +1 -0
- package/build/db/index.js +2 -0
- package/build/db/index.js.map +1 -0
- package/build/dev/create-handler-watcher.d.ts +23 -0
- package/build/dev/create-handler-watcher.d.ts.map +1 -0
- package/build/dev/create-handler-watcher.js +55 -0
- package/build/dev/create-handler-watcher.js.map +1 -0
- package/build/dev/create-source-reloader.d.ts +37 -0
- package/build/dev/create-source-reloader.d.ts.map +1 -0
- package/build/dev/create-source-reloader.js +42 -0
- package/build/dev/create-source-reloader.js.map +1 -0
- package/build/dev/index.d.ts +3 -0
- package/build/dev/index.d.ts.map +1 -0
- package/build/dev/index.js +3 -0
- package/build/dev/index.js.map +1 -0
- package/build/dev/reload-loader.d.ts +11 -0
- package/build/dev/reload-loader.d.ts.map +1 -0
- package/build/dev/reload-loader.js +28 -0
- package/build/dev/reload-loader.js.map +1 -0
- package/build/env/define-env.d.ts +25 -0
- package/build/env/define-env.d.ts.map +1 -0
- package/build/env/define-env.js +24 -0
- package/build/env/define-env.js.map +1 -0
- package/build/env/helpers.d.ts +9 -0
- package/build/env/helpers.d.ts.map +1 -0
- package/build/env/helpers.js +9 -0
- package/build/env/helpers.js.map +1 -0
- package/build/env/index.d.ts +3 -0
- package/build/env/index.d.ts.map +1 -0
- package/build/env/index.js +3 -0
- package/build/env/index.js.map +1 -0
- package/build/i18n/create-command-localizer.d.ts +27 -0
- package/build/i18n/create-command-localizer.d.ts.map +1 -0
- package/build/i18n/create-command-localizer.js +40 -0
- package/build/i18n/create-command-localizer.js.map +1 -0
- package/build/i18n/create-i18n-initializer.d.ts +18 -0
- package/build/i18n/create-i18n-initializer.d.ts.map +1 -0
- package/build/i18n/create-i18n-initializer.js +34 -0
- package/build/i18n/create-i18n-initializer.js.map +1 -0
- package/build/i18n/index.d.ts +3 -0
- package/build/i18n/index.d.ts.map +1 -0
- package/build/i18n/index.js +3 -0
- package/build/i18n/index.js.map +1 -0
- package/build/index.d.ts +8 -0
- package/build/index.d.ts.map +1 -0
- package/build/index.js +12 -0
- package/build/index.js.map +1 -0
- package/build/interactions/custom-id.d.ts +9 -0
- package/build/interactions/custom-id.d.ts.map +1 -0
- package/build/interactions/custom-id.js +15 -0
- package/build/interactions/custom-id.js.map +1 -0
- package/build/interactions/dispatch.d.ts +35 -0
- package/build/interactions/dispatch.d.ts.map +1 -0
- package/build/interactions/dispatch.js +87 -0
- package/build/interactions/dispatch.js.map +1 -0
- package/build/interactions/handle-interaction-error.d.ts +22 -0
- package/build/interactions/handle-interaction-error.d.ts.map +1 -0
- package/build/interactions/handle-interaction-error.js +65 -0
- package/build/interactions/handle-interaction-error.js.map +1 -0
- package/build/interactions/index.d.ts +7 -0
- package/build/interactions/index.d.ts.map +1 -0
- package/build/interactions/index.js +7 -0
- package/build/interactions/index.js.map +1 -0
- package/build/interactions/registry.d.ts +32 -0
- package/build/interactions/registry.d.ts.map +1 -0
- package/build/interactions/registry.js +49 -0
- package/build/interactions/registry.js.map +1 -0
- package/build/interactions/router.d.ts +28 -0
- package/build/interactions/router.d.ts.map +1 -0
- package/build/interactions/router.js +48 -0
- package/build/interactions/router.js.map +1 -0
- package/build/interactions/types.d.ts +37 -0
- package/build/interactions/types.d.ts.map +1 -0
- package/build/interactions/types.js +2 -0
- package/build/interactions/types.js.map +1 -0
- package/build/logger/create-logger.d.ts +27 -0
- package/build/logger/create-logger.d.ts.map +1 -0
- package/build/logger/create-logger.js +36 -0
- package/build/logger/create-logger.js.map +1 -0
- package/build/logger/dev-null-logger.d.ts +11 -0
- package/build/logger/dev-null-logger.d.ts.map +1 -0
- package/build/logger/dev-null-logger.js +19 -0
- package/build/logger/dev-null-logger.js.map +1 -0
- package/build/logger/discord-webhook-batcher.d.ts +38 -0
- package/build/logger/discord-webhook-batcher.d.ts.map +1 -0
- package/build/logger/discord-webhook-batcher.js +87 -0
- package/build/logger/discord-webhook-batcher.js.map +1 -0
- package/build/logger/discord-webhook-transport.d.ts +9 -0
- package/build/logger/discord-webhook-transport.d.ts.map +1 -0
- package/build/logger/discord-webhook-transport.js +20 -0
- package/build/logger/discord-webhook-transport.js.map +1 -0
- package/build/logger/index.d.ts +5 -0
- package/build/logger/index.d.ts.map +1 -0
- package/build/logger/index.js +5 -0
- package/build/logger/index.js.map +1 -0
- package/build/logger/logger.d.ts +30 -0
- package/build/logger/logger.d.ts.map +1 -0
- package/build/logger/logger.js +84 -0
- package/build/logger/logger.js.map +1 -0
- package/build/logger/pino-pretty-options.d.ts +12 -0
- package/build/logger/pino-pretty-options.d.ts.map +1 -0
- package/build/logger/pino-pretty-options.js +17 -0
- package/build/logger/pino-pretty-options.js.map +1 -0
- package/build/logger/types.d.ts +6 -0
- package/build/logger/types.d.ts.map +1 -0
- package/build/logger/types.js +2 -0
- package/build/logger/types.js.map +1 -0
- package/build/utils/discord-lookups.d.ts +16 -0
- package/build/utils/discord-lookups.d.ts.map +1 -0
- package/build/utils/discord-lookups.js +39 -0
- package/build/utils/discord-lookups.js.map +1 -0
- package/build/utils/get-git-data.d.ts +8 -0
- package/build/utils/get-git-data.d.ts.map +1 -0
- package/build/utils/get-git-data.js +18 -0
- package/build/utils/get-git-data.js.map +1 -0
- package/build/utils/index.d.ts +7 -0
- package/build/utils/index.d.ts.map +1 -0
- package/build/utils/index.js +7 -0
- package/build/utils/index.js.map +1 -0
- package/build/utils/messaging.d.ts +15 -0
- package/build/utils/messaging.d.ts.map +1 -0
- package/build/utils/messaging.js +71 -0
- package/build/utils/messaging.js.map +1 -0
- package/build/utils/promises.d.ts +6 -0
- package/build/utils/promises.d.ts.map +1 -0
- package/build/utils/promises.js +13 -0
- package/build/utils/promises.js.map +1 -0
- package/build/utils/run-attempts.d.ts +6 -0
- package/build/utils/run-attempts.d.ts.map +1 -0
- package/build/utils/run-attempts.js +16 -0
- package/build/utils/run-attempts.js.map +1 -0
- package/build/utils/strings.d.ts +7 -0
- package/build/utils/strings.d.ts.map +1 -0
- package/build/utils/strings.js +39 -0
- package/build/utils/strings.js.map +1 -0
- package/package.json +146 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"handle-interaction-error.d.ts","sourceRoot":"","sources":["../../src/interactions/handle-interaction-error.ts"],"names":[],"mappings":"AACA,OAAO,EACL,uBAAuB,EAIvB,uBAAuB,EACvB,oBAAoB,EACrB,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAKpD,MAAM,WAAW,6BAA6B;IAC5C,0FAA0F;IAC1F,YAAY,EAAE,MAAM,MAAM,CAAC;IAC3B;;;;OAIG;IACH,KAAK,CAAC,EAAE,CAAC,WAAW,EAAE,oBAAoB,EAAE,OAAO,EAAE,uBAAuB,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IAClG;;;;OAIG;IACH,iBAAiB,CAAC,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAChD;AAID,eAAO,MAAM,sBAAsB,GACjC,aAAa,oBAAoB,GAAG,uBAAuB,EAC3D,SAAS;IAAE,MAAM,EAAE,cAAc,CAAA;CAAE,EACnC,SAAS,6BAA6B,KACrC,OAAO,CAAC,IAAI,CA2Dd,CAAC"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { MessageFlags } from 'discord-api-types/v10';
|
|
2
|
+
import { ComponentType, DiscordjsError, DiscordjsErrorCodes, } from 'discord.js';
|
|
3
|
+
const ellipsis = '…';
|
|
4
|
+
const maximumMessageLength = 2000;
|
|
5
|
+
const defaultReply = (interaction, options) => interaction.reply(options);
|
|
6
|
+
export const handleInteractionError = async (interaction, context, options) => {
|
|
7
|
+
const { buildMessage, reply = defaultReply, onUnexpectedError } = options;
|
|
8
|
+
if (interaction.isAutocomplete()) {
|
|
9
|
+
await interaction.respond([
|
|
10
|
+
{
|
|
11
|
+
value: '',
|
|
12
|
+
name: buildMessage(),
|
|
13
|
+
},
|
|
14
|
+
]);
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
let alreadyReplied = interaction.replied;
|
|
18
|
+
if (!alreadyReplied) {
|
|
19
|
+
await onUnexpectedError?.();
|
|
20
|
+
try {
|
|
21
|
+
await reply(interaction, {
|
|
22
|
+
content: buildMessage(),
|
|
23
|
+
flags: MessageFlags.Ephemeral,
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
catch (e) {
|
|
27
|
+
if (e instanceof DiscordjsError && e.code === DiscordjsErrorCodes.InteractionAlreadyReplied) {
|
|
28
|
+
alreadyReplied = true;
|
|
29
|
+
}
|
|
30
|
+
else {
|
|
31
|
+
context.logger.error('Failed to send interaction error reply', e);
|
|
32
|
+
throw e;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
if (!alreadyReplied) {
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
// If we already replied, edit the existing message to include the error
|
|
40
|
+
const oldReply = await interaction.fetchReply();
|
|
41
|
+
const flags = oldReply.flags.bitfield;
|
|
42
|
+
const errorMessage = buildMessage();
|
|
43
|
+
const oldReplyComponents = oldReply.components;
|
|
44
|
+
if (oldReply.flags.has(MessageFlags.IsComponentsV2)) {
|
|
45
|
+
await interaction.editReply({
|
|
46
|
+
flags,
|
|
47
|
+
components: [...oldReplyComponents, {
|
|
48
|
+
type: ComponentType.TextDisplay,
|
|
49
|
+
content: errorMessage,
|
|
50
|
+
}],
|
|
51
|
+
});
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
const oldReplyContent = oldReply.content;
|
|
55
|
+
const messageSuffix = `\n\n${errorMessage}`;
|
|
56
|
+
let newContent = oldReplyContent + messageSuffix;
|
|
57
|
+
if (newContent.length > maximumMessageLength) {
|
|
58
|
+
newContent = oldReplyContent.substring(0, maximumMessageLength - messageSuffix.length - ellipsis.length) + ellipsis + messageSuffix;
|
|
59
|
+
}
|
|
60
|
+
await interaction.editReply({
|
|
61
|
+
flags,
|
|
62
|
+
content: newContent,
|
|
63
|
+
});
|
|
64
|
+
};
|
|
65
|
+
//# sourceMappingURL=handle-interaction-error.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"handle-interaction-error.js","sourceRoot":"","sources":["../../src/interactions/handle-interaction-error.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AACrD,OAAO,EAEL,aAAa,EACb,cAAc,EACd,mBAAmB,GAGpB,MAAM,YAAY,CAAC;AAGpB,MAAM,QAAQ,GAAG,GAAG,CAAC;AACrB,MAAM,oBAAoB,GAAG,IAAI,CAAC;AAmBlC,MAAM,YAAY,GAAG,CAAC,WAAiC,EAAE,OAAgC,EAAE,EAAE,CAAC,WAAW,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;AAEzH,MAAM,CAAC,MAAM,sBAAsB,GAAG,KAAK,EACzC,WAA2D,EAC3D,OAAmC,EACnC,OAAsC,EACvB,EAAE;IACjB,MAAM,EAAE,YAAY,EAAE,KAAK,GAAG,YAAY,EAAE,iBAAiB,EAAE,GAAG,OAAO,CAAC;IAE1E,IAAI,WAAW,CAAC,cAAc,EAAE,EAAE,CAAC;QACjC,MAAM,WAAW,CAAC,OAAO,CAAC;YACxB;gBACE,KAAK,EAAE,EAAE;gBACT,IAAI,EAAE,YAAY,EAAE;aACrB;SACF,CAAC,CAAC;QACH,OAAO;IACT,CAAC;IAED,IAAI,cAAc,GAAG,WAAW,CAAC,OAAO,CAAC;IACzC,IAAI,CAAC,cAAc,EAAE,CAAC;QACpB,MAAM,iBAAiB,EAAE,EAAE,CAAC;QAC5B,IAAI,CAAC;YACH,MAAM,KAAK,CAAC,WAAW,EAAE;gBACvB,OAAO,EAAE,YAAY,EAAE;gBACvB,KAAK,EAAE,YAAY,CAAC,SAAS;aAC9B,CAAC,CAAC;QACL,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,IAAI,CAAC,YAAY,cAAc,IAAI,CAAC,CAAC,IAAI,KAAK,mBAAmB,CAAC,yBAAyB,EAAE,CAAC;gBAC5F,cAAc,GAAG,IAAI,CAAC;YACxB,CAAC;iBAAM,CAAC;gBACN,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,wCAAwC,EAAE,CAAC,CAAC,CAAC;gBAClE,MAAM,CAAC,CAAC;YACV,CAAC;QACH,CAAC;IACH,CAAC;IACD,IAAI,CAAC,cAAc,EAAE,CAAC;QACpB,OAAO;IACT,CAAC;IAED,wEAAwE;IACxE,MAAM,QAAQ,GAAG,MAAM,WAAW,CAAC,UAAU,EAAE,CAAC;IAChD,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC,QAAQ,CAAC;IACtC,MAAM,YAAY,GAAG,YAAY,EAAE,CAAC;IACpC,MAAM,kBAAkB,GAAG,QAAQ,CAAC,UAAU,CAAC;IAC/C,IAAI,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,YAAY,CAAC,cAAc,CAAC,EAAE,CAAC;QACpD,MAAM,WAAW,CAAC,SAAS,CAAC;YAC1B,KAAK;YACL,UAAU,EAAE,CAAC,GAAG,kBAAkB,EAAE;oBAClC,IAAI,EAAE,aAAa,CAAC,WAAW;oBAC/B,OAAO,EAAE,YAAY;iBACtB,CAAC;SACH,CAAC,CAAC;QACH,OAAO;IACT,CAAC;IACD,MAAM,eAAe,GAAG,QAAQ,CAAC,OAAO,CAAC;IACzC,MAAM,aAAa,GAAG,OAAO,YAAY,EAAE,CAAC;IAC5C,IAAI,UAAU,GAAG,eAAe,GAAG,aAAa,CAAC;IACjD,IAAI,UAAU,CAAC,MAAM,GAAG,oBAAoB,EAAE,CAAC;QAC7C,UAAU,GAAG,eAAe,CAAC,SAAS,CAAC,CAAC,EAAE,oBAAoB,GAAG,aAAa,CAAC,MAAM,GAAG,QAAQ,CAAC,MAAM,CAAC,GAAG,QAAQ,GAAG,aAAa,CAAC;IACtI,CAAC;IACD,MAAM,WAAW,CAAC,SAAS,CAAC;QAC1B,KAAK;QACL,OAAO,EAAE,UAAU;KACpB,CAAC,CAAC;AACL,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/interactions/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,eAAe,CAAC;AAC9B,cAAc,aAAa,CAAC;AAC5B,cAAc,+BAA+B,CAAC;AAC9C,cAAc,eAAe,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/interactions/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,eAAe,CAAC;AAC9B,cAAc,aAAa,CAAC;AAC5B,cAAc,+BAA+B,CAAC;AAC9C,cAAc,eAAe,CAAC"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { BaseInteractionContext, BotChatInputCommand, BotContextMenuCommand, BotMessageComponent, BotModal } from './types.js';
|
|
2
|
+
export type NamedChatInputCommand<Ctx extends BaseInteractionContext, Name extends string = string> = BotChatInputCommand<Ctx> & {
|
|
3
|
+
name: Name;
|
|
4
|
+
};
|
|
5
|
+
export type NamedContextMenuCommand<Ctx extends BaseInteractionContext, Name extends string = string> = BotContextMenuCommand<Ctx> & {
|
|
6
|
+
name: Name;
|
|
7
|
+
};
|
|
8
|
+
export type NamedComponent<Ctx extends BaseInteractionContext, Id extends string = string> = BotMessageComponent<Ctx> & {
|
|
9
|
+
id: Id;
|
|
10
|
+
};
|
|
11
|
+
export type NamedModal<Ctx extends BaseInteractionContext, Id extends string = string> = BotModal<Ctx> & {
|
|
12
|
+
id: Id;
|
|
13
|
+
};
|
|
14
|
+
export interface Registry<Name extends string, T> {
|
|
15
|
+
readonly byName: Record<Name, T>;
|
|
16
|
+
readonly names: readonly Name[];
|
|
17
|
+
isKnown(name: string): name is Name;
|
|
18
|
+
}
|
|
19
|
+
export declare function createChatInputCommandRegistry<const Commands extends readonly NamedChatInputCommand<any, string>[]>(commands: Commands): Registry<Commands[number]['name'], Commands[number]>;
|
|
20
|
+
export declare function createContextMenuCommandRegistry<const Commands extends readonly NamedContextMenuCommand<any, string>[]>(commands: Commands): Registry<Commands[number]['name'], Commands[number]>;
|
|
21
|
+
export declare function createComponentRegistry<const Components extends readonly NamedComponent<any, string>[]>(components: Components): Registry<Components[number]['id'], Components[number]>;
|
|
22
|
+
export declare function createModalRegistry<const Modals extends readonly NamedModal<any, string>[]>(modals: Modals): Registry<Modals[number]['id'], Modals[number]>;
|
|
23
|
+
/**
|
|
24
|
+
* Flattens every chat-input command's nested `.modal` map into a flat
|
|
25
|
+
* modal-id -> owning-command lookup (mirroring what a bot with Fantastick's
|
|
26
|
+
* shape hand-builds today), presented as a synthesized `Registry` so the
|
|
27
|
+
* existing `dispatchModal` can consume it directly via `.byName` without any
|
|
28
|
+
* changes to `dispatch.ts`. Each synthesized entry's `handle` closes over the
|
|
29
|
+
* owning command's `modal[modalId]`.
|
|
30
|
+
*/
|
|
31
|
+
export declare function flattenCommandModals<Ctx extends BaseInteractionContext>(chatInputRegistry: Registry<string, NamedChatInputCommand<Ctx, string>>): Registry<string, BotModal<Ctx>>;
|
|
32
|
+
//# sourceMappingURL=registry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/interactions/registry.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,sBAAsB,EACtB,mBAAmB,EACnB,qBAAqB,EACrB,mBAAmB,EACnB,QAAQ,EACT,MAAM,YAAY,CAAC;AAEpB,MAAM,MAAM,qBAAqB,CAAC,GAAG,SAAS,sBAAsB,EAAE,IAAI,SAAS,MAAM,GAAG,MAAM,IAChG,mBAAmB,CAAC,GAAG,CAAC,GAAG;IAAE,IAAI,EAAE,IAAI,CAAA;CAAE,CAAC;AAE5C,MAAM,MAAM,uBAAuB,CAAC,GAAG,SAAS,sBAAsB,EAAE,IAAI,SAAS,MAAM,GAAG,MAAM,IAClG,qBAAqB,CAAC,GAAG,CAAC,GAAG;IAAE,IAAI,EAAE,IAAI,CAAA;CAAE,CAAC;AAE9C,MAAM,MAAM,cAAc,CAAC,GAAG,SAAS,sBAAsB,EAAE,EAAE,SAAS,MAAM,GAAG,MAAM,IACvF,mBAAmB,CAAC,GAAG,CAAC,GAAG;IAAE,EAAE,EAAE,EAAE,CAAA;CAAE,CAAC;AAExC,MAAM,MAAM,UAAU,CAAC,GAAG,SAAS,sBAAsB,EAAE,EAAE,SAAS,MAAM,GAAG,MAAM,IACnF,QAAQ,CAAC,GAAG,CAAC,GAAG;IAAE,EAAE,EAAE,EAAE,CAAA;CAAE,CAAC;AAE7B,MAAM,WAAW,QAAQ,CAAC,IAAI,SAAS,MAAM,EAAE,CAAC;IAC9C,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;IACjC,QAAQ,CAAC,KAAK,EAAE,SAAS,IAAI,EAAE,CAAC;IAChC,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,IAAI,IAAI,CAAC;CACrC;AAmBD,wBAAgB,8BAA8B,CAE5C,KAAK,CAAC,QAAQ,SAAS,SAAS,qBAAqB,CAAC,GAAG,EAAE,MAAM,CAAC,EAAE,EACpE,QAAQ,EAAE,QAAQ,GAAG,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC,CAE1E;AAED,wBAAgB,gCAAgC,CAE9C,KAAK,CAAC,QAAQ,SAAS,SAAS,uBAAuB,CAAC,GAAG,EAAE,MAAM,CAAC,EAAE,EACtE,QAAQ,EAAE,QAAQ,GAAG,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC,CAE1E;AAED,wBAAgB,uBAAuB,CAErC,KAAK,CAAC,UAAU,SAAS,SAAS,cAAc,CAAC,GAAG,EAAE,MAAM,CAAC,EAAE,EAC/D,UAAU,EAAE,UAAU,GAAG,QAAQ,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,EAAE,UAAU,CAAC,MAAM,CAAC,CAAC,CAEhF;AAED,wBAAgB,mBAAmB,CAEjC,KAAK,CAAC,MAAM,SAAS,SAAS,UAAU,CAAC,GAAG,EAAE,MAAM,CAAC,EAAE,EACvD,MAAM,EAAE,MAAM,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,CAEhE;AAED;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAAC,GAAG,SAAS,sBAAsB,EACrE,iBAAiB,EAAE,QAAQ,CAAC,MAAM,EAAE,qBAAqB,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC,GACtE,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC,GAAG,CAAC,CAAC,CAUjC"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
function buildRegistry(items, keyOf) {
|
|
2
|
+
const byName = {};
|
|
3
|
+
for (const item of items) {
|
|
4
|
+
const key = keyOf(item);
|
|
5
|
+
if (key in byName) {
|
|
6
|
+
throw new Error(`Duplicate registry key "${key}"`);
|
|
7
|
+
}
|
|
8
|
+
byName[key] = item;
|
|
9
|
+
}
|
|
10
|
+
const names = Object.keys(byName);
|
|
11
|
+
return {
|
|
12
|
+
byName,
|
|
13
|
+
names,
|
|
14
|
+
isKnown: (name) => name in byName,
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
export function createChatInputCommandRegistry(commands) {
|
|
18
|
+
return buildRegistry(commands, (c) => c.name);
|
|
19
|
+
}
|
|
20
|
+
export function createContextMenuCommandRegistry(commands) {
|
|
21
|
+
return buildRegistry(commands, (c) => c.name);
|
|
22
|
+
}
|
|
23
|
+
export function createComponentRegistry(components) {
|
|
24
|
+
return buildRegistry(components, (c) => c.id);
|
|
25
|
+
}
|
|
26
|
+
export function createModalRegistry(modals) {
|
|
27
|
+
return buildRegistry(modals, (m) => m.id);
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Flattens every chat-input command's nested `.modal` map into a flat
|
|
31
|
+
* modal-id -> owning-command lookup (mirroring what a bot with Fantastick's
|
|
32
|
+
* shape hand-builds today), presented as a synthesized `Registry` so the
|
|
33
|
+
* existing `dispatchModal` can consume it directly via `.byName` without any
|
|
34
|
+
* changes to `dispatch.ts`. Each synthesized entry's `handle` closes over the
|
|
35
|
+
* owning command's `modal[modalId]`.
|
|
36
|
+
*/
|
|
37
|
+
export function flattenCommandModals(chatInputRegistry) {
|
|
38
|
+
const modals = [];
|
|
39
|
+
for (const command of chatInputRegistry.names.map((name) => chatInputRegistry.byName[name])) {
|
|
40
|
+
if (!command.modal)
|
|
41
|
+
continue;
|
|
42
|
+
for (const modalId of Object.keys(command.modal)) {
|
|
43
|
+
const handle = command.modal[modalId];
|
|
44
|
+
modals.push({ id: modalId, handle });
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return buildRegistry(modals, (m) => m.id);
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=registry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.js","sourceRoot":"","sources":["../../src/interactions/registry.ts"],"names":[],"mappings":"AA0BA,SAAS,aAAa,CAAyB,KAAmB,EAAE,KAAwB;IAC1F,MAAM,MAAM,GAAG,EAAqB,CAAC;IACrC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,GAAG,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC;QACxB,IAAI,GAAG,IAAI,MAAM,EAAE,CAAC;YAClB,MAAM,IAAI,KAAK,CAAC,2BAA2B,GAAG,GAAG,CAAC,CAAC;QACrD,CAAC;QACD,MAAM,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC;IACrB,CAAC;IACD,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,CAAW,CAAC;IAC5C,OAAO;QACL,MAAM;QACN,KAAK;QACL,OAAO,EAAE,CAAC,IAAY,EAAgB,EAAE,CAAC,IAAI,IAAI,MAAM;KACxD,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,8BAA8B,CAG5C,QAAkB;IAClB,OAAO,aAAa,CAAC,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAyD,CAAC;AACxG,CAAC;AAED,MAAM,UAAU,gCAAgC,CAG9C,QAAkB;IAClB,OAAO,aAAa,CAAC,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAyD,CAAC;AACxG,CAAC;AAED,MAAM,UAAU,uBAAuB,CAGrC,UAAsB;IACtB,OAAO,aAAa,CAAC,UAAU,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAA2D,CAAC;AAC1G,CAAC;AAED,MAAM,UAAU,mBAAmB,CAGjC,MAAc;IACd,OAAO,aAAa,CAAC,MAAM,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAmD,CAAC;AAC9F,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,oBAAoB,CAClC,iBAAuE;IAEvE,MAAM,MAAM,GAAsB,EAAE,CAAC;IACrC,KAAK,MAAM,OAAO,IAAI,iBAAiB,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,iBAAiB,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC;QAC5F,IAAI,CAAC,OAAO,CAAC,KAAK;YAAE,SAAS;QAC7B,KAAK,MAAM,OAAO,IAAI,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;YACjD,MAAM,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;YACtC,MAAM,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,CAAC;QACvC,CAAC;IACH,CAAC;IACD,OAAO,aAAa,CAAC,MAAM,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;AAC5C,CAAC"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { Interaction } from 'discord.js';
|
|
2
|
+
import { OnDispatchError } from './dispatch.js';
|
|
3
|
+
import { BaseInteractionContext, BotChatInputCommand, BotContextMenuCommand, BotMessageComponent, BotModal } from './types.js';
|
|
4
|
+
export interface InteractionRouterConfig<Ctx extends BaseInteractionContext> {
|
|
5
|
+
commands: Record<string, BotChatInputCommand<Ctx>>;
|
|
6
|
+
components?: Record<string, BotMessageComponent<Ctx>>;
|
|
7
|
+
modals?: Record<string, BotModal<Ctx>>;
|
|
8
|
+
contextMenuCommands?: Record<string, BotContextMenuCommand<Ctx>>;
|
|
9
|
+
customIdSeparator?: string;
|
|
10
|
+
/**
|
|
11
|
+
* Builds (or enriches) the per-interaction context. Runs before dispatch on
|
|
12
|
+
* every interaction type. This is the seam bots use to wire in things the
|
|
13
|
+
* router itself has no opinion about, e.g. a per-locale `t` function or a
|
|
14
|
+
* cached settings lookup.
|
|
15
|
+
*/
|
|
16
|
+
buildContext: (interaction: Interaction, baseContext: Ctx) => Ctx | Promise<Ctx>;
|
|
17
|
+
onError: OnDispatchError<Ctx>;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* A convenience dispatcher covering chat-input commands, autocomplete,
|
|
21
|
+
* message components, modal submits, and context-menu commands, wired
|
|
22
|
+
* through a single `Client#interactionCreate` listener. Bots that need
|
|
23
|
+
* finer-grained control (e.g. running telemetry after a command handles
|
|
24
|
+
* successfully) can call the individual `dispatch*` functions directly
|
|
25
|
+
* instead of this convenience wrapper.
|
|
26
|
+
*/
|
|
27
|
+
export declare function createInteractionRouter<Ctx extends BaseInteractionContext>(config: InteractionRouterConfig<Ctx>): (interaction: Interaction, baseContext: Ctx) => Promise<void>;
|
|
28
|
+
//# sourceMappingURL=router.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"router.d.ts","sourceRoot":"","sources":["../../src/interactions/router.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAmB,MAAM,YAAY,CAAC;AAC1D,OAAO,EAML,eAAe,EAChB,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,sBAAsB,EACtB,mBAAmB,EACnB,qBAAqB,EACrB,mBAAmB,EACnB,QAAQ,EACT,MAAM,YAAY,CAAC;AAEpB,MAAM,WAAW,uBAAuB,CAAC,GAAG,SAAS,sBAAsB;IACzE,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,mBAAmB,CAAC,GAAG,CAAC,CAAC,CAAC;IACnD,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,mBAAmB,CAAC,GAAG,CAAC,CAAC,CAAC;IACtD,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC;IACvC,mBAAmB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,qBAAqB,CAAC,GAAG,CAAC,CAAC,CAAC;IACjE,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B;;;;;OAKG;IACH,YAAY,EAAE,CAAC,WAAW,EAAE,WAAW,EAAE,WAAW,EAAE,GAAG,KAAK,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;IACjF,OAAO,EAAE,eAAe,CAAC,GAAG,CAAC,CAAC;CAC/B;AAED;;;;;;;GAOG;AACH,wBAAgB,uBAAuB,CAAC,GAAG,SAAS,sBAAsB,EAAE,MAAM,EAAE,uBAAuB,CAAC,GAAG,CAAC,IAChG,aAAa,WAAW,EAAE,aAAa,GAAG,KAAG,OAAO,CAAC,IAAI,CAAC,CAqCzE"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { InteractionType } from 'discord.js';
|
|
2
|
+
import { dispatchAutocomplete, dispatchChatInputCommand, dispatchComponent, dispatchContextMenu, dispatchModal, } from './dispatch.js';
|
|
3
|
+
/**
|
|
4
|
+
* A convenience dispatcher covering chat-input commands, autocomplete,
|
|
5
|
+
* message components, modal submits, and context-menu commands, wired
|
|
6
|
+
* through a single `Client#interactionCreate` listener. Bots that need
|
|
7
|
+
* finer-grained control (e.g. running telemetry after a command handles
|
|
8
|
+
* successfully) can call the individual `dispatch*` functions directly
|
|
9
|
+
* instead of this convenience wrapper.
|
|
10
|
+
*/
|
|
11
|
+
export function createInteractionRouter(config) {
|
|
12
|
+
return async (interaction, baseContext) => {
|
|
13
|
+
const context = await config.buildContext(interaction, baseContext);
|
|
14
|
+
if (interaction.isChatInputCommand()) {
|
|
15
|
+
await dispatchChatInputCommand(interaction, context, { commands: config.commands, onError: config.onError });
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
if (interaction.isAutocomplete()) {
|
|
19
|
+
await dispatchAutocomplete(interaction, context, { commands: config.commands, onError: config.onError });
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
if (interaction.isMessageComponent()) {
|
|
23
|
+
await dispatchComponent(interaction, context, {
|
|
24
|
+
components: config.components ?? {},
|
|
25
|
+
customIdSeparator: config.customIdSeparator,
|
|
26
|
+
onError: config.onError,
|
|
27
|
+
});
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
if (interaction.isModalSubmit()) {
|
|
31
|
+
await dispatchModal(interaction, context, {
|
|
32
|
+
modals: config.modals ?? {},
|
|
33
|
+
customIdSeparator: config.customIdSeparator,
|
|
34
|
+
onError: config.onError,
|
|
35
|
+
});
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
if (interaction.type === InteractionType.ApplicationCommand && (interaction.isUserContextMenuCommand() || interaction.isMessageContextMenuCommand())) {
|
|
39
|
+
await dispatchContextMenu(interaction, context, {
|
|
40
|
+
contextMenuCommands: config.contextMenuCommands ?? {},
|
|
41
|
+
onError: config.onError,
|
|
42
|
+
});
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
throw new Error(`Unhandled interaction of type ${interaction.type}`);
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=router.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"router.js","sourceRoot":"","sources":["../../src/interactions/router.ts"],"names":[],"mappings":"AAAA,OAAO,EAAe,eAAe,EAAE,MAAM,YAAY,CAAC;AAC1D,OAAO,EACL,oBAAoB,EACpB,wBAAwB,EACxB,iBAAiB,EACjB,mBAAmB,EACnB,aAAa,GAEd,MAAM,eAAe,CAAC;AAyBvB;;;;;;;GAOG;AACH,MAAM,UAAU,uBAAuB,CAAqC,MAAoC;IAC9G,OAAO,KAAK,EAAE,WAAwB,EAAE,WAAgB,EAAiB,EAAE;QACzE,MAAM,OAAO,GAAG,MAAM,MAAM,CAAC,YAAY,CAAC,WAAW,EAAE,WAAW,CAAC,CAAC;QAEpE,IAAI,WAAW,CAAC,kBAAkB,EAAE,EAAE,CAAC;YACrC,MAAM,wBAAwB,CAAC,WAAW,EAAE,OAAO,EAAE,EAAE,QAAQ,EAAE,MAAM,CAAC,QAAQ,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC;YAC7G,OAAO;QACT,CAAC;QACD,IAAI,WAAW,CAAC,cAAc,EAAE,EAAE,CAAC;YACjC,MAAM,oBAAoB,CAAC,WAAW,EAAE,OAAO,EAAE,EAAE,QAAQ,EAAE,MAAM,CAAC,QAAQ,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC;YACzG,OAAO;QACT,CAAC;QACD,IAAI,WAAW,CAAC,kBAAkB,EAAE,EAAE,CAAC;YACrC,MAAM,iBAAiB,CAAC,WAAW,EAAE,OAAO,EAAE;gBAC5C,UAAU,EAAE,MAAM,CAAC,UAAU,IAAI,EAAE;gBACnC,iBAAiB,EAAE,MAAM,CAAC,iBAAiB;gBAC3C,OAAO,EAAE,MAAM,CAAC,OAAO;aACxB,CAAC,CAAC;YACH,OAAO;QACT,CAAC;QACD,IAAI,WAAW,CAAC,aAAa,EAAE,EAAE,CAAC;YAChC,MAAM,aAAa,CAAC,WAAW,EAAE,OAAO,EAAE;gBACxC,MAAM,EAAE,MAAM,CAAC,MAAM,IAAI,EAAE;gBAC3B,iBAAiB,EAAE,MAAM,CAAC,iBAAiB;gBAC3C,OAAO,EAAE,MAAM,CAAC,OAAO;aACxB,CAAC,CAAC;YACH,OAAO;QACT,CAAC;QACD,IAAI,WAAW,CAAC,IAAI,KAAK,eAAe,CAAC,kBAAkB,IAAI,CAAC,WAAW,CAAC,wBAAwB,EAAE,IAAI,WAAW,CAAC,2BAA2B,EAAE,CAAC,EAAE,CAAC;YACrJ,MAAM,mBAAmB,CAAC,WAAW,EAAE,OAAO,EAAE;gBAC9C,mBAAmB,EAAE,MAAM,CAAC,mBAAmB,IAAI,EAAE;gBACrD,OAAO,EAAE,MAAM,CAAC,OAAO;aACxB,CAAC,CAAC;YACH,OAAO;QACT,CAAC;QAED,MAAM,IAAI,KAAK,CAAC,iCAAiC,WAAW,CAAC,IAAI,EAAE,CAAC,CAAC;IACvE,CAAC,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { AutocompleteInteraction, ChatInputCommandInteraction, MessageComponentInteraction, ModalSubmitInteraction, UserContextMenuCommandInteraction, MessageContextMenuCommandInteraction } from 'discord.js';
|
|
2
|
+
import { NestableLogger } from '../logger/types.js';
|
|
3
|
+
export type BaseInteractionContext = {
|
|
4
|
+
logger: NestableLogger;
|
|
5
|
+
};
|
|
6
|
+
export type CommandHandler<Ctx> = (interaction: ChatInputCommandInteraction, context: Ctx) => void | Promise<void>;
|
|
7
|
+
export type AutocompleteHandler<Ctx> = (interaction: AutocompleteInteraction, context: Ctx, optionName: string) => void | Promise<void>;
|
|
8
|
+
export type ComponentHandler<Ctx> = (interaction: MessageComponentInteraction, context: Ctx, resourceId?: string) => void | Promise<void>;
|
|
9
|
+
export type ModalHandler<Ctx> = (interaction: ModalSubmitInteraction, context: Ctx, resourceId?: string) => void | Promise<void>;
|
|
10
|
+
export type ContextMenuHandler<Ctx> = (interaction: UserContextMenuCommandInteraction | MessageContextMenuCommandInteraction, context: Ctx) => void | Promise<void>;
|
|
11
|
+
/**
|
|
12
|
+
* A command's wire definition (name, description, options, permissions) lives
|
|
13
|
+
* in the bot's commands.json file, not here - see `./schema` and
|
|
14
|
+
* `buildApplicationCommandsBody`. This is purely the handler side.
|
|
15
|
+
*/
|
|
16
|
+
export interface BotChatInputCommand<Ctx> {
|
|
17
|
+
/** When present, the command is only included in registration output if this returns true. */
|
|
18
|
+
registerCondition?: () => boolean;
|
|
19
|
+
handle: CommandHandler<Ctx>;
|
|
20
|
+
/** Keyed by the autocompleted option's name. */
|
|
21
|
+
autocomplete?: Record<string, AutocompleteHandler<Ctx>>;
|
|
22
|
+
/** Keyed by modal ID, for modals shown by this command. */
|
|
23
|
+
modal?: Record<string, ModalHandler<Ctx>>;
|
|
24
|
+
}
|
|
25
|
+
export interface BotMessageComponent<Ctx> {
|
|
26
|
+
handle: ComponentHandler<Ctx>;
|
|
27
|
+
}
|
|
28
|
+
export interface BotModal<Ctx> {
|
|
29
|
+
handle: ModalHandler<Ctx>;
|
|
30
|
+
}
|
|
31
|
+
/** A context-menu command's wire definition lives in the bot's commands.json file - see `./schema`. */
|
|
32
|
+
export interface BotContextMenuCommand<Ctx> {
|
|
33
|
+
/** When present, the command is only included in registration output if this returns true. */
|
|
34
|
+
registerCondition?: () => boolean;
|
|
35
|
+
handle: ContextMenuHandler<Ctx>;
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/interactions/types.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,uBAAuB,EACvB,2BAA2B,EAC3B,2BAA2B,EAC3B,sBAAsB,EACtB,iCAAiC,EACjC,oCAAoC,EACrC,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAEpD,MAAM,MAAM,sBAAsB,GAAG;IAAE,MAAM,EAAE,cAAc,CAAA;CAAE,CAAC;AAEhE,MAAM,MAAM,cAAc,CAAC,GAAG,IAAI,CAAC,WAAW,EAAE,2BAA2B,EAAE,OAAO,EAAE,GAAG,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;AACnH,MAAM,MAAM,mBAAmB,CAAC,GAAG,IAAI,CAAC,WAAW,EAAE,uBAAuB,EAAE,OAAO,EAAE,GAAG,EAAE,UAAU,EAAE,MAAM,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;AACxI,MAAM,MAAM,gBAAgB,CAAC,GAAG,IAAI,CAAC,WAAW,EAAE,2BAA2B,EAAE,OAAO,EAAE,GAAG,EAAE,UAAU,CAAC,EAAE,MAAM,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;AAC1I,MAAM,MAAM,YAAY,CAAC,GAAG,IAAI,CAAC,WAAW,EAAE,sBAAsB,EAAE,OAAO,EAAE,GAAG,EAAE,UAAU,CAAC,EAAE,MAAM,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;AACjI,MAAM,MAAM,kBAAkB,CAAC,GAAG,IAAI,CAAC,WAAW,EAAE,iCAAiC,GAAG,oCAAoC,EAAE,OAAO,EAAE,GAAG,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;AAEpK;;;;GAIG;AACH,MAAM,WAAW,mBAAmB,CAAC,GAAG;IACtC,8FAA8F;IAC9F,iBAAiB,CAAC,EAAE,MAAM,OAAO,CAAC;IAClC,MAAM,EAAE,cAAc,CAAC,GAAG,CAAC,CAAC;IAC5B,gDAAgD;IAChD,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,mBAAmB,CAAC,GAAG,CAAC,CAAC,CAAC;IACxD,2DAA2D;IAC3D,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC;CAC3C;AAED,MAAM,WAAW,mBAAmB,CAAC,GAAG;IACtC,MAAM,EAAE,gBAAgB,CAAC,GAAG,CAAC,CAAC;CAC/B;AAED,MAAM,WAAW,QAAQ,CAAC,GAAG;IAC3B,MAAM,EAAE,YAAY,CAAC,GAAG,CAAC,CAAC;CAC3B;AAED,uGAAuG;AACvG,MAAM,WAAW,qBAAqB,CAAC,GAAG;IACxC,8FAA8F;IAC9F,iBAAiB,CAAC,EAAE,MAAM,OAAO,CAAC;IAClC,MAAM,EAAE,kBAAkB,CAAC,GAAG,CAAC,CAAC;CACjC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/interactions/types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import pino from 'pino';
|
|
2
|
+
import { LogMethod, NestableLogger } from './types.js';
|
|
3
|
+
import { DiscordWebhookBatcherOptions } from './discord-webhook-batcher.js';
|
|
4
|
+
export interface CreateLoggerOptions {
|
|
5
|
+
prefix?: string | string[];
|
|
6
|
+
mutedMethods?: LogMethod[] | Set<LogMethod>;
|
|
7
|
+
console?: {
|
|
8
|
+
/** @default true */
|
|
9
|
+
enabled?: boolean;
|
|
10
|
+
/** @default 'trace' */
|
|
11
|
+
level?: pino.Level;
|
|
12
|
+
/** @default true */
|
|
13
|
+
pretty?: boolean;
|
|
14
|
+
};
|
|
15
|
+
discordWebhook?: Omit<DiscordWebhookBatcherOptions, 'fetchImpl'> & {
|
|
16
|
+
/** @default 'warn' */
|
|
17
|
+
level?: pino.Level;
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Builds a `NestableLogger` backed by a single root pino instance, configured with
|
|
22
|
+
* whichever transport targets (console + optional Discord webhook) are requested.
|
|
23
|
+
* `pino.transport()` — which spawns a worker thread — is invoked exactly once here,
|
|
24
|
+
* regardless of how many times the returned Logger is later `nest()`ed.
|
|
25
|
+
*/
|
|
26
|
+
export declare function createLogger(options?: CreateLoggerOptions): NestableLogger;
|
|
27
|
+
//# sourceMappingURL=create-logger.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create-logger.d.ts","sourceRoot":"","sources":["../../src/logger/create-logger.ts"],"names":[],"mappings":"AACA,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAGvD,OAAO,EAAE,4BAA4B,EAAE,MAAM,8BAA8B,CAAC;AAE5E,MAAM,WAAW,mBAAmB;IAClC,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IAC3B,YAAY,CAAC,EAAE,SAAS,EAAE,GAAG,GAAG,CAAC,SAAS,CAAC,CAAC;IAC5C,OAAO,CAAC,EAAE;QACR,oBAAoB;QACpB,OAAO,CAAC,EAAE,OAAO,CAAC;QAClB,uBAAuB;QACvB,KAAK,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC;QACnB,oBAAoB;QACpB,MAAM,CAAC,EAAE,OAAO,CAAC;KAClB,CAAC;IACF,cAAc,CAAC,EAAE,IAAI,CAAC,4BAA4B,EAAE,WAAW,CAAC,GAAG;QACjE,sBAAsB;QACtB,KAAK,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC;KACpB,CAAC;CACH;AAID;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,OAAO,GAAE,mBAAwB,GAAG,cAAc,CAoB9E"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { fileURLToPath } from 'node:url';
|
|
2
|
+
import pino from 'pino';
|
|
3
|
+
import { Logger } from './logger.js';
|
|
4
|
+
import { PINO_PRETTY_OPTIONS } from './pino-pretty-options.js';
|
|
5
|
+
const DISCORD_WEBHOOK_TRANSPORT_PATH = fileURLToPath(new URL('./discord-webhook-transport.js', import.meta.url));
|
|
6
|
+
/**
|
|
7
|
+
* Builds a `NestableLogger` backed by a single root pino instance, configured with
|
|
8
|
+
* whichever transport targets (console + optional Discord webhook) are requested.
|
|
9
|
+
* `pino.transport()` — which spawns a worker thread — is invoked exactly once here,
|
|
10
|
+
* regardless of how many times the returned Logger is later `nest()`ed.
|
|
11
|
+
*/
|
|
12
|
+
export function createLogger(options = {}) {
|
|
13
|
+
const targets = [];
|
|
14
|
+
if (options.console?.enabled !== false) {
|
|
15
|
+
targets.push(options.console?.pretty === false
|
|
16
|
+
? { target: 'pino/file', options: {}, level: options.console?.level ?? 'trace' }
|
|
17
|
+
: { target: 'pino-pretty', options: PINO_PRETTY_OPTIONS, level: options.console?.level ?? 'trace' });
|
|
18
|
+
}
|
|
19
|
+
if (options.discordWebhook) {
|
|
20
|
+
const { level, ...discordWebhookOptions } = options.discordWebhook;
|
|
21
|
+
targets.push({
|
|
22
|
+
target: DISCORD_WEBHOOK_TRANSPORT_PATH,
|
|
23
|
+
options: discordWebhookOptions,
|
|
24
|
+
level: level ?? 'warn',
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
const root = pino({ level: 'trace' }, pino.transport({ targets }));
|
|
28
|
+
return Logger.withPino(root, toArray(options.prefix ?? []), toSet(options.mutedMethods ?? []));
|
|
29
|
+
}
|
|
30
|
+
function toArray(value) {
|
|
31
|
+
return Array.isArray(value) ? value : [value];
|
|
32
|
+
}
|
|
33
|
+
function toSet(value) {
|
|
34
|
+
return Array.isArray(value) ? new Set(value) : value;
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=create-logger.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create-logger.js","sourceRoot":"","sources":["../../src/logger/create-logger.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,IAAI,MAAM,MAAM,CAAC;AAExB,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAoB/D,MAAM,8BAA8B,GAAG,aAAa,CAAC,IAAI,GAAG,CAAC,gCAAgC,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;AAEjH;;;;;GAKG;AACH,MAAM,UAAU,YAAY,CAAC,UAA+B,EAAE;IAC5D,MAAM,OAAO,GAAkC,EAAE,CAAC;IAElD,IAAI,OAAO,CAAC,OAAO,EAAE,OAAO,KAAK,KAAK,EAAE,CAAC;QACvC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,MAAM,KAAK,KAAK;YAC5C,CAAC,CAAC,EAAE,MAAM,EAAE,WAAW,EAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,OAAO,CAAC,OAAO,EAAE,KAAK,IAAI,OAAO,EAAE;YAChF,CAAC,CAAC,EAAE,MAAM,EAAE,aAAa,EAAE,OAAO,EAAE,mBAAmB,EAAE,KAAK,EAAE,OAAO,CAAC,OAAO,EAAE,KAAK,IAAI,OAAO,EAAE,CAAC,CAAC;IACzG,CAAC;IAED,IAAI,OAAO,CAAC,cAAc,EAAE,CAAC;QAC3B,MAAM,EAAE,KAAK,EAAE,GAAG,qBAAqB,EAAE,GAAG,OAAO,CAAC,cAAc,CAAC;QACnE,OAAO,CAAC,IAAI,CAAC;YACX,MAAM,EAAE,8BAA8B;YACtC,OAAO,EAAE,qBAAqB;YAC9B,KAAK,EAAE,KAAK,IAAI,MAAM;SACvB,CAAC,CAAC;IACL,CAAC;IAED,MAAM,IAAI,GAAG,IAAI,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC;IACnE,OAAO,MAAM,CAAC,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC,OAAO,CAAC,MAAM,IAAI,EAAE,CAAC,EAAE,KAAK,CAAC,OAAO,CAAC,YAAY,IAAI,EAAE,CAAC,CAAC,CAAC;AACjG,CAAC;AAED,SAAS,OAAO,CAAC,KAAwB;IACvC,OAAO,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;AAChD,CAAC;AAED,SAAS,KAAK,CAAC,KAAmC;IAChD,OAAO,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;AACvD,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { NestableLogger } from './types.js';
|
|
2
|
+
export declare class DevNullLogger implements NestableLogger {
|
|
3
|
+
debug(): void;
|
|
4
|
+
info(): void;
|
|
5
|
+
log(): void;
|
|
6
|
+
warn(): void;
|
|
7
|
+
error(): void;
|
|
8
|
+
nest(): NestableLogger;
|
|
9
|
+
muteMethods(): this;
|
|
10
|
+
}
|
|
11
|
+
//# sourceMappingURL=dev-null-logger.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dev-null-logger.d.ts","sourceRoot":"","sources":["../../src/logger/dev-null-logger.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAE5C,qBAAa,aAAc,YAAW,cAAc;IAClD,KAAK,IAAI,IAAI;IAGb,IAAI,IAAI,IAAI;IAGZ,GAAG,IAAI,IAAI;IAGX,IAAI,IAAI,IAAI;IAGZ,KAAK,IAAI,IAAI;IAGb,IAAI,IAAI,cAAc;IAItB,WAAW,IAAI,IAAI;CAGpB"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export class DevNullLogger {
|
|
2
|
+
debug() {
|
|
3
|
+
}
|
|
4
|
+
info() {
|
|
5
|
+
}
|
|
6
|
+
log() {
|
|
7
|
+
}
|
|
8
|
+
warn() {
|
|
9
|
+
}
|
|
10
|
+
error() {
|
|
11
|
+
}
|
|
12
|
+
nest() {
|
|
13
|
+
return new DevNullLogger();
|
|
14
|
+
}
|
|
15
|
+
muteMethods() {
|
|
16
|
+
return this;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=dev-null-logger.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dev-null-logger.js","sourceRoot":"","sources":["../../src/logger/dev-null-logger.ts"],"names":[],"mappings":"AAEA,MAAM,OAAO,aAAa;IACxB,KAAK;IACL,CAAC;IAED,IAAI;IACJ,CAAC;IAED,GAAG;IACH,CAAC;IAED,IAAI;IACJ,CAAC;IAED,KAAK;IACL,CAAC;IAED,IAAI;QACF,OAAO,IAAI,aAAa,EAAE,CAAC;IAC7B,CAAC;IAED,WAAW;QACT,OAAO,IAAI,CAAC;IACd,CAAC;CACF"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
export interface DiscordWebhookBatcherOptions {
|
|
2
|
+
url: string;
|
|
3
|
+
username?: string;
|
|
4
|
+
avatarUrl?: string;
|
|
5
|
+
/** @default 20000 */
|
|
6
|
+
batchIntervalMs?: number;
|
|
7
|
+
/** @default 10 */
|
|
8
|
+
maxBatchSize?: number;
|
|
9
|
+
/** @default 500 */
|
|
10
|
+
maxQueueLength?: number;
|
|
11
|
+
/** Overridable for tests; defaults to the global `fetch`. */
|
|
12
|
+
fetchImpl?: typeof fetch;
|
|
13
|
+
}
|
|
14
|
+
export interface PinoLogRecord {
|
|
15
|
+
level: number;
|
|
16
|
+
time: number;
|
|
17
|
+
msg?: string;
|
|
18
|
+
prefixLabel?: string;
|
|
19
|
+
[key: string]: unknown;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Buffers pino log records and flushes them to a Discord webhook at a fixed
|
|
23
|
+
* interval, rather than one POST per log call. A fixed cadence gives a hard,
|
|
24
|
+
* by-construction cap on request volume (600_000 / batchIntervalMs POSTs per
|
|
25
|
+
* 10 minutes), safely under Discord's per-webhook rate limits without needing a
|
|
26
|
+
* separate token-bucket.
|
|
27
|
+
*/
|
|
28
|
+
export declare class DiscordWebhookBatcher {
|
|
29
|
+
private readonly options;
|
|
30
|
+
private queue;
|
|
31
|
+
private readonly timer;
|
|
32
|
+
private readonly fetchImpl;
|
|
33
|
+
constructor(options: DiscordWebhookBatcherOptions);
|
|
34
|
+
write(record: PinoLogRecord): void;
|
|
35
|
+
flush(): Promise<void>;
|
|
36
|
+
close(): Promise<void>;
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=discord-webhook-batcher.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"discord-webhook-batcher.d.ts","sourceRoot":"","sources":["../../src/logger/discord-webhook-batcher.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,4BAA4B;IAC3C,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,qBAAqB;IACrB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,kBAAkB;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,mBAAmB;IACnB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,6DAA6D;IAC7D,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;CAC1B;AAED,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAiBD;;;;;;GAMG;AACH,qBAAa,qBAAqB;IAOpB,OAAO,CAAC,QAAQ,CAAC,OAAO;IANpC,OAAO,CAAC,KAAK,CAAuB;IAEpC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAiC;IAEvD,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAe;gBAEZ,OAAO,EAAE,4BAA4B;IASlE,KAAK,CAAC,MAAM,EAAE,aAAa,GAAG,IAAI;IAY5B,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAwBtB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAI7B"}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
const DEFAULT_BATCH_INTERVAL_MS = 20_000;
|
|
2
|
+
const DEFAULT_MAX_BATCH_SIZE = 10;
|
|
3
|
+
const DEFAULT_MAX_QUEUE_LENGTH = 500;
|
|
4
|
+
const EMBED_DESCRIPTION_LIMIT = 4096;
|
|
5
|
+
// Discord embed side-bar colors, keyed by pino's numeric levels (trace=10 ... fatal=60).
|
|
6
|
+
const LEVEL_COLORS = {
|
|
7
|
+
10: 0x95a5a6,
|
|
8
|
+
20: 0x3498db,
|
|
9
|
+
30: 0x2ecc71,
|
|
10
|
+
40: 0xf1c40f,
|
|
11
|
+
50: 0xe74c3c,
|
|
12
|
+
60: 0x992d22,
|
|
13
|
+
};
|
|
14
|
+
/**
|
|
15
|
+
* Buffers pino log records and flushes them to a Discord webhook at a fixed
|
|
16
|
+
* interval, rather than one POST per log call. A fixed cadence gives a hard,
|
|
17
|
+
* by-construction cap on request volume (600_000 / batchIntervalMs POSTs per
|
|
18
|
+
* 10 minutes), safely under Discord's per-webhook rate limits without needing a
|
|
19
|
+
* separate token-bucket.
|
|
20
|
+
*/
|
|
21
|
+
export class DiscordWebhookBatcher {
|
|
22
|
+
options;
|
|
23
|
+
queue = [];
|
|
24
|
+
timer;
|
|
25
|
+
fetchImpl;
|
|
26
|
+
constructor(options) {
|
|
27
|
+
this.options = options;
|
|
28
|
+
this.fetchImpl = options.fetchImpl ?? fetch;
|
|
29
|
+
const intervalMs = options.batchIntervalMs ?? DEFAULT_BATCH_INTERVAL_MS;
|
|
30
|
+
this.timer = setInterval(() => {
|
|
31
|
+
void this.flush();
|
|
32
|
+
}, intervalMs);
|
|
33
|
+
this.timer.unref?.();
|
|
34
|
+
}
|
|
35
|
+
write(record) {
|
|
36
|
+
this.queue.push(record);
|
|
37
|
+
const maxQueueLength = this.options.maxQueueLength ?? DEFAULT_MAX_QUEUE_LENGTH;
|
|
38
|
+
if (this.queue.length > maxQueueLength) {
|
|
39
|
+
const dropped = this.queue.length - maxQueueLength;
|
|
40
|
+
this.queue.splice(0, dropped);
|
|
41
|
+
// Reported directly to console, never re-entering the webhook pipeline, to
|
|
42
|
+
// avoid a feedback loop during a log storm.
|
|
43
|
+
console.error(`[discord-webhook-transport] Queue exceeded ${maxQueueLength} entries; dropped ${dropped} oldest log record(s).`);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
async flush() {
|
|
47
|
+
if (this.queue.length === 0)
|
|
48
|
+
return;
|
|
49
|
+
const maxBatchSize = this.options.maxBatchSize ?? DEFAULT_MAX_BATCH_SIZE;
|
|
50
|
+
const batch = this.queue.splice(0, maxBatchSize);
|
|
51
|
+
const payload = {
|
|
52
|
+
username: this.options.username,
|
|
53
|
+
avatar_url: this.options.avatarUrl,
|
|
54
|
+
embeds: batch.map(buildEmbed),
|
|
55
|
+
};
|
|
56
|
+
try {
|
|
57
|
+
const response = await this.fetchImpl(this.options.url, {
|
|
58
|
+
method: 'POST',
|
|
59
|
+
headers: { 'content-type': 'application/json' },
|
|
60
|
+
body: JSON.stringify(payload),
|
|
61
|
+
});
|
|
62
|
+
if (!response.ok) {
|
|
63
|
+
console.error(`[discord-webhook-transport] Webhook POST failed with status ${response.status}`);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
catch (e) {
|
|
67
|
+
console.error('[discord-webhook-transport] Webhook POST threw', e);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
async close() {
|
|
71
|
+
clearInterval(this.timer);
|
|
72
|
+
await this.flush();
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
function buildEmbed(record) {
|
|
76
|
+
const prefixLabel = typeof record.prefixLabel === 'string' ? record.prefixLabel : '';
|
|
77
|
+
const msg = typeof record.msg === 'string' ? record.msg : '';
|
|
78
|
+
return {
|
|
79
|
+
description: truncate(`${prefixLabel}${msg}`, EMBED_DESCRIPTION_LIMIT),
|
|
80
|
+
color: LEVEL_COLORS[record.level] ?? LEVEL_COLORS[30],
|
|
81
|
+
timestamp: new Date(record.time ?? Date.now()).toISOString(),
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
function truncate(value, maxLength) {
|
|
85
|
+
return value.length > maxLength ? `${value.slice(0, maxLength - 1)}…` : value;
|
|
86
|
+
}
|
|
87
|
+
//# sourceMappingURL=discord-webhook-batcher.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"discord-webhook-batcher.js","sourceRoot":"","sources":["../../src/logger/discord-webhook-batcher.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import build from 'pino-abstract-transport';
|
|
2
|
+
import { DiscordWebhookBatcherOptions } from './discord-webhook-batcher.js';
|
|
3
|
+
/**
|
|
4
|
+
* pino worker-thread transport entry point, loaded by `createLogger()` via an
|
|
5
|
+
* absolute file path (not a bare module specifier), since nothing outside this
|
|
6
|
+
* module needs to resolve it by name.
|
|
7
|
+
*/
|
|
8
|
+
export default function discordWebhookTransport(options: DiscordWebhookBatcherOptions): import("stream").Transform & build.OnUnknown;
|
|
9
|
+
//# sourceMappingURL=discord-webhook-transport.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"discord-webhook-transport.d.ts","sourceRoot":"","sources":["../../src/logger/discord-webhook-transport.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,yBAAyB,CAAC;AAC5C,OAAO,EAAyB,4BAA4B,EAAiB,MAAM,8BAA8B,CAAC;AAElH;;;;GAIG;AACH,MAAM,CAAC,OAAO,UAAU,uBAAuB,CAAC,OAAO,EAAE,4BAA4B,gDAepF"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import build from 'pino-abstract-transport';
|
|
2
|
+
import { DiscordWebhookBatcher } from './discord-webhook-batcher.js';
|
|
3
|
+
/**
|
|
4
|
+
* pino worker-thread transport entry point, loaded by `createLogger()` via an
|
|
5
|
+
* absolute file path (not a bare module specifier), since nothing outside this
|
|
6
|
+
* module needs to resolve it by name.
|
|
7
|
+
*/
|
|
8
|
+
export default function discordWebhookTransport(options) {
|
|
9
|
+
const batcher = new DiscordWebhookBatcher(options);
|
|
10
|
+
return build(async (source) => {
|
|
11
|
+
for await (const record of source) {
|
|
12
|
+
batcher.write(record);
|
|
13
|
+
}
|
|
14
|
+
}, {
|
|
15
|
+
close: async () => {
|
|
16
|
+
await batcher.close();
|
|
17
|
+
},
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=discord-webhook-transport.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"discord-webhook-transport.js","sourceRoot":"","sources":["../../src/logger/discord-webhook-transport.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,yBAAyB,CAAC;AAC5C,OAAO,EAAE,qBAAqB,EAA+C,MAAM,8BAA8B,CAAC;AAElH;;;;GAIG;AACH,MAAM,CAAC,OAAO,UAAU,uBAAuB,CAAC,OAAqC;IACnF,MAAM,OAAO,GAAG,IAAI,qBAAqB,CAAC,OAAO,CAAC,CAAC;IAEnD,OAAO,KAAK,CACV,KAAK,EAAE,MAAM,EAAE,EAAE;QACf,IAAI,KAAK,EAAE,MAAM,MAAM,IAAI,MAAM,EAAE,CAAC;YAClC,OAAO,CAAC,KAAK,CAAC,MAAuB,CAAC,CAAC;QACzC,CAAC;IACH,CAAC,EACD;QACE,KAAK,EAAE,KAAK,IAAI,EAAE;YAChB,MAAM,OAAO,CAAC,KAAK,EAAE,CAAC;QACxB,CAAC;KACF,CACF,CAAC;AACJ,CAAC"}
|