fix(voice): always install Davey as DAVE is becoming required (#11385)

* fix(voice): always install Davey as DAVE is becoming required

* chore: requested changes

---------

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
This commit is contained in:
Vlad Frangu
2026-01-25 22:28:04 +02:00
committed by GitHub
parent 3550b497f6
commit 323d8e7571
6 changed files with 14 additions and 31 deletions

View File

@@ -62,13 +62,13 @@ After this, you'll be able to play Ogg and WebM Opus files without any other dep
- [`@noble/ciphers`](https://www.npmjs.com/package/@noble/ciphers) - [`@noble/ciphers`](https://www.npmjs.com/package/@noble/ciphers)
- [`libsodium-wrappers`](https://www.npmjs.com/package/libsodium-wrappers) - [`libsodium-wrappers`](https://www.npmjs.com/package/libsodium-wrappers)
#### DAVE Protocol Support #### DAVE Protocol Support for end-to-end encryption of voice audio
- [`@snazzah/davey`](https://www.npmjs.com/package/@snazzah/davey) - to enable end-to-end encryption with the DAVE protocol. - [`@snazzah/davey`](https://www.npmjs.com/package/@snazzah/davey)
<Callout> <Callout>
Some Discord clients already require the DAVE protocol for end-to-end encryption in voice chat. Ensure you have At this time, `@snazzah/davey` is the only supported DAVE protocol library in this package, and comes pre-installed.
`@snazzah/davey` installed to avoid compatibility issues. In the future, we may support other libraries once they are created.
</Callout> </Callout>
<Callout> <Callout>

View File

@@ -65,7 +65,7 @@ try installing another.
**DAVE Protocol Libraries (e2ee)** **DAVE Protocol Libraries (e2ee)**
> [!NOTE] > [!NOTE]
> Some Discord clients may require the DAVE protocol for end-to-end encryption in voice chat and refuse to downgrade the connection in the future. Ensure you have `@snazzah/davey` installed to avoid compatibility issues. > At this time, `@snazzah/davey` is the only supported DAVE protocol library in this package, and comes pre-installed. In the future, we may support other libraries once they are created.
- `@snazzah/davey`: ^0.1.6 - `@snazzah/davey`: ^0.1.6

View File

@@ -63,6 +63,7 @@
"homepage": "https://discord.js.org", "homepage": "https://discord.js.org",
"funding": "https://github.com/discordjs/discord.js?sponsor", "funding": "https://github.com/discordjs/discord.js?sponsor",
"dependencies": { "dependencies": {
"@snazzah/davey": "^0.1.8",
"@types/ws": "^8.18.1", "@types/ws": "^8.18.1",
"discord-api-types": "^0.38.36", "discord-api-types": "^0.38.36",
"prism-media": "^1.3.5", "prism-media": "^1.3.5",
@@ -75,7 +76,6 @@
"@discordjs/scripts": "workspace:^", "@discordjs/scripts": "workspace:^",
"@favware/cliff-jumper": "^6.0.0", "@favware/cliff-jumper": "^6.0.0",
"@noble/ciphers": "^2.1.1", "@noble/ciphers": "^2.1.1",
"@snazzah/davey": "^0.1.8",
"@types/node": "^22.19.2", "@types/node": "^22.19.2",
"@vitest/coverage-v8": "^4.0.15", "@vitest/coverage-v8": "^4.0.15",
"cross-env": "^10.1.0", "cross-env": "^10.1.0",

View File

@@ -1,5 +1,6 @@
import { Buffer } from 'node:buffer'; import { Buffer } from 'node:buffer';
import { EventEmitter } from 'node:events'; import { EventEmitter } from 'node:events';
import Davey from '@snazzah/davey';
import type { VoiceDavePrepareEpochData, VoiceDavePrepareTransitionData } from 'discord-api-types/voice/v8'; import type { VoiceDavePrepareEpochData, VoiceDavePrepareTransitionData } from 'discord-api-types/voice/v8';
import { SILENCE_FRAME } from '../audio/AudioPlayer'; import { SILENCE_FRAME } from '../audio/AudioPlayer';
@@ -25,8 +26,6 @@ interface ProposalsResult {
welcome?: Buffer; welcome?: Buffer;
} }
let Davey: any = null;
/** /**
* The amount of seconds that a previous transition should be valid for. * The amount of seconds that a previous transition should be valid for.
*/ */
@@ -45,16 +44,6 @@ const TRANSITION_EXPIRY_PENDING_DOWNGRADE = 24;
*/ */
export const DEFAULT_DECRYPTION_FAILURE_TOLERANCE = 36; export const DEFAULT_DECRYPTION_FAILURE_TOLERANCE = 36;
// eslint-disable-next-line no-async-promise-executor
export const daveLoadPromise = new Promise<void>(async (resolve) => {
try {
const lib = await import('@snazzah/davey');
Davey = lib;
} catch {}
resolve();
});
interface TransitionResult { interface TransitionResult {
success: boolean; success: boolean;
transitionId: number; transitionId: number;
@@ -69,8 +58,8 @@ export interface DAVESessionOptions {
/** /**
* The maximum DAVE protocol version supported. * The maximum DAVE protocol version supported.
*/ */
export function getMaxProtocolVersion(): number | null { export function getMaxProtocolVersion(): number {
return Davey?.DAVE_PROTOCOL_VERSION; return Davey.DAVE_PROTOCOL_VERSION;
} }
export interface DAVESession extends EventEmitter { export interface DAVESession extends EventEmitter {
@@ -135,12 +124,6 @@ export class DAVESession extends EventEmitter {
public session: SessionMethods | undefined; public session: SessionMethods | undefined;
public constructor(protocolVersion: number, userId: string, channelId: string, options: DAVESessionOptions) { public constructor(protocolVersion: number, userId: string, channelId: string, options: DAVESessionOptions) {
if (Davey === null)
throw new Error(
`Cannot utilize the DAVE protocol as the @snazzah/davey package has not been installed.
- Use the generateDependencyReport() function for more information.\n`,
);
super(); super();
this.protocolVersion = protocolVersion; this.protocolVersion = protocolVersion;
@@ -379,6 +362,7 @@ export class DAVESession extends EventEmitter {
const canDecrypt = this.session?.ready && (this.protocolVersion !== 0 || this.session?.canPassthrough(userId)); const canDecrypt = this.session?.ready && (this.protocolVersion !== 0 || this.session?.canPassthrough(userId));
if (packet.equals(SILENCE_FRAME) || !canDecrypt || !this.session) return packet; if (packet.equals(SILENCE_FRAME) || !canDecrypt || !this.session) return packet;
try { try {
// @ts-expect-error - const enum is exported and works (todo: drop const modifier on Davey end)
const buffer = this.session.decrypt(userId, Davey.MediaType.AUDIO, packet); const buffer = this.session.decrypt(userId, Davey.MediaType.AUDIO, packet);
this.consecutiveFailures = 0; this.consecutiveFailures = 0;
return buffer; return buffer;

View File

@@ -363,7 +363,6 @@ export class Networking extends EventEmitter {
*/ */
private createDaveSession(protocolVersion: number) { private createDaveSession(protocolVersion: number) {
if ( if (
getMaxProtocolVersion() === null ||
this.options.daveEncryption === false || this.options.daveEncryption === false ||
(this.state.code !== NetworkingStatusCode.SelectingProtocol && (this.state.code !== NetworkingStatusCode.SelectingProtocol &&
this.state.code !== NetworkingStatusCode.Ready && this.state.code !== NetworkingStatusCode.Ready &&
@@ -412,7 +411,7 @@ export class Networking extends EventEmitter {
user_id: this.state.connectionOptions.userId, user_id: this.state.connectionOptions.userId,
session_id: this.state.connectionOptions.sessionId, session_id: this.state.connectionOptions.sessionId,
token: this.state.connectionOptions.token, token: this.state.connectionOptions.token,
max_dave_protocol_version: this.options.daveEncryption === false ? 0 : (getMaxProtocolVersion() ?? 0), max_dave_protocol_version: this.options.daveEncryption === false ? 0 : getMaxProtocolVersion(),
}, },
}); });
this.state = { this.state = {

6
pnpm-lock.yaml generated
View File

@@ -1817,6 +1817,9 @@ importers:
packages/voice: packages/voice:
dependencies: dependencies:
'@snazzah/davey':
specifier: ^0.1.8
version: 0.1.8
'@types/ws': '@types/ws':
specifier: ^8.18.1 specifier: ^8.18.1
version: 8.18.1 version: 8.18.1
@@ -1848,9 +1851,6 @@ importers:
'@noble/ciphers': '@noble/ciphers':
specifier: ^2.1.1 specifier: ^2.1.1
version: 2.1.1 version: 2.1.1
'@snazzah/davey':
specifier: ^0.1.8
version: 0.1.8
'@types/node': '@types/node':
specifier: ^22.19.2 specifier: ^22.19.2
version: 22.19.2 version: 22.19.2