seyfert 5.2.1-dev-39592791825.0 → 5.2.1

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,21 +1,23 @@
1
1
  <div align='center'>
2
2
  <img src="./assets/icon.png" alt="seyfert" width="200px" />
3
3
 
4
- **Seyfert is a brand-new Discord framework to take the bot development to a next level**
4
+ **Seyfert is a brand-new Discord framework to take the bot development to a next level**
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)
7
- [![Version](https://img.shields.io/npm/v/seyfert?color=%23ff0000&logo=npm&style=flat-square)](https://www.npmjs.com/package/seyfert)
8
- [![Discord](https://img.shields.io/discord/1003825077969764412?color=%23406da2&label=support&logo=discord&style=flat-square)](https://discord.com/invite/XNw2RZFzaP)
6
+ [![License](https://img.shields.io/npm/l/seyfert?style=flat-square&logo=apache&color=white)](https://github.com/tiramisulabs/seyfert/blob/main/LICENSE)
7
+ [![Version](https://img.shields.io/npm/v/seyfert?color=%23ff0000&logo=npm&style=flat-square)](https://www.npmjs.com/package/seyfert)
8
+ [![Discord](https://img.shields.io/discord/1003825077969764412?color=%23406da2&label=support&logo=discord&style=flat-square)](https://discord.com/invite/XNw2RZFzaP)
9
9
 
10
10
  </div>
11
11
 
12
12
  ## FAQ
13
+
13
14
  ### So, what is `seyfert`?
15
+
14
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.
15
17
 
16
18
  ### Why should I use it?
17
- 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!
18
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!
19
21
  - **Low RAM Usage**
20
22
  - **Latest features**
21
23
  - **Dev experience**
@@ -26,6 +28,7 @@ There are many reasons to use Seyfert, but they dont all fit in this tiny readme
26
28
 
27
29
 
28
30
  ## Installation
31
+
29
32
  > [!NOTE]
30
33
  > Node v18>= (or v16 with `--experimental-fetch` flag), Deno v2.6.9>= is required.
31
34
  > Bun/Node/Deno LTS recommended.
@@ -48,6 +51,7 @@ npm i seyfert
48
51
  > Or other package manager.
49
52
 
50
53
  ## Contributing
54
+
51
55
  We are open to contributions, fork the repo and make your changes!
52
56
 
53
57
  ## Useful links
@@ -1,4 +1,4 @@
1
- export declare const DefaultUserAgent: "DiscordBot (https://seyfert.dev, v5.2.0)";
1
+ export declare const DefaultUserAgent: "DiscordBot (https://seyfert.dev, v5.2.1)";
2
2
  export declare const ALLOWED_EXTENSIONS: readonly ["webp", "png", "jpg", "jpeg", "gif"];
3
3
  export declare const ALLOWED_STICKER_EXTENSIONS: readonly ["png", "json", "gif"];
4
4
  export declare const ALLOWED_SIZES: readonly [16, 32, 64, 100, 128, 256, 512, 1024, 2048, 4096];
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.ALLOWED_TAG_BADGE_EXTENSIONS = exports.ALLOWED_SOUNDS_EXTENSIONS = exports.ALLOWED_SIZES = exports.ALLOWED_STICKER_EXTENSIONS = exports.ALLOWED_EXTENSIONS = exports.DefaultUserAgent = void 0;
4
- exports.DefaultUserAgent = 'DiscordBot (https://seyfert.dev, v5.2.0)';
4
+ exports.DefaultUserAgent = 'DiscordBot (https://seyfert.dev, v5.2.1)';
5
5
  exports.ALLOWED_EXTENSIONS = ['webp', 'png', 'jpg', 'jpeg', 'gif'];
6
6
  exports.ALLOWED_STICKER_EXTENSIONS = ['png', 'json', 'gif'];
7
7
  exports.ALLOWED_SIZES = [16, 32, 64, 100, 128, 256, 512, 1_024, 2_048, 4_096];
@@ -147,10 +147,10 @@ class ClientBase extends base_1.BaseClient {
147
147
  if (pluginPacket === null)
148
148
  return null;
149
149
  packet = pluginPacket;
150
- Promise.allSettled([
150
+ void Promise.allSettled([
151
151
  this.events.runEvent('RAW', this, packet, shardId, false),
152
152
  this.collectors.run('RAW', packet, this),
153
- ]); //ignore promise
153
+ ]);
154
154
  switch (packet.t) {
155
155
  case 'GUILD_MEMBER_UPDATE':
156
156
  {
@@ -515,10 +515,10 @@ class WorkerClient extends base_1.BaseClient {
515
515
  if (pluginPacket === null)
516
516
  return null;
517
517
  packet = pluginPacket;
518
- Promise.allSettled([
518
+ void Promise.allSettled([
519
519
  this.events.runEvent('RAW', this, packet, shardId, false),
520
520
  this.collectors.run('RAW', packet, this),
521
- ]); //ignore promise
521
+ ]);
522
522
  switch (packet.t) {
523
523
  case 'GUILD_MEMBER_UPDATE':
524
524
  {
@@ -19,7 +19,11 @@ export declare class LangsHandler extends BaseHandler {
19
19
  load(dir: string): Promise<void>;
20
20
  parse(file: LangInstance): void | Promise<void>;
21
21
  private applyParsedFile;
22
- set(instances: LangInstance[]): void;
22
+ /**
23
+ * Applies files synchronously until an onFile hook returns a promise.
24
+ * The returned promise covers the remaining files in order and rejects on the first failure.
25
+ */
26
+ set(instances: LangInstance[]): void | Promise<void>;
23
27
  reload(lang: string): Promise<any>;
24
28
  reloadAll(stopIfFail?: boolean): Promise<void>;
25
29
  onFile(locale: string, { file, name, path }: LangInstance): Awaitable<LangFileResult>;
@@ -55,10 +55,23 @@ class LangsHandler extends common_1.BaseHandler {
55
55
  this.__paths[result.locale] = file.path;
56
56
  this.values[result.locale] = result.file;
57
57
  }
58
+ /**
59
+ * Applies files synchronously until an onFile hook returns a promise.
60
+ * The returned promise covers the remaining files in order and rejects on the first failure.
61
+ */
58
62
  set(instances) {
63
+ let pending;
59
64
  for (const i of instances) {
60
- this.parse(i);
65
+ if (pending) {
66
+ pending = pending.then(() => this.parse(i));
67
+ }
68
+ else {
69
+ const parsed = this.parse(i);
70
+ if (parsed)
71
+ pending = parsed;
72
+ }
61
73
  }
74
+ return pending;
62
75
  }
63
76
  async reload(lang) {
64
77
  if ((0, common_1.isCloudflareWorker)()) {
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.WorkerManagerDefaults = exports.ShardManagerDefaults = exports.properties = exports.COMPRESS = void 0;
4
4
  const COMPRESS = false;
5
5
  exports.COMPRESS = COMPRESS;
6
- const propertiesVersion = 'Seyfert v5.2.0 (https://seyfert.dev)';
6
+ const propertiesVersion = 'Seyfert v5.2.1 (https://seyfert.dev)';
7
7
  const properties = {
8
8
  os: process.platform,
9
9
  browser: propertiesVersion,
@@ -16,13 +16,15 @@ class Heartbeater {
16
16
  this.store.set(workerId, {
17
17
  ack: true,
18
18
  interval: setInterval(() => {
19
+ // WorkerManager callbacks observe and report their own transport/replacement failures.
19
20
  const heartbeat = this.store.get(workerId);
20
21
  if (!heartbeat.ack) {
21
22
  heartbeat.ack = true;
22
- return recreate(workerId);
23
+ void recreate(workerId);
24
+ return;
23
25
  }
24
26
  heartbeat.ack = false;
25
- this.sendMethod(workerId, { type: 'HEARTBEAT' });
27
+ void this.sendMethod(workerId, { type: 'HEARTBEAT' });
26
28
  }, this.interval),
27
29
  });
28
30
  }
@@ -62,6 +62,7 @@ export declare class Shard {
62
62
  members: APIGuildMember[];
63
63
  presences: GatewayGuildMembersChunkPresence[];
64
64
  }>;
65
+ private sendGuildMemberRequest;
65
66
  private isExpectedLocalClose;
66
67
  private shouldApplyLocalClosePolicy;
67
68
  private handleConnectionClosed;
@@ -440,16 +440,7 @@ class Shard {
440
440
  this.options.handlePayload(this.id, packet);
441
441
  return;
442
442
  }
443
- const guildMemberChunk = this.requestGuildMembersChunk.get(nonce);
444
- void (0, common_1.delay)((retry_after + 0.5) * 1e3).then(() => {
445
- this.send(false, {
446
- op: types_1.GatewayOpcodes.RequestGuildMembers,
447
- d: {
448
- ...guildMemberChunk.options,
449
- nonce,
450
- },
451
- });
452
- });
443
+ void (0, common_1.delay)((retry_after + 0.5) * 1e3).then(() => this.sendGuildMemberRequest(nonce));
453
444
  }
454
445
  break;
455
446
  }
@@ -492,15 +483,27 @@ class Shard {
492
483
  timeout,
493
484
  options,
494
485
  });
495
- this.send(false, {
496
- op: types_1.GatewayOpcodes.RequestGuildMembers,
497
- d: {
498
- ...options,
499
- nonce,
500
- },
501
- });
486
+ void this.sendGuildMemberRequest(nonce);
502
487
  return promise;
503
488
  }
489
+ async sendGuildMemberRequest(nonce) {
490
+ const chunk = this.requestGuildMembersChunk.get(nonce);
491
+ if (!chunk)
492
+ return;
493
+ try {
494
+ await this.send(false, {
495
+ op: types_1.GatewayOpcodes.RequestGuildMembers,
496
+ d: { ...chunk.options, nonce },
497
+ });
498
+ }
499
+ catch (error) {
500
+ if (this.requestGuildMembersChunk.get(nonce) !== chunk)
501
+ return;
502
+ clearTimeout(chunk.timeout);
503
+ this.requestGuildMembersChunk.delete(nonce);
504
+ chunk.reject(error);
505
+ }
506
+ }
504
507
  isExpectedLocalClose(code) {
505
508
  return (code === shared_1.ShardSocketCloseCodes.Shutdown ||
506
509
  code === shared_1.ShardSocketCloseCodes.Reconnect ||
@@ -25,7 +25,8 @@ export declare class ShardManager extends Map<number, Shard> {
25
25
  disconnect(shardId: number, code?: ShardSocketCloseCodes): void | undefined;
26
26
  disconnectAll(code?: ShardSocketCloseCodes): void;
27
27
  setShardPresence(shardId: number, payload: GatewayUpdatePresence['d']): Promise<boolean>;
28
- setPresence(payload: GatewayUpdatePresence['d']): void;
28
+ /** Waits for all presence sends, rejecting if any shard fails. */
29
+ setPresence(payload: GatewayUpdatePresence['d']): Promise<void>;
29
30
  joinVoice(guild_id: string, channel_id: string, options: Pick<GatewayVoiceStateUpdate['d'], 'self_deaf' | 'self_mute'>): Promise<boolean>;
30
31
  leaveVoice(guild_id: string): Promise<boolean>;
31
32
  requestChannelInfo(guild_id: string, fields: ('status' | 'voice_start_time')[]): Promise<boolean>;
@@ -189,10 +189,9 @@ class ShardManager extends Map {
189
189
  d: payload,
190
190
  });
191
191
  }
192
- setPresence(payload) {
193
- this.forEach(shard => {
194
- this.setShardPresence(shard.id, payload);
195
- }, this);
192
+ /** Waits for all presence sends, rejecting if any shard fails. */
193
+ async setPresence(payload) {
194
+ await Promise.all([...this.values()].map(shard => this.setShardPresence(shard.id, payload)));
196
195
  }
197
196
  joinVoice(guild_id, channel_id, options) {
198
197
  const shardId = this.calculateShardId(guild_id);
@@ -20,7 +20,13 @@ class SeyfertWebSocket {
20
20
  const urlParts = new URL(url);
21
21
  this.hostname = urlParts.hostname || '';
22
22
  this.path = `${urlParts.pathname}${urlParts.search || ''}`;
23
- this.connect();
23
+ void this.connect().catch(error => {
24
+ if (this.__closeCalled)
25
+ return;
26
+ this.onerror(error);
27
+ this.__lastError = { code: 1006, reason: error instanceof Error ? error.message : String(error) };
28
+ this.#emitClose(this.__lastError);
29
+ });
24
30
  }
25
31
  connect(retries = 0) {
26
32
  return new Promise((resolve, rej) => {
@@ -49,11 +55,10 @@ class SeyfertWebSocket {
49
55
  const hash = (0, node_crypto_1.createHash)('sha1').update(`${key}258EAFA5-E914-47DA-95CA-C5AB0DC85B11`).digest('base64');
50
56
  const accept = res.headers['sec-websocket-accept'];
51
57
  if (accept !== hash) {
52
- socket.end(() => {
53
- rej(new common_1.SeyfertError('INVALID_SEC_WEBSOCKET_ACCEPT_HEADER', {
54
- metadata: { detail: 'Invalid sec-websocket-accept header' },
55
- }));
56
- });
58
+ socket.destroy();
59
+ rej(new common_1.SeyfertError('INVALID_SEC_WEBSOCKET_ACCEPT_HEADER', {
60
+ metadata: { detail: 'Invalid sec-websocket-accept header' },
61
+ }));
57
62
  return;
58
63
  }
59
64
  this.socket = socket;
@@ -62,7 +62,8 @@ class DynamicBucket {
62
62
  acquire(force = false) {
63
63
  return new Promise(res => {
64
64
  this.queue[force ? 'unshift' : 'push'](res);
65
- this.processQueue();
65
+ // Each acquisition resolves with its permit, without waiting for the whole queue to drain.
66
+ void this.processQueue();
66
67
  });
67
68
  }
68
69
  static chunk(array, chunks) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "seyfert",
3
- "version": "5.2.1-dev-39592791825.0",
3
+ "version": "5.2.1",
4
4
  "description": "The most advanced framework for discord bots",
5
5
  "packageManager": "pnpm@11.11.0",
6
6
  "workspaces": [
@@ -21,15 +21,15 @@
21
21
  "lint": "biome lint --write ./src",
22
22
  "format": "biome format --write ./src",
23
23
  "check-h": "biome check --write ./src",
24
- "check": "biome check --verbose --no-errors-on-unmatched ./src ./tests ./package.json ./tsconfig.json ./biome.json ./commitlint.config.js",
25
- "check:write": "biome check --verbose --write --no-errors-on-unmatched ./src ./tests ./package.json ./tsconfig.json ./biome.json ./commitlint.config.js",
24
+ "check": "biome check --verbose --no-errors-on-unmatched .",
25
+ "check:write": "biome check --verbose --write --no-errors-on-unmatched .",
26
26
  "test:types": "pnpm run build && tsc --noEmit --project tests/tsconfig.json",
27
27
  "test": "pnpm run test:types && vitest run --config ./tests/vitest.config.mts ./tests/"
28
28
  },
29
29
  "author": "MARCROCK22",
30
30
  "license": "MIT",
31
31
  "devDependencies": {
32
- "@biomejs/biome": "2.5.3",
32
+ "@biomejs/biome": "2.6.2",
33
33
  "@changesets/cli": "^2.31.0",
34
34
  "@commitlint/cli": "^21.2.1",
35
35
  "@commitlint/config-conventional": "^21.2.0",