@zhin.js/adapter-discord 5.0.2 → 5.0.3
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/CHANGELOG.md +41 -0
- package/README.md +46 -77
- package/adapters/discord.ts +46 -0
- package/agent/tools/add_role.ts +2 -2
- package/agent/tools/create_thread.ts +2 -2
- package/agent/tools/forum_post.ts +2 -2
- package/agent/tools/list_roles.ts +2 -2
- package/agent/tools/react.ts +2 -2
- package/agent/tools/remove_role.ts +2 -2
- package/agent/tools/send_embed.ts +2 -2
- package/lib/discord-agent-deps.d.ts +35 -0
- package/lib/discord-agent-deps.js +32 -0
- package/lib/endpoint.d.ts +71 -0
- package/lib/endpoint.js +355 -0
- package/lib/gateway.d.ts +122 -0
- package/lib/gateway.js +235 -0
- package/lib/index.d.ts +6 -0
- package/lib/index.js +6 -0
- package/lib/platform-permit.d.ts +15 -0
- package/lib/{src/platform-permit.js → platform-permit.js} +1 -2
- package/lib/protocol.d.ts +135 -0
- package/lib/protocol.js +234 -0
- package/lib/webhook.d.ts +13 -0
- package/lib/webhook.js +86 -0
- package/package.json +43 -36
- package/plugin.ts +13 -0
- package/schema.json +63 -0
- package/src/discord-agent-deps.ts +68 -11
- package/src/endpoint.ts +385 -1167
- package/src/gateway.ts +337 -0
- package/src/index.ts +56 -157
- package/src/platform-permit.ts +1 -1
- package/src/protocol.ts +392 -0
- package/src/webhook.ts +121 -0
- package/client/Dashboard.tsx +0 -195
- package/client/index.tsx +0 -11
- package/client/tsconfig.json +0 -7
- package/client/utils/api.ts +0 -30
- package/dist/index.js +0 -29
- package/lib/agent/tools/add_role.js +0 -22
- package/lib/agent/tools/add_role.js.map +0 -1
- package/lib/agent/tools/create_thread.js +0 -23
- package/lib/agent/tools/create_thread.js.map +0 -1
- package/lib/agent/tools/forum_post.js +0 -22
- package/lib/agent/tools/forum_post.js.map +0 -1
- package/lib/agent/tools/list_roles.js +0 -20
- package/lib/agent/tools/list_roles.js.map +0 -1
- package/lib/agent/tools/react.js +0 -20
- package/lib/agent/tools/react.js.map +0 -1
- package/lib/agent/tools/remove_role.js +0 -22
- package/lib/agent/tools/remove_role.js.map +0 -1
- package/lib/agent/tools/send_embed.js +0 -40
- package/lib/agent/tools/send_embed.js.map +0 -1
- package/lib/src/adapter.js +0 -96
- package/lib/src/adapter.js.map +0 -1
- package/lib/src/discord-agent-deps.js +0 -10
- package/lib/src/discord-agent-deps.js.map +0 -1
- package/lib/src/endpoint-interactions.js +0 -284
- package/lib/src/endpoint-interactions.js.map +0 -1
- package/lib/src/endpoint.js +0 -1093
- package/lib/src/endpoint.js.map +0 -1
- package/lib/src/index.js +0 -159
- package/lib/src/index.js.map +0 -1
- package/lib/src/platform-permit.js.map +0 -1
- package/lib/src/segment-mapper.js +0 -2
- package/lib/src/segment-mapper.js.map +0 -1
- package/lib/src/types.js +0 -2
- package/lib/src/types.js.map +0 -1
- package/plugin.yml +0 -3
- package/src/adapter.ts +0 -108
- package/src/endpoint-interactions.ts +0 -354
- package/src/segment-mapper.ts +0 -1
- package/src/types.ts +0 -60
package/lib/endpoint.js
ADDED
|
@@ -0,0 +1,355 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DiscordEndpoint — lifecycle, outbound, admit, gateway / interactions modes, agent tool surface.
|
|
3
|
+
*/
|
|
4
|
+
import { ChannelType } from 'discord.js';
|
|
5
|
+
import { formatCompact, getLogger } from '@zhin.js/logger';
|
|
6
|
+
import { registerDiscordAgentEndpoint } from './discord-agent-deps.js';
|
|
7
|
+
import { connectDiscordGatewayClient, defaultCreateClient, DEFAULT_INTENTS, resolveSenderRole, toMessageCreateOptions, } from './gateway.js';
|
|
8
|
+
import { formatButtonContent, formatInboundContent, formatOutboundBody, senderDisplayName, } from './protocol.js';
|
|
9
|
+
import { registerDiscordInteractionRoutes } from './webhook.js';
|
|
10
|
+
const DISCORD_API = 'https://discord.com/api/v10';
|
|
11
|
+
const logger = getLogger('discord');
|
|
12
|
+
export class DiscordGatewayEndpoint {
|
|
13
|
+
#options;
|
|
14
|
+
#createClient;
|
|
15
|
+
#client = null;
|
|
16
|
+
#open = false;
|
|
17
|
+
#started = false;
|
|
18
|
+
#unregisterAgent;
|
|
19
|
+
#messageChannelMap = new Map();
|
|
20
|
+
constructor(options) {
|
|
21
|
+
this.#options = options;
|
|
22
|
+
this.#createClient = options.createClient ?? defaultCreateClient;
|
|
23
|
+
}
|
|
24
|
+
async start() {
|
|
25
|
+
if (this.#started)
|
|
26
|
+
return;
|
|
27
|
+
this.#started = true;
|
|
28
|
+
try {
|
|
29
|
+
this.#unregisterAgent = registerDiscordAgentEndpoint(this.#options.config.name, this);
|
|
30
|
+
const intents = this.#options.config.intents?.length
|
|
31
|
+
? [...this.#options.config.intents]
|
|
32
|
+
: DEFAULT_INTENTS;
|
|
33
|
+
this.#client = this.#createClient(intents);
|
|
34
|
+
await connectDiscordGatewayClient(this.#client, this.#options.config, {
|
|
35
|
+
onMessage: (msg) => this.admit(msg),
|
|
36
|
+
onButton: (interaction) => this.admitButton(interaction),
|
|
37
|
+
});
|
|
38
|
+
logger.info(formatCompact({
|
|
39
|
+
op: 'connect',
|
|
40
|
+
endpoint: this.#options.config.name,
|
|
41
|
+
mode: 'gateway',
|
|
42
|
+
user: this.#client.user?.tag,
|
|
43
|
+
}));
|
|
44
|
+
}
|
|
45
|
+
catch (error) {
|
|
46
|
+
await this.stop();
|
|
47
|
+
logger.error('Failed to connect Discord gateway:', error);
|
|
48
|
+
throw error;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
open() {
|
|
52
|
+
this.#open = true;
|
|
53
|
+
}
|
|
54
|
+
close() {
|
|
55
|
+
this.#open = false;
|
|
56
|
+
}
|
|
57
|
+
async stop() {
|
|
58
|
+
this.#open = false;
|
|
59
|
+
this.#unregisterAgent?.();
|
|
60
|
+
this.#unregisterAgent = undefined;
|
|
61
|
+
if (this.#client) {
|
|
62
|
+
try {
|
|
63
|
+
this.#client.removeAllListeners();
|
|
64
|
+
await this.#client.destroy();
|
|
65
|
+
}
|
|
66
|
+
catch {
|
|
67
|
+
/* ignore */
|
|
68
|
+
}
|
|
69
|
+
this.#client = null;
|
|
70
|
+
}
|
|
71
|
+
this.#started = false;
|
|
72
|
+
logger.debug(formatCompact({ op: 'disconnect', endpoint: this.#options.config.name }));
|
|
73
|
+
}
|
|
74
|
+
async send({ target, payload }) {
|
|
75
|
+
const body = formatOutboundBody(payload);
|
|
76
|
+
const messageId = await this.#sendBody(target, body);
|
|
77
|
+
this.#messageChannelMap.set(messageId, target);
|
|
78
|
+
logger.debug(formatCompact({
|
|
79
|
+
op: 'discord_send',
|
|
80
|
+
endpoint: this.#options.config.name,
|
|
81
|
+
target,
|
|
82
|
+
messageId,
|
|
83
|
+
}));
|
|
84
|
+
return messageId;
|
|
85
|
+
}
|
|
86
|
+
/** Test / internal: admit a message when open. */
|
|
87
|
+
admit(msg) {
|
|
88
|
+
if (!this.#open)
|
|
89
|
+
return;
|
|
90
|
+
if (msg.authorBot)
|
|
91
|
+
return;
|
|
92
|
+
this.#messageChannelMap.set(msg.id, msg.channelId);
|
|
93
|
+
void this.#options.gateway.receive({
|
|
94
|
+
adapter: this.#options.id,
|
|
95
|
+
target: msg.channelId,
|
|
96
|
+
content: formatInboundContent(msg),
|
|
97
|
+
sender: senderDisplayName(msg),
|
|
98
|
+
id: msg.id,
|
|
99
|
+
metadata: Object.freeze({
|
|
100
|
+
endpoint: this.#options.config.name,
|
|
101
|
+
channelKind: msg.channelKind,
|
|
102
|
+
userId: msg.authorId,
|
|
103
|
+
guildId: msg.guildId,
|
|
104
|
+
permissions: msg.permissionTokens,
|
|
105
|
+
role: resolveSenderRole(msg),
|
|
106
|
+
...(msg.mentionedBot ? { mentioned: true } : {}),
|
|
107
|
+
}),
|
|
108
|
+
}).catch((err) => {
|
|
109
|
+
logger.warn(formatCompact({
|
|
110
|
+
op: 'discord_gateway_receive_failed',
|
|
111
|
+
target: msg.channelId,
|
|
112
|
+
error: err instanceof Error ? err.message : String(err),
|
|
113
|
+
}));
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
/** Test / internal: admit a button interaction when open. */
|
|
117
|
+
admitButton(interaction) {
|
|
118
|
+
if (!this.#open)
|
|
119
|
+
return;
|
|
120
|
+
void this.#options.gateway.receive({
|
|
121
|
+
adapter: this.#options.id,
|
|
122
|
+
target: interaction.channelId,
|
|
123
|
+
content: formatButtonContent(interaction),
|
|
124
|
+
sender: interaction.userName,
|
|
125
|
+
id: interaction.id,
|
|
126
|
+
metadata: Object.freeze({
|
|
127
|
+
endpoint: this.#options.config.name,
|
|
128
|
+
eventType: 'button',
|
|
129
|
+
payload: interaction.customId,
|
|
130
|
+
sourceMessageId: interaction.sourceMessageId,
|
|
131
|
+
}),
|
|
132
|
+
}).catch((err) => {
|
|
133
|
+
logger.warn(formatCompact({
|
|
134
|
+
op: 'discord_gateway_receive_failed',
|
|
135
|
+
target: interaction.channelId,
|
|
136
|
+
error: err instanceof Error ? err.message : String(err),
|
|
137
|
+
}));
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
// ── Agent tool surface ──────────────────────────────────────────────
|
|
141
|
+
async addRole(guildId, userId, roleId) {
|
|
142
|
+
const member = await this.#fetchMember(guildId, userId);
|
|
143
|
+
await member.roles.add(roleId);
|
|
144
|
+
return true;
|
|
145
|
+
}
|
|
146
|
+
async removeRole(guildId, userId, roleId) {
|
|
147
|
+
const member = await this.#fetchMember(guildId, userId);
|
|
148
|
+
await member.roles.remove(roleId);
|
|
149
|
+
return true;
|
|
150
|
+
}
|
|
151
|
+
async getRoles(guildId) {
|
|
152
|
+
const guild = await this.#requireClient().guilds.fetch(guildId);
|
|
153
|
+
await guild.roles.fetch();
|
|
154
|
+
const cache = guild.roles.cache;
|
|
155
|
+
return [...cache.values()].map((role) => ({
|
|
156
|
+
id: role.id,
|
|
157
|
+
name: role.name,
|
|
158
|
+
color: role.hexColor,
|
|
159
|
+
position: role.position,
|
|
160
|
+
permissions: role.permissions.bitfield.toString(),
|
|
161
|
+
}));
|
|
162
|
+
}
|
|
163
|
+
async createThread(channelId, name, messageId, autoArchiveDuration) {
|
|
164
|
+
const channel = await this.#requireClient().channels.fetch(channelId);
|
|
165
|
+
if (!channel || !('threads' in channel) || !channel.threads) {
|
|
166
|
+
throw new Error(`Channel ${channelId} 不支持创建帖子`);
|
|
167
|
+
}
|
|
168
|
+
const options = {
|
|
169
|
+
name,
|
|
170
|
+
autoArchiveDuration: autoArchiveDuration || 1440,
|
|
171
|
+
};
|
|
172
|
+
if (messageId)
|
|
173
|
+
options.startMessage = messageId;
|
|
174
|
+
return channel.threads.create(options);
|
|
175
|
+
}
|
|
176
|
+
async addReaction(channelId, messageId, emoji) {
|
|
177
|
+
const channel = await this.#requireClient().channels.fetch(channelId);
|
|
178
|
+
if (!channel?.isTextBased() || !channel.messages) {
|
|
179
|
+
throw new Error(`Channel ${channelId} 不是文本频道`);
|
|
180
|
+
}
|
|
181
|
+
const message = await channel.messages.fetch(messageId);
|
|
182
|
+
await message.react(emoji);
|
|
183
|
+
}
|
|
184
|
+
async sendEmbed(channelId, embedData) {
|
|
185
|
+
const body = { embeds: [embedData] };
|
|
186
|
+
const id = await this.#sendBody(channelId, body);
|
|
187
|
+
return { id };
|
|
188
|
+
}
|
|
189
|
+
async createForumPost(channelId, name, content, tags) {
|
|
190
|
+
const channel = await this.#requireClient().channels.fetch(channelId);
|
|
191
|
+
if (!channel || channel.type !== ChannelType.GuildForum || !channel.threads) {
|
|
192
|
+
throw new Error(`Channel ${channelId} 不是论坛频道`);
|
|
193
|
+
}
|
|
194
|
+
const options = {
|
|
195
|
+
name,
|
|
196
|
+
message: { content },
|
|
197
|
+
};
|
|
198
|
+
if (tags?.length && channel.availableTags?.length) {
|
|
199
|
+
const tagIds = channel.availableTags
|
|
200
|
+
.filter((t) => tags.includes(t.name))
|
|
201
|
+
.map((t) => t.id);
|
|
202
|
+
if (tagIds.length)
|
|
203
|
+
options.appliedTags = tagIds;
|
|
204
|
+
}
|
|
205
|
+
return channel.threads.create(options);
|
|
206
|
+
}
|
|
207
|
+
async kickMember(guildId, userId, reason) {
|
|
208
|
+
const member = await this.#fetchMember(guildId, userId);
|
|
209
|
+
await member.kick(reason);
|
|
210
|
+
return true;
|
|
211
|
+
}
|
|
212
|
+
async banMember(guildId, userId, reason) {
|
|
213
|
+
const guild = await this.#requireClient().guilds.fetch(guildId);
|
|
214
|
+
await guild.members.ban(userId, { reason });
|
|
215
|
+
return true;
|
|
216
|
+
}
|
|
217
|
+
async unbanMember(guildId, userId, reason) {
|
|
218
|
+
const guild = await this.#requireClient().guilds.fetch(guildId);
|
|
219
|
+
await guild.members.unban(userId, reason);
|
|
220
|
+
return true;
|
|
221
|
+
}
|
|
222
|
+
async timeoutMember(guildId, userId, duration = 600, reason) {
|
|
223
|
+
const member = await this.#fetchMember(guildId, userId);
|
|
224
|
+
await member.timeout(duration === 0 ? null : duration * 1000, reason);
|
|
225
|
+
return true;
|
|
226
|
+
}
|
|
227
|
+
async setNickname(guildId, userId, nickname) {
|
|
228
|
+
const member = await this.#fetchMember(guildId, userId);
|
|
229
|
+
await member.setNickname(nickname);
|
|
230
|
+
return true;
|
|
231
|
+
}
|
|
232
|
+
async getMembers(guildId, limit = 100) {
|
|
233
|
+
const guild = await this.#requireClient().guilds.fetch(guildId);
|
|
234
|
+
const members = await guild.members.fetch({ limit });
|
|
235
|
+
return [...members.values()].map((member) => ({
|
|
236
|
+
id: member.id,
|
|
237
|
+
username: member.user.username,
|
|
238
|
+
nickname: member.nickname,
|
|
239
|
+
roles: member.roles.cache.map((r) => r.id),
|
|
240
|
+
joined_at: member.joinedAt?.toISOString(),
|
|
241
|
+
}));
|
|
242
|
+
}
|
|
243
|
+
async getGuildInfo(guildId) {
|
|
244
|
+
const guild = await this.#requireClient().guilds.fetch(guildId);
|
|
245
|
+
return {
|
|
246
|
+
id: guild.id,
|
|
247
|
+
name: guild.name,
|
|
248
|
+
icon: guild.iconURL?.(),
|
|
249
|
+
owner_id: guild.ownerId,
|
|
250
|
+
member_count: guild.memberCount,
|
|
251
|
+
created_at: guild.createdAt?.toISOString(),
|
|
252
|
+
};
|
|
253
|
+
}
|
|
254
|
+
async #sendBody(channelId, body) {
|
|
255
|
+
const channel = await this.#requireClient().channels.fetch(channelId);
|
|
256
|
+
if (!channel || !channel.isTextBased() || !channel.send) {
|
|
257
|
+
throw new Error(`Channel ${channelId} is not a text channel`);
|
|
258
|
+
}
|
|
259
|
+
const options = await toMessageCreateOptions(body);
|
|
260
|
+
const result = await channel.send(options);
|
|
261
|
+
return result.id;
|
|
262
|
+
}
|
|
263
|
+
async #fetchMember(guildId, userId) {
|
|
264
|
+
const guild = await this.#requireClient().guilds.fetch(guildId);
|
|
265
|
+
return guild.members.fetch(userId);
|
|
266
|
+
}
|
|
267
|
+
#requireClient() {
|
|
268
|
+
if (!this.#client)
|
|
269
|
+
throw new Error('Discord client not connected');
|
|
270
|
+
return this.#client;
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
export class DiscordInteractionsEndpoint {
|
|
274
|
+
#options;
|
|
275
|
+
#fetch;
|
|
276
|
+
#routeReleases = [];
|
|
277
|
+
#open = false;
|
|
278
|
+
#started = false;
|
|
279
|
+
constructor(options) {
|
|
280
|
+
this.#options = options;
|
|
281
|
+
this.#fetch = options.fetch ?? globalThis.fetch;
|
|
282
|
+
}
|
|
283
|
+
get isOpen() {
|
|
284
|
+
return this.#open;
|
|
285
|
+
}
|
|
286
|
+
get config() {
|
|
287
|
+
return this.#options.config;
|
|
288
|
+
}
|
|
289
|
+
async start() {
|
|
290
|
+
if (this.#started)
|
|
291
|
+
return;
|
|
292
|
+
this.#started = true;
|
|
293
|
+
this.#routeReleases.push(...registerDiscordInteractionRoutes(this.#options.http, this));
|
|
294
|
+
logger.info(formatCompact({
|
|
295
|
+
op: 'connect',
|
|
296
|
+
endpoint: this.#options.config.name,
|
|
297
|
+
mode: 'interactions',
|
|
298
|
+
path: this.#options.config.interactionsPath,
|
|
299
|
+
}));
|
|
300
|
+
}
|
|
301
|
+
open() {
|
|
302
|
+
this.#open = true;
|
|
303
|
+
}
|
|
304
|
+
close() {
|
|
305
|
+
this.#open = false;
|
|
306
|
+
}
|
|
307
|
+
async stop() {
|
|
308
|
+
this.#open = false;
|
|
309
|
+
for (const release of this.#routeReleases.splice(0))
|
|
310
|
+
release();
|
|
311
|
+
this.#started = false;
|
|
312
|
+
logger.debug(formatCompact({ op: 'disconnect', endpoint: this.#options.config.name }));
|
|
313
|
+
}
|
|
314
|
+
async send({ target, payload }) {
|
|
315
|
+
const body = formatOutboundBody(payload);
|
|
316
|
+
const response = await this.#fetch(`${DISCORD_API}/channels/${target}/messages`, {
|
|
317
|
+
method: 'POST',
|
|
318
|
+
headers: {
|
|
319
|
+
Authorization: `Bot ${this.#options.config.token}`,
|
|
320
|
+
'Content-Type': 'application/json',
|
|
321
|
+
},
|
|
322
|
+
body: JSON.stringify(body),
|
|
323
|
+
});
|
|
324
|
+
const text = await response.text();
|
|
325
|
+
if (!response.ok) {
|
|
326
|
+
throw new Error(`Discord send failed (${response.status}): ${text.slice(0, 200)}`);
|
|
327
|
+
}
|
|
328
|
+
const data = JSON.parse(text);
|
|
329
|
+
return data.id ?? '';
|
|
330
|
+
}
|
|
331
|
+
admit(msg) {
|
|
332
|
+
if (!this.#open)
|
|
333
|
+
return;
|
|
334
|
+
void this.#options.gateway.receive({
|
|
335
|
+
adapter: this.#options.id,
|
|
336
|
+
target: msg.channelId,
|
|
337
|
+
content: formatInboundContent(msg),
|
|
338
|
+
sender: senderDisplayName(msg),
|
|
339
|
+
id: msg.id,
|
|
340
|
+
metadata: Object.freeze({
|
|
341
|
+
endpoint: this.#options.config.name,
|
|
342
|
+
channelKind: msg.channelKind,
|
|
343
|
+
userId: msg.authorId,
|
|
344
|
+
guildId: msg.guildId,
|
|
345
|
+
eventType: 'application_command',
|
|
346
|
+
}),
|
|
347
|
+
}).catch((err) => {
|
|
348
|
+
logger.warn(formatCompact({
|
|
349
|
+
op: 'discord_gateway_receive_failed',
|
|
350
|
+
target: msg.channelId,
|
|
351
|
+
error: err instanceof Error ? err.message : String(err),
|
|
352
|
+
}));
|
|
353
|
+
});
|
|
354
|
+
}
|
|
355
|
+
}
|
package/lib/gateway.d.ts
ADDED
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { GatewayIntentBits, type MessageCreateOptions } from 'discord.js';
|
|
2
|
+
import { type DiscordButtonInbound, type DiscordInboundMessage, type DiscordOutboundBody, type ResolvedDiscordGatewayConfig } from './protocol.js';
|
|
3
|
+
export declare const DEFAULT_INTENTS: GatewayIntentBits[];
|
|
4
|
+
/** Minimal client surface used by the endpoint (real discord.js or test mock). */
|
|
5
|
+
export interface DiscordClientTransport {
|
|
6
|
+
login(token: string): Promise<string>;
|
|
7
|
+
destroy(): Promise<void>;
|
|
8
|
+
on(event: string, listener: (...args: unknown[]) => void): void;
|
|
9
|
+
once(event: string, listener: (...args: unknown[]) => void): void;
|
|
10
|
+
removeAllListeners(): void;
|
|
11
|
+
readonly user?: {
|
|
12
|
+
readonly id: string;
|
|
13
|
+
readonly tag?: string;
|
|
14
|
+
setActivity?(name: string, options?: {
|
|
15
|
+
type?: number;
|
|
16
|
+
url?: string;
|
|
17
|
+
}): void;
|
|
18
|
+
} | null;
|
|
19
|
+
channels: {
|
|
20
|
+
fetch(id: string): Promise<{
|
|
21
|
+
id: string;
|
|
22
|
+
type: number;
|
|
23
|
+
isTextBased(): boolean;
|
|
24
|
+
send?(options: MessageCreateOptions): Promise<{
|
|
25
|
+
id: string;
|
|
26
|
+
}>;
|
|
27
|
+
messages?: {
|
|
28
|
+
fetch(id: string): Promise<{
|
|
29
|
+
react(emoji: string): Promise<unknown>;
|
|
30
|
+
reactions: {
|
|
31
|
+
resolve(emoji: unknown): {
|
|
32
|
+
users: {
|
|
33
|
+
remove(userId: string): Promise<unknown>;
|
|
34
|
+
};
|
|
35
|
+
} | null;
|
|
36
|
+
cache: {
|
|
37
|
+
find(fn: (r: {
|
|
38
|
+
emoji: {
|
|
39
|
+
toString(): string;
|
|
40
|
+
name?: string | null;
|
|
41
|
+
id?: string | null;
|
|
42
|
+
};
|
|
43
|
+
}) => boolean): {
|
|
44
|
+
users: {
|
|
45
|
+
remove(userId: string): Promise<unknown>;
|
|
46
|
+
};
|
|
47
|
+
} | undefined;
|
|
48
|
+
};
|
|
49
|
+
};
|
|
50
|
+
}>;
|
|
51
|
+
};
|
|
52
|
+
threads?: {
|
|
53
|
+
create(options: Record<string, unknown>): Promise<{
|
|
54
|
+
id: string;
|
|
55
|
+
}>;
|
|
56
|
+
};
|
|
57
|
+
availableTags?: Array<{
|
|
58
|
+
id: string;
|
|
59
|
+
name: string;
|
|
60
|
+
}>;
|
|
61
|
+
} | null>;
|
|
62
|
+
};
|
|
63
|
+
guilds: {
|
|
64
|
+
fetch(id: string): Promise<{
|
|
65
|
+
id: string;
|
|
66
|
+
name: string;
|
|
67
|
+
ownerId: string;
|
|
68
|
+
memberCount: number;
|
|
69
|
+
createdAt?: Date | null;
|
|
70
|
+
iconURL?(options?: {
|
|
71
|
+
size?: number;
|
|
72
|
+
}): string | null;
|
|
73
|
+
roles: {
|
|
74
|
+
fetch(): Promise<unknown>;
|
|
75
|
+
cache: Map<string, {
|
|
76
|
+
id: string;
|
|
77
|
+
name: string;
|
|
78
|
+
hexColor: string;
|
|
79
|
+
position: number;
|
|
80
|
+
permissions: {
|
|
81
|
+
bitfield: bigint;
|
|
82
|
+
};
|
|
83
|
+
}> | {
|
|
84
|
+
map(fn: (role: {
|
|
85
|
+
id: string;
|
|
86
|
+
name: string;
|
|
87
|
+
hexColor: string;
|
|
88
|
+
position: number;
|
|
89
|
+
permissions: {
|
|
90
|
+
bitfield: bigint;
|
|
91
|
+
};
|
|
92
|
+
}) => unknown): unknown[];
|
|
93
|
+
};
|
|
94
|
+
};
|
|
95
|
+
members: {
|
|
96
|
+
fetch(userId: string | {
|
|
97
|
+
limit?: number;
|
|
98
|
+
}): Promise<unknown>;
|
|
99
|
+
ban(userId: string, options?: {
|
|
100
|
+
reason?: string;
|
|
101
|
+
deleteMessageSeconds?: number;
|
|
102
|
+
}): Promise<unknown>;
|
|
103
|
+
unban(userId: string, reason?: string): Promise<unknown>;
|
|
104
|
+
};
|
|
105
|
+
}>;
|
|
106
|
+
cache: {
|
|
107
|
+
values(): IterableIterator<{
|
|
108
|
+
id: string;
|
|
109
|
+
}>;
|
|
110
|
+
};
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
export type CreateDiscordClient = (intents: readonly number[]) => DiscordClientTransport;
|
|
114
|
+
export declare function defaultCreateClient(intents: readonly number[]): DiscordClientTransport;
|
|
115
|
+
export declare function resolveSenderRole(msg: DiscordInboundMessage): string | undefined;
|
|
116
|
+
export declare function normalizeDiscordMessage(raw: unknown): DiscordInboundMessage | null;
|
|
117
|
+
export declare function toMessageCreateOptions(body: DiscordOutboundBody): Promise<MessageCreateOptions>;
|
|
118
|
+
export interface DiscordGatewayConnectHandlers {
|
|
119
|
+
onMessage(msg: DiscordInboundMessage): void;
|
|
120
|
+
onButton(interaction: DiscordButtonInbound): void;
|
|
121
|
+
}
|
|
122
|
+
export declare function connectDiscordGatewayClient(client: DiscordClientTransport, config: ResolvedDiscordGatewayConfig, handlers: DiscordGatewayConnectHandlers): Promise<void>;
|