Skip to content

Commit 9561f32

Browse files
authored
feat(NODE-5008): add zstd and kerberos to peer deps (#3691)
1 parent 9f3cc02 commit 9561f32

File tree

6 files changed

+87
-32
lines changed

6 files changed

+87
-32
lines changed

package-lock.json

+8
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+8
Original file line numberDiff line numberDiff line change
@@ -34,13 +34,21 @@
3434
},
3535
"peerDependencies": {
3636
"@aws-sdk/credential-providers": "^3.201.0",
37+
"@mongodb-js/zstd": "^1.1.0",
38+
"kerberos": "^2.0.1",
3739
"mongodb-client-encryption": ">=2.3.0 <3",
3840
"snappy": "^7.2.2"
3941
},
4042
"peerDependenciesMeta": {
4143
"@aws-sdk/credential-providers": {
4244
"optional": true
4345
},
46+
"@mongodb-js/zstd": {
47+
"optional": true
48+
},
49+
"kerberos": {
50+
"optional": true
51+
},
4452
"snappy": {
4553
"optional": true
4654
},

src/cmap/auth/gssapi.ts

+16-4
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import * as dns from 'dns';
22

3-
import { Kerberos, type KerberosClient } from '../../deps';
3+
import { getKerberos, type Kerberos, type KerberosClient } from '../../deps';
44
import { MongoInvalidArgumentError, MongoMissingCredentialsError } from '../../error';
55
import { ns } from '../../utils';
66
import type { Connection } from '../connection';
@@ -36,6 +36,8 @@ async function externalCommand(
3636
}>;
3737
}
3838

39+
let krb: typeof Kerberos;
40+
3941
export class GSSAPI extends AuthProvider {
4042
override async auth(authContext: AuthContext): Promise<void> {
4143
const { connection, credentials } = authContext;
@@ -77,10 +79,11 @@ async function makeKerberosClient(authContext: AuthContext): Promise<KerberosCli
7779
);
7880
}
7981

80-
if ('kModuleError' in Kerberos) {
81-
throw Kerberos['kModuleError'];
82+
loadKrb();
83+
if ('kModuleError' in krb) {
84+
throw krb['kModuleError'];
8285
}
83-
const { initializeClient } = Kerberos;
86+
const { initializeClient } = krb;
8487

8588
const { username, password } = credentials;
8689
const mechanismProperties = credentials.mechanismProperties as MechanismProperties;
@@ -190,3 +193,12 @@ export async function resolveCname(host: string): Promise<string> {
190193
return host;
191194
}
192195
}
196+
197+
/**
198+
* Load the Kerberos library.
199+
*/
200+
function loadKrb() {
201+
if (!krb) {
202+
krb = getKerberos();
203+
}
204+
}

src/cmap/wire_protocol/compression.ts

+36-21
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { promisify } from 'util';
22
import * as zlib from 'zlib';
33

44
import { LEGACY_HELLO_COMMAND } from '../../constants';
5-
import { Snappy, ZStandard } from '../../deps';
5+
import { getZstdLibrary, Snappy, type ZStandard } from '../../deps';
66
import { MongoDecompressionError, MongoInvalidArgumentError } from '../../error';
77

88
/** @public */
@@ -37,35 +37,39 @@ const ZSTD_COMPRESSION_LEVEL = 3;
3737
const zlibInflate = promisify(zlib.inflate.bind(zlib));
3838
const zlibDeflate = promisify(zlib.deflate.bind(zlib));
3939

40+
let zstd: typeof ZStandard;
41+
4042
// Facilitate compressing a message using an agreed compressor
4143
export async function compress(
4244
options: { zlibCompressionLevel: number; agreedCompressor: CompressorName },
4345
dataToBeCompressed: Buffer
4446
): Promise<Buffer> {
4547
const zlibOptions = {} as zlib.ZlibOptions;
4648
switch (options.agreedCompressor) {
47-
case 'snappy':
49+
case 'snappy': {
4850
if ('kModuleError' in Snappy) {
4951
throw Snappy['kModuleError'];
5052
}
5153
return Snappy.compress(dataToBeCompressed);
52-
53-
case 'zstd':
54-
if ('kModuleError' in ZStandard) {
55-
throw ZStandard['kModuleError'];
54+
}
55+
case 'zstd': {
56+
loadZstd();
57+
if ('kModuleError' in zstd) {
58+
throw zstd['kModuleError'];
5659
}
57-
return ZStandard.compress(dataToBeCompressed, ZSTD_COMPRESSION_LEVEL);
58-
59-
case 'zlib':
60+
return zstd.compress(dataToBeCompressed, ZSTD_COMPRESSION_LEVEL);
61+
}
62+
case 'zlib': {
6063
if (options.zlibCompressionLevel) {
6164
zlibOptions.level = options.zlibCompressionLevel;
6265
}
6366
return zlibDeflate(dataToBeCompressed, zlibOptions);
64-
65-
default:
67+
}
68+
default: {
6669
throw new MongoInvalidArgumentError(
6770
`Unknown compressor ${options.agreedCompressor} failed to compress`
6871
);
72+
}
6973
}
7074
}
7175

@@ -83,22 +87,33 @@ export async function decompress(compressorID: number, compressedData: Buffer):
8387
}
8488

8589
switch (compressorID) {
86-
case Compressor.snappy:
90+
case Compressor.snappy: {
8791
if ('kModuleError' in Snappy) {
8892
throw Snappy['kModuleError'];
8993
}
9094
return Snappy.uncompress(compressedData, { asBuffer: true });
91-
92-
case Compressor.zstd:
93-
if ('kModuleError' in ZStandard) {
94-
throw ZStandard['kModuleError'];
95+
}
96+
case Compressor.zstd: {
97+
loadZstd();
98+
if ('kModuleError' in zstd) {
99+
throw zstd['kModuleError'];
95100
}
96-
return ZStandard.decompress(compressedData);
97-
98-
case Compressor.zlib:
101+
return zstd.decompress(compressedData);
102+
}
103+
case Compressor.zlib: {
99104
return zlibInflate(compressedData);
100-
101-
default:
105+
}
106+
default: {
102107
return compressedData;
108+
}
109+
}
110+
}
111+
112+
/**
113+
* Load ZStandard if it is not already set.
114+
*/
115+
function loadZstd() {
116+
if (!zstd) {
117+
zstd = getZstdLibrary();
103118
}
104119
}

src/deps.ts

+17-7
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,15 @@ export let Kerberos: typeof import('kerberos') | { kModuleError: MongoMissingDep
2828
)
2929
);
3030

31-
try {
32-
// Ensure you always wrap an optional require in the try block NODE-3199
33-
Kerberos = require('kerberos');
34-
} catch {} // eslint-disable-line
31+
export function getKerberos(): typeof Kerberos | { kModuleError: MongoMissingDependencyError } {
32+
try {
33+
// Ensure you always wrap an optional require in the try block NODE-3199
34+
Kerberos = require('kerberos');
35+
return Kerberos;
36+
} catch {
37+
return Kerberos;
38+
}
39+
}
3540

3641
export interface KerberosClient {
3742
step(challenge: string): Promise<string>;
@@ -62,9 +67,14 @@ export let ZStandard: ZStandardLib | { kModuleError: MongoMissingDependencyError
6267
)
6368
);
6469

65-
try {
66-
ZStandard = require('@mongodb-js/zstd');
67-
} catch {} // eslint-disable-line
70+
export function getZstdLibrary(): typeof ZStandard | { kModuleError: MongoMissingDependencyError } {
71+
try {
72+
ZStandard = require('@mongodb-js/zstd');
73+
return ZStandard;
74+
} catch {
75+
return ZStandard;
76+
}
77+
}
6878

6979
type CredentialProvider = {
7080
fromNodeProviderChain(this: void): () => Promise<AWSCredentials>;

test/action/dependency.test.ts

+2
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ import { dependencies, peerDependencies, peerDependenciesMeta } from '../../pack
99
const EXPECTED_DEPENDENCIES = ['bson', 'mongodb-connection-string-url', 'socks'];
1010
const EXPECTED_PEER_DEPENDENCIES = [
1111
'@aws-sdk/credential-providers',
12+
'@mongodb-js/zstd',
13+
'kerberos',
1214
'snappy',
1315
'mongodb-client-encryption'
1416
];

0 commit comments

Comments
 (0)