lunibee 0.1.0 → 0.1.2

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 (67) hide show
  1. package/README.md +229 -0
  2. package/dist/builders/attachment.d.ts +20 -0
  3. package/dist/builders/commands.d.ts +118 -0
  4. package/dist/builders/components.d.ts +151 -0
  5. package/dist/builders/embed.d.ts +59 -0
  6. package/dist/builders/index.d.ts +5 -0
  7. package/dist/builders/index.js +828 -0
  8. package/dist/builders/index.js.map +13 -0
  9. package/dist/collection/cache.d.ts +37 -0
  10. package/dist/collection/index.d.ts +47 -0
  11. package/dist/collection/index.js +214 -0
  12. package/dist/collection/index.js.map +11 -0
  13. package/dist/core/client-state.d.ts +10 -0
  14. package/dist/core/collector.d.ts +27 -0
  15. package/dist/core/events.d.ts +5 -0
  16. package/dist/core/index.d.ts +111 -0
  17. package/dist/core/index.js +3188 -0
  18. package/dist/core/index.js.map +29 -0
  19. package/dist/core/permissions.d.ts +293 -0
  20. package/dist/formatters/index.d.ts +10 -0
  21. package/dist/formatters/index.js +43 -0
  22. package/dist/formatters/index.js.map +10 -0
  23. package/dist/handlers/index.d.ts +16 -0
  24. package/dist/handlers/index.js +37 -0
  25. package/dist/handlers/index.js.map +10 -0
  26. package/{src/index.ts → dist/index.d.ts} +2 -29
  27. package/dist/index.js +4182 -0
  28. package/dist/index.js.map +41 -0
  29. package/dist/managers/application.d.ts +28 -0
  30. package/dist/managers/base.d.ts +28 -0
  31. package/dist/managers/index.d.ts +96 -0
  32. package/dist/managers/index.js +947 -0
  33. package/dist/managers/index.js.map +22 -0
  34. package/dist/managers/member.d.ts +35 -0
  35. package/dist/managers/message.d.ts +25 -0
  36. package/dist/managers/role.d.ts +34 -0
  37. package/dist/managers/thread.d.ts +14 -0
  38. package/dist/rest/index.d.ts +49 -0
  39. package/dist/rest/index.js +344 -0
  40. package/dist/rest/index.js.map +12 -0
  41. package/dist/rest/routes.d.ts +44 -0
  42. package/dist/rest/types.d.ts +26 -0
  43. package/dist/rest/webhook.d.ts +40 -0
  44. package/dist/sharding/bus.d.ts +22 -0
  45. package/dist/sharding/index.d.ts +34 -0
  46. package/dist/sharding/index.js +732 -0
  47. package/dist/sharding/index.js.map +13 -0
  48. package/dist/structures/base.d.ts +75 -0
  49. package/dist/structures/index.d.ts +39 -0
  50. package/dist/structures/index.js +571 -0
  51. package/dist/structures/index.js.map +14 -0
  52. package/dist/structures/interactions.d.ts +136 -0
  53. package/dist/structures/permissions.d.ts +73 -0
  54. package/dist/structures/resources.d.ts +64 -0
  55. package/dist/types/index.d.ts +535 -0
  56. package/dist/types/index.js +132 -0
  57. package/dist/types/index.js.map +10 -0
  58. package/dist/utils/index.d.ts +6 -0
  59. package/dist/utils/index.js +18 -0
  60. package/dist/utils/index.js.map +10 -0
  61. package/dist/voice/index.d.ts +97 -0
  62. package/dist/voice/index.js +161 -0
  63. package/dist/voice/index.js.map +10 -0
  64. package/dist/ws/index.d.ts +76 -0
  65. package/dist/ws/index.js +582 -0
  66. package/dist/ws/index.js.map +11 -0
  67. package/package.json +113 -28
@@ -0,0 +1,582 @@
1
+ // @bun
2
+ // packages/types/src/index.ts
3
+ var GatewayIntentBits = {
4
+ Guilds: 1 << 0,
5
+ GuildMembers: 1 << 1,
6
+ GuildModeration: 1 << 2,
7
+ GuildExpressions: 1 << 3,
8
+ GuildIntegrations: 1 << 4,
9
+ GuildWebhooks: 1 << 5,
10
+ GuildInvites: 1 << 6,
11
+ GuildVoiceStates: 1 << 7,
12
+ GuildPresences: 1 << 8,
13
+ GuildMessages: 1 << 9,
14
+ GuildMessageReactions: 1 << 10,
15
+ GuildMessageTyping: 1 << 11,
16
+ DirectMessages: 1 << 12,
17
+ DirectMessageReactions: 1 << 13,
18
+ DirectMessageTyping: 1 << 14,
19
+ MessageContent: 1 << 15,
20
+ GuildScheduledEvents: 1 << 16,
21
+ AutoModerationConfiguration: 1 << 20,
22
+ AutoModerationExecution: 1 << 21,
23
+ GuildMessagePolls: 1 << 24,
24
+ DirectMessagePolls: 1 << 25
25
+ };
26
+ var IntentBits = {
27
+ guild: 1 << 0,
28
+ guilds: 1 << 0,
29
+ guildMembers: 1 << 1,
30
+ guildModeration: 1 << 2,
31
+ guildBans: 1 << 2,
32
+ guildExpressions: 1 << 3,
33
+ guildEmojis: 1 << 3,
34
+ guildEmojisAndStickers: 1 << 3,
35
+ guildIntegrations: 1 << 4,
36
+ guildWebhooks: 1 << 5,
37
+ guildInvites: 1 << 6,
38
+ guildVoiceStates: 1 << 7,
39
+ guildPresences: 1 << 8,
40
+ guildMessages: 1 << 9,
41
+ guildMessage: 1 << 9,
42
+ guildMessageReactions: 1 << 10,
43
+ guildMessageTyping: 1 << 11,
44
+ directMessages: 1 << 12,
45
+ directMessageReactions: 1 << 13,
46
+ directMessageTyping: 1 << 14,
47
+ messageContent: 1 << 15,
48
+ guildScheduledEvents: 1 << 16,
49
+ autoModerationConfiguration: 1 << 20,
50
+ autoModerationExecution: 1 << 21,
51
+ guildMessagePolls: 1 << 24,
52
+ directMessagePolls: 1 << 25
53
+ };
54
+ function resolveGatewayIntents(intents) {
55
+ if (typeof intents === "number")
56
+ return intents;
57
+ if (Array.isArray(intents)) {
58
+ return intents.reduce((acc, intent) => {
59
+ return acc | resolveGatewayIntents(intent);
60
+ }, 0);
61
+ }
62
+ if (typeof intents === "string") {
63
+ if (intents in GatewayIntentBits)
64
+ return GatewayIntentBits[intents];
65
+ if (intents in IntentBits)
66
+ return IntentBits[intents];
67
+ const lower = intents.charAt(0).toLowerCase() + intents.slice(1);
68
+ if (lower in IntentBits)
69
+ return IntentBits[lower];
70
+ const num = Number(intents);
71
+ if (!Number.isNaN(num))
72
+ return num;
73
+ }
74
+ return 0;
75
+ }
76
+
77
+ // packages/ws/src/index.ts
78
+ var GatewayOpcodes = {
79
+ Dispatch: 0,
80
+ Heartbeat: 1,
81
+ Identify: 2,
82
+ PresenceUpdate: 3,
83
+ VoiceStateUpdate: 4,
84
+ Resume: 6,
85
+ Reconnect: 7,
86
+ RequestGuildMembers: 8,
87
+ InvalidSession: 9,
88
+ Hello: 10,
89
+ HeartbeatAck: 11
90
+ };
91
+ var GatewayState;
92
+ ((GatewayState2) => {
93
+ GatewayState2["Connect"] = "CONNECT";
94
+ GatewayState2["Hello"] = "HELLO";
95
+ GatewayState2["Identify"] = "IDENTIFY";
96
+ GatewayState2["Resume"] = "RESUME";
97
+ GatewayState2["Ready"] = "READY";
98
+ GatewayState2["Dispatch"] = "DISPATCH";
99
+ GatewayState2["Heartbeat"] = "HEARTBEAT";
100
+ GatewayState2["Reconnect"] = "RECONNECT";
101
+ GatewayState2["Closed"] = "CLOSED";
102
+ })(GatewayState ||= {});
103
+
104
+ class GatewayError extends Error {
105
+ code;
106
+ constructor(message, code, options) {
107
+ super(message, options);
108
+ this.name = "GatewayError";
109
+ this.code = code;
110
+ }
111
+ }
112
+
113
+ class Gateway {
114
+ state = "CONNECT" /* Connect */;
115
+ #options;
116
+ #ws;
117
+ #sequence = null;
118
+ #sessionId;
119
+ #resumeURL;
120
+ #heartbeatTimer;
121
+ #initialHeartbeat;
122
+ #heartbeatAckTimer;
123
+ #heartbeatACK = true;
124
+ #heartbeatInterval = 0;
125
+ #heartbeatSentAt = 0;
126
+ #lastMessageAt = 0;
127
+ #zombieTimer;
128
+ #zombieReported = false;
129
+ #closed = false;
130
+ #attempt = 0;
131
+ #reconnectTimer;
132
+ #connectPromise;
133
+ #resolveConnect;
134
+ #rejectConnect;
135
+ #listeners = new Map;
136
+ #sendTimestamps = [];
137
+ constructor(options) {
138
+ if (!options.token?.trim())
139
+ throw new TypeError("A Gateway token is required.");
140
+ const resolvedIntents = resolveGatewayIntents(options.intents);
141
+ if (!Number.isInteger(resolvedIntents) || resolvedIntents < 0)
142
+ throw new TypeError("Gateway intents must be a non-negative integer.");
143
+ this.#options = {
144
+ shardId: 0,
145
+ shardCount: 1,
146
+ reconnect: true,
147
+ maxReconnectAttempts: Infinity,
148
+ reconnectBaseDelay: 1000,
149
+ reconnectMaxDelay: 30000,
150
+ heartbeatAckTimeout: 1e4,
151
+ zombieTimeout: 30000,
152
+ properties: {
153
+ os: "Android",
154
+ browser: "Discord Android",
155
+ device: "Discord Android"
156
+ },
157
+ presence: { status: "online", activities: [], afk: false, since: null },
158
+ ...options
159
+ };
160
+ if (this.#options.shardId < 0 || this.#options.shardId >= this.#options.shardCount)
161
+ throw new RangeError("Gateway shardId must be within the configured shard count.");
162
+ if (this.#options.zombieTimeout <= this.#options.heartbeatAckTimeout)
163
+ throw new RangeError("Gateway zombieTimeout must be greater than heartbeatAckTimeout");
164
+ }
165
+ connect(url = "wss://gateway.discord.gg/?v=10&encoding=json") {
166
+ if (this.state === "CLOSED" /* Closed */)
167
+ throw new GatewayError("Gateway has been permanently closed.");
168
+ if (this.#connectPromise)
169
+ return this.#connectPromise;
170
+ this.#closed = false;
171
+ this.#setState("CONNECT" /* Connect */);
172
+ this.#connectPromise = new Promise((resolve, reject) => {
173
+ this.#resolveConnect = resolve;
174
+ this.#rejectConnect = reject;
175
+ this.#open(url);
176
+ });
177
+ return this.#connectPromise;
178
+ }
179
+ close() {
180
+ this.#closed = true;
181
+ this.#clearTimers();
182
+ this.#settleConnect(new GatewayError("Gateway connection closed before socket open."));
183
+ const ws = this.#ws;
184
+ this.#ws = undefined;
185
+ try {
186
+ ws?.close(1000, "Client closed connection");
187
+ } catch (error) {
188
+ this.#emitError(error);
189
+ }
190
+ this.#setState("CLOSED" /* Closed */);
191
+ }
192
+ emit(event, data) {
193
+ this.#emit(event, data);
194
+ }
195
+ on(event, listener) {
196
+ if (!event || typeof listener !== "function")
197
+ throw new TypeError("Gateway event and listener are required.");
198
+ let listeners = this.#listeners.get(event);
199
+ if (!listeners)
200
+ this.#listeners.set(event, listeners = new Set);
201
+ listeners.add(listener);
202
+ return this;
203
+ }
204
+ off(event, listener) {
205
+ this.#listeners.get(event)?.delete(listener);
206
+ return this;
207
+ }
208
+ send(payload) {
209
+ if (!payload || !Number.isInteger(payload.op))
210
+ throw new TypeError("Gateway payload must contain an integer opcode.");
211
+ if (this.#ws?.readyState !== WebSocket.OPEN)
212
+ return false;
213
+ const now = Date.now();
214
+ while (this.#sendTimestamps.length && now - this.#sendTimestamps[0] >= 60000)
215
+ this.#sendTimestamps.shift();
216
+ if (this.#sendTimestamps.length >= 115) {
217
+ this.#emitError(new GatewayError("Gateway send rate budget exhausted."));
218
+ return false;
219
+ }
220
+ try {
221
+ this.#ws.send(JSON.stringify(payload));
222
+ this.#sendTimestamps.push(now);
223
+ return true;
224
+ } catch (error) {
225
+ this.#emitError(error);
226
+ return false;
227
+ }
228
+ }
229
+ setPresence(data) {
230
+ this.#options.presence = { ...this.#options.presence, ...data };
231
+ const payload = {
232
+ since: this.#options.presence.since ?? null,
233
+ activities: this.#options.presence.activities ?? [],
234
+ status: this.#options.presence.status ?? "online",
235
+ afk: Boolean(this.#options.presence.afk)
236
+ };
237
+ return this.send({
238
+ op: GatewayOpcodes.PresenceUpdate,
239
+ d: payload,
240
+ s: null,
241
+ t: null
242
+ });
243
+ }
244
+ setVoiceState(data) {
245
+ return this.send({
246
+ op: GatewayOpcodes.VoiceStateUpdate,
247
+ d: data,
248
+ s: null,
249
+ t: null
250
+ });
251
+ }
252
+ requestGuildMembers(data) {
253
+ return this.send({
254
+ op: GatewayOpcodes.RequestGuildMembers,
255
+ d: data,
256
+ s: null,
257
+ t: null
258
+ });
259
+ }
260
+ #open(url) {
261
+ if (this.#closed)
262
+ return;
263
+ let ws;
264
+ try {
265
+ ws = new WebSocket(url);
266
+ } catch (error) {
267
+ const failure = this.#normalizeError(error);
268
+ this.#emitError(failure);
269
+ if (this.#options.reconnect) {
270
+ this.#setState("RECONNECT" /* Reconnect */);
271
+ this.#scheduleReconnect();
272
+ } else
273
+ this.#settleConnect(failure);
274
+ return;
275
+ }
276
+ this.#ws = ws;
277
+ ws.addEventListener("open", () => {
278
+ this.#lastMessageAt = Date.now();
279
+ this.#zombieReported = false;
280
+ this.#startZombieDetection();
281
+ this.#emit("open", undefined);
282
+ this.#settleConnect();
283
+ });
284
+ ws.addEventListener("message", (event) => {
285
+ this.#lastMessageAt = Date.now();
286
+ this.#zombieReported = false;
287
+ this.#message(ws, String(event.data));
288
+ });
289
+ ws.addEventListener("close", (event) => this.#close(ws, event.code));
290
+ ws.addEventListener("error", () => this.#emitError(new GatewayError("Gateway WebSocket error")));
291
+ }
292
+ #startZombieDetection() {
293
+ if (this.#zombieTimer)
294
+ clearInterval(this.#zombieTimer);
295
+ const interval = Math.max(1, Math.min(250, this.#options.heartbeatAckTimeout, this.#options.zombieTimeout / 2));
296
+ this.#zombieTimer = setInterval(() => {
297
+ if (this.#closed || this.#ws?.readyState !== WebSocket.OPEN || this.#lastMessageAt === 0)
298
+ return;
299
+ const silentFor = Date.now() - this.#lastMessageAt;
300
+ const deadline = Math.max(this.#options.zombieTimeout, this.#heartbeatInterval + this.#options.heartbeatAckTimeout);
301
+ if (silentFor < deadline || this.#zombieReported)
302
+ return;
303
+ this.#zombieReported = true;
304
+ const error = new GatewayError(`Gateway connection appears stale after ${silentFor}ms without traffic.`);
305
+ this.#emit("zombie", { silentFor, timeout: deadline });
306
+ this.#emitError(error);
307
+ try {
308
+ this.#ws.close(1001, "Zombie Gateway connection");
309
+ } catch (closeError) {
310
+ this.#emitError(closeError);
311
+ }
312
+ }, interval);
313
+ }
314
+ #message(ws, raw) {
315
+ let payload;
316
+ try {
317
+ payload = JSON.parse(raw);
318
+ } catch (error) {
319
+ this.#emitError(new GatewayError("Gateway returned invalid JSON", undefined, {
320
+ cause: error
321
+ }));
322
+ ws.close(1002, "Invalid JSON");
323
+ return;
324
+ }
325
+ if (!payload || typeof payload.op !== "number") {
326
+ this.#emitError(new GatewayError("Gateway returned an invalid payload"));
327
+ ws.close(1002, "Invalid payload");
328
+ return;
329
+ }
330
+ if (typeof payload.s === "number")
331
+ this.#sequence = payload.s;
332
+ switch (payload.op) {
333
+ case GatewayOpcodes.Dispatch:
334
+ this.#setState("DISPATCH" /* Dispatch */);
335
+ this.#handleDispatch(payload.t, payload.d);
336
+ break;
337
+ case GatewayOpcodes.Hello:
338
+ this.#handleHello(payload.d);
339
+ break;
340
+ case GatewayOpcodes.Heartbeat:
341
+ this.#setState("HEARTBEAT" /* Heartbeat */);
342
+ this.#sendHeartbeat();
343
+ break;
344
+ case GatewayOpcodes.HeartbeatAck:
345
+ this.#heartbeatACK = true;
346
+ this.#clearHeartbeatAckTimer();
347
+ this.#emit("heartbeatAck", payload.d);
348
+ break;
349
+ case GatewayOpcodes.Reconnect:
350
+ ws.close(1001, "Server requested reconnect");
351
+ break;
352
+ case GatewayOpcodes.InvalidSession:
353
+ this.#sessionId = undefined;
354
+ this.#sequence = null;
355
+ this.#emit("invalidSession", payload.d);
356
+ ws.close(1000, "Invalid session");
357
+ break;
358
+ }
359
+ }
360
+ #handleDispatch(event, data) {
361
+ if (event === "READY") {
362
+ const ready = data;
363
+ if (typeof ready?.session_id !== "string" || typeof ready?.resume_gateway_url !== "string") {
364
+ this.#emitError(new GatewayError("Gateway READY payload is missing session information"));
365
+ return;
366
+ }
367
+ this.#sessionId = ready.session_id;
368
+ this.#resumeURL = ready.resume_gateway_url;
369
+ this.#attempt = 0;
370
+ this.#setState("READY" /* Ready */);
371
+ this.#emit("ready", data);
372
+ }
373
+ this.#emit(event ?? "dispatch", data);
374
+ }
375
+ #handleHello(data) {
376
+ const interval = data?.heartbeat_interval;
377
+ if (typeof interval !== "number" || !Number.isFinite(interval) || interval <= 0) {
378
+ this.#emitError(new GatewayError("Gateway HELLO payload contains an invalid heartbeat interval"));
379
+ this.#ws?.close(1002, "Invalid heartbeat interval");
380
+ return;
381
+ }
382
+ this.#heartbeatInterval = interval;
383
+ this.#setState(this.#sessionId && this.#sequence !== null && this.#resumeURL ? "RESUME" /* Resume */ : "HELLO" /* Hello */);
384
+ this.#startHeartbeat(interval);
385
+ this.#identifyOrResume();
386
+ }
387
+ #identifyOrResume() {
388
+ if (this.#sessionId && this.#sequence !== null && this.#resumeURL) {
389
+ this.#setState("RESUME" /* Resume */);
390
+ this.send({
391
+ op: GatewayOpcodes.Resume,
392
+ d: {
393
+ token: this.#options.token,
394
+ session_id: this.#sessionId,
395
+ seq: this.#sequence
396
+ },
397
+ s: null,
398
+ t: null
399
+ });
400
+ return;
401
+ }
402
+ this.#setState("IDENTIFY" /* Identify */);
403
+ const props = this.#options.properties ?? {
404
+ os: "Android",
405
+ browser: "Discord Android",
406
+ device: "Discord Android"
407
+ };
408
+ const os = props.os ?? "Android";
409
+ const browser = props.browser ?? "Discord Android";
410
+ const device = props.device ?? "Discord Android";
411
+ this.send({
412
+ op: GatewayOpcodes.Identify,
413
+ d: {
414
+ token: this.#options.token,
415
+ intents: this.#options.intents,
416
+ properties: {
417
+ os,
418
+ browser,
419
+ device,
420
+ $os: os,
421
+ $browser: browser,
422
+ $device: device,
423
+ ...props
424
+ },
425
+ presence: {
426
+ since: this.#options.presence?.since ?? null,
427
+ activities: this.#options.presence?.activities ?? [],
428
+ status: this.#options.presence?.status ?? "online",
429
+ afk: Boolean(this.#options.presence?.afk)
430
+ },
431
+ shard: [this.#options.shardId, this.#options.shardCount]
432
+ },
433
+ s: null,
434
+ t: null
435
+ });
436
+ }
437
+ #startHeartbeat(interval) {
438
+ this.#clearHeartbeatTimers();
439
+ this.#heartbeatACK = true;
440
+ this.#initialHeartbeat = setTimeout(() => this.#sendHeartbeat(), Math.random() * interval);
441
+ this.#heartbeatTimer = setInterval(() => this.#sendHeartbeat(), interval);
442
+ }
443
+ #sendHeartbeat() {
444
+ this.#heartbeatACK = false;
445
+ this.#heartbeatSentAt = Date.now();
446
+ if (!this.send({
447
+ op: GatewayOpcodes.Heartbeat,
448
+ d: this.#sequence,
449
+ s: null,
450
+ t: null
451
+ })) {
452
+ this.#emitError(new GatewayError("Unable to send Gateway heartbeat because the WebSocket is not open."));
453
+ return;
454
+ }
455
+ this.#clearHeartbeatAckTimer();
456
+ this.#heartbeatAckTimer = setTimeout(() => {
457
+ if (!this.#heartbeatACK) {
458
+ const elapsed = Date.now() - this.#heartbeatSentAt;
459
+ this.#emitError(new GatewayError(`Gateway heartbeat acknowledgement timed out after ${elapsed}ms.`));
460
+ try {
461
+ this.#ws?.close(1001, "Heartbeat timeout");
462
+ } catch (error) {
463
+ this.#emitError(error);
464
+ }
465
+ }
466
+ }, this.#options.heartbeatAckTimeout);
467
+ }
468
+ #close(ws, code) {
469
+ if (this.#ws !== ws)
470
+ return;
471
+ this.#ws = undefined;
472
+ this.#clearTimers();
473
+ const action = this.#closeAction(code);
474
+ this.#emit("close", { code, action });
475
+ if (this.#closed || !this.#options.reconnect || action === "stop") {
476
+ this.#setState(this.#closed ? "CLOSED" /* Closed */ : "CONNECT" /* Connect */);
477
+ if (this.#connectPromise)
478
+ this.#settleConnect(new GatewayError(`Gateway closed before READY (code ${code}).`, code));
479
+ return;
480
+ }
481
+ if (action === "identify") {
482
+ this.#sequence = null;
483
+ this.#sessionId = undefined;
484
+ }
485
+ this.#setState("RECONNECT" /* Reconnect */);
486
+ this.#scheduleReconnect();
487
+ }
488
+ #closeAction(code) {
489
+ if ([4004, 4010, 4011, 4012, 4013, 4014].includes(code))
490
+ return "stop";
491
+ if ([4007, 4009].includes(code))
492
+ return "identify";
493
+ return this.#sessionId && this.#sequence !== null ? "resume" : "identify";
494
+ }
495
+ #scheduleReconnect() {
496
+ if (this.#closed || !this.#options.reconnect || this.#reconnectTimer)
497
+ return;
498
+ if (this.#attempt >= this.#options.maxReconnectAttempts) {
499
+ this.#settleConnect(new GatewayError("Gateway reconnect attempts exhausted."));
500
+ this.#setState("CONNECT" /* Connect */);
501
+ return;
502
+ }
503
+ const delay = Math.min(this.#options.reconnectMaxDelay, this.#options.reconnectBaseDelay * 2 ** this.#attempt++);
504
+ const jitter = Math.random() * Math.min(250, Math.max(1, delay * 0.25));
505
+ this.#reconnectTimer = setTimeout(() => {
506
+ this.#reconnectTimer = undefined;
507
+ this.#open(this.#resumeURL ?? "wss://gateway.discord.gg/?v=10&encoding=json");
508
+ }, delay + jitter);
509
+ }
510
+ #settleConnect(error) {
511
+ const resolve = this.#resolveConnect;
512
+ const reject = this.#rejectConnect;
513
+ this.#resolveConnect = undefined;
514
+ this.#rejectConnect = undefined;
515
+ this.#connectPromise = undefined;
516
+ if (error)
517
+ reject?.(error);
518
+ else
519
+ resolve?.();
520
+ }
521
+ #clearHeartbeatAckTimer() {
522
+ if (this.#heartbeatAckTimer)
523
+ clearTimeout(this.#heartbeatAckTimer);
524
+ this.#heartbeatAckTimer = undefined;
525
+ }
526
+ #clearHeartbeatTimers() {
527
+ if (this.#heartbeatTimer)
528
+ clearInterval(this.#heartbeatTimer);
529
+ if (this.#initialHeartbeat)
530
+ clearTimeout(this.#initialHeartbeat);
531
+ this.#clearHeartbeatAckTimer();
532
+ this.#heartbeatTimer = undefined;
533
+ this.#initialHeartbeat = undefined;
534
+ }
535
+ #clearTimers() {
536
+ if (this.#reconnectTimer)
537
+ clearTimeout(this.#reconnectTimer);
538
+ if (this.#zombieTimer)
539
+ clearInterval(this.#zombieTimer);
540
+ this.#reconnectTimer = undefined;
541
+ this.#zombieTimer = undefined;
542
+ this.#clearHeartbeatTimers();
543
+ }
544
+ #normalizeError(error) {
545
+ return error instanceof GatewayError ? error : new GatewayError("Gateway connection failed.", undefined, {
546
+ cause: error
547
+ });
548
+ }
549
+ #emitError(error) {
550
+ this.#emit("error", error instanceof Error ? error : new GatewayError(String(error)));
551
+ }
552
+ #emit(event, data) {
553
+ for (const listener of this.#listeners.get(event) ?? []) {
554
+ try {
555
+ const result = listener(data);
556
+ if (result && typeof result.then === "function")
557
+ Promise.resolve(result).catch((error) => {
558
+ if (event !== "error")
559
+ this.#emitError(error);
560
+ });
561
+ } catch (error) {
562
+ if (event !== "error")
563
+ this.#emitError(error);
564
+ }
565
+ }
566
+ }
567
+ #setState(next) {
568
+ if (this.state === next)
569
+ return;
570
+ const previous = this.state;
571
+ this.state = next;
572
+ this.#emit("stateChange", { previous, next });
573
+ }
574
+ }
575
+ export {
576
+ Gateway,
577
+ GatewayError,
578
+ GatewayOpcodes,
579
+ GatewayState
580
+ };
581
+
582
+ //# debugId=8F34B5651398B33564756E2164756E21