Skip to content

Commit 62ea94b

Browse files
feat(NODE-5762): include cause and package name for all MongoMissingDependencyErrors (#4067)
Co-authored-by: Anna Henningsen <[email protected]>
1 parent ce55ca9 commit 62ea94b

File tree

6 files changed

+71
-45
lines changed

6 files changed

+71
-45
lines changed

Diff for: src/cmap/auth/gssapi.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ async function externalCommand(
3636
}>);
3737
}
3838

39-
let krb: typeof Kerberos;
39+
let krb: Kerberos;
4040

4141
export class GSSAPI extends AuthProvider {
4242
override async auth(authContext: AuthContext): Promise<void> {

Diff for: src/cmap/connection.ts

+5-1
Original file line numberDiff line numberDiff line change
@@ -695,7 +695,11 @@ export class CryptoConnection extends Connection {
695695
): Promise<Document> {
696696
const { autoEncrypter } = this;
697697
if (!autoEncrypter) {
698-
throw new MongoMissingDependencyError('No AutoEncrypter available for encryption');
698+
// TODO(NODE-6065): throw a MongoRuntimeError in Node V7
699+
// @ts-expect-error No cause provided because there is no underlying error.
700+
throw new MongoMissingDependencyError('No AutoEncrypter available for encryption', {
701+
dependencyName: 'n/a'
702+
});
699703
}
700704

701705
const serverWireVersion = maxWireVersion(this);

Diff for: src/cmap/wire_protocol/compression.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ const ZSTD_COMPRESSION_LEVEL = 3;
4545
const zlibInflate = promisify(zlib.inflate.bind(zlib));
4646
const zlibDeflate = promisify(zlib.deflate.bind(zlib));
4747

48-
let zstd: typeof ZStandard;
48+
let zstd: ZStandard;
4949
let Snappy: SnappyLib | null = null;
5050
function loadSnappy() {
5151
if (Snappy == null) {

Diff for: src/deps.ts

+52-40
Original file line numberDiff line numberDiff line change
@@ -18,21 +18,22 @@ function makeErrorModule(error: any) {
1818
});
1919
}
2020

21-
export let Kerberos: typeof import('kerberos') | { kModuleError: MongoMissingDependencyError } =
22-
makeErrorModule(
23-
new MongoMissingDependencyError(
24-
'Optional module `kerberos` not found. Please install it to enable kerberos authentication'
25-
)
26-
);
21+
export type Kerberos = typeof import('kerberos') | { kModuleError: MongoMissingDependencyError };
2722

28-
export function getKerberos(): typeof Kerberos | { kModuleError: MongoMissingDependencyError } {
23+
export function getKerberos(): Kerberos {
24+
let kerberos: Kerberos;
2925
try {
3026
// Ensure you always wrap an optional require in the try block NODE-3199
31-
Kerberos = require('kerberos');
32-
return Kerberos;
33-
} catch {
34-
return Kerberos;
27+
kerberos = require('kerberos');
28+
} catch (error) {
29+
kerberos = makeErrorModule(
30+
new MongoMissingDependencyError(
31+
'Optional module `kerberos` not found. Please install it to enable kerberos authentication',
32+
{ cause: error, dependencyName: 'kerberos' }
33+
)
34+
);
3535
}
36+
return kerberos;
3637
}
3738

3839
export interface KerberosClient {
@@ -57,20 +58,22 @@ type ZStandardLib = {
5758
decompress(buf: Buffer): Promise<Buffer>;
5859
};
5960

60-
export let ZStandard: ZStandardLib | { kModuleError: MongoMissingDependencyError } =
61-
makeErrorModule(
62-
new MongoMissingDependencyError(
63-
'Optional module `@mongodb-js/zstd` not found. Please install it to enable zstd compression'
64-
)
65-
);
61+
export type ZStandard = ZStandardLib | { kModuleError: MongoMissingDependencyError };
6662

67-
export function getZstdLibrary(): typeof ZStandard | { kModuleError: MongoMissingDependencyError } {
63+
export function getZstdLibrary(): ZStandardLib | { kModuleError: MongoMissingDependencyError } {
64+
let ZStandard: ZStandardLib | { kModuleError: MongoMissingDependencyError };
6865
try {
6966
ZStandard = require('@mongodb-js/zstd');
70-
return ZStandard;
71-
} catch {
72-
return ZStandard;
67+
} catch (error) {
68+
ZStandard = makeErrorModule(
69+
new MongoMissingDependencyError(
70+
'Optional module `@mongodb-js/zstd` not found. Please install it to enable zstd compression',
71+
{ cause: error, dependencyName: 'zstd' }
72+
)
73+
);
7374
}
75+
76+
return ZStandard;
7477
}
7578

7679
/**
@@ -100,11 +103,12 @@ export function getAwsCredentialProvider():
100103
// Ensure you always wrap an optional require in the try block NODE-3199
101104
const credentialProvider = require('@aws-sdk/credential-providers');
102105
return credentialProvider;
103-
} catch {
106+
} catch (error) {
104107
return makeErrorModule(
105108
new MongoMissingDependencyError(
106109
'Optional module `@aws-sdk/credential-providers` not found.' +
107-
' Please install it to enable getting aws credentials via the official sdk.'
110+
' Please install it to enable getting aws credentials via the official sdk.',
111+
{ cause: error, dependencyName: '@aws-sdk/credential-providers' }
108112
)
109113
);
110114
}
@@ -120,11 +124,12 @@ export function getGcpMetadata(): GcpMetadata {
120124
// Ensure you always wrap an optional require in the try block NODE-3199
121125
const credentialProvider = require('gcp-metadata');
122126
return credentialProvider;
123-
} catch {
127+
} catch (error) {
124128
return makeErrorModule(
125129
new MongoMissingDependencyError(
126130
'Optional module `gcp-metadata` not found.' +
127-
' Please install it to enable getting gcp credentials via the official sdk.'
131+
' Please install it to enable getting gcp credentials via the official sdk.',
132+
{ cause: error, dependencyName: 'gcp-metadata' }
128133
)
129134
);
130135
}
@@ -150,10 +155,10 @@ export function getSnappy(): SnappyLib | { kModuleError: MongoMissingDependencyE
150155
// Ensure you always wrap an optional require in the try block NODE-3199
151156
const value = require('snappy');
152157
return value;
153-
} catch (cause) {
158+
} catch (error) {
154159
const kModuleError = new MongoMissingDependencyError(
155160
'Optional module `snappy` not found. Please install it to enable snappy compression',
156-
{ cause }
161+
{ cause: error, dependencyName: 'snappy' }
157162
);
158163
return { kModuleError };
159164
}
@@ -184,10 +189,10 @@ export function getSocks(): SocksLib | { kModuleError: MongoMissingDependencyErr
184189
// Ensure you always wrap an optional require in the try block NODE-3199
185190
const value = require('socks');
186191
return value;
187-
} catch (cause) {
192+
} catch (error) {
188193
const kModuleError = new MongoMissingDependencyError(
189194
'Optional module `socks` not found. Please install it to connections over a SOCKS5 proxy',
190-
{ cause }
195+
{ cause: error, dependencyName: 'socks' }
191196
);
192197
return { kModuleError };
193198
}
@@ -234,16 +239,23 @@ interface AWS4 {
234239
};
235240
}
236241

237-
export let aws4: AWS4 | { kModuleError: MongoMissingDependencyError } = makeErrorModule(
238-
new MongoMissingDependencyError(
239-
'Optional module `aws4` not found. Please install it to enable AWS authentication'
240-
)
241-
);
242+
export const aws4: AWS4 | { kModuleError: MongoMissingDependencyError } = loadAws4();
242243

243-
try {
244-
// Ensure you always wrap an optional require in the try block NODE-3199
245-
aws4 = require('aws4');
246-
} catch {} // eslint-disable-line
244+
function loadAws4() {
245+
let aws4: AWS4 | { kModuleError: MongoMissingDependencyError };
246+
try {
247+
aws4 = require('aws4');
248+
} catch (error) {
249+
aws4 = makeErrorModule(
250+
new MongoMissingDependencyError(
251+
'Optional module `aws4` not found. Please install it to enable AWS authentication',
252+
{ cause: error, dependencyName: 'aws4' }
253+
)
254+
);
255+
}
256+
257+
return aws4;
258+
}
247259

248260
/** A utility function to get the instance of mongodb-client-encryption, if it exists. */
249261
export function getMongoDBClientEncryption():
@@ -256,10 +268,10 @@ export function getMongoDBClientEncryption():
256268
// Cannot be moved to helper utility function, bundlers search and replace the actual require call
257269
// in a way that makes this line throw at bundle time, not runtime, catching here will make bundling succeed
258270
mongodbClientEncryption = require('mongodb-client-encryption');
259-
} catch (cause) {
271+
} catch (error) {
260272
const kModuleError = new MongoMissingDependencyError(
261273
'Optional module `mongodb-client-encryption` not found. Please install it to use auto encryption or ClientEncryption.',
262-
{ cause }
274+
{ cause: error, dependencyName: 'mongodb-client-encryption' }
263275
);
264276
return { kModuleError };
265277
}

Diff for: src/encrypter.ts

+5-1
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,11 @@ export class Encrypter {
128128
if ('kModuleError' in mongodbClientEncryption) {
129129
throw new MongoMissingDependencyError(
130130
'Auto-encryption requested, but the module is not installed. ' +
131-
'Please add `mongodb-client-encryption` as a dependency of your project'
131+
'Please add `mongodb-client-encryption` as a dependency of your project',
132+
{
133+
cause: mongodbClientEncryption['kModuleError'],
134+
dependencyName: 'mongodb-client-encryption'
135+
}
132136
);
133137
}
134138
}

Diff for: src/error.ts

+7-1
Original file line numberDiff line numberDiff line change
@@ -1008,6 +1008,11 @@ export class MongoMissingCredentialsError extends MongoAPIError {
10081008
* @category Error
10091009
*/
10101010
export class MongoMissingDependencyError extends MongoAPIError {
1011+
dependencyName: string;
1012+
1013+
/** @remarks This property is assigned in the `Error` constructor. */
1014+
declare cause: Error;
1015+
10111016
/**
10121017
* **Do not use this constructor!**
10131018
*
@@ -1019,8 +1024,9 @@ export class MongoMissingDependencyError extends MongoAPIError {
10191024
*
10201025
* @public
10211026
**/
1022-
constructor(message: string, options: { cause?: Error } = {}) {
1027+
constructor(message: string, options: { cause: Error; dependencyName: string }) {
10231028
super(message, options);
1029+
this.dependencyName = options.dependencyName;
10241030
}
10251031

10261032
override get name(): string {

0 commit comments

Comments
 (0)