feat(WebSocketManager): support gateway capabilities

This commit is contained in:
Danial Raza
2026-09-09 18:05:08 +02:00
parent a4116036be
commit dd4f501a6c
6 changed files with 47 additions and 1 deletions
@@ -1,10 +1,13 @@
import type { AsyncEventEmitter } from '@vladfrangu/async_event_emitter';
import type { GatewayCapabilityBits } from 'discord-api-types/v10';
import { expectTypeOf } from 'vitest';
import type { ManagerShardEventsMap, WebSocketShardEventsMap, WebSocketManager } from '../../src/index.js';
declare const manager: WebSocketManager;
declare const eventMap: ManagerShardEventsMap;
expectTypeOf(manager.options.capabilities).toEqualTypeOf<GatewayCapabilityBits | 0>();
type AugmentedShardEventsMap = {
[K in keyof WebSocketShardEventsMap]: [...WebSocketShardEventsMap[K], shardId: number];
};
@@ -1,5 +1,5 @@
import type { GatewaySendPayload } from 'discord-api-types/v10';
import { GatewayOpcodes } from 'discord-api-types/v10';
import { GatewayCapabilityBits, GatewayOpcodes } from 'discord-api-types/v10';
import { describe, expect, test, vi } from 'vitest';
import { WebSocketManager, type IShardingStrategy } from '../../src/index.js';
import { mockGatewayInformation } from '../gateway.mock.js';
@@ -121,6 +121,33 @@ test('it handles passing in both shardIds and shardCount', async () => {
expect(await manager.getShardIds()).toStrictEqual([2, 3]);
});
describe('gateway capabilities', () => {
test('defaults to none', async () => {
const manager = new WebSocketManager({
token: 'A-Very-Fake-Token',
intents: 0,
async fetchGatewayInformation() {
return mockGatewayInformation;
},
});
expect(manager.options.capabilities).toBe(0);
});
test('with a provided bitfield', async () => {
const manager = new WebSocketManager({
token: 'A-Very-Fake-Token',
intents: 0,
capabilities: GatewayCapabilityBits.ChannelObfuscation,
async fetchGatewayInformation() {
return mockGatewayInformation;
},
});
expect(manager.options.capabilities).toBe(GatewayCapabilityBits.ChannelObfuscation);
});
});
test('strategies', async () => {
class MockStrategy implements IShardingStrategy {
public spawn = vi.fn();
@@ -4,6 +4,7 @@ import type { SessionInfo, WebSocketManager, WebSocketManagerOptions } from '../
export interface FetchingStrategyOptions extends Pick<
WebSocketManagerOptions,
| 'capabilities'
| 'compression'
| 'encoding'
| 'handshakeTimeout'
@@ -38,6 +39,7 @@ export interface IContextFetchingStrategy {
export async function managerToFetchingStrategyOptions(manager: WebSocketManager): Promise<FetchingStrategyOptions> {
return {
capabilities: manager.options.capabilities,
compression: manager.options.compression,
encoding: manager.options.encoding,
handshakeTimeout: manager.options.handshakeTimeout,
+1
View File
@@ -42,6 +42,7 @@ export const DefaultWebSocketManagerOptions = {
return new SimpleIdentifyThrottler(info.session_start_limit.max_concurrency);
},
buildStrategy: (manager) => new SimpleShardingStrategy(manager),
capabilities: 0,
shardCount: null,
shardIds: null,
largeThreshold: null,
+8
View File
@@ -3,6 +3,7 @@ import { range, type Awaitable } from '@discordjs/util';
import { AsyncEventEmitter } from '@vladfrangu/async_event_emitter';
import type {
APIGatewayBotInfo,
GatewayCapabilityBits,
GatewayIdentifyProperties,
GatewayPresenceUpdateData,
RESTGetAPIGatewayBotResult,
@@ -101,6 +102,13 @@ export interface OptionalWebSocketManagerOptions {
* ```
*/
buildStrategy(manager: WebSocketManager): IShardingStrategy;
/**
* The gateway capabilities to opt into
*
* @defaultValue `0`
* @see {@link https://discord.com/developers/docs/events/gateway-events#identify-gateway-capabilities}
*/
capabilities: GatewayCapabilityBits | 0;
/**
* The transport compression method to use - mutually exclusive with `useIdentifyCompression`
*
+5
View File
@@ -552,6 +552,7 @@ export class WebSocketShard extends AsyncEventEmitter<WebSocketShardEventsMap> {
`shard id: ${this.id.toString()}`,
`shard count: ${this.strategy.options.shardCount}`,
`intents: ${this.strategy.options.intents}`,
`capabilities: ${this.strategy.options.capabilities}`,
`compression: ${this.transportCompressionEnabled ? CompressionParameterMap[this.strategy.options.compression!] : this.identifyCompressionEnabled ? 'identify' : 'none'}`,
]);
@@ -567,6 +568,10 @@ export class WebSocketShard extends AsyncEventEmitter<WebSocketShardEventsMap> {
data.large_threshold = this.strategy.options.largeThreshold;
}
if (this.strategy.options.capabilities) {
data.capabilities = this.strategy.options.capabilities;
}
if (this.strategy.options.initialPresence) {
data.presence = this.strategy.options.initialPresence;
}