spacecommands 1.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.
Files changed (50) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +519 -0
  3. package/dist/Command.js +384 -0
  4. package/dist/CommandHandler.js +339 -0
  5. package/dist/FeatureHandler.js +89 -0
  6. package/dist/SlashCommands.js +220 -0
  7. package/dist/command-checks/channel-specific.js +30 -0
  8. package/dist/command-checks/guild-only-check.js +24 -0
  9. package/dist/command-checks/has-entitlement.js +52 -0
  10. package/dist/command-checks/has-permissions.js +39 -0
  11. package/dist/command-checks/has-roles.js +69 -0
  12. package/dist/command-checks/has-valid-arguments.js +54 -0
  13. package/dist/command-checks/in-cooldown.js +42 -0
  14. package/dist/command-checks/is-enabled.js +31 -0
  15. package/dist/command-checks/is-not-test-only.js +8 -0
  16. package/dist/command-checks/owner-only-check.js +22 -0
  17. package/dist/commands/channelonly.js +88 -0
  18. package/dist/commands/command.js +87 -0
  19. package/dist/commands/help/!ReactionListener.js +217 -0
  20. package/dist/commands/help/!get-first-embed.js +57 -0
  21. package/dist/commands/help/help.js +97 -0
  22. package/dist/commands/language.js +52 -0
  23. package/dist/commands/prefix.js +42 -0
  24. package/dist/commands/requiredrole.js +61 -0
  25. package/dist/commands/slash.js +102 -0
  26. package/dist/enums/CommandErrors.js +12 -0
  27. package/dist/enums/Events.js +9 -0
  28. package/dist/features/message-upsert.js +15 -0
  29. package/dist/get-all-files.js +25 -0
  30. package/dist/handlers/AutoModHandler.js +316 -0
  31. package/dist/handlers/ComponentHandler.js +110 -0
  32. package/dist/handlers/ContextMenuHandler.js +113 -0
  33. package/dist/handlers/EntitlementHandler.js +193 -0
  34. package/dist/handlers/ModalHandler.js +71 -0
  35. package/dist/handlers/PollHandler.js +230 -0
  36. package/dist/index.js +339 -0
  37. package/dist/message-handler.js +118 -0
  38. package/dist/models/channel-commands.js +49 -0
  39. package/dist/models/cooldown.js +51 -0
  40. package/dist/models/disabled-commands.js +45 -0
  41. package/dist/models/languages.js +46 -0
  42. package/dist/models/prefixes.js +46 -0
  43. package/dist/models/required-roles.js +49 -0
  44. package/dist/mongo.js +25 -0
  45. package/dist/permissions.js +39 -0
  46. package/dist/utils/ComponentBuilder.js +144 -0
  47. package/dist/utils/InteractionCollector.js +80 -0
  48. package/messages.json +391 -0
  49. package/package.json +72 -0
  50. package/typings.d.ts +276 -0
@@ -0,0 +1,193 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ /**
4
+ * Handler for Discord premium features and entitlements
5
+ * Supports Discord's monetization system with SKUs and subscriptions
6
+ */
7
+ class EntitlementHandler {
8
+ _client;
9
+ _instance;
10
+ _skus = new Map();
11
+ _entitlementCache = new Map();
12
+ _cacheTimeout = 5 * 60 * 1000; // 5 minutes
13
+ constructor(instance) {
14
+ this._instance = instance;
15
+ this._client = instance.client;
16
+ this.setUp();
17
+ }
18
+ setUp() {
19
+ // Listen for new entitlements
20
+ this._client.on('entitlementCreate', (entitlement) => {
21
+ this.clearUserCache(entitlement.userId);
22
+ if (this._instance.debug) {
23
+ console.log(`SpaceCommands > Entitlement created: ${entitlement.id} for user ${entitlement.userId}`);
24
+ }
25
+ });
26
+ // Listen for entitlement updates
27
+ this._client.on('entitlementUpdate', (oldEntitlement, newEntitlement) => {
28
+ this.clearUserCache(newEntitlement.userId);
29
+ if (this._instance.debug) {
30
+ console.log(`SpaceCommands > Entitlement updated: ${newEntitlement.id} for user ${newEntitlement.userId}`);
31
+ }
32
+ });
33
+ // Listen for entitlement deletions
34
+ this._client.on('entitlementDelete', (entitlement) => {
35
+ this.clearUserCache(entitlement.userId);
36
+ if (this._instance.debug) {
37
+ console.log(`SpaceCommands > Entitlement deleted: ${entitlement.id} for user ${entitlement.userId}`);
38
+ }
39
+ });
40
+ }
41
+ /**
42
+ * Register a SKU for premium features
43
+ */
44
+ registerSKU(config) {
45
+ this._skus.set(config.skuId, config);
46
+ if (this._instance.debug) {
47
+ console.log(`SpaceCommands > Registered SKU: ${config.skuId} (${config.name || 'Unnamed'})`);
48
+ }
49
+ return this;
50
+ }
51
+ /**
52
+ * Register multiple SKUs at once
53
+ */
54
+ registerSKUs(configs) {
55
+ for (const config of configs) {
56
+ this.registerSKU(config);
57
+ }
58
+ return this;
59
+ }
60
+ /**
61
+ * Check if a user has a specific entitlement
62
+ */
63
+ async hasEntitlement(userId, skuId) {
64
+ const entitlements = await this.getUserEntitlements(userId);
65
+ const entitlement = entitlements.find((e) => e.skuId === skuId);
66
+ return {
67
+ hasEntitlement: !!entitlement,
68
+ entitlement,
69
+ };
70
+ }
71
+ /**
72
+ * Check if a user has any of the specified entitlements
73
+ */
74
+ async hasAnyEntitlement(userId, skuIds) {
75
+ const entitlements = await this.getUserEntitlements(userId);
76
+ const entitlement = entitlements.find((e) => skuIds.includes(e.skuId));
77
+ return {
78
+ hasEntitlement: !!entitlement,
79
+ entitlement,
80
+ };
81
+ }
82
+ /**
83
+ * Check if a user has all of the specified entitlements
84
+ */
85
+ async hasAllEntitlements(userId, skuIds) {
86
+ const entitlements = await this.getUserEntitlements(userId);
87
+ const entitlementSkus = entitlements.map((e) => e.skuId);
88
+ return skuIds.every((skuId) => entitlementSkus.includes(skuId));
89
+ }
90
+ /**
91
+ * Get all active entitlements for a user
92
+ */
93
+ async getUserEntitlements(userId, useCache = true) {
94
+ // Check cache first
95
+ if (useCache && this._entitlementCache.has(userId)) {
96
+ return this._entitlementCache.get(userId);
97
+ }
98
+ try {
99
+ const entitlements = await this._client.application?.entitlements.fetch({
100
+ user: userId,
101
+ });
102
+ if (!entitlements) {
103
+ return [];
104
+ }
105
+ const activeEntitlements = entitlements.filter((e) => !e.deleted && e.endsAt && e.endsAt.getTime() > Date.now());
106
+ // Cache the results
107
+ this._entitlementCache.set(userId, Array.from(activeEntitlements.values()));
108
+ // Clear cache after timeout
109
+ setTimeout(() => {
110
+ this._entitlementCache.delete(userId);
111
+ }, this._cacheTimeout);
112
+ return Array.from(activeEntitlements.values());
113
+ }
114
+ catch (error) {
115
+ console.error(`SpaceCommands > Error fetching entitlements for user ${userId}:`, error);
116
+ return [];
117
+ }
118
+ }
119
+ /**
120
+ * Get all registered SKUs
121
+ */
122
+ getSKUs() {
123
+ return this._skus;
124
+ }
125
+ /**
126
+ * Get a specific SKU configuration
127
+ */
128
+ getSKU(skuId) {
129
+ return this._skus.get(skuId);
130
+ }
131
+ /**
132
+ * Clear the entitlement cache for a specific user
133
+ */
134
+ clearUserCache(userId) {
135
+ if (userId) {
136
+ this._entitlementCache.delete(userId);
137
+ }
138
+ else {
139
+ this._entitlementCache.clear();
140
+ }
141
+ }
142
+ /**
143
+ * Set the cache timeout duration (in milliseconds)
144
+ */
145
+ setCacheTimeout(timeout) {
146
+ this._cacheTimeout = timeout;
147
+ return this;
148
+ }
149
+ /**
150
+ * Check if a user/member has entitlement (works with User or GuildMember)
151
+ */
152
+ async checkAccess(userOrMember, skuId) {
153
+ const userId = userOrMember.id;
154
+ return this.hasEntitlement(userId, skuId);
155
+ }
156
+ /**
157
+ * Consume a one-time purchase entitlement
158
+ * This marks the entitlement as consumed (for one-time purchases)
159
+ */
160
+ async consumeEntitlement(entitlementId) {
161
+ try {
162
+ await this._client.application?.entitlements.consume(entitlementId);
163
+ if (this._instance.debug) {
164
+ console.log(`SpaceCommands > Consumed entitlement: ${entitlementId}`);
165
+ }
166
+ return true;
167
+ }
168
+ catch (error) {
169
+ console.error(`SpaceCommands > Error consuming entitlement ${entitlementId}:`, error);
170
+ return false;
171
+ }
172
+ }
173
+ /**
174
+ * Get all entitlements for a guild
175
+ */
176
+ async getGuildEntitlements(guildId, useCache = false) {
177
+ try {
178
+ const entitlements = await this._client.application?.entitlements.fetch({
179
+ guild: guildId,
180
+ });
181
+ if (!entitlements) {
182
+ return [];
183
+ }
184
+ const activeEntitlements = entitlements.filter((e) => !e.deleted && e.endsAt && e.endsAt.getTime() > Date.now());
185
+ return Array.from(activeEntitlements.values());
186
+ }
187
+ catch (error) {
188
+ console.error(`SpaceCommands > Error fetching entitlements for guild ${guildId}:`, error);
189
+ return [];
190
+ }
191
+ }
192
+ }
193
+ exports.default = EntitlementHandler;
@@ -0,0 +1,71 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const get_all_files_1 = __importDefault(require("../get-all-files"));
7
+ class ModalHandler {
8
+ _client;
9
+ _instance;
10
+ _modalHandlers = new Map();
11
+ constructor(instance, modalsDir, typeScript = false) {
12
+ this._instance = instance;
13
+ this._client = instance.client;
14
+ this.setUp(modalsDir, typeScript);
15
+ }
16
+ async setUp(modalsDir, typeScript = false) {
17
+ // Listen for modal submissions
18
+ this._client.on('interactionCreate', async (interaction) => {
19
+ if (!interaction.isModalSubmit()) {
20
+ return;
21
+ }
22
+ const customId = interaction.customId;
23
+ await this.handleModal(interaction, customId);
24
+ });
25
+ // Load custom modal handlers if directory provided
26
+ if (modalsDir) {
27
+ await this.loadModalHandlers(modalsDir, typeScript);
28
+ }
29
+ }
30
+ async loadModalHandlers(dir, typeScript) {
31
+ const files = (0, get_all_files_1.default)(dir, typeScript ? '.ts' : '');
32
+ for (const [file, fileName] of files) {
33
+ const handler = require(file);
34
+ const config = handler.default || handler;
35
+ if (config.type === 'modal') {
36
+ this.registerModalHandler(config);
37
+ }
38
+ }
39
+ }
40
+ registerModalHandler(handler) {
41
+ const key = typeof handler.customId === 'string'
42
+ ? handler.customId
43
+ : handler.customId.source;
44
+ this._modalHandlers.set(key, handler);
45
+ }
46
+ async handleModal(interaction, customId) {
47
+ for (const [key, handler] of this._modalHandlers.entries()) {
48
+ const regex = handler.customId instanceof RegExp ? handler.customId : null;
49
+ if ((regex && regex.test(customId)) ||
50
+ (!regex && handler.customId === customId)) {
51
+ try {
52
+ await handler.callback(interaction, this._instance);
53
+ }
54
+ catch (error) {
55
+ console.error(`SpaceCommands > Error handling modal "${customId}":`, error);
56
+ if (!interaction.replied && !interaction.deferred) {
57
+ await interaction.reply({
58
+ content: 'An error occurred while processing this form.',
59
+ ephemeral: true,
60
+ });
61
+ }
62
+ }
63
+ return;
64
+ }
65
+ }
66
+ }
67
+ get modalHandlers() {
68
+ return this._modalHandlers;
69
+ }
70
+ }
71
+ exports.default = ModalHandler;
@@ -0,0 +1,230 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ /**
4
+ * Handler for Discord Polls
5
+ * Supports creating, managing, and listening to poll events
6
+ */
7
+ class PollHandler {
8
+ _client;
9
+ _instance;
10
+ _voteHandlers = new Map();
11
+ _endHandlers = [];
12
+ constructor(instance) {
13
+ this._instance = instance;
14
+ this._client = instance.client;
15
+ this.setUp();
16
+ }
17
+ setUp() {
18
+ // Note: Discord.js doesn't have built-in poll events yet
19
+ // Polls are accessed through messages
20
+ // This handler provides utilities for working with polls
21
+ }
22
+ /**
23
+ * Create a poll in a message
24
+ * Returns the message containing the poll
25
+ */
26
+ async createPoll(message, config) {
27
+ try {
28
+ if (config.answers.length < 1 || config.answers.length > 10) {
29
+ throw new Error('Polls must have between 1 and 10 answers');
30
+ }
31
+ const duration = config.duration
32
+ ? Math.min(Math.max(config.duration, 1), 168)
33
+ : 24;
34
+ // Poll creation is done through the message content
35
+ // This is a utility method to help construct poll data
36
+ const pollData = {
37
+ question: { text: config.question },
38
+ answers: config.answers.map((answer, index) => ({
39
+ poll_media: {
40
+ text: answer.text,
41
+ emoji: answer.emoji,
42
+ },
43
+ answer_id: index,
44
+ })),
45
+ duration,
46
+ allow_multiselect: config.allowMultiselect || false,
47
+ layout_type: config.layoutType || 1,
48
+ };
49
+ // Fetch the message to get the poll if it was created
50
+ const fetchedMessage = await message.channel.messages.fetch(message.id);
51
+ return fetchedMessage.poll || null;
52
+ }
53
+ catch (error) {
54
+ console.error('SpaceCommands > Error creating poll:', error);
55
+ return null;
56
+ }
57
+ }
58
+ /**
59
+ * Get poll results
60
+ */
61
+ async getPollResults(poll) {
62
+ const results = new Map();
63
+ try {
64
+ for (const answer of poll.answers.values()) {
65
+ const voters = await answer.fetchVoters();
66
+ results.set(answer.id, voters);
67
+ }
68
+ }
69
+ catch (error) {
70
+ console.error('SpaceCommands > Error fetching poll results:', error);
71
+ }
72
+ return results;
73
+ }
74
+ /**
75
+ * Get the winning answer(s) of a poll
76
+ */
77
+ getWinningAnswers(poll) {
78
+ const answers = Array.from(poll.answers.values());
79
+ if (answers.length === 0)
80
+ return [];
81
+ const maxVotes = Math.max(...answers.map((a) => a.voteCount));
82
+ return answers.filter((a) => a.voteCount === maxVotes);
83
+ }
84
+ /**
85
+ * End a poll early
86
+ */
87
+ async endPoll(poll) {
88
+ try {
89
+ await poll.end();
90
+ if (this._instance.debug) {
91
+ console.log(`SpaceCommands > Ended poll: ${poll.message.id}`);
92
+ }
93
+ // Trigger end handlers
94
+ await this.triggerEndHandlers(poll);
95
+ return true;
96
+ }
97
+ catch (error) {
98
+ console.error('SpaceCommands > Error ending poll:', error);
99
+ return false;
100
+ }
101
+ }
102
+ /**
103
+ * Register a handler for when a poll ends
104
+ */
105
+ registerPollEndHandler(handler) {
106
+ this._endHandlers.push(handler);
107
+ if (this._instance.debug) {
108
+ console.log(`SpaceCommands > Registered poll end handler for: ${handler.pollId}`);
109
+ }
110
+ return this;
111
+ }
112
+ /**
113
+ * Trigger all matching end handlers for a poll
114
+ */
115
+ async triggerEndHandlers(poll) {
116
+ const pollId = poll.message.id;
117
+ for (const handler of this._endHandlers) {
118
+ let matches = false;
119
+ if (typeof handler.pollId === 'string') {
120
+ matches = handler.pollId === pollId;
121
+ }
122
+ else {
123
+ matches = handler.pollId.test(pollId);
124
+ }
125
+ if (matches) {
126
+ try {
127
+ await handler.callback(poll, this._instance);
128
+ }
129
+ catch (error) {
130
+ console.error('SpaceCommands > Error executing poll end handler:', error);
131
+ }
132
+ }
133
+ }
134
+ }
135
+ /**
136
+ * Check if a user has voted on a poll
137
+ */
138
+ async hasUserVoted(poll, userId) {
139
+ try {
140
+ for (const answer of poll.answers.values()) {
141
+ const voters = await answer.fetchVoters();
142
+ if (voters.has(userId)) {
143
+ return true;
144
+ }
145
+ }
146
+ return false;
147
+ }
148
+ catch (error) {
149
+ console.error('SpaceCommands > Error checking poll vote:', error);
150
+ return false;
151
+ }
152
+ }
153
+ /**
154
+ * Get user's votes on a poll
155
+ */
156
+ async getUserVotes(poll, userId) {
157
+ const userVotes = [];
158
+ try {
159
+ for (const answer of poll.answers.values()) {
160
+ const voters = await answer.fetchVoters();
161
+ if (voters.has(userId)) {
162
+ userVotes.push(answer);
163
+ }
164
+ }
165
+ }
166
+ catch (error) {
167
+ console.error('SpaceCommands > Error getting user votes:', error);
168
+ }
169
+ return userVotes;
170
+ }
171
+ /**
172
+ * Get poll statistics
173
+ */
174
+ getPollStats(poll) {
175
+ const answers = Array.from(poll.answers.values());
176
+ const totalVotes = answers.reduce((sum, answer) => sum + answer.voteCount, 0);
177
+ return {
178
+ totalVotes,
179
+ answerCount: answers.length,
180
+ allowsMultiselect: poll.allowMultiselect,
181
+ expiresAt: poll.expiresAt,
182
+ isExpired: poll.expiresAt ? poll.expiresAt.getTime() < Date.now() : false,
183
+ };
184
+ }
185
+ /**
186
+ * Get a formatted summary of poll results
187
+ */
188
+ async getFormattedResults(poll) {
189
+ const results = await this.getPollResults(poll);
190
+ const stats = this.getPollStats(poll);
191
+ let output = `**${poll.question.text}**\n\n`;
192
+ for (const answer of poll.answers.values()) {
193
+ const voters = results.get(answer.id);
194
+ const percentage = stats.totalVotes > 0
195
+ ? ((answer.voteCount / stats.totalVotes) * 100).toFixed(1)
196
+ : '0.0';
197
+ const answerText = 'text' in answer ? answer.text : answer.id.toString();
198
+ output += `${answerText}: ${answer.voteCount} votes (${percentage}%)\n`;
199
+ }
200
+ output += `\nTotal Votes: ${stats.totalVotes}`;
201
+ return output;
202
+ }
203
+ /**
204
+ * Fetch a poll from a message
205
+ */
206
+ async fetchPoll(message, channelId) {
207
+ try {
208
+ let msg;
209
+ if (typeof message === 'string') {
210
+ if (!channelId) {
211
+ throw new Error('Channel ID required when fetching by message ID');
212
+ }
213
+ const channel = await this._client.channels.fetch(channelId);
214
+ if (!channel || !channel.isTextBased()) {
215
+ throw new Error('Invalid channel');
216
+ }
217
+ msg = await channel.messages.fetch(message);
218
+ }
219
+ else {
220
+ msg = message;
221
+ }
222
+ return msg.poll || null;
223
+ }
224
+ catch (error) {
225
+ console.error('SpaceCommands > Error fetching poll:', error);
226
+ return null;
227
+ }
228
+ }
229
+ }
230
+ exports.default = PollHandler;