seyfert 4.5.0 → 4.6.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.
Files changed (175) hide show
  1. package/lib/api/Routes/guilds.d.ts +12 -1
  2. package/lib/api/Routes/index.d.ts +3 -1
  3. package/lib/api/Routes/invites.d.ts +1 -1
  4. package/lib/api/Routes/oauth2.d.ts +11 -0
  5. package/lib/api/Routes/oauth2.js +2 -0
  6. package/lib/api/Routes/skus.d.ts +11 -4
  7. package/lib/api/Routes/users.d.ts +2 -1
  8. package/lib/api/Routes/voice.d.ts +4 -0
  9. package/lib/api/Routes/webhooks.d.ts +1 -1
  10. package/lib/api/api.d.ts +15 -5
  11. package/lib/api/api.js +243 -114
  12. package/lib/api/bucket.js +13 -7
  13. package/lib/api/shared.d.ts +3 -1
  14. package/lib/api/utils/constants.d.ts +1 -1
  15. package/lib/api/utils/constants.js +1 -1
  16. package/lib/builders/Attachment.d.ts +6 -1
  17. package/lib/builders/Attachment.js +13 -9
  18. package/lib/builders/CheckboxGroup.js +1 -1
  19. package/lib/builders/FileUpload.d.ts +8 -1
  20. package/lib/builders/FileUpload.js +9 -0
  21. package/lib/builders/RadioGroup.js +1 -1
  22. package/lib/client/base.d.ts +3 -3
  23. package/lib/client/collectors.d.ts +10 -8
  24. package/lib/client/transformers.d.ts +5 -0
  25. package/lib/client/workerclient.d.ts +8 -1
  26. package/lib/client/workerclient.js +28 -9
  27. package/lib/commands/applications/chat.d.ts +6 -4
  28. package/lib/commands/applications/options.d.ts +6 -4
  29. package/lib/commands/applications/shared.d.ts +2 -2
  30. package/lib/commands/handle.d.ts +7 -3
  31. package/lib/commands/handle.js +36 -11
  32. package/lib/commands/handler.js +11 -0
  33. package/lib/commands/optionresolver.d.ts +6 -7
  34. package/lib/common/it/error.d.ts +13 -0
  35. package/lib/common/it/error.js +15 -1
  36. package/lib/common/it/logger.js +12 -9
  37. package/lib/common/shorters/application.d.ts +1 -1
  38. package/lib/common/shorters/application.js +1 -1
  39. package/lib/common/shorters/bans.js +1 -1
  40. package/lib/common/shorters/guilds.js +5 -1
  41. package/lib/common/shorters/interaction.js +7 -4
  42. package/lib/common/shorters/invites.d.ts +5 -0
  43. package/lib/common/shorters/members.js +2 -1
  44. package/lib/common/shorters/messages.js +2 -2
  45. package/lib/common/shorters/threads.js +1 -1
  46. package/lib/common/shorters/webhook.js +3 -3
  47. package/lib/common/types/util.d.ts +7 -0
  48. package/lib/components/componentcommand.js +2 -2
  49. package/lib/components/customId.d.ts +3 -0
  50. package/lib/components/customId.js +11 -0
  51. package/lib/components/handler.js +2 -3
  52. package/lib/components/modalcommand.js +2 -2
  53. package/lib/events/hooks/invite.d.ts +1 -0
  54. package/lib/events/hooks/presence.d.ts +1 -0
  55. package/lib/events/hooks/thread.d.ts +1 -0
  56. package/lib/structures/AnonymousGuild.d.ts +1 -1
  57. package/lib/structures/AnonymousGuild.js +1 -1
  58. package/lib/structures/Guild.d.ts +3 -0
  59. package/lib/structures/GuildMember.d.ts +2 -2
  60. package/lib/structures/GuildMember.js +22 -4
  61. package/lib/structures/GuildPreview.d.ts +1 -1
  62. package/lib/structures/GuildPreview.js +1 -1
  63. package/lib/structures/GuildRole.d.ts +13 -0
  64. package/lib/structures/GuildRole.js +21 -0
  65. package/lib/structures/GuildTemplate.js +1 -1
  66. package/lib/structures/Interaction.d.ts +7 -7
  67. package/lib/structures/Interaction.js +35 -21
  68. package/lib/structures/Message.d.ts +2 -1
  69. package/lib/structures/channels.d.ts +29 -16
  70. package/lib/structures/channels.js +59 -19
  71. package/lib/structures/extra/BaseGuild.d.ts +4 -4
  72. package/lib/structures/extra/BaseGuild.js +4 -4
  73. package/lib/types/gateway.d.ts +243 -239
  74. package/lib/types/index.d.ts +2 -2
  75. package/lib/types/payloads/_interactions/_applicationCommands/_chatInput/attachment.d.ts +5 -2
  76. package/lib/types/payloads/_interactions/_applicationCommands/_chatInput/shared.d.ts +2 -2
  77. package/lib/types/payloads/_interactions/_applicationCommands/_chatInput/shared.js +1 -1
  78. package/lib/types/payloads/_interactions/_applicationCommands/chatInput.d.ts +7 -7
  79. package/lib/types/payloads/_interactions/_applicationCommands/contextMenu.d.ts +13 -13
  80. package/lib/types/payloads/_interactions/_applicationCommands/permissions.d.ts +4 -4
  81. package/lib/types/payloads/_interactions/_applicationCommands/permissions.js +2 -2
  82. package/lib/types/payloads/_interactions/applicationCommands.d.ts +10 -10
  83. package/lib/types/payloads/_interactions/applicationCommands.js +4 -4
  84. package/lib/types/payloads/_interactions/autocomplete.d.ts +2 -2
  85. package/lib/types/payloads/_interactions/base.d.ts +13 -7
  86. package/lib/types/payloads/_interactions/modalSubmit.d.ts +4 -4
  87. package/lib/types/payloads/_interactions/responses.d.ts +10 -10
  88. package/lib/types/payloads/_interactions/responses.js +2 -2
  89. package/lib/types/payloads/application.d.ts +21 -15
  90. package/lib/types/payloads/application.js +7 -7
  91. package/lib/types/payloads/auditLog.d.ts +22 -17
  92. package/lib/types/payloads/auditLog.js +7 -2
  93. package/lib/types/payloads/autoModeration.d.ts +11 -11
  94. package/lib/types/payloads/autoModeration.js +5 -5
  95. package/lib/types/payloads/channel.d.ts +87 -78
  96. package/lib/types/payloads/channel.js +16 -11
  97. package/lib/types/payloads/components.d.ts +41 -31
  98. package/lib/types/payloads/components.js +9 -5
  99. package/lib/types/payloads/emoji.d.ts +2 -2
  100. package/lib/types/payloads/emoji.js +1 -1
  101. package/lib/types/payloads/gateway.d.ts +33 -29
  102. package/lib/types/payloads/gateway.js +5 -5
  103. package/lib/types/payloads/guild.d.ts +68 -68
  104. package/lib/types/payloads/guild.js +14 -14
  105. package/lib/types/payloads/guildScheduledEvent.d.ts +11 -11
  106. package/lib/types/payloads/guildScheduledEvent.js +3 -3
  107. package/lib/types/payloads/index.d.ts +2 -2
  108. package/lib/types/payloads/interactions.d.ts +3 -3
  109. package/lib/types/payloads/invite.d.ts +11 -11
  110. package/lib/types/payloads/invite.js +3 -3
  111. package/lib/types/payloads/monetization.d.ts +4 -4
  112. package/lib/types/payloads/monetization.js +2 -2
  113. package/lib/types/payloads/oauth2.d.ts +21 -17
  114. package/lib/types/payloads/oauth2.js +21 -17
  115. package/lib/types/payloads/permissions.d.ts +5 -5
  116. package/lib/types/payloads/permissions.js +2 -2
  117. package/lib/types/payloads/poll.d.ts +7 -7
  118. package/lib/types/payloads/poll.js +2 -2
  119. package/lib/types/payloads/soundboard.d.ts +2 -2
  120. package/lib/types/payloads/soundboard.js +1 -1
  121. package/lib/types/payloads/stageInstance.d.ts +5 -5
  122. package/lib/types/payloads/stageInstance.js +1 -1
  123. package/lib/types/payloads/sticker.d.ts +8 -8
  124. package/lib/types/payloads/sticker.js +3 -3
  125. package/lib/types/payloads/teams.d.ts +8 -8
  126. package/lib/types/payloads/teams.js +3 -3
  127. package/lib/types/payloads/template.d.ts +3 -3
  128. package/lib/types/payloads/template.js +1 -1
  129. package/lib/types/payloads/user.d.ts +24 -22
  130. package/lib/types/payloads/user.js +7 -5
  131. package/lib/types/payloads/voice.d.ts +4 -4
  132. package/lib/types/payloads/voice.js +1 -1
  133. package/lib/types/payloads/webhokEvents.d.ts +5 -5
  134. package/lib/types/payloads/webhokEvents.js +2 -2
  135. package/lib/types/payloads/webhook.d.ts +4 -4
  136. package/lib/types/payloads/webhook.js +1 -1
  137. package/lib/types/rest/application.d.ts +14 -14
  138. package/lib/types/rest/auditLog.d.ts +1 -1
  139. package/lib/types/rest/autoModeration.d.ts +7 -7
  140. package/lib/types/rest/channel.d.ts +79 -74
  141. package/lib/types/rest/channel.js +1 -1
  142. package/lib/types/rest/emoji.d.ts +8 -8
  143. package/lib/types/rest/gateway.d.ts +2 -2
  144. package/lib/types/rest/guild.d.ts +98 -98
  145. package/lib/types/rest/guild.js +5 -5
  146. package/lib/types/rest/guildScheduledEvent.d.ts +11 -11
  147. package/lib/types/rest/index.d.ts +34 -3
  148. package/lib/types/rest/index.js +33 -2
  149. package/lib/types/rest/interactions.d.ts +48 -48
  150. package/lib/types/rest/invite.d.ts +5 -5
  151. package/lib/types/rest/monetization.d.ts +9 -9
  152. package/lib/types/rest/monetization.js +1 -1
  153. package/lib/types/rest/oauth2.d.ts +22 -18
  154. package/lib/types/rest/poll.d.ts +4 -4
  155. package/lib/types/rest/soundboard.d.ts +8 -8
  156. package/lib/types/rest/stageInstance.d.ts +6 -6
  157. package/lib/types/rest/sticker.d.ts +10 -10
  158. package/lib/types/rest/template.d.ts +11 -11
  159. package/lib/types/rest/user.d.ts +18 -14
  160. package/lib/types/rest/voice.d.ts +5 -5
  161. package/lib/types/rest/webhook.d.ts +38 -38
  162. package/lib/types/utils/index.d.ts +19 -19
  163. package/lib/types/utils/index.js +19 -19
  164. package/lib/websocket/SharedTypes.d.ts +2 -2
  165. package/lib/websocket/constants/index.js +2 -2
  166. package/lib/websocket/discord/heartbeater.d.ts +1 -0
  167. package/lib/websocket/discord/heartbeater.js +8 -0
  168. package/lib/websocket/discord/shard.d.ts +19 -10
  169. package/lib/websocket/discord/shard.js +254 -121
  170. package/lib/websocket/discord/sharder.d.ts +2 -2
  171. package/lib/websocket/discord/sharder.js +1 -1
  172. package/lib/websocket/discord/shared.d.ts +7 -2
  173. package/lib/websocket/discord/workermanager.d.ts +3 -1
  174. package/lib/websocket/discord/workermanager.js +31 -24
  175. package/package.json +2 -2
@@ -22,8 +22,13 @@ class Shard {
22
22
  interval: 30e3,
23
23
  ack: true,
24
24
  };
25
- isConnecting = false;
26
25
  reconnectPromise;
26
+ // Invalidates delayed connects and callbacks that belong to a replaced socket.
27
+ lifecycle = 0;
28
+ connectingLifecycle;
29
+ handledWebsocket;
30
+ localClose;
31
+ firstHeartbeatTimeout;
27
32
  bucket;
28
33
  offlineSendQueue = [];
29
34
  pendingGuilds;
@@ -76,45 +81,99 @@ class Shard {
76
81
  return this.websocket.ping();
77
82
  }
78
83
  async connect() {
79
- if (this.isConnecting) {
84
+ if (this.connectingLifecycle === undefined)
85
+ this.reconnectPromise = undefined;
86
+ return this.connectSocket(false);
87
+ }
88
+ async connectSocket(immediate) {
89
+ if (this.connectingLifecycle !== undefined) {
80
90
  this.debugger?.debug(`[Shard #${this.id}] Already connecting, skipping`);
81
91
  return;
82
92
  }
83
- this.isConnecting = true;
84
- await this.connectTimeout.wait();
93
+ const lifecycle = ++this.lifecycle;
94
+ this.connectingLifecycle = lifecycle;
95
+ if (!immediate)
96
+ await this.connectTimeout.wait();
97
+ if (this.connectingLifecycle !== lifecycle)
98
+ return;
99
+ if (lifecycle !== this.lifecycle) {
100
+ this.connectingLifecycle = undefined;
101
+ return;
102
+ }
85
103
  if (this.isOpen) {
86
104
  this.debugger?.debug(`[Shard #${this.id}] Attempted to connect while open`);
87
- this.isConnecting = false;
105
+ this.connectingLifecycle = undefined;
88
106
  return;
89
107
  }
90
- clearTimeout(this.heart.nodeInterval);
91
- this.debugger?.debug(`[Shard #${this.id}] Connecting to ${this.currentGatewayURL}`);
92
- this.connectionTimeout = setTimeout(() => this.reconnect(shared_1.ShardSocketCloseCodes.Timeout), this.options.connectionTimeout);
108
+ this.clearHeartbeat();
109
+ clearTimeout(this.connectionTimeout);
110
+ const url = this.currentGatewayURL;
111
+ this.debugger?.debug(`[Shard #${this.id}] Connecting to ${url}`);
93
112
  // @ts-expect-error Use native websocket when using Bun
94
- this.websocket = new basesocket_1.BaseSocket(typeof Bun === 'undefined' ? 'ws' : 'bun', this.currentGatewayURL);
95
- this.websocket.onmessage = ({ data }) => {
96
- this.handleMessage(data);
113
+ const websocket = new basesocket_1.BaseSocket(typeof Bun === 'undefined' ? 'ws' : 'bun', url);
114
+ this.isReady = false;
115
+ this.handledWebsocket = undefined;
116
+ this.localClose = undefined;
117
+ this.websocket = websocket;
118
+ this.connectionTimeout = setTimeout(() => {
119
+ if (!this.isCurrentConnection(websocket))
120
+ return;
121
+ void this.reconnectWith(shared_1.ShardSocketCloseCodes.Timeout, this.options.reconnectTimeout, 'Gateway connection timed out').catch(error => this.logger.error(error));
122
+ }, this.options.connectionTimeout);
123
+ websocket.onmessage = ({ data }) => {
124
+ if (!this.isCurrentConnection(websocket))
125
+ return;
126
+ try {
127
+ void Promise.resolve(this.handleMessage(data)).catch(error => this.logger.error(error));
128
+ }
129
+ catch (error) {
130
+ this.logger.error(error);
131
+ }
97
132
  };
98
- this.websocket.onclose = (event) => this.handleClosed(event);
99
- this.websocket.onerror = (event) => this.logger.error(event);
100
- this.websocket.onopen = () => {
101
- this.isConnecting = false;
133
+ websocket.onclose = (event) => {
134
+ if (!this.isCurrentConnection(websocket))
135
+ return;
136
+ const localClose = this.localClose?.websocket === websocket ? this.localClose : undefined;
137
+ void this.handleConnectionClosed({
138
+ code: event.code,
139
+ reason: event.reason,
140
+ locallyInitiated: !!localClose,
141
+ applyPolicy: localClose?.applyPolicy,
142
+ }, websocket).catch(error => this.logger.error(error));
143
+ };
144
+ websocket.onerror = (event) => {
145
+ if (!this.isCurrentConnection(websocket))
146
+ return;
147
+ this.logger.error(`Shard #${this.id}`, event);
148
+ };
149
+ websocket.onopen = () => {
150
+ if (!this.isCurrentConnection(websocket))
151
+ return;
152
+ this.connectingLifecycle = undefined;
102
153
  this.heart.ack = true;
103
154
  void this.options.onShardReconnect?.({ shardId: this.id });
104
155
  };
105
156
  }
106
157
  async send(force, message) {
107
- this.debugger?.info(`[Shard #${this.id}] Sending: ${types_1.GatewayOpcodes[message.op]} ${JSON.stringify(message.d, (_, value) => {
108
- if (typeof value === 'string')
109
- return value.replaceAll(this.options.token, v => {
110
- const split = v.split('.');
111
- return `${split[0]}.${'*'.repeat(split[1].length)}.${'*'.repeat(split[2].length)}`;
112
- });
113
- return value;
114
- }, 1)}`);
158
+ if (this.debugger) {
159
+ this.debugger.info(`[Shard #${this.id}] Sending: ${types_1.GatewayOpcodes[message.op]} ${JSON.stringify(message.d, (_, value) => {
160
+ if (typeof value === 'string')
161
+ return value.replaceAll(this.options.token, v => {
162
+ const split = v.split('.');
163
+ return `${split[0]}.${'*'.repeat(split[1].length)}.${'*'.repeat(split[2].length)}`;
164
+ });
165
+ return value;
166
+ }, 1)}`);
167
+ }
115
168
  await this.checkOffline(force);
169
+ const websocket = this.websocket;
116
170
  await this.bucket.acquire(force);
117
171
  await this.checkOffline(force);
172
+ // Authentication is connection-scoped; never deliver an Identify or Resume
173
+ // that finished waiting after its socket was replaced.
174
+ if ((message.op === types_1.GatewayOpcodes.Identify || message.op === types_1.GatewayOpcodes.Resume) &&
175
+ (!websocket || !this.isCurrentConnection(websocket)))
176
+ return;
118
177
  this.websocket?.send(JSON.stringify(message));
119
178
  }
120
179
  async identify() {
@@ -144,43 +203,110 @@ class Shard {
144
203
  });
145
204
  }
146
205
  heartbeat(requested) {
206
+ const websocket = this.websocket;
207
+ if (!websocket)
208
+ return;
147
209
  this.debugger?.debug(`[Shard #${this.id}] Sending ${requested ? '' : 'un'}requested heartbeat (Ack=${this.heart.ack})`);
210
+ if (!requested && !this.heart.ack) {
211
+ void this.reconnectWith(shared_1.ShardSocketCloseCodes.ZombiedConnection, 0, 'Heartbeat ACK was not received before the next interval').catch(error => this.logger.error(error));
212
+ return;
213
+ }
214
+ if (websocket.readyState !== 1)
215
+ return;
148
216
  if (!requested) {
149
- if (!this.heart.ack) {
150
- this.reconnect(shared_1.ShardSocketCloseCodes.ZombiedConnection);
151
- return;
152
- }
153
217
  this.heart.ack = false;
154
218
  }
155
219
  this.heart.lastBeat = Date.now();
156
- this.websocket.send(JSON.stringify({
220
+ websocket.send(JSON.stringify({
157
221
  op: types_1.GatewayOpcodes.Heartbeat,
158
222
  d: this.data.resume_seq ?? null,
159
223
  }));
160
- clearTimeout(this.heart.ackTimeout);
161
- this.heart.ackTimeout = setTimeout(() => {
162
- if (!this.heart.ack) {
163
- this.reconnect(shared_1.ShardSocketCloseCodes.ZombiedConnection);
164
- }
165
- }, this.heart.interval * 1.5);
166
224
  }
167
225
  disconnect(code = shared_1.ShardSocketCloseCodes.Shutdown) {
168
- clearTimeout(this.connectionTimeout);
169
- this.connectionTimeout = undefined;
170
- clearTimeout(this.heart.ackTimeout);
171
- this.isConnecting = false;
226
+ this.lifecycle++;
227
+ this.reconnectPromise = undefined;
172
228
  this.debugger?.info(`[Shard #${this.id}] Disconnecting`);
173
- this.close(code, 'Shard down request');
229
+ this.closeConnection(code, 'Shard down request', this.shouldApplyLocalClosePolicy(code));
174
230
  }
175
231
  async reconnect(code = shared_1.ShardSocketCloseCodes.Reconnect) {
176
- return (this.reconnectPromise ??= (async () => {
232
+ return this.reconnectWith(code, this.options.reconnectTimeout, 'Shard reconnect request');
233
+ }
234
+ reconnectWith(code, wait, reason, immediate = code === shared_1.ShardSocketCloseCodes.Timeout ? false : this.resumable) {
235
+ if (this.reconnectPromise)
236
+ return this.reconnectPromise;
237
+ const reconnect = (async () => {
238
+ const lifecycle = ++this.lifecycle;
177
239
  this.debugger?.info(`[Shard #${this.id}] Reconnecting`);
178
- this.disconnect(code);
179
- await (0, common_1.delay)(this.options.reconnectTimeout);
180
- await this.connect();
181
- })().finally(() => {
182
- this.reconnectPromise = undefined;
183
- }));
240
+ this.closeConnection(code, reason);
241
+ if (code === shared_1.ShardSocketCloseCodes.Timeout)
242
+ this.resetSession();
243
+ if (wait > 0)
244
+ await (0, common_1.delay)(wait);
245
+ if (lifecycle !== this.lifecycle)
246
+ return;
247
+ await this.connectSocket(immediate);
248
+ })();
249
+ const settled = reconnect.finally(() => {
250
+ if (this.reconnectPromise === settled)
251
+ this.reconnectPromise = undefined;
252
+ });
253
+ this.reconnectPromise = settled;
254
+ return settled;
255
+ }
256
+ isCurrentConnection(websocket) {
257
+ return this.websocket === websocket && this.handledWebsocket !== websocket;
258
+ }
259
+ clearHeartbeat() {
260
+ clearTimeout(this.firstHeartbeatTimeout);
261
+ clearInterval(this.heart.nodeInterval);
262
+ this.firstHeartbeatTimeout = undefined;
263
+ this.heart.nodeInterval = undefined;
264
+ }
265
+ resetSession() {
266
+ this.data.resume_seq = null;
267
+ this.data.session_id = undefined;
268
+ this.data.resume_gateway_url = undefined;
269
+ this.pendingGuilds = undefined;
270
+ }
271
+ startHeartbeat(websocket) {
272
+ this.clearHeartbeat();
273
+ this.heart.ack = true;
274
+ this.firstHeartbeatTimeout = setTimeout(() => {
275
+ if (!this.isCurrentConnection(websocket))
276
+ return;
277
+ this.heartbeat(false);
278
+ this.heart.nodeInterval = setInterval(() => {
279
+ if (this.isCurrentConnection(websocket))
280
+ this.heartbeat(false);
281
+ }, this.heart.interval);
282
+ }, this.heart.interval * Math.random());
283
+ }
284
+ closeConnection(code, reason, applyPolicy = false) {
285
+ const websocket = this.websocket;
286
+ if (!websocket) {
287
+ this.connectingLifecycle = undefined;
288
+ clearTimeout(this.connectionTimeout);
289
+ this.connectionTimeout = undefined;
290
+ this.clearHeartbeat();
291
+ this.debugger?.warn(`[Shard #${this.id}] Is not open, reason:`, reason);
292
+ return;
293
+ }
294
+ this.debugger?.debug(`[Shard #${this.id}] Called close with reason:`, reason);
295
+ // Native and custom sockets report local Close frames differently. Mark the
296
+ // owner before closing so both paths finalize the same lifecycle exactly once.
297
+ this.localClose = { websocket, applyPolicy };
298
+ try {
299
+ websocket.close(code, reason);
300
+ }
301
+ catch (error) {
302
+ this.localClose = undefined;
303
+ throw error;
304
+ }
305
+ this.connectingLifecycle = undefined;
306
+ if (this.handledWebsocket !== websocket) {
307
+ const close = { code, reason, locallyInitiated: true, applyPolicy };
308
+ void this.handleConnectionClosed(close, websocket).catch(error => this.logger.error(error));
309
+ }
184
310
  }
185
311
  flushOfflineSendQueue() {
186
312
  const queue = this.offlineSendQueue.splice(0);
@@ -194,12 +320,13 @@ class Shard {
194
320
  this.debugger?.debug(`[Shard #${this.id}]`, packet.t ? packet.t : types_1.GatewayOpcodes[packet.op], this.data.resume_seq);
195
321
  switch (packet.op) {
196
322
  case types_1.GatewayOpcodes.Hello: {
323
+ const websocket = this.websocket;
324
+ if (!websocket)
325
+ return;
197
326
  clearTimeout(this.connectionTimeout);
198
327
  this.connectionTimeout = undefined;
199
- clearInterval(this.heart.nodeInterval);
200
328
  this.heart.interval = packet.d.heartbeat_interval;
201
- this.heartbeat(false);
202
- this.heart.nodeInterval = setInterval(() => this.heartbeat(false), this.heart.interval);
329
+ this.startHeartbeat(websocket);
203
330
  if (this.resumable) {
204
331
  return this.resume();
205
332
  }
@@ -209,24 +336,18 @@ class Shard {
209
336
  {
210
337
  this.heart.ack = true;
211
338
  this.heart.lastAck = Date.now();
212
- clearTimeout(this.heart.ackTimeout);
213
339
  }
214
340
  break;
215
341
  case types_1.GatewayOpcodes.Heartbeat:
216
342
  this.heartbeat(true);
217
343
  break;
218
344
  case types_1.GatewayOpcodes.Reconnect:
219
- return this.reconnect();
345
+ return this.reconnectWith(shared_1.ShardSocketCloseCodes.Reconnect, 0, 'Discord requested a reconnect', true);
220
346
  case types_1.GatewayOpcodes.InvalidSession: {
221
- if (packet.d) {
222
- if (!this.resumable) {
223
- return this.logger.fatal('This is a completely unexpected error message.');
224
- }
225
- return this.resume();
226
- }
227
- this.data.resume_seq = 0;
228
- this.data.session_id = undefined;
229
- return this.identify();
347
+ const canResume = packet.d && this.resumable;
348
+ if (!canResume)
349
+ this.resetSession();
350
+ return this.reconnectWith(shared_1.ShardSocketCloseCodes.Reconnect, 0, canResume ? 'Discord invalidated the resumable session' : 'Discord invalidated the session');
230
351
  }
231
352
  case types_1.GatewayOpcodes.Dispatch:
232
353
  {
@@ -342,6 +463,7 @@ class Shard {
342
463
  }
343
464
  break;
344
465
  }
466
+ return undefined;
345
467
  }
346
468
  async requestGuildMember(options) {
347
469
  const nonce = Date.now().toString() + Math.random().toString(36);
@@ -379,59 +501,74 @@ class Shard {
379
501
  });
380
502
  return promise;
381
503
  }
382
- async handleClosed(close) {
504
+ isExpectedLocalClose(code) {
505
+ return (code === shared_1.ShardSocketCloseCodes.Shutdown ||
506
+ code === shared_1.ShardSocketCloseCodes.Reconnect ||
507
+ code === shared_1.ShardSocketCloseCodes.Resharding ||
508
+ code === shared_1.ShardSocketCloseCodes.ShutdownAll);
509
+ }
510
+ shouldApplyLocalClosePolicy(code) {
511
+ return !this.isExpectedLocalClose(code) && code !== shared_1.ShardSocketCloseCodes.ZombiedConnection;
512
+ }
513
+ async handleConnectionClosed(close, websocket) {
514
+ if (!websocket || !this.isCurrentConnection(websocket))
515
+ return;
516
+ this.handledWebsocket = websocket;
517
+ if (this.localClose?.websocket === websocket)
518
+ this.localClose = undefined;
383
519
  this.isReady = false;
384
- clearInterval(this.heart.nodeInterval);
385
- clearTimeout(this.heart.ackTimeout);
386
- this.logger.warn(`${shared_1.ShardSocketCloseCodes[close.code] ?? types_1.GatewayCloseCodes[close.code] ?? close.code} (${close.code})`, close.reason);
520
+ this.connectingLifecycle = undefined;
521
+ clearTimeout(this.connectionTimeout);
522
+ this.connectionTimeout = undefined;
523
+ this.clearHeartbeat();
524
+ const closeMessage = `Shard #${this.id} closed: ${shared_1.ShardSocketCloseCodes[close.code] ?? types_1.GatewayCloseCodes[close.code] ?? close.code} (${close.code})`;
525
+ if (close.locallyInitiated && this.isExpectedLocalClose(close.code)) {
526
+ this.logger.info(closeMessage, close.reason);
527
+ }
528
+ else {
529
+ this.logger.warn(closeMessage, close.reason);
530
+ }
387
531
  try {
388
- switch (close.code) {
389
- case shared_1.ShardSocketCloseCodes.Shutdown:
390
- case shared_1.ShardSocketCloseCodes.Reconnect:
391
- case shared_1.ShardSocketCloseCodes.Resharding:
392
- case shared_1.ShardSocketCloseCodes.ShutdownAll:
393
- case shared_1.ShardSocketCloseCodes.ZombiedConnection:
394
- //Force disconnect, ignore
395
- break;
396
- case 1000:
397
- case types_1.GatewayCloseCodes.UnknownOpcode:
398
- case types_1.GatewayCloseCodes.InvalidSeq:
399
- case types_1.GatewayCloseCodes.SessionTimedOut:
400
- // shard failed to connect, try connecting from scratch
401
- case shared_1.ShardSocketCloseCodes.Timeout:
402
- {
403
- this.data.resume_seq = 0;
404
- this.data.session_id = undefined;
405
- this.data.resume_gateway_url = undefined;
406
- await this.reconnect();
407
- }
408
- break;
409
- case 1001:
410
- case 1006:
411
- case types_1.GatewayCloseCodes.UnknownError:
412
- case types_1.GatewayCloseCodes.DecodeError:
413
- case types_1.GatewayCloseCodes.NotAuthenticated:
414
- case types_1.GatewayCloseCodes.AlreadyAuthenticated:
415
- case types_1.GatewayCloseCodes.RateLimited:
416
- {
417
- this.logger.info('Trying to reconnect');
418
- await this.reconnect();
419
- }
420
- break;
421
- case types_1.GatewayCloseCodes.AuthenticationFailed:
422
- case types_1.GatewayCloseCodes.DisallowedIntents:
423
- case types_1.GatewayCloseCodes.InvalidAPIVersion:
424
- case types_1.GatewayCloseCodes.InvalidIntents:
425
- case types_1.GatewayCloseCodes.InvalidShard:
426
- case types_1.GatewayCloseCodes.ShardingRequired:
427
- this.logger.fatal('Cannot reconnect');
428
- break;
429
- default:
430
- {
431
- this.logger.warn('Unknown close code, trying to reconnect anyways');
432
- await this.reconnect();
433
- }
434
- break;
532
+ if (!close.locallyInitiated || close.applyPolicy) {
533
+ switch (close.code) {
534
+ case 1000:
535
+ case types_1.GatewayCloseCodes.UnknownOpcode:
536
+ case types_1.GatewayCloseCodes.InvalidSeq:
537
+ case types_1.GatewayCloseCodes.SessionTimedOut:
538
+ case shared_1.ShardSocketCloseCodes.Timeout:
539
+ {
540
+ this.resetSession();
541
+ await this.reconnect();
542
+ }
543
+ break;
544
+ case 1001:
545
+ case 1006:
546
+ case types_1.GatewayCloseCodes.UnknownError:
547
+ case types_1.GatewayCloseCodes.DecodeError:
548
+ case types_1.GatewayCloseCodes.NotAuthenticated:
549
+ case types_1.GatewayCloseCodes.AlreadyAuthenticated:
550
+ case types_1.GatewayCloseCodes.RateLimited:
551
+ {
552
+ this.logger.info('Trying to reconnect');
553
+ await this.reconnect();
554
+ }
555
+ break;
556
+ case types_1.GatewayCloseCodes.AuthenticationFailed:
557
+ case types_1.GatewayCloseCodes.DisallowedIntents:
558
+ case types_1.GatewayCloseCodes.InvalidAPIVersion:
559
+ case types_1.GatewayCloseCodes.InvalidIntents:
560
+ case types_1.GatewayCloseCodes.InvalidShard:
561
+ case types_1.GatewayCloseCodes.ShardingRequired:
562
+ this.lifecycle++;
563
+ this.logger.fatal(`Shard #${this.id} cannot reconnect`);
564
+ break;
565
+ default:
566
+ {
567
+ this.logger.warn(`Shard #${this.id} unknown close code (${close.code}), trying to reconnect anyways`);
568
+ await this.reconnect();
569
+ }
570
+ break;
571
+ }
435
572
  }
436
573
  }
437
574
  finally {
@@ -443,23 +580,19 @@ class Shard {
443
580
  }
444
581
  }
445
582
  close(code, reason) {
446
- clearInterval(this.heart.nodeInterval);
447
- if (!this.websocket) {
448
- return this.debugger?.warn(`[Shard #${this.id}] Is not open, reason:`, reason);
449
- }
450
- this.debugger?.debug(`[Shard #${this.id}] Called close with reason:`, reason);
451
- this.websocket?.close(code, reason);
583
+ this.lifecycle++;
584
+ this.reconnectPromise = undefined;
585
+ this.closeConnection(code, reason, this.shouldApplyLocalClosePolicy(code));
452
586
  }
453
587
  handleMessage(data) {
454
588
  let packet;
455
589
  try {
456
- if (data instanceof Buffer) {
590
+ if (data instanceof Buffer)
457
591
  data = (0, node_zlib_1.inflateSync)(data);
458
- }
459
592
  packet = JSON.parse(data);
460
593
  }
461
- catch (e) {
462
- this.logger.error(e);
594
+ catch (error) {
595
+ this.logger.error(error);
463
596
  return;
464
597
  }
465
598
  return this.onpacket(packet);
@@ -1,4 +1,4 @@
1
- import { Logger, type MakeRequired } from '../../common';
1
+ import { Logger, type MakePresent, type MakeRequired } from '../../common';
2
2
  import type { MakeDeepPartial } from '../../common/types/util';
3
3
  import { type GatewaySendPayload, type GatewayUpdatePresence, type GatewayVoiceStateUpdate } from '../../types';
4
4
  import { ShardManagerDefaults } from '../constants';
@@ -7,7 +7,7 @@ import { Shard } from './shard';
7
7
  import { type ShardData, type ShardManagerOptions, ShardSocketCloseCodes } from './shared';
8
8
  export declare class ShardManager extends Map<number, Shard> {
9
9
  connectQueue: ConnectQueue;
10
- options: MakeRequired<ShardManagerOptions, keyof typeof ShardManagerDefaults>;
10
+ options: MakePresent<ShardManagerOptions, keyof typeof ShardManagerDefaults>;
11
11
  debugger?: Logger;
12
12
  constructor(options: MakeDeepPartial<ShardManagerOptions, 'resharding'>);
13
13
  get totalShards(): number;
@@ -156,7 +156,7 @@ class ShardManager extends Map {
156
156
  }
157
157
  /*
158
158
  * spawns buckets in order
159
- * https://discord.com/developers/docs/topics/gateway#sharding-max-concurrency
159
+ * https://docs.discord.com/developers/topics/gateway#sharding-max-concurrency
160
160
  */
161
161
  spawnBuckets() {
162
162
  this.debugger?.info('#0 Preparing buckets');
@@ -61,7 +61,12 @@ export interface WorkerManagerOptions extends Omit<ShardManagerOptions, 'handleP
61
61
  adapter?: CustomManagerAdapter;
62
62
  workers?: number;
63
63
  /**
64
- * @default 16
64
+ * Environment variables to add to each worker.
65
+ * Variables managed by Seyfert take precedence over matching keys.
66
+ */
67
+ workerEnv?: Readonly<Record<string, string>>;
68
+ /**
69
+ * @default 8
65
70
  */
66
71
  shardsPerWorker?: number;
67
72
  workerProxy?: boolean;
@@ -78,7 +83,7 @@ export interface ShardData {
78
83
  resume_seq: number | null;
79
84
  /**
80
85
  * resume_gateway_url is the url to resume the connection
81
- * @link https://discord.com/developers/docs/topics/gateway#ready-event
86
+ * @link https://docs.discord.com/developers/topics/gateway#ready-event
82
87
  */
83
88
  resume_gateway_url?: string;
84
89
  /**
@@ -20,7 +20,7 @@ export declare class WorkerManager extends Map<number, (ClusterWorker | WorkerTh
20
20
  shardEnd: number;
21
21
  shardsPerWorker: number;
22
22
  }, logger?: Logger): number[][];
23
- options: PickPartial<Required<WorkerManagerOptions>, 'adapter' | 'handleWorkerMessage' | 'handlePayload' | 'getRC'>;
23
+ options: PickPartial<Required<WorkerManagerOptions>, 'adapter' | 'handleWorkerMessage' | 'handlePayload' | 'getRC' | 'workerEnv'>;
24
24
  debugger?: Logger;
25
25
  connectQueue: ConnectQueue;
26
26
  workerQueue: (() => void)[];
@@ -53,6 +53,7 @@ export declare class WorkerManager extends Map<number, (ClusterWorker | WorkerTh
53
53
  workerId: number;
54
54
  }): Promise<number>;
55
55
  calculateShardId(guildId: string): number;
56
+ private createWorkerNotFoundError;
56
57
  calculateWorkerId(shardId: number): number;
57
58
  postMessage(id: number, body: ManagerMessages | WorkerHeartbeaterMessages): void;
58
59
  prepareWorkers(shards: number[][], rawResharding?: boolean): void;
@@ -111,6 +112,7 @@ export type ManagerSendCacheResult = CreateManagerMessage<'CACHE_RESULT', {
111
112
  export type ManagerSendBotReady = CreateManagerMessage<'BOT_READY'>;
112
113
  export type ManagerSendApiResponse = CreateManagerMessage<'API_RESPONSE', {
113
114
  response: any;
115
+ responseType?: 'arrayBuffer';
114
116
  error?: any;
115
117
  nonce: string;
116
118
  }>;