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 CHANGED
@@ -1,63 +1,32 @@
1
- <div align='center'>
2
- <img src="./assets/icon.png" alt="seyfert" width="200px" />
1
+ <div align="center">
2
+ <img src="./assets/icon.png" alt="Seyfert" width="200" />
3
3
 
4
- **Seyfert is a brand-new Discord framework to take the bot development to a next level**
4
+ # Seyfert
5
5
 
6
- [![License](https://img.shields.io/npm/l/seyfert?style=flat-square&logo=apache&color=white)](https://github.com/tiramisulabs/seyfert/blob/main/LICENSE)
6
+ A TypeScript framework for building Discord bots.
7
+
8
+ [![License](https://img.shields.io/npm/l/seyfert?style=flat-square&color=white)](./LICENSE)
7
9
  [![Version](https://img.shields.io/npm/v/seyfert?color=%23ff0000&logo=npm&style=flat-square)](https://www.npmjs.com/package/seyfert)
8
10
  [![Discord](https://img.shields.io/discord/1003825077969764412?color=%23406da2&label=support&logo=discord&style=flat-square)](https://discord.com/invite/XNw2RZFzaP)
9
11
 
10
12
  </div>
11
13
 
12
- ## FAQ
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
- ```sh
46
- npm i seyfert
47
- ```
48
- > Or other package manager.
16
+ ## What it offers
49
17
 
50
- ## Contributing
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
- We are open to contributions, fork the repo and make your changes!
25
+ ## Documentation and community
53
26
 
54
- ## Useful links
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
- - [GitHub Repository](https://github.com/tiramisulabs/seyfert)
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>
@@ -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.
@@ -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
- if (this.messages !== undefined) {
415
- const data = [
416
- [CacheFrom.Gateway, 'messages', event.d, event.d.id, event.d.channel_id],
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.
@@ -327,7 +327,7 @@ function resolvePartialEmoji(emoji) {
327
327
  };
328
328
  }
329
329
  if (emoji.includes('%')) {
330
- emoji = encodeURIComponent(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,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "seyfert",
3
- "version": "5.2.2-dev-40488860512.0",
3
+ "version": "5.2.2-dev-40764380528.0",
4
4
  "description": "The most advanced framework for discord bots",
5
5
  "packageManager": "pnpm@11.11.0",
6
6
  "workspaces": [