@open-discord-bots/framework 0.3.2 → 0.3.4
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/dist/api/index.d.ts +1 -0
- package/dist/api/index.js +1 -0
- package/dist/api/main.d.ts +4 -0
- package/dist/api/main.js +3 -1
- package/dist/api/modules/client.d.ts +13 -12
- package/dist/api/modules/client.js +59 -54
- package/dist/api/modules/console.js +3 -1
- package/dist/api/modules/database.d.ts +1 -1
- package/dist/api/modules/fuse.d.ts +10 -2
- package/dist/api/modules/fuse.js +5 -1
- package/dist/api/modules/post.js +2 -2
- package/dist/api/modules/responder.d.ts +11 -13
- package/dist/api/modules/responder.js +112 -112
- package/dist/api/modules/state.d.ts +126 -0
- package/dist/api/modules/state.js +222 -0
- package/dist/startup/errorHandling.js +2 -0
- package/package.json +1 -1
- package/src/api/index.ts +1 -0
- package/src/api/main.ts +6 -1
- package/src/api/modules/client.ts +58 -54
- package/src/api/modules/console.ts +3 -1
- package/src/api/modules/database.ts +1 -1
- package/src/api/modules/fuse.ts +19 -5
- package/src/api/modules/post.ts +2 -2
- package/src/api/modules/responder.ts +106 -113
- package/src/api/modules/state.ts +294 -0
- package/src/startup/errorHandling.ts +3 -0
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
///////////////////////////////////////
|
|
2
|
+
//STATE MODULE
|
|
3
|
+
///////////////////////////////////////
|
|
4
|
+
import { ODManager, ODSystemError, ODManagerData } from "./base.js";
|
|
5
|
+
/**## ODState `class`
|
|
6
|
+
* An Open Discord state is a system for storing additional chunks of metadata for Discord messages.
|
|
7
|
+
* A system for tracking messages or linking metadata, states or progress to Discord messages (ID-based).
|
|
8
|
+
*
|
|
9
|
+
* Features automatic garbage collection to clear expired states.
|
|
10
|
+
*/
|
|
11
|
+
export class ODState extends ODManagerData {
|
|
12
|
+
/**Alias to Open Discord message states database. */
|
|
13
|
+
database;
|
|
14
|
+
/**Alias to Open Discord client manager. */
|
|
15
|
+
client;
|
|
16
|
+
/**Alias to Open Discord debugger. */
|
|
17
|
+
debug = null;
|
|
18
|
+
/**The settings of this state. */
|
|
19
|
+
settings;
|
|
20
|
+
constructor(id, client, database, settings) {
|
|
21
|
+
super(id);
|
|
22
|
+
this.client = client;
|
|
23
|
+
this.database = database;
|
|
24
|
+
this.settings = {
|
|
25
|
+
disableAutodelete: false,
|
|
26
|
+
autodeleteOnChannelDelete: true,
|
|
27
|
+
autodeleteOnMessageDelete: true,
|
|
28
|
+
autodeleteOnUserLeave: true,
|
|
29
|
+
autodeleteOnRestart: false,
|
|
30
|
+
autodeleteOnEphemeral: true,
|
|
31
|
+
autodeleteAfterTimeout: null,
|
|
32
|
+
...settings
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
/**Use the Open Discord debugger in this manager for logs. */
|
|
36
|
+
useDebug(debug) {
|
|
37
|
+
this.debug = debug ?? null;
|
|
38
|
+
}
|
|
39
|
+
/**Init the state and start autodeleting. The client must already be logged-in for this to work. */
|
|
40
|
+
async init() {
|
|
41
|
+
if (!this.client.loggedIn)
|
|
42
|
+
throw new ODSystemError("ODState('" + this.id.value + "').init() => The client must be logged in for states to initialize.");
|
|
43
|
+
//autodelete on restart
|
|
44
|
+
if (!this.settings.disableAutodelete && this.settings.autodeleteOnRestart)
|
|
45
|
+
this.clearAllMsgStates();
|
|
46
|
+
//autodelete on channelDelete
|
|
47
|
+
this.client.client.on("channelDelete", async (deletedChannel) => {
|
|
48
|
+
if (this.settings.disableAutodelete || !this.settings.autodeleteOnChannelDelete)
|
|
49
|
+
return;
|
|
50
|
+
for (const { key, value } of await this.listMsgStates()) {
|
|
51
|
+
if (value.channelId === deletedChannel.id)
|
|
52
|
+
await this.deleteMsgStateWithRawKey(key);
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
//autodelete on messageDelete
|
|
56
|
+
this.client.client.on("messageDelete", async (deletedMsg) => {
|
|
57
|
+
if (this.settings.disableAutodelete || !this.settings.autodeleteOnMessageDelete)
|
|
58
|
+
return;
|
|
59
|
+
for (const { key, value } of await this.listMsgStates()) {
|
|
60
|
+
if (value.messageId === deletedMsg.id)
|
|
61
|
+
await this.deleteMsgStateWithRawKey(key);
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
//autodelete on userLeave
|
|
65
|
+
this.client.client.on("guildMemberRemove", async (member) => {
|
|
66
|
+
if (this.settings.disableAutodelete || !this.settings.autodeleteOnUserLeave)
|
|
67
|
+
return;
|
|
68
|
+
if (member.guild.id !== this.client.mainServer?.id)
|
|
69
|
+
return;
|
|
70
|
+
for (const { key, value } of await this.listMsgStates()) {
|
|
71
|
+
if (value.userId === member.id)
|
|
72
|
+
await this.deleteMsgStateWithRawKey(key);
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
//autodelete when expired (ephemeral/timeout) every 30 seconds
|
|
76
|
+
this.purgeExpiredStates();
|
|
77
|
+
setInterval(() => {
|
|
78
|
+
this.purgeExpiredStates();
|
|
79
|
+
}, 30 * 1000);
|
|
80
|
+
//create a list of all channels, messages & users that still exist (and are part of states)
|
|
81
|
+
const existingChannelIds = [];
|
|
82
|
+
const existingMessageIds = [];
|
|
83
|
+
const existingUserIds = [];
|
|
84
|
+
for (const { key, value } of await this.listMsgStates()) {
|
|
85
|
+
if (!existingChannelIds.includes(value.channelId)) {
|
|
86
|
+
//check if channel still exists
|
|
87
|
+
const channel = await this.client.fetchChannel(value.channelId);
|
|
88
|
+
if (channel)
|
|
89
|
+
existingChannelIds.push(channel.id);
|
|
90
|
+
}
|
|
91
|
+
if (!existingMessageIds.includes(value.messageId)) {
|
|
92
|
+
//check if message still exists
|
|
93
|
+
const message = await this.client.fetchChannelMessage(value.channelId, value.messageId);
|
|
94
|
+
if (message)
|
|
95
|
+
existingMessageIds.push(message.id);
|
|
96
|
+
}
|
|
97
|
+
if (value.userId && this.client.mainServer && !existingUserIds.includes(value.userId)) {
|
|
98
|
+
//check if user still exists
|
|
99
|
+
const user = await this.client.fetchGuildMember(this.client.mainServer.id, value.userId);
|
|
100
|
+
if (user)
|
|
101
|
+
existingUserIds.push(user.id);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
//delete all states where a channel, message or user is missing (when the bot was offline)
|
|
105
|
+
for (const { key, value } of await this.listMsgStates()) {
|
|
106
|
+
if (value.channelId && !existingChannelIds.includes(value.channelId))
|
|
107
|
+
await this.deleteMsgStateWithRawKey(key);
|
|
108
|
+
if (value.messageId && !existingMessageIds.includes(value.messageId))
|
|
109
|
+
await this.deleteMsgStateWithRawKey(key);
|
|
110
|
+
if (value.userId && !existingUserIds.includes(value.userId))
|
|
111
|
+
await this.deleteMsgStateWithRawKey(key);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
/**Purge all expired message states that reached a timeout or ephemeral. */
|
|
115
|
+
async purgeExpiredStates() {
|
|
116
|
+
for (const { key, value } of await this.listMsgStates()) {
|
|
117
|
+
if (value.deleteAfterDate && value.deleteAfterDate < Date.now())
|
|
118
|
+
await this.deleteMsgStateWithRawKey(key);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
/**Transform the object-based message state key contents to a string. */
|
|
122
|
+
transformKey(key) {
|
|
123
|
+
const newGuild = (!key.guild) ? "NULL" : (typeof key.guild === "string" ? key.guild : key.guild.id);
|
|
124
|
+
const newChannel = (!key.channel) ? "NULL" : (typeof key.channel === "string" ? key.channel : key.channel.id);
|
|
125
|
+
const newMessage = (!key.message) ? "NULL" : (typeof key.message === "string" ? key.message : key.message.id);
|
|
126
|
+
const newUser = (!key.user) ? "NULL" : (typeof key.user === "string" ? key.user : key.user.id);
|
|
127
|
+
return `G:${newGuild},C:${newChannel},M:${newMessage},U:${newUser}`;
|
|
128
|
+
}
|
|
129
|
+
/**Transform the message state data contents for storage in the database. */
|
|
130
|
+
transformData(key, data, isEphemeral, keepCreatedDate) {
|
|
131
|
+
const guildId = (!key.guild) ? null : (typeof key.guild === "string" ? key.guild : key.guild.id);
|
|
132
|
+
const channelId = (typeof key.channel === "string" ? key.channel : key.channel.id);
|
|
133
|
+
const messageId = (typeof key.message === "string" ? key.message : key.message.id);
|
|
134
|
+
const userId = (!key.user) ? null : (typeof key.user === "string" ? key.user : key.user.id);
|
|
135
|
+
const createdDate = keepCreatedDate ?? Date.now();
|
|
136
|
+
const modifiedDate = Date.now();
|
|
137
|
+
const unmodifiedTimeoutDate = this.timeoutToUnixTime();
|
|
138
|
+
const ephemeralTimeoutDate = (isEphemeral) ? Date.now() + (3600 * 1000) : null; //delete ephemeral state after 1 hour
|
|
139
|
+
const deleteAfterDate = (unmodifiedTimeoutDate) ? unmodifiedTimeoutDate : ephemeralTimeoutDate;
|
|
140
|
+
return { guildId, channelId, messageId, userId, createdDate, modifiedDate, deleteAfterDate, data };
|
|
141
|
+
}
|
|
142
|
+
/**Calculate milliseconds from a time + unit. */
|
|
143
|
+
timeoutToUnixTime() {
|
|
144
|
+
const timeout = this.settings.autodeleteAfterTimeout;
|
|
145
|
+
if (!timeout)
|
|
146
|
+
return null;
|
|
147
|
+
if (timeout.unit == "seconds")
|
|
148
|
+
return Date.now() + (timeout.time * 1000);
|
|
149
|
+
else if (timeout.unit == "minutes")
|
|
150
|
+
return Date.now() + (timeout.time * 1000 * 60);
|
|
151
|
+
else if (timeout.unit == "hours")
|
|
152
|
+
return Date.now() + (timeout.time * 1000 * 3600);
|
|
153
|
+
else if (timeout.unit == "days")
|
|
154
|
+
return Date.now() + (timeout.time * 1000 * 3600 * 24);
|
|
155
|
+
else
|
|
156
|
+
return null;
|
|
157
|
+
}
|
|
158
|
+
/**Set a message state using guild, channel & message id as key. Returns `true` when overwritten. */
|
|
159
|
+
async setMsgState(key, data, isEphemeral) {
|
|
160
|
+
const rawKey = this.transformKey(key);
|
|
161
|
+
const existingData = await this.getMsgState(key);
|
|
162
|
+
const contents = this.transformData(key, data, isEphemeral, existingData?.createdDate);
|
|
163
|
+
return await this.database.set(this.id.value, rawKey, contents);
|
|
164
|
+
}
|
|
165
|
+
/**Get a message state using guild, channel & message id as key. */
|
|
166
|
+
async getMsgState(key) {
|
|
167
|
+
const rawKey = this.transformKey(key);
|
|
168
|
+
const rawData = await this.database.get(this.id.value, rawKey);
|
|
169
|
+
if (typeof rawData !== "object")
|
|
170
|
+
return null;
|
|
171
|
+
else
|
|
172
|
+
return rawData;
|
|
173
|
+
}
|
|
174
|
+
/**Delete a message state using guild, channel & message id as key. Returns `true` when deleted. */
|
|
175
|
+
async deleteMsgState(key) {
|
|
176
|
+
const rawKey = this.transformKey(key);
|
|
177
|
+
return await this.database.delete(this.id.value, rawKey);
|
|
178
|
+
}
|
|
179
|
+
/**List all message states of this `ODState`. */
|
|
180
|
+
async listMsgStates() {
|
|
181
|
+
return ((await this.database.getCategory(this.id.value)) ?? []);
|
|
182
|
+
}
|
|
183
|
+
/**Delete all message states from this ODState. */
|
|
184
|
+
async clearAllMsgStates() {
|
|
185
|
+
for (const state of await this.database.getAll()) {
|
|
186
|
+
await this.database.delete(state.category, state.key);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
/**Delete a message state using the raw key. Returns `true` when deleted. */
|
|
190
|
+
async deleteMsgStateWithRawKey(rawKey) {
|
|
191
|
+
return await this.database.delete(this.id.value, rawKey);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
/**## ODStateManager `class`
|
|
195
|
+
* The Open Discord state manager is a system for tracking messages or linking metadata, states or progress to Discord messages (ID-based).
|
|
196
|
+
*
|
|
197
|
+
* Features automatic garbage collection to clear expired states.
|
|
198
|
+
*/
|
|
199
|
+
export class ODStateManager extends ODManager {
|
|
200
|
+
constructor(debug) {
|
|
201
|
+
super(debug, "state");
|
|
202
|
+
}
|
|
203
|
+
/**Init all states. */
|
|
204
|
+
async init() {
|
|
205
|
+
for (const state of this.getAll()) {
|
|
206
|
+
await state.init();
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
add(data, overwrite) {
|
|
210
|
+
data.useDebug(this.debug);
|
|
211
|
+
return super.add(data, overwrite);
|
|
212
|
+
}
|
|
213
|
+
get(id) {
|
|
214
|
+
return super.get(id);
|
|
215
|
+
}
|
|
216
|
+
remove(id) {
|
|
217
|
+
return super.remove(id);
|
|
218
|
+
}
|
|
219
|
+
exists(id) {
|
|
220
|
+
return super.exists(id);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import * as api from "../api/index.js";
|
|
2
2
|
export function loadErrorHandling(opendiscord, project) {
|
|
3
|
+
//increase error stack trace
|
|
4
|
+
Error.stackTraceLimit = 50;
|
|
3
5
|
process.on("uncaughtException", async (error, origin) => {
|
|
4
6
|
try {
|
|
5
7
|
const beforeEvent = opendiscord.events.get("onErrorHandling");
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@open-discord-bots/framework",
|
|
3
3
|
"author": "DJj123dj",
|
|
4
|
-
"version": "0.3.
|
|
4
|
+
"version": "0.3.4",
|
|
5
5
|
"description": "The core framework of the popular open-source discord bots: Open Ticket & Open Moderation.",
|
|
6
6
|
"main": "dist/index.js",
|
|
7
7
|
"module": "dist/index.js",
|
package/src/api/index.ts
CHANGED
|
@@ -25,6 +25,7 @@ export * from "./modules/progressbar.js"
|
|
|
25
25
|
export * from "./modules/responder.js"
|
|
26
26
|
export * from "./modules/session.js"
|
|
27
27
|
export * from "./modules/startscreen.js"
|
|
28
|
+
export * from "./modules/state.js"
|
|
28
29
|
export * from "./modules/statistic.js"
|
|
29
30
|
export * from "./modules/verifybar.js"
|
|
30
31
|
export * from "./modules/worker.js"
|
package/src/api/main.ts
CHANGED
|
@@ -24,6 +24,7 @@ import { ODClientManager } from "./modules/client.js"
|
|
|
24
24
|
import { ODSharedFuseManager } from "./modules/fuse.js"
|
|
25
25
|
import { ODStartScreenManager } from "./modules/startscreen.js"
|
|
26
26
|
import { ODComponentManager } from "./modules/component.js"
|
|
27
|
+
import { ODStateManager } from "./modules/state.js"
|
|
27
28
|
|
|
28
29
|
/**## ODMainManagers `interface`
|
|
29
30
|
* The global properties for the main class of the bot.
|
|
@@ -89,6 +90,8 @@ export interface ODMainManagers {
|
|
|
89
90
|
code: ODCodeManager
|
|
90
91
|
/**A collection of static Discord post channels. It allows the bot to find back log, transcript or configured channels based on a linked ID. */
|
|
91
92
|
posts: ODPostManager
|
|
93
|
+
/**A system for tracking messages or linking metadata, states or progress to Discord messages (ID-based). Features automatic garbage collection. */
|
|
94
|
+
states: ODStateManager
|
|
92
95
|
|
|
93
96
|
/**A wrapper around the `discord.Client` class. It handles client login, activity and registering text/slash commands. */
|
|
94
97
|
client: ODClientManager
|
|
@@ -140,6 +143,7 @@ export abstract class ODMain implements ODMainManagers {
|
|
|
140
143
|
readonly statistics: ODStatisticManager
|
|
141
144
|
readonly code: ODCodeManager
|
|
142
145
|
readonly posts: ODPostManager
|
|
146
|
+
readonly states: ODStateManager
|
|
143
147
|
|
|
144
148
|
readonly client: ODClientManager
|
|
145
149
|
readonly sharedFuses: ODSharedFuseManager
|
|
@@ -150,7 +154,7 @@ export abstract class ODMain implements ODMainManagers {
|
|
|
150
154
|
constructor(managers:ODMainManagers,project:ODProjectType){
|
|
151
155
|
this.project = project
|
|
152
156
|
this.versions = managers.versions
|
|
153
|
-
this.versions.add(ODVersion.fromString("opendiscord:api","v0.3.
|
|
157
|
+
this.versions.add(ODVersion.fromString("opendiscord:api","v0.3.4"))
|
|
154
158
|
this.versions.add(ODVersion.fromString("opendiscord:livestatus","v2.0.0"))
|
|
155
159
|
|
|
156
160
|
this.debugfile = managers.debugfile
|
|
@@ -179,6 +183,7 @@ export abstract class ODMain implements ODMainManagers {
|
|
|
179
183
|
this.statistics = managers.statistics
|
|
180
184
|
this.code = managers.code
|
|
181
185
|
this.posts = managers.posts
|
|
186
|
+
this.states = managers.states
|
|
182
187
|
|
|
183
188
|
this.sharedFuses = managers.sharedFuses
|
|
184
189
|
this.env = managers.env
|
|
@@ -123,7 +123,7 @@ export class ODClientManager<SlashIdList extends ODSlashCommandManagerIdConstrai
|
|
|
123
123
|
}
|
|
124
124
|
/**Get all servers the bot is part of. */
|
|
125
125
|
async getGuilds(): Promise<discord.Guild[]> {
|
|
126
|
-
if (!this.initiated) throw new ODSystemError("Client isn't initiated yet
|
|
126
|
+
if (!this.initiated) throw new ODSystemError("ODClientManager() => Unable to use this method. Client isn't initiated yet.")
|
|
127
127
|
if (!this.ready) throw new ODSystemError("Client isn't ready yet!")
|
|
128
128
|
|
|
129
129
|
return this.client.guilds.cache.map((guild) => guild)
|
|
@@ -146,15 +146,15 @@ export class ODClientManager<SlashIdList extends ODSlashCommandManagerIdConstrai
|
|
|
146
146
|
/**Log-in with a discord auth token. Rejects returns `false` using 'softErrors' on failure. */
|
|
147
147
|
login(softErrors?:boolean): Promise<boolean> {
|
|
148
148
|
return new Promise(async (resolve,reject) => {
|
|
149
|
-
if (!this.initiated) reject("Client isn't initiated yet
|
|
150
|
-
if (!this.token) reject("
|
|
149
|
+
if (!this.initiated) reject("ODClientManager.login() => Unable to use this method. Client isn't initiated yet.")
|
|
150
|
+
if (!this.token) reject("ODClientManager.login() => Unable to login, client does not have a token.")
|
|
151
151
|
|
|
152
152
|
try {
|
|
153
153
|
this.client.once("clientReady",async () => {
|
|
154
154
|
this.ready = true
|
|
155
155
|
|
|
156
156
|
//set slashCommandManager & contextMenuManager to client applicationCommandManager
|
|
157
|
-
if (!this.client.application) throw new ODSystemError("
|
|
157
|
+
if (!this.client.application) throw new ODSystemError("ODClientManager.login() => Unable to fetch client application for slashCommand & contextMenu managers.")
|
|
158
158
|
this.slashCommands.commandManager = this.client.application.commands
|
|
159
159
|
this.contextMenus.commandManager = this.client.application.commands
|
|
160
160
|
this.autocompletes.commandManager = this.client.application.commands
|
|
@@ -177,10 +177,10 @@ export class ODClientManager<SlashIdList extends ODSlashCommandManagerIdConstrai
|
|
|
177
177
|
}
|
|
178
178
|
})
|
|
179
179
|
}
|
|
180
|
-
/**A simplified shortcut to get a `discord.User
|
|
180
|
+
/**A simplified shortcut to get a `discord.User`. */
|
|
181
181
|
async fetchUser(id:string): Promise<discord.User|null> {
|
|
182
|
-
if (!this.initiated) throw new ODSystemError("Client isn't initiated yet
|
|
183
|
-
if (!this.ready) throw new ODSystemError("Client isn't ready yet
|
|
182
|
+
if (!this.initiated) throw new ODSystemError("ODClientManager.fetchUser() => Unable to use this method. Client isn't initiated yet.")
|
|
183
|
+
if (!this.ready) throw new ODSystemError("ODClientManager.fetchUser() => Unable to use this method. Client isn't ready and logged in yet.")
|
|
184
184
|
|
|
185
185
|
try{
|
|
186
186
|
return await this.client.users.fetch(id)
|
|
@@ -188,10 +188,10 @@ export class ODClientManager<SlashIdList extends ODSlashCommandManagerIdConstrai
|
|
|
188
188
|
return null
|
|
189
189
|
}
|
|
190
190
|
}
|
|
191
|
-
/**A simplified shortcut to get a `discord.Guild
|
|
191
|
+
/**A simplified shortcut to get a `discord.Guild`. */
|
|
192
192
|
async fetchGuild(id:string): Promise<discord.Guild|null> {
|
|
193
|
-
if (!this.initiated) throw new ODSystemError("Client isn't initiated yet
|
|
194
|
-
if (!this.ready) throw new ODSystemError("Client isn't ready yet
|
|
193
|
+
if (!this.initiated) throw new ODSystemError("ODClientManager.fetchGuild() => Unable to use this method. Client isn't initiated yet.")
|
|
194
|
+
if (!this.ready) throw new ODSystemError("ODClientManager.fetchGuild() => Unable to use this method. Client isn't ready and logged in yet.")
|
|
195
195
|
|
|
196
196
|
try{
|
|
197
197
|
return await this.client.guilds.fetch(id)
|
|
@@ -199,10 +199,10 @@ export class ODClientManager<SlashIdList extends ODSlashCommandManagerIdConstrai
|
|
|
199
199
|
return null
|
|
200
200
|
}
|
|
201
201
|
}
|
|
202
|
-
/**A simplified shortcut to get a `discord.Channel
|
|
202
|
+
/**A simplified shortcut to get a `discord.Channel`. */
|
|
203
203
|
async fetchChannel(id:string): Promise<discord.Channel|null> {
|
|
204
|
-
if (!this.initiated) throw new ODSystemError("Client isn't initiated yet
|
|
205
|
-
if (!this.ready) throw new ODSystemError("Client isn't ready yet
|
|
204
|
+
if (!this.initiated) throw new ODSystemError("ODClientManager.fetchChannel() => Unable to use this method. Client isn't initiated yet.")
|
|
205
|
+
if (!this.ready) throw new ODSystemError("ODClientManager.fetchChannel() => Unable to use this method. Client isn't ready and logged in yet.")
|
|
206
206
|
|
|
207
207
|
try{
|
|
208
208
|
return await this.client.channels.fetch(id)
|
|
@@ -210,10 +210,23 @@ export class ODClientManager<SlashIdList extends ODSlashCommandManagerIdConstrai
|
|
|
210
210
|
return null
|
|
211
211
|
}
|
|
212
212
|
}
|
|
213
|
-
/**A simplified shortcut to get a `discord.
|
|
213
|
+
/**A simplified shortcut to get a `discord.TextChannel` (guild or DM). */
|
|
214
|
+
async fetchTextChannel(id:string): Promise<discord.TextChannel|discord.DMChannel|discord.PartialDMChannel|null> {
|
|
215
|
+
if (!this.initiated) throw new ODSystemError("ODClientManager.fetchTextChannel() => Unable to use this method. Client isn't initiated yet.")
|
|
216
|
+
if (!this.ready) throw new ODSystemError("ODClientManager.fetchTextChannel() => Unable to use this method. Client isn't ready and logged in yet.")
|
|
217
|
+
|
|
218
|
+
try{
|
|
219
|
+
const channel = await this.client.channels.fetch(id)
|
|
220
|
+
if (!channel || (channel.type != discord.ChannelType.GuildText && channel.type != discord.ChannelType.DM)) return null
|
|
221
|
+
return channel
|
|
222
|
+
}catch{
|
|
223
|
+
return null
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
/**A simplified shortcut to get a `discord.GuildBasedChannel`. */
|
|
214
227
|
async fetchGuildChannel(guildId:string|discord.Guild, id:string): Promise<discord.GuildBasedChannel|null> {
|
|
215
|
-
if (!this.initiated) throw new ODSystemError("Client isn't initiated yet
|
|
216
|
-
if (!this.ready) throw new ODSystemError("Client isn't ready yet
|
|
228
|
+
if (!this.initiated) throw new ODSystemError("ODClientManager.fetchGuildChannel() => Unable to use this method. Client isn't initiated yet.")
|
|
229
|
+
if (!this.ready) throw new ODSystemError("ODClientManager.fetchGuildChannel() => Unable to use this method. Client isn't ready and logged in yet.")
|
|
217
230
|
|
|
218
231
|
try{
|
|
219
232
|
const guild = (guildId instanceof discord.Guild) ? guildId : await this.fetchGuild(guildId)
|
|
@@ -224,10 +237,10 @@ export class ODClientManager<SlashIdList extends ODSlashCommandManagerIdConstrai
|
|
|
224
237
|
return null
|
|
225
238
|
}
|
|
226
239
|
}
|
|
227
|
-
/**A simplified shortcut to get a `discord.TextChannel
|
|
240
|
+
/**A simplified shortcut to get a `discord.TextChannel`. */
|
|
228
241
|
async fetchGuildTextChannel(guildId:string|discord.Guild, id:string): Promise<discord.TextChannel|null> {
|
|
229
|
-
if (!this.initiated) throw new ODSystemError("Client isn't initiated yet
|
|
230
|
-
if (!this.ready) throw new ODSystemError("Client isn't ready yet
|
|
242
|
+
if (!this.initiated) throw new ODSystemError("ODClientManager.fetchGuildTextChannel() => Unable to use this method. Client isn't initiated yet.")
|
|
243
|
+
if (!this.ready) throw new ODSystemError("ODClientManager.fetchGuildTextChannel() => Unable to use this method. Client isn't ready and logged in yet.")
|
|
231
244
|
|
|
232
245
|
try{
|
|
233
246
|
const guild = (guildId instanceof discord.Guild) ? guildId : await this.fetchGuild(guildId)
|
|
@@ -239,10 +252,10 @@ export class ODClientManager<SlashIdList extends ODSlashCommandManagerIdConstrai
|
|
|
239
252
|
return null
|
|
240
253
|
}
|
|
241
254
|
}
|
|
242
|
-
/**A simplified shortcut to get a `discord.CategoryChannel
|
|
255
|
+
/**A simplified shortcut to get a `discord.CategoryChannel`. */
|
|
243
256
|
async fetchGuildCategoryChannel(guildId:string|discord.Guild, id:string): Promise<discord.CategoryChannel|null> {
|
|
244
|
-
if (!this.initiated) throw new ODSystemError("Client isn't initiated yet
|
|
245
|
-
if (!this.ready) throw new ODSystemError("Client isn't ready yet
|
|
257
|
+
if (!this.initiated) throw new ODSystemError("ODClientManager.fetchGuildCategoryChannel() => Unable to use this method. Client isn't initiated yet.")
|
|
258
|
+
if (!this.ready) throw new ODSystemError("ODClientManager.fetchGuildCategoryChannel() => Unable to use this method. Client isn't ready and logged in yet.")
|
|
246
259
|
|
|
247
260
|
try{
|
|
248
261
|
const guild = (guildId instanceof discord.Guild) ? guildId : await this.fetchGuild(guildId)
|
|
@@ -254,12 +267,11 @@ export class ODClientManager<SlashIdList extends ODSlashCommandManagerIdConstrai
|
|
|
254
267
|
return null
|
|
255
268
|
}
|
|
256
269
|
}
|
|
257
|
-
/**A simplified shortcut to get a `discord.GuildMember
|
|
270
|
+
/**A simplified shortcut to get a `discord.GuildMember`. */
|
|
258
271
|
async fetchGuildMember(guildId:string|discord.Guild, id:string): Promise<discord.GuildMember|null> {
|
|
259
|
-
if (!this.initiated) throw new ODSystemError("Client isn't initiated yet
|
|
260
|
-
if (!this.ready) throw new ODSystemError("Client isn't ready yet
|
|
261
|
-
|
|
262
|
-
|
|
272
|
+
if (!this.initiated) throw new ODSystemError("ODClientManager.fetchGuildMember() => Unable to use this method. Client isn't initiated yet.")
|
|
273
|
+
if (!this.ready) throw new ODSystemError("ODClientManager.fetchGuildMember() => Unable to use this method. Client isn't ready and logged in yet.")
|
|
274
|
+
|
|
263
275
|
try{
|
|
264
276
|
const guild = (guildId instanceof discord.Guild) ? guildId : await this.fetchGuild(guildId)
|
|
265
277
|
if (!guild) return null
|
|
@@ -268,12 +280,11 @@ export class ODClientManager<SlashIdList extends ODSlashCommandManagerIdConstrai
|
|
|
268
280
|
return null
|
|
269
281
|
}
|
|
270
282
|
}
|
|
271
|
-
/**A simplified shortcut to get a `discord.Role
|
|
283
|
+
/**A simplified shortcut to get a `discord.Role`. */
|
|
272
284
|
async fetchGuildRole(guildId:string|discord.Guild, id:string): Promise<discord.Role|null> {
|
|
273
|
-
if (!this.initiated) throw new ODSystemError("Client isn't initiated yet
|
|
274
|
-
if (!this.ready) throw new ODSystemError("Client isn't ready yet
|
|
275
|
-
|
|
276
|
-
|
|
285
|
+
if (!this.initiated) throw new ODSystemError("ODClientManager.fetchGuildRole() => Unable to use this method. Client isn't initiated yet.")
|
|
286
|
+
if (!this.ready) throw new ODSystemError("ODClientManager.fetchGuildRole() => Unable to use this method. Client isn't ready and logged in yet.")
|
|
287
|
+
|
|
277
288
|
try{
|
|
278
289
|
const guild = (guildId instanceof discord.Guild) ? guildId : await this.fetchGuild(guildId)
|
|
279
290
|
if (!guild) return null
|
|
@@ -282,30 +293,23 @@ export class ODClientManager<SlashIdList extends ODSlashCommandManagerIdConstrai
|
|
|
282
293
|
return null
|
|
283
294
|
}
|
|
284
295
|
}
|
|
285
|
-
/**A simplified shortcut to get a `discord.Message
|
|
286
|
-
async
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
if (!this.initiated) throw new ODSystemError("Client isn't initiated yet!")
|
|
290
|
-
if (!this.ready) throw new ODSystemError("Client isn't ready yet!")
|
|
296
|
+
/**A simplified shortcut to get a `discord.Message`. */
|
|
297
|
+
async fetchChannelMessage(channelId:string|discord.TextChannel|discord.DMChannel, id:string): Promise<discord.Message<boolean>|null> {
|
|
298
|
+
if (!this.initiated) throw new ODSystemError("ODClientManager.fetchChannelMessage() => Unable to use this method. Client isn't initiated yet.")
|
|
299
|
+
if (!this.ready) throw new ODSystemError("ODClientManager.fetchChannelMessage() => Unable to use this method. Client isn't ready and logged in yet.")
|
|
291
300
|
|
|
292
301
|
try{
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
}else if (!(guildId instanceof discord.TextChannel) && id){
|
|
297
|
-
const channel = (channelId instanceof discord.TextChannel) ? channelId : await this.fetchGuildTextChannel(guildId,channelId)
|
|
298
|
-
if (!channel) return null
|
|
299
|
-
return await channel.messages.fetch(id)
|
|
300
|
-
}else return null
|
|
302
|
+
const channel = (channelId instanceof discord.TextChannel || channelId instanceof discord.DMChannel) ? channelId : await this.fetchTextChannel(channelId)
|
|
303
|
+
if (!channel) return null
|
|
304
|
+
return await channel.messages.fetch(id)
|
|
301
305
|
}catch{
|
|
302
306
|
return null
|
|
303
307
|
}
|
|
304
308
|
}
|
|
305
|
-
/**A simplified shortcut to send a DM to a user
|
|
309
|
+
/**A simplified shortcut to send a DM to a user. */
|
|
306
310
|
async sendUserDm(user:string|discord.User, build:ODMessageBuildResult|ODMessageComponentBuildResult): Promise<ODResponderSendResult<false>> {
|
|
307
|
-
if (!this.initiated) throw new ODSystemError("Client isn't initiated yet
|
|
308
|
-
if (!this.ready) throw new ODSystemError("Client isn't ready yet
|
|
311
|
+
if (!this.initiated) throw new ODSystemError("ODClientManager.sendUserDm() => Unable to use this method. Client isn't initiated yet.")
|
|
312
|
+
if (!this.ready) throw new ODSystemError("ODClientManager.sendUserDm() => Unable to use this method. Client isn't ready and logged in yet.")
|
|
309
313
|
|
|
310
314
|
try{
|
|
311
315
|
const msgFlags: number[] = []
|
|
@@ -325,26 +329,26 @@ export class ODClientManager<SlashIdList extends ODSlashCommandManagerIdConstrai
|
|
|
325
329
|
const finalMessage = Object.assign(msgData,{flags:msgFlags})
|
|
326
330
|
|
|
327
331
|
if (user instanceof discord.User){
|
|
328
|
-
if (user.bot) return {success:false
|
|
332
|
+
if (user.bot) return {success:false}
|
|
329
333
|
const channel = await user.createDM()
|
|
330
334
|
const msg = await channel.send(finalMessage)
|
|
331
335
|
return {success:true,message:msg}
|
|
332
336
|
}else{
|
|
333
337
|
const newUser = await this.fetchUser(user)
|
|
334
338
|
if (!newUser) throw new Error()
|
|
335
|
-
if (newUser.bot) return {success:false
|
|
339
|
+
if (newUser.bot) return {success:false}
|
|
336
340
|
const channel = await newUser.createDM()
|
|
337
341
|
const msg = await channel.send(finalMessage)
|
|
338
342
|
return {success:true,message:msg}
|
|
339
343
|
}
|
|
340
344
|
}catch{
|
|
341
345
|
try{
|
|
342
|
-
this.debug.console.log("Failed to send DM
|
|
346
|
+
this.debug.console.log("ODClientManager.sendUserDm() => Failed to send DM. User may have DMs disabled for non-friends. ","warning",[
|
|
343
347
|
{key:"id",value:(user instanceof discord.User ? user.id : user)},
|
|
344
348
|
{key:"message-build",value:build.id.value}
|
|
345
349
|
])
|
|
346
350
|
}catch{}
|
|
347
|
-
return {success:false
|
|
351
|
+
return {success:false}
|
|
348
352
|
}
|
|
349
353
|
}
|
|
350
354
|
}
|
|
@@ -417,7 +421,7 @@ export class ODClientActivityManager {
|
|
|
417
421
|
|
|
418
422
|
/**Update the client status */
|
|
419
423
|
private updateClientActivity(type:ODClientActivityType,text:string){
|
|
420
|
-
if (!this.client.client.user) throw new ODSystemError("Couldn't set client status: client.user
|
|
424
|
+
if (!this.client.client.user) throw new ODSystemError("ODClientActivityManager.updateClientActivity() => Couldn't set client status: client.user is 'undefined'.")
|
|
421
425
|
if (type == false){
|
|
422
426
|
this.client.client.user.setActivity()
|
|
423
427
|
return
|
|
@@ -217,7 +217,9 @@ export class ODError {
|
|
|
217
217
|
}
|
|
218
218
|
/**Create a more-detailed, non-colored version of this error to store it in the `debug.txt` file! */
|
|
219
219
|
toDebugString(){
|
|
220
|
-
|
|
220
|
+
const date = new Date()
|
|
221
|
+
const dstring = `${date.getDate()}/${date.getMonth()+1}/${date.getFullYear()} ${date.getHours()}:${date.getMinutes()}:${date.getSeconds()}`
|
|
222
|
+
return "["+dstring+" UNKNOWN OPENDISCORD ERROR]: "+this.error.message+" | Error Origin: "+this.origin+" | Stacktrace:\n"+this.error.stack
|
|
221
223
|
}
|
|
222
224
|
}
|
|
223
225
|
|
|
@@ -89,7 +89,7 @@ export abstract class ODDatabase<IdList extends ODDatabaseIdConstraint = ODDatab
|
|
|
89
89
|
abstract get(category:string, key:string): ODOptionalPromise<ODValidJsonType|undefined>
|
|
90
90
|
abstract get(category:string, key:string): ODOptionalPromise<ODValidJsonType|undefined>
|
|
91
91
|
|
|
92
|
-
/**Delete a specific category & key in the database */
|
|
92
|
+
/**Delete a specific category & key in the database. Returns `true` when deleted. */
|
|
93
93
|
abstract delete<CategoryId extends keyof ODNoGeneric<IdList>>(category:CategoryId, key:string): ODOptionalPromise<boolean>
|
|
94
94
|
abstract delete(category:string, key:string): ODOptionalPromise<boolean>
|
|
95
95
|
abstract delete(category:string, key:string): ODOptionalPromise<boolean>
|
package/src/api/modules/fuse.ts
CHANGED
|
@@ -142,9 +142,6 @@ export interface ODSharedFuseList {
|
|
|
142
142
|
/**Load the default Open Discord client activity initialization (& status refresh). */
|
|
143
143
|
clientActivityInitiating:boolean,
|
|
144
144
|
|
|
145
|
-
/**Load the default Open Discord priority levels. */
|
|
146
|
-
priorityLoading:boolean,
|
|
147
|
-
|
|
148
145
|
/**Load the default Open Discord slash commands. */
|
|
149
146
|
slashCommandLoading:boolean,
|
|
150
147
|
/**Load the default Open Discord slash command registerer (register slash cmds in discord). */
|
|
@@ -164,6 +161,11 @@ export interface ODSharedFuseList {
|
|
|
164
161
|
/**Load the default Open Discord text commands. */
|
|
165
162
|
textCommandLoading:boolean,
|
|
166
163
|
|
|
164
|
+
/**Load the default Open Discord message states. */
|
|
165
|
+
stateLoading:boolean,
|
|
166
|
+
/**Initiate the default Open Discord message states. */
|
|
167
|
+
stateInitiating:boolean,
|
|
168
|
+
|
|
167
169
|
/**Load the default Open Discord button builders. */
|
|
168
170
|
buttonBuildersLoading:boolean,
|
|
169
171
|
/**Load the default Open Discord dropdown builders. */
|
|
@@ -177,6 +179,13 @@ export interface ODSharedFuseList {
|
|
|
177
179
|
/**Load the default Open Discord modal builders. */
|
|
178
180
|
modalBuildersLoading:boolean,
|
|
179
181
|
|
|
182
|
+
/**Load the default Open Discord shared components. */
|
|
183
|
+
sharedComponentsLoading:boolean,
|
|
184
|
+
/**Load the default Open Discord message components. */
|
|
185
|
+
messageComponentsLoading:boolean,
|
|
186
|
+
/**Load the default Open Discord modal components. */
|
|
187
|
+
modalComponentsLoading:boolean,
|
|
188
|
+
|
|
180
189
|
/**Load the default Open Discord command responders. */
|
|
181
190
|
commandRespondersLoading:boolean,
|
|
182
191
|
/**Load the default Open Discord button responders. */
|
|
@@ -291,8 +300,6 @@ export class ODSharedFuseManager extends ODFuseManager<ODSharedFuseList> {
|
|
|
291
300
|
clientActivityLoading:true,
|
|
292
301
|
clientActivityInitiating:true,
|
|
293
302
|
|
|
294
|
-
priorityLoading:true,
|
|
295
|
-
|
|
296
303
|
slashCommandLoading:true,
|
|
297
304
|
slashCommandRegistering:true,
|
|
298
305
|
forceSlashCommandRegistration:false,
|
|
@@ -303,6 +310,9 @@ export class ODSharedFuseManager extends ODFuseManager<ODSharedFuseList> {
|
|
|
303
310
|
allowContextMenuRemoval:true,
|
|
304
311
|
textCommandLoading:true,
|
|
305
312
|
|
|
313
|
+
stateLoading:true,
|
|
314
|
+
stateInitiating:true,
|
|
315
|
+
|
|
306
316
|
buttonBuildersLoading:true,
|
|
307
317
|
dropdownBuildersLoading:true,
|
|
308
318
|
fileBuildersLoading:true,
|
|
@@ -310,6 +320,10 @@ export class ODSharedFuseManager extends ODFuseManager<ODSharedFuseList> {
|
|
|
310
320
|
messageBuildersLoading:true,
|
|
311
321
|
modalBuildersLoading:true,
|
|
312
322
|
|
|
323
|
+
sharedComponentsLoading:true,
|
|
324
|
+
messageComponentsLoading:true,
|
|
325
|
+
modalComponentsLoading:true,
|
|
326
|
+
|
|
313
327
|
commandRespondersLoading:true,
|
|
314
328
|
buttonRespondersLoading:true,
|
|
315
329
|
dropdownRespondersLoading:true,
|
package/src/api/modules/post.ts
CHANGED
|
@@ -107,13 +107,13 @@ export class ODPost<ChannelType extends discord.GuildBasedChannel> extends ODMan
|
|
|
107
107
|
}
|
|
108
108
|
/**Send a message to this channel using the Open Discord builder system */
|
|
109
109
|
async send(build:ODMessageBuildResult|ODMessageComponentBuildResult): Promise<ODResponderSendResult<true>> {
|
|
110
|
-
if (!this.channel || !this.channel.isTextBased()) return {success:false
|
|
110
|
+
if (!this.channel || !this.channel.isTextBased()) return {success:false}
|
|
111
111
|
try{
|
|
112
112
|
const finalMessage = this.getMessageFromBuildResult(build,"message")
|
|
113
113
|
const sent = await this.channel.send(finalMessage)
|
|
114
114
|
return {success:true,message:sent}
|
|
115
115
|
}catch{
|
|
116
|
-
return {success:false
|
|
116
|
+
return {success:false}
|
|
117
117
|
}
|
|
118
118
|
}
|
|
119
119
|
/**Get the final `messageCreateOptions` from a returned build result from builders/components. */
|