@reciple/modules 10.0.1

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 ADDED
@@ -0,0 +1,160 @@
1
+ <div align="center">
2
+ <img src="https://i.imgur.com/C3gWxwc.png" width="50%">
3
+ <p align="center">
4
+ <b>A Discord.js framework that just works.</b>
5
+ </p>
6
+ <br>
7
+ </div>
8
+
9
+ <h3 align="center">
10
+ <a href="https://discord.gg/KxfPZYuTGV">
11
+ <img src="https://img.shields.io/discord/1453743492722458708?color=5865F2&logo=discord&logoColor=white">
12
+ </a>
13
+ <a href="https://npmjs.org/package/@reciple/modules">
14
+ <img src="https://img.shields.io/npm/v/@reciple/modules?label=npm">
15
+ </a>
16
+ <a href="https://github.com/reciplejs/reciple/tree/main/packages/modules">
17
+ <img src="https://img.shields.io/npm/dt/@reciple/modules?maxAge=3600">
18
+ </a>
19
+ <a href="https://www.codefactor.io/repository/github/reciplejs/reciple">
20
+ <img src="https://www.codefactor.io/repository/github/reciplejs/reciple/badge">
21
+ </a>
22
+ <br>
23
+ <div style="padding-top: 1rem">
24
+ <a href="https://discord.gg/KxfPZYuTGV">
25
+ <img src="http://invidget.switchblade.xyz/KxfPZYuTGV">
26
+ </a>
27
+ </div>
28
+ </h3>
29
+
30
+ ## About
31
+
32
+ `@reciple/modules` A JSX wrapper for [Discord.js](https://discord.js.org/) builders.
33
+
34
+ ## Installation
35
+
36
+ ```bash
37
+ npm install @reciple/modules
38
+ yarn add @reciple/modules
39
+ pnpm add @reciple/modules
40
+ bun install @reciple/modules
41
+ deno install npm:@reciple/modules
42
+ ```
43
+
44
+ ## Usage
45
+
46
+ Create a new reciple module file then create a new module instance as the default export.
47
+
48
+ ### Anticrash
49
+
50
+ A module that catches process and client errors that cause the bot to crash then logs them to a channel if specified.
51
+
52
+ ```js
53
+ // example/src/addons/antiCrash.js
54
+ import { RecipleAnticrash } from '@reciple/modules';
55
+
56
+ export default new RecipleAnticrash({
57
+ // The channels to report errors to
58
+ reportChannels: ['000000000000000000'],
59
+
60
+ // The base options for the report message
61
+ baseReportMessageOptions: {
62
+ content: 'An error has occurred!',
63
+ }
64
+ });
65
+ ```
66
+
67
+ ### Registry Cache
68
+
69
+ A module that caches the application commands to prevent unnecessary requests to the Discord API when registering commands that haven't changed.
70
+
71
+ ```js
72
+ // example/src/addons/registryCache.js
73
+ import { RecipleRegistryCache } from '@reciple/modules';
74
+
75
+ export default new RecipleRegistryCache({
76
+ // Cache duration in milliseconds
77
+ maxCacheAgeMs: 24 * 60 * 60 * 1000,
78
+
79
+ // The directory to store the cache in
80
+ cacheDir: '.cache/reciple-registry/',
81
+
82
+ // The environment variable to check if the cache is enabled
83
+ cacheEnabledEnv: 'RECIPLE_REGISTRY_CACHE',
84
+
85
+ // Create a cache entry even if the cache is disabled
86
+ createCacheEntryEvenIfDisabled: true
87
+ });
88
+ ```
89
+
90
+ ### Interaction Events
91
+
92
+ A module that handles interaction events and executes listeners based on the interaction type. The listeners are resolved from the specified module property.
93
+
94
+ ```js
95
+ // example/src/addons/interactionEvents.js
96
+ import { RecipleInteractionEvents } from '@reciple/modules';
97
+
98
+ export default new RecipleInteractionEvents({
99
+ // Filters the modules to resolve listeners from
100
+ ignoredModules: (module) => module.id === 'ignored_id',
101
+
102
+ // The module property to resolve listeners from
103
+ moduleEventListenersProperty: ['interactions']
104
+ });
105
+ ```
106
+
107
+ ```js
108
+ // example/src/commands/ping.js
109
+ import { InteractionListenerBuilder, InteractionListenerType } from '@reciple/modules';
110
+ import { ActionRowBuilder, ButtonBuilder, ButtonStyle } from 'discord.js';
111
+ import { SlashCommandBuilder, SlashCommandModule, type SlashCommand } from 'reciple';
112
+
113
+ export class ButtonPingCommand extends SlashCommandModule {
114
+ data = new SlashCommandBuilder()
115
+ .setName('ping')
116
+ .setDescription('Test ping command')
117
+ .toJSON();
118
+
119
+ /**
120
+ * @type {InteractionListenerBuilder[]}
121
+ */
122
+ interactions = [
123
+ new InteractionListenerBuilder()
124
+ .setType(InteractionListenerType.Button)
125
+ .setFilter(interaction => interaction.customId === 'ping')
126
+ .setExecute(async interaction => {
127
+ await interaction.reply({
128
+ content: 'Pong!',
129
+ ephemeral: true
130
+ });
131
+ })
132
+ ];
133
+
134
+ /**
135
+ * @param {SlashCommand.ExecuteData} data
136
+ */
137
+ async execute(data) {
138
+ await data.interaction.reply({
139
+ components: [
140
+ new ActionRowBuilder()
141
+ .addComponents(
142
+ new ButtonBuilder()
143
+ .setCustomId('ping')
144
+ .setLabel('Ping')
145
+ .setStyle(ButtonStyle.Primary)
146
+ )
147
+ ]
148
+ });
149
+ }
150
+ }
151
+
152
+ export default new ButtonPingCommand();
153
+ ```
154
+
155
+ ## Links
156
+
157
+ - [Website](https://reciple.js.org)
158
+ - [Discord](https://discord.gg/KxfPZYuTGV)
159
+ - [Github](https://github.com/reciplejs/reciple/tree/main/packages/modules)
160
+ - [NPM](https://npmjs.org/package/@reciple/modules)
@@ -0,0 +1,22 @@
1
+ import { InteractionListenerType } from "../helpers/constants.mjs";
2
+ import { InteractionFromListenerType, InteractionListenerData } from "../helpers/types.mjs";
3
+ import { JSONEncodable } from "discord.js";
4
+
5
+ //#region src/classes/InteractionListener.d.ts
6
+ declare class InteractionListener<T extends InteractionListenerType> implements InteractionListenerData<T> {
7
+ readonly id: string;
8
+ readonly moduleId?: string;
9
+ readonly type: T;
10
+ readonly once?: boolean;
11
+ constructor(data: InteractionListener.Resolvable<T>);
12
+ filter(interaction: InteractionFromListenerType<T>): boolean;
13
+ execute(interaction: InteractionFromListenerType<T>): Promise<void>;
14
+ toJSON(): InteractionListenerData<T>;
15
+ static from<T extends InteractionListenerType>(data: InteractionListener.Resolvable<T>): InteractionListener<T>;
16
+ }
17
+ declare namespace InteractionListener {
18
+ type Resolvable<T extends InteractionListenerType> = InteractionListener<T> | InteractionListenerData<T> | JSONEncodable<InteractionListenerData<T>>;
19
+ }
20
+ //#endregion
21
+ export { InteractionListener };
22
+ //# sourceMappingURL=InteractionListener.d.mts.map
@@ -0,0 +1,34 @@
1
+ import { isJSONEncodable } from "discord.js";
2
+ import { DiscordSnowflake } from "@sapphire/snowflake";
3
+
4
+ //#region src/classes/InteractionListener.ts
5
+ var InteractionListener = class InteractionListener {
6
+ id = DiscordSnowflake.generate().toString();
7
+ moduleId;
8
+ type;
9
+ once;
10
+ constructor(data) {
11
+ Object.assign(this, isJSONEncodable(data) ? data.toJSON() : data);
12
+ }
13
+ filter(interaction) {
14
+ return true;
15
+ }
16
+ execute(interaction) {
17
+ return Promise.resolve();
18
+ }
19
+ toJSON() {
20
+ return {
21
+ type: this.type,
22
+ once: this.once,
23
+ filter: this.filter,
24
+ execute: this.execute
25
+ };
26
+ }
27
+ static from(data) {
28
+ return data instanceof InteractionListener ? data : new InteractionListener(data);
29
+ }
30
+ };
31
+
32
+ //#endregion
33
+ export { InteractionListener };
34
+ //# sourceMappingURL=InteractionListener.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"InteractionListener.mjs","names":[],"sources":["../../src/classes/InteractionListener.ts"],"sourcesContent":["import { isJSONEncodable, type JSONEncodable } from 'discord.js';\nimport type { InteractionListenerType } from '../helpers/constants.js';\nimport type { InteractionListenerData, InteractionFromListenerType } from '../helpers/types.js';\nimport { DiscordSnowflake } from '@sapphire/snowflake';\n\nexport class InteractionListener<T extends InteractionListenerType> implements InteractionListenerData<T> {\n public readonly id: string = DiscordSnowflake.generate().toString();\n public readonly moduleId?: string;\n public readonly type!: T;\n public readonly once?: boolean;\n\n constructor(data: InteractionListener.Resolvable<T>) {\n Object.assign(this, isJSONEncodable(data) ? data.toJSON() : data);\n }\n\n public filter(interaction: InteractionFromListenerType<T>): boolean {\n return true;\n }\n\n public execute(interaction: InteractionFromListenerType<T>): Promise<void> {\n return Promise.resolve();\n }\n\n public toJSON(): InteractionListenerData<T> {\n return {\n type: this.type,\n once: this.once,\n filter: this.filter,\n execute: this.execute\n };\n }\n\n public static from<T extends InteractionListenerType>(data: InteractionListener.Resolvable<T>): InteractionListener<T> {\n return data instanceof InteractionListener ? data : new InteractionListener(data);\n }\n}\n\nexport namespace InteractionListener {\n export type Resolvable<T extends InteractionListenerType> = InteractionListener<T>|InteractionListenerData<T>|JSONEncodable<InteractionListenerData<T>>;\n}\n"],"mappings":";;;;AAKA,IAAa,sBAAb,MAAa,oBAA6F;CACtG,AAAgB,KAAa,iBAAiB,UAAU,CAAC,UAAU;CACnE,AAAgB;CAChB,AAAgB;CAChB,AAAgB;CAEhB,YAAY,MAAyC;AACjD,SAAO,OAAO,MAAM,gBAAgB,KAAK,GAAG,KAAK,QAAQ,GAAG,KAAK;;CAGrE,AAAO,OAAO,aAAsD;AAChE,SAAO;;CAGX,AAAO,QAAQ,aAA4D;AACvE,SAAO,QAAQ,SAAS;;CAG5B,AAAO,SAAqC;AACxC,SAAO;GACH,MAAM,KAAK;GACX,MAAM,KAAK;GACX,QAAQ,KAAK;GACb,SAAS,KAAK;GACjB;;CAGL,OAAc,KAAwC,MAAiE;AACnH,SAAO,gBAAgB,sBAAsB,OAAO,IAAI,oBAAoB,KAAK"}
@@ -0,0 +1,16 @@
1
+ import { InteractionListenerType } from "../../helpers/constants.mjs";
2
+ import { InteractionListenerData } from "../../helpers/types.mjs";
3
+
4
+ //#region src/classes/builders/InteractionListenerBuilder.d.ts
5
+ declare class InteractionListenerBuilder<T extends InteractionListenerType> {
6
+ readonly data: Partial<InteractionListenerData<T>>;
7
+ constructor(data?: Partial<InteractionListenerData<T>>);
8
+ setType<Type extends T>(type: Type): InteractionListenerBuilder<Type>;
9
+ setOnce(once: boolean): this;
10
+ setFilter(filter: InteractionListenerData<T>['filter']): this;
11
+ setExecute(execute: InteractionListenerData<T>['execute']): this;
12
+ toJSON(): InteractionListenerData<T>;
13
+ }
14
+ //#endregion
15
+ export { InteractionListenerBuilder };
16
+ //# sourceMappingURL=InteractionListenerBuilder.d.mts.map
@@ -0,0 +1,30 @@
1
+ //#region src/classes/builders/InteractionListenerBuilder.ts
2
+ var InteractionListenerBuilder = class {
3
+ data = {};
4
+ constructor(data) {
5
+ if (data) this.data = data;
6
+ }
7
+ setType(type) {
8
+ this.data.type = type;
9
+ return this;
10
+ }
11
+ setOnce(once) {
12
+ this.data.once = once;
13
+ return this;
14
+ }
15
+ setFilter(filter) {
16
+ this.data.filter = filter;
17
+ return this;
18
+ }
19
+ setExecute(execute) {
20
+ this.data.execute = execute;
21
+ return this;
22
+ }
23
+ toJSON() {
24
+ return this.data;
25
+ }
26
+ };
27
+
28
+ //#endregion
29
+ export { InteractionListenerBuilder };
30
+ //# sourceMappingURL=InteractionListenerBuilder.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"InteractionListenerBuilder.mjs","names":[],"sources":["../../../src/classes/builders/InteractionListenerBuilder.ts"],"sourcesContent":["import { InteractionListenerType } from '../../helpers/constants.js';\nimport type { InteractionListenerData } from '../../helpers/types.js';\n\nexport class InteractionListenerBuilder<T extends InteractionListenerType> {\n public readonly data: Partial<InteractionListenerData<T>> = {};\n\n public constructor(data?: Partial<InteractionListenerData<T>>) {\n if (data) this.data = data;\n }\n\n public setType<Type extends T>(type: Type): InteractionListenerBuilder<Type> {\n this.data.type = type;\n return this as any;\n }\n\n public setOnce(once: boolean): this {\n this.data.once = once;\n return this;\n }\n\n public setFilter(filter: InteractionListenerData<T>['filter']): this {\n this.data.filter = filter;\n return this;\n }\n\n public setExecute(execute: InteractionListenerData<T>['execute']): this {\n this.data.execute = execute;\n return this;\n }\n\n public toJSON(): InteractionListenerData<T> {\n return this.data as InteractionListenerData<T>;\n }\n}\n"],"mappings":";AAGA,IAAa,6BAAb,MAA2E;CACvE,AAAgB,OAA4C,EAAE;CAE9D,AAAO,YAAY,MAA4C;AAC3D,MAAI,KAAM,MAAK,OAAO;;CAG1B,AAAO,QAAwB,MAA8C;AACzE,OAAK,KAAK,OAAO;AACjB,SAAO;;CAGX,AAAO,QAAQ,MAAqB;AAChC,OAAK,KAAK,OAAO;AACjB,SAAO;;CAGX,AAAO,UAAU,QAAoD;AACjE,OAAK,KAAK,SAAS;AACnB,SAAO;;CAGX,AAAO,WAAW,SAAsD;AACpE,OAAK,KAAK,UAAU;AACpB,SAAO;;CAGX,AAAO,SAAqC;AACxC,SAAO,KAAK"}
@@ -0,0 +1,38 @@
1
+ import { Awaitable, BaseMessageOptions as BaseMessageOptions$1, Message, SendableChannels } from "discord.js";
2
+ import { BaseModule } from "reciple";
3
+
4
+ //#region src/classes/modules/RecipleAnticrash.d.ts
5
+ declare class RecipleAnticrash extends BaseModule implements RecipleAnticrash.Options {
6
+ readonly id: string;
7
+ baseReportMessageOptions?: RecipleAnticrash.Options['baseReportMessageOptions'];
8
+ reportChannels: string[];
9
+ private readonly logger;
10
+ constructor(options?: RecipleAnticrash.Options);
11
+ onEnable(data: BaseModule.EventData<boolean>): Promise<void>;
12
+ onReady(data: BaseModule.EventData<true>): Promise<void>;
13
+ onDisable(data: BaseModule.EventData<boolean>): Promise<void>;
14
+ report(reason: any): Promise<RecipleAnticrash.Report[]>;
15
+ createReportMessageOptions(reason: any, stack: string): Promise<BaseMessageOptions$1>;
16
+ resolveChannel(resolvable: Exclude<RecipleAnticrash.Options['reportChannels'], undefined>[0]): Promise<SendableChannels | null>;
17
+ private _captureErrorEvent;
18
+ }
19
+ declare namespace RecipleAnticrash {
20
+ interface Options {
21
+ baseReportMessageOptions?: BaseMessageOptions | ((reason: any) => Awaitable<BaseMessageOptions>);
22
+ reportChannels?: (string | {
23
+ id: string;
24
+ } | SendableChannels | (() => Awaitable<SendableChannels>))[];
25
+ }
26
+ interface Report {
27
+ message?: Message;
28
+ stackTrace: string;
29
+ timestamp: number;
30
+ }
31
+ interface BaseMessageOptions extends BaseMessageOptions$1 {
32
+ replaceEmbeds?: 'merge' | boolean;
33
+ replaceFiles?: 'merge' | boolean;
34
+ }
35
+ }
36
+ //#endregion
37
+ export { RecipleAnticrash };
38
+ //# sourceMappingURL=RecipleAnticrash.d.mts.map
@@ -0,0 +1,78 @@
1
+ import { AttachmentBuilder, BaseChannel, Colors, EmbedBuilder, codeBlock, escapeCodeBlock } from "discord.js";
2
+ import { inspect } from "node:util";
3
+ import { BaseModule } from "reciple";
4
+
5
+ //#region src/classes/modules/RecipleAnticrash.ts
6
+ var RecipleAnticrash = class extends BaseModule {
7
+ id = "org.reciple.js.anticrash";
8
+ baseReportMessageOptions;
9
+ reportChannels = [];
10
+ logger = useLogger().clone({ label: "Anticrash" });
11
+ constructor(options) {
12
+ super();
13
+ Object.assign(this, options ?? {});
14
+ this._captureErrorEvent = this._captureErrorEvent.bind(this);
15
+ }
16
+ async onEnable(data) {
17
+ this.client.on("error", this._captureErrorEvent);
18
+ this.client.on("shardError", this._captureErrorEvent);
19
+ process.on("uncaughtException", this._captureErrorEvent);
20
+ process.on("uncaughtExceptionMonitor", this._captureErrorEvent);
21
+ process.on("unhandledRejection", this._captureErrorEvent);
22
+ }
23
+ async onReady(data) {}
24
+ async onDisable(data) {
25
+ this.client.off("error", this._captureErrorEvent);
26
+ this.client.off("shardError", this._captureErrorEvent);
27
+ process.off("uncaughtException", this._captureErrorEvent);
28
+ process.off("uncaughtExceptionMonitor", this._captureErrorEvent);
29
+ process.off("unhandledRejection", this._captureErrorEvent);
30
+ }
31
+ async report(reason) {
32
+ const reports = [];
33
+ const stack = inspect(reason, { colors: false });
34
+ this.logger.err(reason);
35
+ for (const channelId of this.reportChannels) {
36
+ const channel = await this.resolveChannel(channelId);
37
+ if (!channel) continue;
38
+ const message = await channel.send(await this.createReportMessageOptions(reason, stack)).catch(() => null);
39
+ if (message) reports.push({
40
+ message,
41
+ stackTrace: stack,
42
+ timestamp: message.createdTimestamp
43
+ });
44
+ }
45
+ return reports;
46
+ }
47
+ async createReportMessageOptions(reason, stack) {
48
+ const base = typeof this.baseReportMessageOptions === "function" ? await Promise.resolve(this.baseReportMessageOptions(reason)).catch(() => null) : this.baseReportMessageOptions ?? {};
49
+ const embed = new EmbedBuilder().setAuthor({ name: `Anticrash report` }).setTitle(String(reason).substring(0, 100)).setColor(Colors.Red).setTimestamp();
50
+ let files = [...base?.files ?? []];
51
+ if (stack.length < 1950) embed.setDescription(codeBlock(escapeCodeBlock(stack)));
52
+ else {
53
+ const file = new AttachmentBuilder(Buffer.from(stack, "utf-8"), { name: "report.log" });
54
+ if (base?.replaceFiles) files = [file];
55
+ else if (base?.replaceFiles === void 0 || base?.replaceFiles === "merge") files.push(file);
56
+ }
57
+ return {
58
+ ...base,
59
+ embeds: base?.replaceEmbeds ? [embed] : base?.replaceEmbeds === void 0 || base?.replaceEmbeds === "merge" ? [...base?.embeds ?? [], embed] : base.embeds,
60
+ files
61
+ };
62
+ }
63
+ async resolveChannel(resolvable) {
64
+ if (resolvable instanceof BaseChannel) return resolvable;
65
+ if (typeof resolvable === "function") return Promise.resolve(resolvable()).catch(() => null);
66
+ const id = typeof resolvable === "string" ? resolvable : resolvable.id;
67
+ const channel = await this.client.channels.fetch(id).catch(() => null);
68
+ if (channel) return channel.isSendable() ? channel : null;
69
+ return (await this.client.users.fetch(id).catch(() => null))?.dmChannel ?? null;
70
+ }
71
+ async _captureErrorEvent(...args) {
72
+ if (args[0]) await this.report(args[0]);
73
+ }
74
+ };
75
+
76
+ //#endregion
77
+ export { RecipleAnticrash };
78
+ //# sourceMappingURL=RecipleAnticrash.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RecipleAnticrash.mjs","names":[],"sources":["../../../src/classes/modules/RecipleAnticrash.ts"],"sourcesContent":["import { AttachmentBuilder, BaseChannel, codeBlock, Colors, EmbedBuilder, escapeCodeBlock, type Awaitable, type BaseMessageOptions as DJSBaseMessageOptions, type Message, type SendableChannels } from 'discord.js';\nimport { inspect } from 'node:util';\nimport { BaseModule } from 'reciple';\n\nexport class RecipleAnticrash extends BaseModule implements RecipleAnticrash.Options {\n public readonly id: string = 'org.reciple.js.anticrash';\n\n public baseReportMessageOptions?: RecipleAnticrash.Options['baseReportMessageOptions'];\n public reportChannels: string[] = [];\n\n private readonly logger = useLogger().clone({ label: 'Anticrash' });\n\n constructor(options?: RecipleAnticrash.Options) {\n super();\n\n Object.assign(this, options ?? {});\n\n this._captureErrorEvent = this._captureErrorEvent.bind(this);\n }\n\n public async onEnable(data: BaseModule.EventData<boolean>): Promise<void> {\n this.client.on('error', this._captureErrorEvent);\n this.client.on('shardError', this._captureErrorEvent);\n process.on('uncaughtException', this._captureErrorEvent);\n process.on('uncaughtExceptionMonitor', this._captureErrorEvent);\n process.on('unhandledRejection', this._captureErrorEvent);\n }\n\n public async onReady(data: BaseModule.EventData<true>): Promise<void> {}\n\n public async onDisable(data: BaseModule.EventData<boolean>): Promise<void> {\n this.client.off('error', this._captureErrorEvent);\n this.client.off('shardError', this._captureErrorEvent);\n process.off('uncaughtException', this._captureErrorEvent);\n process.off('uncaughtExceptionMonitor', this._captureErrorEvent);\n process.off('unhandledRejection', this._captureErrorEvent);\n }\n\n public async report(reason: any): Promise<RecipleAnticrash.Report[]> {\n const reports: RecipleAnticrash.Report[] = [];\n const stack = inspect(reason, { colors: false });\n\n this.logger.err(reason);\n\n for (const channelId of this.reportChannels) {\n const channel = await this.resolveChannel(channelId);\n if (!channel) continue;\n\n const message = await channel.send(await this.createReportMessageOptions(reason, stack)).catch(() => null);\n if (message) reports.push({ message, stackTrace: stack, timestamp: message.createdTimestamp });\n }\n\n return reports;\n }\n\n public async createReportMessageOptions(reason: any, stack: string): Promise<DJSBaseMessageOptions> {\n const base = typeof this.baseReportMessageOptions === 'function'\n ? await Promise.resolve(this.baseReportMessageOptions(reason)).catch(() => null)\n : this.baseReportMessageOptions ?? {};\n\n const embed = new EmbedBuilder()\n .setAuthor({ name: `Anticrash report` })\n .setTitle(String(reason).substring(0, 100))\n .setColor(Colors.Red)\n .setTimestamp();\n\n let files: Exclude<DJSBaseMessageOptions['files'], undefined>[0][] = [...(base?.files ?? [])];\n\n if (stack.length < 1950) {\n embed.setDescription(codeBlock(escapeCodeBlock(stack)))\n } else {\n const file = new AttachmentBuilder(Buffer.from(stack, 'utf-8'), { name: 'report.log' });\n\n if (base?.replaceFiles) {\n files = [file];\n } else if (base?.replaceFiles === undefined || base?.replaceFiles === 'merge') {\n files.push(file);\n }\n }\n\n return {\n ...base,\n embeds: base?.replaceEmbeds\n ? [embed]\n : base?.replaceEmbeds === undefined || base?.replaceEmbeds === 'merge'\n ? [...(base?.embeds ?? []), embed]\n : base.embeds,\n files\n };\n }\n\n public async resolveChannel(resolvable: Exclude<RecipleAnticrash.Options['reportChannels'], undefined>[0]): Promise<SendableChannels|null> {\n if (resolvable instanceof BaseChannel) return resolvable;\n if (typeof resolvable === 'function') return Promise.resolve(resolvable()).catch(() => null);\n\n const id = typeof resolvable === 'string' ? resolvable : resolvable.id;\n const channel = await this.client.channels.fetch(id).catch(() => null);\n\n if (channel) {\n return channel.isSendable() ? channel : null;\n }\n\n const userDm = await this.client.users.fetch(id).catch(() => null);\n\n return userDm?.dmChannel ?? null;\n }\n\n private async _captureErrorEvent(...args: any[]): Promise<void> {\n if (args[0]) await this.report(args[0]);\n }\n}\n\nexport namespace RecipleAnticrash {\n export interface Options {\n baseReportMessageOptions?: BaseMessageOptions|((reason: any) => Awaitable<BaseMessageOptions>);\n reportChannels?: (string|{ id: string; }|SendableChannels|(() => Awaitable<SendableChannels>))[];\n }\n\n export interface Report {\n message?: Message;\n stackTrace: string;\n timestamp: number;\n }\n\n export interface BaseMessageOptions extends DJSBaseMessageOptions {\n replaceEmbeds?: 'merge'|boolean;\n replaceFiles?: 'merge'|boolean;\n }\n}\n"],"mappings":"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"}
@@ -0,0 +1,35 @@
1
+ import { InteractionListenerType } from "../../helpers/constants.mjs";
2
+ import { InteractionListener } from "../InteractionListener.mjs";
3
+ import { Awaitable, CacheType, Collection, Interaction } from "discord.js";
4
+ import { AnyModule, ClientEventModule } from "reciple";
5
+
6
+ //#region src/classes/modules/RecipleInteractionEvents.d.ts
7
+ declare class RecipleInteractionEvents extends ClientEventModule<'interactionCreate'> implements RecipleInteractionEvents.Options {
8
+ readonly id: string;
9
+ event: "interactionCreate";
10
+ moduleEventListenersProperty: string | string[];
11
+ ignoredModules?: (module: AnyModule) => Awaitable<boolean>;
12
+ listeners: Collection<string, InteractionListener<InteractionListenerType>>;
13
+ private readonly logger;
14
+ constructor(options?: RecipleInteractionEvents.Options);
15
+ onReady(): Promise<void>;
16
+ onEvent(interaction: Interaction<CacheType>): Promise<void>;
17
+ resolveListeners(customModules?: AnyModule[]): Promise<InteractionListener<InteractionListenerType>[]>;
18
+ }
19
+ declare namespace RecipleInteractionEvents {
20
+ interface Options {
21
+ /**
22
+ * The property that is scanned from modules to get interaction listeners.
23
+ */
24
+ moduleEventListenersProperty?: string | string[];
25
+ /**
26
+ * Filter modules that should be ignored.
27
+ */
28
+ ignoredModules?: (module: AnyModule) => Awaitable<boolean>;
29
+ }
30
+ type ListenerModule<P extends string, T extends InteractionListenerType> = AnyModule & Record<P, InteractionListener.Resolvable<T>[]>;
31
+ function getInteractionTypeFromInteraction(interaction: Interaction): InteractionListenerType;
32
+ }
33
+ //#endregion
34
+ export { RecipleInteractionEvents };
35
+ //# sourceMappingURL=RecipleInteractionEvents.d.mts.map
@@ -0,0 +1,82 @@
1
+ import { InteractionListenerType } from "../../helpers/constants.mjs";
2
+ import { InteractionListener } from "../InteractionListener.mjs";
3
+ import { Collection } from "discord.js";
4
+ import { ClientEventModule } from "reciple";
5
+
6
+ //#region src/classes/modules/RecipleInteractionEvents.ts
7
+ var RecipleInteractionEvents = class RecipleInteractionEvents extends ClientEventModule {
8
+ id = "org.reciple.js.interaction-events";
9
+ event = "interactionCreate";
10
+ moduleEventListenersProperty = "interactions";
11
+ ignoredModules;
12
+ listeners = new Collection();
13
+ logger = useLogger().clone({ label: "InteractionEvents" });
14
+ constructor(options = {}) {
15
+ super();
16
+ Object.assign(this, options);
17
+ }
18
+ async onReady() {
19
+ this.client.modules.on("readyModules", async (modules) => {
20
+ this.logger.debug(`Resolving listeners for ready modules...`);
21
+ for (const listener of await this.resolveListeners(modules)) this.listeners.set(listener.id, listener);
22
+ });
23
+ this.client.modules.on("disabledModules", async (modules) => {
24
+ this.logger.debug(`Sweeping listeners for disabled modules...`);
25
+ for (const module of modules) this.listeners.sweep((listener) => listener.moduleId === module.id);
26
+ });
27
+ }
28
+ async onEvent(interaction) {
29
+ const type = RecipleInteractionEvents.getInteractionTypeFromInteraction(interaction);
30
+ const listeners = this.listeners.filter((listener) => listener.type === type);
31
+ this.logger.debug(`Triggered (${listeners.size}) listeners for interaction type "${InteractionListenerType[type]}".`);
32
+ for (const [id, listener] of listeners) {
33
+ if (!await Promise.resolve(listener.filter(interaction))) continue;
34
+ await Promise.resolve(listener.execute(interaction));
35
+ if (listener.once) {
36
+ this.logger.debug(`Removed listener "${id}" for interaction type "${InteractionListenerType[type]}".`);
37
+ this.listeners.delete(id);
38
+ }
39
+ }
40
+ }
41
+ async resolveListeners(customModules) {
42
+ this.logger.debug(`Resolving listeners from (${customModules?.length ?? this.client.modules.cache.size}) modules...`);
43
+ const modules = customModules ?? this.client.modules.cache.map((m) => m);
44
+ const listenersProperty = Array.isArray(this.moduleEventListenersProperty) ? this.moduleEventListenersProperty : [this.moduleEventListenersProperty];
45
+ const listeners = [];
46
+ for (const module of modules) {
47
+ if (module.id === this.id) continue;
48
+ this.logger.debug(`Resolving listeners from module "${module.id}"...`);
49
+ propertyLoop: for (const listenerProperty of listenersProperty) {
50
+ if (!(listenerProperty in module)) continue propertyLoop;
51
+ if (!Array.isArray(module[listenerProperty]) || !module[listenerProperty].length) continue;
52
+ if (typeof this.ignoredModules === "function" && await Promise.resolve(this.ignoredModules(module))) continue;
53
+ const moduleListeners = module[listenerProperty];
54
+ this.logger.debug(`Resolving listeners from module "${module.id}" with property "${listenerProperty}"...`);
55
+ for (const data of moduleListeners) {
56
+ const listener = InteractionListener.from(data);
57
+ Reflect.set(listener, "moduleId", module.id);
58
+ listeners.push(listener);
59
+ }
60
+ this.logger.debug(`Resolved (${moduleListeners.length}) listeners from module "${module.id}" with property "${listenerProperty}".`);
61
+ }
62
+ }
63
+ return listeners;
64
+ }
65
+ };
66
+ (function(_RecipleInteractionEvents) {
67
+ function getInteractionTypeFromInteraction(interaction) {
68
+ if (interaction.isAutocomplete()) return InteractionListenerType.Autocomplete;
69
+ else if (interaction.isChatInputCommand()) return InteractionListenerType.ChatInput;
70
+ else if (interaction.isContextMenuCommand()) return InteractionListenerType.ContextMenu;
71
+ else if (interaction.isModalSubmit()) return InteractionListenerType.ModalSubmit;
72
+ else if (interaction.isButton()) return InteractionListenerType.Button;
73
+ else if (interaction.isAnySelectMenu()) return InteractionListenerType.SelectMenu;
74
+ else if (interaction.isPrimaryEntryPointCommand()) return InteractionListenerType.PrimaryEntryPoint;
75
+ throw new Error(`Unknown interaction type.`);
76
+ }
77
+ _RecipleInteractionEvents.getInteractionTypeFromInteraction = getInteractionTypeFromInteraction;
78
+ })(RecipleInteractionEvents || (RecipleInteractionEvents = {}));
79
+
80
+ //#endregion
81
+ export { RecipleInteractionEvents };
82
+ //# sourceMappingURL=RecipleInteractionEvents.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RecipleInteractionEvents.mjs","names":[],"sources":["../../../src/classes/modules/RecipleInteractionEvents.ts"],"sourcesContent":["import { type Interaction, type CacheType, type Awaitable, Collection } from 'discord.js';\nimport { ClientEventModule, type AnyModule } from 'reciple';\nimport { InteractionListener } from '../InteractionListener.js';\nimport { InteractionListenerType } from '../../helpers/constants.js';\n\nexport class RecipleInteractionEvents extends ClientEventModule<'interactionCreate'> implements RecipleInteractionEvents.Options {\n public readonly id: string = 'org.reciple.js.interaction-events';\n public event = 'interactionCreate' as const;\n public moduleEventListenersProperty: string|string[] = 'interactions';\n public ignoredModules?: (module: AnyModule) => Awaitable<boolean>;\n public listeners: Collection<string, InteractionListener<InteractionListenerType>> = new Collection();\n\n private readonly logger = useLogger().clone({ label: 'InteractionEvents' });\n\n constructor(options: RecipleInteractionEvents.Options = {}) {\n super();\n\n Object.assign(this, options);\n }\n\n public async onReady(): Promise<void> {\n this.client.modules.on('readyModules', async (modules: AnyModule[]) => {\n this.logger.debug(`Resolving listeners for ready modules...`);\n\n for (const listener of await this.resolveListeners(modules)) {\n this.listeners.set(listener.id, listener);\n }\n });\n\n this.client.modules.on('disabledModules', async (modules: AnyModule[]) => {\n this.logger.debug(`Sweeping listeners for disabled modules...`);\n\n for (const module of modules) {\n this.listeners.sweep(listener => listener.moduleId === module.id)\n }\n });\n }\n\n public async onEvent(interaction: Interaction<CacheType>): Promise<void> {\n const type = RecipleInteractionEvents.getInteractionTypeFromInteraction(interaction);\n const listeners = this.listeners.filter(listener => listener.type === type);\n\n this.logger.debug(`Triggered (${listeners.size}) listeners for interaction type \"${InteractionListenerType[type]}\".`);\n\n for (const [id, listener] of listeners) {\n if (!await Promise.resolve(listener.filter(interaction))) continue;\n\n await Promise.resolve(listener.execute(interaction));\n\n if (listener.once) {\n this.logger.debug(`Removed listener \"${id}\" for interaction type \"${InteractionListenerType[type]}\".`);\n this.listeners.delete(id);\n }\n }\n }\n\n public async resolveListeners(customModules?: AnyModule[]) {\n this.logger.debug(`Resolving listeners from (${customModules?.length ?? this.client.modules.cache.size}) modules...`);\n\n const modules = (customModules ?? this.client.modules.cache.map(m => m)) as RecipleInteractionEvents.ListenerModule<string, InteractionListenerType>[];\n const listenersProperty = Array.isArray(this.moduleEventListenersProperty) ? this.moduleEventListenersProperty : [this.moduleEventListenersProperty];\n const listeners: InteractionListener<InteractionListenerType>[] = [];\n\n for (const module of modules) {\n if (module.id === this.id) continue;\n\n this.logger.debug(`Resolving listeners from module \"${module.id}\"...`);\n\n propertyLoop: for (const listenerProperty of listenersProperty) {\n if (!(listenerProperty in module)) continue propertyLoop;\n if (!Array.isArray(module[listenerProperty]) || !module[listenerProperty].length) continue;\n if (typeof this.ignoredModules === 'function' && await Promise.resolve(this.ignoredModules(module))) continue;\n\n const moduleListeners = module[listenerProperty];\n\n this.logger.debug(`Resolving listeners from module \"${module.id}\" with property \"${listenerProperty}\"...`);\n\n for (const data of moduleListeners) {\n const listener = InteractionListener.from(data);\n\n Reflect.set(listener, 'moduleId', module.id);\n listeners.push(listener);\n }\n\n this.logger.debug(`Resolved (${moduleListeners.length}) listeners from module \"${module.id}\" with property \"${listenerProperty}\".`);\n }\n }\n\n return listeners;\n }\n}\n\nexport namespace RecipleInteractionEvents {\n export interface Options {\n /**\n * The property that is scanned from modules to get interaction listeners.\n */\n moduleEventListenersProperty?: string|string[];\n /**\n * Filter modules that should be ignored.\n */\n ignoredModules?: (module: AnyModule) => Awaitable<boolean>;\n }\n\n export type ListenerModule<P extends string, T extends InteractionListenerType> = AnyModule & Record<P, InteractionListener.Resolvable<T>[]>;\n\n export function getInteractionTypeFromInteraction(interaction: Interaction): InteractionListenerType {\n if (interaction.isAutocomplete()) {\n return InteractionListenerType.Autocomplete;\n } else if (interaction.isChatInputCommand()) {\n return InteractionListenerType.ChatInput;\n } else if (interaction.isContextMenuCommand()) {\n return InteractionListenerType.ContextMenu;\n } else if (interaction.isModalSubmit()) {\n return InteractionListenerType.ModalSubmit;\n } else if (interaction.isButton()) {\n return InteractionListenerType.Button;\n } else if (interaction.isAnySelectMenu()) {\n return InteractionListenerType.SelectMenu;\n } else if (interaction.isPrimaryEntryPointCommand()) {\n return InteractionListenerType.PrimaryEntryPoint;\n }\n\n throw new Error(`Unknown interaction type.`);\n }\n}\n"],"mappings":"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"}
@@ -0,0 +1,54 @@
1
+ import { AnyCommandData, BaseModule, Config, MessageCommand } from "reciple";
2
+
3
+ //#region src/classes/modules/RecipleRegistryCache.d.ts
4
+ declare class RecipleRegistryCache extends BaseModule implements RecipleRegistryCache.Options {
5
+ readonly id: string;
6
+ createCacheEntryEvenIfDisabled: boolean;
7
+ cacheDir: string;
8
+ maxCacheAgeMs?: number;
9
+ cacheEnabledEnv: string;
10
+ cached: boolean;
11
+ private readonly logger;
12
+ constructor(options?: RecipleRegistryCache.Options);
13
+ get cachePath(): string;
14
+ onReady(): Promise<void>;
15
+ readCacheEntry(): Promise<RecipleRegistryCache.CacheEntry | null>;
16
+ writeCacheEntry(entry?: RecipleRegistryCache.CacheEntry): Promise<void>;
17
+ clearCacheEntry(): Promise<void>;
18
+ createCacheEntry(): Promise<RecipleRegistryCache.CacheEntry>;
19
+ isCacheHit(cached: RecipleRegistryCache.CacheEntry, current: RecipleRegistryCache.CacheEntry): boolean;
20
+ private isEnabled;
21
+ }
22
+ declare namespace RecipleRegistryCache {
23
+ interface Options {
24
+ /**
25
+ * @default true
26
+ */
27
+ createCacheEntryEvenIfDisabled?: boolean;
28
+ /**
29
+ * @default '.cache/reciple-registry/'
30
+ */
31
+ cacheDir?: string;
32
+ /**
33
+ * @default 86400000 // 24 hours in milliseconds
34
+ */
35
+ maxCacheAgeMs?: number;
36
+ /**
37
+ * @default 'RECIPLE_REGISTRY_CACHE'
38
+ */
39
+ cacheEnabledEnv?: string;
40
+ }
41
+ interface CacheEntry {
42
+ commandsHash: string;
43
+ configHash: string;
44
+ createdAt: number;
45
+ }
46
+ type CommandData = Exclude<AnyCommandData, MessageCommand.Data>;
47
+ function checkClientIfEnabled(config: Config): boolean;
48
+ function createCommandsHash(commands: Exclude<AnyCommandData, MessageCommand.Data>[]): string;
49
+ function createConfigHash(config: Config): string;
50
+ function stringifyValue(object: any): string;
51
+ }
52
+ //#endregion
53
+ export { RecipleRegistryCache };
54
+ //# sourceMappingURL=RecipleRegistryCache.d.mts.map
@@ -0,0 +1,150 @@
1
+ import { BaseModule, CommandType } from "reciple";
2
+ import { createHash } from "node:crypto";
3
+ import { mkdir, readFile, rm, stat, writeFile } from "node:fs/promises";
4
+ import path from "node:path";
5
+
6
+ //#region src/classes/modules/RecipleRegistryCache.ts
7
+ var RecipleRegistryCache = class RecipleRegistryCache extends BaseModule {
8
+ id = "org.reciple.js.registry-cache";
9
+ createCacheEntryEvenIfDisabled = true;
10
+ cacheDir = path.join(process.cwd(), ".cache/reciple-registry/");
11
+ maxCacheAgeMs;
12
+ cacheEnabledEnv = "RECIPLE_REGISTRY_CACHE";
13
+ cached = false;
14
+ logger = useLogger().clone({ label: "RegistryCache" });
15
+ constructor(options) {
16
+ super();
17
+ Object.assign(this, options ?? {});
18
+ }
19
+ get cachePath() {
20
+ return path.join(this.cacheDir, this.client.application?.id ?? "cache.json");
21
+ }
22
+ async onReady() {
23
+ const enabled = this.isEnabled();
24
+ if (enabled || this.createCacheEntryEvenIfDisabled) this.client.commands?.once("applicationCommandsRegister", async (commands, guildId) => {
25
+ await this.writeCacheEntry();
26
+ });
27
+ if (!enabled) {
28
+ this.client.modules.on("readyModules", async () => {
29
+ this.logger.warn(`Registry cache is disabled. Cache is not used.`);
30
+ });
31
+ return;
32
+ }
33
+ this.logger.debug("Looking for a application commands cache entry...");
34
+ const cachedEntry = await this.readCacheEntry();
35
+ this.logger.debug("Creating current application commands cache entry...");
36
+ const currentEntry = await this.createCacheEntry();
37
+ if (cachedEntry && this.isCacheHit(cachedEntry, currentEntry)) {
38
+ this.client.config.applicationCommandsRegister = {
39
+ ...this.client.config.applicationCommandsRegister,
40
+ registerGlobally: false,
41
+ registerToGuilds: false
42
+ };
43
+ this.cached = true;
44
+ }
45
+ this.client.modules.on("readyModules", async () => {
46
+ this.logger.warn(`Application commands are ${this.cached ? "" : "not "}cached. ${this.cached ? "Skipping" : "Proceeding with"} registration.`);
47
+ });
48
+ }
49
+ async readCacheEntry() {
50
+ if (!await stat(this.cachePath).catch(() => null)) return null;
51
+ return await readFile(this.cachePath, "utf-8").then(JSON.parse).catch(() => null);
52
+ }
53
+ async writeCacheEntry(entry) {
54
+ entry ??= await this.createCacheEntry();
55
+ this.logger.debug("Writing application commands cache entry...");
56
+ await mkdir(this.cacheDir, { recursive: true });
57
+ await writeFile(this.cachePath, JSON.stringify(entry, null, 4), "utf-8");
58
+ this.logger.debug(`Application commands cache entry written to "${this.cachePath}".`);
59
+ }
60
+ async clearCacheEntry() {
61
+ await rm(this.cachePath).catch(() => null);
62
+ }
63
+ async createCacheEntry() {
64
+ this.logger.debug("Creating current application commands cache entry...");
65
+ const commands = Array.from(this.client.commands?.cache.filter((cmd) => cmd.type !== CommandType.Message).map((cmd) => cmd.toJSON()).values() ?? []);
66
+ for (const command of commands) Object.assign(command, { id: "[cache_value]" });
67
+ const commandsHash = RecipleRegistryCache.createCommandsHash(commands);
68
+ const configHash = RecipleRegistryCache.createConfigHash(this.client.config?.applicationCommandsRegister ?? {});
69
+ this.logger.debug(`Commands hash: ${commandsHash}`);
70
+ this.logger.debug(`Config hash: ${configHash}`);
71
+ this.logger.debug("Current application commands cache entry created.");
72
+ return {
73
+ createdAt: Date.now(),
74
+ commandsHash,
75
+ configHash
76
+ };
77
+ }
78
+ isCacheHit(cached, current) {
79
+ this.logger.debug("Comparing cache entry with current application commands and configuration...");
80
+ if (this.maxCacheAgeMs) {
81
+ const age = Date.now() - cached.createdAt;
82
+ if (age > this.maxCacheAgeMs) {
83
+ this.logger.debug(`Cache entry is too old (age: ${age}ms, max age: ${this.maxCacheAgeMs}ms).`);
84
+ return false;
85
+ }
86
+ }
87
+ if (cached.commandsHash !== current.commandsHash) {
88
+ this.logger.debug(`Cache entry commands hash doesn't match (cached: ${cached.commandsHash}, current: ${current.commandsHash}).`);
89
+ return false;
90
+ }
91
+ if (cached.configHash !== current.configHash) {
92
+ this.logger.debug(`Cache entry config hash doesn't match (cached: ${cached.configHash}, current: ${current.configHash}).`);
93
+ return false;
94
+ }
95
+ this.logger.debug("Cache entry matches current application commands and configuration.");
96
+ return true;
97
+ }
98
+ isEnabled() {
99
+ if (process.env[this.cacheEnabledEnv] !== "false" && process.env[this.cacheEnabledEnv] !== "0") return RecipleRegistryCache.checkClientIfEnabled(this.client.config ?? {});
100
+ return false;
101
+ }
102
+ };
103
+ (function(_RecipleRegistryCache) {
104
+ function checkClientIfEnabled(config) {
105
+ return config.applicationCommandsRegister?.registerGlobally || config.applicationCommandsRegister?.registerToGuilds === true || Array.isArray(config.applicationCommandsRegister?.registerToGuilds) && config.applicationCommandsRegister?.registerToGuilds.length > 0;
106
+ }
107
+ _RecipleRegistryCache.checkClientIfEnabled = checkClientIfEnabled;
108
+ function createCommandsHash(commands) {
109
+ const hash = createHash("sha256");
110
+ hash.update(stringifyValue(commands));
111
+ return hash.digest("hex");
112
+ }
113
+ _RecipleRegistryCache.createCommandsHash = createCommandsHash;
114
+ function createConfigHash(config) {
115
+ const hash = createHash("sha256");
116
+ const relevantConfig = { applicationCommandsRegister: config.applicationCommandsRegister };
117
+ hash.update(stringifyValue(relevantConfig));
118
+ return hash.digest("hex");
119
+ }
120
+ _RecipleRegistryCache.createConfigHash = createConfigHash;
121
+ function stringifyValue(object) {
122
+ switch (typeof object) {
123
+ case "string": return `"${object}"`;
124
+ case "number":
125
+ case "bigint":
126
+ case "boolean":
127
+ case "symbol":
128
+ case "function": return `"${object.toString()}"`;
129
+ case "undefined": return "undefined";
130
+ case "object":
131
+ if (object === null) return "null";
132
+ if (Array.isArray(object)) return `[${object.map((s) => stringifyValue(s)).join(", ")}]`;
133
+ if (object instanceof Map) return `{${Array.from(object.entries()).map(([k, v]) => `${stringifyValue(k)}: ${stringifyValue(v)}`).join(", ")}}`;
134
+ if (object instanceof Set) return `{${Array.from(object.values()).map((v) => stringifyValue(v)).join(", ")}}`;
135
+ if (object instanceof Date) return `"${object.toISOString()}"`;
136
+ try {
137
+ const newObject = {};
138
+ for (const [key, value] of Object.entries(object)) newObject[key] = stringifyValue(value);
139
+ return JSON.stringify(newObject);
140
+ } catch {
141
+ return String(object);
142
+ }
143
+ }
144
+ }
145
+ _RecipleRegistryCache.stringifyValue = stringifyValue;
146
+ })(RecipleRegistryCache || (RecipleRegistryCache = {}));
147
+
148
+ //#endregion
149
+ export { RecipleRegistryCache };
150
+ //# sourceMappingURL=RecipleRegistryCache.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RecipleRegistryCache.mjs","names":[],"sources":["../../../src/classes/modules/RecipleRegistryCache.ts"],"sourcesContent":["import { createHash } from 'node:crypto';\nimport { mkdir, readFile, rm, stat, writeFile } from 'node:fs/promises';\nimport path from 'node:path';\nimport { BaseModule, CommandType, type AnyCommandData, type Config, type MessageCommand } from 'reciple';\n\nexport class RecipleRegistryCache extends BaseModule implements RecipleRegistryCache.Options {\n public readonly id: string = 'org.reciple.js.registry-cache';\n\n public createCacheEntryEvenIfDisabled: boolean = true;\n public cacheDir: string = path.join(process.cwd(), '.cache/reciple-registry/');\n public maxCacheAgeMs?: number;\n public cacheEnabledEnv: string = 'RECIPLE_REGISTRY_CACHE';\n public cached: boolean = false;\n\n private readonly logger = useLogger().clone({ label: 'RegistryCache' });\n\n constructor(options?: RecipleRegistryCache.Options) {\n super();\n Object.assign(this, options ?? {});\n }\n\n get cachePath(): string {\n return path.join(this.cacheDir, this.client.application?.id ?? 'cache.json');\n }\n\n public async onReady(): Promise<void> {\n const enabled = this.isEnabled();\n\n if (enabled || this.createCacheEntryEvenIfDisabled) {\n this.client.commands?.once('applicationCommandsRegister', async (commands, guildId) => {\n await this.writeCacheEntry();\n });\n }\n\n if (!enabled) {\n this.client.modules.on('readyModules', async () => {\n this.logger.warn(`Registry cache is disabled. Cache is not used.`);\n });\n\n return;\n }\n\n this.logger.debug('Looking for a application commands cache entry...');\n const cachedEntry = await this.readCacheEntry();\n\n this.logger.debug('Creating current application commands cache entry...');\n const currentEntry = await this.createCacheEntry();\n\n if (cachedEntry && this.isCacheHit(cachedEntry, currentEntry)) {\n this.client.config!.applicationCommandsRegister = {\n ...this.client.config!.applicationCommandsRegister,\n registerGlobally: false,\n registerToGuilds: false\n }\n\n this.cached = true;\n }\n\n this.client.modules.on('readyModules', async () => {\n this.logger.warn(`Application commands are ${this.cached ? '' : 'not '}cached. ${this.cached ? 'Skipping' : 'Proceeding with'} registration.`);\n });\n }\n\n public async readCacheEntry(): Promise<RecipleRegistryCache.CacheEntry|null> {\n const stats = await stat(this.cachePath).catch(() => null);\n if (!stats) return null;\n\n return await readFile(this.cachePath, 'utf-8').then(JSON.parse).catch(() => null);\n }\n\n public async writeCacheEntry(entry?: RecipleRegistryCache.CacheEntry): Promise<void> {\n entry ??= await this.createCacheEntry();\n\n this.logger.debug('Writing application commands cache entry...');\n await mkdir(this.cacheDir, { recursive: true });\n await writeFile(this.cachePath, JSON.stringify(entry, null, 4), 'utf-8');\n\n this.logger.debug(`Application commands cache entry written to \"${this.cachePath}\".`);\n }\n\n public async clearCacheEntry(): Promise<void> {\n await rm(this.cachePath).catch(() => null);\n }\n\n public async createCacheEntry(): Promise<RecipleRegistryCache.CacheEntry> {\n this.logger.debug('Creating current application commands cache entry...');\n const commands = Array.from(this.client.commands?.cache.filter(cmd => cmd.type !== CommandType.Message).map(cmd => cmd.toJSON()).values() ?? []);\n\n for (const command of commands) {\n Object.assign(command, { id: \"[cache_value]\" });\n }\n\n const commandsHash = RecipleRegistryCache.createCommandsHash(commands);\n const configHash = RecipleRegistryCache.createConfigHash(this.client.config?.applicationCommandsRegister ?? {});\n\n this.logger.debug(`Commands hash: ${commandsHash}`);\n this.logger.debug(`Config hash: ${configHash}`);\n this.logger.debug('Current application commands cache entry created.');\n\n return {\n createdAt: Date.now(),\n commandsHash,\n configHash\n };\n }\n\n public isCacheHit(cached: RecipleRegistryCache.CacheEntry, current: RecipleRegistryCache.CacheEntry): boolean {\n this.logger.debug('Comparing cache entry with current application commands and configuration...');\n if (this.maxCacheAgeMs) {\n const age = Date.now() - cached.createdAt;\n if (age > this.maxCacheAgeMs) {\n this.logger.debug(`Cache entry is too old (age: ${age}ms, max age: ${this.maxCacheAgeMs}ms).`);\n return false;\n }\n }\n\n if (cached.commandsHash !== current.commandsHash) {\n this.logger.debug(`Cache entry commands hash doesn't match (cached: ${cached.commandsHash}, current: ${current.commandsHash}).`);\n return false;\n }\n if (cached.configHash !== current.configHash) {\n this.logger.debug(`Cache entry config hash doesn't match (cached: ${cached.configHash}, current: ${current.configHash}).`);\n return false;\n }\n\n this.logger.debug('Cache entry matches current application commands and configuration.');\n return true;\n }\n\n private isEnabled(): boolean {\n if (process.env[this.cacheEnabledEnv] !== 'false' && process.env[this.cacheEnabledEnv] !== '0') {\n return RecipleRegistryCache.checkClientIfEnabled(this.client.config ?? {});\n }\n\n return false;\n }\n}\n\nexport namespace RecipleRegistryCache {\n export interface Options {\n /**\n * @default true\n */\n createCacheEntryEvenIfDisabled?: boolean;\n /**\n * @default '.cache/reciple-registry/'\n */\n cacheDir?: string;\n /**\n * @default 86400000 // 24 hours in milliseconds\n */\n maxCacheAgeMs?: number;\n /**\n * @default 'RECIPLE_REGISTRY_CACHE'\n */\n cacheEnabledEnv?: string;\n }\n\n export interface CacheEntry {\n commandsHash: string;\n configHash: string;\n createdAt: number;\n }\n\n export type CommandData = Exclude<AnyCommandData, MessageCommand.Data>;\n\n export function checkClientIfEnabled(config: Config): boolean {\n return config.applicationCommandsRegister?.registerGlobally\n || config.applicationCommandsRegister?.registerToGuilds === true\n || (\n Array.isArray(config.applicationCommandsRegister?.registerToGuilds)\n && config.applicationCommandsRegister?.registerToGuilds.length > 0\n );\n }\n\n export function createCommandsHash(commands: Exclude<AnyCommandData, MessageCommand.Data>[]): string {\n const hash = createHash('sha256');\n\n hash.update(stringifyValue(commands));\n\n return hash.digest('hex');\n }\n\n export function createConfigHash(config: Config): string {\n const hash = createHash('sha256');\n const relevantConfig = { applicationCommandsRegister: config.applicationCommandsRegister };\n\n hash.update(stringifyValue(relevantConfig));\n\n return hash.digest('hex');\n }\n\n export function stringifyValue(object: any): string {\n switch (typeof object) {\n case 'string':\n return `\"${object}\"`;\n case 'number':\n case 'bigint':\n case 'boolean':\n case 'symbol':\n case 'function':\n return `\"${object.toString()}\"`;\n case 'undefined':\n return 'undefined';\n case 'object':\n if (object === null) {\n return 'null';\n }\n\n if (Array.isArray(object)) {\n return `[${object.map(s => stringifyValue(s)).join(', ')}]`;\n }\n\n if (object instanceof Map) {\n return `{${Array.from(object.entries()).map(([k, v]) => `${stringifyValue(k)}: ${stringifyValue(v)}`).join(', ')}}`;\n }\n\n if (object instanceof Set) {\n return `{${Array.from(object.values()).map(v => stringifyValue(v)).join(', ')}}`;\n }\n\n if (object instanceof Date) {\n return `\"${object.toISOString()}\"`;\n }\n\n try {\n const newObject: Record<string, string> = {};\n\n for (const [key, value] of Object.entries(object)) {\n newObject[key] = stringifyValue(value);\n }\n\n return JSON.stringify(newObject);\n } catch {\n return String(object);\n }\n }\n }\n}\n"],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ //#region src/helpers/constants.d.ts
2
+ declare enum InteractionListenerType {
3
+ Autocomplete = 1,
4
+ ContextMenu = 2,
5
+ ChatInput = 3,
6
+ Button = 4,
7
+ ModalSubmit = 5,
8
+ SelectMenu = 6,
9
+ PrimaryEntryPoint = 7
10
+ }
11
+ //#endregion
12
+ export { InteractionListenerType };
13
+ //# sourceMappingURL=constants.d.mts.map
@@ -0,0 +1,15 @@
1
+ //#region src/helpers/constants.ts
2
+ let InteractionListenerType = /* @__PURE__ */ function(InteractionListenerType) {
3
+ InteractionListenerType[InteractionListenerType["Autocomplete"] = 1] = "Autocomplete";
4
+ InteractionListenerType[InteractionListenerType["ContextMenu"] = 2] = "ContextMenu";
5
+ InteractionListenerType[InteractionListenerType["ChatInput"] = 3] = "ChatInput";
6
+ InteractionListenerType[InteractionListenerType["Button"] = 4] = "Button";
7
+ InteractionListenerType[InteractionListenerType["ModalSubmit"] = 5] = "ModalSubmit";
8
+ InteractionListenerType[InteractionListenerType["SelectMenu"] = 6] = "SelectMenu";
9
+ InteractionListenerType[InteractionListenerType["PrimaryEntryPoint"] = 7] = "PrimaryEntryPoint";
10
+ return InteractionListenerType;
11
+ }({});
12
+
13
+ //#endregion
14
+ export { InteractionListenerType };
15
+ //# sourceMappingURL=constants.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.mjs","names":[],"sources":["../../src/helpers/constants.ts"],"sourcesContent":["export enum InteractionListenerType {\n Autocomplete = 1,\n ContextMenu,\n ChatInput,\n Button,\n ModalSubmit,\n SelectMenu,\n PrimaryEntryPoint\n}\n"],"mappings":";AAAA,IAAY,4EAAL;AACH;AACA;AACA;AACA;AACA;AACA;AACA"}
@@ -0,0 +1,17 @@
1
+ import { InteractionListenerType } from "./constants.mjs";
2
+ import { AnySelectMenuInteraction, AutocompleteInteraction, Awaitable, ButtonInteraction, ChatInputCommandInteraction, ContextMenuCommandInteraction, Interaction, ModalSubmitInteraction, PrimaryEntryPointCommandInteraction } from "discord.js";
3
+
4
+ //#region src/helpers/types.d.ts
5
+ interface InteractionListenerData<T extends InteractionListenerType = InteractionListenerType> {
6
+ type: T;
7
+ once?: boolean;
8
+ filter?: (interaction: InteractionFromListenerType<T>) => Awaitable<boolean>;
9
+ execute: (interaction: InteractionFromListenerType<T>) => Awaitable<void>;
10
+ }
11
+ type AnyCommandInteraction = AutocompleteInteraction | ChatInputCommandInteraction | ContextMenuCommandInteraction | PrimaryEntryPointCommandInteraction;
12
+ type AnyComponentInteraction = ButtonInteraction | ModalSubmitInteraction | AnySelectMenuInteraction;
13
+ type InteractionFromListenerType<T extends InteractionListenerType> = T extends InteractionListenerType.Autocomplete ? AutocompleteInteraction : T extends InteractionListenerType.ChatInput ? ChatInputCommandInteraction : T extends InteractionListenerType.ContextMenu ? ContextMenuCommandInteraction : T extends InteractionListenerType.Button ? ButtonInteraction : T extends InteractionListenerType.ModalSubmit ? ModalSubmitInteraction : T extends InteractionListenerType.SelectMenu ? AnySelectMenuInteraction : T extends InteractionListenerType.PrimaryEntryPoint ? PrimaryEntryPointCommandInteraction : Interaction;
14
+ type ListenerTypeFromInteraction<T extends InteractionFromListenerType<InteractionListenerType>> = T extends AutocompleteInteraction ? InteractionListenerType.Autocomplete : T extends ChatInputCommandInteraction ? InteractionListenerType.ChatInput : T extends ContextMenuCommandInteraction ? InteractionListenerType.ContextMenu : T extends ButtonInteraction ? InteractionListenerType.Button : T extends ModalSubmitInteraction ? InteractionListenerType.ModalSubmit : T extends AnySelectMenuInteraction ? InteractionListenerType.SelectMenu : T extends PrimaryEntryPointCommandInteraction ? InteractionListenerType.PrimaryEntryPoint : InteractionListenerType;
15
+ //#endregion
16
+ export { AnyCommandInteraction, AnyComponentInteraction, InteractionFromListenerType, InteractionListenerData, ListenerTypeFromInteraction };
17
+ //# sourceMappingURL=types.d.mts.map
@@ -0,0 +1 @@
1
+ export { };
@@ -0,0 +1,8 @@
1
+ import { InteractionListenerType } from "./helpers/constants.mjs";
2
+ import { AnyCommandInteraction, AnyComponentInteraction, InteractionFromListenerType, InteractionListenerData, ListenerTypeFromInteraction } from "./helpers/types.mjs";
3
+ import { InteractionListener } from "./classes/InteractionListener.mjs";
4
+ import { InteractionListenerBuilder } from "./classes/builders/InteractionListenerBuilder.mjs";
5
+ import { RecipleAnticrash } from "./classes/modules/RecipleAnticrash.mjs";
6
+ import { RecipleInteractionEvents } from "./classes/modules/RecipleInteractionEvents.mjs";
7
+ import { RecipleRegistryCache } from "./classes/modules/RecipleRegistryCache.mjs";
8
+ export { AnyCommandInteraction, AnyComponentInteraction, InteractionFromListenerType, InteractionListener, InteractionListenerBuilder, InteractionListenerData, InteractionListenerType, ListenerTypeFromInteraction, RecipleAnticrash, RecipleInteractionEvents, RecipleRegistryCache };
package/dist/index.mjs ADDED
@@ -0,0 +1,8 @@
1
+ import { InteractionListenerType } from "./helpers/constants.mjs";
2
+ import { InteractionListenerBuilder } from "./classes/builders/InteractionListenerBuilder.mjs";
3
+ import { RecipleAnticrash } from "./classes/modules/RecipleAnticrash.mjs";
4
+ import { InteractionListener } from "./classes/InteractionListener.mjs";
5
+ import { RecipleInteractionEvents } from "./classes/modules/RecipleInteractionEvents.mjs";
6
+ import { RecipleRegistryCache } from "./classes/modules/RecipleRegistryCache.mjs";
7
+
8
+ export { InteractionListener, InteractionListenerBuilder, InteractionListenerType, RecipleAnticrash, RecipleInteractionEvents, RecipleRegistryCache };
package/package.json ADDED
@@ -0,0 +1,49 @@
1
+ {
2
+ "name": "@reciple/modules",
3
+ "version": "10.0.1",
4
+ "license": "LGPL-3.0-only",
5
+ "description": "A collection of useful modules for reciple",
6
+ "module": "./dist/index.mjs",
7
+ "types": "./dist/index.d.mts",
8
+ "type": "module",
9
+ "exports": {
10
+ ".": {
11
+ "import": "./dist/index.mjs",
12
+ "types": "./dist/index.d.mts"
13
+ }
14
+ },
15
+ "files": [
16
+ "dist",
17
+ "README.md"
18
+ ],
19
+ "scripts": {
20
+ "clean": "rimraf ./dist",
21
+ "build": "tsdown --config-loader unrun",
22
+ "docs": "deno doc --json --sloppy-imports ./src/index.ts > docs.json",
23
+ "check": "tsc --noEmit",
24
+ "prepack": "bun run build"
25
+ },
26
+ "repository": {
27
+ "type": "git",
28
+ "url": "https://github.com/thenorthsolution/reciple",
29
+ "directory": "packages/modules"
30
+ },
31
+ "peerDependencies": {
32
+ "discord.js": "^14.25.1",
33
+ "reciple": "^10.0.1"
34
+ },
35
+ "peerDependenciesMeta": {
36
+ "discord.js": {
37
+ "optional": false
38
+ },
39
+ "reciple": {
40
+ "optional": false
41
+ }
42
+ },
43
+ "publishConfig": {
44
+ "access": "public"
45
+ },
46
+ "dependencies": {
47
+ "@sapphire/snowflake": "^3.5.5"
48
+ }
49
+ }