seyfert 5.2.2-dev-40488860512.0 → 5.2.2-dev-40764380528.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +17 -48
- package/lib/cache/index.d.ts +3 -1
- package/lib/cache/index.js +57 -24
- package/lib/common/it/formatter.d.ts +19 -0
- package/lib/common/it/formatter.js +25 -0
- package/lib/common/it/utils.js +1 -1
- package/lib/components/handler.js +1 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,63 +1,32 @@
|
|
|
1
|
-
<div align=
|
|
2
|
-
<img src="./assets/icon.png" alt="
|
|
1
|
+
<div align="center">
|
|
2
|
+
<img src="./assets/icon.png" alt="Seyfert" width="200" />
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
# Seyfert
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
A TypeScript framework for building Discord bots.
|
|
7
|
+
|
|
8
|
+
[](./LICENSE)
|
|
7
9
|
[](https://www.npmjs.com/package/seyfert)
|
|
8
10
|
[](https://discord.com/invite/XNw2RZFzaP)
|
|
9
11
|
|
|
10
12
|
</div>
|
|
11
13
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
### So, what is `seyfert`?
|
|
15
|
-
|
|
16
|
-
Seyfert is the ultimate Discord framework! We make it easy to interact with the Discord API, big cache control, scalable code and a pretty dev experience.
|
|
17
|
-
|
|
18
|
-
### Why should I use it?
|
|
19
|
-
|
|
20
|
-
There are many reasons to use Seyfert, but they dont all fit in this tiny readme, so here is a list of the most awesome reasons!
|
|
21
|
-
- **Low RAM Usage**
|
|
22
|
-
- **Latest features**
|
|
23
|
-
- **Dev experience**
|
|
24
|
-
- **24/6 support (Sunday is for church)**
|
|
25
|
-
- **Written from Scratch**
|
|
26
|
-
- **Type-safe**
|
|
27
|
-
- **And many more!!**
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
## Installation
|
|
31
|
-
|
|
32
|
-
> [!NOTE]
|
|
33
|
-
> Supported runtimes: Node.js and Bun.
|
|
34
|
-
> Node v18>= (or v16 with `--experimental-fetch` flag) is required.
|
|
35
|
-
> Bun/Node LTS recommended.
|
|
36
|
-
|
|
37
|
-
```sh
|
|
38
|
-
pnpm add seyfert
|
|
39
|
-
```
|
|
40
|
-
|
|
41
|
-
```sh
|
|
42
|
-
bun add seyfert
|
|
43
|
-
```
|
|
14
|
+
Seyfert brings Discord's API and gateway together with typed commands, interaction handlers, and plugins. Written in TypeScript for Node.js and Bun, it provides the tools to organize a bot while keeping the underlying Discord types and REST routes accessible.
|
|
44
15
|
|
|
45
|
-
|
|
46
|
-
npm i seyfert
|
|
47
|
-
```
|
|
48
|
-
> Or other package manager.
|
|
16
|
+
## What it offers
|
|
49
17
|
|
|
50
|
-
|
|
18
|
+
- **Typed commands:** Application and prefix commands with option inference, choices, subcommands, and autocomplete. Contexts give handlers access to resolved options and the appropriate response methods.
|
|
19
|
+
- **Middleware and localization:** Share checks and preparation across commands, pass metadata to handlers, and translate command definitions and responses.
|
|
20
|
+
- **Interactions and builders:** Handle components and modals through dedicated contexts. Build responses with embeds, buttons, select menus, and layout components.
|
|
21
|
+
- **Discord resources:** Work with transformed structures and resource methods, or use the REST client directly when you need access to a route.
|
|
22
|
+
- **Gateway and cache:** Handle gateway and custom events, distribute connections across shards and workers, and choose which resources to cache with configurable adapters.
|
|
23
|
+
- **Plugins:** Package reusable commands, events, middleware, and client extensions with lifecycle hooks for setup and cleanup.
|
|
51
24
|
|
|
52
|
-
|
|
25
|
+
## Documentation and community
|
|
53
26
|
|
|
54
|
-
|
|
27
|
+
Explore the [documentation](https://seyfert.dev/guide) for guides and API usage, or join the [Discord server](https://discord.com/invite/XNw2RZFzaP) for questions and community support.
|
|
55
28
|
|
|
56
|
-
|
|
57
|
-
- [Discord server](https://discord.com/invite/XNw2RZFzaP)
|
|
58
|
-
- [npm - core](https://www.npmjs.com/package/seyfert)
|
|
59
|
-
- [Website](https://seyfert.dev)
|
|
60
|
-
- [Documentation](https://seyfert.dev/guide)
|
|
29
|
+
Contributions are welcome.
|
|
61
30
|
|
|
62
31
|
<a href="https://www.star-history.com/?repos=tiramisulabs%2Fseyfert&type=date&legend=top-left">
|
|
63
32
|
<picture>
|
package/lib/cache/index.d.ts
CHANGED
|
@@ -42,7 +42,7 @@ type BulkGetResult<K extends BulkGetKey[0] = BulkGetKey[0]> = Partial<{
|
|
|
42
42
|
[P in K]: ReturnManagers[P][];
|
|
43
43
|
}>;
|
|
44
44
|
export * from './adapters/index';
|
|
45
|
-
export type CachedEvents = 'READY' | 'GUILD_CREATE' | 'GUILD_UPDATE' | 'GUILD_DELETE' | 'CHANNEL_CREATE' | 'CHANNEL_UPDATE' | 'CHANNEL_DELETE' | 'GUILD_ROLE_CREATE' | 'GUILD_ROLE_UPDATE' | 'GUILD_ROLE_DELETE' | 'GUILD_BAN_ADD' | 'GUILD_BAN_REMOVE' | 'GUILD_EMOJIS_UPDATE' | 'GUILD_STICKERS_UPDATE' | 'GUILD_MEMBER_ADD' | 'GUILD_MEMBER_UPDATE' | 'GUILD_MEMBER_REMOVE' | 'MESSAGE_CREATE' | 'PRESENCE_UPDATE' | 'THREAD_DELETE' | 'THREAD_CREATE' | 'THREAD_UPDATE' | 'USER_UPDATE' | 'VOICE_CHANNEL_STATUS_UPDATE' | 'VOICE_STATE_UPDATE' | 'STAGE_INSTANCE_CREATE' | 'STAGE_INSTANCE_UPDATE' | 'STAGE_INSTANCE_DELETE' | 'GUILD_MEMBERS_CHUNK';
|
|
45
|
+
export type CachedEvents = 'READY' | 'GUILD_CREATE' | 'GUILD_UPDATE' | 'GUILD_DELETE' | 'CHANNEL_CREATE' | 'CHANNEL_UPDATE' | 'CHANNEL_DELETE' | 'GUILD_ROLE_CREATE' | 'GUILD_ROLE_UPDATE' | 'GUILD_ROLE_DELETE' | 'GUILD_BAN_ADD' | 'GUILD_BAN_REMOVE' | 'GUILD_EMOJIS_UPDATE' | 'GUILD_STICKERS_UPDATE' | 'GUILD_MEMBER_ADD' | 'GUILD_MEMBER_UPDATE' | 'GUILD_MEMBER_REMOVE' | 'INTERACTION_CREATE' | 'MESSAGE_CREATE' | 'MESSAGE_UPDATE' | 'MESSAGE_REACTION_ADD' | 'TYPING_START' | 'PRESENCE_UPDATE' | 'THREAD_DELETE' | 'THREAD_CREATE' | 'THREAD_UPDATE' | 'USER_UPDATE' | 'VOICE_CHANNEL_STATUS_UPDATE' | 'VOICE_STATE_UPDATE' | 'STAGE_INSTANCE_CREATE' | 'STAGE_INSTANCE_UPDATE' | 'STAGE_INSTANCE_DELETE' | 'GUILD_MEMBERS_CHUNK';
|
|
46
46
|
export type DisabledCache = {
|
|
47
47
|
[P in NonGuildBased | GuildBased | GuildRelated | SeyfertBased]?: boolean;
|
|
48
48
|
};
|
|
@@ -85,6 +85,8 @@ export declare class Cache {
|
|
|
85
85
|
bulkSet(keys: BulkWriteKey[]): Promise<void>;
|
|
86
86
|
onPacket(event: GatewayDispatchPayload): Promise<void>;
|
|
87
87
|
private onPacketWithPluginResources;
|
|
88
|
+
private appendUserAndMember;
|
|
89
|
+
private appendMessageUsers;
|
|
88
90
|
protected onPacketDefault(event: GatewayDispatchPayload): Promise<void>;
|
|
89
91
|
/**
|
|
90
92
|
* Destructively validates the adapter by flushing its complete storage before, during, and after the run.
|
package/lib/cache/index.js
CHANGED
|
@@ -264,6 +264,25 @@ class Cache {
|
|
|
264
264
|
}
|
|
265
265
|
}
|
|
266
266
|
}
|
|
267
|
+
appendUserAndMember(data, user, member, guildId) {
|
|
268
|
+
if (!user?.id)
|
|
269
|
+
return;
|
|
270
|
+
if (this.users)
|
|
271
|
+
data.push([CacheFrom.Gateway, 'users', user, user.id]);
|
|
272
|
+
if (this.members && member && guildId) {
|
|
273
|
+
// Interaction permissions include channel overwrites and must stay local to the interaction.
|
|
274
|
+
const { permissions: _permissions, ...guildMember } = member;
|
|
275
|
+
guildMember.user = user;
|
|
276
|
+
data.push([CacheFrom.Gateway, 'members', guildMember, user.id, guildId]);
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
appendMessageUsers(data, message, guildId) {
|
|
280
|
+
for (const mention of message.mentions ?? []) {
|
|
281
|
+
const { member, ...user } = mention;
|
|
282
|
+
this.appendUserAndMember(data, user, member, guildId);
|
|
283
|
+
}
|
|
284
|
+
this.appendUserAndMember(data, message.author, message.member, guildId);
|
|
285
|
+
}
|
|
267
286
|
async onPacketDefault(event) {
|
|
268
287
|
switch (event.t) {
|
|
269
288
|
case 'READY':
|
|
@@ -350,6 +369,34 @@ class Cache {
|
|
|
350
369
|
await this.members?.remove(event.d.user.id, event.d.guild_id);
|
|
351
370
|
await this.presences?.remove(event.d.user.id, event.d.guild_id);
|
|
352
371
|
break;
|
|
372
|
+
case 'INTERACTION_CREATE':
|
|
373
|
+
{
|
|
374
|
+
const data = [];
|
|
375
|
+
const resolved = event.d.data && 'resolved' in event.d.data ? event.d.data.resolved : undefined;
|
|
376
|
+
if (resolved && 'messages' in resolved) {
|
|
377
|
+
for (const message of Object.values(resolved.messages)) {
|
|
378
|
+
this.appendMessageUsers(data, message, event.d.guild_id);
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
if (resolved && 'users' in resolved) {
|
|
382
|
+
for (const [id, user] of Object.entries(resolved.users ?? {})) {
|
|
383
|
+
this.appendUserAndMember(data, user, resolved.members?.[id], event.d.guild_id);
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
this.appendUserAndMember(data, event.d.member?.user ?? event.d.user, event.d.member, event.d.guild_id);
|
|
387
|
+
if (data.length)
|
|
388
|
+
await this.bulkPatch(data);
|
|
389
|
+
}
|
|
390
|
+
break;
|
|
391
|
+
case 'MESSAGE_REACTION_ADD':
|
|
392
|
+
case 'TYPING_START':
|
|
393
|
+
{
|
|
394
|
+
const data = [];
|
|
395
|
+
this.appendUserAndMember(data, event.d.member?.user, event.d.member, event.d.guild_id);
|
|
396
|
+
if (data.length)
|
|
397
|
+
await this.bulkPatch(data);
|
|
398
|
+
}
|
|
399
|
+
break;
|
|
353
400
|
case 'PRESENCE_UPDATE':
|
|
354
401
|
// Should update member data?
|
|
355
402
|
await this.presences?.set(CacheFrom.Gateway, event.d.user.id, event.d.guild_id, event.d);
|
|
@@ -371,6 +418,10 @@ class Cache {
|
|
|
371
418
|
break;
|
|
372
419
|
case 'VOICE_STATE_UPDATE':
|
|
373
420
|
{
|
|
421
|
+
const data = [];
|
|
422
|
+
this.appendUserAndMember(data, event.d.member?.user, event.d.member, event.d.guild_id);
|
|
423
|
+
if (data.length)
|
|
424
|
+
await this.bulkPatch(data);
|
|
374
425
|
if (!event.d.guild_id) {
|
|
375
426
|
return;
|
|
376
427
|
}
|
|
@@ -395,33 +446,15 @@ class Cache {
|
|
|
395
446
|
await this.stageInstances?.remove(event.d.channel_id, event.d.guild_id);
|
|
396
447
|
break;
|
|
397
448
|
case 'MESSAGE_CREATE':
|
|
398
|
-
{
|
|
399
|
-
if (this.messages !== undefined) {
|
|
400
|
-
const data = [
|
|
401
|
-
[CacheFrom.Gateway, 'messages', event.d, event.d.id, event.d.channel_id],
|
|
402
|
-
[CacheFrom.Gateway, 'users', event.d.author, event.d.author.id],
|
|
403
|
-
];
|
|
404
|
-
if (event.d.guild_id) {
|
|
405
|
-
if (event.d.member)
|
|
406
|
-
data.push([CacheFrom.Gateway, 'members', event.d.member, event.d.author.id, event.d.guild_id]);
|
|
407
|
-
}
|
|
408
|
-
await this.bulkPatch(data);
|
|
409
|
-
}
|
|
410
|
-
}
|
|
411
|
-
break;
|
|
412
449
|
case 'MESSAGE_UPDATE':
|
|
413
450
|
{
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
[CacheFrom.Gateway, 'users', event.d.author, event.d.author.id],
|
|
418
|
-
];
|
|
419
|
-
if (event.d.guild_id) {
|
|
420
|
-
if (event.d.member)
|
|
421
|
-
data.push([CacheFrom.Gateway, 'members', event.d.member, event.d.author.id, event.d.guild_id]);
|
|
422
|
-
}
|
|
423
|
-
await this.bulkPatch(data);
|
|
451
|
+
const data = [];
|
|
452
|
+
if (this.messages) {
|
|
453
|
+
data.push([CacheFrom.Gateway, 'messages', event.d, event.d.id, event.d.channel_id]);
|
|
424
454
|
}
|
|
455
|
+
this.appendMessageUsers(data, event.d, event.d.guild_id);
|
|
456
|
+
if (data.length)
|
|
457
|
+
await this.bulkPatch(data);
|
|
425
458
|
}
|
|
426
459
|
break;
|
|
427
460
|
case 'MESSAGE_DELETE':
|
|
@@ -162,6 +162,12 @@ export declare const Formatter: {
|
|
|
162
162
|
* @returns The formatted content.
|
|
163
163
|
*/
|
|
164
164
|
quote(content: string): `> ${string}`;
|
|
165
|
+
/**
|
|
166
|
+
* Formats content into subtext.
|
|
167
|
+
* @param content The content to format.
|
|
168
|
+
* @returns The formatted content.
|
|
169
|
+
*/
|
|
170
|
+
subtext(content: string): `-# ${string}`;
|
|
165
171
|
/**
|
|
166
172
|
* Formats a message link.
|
|
167
173
|
* @param guildId The ID of the guild.
|
|
@@ -209,6 +215,13 @@ export declare const Formatter: {
|
|
|
209
215
|
* @returns The formatted channel mention.
|
|
210
216
|
*/
|
|
211
217
|
channelMention(channelId: string): `<#${string}>`;
|
|
218
|
+
/**
|
|
219
|
+
* Formats a slash command mention.
|
|
220
|
+
* @param name The name of the command, including subcommands (e.g. `config set`).
|
|
221
|
+
* @param commandId The ID of the command.
|
|
222
|
+
* @returns The formatted command mention.
|
|
223
|
+
*/
|
|
224
|
+
commandMention(name: string, commandId: string): `</${string}:${string}>`;
|
|
212
225
|
/**
|
|
213
226
|
* Formats an emoji.
|
|
214
227
|
* @param emojiId The ID of the emoji.
|
|
@@ -223,6 +236,12 @@ export declare const Formatter: {
|
|
|
223
236
|
* @returns The formatted channel link.
|
|
224
237
|
*/
|
|
225
238
|
channelLink(channelId: string, guildId?: string): ChannelLink;
|
|
239
|
+
/**
|
|
240
|
+
* Formats a guild navigation mention.
|
|
241
|
+
* @param type The guild page to link to.
|
|
242
|
+
* @returns The formatted guild navigation mention.
|
|
243
|
+
*/
|
|
244
|
+
guildNavigation(type: 'customize' | 'browse' | 'guide' | 'linked-roles'): `<id:${string}>`;
|
|
226
245
|
/**
|
|
227
246
|
* Forms a oauth2 invite link for the bot.
|
|
228
247
|
* @param applicationId The ID of the application.
|
|
@@ -157,6 +157,14 @@ exports.Formatter = {
|
|
|
157
157
|
quote(content) {
|
|
158
158
|
return `> ${content}`;
|
|
159
159
|
},
|
|
160
|
+
/**
|
|
161
|
+
* Formats content into subtext.
|
|
162
|
+
* @param content The content to format.
|
|
163
|
+
* @returns The formatted content.
|
|
164
|
+
*/
|
|
165
|
+
subtext(content) {
|
|
166
|
+
return `-# ${content}`;
|
|
167
|
+
},
|
|
160
168
|
/**
|
|
161
169
|
* Formats a message link.
|
|
162
170
|
* @param guildId The ID of the guild.
|
|
@@ -223,6 +231,15 @@ exports.Formatter = {
|
|
|
223
231
|
channelMention(channelId) {
|
|
224
232
|
return `<#${channelId}>`;
|
|
225
233
|
},
|
|
234
|
+
/**
|
|
235
|
+
* Formats a slash command mention.
|
|
236
|
+
* @param name The name of the command, including subcommands (e.g. `config set`).
|
|
237
|
+
* @param commandId The ID of the command.
|
|
238
|
+
* @returns The formatted command mention.
|
|
239
|
+
*/
|
|
240
|
+
commandMention(name, commandId) {
|
|
241
|
+
return `</${name}:${commandId}>`;
|
|
242
|
+
},
|
|
226
243
|
/**
|
|
227
244
|
* Formats an emoji.
|
|
228
245
|
* @param emojiId The ID of the emoji.
|
|
@@ -241,6 +258,14 @@ exports.Formatter = {
|
|
|
241
258
|
channelLink(channelId, guildId) {
|
|
242
259
|
return `https://discord.com/channels/${guildId ?? '@me'}/${channelId}`;
|
|
243
260
|
},
|
|
261
|
+
/**
|
|
262
|
+
* Formats a guild navigation mention.
|
|
263
|
+
* @param type The guild page to link to.
|
|
264
|
+
* @returns The formatted guild navigation mention.
|
|
265
|
+
*/
|
|
266
|
+
guildNavigation(type) {
|
|
267
|
+
return `<id:${type}>`;
|
|
268
|
+
},
|
|
244
269
|
/**
|
|
245
270
|
* Forms a oauth2 invite link for the bot.
|
|
246
271
|
* @param applicationId The ID of the application.
|
package/lib/common/it/utils.js
CHANGED
|
@@ -327,7 +327,7 @@ function resolvePartialEmoji(emoji) {
|
|
|
327
327
|
};
|
|
328
328
|
}
|
|
329
329
|
if (emoji.includes('%')) {
|
|
330
|
-
emoji =
|
|
330
|
+
emoji = decodeURIComponent(emoji);
|
|
331
331
|
}
|
|
332
332
|
if (!(emoji.includes(':') || emoji.match(/\d{17,20}/g))) {
|
|
333
333
|
return { name: emoji, id: null };
|
|
@@ -26,6 +26,7 @@ class ComponentHandler extends common_1.BaseHandler {
|
|
|
26
26
|
return str => (0, customId_1.matchesCustomId)(match, str);
|
|
27
27
|
}
|
|
28
28
|
createComponentCollector(messageId, channelId, guildId, options = {}, components = []) {
|
|
29
|
+
this.clearValue(messageId);
|
|
29
30
|
this.values.set(messageId, {
|
|
30
31
|
messageId,
|
|
31
32
|
channelId,
|