lunibee 0.2.3 → 0.3.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 +3 -3
- package/dist/builders/attachment.d.ts +8 -4
- package/dist/builders/commands.d.ts +122 -149
- package/dist/builders/components.d.ts +10 -150
- package/dist/builders/embed.d.ts +66 -37
- package/dist/builders/index.d.ts +0 -4
- package/dist/builders/index.js +112 -221
- package/dist/builders/index.js.map +10 -9
- package/dist/collection/cache.d.ts +15 -6
- package/dist/collection/index.d.ts +92 -17
- package/dist/collection/index.js +471 -279
- package/dist/collection/index.js.map +4 -4
- package/dist/core/api.d.ts +130 -0
- package/dist/core/channel-create.d.ts +72 -0
- package/dist/core/commands.d.ts +232 -0
- package/dist/core/events.d.ts +24 -7
- package/dist/core/handles.d.ts +157 -0
- package/dist/core/index.d.ts +68 -4
- package/dist/core/index.js +2639 -493
- package/dist/core/index.js.map +47 -37
- package/dist/core/permissions.d.ts +7 -7
- package/dist/formatters/index.js +9 -5
- package/dist/formatters/index.js.map +3 -3
- package/dist/handlers/index.js +5 -10
- package/dist/handlers/index.js.map +3 -3
- package/dist/index.d.ts +2 -2
- package/dist/index.js +9527 -7809
- package/dist/index.js.map +63 -53
- package/dist/managers/advanced.d.ts +29 -1
- package/dist/managers/base.d.ts +22 -14
- package/dist/managers/emoji.d.ts +0 -2
- package/dist/managers/guild-resources.d.ts +13 -5
- package/dist/managers/guild.d.ts +40 -4
- package/dist/managers/index.d.ts +21 -13
- package/dist/managers/index.js +969 -386
- package/dist/managers/index.js.map +30 -25
- package/dist/managers/member.d.ts +9 -2
- package/dist/managers/message.d.ts +10 -15
- package/dist/managers/role.d.ts +18 -10
- package/dist/managers/thread.d.ts +68 -0
- package/dist/managers/user.d.ts +18 -0
- package/dist/rest/errors.d.ts +14 -7
- package/dist/rest/index.d.ts +24 -12
- package/dist/rest/index.js +70 -20
- package/dist/rest/index.js.map +9 -9
- package/dist/rest/redis.d.ts +1 -1
- package/dist/rest/route.d.ts +8 -4
- package/dist/rest/routes.d.ts +122 -48
- package/dist/rest/transport.d.ts +10 -5
- package/dist/rest/webhook.d.ts +9 -5
- package/dist/sharding/bus.d.ts +47 -19
- package/dist/sharding/cluster.d.ts +11 -0
- package/dist/sharding/gateway-bot.d.ts +18 -0
- package/dist/sharding/index.d.ts +64 -25
- package/dist/sharding/index.js +439 -124
- package/dist/sharding/index.js.map +19 -14
- package/dist/sharding/supervisor.d.ts +32 -0
- package/dist/sharding/transport.d.ts +45 -0
- package/dist/structures/audit-log.d.ts +99 -2
- package/dist/structures/base.d.ts +40 -23
- package/dist/structures/channels.d.ts +45 -14
- package/dist/structures/index.d.ts +8 -12
- package/dist/structures/index.js +280 -132
- package/dist/structures/index.js.map +21 -15
- package/dist/structures/interactions.d.ts +91 -63
- package/dist/structures/resources.d.ts +99 -52
- package/dist/structures/sticker.d.ts +33 -0
- package/dist/types/channel-kind.d.ts +26 -0
- package/dist/types/gateway.d.ts +24 -12
- package/dist/types/index.d.ts +115 -113
- package/dist/types/index.js +53 -48
- package/dist/types/index.js.map +6 -5
- package/dist/voice/index.d.ts +12 -4
- package/dist/voice/index.js +14 -18
- package/dist/voice/index.js.map +3 -3
- package/dist/ws/decoder.d.ts +6 -2
- package/dist/ws/dispatcher.d.ts +19 -0
- package/dist/ws/index.d.ts +61 -15
- package/dist/ws/index.js +194 -77
- package/dist/ws/index.js.map +13 -11
- package/dist/ws/protocol.d.ts +10 -2
- package/dist/ws/reconnect.d.ts +10 -0
- package/dist/ws/send-budget.d.ts +6 -2
- package/dist/ws/session.d.ts +14 -4
- package/dist/ws/state.d.ts +22 -11
- package/package.json +20 -16
package/dist/ws/decoder.d.ts
CHANGED
|
@@ -42,8 +42,12 @@ export declare class PlainTextDecoder implements GatewayDecoder {
|
|
|
42
42
|
*/
|
|
43
43
|
export declare class ZlibStreamDecoder implements GatewayDecoder {
|
|
44
44
|
#private;
|
|
45
|
-
/**
|
|
46
|
-
|
|
45
|
+
/**
|
|
46
|
+
* @param create Inflater factory; injected in tests.
|
|
47
|
+
* @param maxFrameBytes Largest inflated frame accepted (default 64 MiB);
|
|
48
|
+
* past it the stream fails instead of growing until memory runs out.
|
|
49
|
+
*/
|
|
50
|
+
constructor(create?: () => Inflate, maxFrameBytes?: number);
|
|
47
51
|
/**
|
|
48
52
|
* A text frame on a compressed connection is already a complete frame, so
|
|
49
53
|
* it is returned synchronously and never touches the inflater. Discord
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/** Gateway event listener. */
|
|
2
|
+
export type GatewayListener = (data: unknown) => unknown;
|
|
3
|
+
/**
|
|
4
|
+
* Listener registry and emission for one Gateway.
|
|
5
|
+
*
|
|
6
|
+
* A listener that throws, or returns a promise that rejects, is isolated from
|
|
7
|
+
* the others and reported through `onFailure`, except for `error` listeners:
|
|
8
|
+
* a failing error listener must not report itself again.
|
|
9
|
+
*/
|
|
10
|
+
export declare class GatewayDispatcher {
|
|
11
|
+
#private;
|
|
12
|
+
constructor(onFailure: (error: unknown) => void);
|
|
13
|
+
/** Adds a listener. */
|
|
14
|
+
on(event: string, listener: GatewayListener): void;
|
|
15
|
+
/** Removes a listener. */
|
|
16
|
+
off(event: string, listener: GatewayListener): void;
|
|
17
|
+
/** Calls the listeners of `event` with `data`. */
|
|
18
|
+
emit(event: string, data: unknown): void;
|
|
19
|
+
}
|
package/dist/ws/index.d.ts
CHANGED
|
@@ -1,29 +1,48 @@
|
|
|
1
1
|
import { type SocketFactory } from "./transport.js";
|
|
2
2
|
import { type GatewayPayload, type GatewayProperties, type GatewayPresence, type GatewayIntentResolvable } from "@lunibee/types";
|
|
3
|
-
export { classifyFrame, classifyPayload, identifyPayload, resumePayload, heartbeatPayload, type GatewayAction, type ProtocolResult, type ProtocolViolation, type IdentifyOptions, type IdentifyProperties, } from "./protocol.js";
|
|
3
|
+
export { classifyFrame, classifyPayload, identifyPayload, resumePayload, heartbeatPayload, type GatewayAction, type ProtocolResult, type ProtocolViolation, type IdentifyOptions, type IdentifyProperties, type IdentifyData, } from "./protocol.js";
|
|
4
4
|
export { WebSocketTransport, type TransportHandlers, type TransportOptions, type SocketFactory, } from "./transport.js";
|
|
5
5
|
export { createDecoder, PlainTextDecoder, ZlibStreamDecoder, type GatewayDecoder, } from "./decoder.js";
|
|
6
6
|
export { GatewayReconnect, classifyCloseCode, FATAL_CLOSE_CODES, IDENTIFY_CLOSE_CODES, type CloseAction, type ReconnectOptions, type ScheduleResult, type ScheduleRefusal, } from "./reconnect.js";
|
|
7
7
|
export { GatewayHeartbeat, type HeartbeatOptions, type HeartbeatTimeout, } from "./heartbeat.js";
|
|
8
8
|
export { GatewaySession, type ResumeInfo, type HandshakeIntent, type InvalidationReason, } from "./session.js";
|
|
9
|
+
export { GatewayDispatcher, type GatewayListener } from "./dispatcher.js";
|
|
10
|
+
export { GatewaySendLimiter, SendBudget } from "./send-budget.js";
|
|
9
11
|
export { GatewayOpcodes } from "./opcodes.js";
|
|
10
12
|
export { GatewayCloseCodes } from "./close-codes.js";
|
|
11
13
|
export { GatewayState, Status, GatewayError } from "./state.js";
|
|
12
14
|
import { GatewayState } from "./state.js";
|
|
15
|
+
import { type GatewayListener } from "./dispatcher.js";
|
|
13
16
|
/** Gateway connection configuration. */
|
|
14
17
|
export interface GatewayOptions {
|
|
15
|
-
/** Authentication token. */
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
|
|
18
|
+
/** Authentication token. */
|
|
19
|
+
token: string;
|
|
20
|
+
/** Gateway intent bitfield or resolvable. */
|
|
21
|
+
intents: GatewayIntentResolvable;
|
|
22
|
+
/** Shard identifier. */
|
|
23
|
+
shardId?: number;
|
|
24
|
+
/** Total shard count. */
|
|
25
|
+
shardCount?: number;
|
|
26
|
+
/** Whether automatic reconnect is enabled. */
|
|
27
|
+
reconnect?: boolean;
|
|
28
|
+
/** Maximum reconnect attempts. */
|
|
29
|
+
maxReconnectAttempts?: number;
|
|
30
|
+
/** Initial reconnect delay. */
|
|
31
|
+
reconnectBaseDelay?: number;
|
|
32
|
+
/** Maximum reconnect delay. */
|
|
33
|
+
reconnectMaxDelay?: number;
|
|
34
|
+
/** Heartbeat acknowledgement timeout. */
|
|
35
|
+
heartbeatAckTimeout?: number;
|
|
36
|
+
/** Zombie connection timeout. */
|
|
37
|
+
zombieTimeout?: number;
|
|
38
|
+
/** Reconnects inside `reconnectStormWindow` after which the link counts as unstable: `unstable` is emitted and the delay keeps doubling. Default 5. */
|
|
39
|
+
reconnectStormLimit?: number;
|
|
40
|
+
/** The span over which reconnects are counted for storm detection, in ms. Default 60,000. */
|
|
41
|
+
reconnectStormWindow?: number;
|
|
42
|
+
/** Identification properties. */
|
|
43
|
+
properties?: GatewayProperties;
|
|
44
|
+
/** Presence data. */
|
|
45
|
+
presence?: GatewayPresence;
|
|
27
46
|
/**
|
|
28
47
|
* Whether to enable zlib-stream transport compression.
|
|
29
48
|
* Decoded with a persistent `node:zlib` inflate stream, matching
|
|
@@ -37,8 +56,17 @@ export interface GatewayOptions {
|
|
|
37
56
|
*/
|
|
38
57
|
createSocket?: SocketFactory;
|
|
39
58
|
}
|
|
40
|
-
/**
|
|
41
|
-
|
|
59
|
+
/** What {@link Gateway.health} reports. */
|
|
60
|
+
export interface GatewayHealth {
|
|
61
|
+
/** Connection lifecycle state. */
|
|
62
|
+
state: GatewayState;
|
|
63
|
+
/** Round trip of the last acknowledged heartbeat in ms, or -1 before the first. */
|
|
64
|
+
latency: number;
|
|
65
|
+
/** Milliseconds since the last message from Discord, or 0 before any. */
|
|
66
|
+
silentFor: number;
|
|
67
|
+
/** Reconnects scheduled since this Gateway was created. */
|
|
68
|
+
reconnects: number;
|
|
69
|
+
}
|
|
42
70
|
/** Manages a Discord Gateway connection. */
|
|
43
71
|
export declare class Gateway {
|
|
44
72
|
#private;
|
|
@@ -57,12 +85,30 @@ export declare class Gateway {
|
|
|
57
85
|
on(event: string, listener: GatewayListener): this;
|
|
58
86
|
/** Removes a Gateway event listener. @param event Event name. @param listener Event callback. @returns This Gateway. */
|
|
59
87
|
off(event: string, listener: GatewayListener): this;
|
|
88
|
+
/**
|
|
89
|
+
* A snapshot for dashboards and health checks: connection state, last
|
|
90
|
+
* heartbeat round trip, how long the link has been silent, and how many
|
|
91
|
+
* times it has reconnected.
|
|
92
|
+
*/
|
|
93
|
+
health(): GatewayHealth;
|
|
60
94
|
/** Sends a Gateway payload. @param payload Gateway payload. @returns Whether it was sent. */
|
|
61
95
|
send(payload: GatewayPayload): boolean;
|
|
62
96
|
/** Sends a presence update. @param data Presence payload. @returns Whether it was sent. */
|
|
63
97
|
setPresence(data: GatewayPresence): boolean;
|
|
64
98
|
/** Sends a voice state update. @param data Voice state payload. @returns Whether it was sent. */
|
|
65
99
|
setVoiceState(data: Record<string, unknown>): boolean;
|
|
100
|
+
/**
|
|
101
|
+
* Joins, moves or leaves a voice channel (op 4). Returns `false` without
|
|
102
|
+
* sending when the guild belongs to another shard, or when disconnected.
|
|
103
|
+
* @param guildId Guild snowflake. @param channelId Channel to join, or `null` to leave.
|
|
104
|
+
* @param options `selfMute` and `selfDeaf`, both default `false`. @returns Whether it was sent.
|
|
105
|
+
*/
|
|
106
|
+
sendVoiceState(guildId: string, channelId: string | null, options?: {
|
|
107
|
+
selfMute?: boolean;
|
|
108
|
+
selfDeaf?: boolean;
|
|
109
|
+
}): boolean;
|
|
110
|
+
/** Whether `guildId` maps to this Gateway's shard (`(id >> 22) % shardCount === shardId`). */
|
|
111
|
+
ownsGuild(guildId: string): boolean;
|
|
66
112
|
/** Requests guild members. @param data Guild member request payload. @returns Whether it was sent. */
|
|
67
113
|
requestGuildMembers(data: Record<string, unknown>): boolean;
|
|
68
114
|
}
|
package/dist/ws/index.js
CHANGED
|
@@ -73,7 +73,26 @@ class GatewaySession {
|
|
|
73
73
|
return resume ? { type: "resume", ...resume } : { type: "identify" };
|
|
74
74
|
}
|
|
75
75
|
connectURL(fallback) {
|
|
76
|
-
|
|
76
|
+
const resume = this.resumeInfo()?.resumeURL;
|
|
77
|
+
return resume !== undefined && isTrustedGatewayURL(resume, fallback) ? resume : fallback;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
function isTrustedGatewayURL(url, fallback) {
|
|
81
|
+
let parsed;
|
|
82
|
+
try {
|
|
83
|
+
parsed = new URL(url);
|
|
84
|
+
} catch {
|
|
85
|
+
return false;
|
|
86
|
+
}
|
|
87
|
+
if (parsed.protocol !== "wss:" || parsed.username || parsed.password)
|
|
88
|
+
return false;
|
|
89
|
+
const host = parsed.hostname.toLowerCase();
|
|
90
|
+
if (host === "discord.gg" || host.endsWith(".discord.gg"))
|
|
91
|
+
return true;
|
|
92
|
+
try {
|
|
93
|
+
return host === new URL(fallback).hostname.toLowerCase();
|
|
94
|
+
} catch {
|
|
95
|
+
return false;
|
|
77
96
|
}
|
|
78
97
|
}
|
|
79
98
|
|
|
@@ -245,6 +264,7 @@ class GatewayReconnect {
|
|
|
245
264
|
#options;
|
|
246
265
|
#random;
|
|
247
266
|
#attempt = 0;
|
|
267
|
+
#recent = [];
|
|
248
268
|
#timer;
|
|
249
269
|
#promise;
|
|
250
270
|
#resolve;
|
|
@@ -285,14 +305,29 @@ class GatewayReconnect {
|
|
|
285
305
|
if (this.exhausted)
|
|
286
306
|
return { scheduled: false, reason: "exhausted" };
|
|
287
307
|
const attempt = this.#attempt;
|
|
288
|
-
const
|
|
308
|
+
const now = (this.#options.now ?? Date.now)();
|
|
309
|
+
const window = this.#options.stormWindow ?? 60000;
|
|
310
|
+
const limit = this.#options.stormLimit ?? 5;
|
|
311
|
+
while (this.#recent.length && now - this.#recent[0] >= window)
|
|
312
|
+
this.#recent.shift();
|
|
313
|
+
const over = this.#recent.length - limit;
|
|
314
|
+
this.#recent.push(now);
|
|
315
|
+
let delay = Math.min(this.#options.maxDelay, this.#options.baseDelay * 2 ** this.#attempt++);
|
|
316
|
+
const unstable = over >= 0;
|
|
317
|
+
if (unstable)
|
|
318
|
+
delay = Math.min(this.#options.maxDelay, Math.max(delay, this.#options.baseDelay * 2 ** (over + 1)));
|
|
289
319
|
const jitter = this.#random() * Math.max(1, delay * 0.25);
|
|
290
320
|
const delayMs = delay + jitter;
|
|
291
321
|
this.#timer = setTimeout(() => {
|
|
292
322
|
this.#timer = undefined;
|
|
293
323
|
run();
|
|
294
324
|
}, delayMs);
|
|
295
|
-
return {
|
|
325
|
+
return {
|
|
326
|
+
scheduled: true,
|
|
327
|
+
delayMs,
|
|
328
|
+
attempt,
|
|
329
|
+
...unstable ? { unstable: { reconnects: this.#recent.length } } : {}
|
|
330
|
+
};
|
|
296
331
|
}
|
|
297
332
|
cancel() {
|
|
298
333
|
if (this.#timer)
|
|
@@ -349,12 +384,15 @@ class PlainTextDecoder {
|
|
|
349
384
|
|
|
350
385
|
class ZlibStreamDecoder {
|
|
351
386
|
#create;
|
|
387
|
+
#maxFrameBytes;
|
|
352
388
|
#inflate;
|
|
353
389
|
#chunks = [];
|
|
390
|
+
#size = 0;
|
|
354
391
|
#failure;
|
|
355
392
|
#pendingReject;
|
|
356
|
-
constructor(create = () => createInflate()) {
|
|
393
|
+
constructor(create = () => createInflate(), maxFrameBytes = 64 * 1024 * 1024) {
|
|
357
394
|
this.#create = create;
|
|
395
|
+
this.#maxFrameBytes = maxFrameBytes;
|
|
358
396
|
}
|
|
359
397
|
push(data) {
|
|
360
398
|
if (typeof data === "string")
|
|
@@ -373,6 +411,7 @@ class ZlibStreamDecoder {
|
|
|
373
411
|
await this.#awaiting((settle) => inflate.flush(zlibConstants.Z_SYNC_FLUSH, () => settle()));
|
|
374
412
|
const parts = this.#chunks;
|
|
375
413
|
this.#chunks = [];
|
|
414
|
+
this.#size = 0;
|
|
376
415
|
if (parts.length === 0)
|
|
377
416
|
return [];
|
|
378
417
|
const total = parts.reduce((size, part) => size + part.length, 0);
|
|
@@ -388,6 +427,7 @@ class ZlibStreamDecoder {
|
|
|
388
427
|
const inflate = this.#inflate;
|
|
389
428
|
this.#inflate = undefined;
|
|
390
429
|
this.#chunks = [];
|
|
430
|
+
this.#size = 0;
|
|
391
431
|
this.#failure = undefined;
|
|
392
432
|
this.#pendingReject = undefined;
|
|
393
433
|
if (!inflate)
|
|
@@ -415,7 +455,17 @@ class ZlibStreamDecoder {
|
|
|
415
455
|
}
|
|
416
456
|
#open() {
|
|
417
457
|
const inflate = this.#create();
|
|
418
|
-
inflate.on("data", (chunk) =>
|
|
458
|
+
inflate.on("data", (chunk) => {
|
|
459
|
+
if (this.#failure)
|
|
460
|
+
return;
|
|
461
|
+
this.#size += chunk.length;
|
|
462
|
+
if (this.#size > this.#maxFrameBytes) {
|
|
463
|
+
this.#chunks = [];
|
|
464
|
+
inflate.emit("error", new Error(`Gateway frame inflated past ${this.#maxFrameBytes} bytes.`));
|
|
465
|
+
return;
|
|
466
|
+
}
|
|
467
|
+
this.#chunks.push(chunk);
|
|
468
|
+
});
|
|
419
469
|
inflate.on("error", (error) => {
|
|
420
470
|
this.#failure = error;
|
|
421
471
|
const reject = this.#pendingReject;
|
|
@@ -658,9 +708,9 @@ function classifyPayload(payload) {
|
|
|
658
708
|
}
|
|
659
709
|
function identifyPayload(options) {
|
|
660
710
|
const props = options.properties ?? {};
|
|
661
|
-
const os = props.os ??
|
|
662
|
-
const browser = props.browser ?? "
|
|
663
|
-
const device = props.device ?? "
|
|
711
|
+
const os = props.os ?? process.platform;
|
|
712
|
+
const browser = props.browser ?? "Lunibee";
|
|
713
|
+
const device = props.device ?? "Lunibee";
|
|
664
714
|
return {
|
|
665
715
|
op: GatewayOpcodes.Identify,
|
|
666
716
|
d: {
|
|
@@ -703,6 +753,21 @@ function heartbeatPayload(sequence) {
|
|
|
703
753
|
return { op: GatewayOpcodes.Heartbeat, d: sequence, s: null, t: null };
|
|
704
754
|
}
|
|
705
755
|
|
|
756
|
+
// packages/types/src/channel-kind.ts
|
|
757
|
+
var ChannelKinds = {
|
|
758
|
+
text: [0],
|
|
759
|
+
dm: [1],
|
|
760
|
+
voice: [2],
|
|
761
|
+
"group-dm": [3],
|
|
762
|
+
category: [4],
|
|
763
|
+
announcement: [5],
|
|
764
|
+
thread: [10, 11, 12],
|
|
765
|
+
stage: [13],
|
|
766
|
+
directory: [14],
|
|
767
|
+
forum: [15],
|
|
768
|
+
media: [16]
|
|
769
|
+
};
|
|
770
|
+
var KIND_OF_TYPE = new Map(Object.keys(ChannelKinds).flatMap((kind) => ChannelKinds[kind].map((type) => [type, kind])));
|
|
706
771
|
// packages/types/src/gateway.ts
|
|
707
772
|
var GatewayIntentBits = {
|
|
708
773
|
Guilds: 1 << 0,
|
|
@@ -756,52 +821,59 @@ var IntentBits = {
|
|
|
756
821
|
directMessagePolls: 1 << 25
|
|
757
822
|
};
|
|
758
823
|
function resolveGatewayIntents(intents) {
|
|
759
|
-
if (
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
return intents.bitfield;
|
|
763
|
-
if (Array.isArray(intents)) {
|
|
764
|
-
return intents.reduce((acc, intent) => {
|
|
765
|
-
return acc | resolveGatewayIntents(intent);
|
|
766
|
-
}, 0);
|
|
767
|
-
}
|
|
768
|
-
if (typeof intents === "string") {
|
|
769
|
-
if (intents in GatewayIntentBits)
|
|
770
|
-
return GatewayIntentBits[intents];
|
|
771
|
-
if (intents in IntentBits)
|
|
772
|
-
return IntentBits[intents];
|
|
773
|
-
const lower = intents.charAt(0).toLowerCase() + intents.slice(1);
|
|
774
|
-
if (lower in IntentBits)
|
|
775
|
-
return IntentBits[lower];
|
|
776
|
-
const num = Number(intents);
|
|
777
|
-
if (!Number.isNaN(num))
|
|
778
|
-
return num;
|
|
779
|
-
}
|
|
780
|
-
return 0;
|
|
824
|
+
if (!Array.isArray(intents))
|
|
825
|
+
throw new TypeError("Gateway intents must be an array, e.g. [GatewayIntentBits.Guilds, GatewayIntentBits.GuildMessages].");
|
|
826
|
+
return intents.reduce((acc, intent) => acc | resolveIntent(intent), 0);
|
|
781
827
|
}
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
828
|
+
function resolveIntent(intent) {
|
|
829
|
+
if (typeof intent === "number")
|
|
830
|
+
return intent;
|
|
831
|
+
const bits = {
|
|
832
|
+
...IntentBits,
|
|
833
|
+
...GatewayIntentBits
|
|
834
|
+
};
|
|
835
|
+
const lower = intent.charAt(0).toLowerCase() + intent.slice(1);
|
|
836
|
+
if (Object.hasOwn(bits, intent))
|
|
837
|
+
return bits[intent];
|
|
838
|
+
if (Object.hasOwn(bits, lower))
|
|
839
|
+
return bits[lower];
|
|
840
|
+
const num = Number(intent);
|
|
841
|
+
return Number.isNaN(num) ? 0 : num;
|
|
842
|
+
}
|
|
843
|
+
// packages/ws/src/dispatcher.ts
|
|
844
|
+
class GatewayDispatcher {
|
|
845
|
+
#listeners = new Map;
|
|
846
|
+
#onFailure;
|
|
847
|
+
constructor(onFailure) {
|
|
848
|
+
this.#onFailure = onFailure;
|
|
849
|
+
}
|
|
850
|
+
on(event, listener) {
|
|
851
|
+
let listeners = this.#listeners.get(event);
|
|
852
|
+
if (!listeners)
|
|
853
|
+
this.#listeners.set(event, listeners = new Set);
|
|
854
|
+
listeners.add(listener);
|
|
855
|
+
}
|
|
856
|
+
off(event, listener) {
|
|
857
|
+
this.#listeners.get(event)?.delete(listener);
|
|
858
|
+
}
|
|
859
|
+
emit(event, data) {
|
|
860
|
+
for (const listener of this.#listeners.get(event) ?? []) {
|
|
861
|
+
try {
|
|
862
|
+
const result = listener(data);
|
|
863
|
+
if (result && typeof result.then === "function")
|
|
864
|
+
Promise.resolve(result).catch((error) => {
|
|
865
|
+
if (event !== "error")
|
|
866
|
+
this.#onFailure(error);
|
|
867
|
+
});
|
|
868
|
+
} catch (error) {
|
|
869
|
+
if (event !== "error")
|
|
870
|
+
this.#onFailure(error);
|
|
871
|
+
}
|
|
872
|
+
}
|
|
801
873
|
}
|
|
802
874
|
}
|
|
803
875
|
// packages/ws/src/send-budget.ts
|
|
804
|
-
class
|
|
876
|
+
class GatewaySendLimiter {
|
|
805
877
|
#timestamps = [];
|
|
806
878
|
#limit;
|
|
807
879
|
#windowMs;
|
|
@@ -821,7 +893,28 @@ class SendBudget {
|
|
|
821
893
|
this.#timestamps.push(now);
|
|
822
894
|
}
|
|
823
895
|
}
|
|
824
|
-
|
|
896
|
+
var SendBudget = GatewaySendLimiter;
|
|
897
|
+
// packages/ws/src/state.ts
|
|
898
|
+
var GatewayState;
|
|
899
|
+
((GatewayState) => {
|
|
900
|
+
GatewayState["Connect"] = "CONNECT";
|
|
901
|
+
GatewayState["Hello"] = "HELLO";
|
|
902
|
+
GatewayState["Identify"] = "IDENTIFY";
|
|
903
|
+
GatewayState["Resume"] = "RESUME";
|
|
904
|
+
GatewayState["Ready"] = "READY";
|
|
905
|
+
GatewayState["Dispatch"] = "DISPATCH";
|
|
906
|
+
GatewayState["Heartbeat"] = "HEARTBEAT";
|
|
907
|
+
GatewayState["Reconnect"] = "RECONNECT";
|
|
908
|
+
GatewayState["Closed"] = "CLOSED";
|
|
909
|
+
})(GatewayState ||= {});
|
|
910
|
+
class GatewayError extends Error {
|
|
911
|
+
code;
|
|
912
|
+
constructor(message, code, options) {
|
|
913
|
+
super(message, options);
|
|
914
|
+
this.name = "GatewayError";
|
|
915
|
+
this.code = code;
|
|
916
|
+
}
|
|
917
|
+
}
|
|
825
918
|
// packages/ws/src/index.ts
|
|
826
919
|
var RESUMABLE_CLOSE_CODE = 4900;
|
|
827
920
|
var DEFAULT_GATEWAY_URL = "wss://gateway.discord.gg/?v=10&encoding=json";
|
|
@@ -835,8 +928,9 @@ class Gateway {
|
|
|
835
928
|
#heartbeat;
|
|
836
929
|
#closed = false;
|
|
837
930
|
#reconnect;
|
|
838
|
-
#
|
|
839
|
-
#sendBudget = new
|
|
931
|
+
#events = new GatewayDispatcher((error) => this.#emitError(error));
|
|
932
|
+
#sendBudget = new GatewaySendLimiter;
|
|
933
|
+
#reconnects = 0;
|
|
840
934
|
ping = -1;
|
|
841
935
|
constructor(options) {
|
|
842
936
|
if (!options.token?.trim())
|
|
@@ -854,9 +948,9 @@ class Gateway {
|
|
|
854
948
|
heartbeatAckTimeout: 1e4,
|
|
855
949
|
zombieTimeout: 30000,
|
|
856
950
|
properties: {
|
|
857
|
-
os:
|
|
858
|
-
browser: "
|
|
859
|
-
device: "
|
|
951
|
+
os: process.platform,
|
|
952
|
+
browser: "Lunibee",
|
|
953
|
+
device: "Lunibee"
|
|
860
954
|
},
|
|
861
955
|
presence: {
|
|
862
956
|
status: "online",
|
|
@@ -887,7 +981,9 @@ class Gateway {
|
|
|
887
981
|
enabled: this.#options.reconnect,
|
|
888
982
|
maxAttempts: this.#options.maxReconnectAttempts,
|
|
889
983
|
baseDelay: this.#options.reconnectBaseDelay,
|
|
890
|
-
maxDelay: this.#options.reconnectMaxDelay
|
|
984
|
+
maxDelay: this.#options.reconnectMaxDelay,
|
|
985
|
+
stormLimit: options.reconnectStormLimit,
|
|
986
|
+
stormWindow: options.reconnectStormWindow
|
|
891
987
|
});
|
|
892
988
|
this.#heartbeat = new GatewayHeartbeat({
|
|
893
989
|
ackTimeout: this.#options.heartbeatAckTimeout,
|
|
@@ -938,16 +1034,21 @@ class Gateway {
|
|
|
938
1034
|
on(event, listener) {
|
|
939
1035
|
if (!event || typeof listener !== "function")
|
|
940
1036
|
throw new TypeError("Gateway event and listener are required.");
|
|
941
|
-
|
|
942
|
-
if (!listeners)
|
|
943
|
-
this.#listeners.set(event, listeners = new Set);
|
|
944
|
-
listeners.add(listener);
|
|
1037
|
+
this.#events.on(event, listener);
|
|
945
1038
|
return this;
|
|
946
1039
|
}
|
|
947
1040
|
off(event, listener) {
|
|
948
|
-
this.#
|
|
1041
|
+
this.#events.off(event, listener);
|
|
949
1042
|
return this;
|
|
950
1043
|
}
|
|
1044
|
+
health() {
|
|
1045
|
+
return {
|
|
1046
|
+
state: this.state,
|
|
1047
|
+
latency: this.#heartbeat.latency,
|
|
1048
|
+
silentFor: this.#heartbeat.silentFor,
|
|
1049
|
+
reconnects: this.#reconnects
|
|
1050
|
+
};
|
|
1051
|
+
}
|
|
951
1052
|
send(payload) {
|
|
952
1053
|
if (!payload || !Number.isInteger(payload.op))
|
|
953
1054
|
throw new TypeError("Gateway payload must contain an integer opcode.");
|
|
@@ -989,6 +1090,22 @@ class Gateway {
|
|
|
989
1090
|
t: null
|
|
990
1091
|
});
|
|
991
1092
|
}
|
|
1093
|
+
sendVoiceState(guildId, channelId, options = {}) {
|
|
1094
|
+
if (!this.ownsGuild(guildId))
|
|
1095
|
+
return false;
|
|
1096
|
+
return this.setVoiceState({
|
|
1097
|
+
guild_id: guildId,
|
|
1098
|
+
channel_id: channelId,
|
|
1099
|
+
self_mute: options.selfMute ?? false,
|
|
1100
|
+
self_deaf: options.selfDeaf ?? false
|
|
1101
|
+
});
|
|
1102
|
+
}
|
|
1103
|
+
ownsGuild(guildId) {
|
|
1104
|
+
const count = this.#options.shardCount;
|
|
1105
|
+
if (count <= 1)
|
|
1106
|
+
return true;
|
|
1107
|
+
return Number((BigInt(guildId) >> 22n) % BigInt(count)) === this.#options.shardId;
|
|
1108
|
+
}
|
|
992
1109
|
requestGuildMembers(data) {
|
|
993
1110
|
return this.send({
|
|
994
1111
|
op: GatewayOpcodes.RequestGuildMembers,
|
|
@@ -1126,7 +1243,16 @@ class Gateway {
|
|
|
1126
1243
|
if (this.#closed)
|
|
1127
1244
|
return;
|
|
1128
1245
|
const result = this.#reconnect.schedule(() => this.#open(this.#session.connectURL(DEFAULT_GATEWAY_URL)));
|
|
1129
|
-
if (result.scheduled
|
|
1246
|
+
if (result.scheduled) {
|
|
1247
|
+
this.#reconnects++;
|
|
1248
|
+
if (result.unstable)
|
|
1249
|
+
this.#emit("unstable", {
|
|
1250
|
+
reconnects: result.unstable.reconnects,
|
|
1251
|
+
delay: result.delayMs
|
|
1252
|
+
});
|
|
1253
|
+
return;
|
|
1254
|
+
}
|
|
1255
|
+
if (result.reason !== "exhausted")
|
|
1130
1256
|
return;
|
|
1131
1257
|
this.#reconnect.settle(new GatewayError("Gateway reconnect attempts exhausted."));
|
|
1132
1258
|
this.#setState("CONNECT" /* Connect */);
|
|
@@ -1147,19 +1273,7 @@ class Gateway {
|
|
|
1147
1273
|
this.#emit("error", error instanceof Error ? error : new GatewayError(String(error)));
|
|
1148
1274
|
}
|
|
1149
1275
|
#emit(event, data) {
|
|
1150
|
-
|
|
1151
|
-
try {
|
|
1152
|
-
const result = listener(data);
|
|
1153
|
-
if (result && typeof result.then === "function")
|
|
1154
|
-
Promise.resolve(result).catch((error) => {
|
|
1155
|
-
if (event !== "error")
|
|
1156
|
-
this.#emitError(error);
|
|
1157
|
-
});
|
|
1158
|
-
} catch (error) {
|
|
1159
|
-
if (event !== "error")
|
|
1160
|
-
this.#emitError(error);
|
|
1161
|
-
}
|
|
1162
|
-
}
|
|
1276
|
+
this.#events.emit(event, data);
|
|
1163
1277
|
}
|
|
1164
1278
|
#setState(next) {
|
|
1165
1279
|
if (this.state === next)
|
|
@@ -1173,14 +1287,17 @@ export {
|
|
|
1173
1287
|
FATAL_CLOSE_CODES,
|
|
1174
1288
|
Gateway,
|
|
1175
1289
|
GatewayCloseCodes,
|
|
1290
|
+
GatewayDispatcher,
|
|
1176
1291
|
GatewayError,
|
|
1177
1292
|
GatewayHeartbeat,
|
|
1178
1293
|
GatewayOpcodes,
|
|
1179
1294
|
GatewayReconnect,
|
|
1295
|
+
GatewaySendLimiter,
|
|
1180
1296
|
GatewaySession,
|
|
1181
1297
|
GatewayState,
|
|
1182
1298
|
IDENTIFY_CLOSE_CODES,
|
|
1183
1299
|
PlainTextDecoder,
|
|
1300
|
+
SendBudget,
|
|
1184
1301
|
GatewayState as Status,
|
|
1185
1302
|
WebSocketTransport,
|
|
1186
1303
|
ZlibStreamDecoder,
|
|
@@ -1193,4 +1310,4 @@ export {
|
|
|
1193
1310
|
resumePayload
|
|
1194
1311
|
};
|
|
1195
1312
|
|
|
1196
|
-
//# debugId=
|
|
1313
|
+
//# debugId=BCA247EAFCA9772B64756E2164756E21
|